183e085b7a331c96237cf8e814f97b3ef4c36a70fjimblandy// Copyright (c) 2010 Google Inc.
268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// All rights reserved.
368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai//
468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// Redistribution and use in source and binary forms, with or without
568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// modification, are permitted provided that the following conditions are
668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// met:
768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai//
868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai//     * Redistributions of source code must retain the above copyright
968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// notice, this list of conditions and the following disclaimer.
1068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai//     * Redistributions in binary form must reproduce the above
1168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// copyright notice, this list of conditions and the following disclaimer
1268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// in the documentation and/or other materials provided with the
1368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// distribution.
1468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai//     * Neither the name of Google Inc. nor the names of its
1568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// contributors may be used to endorse or promote products derived from
1668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// this software without specific prior written permission.
1768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai//
1868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
3068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// Author: Alfred Peng
3168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
3268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai#include <demangle.h>
3368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai#include <fcntl.h>
3468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai#include <gelf.h>
3568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai#include <link.h>
3668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai#include <sys/mman.h>
3768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai#include <stab.h>
3868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai#include <sys/stat.h>
3968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai#include <sys/types.h>
4068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai#include <unistd.h>
4168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
4268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai#include <functional>
43dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek#include <map>
4468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai#include <vector>
4568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
462cc15ba4327831f917ff55b87e6d5fc3c7750085ted.mielczarek@gmail.com#include "common/scoped_ptr.h"
4768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai#include "common/solaris/dump_symbols.h"
4868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai#include "common/solaris/file_id.h"
4968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai#include "common/solaris/guid_creator.h"
5068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
5168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// This namespace contains helper functions.
5268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovainamespace {
5368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
54dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarekusing std::make_pair;
55dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
56dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek#if defined(_LP64)
57dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarektypedef Elf64_Sym   Elf_Sym;
58dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek#else
59dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarektypedef Elf32_Sym   Elf_Sym;
60dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek#endif
61dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
62dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek// Symbol table entry from stabs. Sun CC specific.
6368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaistruct slist {
6468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // String table index.
6568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  unsigned int n_strx;
6668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Stab type.
6768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  unsigned char n_type;
6868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  char n_other;
6968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  short n_desc;
7068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  unsigned long n_value;
7168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai};
7268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
73dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek// Symbol table entry
74dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarekstruct SymbolEntry {
75dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  // Offset from the start of the file.
76dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  GElf_Addr offset;
77dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  // Function size.
78dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  GElf_Word size;
79dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek};
80dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
8168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// Infomation of a line.
8268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaistruct LineInfo {
8368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Offset from start of the function.
8468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Load from stab symbol.
8568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  GElf_Off rva_to_func;
8668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Offset from base of the loading binary.
8768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  GElf_Off rva_to_base;
8868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Size of the line.
8968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // The first line: equals to rva_to_func.
9068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // The other lines: the difference of rva_to_func of the line and
9168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // rva_to_func of the previous N_SLINE.
9268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  uint32_t size;
9368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Line number.
9468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  uint32_t line_num;
9568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai};
9668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
9768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// Information of a function.
9868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaistruct FuncInfo {
9968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Name of the function.
10068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  const char *name;
10168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Offset from the base of the loading address.
10268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  GElf_Off rva_to_base;
10368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Virtual address of the function.
10468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Load from stab symbol.
10568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  GElf_Addr addr;
10668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Size of the function.
10768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Equal to rva_to_func of the last function line.
10868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  uint32_t size;
10968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Total size of stack parameters.
11068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  uint32_t stack_param_size;
11168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Line information array.
11268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  std::vector<struct LineInfo> line_info;
11368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai};
11468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
11568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// Information of a source file.
11668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaistruct SourceFileInfo {
11768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Name of the source file.
11868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  const char *name;
11968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Starting address of the source file.
12068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  GElf_Addr addr;
12168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Id of the source file.
12268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  int source_id;
12368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Functions information.
12468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  std::vector<struct FuncInfo> func_info;
12568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai};
12668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
127dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarekstruct CompareString {
128dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  bool operator()(const char *s1, const char *s2) const {
129dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    return strcmp(s1, s2) < 0;
130dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  }
131dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek};
132dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
133dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarektypedef std::map<const char *, struct SymbolEntry *, CompareString> SymbolMap;
134dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
13568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// Information of a symbol table.
13668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// This is the root of all types of symbol.
13768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaistruct SymbolInfo {
13868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  std::vector<struct SourceFileInfo> source_file_info;
139dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  // Symbols information.
140dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  SymbolMap symbol_entries;
14168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai};
14268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
14368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// Stab section name.
14468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaiconst char *kStabName = ".stab";
14568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
14668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// Stab str section name.
14768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaiconst char *kStabStrName = ".stabstr";
14868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
149dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek// Symtab section name.
150dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarekconst char *kSymtabName = ".symtab";
151dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
152dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek// Strtab section name.
153dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarekconst char *kStrtabName = ".strtab";
154dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
15568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// Default buffer lenght for demangle.
156dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarekconst int demangleLen = 20000;
157dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
158dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek// Offset to the string table.
1596162aed3c3fcfc53373c963ac375d39a5dfa5a25ted.mielczarek@gmail.comuint64_t stringOffset = 0;
160dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
161dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek// Update the offset to the start of the string index of the next
162dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek// object module for every N_ENDM stabs.
163dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarekinline void RecalculateOffset(struct slist* cur_list, char *stabstr) {
164dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  while ((--cur_list)->n_strx == 0) ;
165dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  stringOffset += cur_list->n_strx;
166dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
167dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  char *temp = stabstr + stringOffset;
168dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  while (*temp != '\0') {
169dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    ++stringOffset;
170dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    ++temp;
171dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  }
172dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  // Skip the extra '\0'
173dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  ++stringOffset;
174dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek}
17568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
17668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// Demangle using demangle library on Solaris.
17768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaistd::string Demangle(const char *mangled) {
17868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  int status = 0;
1794af5fe0b593f5d79aee8c54f6bc1542b1deed87enealsid  std::string str(mangled);
18068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  char *demangled = (char *)malloc(demangleLen);
1814af5fe0b593f5d79aee8c54f6bc1542b1deed87enealsid
18268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  if (!demangled) {
18368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    fprintf(stderr, "no enough memory.\n");
18468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    goto out;
18568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
18668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
18768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  if ((status = cplus_demangle(mangled, demangled, demangleLen)) ==
18868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      DEMANGLE_ESPACE) {
18968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    fprintf(stderr, "incorrect demangle.\n");
19068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    goto out;
19168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
19268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
1934af5fe0b593f5d79aee8c54f6bc1542b1deed87enealsid  str = demangled;
19468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  free(demangled);
19568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
19668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaiout:
1974af5fe0b593f5d79aee8c54f6bc1542b1deed87enealsid  return str;
19868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}
19968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
20068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaibool WriteFormat(int fd, const char *fmt, ...) {
20168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  va_list list;
20268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  char buffer[4096];
20368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  ssize_t expected, written;
20468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  va_start(list, fmt);
20568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  vsnprintf(buffer, sizeof(buffer), fmt, list);
20668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  expected = strlen(buffer);
20768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  written = write(fd, buffer, strlen(buffer));
20868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  va_end(list);
20968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  return expected == written;
21068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}
21168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
21268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaibool IsValidElf(const GElf_Ehdr *elf_header) {
21368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  return memcmp(elf_header, ELFMAG, SELFMAG) == 0;
21468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}
21568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
21668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaistatic bool FindSectionByName(Elf *elf, const char *name,
21768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                              int shstrndx,
21868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                              GElf_Shdr *shdr) {
21968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  assert(name != NULL);
22068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
22168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  if (strlen(name) == 0)
22268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return false;
22368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
22468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  Elf_Scn *scn = NULL;
22568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
22668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  while ((scn = elf_nextscn(elf, scn)) != NULL) {
22768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    if (gelf_getshdr(scn, shdr) == (GElf_Shdr *)0) {
22868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      fprintf(stderr, "failed to read section header: %s\n", elf_errmsg(0));
22968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      return false;
23068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    }
23168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
23268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    const char *section_name = elf_strptr(elf, shstrndx, shdr->sh_name);
23368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    if (!section_name) {
23468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      fprintf(stderr, "Section name error: %s\n", elf_errmsg(-1));
23568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      continue;
23668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    }
23768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
23868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    if (strcmp(section_name, name) == 0)
23968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      return true;
24068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
24168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
24268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  return false;
24368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}
24468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
24568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// The parameter size is used for FPO-optimized code, and
24668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// this is all tied up with the debugging data for Windows x86.
24768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// Set it to 0 on Solaris.
24868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaiint LoadStackParamSize(struct slist *list,
24968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                       struct slist *list_end,
25068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                       struct FuncInfo *func_info) {
25168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  struct slist *cur_list = list;
25268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  int step = 1;
25368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  while (cur_list < list_end && cur_list->n_type == N_PSYM) {
25468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    ++cur_list;
25568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    ++step;
25668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
25768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
25868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  func_info->stack_param_size = 0;
25968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  return step;
26068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}
26168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
26268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaiint LoadLineInfo(struct slist *list,
26368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                 struct slist *list_end,
26468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                 struct FuncInfo *func_info) {
26568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  struct slist *cur_list = list;
26668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  do {
26768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    // Skip non line information.
26868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    while (cur_list < list_end && cur_list->n_type != N_SLINE) {
269dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      // Only exit when got another function, or source file, or end stab.
270dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      if (cur_list->n_type == N_FUN || cur_list->n_type == N_SO ||
271dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek          cur_list->n_type == N_ENDM) {
27268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai        return cur_list - list;
273dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      }
27468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      ++cur_list;
27568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    }
27668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    struct LineInfo line;
27768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    while (cur_list < list_end && cur_list->n_type == N_SLINE) {
27868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      line.rva_to_func = cur_list->n_value;
27968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      // n_desc is a signed short
28068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      line.line_num = (unsigned short)cur_list->n_desc;
28168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      func_info->line_info.push_back(line);
28268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      ++cur_list;
28368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    }
28468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    if (cur_list == list_end && cur_list->n_type == N_ENDM)
28568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      break;
28668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  } while (list < list_end);
28768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
28868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  return cur_list - list;
28968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}
29068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
29168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaiint LoadFuncSymbols(struct slist *list,
29268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                    struct slist *list_end,
293dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek                    char *stabstr,
29468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                    GElf_Word base,
29568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                    struct SourceFileInfo *source_file_info) {
29668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  struct slist *cur_list = list;
29768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  assert(cur_list->n_type == N_SO);
29868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  ++cur_list;
29968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
30068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  source_file_info->func_info.clear();
30168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  while (cur_list < list_end) {
30268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    // Go until the function symbol.
30368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    while (cur_list < list_end && cur_list->n_type != N_FUN) {
30468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      if (cur_list->n_type == N_SO) {
30568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai        return cur_list - list;
30668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      }
30768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      ++cur_list;
308dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      if (cur_list->n_type == N_ENDM)
309dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek        RecalculateOffset(cur_list, stabstr);
31068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      continue;
31168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    }
31268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    while (cur_list->n_type == N_FUN) {
31368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      struct FuncInfo func_info;
31468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      memset(&func_info, 0, sizeof(func_info));
315dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      func_info.name = stabstr + cur_list->n_strx + stringOffset;
31668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      // The n_value field is always 0 from stab generated by Sun CC.
31768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      // TODO(Alfred): Find the correct value.
31868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      func_info.addr = cur_list->n_value;
31968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      ++cur_list;
320dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      if (cur_list->n_type == N_ENDM)
321dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek        RecalculateOffset(cur_list, stabstr);
32268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      if (cur_list->n_type != N_ESYM && cur_list->n_type != N_ISYM &&
32368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai          cur_list->n_type != N_FUN) {
32468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai        // Stack parameter size.
32568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai        cur_list += LoadStackParamSize(cur_list, list_end, &func_info);
32668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai        // Line info.
32768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai        cur_list += LoadLineInfo(cur_list, list_end, &func_info);
32868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      }
329dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      if (cur_list < list_end && cur_list->n_type == N_ENDM)
330dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek        RecalculateOffset(cur_list, stabstr);
33168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      // Functions in this module should have address bigger than the module
33268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      // starting address.
33368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      //
33468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      // These two values are always 0 with Sun CC.
33568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      // TODO(Alfred): Get the correct value or remove the condition statement.
33668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      if (func_info.addr >= source_file_info->addr) {
33768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai        source_file_info->func_info.push_back(func_info);
33868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      }
33968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    }
34068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
34168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  return cur_list - list;
34268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}
34368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
34468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// Compute size and rva information based on symbols loaded from stab section.
345dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarekbool ComputeSizeAndRVA(struct SymbolInfo *symbols) {
34668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  std::vector<struct SourceFileInfo> *sorted_files =
34768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    &(symbols->source_file_info);
348dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  SymbolMap *symbol_entries = &(symbols->symbol_entries);
34968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  for (size_t i = 0; i < sorted_files->size(); ++i) {
35068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    struct SourceFileInfo &source_file = (*sorted_files)[i];
35168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    std::vector<struct FuncInfo> *sorted_functions = &(source_file.func_info);
352dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    int func_size = sorted_functions->size();
353dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
354dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    for (size_t j = 0; j < func_size; ++j) {
35568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      struct FuncInfo &func_info = (*sorted_functions)[j];
35668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      int line_count = func_info.line_info.size();
357dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
358dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      // Discard the ending part of the name.
359dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      std::string func_name(func_info.name);
360dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      std::string::size_type last_colon = func_name.find_first_of(':');
361dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      if (last_colon != std::string::npos)
362dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek        func_name = func_name.substr(0, last_colon);
363dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
364dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      // Fine the symbol offset from the loading address and size by name.
365dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      SymbolMap::const_iterator it = symbol_entries->find(func_name.c_str());
366dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      if (it->second) {
367dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek        func_info.rva_to_base = it->second->offset;
368dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek        func_info.size = (line_count == 0) ? 0 : it->second->size;
369dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      } else {
370dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek        func_info.rva_to_base = 0;
371dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek        func_info.size = 0;
372dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      }
373dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
37468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      // Compute function and line size.
37568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      for (size_t k = 0; k < line_count; ++k) {
37668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai        struct LineInfo &line_info = func_info.line_info[k];
377dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
378dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek        line_info.rva_to_base = line_info.rva_to_func + func_info.rva_to_base;
379dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek        if (k == line_count - 1) {
380dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek          line_info.size = func_info.size - line_info.rva_to_func;
38168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai        } else {
382dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek          struct LineInfo &next_line = func_info.line_info[k + 1];
383dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek          line_info.size = next_line.rva_to_func - line_info.rva_to_func;
38468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai        }
38568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      }  // for each line.
38668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    }  // for each function.
38768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }  // for each source file.
388dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  for (SymbolMap::iterator it = symbol_entries->begin();
389dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek       it != symbol_entries->end(); ++it) {
390dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    free(it->second);
391dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  }
39268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  return true;
39368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}
39468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
39568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaibool LoadAllSymbols(const GElf_Shdr *stab_section,
39668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                    const GElf_Shdr *stabstr_section,
39768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                    GElf_Word base,
39868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                    struct SymbolInfo *symbols) {
39968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  if (stab_section == NULL || stabstr_section == NULL)
40068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return false;
40168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
402dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  char *stabstr =
403dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    reinterpret_cast<char *>(stabstr_section->sh_offset + base);
40468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  struct slist *lists =
40568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    reinterpret_cast<struct slist *>(stab_section->sh_offset + base);
40668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  int nstab = stab_section->sh_size / sizeof(struct slist);
40768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  int source_id = 0;
408dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
40968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // First pass, load all symbols from the object file.
41068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  for (int i = 0; i < nstab; ) {
41168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    int step = 1;
41268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    struct slist *cur_list = lists + i;
41368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    if (cur_list->n_type == N_SO) {
41468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      // FUNC <address> <size> <param_stack_size> <function>
41568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      struct SourceFileInfo source_file_info;
416dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      source_file_info.name = stabstr + cur_list->n_strx + stringOffset;
41768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      // The n_value field is always 0 from stab generated by Sun CC.
41868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      // TODO(Alfred): Find the correct value.
41968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      source_file_info.addr = cur_list->n_value;
42068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      if (strchr(source_file_info.name, '.'))
42168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai        source_file_info.source_id = source_id++;
42268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      else
42368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai        source_file_info.source_id = -1;
424dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      step = LoadFuncSymbols(cur_list, lists + nstab - 1, stabstr,
425dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek                             base, &source_file_info);
42668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      symbols->source_file_info.push_back(source_file_info);
42768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    }
42868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    i += step;
42968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
43068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Second pass, compute the size of functions and lines.
431dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  return ComputeSizeAndRVA(symbols);
43268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}
43368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
43468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaibool LoadSymbols(Elf *elf, GElf_Ehdr *elf_header, struct SymbolInfo *symbols,
43568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                 void *obj_base) {
43668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  GElf_Word base = reinterpret_cast<GElf_Word>(obj_base);
43768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
43868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  const GElf_Shdr *sections =
43968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    reinterpret_cast<GElf_Shdr *>(elf_header->e_shoff + base);
44068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  GElf_Shdr stab_section;
44168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  if (!FindSectionByName(elf, kStabName, elf_header->e_shstrndx,
44268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                         &stab_section)) {
44368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    fprintf(stderr, "Stab section not found.\n");
44468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return false;
44568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
44668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  GElf_Shdr stabstr_section;
44768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  if (!FindSectionByName(elf, kStabStrName, elf_header->e_shstrndx,
44868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                         &stabstr_section)) {
44968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    fprintf(stderr, "Stabstr section not found.\n");
45068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return false;
45168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
452dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  GElf_Shdr symtab_section;
453dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  if (!FindSectionByName(elf, kSymtabName, elf_header->e_shstrndx,
454dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek                         &symtab_section)) {
455dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    fprintf(stderr, "Symtab section not found.\n");
456dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    return false;
457dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  }
458dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  GElf_Shdr strtab_section;
459dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  if (!FindSectionByName(elf, kStrtabName, elf_header->e_shstrndx,
460dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek                         &strtab_section)) {
461dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    fprintf(stderr, "Strtab section not found.\n");
462dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    return false;
463dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  }
464dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
465dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  Elf_Sym *symbol = (Elf_Sym *)((char *)base + symtab_section.sh_offset);
466dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  for (int i = 0; i < symtab_section.sh_size/symtab_section.sh_entsize; ++i) {
467dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    struct SymbolEntry *symbol_entry =
468dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek        (struct SymbolEntry *)malloc(sizeof(struct SymbolEntry));
469dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    const char *name = reinterpret_cast<char *>(
470dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek        strtab_section.sh_offset + (GElf_Word)base + symbol->st_name);
471dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    symbol_entry->offset = symbol->st_value;
472dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    symbol_entry->size = symbol->st_size;
473dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    symbols->symbol_entries.insert(make_pair(name, symbol_entry));
474dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    ++symbol;
475dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  }
476dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek
47768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
47868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Load symbols.
479dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  return LoadAllSymbols(&stab_section, &stabstr_section, base, symbols);
48068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}
48168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
48268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaibool WriteModuleInfo(int fd, GElf_Half arch, const std::string &obj_file) {
48368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  const char *arch_name = NULL;
48468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  if (arch == EM_386)
48568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    arch_name = "x86";
48668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  else if (arch == EM_X86_64)
48768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    arch_name = "x86_64";
488dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  else if (arch == EM_SPARC32PLUS)
489dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    arch_name = "SPARC_32+";
490dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  else {
491dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek    printf("Please add more ARCH support\n");
49268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return false;
493dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  }
49468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
49568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  unsigned char identifier[16];
49668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  google_breakpad::FileID file_id(obj_file.c_str());
49768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  if (file_id.ElfFileIdentifier(identifier)) {
49868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    char identifier_str[40];
49968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    file_id.ConvertIdentifierToString(identifier,
50068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                                      identifier_str, sizeof(identifier_str));
50168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    std::string filename = obj_file;
50268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    size_t slash_pos = obj_file.find_last_of("/");
50368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    if (slash_pos != std::string::npos)
50468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      filename = obj_file.substr(slash_pos + 1);
50568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return WriteFormat(fd, "MODULE solaris %s %s %s\n", arch_name,
50668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                       identifier_str, filename.c_str());
50768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
50868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  return false;
50968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}
51068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
51168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaibool WriteSourceFileInfo(int fd, const struct SymbolInfo &symbols) {
51268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  for (size_t i = 0; i < symbols.source_file_info.size(); ++i) {
51368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    if (symbols.source_file_info[i].source_id != -1) {
51468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      const char *name = symbols.source_file_info[i].name;
51568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      if (!WriteFormat(fd, "FILE %d %s\n",
51668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                       symbols.source_file_info[i].source_id, name))
51768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai        return false;
51868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    }
51968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
52068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  return true;
52168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}
52268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
52368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaibool WriteOneFunction(int fd, int source_id,
52468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                      const struct FuncInfo &func_info){
52568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Discard the ending part of the name.
52668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  std::string func_name(func_info.name);
52768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  std::string::size_type last_colon = func_name.find_last_of(':');
52868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  if (last_colon != std::string::npos)
52968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    func_name = func_name.substr(0, last_colon);
53068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  func_name = Demangle(func_name.c_str());
53168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
532dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  if (func_info.size <= 0)
53368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return true;
53468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
53568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // rva_to_base could be unsigned long(32 bit) or unsigned long long(64 bit).
536dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek  if (WriteFormat(fd, "FUNC %llx %x %d %s\n",
53768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                  (long long)func_info.rva_to_base,
53868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                  func_info.size,
53968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                  func_info.stack_param_size,
54068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                  func_name.c_str())) {
54168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    for (size_t i = 0; i < func_info.line_info.size(); ++i) {
54268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      const struct LineInfo &line_info = func_info.line_info[i];
543dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      if (line_info.line_num == 0)
544dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek        return true;
545dd2ff4a21c57672170eb14ccc5142efd7d92f3f1ted.mielczarek      if (!WriteFormat(fd, "%llx %x %d %d\n",
54668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                       (long long)line_info.rva_to_base,
54768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                       line_info.size,
54868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                       line_info.line_num,
54968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                       source_id))
55068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai        return false;
55168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    }
55268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return true;
55368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
55468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  return false;
55568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}
55668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
55768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaibool WriteFunctionInfo(int fd, const struct SymbolInfo &symbols) {
55868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  for (size_t i = 0; i < symbols.source_file_info.size(); ++i) {
55968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    const struct SourceFileInfo &file_info = symbols.source_file_info[i];
56068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    for (size_t j = 0; j < file_info.func_info.size(); ++j) {
56168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      const struct FuncInfo &func_info = file_info.func_info[j];
56268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      if (!WriteOneFunction(fd, file_info.source_id, func_info))
56368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai        return false;
56468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    }
56568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
56668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  return true;
56768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}
56868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
56968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaibool DumpStabSymbols(int fd, const struct SymbolInfo &symbols) {
57068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  return WriteSourceFileInfo(fd, symbols) &&
57168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    WriteFunctionInfo(fd, symbols);
57268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}
57368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
57468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai//
57568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// FDWrapper
57668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai//
57768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// Wrapper class to make sure opened file is closed.
57868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai//
57968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaiclass FDWrapper {
58068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai public:
58168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  explicit FDWrapper(int fd) :
58268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    fd_(fd) {
58368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    }
58468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  ~FDWrapper() {
58568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    if (fd_ != -1)
58668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      close(fd_);
58768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
58868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  int get() {
58968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return fd_;
59068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
59168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  int release() {
59268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    int fd = fd_;
59368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    fd_ = -1;
59468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return fd;
59568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
59668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai private:
59768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  int fd_;
59868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai};
59968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
60068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai//
60168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// MmapWrapper
60268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai//
60368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai// Wrapper class to make sure mapped regions are unmapped.
60468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai//
60568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaiclass MmapWrapper {
60668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai public:
60768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  MmapWrapper(void *mapped_address, size_t mapped_size) :
60868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    base_(mapped_address), size_(mapped_size) {
60968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
61068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  ~MmapWrapper() {
61168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    if (base_ != NULL) {
61268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      assert(size_ > 0);
61368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      munmap((char *)base_, size_);
61468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    }
61568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
61668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  void release() {
61768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    base_ = NULL;
61868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    size_ = 0;
61968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
62068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
62168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai private:
62268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  void *base_;
62368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  size_t size_;
62468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai};
62568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
62668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}  // namespace
62768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
62868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovainamespace google_breakpad {
62968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
63068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaiclass AutoElfEnder {
63168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai public:
63268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  AutoElfEnder(Elf *elf) : elf_(elf) {}
63368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  ~AutoElfEnder() { if (elf_) elf_end(elf_); }
63468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai private:
63568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  Elf *elf_;
63668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai};
63768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
63868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
63968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovaibool DumpSymbols::WriteSymbolFile(const std::string &obj_file, int sym_fd) {
64068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  if (elf_version(EV_CURRENT) == EV_NONE) {
64168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    fprintf(stderr, "elf_version() failed: %s\n", elf_errmsg(0));
64268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return false;
64368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
64468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
64568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  int obj_fd = open(obj_file.c_str(), O_RDONLY);
64668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  if (obj_fd < 0)
64768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return false;
64868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  FDWrapper obj_fd_wrapper(obj_fd);
64968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  struct stat st;
65068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  if (fstat(obj_fd, &st) != 0 && st.st_size <= 0)
65168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return false;
65268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  void *obj_base = mmap(NULL, st.st_size,
65368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai                        PROT_READ, MAP_PRIVATE, obj_fd, 0);
654718478d95dad2d0e95ba7ad347e3074f99d28e3dnealsid  if (obj_base == MAP_FAILED)
65568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return false;
65668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  MmapWrapper map_wrapper(obj_base, st.st_size);
65768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  GElf_Ehdr elf_header;
65868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  Elf *elf = elf_begin(obj_fd, ELF_C_READ, NULL);
65968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  AutoElfEnder elfEnder(elf);
66068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
66168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  if (gelf_getehdr(elf, &elf_header) == (GElf_Ehdr *)NULL) {
66268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    fprintf(stderr, "failed to read elf header: %s\n", elf_errmsg(-1));
66368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return false;
66468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
66568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
66668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  if (!IsValidElf(&elf_header)) {
66768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    fprintf(stderr, "header magic doesn't match\n");
66868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return false;
66968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  }
67068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  struct SymbolInfo symbols;
67168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  if (!LoadSymbols(elf, &elf_header, &symbols, obj_base))
67268004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return false;
67368004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  // Write to symbol file.
67468004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  if (WriteModuleInfo(sym_fd, elf_header.e_machine, obj_file) &&
67568004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai      DumpStabSymbols(sym_fd, symbols))
67668004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai    return true;
67768004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
67868004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai  return false;
67968004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}
68068004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai
68168004c84d6b852cfd4096cd211d2f8d3ff1d9f48mmentovai}  // namespace google_breakpad
682