1 | // -*- mode: c++ -*- |
2 | |
3 | // Copyright (c) 2011, Google Inc. |
4 | // All rights reserved. |
5 | // |
6 | // Redistribution and use in source and binary forms, with or without |
7 | // modification, are permitted provided that the following conditions are |
8 | // met: |
9 | // |
10 | // * Redistributions of source code must retain the above copyright |
11 | // notice, this list of conditions and the following disclaimer. |
12 | // * Redistributions in binary form must reproduce the above |
13 | // copyright notice, this list of conditions and the following disclaimer |
14 | // in the documentation and/or other materials provided with the |
15 | // distribution. |
16 | // * Neither the name of Google Inc. nor the names of its |
17 | // contributors may be used to endorse or promote products derived from |
18 | // this software without specific prior written permission. |
19 | // |
20 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
21 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
22 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
23 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
24 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
25 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
26 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
27 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
28 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
29 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
30 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
31 | |
32 | // Author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> |
33 | |
34 | // dump_syms.h: Declaration of google_breakpad::DumpSymbols, a class for |
35 | // reading debugging information from Mach-O files and writing it out as a |
36 | // Breakpad symbol file. |
37 | |
38 | #include <mach-o/loader.h> |
39 | #include <stdio.h> |
40 | #include <stdlib.h> |
41 | |
42 | #include <ostream> |
43 | #include <string> |
44 | #include <vector> |
45 | |
46 | #include "common/byte_cursor.h" |
47 | #include "common/mac/macho_reader.h" |
48 | #include "common/mac/super_fat_arch.h" |
49 | #include "common/module.h" |
50 | #include "common/scoped_ptr.h" |
51 | #include "common/symbol_data.h" |
52 | |
53 | namespace google_breakpad { |
54 | |
55 | class DumpSymbols { |
56 | public: |
57 | DumpSymbols(SymbolData symbol_data, bool handle_inter_cu_refs) |
58 | : symbol_data_(symbol_data), |
59 | handle_inter_cu_refs_(handle_inter_cu_refs), |
60 | object_filename_(), |
61 | contents_(), |
62 | size_(0), |
63 | from_disk_(false), |
64 | object_files_(), |
65 | selected_object_file_(), |
66 | selected_object_name_() {} |
67 | ~DumpSymbols() { |
68 | } |
69 | |
70 | // Prepare to read debugging information from |filename|. |filename| may be |
71 | // the name of a fat file, a Mach-O file, or a dSYM bundle containing either |
72 | // of the above. On success, return true; if there is a problem reading |
73 | // |filename|, report it and return false. |
74 | bool Read(const std::string& filename); |
75 | |
76 | // Prepare to read debugging information from |contents|. |contents| is |
77 | // expected to be the data obtained from reading a fat file, or a Mach-O file. |
78 | // |filename| is used to determine the object filename in the generated |
79 | // output; there will not be an attempt to open this file as the data |
80 | // is already expected to be in memory. On success, return true; if there is a |
81 | // problem reading |contents|, report it and return false. |
82 | bool ReadData(uint8_t* contents, size_t size, const std::string& filename); |
83 | |
84 | // If this dumper's file includes an object file for |cpu_type| and |
85 | // |cpu_subtype|, then select that object file for dumping, and return |
86 | // true. Otherwise, return false, and leave this dumper's selected |
87 | // architecture unchanged. |
88 | // |
89 | // By default, if this dumper's file contains only one object file, then |
90 | // the dumper will dump those symbols; and if it contains more than one |
91 | // object file, then the dumper will dump the object file whose |
92 | // architecture matches that of this dumper program. |
93 | bool SetArchitecture(cpu_type_t cpu_type, cpu_subtype_t cpu_subtype); |
94 | |
95 | // If this dumper's file includes an object file for |arch_name|, then select |
96 | // that object file for dumping, and return true. Otherwise, return false, |
97 | // and leave this dumper's selected architecture unchanged. |
98 | // |
99 | // By default, if this dumper's file contains only one object file, then |
100 | // the dumper will dump those symbols; and if it contains more than one |
101 | // object file, then the dumper will dump the object file whose |
102 | // architecture matches that of this dumper program. |
103 | bool SetArchitecture(const std::string& arch_name); |
104 | |
105 | // Return a pointer to an array of SuperFatArch structures describing the |
106 | // object files contained in this dumper's file. Set *|count| to the number |
107 | // of elements in the array. The returned array is owned by this DumpSymbols |
108 | // instance. |
109 | // |
110 | // If there are no available architectures, this function |
111 | // may return NULL. |
112 | const SuperFatArch* AvailableArchitectures(size_t* count) { |
113 | *count = object_files_.size(); |
114 | if (object_files_.size() > 0) |
115 | return &object_files_[0]; |
116 | return NULL; |
117 | } |
118 | |
119 | // Read the selected object file's debugging information, and write it out to |
120 | // |stream|. Return true on success; if an error occurs, report it and |
121 | // return false. |
122 | bool WriteSymbolFile(std::ostream& stream); |
123 | |
124 | // Read the selected object file's debugging information, and write out the |
125 | // header only to |stream|. Return true on success; if an error occurs, report |
126 | // it and return false. |
127 | bool (std::ostream& stream); |
128 | |
129 | // As above, but simply return the debugging information in module |
130 | // instead of writing it to a stream. The caller owns the resulting |
131 | // module object and must delete it when finished. |
132 | bool ReadSymbolData(Module** module); |
133 | |
134 | // Return an identifier string for the file this DumpSymbols is dumping. |
135 | std::string Identifier(); |
136 | |
137 | private: |
138 | // Used internally. |
139 | class DumperLineToModule; |
140 | class DumperRangesHandler; |
141 | class LoadCommandDumper; |
142 | |
143 | // This method behaves similarly to NXFindBestFatArch, but it supports |
144 | // SuperFatArch. |
145 | SuperFatArch* FindBestMatchForArchitecture( |
146 | cpu_type_t cpu_type, cpu_subtype_t cpu_subtype); |
147 | |
148 | // Creates an empty module object. |
149 | bool CreateEmptyModule(scoped_ptr<Module>& module); |
150 | |
151 | // Read debugging information from |dwarf_sections|, which was taken from |
152 | // |macho_reader|, and add it to |module|. |
153 | void ReadDwarf(google_breakpad::Module* module, |
154 | const mach_o::Reader& macho_reader, |
155 | const mach_o::SectionMap& dwarf_sections, |
156 | bool handle_inter_cu_refs) const; |
157 | |
158 | // Read DWARF CFI or .eh_frame data from |section|, belonging to |
159 | // |macho_reader|, and record it in |module|. If |eh_frame| is true, |
160 | // then the data is .eh_frame-format data; otherwise, it is standard DWARF |
161 | // .debug_frame data. On success, return true; on failure, report |
162 | // the problem and return false. |
163 | bool ReadCFI(google_breakpad::Module* module, |
164 | const mach_o::Reader& macho_reader, |
165 | const mach_o::Section& section, |
166 | bool eh_frame) const; |
167 | |
168 | // The selection of what type of symbol data to read/write. |
169 | const SymbolData symbol_data_; |
170 | |
171 | // Whether to handle references between compilation units. |
172 | const bool handle_inter_cu_refs_; |
173 | |
174 | // The name of the file this DumpSymbols will actually read debugging |
175 | // information from. If the filename passed to Read refers to a dSYM bundle, |
176 | // then this is the resource file within that bundle. |
177 | std::string object_filename_; |
178 | |
179 | // The complete contents of object_filename_, mapped into memory. |
180 | scoped_array<uint8_t> contents_; |
181 | |
182 | // The size of contents_. |
183 | size_t size_; |
184 | |
185 | // Indicates which entry point to DumpSymbols was used, i.e. Read vs ReadData. |
186 | // This is used to indicate that downstream code paths can/should also read |
187 | // from disk or not. |
188 | bool from_disk_; |
189 | |
190 | // A vector of SuperFatArch structures describing the object files |
191 | // object_filename_ contains. If object_filename_ refers to a fat binary, |
192 | // this may have more than one element; if it refers to a Mach-O file, this |
193 | // has exactly one element. |
194 | vector<SuperFatArch> object_files_; |
195 | |
196 | // The object file in object_files_ selected to dump, or NULL if |
197 | // SetArchitecture hasn't been called yet. |
198 | const SuperFatArch* selected_object_file_; |
199 | |
200 | // A string that identifies the selected object file, for use in error |
201 | // messages. This is usually object_filename_, but if that refers to a |
202 | // fat binary, it includes an indication of the particular architecture |
203 | // within that binary. |
204 | string selected_object_name_; |
205 | }; |
206 | |
207 | } // namespace google_breakpad |
208 | |