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
53namespace google_breakpad {
54
55class 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 WriteSymbolFileHeader(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