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/Module.h" 13 #include "lldb/Core/ModuleSpec.h" 14 #include "lldb/Symbol/ObjectFile.h" 15 #include "lldb/Target/Target.h" 16 #include "lldb/Utility/DataBuffer.h" 17 #include "lldb/Utility/DataExtractor.h" 18 #include "lldb/Utility/Log.h" 19 #include "lldb/Utility/SafeMachO.h" 20 #include "lldb/Utility/StreamString.h" 21 #include "lldb/Utility/Timer.h" 22 #include "lldb/Utility/UUID.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 bool got_spec = module_specs.GetModuleSpecAtIndex(i, spec); 58 UNUSED_IF_ASSERT_DISABLED(got_spec); 59 assert(got_spec); 60 if ((uuid == NULL || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) && 61 (arch == NULL || (spec.GetArchitecturePtr() && 62 spec.GetArchitecture().IsCompatibleMatch(*arch)))) { 63 return true; 64 } 65 } 66 } 67 return false; 68 } 69 70 static bool LocateDSYMInVincinityOfExecutable(const ModuleSpec &module_spec, 71 FileSpec &dsym_fspec) { 72 Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); 73 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); 74 if (exec_fspec) { 75 char path[PATH_MAX]; 76 if (exec_fspec->GetPath(path, sizeof(path))) { 77 // Make sure the module isn't already just a dSYM file... 78 if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL) { 79 if (log) { 80 if (module_spec.GetUUIDPtr() && module_spec.GetUUIDPtr()->IsValid()) { 81 log->Printf( 82 "Searching for dSYM bundle next to executable %s, UUID %s", 83 path, module_spec.GetUUIDPtr()->GetAsString().c_str()); 84 } else { 85 log->Printf("Searching for dSYM bundle next to executable %s", 86 path); 87 } 88 } 89 ::strncat(path, ".dSYM/Contents/Resources/DWARF/", 90 sizeof(path) - strlen(path) - 1); 91 ::strncat(path, exec_fspec->GetFilename().AsCString(), 92 sizeof(path) - strlen(path) - 1); 93 94 dsym_fspec.SetFile(path, false); 95 96 ModuleSpecList module_specs; 97 ModuleSpec matched_module_spec; 98 if (dsym_fspec.Exists() && 99 FileAtPathContainsArchAndUUID(dsym_fspec, 100 module_spec.GetArchitecturePtr(), 101 module_spec.GetUUIDPtr())) { 102 if (log) { 103 log->Printf("dSYM with matching UUID & arch found at %s", path); 104 } 105 return true; 106 } else { 107 FileSpec parent_dirs = exec_fspec; 108 109 // Remove the binary name from the FileSpec 110 parent_dirs.RemoveLastPathComponent(); 111 112 // Add a ".dSYM" name to each directory component of the path, stripping 113 // off components. e.g. we may have a binary like 114 // /S/L/F/Foundation.framework/Versions/A/Foundation 115 // and 116 // /S/L/F/Foundation.framework.dSYM 117 // 118 // so we'll need to start with /S/L/F/Foundation.framework/Versions/A, 119 // add the .dSYM part to the "A", and if that doesn't exist, strip off 120 // the "A" and try it again with "Versions", etc., until we find a dSYM 121 // bundle or we've stripped off enough path components that there's no 122 // need to continue. 123 124 for (int i = 0; i < 4; i++) { 125 // Does this part of the path have a "." character - could it be a bundle's 126 // top level directory? 127 const char *fn = parent_dirs.GetFilename().AsCString(); 128 if (fn == nullptr) 129 break; 130 if (::strchr (fn, '.') != nullptr) { 131 dsym_fspec = parent_dirs; 132 dsym_fspec.RemoveLastPathComponent(); 133 134 // If the current directory name is "Foundation.framework", see if 135 // "Foundation.framework.dSYM/Contents/Resources/DWARF/Foundation" 136 // exists & has the right uuid. 137 std::string dsym_fn = fn; 138 dsym_fn += ".dSYM"; 139 dsym_fspec.AppendPathComponent(dsym_fn.c_str()); 140 dsym_fspec.AppendPathComponent("Contents"); 141 dsym_fspec.AppendPathComponent("Resources"); 142 dsym_fspec.AppendPathComponent("DWARF"); 143 dsym_fspec.AppendPathComponent(exec_fspec->GetFilename().AsCString()); 144 if (dsym_fspec.Exists() && 145 FileAtPathContainsArchAndUUID( 146 dsym_fspec, module_spec.GetArchitecturePtr(), 147 module_spec.GetUUIDPtr())) { 148 if (log) { 149 log->Printf("dSYM with matching UUID & arch found at %s", 150 dsym_fspec.GetPath().c_str()); 151 } 152 return true; 153 } 154 } 155 parent_dirs.RemoveLastPathComponent(); 156 } 157 } 158 } 159 } 160 } 161 dsym_fspec.Clear(); 162 return false; 163 } 164 165 FileSpec LocateExecutableSymbolFileDsym(const ModuleSpec &module_spec) { 166 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); 167 const ArchSpec *arch = module_spec.GetArchitecturePtr(); 168 const UUID *uuid = module_spec.GetUUIDPtr(); 169 170 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); 171 Timer scoped_timer( 172 func_cat, 173 "LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)", 174 exec_fspec ? exec_fspec->GetFilename().AsCString("<NULL>") : "<NULL>", 175 arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid); 176 177 FileSpec symbol_fspec; 178 ModuleSpec dsym_module_spec; 179 // First try and find the dSYM in the same directory as the executable or in 180 // an appropriate parent directory 181 if (LocateDSYMInVincinityOfExecutable(module_spec, symbol_fspec) == false) { 182 // We failed to easily find the dSYM above, so use DebugSymbols 183 LocateMacOSXFilesUsingDebugSymbols(module_spec, dsym_module_spec); 184 } else { 185 dsym_module_spec.GetSymbolFileSpec() = symbol_fspec; 186 } 187 return dsym_module_spec.GetSymbolFileSpec(); 188 } 189 190 ModuleSpec Symbols::LocateExecutableObjectFile(const ModuleSpec &module_spec) { 191 ModuleSpec result; 192 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr(); 193 const ArchSpec *arch = module_spec.GetArchitecturePtr(); 194 const UUID *uuid = module_spec.GetUUIDPtr(); 195 static Timer::Category func_cat(LLVM_PRETTY_FUNCTION); 196 Timer scoped_timer( 197 func_cat, "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)", 198 exec_fspec ? exec_fspec->GetFilename().AsCString("<NULL>") : "<NULL>", 199 arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid); 200 201 ModuleSpecList module_specs; 202 ModuleSpec matched_module_spec; 203 if (exec_fspec && 204 ObjectFile::GetModuleSpecifications(*exec_fspec, 0, 0, module_specs) && 205 module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) { 206 result.GetFileSpec() = exec_fspec; 207 } else { 208 LocateMacOSXFilesUsingDebugSymbols(module_spec, result); 209 } 210 return result; 211 } 212 213 FileSpec Symbols::LocateExecutableSymbolFile(const ModuleSpec &module_spec) { 214 FileSpec symbol_file_spec = module_spec.GetSymbolFileSpec(); 215 if (symbol_file_spec.IsAbsolute() && symbol_file_spec.Exists()) 216 return symbol_file_spec; 217 218 const char *symbol_filename = symbol_file_spec.GetFilename().AsCString(); 219 if (symbol_filename && symbol_filename[0]) { 220 FileSpecList debug_file_search_paths( 221 Target::GetDefaultDebugFileSearchPaths()); 222 223 // Add module directory. 224 const ConstString &file_dir = module_spec.GetFileSpec().GetDirectory(); 225 debug_file_search_paths.AppendIfUnique( 226 FileSpec(file_dir.AsCString("."), true)); 227 228 // Add current working directory. 229 debug_file_search_paths.AppendIfUnique(FileSpec(".", true)); 230 231 #ifndef LLVM_ON_WIN32 232 #if defined(__NetBSD__) 233 // Add /usr/libdata/debug directory. 234 debug_file_search_paths.AppendIfUnique(FileSpec("/usr/libdata/debug", true)); 235 #else 236 // Add /usr/lib/debug directory. 237 debug_file_search_paths.AppendIfUnique(FileSpec("/usr/lib/debug", true)); 238 #endif 239 #endif // LLVM_ON_WIN32 240 241 std::string uuid_str; 242 const UUID &module_uuid = module_spec.GetUUID(); 243 if (module_uuid.IsValid()) { 244 // Some debug files are stored in the .build-id directory like this: 245 // /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug 246 uuid_str = module_uuid.GetAsString(""); 247 uuid_str.insert(2, 1, '/'); 248 uuid_str = uuid_str + ".debug"; 249 } 250 251 size_t num_directories = debug_file_search_paths.GetSize(); 252 for (size_t idx = 0; idx < num_directories; ++idx) { 253 FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx); 254 dirspec.ResolvePath(); 255 if (!llvm::sys::fs::is_directory(dirspec.GetPath())) 256 continue; 257 258 std::vector<std::string> files; 259 std::string dirname = dirspec.GetPath(); 260 261 files.push_back(dirname + "/" + symbol_filename); 262 files.push_back(dirname + "/.debug/" + symbol_filename); 263 files.push_back(dirname + "/.build-id/" + uuid_str); 264 265 // Some debug files may stored in the module directory like this: 266 // /usr/lib/debug/usr/lib/library.so.debug 267 if (!file_dir.IsEmpty()) 268 files.push_back(dirname + file_dir.AsCString() + "/" + symbol_filename); 269 270 const uint32_t num_files = files.size(); 271 for (size_t idx_file = 0; idx_file < num_files; ++idx_file) { 272 const std::string &filename = files[idx_file]; 273 FileSpec file_spec(filename, true); 274 275 if (llvm::sys::fs::equivalent(file_spec.GetPath(), 276 module_spec.GetFileSpec().GetPath())) 277 continue; 278 279 if (file_spec.Exists()) { 280 lldb_private::ModuleSpecList specs; 281 const size_t num_specs = 282 ObjectFile::GetModuleSpecifications(file_spec, 0, 0, specs); 283 assert(num_specs <= 1 && 284 "Symbol Vendor supports only a single architecture"); 285 if (num_specs == 1) { 286 ModuleSpec mspec; 287 if (specs.GetModuleSpecAtIndex(0, mspec)) { 288 if (mspec.GetUUID() == module_uuid) 289 return file_spec; 290 } 291 } 292 } 293 } 294 } 295 } 296 297 return LocateExecutableSymbolFileDsym(module_spec); 298 } 299 300 #if !defined(__APPLE__) 301 302 FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &symfile_bundle, 303 const lldb_private::UUID *uuid, 304 const ArchSpec *arch) { 305 // FIXME 306 return FileSpec(); 307 } 308 309 bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec, 310 bool force_lookup) { 311 // Fill in the module_spec.GetFileSpec() for the object file and/or the 312 // module_spec.GetSymbolFileSpec() for the debug symbols file. 313 return false; 314 } 315 316 #endif 317