Index: src/common/mac/dump_syms.cc |
diff --git a/src/common/mac/dump_syms.mm b/src/common/mac/dump_syms.cc |
similarity index 84% |
rename from src/common/mac/dump_syms.mm |
rename to src/common/mac/dump_syms.cc |
index 58cf4c208ae4220fe9eedb97ccd4189d6f5588a0..0558970237da40851ff39e1936cadb6f8745dfef 100644 |
--- a/src/common/mac/dump_syms.mm |
+++ b/src/common/mac/dump_syms.cc |
@@ -36,10 +36,15 @@ |
#include "common/mac/dump_syms.h" |
#include <assert.h> |
-#include <Foundation/Foundation.h> |
+#include <dirent.h> |
+#include <errno.h> |
+#include <libgen.h> |
#include <mach-o/arch.h> |
#include <mach-o/fat.h> |
#include <stdio.h> |
+#include <sys/stat.h> |
+#include <sys/types.h> |
+#include <unistd.h> |
#include <ostream> |
#include <string> |
@@ -83,89 +88,105 @@ using std::pair; |
using std::string; |
using std::vector; |
+namespace { |
+// Return a vector<string> with absolute paths to all the entries |
+// in directory (excluding . and ..). |
+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.
|
+ vector<string> entries; |
+ DIR* dir = opendir(directory.c_str()); |
+ if (!dir) { |
+ return entries; |
+ } |
+ |
+ string path = directory; |
+ if (path[path.length() - 1] != '/') { |
+ path += '/'; |
+ } |
+ |
+ struct dirent* entry = NULL; |
+ while ((entry = readdir(dir))) { |
+ if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) { |
+ entries.push_back(path + entry->d_name); |
+ } |
+ } |
+ |
+ closedir(dir); |
+ return entries; |
+} |
+} |
+ |
namespace google_breakpad { |
-bool DumpSymbols::Read(NSString *filename) { |
- if (![[NSFileManager defaultManager] fileExistsAtPath:filename]) { |
- fprintf(stderr, "Object file does not exist: %s\n", |
- [filename fileSystemRepresentation]); |
+bool DumpSymbols::Read(const string &filename) { |
+ struct stat st; |
+ if (stat(filename.c_str(), &st) == -1) { |
+ fprintf(stderr, "Could not access object file %s: %s\n", |
+ filename.c_str(), strerror(errno)); |
return false; |
} |
- input_pathname_ = [filename retain]; |
+ input_pathname_ = filename; |
// Does this filename refer to a dSYM bundle? |
- NSBundle *bundle = [NSBundle bundleWithPath:input_pathname_]; |
- |
- if (bundle) { |
- // Filenames referring to bundles usually have names of the form |
- // "<basename>.dSYM"; however, if the user has specified a wrapper |
- // suffix (the WRAPPER_SUFFIX and WRAPPER_EXTENSION build settings), |
- // then the name may have the form "<basename>.<extension>.dSYM". In |
- // either case, the resource name for the file containing the DWARF |
- // info within the bundle is <basename>. |
- // |
- // Since there's no way to tell how much to strip off, remove one |
- // extension at a time, and use the first one that |
- // pathForResource:ofType:inDirectory likes. |
- NSString *base_name = [input_pathname_ lastPathComponent]; |
- NSString *dwarf_resource; |
- |
- do { |
- NSString *new_base_name = [base_name stringByDeletingPathExtension]; |
- |
- // If stringByDeletingPathExtension returned the name unchanged, then |
- // there's nothing more for us to strip off --- lose. |
- if ([new_base_name isEqualToString:base_name]) { |
- fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n", |
- [input_pathname_ fileSystemRepresentation]); |
- return false; |
- } |
- |
- // Take the shortened result as our new base_name. |
- base_name = new_base_name; |
- |
- // Try to find a DWARF resource in the bundle under the new base_name. |
- dwarf_resource = [bundle pathForResource:base_name |
- ofType:nil inDirectory:@"DWARF"]; |
- } while (!dwarf_resource); |
+ string contents_path = input_pathname_ + "/Contents/Resources/DWARF"; |
+ if (S_ISDIR(st.st_mode) && |
+ access(contents_path.c_str(), F_OK) == 0) { |
+ // If there's one file under Contents/Resources/DWARF then use that, |
+ // otherwise bail out. |
+ const vector<string> entries = list_directory(contents_path); |
+ if (entries.size() == 0) { |
+ fprintf(stderr, "Unable to find DWARF-bearing file in bundle: %s\n", |
+ input_pathname_.c_str()); |
+ return false; |
+ } |
+ if (entries.size() > 1) { |
+ fprintf(stderr, "Too many DWARF files in bundle: %s\n", |
+ input_pathname_.c_str()); |
+ return false; |
+ } |
- object_filename_ = [dwarf_resource retain]; |
+ object_filename_ = entries[0]; |
} else { |
- object_filename_ = [input_pathname_ retain]; |
+ object_filename_ = input_pathname_; |
} |
// Read the file's contents into memory. |
- // |
- // The documentation for dataWithContentsOfMappedFile says: |
- // |
- // Because of file mapping restrictions, this method should only be |
- // used if the file is guaranteed to exist for the duration of the |
- // data object’s existence. It is generally safer to use the |
- // dataWithContentsOfFile: method. |
- // |
- // I gather this means that OS X doesn't have (or at least, that method |
- // doesn't use) a form of mapping like Linux's MAP_PRIVATE, where the |
- // process appears to get its own copy of the data, and changes to the |
- // file don't affect memory and vice versa). |
- NSError *error; |
- contents_ = [NSData dataWithContentsOfFile:object_filename_ |
- options:0 |
- error:&error]; |
- if (!contents_) { |
+ bool read_ok = true; |
+ string error; |
+ if (stat(object_filename_.c_str(), &st) != -1) { |
+ FILE* f = fopen(object_filename_.c_str(), "rb"); |
+ if (f) { |
+ contents_.reset(new uint8_t[st.st_size]); |
+ off_t total = 0; |
+ while (total < st.st_size && !feof(f)) { |
+ size_t read = fread(&contents_[0] + total, 1, st.st_size - total, f); |
+ if (read == 0) { |
+ if (ferror(f)) { |
+ read_ok = false; |
+ error = strerror(errno); |
+ } |
+ break; |
+ } |
+ total += read; |
+ } |
+ fclose(f); |
+ } else { |
+ error = strerror(errno); |
+ } |
+ } |
+ |
+ if (!read_ok) { |
fprintf(stderr, "Error reading object file: %s: %s\n", |
- [object_filename_ fileSystemRepresentation], |
- [[error localizedDescription] UTF8String]); |
+ object_filename_.c_str(), |
+ error.c_str()); |
return false; |
} |
- [contents_ retain]; |
// Get the list of object files present in the file. |
- FatReader::Reporter fat_reporter([object_filename_ |
- fileSystemRepresentation]); |
+ FatReader::Reporter fat_reporter(object_filename_); |
FatReader fat_reader(&fat_reporter); |
- if (!fat_reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes]), |
- [contents_ length])) { |
+ if (!fat_reader.Read(&contents_[0], |
+ st.st_size)) { |
return false; |
} |
@@ -175,7 +196,7 @@ bool DumpSymbols::Read(NSString *filename) { |
fat_reader.object_files(&object_files_count); |
if (object_files_count == 0) { |
fprintf(stderr, "Fat binary file contains *no* architectures: %s\n", |
- [object_filename_ fileSystemRepresentation]); |
+ object_filename_.c_str()); |
return false; |
} |
object_files_.resize(object_files_count); |
@@ -243,7 +264,8 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture( |
for (vector<SuperFatArch>::iterator it = object_files_.begin(); |
it != object_files_.end(); |
++it) { |
- if (it->cputype == cpu_type && it->cpusubtype == cpu_subtype) |
+ if (static_cast<cpu_type_t>(it->cputype) == cpu_type && |
+ static_cast<cpu_subtype_t>(it->cpusubtype) == cpu_subtype) |
return &*it; |
} |
@@ -258,13 +280,13 @@ SuperFatArch* DumpSymbols::FindBestMatchForArchitecture( |
} |
string DumpSymbols::Identifier() { |
- FileID file_id([object_filename_ fileSystemRepresentation]); |
+ FileID file_id(object_filename_.c_str()); |
unsigned char identifier_bytes[16]; |
cpu_type_t cpu_type = selected_object_file_->cputype; |
cpu_subtype_t cpu_subtype = selected_object_file_->cpusubtype; |
if (!file_id.MachoIdentifier(cpu_type, cpu_subtype, identifier_bytes)) { |
fprintf(stderr, "Unable to calculate UUID of mach-o binary %s!\n", |
- [object_filename_ fileSystemRepresentation]); |
+ object_filename_.c_str()); |
return ""; |
} |
@@ -526,7 +548,7 @@ bool DumpSymbols::ReadSymbolData(Module** out_module) { |
" architecture, none of which match the current" |
" architecture; specify an architecture explicitly" |
" with '-a ARCH' to resolve the ambiguity\n", |
- [object_filename_ fileSystemRepresentation]); |
+ object_filename_.c_str()); |
return false; |
} |
} |
@@ -546,14 +568,15 @@ bool DumpSymbols::ReadSymbolData(Module** out_module) { |
// Produce a name to use in error messages that includes the |
// filename, and the architecture, if there is more than one. |
- selected_object_name_ = [object_filename_ UTF8String]; |
+ selected_object_name_ = object_filename_; |
if (object_files_.size() > 1) { |
selected_object_name_ += ", architecture "; |
selected_object_name_ + selected_arch_name; |
} |
// Compute a module name, to appear in the MODULE record. |
- NSString *module_name = [object_filename_ lastPathComponent]; |
+ string module_name = object_filename_; |
+ module_name = basename(&module_name[0]); |
// Choose an identifier string, to appear in the MODULE record. |
string identifier = Identifier(); |
@@ -562,7 +585,7 @@ bool DumpSymbols::ReadSymbolData(Module** out_module) { |
identifier += "0"; |
// Create a module to hold the debugging information. |
- scoped_ptr<Module> module(new Module([module_name UTF8String], |
+ scoped_ptr<Module> module(new Module(module_name, |
"mac", |
selected_arch_name, |
identifier)); |
@@ -570,7 +593,7 @@ bool DumpSymbols::ReadSymbolData(Module** out_module) { |
// Parse the selected object file. |
mach_o::Reader::Reporter reporter(selected_object_name_); |
mach_o::Reader reader(&reporter); |
- if (!reader.Read(reinterpret_cast<const uint8_t *>([contents_ bytes]) |
+ if (!reader.Read(&contents_[0] |
+ selected_object_file_->offset, |
selected_object_file_->size, |
selected_object_file_->cputype, |