1 //===-- Symbols.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 "lldb/Host/Symbols.h" 11 #include "lldb/Core/ArchSpec.h" 12 #include "lldb/Core/DataBuffer.h" 13 #include "lldb/Core/DataExtractor.h" 14 #include "lldb/Core/Log.h" 15 #include "lldb/Core/Module.h" 16 #include "lldb/Core/ModuleSpec.h" 17 #include "lldb/Core/StreamString.h" 18 #include "lldb/Core/Timer.h" 19 #include "lldb/Core/UUID.h" 20 #include "lldb/Symbol/ObjectFile.h" 21 #include "lldb/Target/Target.h" 22 #include "lldb/Utility/SafeMachO.h" 23 24 #include "llvm/Support/FileSystem.h" 25 26 // From MacOSX system header "mach/machine.h" 27 typedef int cpu_type_t; 28 typedef int cpu_subtype_t; 29 30 using namespace lldb; 31 using namespace lldb_private; 32 using namespace llvm::MachO; 33 34 #if defined(__APPLE__) 35 36 // Forward declaration of method defined in source/Host/macosx/Symbols.cpp 37 int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec, 38 ModuleSpec &return_module_spec); 39 40 #else 41 42 int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec, 43 ModuleSpec &return_module_spec) { 44 // Cannot find MacOSX files using debug symbols on non MacOSX. 45 return 0; 46 } 47 48 #endif 49 50 static bool FileAtPathContainsArchAndUUID(const FileSpec &file_fspec, 51 const ArchSpec *arch, 52 const lldb_private::UUID *uuid) { 53 ModuleSpecList module_specs; 54 if (ObjectFile::GetModuleSpecifications(file_fspec, 0, 0, module_specs)) { 55 ModuleSpec spec; 56 for (size_t i = 0; i < module_specs.GetSize(); ++i) { 57 assert(module_specs.GetModuleSpecAtIndex(i, spec)); 58 if ((uuid == NULL || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) && 59 (arch == NULL || (spec.GetArchitecturePtr() && 60 spec.GetArchitecture().IsCompatibleMatch(*arch)))) { 61 return true; 62 } 63 } 64 } 65 return false; 66 } 67 68 static bool LocateDSYMInVincinityOfExecutable(const ModuleSpec &module_spec, 69 FileSpec &dsym_fspec) { 70 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 71 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); 72 if (exec_fspec) { 73 char path[PATH_MAX]; 74 if (exec_fspec->GetPath(path, sizeof(path))) { 75 // Make sure the module isn't already just a dSYM file... 76 if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL) { 77 if (log) { 78 if (module_spec.GetUUIDPtr() && module_spec.GetUUIDPtr()->IsValid()) { 79 log->Printf( 80 "Searching for dSYM bundle next to executable %s, UUID %s", 81 path, module_spec.GetUUIDPtr()->GetAsString().c_str()); 82 } else { 83 log->Printf("Searching for dSYM bundle next to executable %s", 84 path); 85 } 86 } 87 size_t obj_file_path_length = strlen(path); 88 ::strncat(path, ".dSYM/Contents/Resources/DWARF/", 89 sizeof(path) - strlen(path) - 1); 90 ::strncat(path, exec_fspec->GetFilename().AsCString(), 91 sizeof(path) - strlen(path) - 1); 92 93 dsym_fspec.SetFile(path, false); 94 95 ModuleSpecList module_specs; 96 ModuleSpec matched_module_spec; 97 if (dsym_fspec.Exists() && 98 FileAtPathContainsArchAndUUID(dsym_fspec, 99 module_spec.GetArchitecturePtr(), 100 module_spec.GetUUIDPtr())) { 101 if (log) { 102 log->Printf("dSYM with matching UUID & arch found at %s", path); 103 } 104 return true; 105 } else { 106 path[obj_file_path_length] = '\0'; 107 108 char *last_dot = strrchr(path, '.'); 109 while (last_dot != NULL && last_dot[0]) { 110 char *next_slash = strchr(last_dot, '/'); 111 if (next_slash != NULL) { 112 *next_slash = '\0'; 113 ::strncat(path, ".dSYM/Contents/Resources/DWARF/", 114 sizeof(path) - strlen(path) - 1); 115 ::strncat(path, exec_fspec->GetFilename().AsCString(), 116 sizeof(path) - strlen(path) - 1); 117 dsym_fspec.SetFile(path, false); 118 if (dsym_fspec.Exists() && 119 FileAtPathContainsArchAndUUID( 120 dsym_fspec, module_spec.GetArchitecturePtr(), 121 module_spec.GetUUIDPtr())) { 122 if (log) { 123 log->Printf("dSYM with matching UUID & arch found at %s", 124 path); 125 } 126 return true; 127 } else { 128 *last_dot = '\0'; 129 char *prev_slash = strrchr(path, '/'); 130 if (prev_slash != NULL) 131 *prev_slash = '\0'; 132 else 133 break; 134 } 135 } else { 136 break; 137 } 138 } 139 } 140 } 141 } 142 } 143 dsym_fspec.Clear(); 144 return false; 145 } 146 147 FileSpec LocateExecutableSymbolFileDsym(const ModuleSpec &module_spec) { 148 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); 149 const ArchSpec *arch = module_spec.GetArchitecturePtr(); 150 const UUID *uuid = module_spec.GetUUIDPtr(); 151 152 Timer scoped_timer( 153 LLVM_PRETTY_FUNCTION, 154 "LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)", 155 exec_fspec ? exec_fspec->GetFilename().AsCString("<NULL>") : "<NULL>", 156 arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid); 157 158 FileSpec symbol_fspec; 159 ModuleSpec dsym_module_spec; 160 // First try and find the dSYM in the same directory as the executable or in 161 // an appropriate parent directory 162 if (LocateDSYMInVincinityOfExecutable(module_spec, symbol_fspec) == false) { 163 // We failed to easily find the dSYM above, so use DebugSymbols 164 LocateMacOSXFilesUsingDebugSymbols(module_spec, dsym_module_spec); 165 } else { 166 dsym_module_spec.GetSymbolFileSpec() = symbol_fspec; 167 } 168 return dsym_module_spec.GetSymbolFileSpec(); 169 } 170 171 ModuleSpec Symbols::LocateExecutableObjectFile(const ModuleSpec &module_spec) { 172 ModuleSpec result; 173 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); 174 const ArchSpec *arch = module_spec.GetArchitecturePtr(); 175 const UUID *uuid = module_spec.GetUUIDPtr(); 176 Timer scoped_timer( 177 LLVM_PRETTY_FUNCTION, 178 "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)", 179 exec_fspec ? exec_fspec->GetFilename().AsCString("<NULL>") : "<NULL>", 180 arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid); 181 182 ModuleSpecList module_specs; 183 ModuleSpec matched_module_spec; 184 if (exec_fspec && 185 ObjectFile::GetModuleSpecifications(*exec_fspec, 0, 0, module_specs) && 186 module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) { 187 result.GetFileSpec() = exec_fspec; 188 } else { 189 LocateMacOSXFilesUsingDebugSymbols(module_spec, result); 190 } 191 return result; 192 } 193 194 FileSpec Symbols::LocateExecutableSymbolFile(const ModuleSpec &module_spec) { 195 FileSpec symbol_file_spec = module_spec.GetSymbolFileSpec(); 196 if (symbol_file_spec.IsAbsolute() && symbol_file_spec.Exists()) 197 return symbol_file_spec; 198 199 const char *symbol_filename = symbol_file_spec.GetFilename().AsCString(); 200 if (symbol_filename && symbol_filename[0]) { 201 FileSpecList debug_file_search_paths( 202 Target::GetDefaultDebugFileSearchPaths()); 203 204 // Add module directory. 205 const ConstString &file_dir = module_spec.GetFileSpec().GetDirectory(); 206 debug_file_search_paths.AppendIfUnique( 207 FileSpec(file_dir.AsCString("."), true)); 208 209 // Add current working directory. 210 debug_file_search_paths.AppendIfUnique(FileSpec(".", true)); 211 212 #ifndef LLVM_ON_WIN32 213 // Add /usr/lib/debug directory. 214 debug_file_search_paths.AppendIfUnique(FileSpec("/usr/lib/debug", true)); 215 #endif // LLVM_ON_WIN32 216 217 std::string uuid_str; 218 const UUID &module_uuid = module_spec.GetUUID(); 219 if (module_uuid.IsValid()) { 220 // Some debug files are stored in the .build-id directory like this: 221 // /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug 222 uuid_str = module_uuid.GetAsString(""); 223 uuid_str.insert(2, 1, '/'); 224 uuid_str = uuid_str + ".debug"; 225 } 226 227 size_t num_directories = debug_file_search_paths.GetSize(); 228 for (size_t idx = 0; idx < num_directories; ++idx) { 229 FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx); 230 dirspec.ResolvePath(); 231 if (!dirspec.Exists() || !dirspec.IsDirectory()) 232 continue; 233 234 std::vector<std::string> files; 235 std::string dirname = dirspec.GetPath(); 236 237 files.push_back(dirname + "/" + symbol_filename); 238 files.push_back(dirname + "/.debug/" + symbol_filename); 239 files.push_back(dirname + "/.build-id/" + uuid_str); 240 241 // Some debug files may stored in the module directory like this: 242 // /usr/lib/debug/usr/lib/library.so.debug 243 if (!file_dir.IsEmpty()) 244 files.push_back(dirname + file_dir.AsCString() + "/" + symbol_filename); 245 246 const uint32_t num_files = files.size(); 247 for (size_t idx_file = 0; idx_file < num_files; ++idx_file) { 248 const std::string &filename = files[idx_file]; 249 FileSpec file_spec(filename, true); 250 251 if (llvm::sys::fs::equivalent(file_spec.GetPath(), 252 module_spec.GetFileSpec().GetPath())) 253 continue; 254 255 if (file_spec.Exists()) { 256 lldb_private::ModuleSpecList specs; 257 const size_t num_specs = 258 ObjectFile::GetModuleSpecifications(file_spec, 0, 0, specs); 259 assert(num_specs <= 1 && 260 "Symbol Vendor supports only a single architecture"); 261 if (num_specs == 1) { 262 ModuleSpec mspec; 263 if (specs.GetModuleSpecAtIndex(0, mspec)) { 264 if (mspec.GetUUID() == module_uuid) 265 return file_spec; 266 } 267 } 268 } 269 } 270 } 271 } 272 273 return LocateExecutableSymbolFileDsym(module_spec); 274 } 275 276 #if !defined(__APPLE__) 277 278 FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &symfile_bundle, 279 const lldb_private::UUID *uuid, 280 const ArchSpec *arch) { 281 // FIXME 282 return FileSpec(); 283 } 284 285 bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, 286 bool force_lookup) { 287 // Fill in the module_spec.GetFileSpec() for the object file and/or the 288 // module_spec.GetSymbolFileSpec() for the debug symbols file. 289 return false; 290 } 291 292 #endif 293