blob: ddec1c4374474e2c800df6c59c50715deff9d89b [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <ucontext.h>
#include <map>
#include <vector>
#include "base/debug/proc_maps_linux.h"
#include "base/profiler/native_stack_sampler.h"
#include "base/threading/platform_thread.h"
#include "components/tracing/tracing_export.h"
namespace jni_generator {
struct JniJavaCallContextUnchecked;
struct unw_context_t;
namespace tracing {
// Utility to unwind stacks for current thread on ARM devices. Contains ability
// to unwind stacks based on EHABI section in Android libraries and using the
// custom stack unwind information in Chrome. This works on top of
// base::trace_event::CFIBacktraceAndroid, which unwinds Chrome only stacks.
// This class does not provide any thread safety guarantees. It is also unsafe
// to use multiple instances of this class at the same time due to signal
// handling. So, the client must ensure synchronization between multiple
// instances of this class.
class TRACING_EXPORT StackUnwinderAndroid {
using JniMarker = jni_generator::JniJavaCallContextUnchecked;
// Whether to use libunwind for android framework frames.
static const bool kUseLibunwind;
// Initializes the unwinder for current process. It finds all loaded libraries
// in current process and also initializes CFIBacktraceAndroid, with file IO.
// Can be called multiple times, to update the loaded modules.
void Initialize();
// Unwinds stack frames for current thread and stores the program counters in
// |out_trace|, and returns the number of frames stored.
size_t TraceStack(const void** out_trace, size_t max_depth) const;
// Same as above function, but pauses the thread with the given |tid| and then
// unwinds. |tid| should not be current thread's.
size_t TraceStack(base::PlatformThreadId tid,
base::NativeStackSampler::StackBuffer* stack_buffer,
const void** out_trace,
size_t max_depth) const;
// Returns the end address of the memory map with given |addr|.
uintptr_t GetEndAddressOfRegion(uintptr_t addr) const;
// Returns true if the given |pc| was part of any mapped segments in the
// process.
bool IsAddressMapped(uintptr_t pc) const;
bool is_initialized() const { return is_initialized_; }
// Sends a SIGURG signal to the thread with id |tid| and copies the stack
// segment of the thread, along with register context. Returns true on
// success.
bool SuspendThreadAndRecordStack(
base::PlatformThreadId tid,
base::NativeStackSampler::StackBuffer* stack_buffer,
uintptr_t* sp,
size_t* stack_size,
unw_context_t* context,
ucontext_t* signal_context) const;
// Replaces any pointers to the old stack to point to the new stack segment.
// Returns the jni markers found on stack while scanning stack for pointers.
std::vector<const JniMarker*> RewritePointersAndGetMarkers(
base::NativeStackSampler::StackBuffer* stack_buffer,
uintptr_t sp,
size_t stack_size) const;
bool is_initialized_ = false;
// Stores all the memory mapped regions in the current process, including all
// the files mapped and anonymous regions. This data could be stale, but the
// error caused by changes in library loads would be missing stackframes and
// is acceptable.
std::vector<base::debug::MappedMemoryRegion> regions_;
} // namespace tracing