]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/source/Host/common/Symbols.cpp
Merge clang 7.0.1 and several follow-up changes
[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/ModuleSpec.h"
12 #include "lldb/Host/FileSystem.h"
13 #include "lldb/Symbol/ObjectFile.h"
14 #include "lldb/Target/Target.h"
15 #include "lldb/Utility/ArchSpec.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, FileSpec::Style::native);
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,
113           // stripping off components.  e.g. we may have a binary like
114           // /S/L/F/Foundation.framework/Versions/A/Foundation and
115           // /S/L/F/Foundation.framework.dSYM
116           //
117           // so we'll need to start with
118           // /S/L/F/Foundation.framework/Versions/A, add the .dSYM part to the
119           // "A", and if that doesn't exist, strip off the "A" and try it again
120           // with "Versions", etc., until we find a dSYM bundle or we've
121           // stripped off enough path components that there's no need to
122           // continue.
123
124           for (int i = 0; i < 4; i++) {
125             // Does this part of the path have a "." character - could it be a
126             // bundle's 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
135               // if
136               // "Foundation.framework.dSYM/Contents/Resources/DWARF/Foundation"
137               // exists & has the right uuid.
138               std::string dsym_fn = fn;
139               dsym_fn += ".dSYM";
140               dsym_fspec.AppendPathComponent(dsym_fn.c_str());
141               dsym_fspec.AppendPathComponent("Contents");
142               dsym_fspec.AppendPathComponent("Resources");
143               dsym_fspec.AppendPathComponent("DWARF");
144               dsym_fspec.AppendPathComponent(
145                   exec_fspec->GetFilename().AsCString());
146               if (dsym_fspec.Exists() &&
147                   FileAtPathContainsArchAndUUID(
148                       dsym_fspec, module_spec.GetArchitecturePtr(),
149                       module_spec.GetUUIDPtr())) {
150                 if (log) {
151                   log->Printf("dSYM with matching UUID & arch found at %s",
152                               dsym_fspec.GetPath().c_str());
153                 }
154                 return true;
155               }
156             }
157             parent_dirs.RemoveLastPathComponent();
158           }
159         }
160       }
161     }
162   }
163   dsym_fspec.Clear();
164   return false;
165 }
166
167 FileSpec LocateExecutableSymbolFileDsym(const ModuleSpec &module_spec) {
168   const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
169   const ArchSpec *arch = module_spec.GetArchitecturePtr();
170   const UUID *uuid = module_spec.GetUUIDPtr();
171
172   static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
173   Timer scoped_timer(
174       func_cat,
175       "LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)",
176       exec_fspec ? exec_fspec->GetFilename().AsCString("<NULL>") : "<NULL>",
177       arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid);
178
179   FileSpec symbol_fspec;
180   ModuleSpec dsym_module_spec;
181   // First try and find the dSYM in the same directory as the executable or in
182   // an appropriate parent directory
183   if (LocateDSYMInVincinityOfExecutable(module_spec, symbol_fspec) == false) {
184     // We failed to easily find the dSYM above, so use DebugSymbols
185     LocateMacOSXFilesUsingDebugSymbols(module_spec, dsym_module_spec);
186   } else {
187     dsym_module_spec.GetSymbolFileSpec() = symbol_fspec;
188   }
189   return dsym_module_spec.GetSymbolFileSpec();
190 }
191
192 ModuleSpec Symbols::LocateExecutableObjectFile(const ModuleSpec &module_spec) {
193   ModuleSpec result;
194   const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
195   const ArchSpec *arch = module_spec.GetArchitecturePtr();
196   const UUID *uuid = module_spec.GetUUIDPtr();
197   static Timer::Category func_cat(LLVM_PRETTY_FUNCTION);
198   Timer scoped_timer(
199       func_cat, "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)",
200       exec_fspec ? exec_fspec->GetFilename().AsCString("<NULL>") : "<NULL>",
201       arch ? arch->GetArchitectureName() : "<NULL>", (const void *)uuid);
202
203   ModuleSpecList module_specs;
204   ModuleSpec matched_module_spec;
205   if (exec_fspec &&
206       ObjectFile::GetModuleSpecifications(*exec_fspec, 0, 0, module_specs) &&
207       module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec)) {
208     result.GetFileSpec() = exec_fspec;
209   } else {
210     LocateMacOSXFilesUsingDebugSymbols(module_spec, result);
211   }
212   return result;
213 }
214
215 FileSpec Symbols::LocateExecutableSymbolFile(const ModuleSpec &module_spec) {
216   FileSpec symbol_file_spec = module_spec.GetSymbolFileSpec();
217   if (symbol_file_spec.IsAbsolute() && symbol_file_spec.Exists())
218     return symbol_file_spec;
219
220   const char *symbol_filename = symbol_file_spec.GetFilename().AsCString();
221   if (symbol_filename && symbol_filename[0]) {
222     FileSpecList debug_file_search_paths(
223         Target::GetDefaultDebugFileSearchPaths());
224
225     // Add module directory.
226     FileSpec module_file_spec = module_spec.GetFileSpec();
227     // We keep the unresolved pathname if it fails.
228     FileSystem::ResolveSymbolicLink(module_file_spec, module_file_spec);
229
230     const ConstString &file_dir = module_file_spec.GetDirectory();
231     debug_file_search_paths.AppendIfUnique(
232         FileSpec(file_dir.AsCString("."), true));
233
234     // Add current working directory.
235     debug_file_search_paths.AppendIfUnique(FileSpec(".", true));
236
237 #ifndef _WIN32
238 #if defined(__NetBSD__)
239     // Add /usr/libdata/debug directory.
240     debug_file_search_paths.AppendIfUnique(
241         FileSpec("/usr/libdata/debug", true));
242 #else
243     // Add /usr/lib/debug directory.
244     debug_file_search_paths.AppendIfUnique(FileSpec("/usr/lib/debug", true));
245 #endif
246 #endif // _WIN32
247
248     std::string uuid_str;
249     const UUID &module_uuid = module_spec.GetUUID();
250     if (module_uuid.IsValid()) {
251       // Some debug files are stored in the .build-id directory like this:
252       //   /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug
253       uuid_str = module_uuid.GetAsString("");
254       std::transform(uuid_str.begin(), uuid_str.end(), uuid_str.begin(),
255           ::tolower);
256       uuid_str.insert(2, 1, '/');
257       uuid_str = uuid_str + ".debug";
258     }
259
260     size_t num_directories = debug_file_search_paths.GetSize();
261     for (size_t idx = 0; idx < num_directories; ++idx) {
262       FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex(idx);
263       dirspec.ResolvePath();
264       if (!llvm::sys::fs::is_directory(dirspec.GetPath()))
265         continue;
266
267       std::vector<std::string> files;
268       std::string dirname = dirspec.GetPath();
269
270       files.push_back(dirname + "/" + symbol_filename);
271       files.push_back(dirname + "/.debug/" + symbol_filename);
272       files.push_back(dirname + "/.build-id/" + uuid_str);
273
274       // Some debug files may stored in the module directory like this:
275       //   /usr/lib/debug/usr/lib/library.so.debug
276       if (!file_dir.IsEmpty())
277         files.push_back(dirname + file_dir.AsCString() + "/" + symbol_filename);
278
279       const uint32_t num_files = files.size();
280       for (size_t idx_file = 0; idx_file < num_files; ++idx_file) {
281         const std::string &filename = files[idx_file];
282         FileSpec file_spec(filename, true);
283
284         if (llvm::sys::fs::equivalent(file_spec.GetPath(),
285                                       module_file_spec.GetPath()))
286           continue;
287
288         if (file_spec.Exists()) {
289           lldb_private::ModuleSpecList specs;
290           const size_t num_specs =
291               ObjectFile::GetModuleSpecifications(file_spec, 0, 0, specs);
292           assert(num_specs <= 1 &&
293                  "Symbol Vendor supports only a single architecture");
294           if (num_specs == 1) {
295             ModuleSpec mspec;
296             if (specs.GetModuleSpecAtIndex(0, mspec)) {
297               // Skip the uuids check if module_uuid is invalid. For example,
298               // this happens for *.dwp files since at the moment llvm-dwp
299               // doesn't output build ids, nor does binutils dwp.
300               if (!module_uuid.IsValid() || module_uuid == mspec.GetUUID())
301                 return file_spec;
302             }
303           }
304         }
305       }
306     }
307   }
308
309   return LocateExecutableSymbolFileDsym(module_spec);
310 }
311
312 #if !defined(__APPLE__)
313
314 FileSpec Symbols::FindSymbolFileInBundle(const FileSpec &symfile_bundle,
315                                          const lldb_private::UUID *uuid,
316                                          const ArchSpec *arch) {
317   // FIXME
318   return FileSpec();
319 }
320
321 bool Symbols::DownloadObjectAndSymbolFile(ModuleSpec &module_spec,
322                                           bool force_lookup) {
323   // Fill in the module_spec.GetFileSpec() for the object file and/or the
324   // module_spec.GetSymbolFileSpec() for the debug symbols file.
325   return false;
326 }
327
328 #endif