| //===-- SymbolVendorMacOSX.cpp ----------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "SymbolVendorMacOSX.h" |
| |
| #include <AvailabilityMacros.h> |
| |
| #include "lldb/Core/Module.h" |
| #include "lldb/Core/PluginManager.h" |
| #include "lldb/Core/Section.h" |
| #include "lldb/Core/Timer.h" |
| #include "lldb/Host/Symbols.h" |
| #include "lldb/Symbol/ObjectFile.h" |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| |
| //---------------------------------------------------------------------- |
| // SymbolVendorMacOSX constructor |
| //---------------------------------------------------------------------- |
| SymbolVendorMacOSX::SymbolVendorMacOSX(Module *module) : |
| SymbolVendor(module) |
| { |
| } |
| |
| //---------------------------------------------------------------------- |
| // Destructor |
| //---------------------------------------------------------------------- |
| SymbolVendorMacOSX::~SymbolVendorMacOSX() |
| { |
| } |
| |
| |
| static bool |
| UUIDsMatch(Module *module, ObjectFile *ofile) |
| { |
| if (module && ofile) |
| { |
| // Make sure the UUIDs match |
| lldb_private::UUID dsym_uuid; |
| if (ofile->GetUUID(&dsym_uuid)) |
| return dsym_uuid == module->GetUUID(); |
| } |
| return false; |
| } |
| |
| |
| //ObjectFile * |
| //LocateDSYMMachFileInDSYMBundle (Module* module, FileSpec& dsym_fspec) |
| //{ |
| // ObjectFile *dsym_objfile = NULL; |
| // |
| // char path[PATH_MAX]; |
| // |
| // if (dsym_fspec.GetPath(path, sizeof(path))) |
| // { |
| // size_t path_len = strlen(path); |
| // const char *bundle_subpath = "/Contents/Resources/DWARF/"; |
| // if (path_len > 0) |
| // { |
| // if (path[path_len-1] == '/') |
| // ::strncat (path, bundle_subpath + 1, sizeof(path)); |
| // else |
| // ::strncat (path, bundle_subpath, sizeof(path)); |
| // ::strncat (path, dsym_fspec.GetFilename().AsCString(), sizeof(path)); |
| // |
| // path_len = strlen(path); |
| // |
| // if (::strcasecmp (&path[path_len - strlen(".dSYM")], ".dSYM") == 0) |
| // { |
| // path[path_len - ::strlen(".dSYM")] = '\0'; |
| // dsym_fspec.SetFile(path); |
| // dsym_objfile = ObjectFile::FindPlugin(module, &dsym_fspec, 0); |
| // } |
| // } |
| // } |
| // return dsym_objfile; |
| //} |
| // |
| //CFURLRef DBGCopyFullDSYMURLForUUID (CFUUIDRef uuid, CFURLRef exec_url) __attribute__((weak_import)); |
| |
| |
| //ObjectFile * |
| //FindDSYMUsingDebugSymbols (Module* module, FileSpec& dsym_fspec) |
| //{ |
| // Timer scoped_locate("FindDSYMUsingDebugSymbols"); |
| // dsym_fspec.Clear(); |
| // ObjectFile *dsym_objfile = NULL; |
| // if (module->GetUUID().IsValid()) |
| // { |
| // // Try and locate the dSYM file using DebugSymbols first |
| // const UInt8 *module_uuid = (const UInt8 *)module->GetUUID().GetBytes(); |
| // if (module_uuid != NULL) |
| // { |
| // CFUUIDRef module_uuid_ref; |
| // module_uuid_ref = ::CFUUIDCreateWithBytes ( NULL, |
| // module_uuid[0], |
| // module_uuid[1], |
| // module_uuid[2], |
| // module_uuid[3], |
| // module_uuid[4], |
| // module_uuid[5], |
| // module_uuid[6], |
| // module_uuid[7], |
| // module_uuid[8], |
| // module_uuid[9], |
| // module_uuid[10], |
| // module_uuid[11], |
| // module_uuid[12], |
| // module_uuid[13], |
| // module_uuid[14], |
| // module_uuid[15]); |
| // |
| // if (module_uuid_ref) |
| // { |
| // CFURLRef dsym_url = NULL; |
| // CFURLRef exec_url = NULL; |
| // |
| // // if (DBGCopyFullDSYMURLForUUID) |
| // { |
| // char exec_path[PATH_MAX]; |
| // if (module->GetFileSpec().GetPath(exec_path, sizeof(exec_path))) |
| // { |
| // exec_url = CFURLCreateFromFileSystemRepresentation ( NULL, |
| // (const UInt8 *)exec_path, |
| // strlen(exec_path), |
| // FALSE); |
| // } |
| // |
| // dsym_url = DBGCopyFullDSYMURLForUUID(module_uuid_ref, exec_url); |
| // } |
| // // else |
| // // { |
| // // dsym_url = DBGCopyDSYMURLForUUID(module_uuid_ref); |
| // // } |
| // |
| // if (exec_url) |
| // { |
| // ::CFRelease (exec_url); |
| // exec_url = NULL; |
| // } |
| // |
| // ::CFRelease(module_uuid_ref); |
| // module_uuid_ref = NULL; |
| // |
| // if (dsym_url) |
| // { |
| // char dsym_path[PATH_MAX]; |
| // Boolean success = CFURLGetFileSystemRepresentation (dsym_url, true, (UInt8*)dsym_path, sizeof(dsym_path)-1); |
| // |
| // ::CFRelease(dsym_url), dsym_url = NULL; |
| // |
| // if (success) |
| // { |
| // dsym_fspec.SetFile(dsym_path); |
| // |
| // // Some newer versions of DebugSymbols will return a full path into a dSYM bundle |
| // // that points to the correct mach file within the dSYM bundle (MH_DSYM mach file |
| // // type). |
| // dsym_objfile = ObjectFile::FindPlugin(module, &dsym_fspec, 0); |
| // |
| // // Olders versions of DebugSymbols will return a path to a dSYM bundle. |
| // if (dsym_objfile == NULL) |
| // dsym_objfile = LocateDSYMMachFileInDSYMBundle (module, dsym_fspec); |
| // } |
| // } |
| // } |
| // } |
| // } |
| // return dsym_objfile; |
| //} |
| |
| static void |
| ReplaceDSYMSectionsWithExecutableSections (ObjectFile *exec_objfile, ObjectFile *dsym_objfile) |
| { |
| // We need both the executable and the dSYM to live off of the |
| // same section lists. So we take all of the sections from the |
| // executable, and replace them in the dSYM. This allows section |
| // offset addresses that come from the dSYM to automatically |
| // get updated as images (shared libraries) get loaded and |
| // unloaded. |
| SectionList *exec_section_list = exec_objfile->GetSectionList(); |
| SectionList *dsym_section_list = dsym_objfile->GetSectionList(); |
| if (exec_section_list && dsym_section_list) |
| { |
| const uint32_t num_exec_sections = dsym_section_list->GetSize(); |
| uint32_t exec_sect_idx; |
| for (exec_sect_idx = 0; exec_sect_idx < num_exec_sections; ++exec_sect_idx) |
| { |
| SectionSP exec_sect_sp(exec_section_list->GetSectionAtIndex(exec_sect_idx)); |
| if (exec_sect_sp.get()) |
| { |
| // Try and replace any sections that exist in both the executable |
| // and in the dSYM with those from the executable. If we fail to |
| // replace the one in the dSYM, then add the executable section to |
| // the dSYM. |
| if (dsym_section_list->ReplaceSection(exec_sect_sp->GetID(), exec_sect_sp, 0) == false) |
| dsym_section_list->AddSection(exec_sect_sp); |
| } |
| } |
| } |
| } |
| |
| void |
| SymbolVendorMacOSX::Initialize() |
| { |
| PluginManager::RegisterPlugin (GetPluginNameStatic(), |
| GetPluginDescriptionStatic(), |
| CreateInstance); |
| } |
| |
| void |
| SymbolVendorMacOSX::Terminate() |
| { |
| PluginManager::UnregisterPlugin (CreateInstance); |
| } |
| |
| |
| const char * |
| SymbolVendorMacOSX::GetPluginNameStatic() |
| { |
| return "symbol-vendor.macosx"; |
| } |
| |
| const char * |
| SymbolVendorMacOSX::GetPluginDescriptionStatic() |
| { |
| return "Symbol vendor for MacOSX that looks for dSYM files that match executables."; |
| } |
| |
| |
| |
| //---------------------------------------------------------------------- |
| // CreateInstance |
| // |
| // Platforms can register a callback to use when creating symbol |
| // vendors to allow for complex debug information file setups, and to |
| // also allow for finding separate debug information files. |
| //---------------------------------------------------------------------- |
| SymbolVendor* |
| SymbolVendorMacOSX::CreateInstance(Module* module) |
| { |
| Timer scoped_timer (__PRETTY_FUNCTION__, |
| "SymbolVendorMacOSX::CreateInstance (module = %s/%s)", |
| module->GetFileSpec().GetDirectory().AsCString(), |
| module->GetFileSpec().GetFilename().AsCString()); |
| SymbolVendorMacOSX* symbol_vendor = new SymbolVendorMacOSX(module); |
| if (symbol_vendor) |
| { |
| char path[PATH_MAX]; |
| path[0] = '\0'; |
| |
| // Try and locate the dSYM file on Mac OS X |
| ObjectFile * obj_file = module->GetObjectFile(); |
| if (obj_file) |
| { |
| Timer scoped_timer2 ("SymbolVendorMacOSX::CreateInstance () locate dSYM", |
| "SymbolVendorMacOSX::CreateInstance (module = %s/%s) locate dSYM", |
| module->GetFileSpec().GetDirectory().AsCString(), |
| module->GetFileSpec().GetFilename().AsCString()); |
| |
| FileSpec dsym_fspec; |
| std::auto_ptr<ObjectFile> dsym_objfile_ap; |
| const FileSpec &file_spec = obj_file->GetFileSpec(); |
| if (file_spec) |
| { |
| dsym_fspec = Symbols::LocateExecutableSymbolFile (&file_spec, &module->GetArchitecture(), &module->GetUUID()); |
| |
| if (dsym_fspec) |
| { |
| dsym_objfile_ap.reset(ObjectFile::FindPlugin(module, &dsym_fspec, 0, dsym_fspec.GetByteSize())); |
| if (UUIDsMatch(module, dsym_objfile_ap.get())) |
| { |
| ReplaceDSYMSectionsWithExecutableSections (obj_file, dsym_objfile_ap.get()); |
| symbol_vendor->AddSymbolFileRepresendation(dsym_objfile_ap.release()); |
| return symbol_vendor; |
| } |
| } |
| } |
| |
| // Just create our symbol vendor using the current objfile as this is either |
| // an executable with no dSYM (that we could locate), and executable with |
| // a dSYM that has a UUID that doesn't match, or it is a dSYM file itself. |
| symbol_vendor->AddSymbolFileRepresendation(obj_file); |
| } |
| } |
| return symbol_vendor; |
| } |
| |
| |
| |
| //------------------------------------------------------------------ |
| // PluginInterface protocol |
| //------------------------------------------------------------------ |
| const char * |
| SymbolVendorMacOSX::GetPluginName() |
| { |
| return "SymbolVendorMacOSX"; |
| } |
| |
| const char * |
| SymbolVendorMacOSX::GetShortPluginName() |
| { |
| return GetPluginNameStatic(); |
| } |
| |
| uint32_t |
| SymbolVendorMacOSX::GetPluginVersion() |
| { |
| return 1; |
| } |
| |
| void |
| SymbolVendorMacOSX::GetPluginCommandHelp (const char *command, Stream *strm) |
| { |
| } |
| |
| Error |
| SymbolVendorMacOSX::ExecutePluginCommand (Args &command, Stream *strm) |
| { |
| Error error; |
| error.SetErrorString("No plug-in command are currently supported."); |
| return error; |
| } |
| |
| Log * |
| SymbolVendorMacOSX::EnablePluginLogging (Stream *strm, Args &command) |
| { |
| return NULL; |
| } |
| |