toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.cc

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/crashreporter/google-breakpad/src/common/solaris/dump_symbols.cc	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,681 @@
     1.4 +// Copyright (c) 2010 Google Inc.
     1.5 +// All rights reserved.
     1.6 +//
     1.7 +// Redistribution and use in source and binary forms, with or without
     1.8 +// modification, are permitted provided that the following conditions are
     1.9 +// met:
    1.10 +//
    1.11 +//     * Redistributions of source code must retain the above copyright
    1.12 +// notice, this list of conditions and the following disclaimer.
    1.13 +//     * Redistributions in binary form must reproduce the above
    1.14 +// copyright notice, this list of conditions and the following disclaimer
    1.15 +// in the documentation and/or other materials provided with the
    1.16 +// distribution.
    1.17 +//     * Neither the name of Google Inc. nor the names of its
    1.18 +// contributors may be used to endorse or promote products derived from
    1.19 +// this software without specific prior written permission.
    1.20 +//
    1.21 +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    1.22 +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    1.23 +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    1.24 +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    1.25 +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    1.26 +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    1.27 +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    1.28 +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    1.29 +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    1.30 +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    1.31 +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.32 +
    1.33 +// Author: Alfred Peng
    1.34 +
    1.35 +#include <demangle.h>
    1.36 +#include <fcntl.h>
    1.37 +#include <gelf.h>
    1.38 +#include <link.h>
    1.39 +#include <sys/mman.h>
    1.40 +#include <stab.h>
    1.41 +#include <sys/stat.h>
    1.42 +#include <sys/types.h>
    1.43 +#include <unistd.h>
    1.44 +
    1.45 +#include <functional>
    1.46 +#include <map>
    1.47 +#include <vector>
    1.48 +
    1.49 +#include "common/scoped_ptr.h"
    1.50 +#include "common/solaris/dump_symbols.h"
    1.51 +#include "common/solaris/file_id.h"
    1.52 +#include "common/solaris/guid_creator.h"
    1.53 +
    1.54 +// This namespace contains helper functions.
    1.55 +namespace {
    1.56 +
    1.57 +using std::make_pair;
    1.58 +
    1.59 +#if defined(_LP64)
    1.60 +typedef Elf64_Sym   Elf_Sym;
    1.61 +#else
    1.62 +typedef Elf32_Sym   Elf_Sym;
    1.63 +#endif
    1.64 +
    1.65 +// Symbol table entry from stabs. Sun CC specific.
    1.66 +struct slist {
    1.67 +  // String table index.
    1.68 +  unsigned int n_strx;
    1.69 +  // Stab type. 
    1.70 +  unsigned char n_type;
    1.71 +  char n_other;
    1.72 +  short n_desc;
    1.73 +  unsigned long n_value;
    1.74 +};
    1.75 +
    1.76 +// Symbol table entry
    1.77 +struct SymbolEntry {
    1.78 +  // Offset from the start of the file.
    1.79 +  GElf_Addr offset;
    1.80 +  // Function size.
    1.81 +  GElf_Word size;
    1.82 +};
    1.83 +
    1.84 +// Infomation of a line.
    1.85 +struct LineInfo {
    1.86 +  // Offset from start of the function.
    1.87 +  // Load from stab symbol.
    1.88 +  GElf_Off rva_to_func;
    1.89 +  // Offset from base of the loading binary.
    1.90 +  GElf_Off rva_to_base;
    1.91 +  // Size of the line.
    1.92 +  // The first line: equals to rva_to_func.
    1.93 +  // The other lines: the difference of rva_to_func of the line and
    1.94 +  // rva_to_func of the previous N_SLINE.
    1.95 +  uint32_t size;
    1.96 +  // Line number.
    1.97 +  uint32_t line_num;
    1.98 +};
    1.99 +
   1.100 +// Information of a function.
   1.101 +struct FuncInfo {
   1.102 +  // Name of the function.
   1.103 +  const char *name;
   1.104 +  // Offset from the base of the loading address.
   1.105 +  GElf_Off rva_to_base;
   1.106 +  // Virtual address of the function.
   1.107 +  // Load from stab symbol.
   1.108 +  GElf_Addr addr;
   1.109 +  // Size of the function.
   1.110 +  // Equal to rva_to_func of the last function line.
   1.111 +  uint32_t size;
   1.112 +  // Total size of stack parameters.
   1.113 +  uint32_t stack_param_size;
   1.114 +  // Line information array.
   1.115 +  std::vector<struct LineInfo> line_info;
   1.116 +};
   1.117 +
   1.118 +// Information of a source file.
   1.119 +struct SourceFileInfo {
   1.120 +  // Name of the source file.
   1.121 +  const char *name;
   1.122 +  // Starting address of the source file.
   1.123 +  GElf_Addr addr;
   1.124 +  // Id of the source file.
   1.125 +  int source_id;
   1.126 +  // Functions information.
   1.127 +  std::vector<struct FuncInfo> func_info;
   1.128 +};
   1.129 +
   1.130 +struct CompareString {
   1.131 +  bool operator()(const char *s1, const char *s2) const {
   1.132 +    return strcmp(s1, s2) < 0;
   1.133 +  }
   1.134 +};
   1.135 +
   1.136 +typedef std::map<const char *, struct SymbolEntry *, CompareString> SymbolMap;
   1.137 +
   1.138 +// Information of a symbol table.
   1.139 +// This is the root of all types of symbol.
   1.140 +struct SymbolInfo {
   1.141 +  std::vector<struct SourceFileInfo> source_file_info;
   1.142 +  // Symbols information.
   1.143 +  SymbolMap symbol_entries;
   1.144 +};
   1.145 +
   1.146 +// Stab section name.
   1.147 +const char *kStabName = ".stab";
   1.148 +
   1.149 +// Stab str section name.
   1.150 +const char *kStabStrName = ".stabstr";
   1.151 +
   1.152 +// Symtab section name.
   1.153 +const char *kSymtabName = ".symtab";
   1.154 +
   1.155 +// Strtab section name.
   1.156 +const char *kStrtabName = ".strtab";
   1.157 +
   1.158 +// Default buffer lenght for demangle.
   1.159 +const int demangleLen = 20000;
   1.160 +
   1.161 +// Offset to the string table.
   1.162 +uint64_t stringOffset = 0;
   1.163 +
   1.164 +// Update the offset to the start of the string index of the next
   1.165 +// object module for every N_ENDM stabs.
   1.166 +inline void RecalculateOffset(struct slist* cur_list, char *stabstr) {
   1.167 +  while ((--cur_list)->n_strx == 0) ;
   1.168 +  stringOffset += cur_list->n_strx;
   1.169 +
   1.170 +  char *temp = stabstr + stringOffset;
   1.171 +  while (*temp != '\0') {
   1.172 +    ++stringOffset;
   1.173 +    ++temp;
   1.174 +  }
   1.175 +  // Skip the extra '\0'
   1.176 +  ++stringOffset;
   1.177 +}
   1.178 +
   1.179 +// Demangle using demangle library on Solaris.
   1.180 +std::string Demangle(const char *mangled) {
   1.181 +  int status = 0;
   1.182 +  std::string str(mangled);
   1.183 +  char *demangled = (char *)malloc(demangleLen);
   1.184 +
   1.185 +  if (!demangled) {
   1.186 +    fprintf(stderr, "no enough memory.\n");
   1.187 +    goto out;
   1.188 +  }
   1.189 +
   1.190 +  if ((status = cplus_demangle(mangled, demangled, demangleLen)) ==
   1.191 +      DEMANGLE_ESPACE) {
   1.192 +    fprintf(stderr, "incorrect demangle.\n");
   1.193 +    goto out;
   1.194 +  }
   1.195 +
   1.196 +  str = demangled;
   1.197 +  free(demangled);
   1.198 +
   1.199 +out:
   1.200 +  return str; 
   1.201 +}
   1.202 +
   1.203 +bool WriteFormat(int fd, const char *fmt, ...) {
   1.204 +  va_list list;
   1.205 +  char buffer[4096];
   1.206 +  ssize_t expected, written;
   1.207 +  va_start(list, fmt);
   1.208 +  vsnprintf(buffer, sizeof(buffer), fmt, list);
   1.209 +  expected = strlen(buffer);
   1.210 +  written = write(fd, buffer, strlen(buffer));
   1.211 +  va_end(list);
   1.212 +  return expected == written;
   1.213 +}
   1.214 +
   1.215 +bool IsValidElf(const GElf_Ehdr *elf_header) {
   1.216 +  return memcmp(elf_header, ELFMAG, SELFMAG) == 0;
   1.217 +}
   1.218 +
   1.219 +static bool FindSectionByName(Elf *elf, const char *name,
   1.220 +                              int shstrndx,
   1.221 +                              GElf_Shdr *shdr) {
   1.222 +  assert(name != NULL);
   1.223 +
   1.224 +  if (strlen(name) == 0)
   1.225 +    return false;
   1.226 +
   1.227 +  Elf_Scn *scn = NULL;
   1.228 +
   1.229 +  while ((scn = elf_nextscn(elf, scn)) != NULL) {
   1.230 +    if (gelf_getshdr(scn, shdr) == (GElf_Shdr *)0) {
   1.231 +      fprintf(stderr, "failed to read section header: %s\n", elf_errmsg(0));
   1.232 +      return false;
   1.233 +    }
   1.234 +
   1.235 +    const char *section_name = elf_strptr(elf, shstrndx, shdr->sh_name);
   1.236 +    if (!section_name) {
   1.237 +      fprintf(stderr, "Section name error: %s\n", elf_errmsg(-1));
   1.238 +      continue;
   1.239 +    }
   1.240 +
   1.241 +    if (strcmp(section_name, name) == 0)
   1.242 +      return true;
   1.243 +  }
   1.244 +
   1.245 +  return false;
   1.246 +}
   1.247 +
   1.248 +// The parameter size is used for FPO-optimized code, and
   1.249 +// this is all tied up with the debugging data for Windows x86.
   1.250 +// Set it to 0 on Solaris.
   1.251 +int LoadStackParamSize(struct slist *list,
   1.252 +                       struct slist *list_end,
   1.253 +                       struct FuncInfo *func_info) {
   1.254 +  struct slist *cur_list = list;
   1.255 +  int step = 1;
   1.256 +  while (cur_list < list_end && cur_list->n_type == N_PSYM) {
   1.257 +    ++cur_list;
   1.258 +    ++step;
   1.259 +  }
   1.260 +
   1.261 +  func_info->stack_param_size = 0;
   1.262 +  return step;
   1.263 +}
   1.264 +
   1.265 +int LoadLineInfo(struct slist *list,
   1.266 +                 struct slist *list_end,
   1.267 +                 struct FuncInfo *func_info) {
   1.268 +  struct slist *cur_list = list;
   1.269 +  do {
   1.270 +    // Skip non line information.
   1.271 +    while (cur_list < list_end && cur_list->n_type != N_SLINE) {
   1.272 +      // Only exit when got another function, or source file, or end stab.
   1.273 +      if (cur_list->n_type == N_FUN || cur_list->n_type == N_SO ||
   1.274 +          cur_list->n_type == N_ENDM) {
   1.275 +        return cur_list - list;
   1.276 +      }
   1.277 +      ++cur_list;
   1.278 +    }
   1.279 +    struct LineInfo line;
   1.280 +    while (cur_list < list_end && cur_list->n_type == N_SLINE) {
   1.281 +      line.rva_to_func = cur_list->n_value;
   1.282 +      // n_desc is a signed short
   1.283 +      line.line_num = (unsigned short)cur_list->n_desc;
   1.284 +      func_info->line_info.push_back(line);
   1.285 +      ++cur_list;
   1.286 +    }
   1.287 +    if (cur_list == list_end && cur_list->n_type == N_ENDM)
   1.288 +      break;
   1.289 +  } while (list < list_end);
   1.290 +
   1.291 +  return cur_list - list;
   1.292 +}
   1.293 +
   1.294 +int LoadFuncSymbols(struct slist *list,
   1.295 +                    struct slist *list_end,
   1.296 +                    char *stabstr,
   1.297 +                    GElf_Word base,
   1.298 +                    struct SourceFileInfo *source_file_info) {
   1.299 +  struct slist *cur_list = list;
   1.300 +  assert(cur_list->n_type == N_SO);
   1.301 +  ++cur_list;
   1.302 +
   1.303 +  source_file_info->func_info.clear();
   1.304 +  while (cur_list < list_end) {
   1.305 +    // Go until the function symbol.
   1.306 +    while (cur_list < list_end && cur_list->n_type != N_FUN) {
   1.307 +      if (cur_list->n_type == N_SO) {
   1.308 +        return cur_list - list;
   1.309 +      }
   1.310 +      ++cur_list;
   1.311 +      if (cur_list->n_type == N_ENDM)
   1.312 +        RecalculateOffset(cur_list, stabstr);
   1.313 +      continue;
   1.314 +    }
   1.315 +    while (cur_list->n_type == N_FUN) {
   1.316 +      struct FuncInfo func_info;
   1.317 +      memset(&func_info, 0, sizeof(func_info));
   1.318 +      func_info.name = stabstr + cur_list->n_strx + stringOffset;
   1.319 +      // The n_value field is always 0 from stab generated by Sun CC.
   1.320 +      // TODO(Alfred): Find the correct value.
   1.321 +      func_info.addr = cur_list->n_value;
   1.322 +      ++cur_list;
   1.323 +      if (cur_list->n_type == N_ENDM)
   1.324 +        RecalculateOffset(cur_list, stabstr);
   1.325 +      if (cur_list->n_type != N_ESYM && cur_list->n_type != N_ISYM &&
   1.326 +          cur_list->n_type != N_FUN) {
   1.327 +        // Stack parameter size.
   1.328 +        cur_list += LoadStackParamSize(cur_list, list_end, &func_info);
   1.329 +        // Line info.
   1.330 +        cur_list += LoadLineInfo(cur_list, list_end, &func_info);
   1.331 +      }
   1.332 +      if (cur_list < list_end && cur_list->n_type == N_ENDM)
   1.333 +        RecalculateOffset(cur_list, stabstr);
   1.334 +      // Functions in this module should have address bigger than the module
   1.335 +      // starting address.
   1.336 +      //
   1.337 +      // These two values are always 0 with Sun CC.
   1.338 +      // TODO(Alfred): Get the correct value or remove the condition statement.
   1.339 +      if (func_info.addr >= source_file_info->addr) {
   1.340 +        source_file_info->func_info.push_back(func_info);
   1.341 +      }
   1.342 +    }
   1.343 +  }
   1.344 +  return cur_list - list;
   1.345 +}
   1.346 +
   1.347 +// Compute size and rva information based on symbols loaded from stab section.
   1.348 +bool ComputeSizeAndRVA(struct SymbolInfo *symbols) {
   1.349 +  std::vector<struct SourceFileInfo> *sorted_files =
   1.350 +    &(symbols->source_file_info);
   1.351 +  SymbolMap *symbol_entries = &(symbols->symbol_entries);
   1.352 +  for (size_t i = 0; i < sorted_files->size(); ++i) {
   1.353 +    struct SourceFileInfo &source_file = (*sorted_files)[i];
   1.354 +    std::vector<struct FuncInfo> *sorted_functions = &(source_file.func_info);
   1.355 +    int func_size = sorted_functions->size();
   1.356 +
   1.357 +    for (size_t j = 0; j < func_size; ++j) {
   1.358 +      struct FuncInfo &func_info = (*sorted_functions)[j];
   1.359 +      int line_count = func_info.line_info.size();
   1.360 +
   1.361 +      // Discard the ending part of the name.
   1.362 +      std::string func_name(func_info.name);
   1.363 +      std::string::size_type last_colon = func_name.find_first_of(':');
   1.364 +      if (last_colon != std::string::npos)
   1.365 +        func_name = func_name.substr(0, last_colon);
   1.366 +
   1.367 +      // Fine the symbol offset from the loading address and size by name.
   1.368 +      SymbolMap::const_iterator it = symbol_entries->find(func_name.c_str());
   1.369 +      if (it->second) {
   1.370 +        func_info.rva_to_base = it->second->offset;
   1.371 +        func_info.size = (line_count == 0) ? 0 : it->second->size;
   1.372 +      } else {
   1.373 +        func_info.rva_to_base = 0;
   1.374 +        func_info.size = 0;
   1.375 +      }
   1.376 +
   1.377 +      // Compute function and line size.
   1.378 +      for (size_t k = 0; k < line_count; ++k) {
   1.379 +        struct LineInfo &line_info = func_info.line_info[k];
   1.380 +
   1.381 +        line_info.rva_to_base = line_info.rva_to_func + func_info.rva_to_base;
   1.382 +        if (k == line_count - 1) {
   1.383 +          line_info.size = func_info.size - line_info.rva_to_func;
   1.384 +        } else {
   1.385 +          struct LineInfo &next_line = func_info.line_info[k + 1];
   1.386 +          line_info.size = next_line.rva_to_func - line_info.rva_to_func;
   1.387 +        }
   1.388 +      }  // for each line.
   1.389 +    }  // for each function.
   1.390 +  }  // for each source file.
   1.391 +  for (SymbolMap::iterator it = symbol_entries->begin();
   1.392 +       it != symbol_entries->end(); ++it) {
   1.393 +    free(it->second);
   1.394 +  }
   1.395 +  return true;
   1.396 +}
   1.397 +
   1.398 +bool LoadAllSymbols(const GElf_Shdr *stab_section,
   1.399 +                    const GElf_Shdr *stabstr_section,
   1.400 +                    GElf_Word base,
   1.401 +                    struct SymbolInfo *symbols) {
   1.402 +  if (stab_section == NULL || stabstr_section == NULL)
   1.403 +    return false;
   1.404 +
   1.405 +  char *stabstr = 
   1.406 +    reinterpret_cast<char *>(stabstr_section->sh_offset + base);
   1.407 +  struct slist *lists =
   1.408 +    reinterpret_cast<struct slist *>(stab_section->sh_offset + base);
   1.409 +  int nstab = stab_section->sh_size / sizeof(struct slist);
   1.410 +  int source_id = 0;
   1.411 +
   1.412 +  // First pass, load all symbols from the object file.
   1.413 +  for (int i = 0; i < nstab; ) {
   1.414 +    int step = 1;
   1.415 +    struct slist *cur_list = lists + i;
   1.416 +    if (cur_list->n_type == N_SO) {
   1.417 +      // FUNC <address> <size> <param_stack_size> <function>
   1.418 +      struct SourceFileInfo source_file_info;
   1.419 +      source_file_info.name = stabstr + cur_list->n_strx + stringOffset;
   1.420 +      // The n_value field is always 0 from stab generated by Sun CC.
   1.421 +      // TODO(Alfred): Find the correct value.
   1.422 +      source_file_info.addr = cur_list->n_value;
   1.423 +      if (strchr(source_file_info.name, '.'))
   1.424 +        source_file_info.source_id = source_id++;
   1.425 +      else
   1.426 +        source_file_info.source_id = -1;
   1.427 +      step = LoadFuncSymbols(cur_list, lists + nstab - 1, stabstr,
   1.428 +                             base, &source_file_info);
   1.429 +      symbols->source_file_info.push_back(source_file_info);
   1.430 +    }
   1.431 +    i += step;
   1.432 +  }
   1.433 +  // Second pass, compute the size of functions and lines.
   1.434 +  return ComputeSizeAndRVA(symbols);
   1.435 +}
   1.436 +
   1.437 +bool LoadSymbols(Elf *elf, GElf_Ehdr *elf_header, struct SymbolInfo *symbols,
   1.438 +                 void *obj_base) {
   1.439 +  GElf_Word base = reinterpret_cast<GElf_Word>(obj_base);
   1.440 +
   1.441 +  const GElf_Shdr *sections =
   1.442 +    reinterpret_cast<GElf_Shdr *>(elf_header->e_shoff + base);
   1.443 +  GElf_Shdr stab_section;
   1.444 +  if (!FindSectionByName(elf, kStabName, elf_header->e_shstrndx,
   1.445 +                         &stab_section)) {
   1.446 +    fprintf(stderr, "Stab section not found.\n");
   1.447 +    return false;
   1.448 +  }
   1.449 +  GElf_Shdr stabstr_section;
   1.450 +  if (!FindSectionByName(elf, kStabStrName, elf_header->e_shstrndx,
   1.451 +                         &stabstr_section)) {
   1.452 +    fprintf(stderr, "Stabstr section not found.\n");
   1.453 +    return false;
   1.454 +  }
   1.455 +  GElf_Shdr symtab_section;
   1.456 +  if (!FindSectionByName(elf, kSymtabName, elf_header->e_shstrndx,
   1.457 +                         &symtab_section)) {
   1.458 +    fprintf(stderr, "Symtab section not found.\n");
   1.459 +    return false;
   1.460 +  }
   1.461 +  GElf_Shdr strtab_section;
   1.462 +  if (!FindSectionByName(elf, kStrtabName, elf_header->e_shstrndx,
   1.463 +                         &strtab_section)) {
   1.464 +    fprintf(stderr, "Strtab section not found.\n");
   1.465 +    return false;
   1.466 +  }
   1.467 +
   1.468 +  Elf_Sym *symbol = (Elf_Sym *)((char *)base + symtab_section.sh_offset);
   1.469 +  for (int i = 0; i < symtab_section.sh_size/symtab_section.sh_entsize; ++i) {
   1.470 +    struct SymbolEntry *symbol_entry =
   1.471 +        (struct SymbolEntry *)malloc(sizeof(struct SymbolEntry));
   1.472 +    const char *name = reinterpret_cast<char *>(
   1.473 +        strtab_section.sh_offset + (GElf_Word)base + symbol->st_name);
   1.474 +    symbol_entry->offset = symbol->st_value;
   1.475 +    symbol_entry->size = symbol->st_size;
   1.476 +    symbols->symbol_entries.insert(make_pair(name, symbol_entry));
   1.477 +    ++symbol;
   1.478 +  }
   1.479 +
   1.480 +
   1.481 +  // Load symbols.
   1.482 +  return LoadAllSymbols(&stab_section, &stabstr_section, base, symbols);
   1.483 +}
   1.484 +
   1.485 +bool WriteModuleInfo(int fd, GElf_Half arch, const std::string &obj_file) {
   1.486 +  const char *arch_name = NULL;
   1.487 +  if (arch == EM_386)
   1.488 +    arch_name = "x86";
   1.489 +  else if (arch == EM_X86_64)
   1.490 +    arch_name = "x86_64";
   1.491 +  else if (arch == EM_SPARC32PLUS)
   1.492 +    arch_name = "SPARC_32+";
   1.493 +  else {
   1.494 +    printf("Please add more ARCH support\n");
   1.495 +    return false;
   1.496 +  }
   1.497 +
   1.498 +  unsigned char identifier[16];
   1.499 +  google_breakpad::FileID file_id(obj_file.c_str());
   1.500 +  if (file_id.ElfFileIdentifier(identifier)) {
   1.501 +    char identifier_str[40];
   1.502 +    file_id.ConvertIdentifierToString(identifier,
   1.503 +                                      identifier_str, sizeof(identifier_str));
   1.504 +    std::string filename = obj_file;
   1.505 +    size_t slash_pos = obj_file.find_last_of("/");
   1.506 +    if (slash_pos != std::string::npos)
   1.507 +      filename = obj_file.substr(slash_pos + 1);
   1.508 +    return WriteFormat(fd, "MODULE solaris %s %s %s\n", arch_name,
   1.509 +                       identifier_str, filename.c_str());
   1.510 +  }
   1.511 +  return false;
   1.512 +}
   1.513 +
   1.514 +bool WriteSourceFileInfo(int fd, const struct SymbolInfo &symbols) {
   1.515 +  for (size_t i = 0; i < symbols.source_file_info.size(); ++i) {
   1.516 +    if (symbols.source_file_info[i].source_id != -1) {
   1.517 +      const char *name = symbols.source_file_info[i].name;
   1.518 +      if (!WriteFormat(fd, "FILE %d %s\n",
   1.519 +                       symbols.source_file_info[i].source_id, name))
   1.520 +        return false;
   1.521 +    }
   1.522 +  }
   1.523 +  return true;
   1.524 +}
   1.525 +
   1.526 +bool WriteOneFunction(int fd, int source_id,
   1.527 +                      const struct FuncInfo &func_info){
   1.528 +  // Discard the ending part of the name.
   1.529 +  std::string func_name(func_info.name);
   1.530 +  std::string::size_type last_colon = func_name.find_last_of(':');
   1.531 +  if (last_colon != std::string::npos)
   1.532 +    func_name = func_name.substr(0, last_colon);
   1.533 +  func_name = Demangle(func_name.c_str());
   1.534 +
   1.535 +  if (func_info.size <= 0)
   1.536 +    return true;
   1.537 +
   1.538 +  // rva_to_base could be unsigned long(32 bit) or unsigned long long(64 bit).
   1.539 +  if (WriteFormat(fd, "FUNC %llx %x %d %s\n",
   1.540 +                  (long long)func_info.rva_to_base,
   1.541 +                  func_info.size,
   1.542 +                  func_info.stack_param_size,
   1.543 +                  func_name.c_str())) {
   1.544 +    for (size_t i = 0; i < func_info.line_info.size(); ++i) {
   1.545 +      const struct LineInfo &line_info = func_info.line_info[i];
   1.546 +      if (line_info.line_num == 0)
   1.547 +        return true;
   1.548 +      if (!WriteFormat(fd, "%llx %x %d %d\n",
   1.549 +                       (long long)line_info.rva_to_base,
   1.550 +                       line_info.size,
   1.551 +                       line_info.line_num,
   1.552 +                       source_id))
   1.553 +        return false;
   1.554 +    }
   1.555 +    return true;
   1.556 +  }
   1.557 +  return false;
   1.558 +}
   1.559 +
   1.560 +bool WriteFunctionInfo(int fd, const struct SymbolInfo &symbols) {
   1.561 +  for (size_t i = 0; i < symbols.source_file_info.size(); ++i) {
   1.562 +    const struct SourceFileInfo &file_info = symbols.source_file_info[i];
   1.563 +    for (size_t j = 0; j < file_info.func_info.size(); ++j) {
   1.564 +      const struct FuncInfo &func_info = file_info.func_info[j];
   1.565 +      if (!WriteOneFunction(fd, file_info.source_id, func_info))
   1.566 +        return false;
   1.567 +    }
   1.568 +  }
   1.569 +  return true;
   1.570 +}
   1.571 +
   1.572 +bool DumpStabSymbols(int fd, const struct SymbolInfo &symbols) {
   1.573 +  return WriteSourceFileInfo(fd, symbols) &&
   1.574 +    WriteFunctionInfo(fd, symbols);
   1.575 +}
   1.576 +
   1.577 +//
   1.578 +// FDWrapper
   1.579 +//
   1.580 +// Wrapper class to make sure opened file is closed.
   1.581 +//
   1.582 +class FDWrapper {
   1.583 + public:
   1.584 +  explicit FDWrapper(int fd) :
   1.585 +    fd_(fd) {
   1.586 +    }
   1.587 +  ~FDWrapper() {
   1.588 +    if (fd_ != -1)
   1.589 +      close(fd_);
   1.590 +  }
   1.591 +  int get() {
   1.592 +    return fd_;
   1.593 +  }
   1.594 +  int release() {
   1.595 +    int fd = fd_;
   1.596 +    fd_ = -1;
   1.597 +    return fd;
   1.598 +  }
   1.599 + private:
   1.600 +  int fd_;
   1.601 +};
   1.602 +
   1.603 +//
   1.604 +// MmapWrapper
   1.605 +//
   1.606 +// Wrapper class to make sure mapped regions are unmapped.
   1.607 +//
   1.608 +class MmapWrapper {
   1.609 + public:
   1.610 +  MmapWrapper(void *mapped_address, size_t mapped_size) :
   1.611 +    base_(mapped_address), size_(mapped_size) {
   1.612 +  }
   1.613 +  ~MmapWrapper() {
   1.614 +    if (base_ != NULL) {
   1.615 +      assert(size_ > 0);
   1.616 +      munmap((char *)base_, size_);
   1.617 +    }
   1.618 +  }
   1.619 +  void release() {
   1.620 +    base_ = NULL;
   1.621 +    size_ = 0;
   1.622 +  }
   1.623 +
   1.624 + private:
   1.625 +  void *base_;
   1.626 +  size_t size_;
   1.627 +};
   1.628 +
   1.629 +}  // namespace
   1.630 +
   1.631 +namespace google_breakpad {
   1.632 +
   1.633 +class AutoElfEnder {
   1.634 + public:
   1.635 +  AutoElfEnder(Elf *elf) : elf_(elf) {}
   1.636 +  ~AutoElfEnder() { if (elf_) elf_end(elf_); }
   1.637 + private:
   1.638 +  Elf *elf_;
   1.639 +};
   1.640 +
   1.641 +
   1.642 +bool DumpSymbols::WriteSymbolFile(const std::string &obj_file, int sym_fd) {
   1.643 +  if (elf_version(EV_CURRENT) == EV_NONE) {
   1.644 +    fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0));
   1.645 +    return false;
   1.646 +  }
   1.647 +
   1.648 +  int obj_fd = open(obj_file.c_str(), O_RDONLY);
   1.649 +  if (obj_fd < 0)
   1.650 +    return false;
   1.651 +  FDWrapper obj_fd_wrapper(obj_fd);
   1.652 +  struct stat st;
   1.653 +  if (fstat(obj_fd, &st) != 0 && st.st_size <= 0)
   1.654 +    return false;
   1.655 +  void *obj_base = mmap(NULL, st.st_size,
   1.656 +                        PROT_READ, MAP_PRIVATE, obj_fd, 0);
   1.657 +  if (obj_base == MAP_FAILED)
   1.658 +    return false;
   1.659 +  MmapWrapper map_wrapper(obj_base, st.st_size);
   1.660 +  GElf_Ehdr elf_header;
   1.661 +  Elf *elf = elf_begin(obj_fd, ELF_C_READ, NULL);
   1.662 +  AutoElfEnder elfEnder(elf);
   1.663 +
   1.664 +  if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr *)NULL) {
   1.665 +    fprintf(stderr, "failed to read elf header: %s\n", elf_errmsg(-1));
   1.666 +    return false;
   1.667 +  }
   1.668 +
   1.669 +  if (!IsValidElf(&elf_header)) {
   1.670 +    fprintf(stderr, "header magic doesn't match\n");
   1.671 +    return false;
   1.672 +  }
   1.673 +  struct SymbolInfo symbols;
   1.674 +  if (!LoadSymbols(elf, &elf_header, &symbols, obj_base))
   1.675 +    return false;
   1.676 +  // Write to symbol file.
   1.677 +  if (WriteModuleInfo(sym_fd, elf_header.e_machine, obj_file) &&
   1.678 +      DumpStabSymbols(sym_fd, symbols))
   1.679 +    return true;
   1.680 +
   1.681 +  return false;
   1.682 +}
   1.683 +
   1.684 +}  // namespace google_breakpad

mercurial