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

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: 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
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 <libgen.h>
40 #include <mach-o/arch.h> 40 #include <mach-o/arch.h>
41 #include <mach-o/fat.h> 41 #include <mach-o/fat.h>
42 #include <stdio.h> 42 #include <stdio.h>
43 #include <sys/stat.h>
44 #include <unistd.h>
43 45
44 #include <ostream> 46 #include <ostream>
45 #include <string> 47 #include <string>
46 #include <vector> 48 #include <vector>
47 49
48 #include "common/dwarf/bytereader-inl.h" 50 #include "common/dwarf/bytereader-inl.h"
49 #include "common/dwarf/dwarf2reader.h" 51 #include "common/dwarf/dwarf2reader.h"
50 #include "common/dwarf_cfi_to_module.h" 52 #include "common/dwarf_cfi_to_module.h"
51 #include "common/dwarf_cu_to_module.h" 53 #include "common/dwarf_cu_to_module.h"
52 #include "common/dwarf_line_to_module.h" 54 #include "common/dwarf_line_to_module.h"
(...skipping 25 matching lines...) Expand all
78 using google_breakpad::StabsReader; 80 using google_breakpad::StabsReader;
79 using google_breakpad::StabsToModule; 81 using google_breakpad::StabsToModule;
80 using google_breakpad::scoped_ptr; 82 using google_breakpad::scoped_ptr;
81 using std::make_pair; 83 using std::make_pair;
82 using std::pair; 84 using std::pair;
83 using std::string; 85 using std::string;
84 using std::vector; 86 using std::vector;
85 87
86 namespace google_breakpad { 88 namespace google_breakpad {
87 89
88 bool DumpSymbols::Read(NSString *filename) { 90 bool DumpSymbols::Read(const string &filename) {
89 if (![[NSFileManager defaultManager] fileExistsAtPath:filename]) { 91 struct stat st;
92 if (stat(filename.c_str(), &st) == -1) {
90 fprintf(stderr, "Object file does not exist: %s\n", 93 fprintf(stderr, "Object file does not exist: %s\n",
Mark Mentovai 2015/09/11 15:49:50 Not necessarily—use strerror(errno) for the real e
Ted Mielczarek 2015/09/15 12:58:36 Done.
91 [filename fileSystemRepresentation]); 94 filename.c_str());
92 return false; 95 return false;
93 } 96 }
94 97
95 input_pathname_ = [filename retain]; 98 input_pathname_ = filename;
96 99
97 // Does this filename refer to a dSYM bundle? 100 // Does this filename refer to a dSYM bundle?
98 NSBundle *bundle = [NSBundle bundleWithPath:input_pathname_]; 101 string contents_path = input_pathname_ + "/Contents/Resources/DWARF";
99 102 if (S_ISDIR(st.st_mode) &&
100 if (bundle) { 103 access(contents_path.c_str(), F_OK) == 0) {
101 // Filenames referring to bundles usually have names of the form 104 // Filenames referring to bundles usually have names of the form
Mark Mentovai 2015/09/11 15:49:50 This is totally hokey. It seems to break down if t
Ted Mielczarek 2015/09/15 12:58:36 Done.
102 // "<basename>.dSYM"; however, if the user has specified a wrapper 105 // "<basename>.dSYM"; however, if the user has specified a wrapper
103 // suffix (the WRAPPER_SUFFIX and WRAPPER_EXTENSION build settings), 106 // suffix (the WRAPPER_SUFFIX and WRAPPER_EXTENSION build settings),
104 // then the name may have the form "<basename>.<extension>.dSYM". In 107 // then the name may have the form "<basename>.<extension>.dSYM". In
105 // either case, the resource name for the file containing the DWARF 108 // either case, the resource name for the file containing the DWARF
106 // info within the bundle is <basename>. 109 // info within the bundle is <basename>.
107 // 110 //
108 // Since there's no way to tell how much to strip off, remove one 111 // 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 112 // extension at a time, and use the first one that
110 // pathForResource:ofType:inDirectory likes. 113 // exists under Contents/Resources/DWARF.
111 NSString *base_name = [input_pathname_ lastPathComponent]; 114 string base_name = input_pathname_;
112 NSString *dwarf_resource; 115 base_name = basename(&base_name[0]);
116
117 string dwarf_resource;
113 118
114 do { 119 do {
115 NSString *new_base_name = [base_name stringByDeletingPathExtension]; 120 size_t lastindex = base_name.find_last_of(".");
116 121 if (lastindex == string::npos) {
117 // If stringByDeletingPathExtension returned the name unchanged, then 122 // there's nothing more for us to strip off --- lose.
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", 123 fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n",
121 [input_pathname_ fileSystemRepresentation]); 124 input_pathname_.c_str());
122 return false; 125 return false;
123 } 126 }
124 127
125 // Take the shortened result as our new base_name. 128 // Take the shortened result as our new base_name.
126 base_name = new_base_name; 129 base_name = base_name.substr(0, lastindex);
127 130
128 // Try to find a DWARF resource in the bundle under the new base_name. 131 // Try to find a DWARF resource in the bundle under the new base_name.
129 dwarf_resource = [bundle pathForResource:base_name 132 dwarf_resource = contents_path + "/" + base_name;
130 ofType:nil inDirectory:@"DWARF"]; 133 } while (access(dwarf_resource.c_str(), F_OK) == -1);
131 } while (!dwarf_resource);
132 134
133 object_filename_ = [dwarf_resource retain]; 135 object_filename_ = dwarf_resource;
134 } else { 136 } else {
135 object_filename_ = [input_pathname_ retain]; 137 object_filename_ = input_pathname_;
136 } 138 }
137 139
138 // Read the file's contents into memory. 140 // Read the file's contents into memory.
139 // 141 bool read_ok = false;
140 // The documentation for dataWithContentsOfMappedFile says: 142 string error;
141 // 143 if (stat(object_filename_.c_str(), &st) != -1) {
142 // Because of file mapping restrictions, this method should only be 144 FILE* f = fopen(object_filename_.c_str(), "rb");
143 // used if the file is guaranteed to exist for the duration of the 145 if (f) {
144 // data object’s existence. It is generally safer to use the 146 contents_.resize(st.st_size);
145 // dataWithContentsOfFile: method. 147 read_ok = (fread(&contents_[0], st.st_size, 1, f) == 1);
Mark Mentovai 2015/09/11 15:49:50 No read loop? Generally it’s preferable to read u
Ted Mielczarek 2015/09/15 12:58:36 Done.
146 // 148 if (!read_ok) {
147 // I gather this means that OS X doesn't have (or at least, that method 149 error = strerror(errno);
148 // doesn't use) a form of mapping like Linux's MAP_PRIVATE, where the 150 }
149 // process appears to get its own copy of the data, and changes to the 151 fclose(f);
150 // file don't affect memory and vice versa). 152 } else {
151 NSError *error; 153 error = strerror(errno);
152 contents_ = [NSData dataWithContentsOfFile:object_filename_ 154 }
153 options:0 155 }
154 error:&error]; 156
155 if (!contents_) { 157 if (!read_ok) {
156 fprintf(stderr, "Error reading object file: %s: %s\n", 158 fprintf(stderr, "Error reading object file: %s: %s\n",
157 [object_filename_ fileSystemRepresentation], 159 object_filename_.c_str(),
158 [[error localizedDescription] UTF8String]); 160 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; 161 return false;
170 } 162 }
171 163
164 // Get the list of object files present in the file.
165 FatReader::Reporter fat_reporter(object_filename_);
166 FatReader fat_reader(&fat_reporter);
167 if (!fat_reader.Read(&contents_[0],
168 contents_.size())) {
169 return false;
170 }
171
172 // Get our own copy of fat_reader's object file list. 172 // Get our own copy of fat_reader's object file list.
173 size_t object_files_count; 173 size_t object_files_count;
174 const SuperFatArch *object_files = 174 const SuperFatArch *object_files =
175 fat_reader.object_files(&object_files_count); 175 fat_reader.object_files(&object_files_count);
176 if (object_files_count == 0) { 176 if (object_files_count == 0) {
177 fprintf(stderr, "Fat binary file contains *no* architectures: %s\n", 177 fprintf(stderr, "Fat binary file contains *no* architectures: %s\n",
178 [object_filename_ fileSystemRepresentation]); 178 object_filename_.c_str());
179 return false; 179 return false;
180 } 180 }
181 object_files_.resize(object_files_count); 181 object_files_.resize(object_files_count);
182 memcpy(&object_files_[0], object_files, 182 memcpy(&object_files_[0], object_files,
183 sizeof(SuperFatArch) * object_files_count); 183 sizeof(SuperFatArch) * object_files_count);
184 184
185 return true; 185 return true;
186 } 186 }
187 187
188 bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type, 188 bool DumpSymbols::SetArchitecture(cpu_type_t cpu_type,
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
251 // TODO(erikchen): If it becomes necessary, we can copy the implementation of 251 // TODO(erikchen): If it becomes necessary, we can copy the implementation of
252 // NXFindBestFatArch, located at 252 // NXFindBestFatArch, located at
253 // http://web.mit.edu/darwin/src/modules/cctools/libmacho/arch.c. 253 // 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 " 254 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 " 255 "type: %d and cpu subtype: %d. Furthermore, at least one object file is "
256 "larger than 2**32.\n", cpu_type, cpu_subtype); 256 "larger than 2**32.\n", cpu_type, cpu_subtype);
257 return NULL; 257 return NULL;
258 } 258 }
259 259
260 string DumpSymbols::Identifier() { 260 string DumpSymbols::Identifier() {
261 FileID file_id([object_filename_ fileSystemRepresentation]); 261 FileID file_id(object_filename_.c_str());
262 unsigned char identifier_bytes[16]; 262 unsigned char identifier_bytes[16];
263 cpu_type_t cpu_type = selected_object_file_->cputype; 263 cpu_type_t cpu_type = selected_object_file_->cputype;
264 cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype; 264 cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype;
265 if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) { 265 if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) {
266 fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n", 266 fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n",
267 [object_filename_ fileSystemRepresentation]); 267 object_filename_.c_str());
268 return ""; 268 return "";
269 } 269 }
270 270
271 char identifier_string[40]; 271 char identifier_string[40];
272 FileID::ConvertIdentifierToString(identifier_bytes, identifier_string, 272 FileID::ConvertIdentifierToString(identifier_bytes, identifier_string,
273 sizeof(identifier_string)); 273 sizeof(identifier_string));
274 274
275 string compacted(identifier_string); 275 string compacted(identifier_string);
276 for(size_t i = compacted.find('-'); i != string::npos; 276 for(size_t i = compacted.find('-'); i != string::npos;
277 i = compacted.find('-', i)) 277 i = compacted.find('-', i))
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 if (object_files_.size() == 1) 519 if (object_files_.size() == 1)
520 selected_object_file_ = &object_files_[0]; 520 selected_object_file_ = &object_files_[0];
521 else { 521 else {
522 // Look for an object file whose architecture matches our own. 522 // Look for an object file whose architecture matches our own.
523 const NXArchInfo *local_arch = NXGetLocalArchInfo(); 523 const NXArchInfo *local_arch = NXGetLocalArchInfo();
524 if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) { 524 if (!SetArchitecture(local_arch->cputype, local_arch->cpusubtype)) {
525 fprintf(stderr, "%s: object file contains more than one" 525 fprintf(stderr, "%s: object file contains more than one"
526 " architecture, none of which match the current" 526 " architecture, none of which match the current"
527 " architecture; specify an architecture explicitly" 527 " architecture; specify an architecture explicitly"
528 " with '-a ARCH' to resolve the ambiguity\n", 528 " with '-a ARCH' to resolve the ambiguity\n",
529 [object_filename_ fileSystemRepresentation]); 529 object_filename_.c_str());
530 return false; 530 return false;
531 } 531 }
532 } 532 }
533 } 533 }
534 534
535 assert(selected_object_file_); 535 assert(selected_object_file_);
536 536
537 // Find the name of the selected file's architecture, to appear in 537 // Find the name of the selected file's architecture, to appear in
538 // the MODULE record and in error messages. 538 // the MODULE record and in error messages.
539 const NXArchInfo *selected_arch_info = 539 const NXArchInfo *selected_arch_info =
540 google_breakpad::BreakpadGetArchInfoFromCpuType( 540 google_breakpad::BreakpadGetArchInfoFromCpuType(
541 selected_object_file_->cputype, selected_object_file_->cpusubtype); 541 selected_object_file_->cputype, selected_object_file_->cpusubtype);
542 542
543 const char *selected_arch_name = selected_arch_info->name; 543 const char *selected_arch_name = selected_arch_info->name;
544 if (strcmp(selected_arch_name, "i386") == 0) 544 if (strcmp(selected_arch_name, "i386") == 0)
545 selected_arch_name = "x86"; 545 selected_arch_name = "x86";
546 546
547 // Produce a name to use in error messages that includes the 547 // Produce a name to use in error messages that includes the
548 // filename, and the architecture, if there is more than one. 548 // filename, and the architecture, if there is more than one.
549 selected_object_name_ = [object_filename_ UTF8String]; 549 selected_object_name_ = object_filename_;
550 if (object_files_.size() > 1) { 550 if (object_files_.size() > 1) {
551 selected_object_name_ += ", architecture "; 551 selected_object_name_ += ", architecture ";
552 selected_object_name_ + selected_arch_name; 552 selected_object_name_ + selected_arch_name;
553 } 553 }
554 554
555 // Compute a module name, to appear in the MODULE record. 555 // Compute a module name, to appear in the MODULE record.
556 NSString *module_name = [object_filename_ lastPathComponent]; 556 string module_name = object_filename_;
557 module_name = basename(&module_name[0]);
557 558
558 // Choose an identifier string, to appear in the MODULE record. 559 // Choose an identifier string, to appear in the MODULE record.
559 string identifier = Identifier(); 560 string identifier = Identifier();
560 if (identifier.empty()) 561 if (identifier.empty())
561 return false; 562 return false;
562 identifier += "0"; 563 identifier += "0";
563 564
564 // Create a module to hold the debugging information. 565 // Create a module to hold the debugging information.
565 scoped_ptr<Module> module(new Module([module_name UTF8String], 566 scoped_ptr<Module> module(new Module(module_name,
566 "mac", 567 "mac",
567 selected_arch_name, 568 selected_arch_name,
568 identifier)); 569 identifier));
569 570
570 // Parse the selected object file. 571 // Parse the selected object file.
571 mach_o::Reader::Reporter reporter(selected_object_name_); 572 mach_o::Reader::Reporter reporter(selected_object_name_);
572 mach_o::Reader reader(&reporter); 573 mach_o::Reader reader(&reporter);
573 if (!reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes]) 574 if (!reader.Read(&contents_[0]
574 + selected_object_file_->offset, 575 + selected_object_file_->offset,
575 selected_object_file_->size, 576 selected_object_file_->size,
576 selected_object_file_->cputype, 577 selected_object_file_->cputype,
577 selected_object_file_->cpusubtype)) 578 selected_object_file_->cpusubtype))
578 return false; 579 return false;
579 580
580 // Walk its load commands, and deal with whatever is there. 581 // Walk its load commands, and deal with whatever is there.
581 LoadCommandDumper load_command_dumper(*this, module.get(), reader, 582 LoadCommandDumper load_command_dumper(*this, module.get(), reader,
582 symbol_data_, handle_inter_cu_refs_); 583 symbol_data_, handle_inter_cu_refs_);
583 if (!reader.WalkLoadCommands(&load_command_dumper)) 584 if (!reader.WalkLoadCommands(&load_command_dumper))
(...skipping 10 matching lines...) Expand all
594 if (ReadSymbolData(&module) && module) { 595 if (ReadSymbolData(&module) && module) {
595 bool res = module->Write(stream, symbol_data_); 596 bool res = module->Write(stream, symbol_data_);
596 delete module; 597 delete module;
597 return res; 598 return res;
598 } 599 }
599 600
600 return false; 601 return false;
601 } 602 }
602 603
603 } // namespace google_breakpad 604 } // namespace google_breakpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698