]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Host/common/Symbols.cpp
Merge llvm, clang, lld, lldb, compiler-rt and libc++ r305575, and update
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / source / Host / common / Symbols.cpp
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/Core/Timer.h"
15 #include "lldb/Symbol/ObjectFile.h"
16 #include "lldb/Target/Target.h"
17 #include "lldb/Utility/DataBuffer.h"
18 #include "lldb/Utility/DataExtractor.h"
19 #include "lldb/Utility/Log.h"
20 #include "lldb/Utility/SafeMachO.h"
21 #include "lldb/Utility/StreamString.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