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/Module.h"
15 #include "lldb/Core/ModuleSpec.h"
16 #include "lldb/Core/StreamString.h"
17 #include "lldb/Core/Timer.h"
18 #include "lldb/Core/UUID.h"
19 #include "lldb/Symbol/ObjectFile.h"
20 #include "lldb/Target/Target.h"
21 #include "lldb/Utility/SafeMachO.h"
22
23 #include "llvm/Support/FileSystem.h"
24
25 // From MacOSX system header "mach/machine.h"
26 typedef int cpu_type_t;
27 typedef int cpu_subtype_t;
28
29 using namespace lldb;
30 using namespace lldb_private;
31 using namespace llvm::MachO;
32
33 #if defined(__APPLE__)
34
35 // Forward declaration of method defined in source/Host/macosx/Symbols.cpp
36 int
37 LocateMacOSXFilesUsingDebugSymbols
38 (
39 const ModuleSpec &module_spec,
40 FileSpec *out_exec_fspec, // If non-NULL, try and find the executable
41 FileSpec *out_dsym_fspec // If non-NULL try and find the debug symbol file
42 );
43
44 #else
45
46 int
LocateMacOSXFilesUsingDebugSymbols(const ModuleSpec & module_spec,FileSpec * out_exec_fspec,FileSpec * out_dsym_fspec)47 LocateMacOSXFilesUsingDebugSymbols
48 (
49 const ModuleSpec &module_spec,
50 FileSpec *out_exec_fspec, // If non-NULL, try and find the executable
51 FileSpec *out_dsym_fspec // If non-NULL try and find the debug symbol file
52 ) {
53 // Cannot find MacOSX files using debug symbols on non MacOSX.
54 return 0;
55 }
56
57 #endif
58
59 static bool
FileAtPathContainsArchAndUUID(const FileSpec & file_fspec,const ArchSpec * arch,const lldb_private::UUID * uuid)60 FileAtPathContainsArchAndUUID (const FileSpec &file_fspec, const ArchSpec *arch, const lldb_private::UUID *uuid)
61 {
62 ModuleSpecList module_specs;
63 if (ObjectFile::GetModuleSpecifications(file_fspec, 0, 0, module_specs))
64 {
65 ModuleSpec spec;
66 for (size_t i = 0; i < module_specs.GetSize(); ++i)
67 {
68 assert(module_specs.GetModuleSpecAtIndex(i, spec));
69 if ((uuid == NULL || (spec.GetUUIDPtr() && spec.GetUUID() == *uuid)) &&
70 (arch == NULL || (spec.GetArchitecturePtr() && spec.GetArchitecture().IsCompatibleMatch(*arch))))
71 {
72 return true;
73 }
74 }
75 }
76 return false;
77 }
78
79 static bool
LocateDSYMInVincinityOfExecutable(const ModuleSpec & module_spec,FileSpec & dsym_fspec)80 LocateDSYMInVincinityOfExecutable (const ModuleSpec &module_spec, FileSpec &dsym_fspec)
81 {
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 size_t obj_file_path_length = strlen(path);
92 ::strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path) - strlen(path) - 1);
93 ::strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path) - strlen(path) - 1);
94
95 dsym_fspec.SetFile(path, false);
96
97 ModuleSpecList module_specs;
98 ModuleSpec matched_module_spec;
99 if (dsym_fspec.Exists() &&
100 FileAtPathContainsArchAndUUID(dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr()))
101 {
102 return true;
103 }
104 else
105 {
106 path[obj_file_path_length] = '\0';
107
108 char *last_dot = strrchr(path, '.');
109 while (last_dot != NULL && last_dot[0])
110 {
111 char *next_slash = strchr(last_dot, '/');
112 if (next_slash != NULL)
113 {
114 *next_slash = '\0';
115 ::strncat(path, ".dSYM/Contents/Resources/DWARF/", sizeof(path) - strlen(path) - 1);
116 ::strncat(path, exec_fspec->GetFilename().AsCString(), sizeof(path) - strlen(path) - 1);
117 dsym_fspec.SetFile(path, false);
118 if (dsym_fspec.Exists() &&
119 FileAtPathContainsArchAndUUID(dsym_fspec, module_spec.GetArchitecturePtr(), module_spec.GetUUIDPtr()))
120 {
121 return true;
122 }
123 else
124 {
125 *last_dot = '\0';
126 char *prev_slash = strrchr(path, '/');
127 if (prev_slash != NULL)
128 *prev_slash = '\0';
129 else
130 break;
131 }
132 }
133 else
134 {
135 break;
136 }
137 }
138 }
139 }
140 }
141 }
142 dsym_fspec.Clear();
143 return false;
144 }
145
146 FileSpec
LocateExecutableSymbolFileDsym(const ModuleSpec & module_spec)147 LocateExecutableSymbolFileDsym (const ModuleSpec &module_spec)
148 {
149 const FileSpec *exec_fspec = module_spec.GetFileSpecPtr();
150 const ArchSpec *arch = module_spec.GetArchitecturePtr();
151 const UUID *uuid = module_spec.GetUUIDPtr();
152
153 Timer scoped_timer (__PRETTY_FUNCTION__,
154 "LocateExecutableSymbolFileDsym (file = %s, arch = %s, uuid = %p)",
155 exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>",
156 arch ? arch->GetArchitectureName() : "<NULL>",
157 (void*)uuid);
158
159 FileSpec symbol_fspec;
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 {
164 // We failed to easily find the dSYM above, so use DebugSymbols
165 LocateMacOSXFilesUsingDebugSymbols (module_spec, NULL, &symbol_fspec);
166 }
167 return symbol_fspec;
168 }
169
170 FileSpec
LocateExecutableObjectFile(const ModuleSpec & module_spec)171 Symbols::LocateExecutableObjectFile (const ModuleSpec &module_spec)
172 {
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 (__PRETTY_FUNCTION__,
177 "LocateExecutableObjectFile (file = %s, arch = %s, uuid = %p)",
178 exec_fspec ? exec_fspec->GetFilename().AsCString ("<NULL>") : "<NULL>",
179 arch ? arch->GetArchitectureName() : "<NULL>",
180 (void*)uuid);
181
182 FileSpec objfile_fspec;
183 ModuleSpecList module_specs;
184 ModuleSpec matched_module_spec;
185 if (exec_fspec &&
186 ObjectFile::GetModuleSpecifications(*exec_fspec, 0, 0, module_specs) &&
187 module_specs.FindMatchingModuleSpec(module_spec, matched_module_spec))
188 {
189 objfile_fspec = exec_fspec;
190 }
191 else
192 {
193 LocateMacOSXFilesUsingDebugSymbols (module_spec, &objfile_fspec, NULL);
194 }
195 return objfile_fspec;
196 }
197
198 FileSpec
LocateExecutableSymbolFile(const ModuleSpec & module_spec)199 Symbols::LocateExecutableSymbolFile (const ModuleSpec &module_spec)
200 {
201 const char *symbol_filename = module_spec.GetSymbolFileSpec().GetFilename().AsCString();
202 if (symbol_filename && symbol_filename[0])
203 {
204 FileSpecList debug_file_search_paths (Target::GetDefaultDebugFileSearchPaths());
205
206 // Add module directory.
207 const ConstString &file_dir = module_spec.GetFileSpec().GetDirectory();
208 debug_file_search_paths.AppendIfUnique (FileSpec(file_dir.AsCString("."), true));
209
210 // Add current working directory.
211 debug_file_search_paths.AppendIfUnique (FileSpec(".", true));
212
213 // Add /usr/lib/debug directory.
214 debug_file_search_paths.AppendIfUnique (FileSpec("/usr/lib/debug", true));
215
216 std::string uuid_str;
217 const UUID &module_uuid = module_spec.GetUUID();
218 if (module_uuid.IsValid())
219 {
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 // Get directory of our module. Needed to check debug files like this:
228 // /usr/lib/debug/usr/lib/library.so.debug
229 std::string module_directory = module_spec.GetFileSpec().GetDirectory().AsCString();
230
231 size_t num_directories = debug_file_search_paths.GetSize();
232 for (size_t idx = 0; idx < num_directories; ++idx)
233 {
234 FileSpec dirspec = debug_file_search_paths.GetFileSpecAtIndex (idx);
235 dirspec.ResolvePath();
236 if (!dirspec.Exists() || !dirspec.IsDirectory())
237 continue;
238
239 std::vector<std::string> files;
240 std::string dirname = dirspec.GetPath();
241
242 files.push_back (dirname + "/" + symbol_filename);
243 files.push_back (dirname + "/.debug/" + symbol_filename);
244 files.push_back (dirname + "/.build-id/" + uuid_str);
245 files.push_back (dirname + module_directory + "/" + symbol_filename);
246
247 const uint32_t num_files = files.size();
248 for (size_t idx_file = 0; idx_file < num_files; ++idx_file)
249 {
250 const std::string &filename = files[idx_file];
251 FileSpec file_spec (filename.c_str(), true);
252
253 if (llvm::sys::fs::equivalent (file_spec.GetPath(), module_spec.GetFileSpec().GetPath()))
254 continue;
255
256 if (file_spec.Exists())
257 {
258 lldb_private::ModuleSpecList specs;
259 const size_t num_specs = ObjectFile::GetModuleSpecifications (file_spec, 0, 0, specs);
260 assert (num_specs <= 1 && "Symbol Vendor supports only a single architecture");
261 if (num_specs == 1)
262 {
263 ModuleSpec mspec;
264 if (specs.GetModuleSpecAtIndex (0, mspec))
265 {
266 if (mspec.GetUUID() == module_uuid)
267 return file_spec;
268 }
269 }
270 }
271 }
272 }
273 }
274
275 return LocateExecutableSymbolFileDsym(module_spec);
276 }
277
278 #if !defined (__APPLE__)
279
280 FileSpec
FindSymbolFileInBundle(const FileSpec & symfile_bundle,const lldb_private::UUID * uuid,const ArchSpec * arch)281 Symbols::FindSymbolFileInBundle (const FileSpec& symfile_bundle,
282 const lldb_private::UUID *uuid,
283 const ArchSpec *arch)
284 {
285 // FIXME
286 return FileSpec();
287 }
288
289 bool
DownloadObjectAndSymbolFile(ModuleSpec & module_spec,bool force_lookup)290 Symbols::DownloadObjectAndSymbolFile (ModuleSpec &module_spec, bool force_lookup)
291 {
292 // Fill in the module_spec.GetFileSpec() for the object file and/or the
293 // module_spec.GetSymbolFileSpec() for the debug symbols file.
294 return false;
295 }
296
297 #endif
298