Skip to content

Commit

Permalink
Revert "[Sampling profiler] Fix and test NativeUnwinderAndroid module…
Browse files Browse the repository at this point in the history
… extents"

This reverts commit b95277b.

Reason for revert: suspected of causing test failures on Marshmallow
Tablet Tester and android-asan

Original change's description:
> [Sampling profiler] Fix and test NativeUnwinderAndroid module extents
> 
> Reuses the ModuleCache POSIX module implementation for Android ELF
> modules, which fixes the incorrect start and end addresses previously
> generated by AndroidModule. Renames AndroidModule to NonElfModule.
> Removes tests specific to the previous implementation.
> 
> Also includes a latent 64-bit bug fix where the register copy would
> only copy half the registers.
> 
> Bug: 1004855
> Change-Id: I3b26fac427043b2022b1d35b5c985e468ce35692
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2253221
> Reviewed-by: Etienne Pierre-Doray <etiennep@chromium.org>
> Commit-Queue: Mike Wittman <wittman@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#783689}

TBR=wittman@chromium.org,etiennep@chromium.org

Change-Id: I48aca7285e572eab5147ef584dda01eeabfb2008
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 1004855, 1101023
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2274327
Reviewed-by: Mike Wittman <wittman@chromium.org>
Commit-Queue: Mike Wittman <wittman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#784062}
  • Loading branch information
Mike Wittman authored and Commit Bot committed Jun 30, 2020
1 parent 348741b commit 1032158
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 84 deletions.
78 changes: 44 additions & 34 deletions base/profiler/native_unwinder_android.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#include "base/profiler/module_cache.h"
#include "base/profiler/native_unwinder.h"
#include "base/profiler/profile_builder.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "build/build_config.h"

#if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
Expand All @@ -31,32 +33,57 @@
namespace base {
namespace {

class NonElfModule : public ModuleCache::Module {
// Returns the hex string build id given the binary build id from MapInfo.
// Returns the empty string if no build id is present.
//
// Build IDs follow a cross-platform format consisting of two fields
// concatenated together:
// - the module's unique id encoded as a hex string, and
// - the age suffix for incremental builds.
//
// On POSIX, the unique id comes from the ELF binary's .note.gnu.build-id
// section. The age field is always 0.
std::string EncodeBuildID(StringPiece map_info_build_id) {
if (map_info_build_id.empty())
return std::string();

return HexEncode(map_info_build_id.data(), map_info_build_id.size()) + "0";
}

// We assume this is a file-backed region if the name looks like an absolute
// path, and return the basename. Otherwise we assume the region is not
// associated with a file and return the full name string.
FilePath CreateDebugBasename(StringPiece map_info_name) {
const FilePath path = FilePath(map_info_name);
return !map_info_name.empty() && map_info_name[0] == '/' ? path.BaseName()
: path;
}

class AndroidModule : public ModuleCache::Module {
public:
NonElfModule(unwindstack::MapInfo* map_info)
AndroidModule(unwindstack::MapInfo* map_info)
: start_(map_info->start),
size_(map_info->end - start_),
map_info_name_(map_info->name) {}
~NonElfModule() override = default;
size_(map_info->end - map_info->start),
build_id_(EncodeBuildID(map_info->GetBuildID())),
debug_basename_(CreateDebugBasename(map_info->name)) {}
~AndroidModule() override = default;

uintptr_t GetBaseAddress() const override { return start_; }

std::string GetId() const override { return std::string(); }
std::string GetId() const override { return build_id_; }

FilePath GetDebugBasename() const override {
return FilePath(map_info_name_);
}
FilePath GetDebugBasename() const override { return debug_basename_; }

// Gets the size of the module.
size_t GetSize() const override { return size_; }

// True if this is a native module.
bool IsNative() const override { return true; }

private:
const uintptr_t start_;
const size_t size_;
const std::string map_info_name_;
const std::string build_id_;
const FilePath debug_basename_;
};

std::unique_ptr<unwindstack::Regs> CreateFromRegisterContext(
Expand All @@ -77,10 +104,10 @@ void CopyToRegisterContext(unwindstack::Regs* regs,
RegisterContext* thread_context) {
#if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
memcpy(reinterpret_cast<void*>(&thread_context->arm_r0), regs->RawData(),
unwindstack::ARM_REG_LAST * sizeof(uintptr_t));
unwindstack::ARM_REG_LAST * sizeof(uint32_t));
#elif defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_64_BITS)
memcpy(reinterpret_cast<void*>(&thread_context->regs[0]), regs->RawData(),
unwindstack::ARM64_REG_LAST * sizeof(uintptr_t));
unwindstack::ARM64_REG_LAST * sizeof(uint32_t));
#else // #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
NOTREACHED();
#endif // #if defined(ARCH_CPU_ARM_FAMILY) && defined(ARCH_CPU_32_BITS)
Expand Down Expand Up @@ -219,29 +246,12 @@ UnwindResult NativeUnwinderAndroid::TryUnwind(RegisterContext* thread_context,
void NativeUnwinderAndroid::AddInitialModulesFromMaps(
const unwindstack::Maps& memory_regions_map,
ModuleCache* module_cache) {
// The effect of this loop is to create modules for the executable regions in
// the memory map. Regions composing a mapped ELF file are handled specially
// however: for just one module extending from the ELF base address to the
// *last* executable region backed by the file is implicitly created by
// ModuleCache. This avoids duplicate module instances covering the same
// in-memory module in the case that a module has multiple mmapped executable
// regions.
for (const std::unique_ptr<unwindstack::MapInfo>& region :
memory_regions_map) {
for (const auto& region : memory_regions_map) {
// Only add executable regions.
if (!(region->flags & PROT_EXEC))
continue;

// Use the standard ModuleCache POSIX module representation for ELF files.
// This call returns the containing ELF module for the region, creating it
// if it doesn't exist.
if (module_cache->GetModuleForAddress(
static_cast<uintptr_t>(region->start))) {
continue;
}

// Non-ELF modules are represented with NonElfModule.
module_cache->AddCustomNativeModule(
std::make_unique<NonElfModule>(region.get()));
std::make_unique<AndroidModule>(region.get()));
}
}

Expand All @@ -257,7 +267,7 @@ void NativeUnwinderAndroid::EmitDexFrame(uintptr_t dex_pc,
// AddInitialModulesFromMaps().
unwindstack::MapInfo* map_info = memory_regions_map_->Find(dex_pc);
if (map_info) {
auto new_module = std::make_unique<NonElfModule>(map_info);
auto new_module = std::make_unique<AndroidModule>(map_info);
module = new_module.get();
module_cache->AddCustomNativeModule(std::move(new_module));
}
Expand Down
94 changes: 44 additions & 50 deletions base/profiler/native_unwinder_android_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,9 @@

#include <sys/mman.h>

#include <inttypes.h>
#include <stdio.h> // For printf address.
#include <string.h>
#include <algorithm>
#include <iterator>
#include <vector>

#include "base/android/build_info.h"
#include "base/android/jni_android.h"
Expand All @@ -23,7 +20,6 @@
#include "base/profiler/stack_sampler.h"
#include "base/profiler/stack_sampling_profiler_test_util.h"
#include "base/profiler/thread_delegate_posix.h"
#include "base/strings/stringprintf.h"
#include "base/test/bind_test_util.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
Expand All @@ -34,11 +30,6 @@ namespace base {

namespace {

bool CompareModulesByBaseAddress(const ModuleCache::Module* a,
const ModuleCache::Module* b) {
return a->GetBaseAddress() < b->GetBaseAddress();
}

// Add a MapInfo with the provided values to |maps|.
void AddMapInfo(uint64_t start,
uint64_t end,
Expand Down Expand Up @@ -396,8 +387,25 @@ TEST(NativeUnwinderAndroidTest, UnwindStackMemoryTest) {
check_read_succeeds(end - 1, 1);
}

// Checks the debug basename is the whole name for a non-ELF module.
TEST(NativeUnwinderAndroidTest, ModuleDebugBasenameForNonElf) {
// Checks the debug basename for a module with a path name.
TEST(NativeUnwinderAndroidTest, ModuleDebugBasenameForPath) {
unwindstack::Maps maps;

AddMapInfo(0x1000u, 0x2000u, 0u, PROT_READ | PROT_EXEC, "/usr/lib/foo.so",
{0xAA}, maps);

ModuleCache module_cache;
NativeUnwinderAndroid::AddInitialModulesFromMaps(maps, &module_cache);

std::vector<const ModuleCache::Module*> modules = module_cache.GetModules();

ASSERT_EQ(1u, modules.size());
EXPECT_EQ("foo.so", modules[0]->GetDebugBasename().value());
}

// Checks the debug basename is the whole name for a module with a non-path
// name.
TEST(NativeUnwinderAndroidTest, ModuleDebugBasenameForNonPath) {
unwindstack::Maps maps;

AddMapInfo(0x1000u, 0x2000u, 0u, PROT_READ | PROT_EXEC, "[foo / bar]", {0xAA},
Expand All @@ -412,48 +420,37 @@ TEST(NativeUnwinderAndroidTest, ModuleDebugBasenameForNonElf) {
EXPECT_EQ("[foo / bar]", modules[0]->GetDebugBasename().value());
}

// Checks that modules are only created for executable memory regions.
TEST(NativeUnwinderAndroidTest, ModulesCreatedOnlyForExecutableRegions) {
// Checks that the specified build id is returned.
TEST(NativeUnwinderAndroidTest, ModuleId) {
unwindstack::Maps maps;
AddMapInfo(0x1000u, 0x2000u, 0u, PROT_READ | PROT_EXEC, "[a]", {0xAA}, maps);
AddMapInfo(0x2000u, 0x3000u, 0u, PROT_READ, "[b]", {0xAB}, maps);
AddMapInfo(0x3000u, 0x4000u, 0u, PROT_READ | PROT_EXEC, "[c]", {0xAC}, maps);

AddMapInfo(0x1000u, 0x2000u, 0u, PROT_READ | PROT_EXEC, "/lib/foo.so",
{0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF}, maps);

ModuleCache module_cache;
NativeUnwinderAndroid::AddInitialModulesFromMaps(maps, &module_cache);

std::vector<const ModuleCache::Module*> modules = module_cache.GetModules();
std::sort(modules.begin(), modules.end(), CompareModulesByBaseAddress);

ASSERT_EQ(2u, modules.size());
EXPECT_EQ(0x1000u, modules[0]->GetBaseAddress());
EXPECT_EQ(0x3000u, modules[1]->GetBaseAddress());
ASSERT_EQ(1u, modules.size());
// The id should have a '0' age field appended.
EXPECT_EQ("1234567890ABCDEF0", modules[0]->GetId());
}

// Checks that module address ranges don't overlap.
TEST(NativeUnwinderAndroidTest, NonOverlappingModules) {
// Checks that an empty module id has no age field appended.
TEST(NativeUnwinderAndroidTest, EmptyModuleId) {
unwindstack::Maps maps;

AddMapInfo(0x1000u, 0x2000u, 0u, PROT_READ | PROT_EXEC, "/lib/foo.so",
std::string(), maps);

ModuleCache module_cache;
std::unique_ptr<unwindstack::Maps> maps = NativeUnwinderAndroid::CreateMaps();
NativeUnwinderAndroid::AddInitialModulesFromMaps(*maps, &module_cache);
NativeUnwinderAndroid::AddInitialModulesFromMaps(maps, &module_cache);

std::vector<const ModuleCache::Module*> modules = module_cache.GetModules();
std::sort(modules.begin(), modules.end(), CompareModulesByBaseAddress);
auto loc = std::adjacent_find(
modules.begin(), modules.end(),
[](const ModuleCache::Module* m1, const ModuleCache::Module* m2) {
return m2->GetBaseAddress() < m1->GetBaseAddress() + m1->GetSize();
});

const auto describe_module = [](const ModuleCache::Module* module) {
return StringPrintf(
"id \"%s\", debug basename \"%s\" at [0x%" PRIxPTR ", 0x%" PRIxPTR ")",
module->GetId().c_str(), module->GetDebugBasename().value().c_str(),
module->GetBaseAddress(), module->GetBaseAddress() + module->GetSize());
};

EXPECT_EQ(modules.end(), loc) << "module overlap found between\n"
<< " " << describe_module(*loc) << " and \n"
<< " " << describe_module(*std::next(loc));
ASSERT_EQ(1u, modules.size());
EXPECT_EQ(std::string(), modules[0]->GetId());
}

// ModuleCache::GetModuleForAddress() is not implemented for 64-bit arm.
Expand All @@ -466,9 +463,8 @@ TEST(NativeUnwinderAndroidTest, NonOverlappingModules) {
// state created by the ModuleCache. Checks the module for a system library.
TEST(NativeUnwinderAndroidTest, MAYBE_ModuleState_SystemLibrary) {
ModuleCache unwinder_module_cache;
std::unique_ptr<unwindstack::Maps> maps = NativeUnwinderAndroid::CreateMaps();
NativeUnwinderAndroid::AddInitialModulesFromMaps(*maps,
&unwinder_module_cache);
NativeUnwinderAndroid::AddInitialModulesFromMaps(
*NativeUnwinderAndroid::CreateMaps(), &unwinder_module_cache);

const uintptr_t c_library_function_address =
reinterpret_cast<uintptr_t>(&printf);
Expand All @@ -483,12 +479,11 @@ TEST(NativeUnwinderAndroidTest, MAYBE_ModuleState_SystemLibrary) {
reference_module_cache.GetModuleForAddress(c_library_function_address);
ASSERT_NE(nullptr, reference_module);

EXPECT_EQ(reference_module->GetBaseAddress(),
unwinder_module->GetBaseAddress());
// TODO(https://crbug.com/1004855): Fix base address and size discrepancies
// and add checks.
EXPECT_EQ(reference_module->GetId(), unwinder_module->GetId());
EXPECT_EQ(reference_module->GetDebugBasename(),
unwinder_module->GetDebugBasename());
EXPECT_EQ(unwinder_module->GetSize(), reference_module->GetSize());
}

// ModuleCache::GetModuleForAddress() is not implemented for 64-bit arm.
Expand All @@ -502,9 +497,8 @@ TEST(NativeUnwinderAndroidTest, MAYBE_ModuleState_SystemLibrary) {
// library.
TEST(NativeUnwinderAndroidTest, MAYBE_ModuleState_ChromeLibrary) {
ModuleCache unwinder_module_cache;
std::unique_ptr<unwindstack::Maps> maps = NativeUnwinderAndroid::CreateMaps();
NativeUnwinderAndroid::AddInitialModulesFromMaps(*maps,
&unwinder_module_cache);
NativeUnwinderAndroid::AddInitialModulesFromMaps(
*NativeUnwinderAndroid::CreateMaps(), &unwinder_module_cache);

const uintptr_t chrome_function_address =
reinterpret_cast<uintptr_t>(&CaptureScenario);
Expand All @@ -525,7 +519,7 @@ TEST(NativeUnwinderAndroidTest, MAYBE_ModuleState_ChromeLibrary) {
EXPECT_EQ(reference_module->GetId(), unwinder_module->GetId());
EXPECT_EQ(reference_module->GetDebugBasename(),
unwinder_module->GetDebugBasename());
EXPECT_EQ(unwinder_module->GetSize(), reference_module->GetSize());
// TODO(https://crbug.com/1004855): Fix size discrepancy and add check.
}

} // namespace base

0 comments on commit 1032158

Please sign in to comment.