1*9712c20fSFrederick Mayle // Copyright 2011 Google LLC
2*9712c20fSFrederick Mayle //
3*9712c20fSFrederick Mayle // Redistribution and use in source and binary forms, with or without
4*9712c20fSFrederick Mayle // modification, are permitted provided that the following conditions are
5*9712c20fSFrederick Mayle // met:
6*9712c20fSFrederick Mayle //
7*9712c20fSFrederick Mayle // * Redistributions of source code must retain the above copyright
8*9712c20fSFrederick Mayle // notice, this list of conditions and the following disclaimer.
9*9712c20fSFrederick Mayle // * Redistributions in binary form must reproduce the above
10*9712c20fSFrederick Mayle // copyright notice, this list of conditions and the following disclaimer
11*9712c20fSFrederick Mayle // in the documentation and/or other materials provided with the
12*9712c20fSFrederick Mayle // distribution.
13*9712c20fSFrederick Mayle // * Neither the name of Google LLC nor the names of its
14*9712c20fSFrederick Mayle // contributors may be used to endorse or promote products derived from
15*9712c20fSFrederick Mayle // this software without specific prior written permission.
16*9712c20fSFrederick Mayle //
17*9712c20fSFrederick Mayle // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*9712c20fSFrederick Mayle // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*9712c20fSFrederick Mayle // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*9712c20fSFrederick Mayle // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*9712c20fSFrederick Mayle // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*9712c20fSFrederick Mayle // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*9712c20fSFrederick Mayle // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*9712c20fSFrederick Mayle // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*9712c20fSFrederick Mayle // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*9712c20fSFrederick Mayle // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*9712c20fSFrederick Mayle // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*9712c20fSFrederick Mayle
29*9712c20fSFrederick Mayle // Restructured in 2009 by: Jim Blandy <[email protected]> <[email protected]>
30*9712c20fSFrederick Mayle
31*9712c20fSFrederick Mayle // dump_symbols.cc: implement google_breakpad::WriteSymbolFile:
32*9712c20fSFrederick Mayle // Find all the debugging info in a file and dump it as a Breakpad symbol file.
33*9712c20fSFrederick Mayle
34*9712c20fSFrederick Mayle #ifdef HAVE_CONFIG_H
35*9712c20fSFrederick Mayle #include <config.h> // Must come first
36*9712c20fSFrederick Mayle #endif
37*9712c20fSFrederick Mayle
38*9712c20fSFrederick Mayle #include "common/linux/dump_symbols.h"
39*9712c20fSFrederick Mayle
40*9712c20fSFrederick Mayle #include <assert.h>
41*9712c20fSFrederick Mayle #include <elf.h>
42*9712c20fSFrederick Mayle #include <errno.h>
43*9712c20fSFrederick Mayle #include <fcntl.h>
44*9712c20fSFrederick Mayle #include <limits.h>
45*9712c20fSFrederick Mayle #include <link.h>
46*9712c20fSFrederick Mayle #include <stdint.h>
47*9712c20fSFrederick Mayle #include <stdio.h>
48*9712c20fSFrederick Mayle #include <stdlib.h>
49*9712c20fSFrederick Mayle #include <string.h>
50*9712c20fSFrederick Mayle #include <sys/mman.h>
51*9712c20fSFrederick Mayle #include <sys/stat.h>
52*9712c20fSFrederick Mayle #include <unistd.h>
53*9712c20fSFrederick Mayle #include <zlib.h>
54*9712c20fSFrederick Mayle #ifdef HAVE_LIBZSTD
55*9712c20fSFrederick Mayle #include <zstd.h>
56*9712c20fSFrederick Mayle #endif
57*9712c20fSFrederick Mayle
58*9712c20fSFrederick Mayle #include <set>
59*9712c20fSFrederick Mayle #include <string>
60*9712c20fSFrederick Mayle #include <utility>
61*9712c20fSFrederick Mayle #include <vector>
62*9712c20fSFrederick Mayle
63*9712c20fSFrederick Mayle #include "common/dwarf/bytereader-inl.h"
64*9712c20fSFrederick Mayle #include "common/dwarf/dwarf2diehandler.h"
65*9712c20fSFrederick Mayle #include "common/dwarf_cfi_to_module.h"
66*9712c20fSFrederick Mayle #include "common/dwarf_cu_to_module.h"
67*9712c20fSFrederick Mayle #include "common/dwarf_line_to_module.h"
68*9712c20fSFrederick Mayle #include "common/dwarf_range_list_handler.h"
69*9712c20fSFrederick Mayle #include "common/linux/crc32.h"
70*9712c20fSFrederick Mayle #include "common/linux/eintr_wrapper.h"
71*9712c20fSFrederick Mayle #include "common/linux/elfutils.h"
72*9712c20fSFrederick Mayle #include "common/linux/elfutils-inl.h"
73*9712c20fSFrederick Mayle #include "common/linux/elf_symbols_to_module.h"
74*9712c20fSFrederick Mayle #include "common/linux/file_id.h"
75*9712c20fSFrederick Mayle #include "common/memory_allocator.h"
76*9712c20fSFrederick Mayle #include "common/module.h"
77*9712c20fSFrederick Mayle #include "common/path_helper.h"
78*9712c20fSFrederick Mayle #include "common/scoped_ptr.h"
79*9712c20fSFrederick Mayle #ifndef NO_STABS_SUPPORT
80*9712c20fSFrederick Mayle #include "common/stabs_reader.h"
81*9712c20fSFrederick Mayle #include "common/stabs_to_module.h"
82*9712c20fSFrederick Mayle #endif
83*9712c20fSFrederick Mayle #include "common/using_std_string.h"
84*9712c20fSFrederick Mayle
85*9712c20fSFrederick Mayle // This namespace contains helper functions.
86*9712c20fSFrederick Mayle namespace {
87*9712c20fSFrederick Mayle
88*9712c20fSFrederick Mayle using google_breakpad::DumpOptions;
89*9712c20fSFrederick Mayle using google_breakpad::DwarfCFIToModule;
90*9712c20fSFrederick Mayle using google_breakpad::DwarfCUToModule;
91*9712c20fSFrederick Mayle using google_breakpad::DwarfLineToModule;
92*9712c20fSFrederick Mayle using google_breakpad::DwarfRangeListHandler;
93*9712c20fSFrederick Mayle using google_breakpad::ElfClass;
94*9712c20fSFrederick Mayle using google_breakpad::ElfClass32;
95*9712c20fSFrederick Mayle using google_breakpad::ElfClass64;
96*9712c20fSFrederick Mayle using google_breakpad::elf::FileID;
97*9712c20fSFrederick Mayle using google_breakpad::FindElfSectionByName;
98*9712c20fSFrederick Mayle using google_breakpad::GetOffset;
99*9712c20fSFrederick Mayle using google_breakpad::IsValidElf;
100*9712c20fSFrederick Mayle using google_breakpad::elf::kDefaultBuildIdSize;
101*9712c20fSFrederick Mayle using google_breakpad::Module;
102*9712c20fSFrederick Mayle using google_breakpad::PageAllocator;
103*9712c20fSFrederick Mayle #ifndef NO_STABS_SUPPORT
104*9712c20fSFrederick Mayle using google_breakpad::StabsToModule;
105*9712c20fSFrederick Mayle #endif
106*9712c20fSFrederick Mayle using google_breakpad::scoped_ptr;
107*9712c20fSFrederick Mayle using google_breakpad::wasteful_vector;
108*9712c20fSFrederick Mayle
109*9712c20fSFrederick Mayle // Define AARCH64 ELF architecture if host machine does not include this define.
110*9712c20fSFrederick Mayle #ifndef EM_AARCH64
111*9712c20fSFrederick Mayle #define EM_AARCH64 183
112*9712c20fSFrederick Mayle #endif
113*9712c20fSFrederick Mayle
114*9712c20fSFrederick Mayle // Define ZStd compression if host machine does not include this define.
115*9712c20fSFrederick Mayle #ifndef ELFCOMPRESS_ZSTD
116*9712c20fSFrederick Mayle #define ELFCOMPRESS_ZSTD 2
117*9712c20fSFrederick Mayle #endif
118*9712c20fSFrederick Mayle
119*9712c20fSFrederick Mayle //
120*9712c20fSFrederick Mayle // FDWrapper
121*9712c20fSFrederick Mayle //
122*9712c20fSFrederick Mayle // Wrapper class to make sure opened file is closed.
123*9712c20fSFrederick Mayle //
124*9712c20fSFrederick Mayle class FDWrapper {
125*9712c20fSFrederick Mayle public:
FDWrapper(int fd)126*9712c20fSFrederick Mayle explicit FDWrapper(int fd) :
127*9712c20fSFrederick Mayle fd_(fd) {}
~FDWrapper()128*9712c20fSFrederick Mayle ~FDWrapper() {
129*9712c20fSFrederick Mayle if (fd_ != -1)
130*9712c20fSFrederick Mayle close(fd_);
131*9712c20fSFrederick Mayle }
get()132*9712c20fSFrederick Mayle int get() {
133*9712c20fSFrederick Mayle return fd_;
134*9712c20fSFrederick Mayle }
release()135*9712c20fSFrederick Mayle int release() {
136*9712c20fSFrederick Mayle int fd = fd_;
137*9712c20fSFrederick Mayle fd_ = -1;
138*9712c20fSFrederick Mayle return fd;
139*9712c20fSFrederick Mayle }
140*9712c20fSFrederick Mayle private:
141*9712c20fSFrederick Mayle int fd_;
142*9712c20fSFrederick Mayle };
143*9712c20fSFrederick Mayle
144*9712c20fSFrederick Mayle //
145*9712c20fSFrederick Mayle // MmapWrapper
146*9712c20fSFrederick Mayle //
147*9712c20fSFrederick Mayle // Wrapper class to make sure mapped regions are unmapped.
148*9712c20fSFrederick Mayle //
149*9712c20fSFrederick Mayle class MmapWrapper {
150*9712c20fSFrederick Mayle public:
MmapWrapper()151*9712c20fSFrederick Mayle MmapWrapper() : is_set_(false) {}
~MmapWrapper()152*9712c20fSFrederick Mayle ~MmapWrapper() {
153*9712c20fSFrederick Mayle if (is_set_ && base_ != NULL) {
154*9712c20fSFrederick Mayle assert(size_ > 0);
155*9712c20fSFrederick Mayle munmap(base_, size_);
156*9712c20fSFrederick Mayle }
157*9712c20fSFrederick Mayle }
set(void * mapped_address,size_t mapped_size)158*9712c20fSFrederick Mayle void set(void* mapped_address, size_t mapped_size) {
159*9712c20fSFrederick Mayle is_set_ = true;
160*9712c20fSFrederick Mayle base_ = mapped_address;
161*9712c20fSFrederick Mayle size_ = mapped_size;
162*9712c20fSFrederick Mayle }
release()163*9712c20fSFrederick Mayle void release() {
164*9712c20fSFrederick Mayle assert(is_set_);
165*9712c20fSFrederick Mayle is_set_ = false;
166*9712c20fSFrederick Mayle base_ = NULL;
167*9712c20fSFrederick Mayle size_ = 0;
168*9712c20fSFrederick Mayle }
169*9712c20fSFrederick Mayle
170*9712c20fSFrederick Mayle private:
171*9712c20fSFrederick Mayle bool is_set_;
172*9712c20fSFrederick Mayle void* base_;
173*9712c20fSFrederick Mayle size_t size_;
174*9712c20fSFrederick Mayle };
175*9712c20fSFrederick Mayle
176*9712c20fSFrederick Mayle // Find the preferred loading address of the binary.
177*9712c20fSFrederick Mayle template<typename ElfClass>
GetLoadingAddress(const typename ElfClass::Phdr * program_headers,int nheader)178*9712c20fSFrederick Mayle typename ElfClass::Addr GetLoadingAddress(
179*9712c20fSFrederick Mayle const typename ElfClass::Phdr* program_headers,
180*9712c20fSFrederick Mayle int nheader) {
181*9712c20fSFrederick Mayle typedef typename ElfClass::Phdr Phdr;
182*9712c20fSFrederick Mayle
183*9712c20fSFrederick Mayle // For non-PIC executables (e_type == ET_EXEC), the load address is
184*9712c20fSFrederick Mayle // the start address of the first PT_LOAD segment. (ELF requires
185*9712c20fSFrederick Mayle // the segments to be sorted by load address.) For PIC executables
186*9712c20fSFrederick Mayle // and dynamic libraries (e_type == ET_DYN), this address will
187*9712c20fSFrederick Mayle // normally be zero.
188*9712c20fSFrederick Mayle for (int i = 0; i < nheader; ++i) {
189*9712c20fSFrederick Mayle const Phdr& header = program_headers[i];
190*9712c20fSFrederick Mayle if (header.p_type == PT_LOAD)
191*9712c20fSFrederick Mayle return header.p_vaddr;
192*9712c20fSFrederick Mayle }
193*9712c20fSFrederick Mayle return 0;
194*9712c20fSFrederick Mayle }
195*9712c20fSFrederick Mayle
196*9712c20fSFrederick Mayle // Find the set of address ranges for all PT_LOAD segments.
197*9712c20fSFrederick Mayle template <typename ElfClass>
GetPtLoadSegmentRanges(const typename ElfClass::Phdr * program_headers,int nheader)198*9712c20fSFrederick Mayle vector<Module::Range> GetPtLoadSegmentRanges(
199*9712c20fSFrederick Mayle const typename ElfClass::Phdr* program_headers,
200*9712c20fSFrederick Mayle int nheader) {
201*9712c20fSFrederick Mayle typedef typename ElfClass::Phdr Phdr;
202*9712c20fSFrederick Mayle vector<Module::Range> ranges;
203*9712c20fSFrederick Mayle
204*9712c20fSFrederick Mayle for (int i = 0; i < nheader; ++i) {
205*9712c20fSFrederick Mayle const Phdr& header = program_headers[i];
206*9712c20fSFrederick Mayle if (header.p_type == PT_LOAD) {
207*9712c20fSFrederick Mayle ranges.push_back(Module::Range(header.p_vaddr, header.p_memsz));
208*9712c20fSFrederick Mayle }
209*9712c20fSFrederick Mayle }
210*9712c20fSFrederick Mayle return ranges;
211*9712c20fSFrederick Mayle }
212*9712c20fSFrederick Mayle
213*9712c20fSFrederick Mayle #ifndef NO_STABS_SUPPORT
214*9712c20fSFrederick Mayle template<typename ElfClass>
LoadStabs(const typename ElfClass::Ehdr * elf_header,const typename ElfClass::Shdr * stab_section,const typename ElfClass::Shdr * stabstr_section,const bool big_endian,Module * module)215*9712c20fSFrederick Mayle bool LoadStabs(const typename ElfClass::Ehdr* elf_header,
216*9712c20fSFrederick Mayle const typename ElfClass::Shdr* stab_section,
217*9712c20fSFrederick Mayle const typename ElfClass::Shdr* stabstr_section,
218*9712c20fSFrederick Mayle const bool big_endian,
219*9712c20fSFrederick Mayle Module* module) {
220*9712c20fSFrederick Mayle // A callback object to handle data from the STABS reader.
221*9712c20fSFrederick Mayle StabsToModule handler(module);
222*9712c20fSFrederick Mayle // Find the addresses of the STABS data, and create a STABS reader object.
223*9712c20fSFrederick Mayle // On Linux, STABS entries always have 32-bit values, regardless of the
224*9712c20fSFrederick Mayle // address size of the architecture whose code they're describing, and
225*9712c20fSFrederick Mayle // the strings are always "unitized".
226*9712c20fSFrederick Mayle const uint8_t* stabs =
227*9712c20fSFrederick Mayle GetOffset<ElfClass, uint8_t>(elf_header, stab_section->sh_offset);
228*9712c20fSFrederick Mayle const uint8_t* stabstr =
229*9712c20fSFrederick Mayle GetOffset<ElfClass, uint8_t>(elf_header, stabstr_section->sh_offset);
230*9712c20fSFrederick Mayle google_breakpad::StabsReader reader(stabs, stab_section->sh_size,
231*9712c20fSFrederick Mayle stabstr, stabstr_section->sh_size,
232*9712c20fSFrederick Mayle big_endian, 4, true, &handler);
233*9712c20fSFrederick Mayle // Read the STABS data, and do post-processing.
234*9712c20fSFrederick Mayle if (!reader.Process())
235*9712c20fSFrederick Mayle return false;
236*9712c20fSFrederick Mayle handler.Finalize();
237*9712c20fSFrederick Mayle return true;
238*9712c20fSFrederick Mayle }
239*9712c20fSFrederick Mayle #endif // NO_STABS_SUPPORT
240*9712c20fSFrederick Mayle
241*9712c20fSFrederick Mayle // A range handler that accepts rangelist data parsed by
242*9712c20fSFrederick Mayle // google_breakpad::RangeListReader and populates a range vector (typically
243*9712c20fSFrederick Mayle // owned by a function) with the results.
244*9712c20fSFrederick Mayle class DumperRangesHandler : public DwarfCUToModule::RangesHandler {
245*9712c20fSFrederick Mayle public:
DumperRangesHandler(google_breakpad::ByteReader * reader)246*9712c20fSFrederick Mayle DumperRangesHandler(google_breakpad::ByteReader* reader) :
247*9712c20fSFrederick Mayle reader_(reader) { }
248*9712c20fSFrederick Mayle
ReadRanges(enum google_breakpad::DwarfForm form,uint64_t data,google_breakpad::RangeListReader::CURangesInfo * cu_info,vector<Module::Range> * ranges)249*9712c20fSFrederick Mayle bool ReadRanges(
250*9712c20fSFrederick Mayle enum google_breakpad::DwarfForm form, uint64_t data,
251*9712c20fSFrederick Mayle google_breakpad::RangeListReader::CURangesInfo* cu_info,
252*9712c20fSFrederick Mayle vector<Module::Range>* ranges) {
253*9712c20fSFrederick Mayle DwarfRangeListHandler handler(ranges);
254*9712c20fSFrederick Mayle google_breakpad::RangeListReader range_list_reader(reader_, cu_info,
255*9712c20fSFrederick Mayle &handler);
256*9712c20fSFrederick Mayle return range_list_reader.ReadRanges(form, data);
257*9712c20fSFrederick Mayle }
258*9712c20fSFrederick Mayle
259*9712c20fSFrederick Mayle private:
260*9712c20fSFrederick Mayle google_breakpad::ByteReader* reader_;
261*9712c20fSFrederick Mayle };
262*9712c20fSFrederick Mayle
263*9712c20fSFrederick Mayle // A line-to-module loader that accepts line number info parsed by
264*9712c20fSFrederick Mayle // google_breakpad::LineInfo and populates a Module and a line vector
265*9712c20fSFrederick Mayle // with the results.
266*9712c20fSFrederick Mayle class DumperLineToModule: public DwarfCUToModule::LineToModuleHandler {
267*9712c20fSFrederick Mayle public:
268*9712c20fSFrederick Mayle // Create a line-to-module converter using BYTE_READER.
DumperLineToModule(google_breakpad::ByteReader * byte_reader)269*9712c20fSFrederick Mayle explicit DumperLineToModule(google_breakpad::ByteReader* byte_reader)
270*9712c20fSFrederick Mayle : byte_reader_(byte_reader) { }
StartCompilationUnit(const string & compilation_dir)271*9712c20fSFrederick Mayle void StartCompilationUnit(const string& compilation_dir) {
272*9712c20fSFrederick Mayle compilation_dir_ = compilation_dir;
273*9712c20fSFrederick Mayle }
ReadProgram(const uint8_t * program,uint64_t length,const uint8_t * string_section,uint64_t string_section_length,const uint8_t * line_string_section,uint64_t line_string_section_length,Module * module,std::vector<Module::Line> * lines,std::map<uint32_t,Module::File * > * files)274*9712c20fSFrederick Mayle void ReadProgram(const uint8_t* program,
275*9712c20fSFrederick Mayle uint64_t length,
276*9712c20fSFrederick Mayle const uint8_t* string_section,
277*9712c20fSFrederick Mayle uint64_t string_section_length,
278*9712c20fSFrederick Mayle const uint8_t* line_string_section,
279*9712c20fSFrederick Mayle uint64_t line_string_section_length,
280*9712c20fSFrederick Mayle Module* module,
281*9712c20fSFrederick Mayle std::vector<Module::Line>* lines,
282*9712c20fSFrederick Mayle std::map<uint32_t, Module::File*>* files) {
283*9712c20fSFrederick Mayle DwarfLineToModule handler(module, compilation_dir_, lines, files);
284*9712c20fSFrederick Mayle google_breakpad::LineInfo parser(program, length, byte_reader_,
285*9712c20fSFrederick Mayle string_section, string_section_length,
286*9712c20fSFrederick Mayle line_string_section,
287*9712c20fSFrederick Mayle line_string_section_length,
288*9712c20fSFrederick Mayle &handler);
289*9712c20fSFrederick Mayle parser.Start();
290*9712c20fSFrederick Mayle }
291*9712c20fSFrederick Mayle private:
292*9712c20fSFrederick Mayle string compilation_dir_;
293*9712c20fSFrederick Mayle google_breakpad::ByteReader* byte_reader_;
294*9712c20fSFrederick Mayle };
295*9712c20fSFrederick Mayle
296*9712c20fSFrederick Mayle template<typename ElfClass>
IsCompressedHeader(const typename ElfClass::Shdr * section)297*9712c20fSFrederick Mayle bool IsCompressedHeader(const typename ElfClass::Shdr* section) {
298*9712c20fSFrederick Mayle return (section->sh_flags & SHF_COMPRESSED) != 0;
299*9712c20fSFrederick Mayle }
300*9712c20fSFrederick Mayle
301*9712c20fSFrederick Mayle template<typename ElfClass>
GetCompressionHeader(typename ElfClass::Chdr & compression_header,const uint8_t * content,uint64_t size)302*9712c20fSFrederick Mayle uint32_t GetCompressionHeader(
303*9712c20fSFrederick Mayle typename ElfClass::Chdr& compression_header,
304*9712c20fSFrederick Mayle const uint8_t* content, uint64_t size) {
305*9712c20fSFrederick Mayle const typename ElfClass::Chdr* header =
306*9712c20fSFrederick Mayle reinterpret_cast<const typename ElfClass::Chdr *>(content);
307*9712c20fSFrederick Mayle
308*9712c20fSFrederick Mayle if (size < sizeof (*header)) {
309*9712c20fSFrederick Mayle return 0;
310*9712c20fSFrederick Mayle }
311*9712c20fSFrederick Mayle
312*9712c20fSFrederick Mayle compression_header = *header;
313*9712c20fSFrederick Mayle return sizeof (*header);
314*9712c20fSFrederick Mayle }
315*9712c20fSFrederick Mayle
UncompressZlibSectionContents(const uint8_t * compressed_buffer,uint64_t compressed_size,uint64_t uncompressed_size)316*9712c20fSFrederick Mayle std::pair<uint8_t *, uint64_t> UncompressZlibSectionContents(
317*9712c20fSFrederick Mayle const uint8_t* compressed_buffer, uint64_t compressed_size, uint64_t uncompressed_size) {
318*9712c20fSFrederick Mayle z_stream stream;
319*9712c20fSFrederick Mayle memset(&stream, 0, sizeof stream);
320*9712c20fSFrederick Mayle
321*9712c20fSFrederick Mayle stream.avail_in = compressed_size;
322*9712c20fSFrederick Mayle stream.avail_out = uncompressed_size;
323*9712c20fSFrederick Mayle stream.next_in = const_cast<uint8_t *>(compressed_buffer);
324*9712c20fSFrederick Mayle
325*9712c20fSFrederick Mayle google_breakpad::scoped_array<uint8_t> uncompressed_buffer(
326*9712c20fSFrederick Mayle new uint8_t[uncompressed_size]);
327*9712c20fSFrederick Mayle
328*9712c20fSFrederick Mayle int status = inflateInit(&stream);
329*9712c20fSFrederick Mayle while (stream.avail_in != 0 && status == Z_OK) {
330*9712c20fSFrederick Mayle stream.next_out =
331*9712c20fSFrederick Mayle uncompressed_buffer.get() + uncompressed_size - stream.avail_out;
332*9712c20fSFrederick Mayle
333*9712c20fSFrederick Mayle if ((status = inflate(&stream, Z_FINISH)) != Z_STREAM_END) {
334*9712c20fSFrederick Mayle break;
335*9712c20fSFrederick Mayle }
336*9712c20fSFrederick Mayle
337*9712c20fSFrederick Mayle status = inflateReset(&stream);
338*9712c20fSFrederick Mayle }
339*9712c20fSFrederick Mayle
340*9712c20fSFrederick Mayle return inflateEnd(&stream) != Z_OK || status != Z_OK || stream.avail_out != 0
341*9712c20fSFrederick Mayle ? std::make_pair(nullptr, 0)
342*9712c20fSFrederick Mayle : std::make_pair(uncompressed_buffer.release(), uncompressed_size);
343*9712c20fSFrederick Mayle }
344*9712c20fSFrederick Mayle
345*9712c20fSFrederick Mayle #ifdef HAVE_LIBZSTD
UncompressZstdSectionContents(const uint8_t * compressed_buffer,uint64_t compressed_size,uint64_t uncompressed_size)346*9712c20fSFrederick Mayle std::pair<uint8_t *, uint64_t> UncompressZstdSectionContents(
347*9712c20fSFrederick Mayle const uint8_t* compressed_buffer, uint64_t compressed_size,uint64_t uncompressed_size) {
348*9712c20fSFrederick Mayle
349*9712c20fSFrederick Mayle google_breakpad::scoped_array<uint8_t> uncompressed_buffer(new uint8_t[uncompressed_size]);
350*9712c20fSFrederick Mayle size_t out_size = ZSTD_decompress(uncompressed_buffer.get(), uncompressed_size,
351*9712c20fSFrederick Mayle compressed_buffer, compressed_size);
352*9712c20fSFrederick Mayle if (ZSTD_isError(out_size)) {
353*9712c20fSFrederick Mayle return std::make_pair(nullptr, 0);
354*9712c20fSFrederick Mayle }
355*9712c20fSFrederick Mayle assert(out_size == uncompressed_size);
356*9712c20fSFrederick Mayle return std::make_pair(uncompressed_buffer.release(), uncompressed_size);
357*9712c20fSFrederick Mayle }
358*9712c20fSFrederick Mayle #endif
359*9712c20fSFrederick Mayle
UncompressSectionContents(uint64_t compression_type,const uint8_t * compressed_buffer,uint64_t compressed_size,uint64_t uncompressed_size)360*9712c20fSFrederick Mayle std::pair<uint8_t *, uint64_t> UncompressSectionContents(
361*9712c20fSFrederick Mayle uint64_t compression_type, const uint8_t* compressed_buffer,
362*9712c20fSFrederick Mayle uint64_t compressed_size, uint64_t uncompressed_size) {
363*9712c20fSFrederick Mayle if (compression_type == ELFCOMPRESS_ZLIB) {
364*9712c20fSFrederick Mayle return UncompressZlibSectionContents(compressed_buffer, compressed_size, uncompressed_size);
365*9712c20fSFrederick Mayle }
366*9712c20fSFrederick Mayle
367*9712c20fSFrederick Mayle #ifdef HAVE_LIBZSTD
368*9712c20fSFrederick Mayle if (compression_type == ELFCOMPRESS_ZSTD) {
369*9712c20fSFrederick Mayle return UncompressZstdSectionContents(compressed_buffer, compressed_size, uncompressed_size);
370*9712c20fSFrederick Mayle }
371*9712c20fSFrederick Mayle #endif
372*9712c20fSFrederick Mayle
373*9712c20fSFrederick Mayle return std::make_pair(nullptr, 0);
374*9712c20fSFrederick Mayle }
375*9712c20fSFrederick Mayle
StartProcessSplitDwarf(google_breakpad::CompilationUnit * reader,Module * module,google_breakpad::Endianness endianness,bool handle_inter_cu_refs,bool handle_inline)376*9712c20fSFrederick Mayle void StartProcessSplitDwarf(google_breakpad::CompilationUnit* reader,
377*9712c20fSFrederick Mayle Module* module,
378*9712c20fSFrederick Mayle google_breakpad::Endianness endianness,
379*9712c20fSFrederick Mayle bool handle_inter_cu_refs,
380*9712c20fSFrederick Mayle bool handle_inline) {
381*9712c20fSFrederick Mayle std::string split_file;
382*9712c20fSFrederick Mayle google_breakpad::SectionMap split_sections;
383*9712c20fSFrederick Mayle google_breakpad::ByteReader split_byte_reader(endianness);
384*9712c20fSFrederick Mayle uint64_t cu_offset = 0;
385*9712c20fSFrederick Mayle if (!reader->ProcessSplitDwarf(split_file, split_sections, split_byte_reader,
386*9712c20fSFrederick Mayle cu_offset))
387*9712c20fSFrederick Mayle return;
388*9712c20fSFrederick Mayle DwarfCUToModule::FileContext file_context(split_file, module,
389*9712c20fSFrederick Mayle handle_inter_cu_refs);
390*9712c20fSFrederick Mayle for (auto section : split_sections)
391*9712c20fSFrederick Mayle file_context.AddSectionToSectionMap(section.first, section.second.first,
392*9712c20fSFrederick Mayle section.second.second);
393*9712c20fSFrederick Mayle // Because DWP/DWO file doesn't have .debug_addr/.debug_line/.debug_line_str,
394*9712c20fSFrederick Mayle // its debug info will refer to .debug_addr/.debug_line in the main binary.
395*9712c20fSFrederick Mayle if (file_context.section_map().find(".debug_addr") ==
396*9712c20fSFrederick Mayle file_context.section_map().end())
397*9712c20fSFrederick Mayle file_context.AddSectionToSectionMap(".debug_addr", reader->GetAddrBuffer(),
398*9712c20fSFrederick Mayle reader->GetAddrBufferLen());
399*9712c20fSFrederick Mayle if (file_context.section_map().find(".debug_line") ==
400*9712c20fSFrederick Mayle file_context.section_map().end())
401*9712c20fSFrederick Mayle file_context.AddSectionToSectionMap(".debug_line", reader->GetLineBuffer(),
402*9712c20fSFrederick Mayle reader->GetLineBufferLen());
403*9712c20fSFrederick Mayle if (file_context.section_map().find(".debug_line_str") ==
404*9712c20fSFrederick Mayle file_context.section_map().end())
405*9712c20fSFrederick Mayle file_context.AddSectionToSectionMap(".debug_line_str",
406*9712c20fSFrederick Mayle reader->GetLineStrBuffer(),
407*9712c20fSFrederick Mayle reader->GetLineStrBufferLen());
408*9712c20fSFrederick Mayle
409*9712c20fSFrederick Mayle DumperRangesHandler ranges_handler(&split_byte_reader);
410*9712c20fSFrederick Mayle DumperLineToModule line_to_module(&split_byte_reader);
411*9712c20fSFrederick Mayle DwarfCUToModule::WarningReporter reporter(split_file, cu_offset);
412*9712c20fSFrederick Mayle DwarfCUToModule root_handler(
413*9712c20fSFrederick Mayle &file_context, &line_to_module, &ranges_handler, &reporter, handle_inline,
414*9712c20fSFrederick Mayle reader->GetLowPC(), reader->GetAddrBase(), reader->HasSourceLineInfo(),
415*9712c20fSFrederick Mayle reader->GetSourceLineOffset());
416*9712c20fSFrederick Mayle google_breakpad::DIEDispatcher die_dispatcher(&root_handler);
417*9712c20fSFrederick Mayle google_breakpad::CompilationUnit split_reader(
418*9712c20fSFrederick Mayle split_file, file_context.section_map(), cu_offset, &split_byte_reader,
419*9712c20fSFrederick Mayle &die_dispatcher);
420*9712c20fSFrederick Mayle split_reader.SetSplitDwarf(reader->GetAddrBase(), reader->GetDWOID());
421*9712c20fSFrederick Mayle split_reader.Start();
422*9712c20fSFrederick Mayle // Normally, it won't happen unless we have transitive reference.
423*9712c20fSFrederick Mayle if (split_reader.ShouldProcessSplitDwarf()) {
424*9712c20fSFrederick Mayle StartProcessSplitDwarf(&split_reader, module, endianness,
425*9712c20fSFrederick Mayle handle_inter_cu_refs, handle_inline);
426*9712c20fSFrederick Mayle }
427*9712c20fSFrederick Mayle }
428*9712c20fSFrederick Mayle
429*9712c20fSFrederick Mayle template<typename ElfClass>
LoadDwarf(const string & dwarf_filename,const typename ElfClass::Ehdr * elf_header,const bool big_endian,bool handle_inter_cu_refs,bool handle_inline,Module * module)430*9712c20fSFrederick Mayle bool LoadDwarf(const string& dwarf_filename,
431*9712c20fSFrederick Mayle const typename ElfClass::Ehdr* elf_header,
432*9712c20fSFrederick Mayle const bool big_endian,
433*9712c20fSFrederick Mayle bool handle_inter_cu_refs,
434*9712c20fSFrederick Mayle bool handle_inline,
435*9712c20fSFrederick Mayle Module* module) {
436*9712c20fSFrederick Mayle typedef typename ElfClass::Shdr Shdr;
437*9712c20fSFrederick Mayle
438*9712c20fSFrederick Mayle const google_breakpad::Endianness endianness = big_endian ?
439*9712c20fSFrederick Mayle google_breakpad::ENDIANNESS_BIG : google_breakpad::ENDIANNESS_LITTLE;
440*9712c20fSFrederick Mayle google_breakpad::ByteReader byte_reader(endianness);
441*9712c20fSFrederick Mayle
442*9712c20fSFrederick Mayle // Construct a context for this file.
443*9712c20fSFrederick Mayle DwarfCUToModule::FileContext file_context(dwarf_filename,
444*9712c20fSFrederick Mayle module,
445*9712c20fSFrederick Mayle handle_inter_cu_refs);
446*9712c20fSFrederick Mayle
447*9712c20fSFrederick Mayle // Build a map of the ELF file's sections.
448*9712c20fSFrederick Mayle const Shdr* sections =
449*9712c20fSFrederick Mayle GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff);
450*9712c20fSFrederick Mayle int num_sections = elf_header->e_shnum;
451*9712c20fSFrederick Mayle const Shdr* section_names = sections + elf_header->e_shstrndx;
452*9712c20fSFrederick Mayle for (int i = 0; i < num_sections; i++) {
453*9712c20fSFrederick Mayle const Shdr* section = §ions[i];
454*9712c20fSFrederick Mayle string name = GetOffset<ElfClass, char>(elf_header,
455*9712c20fSFrederick Mayle section_names->sh_offset) +
456*9712c20fSFrederick Mayle section->sh_name;
457*9712c20fSFrederick Mayle const uint8_t* contents = GetOffset<ElfClass, uint8_t>(elf_header,
458*9712c20fSFrederick Mayle section->sh_offset);
459*9712c20fSFrederick Mayle uint64_t size = section->sh_size;
460*9712c20fSFrederick Mayle
461*9712c20fSFrederick Mayle if (!IsCompressedHeader<ElfClass>(section)) {
462*9712c20fSFrederick Mayle file_context.AddSectionToSectionMap(name, contents, size);
463*9712c20fSFrederick Mayle continue;
464*9712c20fSFrederick Mayle }
465*9712c20fSFrederick Mayle
466*9712c20fSFrederick Mayle typename ElfClass::Chdr chdr;
467*9712c20fSFrederick Mayle
468*9712c20fSFrederick Mayle uint32_t compression_header_size =
469*9712c20fSFrederick Mayle GetCompressionHeader<ElfClass>(chdr, contents, size);
470*9712c20fSFrederick Mayle
471*9712c20fSFrederick Mayle if (compression_header_size == 0 || chdr.ch_size == 0) {
472*9712c20fSFrederick Mayle continue;
473*9712c20fSFrederick Mayle }
474*9712c20fSFrederick Mayle
475*9712c20fSFrederick Mayle contents += compression_header_size;
476*9712c20fSFrederick Mayle size -= compression_header_size;
477*9712c20fSFrederick Mayle
478*9712c20fSFrederick Mayle std::pair<uint8_t *, uint64_t> uncompressed =
479*9712c20fSFrederick Mayle UncompressSectionContents(chdr.ch_type, contents, size, chdr.ch_size);
480*9712c20fSFrederick Mayle
481*9712c20fSFrederick Mayle if (uncompressed.first != nullptr && uncompressed.second != 0) {
482*9712c20fSFrederick Mayle file_context.AddManagedSectionToSectionMap(name, uncompressed.first, uncompressed.second);
483*9712c20fSFrederick Mayle }
484*9712c20fSFrederick Mayle }
485*9712c20fSFrederick Mayle
486*9712c20fSFrederick Mayle // .debug_ranges and .debug_rnglists reader
487*9712c20fSFrederick Mayle DumperRangesHandler ranges_handler(&byte_reader);
488*9712c20fSFrederick Mayle
489*9712c20fSFrederick Mayle // Parse all the compilation units in the .debug_info section.
490*9712c20fSFrederick Mayle DumperLineToModule line_to_module(&byte_reader);
491*9712c20fSFrederick Mayle google_breakpad::SectionMap::const_iterator debug_info_entry =
492*9712c20fSFrederick Mayle file_context.section_map().find(".debug_info");
493*9712c20fSFrederick Mayle assert(debug_info_entry != file_context.section_map().end());
494*9712c20fSFrederick Mayle const std::pair<const uint8_t*, uint64_t>& debug_info_section =
495*9712c20fSFrederick Mayle debug_info_entry->second;
496*9712c20fSFrederick Mayle // This should never have been called if the file doesn't have a
497*9712c20fSFrederick Mayle // .debug_info section.
498*9712c20fSFrederick Mayle assert(debug_info_section.first);
499*9712c20fSFrederick Mayle uint64_t debug_info_length = debug_info_section.second;
500*9712c20fSFrederick Mayle for (uint64_t offset = 0; offset < debug_info_length;) {
501*9712c20fSFrederick Mayle // Make a handler for the root DIE that populates MODULE with the
502*9712c20fSFrederick Mayle // data that was found.
503*9712c20fSFrederick Mayle DwarfCUToModule::WarningReporter reporter(dwarf_filename, offset);
504*9712c20fSFrederick Mayle DwarfCUToModule root_handler(&file_context, &line_to_module,
505*9712c20fSFrederick Mayle &ranges_handler, &reporter, handle_inline);
506*9712c20fSFrederick Mayle // Make a Dwarf2Handler that drives the DIEHandler.
507*9712c20fSFrederick Mayle google_breakpad::DIEDispatcher die_dispatcher(&root_handler);
508*9712c20fSFrederick Mayle // Make a DWARF parser for the compilation unit at OFFSET.
509*9712c20fSFrederick Mayle google_breakpad::CompilationUnit reader(dwarf_filename,
510*9712c20fSFrederick Mayle file_context.section_map(),
511*9712c20fSFrederick Mayle offset,
512*9712c20fSFrederick Mayle &byte_reader,
513*9712c20fSFrederick Mayle &die_dispatcher);
514*9712c20fSFrederick Mayle // Process the entire compilation unit; get the offset of the next.
515*9712c20fSFrederick Mayle offset += reader.Start();
516*9712c20fSFrederick Mayle // Start to process split dwarf file.
517*9712c20fSFrederick Mayle if (reader.ShouldProcessSplitDwarf()) {
518*9712c20fSFrederick Mayle StartProcessSplitDwarf(&reader, module, endianness, handle_inter_cu_refs,
519*9712c20fSFrederick Mayle handle_inline);
520*9712c20fSFrederick Mayle }
521*9712c20fSFrederick Mayle }
522*9712c20fSFrederick Mayle return true;
523*9712c20fSFrederick Mayle }
524*9712c20fSFrederick Mayle
525*9712c20fSFrederick Mayle // Fill REGISTER_NAMES with the register names appropriate to the
526*9712c20fSFrederick Mayle // machine architecture given in HEADER, indexed by the register
527*9712c20fSFrederick Mayle // numbers used in DWARF call frame information. Return true on
528*9712c20fSFrederick Mayle // success, or false if HEADER's machine architecture is not
529*9712c20fSFrederick Mayle // supported.
530*9712c20fSFrederick Mayle template<typename ElfClass>
DwarfCFIRegisterNames(const typename ElfClass::Ehdr * elf_header,std::vector<string> * register_names)531*9712c20fSFrederick Mayle bool DwarfCFIRegisterNames(const typename ElfClass::Ehdr* elf_header,
532*9712c20fSFrederick Mayle std::vector<string>* register_names) {
533*9712c20fSFrederick Mayle switch (elf_header->e_machine) {
534*9712c20fSFrederick Mayle case EM_386:
535*9712c20fSFrederick Mayle *register_names = DwarfCFIToModule::RegisterNames::I386();
536*9712c20fSFrederick Mayle return true;
537*9712c20fSFrederick Mayle case EM_ARM:
538*9712c20fSFrederick Mayle *register_names = DwarfCFIToModule::RegisterNames::ARM();
539*9712c20fSFrederick Mayle return true;
540*9712c20fSFrederick Mayle case EM_AARCH64:
541*9712c20fSFrederick Mayle *register_names = DwarfCFIToModule::RegisterNames::ARM64();
542*9712c20fSFrederick Mayle return true;
543*9712c20fSFrederick Mayle case EM_MIPS:
544*9712c20fSFrederick Mayle *register_names = DwarfCFIToModule::RegisterNames::MIPS();
545*9712c20fSFrederick Mayle return true;
546*9712c20fSFrederick Mayle case EM_X86_64:
547*9712c20fSFrederick Mayle *register_names = DwarfCFIToModule::RegisterNames::X86_64();
548*9712c20fSFrederick Mayle return true;
549*9712c20fSFrederick Mayle case EM_RISCV:
550*9712c20fSFrederick Mayle *register_names = DwarfCFIToModule::RegisterNames::RISCV();
551*9712c20fSFrederick Mayle return true;
552*9712c20fSFrederick Mayle default:
553*9712c20fSFrederick Mayle return false;
554*9712c20fSFrederick Mayle }
555*9712c20fSFrederick Mayle }
556*9712c20fSFrederick Mayle
557*9712c20fSFrederick Mayle template<typename ElfClass>
LoadDwarfCFI(const string & dwarf_filename,const typename ElfClass::Ehdr * elf_header,const char * section_name,const typename ElfClass::Shdr * section,const bool eh_frame,const typename ElfClass::Shdr * got_section,const typename ElfClass::Shdr * text_section,const bool big_endian,Module * module)558*9712c20fSFrederick Mayle bool LoadDwarfCFI(const string& dwarf_filename,
559*9712c20fSFrederick Mayle const typename ElfClass::Ehdr* elf_header,
560*9712c20fSFrederick Mayle const char* section_name,
561*9712c20fSFrederick Mayle const typename ElfClass::Shdr* section,
562*9712c20fSFrederick Mayle const bool eh_frame,
563*9712c20fSFrederick Mayle const typename ElfClass::Shdr* got_section,
564*9712c20fSFrederick Mayle const typename ElfClass::Shdr* text_section,
565*9712c20fSFrederick Mayle const bool big_endian,
566*9712c20fSFrederick Mayle Module* module) {
567*9712c20fSFrederick Mayle // Find the appropriate set of register names for this file's
568*9712c20fSFrederick Mayle // architecture.
569*9712c20fSFrederick Mayle std::vector<string> register_names;
570*9712c20fSFrederick Mayle if (!DwarfCFIRegisterNames<ElfClass>(elf_header, ®ister_names)) {
571*9712c20fSFrederick Mayle fprintf(stderr, "%s: unrecognized ELF machine architecture '%d';"
572*9712c20fSFrederick Mayle " cannot convert DWARF call frame information\n",
573*9712c20fSFrederick Mayle dwarf_filename.c_str(), elf_header->e_machine);
574*9712c20fSFrederick Mayle return false;
575*9712c20fSFrederick Mayle }
576*9712c20fSFrederick Mayle
577*9712c20fSFrederick Mayle const google_breakpad::Endianness endianness = big_endian ?
578*9712c20fSFrederick Mayle google_breakpad::ENDIANNESS_BIG : google_breakpad::ENDIANNESS_LITTLE;
579*9712c20fSFrederick Mayle
580*9712c20fSFrederick Mayle // Find the call frame information and its size.
581*9712c20fSFrederick Mayle const uint8_t* cfi =
582*9712c20fSFrederick Mayle GetOffset<ElfClass, uint8_t>(elf_header, section->sh_offset);
583*9712c20fSFrederick Mayle size_t cfi_size = section->sh_size;
584*9712c20fSFrederick Mayle
585*9712c20fSFrederick Mayle // Plug together the parser, handler, and their entourages.
586*9712c20fSFrederick Mayle DwarfCFIToModule::Reporter module_reporter(dwarf_filename, section_name);
587*9712c20fSFrederick Mayle DwarfCFIToModule handler(module, register_names, &module_reporter);
588*9712c20fSFrederick Mayle google_breakpad::ByteReader byte_reader(endianness);
589*9712c20fSFrederick Mayle
590*9712c20fSFrederick Mayle byte_reader.SetAddressSize(ElfClass::kAddrSize);
591*9712c20fSFrederick Mayle
592*9712c20fSFrederick Mayle // Provide the base addresses for .eh_frame encoded pointers, if
593*9712c20fSFrederick Mayle // possible.
594*9712c20fSFrederick Mayle byte_reader.SetCFIDataBase(section->sh_addr, cfi);
595*9712c20fSFrederick Mayle if (got_section)
596*9712c20fSFrederick Mayle byte_reader.SetDataBase(got_section->sh_addr);
597*9712c20fSFrederick Mayle if (text_section)
598*9712c20fSFrederick Mayle byte_reader.SetTextBase(text_section->sh_addr);
599*9712c20fSFrederick Mayle
600*9712c20fSFrederick Mayle google_breakpad::CallFrameInfo::Reporter dwarf_reporter(dwarf_filename,
601*9712c20fSFrederick Mayle section_name);
602*9712c20fSFrederick Mayle if (!IsCompressedHeader<ElfClass>(section)) {
603*9712c20fSFrederick Mayle google_breakpad::CallFrameInfo parser(cfi, cfi_size,
604*9712c20fSFrederick Mayle &byte_reader, &handler,
605*9712c20fSFrederick Mayle &dwarf_reporter, eh_frame);
606*9712c20fSFrederick Mayle parser.Start();
607*9712c20fSFrederick Mayle return true;
608*9712c20fSFrederick Mayle }
609*9712c20fSFrederick Mayle
610*9712c20fSFrederick Mayle typename ElfClass::Chdr chdr;
611*9712c20fSFrederick Mayle uint32_t compression_header_size =
612*9712c20fSFrederick Mayle GetCompressionHeader<ElfClass>(chdr, cfi, cfi_size);
613*9712c20fSFrederick Mayle
614*9712c20fSFrederick Mayle if (compression_header_size == 0 || chdr.ch_size == 0) {
615*9712c20fSFrederick Mayle fprintf(stderr, "%s: decompression failed at header\n",
616*9712c20fSFrederick Mayle dwarf_filename.c_str());
617*9712c20fSFrederick Mayle return false;
618*9712c20fSFrederick Mayle }
619*9712c20fSFrederick Mayle if (compression_header_size > cfi_size) {
620*9712c20fSFrederick Mayle fprintf(stderr, "%s: decompression error, compression_header too large\n",
621*9712c20fSFrederick Mayle dwarf_filename.c_str());
622*9712c20fSFrederick Mayle return false;
623*9712c20fSFrederick Mayle }
624*9712c20fSFrederick Mayle
625*9712c20fSFrederick Mayle cfi += compression_header_size;
626*9712c20fSFrederick Mayle cfi_size -= compression_header_size;
627*9712c20fSFrederick Mayle
628*9712c20fSFrederick Mayle std::pair<uint8_t *, uint64_t> uncompressed =
629*9712c20fSFrederick Mayle UncompressSectionContents(chdr.ch_type, cfi, cfi_size, chdr.ch_size);
630*9712c20fSFrederick Mayle
631*9712c20fSFrederick Mayle if (uncompressed.first == nullptr || uncompressed.second == 0) {
632*9712c20fSFrederick Mayle fprintf(stderr, "%s: decompression failed\n", dwarf_filename.c_str());
633*9712c20fSFrederick Mayle return false;
634*9712c20fSFrederick Mayle }
635*9712c20fSFrederick Mayle google_breakpad::CallFrameInfo parser(uncompressed.first, uncompressed.second,
636*9712c20fSFrederick Mayle &byte_reader, &handler, &dwarf_reporter,
637*9712c20fSFrederick Mayle eh_frame);
638*9712c20fSFrederick Mayle parser.Start();
639*9712c20fSFrederick Mayle return true;
640*9712c20fSFrederick Mayle }
641*9712c20fSFrederick Mayle
LoadELF(const string & obj_file,MmapWrapper * map_wrapper,void ** elf_header)642*9712c20fSFrederick Mayle bool LoadELF(const string& obj_file, MmapWrapper* map_wrapper,
643*9712c20fSFrederick Mayle void** elf_header) {
644*9712c20fSFrederick Mayle int obj_fd = open(obj_file.c_str(), O_RDONLY);
645*9712c20fSFrederick Mayle if (obj_fd < 0) {
646*9712c20fSFrederick Mayle fprintf(stderr, "Failed to open ELF file '%s': %s\n",
647*9712c20fSFrederick Mayle obj_file.c_str(), strerror(errno));
648*9712c20fSFrederick Mayle return false;
649*9712c20fSFrederick Mayle }
650*9712c20fSFrederick Mayle FDWrapper obj_fd_wrapper(obj_fd);
651*9712c20fSFrederick Mayle struct stat st;
652*9712c20fSFrederick Mayle if (fstat(obj_fd, &st) != 0 && st.st_size <= 0) {
653*9712c20fSFrederick Mayle fprintf(stderr, "Unable to fstat ELF file '%s': %s\n",
654*9712c20fSFrederick Mayle obj_file.c_str(), strerror(errno));
655*9712c20fSFrederick Mayle return false;
656*9712c20fSFrederick Mayle }
657*9712c20fSFrederick Mayle void* obj_base = mmap(NULL, st.st_size,
658*9712c20fSFrederick Mayle PROT_READ | PROT_WRITE, MAP_PRIVATE, obj_fd, 0);
659*9712c20fSFrederick Mayle if (obj_base == MAP_FAILED) {
660*9712c20fSFrederick Mayle fprintf(stderr, "Failed to mmap ELF file '%s': %s\n",
661*9712c20fSFrederick Mayle obj_file.c_str(), strerror(errno));
662*9712c20fSFrederick Mayle return false;
663*9712c20fSFrederick Mayle }
664*9712c20fSFrederick Mayle map_wrapper->set(obj_base, st.st_size);
665*9712c20fSFrederick Mayle *elf_header = obj_base;
666*9712c20fSFrederick Mayle if (!IsValidElf(*elf_header)) {
667*9712c20fSFrederick Mayle fprintf(stderr, "Not a valid ELF file: %s\n", obj_file.c_str());
668*9712c20fSFrederick Mayle return false;
669*9712c20fSFrederick Mayle }
670*9712c20fSFrederick Mayle return true;
671*9712c20fSFrederick Mayle }
672*9712c20fSFrederick Mayle
673*9712c20fSFrederick Mayle // Get the endianness of ELF_HEADER. If it's invalid, return false.
674*9712c20fSFrederick Mayle template<typename ElfClass>
ElfEndianness(const typename ElfClass::Ehdr * elf_header,bool * big_endian)675*9712c20fSFrederick Mayle bool ElfEndianness(const typename ElfClass::Ehdr* elf_header,
676*9712c20fSFrederick Mayle bool* big_endian) {
677*9712c20fSFrederick Mayle if (elf_header->e_ident[EI_DATA] == ELFDATA2LSB) {
678*9712c20fSFrederick Mayle *big_endian = false;
679*9712c20fSFrederick Mayle return true;
680*9712c20fSFrederick Mayle }
681*9712c20fSFrederick Mayle if (elf_header->e_ident[EI_DATA] == ELFDATA2MSB) {
682*9712c20fSFrederick Mayle *big_endian = true;
683*9712c20fSFrederick Mayle return true;
684*9712c20fSFrederick Mayle }
685*9712c20fSFrederick Mayle
686*9712c20fSFrederick Mayle fprintf(stderr, "bad data encoding in ELF header: %d\n",
687*9712c20fSFrederick Mayle elf_header->e_ident[EI_DATA]);
688*9712c20fSFrederick Mayle return false;
689*9712c20fSFrederick Mayle }
690*9712c20fSFrederick Mayle
691*9712c20fSFrederick Mayle // Given |left_abspath|, find the absolute path for |right_path| and see if the
692*9712c20fSFrederick Mayle // two absolute paths are the same.
IsSameFile(const char * left_abspath,const string & right_path)693*9712c20fSFrederick Mayle bool IsSameFile(const char* left_abspath, const string& right_path) {
694*9712c20fSFrederick Mayle char right_abspath[PATH_MAX];
695*9712c20fSFrederick Mayle if (!realpath(right_path.c_str(), right_abspath))
696*9712c20fSFrederick Mayle return false;
697*9712c20fSFrederick Mayle return strcmp(left_abspath, right_abspath) == 0;
698*9712c20fSFrederick Mayle }
699*9712c20fSFrederick Mayle
700*9712c20fSFrederick Mayle // Read the .gnu_debuglink and get the debug file name. If anything goes
701*9712c20fSFrederick Mayle // wrong, return an empty string.
ReadDebugLink(const uint8_t * debuglink,const size_t debuglink_size,const bool big_endian,const string & obj_file,const std::vector<string> & debug_dirs)702*9712c20fSFrederick Mayle string ReadDebugLink(const uint8_t* debuglink,
703*9712c20fSFrederick Mayle const size_t debuglink_size,
704*9712c20fSFrederick Mayle const bool big_endian,
705*9712c20fSFrederick Mayle const string& obj_file,
706*9712c20fSFrederick Mayle const std::vector<string>& debug_dirs) {
707*9712c20fSFrederick Mayle // Include '\0' + CRC32 (4 bytes).
708*9712c20fSFrederick Mayle size_t debuglink_len = strlen(reinterpret_cast<const char*>(debuglink)) + 5;
709*9712c20fSFrederick Mayle debuglink_len = 4 * ((debuglink_len + 3) / 4); // Round up to 4 bytes.
710*9712c20fSFrederick Mayle
711*9712c20fSFrederick Mayle // Sanity check.
712*9712c20fSFrederick Mayle if (debuglink_len != debuglink_size) {
713*9712c20fSFrederick Mayle fprintf(stderr, "Mismatched .gnu_debuglink string / section size: "
714*9712c20fSFrederick Mayle "%zx %zx\n", debuglink_len, debuglink_size);
715*9712c20fSFrederick Mayle return string();
716*9712c20fSFrederick Mayle }
717*9712c20fSFrederick Mayle
718*9712c20fSFrederick Mayle char obj_file_abspath[PATH_MAX];
719*9712c20fSFrederick Mayle if (!realpath(obj_file.c_str(), obj_file_abspath)) {
720*9712c20fSFrederick Mayle fprintf(stderr, "Cannot resolve absolute path for %s\n", obj_file.c_str());
721*9712c20fSFrederick Mayle return string();
722*9712c20fSFrederick Mayle }
723*9712c20fSFrederick Mayle
724*9712c20fSFrederick Mayle std::vector<string> searched_paths;
725*9712c20fSFrederick Mayle string debuglink_path;
726*9712c20fSFrederick Mayle std::vector<string>::const_iterator it;
727*9712c20fSFrederick Mayle for (it = debug_dirs.begin(); it < debug_dirs.end(); ++it) {
728*9712c20fSFrederick Mayle const string& debug_dir = *it;
729*9712c20fSFrederick Mayle debuglink_path = debug_dir + "/" +
730*9712c20fSFrederick Mayle reinterpret_cast<const char*>(debuglink);
731*9712c20fSFrederick Mayle
732*9712c20fSFrederick Mayle // There is the annoying case of /path/to/foo.so having foo.so as the
733*9712c20fSFrederick Mayle // debug link file name. Thus this may end up opening /path/to/foo.so again,
734*9712c20fSFrederick Mayle // and there is a small chance of the two files having the same CRC.
735*9712c20fSFrederick Mayle if (IsSameFile(obj_file_abspath, debuglink_path))
736*9712c20fSFrederick Mayle continue;
737*9712c20fSFrederick Mayle
738*9712c20fSFrederick Mayle searched_paths.push_back(debug_dir);
739*9712c20fSFrederick Mayle int debuglink_fd = open(debuglink_path.c_str(), O_RDONLY);
740*9712c20fSFrederick Mayle if (debuglink_fd < 0)
741*9712c20fSFrederick Mayle continue;
742*9712c20fSFrederick Mayle
743*9712c20fSFrederick Mayle FDWrapper debuglink_fd_wrapper(debuglink_fd);
744*9712c20fSFrederick Mayle
745*9712c20fSFrederick Mayle // The CRC is the last 4 bytes in |debuglink|.
746*9712c20fSFrederick Mayle const google_breakpad::Endianness endianness = big_endian ?
747*9712c20fSFrederick Mayle google_breakpad::ENDIANNESS_BIG : google_breakpad::ENDIANNESS_LITTLE;
748*9712c20fSFrederick Mayle google_breakpad::ByteReader byte_reader(endianness);
749*9712c20fSFrederick Mayle uint32_t expected_crc =
750*9712c20fSFrederick Mayle byte_reader.ReadFourBytes(&debuglink[debuglink_size - 4]);
751*9712c20fSFrederick Mayle
752*9712c20fSFrederick Mayle uint32_t actual_crc = 0;
753*9712c20fSFrederick Mayle while (true) {
754*9712c20fSFrederick Mayle const size_t kReadSize = 4096;
755*9712c20fSFrederick Mayle char buf[kReadSize];
756*9712c20fSFrederick Mayle ssize_t bytes_read = HANDLE_EINTR(read(debuglink_fd, &buf, kReadSize));
757*9712c20fSFrederick Mayle if (bytes_read < 0) {
758*9712c20fSFrederick Mayle fprintf(stderr, "Error reading debug ELF file %s.\n",
759*9712c20fSFrederick Mayle debuglink_path.c_str());
760*9712c20fSFrederick Mayle return string();
761*9712c20fSFrederick Mayle }
762*9712c20fSFrederick Mayle if (bytes_read == 0)
763*9712c20fSFrederick Mayle break;
764*9712c20fSFrederick Mayle actual_crc = google_breakpad::UpdateCrc32(actual_crc, buf, bytes_read);
765*9712c20fSFrederick Mayle }
766*9712c20fSFrederick Mayle if (actual_crc != expected_crc) {
767*9712c20fSFrederick Mayle fprintf(stderr, "Error reading debug ELF file - CRC32 mismatch: %s\n",
768*9712c20fSFrederick Mayle debuglink_path.c_str());
769*9712c20fSFrederick Mayle continue;
770*9712c20fSFrederick Mayle }
771*9712c20fSFrederick Mayle
772*9712c20fSFrederick Mayle // Found debug file.
773*9712c20fSFrederick Mayle return debuglink_path;
774*9712c20fSFrederick Mayle }
775*9712c20fSFrederick Mayle
776*9712c20fSFrederick Mayle // Not found case.
777*9712c20fSFrederick Mayle fprintf(stderr, "Failed to find debug ELF file for '%s' after trying:\n",
778*9712c20fSFrederick Mayle obj_file.c_str());
779*9712c20fSFrederick Mayle for (it = searched_paths.begin(); it < searched_paths.end(); ++it) {
780*9712c20fSFrederick Mayle const string& debug_dir = *it;
781*9712c20fSFrederick Mayle fprintf(stderr, " %s/%s\n", debug_dir.c_str(), debuglink);
782*9712c20fSFrederick Mayle }
783*9712c20fSFrederick Mayle return string();
784*9712c20fSFrederick Mayle }
785*9712c20fSFrederick Mayle
786*9712c20fSFrederick Mayle //
787*9712c20fSFrederick Mayle // LoadSymbolsInfo
788*9712c20fSFrederick Mayle //
789*9712c20fSFrederick Mayle // Holds the state between the two calls to LoadSymbols() in case it's necessary
790*9712c20fSFrederick Mayle // to follow the .gnu_debuglink section and load debug information from a
791*9712c20fSFrederick Mayle // different file.
792*9712c20fSFrederick Mayle //
793*9712c20fSFrederick Mayle template<typename ElfClass>
794*9712c20fSFrederick Mayle class LoadSymbolsInfo {
795*9712c20fSFrederick Mayle public:
796*9712c20fSFrederick Mayle typedef typename ElfClass::Addr Addr;
797*9712c20fSFrederick Mayle
LoadSymbolsInfo(const std::vector<string> & dbg_dirs)798*9712c20fSFrederick Mayle explicit LoadSymbolsInfo(const std::vector<string>& dbg_dirs) :
799*9712c20fSFrederick Mayle debug_dirs_(dbg_dirs),
800*9712c20fSFrederick Mayle has_loading_addr_(false) {}
801*9712c20fSFrederick Mayle
802*9712c20fSFrederick Mayle // Keeps track of which sections have been loaded so sections don't
803*9712c20fSFrederick Mayle // accidentally get loaded twice from two different files.
LoadedSection(const string & section)804*9712c20fSFrederick Mayle void LoadedSection(const string& section) {
805*9712c20fSFrederick Mayle if (loaded_sections_.count(section) == 0) {
806*9712c20fSFrederick Mayle loaded_sections_.insert(section);
807*9712c20fSFrederick Mayle } else {
808*9712c20fSFrederick Mayle fprintf(stderr, "Section %s has already been loaded.\n",
809*9712c20fSFrederick Mayle section.c_str());
810*9712c20fSFrederick Mayle }
811*9712c20fSFrederick Mayle }
812*9712c20fSFrederick Mayle
813*9712c20fSFrederick Mayle // The ELF file and linked debug file are expected to have the same preferred
814*9712c20fSFrederick Mayle // loading address.
set_loading_addr(Addr addr,const string & filename)815*9712c20fSFrederick Mayle void set_loading_addr(Addr addr, const string& filename) {
816*9712c20fSFrederick Mayle if (!has_loading_addr_) {
817*9712c20fSFrederick Mayle loading_addr_ = addr;
818*9712c20fSFrederick Mayle loaded_file_ = filename;
819*9712c20fSFrederick Mayle return;
820*9712c20fSFrederick Mayle }
821*9712c20fSFrederick Mayle
822*9712c20fSFrederick Mayle if (addr != loading_addr_) {
823*9712c20fSFrederick Mayle fprintf(stderr,
824*9712c20fSFrederick Mayle "ELF file '%s' and debug ELF file '%s' "
825*9712c20fSFrederick Mayle "have different load addresses.\n",
826*9712c20fSFrederick Mayle loaded_file_.c_str(), filename.c_str());
827*9712c20fSFrederick Mayle assert(false);
828*9712c20fSFrederick Mayle }
829*9712c20fSFrederick Mayle }
830*9712c20fSFrederick Mayle
831*9712c20fSFrederick Mayle // Setters and getters
debug_dirs() const832*9712c20fSFrederick Mayle const std::vector<string>& debug_dirs() const {
833*9712c20fSFrederick Mayle return debug_dirs_;
834*9712c20fSFrederick Mayle }
835*9712c20fSFrederick Mayle
debuglink_file() const836*9712c20fSFrederick Mayle string debuglink_file() const {
837*9712c20fSFrederick Mayle return debuglink_file_;
838*9712c20fSFrederick Mayle }
set_debuglink_file(string file)839*9712c20fSFrederick Mayle void set_debuglink_file(string file) {
840*9712c20fSFrederick Mayle debuglink_file_ = file;
841*9712c20fSFrederick Mayle }
842*9712c20fSFrederick Mayle
843*9712c20fSFrederick Mayle private:
844*9712c20fSFrederick Mayle const std::vector<string>& debug_dirs_; // Directories in which to
845*9712c20fSFrederick Mayle // search for the debug ELF file.
846*9712c20fSFrederick Mayle
847*9712c20fSFrederick Mayle string debuglink_file_; // Full path to the debug ELF file.
848*9712c20fSFrederick Mayle
849*9712c20fSFrederick Mayle bool has_loading_addr_; // Indicate if LOADING_ADDR_ is valid.
850*9712c20fSFrederick Mayle
851*9712c20fSFrederick Mayle Addr loading_addr_; // Saves the preferred loading address from the
852*9712c20fSFrederick Mayle // first call to LoadSymbols().
853*9712c20fSFrederick Mayle
854*9712c20fSFrederick Mayle string loaded_file_; // Name of the file loaded from the first call to
855*9712c20fSFrederick Mayle // LoadSymbols().
856*9712c20fSFrederick Mayle
857*9712c20fSFrederick Mayle std::set<string> loaded_sections_; // Tracks the Loaded ELF sections
858*9712c20fSFrederick Mayle // between calls to LoadSymbols().
859*9712c20fSFrederick Mayle };
860*9712c20fSFrederick Mayle
861*9712c20fSFrederick Mayle template<typename ElfClass>
LoadSymbols(const string & obj_file,const bool big_endian,const typename ElfClass::Ehdr * elf_header,const bool read_gnu_debug_link,LoadSymbolsInfo<ElfClass> * info,const DumpOptions & options,Module * module)862*9712c20fSFrederick Mayle bool LoadSymbols(const string& obj_file,
863*9712c20fSFrederick Mayle const bool big_endian,
864*9712c20fSFrederick Mayle const typename ElfClass::Ehdr* elf_header,
865*9712c20fSFrederick Mayle const bool read_gnu_debug_link,
866*9712c20fSFrederick Mayle LoadSymbolsInfo<ElfClass>* info,
867*9712c20fSFrederick Mayle const DumpOptions& options,
868*9712c20fSFrederick Mayle Module* module) {
869*9712c20fSFrederick Mayle typedef typename ElfClass::Addr Addr;
870*9712c20fSFrederick Mayle typedef typename ElfClass::Phdr Phdr;
871*9712c20fSFrederick Mayle typedef typename ElfClass::Shdr Shdr;
872*9712c20fSFrederick Mayle
873*9712c20fSFrederick Mayle Addr loading_addr = GetLoadingAddress<ElfClass>(
874*9712c20fSFrederick Mayle GetOffset<ElfClass, Phdr>(elf_header, elf_header->e_phoff),
875*9712c20fSFrederick Mayle elf_header->e_phnum);
876*9712c20fSFrederick Mayle module->SetLoadAddress(loading_addr);
877*9712c20fSFrederick Mayle info->set_loading_addr(loading_addr, obj_file);
878*9712c20fSFrederick Mayle
879*9712c20fSFrederick Mayle // Allow filtering of extraneous debug information in partitioned libraries.
880*9712c20fSFrederick Mayle // Such libraries contain debug information for all libraries extracted from
881*9712c20fSFrederick Mayle // the same combined library, implying extensive duplication.
882*9712c20fSFrederick Mayle vector<Module::Range> address_ranges = GetPtLoadSegmentRanges<ElfClass>(
883*9712c20fSFrederick Mayle GetOffset<ElfClass, Phdr>(elf_header, elf_header->e_phoff),
884*9712c20fSFrederick Mayle elf_header->e_phnum);
885*9712c20fSFrederick Mayle module->SetAddressRanges(address_ranges);
886*9712c20fSFrederick Mayle
887*9712c20fSFrederick Mayle const Shdr* sections =
888*9712c20fSFrederick Mayle GetOffset<ElfClass, Shdr>(elf_header, elf_header->e_shoff);
889*9712c20fSFrederick Mayle const Shdr* section_names = sections + elf_header->e_shstrndx;
890*9712c20fSFrederick Mayle const char* names =
891*9712c20fSFrederick Mayle GetOffset<ElfClass, char>(elf_header, section_names->sh_offset);
892*9712c20fSFrederick Mayle const char* names_end = names + section_names->sh_size;
893*9712c20fSFrederick Mayle bool found_debug_info_section = false;
894*9712c20fSFrederick Mayle bool found_usable_info = false;
895*9712c20fSFrederick Mayle
896*9712c20fSFrederick Mayle if ((options.symbol_data & SYMBOLS_AND_FILES) ||
897*9712c20fSFrederick Mayle (options.symbol_data & INLINES)) {
898*9712c20fSFrederick Mayle #ifndef NO_STABS_SUPPORT
899*9712c20fSFrederick Mayle // Look for STABS debugging information, and load it if present.
900*9712c20fSFrederick Mayle const Shdr* stab_section =
901*9712c20fSFrederick Mayle FindElfSectionByName<ElfClass>(".stab", SHT_PROGBITS,
902*9712c20fSFrederick Mayle sections, names, names_end,
903*9712c20fSFrederick Mayle elf_header->e_shnum);
904*9712c20fSFrederick Mayle if (stab_section) {
905*9712c20fSFrederick Mayle const Shdr* stabstr_section = stab_section->sh_link + sections;
906*9712c20fSFrederick Mayle if (stabstr_section) {
907*9712c20fSFrederick Mayle found_debug_info_section = true;
908*9712c20fSFrederick Mayle found_usable_info = true;
909*9712c20fSFrederick Mayle info->LoadedSection(".stab");
910*9712c20fSFrederick Mayle if (!LoadStabs<ElfClass>(elf_header, stab_section, stabstr_section,
911*9712c20fSFrederick Mayle big_endian, module)) {
912*9712c20fSFrederick Mayle fprintf(stderr, "%s: \".stab\" section found, but failed to load"
913*9712c20fSFrederick Mayle " STABS debugging information\n", obj_file.c_str());
914*9712c20fSFrederick Mayle }
915*9712c20fSFrederick Mayle }
916*9712c20fSFrederick Mayle }
917*9712c20fSFrederick Mayle #endif // NO_STABS_SUPPORT
918*9712c20fSFrederick Mayle
919*9712c20fSFrederick Mayle // See if there are export symbols available.
920*9712c20fSFrederick Mayle const Shdr* symtab_section =
921*9712c20fSFrederick Mayle FindElfSectionByName<ElfClass>(".symtab", SHT_SYMTAB,
922*9712c20fSFrederick Mayle sections, names, names_end,
923*9712c20fSFrederick Mayle elf_header->e_shnum);
924*9712c20fSFrederick Mayle const Shdr* strtab_section =
925*9712c20fSFrederick Mayle FindElfSectionByName<ElfClass>(".strtab", SHT_STRTAB,
926*9712c20fSFrederick Mayle sections, names, names_end,
927*9712c20fSFrederick Mayle elf_header->e_shnum);
928*9712c20fSFrederick Mayle if (symtab_section && strtab_section) {
929*9712c20fSFrederick Mayle info->LoadedSection(".symtab");
930*9712c20fSFrederick Mayle
931*9712c20fSFrederick Mayle const uint8_t* symtab =
932*9712c20fSFrederick Mayle GetOffset<ElfClass, uint8_t>(elf_header,
933*9712c20fSFrederick Mayle symtab_section->sh_offset);
934*9712c20fSFrederick Mayle const uint8_t* strtab =
935*9712c20fSFrederick Mayle GetOffset<ElfClass, uint8_t>(elf_header,
936*9712c20fSFrederick Mayle strtab_section->sh_offset);
937*9712c20fSFrederick Mayle bool result =
938*9712c20fSFrederick Mayle ELFSymbolsToModule(symtab,
939*9712c20fSFrederick Mayle symtab_section->sh_size,
940*9712c20fSFrederick Mayle strtab,
941*9712c20fSFrederick Mayle strtab_section->sh_size,
942*9712c20fSFrederick Mayle big_endian,
943*9712c20fSFrederick Mayle ElfClass::kAddrSize,
944*9712c20fSFrederick Mayle module);
945*9712c20fSFrederick Mayle found_usable_info = found_usable_info || result;
946*9712c20fSFrederick Mayle } else {
947*9712c20fSFrederick Mayle // Look in dynsym only if full symbol table was not available.
948*9712c20fSFrederick Mayle const Shdr* dynsym_section =
949*9712c20fSFrederick Mayle FindElfSectionByName<ElfClass>(".dynsym", SHT_DYNSYM,
950*9712c20fSFrederick Mayle sections, names, names_end,
951*9712c20fSFrederick Mayle elf_header->e_shnum);
952*9712c20fSFrederick Mayle const Shdr* dynstr_section =
953*9712c20fSFrederick Mayle FindElfSectionByName<ElfClass>(".dynstr", SHT_STRTAB,
954*9712c20fSFrederick Mayle sections, names, names_end,
955*9712c20fSFrederick Mayle elf_header->e_shnum);
956*9712c20fSFrederick Mayle if (dynsym_section && dynstr_section) {
957*9712c20fSFrederick Mayle info->LoadedSection(".dynsym");
958*9712c20fSFrederick Mayle
959*9712c20fSFrederick Mayle const uint8_t* dynsyms =
960*9712c20fSFrederick Mayle GetOffset<ElfClass, uint8_t>(elf_header,
961*9712c20fSFrederick Mayle dynsym_section->sh_offset);
962*9712c20fSFrederick Mayle const uint8_t* dynstrs =
963*9712c20fSFrederick Mayle GetOffset<ElfClass, uint8_t>(elf_header,
964*9712c20fSFrederick Mayle dynstr_section->sh_offset);
965*9712c20fSFrederick Mayle bool result =
966*9712c20fSFrederick Mayle ELFSymbolsToModule(dynsyms,
967*9712c20fSFrederick Mayle dynsym_section->sh_size,
968*9712c20fSFrederick Mayle dynstrs,
969*9712c20fSFrederick Mayle dynstr_section->sh_size,
970*9712c20fSFrederick Mayle big_endian,
971*9712c20fSFrederick Mayle ElfClass::kAddrSize,
972*9712c20fSFrederick Mayle module);
973*9712c20fSFrederick Mayle found_usable_info = found_usable_info || result;
974*9712c20fSFrederick Mayle }
975*9712c20fSFrederick Mayle }
976*9712c20fSFrederick Mayle
977*9712c20fSFrederick Mayle // Only Load .debug_info after loading symbol table to avoid duplicate
978*9712c20fSFrederick Mayle // PUBLIC records.
979*9712c20fSFrederick Mayle // Look for DWARF debugging information, and load it if present.
980*9712c20fSFrederick Mayle const Shdr* dwarf_section =
981*9712c20fSFrederick Mayle FindElfSectionByName<ElfClass>(".debug_info", SHT_PROGBITS,
982*9712c20fSFrederick Mayle sections, names, names_end,
983*9712c20fSFrederick Mayle elf_header->e_shnum);
984*9712c20fSFrederick Mayle
985*9712c20fSFrederick Mayle // .debug_info section type is SHT_PROGBITS for mips on pnacl toolchains,
986*9712c20fSFrederick Mayle // but MIPS_DWARF for regular gnu toolchains, so both need to be checked
987*9712c20fSFrederick Mayle if (elf_header->e_machine == EM_MIPS && !dwarf_section) {
988*9712c20fSFrederick Mayle dwarf_section =
989*9712c20fSFrederick Mayle FindElfSectionByName<ElfClass>(".debug_info", SHT_MIPS_DWARF,
990*9712c20fSFrederick Mayle sections, names, names_end,
991*9712c20fSFrederick Mayle elf_header->e_shnum);
992*9712c20fSFrederick Mayle }
993*9712c20fSFrederick Mayle
994*9712c20fSFrederick Mayle if (dwarf_section) {
995*9712c20fSFrederick Mayle found_debug_info_section = true;
996*9712c20fSFrederick Mayle found_usable_info = true;
997*9712c20fSFrederick Mayle info->LoadedSection(".debug_info");
998*9712c20fSFrederick Mayle if (!LoadDwarf<ElfClass>(obj_file, elf_header, big_endian,
999*9712c20fSFrederick Mayle options.handle_inter_cu_refs,
1000*9712c20fSFrederick Mayle options.symbol_data & INLINES, module)) {
1001*9712c20fSFrederick Mayle fprintf(stderr, "%s: \".debug_info\" section found, but failed to load "
1002*9712c20fSFrederick Mayle "DWARF debugging information\n", obj_file.c_str());
1003*9712c20fSFrederick Mayle }
1004*9712c20fSFrederick Mayle }
1005*9712c20fSFrederick Mayle }
1006*9712c20fSFrederick Mayle
1007*9712c20fSFrederick Mayle if (options.symbol_data & CFI) {
1008*9712c20fSFrederick Mayle // Dwarf Call Frame Information (CFI) is actually independent from
1009*9712c20fSFrederick Mayle // the other DWARF debugging information, and can be used alone.
1010*9712c20fSFrederick Mayle const Shdr* dwarf_cfi_section =
1011*9712c20fSFrederick Mayle FindElfSectionByName<ElfClass>(".debug_frame", SHT_PROGBITS,
1012*9712c20fSFrederick Mayle sections, names, names_end,
1013*9712c20fSFrederick Mayle elf_header->e_shnum);
1014*9712c20fSFrederick Mayle
1015*9712c20fSFrederick Mayle // .debug_frame section type is SHT_PROGBITS for mips on pnacl toolchains,
1016*9712c20fSFrederick Mayle // but MIPS_DWARF for regular gnu toolchains, so both need to be checked
1017*9712c20fSFrederick Mayle if (elf_header->e_machine == EM_MIPS && !dwarf_cfi_section) {
1018*9712c20fSFrederick Mayle dwarf_cfi_section =
1019*9712c20fSFrederick Mayle FindElfSectionByName<ElfClass>(".debug_frame", SHT_MIPS_DWARF,
1020*9712c20fSFrederick Mayle sections, names, names_end,
1021*9712c20fSFrederick Mayle elf_header->e_shnum);
1022*9712c20fSFrederick Mayle }
1023*9712c20fSFrederick Mayle
1024*9712c20fSFrederick Mayle if (dwarf_cfi_section) {
1025*9712c20fSFrederick Mayle // Ignore the return value of this function; even without call frame
1026*9712c20fSFrederick Mayle // information, the other debugging information could be perfectly
1027*9712c20fSFrederick Mayle // useful.
1028*9712c20fSFrederick Mayle info->LoadedSection(".debug_frame");
1029*9712c20fSFrederick Mayle bool result =
1030*9712c20fSFrederick Mayle LoadDwarfCFI<ElfClass>(obj_file, elf_header, ".debug_frame",
1031*9712c20fSFrederick Mayle dwarf_cfi_section, false, 0, 0, big_endian,
1032*9712c20fSFrederick Mayle module);
1033*9712c20fSFrederick Mayle found_usable_info = found_usable_info || result;
1034*9712c20fSFrederick Mayle }
1035*9712c20fSFrederick Mayle
1036*9712c20fSFrederick Mayle // Linux C++ exception handling information can also provide
1037*9712c20fSFrederick Mayle // unwinding data.
1038*9712c20fSFrederick Mayle const Shdr* eh_frame_section =
1039*9712c20fSFrederick Mayle FindElfSectionByName<ElfClass>(".eh_frame", SHT_PROGBITS,
1040*9712c20fSFrederick Mayle sections, names, names_end,
1041*9712c20fSFrederick Mayle elf_header->e_shnum);
1042*9712c20fSFrederick Mayle if (eh_frame_section) {
1043*9712c20fSFrederick Mayle // Pointers in .eh_frame data may be relative to the base addresses of
1044*9712c20fSFrederick Mayle // certain sections. Provide those sections if present.
1045*9712c20fSFrederick Mayle const Shdr* got_section =
1046*9712c20fSFrederick Mayle FindElfSectionByName<ElfClass>(".got", SHT_PROGBITS,
1047*9712c20fSFrederick Mayle sections, names, names_end,
1048*9712c20fSFrederick Mayle elf_header->e_shnum);
1049*9712c20fSFrederick Mayle const Shdr* text_section =
1050*9712c20fSFrederick Mayle FindElfSectionByName<ElfClass>(".text", SHT_PROGBITS,
1051*9712c20fSFrederick Mayle sections, names, names_end,
1052*9712c20fSFrederick Mayle elf_header->e_shnum);
1053*9712c20fSFrederick Mayle info->LoadedSection(".eh_frame");
1054*9712c20fSFrederick Mayle // As above, ignore the return value of this function.
1055*9712c20fSFrederick Mayle bool result =
1056*9712c20fSFrederick Mayle LoadDwarfCFI<ElfClass>(obj_file, elf_header, ".eh_frame",
1057*9712c20fSFrederick Mayle eh_frame_section, true,
1058*9712c20fSFrederick Mayle got_section, text_section, big_endian, module);
1059*9712c20fSFrederick Mayle found_usable_info = found_usable_info || result;
1060*9712c20fSFrederick Mayle }
1061*9712c20fSFrederick Mayle }
1062*9712c20fSFrederick Mayle
1063*9712c20fSFrederick Mayle if (!found_debug_info_section) {
1064*9712c20fSFrederick Mayle fprintf(stderr, "%s: file contains no debugging information"
1065*9712c20fSFrederick Mayle " (no \".stab\" or \".debug_info\" sections)\n",
1066*9712c20fSFrederick Mayle obj_file.c_str());
1067*9712c20fSFrederick Mayle
1068*9712c20fSFrederick Mayle // Failed, but maybe there's a .gnu_debuglink section?
1069*9712c20fSFrederick Mayle if (read_gnu_debug_link) {
1070*9712c20fSFrederick Mayle const Shdr* gnu_debuglink_section
1071*9712c20fSFrederick Mayle = FindElfSectionByName<ElfClass>(".gnu_debuglink", SHT_PROGBITS,
1072*9712c20fSFrederick Mayle sections, names,
1073*9712c20fSFrederick Mayle names_end, elf_header->e_shnum);
1074*9712c20fSFrederick Mayle if (gnu_debuglink_section) {
1075*9712c20fSFrederick Mayle if (!info->debug_dirs().empty()) {
1076*9712c20fSFrederick Mayle const uint8_t* debuglink_contents =
1077*9712c20fSFrederick Mayle GetOffset<ElfClass, uint8_t>(elf_header,
1078*9712c20fSFrederick Mayle gnu_debuglink_section->sh_offset);
1079*9712c20fSFrederick Mayle string debuglink_file =
1080*9712c20fSFrederick Mayle ReadDebugLink(debuglink_contents,
1081*9712c20fSFrederick Mayle gnu_debuglink_section->sh_size,
1082*9712c20fSFrederick Mayle big_endian,
1083*9712c20fSFrederick Mayle obj_file,
1084*9712c20fSFrederick Mayle info->debug_dirs());
1085*9712c20fSFrederick Mayle info->set_debuglink_file(debuglink_file);
1086*9712c20fSFrederick Mayle } else {
1087*9712c20fSFrederick Mayle fprintf(stderr, ".gnu_debuglink section found in '%s', "
1088*9712c20fSFrederick Mayle "but no debug path specified.\n", obj_file.c_str());
1089*9712c20fSFrederick Mayle }
1090*9712c20fSFrederick Mayle } else {
1091*9712c20fSFrederick Mayle fprintf(stderr, "%s does not contain a .gnu_debuglink section.\n",
1092*9712c20fSFrederick Mayle obj_file.c_str());
1093*9712c20fSFrederick Mayle }
1094*9712c20fSFrederick Mayle } else {
1095*9712c20fSFrederick Mayle // Return true if some usable information was found, since the caller
1096*9712c20fSFrederick Mayle // doesn't want to use .gnu_debuglink.
1097*9712c20fSFrederick Mayle return found_usable_info;
1098*9712c20fSFrederick Mayle }
1099*9712c20fSFrederick Mayle
1100*9712c20fSFrederick Mayle // No debug info was found, let the user try again with .gnu_debuglink
1101*9712c20fSFrederick Mayle // if present.
1102*9712c20fSFrederick Mayle return false;
1103*9712c20fSFrederick Mayle }
1104*9712c20fSFrederick Mayle
1105*9712c20fSFrederick Mayle return true;
1106*9712c20fSFrederick Mayle }
1107*9712c20fSFrederick Mayle
1108*9712c20fSFrederick Mayle // Return the breakpad symbol file identifier for the architecture of
1109*9712c20fSFrederick Mayle // ELF_HEADER.
1110*9712c20fSFrederick Mayle template<typename ElfClass>
ElfArchitecture(const typename ElfClass::Ehdr * elf_header)1111*9712c20fSFrederick Mayle const char* ElfArchitecture(const typename ElfClass::Ehdr* elf_header) {
1112*9712c20fSFrederick Mayle typedef typename ElfClass::Half Half;
1113*9712c20fSFrederick Mayle Half arch = elf_header->e_machine;
1114*9712c20fSFrederick Mayle switch (arch) {
1115*9712c20fSFrederick Mayle case EM_386: return "x86";
1116*9712c20fSFrederick Mayle case EM_ARM: return "arm";
1117*9712c20fSFrederick Mayle case EM_AARCH64: return "arm64";
1118*9712c20fSFrederick Mayle case EM_MIPS: return "mips";
1119*9712c20fSFrederick Mayle case EM_PPC64: return "ppc64";
1120*9712c20fSFrederick Mayle case EM_PPC: return "ppc";
1121*9712c20fSFrederick Mayle case EM_S390: return "s390";
1122*9712c20fSFrederick Mayle case EM_SPARC: return "sparc";
1123*9712c20fSFrederick Mayle case EM_SPARCV9: return "sparcv9";
1124*9712c20fSFrederick Mayle case EM_X86_64: return "x86_64";
1125*9712c20fSFrederick Mayle case EM_RISCV: return "riscv";
1126*9712c20fSFrederick Mayle default: return NULL;
1127*9712c20fSFrederick Mayle }
1128*9712c20fSFrederick Mayle }
1129*9712c20fSFrederick Mayle
1130*9712c20fSFrederick Mayle template<typename ElfClass>
SanitizeDebugFile(const typename ElfClass::Ehdr * debug_elf_header,const string & debuglink_file,const string & obj_filename,const char * obj_file_architecture,const bool obj_file_is_big_endian)1131*9712c20fSFrederick Mayle bool SanitizeDebugFile(const typename ElfClass::Ehdr* debug_elf_header,
1132*9712c20fSFrederick Mayle const string& debuglink_file,
1133*9712c20fSFrederick Mayle const string& obj_filename,
1134*9712c20fSFrederick Mayle const char* obj_file_architecture,
1135*9712c20fSFrederick Mayle const bool obj_file_is_big_endian) {
1136*9712c20fSFrederick Mayle const char* debug_architecture =
1137*9712c20fSFrederick Mayle ElfArchitecture<ElfClass>(debug_elf_header);
1138*9712c20fSFrederick Mayle if (!debug_architecture) {
1139*9712c20fSFrederick Mayle fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n",
1140*9712c20fSFrederick Mayle debuglink_file.c_str(), debug_elf_header->e_machine);
1141*9712c20fSFrederick Mayle return false;
1142*9712c20fSFrederick Mayle }
1143*9712c20fSFrederick Mayle if (strcmp(obj_file_architecture, debug_architecture)) {
1144*9712c20fSFrederick Mayle fprintf(stderr, "%s with ELF machine architecture %s does not match "
1145*9712c20fSFrederick Mayle "%s with ELF architecture %s\n",
1146*9712c20fSFrederick Mayle debuglink_file.c_str(), debug_architecture,
1147*9712c20fSFrederick Mayle obj_filename.c_str(), obj_file_architecture);
1148*9712c20fSFrederick Mayle return false;
1149*9712c20fSFrederick Mayle }
1150*9712c20fSFrederick Mayle bool debug_big_endian;
1151*9712c20fSFrederick Mayle if (!ElfEndianness<ElfClass>(debug_elf_header, &debug_big_endian))
1152*9712c20fSFrederick Mayle return false;
1153*9712c20fSFrederick Mayle if (debug_big_endian != obj_file_is_big_endian) {
1154*9712c20fSFrederick Mayle fprintf(stderr, "%s and %s does not match in endianness\n",
1155*9712c20fSFrederick Mayle obj_filename.c_str(), debuglink_file.c_str());
1156*9712c20fSFrederick Mayle return false;
1157*9712c20fSFrederick Mayle }
1158*9712c20fSFrederick Mayle return true;
1159*9712c20fSFrederick Mayle }
1160*9712c20fSFrederick Mayle
1161*9712c20fSFrederick Mayle template<typename ElfClass>
InitModuleForElfClass(const typename ElfClass::Ehdr * elf_header,const string & obj_filename,const string & obj_os,scoped_ptr<Module> & module,bool enable_multiple_field)1162*9712c20fSFrederick Mayle bool InitModuleForElfClass(const typename ElfClass::Ehdr* elf_header,
1163*9712c20fSFrederick Mayle const string& obj_filename,
1164*9712c20fSFrederick Mayle const string& obj_os,
1165*9712c20fSFrederick Mayle scoped_ptr<Module>& module,
1166*9712c20fSFrederick Mayle bool enable_multiple_field) {
1167*9712c20fSFrederick Mayle PageAllocator allocator;
1168*9712c20fSFrederick Mayle wasteful_vector<uint8_t> identifier(&allocator, kDefaultBuildIdSize);
1169*9712c20fSFrederick Mayle if (!FileID::ElfFileIdentifierFromMappedFile(elf_header, identifier)) {
1170*9712c20fSFrederick Mayle fprintf(stderr, "%s: unable to generate file identifier\n",
1171*9712c20fSFrederick Mayle obj_filename.c_str());
1172*9712c20fSFrederick Mayle return false;
1173*9712c20fSFrederick Mayle }
1174*9712c20fSFrederick Mayle
1175*9712c20fSFrederick Mayle const char* architecture = ElfArchitecture<ElfClass>(elf_header);
1176*9712c20fSFrederick Mayle if (!architecture) {
1177*9712c20fSFrederick Mayle fprintf(stderr, "%s: unrecognized ELF machine architecture: %d\n",
1178*9712c20fSFrederick Mayle obj_filename.c_str(), elf_header->e_machine);
1179*9712c20fSFrederick Mayle return false;
1180*9712c20fSFrederick Mayle }
1181*9712c20fSFrederick Mayle
1182*9712c20fSFrederick Mayle char name_buf[NAME_MAX] = {};
1183*9712c20fSFrederick Mayle std::string name = google_breakpad::ElfFileSoNameFromMappedFile(
1184*9712c20fSFrederick Mayle elf_header, name_buf, sizeof(name_buf))
1185*9712c20fSFrederick Mayle ? name_buf
1186*9712c20fSFrederick Mayle : google_breakpad::BaseName(obj_filename);
1187*9712c20fSFrederick Mayle
1188*9712c20fSFrederick Mayle // Add an extra "0" at the end. PDB files on Windows have an 'age'
1189*9712c20fSFrederick Mayle // number appended to the end of the file identifier; this isn't
1190*9712c20fSFrederick Mayle // really used or necessary on other platforms, but be consistent.
1191*9712c20fSFrederick Mayle string id = FileID::ConvertIdentifierToUUIDString(identifier) + "0";
1192*9712c20fSFrederick Mayle // This is just the raw Build ID in hex.
1193*9712c20fSFrederick Mayle string code_id = FileID::ConvertIdentifierToString(identifier);
1194*9712c20fSFrederick Mayle
1195*9712c20fSFrederick Mayle module.reset(new Module(name, obj_os, architecture, id, code_id,
1196*9712c20fSFrederick Mayle enable_multiple_field));
1197*9712c20fSFrederick Mayle
1198*9712c20fSFrederick Mayle return true;
1199*9712c20fSFrederick Mayle }
1200*9712c20fSFrederick Mayle
1201*9712c20fSFrederick Mayle template<typename ElfClass>
ReadSymbolDataElfClass(const typename ElfClass::Ehdr * elf_header,const string & obj_filename,const string & obj_os,const std::vector<string> & debug_dirs,const DumpOptions & options,Module ** out_module)1202*9712c20fSFrederick Mayle bool ReadSymbolDataElfClass(const typename ElfClass::Ehdr* elf_header,
1203*9712c20fSFrederick Mayle const string& obj_filename,
1204*9712c20fSFrederick Mayle const string& obj_os,
1205*9712c20fSFrederick Mayle const std::vector<string>& debug_dirs,
1206*9712c20fSFrederick Mayle const DumpOptions& options,
1207*9712c20fSFrederick Mayle Module** out_module) {
1208*9712c20fSFrederick Mayle typedef typename ElfClass::Ehdr Ehdr;
1209*9712c20fSFrederick Mayle
1210*9712c20fSFrederick Mayle *out_module = NULL;
1211*9712c20fSFrederick Mayle
1212*9712c20fSFrederick Mayle scoped_ptr<Module> module;
1213*9712c20fSFrederick Mayle if (!InitModuleForElfClass<ElfClass>(elf_header, obj_filename, obj_os, module,
1214*9712c20fSFrederick Mayle options.enable_multiple_field)) {
1215*9712c20fSFrederick Mayle return false;
1216*9712c20fSFrederick Mayle }
1217*9712c20fSFrederick Mayle
1218*9712c20fSFrederick Mayle // Figure out what endianness this file is.
1219*9712c20fSFrederick Mayle bool big_endian;
1220*9712c20fSFrederick Mayle if (!ElfEndianness<ElfClass>(elf_header, &big_endian))
1221*9712c20fSFrederick Mayle return false;
1222*9712c20fSFrederick Mayle
1223*9712c20fSFrederick Mayle LoadSymbolsInfo<ElfClass> info(debug_dirs);
1224*9712c20fSFrederick Mayle if (!LoadSymbols<ElfClass>(obj_filename, big_endian, elf_header,
1225*9712c20fSFrederick Mayle !debug_dirs.empty(), &info,
1226*9712c20fSFrederick Mayle options, module.get())) {
1227*9712c20fSFrederick Mayle const string debuglink_file = info.debuglink_file();
1228*9712c20fSFrederick Mayle if (debuglink_file.empty())
1229*9712c20fSFrederick Mayle return false;
1230*9712c20fSFrederick Mayle
1231*9712c20fSFrederick Mayle // Load debuglink ELF file.
1232*9712c20fSFrederick Mayle fprintf(stderr, "Found debugging info in %s\n", debuglink_file.c_str());
1233*9712c20fSFrederick Mayle MmapWrapper debug_map_wrapper;
1234*9712c20fSFrederick Mayle Ehdr* debug_elf_header = NULL;
1235*9712c20fSFrederick Mayle if (!LoadELF(debuglink_file, &debug_map_wrapper,
1236*9712c20fSFrederick Mayle reinterpret_cast<void**>(&debug_elf_header)) ||
1237*9712c20fSFrederick Mayle !SanitizeDebugFile<ElfClass>(debug_elf_header, debuglink_file,
1238*9712c20fSFrederick Mayle obj_filename,
1239*9712c20fSFrederick Mayle module->architecture().c_str(),
1240*9712c20fSFrederick Mayle big_endian)) {
1241*9712c20fSFrederick Mayle return false;
1242*9712c20fSFrederick Mayle }
1243*9712c20fSFrederick Mayle
1244*9712c20fSFrederick Mayle if (!LoadSymbols<ElfClass>(debuglink_file, big_endian,
1245*9712c20fSFrederick Mayle debug_elf_header, false, &info,
1246*9712c20fSFrederick Mayle options, module.get())) {
1247*9712c20fSFrederick Mayle return false;
1248*9712c20fSFrederick Mayle }
1249*9712c20fSFrederick Mayle }
1250*9712c20fSFrederick Mayle
1251*9712c20fSFrederick Mayle *out_module = module.release();
1252*9712c20fSFrederick Mayle return true;
1253*9712c20fSFrederick Mayle }
1254*9712c20fSFrederick Mayle
1255*9712c20fSFrederick Mayle } // namespace
1256*9712c20fSFrederick Mayle
1257*9712c20fSFrederick Mayle namespace google_breakpad {
1258*9712c20fSFrederick Mayle
1259*9712c20fSFrederick Mayle // Not explicitly exported, but not static so it can be used in unit tests.
ReadSymbolDataInternal(const uint8_t * obj_file,const string & obj_filename,const string & obj_os,const std::vector<string> & debug_dirs,const DumpOptions & options,Module ** module)1260*9712c20fSFrederick Mayle bool ReadSymbolDataInternal(const uint8_t* obj_file,
1261*9712c20fSFrederick Mayle const string& obj_filename,
1262*9712c20fSFrederick Mayle const string& obj_os,
1263*9712c20fSFrederick Mayle const std::vector<string>& debug_dirs,
1264*9712c20fSFrederick Mayle const DumpOptions& options,
1265*9712c20fSFrederick Mayle Module** module) {
1266*9712c20fSFrederick Mayle if (!IsValidElf(obj_file)) {
1267*9712c20fSFrederick Mayle fprintf(stderr, "Not a valid ELF file: %s\n", obj_filename.c_str());
1268*9712c20fSFrederick Mayle return false;
1269*9712c20fSFrederick Mayle }
1270*9712c20fSFrederick Mayle
1271*9712c20fSFrederick Mayle int elfclass = ElfClass(obj_file);
1272*9712c20fSFrederick Mayle if (elfclass == ELFCLASS32) {
1273*9712c20fSFrederick Mayle return ReadSymbolDataElfClass<ElfClass32>(
1274*9712c20fSFrederick Mayle reinterpret_cast<const Elf32_Ehdr*>(obj_file), obj_filename, obj_os,
1275*9712c20fSFrederick Mayle debug_dirs, options, module);
1276*9712c20fSFrederick Mayle }
1277*9712c20fSFrederick Mayle if (elfclass == ELFCLASS64) {
1278*9712c20fSFrederick Mayle return ReadSymbolDataElfClass<ElfClass64>(
1279*9712c20fSFrederick Mayle reinterpret_cast<const Elf64_Ehdr*>(obj_file), obj_filename, obj_os,
1280*9712c20fSFrederick Mayle debug_dirs, options, module);
1281*9712c20fSFrederick Mayle }
1282*9712c20fSFrederick Mayle
1283*9712c20fSFrederick Mayle return false;
1284*9712c20fSFrederick Mayle }
1285*9712c20fSFrederick Mayle
WriteSymbolFile(const string & load_path,const string & obj_file,const string & obj_os,const std::vector<string> & debug_dirs,const DumpOptions & options,std::ostream & sym_stream)1286*9712c20fSFrederick Mayle bool WriteSymbolFile(const string& load_path,
1287*9712c20fSFrederick Mayle const string& obj_file,
1288*9712c20fSFrederick Mayle const string& obj_os,
1289*9712c20fSFrederick Mayle const std::vector<string>& debug_dirs,
1290*9712c20fSFrederick Mayle const DumpOptions& options,
1291*9712c20fSFrederick Mayle std::ostream& sym_stream) {
1292*9712c20fSFrederick Mayle Module* module;
1293*9712c20fSFrederick Mayle if (!ReadSymbolData(load_path, obj_file, obj_os, debug_dirs, options,
1294*9712c20fSFrederick Mayle &module))
1295*9712c20fSFrederick Mayle return false;
1296*9712c20fSFrederick Mayle
1297*9712c20fSFrederick Mayle bool result = module->Write(sym_stream, options.symbol_data);
1298*9712c20fSFrederick Mayle delete module;
1299*9712c20fSFrederick Mayle return result;
1300*9712c20fSFrederick Mayle }
1301*9712c20fSFrederick Mayle
1302*9712c20fSFrederick Mayle // Read the selected object file's debugging information, and write out the
1303*9712c20fSFrederick Mayle // header only to |stream|. Return true on success; if an error occurs, report
1304*9712c20fSFrederick Mayle // it and return false.
WriteSymbolFileHeader(const string & load_path,const string & obj_file,const string & obj_os,std::ostream & sym_stream)1305*9712c20fSFrederick Mayle bool WriteSymbolFileHeader(const string& load_path,
1306*9712c20fSFrederick Mayle const string& obj_file,
1307*9712c20fSFrederick Mayle const string& obj_os,
1308*9712c20fSFrederick Mayle std::ostream& sym_stream) {
1309*9712c20fSFrederick Mayle MmapWrapper map_wrapper;
1310*9712c20fSFrederick Mayle void* elf_header = NULL;
1311*9712c20fSFrederick Mayle if (!LoadELF(load_path, &map_wrapper, &elf_header)) {
1312*9712c20fSFrederick Mayle fprintf(stderr, "Could not load ELF file: %s\n", obj_file.c_str());
1313*9712c20fSFrederick Mayle return false;
1314*9712c20fSFrederick Mayle }
1315*9712c20fSFrederick Mayle
1316*9712c20fSFrederick Mayle if (!IsValidElf(elf_header)) {
1317*9712c20fSFrederick Mayle fprintf(stderr, "Not a valid ELF file: %s\n", obj_file.c_str());
1318*9712c20fSFrederick Mayle return false;
1319*9712c20fSFrederick Mayle }
1320*9712c20fSFrederick Mayle
1321*9712c20fSFrederick Mayle int elfclass = ElfClass(elf_header);
1322*9712c20fSFrederick Mayle scoped_ptr<Module> module;
1323*9712c20fSFrederick Mayle if (elfclass == ELFCLASS32) {
1324*9712c20fSFrederick Mayle if (!InitModuleForElfClass<ElfClass32>(
1325*9712c20fSFrederick Mayle reinterpret_cast<const Elf32_Ehdr*>(elf_header), obj_file, obj_os,
1326*9712c20fSFrederick Mayle module, /*enable_multiple_field=*/false)) {
1327*9712c20fSFrederick Mayle fprintf(stderr, "Failed to load ELF module: %s\n", obj_file.c_str());
1328*9712c20fSFrederick Mayle return false;
1329*9712c20fSFrederick Mayle }
1330*9712c20fSFrederick Mayle } else if (elfclass == ELFCLASS64) {
1331*9712c20fSFrederick Mayle if (!InitModuleForElfClass<ElfClass64>(
1332*9712c20fSFrederick Mayle reinterpret_cast<const Elf64_Ehdr*>(elf_header), obj_file, obj_os,
1333*9712c20fSFrederick Mayle module, /*enable_multiple_field=*/false)) {
1334*9712c20fSFrederick Mayle fprintf(stderr, "Failed to load ELF module: %s\n", obj_file.c_str());
1335*9712c20fSFrederick Mayle return false;
1336*9712c20fSFrederick Mayle }
1337*9712c20fSFrederick Mayle } else {
1338*9712c20fSFrederick Mayle fprintf(stderr, "Unsupported module file: %s\n", obj_file.c_str());
1339*9712c20fSFrederick Mayle return false;
1340*9712c20fSFrederick Mayle }
1341*9712c20fSFrederick Mayle
1342*9712c20fSFrederick Mayle return module->Write(sym_stream, ALL_SYMBOL_DATA);
1343*9712c20fSFrederick Mayle }
1344*9712c20fSFrederick Mayle
ReadSymbolData(const string & load_path,const string & obj_file,const string & obj_os,const std::vector<string> & debug_dirs,const DumpOptions & options,Module ** module)1345*9712c20fSFrederick Mayle bool ReadSymbolData(const string& load_path,
1346*9712c20fSFrederick Mayle const string& obj_file,
1347*9712c20fSFrederick Mayle const string& obj_os,
1348*9712c20fSFrederick Mayle const std::vector<string>& debug_dirs,
1349*9712c20fSFrederick Mayle const DumpOptions& options,
1350*9712c20fSFrederick Mayle Module** module) {
1351*9712c20fSFrederick Mayle MmapWrapper map_wrapper;
1352*9712c20fSFrederick Mayle void* elf_header = NULL;
1353*9712c20fSFrederick Mayle if (!LoadELF(load_path, &map_wrapper, &elf_header))
1354*9712c20fSFrederick Mayle return false;
1355*9712c20fSFrederick Mayle
1356*9712c20fSFrederick Mayle return ReadSymbolDataInternal(reinterpret_cast<uint8_t*>(elf_header),
1357*9712c20fSFrederick Mayle obj_file, obj_os, debug_dirs, options, module);
1358*9712c20fSFrederick Mayle }
1359*9712c20fSFrederick Mayle
1360*9712c20fSFrederick Mayle } // namespace google_breakpad
1361