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

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

Merge "Print the build id of shared libraries if present."

parents 2df0aac6 a21bd93e
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
    backtrace.cpp \
    debuggerd.cpp \
    elf_utils.cpp \
    getevent.cpp \
    tombstone.cpp \
    utility.cpp \
@@ -28,6 +29,7 @@ endif

LOCAL_SHARED_LIBRARIES := \
    libbacktrace \
    libbase \
    libcutils \
    liblog \
    libselinux \
@@ -38,7 +40,6 @@ LOCAL_MODULE := debuggerd
LOCAL_MODULE_STEM_32 := debuggerd
LOCAL_MODULE_STEM_64 := debuggerd64
LOCAL_MULTILIB := both
LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk

include $(BUILD_EXECUTABLE)

+119 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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.
 */

#define LOG_TAG "DEBUG"

#include <elf.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>

#include <string>

#include <backtrace/Backtrace.h>
#include <base/stringprintf.h>
#include <log/log.h>

#include "elf_utils.h"

template <typename HdrType, typename PhdrType, typename NhdrType>
static bool get_build_id(
    Backtrace* backtrace, uintptr_t base_addr, uint8_t* e_ident, std::string* build_id) {
  HdrType hdr;

  memcpy(&hdr.e_ident[0], e_ident, EI_NIDENT);

  // First read the rest of the header.
  if (backtrace->Read(base_addr + EI_NIDENT, reinterpret_cast<uint8_t*>(&hdr) + EI_NIDENT,
                      sizeof(HdrType) - EI_NIDENT) != sizeof(HdrType) - EI_NIDENT) {
    return false;
  }

  for (size_t i = 0; i < hdr.e_phnum; i++) {
    PhdrType phdr;
    if (backtrace->Read(base_addr + hdr.e_phoff + i * hdr.e_phentsize,
                        reinterpret_cast<uint8_t*>(&phdr), sizeof(phdr)) != sizeof(phdr)) {
      return false;
    }
    // Looking for the .note.gnu.build-id note.
    if (phdr.p_type == PT_NOTE) {
      size_t hdr_size = phdr.p_filesz;
      uintptr_t addr = base_addr + phdr.p_offset;
      while (hdr_size >= sizeof(NhdrType)) {
        NhdrType nhdr;
        if (backtrace->Read(addr, reinterpret_cast<uint8_t*>(&nhdr), sizeof(nhdr)) != sizeof(nhdr)) {
          return false;
        }
        addr += sizeof(nhdr);
        if (nhdr.n_type == NT_GNU_BUILD_ID) {
          // Skip the name (which is the owner and should be "GNU").
          addr += nhdr.n_namesz;
          uint8_t build_id_data[128];
          if (nhdr.n_namesz > sizeof(build_id_data)) {
            ALOGE("Possible corrupted note, name size value is too large: %u",
                  nhdr.n_namesz);
            return false;
          }
          if (backtrace->Read(addr, build_id_data, nhdr.n_descsz) != nhdr.n_descsz) {
            return false;
          }

          build_id->clear();
          for (size_t bytes = 0; bytes < nhdr.n_descsz; bytes++) {
            *build_id += android::base::StringPrintf("%02x", build_id_data[bytes]);
          }

          return true;
        } else {
          // Move past the extra note data.
          hdr_size -= sizeof(nhdr);
          size_t skip_bytes = nhdr.n_namesz + nhdr.n_descsz;
          addr += skip_bytes;
          if (hdr_size < skip_bytes) {
            break;
          }
          hdr_size -= skip_bytes;
        }
      }
    }
  }
  return false;
}

bool elf_get_build_id(Backtrace* backtrace, uintptr_t addr, std::string* build_id) {
  // Read and verify the elf magic number first.
  uint8_t e_ident[EI_NIDENT];
  if (backtrace->Read(addr, e_ident, SELFMAG) != SELFMAG) {
    return false;
  }

  if (memcmp(e_ident, ELFMAG, SELFMAG) != 0) {
    return false;
  }

  // Read the rest of EI_NIDENT.
  if (backtrace->Read(addr + SELFMAG, e_ident + SELFMAG, EI_NIDENT - SELFMAG) != EI_NIDENT - SELFMAG) {
    return false;
  }

  if (e_ident[EI_CLASS] == ELFCLASS32) {
    return get_build_id<Elf32_Ehdr, Elf32_Phdr, Elf32_Nhdr>(backtrace, addr, e_ident, build_id);
  } else if (e_ident[EI_CLASS] == ELFCLASS64) {
    return get_build_id<Elf64_Ehdr, Elf64_Phdr, Elf64_Nhdr>(backtrace, addr, e_ident, build_id);
  }

  return false;
}

debuggerd/elf_utils.h

0 → 100644
+27 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 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 _DEBUGGERD_ELF_UTILS_H
#define _DEBUGGERD_ELF_UTILS_H

#include <stdint.h>
#include <string>

class Backtrace;

bool elf_get_build_id(Backtrace*, uintptr_t, std::string*);

#endif // _DEBUGGERD_ELF_UTILS_H
+81 −60
Original line number Diff line number Diff line
@@ -34,6 +34,7 @@

#include <private/android_filesystem_config.h>

#include <base/stringprintf.h>
#include <cutils/properties.h>
#include <log/log.h>
#include <log/logger.h>
@@ -46,9 +47,12 @@

#include <UniquePtr.h>

#include <string>

#include "backtrace.h"
#include "elf_utils.h"
#include "machine.h"
#include "tombstone.h"
#include "backtrace.h"

#define STACK_WORDS 16

@@ -234,47 +238,36 @@ static void dump_thread_info(log_t* log, pid_t pid, pid_t tid) {

static void dump_stack_segment(
    Backtrace* backtrace, log_t* log, uintptr_t* sp, size_t words, int label) {
  // Read the data all at once.
  word_t stack_data[words];
  size_t bytes_read = backtrace->Read(*sp, reinterpret_cast<uint8_t*>(&stack_data[0]), sizeof(word_t) * words);
  words = bytes_read / sizeof(word_t);
  std::string line;
  for (size_t i = 0; i < words; i++) {
    word_t stack_content;
    if (!backtrace->ReadWord(*sp, &stack_content)) {
      break;
    line = "    ";
    if (i == 0 && label >= 0) {
      // Print the label once.
      line += android::base::StringPrintf("#%02d  ", label);
    } else {
      line += "     ";
    }
    line += android::base::StringPrintf("%" PRIPTR "  %" PRIPTR, *sp, stack_data[i]);

    backtrace_map_t map;
    backtrace->FillInMap(stack_content, &map);
    std::string map_name;
    if (BacktraceMap::IsValid(map) && map.name.length() > 0) {
      map_name = "  " + map.name;
    }
    backtrace->FillInMap(stack_data[i], &map);
    if (BacktraceMap::IsValid(map) && !map.name.empty()) {
      line += "  " + map.name;
      uintptr_t offset = 0;
    std::string func_name(backtrace->GetFunctionName(stack_content, &offset));
      std::string func_name(backtrace->GetFunctionName(stack_data[i], &offset));
      if (!func_name.empty()) {
      if (!i && label >= 0) {
        line += " (" + func_name;
        if (offset) {
          _LOG(log, logtype::STACK, "    #%02d  %" PRIPTR "  %" PRIPTR "%s (%s+%" PRIuPTR ")\n",
               label, *sp, stack_content, map_name.c_str(), func_name.c_str(), offset);
        } else {
          _LOG(log, logtype::STACK, "    #%02d  %" PRIPTR "  %" PRIPTR "%s (%s)\n",
               label, *sp, stack_content, map_name.c_str(), func_name.c_str());
          line += android::base::StringPrintf("+%" PRIuPTR, offset);
        }
      } else {
        if (offset) {
          _LOG(log, logtype::STACK, "         %" PRIPTR "  %" PRIPTR "%s (%s+%" PRIuPTR ")\n",
               *sp, stack_content, map_name.c_str(), func_name.c_str(), offset);
        } else {
          _LOG(log, logtype::STACK, "         %" PRIPTR "  %" PRIPTR "%s (%s)\n",
               *sp, stack_content, map_name.c_str(), func_name.c_str());
        }
      }
    } else {
      if (!i && label >= 0) {
        _LOG(log, logtype::STACK, "    #%02d  %" PRIPTR "  %" PRIPTR "%s\n",
             label, *sp, stack_content, map_name.c_str());
      } else {
        _LOG(log, logtype::STACK, "         %" PRIPTR "  %" PRIPTR "%s\n",
             *sp, stack_content, map_name.c_str());
        line += ')';
      }
    }
    _LOG(log, logtype::STACK, "%s\n", line.c_str());

    *sp += sizeof(word_t);
  }
@@ -325,44 +318,72 @@ static void dump_stack(Backtrace* backtrace, log_t* log) {
  }
}

static void dump_map(log_t* log, const backtrace_map_t* map, bool fault_addr) {
  _LOG(log, logtype::MAPS, "%s%" PRIPTR "-%" PRIPTR " %c%c%c  %7" PRIdPTR "%s\n",
         (fault_addr? "--->" : "    "), map->start, map->end - 1,
         (map->flags & PROT_READ) ? 'r' : '-', (map->flags & PROT_WRITE) ? 'w' : '-',
         (map->flags & PROT_EXEC) ? 'x' : '-',
         (map->end - map->start),
         (map->name.length() > 0) ? ("  " + map->name).c_str() : "");
}

static void dump_all_maps(BacktraceMap* map, log_t* log, pid_t tid) {
  bool has_fault_address = false;
static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, pid_t tid) {
  bool print_fault_address_marker = false;
  uintptr_t addr = 0;
  siginfo_t si;
  memset(&si, 0, sizeof(si));
  if (ptrace(PTRACE_GETSIGINFO, tid, 0, &si)) {
    _LOG(log, logtype::MAPS, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
    _LOG(log, logtype::ERROR, "cannot get siginfo for %d: %s\n", tid, strerror(errno));
  } else {
    has_fault_address = signal_has_si_addr(si.si_signo);
    print_fault_address_marker = signal_has_si_addr(si.si_signo);
    addr = reinterpret_cast<uintptr_t>(si.si_addr);
  }

  _LOG(log, logtype::MAPS, "\nmemory map:%s\n", has_fault_address ? " (fault address prefixed with --->)" : "");

  if (has_fault_address && (addr < map->begin()->start)) {
    _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " before any mapped regions\n", addr);
  _LOG(log, logtype::MAPS, "\n");
  if (!print_fault_address_marker) {
    _LOG(log, logtype::MAPS, "memory map:\n");
  } else {
    _LOG(log, logtype::MAPS, "memory map: (fault address prefixed with --->)\n");
    if (map->begin() != map->end() && addr < map->begin()->start) {
      _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " before any mapped regions\n",
           addr);
      print_fault_address_marker = false;
    }
  }

  BacktraceMap::const_iterator prev = map->begin();
  std::string line;
  for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
    if (addr >= (*prev).end && addr < (*it).start) {
      _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " between mapped regions\n", addr);
    line = "    ";
    if (print_fault_address_marker) {
      if (addr < it->start) {
        _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " between mapped regions\n",
             addr);
        print_fault_address_marker = false;
      } else if (addr >= it->start && addr < it->end) {
        line = "--->";
        print_fault_address_marker = false;
      }
    }
    line += android::base::StringPrintf("%" PRIPTR "-%" PRIPTR " ", it->start, it->end - 1);
    if (it->flags & PROT_READ) {
      line += 'r';
    } else {
      line += '-';
    }
    if (it->flags & PROT_WRITE) {
      line += 'w';
    } else {
      line += '-';
    }
    if (it->flags & PROT_EXEC) {
      line += 'x';
    } else {
      line += '-';
    }
    line += android::base::StringPrintf("  %8" PRIxPTR, it->end - it->start);
    if (it->name.length() > 0) {
      line += "  " + it->name;
      std::string build_id;
      if ((it->flags & PROT_READ) && elf_get_build_id(backtrace, it->start, &build_id)) {
        line += " (BuildId: " + build_id + ")";
      }
    }
    prev = it;
    bool in_map = has_fault_address && (addr >= (*it).start) && (addr < (*it).end);
    dump_map(log, &*it, in_map);
    _LOG(log, logtype::MAPS, "%s\n", line.c_str());
  }
  if (has_fault_address && (addr >= (*prev).end)) {
    _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " after any mapped regions\n", addr);
  if (print_fault_address_marker) {
    _LOG(log, logtype::MAPS, "--->Fault address falls at %" PRIPTR " after any mapped regions\n",
        addr);
  }
}

@@ -627,7 +648,7 @@ static bool dump_crash(log_t* log, pid_t pid, pid_t tid, int signal, int si_code
    dump_backtrace_and_stack(backtrace.get(), log);
  }
  dump_memory_and_code(log, tid);
  dump_all_maps(map.get(), log, tid);
  dump_all_maps(backtrace.get(), map.get(), log, tid);

  if (want_logs) {
    dump_logs(log, pid, 5);