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

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

Merge "Rewrite libbacktrace to be all C++."

parents 524b3a0c 46756821
Loading
Loading
Loading
Loading
+40 −38
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include <cutils/properties.h>

#include <backtrace/Backtrace.h>
#include <backtrace/BacktraceMap.h>

#include <sys/socket.h>
#include <linux/un.h>
@@ -230,9 +231,12 @@ static void dump_stack_segment(
      break;
    }

    const char* map_name = backtrace->GetMapName(stack_content, NULL);
    if (!map_name) {
    const backtrace_map_t* map = backtrace->FindMap(stack_content);
    const char* map_name;
    if (!map) {
      map_name = "";
    } else {
      map_name = map->name.c_str();
    }
    uintptr_t offset = 0;
    std::string func_name(backtrace->GetFunctionName(stack_content, &offset));
@@ -328,17 +332,17 @@ static void dump_backtrace_and_stack(Backtrace* backtrace, log_t* log, int scope
  }
}

static void dump_map(log_t* log, const backtrace_map_info_t* m, const char* what, int scope_flags) {
  if (m != NULL) {
    _LOG(log, scope_flags, "    %08x-%08x %c%c%c %s\n", m->start, m->end,
         m->is_readable ? 'r' : '-', m->is_writable ? 'w' : '-',
         m->is_executable ? 'x' : '-', m->name);
static void dump_map(log_t* log, const backtrace_map_t* map, const char* what, int scope_flags) {
  if (map != NULL) {
    _LOG(log, scope_flags, "    %08x-%08x %c%c%c %s\n", map->start, map->end,
         (map->flags & PROT_READ) ? 'r' : '-', (map->flags & PROT_WRITE) ? 'w' : '-',
         (map->flags & PROT_EXEC) ? 'x' : '-', map->name.c_str());
  } else {
    _LOG(log, scope_flags, "    (no %s)\n", what);
  }
}

static void dump_nearby_maps(const backtrace_map_info_t* map_info_list, log_t* log, pid_t tid, int scope_flags) {
static void dump_nearby_maps(BacktraceMap* map, log_t* log, pid_t tid, int scope_flags) {
  scope_flags |= SCOPE_SENSITIVE;
  siginfo_t si;
  memset(&si, 0, sizeof(si));
@@ -350,7 +354,7 @@ static void dump_nearby_maps(const backtrace_map_info_t* map_info_list, log_t* l
    return;
  }

  uintptr_t addr = (uintptr_t) si.si_addr;
  uintptr_t addr = reinterpret_cast<uintptr_t>(si.si_addr);
  addr &= ~0xfff;     // round to 4K page boundary
  if (addr == 0) {    // null-pointer deref
    return;
@@ -361,29 +365,26 @@ static void dump_nearby_maps(const backtrace_map_info_t* map_info_list, log_t* l

  // Search for a match, or for a hole where the match would be.  The list
  // is backward from the file content, so it starts at high addresses.
  const backtrace_map_info_t* map = map_info_list;
  const backtrace_map_info_t* next = NULL;
  const backtrace_map_info_t* prev = NULL;
  while (map != NULL) {
    if (addr >= map->start && addr < map->end) {
      next = map->next;
      break;
    } else if (addr >= map->end) {
      // map would be between "prev" and this entry
      next = map;
      map = NULL;
  const backtrace_map_t* cur_map = NULL;
  const backtrace_map_t* next_map = NULL;
  const backtrace_map_t* prev_map = NULL;
  for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
    if (addr >= it->start && addr < it->end) {
      cur_map = &*it;
      if (it != map->begin()) {
        prev_map = &*(it-1);
      }
      if (++it != map->end()) {
        next_map = &*it;
      }
      break;
    }

    prev = map;
    map = map->next;
  }

  // Show "next" then "match" then "prev" so that the addresses appear in
  // ascending order (like /proc/pid/maps).
  dump_map(log, next, "map below", scope_flags);
  dump_map(log, map, "map for address", scope_flags);
  dump_map(log, prev, "map above", scope_flags);
  // Show the map address in ascending order (like /proc/pid/maps).
  dump_map(log, prev_map, "map below", scope_flags);
  dump_map(log, cur_map, "map for address", scope_flags);
  dump_map(log, next_map, "map above", scope_flags);
}

static void dump_thread(
@@ -394,13 +395,13 @@ static void dump_thread(
  dump_backtrace_and_stack(backtrace, log, scope_flags);
  if (IS_AT_FAULT(scope_flags)) {
    dump_memory_and_code(log, backtrace->Tid(), scope_flags);
    dump_nearby_maps(backtrace->GetMapList(), log, backtrace->Tid(), scope_flags);
    dump_nearby_maps(backtrace->GetMap(), log, backtrace->Tid(), scope_flags);
  }
}

// Return true if some thread is not detached cleanly
static bool dump_sibling_thread_report(
    log_t* log, pid_t pid, pid_t tid, int* total_sleep_time_usec, backtrace_map_info_t* map_info) {
    log_t* log, pid_t pid, pid_t tid, int* total_sleep_time_usec, BacktraceMap* map) {
  char task_path[64];
  snprintf(task_path, sizeof(task_path), "/proc/%d/task", pid);

@@ -434,7 +435,7 @@ static bool dump_sibling_thread_report(
    _LOG(log, 0, "--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---\n");
    dump_thread_info(log, pid, new_tid, 0);

    UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map_info));
    UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, new_tid, map));
    if (backtrace->Unwind(0)) {
      dump_thread(backtrace.get(), log, 0, total_sleep_time_usec);
    }
@@ -637,11 +638,12 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t a
    dump_fault_addr(log, tid, signal);
  }

  // Gather the map info once for all this process' threads.
  backtrace_map_info_t* map_info = backtrace_create_map_info_list(pid);

  UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid, map_info));
  BacktraceMap* map = NULL;
  UniquePtr<Backtrace> backtrace(Backtrace::Create(pid, tid));
  if (backtrace->Unwind(0)) {
    // Grab the map that was created and share it with the siblings.
    map = backtrace->TakeMapOwnership();

    dump_abort_message(backtrace.get(), log, abort_msg_address);
    dump_thread(backtrace.get(), log, SCOPE_AT_FAULT, total_sleep_time_usec);
  }
@@ -652,11 +654,11 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, uintptr_t a

  bool detach_failed = false;
  if (dump_sibling_threads) {
    detach_failed = dump_sibling_thread_report(log, pid, tid, total_sleep_time_usec, map_info);
    detach_failed = dump_sibling_thread_report(log, pid, tid, total_sleep_time_usec, map);
  }

  // Destroy the previously created map info.
  backtrace_destroy_map_info_list(map_info);
  // Destroy the BacktraceMap object.
  delete map;

  if (want_logs) {
    dump_logs(log, pid, false);
+47 −25
Original line number Diff line number Diff line
@@ -17,10 +17,25 @@
#ifndef _BACKTRACE_BACKTRACE_H
#define _BACKTRACE_BACKTRACE_H

#include <backtrace/backtrace.h>
#include <stdint.h>

#include <string>
#include <vector>

#include <backtrace/backtrace_constants.h>
#include <backtrace/BacktraceMap.h>

struct backtrace_frame_data_t {
  size_t num;             // The current fame number.
  uintptr_t pc;           // The absolute pc.
  uintptr_t sp;           // The top of the stack.
  size_t stack_size;      // The size of the stack, zero indicate an unknown stack size.
  const backtrace_map_t* map;   // The map associated with the given pc.
  std::string 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.
};

// Forward declarations.
class BacktraceImpl;

class Backtrace {
@@ -33,9 +48,9 @@ public:
  // 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.
  // If map_info is NULL, then create the map and manage it internally.
  // If map_info is not NULL, the map is still owned by the caller.
  static Backtrace* Create(pid_t pid, pid_t tid, backtrace_map_info_t* map_info = NULL);
  // If map is NULL, then create the map and manage it internally.
  // If map is not NULL, the map is still owned by the caller.
  static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = NULL);

  virtual ~Backtrace();

@@ -46,13 +61,12 @@ public:
  // 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);
  // Find the map associated with the given pc.
  virtual const backtrace_map_t* FindMap(uintptr_t pc);

  // Finds the memory map associated with the given ptr.
  virtual const backtrace_map_info_t* FindMapInfo(uintptr_t ptr);
  // Take ownership of the BacktraceMap object associated with the backtrace.
  // If this is called, the caller must handle deleting the object themselves.
  virtual BacktraceMap* TakeMapOwnership();

  // Read the data at a specific address.
  virtual bool ReadWord(uintptr_t ptr, uint32_t* out_value) = 0;
@@ -62,35 +76,43 @@ public:
  virtual std::string FormatFrameData(size_t frame_num);
  virtual std::string FormatFrameData(const backtrace_frame_data_t* frame);

  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_; }
  pid_t Pid() { return pid_; }
  pid_t Tid() { return tid_; }
  size_t NumFrames() { return frames_.size(); }

  const backtrace_frame_data_t* GetFrame(size_t frame_num) {
    if (frame_num > NumFrames()) {
    if (frame_num >= frames_.size()) {
      return NULL;
    }
    return &backtrace_.frames[frame_num];
    return &frames_[frame_num];
  }

  const backtrace_map_info_t* GetMapList() {
    return map_info_;
  }
  typedef std::vector<backtrace_frame_data_t>::iterator iterator;
  iterator begin() { return frames_.begin(); }
  iterator end() { return frames_.end(); }

  typedef std::vector<backtrace_frame_data_t>::const_iterator const_iterator;
  const_iterator begin() const { return frames_.begin(); }
  const_iterator end() const { return frames_.end(); }

  BacktraceMap* GetMap() { return map_; }

protected:
  Backtrace(BacktraceImpl* impl, pid_t pid, backtrace_map_info_t* map_info);
  Backtrace(BacktraceImpl* impl, pid_t pid, BacktraceMap* map);

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

  BacktraceImpl* impl_;
  bool BuildMap();

  backtrace_map_info_t* map_info_;
  pid_t pid_;
  pid_t tid_;

  bool map_info_requires_delete_;
  BacktraceMap* map_;
  bool map_shared_;

  backtrace_t backtrace_;
  std::vector<backtrace_frame_data_t> frames_;

  BacktraceImpl* impl_;

  friend class BacktraceImpl;
};
+72 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 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_MAP_H
#define _BACKTRACE_BACKTRACE_MAP_H

#include <stdint.h>
#include <sys/mman.h>

#include <string>
#include <vector>

struct backtrace_map_t {
  uintptr_t start;
  uintptr_t end;
  int flags;
  std::string name;
};

class BacktraceMap {
public:
  BacktraceMap(pid_t pid);
  virtual ~BacktraceMap();

  // Get the map data structure for the given address.
  const backtrace_map_t* Find(uintptr_t addr);

  // The flags returned are the same flags as used by the mmap call.
  // The values are PROT_*.
  int GetFlags(uintptr_t pc) {
    const backtrace_map_t* map = Find(pc);
    if (map) {
      return map->flags;
    }
    return PROT_NONE;
  }

  bool IsReadable(uintptr_t pc) { return GetFlags(pc) & PROT_READ; }
  bool IsWritable(uintptr_t pc) { return GetFlags(pc) & PROT_WRITE; }
  bool IsExecutable(uintptr_t pc) { return GetFlags(pc) & PROT_EXEC; }

  typedef std::vector<backtrace_map_t>::iterator iterator;
  iterator begin() { return maps_.begin(); }
  iterator end() { return maps_.end(); }

  typedef std::vector<backtrace_map_t>::const_iterator const_iterator;
  const_iterator begin() const { return maps_.begin(); }
  const_iterator end() const { return maps_.end(); }

  virtual bool Build();

protected:
  virtual bool ParseLine(const char* line, backtrace_map_t* map);

  std::vector<backtrace_map_t> maps_;
  pid_t pid_;
};

#endif // _BACKTRACE_BACKTRACE_MAP_H

include/backtrace/backtrace.h

deleted100644 → 0
+0 −131
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_H
#define _BACKTRACE_H

#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>

__BEGIN_DECLS

// When the pid to be traced is set to this value, then trace the current
// process. If the tid value is not BACKTRACE_NO_TID, then the specified
// thread from the current process will be traced.
#define BACKTRACE_CURRENT_PROCESS -1
// When the tid to be traced is set to this value, then trace the specified
// current thread of the specified pid.
#define BACKTRACE_CURRENT_THREAD -1

#define MAX_BACKTRACE_FRAMES 64

typedef struct backtrace_map_info {
  struct backtrace_map_info* next;
  uintptr_t start;
  uintptr_t end;
  bool is_readable;
  bool is_writable;
  bool is_executable;
  char name[];
} backtrace_map_info_t;

typedef struct {
  size_t num;             /* The current fame number. */
  uintptr_t pc;           /* The absolute pc. */
  uintptr_t sp;           /* The top of the stack. */
  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* 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;
} backtrace_t;

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_create_context(
    backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames);

/* The same as backtrace_create_context, except that it is assumed that
 * the pid map has already been acquired and the caller will handle freeing
 * the map data.
 */
bool backtrace_create_context_with_map(
    backtrace_context_t* context, pid_t pid, pid_t tid, size_t num_ignore_frames,
    backtrace_map_info_t* map_info);

/* 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_context_t* context, uintptr_t ptr, uint32_t* value);

/* 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_name(
    const backtrace_context_t* context, uintptr_t pc, uintptr_t* map_start);

/* 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_func_name(
    const backtrace_context_t* context, uintptr_t pc, uintptr_t* func_offset);

/* 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 pid);

/* Frees memory associated with the map list. */
void backtrace_destroy_map_info_list(backtrace_map_info_t* map_info_list);

/* Finds the memory map that contains the specified pc. */
const backtrace_map_info_t* backtrace_find_map_info(
    const backtrace_map_info_t* map_info_list, uintptr_t pc);

/* Create a formatted line of backtrace information for a single frame. */
void backtrace_format_frame_data(
    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);

__END_DECLS

#endif /* _BACKTRACE_H */
+30 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2014 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_CONSTANTS_H
#define _BACKTRACE_BACKTRACE_CONSTANTS_H

// When the pid to be traced is set to this value, then trace the current
// process. If the tid value is not BACKTRACE_NO_TID, then the specified
// thread from the current process will be traced.
#define BACKTRACE_CURRENT_PROCESS -1
// When the tid to be traced is set to this value, then trace the specified
// current thread of the specified pid.
#define BACKTRACE_CURRENT_THREAD -1

#define MAX_BACKTRACE_FRAMES 64

#endif // _BACKTRACE_BACKTRACE_CONSTANTS_H
Loading