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 <string.h> 13 14 #include "lldb/Core/Module.h" 15 #include "lldb/Core/ModuleSpec.h" 16 #include "lldb/Core/PluginManager.h" 17 #include "lldb/Core/Section.h" 18 #include "lldb/Core/StreamString.h" 19 #include "lldb/Core/Timer.h" 20 #include "lldb/Host/Host.h" 21 #include "lldb/Host/Symbols.h" 22 #include "lldb/Host/XML.h" 23 #include "lldb/Symbol/ObjectFile.h" 24 25 using namespace lldb; 26 using namespace lldb_private; 27 28 //---------------------------------------------------------------------- 29 // SymbolVendorMacOSX constructor 30 //---------------------------------------------------------------------- 31 SymbolVendorMacOSX::SymbolVendorMacOSX(const lldb::ModuleSP &module_sp) 32 : SymbolVendor(module_sp) {} 33 34 //---------------------------------------------------------------------- 35 // Destructor 36 //---------------------------------------------------------------------- 37 SymbolVendorMacOSX::~SymbolVendorMacOSX() {} 38 39 static bool UUIDsMatch(Module *module, ObjectFile *ofile, 40 lldb_private::Stream *feedback_strm) { 41 if (module && ofile) { 42 // Make sure the UUIDs match 43 lldb_private::UUID dsym_uuid; 44 45 if (!ofile->GetUUID(&dsym_uuid)) { 46 if (feedback_strm) { 47 feedback_strm->PutCString( 48 "warning: failed to get the uuid for object file: '"); 49 ofile->GetFileSpec().Dump(feedback_strm); 50 feedback_strm->PutCString("\n"); 51 } 52 return false; 53 } 54 55 if (dsym_uuid == module->GetUUID()) 56 return true; 57 58 // Emit some warning messages since the UUIDs do not match! 59 if (feedback_strm) { 60 feedback_strm->PutCString( 61 "warning: UUID mismatch detected between modules:\n "); 62 module->GetUUID().Dump(feedback_strm); 63 feedback_strm->PutChar(' '); 64 module->GetFileSpec().Dump(feedback_strm); 65 feedback_strm->PutCString("\n "); 66 dsym_uuid.Dump(feedback_strm); 67 feedback_strm->PutChar(' '); 68 ofile->GetFileSpec().Dump(feedback_strm); 69 feedback_strm->EOL(); 70 } 71 } 72 return false; 73 } 74 75 void SymbolVendorMacOSX::Initialize() { 76 PluginManager::RegisterPlugin(GetPluginNameStatic(), 77 GetPluginDescriptionStatic(), CreateInstance); 78 } 79 80 void SymbolVendorMacOSX::Terminate() { 81 PluginManager::UnregisterPlugin(CreateInstance); 82 } 83 84 lldb_private::ConstString SymbolVendorMacOSX::GetPluginNameStatic() { 85 static ConstString g_name("macosx"); 86 return g_name; 87 } 88 89 const char *SymbolVendorMacOSX::GetPluginDescriptionStatic() { 90 return "Symbol vendor for MacOSX that looks for dSYM files that match " 91 "executables."; 92 } 93 94 //---------------------------------------------------------------------- 95 // CreateInstance 96 // 97 // Platforms can register a callback to use when creating symbol 98 // vendors to allow for complex debug information file setups, and to 99 // also allow for finding separate debug information files. 100 //---------------------------------------------------------------------- 101 SymbolVendor * 102 SymbolVendorMacOSX::CreateInstance(const lldb::ModuleSP &module_sp, 103 lldb_private::Stream *feedback_strm) { 104 if (!module_sp) 105 return NULL; 106 107 ObjectFile *obj_file = module_sp->GetObjectFile(); 108 if (!obj_file) 109 return NULL; 110 111 static ConstString obj_file_macho("mach-o"); 112 ConstString obj_name = obj_file->GetPluginName(); 113 if (obj_name != obj_file_macho) 114 return NULL; 115 116 Timer scoped_timer(LLVM_PRETTY_FUNCTION, 117 "SymbolVendorMacOSX::CreateInstance (module = %s)", 118 module_sp->GetFileSpec().GetPath().c_str()); 119 SymbolVendorMacOSX *symbol_vendor = new SymbolVendorMacOSX(module_sp); 120 if (symbol_vendor) { 121 char path[PATH_MAX]; 122 path[0] = '\0'; 123 124 // Try and locate the dSYM file on Mac OS X 125 Timer scoped_timer2( 126 "SymbolVendorMacOSX::CreateInstance () locate dSYM", 127 "SymbolVendorMacOSX::CreateInstance (module = %s) locate dSYM", 128 module_sp->GetFileSpec().GetPath().c_str()); 129 130 // First check to see if the module has a symbol file in mind already. 131 // If it does, then we MUST use that. 132 FileSpec dsym_fspec(module_sp->GetSymbolFileFileSpec()); 133 134 ObjectFileSP dsym_objfile_sp; 135 if (!dsym_fspec) { 136 // No symbol file was specified in the module, lets try and find 137 // one ourselves. 138 FileSpec file_spec = obj_file->GetFileSpec(); 139 if (!file_spec) 140 file_spec = module_sp->GetFileSpec(); 141 142 ModuleSpec module_spec(file_spec, module_sp->GetArchitecture()); 143 module_spec.GetUUID() = module_sp->GetUUID(); 144 dsym_fspec = Symbols::LocateExecutableSymbolFile(module_spec); 145 if (module_spec.GetSourceMappingList().GetSize()) 146 module_sp->GetSourceMappingList().Append( 147 module_spec.GetSourceMappingList(), true); 148 } 149 150 if (dsym_fspec) { 151 DataBufferSP dsym_file_data_sp; 152 lldb::offset_t dsym_file_data_offset = 0; 153 dsym_objfile_sp = ObjectFile::FindPlugin( 154 module_sp, &dsym_fspec, 0, dsym_fspec.GetByteSize(), 155 dsym_file_data_sp, dsym_file_data_offset); 156 if (UUIDsMatch(module_sp.get(), dsym_objfile_sp.get(), feedback_strm)) { 157 // We need a XML parser if we hope to parse a plist... 158 if (XMLDocument::XMLEnabled()) { 159 char dsym_path[PATH_MAX]; 160 if (module_sp->GetSourceMappingList().IsEmpty() && 161 dsym_fspec.GetPath(dsym_path, sizeof(dsym_path))) { 162 lldb_private::UUID dsym_uuid; 163 if (dsym_objfile_sp->GetUUID(&dsym_uuid)) { 164 std::string uuid_str = dsym_uuid.GetAsString(); 165 if (!uuid_str.empty()) { 166 char *resources = strstr(dsym_path, "/Contents/Resources/"); 167 if (resources) { 168 char dsym_uuid_plist_path[PATH_MAX]; 169 resources[strlen("/Contents/Resources/")] = '\0'; 170 snprintf(dsym_uuid_plist_path, sizeof(dsym_uuid_plist_path), 171 "%s%s.plist", dsym_path, uuid_str.c_str()); 172 FileSpec dsym_uuid_plist_spec(dsym_uuid_plist_path, false); 173 if (dsym_uuid_plist_spec.Exists()) { 174 ApplePropertyList plist(dsym_uuid_plist_path); 175 if (plist) { 176 std::string DBGBuildSourcePath; 177 std::string DBGSourcePath; 178 179 plist.GetValueAsString("DBGBuildSourcePath", 180 DBGBuildSourcePath); 181 plist.GetValueAsString("DBGSourcePath", DBGSourcePath); 182 if (!DBGBuildSourcePath.empty() && 183 !DBGSourcePath.empty()) { 184 if (DBGSourcePath[0] == '~') { 185 FileSpec resolved_source_path(DBGSourcePath.c_str(), 186 true); 187 DBGSourcePath = resolved_source_path.GetPath(); 188 } 189 module_sp->GetSourceMappingList().Append( 190 ConstString(DBGBuildSourcePath), 191 ConstString(DBGSourcePath), true); 192 } 193 194 // DBGSourcePathRemapping is a dictionary in the plist 195 // with 196 // keys which are DBGBuildSourcePath file paths and 197 // values which are DBGSourcePath file paths 198 199 StructuredData::ObjectSP plist_sp = 200 plist.GetStructuredData(); 201 if (plist_sp.get() && plist_sp->GetAsDictionary() && 202 plist_sp->GetAsDictionary()->HasKey( 203 "DBGSourcePathRemapping") && 204 plist_sp->GetAsDictionary() 205 ->GetValueForKey("DBGSourcePathRemapping") 206 ->GetAsDictionary()) { 207 208 // In an early version of DBGSourcePathRemapping, the 209 // DBGSourcePath 210 // values were incorrect. If we have a newer style 211 // DBGSourcePathRemapping, there will be a DBGVersion 212 // key in the plist 213 // (we don't care about the value at this point). 214 // 215 // If this is an old style DBGSourcePathRemapping, 216 // ignore the 217 // value half of the key-value remappings and use reuse 218 // the original 219 // gloal DBGSourcePath string. 220 bool new_style_source_remapping_dictionary = false; 221 std::string original_DBGSourcePath_value = 222 DBGSourcePath; 223 if (plist_sp->GetAsDictionary()->HasKey("DBGVersion")) { 224 new_style_source_remapping_dictionary = true; 225 } 226 227 StructuredData::Dictionary *remappings_dict = 228 plist_sp->GetAsDictionary() 229 ->GetValueForKey("DBGSourcePathRemapping") 230 ->GetAsDictionary(); 231 remappings_dict->ForEach( 232 [&module_sp, new_style_source_remapping_dictionary, 233 original_DBGSourcePath_value]( 234 ConstString key, 235 StructuredData::Object *object) -> bool { 236 if (object && object->GetAsString()) { 237 238 // key is DBGBuildSourcePath 239 // object is DBGSourcePath 240 std::string DBGSourcePath = 241 object->GetStringValue(); 242 if (new_style_source_remapping_dictionary == 243 false && 244 !original_DBGSourcePath_value.empty()) { 245 DBGSourcePath = original_DBGSourcePath_value; 246 } 247 if (DBGSourcePath[0] == '~') { 248 FileSpec resolved_source_path( 249 DBGSourcePath.c_str(), true); 250 DBGSourcePath = 251 resolved_source_path.GetPath(); 252 } 253 module_sp->GetSourceMappingList().Append( 254 key, ConstString(DBGSourcePath), true); 255 } 256 return true; 257 }); 258 } 259 } 260 } 261 } 262 } 263 } 264 } 265 } 266 267 symbol_vendor->AddSymbolFileRepresentation(dsym_objfile_sp); 268 return symbol_vendor; 269 } 270 } 271 272 // Just create our symbol vendor using the current objfile as this is either 273 // an executable with no dSYM (that we could locate), an executable with 274 // a dSYM that has a UUID that doesn't match. 275 symbol_vendor->AddSymbolFileRepresentation(obj_file->shared_from_this()); 276 } 277 return symbol_vendor; 278 } 279 280 //------------------------------------------------------------------ 281 // PluginInterface protocol 282 //------------------------------------------------------------------ 283 ConstString SymbolVendorMacOSX::GetPluginName() { 284 return GetPluginNameStatic(); 285 } 286 287 uint32_t SymbolVendorMacOSX::GetPluginVersion() { return 1; } 288