1//===-- SymbolVendorMacOSX.cpp ----------------------------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#include "SymbolVendorMacOSX.h" 11 12#include <libxml/parser.h> 13#include <libxml/tree.h> 14#include <string.h> 15 16#include <AvailabilityMacros.h> 17 18#include "lldb/Core/Module.h" 19#include "lldb/Core/ModuleSpec.h" 20#include "lldb/Core/PluginManager.h" 21#include "lldb/Core/Section.h" 22#include "lldb/Core/StreamString.h" 23#include "lldb/Core/Timer.h" 24#include "lldb/Host/Host.h" 25#include "lldb/Host/Symbols.h" 26#include "lldb/Symbol/ObjectFile.h" 27 28using namespace lldb; 29using namespace lldb_private; 30 31//---------------------------------------------------------------------- 32// SymbolVendorMacOSX constructor 33//---------------------------------------------------------------------- 34SymbolVendorMacOSX::SymbolVendorMacOSX(const lldb::ModuleSP &module_sp) : 35 SymbolVendor (module_sp) 36{ 37} 38 39//---------------------------------------------------------------------- 40// Destructor 41//---------------------------------------------------------------------- 42SymbolVendorMacOSX::~SymbolVendorMacOSX() 43{ 44} 45 46 47static bool 48UUIDsMatch(Module *module, ObjectFile *ofile, lldb_private::Stream *feedback_strm) 49{ 50 if (module && ofile) 51 { 52 // Make sure the UUIDs match 53 lldb_private::UUID dsym_uuid; 54 55 if (!ofile->GetUUID(&dsym_uuid)) 56 { 57 if (feedback_strm) 58 { 59 feedback_strm->PutCString("warning: failed to get the uuid for object file: '"); 60 ofile->GetFileSpec().Dump(feedback_strm); 61 feedback_strm->PutCString("\n"); 62 } 63 return false; 64 } 65 66 if (dsym_uuid == module->GetUUID()) 67 return true; 68 69 // Emit some warning messages since the UUIDs do not match! 70 if (feedback_strm) 71 { 72 feedback_strm->PutCString("warning: UUID mismatch detected between modules:\n "); 73 module->GetUUID().Dump(feedback_strm); 74 feedback_strm->PutChar(' '); 75 module->GetFileSpec().Dump(feedback_strm); 76 feedback_strm->PutCString("\n "); 77 dsym_uuid.Dump(feedback_strm); 78 feedback_strm->PutChar(' '); 79 ofile->GetFileSpec().Dump(feedback_strm); 80 feedback_strm->EOL(); 81 } 82 } 83 return false; 84} 85 86void 87SymbolVendorMacOSX::Initialize() 88{ 89 PluginManager::RegisterPlugin (GetPluginNameStatic(), 90 GetPluginDescriptionStatic(), 91 CreateInstance); 92} 93 94void 95SymbolVendorMacOSX::Terminate() 96{ 97 PluginManager::UnregisterPlugin (CreateInstance); 98} 99 100 101lldb_private::ConstString 102SymbolVendorMacOSX::GetPluginNameStatic() 103{ 104 static ConstString g_name("macosx"); 105 return g_name; 106} 107 108const char * 109SymbolVendorMacOSX::GetPluginDescriptionStatic() 110{ 111 return "Symbol vendor for MacOSX that looks for dSYM files that match executables."; 112} 113 114 115 116//---------------------------------------------------------------------- 117// CreateInstance 118// 119// Platforms can register a callback to use when creating symbol 120// vendors to allow for complex debug information file setups, and to 121// also allow for finding separate debug information files. 122//---------------------------------------------------------------------- 123SymbolVendor* 124SymbolVendorMacOSX::CreateInstance (const lldb::ModuleSP &module_sp, lldb_private::Stream *feedback_strm) 125{ 126 if (!module_sp) 127 return NULL; 128 129 ObjectFile * obj_file = module_sp->GetObjectFile(); 130 if (!obj_file) 131 return NULL; 132 133 static ConstString obj_file_macho("mach-o"); 134 ConstString obj_name = obj_file->GetPluginName(); 135 if (obj_name != obj_file_macho) 136 return NULL; 137 138 Timer scoped_timer (__PRETTY_FUNCTION__, 139 "SymbolVendorMacOSX::CreateInstance (module = %s)", 140 module_sp->GetFileSpec().GetPath().c_str()); 141 SymbolVendorMacOSX* symbol_vendor = new SymbolVendorMacOSX(module_sp); 142 if (symbol_vendor) 143 { 144 char path[PATH_MAX]; 145 path[0] = '\0'; 146 147 // Try and locate the dSYM file on Mac OS X 148 Timer scoped_timer2 ("SymbolVendorMacOSX::CreateInstance () locate dSYM", 149 "SymbolVendorMacOSX::CreateInstance (module = %s) locate dSYM", 150 module_sp->GetFileSpec().GetPath().c_str()); 151 152 // First check to see if the module has a symbol file in mind already. 153 // If it does, then we MUST use that. 154 FileSpec dsym_fspec (module_sp->GetSymbolFileFileSpec()); 155 156 ObjectFileSP dsym_objfile_sp; 157 if (!dsym_fspec) 158 { 159 // No symbol file was specified in the module, lets try and find 160 // one ourselves. 161 FileSpec file_spec = obj_file->GetFileSpec(); 162 if (!file_spec) 163 file_spec = module_sp->GetFileSpec(); 164 165 ModuleSpec module_spec(file_spec, module_sp->GetArchitecture()); 166 module_spec.GetUUID() = module_sp->GetUUID(); 167 dsym_fspec = Symbols::LocateExecutableSymbolFile (module_spec); 168 if (module_spec.GetSourceMappingList().GetSize()) 169 module_sp->GetSourceMappingList().Append (module_spec.GetSourceMappingList (), true); 170 } 171 172 if (dsym_fspec) 173 { 174 DataBufferSP dsym_file_data_sp; 175 lldb::offset_t dsym_file_data_offset = 0; 176 dsym_objfile_sp = ObjectFile::FindPlugin(module_sp, &dsym_fspec, 0, dsym_fspec.GetByteSize(), dsym_file_data_sp, dsym_file_data_offset); 177 if (UUIDsMatch(module_sp.get(), dsym_objfile_sp.get(), feedback_strm)) 178 { 179 char dsym_path[PATH_MAX]; 180 if (module_sp->GetSourceMappingList().IsEmpty() && dsym_fspec.GetPath(dsym_path, sizeof(dsym_path))) 181 { 182 lldb_private::UUID dsym_uuid; 183 if (dsym_objfile_sp->GetUUID(&dsym_uuid)) 184 { 185 std::string uuid_str = dsym_uuid.GetAsString (); 186 if (!uuid_str.empty()) 187 { 188 char *resources = strstr (dsym_path, "/Contents/Resources/"); 189 if (resources) 190 { 191 char dsym_uuid_plist_path[PATH_MAX]; 192 resources[strlen("/Contents/Resources/")] = '\0'; 193 snprintf(dsym_uuid_plist_path, sizeof(dsym_uuid_plist_path), "%s%s.plist", dsym_path, uuid_str.c_str()); 194 FileSpec dsym_uuid_plist_spec(dsym_uuid_plist_path, false); 195 if (dsym_uuid_plist_spec.Exists()) 196 { 197 xmlDoc *doc = ::xmlReadFile (dsym_uuid_plist_path, NULL, 0); 198 if (doc) 199 { 200 char DBGBuildSourcePath[PATH_MAX]; 201 char DBGSourcePath[PATH_MAX]; 202 DBGBuildSourcePath[0] = '\0'; 203 DBGSourcePath[0] = '\0'; 204 for (xmlNode *node = doc->children; node; node = node ? node->next : NULL) 205 { 206 if (node->type == XML_ELEMENT_NODE) 207 { 208 if (node->name && strcmp((const char*)node->name, "plist") == 0) 209 { 210 xmlNode *dict_node = node->children; 211 while (dict_node && dict_node->type != XML_ELEMENT_NODE) 212 dict_node = dict_node->next; 213 if (dict_node && dict_node->name && strcmp((const char *)dict_node->name, "dict") == 0) 214 { 215 for (xmlNode *key_node = dict_node->children; key_node; key_node = key_node->next) 216 { 217 if (key_node && key_node->type == XML_ELEMENT_NODE && key_node->name) 218 { 219 if (strcmp((const char *)key_node->name, "key") == 0) 220 { 221 const char *key_name = (const char *)::xmlNodeGetContent(key_node); 222 if (strcmp(key_name, "DBGBuildSourcePath") == 0) 223 { 224 xmlNode *value_node = key_node->next; 225 while (value_node && value_node->type != XML_ELEMENT_NODE) 226 value_node = value_node->next; 227 if (value_node && value_node->name) 228 { 229 if (strcmp((const char *)value_node->name, "string") == 0) 230 { 231 const char *node_content = (const char *)::xmlNodeGetContent(value_node); 232 if (node_content) 233 { 234 strncpy(DBGBuildSourcePath, node_content, sizeof(DBGBuildSourcePath)); 235 xmlFree((void *) node_content); 236 } 237 } 238 key_node = value_node; 239 } 240 } 241 else if (strcmp(key_name, "DBGSourcePath") == 0) 242 { 243 xmlNode *value_node = key_node->next; 244 while (value_node && value_node->type != XML_ELEMENT_NODE) 245 value_node = value_node->next; 246 if (value_node && value_node->name) 247 { 248 if (strcmp((const char *)value_node->name, "string") == 0) 249 { 250 const char *node_content = (const char *)::xmlNodeGetContent(value_node); 251 if (node_content) 252 { 253 FileSpec resolved_source_path(node_content, true); 254 resolved_source_path.GetPath(DBGSourcePath, sizeof(DBGSourcePath)); 255 xmlFree ((void *) node_content); 256 } 257 } 258 key_node = value_node; 259 } 260 } 261 if (key_name != NULL) 262 xmlFree((void *) key_name); 263 } 264 } 265 } 266 } 267 } 268 } 269 } 270 ::xmlFreeDoc (doc); 271 272 if (DBGBuildSourcePath[0] && DBGSourcePath[0]) 273 { 274 module_sp->GetSourceMappingList().Append (ConstString(DBGBuildSourcePath), ConstString(DBGSourcePath), true); 275 } 276 } 277 } 278 } 279 } 280 } 281 } 282 283 symbol_vendor->AddSymbolFileRepresentation(dsym_objfile_sp); 284 return symbol_vendor; 285 } 286 } 287 288 // Just create our symbol vendor using the current objfile as this is either 289 // an executable with no dSYM (that we could locate), an executable with 290 // a dSYM that has a UUID that doesn't match. 291 symbol_vendor->AddSymbolFileRepresentation(obj_file->shared_from_this()); 292 } 293 return symbol_vendor; 294} 295 296 297 298//------------------------------------------------------------------ 299// PluginInterface protocol 300//------------------------------------------------------------------ 301ConstString 302SymbolVendorMacOSX::GetPluginName() 303{ 304 return GetPluginNameStatic(); 305} 306 307uint32_t 308SymbolVendorMacOSX::GetPluginVersion() 309{ 310 return 1; 311} 312 313