diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 17:32:43 +0000 |
commit | 6bf0a5cb5034a7e684dcc3500e841785237ce2dd (patch) | |
tree | a68f146d7fa01f0134297619fbe7e33db084e0aa /toolkit/crashreporter/google-breakpad/src/common/solaris | |
parent | Initial commit. (diff) | |
download | thunderbird-upstream.tar.xz thunderbird-upstream.zip |
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/crashreporter/google-breakpad/src/common/solaris')
7 files changed, 1181 insertions, 0 deletions
diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.cc b/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.cc new file mode 100644 index 0000000000..168d0b2879 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.cc @@ -0,0 +1,681 @@ +// Copyright (c) 2010 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Alfred Peng + +#include <demangle.h> +#include <fcntl.h> +#include <gelf.h> +#include <link.h> +#include <sys/mman.h> +#include <stab.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +#include <functional> +#include <map> +#include <vector> + +#include "common/scoped_ptr.h" +#include "common/solaris/dump_symbols.h" +#include "common/solaris/file_id.h" +#include "common/solaris/guid_creator.h" + +// This namespace contains helper functions. +namespace { + +using std::make_pair; + +#if defined(_LP64) +typedef Elf64_Sym Elf_Sym; +#else +typedef Elf32_Sym Elf_Sym; +#endif + +// Symbol table entry from stabs. Sun CC specific. +struct slist { + // String table index. + unsigned int n_strx; + // Stab type. + unsigned char n_type; + char n_other; + short n_desc; + unsigned long n_value; +}; + +// Symbol table entry +struct SymbolEntry { + // Offset from the start of the file. + GElf_Addr offset; + // Function size. + GElf_Word size; +}; + +// Infomation of a line. +struct LineInfo { + // Offset from start of the function. + // Load from stab symbol. + GElf_Off rva_to_func; + // Offset from base of the loading binary. + GElf_Off rva_to_base; + // Size of the line. + // The first line: equals to rva_to_func. + // The other lines: the difference of rva_to_func of the line and + // rva_to_func of the previous N_SLINE. + uint32_t size; + // Line number. + uint32_t line_num; +}; + +// Information of a function. +struct FuncInfo { + // Name of the function. + const char *name; + // Offset from the base of the loading address. + GElf_Off rva_to_base; + // Virtual address of the function. + // Load from stab symbol. + GElf_Addr addr; + // Size of the function. + // Equal to rva_to_func of the last function line. + uint32_t size; + // Total size of stack parameters. + uint32_t stack_param_size; + // Line information array. + std::vector<struct LineInfo> line_info; +}; + +// Information of a source file. +struct SourceFileInfo { + // Name of the source file. + const char *name; + // Starting address of the source file. + GElf_Addr addr; + // Id of the source file. + int source_id; + // Functions information. + std::vector<struct FuncInfo> func_info; +}; + +struct CompareString { + bool operator()(const char *s1, const char *s2) const { + return strcmp(s1, s2) < 0; + } +}; + +typedef std::map<const char *, struct SymbolEntry *, CompareString> SymbolMap; + +// Information of a symbol table. +// This is the root of all types of symbol. +struct SymbolInfo { + std::vector<struct SourceFileInfo> source_file_info; + // Symbols information. + SymbolMap symbol_entries; +}; + +// Stab section name. +const char *kStabName = ".stab"; + +// Stab str section name. +const char *kStabStrName = ".stabstr"; + +// Symtab section name. +const char *kSymtabName = ".symtab"; + +// Strtab section name. +const char *kStrtabName = ".strtab"; + +// Default buffer lenght for demangle. +const int demangleLen = 20000; + +// Offset to the string table. +uint64_t stringOffset = 0; + +// Update the offset to the start of the string index of the next +// object module for every N_ENDM stabs. +inline void RecalculateOffset(struct slist* cur_list, char *stabstr) { + while ((--cur_list)->n_strx == 0) ; + stringOffset += cur_list->n_strx; + + char *temp = stabstr + stringOffset; + while (*temp != '\0') { + ++stringOffset; + ++temp; + } + // Skip the extra '\0' + ++stringOffset; +} + +// Demangle using demangle library on Solaris. +std::string Demangle(const char *mangled) { + int status = 0; + std::string str(mangled); + char *demangled = (char *)malloc(demangleLen); + + if (!demangled) { + fprintf(stderr, "no enough memory.\n"); + goto out; + } + + if ((status = cplus_demangle(mangled, demangled, demangleLen)) == + DEMANGLE_ESPACE) { + fprintf(stderr, "incorrect demangle.\n"); + goto out; + } + + str = demangled; + free(demangled); + +out: + return str; +} + +bool WriteFormat(int fd, const char *fmt, ...) { + va_list list; + char buffer[4096]; + ssize_t expected, written; + va_start(list, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, list); + expected = strlen(buffer); + written = write(fd, buffer, strlen(buffer)); + va_end(list); + return expected == written; +} + +bool IsValidElf(const GElf_Ehdr *elf_header) { + return memcmp(elf_header, ELFMAG, SELFMAG) == 0; +} + +static bool FindSectionByName(Elf *elf, const char *name, + int shstrndx, + GElf_Shdr *shdr) { + assert(name != NULL); + + if (strlen(name) == 0) + return false; + + Elf_Scn *scn = NULL; + + while ((scn = elf_nextscn(elf, scn)) != NULL) { + if (gelf_getshdr(scn, shdr) == (GElf_Shdr *)0) { + fprintf(stderr, "failed to read section header: %s\n", elf_errmsg(0)); + return false; + } + + const char *section_name = elf_strptr(elf, shstrndx, shdr->sh_name); + if (!section_name) { + fprintf(stderr, "Section name error: %s\n", elf_errmsg(-1)); + continue; + } + + if (strcmp(section_name, name) == 0) + return true; + } + + return false; +} + +// The parameter size is used for FPO-optimized code, and +// this is all tied up with the debugging data for Windows x86. +// Set it to 0 on Solaris. +int LoadStackParamSize(struct slist *list, + struct slist *list_end, + struct FuncInfo *func_info) { + struct slist *cur_list = list; + int step = 1; + while (cur_list < list_end && cur_list->n_type == N_PSYM) { + ++cur_list; + ++step; + } + + func_info->stack_param_size = 0; + return step; +} + +int LoadLineInfo(struct slist *list, + struct slist *list_end, + struct FuncInfo *func_info) { + struct slist *cur_list = list; + do { + // Skip non line information. + while (cur_list < list_end && cur_list->n_type != N_SLINE) { + // Only exit when got another function, or source file, or end stab. + if (cur_list->n_type == N_FUN || cur_list->n_type == N_SO || + cur_list->n_type == N_ENDM) { + return cur_list - list; + } + ++cur_list; + } + struct LineInfo line; + while (cur_list < list_end && cur_list->n_type == N_SLINE) { + line.rva_to_func = cur_list->n_value; + // n_desc is a signed short + line.line_num = (unsigned short)cur_list->n_desc; + func_info->line_info.push_back(line); + ++cur_list; + } + if (cur_list == list_end && cur_list->n_type == N_ENDM) + break; + } while (list < list_end); + + return cur_list - list; +} + +int LoadFuncSymbols(struct slist *list, + struct slist *list_end, + char *stabstr, + GElf_Word base, + struct SourceFileInfo *source_file_info) { + struct slist *cur_list = list; + assert(cur_list->n_type == N_SO); + ++cur_list; + + source_file_info->func_info.clear(); + while (cur_list < list_end) { + // Go until the function symbol. + while (cur_list < list_end && cur_list->n_type != N_FUN) { + if (cur_list->n_type == N_SO) { + return cur_list - list; + } + ++cur_list; + if (cur_list->n_type == N_ENDM) + RecalculateOffset(cur_list, stabstr); + continue; + } + while (cur_list->n_type == N_FUN) { + struct FuncInfo func_info; + memset(&func_info, 0, sizeof(func_info)); + func_info.name = stabstr + cur_list->n_strx + stringOffset; + // The n_value field is always 0 from stab generated by Sun CC. + // TODO(Alfred): Find the correct value. + func_info.addr = cur_list->n_value; + ++cur_list; + if (cur_list->n_type == N_ENDM) + RecalculateOffset(cur_list, stabstr); + if (cur_list->n_type != N_ESYM && cur_list->n_type != N_ISYM && + cur_list->n_type != N_FUN) { + // Stack parameter size. + cur_list += LoadStackParamSize(cur_list, list_end, &func_info); + // Line info. + cur_list += LoadLineInfo(cur_list, list_end, &func_info); + } + if (cur_list < list_end && cur_list->n_type == N_ENDM) + RecalculateOffset(cur_list, stabstr); + // Functions in this module should have address bigger than the module + // starting address. + // + // These two values are always 0 with Sun CC. + // TODO(Alfred): Get the correct value or remove the condition statement. + if (func_info.addr >= source_file_info->addr) { + source_file_info->func_info.push_back(func_info); + } + } + } + return cur_list - list; +} + +// Compute size and rva information based on symbols loaded from stab section. +bool ComputeSizeAndRVA(struct SymbolInfo *symbols) { + std::vector<struct SourceFileInfo> *sorted_files = + &(symbols->source_file_info); + SymbolMap *symbol_entries = &(symbols->symbol_entries); + for (size_t i = 0; i < sorted_files->size(); ++i) { + struct SourceFileInfo &source_file = (*sorted_files)[i]; + std::vector<struct FuncInfo> *sorted_functions = &(source_file.func_info); + int func_size = sorted_functions->size(); + + for (size_t j = 0; j < func_size; ++j) { + struct FuncInfo &func_info = (*sorted_functions)[j]; + int line_count = func_info.line_info.size(); + + // Discard the ending part of the name. + std::string func_name(func_info.name); + std::string::size_type last_colon = func_name.find_first_of(':'); + if (last_colon != std::string::npos) + func_name = func_name.substr(0, last_colon); + + // Fine the symbol offset from the loading address and size by name. + SymbolMap::const_iterator it = symbol_entries->find(func_name.c_str()); + if (it->second) { + func_info.rva_to_base = it->second->offset; + func_info.size = (line_count == 0) ? 0 : it->second->size; + } else { + func_info.rva_to_base = 0; + func_info.size = 0; + } + + // Compute function and line size. + for (size_t k = 0; k < line_count; ++k) { + struct LineInfo &line_info = func_info.line_info[k]; + + line_info.rva_to_base = line_info.rva_to_func + func_info.rva_to_base; + if (k == line_count - 1) { + line_info.size = func_info.size - line_info.rva_to_func; + } else { + struct LineInfo &next_line = func_info.line_info[k + 1]; + line_info.size = next_line.rva_to_func - line_info.rva_to_func; + } + } // for each line. + } // for each function. + } // for each source file. + for (SymbolMap::iterator it = symbol_entries->begin(); + it != symbol_entries->end(); ++it) { + free(it->second); + } + return true; +} + +bool LoadAllSymbols(const GElf_Shdr *stab_section, + const GElf_Shdr *stabstr_section, + GElf_Word base, + struct SymbolInfo *symbols) { + if (stab_section == NULL || stabstr_section == NULL) + return false; + + char *stabstr = + reinterpret_cast<char *>(stabstr_section->sh_offset + base); + struct slist *lists = + reinterpret_cast<struct slist *>(stab_section->sh_offset + base); + int nstab = stab_section->sh_size / sizeof(struct slist); + int source_id = 0; + + // First pass, load all symbols from the object file. + for (int i = 0; i < nstab; ) { + int step = 1; + struct slist *cur_list = lists + i; + if (cur_list->n_type == N_SO) { + // FUNC <address> <size> <param_stack_size> <function> + struct SourceFileInfo source_file_info; + source_file_info.name = stabstr + cur_list->n_strx + stringOffset; + // The n_value field is always 0 from stab generated by Sun CC. + // TODO(Alfred): Find the correct value. + source_file_info.addr = cur_list->n_value; + if (strchr(source_file_info.name, '.')) + source_file_info.source_id = source_id++; + else + source_file_info.source_id = -1; + step = LoadFuncSymbols(cur_list, lists + nstab - 1, stabstr, + base, &source_file_info); + symbols->source_file_info.push_back(source_file_info); + } + i += step; + } + // Second pass, compute the size of functions and lines. + return ComputeSizeAndRVA(symbols); +} + +bool LoadSymbols(Elf *elf, GElf_Ehdr *elf_header, struct SymbolInfo *symbols, + void *obj_base) { + GElf_Word base = reinterpret_cast<GElf_Word>(obj_base); + + const GElf_Shdr *sections = + reinterpret_cast<GElf_Shdr *>(elf_header->e_shoff + base); + GElf_Shdr stab_section; + if (!FindSectionByName(elf, kStabName, elf_header->e_shstrndx, + &stab_section)) { + fprintf(stderr, "Stab section not found.\n"); + return false; + } + GElf_Shdr stabstr_section; + if (!FindSectionByName(elf, kStabStrName, elf_header->e_shstrndx, + &stabstr_section)) { + fprintf(stderr, "Stabstr section not found.\n"); + return false; + } + GElf_Shdr symtab_section; + if (!FindSectionByName(elf, kSymtabName, elf_header->e_shstrndx, + &symtab_section)) { + fprintf(stderr, "Symtab section not found.\n"); + return false; + } + GElf_Shdr strtab_section; + if (!FindSectionByName(elf, kStrtabName, elf_header->e_shstrndx, + &strtab_section)) { + fprintf(stderr, "Strtab section not found.\n"); + return false; + } + + Elf_Sym *symbol = (Elf_Sym *)((char *)base + symtab_section.sh_offset); + for (int i = 0; i < symtab_section.sh_size/symtab_section.sh_entsize; ++i) { + struct SymbolEntry *symbol_entry = + (struct SymbolEntry *)malloc(sizeof(struct SymbolEntry)); + const char *name = reinterpret_cast<char *>( + strtab_section.sh_offset + (GElf_Word)base + symbol->st_name); + symbol_entry->offset = symbol->st_value; + symbol_entry->size = symbol->st_size; + symbols->symbol_entries.insert(make_pair(name, symbol_entry)); + ++symbol; + } + + + // Load symbols. + return LoadAllSymbols(&stab_section, &stabstr_section, base, symbols); +} + +bool WriteModuleInfo(int fd, GElf_Half arch, const std::string &obj_file) { + const char *arch_name = NULL; + if (arch == EM_386) + arch_name = "x86"; + else if (arch == EM_X86_64) + arch_name = "x86_64"; + else if (arch == EM_SPARC32PLUS) + arch_name = "SPARC_32+"; + else { + printf("Please add more ARCH support\n"); + return false; + } + + unsigned char identifier[16]; + google_breakpad::FileID file_id(obj_file.c_str()); + if (file_id.ElfFileIdentifier(identifier)) { + char identifier_str[40]; + file_id.ConvertIdentifierToString(identifier, + identifier_str, sizeof(identifier_str)); + std::string filename = obj_file; + size_t slash_pos = obj_file.find_last_of("/"); + if (slash_pos != std::string::npos) + filename = obj_file.substr(slash_pos + 1); + return WriteFormat(fd, "MODULE solaris %s %s %s\n", arch_name, + identifier_str, filename.c_str()); + } + return false; +} + +bool WriteSourceFileInfo(int fd, const struct SymbolInfo &symbols) { + for (size_t i = 0; i < symbols.source_file_info.size(); ++i) { + if (symbols.source_file_info[i].source_id != -1) { + const char *name = symbols.source_file_info[i].name; + if (!WriteFormat(fd, "FILE %d %s\n", + symbols.source_file_info[i].source_id, name)) + return false; + } + } + return true; +} + +bool WriteOneFunction(int fd, int source_id, + const struct FuncInfo &func_info){ + // Discard the ending part of the name. + std::string func_name(func_info.name); + std::string::size_type last_colon = func_name.find_last_of(':'); + if (last_colon != std::string::npos) + func_name = func_name.substr(0, last_colon); + func_name = Demangle(func_name.c_str()); + + if (func_info.size <= 0) + return true; + + // rva_to_base could be unsigned long(32 bit) or unsigned long long(64 bit). + if (WriteFormat(fd, "FUNC %llx %x %d %s\n", + (long long)func_info.rva_to_base, + func_info.size, + func_info.stack_param_size, + func_name.c_str())) { + for (size_t i = 0; i < func_info.line_info.size(); ++i) { + const struct LineInfo &line_info = func_info.line_info[i]; + if (line_info.line_num == 0) + return true; + if (!WriteFormat(fd, "%llx %x %d %d\n", + (long long)line_info.rva_to_base, + line_info.size, + line_info.line_num, + source_id)) + return false; + } + return true; + } + return false; +} + +bool WriteFunctionInfo(int fd, const struct SymbolInfo &symbols) { + for (size_t i = 0; i < symbols.source_file_info.size(); ++i) { + const struct SourceFileInfo &file_info = symbols.source_file_info[i]; + for (size_t j = 0; j < file_info.func_info.size(); ++j) { + const struct FuncInfo &func_info = file_info.func_info[j]; + if (!WriteOneFunction(fd, file_info.source_id, func_info)) + return false; + } + } + return true; +} + +bool DumpStabSymbols(int fd, const struct SymbolInfo &symbols) { + return WriteSourceFileInfo(fd, symbols) && + WriteFunctionInfo(fd, symbols); +} + +// +// FDWrapper +// +// Wrapper class to make sure opened file is closed. +// +class FDWrapper { + public: + explicit FDWrapper(int fd) : + fd_(fd) { + } + ~FDWrapper() { + if (fd_ != -1) + close(fd_); + } + int get() { + return fd_; + } + int release() { + int fd = fd_; + fd_ = -1; + return fd; + } + private: + int fd_; +}; + +// +// MmapWrapper +// +// Wrapper class to make sure mapped regions are unmapped. +// +class MmapWrapper { + public: + MmapWrapper(void *mapped_address, size_t mapped_size) : + base_(mapped_address), size_(mapped_size) { + } + ~MmapWrapper() { + if (base_ != NULL) { + assert(size_ > 0); + munmap((char *)base_, size_); + } + } + void release() { + base_ = NULL; + size_ = 0; + } + + private: + void *base_; + size_t size_; +}; + +} // namespace + +namespace google_breakpad { + +class AutoElfEnder { + public: + AutoElfEnder(Elf *elf) : elf_(elf) {} + ~AutoElfEnder() { if (elf_) elf_end(elf_); } + private: + Elf *elf_; +}; + + +bool DumpSymbols::WriteSymbolFile(const std::string &obj_file, int sym_fd) { + if (elf_version(EV_CURRENT) == EV_NONE) { + fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0)); + return false; + } + + int obj_fd = open(obj_file.c_str(), O_RDONLY); + if (obj_fd < 0) + return false; + FDWrapper obj_fd_wrapper(obj_fd); + struct stat st; + if (fstat(obj_fd, &st) != 0 && st.st_size <= 0) + return false; + void *obj_base = mmap(NULL, st.st_size, + PROT_READ, MAP_PRIVATE, obj_fd, 0); + if (obj_base == MAP_FAILED) + return false; + MmapWrapper map_wrapper(obj_base, st.st_size); + GElf_Ehdr elf_header; + Elf *elf = elf_begin(obj_fd, ELF_C_READ, NULL); + AutoElfEnder elfEnder(elf); + + if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr *)NULL) { + fprintf(stderr, "failed to read elf header: %s\n", elf_errmsg(-1)); + return false; + } + + if (!IsValidElf(&elf_header)) { + fprintf(stderr, "header magic doesn't match\n"); + return false; + } + struct SymbolInfo symbols; + if (!LoadSymbols(elf, &elf_header, &symbols, obj_base)) + return false; + // Write to symbol file. + if (WriteModuleInfo(sym_fd, elf_header.e_machine, obj_file) && + DumpStabSymbols(sym_fd, symbols)) + return true; + + return false; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.h b/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.h new file mode 100644 index 0000000000..7f4baadcfc --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.h @@ -0,0 +1,49 @@ +// Copyright (c) 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// dump_symbols.cc: Implements a Solaris stab debugging format dumper. +// +// Author: Alfred Peng + +#ifndef COMMON_SOLARIS_DUMP_SYMBOLS_H__ +#define COMMON_SOLARIS_DUMP_SYMBOLS_H__ + +#include <string> + +namespace google_breakpad { + +class DumpSymbols { + public: + bool WriteSymbolFile(const std::string &obj_file, + int sym_fd); +}; + +} // namespace google_breakpad + +#endif // COMMON_SOLARIS_DUMP_SYMBOLS_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.cc b/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.cc new file mode 100644 index 0000000000..643a14629d --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.cc @@ -0,0 +1,197 @@ +// Copyright (c) 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// file_id.cc: Return a unique identifier for a file +// +// See file_id.h for documentation +// +// Author: Alfred Peng + +#include <elf.h> +#include <fcntl.h> +#include <gelf.h> +#include <sys/mman.h> +#include <sys/ksyms.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <cassert> +#include <cstdio> + +#include "common/md5.h" +#include "common/solaris/file_id.h" +#include "common/solaris/message_output.h" +#include "google_breakpad/common/minidump_format.h" + +namespace google_breakpad { + +class AutoElfEnder { + public: + AutoElfEnder(Elf *elf) : elf_(elf) {} + ~AutoElfEnder() { if (elf_) elf_end(elf_); } + private: + Elf *elf_; +}; + +// Find the text section in elf object file. +// Return the section start address and the size. +static bool FindElfTextSection(int fd, const void *elf_base, + const void **text_start, + int *text_size) { + assert(text_start); + assert(text_size); + + *text_start = NULL; + *text_size = 0; + + if (elf_version(EV_CURRENT) == EV_NONE) { + print_message2(2, "elf_version() failed: %s\n", elf_errmsg(0)); + return false; + } + + GElf_Ehdr elf_header; + lseek(fd, 0L, 0); + Elf *elf = elf_begin(fd, ELF_C_READ, NULL); + AutoElfEnder elfEnder(elf); + + if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr *)NULL) { + print_message2(2, "failed to read elf header: %s\n", elf_errmsg(-1)); + return false; + } + + if (elf_header.e_ident[EI_MAG0] != ELFMAG0 || + elf_header.e_ident[EI_MAG1] != ELFMAG1 || + elf_header.e_ident[EI_MAG2] != ELFMAG2 || + elf_header.e_ident[EI_MAG3] != ELFMAG3) { + print_message1(2, "header magic doesn't match\n"); + return false; + } + + static const char kTextSectionName[] = ".text"; + const GElf_Shdr *text_section = NULL; + Elf_Scn *scn = NULL; + GElf_Shdr shdr; + + while ((scn = elf_nextscn(elf, scn)) != NULL) { + if (gelf_getshdr(scn, &shdr) == (GElf_Shdr *)0) { + print_message2(2, "failed to read section header: %s\n", elf_errmsg(0)); + return false; + } + + if (shdr.sh_type == SHT_PROGBITS) { + const char *section_name = elf_strptr(elf, elf_header.e_shstrndx, + shdr.sh_name); + if (!section_name) { + print_message2(2, "Section name error: %s\n", elf_errmsg(-1)); + continue; + } + + if (strcmp(section_name, kTextSectionName) == 0) { + text_section = &shdr; + break; + } + } + } + if (text_section != NULL && text_section->sh_size > 0) { + *text_start = (char *)elf_base + text_section->sh_offset; + *text_size = text_section->sh_size; + return true; + } + + return false; +} + +FileID::FileID(const char *path) { + strcpy(path_, path); +} + +class AutoCloser { + public: + AutoCloser(int fd) : fd_(fd) {} + ~AutoCloser() { if (fd_) close(fd_); } + private: + int fd_; +}; + +bool FileID::ElfFileIdentifier(unsigned char identifier[16]) { + int fd = 0; + if ((fd = open(path_, O_RDONLY)) < 0) + return false; + + AutoCloser autocloser(fd); + struct stat st; + if (fstat(fd, &st) != 0 || st.st_size <= 0) + return false; + + void *base = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (base == MAP_FAILED) + return false; + + bool success = false; + const void *text_section = NULL; + int text_size = 0; + + if (FindElfTextSection(fd, base, &text_section, &text_size)) { + MD5Context md5; + MD5Init(&md5); + MD5Update(&md5, (const unsigned char *)text_section, text_size); + MD5Final(identifier, &md5); + success = true; + } + + munmap((char *)base, st.st_size); + return success; +} + +// static +bool FileID::ConvertIdentifierToString(const unsigned char identifier[16], + char *buffer, int buffer_length) { + if (buffer_length < 34) + return false; + + int buffer_idx = 0; + for (int idx = 0; idx < 16; ++idx) { + int hi = (identifier[idx] >> 4) & 0x0F; + int lo = (identifier[idx]) & 0x0F; + + buffer[buffer_idx++] = (hi >= 10) ? 'A' + hi - 10 : '0' + hi; + buffer[buffer_idx++] = (lo >= 10) ? 'A' + lo - 10 : '0' + lo; + } + + // Add an extra "0" by the end. + buffer[buffer_idx++] = '0'; + + // NULL terminate + buffer[buffer_idx] = 0; + + return true; +} + +} // namespace google_breakpad diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.h b/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.h new file mode 100644 index 0000000000..375e857512 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/solaris/file_id.h @@ -0,0 +1,66 @@ +// Copyright (c) 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// file_id.h: Return a unique identifier for a file +// +// Author: Alfred Peng + +#ifndef COMMON_SOLARIS_FILE_ID_H__ +#define COMMON_SOLARIS_FILE_ID_H__ + +#include <limits.h> + +namespace google_breakpad { + +class FileID { + public: + FileID(const char *path); + ~FileID() {}; + + // Load the identifier for the elf file path specified in the constructor into + // |identifier|. Return false if the identifier could not be created for the + // file. + // The current implementation will return the MD5 hash of the file's bytes. + bool ElfFileIdentifier(unsigned char identifier[16]); + + // Convert the |identifier| data to a NULL terminated string. The string will + // be formatted as a MDCVInfoPDB70 struct. + // The |buffer| should be at least 34 bytes long to receive all of the data + // and termination. Shorter buffers will return false. + static bool ConvertIdentifierToString(const unsigned char identifier[16], + char *buffer, int buffer_length); + + private: + // Storage for the path specified + char path_[PATH_MAX]; +}; + +} // namespace google_breakpad + +#endif // COMMON_SOLARIS_FILE_ID_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.cc b/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.cc new file mode 100644 index 0000000000..e9e6c6f5d2 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.cc @@ -0,0 +1,84 @@ +// Copyright (c) 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Alfred Peng + +#include <cassert> +#include <ctime> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "common/solaris/guid_creator.h" + +// +// GUIDGenerator +// +// This class is used to generate random GUID. +// Currently use random number to generate a GUID. This should be OK since +// we don't expect crash to happen very offen. +// +class GUIDGenerator { + public: + GUIDGenerator() { + srandom(time(NULL)); + } + + bool CreateGUID(GUID *guid) const { + guid->data1 = random(); + guid->data2 = (uint16_t)(random()); + guid->data3 = (uint16_t)(random()); + *reinterpret_cast<uint32_t*>(&guid->data4[0]) = random(); + *reinterpret_cast<uint32_t*>(&guid->data4[4]) = random(); + return true; + } +}; + +// Guid generator. +const GUIDGenerator kGuidGenerator; + +bool CreateGUID(GUID *guid) { + return kGuidGenerator.CreateGUID(guid); +} + +// Parse guid to string. +bool GUIDToString(const GUID *guid, char *buf, int buf_len) { + // Should allow more space the the max length of GUID. + assert(buf_len > kGUIDStringLength); + int num = snprintf(buf, buf_len, kGUIDFormatString, + guid->data1, guid->data2, guid->data3, + *reinterpret_cast<const uint32_t *>(&(guid->data4[0])), + *reinterpret_cast<const uint32_t *>(&(guid->data4[4]))); + if (num != kGUIDStringLength) + return false; + + buf[num] = '\0'; + return true; +} diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.h b/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.h new file mode 100644 index 0000000000..4aee3a1c24 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/solaris/guid_creator.h @@ -0,0 +1,50 @@ +// Copyright (c) 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Alfred Peng + +#ifndef COMMON_SOLARIS_GUID_CREATOR_H__ +#define COMMON_SOLARIS_GUID_CREATOR_H__ + +#include "google_breakpad/common/minidump_format.h" + +typedef MDGUID GUID; + +// Format string for parsing GUID. +#define kGUIDFormatString "%08x-%04x-%04x-%08x-%08x" +// Length of GUID string. Don't count the ending '\0'. +#define kGUIDStringLength 36 + +// Create a guid. +bool CreateGUID(GUID *guid); + +// Get the string from guid. +bool GUIDToString(const GUID *guid, char *buf, int buf_len); + +#endif // COMMON_SOLARIS_GUID_CREATOR_H__ diff --git a/toolkit/crashreporter/google-breakpad/src/common/solaris/message_output.h b/toolkit/crashreporter/google-breakpad/src/common/solaris/message_output.h new file mode 100644 index 0000000000..3e3b1d4652 --- /dev/null +++ b/toolkit/crashreporter/google-breakpad/src/common/solaris/message_output.h @@ -0,0 +1,54 @@ +// Copyright (c) 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: Alfred Peng + +#ifndef COMMON_SOLARIS_MESSAGE_OUTPUT_H__ +#define COMMON_SOLARIS_MESSAGE_OUTPUT_H__ + +namespace google_breakpad { + +const int MESSAGE_MAX = 1000; + +// Message output macros. +// snprintf doesn't operate heap on Solaris, while printf and fprintf do. +// Use snprintf here to avoid heap allocation. +#define print_message1(std, message) \ + char buffer[MESSAGE_MAX]; \ + int len = snprintf(buffer, MESSAGE_MAX, message); \ + write(std, buffer, len) + +#define print_message2(std, message, para) \ + char buffer[MESSAGE_MAX]; \ + int len = snprintf(buffer, MESSAGE_MAX, message, para); \ + write(std, buffer, len); + +} // namespace google_breakpad + +#endif // COMMON_SOLARIS_MESSAGE_OUTPUT_H__ |