//===-- 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 #include #include #include #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Section.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/Timer.h" #include "lldb/Host/Host.h" #include "lldb/Host/Symbols.h" #include "lldb/Symbol/ObjectFile.h" using namespace lldb; using namespace lldb_private; //---------------------------------------------------------------------- // SymbolVendorMacOSX constructor //---------------------------------------------------------------------- SymbolVendorMacOSX::SymbolVendorMacOSX(const lldb::ModuleSP &module_sp) : SymbolVendor (module_sp) { } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- SymbolVendorMacOSX::~SymbolVendorMacOSX() { } static bool UUIDsMatch(Module *module, ObjectFile *ofile, lldb_private::Stream *feedback_strm) { if (module && ofile) { // Make sure the UUIDs match lldb_private::UUID dsym_uuid; if (!ofile->GetUUID(&dsym_uuid)) { if (feedback_strm) { feedback_strm->PutCString("warning: failed to get the uuid for object file: '"); ofile->GetFileSpec().Dump(feedback_strm); feedback_strm->PutCString("\n"); } return false; } if (dsym_uuid == module->GetUUID()) return true; // Emit some warning messages since the UUIDs do not match! if (feedback_strm) { feedback_strm->PutCString("warning: UUID mismatch detected between modules:\n "); module->GetUUID().Dump(feedback_strm); feedback_strm->PutChar(' '); module->GetFileSpec().Dump(feedback_strm); feedback_strm->PutCString("\n "); dsym_uuid.Dump(feedback_strm); feedback_strm->PutChar(' '); ofile->GetFileSpec().Dump(feedback_strm); feedback_strm->EOL(); } } return false; } void SymbolVendorMacOSX::Initialize() { PluginManager::RegisterPlugin (GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance); } void SymbolVendorMacOSX::Terminate() { PluginManager::UnregisterPlugin (CreateInstance); } lldb_private::ConstString SymbolVendorMacOSX::GetPluginNameStatic() { static ConstString g_name("macosx"); return g_name; } 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 (const lldb::ModuleSP &module_sp, lldb_private::Stream *feedback_strm) { if (!module_sp) return NULL; ObjectFile * obj_file = module_sp->GetObjectFile(); if (!obj_file) return NULL; static ConstString obj_file_macho("mach-o"); ConstString obj_name = obj_file->GetPluginName(); if (obj_name != obj_file_macho) return NULL; Timer scoped_timer (__PRETTY_FUNCTION__, "SymbolVendorMacOSX::CreateInstance (module = %s)", module_sp->GetFileSpec().GetPath().c_str()); SymbolVendorMacOSX* symbol_vendor = new SymbolVendorMacOSX(module_sp); if (symbol_vendor) { char path[PATH_MAX]; path[0] = '\0'; // Try and locate the dSYM file on Mac OS X Timer scoped_timer2 ("SymbolVendorMacOSX::CreateInstance () locate dSYM", "SymbolVendorMacOSX::CreateInstance (module = %s) locate dSYM", module_sp->GetFileSpec().GetPath().c_str()); // First check to see if the module has a symbol file in mind already. // If it does, then we MUST use that. FileSpec dsym_fspec (module_sp->GetSymbolFileFileSpec()); ObjectFileSP dsym_objfile_sp; if (!dsym_fspec) { // No symbol file was specified in the module, lets try and find // one ourselves. FileSpec file_spec = obj_file->GetFileSpec(); if (!file_spec) file_spec = module_sp->GetFileSpec(); ModuleSpec module_spec(file_spec, module_sp->GetArchitecture()); module_spec.GetUUID() = module_sp->GetUUID(); dsym_fspec = Symbols::LocateExecutableSymbolFile (module_spec); if (module_spec.GetSourceMappingList().GetSize()) module_sp->GetSourceMappingList().Append (module_spec.GetSourceMappingList (), true); } if (dsym_fspec) { DataBufferSP dsym_file_data_sp; lldb::offset_t dsym_file_data_offset = 0; dsym_objfile_sp = ObjectFile::FindPlugin(module_sp, &dsym_fspec, 0, dsym_fspec.GetByteSize(), dsym_file_data_sp, dsym_file_data_offset); if (UUIDsMatch(module_sp.get(), dsym_objfile_sp.get(), feedback_strm)) { char dsym_path[PATH_MAX]; if (module_sp->GetSourceMappingList().IsEmpty() && dsym_fspec.GetPath(dsym_path, sizeof(dsym_path))) { lldb_private::UUID dsym_uuid; if (dsym_objfile_sp->GetUUID(&dsym_uuid)) { std::string uuid_str = dsym_uuid.GetAsString (); if (!uuid_str.empty()) { char *resources = strstr (dsym_path, "/Contents/Resources/"); if (resources) { char dsym_uuid_plist_path[PATH_MAX]; resources[strlen("/Contents/Resources/")] = '\0'; snprintf(dsym_uuid_plist_path, sizeof(dsym_uuid_plist_path), "%s%s.plist", dsym_path, uuid_str.c_str()); FileSpec dsym_uuid_plist_spec(dsym_uuid_plist_path, false); if (dsym_uuid_plist_spec.Exists()) { xmlDoc *doc = ::xmlReadFile (dsym_uuid_plist_path, NULL, 0); if (doc) { char DBGBuildSourcePath[PATH_MAX]; char DBGSourcePath[PATH_MAX]; DBGBuildSourcePath[0] = '\0'; DBGSourcePath[0] = '\0'; for (xmlNode *node = doc->children; node; node = node ? node->next : NULL) { if (node->type == XML_ELEMENT_NODE) { if (node->name && strcmp((const char*)node->name, "plist") == 0) { xmlNode *dict_node = node->children; while (dict_node && dict_node->type != XML_ELEMENT_NODE) dict_node = dict_node->next; if (dict_node && dict_node->name && strcmp((const char *)dict_node->name, "dict") == 0) { for (xmlNode *key_node = dict_node->children; key_node; key_node = key_node->next) { if (key_node && key_node->type == XML_ELEMENT_NODE && key_node->name) { if (strcmp((const char *)key_node->name, "key") == 0) { const char *key_name = (const char *)::xmlNodeGetContent(key_node); if (strcmp(key_name, "DBGBuildSourcePath") == 0) { xmlNode *value_node = key_node->next; while (value_node && value_node->type != XML_ELEMENT_NODE) value_node = value_node->next; if (value_node && value_node->name) { if (strcmp((const char *)value_node->name, "string") == 0) { const char *node_content = (const char *)::xmlNodeGetContent(value_node); if (node_content) { strncpy(DBGBuildSourcePath, node_content, sizeof(DBGBuildSourcePath)); xmlFree((void *) node_content); } } key_node = value_node; } } else if (strcmp(key_name, "DBGSourcePath") == 0) { xmlNode *value_node = key_node->next; while (value_node && value_node->type != XML_ELEMENT_NODE) value_node = value_node->next; if (value_node && value_node->name) { if (strcmp((const char *)value_node->name, "string") == 0) { const char *node_content = (const char *)::xmlNodeGetContent(value_node); if (node_content) { FileSpec resolved_source_path(node_content, true); resolved_source_path.GetPath(DBGSourcePath, sizeof(DBGSourcePath)); xmlFree ((void *) node_content); } } key_node = value_node; } } if (key_name != NULL) xmlFree((void *) key_name); } } } } } } } ::xmlFreeDoc (doc); if (DBGBuildSourcePath[0] && DBGSourcePath[0]) { module_sp->GetSourceMappingList().Append (ConstString(DBGBuildSourcePath), ConstString(DBGSourcePath), true); } } } } } } } symbol_vendor->AddSymbolFileRepresentation(dsym_objfile_sp); 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), an executable with // a dSYM that has a UUID that doesn't match. symbol_vendor->AddSymbolFileRepresentation(obj_file->shared_from_this()); } return symbol_vendor; } //------------------------------------------------------------------ // PluginInterface protocol //------------------------------------------------------------------ ConstString SymbolVendorMacOSX::GetPluginName() { return GetPluginNameStatic(); } uint32_t SymbolVendorMacOSX::GetPluginVersion() { return 1; }