Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhance information available for debugging NDK stack unwinds #17

Merged
merged 2 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ uint64_t RegsArm::sp() {
return regs_[ARM_REG_SP];
}

uint64_t RegsArm::lr() {
return regs_[ARM_REG_LR];
}

void RegsArm::set_pc(uint64_t pc) {
regs_[ARM_REG_PC] = pc;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ uint64_t RegsArm64::sp() {
return regs_[ARM64_REG_SP];
}

uint64_t RegsArm64::lr() {
return regs_[ARM64_REG_LR];
}

static uint64_t strip_pac(uint64_t pc, uint64_t mask) {
// If the target is aarch64 then the return address may have been
// signed using the Armv8.3-A Pointer Authentication extension. The
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ uint64_t RegsX86::sp() {
return regs_[X86_REG_SP];
}

uint64_t RegsX86::lr() {
return 0;
}

void RegsX86::set_pc(uint64_t pc) {
regs_[X86_REG_PC] = static_cast<uint32_t>(pc);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ uint64_t RegsX86_64::sp() {
return regs_[X86_64_REG_SP];
}

uint64_t RegsX86_64::lr() {
return 0;
}

void RegsX86_64::set_pc(uint64_t pc) {
regs_[X86_64_REG_PC] = pc;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class Regs {
virtual void* RawData() = 0;
virtual uint64_t pc() = 0;
virtual uint64_t sp() = 0;
virtual uint64_t lr() = 0; // embrace added

virtual void set_pc(uint64_t pc) = 0;
virtual void set_sp(uint64_t sp) = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class RegsArm : public RegsImpl<uint32_t> {

uint64_t pc() override;
uint64_t sp() override;
uint64_t lr() override;

void set_pc(uint64_t pc) override;
void set_sp(uint64_t sp) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class RegsArm64 : public RegsImpl<uint64_t> {

uint64_t pc() override;
uint64_t sp() override;
uint64_t lr() override;

void set_pc(uint64_t pc) override;
void set_sp(uint64_t sp) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class RegsX86 : public RegsImpl<uint32_t> {

uint64_t pc() override;
uint64_t sp() override;
uint64_t lr() override;

void set_pc(uint64_t pc) override;
void set_sp(uint64_t sp) override;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ class RegsX86_64 : public RegsImpl<uint64_t> {

uint64_t pc() override;
uint64_t sp() override;
uint64_t lr() override;

void set_pc(uint64_t pc) override;
void set_sp(uint64_t sp) override;
Expand Down
51 changes: 51 additions & 0 deletions embrace-android-sdk/src/main/cpp/file_writer.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@ static const char *kOffsetAddrKey = "oa";
static const char *kModuleAddrKey = "ma";
static const char *kLineNumKey = "ln";
static const char *kBuildIdKey = "build_id";
static const char *kFullNameKey = "full_name";
static const char *kFunctionNameKey = "function_name";
static const char *kRelPcKey = "rel_pc";
static const char *kPcKey = "pc";
static const char *kSpKey = "sp";
static const char *kLrKey = "lr";
static const char *kStartKey = "start";
static const char *kEndKey = "end";
static const char *kOffsetKey = "offset";
static const char *kFunctionOffsetKey = "function_offset";
static const char *kFlagsKey = "flags";
static const char *kElfFileNotReadableKey = "elf_file_not_readable";
static const char *kCrashKey = "crash";
static const char *kVersionKey = "v";

Expand Down Expand Up @@ -123,6 +135,29 @@ emb_error *emb_read_errors_from_file(const char *path) {
return errors;
}

void emb_log_frame_dbg_info(int i, emb_sframe *frame) {
EMB_LOGDEV("Logging out debug info for stackframe %d", i);
EMB_LOGDEV("filename: %s", frame->filename);
EMB_LOGDEV("method: %s", frame->method);
EMB_LOGDEV("frame_addr: 0x%lx", (unsigned long) frame->frame_addr);
EMB_LOGDEV("offset_addr: 0x%lx", (unsigned long) frame->offset_addr);
EMB_LOGDEV("module_addr: 0x%lx", (unsigned long) frame->module_addr);
EMB_LOGDEV("line_num: 0x%lx", (unsigned long) frame->line_num);
EMB_LOGDEV("build_id: %s", frame->build_id);
EMB_LOGDEV("full_name: %s", frame->full_name);
EMB_LOGDEV("function_name: %s", frame->function_name);
EMB_LOGDEV("rel_pc: 0x%lx", (unsigned long) frame->rel_pc);
EMB_LOGDEV("pc: 0x%lx", (unsigned long) frame->pc);
EMB_LOGDEV("sp: 0x%lx", (unsigned long) frame->sp);
EMB_LOGDEV("lr: 0x%lx", (unsigned long) frame->lr);
EMB_LOGDEV("start: 0x%lx", (unsigned long) frame->start);
EMB_LOGDEV("end: 0x%lx", (unsigned long) frame->end);
EMB_LOGDEV("offset: 0x%lx", (unsigned long) frame->offset);
EMB_LOGDEV("function_offset: 0x%lx", (unsigned long) frame->function_offset);
EMB_LOGDEV("flags: 0x%lx", (unsigned long) frame->flags);
EMB_LOGDEV("flags: %d", frame->elf_file_not_readable);
}

char *emb_crash_to_json(emb_crash *crash) {
EMB_LOGDEV("Starting serialization of emb_crash struct to JSON string.");
JSON_Value *root_value = json_value_init_object();
Expand Down Expand Up @@ -205,7 +240,23 @@ char *emb_crash_to_json(emb_crash *crash) {
json_object_set_number(frame_object, kModuleAddrKey, frame.module_addr);
json_object_set_number(frame_object, kLineNumKey, frame.line_num);
json_object_set_string(frame_object, kBuildIdKey, frame.build_id);

// extra debug info
json_object_set_string(frame_object, kFullNameKey, frame.full_name);
json_object_set_string(frame_object, kFunctionNameKey, frame.function_name);
json_object_set_number(frame_object, kRelPcKey, (unsigned long) frame.rel_pc);
json_object_set_number(frame_object, kPcKey, (unsigned long) frame.pc);
json_object_set_number(frame_object, kSpKey, (unsigned long) frame.sp);
json_object_set_number(frame_object, kLrKey, (unsigned long) frame.lr);
json_object_set_number(frame_object, kStartKey, (unsigned long) frame.start);
json_object_set_number(frame_object, kEndKey, (unsigned long) frame.end);
json_object_set_number(frame_object, kOffsetKey, (unsigned long) frame.offset);
json_object_set_number(frame_object, kFunctionOffsetKey,(unsigned long) frame.function_offset);
json_object_set_number(frame_object, kFlagsKey, frame.flags);
json_object_set_number(frame_object, kElfFileNotReadableKey, frame.elf_file_not_readable);

json_array_append_value(frames_object, frame_value);
emb_log_frame_dbg_info(i, &frame);
}
EMB_LOGDEV("Finished serializing stackframes.");

Expand Down
19 changes: 16 additions & 3 deletions embrace-android-sdk/src/main/cpp/stack_frames.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@
#define EMB_SESSION_ID_SIZE 256
#endif

#ifndef EMB_BUILD_ID_SIZE
#define EMB_BUILD_ID_SIZE 512
#ifndef EMB_FRAME_STR_SIZE
#define EMB_FRAME_STR_SIZE 512
#endif

#ifndef EMB_PATH_SIZE
Expand All @@ -73,12 +73,25 @@
typedef struct {
char filename[256];
char method[256];
char build_id[EMB_BUILD_ID_SIZE];
char build_id[EMB_FRAME_STR_SIZE];

uintptr_t frame_addr;
uintptr_t offset_addr;
uintptr_t module_addr;
uintptr_t line_num;
uint64_t rel_pc;
uint64_t pc;
uint64_t sp;
uint64_t lr; // only populated for the first frame.
uint64_t function_offset;
char function_name[EMB_FRAME_STR_SIZE];

bool elf_file_not_readable;
uint64_t start;
uint64_t end;
uint64_t offset;
uint16_t flags;
char full_name[EMB_FRAME_STR_SIZE];
} emb_sframe;

typedef struct {
Expand Down
32 changes: 31 additions & 1 deletion embrace-android-sdk/src/main/cpp/unwinders/unwinder_stack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,43 @@ emb_process_stack(emb_env *env, siginfo_t *info, void *user_context) {

env->crash.unwinder_error = android_unwinder_data.error.code;

// required to demangle function names locally
android_unwinder_data.DemangleFunctionNames();

if (unwindSuccessful) {
int i = 0;


for (const auto &frame: android_unwinder_data.frames) {
emb_sframe *data = &stacktrace[i++];

// populate the link register for the first value only
if (i == 0 && android_unwinder_data.saved_initial_regs.has_value()) {
data->lr = android_unwinder_data.saved_initial_regs->get()->lr();
}

data->frame_addr = frame.pc;
const auto map_info = frame.map_info;
emb_strncpy(data->build_id, map_info->GetPrintableBuildID().c_str(), EMB_BUILD_ID_SIZE);
emb_strncpy(data->build_id, map_info->GetPrintableBuildID().c_str(), EMB_FRAME_STR_SIZE);

// populate additional information.
// FrameData
data->rel_pc = frame.rel_pc;
data->pc = frame.pc;
data->sp = frame.sp;
data->function_offset = frame.function_offset;

// need to call DemangleFunctionNames() for this.
emb_strncpy(data->function_name, frame.function_name.c_str(), EMB_FRAME_STR_SIZE);

// map info
data->elf_file_not_readable = map_info->ElfFileNotReadable();
data->start = map_info->start();
data->end = map_info->end();
data->offset = map_info->offset();
data->flags = map_info->flags();
emb_strncpy(data->full_name, map_info->GetFullName().c_str(), EMB_FRAME_STR_SIZE);
emb_strncpy(data->build_id, map_info->GetPrintableBuildID().c_str(), EMB_FRAME_STR_SIZE);
}
} else {
return 0;
Expand Down