#ifdef UNSAFE_BUFFERS_BUILD
#pragma allow_unsafe_buffers
#endif
#include "base/profiler/stack_sampling_profiler_test_util.h"
#include <string_view>
#include <utility>
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/path_service.h"
#include "base/profiler/native_unwinder_android_map_delegate.h"
#include "base/profiler/native_unwinder_android_memory_regions_map.h"
#include "base/profiler/profiler_buildflags.h"
#include "base/profiler/stack_buffer.h"
#include "base/profiler/stack_sampling_profiler.h"
#include "base/profiler/unwinder.h"
#include "base/strings/stringprintf.h"
#include "base/test/bind.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#if BUILDFLAG(IS_ANDROID) && BUILDFLAG(ENABLE_ARM_CFI_TABLE)
#include "base/android/apk_assets.h"
#include "base/android/library_loader/anchor_functions.h"
#include "base/files/memory_mapped_file.h"
#include "base/no_destructor.h"
#include "base/profiler/chrome_unwinder_android.h"
#include "base/profiler/native_unwinder_android.h"
#endif
#if BUILDFLAG(IS_WIN)
#include <malloc.h>
#define alloca …
#else
#include <alloca.h>
#endif
extern "C" {
extern char __executable_start;
}
namespace base {
namespace {
class TestProfileBuilder : public ProfileBuilder { … };
void OtherLibraryCallback(void* arg) { … }
#if BUILDFLAG(IS_ANDROID) && BUILDFLAG(ENABLE_ARM_CFI_TABLE)
class NativeUnwinderAndroidMapDelegateForTesting
: public NativeUnwinderAndroidMapDelegate {
public:
explicit NativeUnwinderAndroidMapDelegateForTesting(
std::unique_ptr<NativeUnwinderAndroidMemoryRegionsMap> memory_regions_map)
: memory_regions_map_(std::move(memory_regions_map)) {}
NativeUnwinderAndroidMemoryRegionsMap* GetMapReference() override {
return memory_regions_map_.get();
}
void ReleaseMapReference() override {}
private:
const std::unique_ptr<NativeUnwinderAndroidMemoryRegionsMap>
memory_regions_map_;
};
NativeUnwinderAndroidMapDelegateForTesting* GetMapDelegateForTesting() {
static base::NoDestructor<NativeUnwinderAndroidMapDelegateForTesting>
map_delegate(NativeUnwinderAndroid::CreateMemoryRegionsMap());
return map_delegate.get();
}
std::unique_ptr<NativeUnwinderAndroid> CreateNativeUnwinderAndroidForTesting(
uintptr_t exclude_module_with_base_address) {
return std::make_unique<NativeUnwinderAndroid>(
exclude_module_with_base_address, GetMapDelegateForTesting());
}
std::unique_ptr<Unwinder> CreateChromeUnwinderAndroidForTesting(
uintptr_t chrome_module_base_address) {
static constexpr char kCfiFileName[] = "assets/unwind_cfi_32_v2";
class ChromeUnwinderAndroidForTesting : public ChromeUnwinderAndroid {
public:
ChromeUnwinderAndroidForTesting(std::unique_ptr<MemoryMappedFile> cfi_file,
const ChromeUnwindInfoAndroid& unwind_info,
uintptr_t chrome_module_base_address,
uintptr_t text_section_start_address)
: ChromeUnwinderAndroid(unwind_info,
chrome_module_base_address,
text_section_start_address),
cfi_file_(std::move(cfi_file)) {}
~ChromeUnwinderAndroidForTesting() override = default;
private:
std::unique_ptr<MemoryMappedFile> cfi_file_;
};
MemoryMappedFile::Region cfi_region;
int fd = base::android::OpenApkAsset(kCfiFileName, &cfi_region);
DCHECK_GT(fd, 0);
auto cfi_file = std::make_unique<MemoryMappedFile>();
bool ok = cfi_file->Initialize(base::File(fd), cfi_region);
DCHECK(ok);
return std::make_unique<ChromeUnwinderAndroidForTesting>(
std::move(cfi_file),
base::CreateChromeUnwindInfoAndroid(
{cfi_file->data(), cfi_file->length()}),
chrome_module_base_address,
base::android::kStartOfText);
}
#endif
}
TargetThread::TargetThread(OnceClosure to_run) : … { … }
TargetThread::~TargetThread() = default;
void TargetThread::Start() { … }
void TargetThread::Join() { … }
void TargetThread::ThreadMain() { … }
UnwindScenario::UnwindScenario(const SetupFunction& setup_function)
: … { … }
UnwindScenario::~UnwindScenario() = default;
FunctionAddressRange UnwindScenario::GetWaitForSampleAddressRange() const { … }
FunctionAddressRange UnwindScenario::GetSetupFunctionAddressRange() const { … }
FunctionAddressRange UnwindScenario::GetOuterFunctionAddressRange() const { … }
void UnwindScenario::Execute(SampleEvents* events) { … }
NOINLINE FunctionAddressRange
UnwindScenario::InvokeSetupFunction(const SetupFunction& setup_function,
SampleEvents* events) { … }
NOINLINE FunctionAddressRange
UnwindScenario::WaitForSample(SampleEvents* events) { … }
NOINLINE FunctionAddressRange
CallWithPlainFunction(OnceClosure wait_for_sample) { … }
NOINLINE FunctionAddressRange CallWithAlloca(OnceClosure wait_for_sample) { … }
NOINLINE FunctionAddressRange
CallThroughOtherLibrary(NativeLibrary library, OnceClosure wait_for_sample) { … }
void WithTargetThread(UnwindScenario* scenario,
ProfileCallback profile_callback) { … }
std::vector<Frame> SampleScenario(UnwindScenario* scenario,
ModuleCache* module_cache,
UnwinderFactory aux_unwinder_factory) { … }
std::string FormatSampleForDiagnosticOutput(const std::vector<Frame>& sample) { … }
void ExpectStackContains(const std::vector<Frame>& stack,
const std::vector<FunctionAddressRange>& functions) { … }
void ExpectStackDoesNotContain(
const std::vector<Frame>& stack,
const std::vector<FunctionAddressRange>& functions) { … }
NativeLibrary LoadTestLibrary(std::string_view library_name) { … }
NativeLibrary LoadOtherLibrary() { … }
uintptr_t GetAddressInOtherLibrary(NativeLibrary library) { … }
StackSamplingProfiler::UnwindersFactory CreateCoreUnwindersFactoryForTesting(
ModuleCache* module_cache) { … }
uintptr_t TestModule::GetBaseAddress() const { … }
std::string TestModule::GetId() const { … }
FilePath TestModule::GetDebugBasename() const { … }
size_t TestModule::GetSize() const { … }
bool TestModule::IsNative() const { … }
bool operator==(const Frame& a, const Frame& b) { … }
}