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 with version 2 or higher. 213 // 214 // If this is an old style DBGSourcePathRemapping, 215 // ignore the 216 // value half of the key-value remappings and use reuse 217 // the original 218 // gloal DBGSourcePath string. 219 bool new_style_source_remapping_dictionary = false; 220 std::string original_DBGSourcePath_value = 221 DBGSourcePath; 222 if (plist_sp->GetAsDictionary()->HasKey("DBGVersion")) { 223 std::string version_string = 224 plist_sp->GetAsDictionary() 225 ->GetValueForKey("DBGVersion") 226 ->GetStringValue(""); 227 if (!version_string.empty() && 228 isdigit(version_string[0])) { 229 int version_number = atoi(version_string.c_str()); 230 if (version_number > 1) { 231 new_style_source_remapping_dictionary = true; 232 } 233 } 234 } 235 236 StructuredData::Dictionary *remappings_dict = 237 plist_sp->GetAsDictionary() 238 ->GetValueForKey("DBGSourcePathRemapping") 239 ->GetAsDictionary(); 240 remappings_dict->ForEach( 241 [&module_sp, new_style_source_remapping_dictionary, 242 original_DBGSourcePath_value]( 243 ConstString key, 244 StructuredData::Object *object) -> bool { 245 if (object && object->GetAsString()) { 246 247 // key is DBGBuildSourcePath 248 // object is DBGSourcePath 249 std::string DBGSourcePath = 250 object->GetStringValue(); 251 if (new_style_source_remapping_dictionary == 252 false && 253 !original_DBGSourcePath_value.empty()) { 254 DBGSourcePath = original_DBGSourcePath_value; 255 } 256 if (DBGSourcePath[0] == '~') { 257 FileSpec resolved_source_path( 258 DBGSourcePath.c_str(), true); 259 DBGSourcePath = 260 resolved_source_path.GetPath(); 261 } 262 module_sp->GetSourceMappingList().Append( 263 key, ConstString(DBGSourcePath), true); 264 } 265 return true; 266 }); 267 } 268 } 269 } 270 } 271 } 272 } 273 } 274 } 275 276 symbol_vendor->AddSymbolFileRepresentation(dsym_objfile_sp); 277 return symbol_vendor; 278 } 279 } 280 281 // Just create our symbol vendor using the current objfile as this is either 282 // an executable with no dSYM (that we could locate), an executable with 283 // a dSYM that has a UUID that doesn't match. 284 symbol_vendor->AddSymbolFileRepresentation(obj_file->shared_from_this()); 285 } 286 return symbol_vendor; 287 } 288 289 //------------------------------------------------------------------ 290 // PluginInterface protocol 291 //------------------------------------------------------------------ 292 ConstString SymbolVendorMacOSX::GetPluginName() { 293 return GetPluginNameStatic(); 294 } 295 296 uint32_t SymbolVendorMacOSX::GetPluginVersion() { return 1; } 297