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
38 LocateMacOSXFilesUsingDebugSymbols
39 (
40     const ModuleSpec &module_spec,
41     ModuleSpec &return_module_spec
42 );
43 
44 #else
45 
46 int
47 LocateMacOSXFilesUsingDebugSymbols
48 (
49     const ModuleSpec &module_spec,
50     ModuleSpec &return_module_spec
51 ) {
52     // Cannot find MacOSX files using debug symbols on non MacOSX.
53     return 0;
54 }
55 
56 #endif
57 
58 static bool
59 FileAtPathContainsArchAndUUID (const FileSpec &file_fspec, const ArchSpec *arch, const lldb_private::UUID *uuid)
60 {
61     ModuleSpecList module_specs;
62     if (ObjectFile::GetModuleSpecifications(file_fspec, 0, 0, module_specs))
63     {
64         ModuleSpec spec;
65         for (size_t i = 0; i < module_specs.GetSize(); ++i)
66         {
67             assert(module_specs.GetModuleSpecAtIndex(i, spec));
68             if ((uuid == NULL || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
69                 (arch == NULL || (spec.GetArchitecturePtr() && spec.GetArchitecture().IsCompatibleMatch(*arch))))
70             {
71                 return true;
72             }
73         }
74     }
75     return false;
76 }
77 
78 static bool
79 LocateDSYMInVincinityOfExecutable (const ModuleSpec &module_spec, FileSpec &dsym_fspec)
80 {
81     Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
82     const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
83     if (exec_fspec)
84     {
85         char path[PATH_MAX];
86         if (exec_fspec->GetPath(path, sizeof(path)))
87         {
88             // Make sure the module isn't already just a dSYM file...
89             if (strcasestr(path, ".dSYM/Contents/Resources/DWARF") == NULL)
90             {
91                 if (log)
92                 {
93                     if (module_spec.GetUUIDPtr() && module_spec.GetUUIDPtr()->IsValid())
94                     {
95                         log->Printf ("Searching for dSYM bundle next to executable %s, UUID %s", path, module_spec.GetUUIDPtr()->GetAsString().c_str());
96                     }
97                     else
98                     {
99                         log->Printf ("Searching for dSYM bundle next to executable %s", path);
100                     }
101                 }
102                 size_t obj_file_path_length = strlen(path);
103                 ::strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path) - strlen(path) - 1);
104                 ::strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path) - strlen(path) - 1);
105 
106                 dsym_fspec.SetFile(path, false);
107 
108                 ModuleSpecList module_specs;
109                 ModuleSpec matched_module_spec;
110                 if (dsym_fspec.Exists() &&
111                     FileAtPathContainsArchAndUUID(dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr()))
112                 {
113                     if (log)
114                     {
115                         log->Printf ("dSYM with matching UUID & arch found at %s", path);
116                     }
117                     return true;
118                 }
119                 else
120                 {
121                     path[obj_file_path_length] = '\0';
122 
123                     char *last_dot = strrchr(path, '.');
124                     while (last_dot != NULL && last_dot[0])
125                     {
126                         char *next_slash = strchr(last_dot, '/');
127                         if (next_slash != NULL)
128                         {
129                             *next_slash = '\0';
130                             ::strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path) - strlen(path) - 1);
131                             ::strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path) - strlen(path) - 1);
132                             dsym_fspec.SetFile(path, false);
133                             if (dsym_fspec.Exists() &&
134                                 FileAtPathContainsArchAndUUID(dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr()))
135                             {
136                                 if (log)
137                                 {
138                                     log->Printf ("dSYM with matching UUID & arch found at %s", path);
139                                 }
140                                 return true;
141                             }
142                             else
143                             {
144                                 *last_dot = '\0';
145                                 char *prev_slash = strrchr(path, '/');
146                                 if (prev_slash != NULL)
147                                     *prev_slash = '\0';
148                                 else
149                                     break;
150                             }
151                         }
152                         else
153                         {
154                             break;
155                         }
156                     }
157                 }
158             }
159         }
160     }
161     dsym_fspec.Clear();
162     return false;
163 }
164 
165 FileSpec
166 LocateExecutableSymbolFileDsym (const ModuleSpec &module_spec)
167 {
168     const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
169     const ArchSpec *arch = module_spec.GetArchitecturePtr();
170     const UUID *uuid = module_spec.GetUUIDPtr();
171 
172     Timer scoped_timer (__PRETTY_FUNCTION__,
173                         "LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)",
174                         exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>",
175                         arch ? arch->GetArchitectureName() : "<NULL>",
176                         (const void*)uuid);
177 
178     FileSpec symbol_fspec;
179     ModuleSpec dsym_module_spec;
180     // First try and find the dSYM in the same directory as the executable or in
181     // an appropriate parent directory
182     if (LocateDSYMInVincinityOfExecutable (module_spec, symbol_fspec) == false)
183     {
184         // We failed to easily find the dSYM above, so use DebugSymbols
185         LocateMacOSXFilesUsingDebugSymbols (module_spec, dsym_module_spec);
186     }
187     else
188     {
189         dsym_module_spec.GetSymbolFileSpec() = symbol_fspec;
190     }
191     return dsym_module_spec.GetSymbolFileSpec();
192 }
193 
194 ModuleSpec
195 Symbols::LocateExecutableObjectFile (const ModuleSpec &module_spec)
196 {
197     ModuleSpec result;
198     const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
199     const ArchSpec *arch = module_spec.GetArchitecturePtr();
200     const UUID *uuid = module_spec.GetUUIDPtr();
201     Timer scoped_timer (__PRETTY_FUNCTION__,
202                         "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)",
203                         exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>",
204                         arch ? arch->GetArchitectureName() : "<NULL>",
205                         (const void*)uuid);
206 
207     ModuleSpecList module_specs;
208     ModuleSpec matched_module_spec;
209     if (exec_fspec &&
210         ObjectFile::GetModuleSpecifications(*exec_fspec, 0, 0, module_specs) &&
211         module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec))
212     {
213         result.GetFileSpec() = exec_fspec;
214     }
215     else
216     {
217         LocateMacOSXFilesUsingDebugSymbols (module_spec, result);
218     }
219     return result;
220 }
221 
222 FileSpec
223 Symbols::LocateExecutableSymbolFile (const ModuleSpec &module_spec)
224 {
225     FileSpec symbol_file_spec = module_spec.GetSymbolFileSpec();
226     if (symbol_file_spec.IsAbsolute() && symbol_file_spec.Exists())
227         return symbol_file_spec;
228 
229     const char *symbol_filename = symbol_file_spec.GetFilename().AsCString();
230     if (symbol_filename && symbol_filename[0])
231     {
232         FileSpecList debug_file_search_paths (Target::GetDefaultDebugFileSearchPaths());
233 
234         // Add module directory.
235         const ConstString &file_dir = module_spec.GetFileSpec().GetDirectory();
236         debug_file_search_paths.AppendIfUnique (FileSpec(file_dir.AsCString("."), true));
237 
238         // Add current working directory.
239         debug_file_search_paths.AppendIfUnique (FileSpec(".", true));
240 
241 #ifndef LLVM_ON_WIN32
242         // Add /usr/lib/debug directory.
243         debug_file_search_paths.AppendIfUnique (FileSpec("/usr/lib/debug", true));
244 #endif // LLVM_ON_WIN32
245 
246         std::string uuid_str;
247         const UUID &module_uuid = module_spec.GetUUID();
248         if (module_uuid.IsValid())
249         {
250             // Some debug files are stored in the .build-id directory like this:
251             //   /usr/lib/debug/.build-id/ff/e7fe727889ad82bb153de2ad065b2189693315.debug
252             uuid_str = module_uuid.GetAsString("");
253             uuid_str.insert (2, 1, '/');
254             uuid_str = uuid_str + ".debug";
255         }
256 
257         size_t num_directories = debug_file_search_paths.GetSize();
258         for (size_t idx = 0; idx < num_directories; ++idx)
259         {
260             FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex (idx);
261             dirspec.ResolvePath();
262             if (!dirspec.Exists() || !dirspec.IsDirectory())
263                 continue;
264 
265             std::vector<std::string> files;
266             std::string dirname = dirspec.GetPath();
267 
268             files.push_back (dirname + "/" + symbol_filename);
269             files.push_back (dirname + "/.debug/" + symbol_filename);
270             files.push_back (dirname + "/.build-id/" + uuid_str);
271 
272             // Some debug files may stored in the module directory like this:
273             //   /usr/lib/debug/usr/lib/library.so.debug
274             if (!file_dir.IsEmpty())
275                 files.push_back (dirname + file_dir.AsCString() + "/" + symbol_filename);
276 
277             const uint32_t num_files = files.size();
278             for (size_t idx_file = 0; idx_file < num_files; ++idx_file)
279             {
280                 const std::string &filename = files[idx_file];
281                 FileSpec file_spec (filename.c_str(), true);
282 
283                 if (llvm::sys::fs::equivalent (file_spec.GetPath(), module_spec.GetFileSpec().GetPath()))
284                     continue;
285 
286                 if (file_spec.Exists())
287                 {
288                     lldb_private::ModuleSpecList specs;
289                     const size_t num_specs = ObjectFile::GetModuleSpecifications (file_spec, 0, 0, specs);
290                     assert (num_specs <= 1 && "Symbol Vendor supports only a single architecture");
291                     if (num_specs == 1)
292                     {
293                         ModuleSpec mspec;
294                         if (specs.GetModuleSpecAtIndex (0, mspec))
295                         {
296                             if (mspec.GetUUID() == module_uuid)
297                                 return file_spec;
298                         }
299                     }
300                 }
301             }
302         }
303     }
304 
305     return LocateExecutableSymbolFileDsym(module_spec);
306 }
307 
308 #if !defined (__APPLE__)
309 
310 FileSpec
311 Symbols::FindSymbolFileInBundle (const FileSpec& symfile_bundle,
312                                  const lldb_private::UUID *uuid,
313                                  const ArchSpec *arch)
314 {
315     // FIXME
316     return FileSpec();
317 }
318 
319 bool
320 Symbols::DownloadObjectAndSymbolFile (ModuleSpec &module_spec, bool force_lookup)
321 {
322     // Fill in the module_spec.GetFileSpec() for the object file and/or the
323     // module_spec.GetSymbolFileSpec() for the debug symbols file.
324     return false;
325 }
326 
327 #endif
328