Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 98f87d92 authored by Christopher Ferris's avatar Christopher Ferris Committed by Gerrit Code Review
Browse files

Merge "Rewrite libbacktrace using C++."

parents 87af04a4 17e91d44
Loading
Loading
Loading
Loading
+7 −7
Original line number Diff line number Diff line
@@ -89,12 +89,12 @@ static void dump_thread(log_t* log, pid_t tid, bool attached,

    wait_for_stop(tid, total_sleep_time_usec);

    backtrace_t backtrace;
    if (!backtrace_get_data(&backtrace, tid)) {
    backtrace_context_t context;
    if (!backtrace_create_context(&context, tid, -1, 0)) {
        _LOG(log, SCOPE_AT_FAULT, "Could not create backtrace context.\n");
    } else {
        dump_backtrace_to_log(&backtrace, log, SCOPE_AT_FAULT, "  ");
        backtrace_free_data(&backtrace);
        dump_backtrace_to_log(&context, log, SCOPE_AT_FAULT, "  ");
        backtrace_destroy_context(&context);
    }

    if (!attached && ptrace(PTRACE_DETACH, tid, 0, 0) != 0) {
@@ -137,11 +137,11 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
    dump_process_footer(&log, pid);
}

void dump_backtrace_to_log(const backtrace_t* backtrace, log_t* log,
void dump_backtrace_to_log(const backtrace_context_t* context, log_t* log,
                           int scope_flags, const char* prefix) {
    char buf[512];
    for (size_t i = 0; i < backtrace->num_frames; i++) {
        backtrace_format_frame_data(&backtrace->frames[i], i, buf, sizeof(buf));
    for (size_t i = 0; i < context->backtrace->num_frames; i++) {
        backtrace_format_frame_data(context, i, buf, sizeof(buf));
        _LOG(log, scope_flags, "%s%s\n", prefix, buf);
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ void dump_backtrace(int fd, int amfd, pid_t pid, pid_t tid, bool* detach_failed,
        int* total_sleep_time_usec);

/* Dumps the backtrace in the backtrace data structure to the log. */
void dump_backtrace_to_log(const backtrace_t* backtrace, log_t* log,
void dump_backtrace_to_log(const backtrace_context_t* context, log_t* log,
        int scope_flags, const char* prefix);

#endif // _DEBUGGERD_BACKTRACE_H
+35 −33
Original line number Diff line number Diff line
@@ -228,39 +228,39 @@ static void dump_thread_info(log_t* log, pid_t pid, pid_t tid, int scope_flags)
    }
}

static void dump_stack_segment(const backtrace_t* backtrace, log_t* log,
static void dump_stack_segment(const backtrace_context_t* context, log_t* log,
        int scope_flags, uintptr_t *sp, size_t words, int label) {
    for (size_t i = 0; i < words; i++) {
        uint32_t stack_content;
        if (!backtrace_read_word(backtrace, *sp, &stack_content)) {
        if (!backtrace_read_word(context, *sp, &stack_content)) {
            break;
        }

        const char* map_name = backtrace_get_map_info(backtrace, stack_content, NULL);
        const char* map_name = backtrace_get_map_name(context, stack_content, NULL);
        if (!map_name) {
            map_name = "";
        }
        uintptr_t offset = 0;
        char* proc_name = backtrace_get_proc_name(backtrace, stack_content, &offset);
        if (proc_name) {
        char* func_name = backtrace_get_func_name(context, stack_content, &offset);
        if (func_name) {
            if (!i && label >= 0) {
                if (offset) {
                    _LOG(log, scope_flags, "    #%02d  %08x  %08x  %s (%s+%u)\n",
                            label, *sp, stack_content, map_name, proc_name, offset);
                            label, *sp, stack_content, map_name, func_name, offset);
                } else {
                    _LOG(log, scope_flags, "    #%02d  %08x  %08x  %s (%s)\n",
                            label, *sp, stack_content, map_name, proc_name);
                            label, *sp, stack_content, map_name, func_name);
                }
            } else {
                if (offset) {
                    _LOG(log, scope_flags, "         %08x  %08x  %s (%s+%u)\n",
                            *sp, stack_content, map_name, proc_name, offset);
                            *sp, stack_content, map_name, func_name, offset);
                } else {
                    _LOG(log, scope_flags, "         %08x  %08x  %s (%s)\n",
                            *sp, stack_content, map_name, proc_name);
                            *sp, stack_content, map_name, func_name);
                }
            }
            free(proc_name);
            free(func_name);
        } else {
            if (!i && label >= 0) {
                _LOG(log, scope_flags, "    #%02d  %08x  %08x  %s\n",
@@ -275,7 +275,8 @@ static void dump_stack_segment(const backtrace_t* backtrace, log_t* log,
    }
}

static void dump_stack(const backtrace_t* backtrace, log_t* log, int scope_flags) {
static void dump_stack(const backtrace_context_t* context, log_t* log, int scope_flags) {
    const backtrace_t* backtrace = context->backtrace;
    size_t first = 0, last;
    for (size_t i = 0; i < backtrace->num_frames; i++) {
        if (backtrace->frames[i].sp) {
@@ -294,7 +295,7 @@ static void dump_stack(const backtrace_t* backtrace, log_t* log, int scope_flags

    // Dump a few words before the first frame.
    uintptr_t sp = backtrace->frames[first].sp - STACK_WORDS * sizeof(uint32_t);
    dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, -1);
    dump_stack_segment(context, log, scope_flags, &sp, STACK_WORDS, -1);

    // Dump a few words from all successive frames.
    // Only log the first 3 frames, put the rest in the tombstone.
@@ -308,7 +309,7 @@ static void dump_stack(const backtrace_t* backtrace, log_t* log, int scope_flags
            scope_flags &= (~SCOPE_AT_FAULT);
        }
        if (i == last) {
            dump_stack_segment(backtrace, log, scope_flags, &sp, STACK_WORDS, i);
            dump_stack_segment(context, log, scope_flags, &sp, STACK_WORDS, i);
            if (sp < frame->sp + frame->stack_size) {
                _LOG(log, scope_flags, "         ........  ........\n");
            }
@@ -319,19 +320,19 @@ static void dump_stack(const backtrace_t* backtrace, log_t* log, int scope_flags
            } else if (words > STACK_WORDS) {
                words = STACK_WORDS;
            }
            dump_stack_segment(backtrace, log, scope_flags, &sp, words, i);
            dump_stack_segment(context, log, scope_flags, &sp, words, i);
        }
    }
}

static void dump_backtrace_and_stack(const backtrace_t* backtrace, log_t* log,
        int scope_flags) {
    if (backtrace->num_frames) {
static void dump_backtrace_and_stack(const backtrace_context_t* context,
        log_t* log, int scope_flags) {
    if (context->backtrace->num_frames) {
        _LOG(log, scope_flags, "\nbacktrace:\n");
        dump_backtrace_to_log(backtrace, log, scope_flags, "    ");
        dump_backtrace_to_log(context, log, scope_flags, "    ");

        _LOG(log, scope_flags, "\nstack:\n");
        dump_stack(backtrace, log, scope_flags);
        dump_stack(context, log, scope_flags);
    }
}

@@ -399,12 +400,13 @@ static void dump_nearby_maps(const backtrace_map_info_t* map_info_list, log_t* l
    dump_map(log, prev, "map above", scope_flags);
}

static void dump_thread(const backtrace_t* backtrace, log_t* log, int scope_flags,
        int* total_sleep_time_usec) {
static void dump_thread(const backtrace_context_t* context, log_t* log,
        int scope_flags, int* total_sleep_time_usec) {
    const backtrace_t* backtrace = context->backtrace;
    wait_for_stop(backtrace->tid, total_sleep_time_usec);

    dump_registers(log, backtrace->tid, scope_flags);
    dump_backtrace_and_stack(backtrace, log, scope_flags);
    dump_backtrace_and_stack(context, log, scope_flags);
    if (IS_AT_FAULT(scope_flags)) {
        dump_memory_and_code(log, backtrace->tid, scope_flags);
        dump_nearby_maps(backtrace->map_info_list, log, backtrace->tid, scope_flags);
@@ -446,11 +448,11 @@ static bool dump_sibling_thread_report(

        _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
        dump_thread_info(log, pid, new_tid, 0);
        backtrace_t new_backtrace;
        if (backtrace_get_data(&new_backtrace, new_tid)) {
            dump_thread(&new_backtrace, log, 0, total_sleep_time_usec);
        backtrace_context_t new_context;
        if (backtrace_create_context(&new_context, pid, new_tid, 0)) {
            dump_thread(&new_context, log, 0, total_sleep_time_usec);
            backtrace_destroy_context(&new_context);
        }
        backtrace_free_data(&new_backtrace);

        if (ptrace(PTRACE_DETACH, new_tid, 0, 0) != 0) {
            LOG("ptrace detach from %d failed: %s\n", new_tid, strerror(errno));
@@ -606,7 +608,7 @@ static void dump_logs(log_t* log, pid_t pid, bool tailOnly)
    dump_log_file(log, pid, "/dev/log/main", tailOnly);
}

static void dump_abort_message(const backtrace_t* backtrace, log_t* log, uintptr_t address) {
static void dump_abort_message(const backtrace_context_t* context, log_t* log, uintptr_t address) {
  if (address == 0) {
    return;
  }
@@ -618,7 +620,7 @@ static void dump_abort_message(const backtrace_t* backtrace, log_t* log, uintptr
  char* p = &msg[0];
  while (p < &msg[sizeof(msg)]) {
    uint32_t data;
    if (!backtrace_read_word(backtrace, address, &data)) {
    if (!backtrace_read_word(context, address, &data)) {
      break;
    }
    address += sizeof(uint32_t);
@@ -673,11 +675,11 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t a
        dump_fault_addr(log, tid, signal);
    }

    backtrace_t backtrace;
    if (backtrace_get_data(&backtrace, tid)) {
        dump_abort_message(&backtrace, log, abort_msg_address);
        dump_thread(&backtrace, log, SCOPE_AT_FAULT, total_sleep_time_usec);
        backtrace_free_data(&backtrace);
    backtrace_context_t context;
    if (backtrace_create_context(&context, pid, tid, 0)) {
        dump_abort_message(&context, log, abort_msg_address);
        dump_thread(&context, log, SCOPE_AT_FAULT, total_sleep_time_usec);
        backtrace_destroy_context(&context);
    }

    if (want_logs) {
+85 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2013 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef _BACKTRACE_BACKTRACE_H
#define _BACKTRACE_BACKTRACE_H

#include <backtrace/backtrace.h>

#include <string>

class BacktraceImpl;

class Backtrace {
public:
  Backtrace(BacktraceImpl* impl);
  virtual ~Backtrace();

  // Get the current stack trace and store in the backtrace_ structure.
  virtual bool Unwind(size_t num_ignore_frames);

  // Get the function name and offset into the function given the pc.
  // If the string is empty, then no valid function name was found.
  virtual std::string GetFunctionName(uintptr_t pc, uintptr_t* offset);

  // Get the name of the map associated with the given pc. If NULL is returned,
  // then map_start is not set. Otherwise, map_start is the beginning of this
  // map.
  virtual const char* GetMapName(uintptr_t pc, uintptr_t* map_start);

  // Finds the memory map associated with the given ptr.
  virtual const backtrace_map_info_t* FindMapInfo(uintptr_t ptr);

  // Read the data at a specific address.
  virtual bool ReadWord(uintptr_t ptr, uint32_t* out_value) = 0;

  // Create a string representing the formatted line of backtrace information
  // for a single frame.
  virtual std::string FormatFrameData(size_t frame_num);

  pid_t Pid() { return backtrace_.pid; }
  pid_t Tid() { return backtrace_.tid; }
  size_t NumFrames() { return backtrace_.num_frames; }

  const backtrace_t* GetBacktrace() { return &backtrace_; }

  const backtrace_frame_data_t* GetFrame(size_t frame_num) {
    return &backtrace_.frames[frame_num];
  }

  // Create the correct Backtrace object based on what is to be unwound.
  // If pid < 0 or equals the current pid, then the Backtrace object
  // corresponds to the current process.
  // If pid < 0 or equals the current pid and tid >= 0, then the Backtrace
  // object corresponds to a thread in the current process.
  // If pid >= 0 and tid < 0, then the Backtrace object corresponds to a
  // different process.
  // Tracing a thread in a different process is not supported.
  static Backtrace* Create(pid_t pid, pid_t tid);

protected:
  virtual bool VerifyReadWordArgs(uintptr_t ptr, uint32_t* out_value);

  BacktraceImpl* impl_;

  backtrace_map_info_t* map_info_;

  backtrace_t backtrace_;

  friend class BacktraceImpl;
};

#endif // _BACKTRACE_BACKTRACE_H
+35 −25
Original line number Diff line number Diff line
@@ -21,9 +21,7 @@
#include <stdbool.h>
#include <inttypes.h>

#ifdef __cplusplus
extern "C" {
#endif
__BEGIN_DECLS

#define MAX_BACKTRACE_FRAMES 64

@@ -43,48 +41,58 @@ typedef struct {
  size_t stack_size;      /* The size of the stack, zero indicate an unknown stack size. */
  const char* map_name;   /* The name of the map to which this pc belongs, NULL indicates the pc doesn't belong to a known map. */
  uintptr_t map_offset;   /* pc relative to the start of the map, only valid if map_name is not NULL. */
  char* proc_name;        /* The function name associated with this pc, NULL if not found. */
  uintptr_t proc_offset;  /* pc relative to the start of the procedure, only valid if proc_name is not NULL. */
  char* func_name;        /* The function name associated with this pc, NULL if not found. */
  uintptr_t func_offset;  /* pc relative to the start of the function, only valid if func_name is not NULL. */
} backtrace_frame_data_t;

typedef struct {
  backtrace_frame_data_t frames[MAX_BACKTRACE_FRAMES];
  size_t num_frames;

  pid_t pid;
  pid_t tid;
  backtrace_map_info_t* map_info_list;
  void* private_data;
} backtrace_t;

/* Gather the backtrace data for tid and fill in the backtrace structure.
 * If tid < 0, then gather the backtrace for the current thread.
typedef struct {
  void* data;
  const backtrace_t* backtrace;
} backtrace_context_t;

/* Create a context for the backtrace data and gather the backtrace.
 * If pid < 0, then gather the backtrace for the current process.
 */
bool backtrace_get_data(backtrace_t* backtrace, pid_t tid);
bool backtrace_create_context(
    backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames);

/* Free any memory associated with the backtrace structure. */
void backtrace_free_data(backtrace_t* backtrace);
/* Gather the backtrace data for a pthread instead of a process. */
bool backtrace_create_thread_context(
    backtrace_context_t* context, pid_t tid, size_t num_ignore_frames);

/* Free any memory allocated during the context create. */
void backtrace_destroy_context(backtrace_context_t* context);

/* Read data at a specific address for a process. */
bool backtrace_read_word(
    const backtrace_t* backtrace, uintptr_t ptr, uint32_t* value);
    const backtrace_context_t* context, uintptr_t ptr, uint32_t* value);

/* Get information about the map associated with a pc. If NULL is
/* Get information about the map name associated with a pc. If NULL is
 * returned, then map_start is not set.
 */
const char* backtrace_get_map_info(
    const backtrace_t* backtrace, uintptr_t pc, uintptr_t* map_start);
const char* backtrace_get_map_name(
    const backtrace_context_t* context, uintptr_t pc, uintptr_t* map_start);

/* Get the procedure name and offest given the pc. If NULL is returned,
 * then proc_offset is not set. The returned string is allocated using
/* Get the function name and offset given the pc. If NULL is returned,
 * then func_offset is not set. The returned string is allocated using
 * malloc and must be freed by the caller.
 */
char* backtrace_get_proc_name(
    const backtrace_t* backtrace, uintptr_t pc, uintptr_t* proc_offset);
char* backtrace_get_func_name(
    const backtrace_context_t* context, uintptr_t pc, uintptr_t* func_offset);

/* Loads memory map from /proc/<tid>/maps. If tid < 0, then load the memory
/* Loads memory map from /proc/<pid>/maps. If pid < 0, then load the memory
 * map for the current process.
 */
backtrace_map_info_t* backtrace_create_map_info_list(pid_t tid);
backtrace_map_info_t* backtrace_create_map_info_list(pid_t pid);

/* Frees memory associated with the map list. */
void backtrace_destroy_map_info_list(backtrace_map_info_t* map_info_list);
@@ -95,10 +103,12 @@ const backtrace_map_info_t* backtrace_find_map_info(

/* Create a formatted line of backtrace information for a single frame. */
void backtrace_format_frame_data(
    const backtrace_frame_data_t* frame, size_t frame_num, char *buf, size_t buf_size);
    const backtrace_context_t* context, size_t frame_num, char* buf,
    size_t buf_size);

/* Get the backtrace data structure associated with the context. */
const backtrace_t* backtrace_get_data(backtrace_context_t* context);

#ifdef __cplusplus
}
#endif
__END_DECLS

#endif /* _BACKTRACE_H */
Loading