1 //===-- Symbols.cpp ---------------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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"
24 #include "llvm/Support/FileSystem.h"
26 // From MacOSX system header "mach/machine.h"
27 typedef int cpu_type_t;
28 typedef int cpu_subtype_t;
31 using namespace lldb_private;
32 using namespace llvm::MachO;
34 #if defined(__APPLE__)
36 // Forward declaration of method defined in source/Host/macosx/Symbols.cpp
37 int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec,
38 ModuleSpec &return_module_spec);
42 int LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec &module_spec,
43 ModuleSpec &return_module_spec) {
44 // Cannot find MacOSX files using debug symbols on non MacOSX.
50 static bool FileAtPathContainsArchAndUUID(const FileSpec &file_fspec,
52 const lldb_private::UUID *uuid) {
53 ModuleSpecList module_specs;
54 if (ObjectFile::GetModuleSpecifications(file_fspec, 0, 0, module_specs)) {
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)))) {
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();
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) {
78 if (module_spec.GetUUIDPtr() && module_spec.GetUUIDPtr()->IsValid()) {
80 "Searching for dSYM bundle next to executable %s, UUID %s",
81 path, module_spec.GetUUIDPtr()->GetAsString().c_str());
83 log->Printf("Searching for dSYM bundle next to executable %s",
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);
93 dsym_fspec.SetFile(path, false);
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())) {
102 log->Printf("dSYM with matching UUID & arch found at %s", path);
106 path[obj_file_path_length] = '\0';
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) {
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())) {
123 log->Printf("dSYM with matching UUID & arch found at %s",
129 char *prev_slash = strrchr(path, '/');
130 if (prev_slash != NULL)
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();
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);
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);
166 dsym_module_spec.GetSymbolFileSpec() = symbol_fspec;
168 return dsym_module_spec.GetSymbolFileSpec();
171 ModuleSpec Symbols::LocateExecutableObjectFile(const ModuleSpec &module_spec) {
173 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
174 const ArchSpec *arch = module_spec.GetArchitecturePtr();
175 const UUID *uuid = module_spec.GetUUIDPtr();
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);
182 ModuleSpecList module_specs;
183 ModuleSpec matched_module_spec;
185 ObjectFile::GetModuleSpecifications(*exec_fspec, 0, 0, module_specs) &&
186 module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) {
187 result.GetFileSpec() = exec_fspec;
189 LocateMacOSXFilesUsingDebugSymbols(module_spec, result);
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;
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());
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));
209 // Add current working directory.
210 debug_file_search_paths.AppendIfUnique(FileSpec(".", true));
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
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";
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())
234 std::vector<std::string> files;
235 std::string dirname = dirspec.GetPath();
237 files.push_back(dirname + "/" + symbol_filename);
238 files.push_back(dirname + "/.debug/" + symbol_filename);
239 files.push_back(dirname + "/.build-id/" + uuid_str);
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);
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);
251 if (llvm::sys::fs::equivalent(file_spec.GetPath(),
252 module_spec.GetFileSpec().GetPath()))
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) {
263 if (specs.GetModuleSpecAtIndex(0, mspec)) {
264 if (mspec.GetUUID() == module_uuid)
273 return LocateExecutableSymbolFileDsym(module_spec);
276 #if !defined(__APPLE__)
278 FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &symfile_bundle,
279 const lldb_private::UUID *uuid,
280 const ArchSpec *arch) {
285 bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
287 // Fill in the module_spec.GetFileSpec() for the object file and/or the
288 // module_spec.GetSymbolFileSpec() for the debug symbols file.