Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: src/common/mac/dump_syms.cc

Issue 1340543002: Fix Mac Breakpad host tools to build in Linux cross-compile (Closed) Base URL: https://chromium.googlesource.com/breakpad/breakpad.git@master
Patch Set: Move mac-headers to mac_headers Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/common/mac/dump_syms.h ('k') | src/common/mac/dump_syms.mm » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // -*- mode: c++ -*- 1 // -*- mode: c++ -*-
2 2
3 // Copyright (c) 2011, Google Inc. 3 // Copyright (c) 2011, Google Inc.
4 // All rights reserved. 4 // All rights reserved.
5 // 5 //
6 // Redistribution and use in source and binary forms, with or without 6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are 7 // modification, are permitted provided that the following conditions are
8 // met: 8 // met:
9 // 9 //
10 // * Redistributions of source code must retain the above copyright 10 // * Redistributions of source code must retain the above copyright
(...skipping 18 matching lines...) Expand all
29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 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. 30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 31
32 // Author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com> 32 // Author: Jim Blandy <jimb@mozilla.com> <jimb@red-bean.com>
33 33
34 // dump_syms.mm: Create a symbol file for use with minidumps 34 // dump_syms.mm: Create a symbol file for use with minidumps
35 35
36 #include "common/mac/dump_syms.h" 36 #include "common/mac/dump_syms.h"
37 37
38 #include <assert.h> 38 #include <assert.h>
39 #include <Foundation/Foundation.h> 39 #include <dirent.h>
40 #include <errno.h>
41 #include <libgen.h>
40 #include <mach-o/arch.h> 42 #include <mach-o/arch.h>
41 #include <mach-o/fat.h> 43 #include <mach-o/fat.h>
42 #include <stdio.h> 44 #include <stdio.h>
45 #include <sys/stat.h>
46 #include <sys/types.h>
47 #include <unistd.h>
43 48
44 #include <ostream> 49 #include <ostream>
45 #include <string> 50 #include <string>
46 #include <vector> 51 #include <vector>
47 52
48 #include "common/dwarf/bytereader-inl.h" 53 #include "common/dwarf/bytereader-inl.h"
49 #include "common/dwarf/dwarf2reader.h" 54 #include "common/dwarf/dwarf2reader.h"
50 #include "common/dwarf_cfi_to_module.h" 55 #include "common/dwarf_cfi_to_module.h"
51 #include "common/dwarf_cu_to_module.h" 56 #include "common/dwarf_cu_to_module.h"
52 #include "common/dwarf_line_to_module.h" 57 #include "common/dwarf_line_to_module.h"
(...skipping 23 matching lines...) Expand all
76 using google_breakpad::mach_o::Segment; 81 using google_breakpad::mach_o::Segment;
77 using google_breakpad::Module; 82 using google_breakpad::Module;
78 using google_breakpad::StabsReader; 83 using google_breakpad::StabsReader;
79 using google_breakpad::StabsToModule; 84 using google_breakpad::StabsToModule;
80 using google_breakpad::scoped_ptr; 85 using google_breakpad::scoped_ptr;
81 using std::make_pair; 86 using std::make_pair;
82 using std::pair; 87 using std::pair;
83 using std::string; 88 using std::string;
84 using std::vector; 89 using std::vector;
85 90
91 namespace {
92 // Return a vector<string> with absolute paths to all the entries
93 // in directory (excluding . and ..).
94 const vector<string> list_directory(const string& directory) {
Mark Mentovai 2015/09/15 18:24:23 The return value shouldn’t be const. It’s up to th
Ted Mielczarek 2015/09/16 10:45:32 Done.
95 vector<string> entries;
96 DIR* dir = opendir(directory.c_str());
97 if (!dir) {
98 return entries;
99 }
100
101 string path = directory;
102 if (path[path.length() - 1] != '/') {
103 path += '/';
104 }
105
106 struct dirent* entry = NULL;
107 while ((entry = readdir(dir))) {
108 if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
109 entries.push_back(path + entry->d_name);
110 }
111 }
112
113 closedir(dir);
114 return entries;
115 }
116 }
117
86 namespace google_breakpad { 118 namespace google_breakpad {
87 119
88 bool DumpSymbols::Read(NSString *filename) { 120 bool DumpSymbols::Read(const string &filename) {
89 if (![[NSFileManager defaultManager] fileExistsAtPath:filename]) { 121 struct stat st;
90 fprintf(stderr, "Object file does not exist: %s\n", 122 if (stat(filename.c_str(), &st) == -1) {
91 [filename fileSystemRepresentation]); 123 fprintf(stderr, "Could not access object file %s: %s\n",
124 filename.c_str(), strerror(errno));
92 return false; 125 return false;
93 } 126 }
94 127
95 input_pathname_ = [filename retain]; 128 input_pathname_ = filename;
96 129
97 // Does this filename refer to a dSYM bundle? 130 // Does this filename refer to a dSYM bundle?
98 NSBundle *bundle = [NSBundle bundleWithPath:input_pathname_]; 131 string contents_path = input_pathname_ + "/Contents/Resources/DWARF";
132 if (S_ISDIR(st.st_mode) &&
133 access(contents_path.c_str(), F_OK) == 0) {
134 // If there's one file under Contents/Resources/DWARF then use that,
135 // otherwise bail out.
136 const vector<string> entries = list_directory(contents_path);
137 if (entries.size() == 0) {
138 fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n",
139 input_pathname_.c_str());
140 return false;
141 }
142 if (entries.size() > 1) {
143 fprintf(stderr, "Too many DWARF files in bundle: %s\n",
144 input_pathname_.c_str());
145 return false;
146 }
99 147
100 if (bundle) { 148 object_filename_ = entries[0];
101 // Filenames referring to bundles usually have names of the form
102 // "<basename>.dSYM"; however, if the user has specified a wrapper
103 // suffix (the WRAPPER_SUFFIX and WRAPPER_EXTENSION build settings),
104 // then the name may have the form "<basename>.<extension>.dSYM". In
105 // either case, the resource name for the file containing the DWARF
106 // info within the bundle is <basename>.
107 //
108 // Since there's no way to tell how much to strip off, remove one
109 // extension at a time, and use the first one that
110 // pathForResource:ofType:inDirectory likes.
111 NSString *base_name = [input_pathname_ lastPathComponent];
112 NSString *dwarf_resource;
113
114 do {
115 NSString *new_base_name = [base_name stringByDeletingPathExtension];
116
117 // If stringByDeletingPathExtension returned the name unchanged, then
118 // there's nothing more for us to strip off --- lose.
119 if ([new_base_name isEqualToString:base_name]) {
120 fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n",
121 [input_pathname_ fileSystemRepresentation]);
122 return false;
123 }
124
125 // Take the shortened result as our new base_name.
126 base_name = new_base_name;
127
128 // Try to find a DWARF resource in the bundle under the new base_name.
129 dwarf_resource = [bundle pathForResource:base_name
130 ofType:nil inDirectory:@"DWARF"];
131 } while (!dwarf_resource);
132
133 object_filename_ = [dwarf_resource retain];
134 } else { 149 } else {
135 object_filename_ = [input_pathname_ retain]; 150 object_filename_ = input_pathname_;
136 } 151 }
137 152
138 // Read the file's contents into memory. 153 // Read the file's contents into memory.
139 // 154 bool read_ok = true;
140 // The documentation for dataWithContentsOfMappedFile says: 155 string error;
141 // 156 if (stat(object_filename_.c_str(), &st) != -1) {
142 // Because of file mapping restrictions, this method should only be 157 FILE* f = fopen(object_filename_.c_str(), "rb");
143 // used if the file is guaranteed to exist for the duration of the 158 if (f) {
144 // data object’s existence. It is generally safer to use the 159 contents_.reset(new uint8_t[st.st_size]);
145 // dataWithContentsOfFile: method. 160 off_t total = 0;
146 // 161 while (total < st.st_size && !feof(f)) {
147 // I gather this means that OS X doesn't have (or at least, that method 162 size_t read = fread(&contents_[0] + total, 1, st.st_size - total, f);
148 // doesn't use) a form of mapping like Linux's MAP_PRIVATE, where the 163 if (read == 0) {
149 // process appears to get its own copy of the data, and changes to the 164 if (ferror(f)) {
150 // file don't affect memory and vice versa). 165 read_ok = false;
151 NSError *error; 166 error = strerror(errno);
152 contents_ = [NSData dataWithContentsOfFile:object_filename_ 167 }
153 options:0 168 break;
154 error:&error]; 169 }
155 if (!contents_) { 170 total += read;
171 }
172 fclose(f);
173 } else {
174 error = strerror(errno);
175 }
176 }
177
178 if (!read_ok) {
156 fprintf(stderr, "Error reading object file: %s: %s\n", 179 fprintf(stderr, "Error reading object file: %s: %s\n",
157 [object_filename_ fileSystemRepresentation], 180 object_filename_.c_str(),
158 [[error localizedDescription] UTF8String]); 181 error.c_str());
159 return false;
160 }
161 [contents_ retain];
162
163 // Get the list of object files present in the file.
164 FatReader::Reporter fat_reporter([object_filename_
165 fileSystemRepresentation]);
166 FatReader fat_reader(&fat_reporter);
167 if (!fat_reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes]),
168 [contents_ length])) {
169 return false; 182 return false;
170 } 183 }
171 184
185 // Get the list of object files present in the file.
186 FatReader::Reporter fat_reporter(object_filename_);
187 FatReader fat_reader(&fat_reporter);
188 if (!fat_reader.Read(&contents_[0],
189 st.st_size)) {
190 return false;
191 }
192
172 // Get our own copy of fat_reader's object file list. 193 // Get our own copy of fat_reader's object file list.
173 size_t object_files_count; 194 size_t object_files_count;
174 const SuperFatArch *object_files = 195 const SuperFatArch *object_files =
175 fat_reader.object_files(&object_files_count); 196 fat_reader.object_files(&object_files_count);
176 if (object_files_count == 0) { 197 if (object_files_count == 0) {
177 fprintf(stderr, "Fat binary file contains *no* architectures: %s\n", 198 fprintf(stderr, "Fat binary file contains *no* architectures: %s\n",
178 [object_filename_ fileSystemRepresentation]); 199 object_filename_.c_str());
179 return false; 200 return false;
180 } 201 }
181 object_files_.resize(object_files_count); 202 object_files_.resize(object_files_count);
182 memcpy(&object_files_[0], object_files, 203 memcpy(&object_files_[0], object_files,
183 sizeof(SuperFatArch) * object_files_count); 204 sizeof(SuperFatArch) * object_files_count);
184 205
185 return true; 206 return true;
186 } 207 }
187 208
188 bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type, 209 bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 return &object_files_[i]; 257 return &object_files_[i];
237 } 258 }
238 assert(best_match == NULL); 259 assert(best_match == NULL);
239 return NULL; 260 return NULL;
240 } 261 }
241 262
242 // Check for an exact match with cpu_type and cpu_subtype. 263 // Check for an exact match with cpu_type and cpu_subtype.
243 for (vector<SuperFatArch>::iterator it = object_files_.begin(); 264 for (vector<SuperFatArch>::iterator it = object_files_.begin();
244 it != object_files_.end(); 265 it != object_files_.end();
245 ++it) { 266 ++it) {
246 if (it->cputype == cpu_type && it->cpusubtype == cpu_subtype) 267 if (static_cast<cpu_type_t>(it->cputype) == cpu_type &&
268 static_cast<cpu_subtype_t>(it->cpusubtype) == cpu_subtype)
247 return &*it; 269 return &*it;
248 } 270 }
249 271
250 // No exact match found. 272 // No exact match found.
251 // TODO(erikchen): If it becomes necessary, we can copy the implementation of 273 // TODO(erikchen): If it becomes necessary, we can copy the implementation of
252 // NXFindBestFatArch, located at 274 // NXFindBestFatArch, located at
253 // http://web.mit.edu/darwin/src/modules/cctools/libmacho/arch.c. 275 // http://web.mit.edu/darwin/src/modules/cctools/libmacho/arch.c.
254 fprintf(stderr, "Failed to find an exact match for an object file with cpu " 276 fprintf(stderr, "Failed to find an exact match for an object file with cpu "
255 "type: %d and cpu subtype: %d. Furthermore, at least one object file is " 277 "type: %d and cpu subtype: %d. Furthermore, at least one object file is "
256 "larger than 2**32.\n", cpu_type, cpu_subtype); 278 "larger than 2**32.\n", cpu_type, cpu_subtype);
257 return NULL; 279 return NULL;
258 } 280 }
259 281
260 string DumpSymbols::Identifier() { 282 string DumpSymbols::Identifier() {
261 FileID file_id([object_filename_ fileSystemRepresentation]); 283 FileID file_id(object_filename_.c_str());
262 unsigned char identifier_bytes[16]; 284 unsigned char identifier_bytes[16];
263 cpu_type_t cpu_type = selected_object_file_->cputype; 285 cpu_type_t cpu_type = selected_object_file_->cputype;
264 cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype; 286 cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype;
265 if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) { 287 if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) {
266 fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n", 288 fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n",
267 [object_filename_ fileSystemRepresentation]); 289 object_filename_.c_str());
268 return ""; 290 return "";
269 } 291 }
270 292
271 char identifier_string[40]; 293 char identifier_string[40];
272 FileID::ConvertIdentifierToString(identifier_bytes, identifier_string, 294 FileID::ConvertIdentifierToString(identifier_bytes, identifier_string,
273 sizeof(identifier_string)); 295 sizeof(identifier_string));
274 296
275 string compacted(identifier_string); 297 string compacted(identifier_string);
276 for(size_t i = compacted.find('-'); i != string::npos; 298 for(size_t i = compacted.find('-'); i != string::npos;
277 i = compacted.find('-', i)) 299 i = compacted.find('-', i))
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 if (object_files_.size() == 1) 541 if (object_files_.size() == 1)
520 selected_object_file_ = &object_files_[0]; 542 selected_object_file_ = &object_files_[0];
521 else { 543 else {
522 // Look for an object file whose architecture matches our own. 544 // Look for an object file whose architecture matches our own.
523 const NXArchInfo *local_arch = NXGetLocalArchInfo(); 545 const NXArchInfo *local_arch = NXGetLocalArchInfo();
524 if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) { 546 if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) {
525 fprintf(stderr, "%s: object file contains more than one" 547 fprintf(stderr, "%s: object file contains more than one"
526 " architecture, none of which match the current" 548 " architecture, none of which match the current"
527 " architecture; specify an architecture explicitly" 549 " architecture; specify an architecture explicitly"
528 " with '-a ARCH' to resolve the ambiguity\n", 550 " with '-a ARCH' to resolve the ambiguity\n",
529 [object_filename_ fileSystemRepresentation]); 551 object_filename_.c_str());
530 return false; 552 return false;
531 } 553 }
532 } 554 }
533 } 555 }
534 556
535 assert(selected_object_file_); 557 assert(selected_object_file_);
536 558
537 // Find the name of the selected file's architecture, to appear in 559 // Find the name of the selected file's architecture, to appear in
538 // the MODULE record and in error messages. 560 // the MODULE record and in error messages.
539 const NXArchInfo *selected_arch_info = 561 const NXArchInfo *selected_arch_info =
540 google_breakpad::BreakpadGetArchInfoFromCpuType( 562 google_breakpad::BreakpadGetArchInfoFromCpuType(
541 selected_object_file_->cputype, selected_object_file_->cpusubtype); 563 selected_object_file_->cputype, selected_object_file_->cpusubtype);
542 564
543 const char *selected_arch_name = selected_arch_info->name; 565 const char *selected_arch_name = selected_arch_info->name;
544 if (strcmp(selected_arch_name, "i386") == 0) 566 if (strcmp(selected_arch_name, "i386") == 0)
545 selected_arch_name = "x86"; 567 selected_arch_name = "x86";
546 568
547 // Produce a name to use in error messages that includes the 569 // Produce a name to use in error messages that includes the
548 // filename, and the architecture, if there is more than one. 570 // filename, and the architecture, if there is more than one.
549 selected_object_name_ = [object_filename_ UTF8String]; 571 selected_object_name_ = object_filename_;
550 if (object_files_.size() > 1) { 572 if (object_files_.size() > 1) {
551 selected_object_name_ += ", architecture "; 573 selected_object_name_ += ", architecture ";
552 selected_object_name_ + selected_arch_name; 574 selected_object_name_ + selected_arch_name;
553 } 575 }
554 576
555 // Compute a module name, to appear in the MODULE record. 577 // Compute a module name, to appear in the MODULE record.
556 NSString *module_name = [object_filename_ lastPathComponent]; 578 string module_name = object_filename_;
579 module_name = basename(&module_name[0]);
557 580
558 // Choose an identifier string, to appear in the MODULE record. 581 // Choose an identifier string, to appear in the MODULE record.
559 string identifier = Identifier(); 582 string identifier = Identifier();
560 if (identifier.empty()) 583 if (identifier.empty())
561 return false; 584 return false;
562 identifier += "0"; 585 identifier += "0";
563 586
564 // Create a module to hold the debugging information. 587 // Create a module to hold the debugging information.
565 scoped_ptr<Module> module(new Module([module_name UTF8String], 588 scoped_ptr<Module> module(new Module(module_name,
566 "mac", 589 "mac",
567 selected_arch_name, 590 selected_arch_name,
568 identifier)); 591 identifier));
569 592
570 // Parse the selected object file. 593 // Parse the selected object file.
571 mach_o::Reader::Reporter reporter(selected_object_name_); 594 mach_o::Reader::Reporter reporter(selected_object_name_);
572 mach_o::Reader reader(&reporter); 595 mach_o::Reader reader(&reporter);
573 if (!reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes]) 596 if (!reader.Read(&contents_[0]
574 + selected_object_file_->offset, 597 + selected_object_file_->offset,
575 selected_object_file_->size, 598 selected_object_file_->size,
576 selected_object_file_->cputype, 599 selected_object_file_->cputype,
577 selected_object_file_->cpusubtype)) 600 selected_object_file_->cpusubtype))
578 return false; 601 return false;
579 602
580 // Walk its load commands, and deal with whatever is there. 603 // Walk its load commands, and deal with whatever is there.
581 LoadCommandDumper load_command_dumper(*this, module.get(), reader, 604 LoadCommandDumper load_command_dumper(*this, module.get(), reader,
582 symbol_data_, handle_inter_cu_refs_); 605 symbol_data_, handle_inter_cu_refs_);
583 if (!reader.WalkLoadCommands(&load_command_dumper)) 606 if (!reader.WalkLoadCommands(&load_command_dumper))
(...skipping 10 matching lines...) Expand all
594 if (ReadSymbolData(&module) && module) { 617 if (ReadSymbolData(&module) && module) {
595 bool res = module->Write(stream, symbol_data_); 618 bool res = module->Write(stream, symbol_data_);
596 delete module; 619 delete module;
597 return res; 620 return res;
598 } 621 }
599 622
600 return false; 623 return false;
601 } 624 }
602 625
603 } // namespace google_breakpad 626 } // namespace google_breakpad
OLDNEW
« no previous file with comments | « src/common/mac/dump_syms.h ('k') | src/common/mac/dump_syms.mm » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698