diff options
author | Christopher Ferris <cferris@google.com> | 2015-02-27 13:39:47 -0800 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2015-03-17 15:13:35 -0700 |
commit | a21bd93ef5223ce585985e3b426ff5f07c9f4499 (patch) | |
tree | dbac2064ebc3aa11dab338ff75a1b37b1d481252 | |
parent | 837a67393d8493cccb28f20e2e00c5fc1e3b0272 (diff) | |
download | system_core-a21bd93ef5223ce585985e3b426ff5f07c9f4499.zip system_core-a21bd93ef5223ce585985e3b426ff5f07c9f4499.tar.gz system_core-a21bd93ef5223ce585985e3b426ff5f07c9f4499.tar.bz2 |
Print the build id of shared libraries if present.
For every map that has a name, and if it's a mapped in shared library,
print the build id.
Refactor the way dump_all_maps logs data.
Refactor the way stack segments are dumped.
Bug: 19371018
Change-Id: Ic08d05a4b13f128925743936fb84d8059f7cb56f
-rw-r--r-- | debuggerd/Android.mk | 3 | ||||
-rw-r--r-- | debuggerd/elf_utils.cpp | 119 | ||||
-rw-r--r-- | debuggerd/elf_utils.h | 27 | ||||
-rw-r--r-- | debuggerd/tombstone.cpp | 141 |
4 files changed, 229 insertions, 61 deletions
diff --git a/debuggerd/Android.mk b/debuggerd/Android.mk index 8cc4682..dd53296 100644 --- a/debuggerd/Android.mk +++ b/debuggerd/Android.mk @@ -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) diff --git a/debuggerd/elf_utils.cpp b/debuggerd/elf_utils.cpp new file mode 100644 index 0000000..764b9db --- /dev/null +++ b/debuggerd/elf_utils.cpp @@ -0,0 +1,119 @@ +/* + * 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; +} diff --git a/debuggerd/elf_utils.h b/debuggerd/elf_utils.h new file mode 100644 index 0000000..11d0a43 --- /dev/null +++ b/debuggerd/elf_utils.h @@ -0,0 +1,27 @@ +/* + * 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 diff --git a/debuggerd/tombstone.cpp b/debuggerd/tombstone.cpp index e927ea3..094ab48 100644 --- a/debuggerd/tombstone.cpp +++ b/debuggerd/tombstone.cpp @@ -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; - } - uintptr_t offset = 0; - std::string func_name(backtrace->GetFunctionName(stack_content, &offset)); - if (!func_name.empty()) { - if (!i && label >= 0) { + 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_data[i], &offset)); + if (!func_name.empty()) { + 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); |