]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/Host/common/Symbols.cpp
Vendor import of lldb trunk r290819:
[FreeBSD/FreeBSD.git] / 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/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