File: | src/gnu/usr.bin/clang/liblldbPluginObjectFile/../../../llvm/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp |
Warning: | line 4641, column 7 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | //===-- ObjectFileMachO.cpp -----------------------------------------------===// | ||||||||
2 | // | ||||||||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||||||
4 | // See https://llvm.org/LICENSE.txt for license information. | ||||||||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||||||
6 | // | ||||||||
7 | //===----------------------------------------------------------------------===// | ||||||||
8 | |||||||||
9 | #include "llvm/ADT/StringRef.h" | ||||||||
10 | |||||||||
11 | #include "Plugins/Process/Utility/RegisterContextDarwin_arm.h" | ||||||||
12 | #include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h" | ||||||||
13 | #include "Plugins/Process/Utility/RegisterContextDarwin_i386.h" | ||||||||
14 | #include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h" | ||||||||
15 | #include "lldb/Core/Debugger.h" | ||||||||
16 | #include "lldb/Core/FileSpecList.h" | ||||||||
17 | #include "lldb/Core/Module.h" | ||||||||
18 | #include "lldb/Core/ModuleSpec.h" | ||||||||
19 | #include "lldb/Core/PluginManager.h" | ||||||||
20 | #include "lldb/Core/Progress.h" | ||||||||
21 | #include "lldb/Core/Section.h" | ||||||||
22 | #include "lldb/Core/StreamFile.h" | ||||||||
23 | #include "lldb/Host/Host.h" | ||||||||
24 | #include "lldb/Host/SafeMachO.h" | ||||||||
25 | #include "lldb/Symbol/DWARFCallFrameInfo.h" | ||||||||
26 | #include "lldb/Symbol/LocateSymbolFile.h" | ||||||||
27 | #include "lldb/Symbol/ObjectFile.h" | ||||||||
28 | #include "lldb/Target/DynamicLoader.h" | ||||||||
29 | #include "lldb/Target/MemoryRegionInfo.h" | ||||||||
30 | #include "lldb/Target/Platform.h" | ||||||||
31 | #include "lldb/Target/Process.h" | ||||||||
32 | #include "lldb/Target/SectionLoadList.h" | ||||||||
33 | #include "lldb/Target/Target.h" | ||||||||
34 | #include "lldb/Target/Thread.h" | ||||||||
35 | #include "lldb/Target/ThreadList.h" | ||||||||
36 | #include "lldb/Utility/ArchSpec.h" | ||||||||
37 | #include "lldb/Utility/DataBuffer.h" | ||||||||
38 | #include "lldb/Utility/FileSpec.h" | ||||||||
39 | #include "lldb/Utility/Log.h" | ||||||||
40 | #include "lldb/Utility/RangeMap.h" | ||||||||
41 | #include "lldb/Utility/RegisterValue.h" | ||||||||
42 | #include "lldb/Utility/Status.h" | ||||||||
43 | #include "lldb/Utility/StreamString.h" | ||||||||
44 | #include "lldb/Utility/Timer.h" | ||||||||
45 | #include "lldb/Utility/UUID.h" | ||||||||
46 | |||||||||
47 | #include "llvm/ADT/DenseSet.h" | ||||||||
48 | #include "llvm/Support/FormatVariadic.h" | ||||||||
49 | #include "llvm/Support/MemoryBuffer.h" | ||||||||
50 | |||||||||
51 | #include "ObjectFileMachO.h" | ||||||||
52 | |||||||||
53 | #if defined(__APPLE__) | ||||||||
54 | #include <TargetConditionals.h> | ||||||||
55 | // GetLLDBSharedCacheUUID() needs to call dlsym() | ||||||||
56 | #include <dlfcn.h> | ||||||||
57 | #endif | ||||||||
58 | |||||||||
59 | #ifndef __APPLE__ | ||||||||
60 | #include "Utility/UuidCompatibility.h" | ||||||||
61 | #else | ||||||||
62 | #include <uuid/uuid.h> | ||||||||
63 | #endif | ||||||||
64 | |||||||||
65 | #include <bitset> | ||||||||
66 | #include <memory> | ||||||||
67 | |||||||||
68 | #if LLVM_SUPPORT_XCODE_SIGNPOSTS0 | ||||||||
69 | // Unfortunately the signpost header pulls in the system MachO header, too. | ||||||||
70 | #undef CPU_TYPE_ARM | ||||||||
71 | #undef CPU_TYPE_ARM64 | ||||||||
72 | #undef CPU_TYPE_ARM64_32 | ||||||||
73 | #undef CPU_TYPE_I386 | ||||||||
74 | #undef CPU_TYPE_X86_64 | ||||||||
75 | #undef MH_BINDATLOAD | ||||||||
76 | #undef MH_BUNDLE | ||||||||
77 | #undef MH_CIGAM | ||||||||
78 | #undef MH_CIGAM_64 | ||||||||
79 | #undef MH_CORE | ||||||||
80 | #undef MH_DSYM | ||||||||
81 | #undef MH_DYLDLINK | ||||||||
82 | #undef MH_DYLIB | ||||||||
83 | #undef MH_DYLIB_STUB | ||||||||
84 | #undef MH_DYLINKER | ||||||||
85 | #undef MH_DYLINKER | ||||||||
86 | #undef MH_EXECUTE | ||||||||
87 | #undef MH_FVMLIB | ||||||||
88 | #undef MH_INCRLINK | ||||||||
89 | #undef MH_KEXT_BUNDLE | ||||||||
90 | #undef MH_MAGIC | ||||||||
91 | #undef MH_MAGIC_64 | ||||||||
92 | #undef MH_NOUNDEFS | ||||||||
93 | #undef MH_OBJECT | ||||||||
94 | #undef MH_OBJECT | ||||||||
95 | #undef MH_PRELOAD | ||||||||
96 | |||||||||
97 | #undef LC_BUILD_VERSION | ||||||||
98 | #undef LC_VERSION_MIN_MACOSX | ||||||||
99 | #undef LC_VERSION_MIN_IPHONEOS | ||||||||
100 | #undef LC_VERSION_MIN_TVOS | ||||||||
101 | #undef LC_VERSION_MIN_WATCHOS | ||||||||
102 | |||||||||
103 | #undef PLATFORM_MACOS | ||||||||
104 | #undef PLATFORM_MACCATALYST | ||||||||
105 | #undef PLATFORM_IOS | ||||||||
106 | #undef PLATFORM_IOSSIMULATOR | ||||||||
107 | #undef PLATFORM_TVOS | ||||||||
108 | #undef PLATFORM_TVOSSIMULATOR | ||||||||
109 | #undef PLATFORM_WATCHOS | ||||||||
110 | #undef PLATFORM_WATCHOSSIMULATOR | ||||||||
111 | #endif | ||||||||
112 | |||||||||
113 | #define THUMB_ADDRESS_BIT_MASK0xfffffffffffffffeull 0xfffffffffffffffeull | ||||||||
114 | using namespace lldb; | ||||||||
115 | using namespace lldb_private; | ||||||||
116 | using namespace llvm::MachO; | ||||||||
117 | |||||||||
118 | LLDB_PLUGIN_DEFINE(ObjectFileMachO)namespace lldb_private { void lldb_initialize_ObjectFileMachO () { ObjectFileMachO::Initialize(); } void lldb_terminate_ObjectFileMachO () { ObjectFileMachO::Terminate(); } } | ||||||||
119 | |||||||||
120 | // Some structure definitions needed for parsing the dyld shared cache files | ||||||||
121 | // found on iOS devices. | ||||||||
122 | |||||||||
123 | struct lldb_copy_dyld_cache_header_v1 { | ||||||||
124 | char magic[16]; // e.g. "dyld_v0 i386", "dyld_v1 armv7", etc. | ||||||||
125 | uint32_t mappingOffset; // file offset to first dyld_cache_mapping_info | ||||||||
126 | uint32_t mappingCount; // number of dyld_cache_mapping_info entries | ||||||||
127 | uint32_t imagesOffset; | ||||||||
128 | uint32_t imagesCount; | ||||||||
129 | uint64_t dyldBaseAddress; | ||||||||
130 | uint64_t codeSignatureOffset; | ||||||||
131 | uint64_t codeSignatureSize; | ||||||||
132 | uint64_t slideInfoOffset; | ||||||||
133 | uint64_t slideInfoSize; | ||||||||
134 | uint64_t localSymbolsOffset; | ||||||||
135 | uint64_t localSymbolsSize; | ||||||||
136 | uint8_t uuid[16]; // v1 and above, also recorded in dyld_all_image_infos v13 | ||||||||
137 | // and later | ||||||||
138 | }; | ||||||||
139 | |||||||||
140 | struct lldb_copy_dyld_cache_mapping_info { | ||||||||
141 | uint64_t address; | ||||||||
142 | uint64_t size; | ||||||||
143 | uint64_t fileOffset; | ||||||||
144 | uint32_t maxProt; | ||||||||
145 | uint32_t initProt; | ||||||||
146 | }; | ||||||||
147 | |||||||||
148 | struct lldb_copy_dyld_cache_local_symbols_info { | ||||||||
149 | uint32_t nlistOffset; | ||||||||
150 | uint32_t nlistCount; | ||||||||
151 | uint32_t stringsOffset; | ||||||||
152 | uint32_t stringsSize; | ||||||||
153 | uint32_t entriesOffset; | ||||||||
154 | uint32_t entriesCount; | ||||||||
155 | }; | ||||||||
156 | struct lldb_copy_dyld_cache_local_symbols_entry { | ||||||||
157 | uint32_t dylibOffset; | ||||||||
158 | uint32_t nlistStartIndex; | ||||||||
159 | uint32_t nlistCount; | ||||||||
160 | }; | ||||||||
161 | |||||||||
162 | static void PrintRegisterValue(RegisterContext *reg_ctx, const char *name, | ||||||||
163 | const char *alt_name, size_t reg_byte_size, | ||||||||
164 | Stream &data) { | ||||||||
165 | const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name); | ||||||||
166 | if (reg_info == nullptr) | ||||||||
167 | reg_info = reg_ctx->GetRegisterInfoByName(alt_name); | ||||||||
168 | if (reg_info) { | ||||||||
169 | lldb_private::RegisterValue reg_value; | ||||||||
170 | if (reg_ctx->ReadRegister(reg_info, reg_value)) { | ||||||||
171 | if (reg_info->byte_size >= reg_byte_size) | ||||||||
172 | data.Write(reg_value.GetBytes(), reg_byte_size); | ||||||||
173 | else { | ||||||||
174 | data.Write(reg_value.GetBytes(), reg_info->byte_size); | ||||||||
175 | for (size_t i = 0, n = reg_byte_size - reg_info->byte_size; i < n; ++i) | ||||||||
176 | data.PutChar(0); | ||||||||
177 | } | ||||||||
178 | return; | ||||||||
179 | } | ||||||||
180 | } | ||||||||
181 | // Just write zeros if all else fails | ||||||||
182 | for (size_t i = 0; i < reg_byte_size; ++i) | ||||||||
183 | data.PutChar(0); | ||||||||
184 | } | ||||||||
185 | |||||||||
186 | class RegisterContextDarwin_x86_64_Mach : public RegisterContextDarwin_x86_64 { | ||||||||
187 | public: | ||||||||
188 | RegisterContextDarwin_x86_64_Mach(lldb_private::Thread &thread, | ||||||||
189 | const DataExtractor &data) | ||||||||
190 | : RegisterContextDarwin_x86_64(thread, 0) { | ||||||||
191 | SetRegisterDataFrom_LC_THREAD(data); | ||||||||
192 | } | ||||||||
193 | |||||||||
194 | void InvalidateAllRegisters() override { | ||||||||
195 | // Do nothing... registers are always valid... | ||||||||
196 | } | ||||||||
197 | |||||||||
198 | void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) { | ||||||||
199 | lldb::offset_t offset = 0; | ||||||||
200 | SetError(GPRRegSet, Read, -1); | ||||||||
201 | SetError(FPURegSet, Read, -1); | ||||||||
202 | SetError(EXCRegSet, Read, -1); | ||||||||
203 | bool done = false; | ||||||||
204 | |||||||||
205 | while (!done) { | ||||||||
206 | int flavor = data.GetU32(&offset); | ||||||||
207 | if (flavor == 0) | ||||||||
208 | done = true; | ||||||||
209 | else { | ||||||||
210 | uint32_t i; | ||||||||
211 | uint32_t count = data.GetU32(&offset); | ||||||||
212 | switch (flavor) { | ||||||||
213 | case GPRRegSet: | ||||||||
214 | for (i = 0; i < count; ++i) | ||||||||
215 | (&gpr.rax)[i] = data.GetU64(&offset); | ||||||||
216 | SetError(GPRRegSet, Read, 0); | ||||||||
217 | done = true; | ||||||||
218 | |||||||||
219 | break; | ||||||||
220 | case FPURegSet: | ||||||||
221 | // TODO: fill in FPU regs.... | ||||||||
222 | // SetError (FPURegSet, Read, -1); | ||||||||
223 | done = true; | ||||||||
224 | |||||||||
225 | break; | ||||||||
226 | case EXCRegSet: | ||||||||
227 | exc.trapno = data.GetU32(&offset); | ||||||||
228 | exc.err = data.GetU32(&offset); | ||||||||
229 | exc.faultvaddr = data.GetU64(&offset); | ||||||||
230 | SetError(EXCRegSet, Read, 0); | ||||||||
231 | done = true; | ||||||||
232 | break; | ||||||||
233 | case 7: | ||||||||
234 | case 8: | ||||||||
235 | case 9: | ||||||||
236 | // fancy flavors that encapsulate of the above flavors... | ||||||||
237 | break; | ||||||||
238 | |||||||||
239 | default: | ||||||||
240 | done = true; | ||||||||
241 | break; | ||||||||
242 | } | ||||||||
243 | } | ||||||||
244 | } | ||||||||
245 | } | ||||||||
246 | |||||||||
247 | static bool Create_LC_THREAD(Thread *thread, Stream &data) { | ||||||||
248 | RegisterContextSP reg_ctx_sp(thread->GetRegisterContext()); | ||||||||
249 | if (reg_ctx_sp) { | ||||||||
250 | RegisterContext *reg_ctx = reg_ctx_sp.get(); | ||||||||
251 | |||||||||
252 | data.PutHex32(GPRRegSet); // Flavor | ||||||||
253 | data.PutHex32(GPRWordCount); | ||||||||
254 | PrintRegisterValue(reg_ctx, "rax", nullptr, 8, data); | ||||||||
255 | PrintRegisterValue(reg_ctx, "rbx", nullptr, 8, data); | ||||||||
256 | PrintRegisterValue(reg_ctx, "rcx", nullptr, 8, data); | ||||||||
257 | PrintRegisterValue(reg_ctx, "rdx", nullptr, 8, data); | ||||||||
258 | PrintRegisterValue(reg_ctx, "rdi", nullptr, 8, data); | ||||||||
259 | PrintRegisterValue(reg_ctx, "rsi", nullptr, 8, data); | ||||||||
260 | PrintRegisterValue(reg_ctx, "rbp", nullptr, 8, data); | ||||||||
261 | PrintRegisterValue(reg_ctx, "rsp", nullptr, 8, data); | ||||||||
262 | PrintRegisterValue(reg_ctx, "r8", nullptr, 8, data); | ||||||||
263 | PrintRegisterValue(reg_ctx, "r9", nullptr, 8, data); | ||||||||
264 | PrintRegisterValue(reg_ctx, "r10", nullptr, 8, data); | ||||||||
265 | PrintRegisterValue(reg_ctx, "r11", nullptr, 8, data); | ||||||||
266 | PrintRegisterValue(reg_ctx, "r12", nullptr, 8, data); | ||||||||
267 | PrintRegisterValue(reg_ctx, "r13", nullptr, 8, data); | ||||||||
268 | PrintRegisterValue(reg_ctx, "r14", nullptr, 8, data); | ||||||||
269 | PrintRegisterValue(reg_ctx, "r15", nullptr, 8, data); | ||||||||
270 | PrintRegisterValue(reg_ctx, "rip", nullptr, 8, data); | ||||||||
271 | PrintRegisterValue(reg_ctx, "rflags", nullptr, 8, data); | ||||||||
272 | PrintRegisterValue(reg_ctx, "cs", nullptr, 8, data); | ||||||||
273 | PrintRegisterValue(reg_ctx, "fs", nullptr, 8, data); | ||||||||
274 | PrintRegisterValue(reg_ctx, "gs", nullptr, 8, data); | ||||||||
275 | |||||||||
276 | // // Write out the FPU registers | ||||||||
277 | // const size_t fpu_byte_size = sizeof(FPU); | ||||||||
278 | // size_t bytes_written = 0; | ||||||||
279 | // data.PutHex32 (FPURegSet); | ||||||||
280 | // data.PutHex32 (fpu_byte_size/sizeof(uint64_t)); | ||||||||
281 | // bytes_written += data.PutHex32(0); // uint32_t pad[0] | ||||||||
282 | // bytes_written += data.PutHex32(0); // uint32_t pad[1] | ||||||||
283 | // bytes_written += WriteRegister (reg_ctx, "fcw", "fctrl", 2, | ||||||||
284 | // data); // uint16_t fcw; // "fctrl" | ||||||||
285 | // bytes_written += WriteRegister (reg_ctx, "fsw" , "fstat", 2, | ||||||||
286 | // data); // uint16_t fsw; // "fstat" | ||||||||
287 | // bytes_written += WriteRegister (reg_ctx, "ftw" , "ftag", 1, | ||||||||
288 | // data); // uint8_t ftw; // "ftag" | ||||||||
289 | // bytes_written += data.PutHex8 (0); // uint8_t pad1; | ||||||||
290 | // bytes_written += WriteRegister (reg_ctx, "fop" , NULL, 2, | ||||||||
291 | // data); // uint16_t fop; // "fop" | ||||||||
292 | // bytes_written += WriteRegister (reg_ctx, "fioff", "ip", 4, | ||||||||
293 | // data); // uint32_t ip; // "fioff" | ||||||||
294 | // bytes_written += WriteRegister (reg_ctx, "fiseg", NULL, 2, | ||||||||
295 | // data); // uint16_t cs; // "fiseg" | ||||||||
296 | // bytes_written += data.PutHex16 (0); // uint16_t pad2; | ||||||||
297 | // bytes_written += WriteRegister (reg_ctx, "dp", "fooff" , 4, | ||||||||
298 | // data); // uint32_t dp; // "fooff" | ||||||||
299 | // bytes_written += WriteRegister (reg_ctx, "foseg", NULL, 2, | ||||||||
300 | // data); // uint16_t ds; // "foseg" | ||||||||
301 | // bytes_written += data.PutHex16 (0); // uint16_t pad3; | ||||||||
302 | // bytes_written += WriteRegister (reg_ctx, "mxcsr", NULL, 4, | ||||||||
303 | // data); // uint32_t mxcsr; | ||||||||
304 | // bytes_written += WriteRegister (reg_ctx, "mxcsrmask", NULL, | ||||||||
305 | // 4, data);// uint32_t mxcsrmask; | ||||||||
306 | // bytes_written += WriteRegister (reg_ctx, "stmm0", NULL, | ||||||||
307 | // sizeof(MMSReg), data); | ||||||||
308 | // bytes_written += WriteRegister (reg_ctx, "stmm1", NULL, | ||||||||
309 | // sizeof(MMSReg), data); | ||||||||
310 | // bytes_written += WriteRegister (reg_ctx, "stmm2", NULL, | ||||||||
311 | // sizeof(MMSReg), data); | ||||||||
312 | // bytes_written += WriteRegister (reg_ctx, "stmm3", NULL, | ||||||||
313 | // sizeof(MMSReg), data); | ||||||||
314 | // bytes_written += WriteRegister (reg_ctx, "stmm4", NULL, | ||||||||
315 | // sizeof(MMSReg), data); | ||||||||
316 | // bytes_written += WriteRegister (reg_ctx, "stmm5", NULL, | ||||||||
317 | // sizeof(MMSReg), data); | ||||||||
318 | // bytes_written += WriteRegister (reg_ctx, "stmm6", NULL, | ||||||||
319 | // sizeof(MMSReg), data); | ||||||||
320 | // bytes_written += WriteRegister (reg_ctx, "stmm7", NULL, | ||||||||
321 | // sizeof(MMSReg), data); | ||||||||
322 | // bytes_written += WriteRegister (reg_ctx, "xmm0" , NULL, | ||||||||
323 | // sizeof(XMMReg), data); | ||||||||
324 | // bytes_written += WriteRegister (reg_ctx, "xmm1" , NULL, | ||||||||
325 | // sizeof(XMMReg), data); | ||||||||
326 | // bytes_written += WriteRegister (reg_ctx, "xmm2" , NULL, | ||||||||
327 | // sizeof(XMMReg), data); | ||||||||
328 | // bytes_written += WriteRegister (reg_ctx, "xmm3" , NULL, | ||||||||
329 | // sizeof(XMMReg), data); | ||||||||
330 | // bytes_written += WriteRegister (reg_ctx, "xmm4" , NULL, | ||||||||
331 | // sizeof(XMMReg), data); | ||||||||
332 | // bytes_written += WriteRegister (reg_ctx, "xmm5" , NULL, | ||||||||
333 | // sizeof(XMMReg), data); | ||||||||
334 | // bytes_written += WriteRegister (reg_ctx, "xmm6" , NULL, | ||||||||
335 | // sizeof(XMMReg), data); | ||||||||
336 | // bytes_written += WriteRegister (reg_ctx, "xmm7" , NULL, | ||||||||
337 | // sizeof(XMMReg), data); | ||||||||
338 | // bytes_written += WriteRegister (reg_ctx, "xmm8" , NULL, | ||||||||
339 | // sizeof(XMMReg), data); | ||||||||
340 | // bytes_written += WriteRegister (reg_ctx, "xmm9" , NULL, | ||||||||
341 | // sizeof(XMMReg), data); | ||||||||
342 | // bytes_written += WriteRegister (reg_ctx, "xmm10", NULL, | ||||||||
343 | // sizeof(XMMReg), data); | ||||||||
344 | // bytes_written += WriteRegister (reg_ctx, "xmm11", NULL, | ||||||||
345 | // sizeof(XMMReg), data); | ||||||||
346 | // bytes_written += WriteRegister (reg_ctx, "xmm12", NULL, | ||||||||
347 | // sizeof(XMMReg), data); | ||||||||
348 | // bytes_written += WriteRegister (reg_ctx, "xmm13", NULL, | ||||||||
349 | // sizeof(XMMReg), data); | ||||||||
350 | // bytes_written += WriteRegister (reg_ctx, "xmm14", NULL, | ||||||||
351 | // sizeof(XMMReg), data); | ||||||||
352 | // bytes_written += WriteRegister (reg_ctx, "xmm15", NULL, | ||||||||
353 | // sizeof(XMMReg), data); | ||||||||
354 | // | ||||||||
355 | // // Fill rest with zeros | ||||||||
356 | // for (size_t i=0, n = fpu_byte_size - bytes_written; i<n; ++ | ||||||||
357 | // i) | ||||||||
358 | // data.PutChar(0); | ||||||||
359 | |||||||||
360 | // Write out the EXC registers | ||||||||
361 | data.PutHex32(EXCRegSet); | ||||||||
362 | data.PutHex32(EXCWordCount); | ||||||||
363 | PrintRegisterValue(reg_ctx, "trapno", nullptr, 4, data); | ||||||||
364 | PrintRegisterValue(reg_ctx, "err", nullptr, 4, data); | ||||||||
365 | PrintRegisterValue(reg_ctx, "faultvaddr", nullptr, 8, data); | ||||||||
366 | return true; | ||||||||
367 | } | ||||||||
368 | return false; | ||||||||
369 | } | ||||||||
370 | |||||||||
371 | protected: | ||||||||
372 | int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return 0; } | ||||||||
373 | |||||||||
374 | int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return 0; } | ||||||||
375 | |||||||||
376 | int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return 0; } | ||||||||
377 | |||||||||
378 | int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override { | ||||||||
379 | return 0; | ||||||||
380 | } | ||||||||
381 | |||||||||
382 | int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override { | ||||||||
383 | return 0; | ||||||||
384 | } | ||||||||
385 | |||||||||
386 | int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override { | ||||||||
387 | return 0; | ||||||||
388 | } | ||||||||
389 | }; | ||||||||
390 | |||||||||
391 | class RegisterContextDarwin_i386_Mach : public RegisterContextDarwin_i386 { | ||||||||
392 | public: | ||||||||
393 | RegisterContextDarwin_i386_Mach(lldb_private::Thread &thread, | ||||||||
394 | const DataExtractor &data) | ||||||||
395 | : RegisterContextDarwin_i386(thread, 0) { | ||||||||
396 | SetRegisterDataFrom_LC_THREAD(data); | ||||||||
397 | } | ||||||||
398 | |||||||||
399 | void InvalidateAllRegisters() override { | ||||||||
400 | // Do nothing... registers are always valid... | ||||||||
401 | } | ||||||||
402 | |||||||||
403 | void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) { | ||||||||
404 | lldb::offset_t offset = 0; | ||||||||
405 | SetError(GPRRegSet, Read, -1); | ||||||||
406 | SetError(FPURegSet, Read, -1); | ||||||||
407 | SetError(EXCRegSet, Read, -1); | ||||||||
408 | bool done = false; | ||||||||
409 | |||||||||
410 | while (!done) { | ||||||||
411 | int flavor = data.GetU32(&offset); | ||||||||
412 | if (flavor == 0) | ||||||||
413 | done = true; | ||||||||
414 | else { | ||||||||
415 | uint32_t i; | ||||||||
416 | uint32_t count = data.GetU32(&offset); | ||||||||
417 | switch (flavor) { | ||||||||
418 | case GPRRegSet: | ||||||||
419 | for (i = 0; i < count; ++i) | ||||||||
420 | (&gpr.eax)[i] = data.GetU32(&offset); | ||||||||
421 | SetError(GPRRegSet, Read, 0); | ||||||||
422 | done = true; | ||||||||
423 | |||||||||
424 | break; | ||||||||
425 | case FPURegSet: | ||||||||
426 | // TODO: fill in FPU regs.... | ||||||||
427 | // SetError (FPURegSet, Read, -1); | ||||||||
428 | done = true; | ||||||||
429 | |||||||||
430 | break; | ||||||||
431 | case EXCRegSet: | ||||||||
432 | exc.trapno = data.GetU32(&offset); | ||||||||
433 | exc.err = data.GetU32(&offset); | ||||||||
434 | exc.faultvaddr = data.GetU32(&offset); | ||||||||
435 | SetError(EXCRegSet, Read, 0); | ||||||||
436 | done = true; | ||||||||
437 | break; | ||||||||
438 | case 7: | ||||||||
439 | case 8: | ||||||||
440 | case 9: | ||||||||
441 | // fancy flavors that encapsulate of the above flavors... | ||||||||
442 | break; | ||||||||
443 | |||||||||
444 | default: | ||||||||
445 | done = true; | ||||||||
446 | break; | ||||||||
447 | } | ||||||||
448 | } | ||||||||
449 | } | ||||||||
450 | } | ||||||||
451 | |||||||||
452 | static bool Create_LC_THREAD(Thread *thread, Stream &data) { | ||||||||
453 | RegisterContextSP reg_ctx_sp(thread->GetRegisterContext()); | ||||||||
454 | if (reg_ctx_sp) { | ||||||||
455 | RegisterContext *reg_ctx = reg_ctx_sp.get(); | ||||||||
456 | |||||||||
457 | data.PutHex32(GPRRegSet); // Flavor | ||||||||
458 | data.PutHex32(GPRWordCount); | ||||||||
459 | PrintRegisterValue(reg_ctx, "eax", nullptr, 4, data); | ||||||||
460 | PrintRegisterValue(reg_ctx, "ebx", nullptr, 4, data); | ||||||||
461 | PrintRegisterValue(reg_ctx, "ecx", nullptr, 4, data); | ||||||||
462 | PrintRegisterValue(reg_ctx, "edx", nullptr, 4, data); | ||||||||
463 | PrintRegisterValue(reg_ctx, "edi", nullptr, 4, data); | ||||||||
464 | PrintRegisterValue(reg_ctx, "esi", nullptr, 4, data); | ||||||||
465 | PrintRegisterValue(reg_ctx, "ebp", nullptr, 4, data); | ||||||||
466 | PrintRegisterValue(reg_ctx, "esp", nullptr, 4, data); | ||||||||
467 | PrintRegisterValue(reg_ctx, "ss", nullptr, 4, data); | ||||||||
468 | PrintRegisterValue(reg_ctx, "eflags", nullptr, 4, data); | ||||||||
469 | PrintRegisterValue(reg_ctx, "eip", nullptr, 4, data); | ||||||||
470 | PrintRegisterValue(reg_ctx, "cs", nullptr, 4, data); | ||||||||
471 | PrintRegisterValue(reg_ctx, "ds", nullptr, 4, data); | ||||||||
472 | PrintRegisterValue(reg_ctx, "es", nullptr, 4, data); | ||||||||
473 | PrintRegisterValue(reg_ctx, "fs", nullptr, 4, data); | ||||||||
474 | PrintRegisterValue(reg_ctx, "gs", nullptr, 4, data); | ||||||||
475 | |||||||||
476 | // Write out the EXC registers | ||||||||
477 | data.PutHex32(EXCRegSet); | ||||||||
478 | data.PutHex32(EXCWordCount); | ||||||||
479 | PrintRegisterValue(reg_ctx, "trapno", nullptr, 4, data); | ||||||||
480 | PrintRegisterValue(reg_ctx, "err", nullptr, 4, data); | ||||||||
481 | PrintRegisterValue(reg_ctx, "faultvaddr", nullptr, 4, data); | ||||||||
482 | return true; | ||||||||
483 | } | ||||||||
484 | return false; | ||||||||
485 | } | ||||||||
486 | |||||||||
487 | protected: | ||||||||
488 | int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return 0; } | ||||||||
489 | |||||||||
490 | int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return 0; } | ||||||||
491 | |||||||||
492 | int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return 0; } | ||||||||
493 | |||||||||
494 | int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override { | ||||||||
495 | return 0; | ||||||||
496 | } | ||||||||
497 | |||||||||
498 | int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override { | ||||||||
499 | return 0; | ||||||||
500 | } | ||||||||
501 | |||||||||
502 | int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override { | ||||||||
503 | return 0; | ||||||||
504 | } | ||||||||
505 | }; | ||||||||
506 | |||||||||
507 | class RegisterContextDarwin_arm_Mach : public RegisterContextDarwin_arm { | ||||||||
508 | public: | ||||||||
509 | RegisterContextDarwin_arm_Mach(lldb_private::Thread &thread, | ||||||||
510 | const DataExtractor &data) | ||||||||
511 | : RegisterContextDarwin_arm(thread, 0) { | ||||||||
512 | SetRegisterDataFrom_LC_THREAD(data); | ||||||||
513 | } | ||||||||
514 | |||||||||
515 | void InvalidateAllRegisters() override { | ||||||||
516 | // Do nothing... registers are always valid... | ||||||||
517 | } | ||||||||
518 | |||||||||
519 | void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) { | ||||||||
520 | lldb::offset_t offset = 0; | ||||||||
521 | SetError(GPRRegSet, Read, -1); | ||||||||
522 | SetError(FPURegSet, Read, -1); | ||||||||
523 | SetError(EXCRegSet, Read, -1); | ||||||||
524 | bool done = false; | ||||||||
525 | |||||||||
526 | while (!done) { | ||||||||
527 | int flavor = data.GetU32(&offset); | ||||||||
528 | uint32_t count = data.GetU32(&offset); | ||||||||
529 | lldb::offset_t next_thread_state = offset + (count * 4); | ||||||||
530 | switch (flavor) { | ||||||||
531 | case GPRAltRegSet: | ||||||||
532 | case GPRRegSet: | ||||||||
533 | // On ARM, the CPSR register is also included in the count but it is | ||||||||
534 | // not included in gpr.r so loop until (count-1). | ||||||||
535 | for (uint32_t i = 0; i < (count - 1); ++i) { | ||||||||
536 | gpr.r[i] = data.GetU32(&offset); | ||||||||
537 | } | ||||||||
538 | // Save cpsr explicitly. | ||||||||
539 | gpr.cpsr = data.GetU32(&offset); | ||||||||
540 | |||||||||
541 | SetError(GPRRegSet, Read, 0); | ||||||||
542 | offset = next_thread_state; | ||||||||
543 | break; | ||||||||
544 | |||||||||
545 | case FPURegSet: { | ||||||||
546 | uint8_t *fpu_reg_buf = (uint8_t *)&fpu.floats.s[0]; | ||||||||
547 | const int fpu_reg_buf_size = sizeof(fpu.floats); | ||||||||
548 | if (data.ExtractBytes(offset, fpu_reg_buf_size, eByteOrderLittle, | ||||||||
549 | fpu_reg_buf) == fpu_reg_buf_size) { | ||||||||
550 | offset += fpu_reg_buf_size; | ||||||||
551 | fpu.fpscr = data.GetU32(&offset); | ||||||||
552 | SetError(FPURegSet, Read, 0); | ||||||||
553 | } else { | ||||||||
554 | done = true; | ||||||||
555 | } | ||||||||
556 | } | ||||||||
557 | offset = next_thread_state; | ||||||||
558 | break; | ||||||||
559 | |||||||||
560 | case EXCRegSet: | ||||||||
561 | if (count == 3) { | ||||||||
562 | exc.exception = data.GetU32(&offset); | ||||||||
563 | exc.fsr = data.GetU32(&offset); | ||||||||
564 | exc.far = data.GetU32(&offset); | ||||||||
565 | SetError(EXCRegSet, Read, 0); | ||||||||
566 | } | ||||||||
567 | done = true; | ||||||||
568 | offset = next_thread_state; | ||||||||
569 | break; | ||||||||
570 | |||||||||
571 | // Unknown register set flavor, stop trying to parse. | ||||||||
572 | default: | ||||||||
573 | done = true; | ||||||||
574 | } | ||||||||
575 | } | ||||||||
576 | } | ||||||||
577 | |||||||||
578 | static bool Create_LC_THREAD(Thread *thread, Stream &data) { | ||||||||
579 | RegisterContextSP reg_ctx_sp(thread->GetRegisterContext()); | ||||||||
580 | if (reg_ctx_sp) { | ||||||||
581 | RegisterContext *reg_ctx = reg_ctx_sp.get(); | ||||||||
582 | |||||||||
583 | data.PutHex32(GPRRegSet); // Flavor | ||||||||
584 | data.PutHex32(GPRWordCount); | ||||||||
585 | PrintRegisterValue(reg_ctx, "r0", nullptr, 4, data); | ||||||||
586 | PrintRegisterValue(reg_ctx, "r1", nullptr, 4, data); | ||||||||
587 | PrintRegisterValue(reg_ctx, "r2", nullptr, 4, data); | ||||||||
588 | PrintRegisterValue(reg_ctx, "r3", nullptr, 4, data); | ||||||||
589 | PrintRegisterValue(reg_ctx, "r4", nullptr, 4, data); | ||||||||
590 | PrintRegisterValue(reg_ctx, "r5", nullptr, 4, data); | ||||||||
591 | PrintRegisterValue(reg_ctx, "r6", nullptr, 4, data); | ||||||||
592 | PrintRegisterValue(reg_ctx, "r7", nullptr, 4, data); | ||||||||
593 | PrintRegisterValue(reg_ctx, "r8", nullptr, 4, data); | ||||||||
594 | PrintRegisterValue(reg_ctx, "r9", nullptr, 4, data); | ||||||||
595 | PrintRegisterValue(reg_ctx, "r10", nullptr, 4, data); | ||||||||
596 | PrintRegisterValue(reg_ctx, "r11", nullptr, 4, data); | ||||||||
597 | PrintRegisterValue(reg_ctx, "r12", nullptr, 4, data); | ||||||||
598 | PrintRegisterValue(reg_ctx, "sp", nullptr, 4, data); | ||||||||
599 | PrintRegisterValue(reg_ctx, "lr", nullptr, 4, data); | ||||||||
600 | PrintRegisterValue(reg_ctx, "pc", nullptr, 4, data); | ||||||||
601 | PrintRegisterValue(reg_ctx, "cpsr", nullptr, 4, data); | ||||||||
602 | |||||||||
603 | // Write out the EXC registers | ||||||||
604 | // data.PutHex32 (EXCRegSet); | ||||||||
605 | // data.PutHex32 (EXCWordCount); | ||||||||
606 | // WriteRegister (reg_ctx, "exception", NULL, 4, data); | ||||||||
607 | // WriteRegister (reg_ctx, "fsr", NULL, 4, data); | ||||||||
608 | // WriteRegister (reg_ctx, "far", NULL, 4, data); | ||||||||
609 | return true; | ||||||||
610 | } | ||||||||
611 | return false; | ||||||||
612 | } | ||||||||
613 | |||||||||
614 | protected: | ||||||||
615 | int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return -1; } | ||||||||
616 | |||||||||
617 | int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return -1; } | ||||||||
618 | |||||||||
619 | int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return -1; } | ||||||||
620 | |||||||||
621 | int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override { return -1; } | ||||||||
622 | |||||||||
623 | int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override { | ||||||||
624 | return 0; | ||||||||
625 | } | ||||||||
626 | |||||||||
627 | int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override { | ||||||||
628 | return 0; | ||||||||
629 | } | ||||||||
630 | |||||||||
631 | int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override { | ||||||||
632 | return 0; | ||||||||
633 | } | ||||||||
634 | |||||||||
635 | int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override { | ||||||||
636 | return -1; | ||||||||
637 | } | ||||||||
638 | }; | ||||||||
639 | |||||||||
640 | class RegisterContextDarwin_arm64_Mach : public RegisterContextDarwin_arm64 { | ||||||||
641 | public: | ||||||||
642 | RegisterContextDarwin_arm64_Mach(lldb_private::Thread &thread, | ||||||||
643 | const DataExtractor &data) | ||||||||
644 | : RegisterContextDarwin_arm64(thread, 0) { | ||||||||
645 | SetRegisterDataFrom_LC_THREAD(data); | ||||||||
646 | } | ||||||||
647 | |||||||||
648 | void InvalidateAllRegisters() override { | ||||||||
649 | // Do nothing... registers are always valid... | ||||||||
650 | } | ||||||||
651 | |||||||||
652 | void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) { | ||||||||
653 | lldb::offset_t offset = 0; | ||||||||
654 | SetError(GPRRegSet, Read, -1); | ||||||||
655 | SetError(FPURegSet, Read, -1); | ||||||||
656 | SetError(EXCRegSet, Read, -1); | ||||||||
657 | bool done = false; | ||||||||
658 | while (!done) { | ||||||||
659 | int flavor = data.GetU32(&offset); | ||||||||
660 | uint32_t count = data.GetU32(&offset); | ||||||||
661 | lldb::offset_t next_thread_state = offset + (count * 4); | ||||||||
662 | switch (flavor) { | ||||||||
663 | case GPRRegSet: | ||||||||
664 | // x0-x29 + fp + lr + sp + pc (== 33 64-bit registers) plus cpsr (1 | ||||||||
665 | // 32-bit register) | ||||||||
666 | if (count >= (33 * 2) + 1) { | ||||||||
667 | for (uint32_t i = 0; i < 29; ++i) | ||||||||
668 | gpr.x[i] = data.GetU64(&offset); | ||||||||
669 | gpr.fp = data.GetU64(&offset); | ||||||||
670 | gpr.lr = data.GetU64(&offset); | ||||||||
671 | gpr.sp = data.GetU64(&offset); | ||||||||
672 | gpr.pc = data.GetU64(&offset); | ||||||||
673 | gpr.cpsr = data.GetU32(&offset); | ||||||||
674 | SetError(GPRRegSet, Read, 0); | ||||||||
675 | } | ||||||||
676 | offset = next_thread_state; | ||||||||
677 | break; | ||||||||
678 | case FPURegSet: { | ||||||||
679 | uint8_t *fpu_reg_buf = (uint8_t *)&fpu.v[0]; | ||||||||
680 | const int fpu_reg_buf_size = sizeof(fpu); | ||||||||
681 | if (fpu_reg_buf_size == count * sizeof(uint32_t) && | ||||||||
682 | data.ExtractBytes(offset, fpu_reg_buf_size, eByteOrderLittle, | ||||||||
683 | fpu_reg_buf) == fpu_reg_buf_size) { | ||||||||
684 | SetError(FPURegSet, Read, 0); | ||||||||
685 | } else { | ||||||||
686 | done = true; | ||||||||
687 | } | ||||||||
688 | } | ||||||||
689 | offset = next_thread_state; | ||||||||
690 | break; | ||||||||
691 | case EXCRegSet: | ||||||||
692 | if (count == 4) { | ||||||||
693 | exc.far = data.GetU64(&offset); | ||||||||
694 | exc.esr = data.GetU32(&offset); | ||||||||
695 | exc.exception = data.GetU32(&offset); | ||||||||
696 | SetError(EXCRegSet, Read, 0); | ||||||||
697 | } | ||||||||
698 | offset = next_thread_state; | ||||||||
699 | break; | ||||||||
700 | default: | ||||||||
701 | done = true; | ||||||||
702 | break; | ||||||||
703 | } | ||||||||
704 | } | ||||||||
705 | } | ||||||||
706 | |||||||||
707 | static bool Create_LC_THREAD(Thread *thread, Stream &data) { | ||||||||
708 | RegisterContextSP reg_ctx_sp(thread->GetRegisterContext()); | ||||||||
709 | if (reg_ctx_sp) { | ||||||||
710 | RegisterContext *reg_ctx = reg_ctx_sp.get(); | ||||||||
711 | |||||||||
712 | data.PutHex32(GPRRegSet); // Flavor | ||||||||
713 | data.PutHex32(GPRWordCount); | ||||||||
714 | PrintRegisterValue(reg_ctx, "x0", nullptr, 8, data); | ||||||||
715 | PrintRegisterValue(reg_ctx, "x1", nullptr, 8, data); | ||||||||
716 | PrintRegisterValue(reg_ctx, "x2", nullptr, 8, data); | ||||||||
717 | PrintRegisterValue(reg_ctx, "x3", nullptr, 8, data); | ||||||||
718 | PrintRegisterValue(reg_ctx, "x4", nullptr, 8, data); | ||||||||
719 | PrintRegisterValue(reg_ctx, "x5", nullptr, 8, data); | ||||||||
720 | PrintRegisterValue(reg_ctx, "x6", nullptr, 8, data); | ||||||||
721 | PrintRegisterValue(reg_ctx, "x7", nullptr, 8, data); | ||||||||
722 | PrintRegisterValue(reg_ctx, "x8", nullptr, 8, data); | ||||||||
723 | PrintRegisterValue(reg_ctx, "x9", nullptr, 8, data); | ||||||||
724 | PrintRegisterValue(reg_ctx, "x10", nullptr, 8, data); | ||||||||
725 | PrintRegisterValue(reg_ctx, "x11", nullptr, 8, data); | ||||||||
726 | PrintRegisterValue(reg_ctx, "x12", nullptr, 8, data); | ||||||||
727 | PrintRegisterValue(reg_ctx, "x13", nullptr, 8, data); | ||||||||
728 | PrintRegisterValue(reg_ctx, "x14", nullptr, 8, data); | ||||||||
729 | PrintRegisterValue(reg_ctx, "x15", nullptr, 8, data); | ||||||||
730 | PrintRegisterValue(reg_ctx, "x16", nullptr, 8, data); | ||||||||
731 | PrintRegisterValue(reg_ctx, "x17", nullptr, 8, data); | ||||||||
732 | PrintRegisterValue(reg_ctx, "x18", nullptr, 8, data); | ||||||||
733 | PrintRegisterValue(reg_ctx, "x19", nullptr, 8, data); | ||||||||
734 | PrintRegisterValue(reg_ctx, "x20", nullptr, 8, data); | ||||||||
735 | PrintRegisterValue(reg_ctx, "x21", nullptr, 8, data); | ||||||||
736 | PrintRegisterValue(reg_ctx, "x22", nullptr, 8, data); | ||||||||
737 | PrintRegisterValue(reg_ctx, "x23", nullptr, 8, data); | ||||||||
738 | PrintRegisterValue(reg_ctx, "x24", nullptr, 8, data); | ||||||||
739 | PrintRegisterValue(reg_ctx, "x25", nullptr, 8, data); | ||||||||
740 | PrintRegisterValue(reg_ctx, "x26", nullptr, 8, data); | ||||||||
741 | PrintRegisterValue(reg_ctx, "x27", nullptr, 8, data); | ||||||||
742 | PrintRegisterValue(reg_ctx, "x28", nullptr, 8, data); | ||||||||
743 | PrintRegisterValue(reg_ctx, "fp", nullptr, 8, data); | ||||||||
744 | PrintRegisterValue(reg_ctx, "lr", nullptr, 8, data); | ||||||||
745 | PrintRegisterValue(reg_ctx, "sp", nullptr, 8, data); | ||||||||
746 | PrintRegisterValue(reg_ctx, "pc", nullptr, 8, data); | ||||||||
747 | PrintRegisterValue(reg_ctx, "cpsr", nullptr, 4, data); | ||||||||
748 | |||||||||
749 | // Write out the EXC registers | ||||||||
750 | // data.PutHex32 (EXCRegSet); | ||||||||
751 | // data.PutHex32 (EXCWordCount); | ||||||||
752 | // WriteRegister (reg_ctx, "far", NULL, 8, data); | ||||||||
753 | // WriteRegister (reg_ctx, "esr", NULL, 4, data); | ||||||||
754 | // WriteRegister (reg_ctx, "exception", NULL, 4, data); | ||||||||
755 | return true; | ||||||||
756 | } | ||||||||
757 | return false; | ||||||||
758 | } | ||||||||
759 | |||||||||
760 | protected: | ||||||||
761 | int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return -1; } | ||||||||
762 | |||||||||
763 | int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return -1; } | ||||||||
764 | |||||||||
765 | int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return -1; } | ||||||||
766 | |||||||||
767 | int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override { return -1; } | ||||||||
768 | |||||||||
769 | int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override { | ||||||||
770 | return 0; | ||||||||
771 | } | ||||||||
772 | |||||||||
773 | int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override { | ||||||||
774 | return 0; | ||||||||
775 | } | ||||||||
776 | |||||||||
777 | int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override { | ||||||||
778 | return 0; | ||||||||
779 | } | ||||||||
780 | |||||||||
781 | int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override { | ||||||||
782 | return -1; | ||||||||
783 | } | ||||||||
784 | }; | ||||||||
785 | |||||||||
786 | static uint32_t MachHeaderSizeFromMagic(uint32_t magic) { | ||||||||
787 | switch (magic) { | ||||||||
788 | case MH_MAGIC: | ||||||||
789 | case MH_CIGAM: | ||||||||
790 | return sizeof(struct llvm::MachO::mach_header); | ||||||||
791 | |||||||||
792 | case MH_MAGIC_64: | ||||||||
793 | case MH_CIGAM_64: | ||||||||
794 | return sizeof(struct llvm::MachO::mach_header_64); | ||||||||
795 | break; | ||||||||
796 | |||||||||
797 | default: | ||||||||
798 | break; | ||||||||
799 | } | ||||||||
800 | return 0; | ||||||||
801 | } | ||||||||
802 | |||||||||
803 | #define MACHO_NLIST_ARM_SYMBOL_IS_THUMB0x0008 0x0008 | ||||||||
804 | |||||||||
805 | char ObjectFileMachO::ID; | ||||||||
806 | |||||||||
807 | void ObjectFileMachO::Initialize() { | ||||||||
808 | PluginManager::RegisterPlugin( | ||||||||
809 | GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, | ||||||||
810 | CreateMemoryInstance, GetModuleSpecifications, SaveCore); | ||||||||
811 | } | ||||||||
812 | |||||||||
813 | void ObjectFileMachO::Terminate() { | ||||||||
814 | PluginManager::UnregisterPlugin(CreateInstance); | ||||||||
815 | } | ||||||||
816 | |||||||||
817 | lldb_private::ConstString ObjectFileMachO::GetPluginNameStatic() { | ||||||||
818 | static ConstString g_name("mach-o"); | ||||||||
819 | return g_name; | ||||||||
820 | } | ||||||||
821 | |||||||||
822 | const char *ObjectFileMachO::GetPluginDescriptionStatic() { | ||||||||
823 | return "Mach-o object file reader (32 and 64 bit)"; | ||||||||
824 | } | ||||||||
825 | |||||||||
826 | ObjectFile *ObjectFileMachO::CreateInstance(const lldb::ModuleSP &module_sp, | ||||||||
827 | DataBufferSP &data_sp, | ||||||||
828 | lldb::offset_t data_offset, | ||||||||
829 | const FileSpec *file, | ||||||||
830 | lldb::offset_t file_offset, | ||||||||
831 | lldb::offset_t length) { | ||||||||
832 | if (!data_sp) { | ||||||||
833 | data_sp = MapFileData(*file, length, file_offset); | ||||||||
834 | if (!data_sp) | ||||||||
835 | return nullptr; | ||||||||
836 | data_offset = 0; | ||||||||
837 | } | ||||||||
838 | |||||||||
839 | if (!ObjectFileMachO::MagicBytesMatch(data_sp, data_offset, length)) | ||||||||
840 | return nullptr; | ||||||||
841 | |||||||||
842 | // Update the data to contain the entire file if it doesn't already | ||||||||
843 | if (data_sp->GetByteSize() < length) { | ||||||||
844 | data_sp = MapFileData(*file, length, file_offset); | ||||||||
845 | if (!data_sp) | ||||||||
846 | return nullptr; | ||||||||
847 | data_offset = 0; | ||||||||
848 | } | ||||||||
849 | auto objfile_up = std::make_unique<ObjectFileMachO>( | ||||||||
850 | module_sp, data_sp, data_offset, file, file_offset, length); | ||||||||
851 | if (!objfile_up || !objfile_up->ParseHeader()) | ||||||||
852 | return nullptr; | ||||||||
853 | |||||||||
854 | return objfile_up.release(); | ||||||||
855 | } | ||||||||
856 | |||||||||
857 | ObjectFile *ObjectFileMachO::CreateMemoryInstance( | ||||||||
858 | const lldb::ModuleSP &module_sp, DataBufferSP &data_sp, | ||||||||
859 | const ProcessSP &process_sp, lldb::addr_t header_addr) { | ||||||||
860 | if (ObjectFileMachO::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { | ||||||||
861 | std::unique_ptr<ObjectFile> objfile_up( | ||||||||
862 | new ObjectFileMachO(module_sp, data_sp, process_sp, header_addr)); | ||||||||
863 | if (objfile_up.get() && objfile_up->ParseHeader()) | ||||||||
864 | return objfile_up.release(); | ||||||||
865 | } | ||||||||
866 | return nullptr; | ||||||||
867 | } | ||||||||
868 | |||||||||
869 | size_t ObjectFileMachO::GetModuleSpecifications( | ||||||||
870 | const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp, | ||||||||
871 | lldb::offset_t data_offset, lldb::offset_t file_offset, | ||||||||
872 | lldb::offset_t length, lldb_private::ModuleSpecList &specs) { | ||||||||
873 | const size_t initial_count = specs.GetSize(); | ||||||||
874 | |||||||||
875 | if (ObjectFileMachO::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) { | ||||||||
876 | DataExtractor data; | ||||||||
877 | data.SetData(data_sp); | ||||||||
878 | llvm::MachO::mach_header header; | ||||||||
879 | if (ParseHeader(data, &data_offset, header)) { | ||||||||
880 | size_t header_and_load_cmds = | ||||||||
881 | header.sizeofcmds + MachHeaderSizeFromMagic(header.magic); | ||||||||
882 | if (header_and_load_cmds >= data_sp->GetByteSize()) { | ||||||||
883 | data_sp = MapFileData(file, header_and_load_cmds, file_offset); | ||||||||
884 | data.SetData(data_sp); | ||||||||
885 | data_offset = MachHeaderSizeFromMagic(header.magic); | ||||||||
886 | } | ||||||||
887 | if (data_sp) { | ||||||||
888 | ModuleSpec base_spec; | ||||||||
889 | base_spec.GetFileSpec() = file; | ||||||||
890 | base_spec.SetObjectOffset(file_offset); | ||||||||
891 | base_spec.SetObjectSize(length); | ||||||||
892 | GetAllArchSpecs(header, data, data_offset, base_spec, specs); | ||||||||
893 | } | ||||||||
894 | } | ||||||||
895 | } | ||||||||
896 | return specs.GetSize() - initial_count; | ||||||||
897 | } | ||||||||
898 | |||||||||
899 | ConstString ObjectFileMachO::GetSegmentNameTEXT() { | ||||||||
900 | static ConstString g_segment_name_TEXT("__TEXT"); | ||||||||
901 | return g_segment_name_TEXT; | ||||||||
902 | } | ||||||||
903 | |||||||||
904 | ConstString ObjectFileMachO::GetSegmentNameDATA() { | ||||||||
905 | static ConstString g_segment_name_DATA("__DATA"); | ||||||||
906 | return g_segment_name_DATA; | ||||||||
907 | } | ||||||||
908 | |||||||||
909 | ConstString ObjectFileMachO::GetSegmentNameDATA_DIRTY() { | ||||||||
910 | static ConstString g_segment_name("__DATA_DIRTY"); | ||||||||
911 | return g_segment_name; | ||||||||
912 | } | ||||||||
913 | |||||||||
914 | ConstString ObjectFileMachO::GetSegmentNameDATA_CONST() { | ||||||||
915 | static ConstString g_segment_name("__DATA_CONST"); | ||||||||
916 | return g_segment_name; | ||||||||
917 | } | ||||||||
918 | |||||||||
919 | ConstString ObjectFileMachO::GetSegmentNameOBJC() { | ||||||||
920 | static ConstString g_segment_name_OBJC("__OBJC"); | ||||||||
921 | return g_segment_name_OBJC; | ||||||||
922 | } | ||||||||
923 | |||||||||
924 | ConstString ObjectFileMachO::GetSegmentNameLINKEDIT() { | ||||||||
925 | static ConstString g_section_name_LINKEDIT("__LINKEDIT"); | ||||||||
926 | return g_section_name_LINKEDIT; | ||||||||
927 | } | ||||||||
928 | |||||||||
929 | ConstString ObjectFileMachO::GetSegmentNameDWARF() { | ||||||||
930 | static ConstString g_section_name("__DWARF"); | ||||||||
931 | return g_section_name; | ||||||||
932 | } | ||||||||
933 | |||||||||
934 | ConstString ObjectFileMachO::GetSectionNameEHFrame() { | ||||||||
935 | static ConstString g_section_name_eh_frame("__eh_frame"); | ||||||||
936 | return g_section_name_eh_frame; | ||||||||
937 | } | ||||||||
938 | |||||||||
939 | bool ObjectFileMachO::MagicBytesMatch(DataBufferSP &data_sp, | ||||||||
940 | lldb::addr_t data_offset, | ||||||||
941 | lldb::addr_t data_length) { | ||||||||
942 | DataExtractor data; | ||||||||
943 | data.SetData(data_sp, data_offset, data_length); | ||||||||
944 | lldb::offset_t offset = 0; | ||||||||
945 | uint32_t magic = data.GetU32(&offset); | ||||||||
946 | return MachHeaderSizeFromMagic(magic) != 0; | ||||||||
947 | } | ||||||||
948 | |||||||||
949 | ObjectFileMachO::ObjectFileMachO(const lldb::ModuleSP &module_sp, | ||||||||
950 | DataBufferSP &data_sp, | ||||||||
951 | lldb::offset_t data_offset, | ||||||||
952 | const FileSpec *file, | ||||||||
953 | lldb::offset_t file_offset, | ||||||||
954 | lldb::offset_t length) | ||||||||
955 | : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset), | ||||||||
956 | m_mach_segments(), m_mach_sections(), m_entry_point_address(), | ||||||||
957 | m_thread_context_offsets(), m_thread_context_offsets_valid(false), | ||||||||
958 | m_reexported_dylibs(), m_allow_assembly_emulation_unwind_plans(true) { | ||||||||
959 | ::memset(&m_header, 0, sizeof(m_header)); | ||||||||
960 | ::memset(&m_dysymtab, 0, sizeof(m_dysymtab)); | ||||||||
961 | } | ||||||||
962 | |||||||||
963 | ObjectFileMachO::ObjectFileMachO(const lldb::ModuleSP &module_sp, | ||||||||
964 | lldb::DataBufferSP &header_data_sp, | ||||||||
965 | const lldb::ProcessSP &process_sp, | ||||||||
966 | lldb::addr_t header_addr) | ||||||||
967 | : ObjectFile(module_sp, process_sp, header_addr, header_data_sp), | ||||||||
968 | m_mach_segments(), m_mach_sections(), m_entry_point_address(), | ||||||||
969 | m_thread_context_offsets(), m_thread_context_offsets_valid(false), | ||||||||
970 | m_reexported_dylibs(), m_allow_assembly_emulation_unwind_plans(true) { | ||||||||
971 | ::memset(&m_header, 0, sizeof(m_header)); | ||||||||
972 | ::memset(&m_dysymtab, 0, sizeof(m_dysymtab)); | ||||||||
973 | } | ||||||||
974 | |||||||||
975 | bool ObjectFileMachO::ParseHeader(DataExtractor &data, | ||||||||
976 | lldb::offset_t *data_offset_ptr, | ||||||||
977 | llvm::MachO::mach_header &header) { | ||||||||
978 | data.SetByteOrder(endian::InlHostByteOrder()); | ||||||||
979 | // Leave magic in the original byte order | ||||||||
980 | header.magic = data.GetU32(data_offset_ptr); | ||||||||
981 | bool can_parse = false; | ||||||||
982 | bool is_64_bit = false; | ||||||||
983 | switch (header.magic) { | ||||||||
984 | case MH_MAGIC: | ||||||||
985 | data.SetByteOrder(endian::InlHostByteOrder()); | ||||||||
986 | data.SetAddressByteSize(4); | ||||||||
987 | can_parse = true; | ||||||||
988 | break; | ||||||||
989 | |||||||||
990 | case MH_MAGIC_64: | ||||||||
991 | data.SetByteOrder(endian::InlHostByteOrder()); | ||||||||
992 | data.SetAddressByteSize(8); | ||||||||
993 | can_parse = true; | ||||||||
994 | is_64_bit = true; | ||||||||
995 | break; | ||||||||
996 | |||||||||
997 | case MH_CIGAM: | ||||||||
998 | data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig | ||||||||
999 | ? eByteOrderLittle | ||||||||
1000 | : eByteOrderBig); | ||||||||
1001 | data.SetAddressByteSize(4); | ||||||||
1002 | can_parse = true; | ||||||||
1003 | break; | ||||||||
1004 | |||||||||
1005 | case MH_CIGAM_64: | ||||||||
1006 | data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig | ||||||||
1007 | ? eByteOrderLittle | ||||||||
1008 | : eByteOrderBig); | ||||||||
1009 | data.SetAddressByteSize(8); | ||||||||
1010 | is_64_bit = true; | ||||||||
1011 | can_parse = true; | ||||||||
1012 | break; | ||||||||
1013 | |||||||||
1014 | default: | ||||||||
1015 | break; | ||||||||
1016 | } | ||||||||
1017 | |||||||||
1018 | if (can_parse) { | ||||||||
1019 | data.GetU32(data_offset_ptr, &header.cputype, 6); | ||||||||
1020 | if (is_64_bit) | ||||||||
1021 | *data_offset_ptr += 4; | ||||||||
1022 | return true; | ||||||||
1023 | } else { | ||||||||
1024 | memset(&header, 0, sizeof(header)); | ||||||||
1025 | } | ||||||||
1026 | return false; | ||||||||
1027 | } | ||||||||
1028 | |||||||||
1029 | bool ObjectFileMachO::ParseHeader() { | ||||||||
1030 | ModuleSP module_sp(GetModule()); | ||||||||
1031 | if (!module_sp) | ||||||||
1032 | return false; | ||||||||
1033 | |||||||||
1034 | std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); | ||||||||
1035 | bool can_parse = false; | ||||||||
1036 | lldb::offset_t offset = 0; | ||||||||
1037 | m_data.SetByteOrder(endian::InlHostByteOrder()); | ||||||||
1038 | // Leave magic in the original byte order | ||||||||
1039 | m_header.magic = m_data.GetU32(&offset); | ||||||||
1040 | switch (m_header.magic) { | ||||||||
1041 | case MH_MAGIC: | ||||||||
1042 | m_data.SetByteOrder(endian::InlHostByteOrder()); | ||||||||
1043 | m_data.SetAddressByteSize(4); | ||||||||
1044 | can_parse = true; | ||||||||
1045 | break; | ||||||||
1046 | |||||||||
1047 | case MH_MAGIC_64: | ||||||||
1048 | m_data.SetByteOrder(endian::InlHostByteOrder()); | ||||||||
1049 | m_data.SetAddressByteSize(8); | ||||||||
1050 | can_parse = true; | ||||||||
1051 | break; | ||||||||
1052 | |||||||||
1053 | case MH_CIGAM: | ||||||||
1054 | m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig | ||||||||
1055 | ? eByteOrderLittle | ||||||||
1056 | : eByteOrderBig); | ||||||||
1057 | m_data.SetAddressByteSize(4); | ||||||||
1058 | can_parse = true; | ||||||||
1059 | break; | ||||||||
1060 | |||||||||
1061 | case MH_CIGAM_64: | ||||||||
1062 | m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig | ||||||||
1063 | ? eByteOrderLittle | ||||||||
1064 | : eByteOrderBig); | ||||||||
1065 | m_data.SetAddressByteSize(8); | ||||||||
1066 | can_parse = true; | ||||||||
1067 | break; | ||||||||
1068 | |||||||||
1069 | default: | ||||||||
1070 | break; | ||||||||
1071 | } | ||||||||
1072 | |||||||||
1073 | if (can_parse) { | ||||||||
1074 | m_data.GetU32(&offset, &m_header.cputype, 6); | ||||||||
1075 | |||||||||
1076 | ModuleSpecList all_specs; | ||||||||
1077 | ModuleSpec base_spec; | ||||||||
1078 | GetAllArchSpecs(m_header, m_data, MachHeaderSizeFromMagic(m_header.magic), | ||||||||
1079 | base_spec, all_specs); | ||||||||
1080 | |||||||||
1081 | for (unsigned i = 0, e = all_specs.GetSize(); i != e; ++i) { | ||||||||
1082 | ArchSpec mach_arch = | ||||||||
1083 | all_specs.GetModuleSpecRefAtIndex(i).GetArchitecture(); | ||||||||
1084 | |||||||||
1085 | // Check if the module has a required architecture | ||||||||
1086 | const ArchSpec &module_arch = module_sp->GetArchitecture(); | ||||||||
1087 | if (module_arch.IsValid() && !module_arch.IsCompatibleMatch(mach_arch)) | ||||||||
1088 | continue; | ||||||||
1089 | |||||||||
1090 | if (SetModulesArchitecture(mach_arch)) { | ||||||||
1091 | const size_t header_and_lc_size = | ||||||||
1092 | m_header.sizeofcmds + MachHeaderSizeFromMagic(m_header.magic); | ||||||||
1093 | if (m_data.GetByteSize() < header_and_lc_size) { | ||||||||
1094 | DataBufferSP data_sp; | ||||||||
1095 | ProcessSP process_sp(m_process_wp.lock()); | ||||||||
1096 | if (process_sp) { | ||||||||
1097 | data_sp = ReadMemory(process_sp, m_memory_addr, header_and_lc_size); | ||||||||
1098 | } else { | ||||||||
1099 | // Read in all only the load command data from the file on disk | ||||||||
1100 | data_sp = MapFileData(m_file, header_and_lc_size, m_file_offset); | ||||||||
1101 | if (data_sp->GetByteSize() != header_and_lc_size) | ||||||||
1102 | continue; | ||||||||
1103 | } | ||||||||
1104 | if (data_sp) | ||||||||
1105 | m_data.SetData(data_sp); | ||||||||
1106 | } | ||||||||
1107 | } | ||||||||
1108 | return true; | ||||||||
1109 | } | ||||||||
1110 | // None found. | ||||||||
1111 | return false; | ||||||||
1112 | } else { | ||||||||
1113 | memset(&m_header, 0, sizeof(struct llvm::MachO::mach_header)); | ||||||||
1114 | } | ||||||||
1115 | return false; | ||||||||
1116 | } | ||||||||
1117 | |||||||||
1118 | ByteOrder ObjectFileMachO::GetByteOrder() const { | ||||||||
1119 | return m_data.GetByteOrder(); | ||||||||
1120 | } | ||||||||
1121 | |||||||||
1122 | bool ObjectFileMachO::IsExecutable() const { | ||||||||
1123 | return m_header.filetype == MH_EXECUTE; | ||||||||
1124 | } | ||||||||
1125 | |||||||||
1126 | bool ObjectFileMachO::IsDynamicLoader() const { | ||||||||
1127 | return m_header.filetype == MH_DYLINKER; | ||||||||
1128 | } | ||||||||
1129 | |||||||||
1130 | uint32_t ObjectFileMachO::GetAddressByteSize() const { | ||||||||
1131 | return m_data.GetAddressByteSize(); | ||||||||
1132 | } | ||||||||
1133 | |||||||||
1134 | AddressClass ObjectFileMachO::GetAddressClass(lldb::addr_t file_addr) { | ||||||||
1135 | Symtab *symtab = GetSymtab(); | ||||||||
1136 | if (!symtab) | ||||||||
1137 | return AddressClass::eUnknown; | ||||||||
1138 | |||||||||
1139 | Symbol *symbol = symtab->FindSymbolContainingFileAddress(file_addr); | ||||||||
1140 | if (symbol) { | ||||||||
1141 | if (symbol->ValueIsAddress()) { | ||||||||
1142 | SectionSP section_sp(symbol->GetAddressRef().GetSection()); | ||||||||
1143 | if (section_sp) { | ||||||||
1144 | const lldb::SectionType section_type = section_sp->GetType(); | ||||||||
1145 | switch (section_type) { | ||||||||
1146 | case eSectionTypeInvalid: | ||||||||
1147 | return AddressClass::eUnknown; | ||||||||
1148 | |||||||||
1149 | case eSectionTypeCode: | ||||||||
1150 | if (m_header.cputype == llvm::MachO::CPU_TYPE_ARM) { | ||||||||
1151 | // For ARM we have a bit in the n_desc field of the symbol that | ||||||||
1152 | // tells us ARM/Thumb which is bit 0x0008. | ||||||||
1153 | if (symbol->GetFlags() & MACHO_NLIST_ARM_SYMBOL_IS_THUMB0x0008) | ||||||||
1154 | return AddressClass::eCodeAlternateISA; | ||||||||
1155 | } | ||||||||
1156 | return AddressClass::eCode; | ||||||||
1157 | |||||||||
1158 | case eSectionTypeContainer: | ||||||||
1159 | return AddressClass::eUnknown; | ||||||||
1160 | |||||||||
1161 | case eSectionTypeData: | ||||||||
1162 | case eSectionTypeDataCString: | ||||||||
1163 | case eSectionTypeDataCStringPointers: | ||||||||
1164 | case eSectionTypeDataSymbolAddress: | ||||||||
1165 | case eSectionTypeData4: | ||||||||
1166 | case eSectionTypeData8: | ||||||||
1167 | case eSectionTypeData16: | ||||||||
1168 | case eSectionTypeDataPointers: | ||||||||
1169 | case eSectionTypeZeroFill: | ||||||||
1170 | case eSectionTypeDataObjCMessageRefs: | ||||||||
1171 | case eSectionTypeDataObjCCFStrings: | ||||||||
1172 | case eSectionTypeGoSymtab: | ||||||||
1173 | return AddressClass::eData; | ||||||||
1174 | |||||||||
1175 | case eSectionTypeDebug: | ||||||||
1176 | case eSectionTypeDWARFDebugAbbrev: | ||||||||
1177 | case eSectionTypeDWARFDebugAbbrevDwo: | ||||||||
1178 | case eSectionTypeDWARFDebugAddr: | ||||||||
1179 | case eSectionTypeDWARFDebugAranges: | ||||||||
1180 | case eSectionTypeDWARFDebugCuIndex: | ||||||||
1181 | case eSectionTypeDWARFDebugFrame: | ||||||||
1182 | case eSectionTypeDWARFDebugInfo: | ||||||||
1183 | case eSectionTypeDWARFDebugInfoDwo: | ||||||||
1184 | case eSectionTypeDWARFDebugLine: | ||||||||
1185 | case eSectionTypeDWARFDebugLineStr: | ||||||||
1186 | case eSectionTypeDWARFDebugLoc: | ||||||||
1187 | case eSectionTypeDWARFDebugLocDwo: | ||||||||
1188 | case eSectionTypeDWARFDebugLocLists: | ||||||||
1189 | case eSectionTypeDWARFDebugLocListsDwo: | ||||||||
1190 | case eSectionTypeDWARFDebugMacInfo: | ||||||||
1191 | case eSectionTypeDWARFDebugMacro: | ||||||||
1192 | case eSectionTypeDWARFDebugNames: | ||||||||
1193 | case eSectionTypeDWARFDebugPubNames: | ||||||||
1194 | case eSectionTypeDWARFDebugPubTypes: | ||||||||
1195 | case eSectionTypeDWARFDebugRanges: | ||||||||
1196 | case eSectionTypeDWARFDebugRngLists: | ||||||||
1197 | case eSectionTypeDWARFDebugRngListsDwo: | ||||||||
1198 | case eSectionTypeDWARFDebugStr: | ||||||||
1199 | case eSectionTypeDWARFDebugStrDwo: | ||||||||
1200 | case eSectionTypeDWARFDebugStrOffsets: | ||||||||
1201 | case eSectionTypeDWARFDebugStrOffsetsDwo: | ||||||||
1202 | case eSectionTypeDWARFDebugTuIndex: | ||||||||
1203 | case eSectionTypeDWARFDebugTypes: | ||||||||
1204 | case eSectionTypeDWARFDebugTypesDwo: | ||||||||
1205 | case eSectionTypeDWARFAppleNames: | ||||||||
1206 | case eSectionTypeDWARFAppleTypes: | ||||||||
1207 | case eSectionTypeDWARFAppleNamespaces: | ||||||||
1208 | case eSectionTypeDWARFAppleObjC: | ||||||||
1209 | case eSectionTypeDWARFGNUDebugAltLink: | ||||||||
1210 | return AddressClass::eDebug; | ||||||||
1211 | |||||||||
1212 | case eSectionTypeEHFrame: | ||||||||
1213 | case eSectionTypeARMexidx: | ||||||||
1214 | case eSectionTypeARMextab: | ||||||||
1215 | case eSectionTypeCompactUnwind: | ||||||||
1216 | return AddressClass::eRuntime; | ||||||||
1217 | |||||||||
1218 | case eSectionTypeAbsoluteAddress: | ||||||||
1219 | case eSectionTypeELFSymbolTable: | ||||||||
1220 | case eSectionTypeELFDynamicSymbols: | ||||||||
1221 | case eSectionTypeELFRelocationEntries: | ||||||||
1222 | case eSectionTypeELFDynamicLinkInfo: | ||||||||
1223 | case eSectionTypeOther: | ||||||||
1224 | return AddressClass::eUnknown; | ||||||||
1225 | } | ||||||||
1226 | } | ||||||||
1227 | } | ||||||||
1228 | |||||||||
1229 | const SymbolType symbol_type = symbol->GetType(); | ||||||||
1230 | switch (symbol_type) { | ||||||||
1231 | case eSymbolTypeAny: | ||||||||
1232 | return AddressClass::eUnknown; | ||||||||
1233 | case eSymbolTypeAbsolute: | ||||||||
1234 | return AddressClass::eUnknown; | ||||||||
1235 | |||||||||
1236 | case eSymbolTypeCode: | ||||||||
1237 | case eSymbolTypeTrampoline: | ||||||||
1238 | case eSymbolTypeResolver: | ||||||||
1239 | if (m_header.cputype == llvm::MachO::CPU_TYPE_ARM) { | ||||||||
1240 | // For ARM we have a bit in the n_desc field of the symbol that tells | ||||||||
1241 | // us ARM/Thumb which is bit 0x0008. | ||||||||
1242 | if (symbol->GetFlags() & MACHO_NLIST_ARM_SYMBOL_IS_THUMB0x0008) | ||||||||
1243 | return AddressClass::eCodeAlternateISA; | ||||||||
1244 | } | ||||||||
1245 | return AddressClass::eCode; | ||||||||
1246 | |||||||||
1247 | case eSymbolTypeData: | ||||||||
1248 | return AddressClass::eData; | ||||||||
1249 | case eSymbolTypeRuntime: | ||||||||
1250 | return AddressClass::eRuntime; | ||||||||
1251 | case eSymbolTypeException: | ||||||||
1252 | return AddressClass::eRuntime; | ||||||||
1253 | case eSymbolTypeSourceFile: | ||||||||
1254 | return AddressClass::eDebug; | ||||||||
1255 | case eSymbolTypeHeaderFile: | ||||||||
1256 | return AddressClass::eDebug; | ||||||||
1257 | case eSymbolTypeObjectFile: | ||||||||
1258 | return AddressClass::eDebug; | ||||||||
1259 | case eSymbolTypeCommonBlock: | ||||||||
1260 | return AddressClass::eDebug; | ||||||||
1261 | case eSymbolTypeBlock: | ||||||||
1262 | return AddressClass::eDebug; | ||||||||
1263 | case eSymbolTypeLocal: | ||||||||
1264 | return AddressClass::eData; | ||||||||
1265 | case eSymbolTypeParam: | ||||||||
1266 | return AddressClass::eData; | ||||||||
1267 | case eSymbolTypeVariable: | ||||||||
1268 | return AddressClass::eData; | ||||||||
1269 | case eSymbolTypeVariableType: | ||||||||
1270 | return AddressClass::eDebug; | ||||||||
1271 | case eSymbolTypeLineEntry: | ||||||||
1272 | return AddressClass::eDebug; | ||||||||
1273 | case eSymbolTypeLineHeader: | ||||||||
1274 | return AddressClass::eDebug; | ||||||||
1275 | case eSymbolTypeScopeBegin: | ||||||||
1276 | return AddressClass::eDebug; | ||||||||
1277 | case eSymbolTypeScopeEnd: | ||||||||
1278 | return AddressClass::eDebug; | ||||||||
1279 | case eSymbolTypeAdditional: | ||||||||
1280 | return AddressClass::eUnknown; | ||||||||
1281 | case eSymbolTypeCompiler: | ||||||||
1282 | return AddressClass::eDebug; | ||||||||
1283 | case eSymbolTypeInstrumentation: | ||||||||
1284 | return AddressClass::eDebug; | ||||||||
1285 | case eSymbolTypeUndefined: | ||||||||
1286 | return AddressClass::eUnknown; | ||||||||
1287 | case eSymbolTypeObjCClass: | ||||||||
1288 | return AddressClass::eRuntime; | ||||||||
1289 | case eSymbolTypeObjCMetaClass: | ||||||||
1290 | return AddressClass::eRuntime; | ||||||||
1291 | case eSymbolTypeObjCIVar: | ||||||||
1292 | return AddressClass::eRuntime; | ||||||||
1293 | case eSymbolTypeReExported: | ||||||||
1294 | return AddressClass::eRuntime; | ||||||||
1295 | } | ||||||||
1296 | } | ||||||||
1297 | return AddressClass::eUnknown; | ||||||||
1298 | } | ||||||||
1299 | |||||||||
1300 | Symtab *ObjectFileMachO::GetSymtab() { | ||||||||
1301 | ModuleSP module_sp(GetModule()); | ||||||||
1302 | if (module_sp) { | ||||||||
1303 | std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); | ||||||||
1304 | if (m_symtab_up == nullptr) { | ||||||||
1305 | m_symtab_up = std::make_unique<Symtab>(this); | ||||||||
1306 | std::lock_guard<std::recursive_mutex> symtab_guard( | ||||||||
1307 | m_symtab_up->GetMutex()); | ||||||||
1308 | ParseSymtab(); | ||||||||
1309 | m_symtab_up->Finalize(); | ||||||||
1310 | } | ||||||||
1311 | } | ||||||||
1312 | return m_symtab_up.get(); | ||||||||
1313 | } | ||||||||
1314 | |||||||||
1315 | bool ObjectFileMachO::IsStripped() { | ||||||||
1316 | if (m_dysymtab.cmd == 0) { | ||||||||
1317 | ModuleSP module_sp(GetModule()); | ||||||||
1318 | if (module_sp) { | ||||||||
1319 | lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); | ||||||||
1320 | for (uint32_t i = 0; i < m_header.ncmds; ++i) { | ||||||||
1321 | const lldb::offset_t load_cmd_offset = offset; | ||||||||
1322 | |||||||||
1323 | llvm::MachO::load_command lc; | ||||||||
1324 | if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr) | ||||||||
1325 | break; | ||||||||
1326 | if (lc.cmd == LC_DYSYMTAB) { | ||||||||
1327 | m_dysymtab.cmd = lc.cmd; | ||||||||
1328 | m_dysymtab.cmdsize = lc.cmdsize; | ||||||||
1329 | if (m_data.GetU32(&offset, &m_dysymtab.ilocalsym, | ||||||||
1330 | (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2) == | ||||||||
1331 | nullptr) { | ||||||||
1332 | // Clear m_dysymtab if we were unable to read all items from the | ||||||||
1333 | // load command | ||||||||
1334 | ::memset(&m_dysymtab, 0, sizeof(m_dysymtab)); | ||||||||
1335 | } | ||||||||
1336 | } | ||||||||
1337 | offset = load_cmd_offset + lc.cmdsize; | ||||||||
1338 | } | ||||||||
1339 | } | ||||||||
1340 | } | ||||||||
1341 | if (m_dysymtab.cmd) | ||||||||
1342 | return m_dysymtab.nlocalsym <= 1; | ||||||||
1343 | return false; | ||||||||
1344 | } | ||||||||
1345 | |||||||||
1346 | ObjectFileMachO::EncryptedFileRanges ObjectFileMachO::GetEncryptedFileRanges() { | ||||||||
1347 | EncryptedFileRanges result; | ||||||||
1348 | lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); | ||||||||
1349 | |||||||||
1350 | llvm::MachO::encryption_info_command encryption_cmd; | ||||||||
1351 | for (uint32_t i = 0; i < m_header.ncmds; ++i) { | ||||||||
1352 | const lldb::offset_t load_cmd_offset = offset; | ||||||||
1353 | if (m_data.GetU32(&offset, &encryption_cmd, 2) == nullptr) | ||||||||
1354 | break; | ||||||||
1355 | |||||||||
1356 | // LC_ENCRYPTION_INFO and LC_ENCRYPTION_INFO_64 have the same sizes for the | ||||||||
1357 | // 3 fields we care about, so treat them the same. | ||||||||
1358 | if (encryption_cmd.cmd == LC_ENCRYPTION_INFO || | ||||||||
1359 | encryption_cmd.cmd == LC_ENCRYPTION_INFO_64) { | ||||||||
1360 | if (m_data.GetU32(&offset, &encryption_cmd.cryptoff, 3)) { | ||||||||
1361 | if (encryption_cmd.cryptid != 0) { | ||||||||
1362 | EncryptedFileRanges::Entry entry; | ||||||||
1363 | entry.SetRangeBase(encryption_cmd.cryptoff); | ||||||||
1364 | entry.SetByteSize(encryption_cmd.cryptsize); | ||||||||
1365 | result.Append(entry); | ||||||||
1366 | } | ||||||||
1367 | } | ||||||||
1368 | } | ||||||||
1369 | offset = load_cmd_offset + encryption_cmd.cmdsize; | ||||||||
1370 | } | ||||||||
1371 | |||||||||
1372 | return result; | ||||||||
1373 | } | ||||||||
1374 | |||||||||
1375 | void ObjectFileMachO::SanitizeSegmentCommand( | ||||||||
1376 | llvm::MachO::segment_command_64 &seg_cmd, uint32_t cmd_idx) { | ||||||||
1377 | if (m_length == 0 || seg_cmd.filesize == 0) | ||||||||
1378 | return; | ||||||||
1379 | |||||||||
1380 | if ((m_header.flags & MH_DYLIB_IN_CACHE) && !IsInMemory()) { | ||||||||
1381 | // In shared cache images, the load commands are relative to the | ||||||||
1382 | // shared cache file, and not the specific image we are | ||||||||
1383 | // examining. Let's fix this up so that it looks like a normal | ||||||||
1384 | // image. | ||||||||
1385 | if (strncmp(seg_cmd.segname, "__TEXT", sizeof(seg_cmd.segname)) == 0) | ||||||||
1386 | m_text_address = seg_cmd.vmaddr; | ||||||||
1387 | if (strncmp(seg_cmd.segname, "__LINKEDIT", sizeof(seg_cmd.segname)) == 0) | ||||||||
1388 | m_linkedit_original_offset = seg_cmd.fileoff; | ||||||||
1389 | |||||||||
1390 | seg_cmd.fileoff = seg_cmd.vmaddr - m_text_address; | ||||||||
1391 | } | ||||||||
1392 | |||||||||
1393 | if (seg_cmd.fileoff > m_length) { | ||||||||
1394 | // We have a load command that says it extends past the end of the file. | ||||||||
1395 | // This is likely a corrupt file. We don't have any way to return an error | ||||||||
1396 | // condition here (this method was likely invoked from something like | ||||||||
1397 | // ObjectFile::GetSectionList()), so we just null out the section contents, | ||||||||
1398 | // and dump a message to stdout. The most common case here is core file | ||||||||
1399 | // debugging with a truncated file. | ||||||||
1400 | const char *lc_segment_name = | ||||||||
1401 | seg_cmd.cmd == LC_SEGMENT_64 ? "LC_SEGMENT_64" : "LC_SEGMENT"; | ||||||||
1402 | GetModule()->ReportWarning( | ||||||||
1403 | "load command %u %s has a fileoff (0x%" PRIx64"llx" | ||||||||
1404 | ") that extends beyond the end of the file (0x%" PRIx64"llx" | ||||||||
1405 | "), ignoring this section", | ||||||||
1406 | cmd_idx, lc_segment_name, seg_cmd.fileoff, m_length); | ||||||||
1407 | |||||||||
1408 | seg_cmd.fileoff = 0; | ||||||||
1409 | seg_cmd.filesize = 0; | ||||||||
1410 | } | ||||||||
1411 | |||||||||
1412 | if (seg_cmd.fileoff + seg_cmd.filesize > m_length) { | ||||||||
1413 | // We have a load command that says it extends past the end of the file. | ||||||||
1414 | // This is likely a corrupt file. We don't have any way to return an error | ||||||||
1415 | // condition here (this method was likely invoked from something like | ||||||||
1416 | // ObjectFile::GetSectionList()), so we just null out the section contents, | ||||||||
1417 | // and dump a message to stdout. The most common case here is core file | ||||||||
1418 | // debugging with a truncated file. | ||||||||
1419 | const char *lc_segment_name = | ||||||||
1420 | seg_cmd.cmd == LC_SEGMENT_64 ? "LC_SEGMENT_64" : "LC_SEGMENT"; | ||||||||
1421 | GetModule()->ReportWarning( | ||||||||
1422 | "load command %u %s has a fileoff + filesize (0x%" PRIx64"llx" | ||||||||
1423 | ") that extends beyond the end of the file (0x%" PRIx64"llx" | ||||||||
1424 | "), the segment will be truncated to match", | ||||||||
1425 | cmd_idx, lc_segment_name, seg_cmd.fileoff + seg_cmd.filesize, m_length); | ||||||||
1426 | |||||||||
1427 | // Truncate the length | ||||||||
1428 | seg_cmd.filesize = m_length - seg_cmd.fileoff; | ||||||||
1429 | } | ||||||||
1430 | } | ||||||||
1431 | |||||||||
1432 | static uint32_t | ||||||||
1433 | GetSegmentPermissions(const llvm::MachO::segment_command_64 &seg_cmd) { | ||||||||
1434 | uint32_t result = 0; | ||||||||
1435 | if (seg_cmd.initprot & VM_PROT_READ) | ||||||||
1436 | result |= ePermissionsReadable; | ||||||||
1437 | if (seg_cmd.initprot & VM_PROT_WRITE) | ||||||||
1438 | result |= ePermissionsWritable; | ||||||||
1439 | if (seg_cmd.initprot & VM_PROT_EXECUTE) | ||||||||
1440 | result |= ePermissionsExecutable; | ||||||||
1441 | return result; | ||||||||
1442 | } | ||||||||
1443 | |||||||||
1444 | static lldb::SectionType GetSectionType(uint32_t flags, | ||||||||
1445 | ConstString section_name) { | ||||||||
1446 | |||||||||
1447 | if (flags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS)) | ||||||||
1448 | return eSectionTypeCode; | ||||||||
1449 | |||||||||
1450 | uint32_t mach_sect_type = flags & SECTION_TYPE; | ||||||||
1451 | static ConstString g_sect_name_objc_data("__objc_data"); | ||||||||
1452 | static ConstString g_sect_name_objc_msgrefs("__objc_msgrefs"); | ||||||||
1453 | static ConstString g_sect_name_objc_selrefs("__objc_selrefs"); | ||||||||
1454 | static ConstString g_sect_name_objc_classrefs("__objc_classrefs"); | ||||||||
1455 | static ConstString g_sect_name_objc_superrefs("__objc_superrefs"); | ||||||||
1456 | static ConstString g_sect_name_objc_const("__objc_const"); | ||||||||
1457 | static ConstString g_sect_name_objc_classlist("__objc_classlist"); | ||||||||
1458 | static ConstString g_sect_name_cfstring("__cfstring"); | ||||||||
1459 | |||||||||
1460 | static ConstString g_sect_name_dwarf_debug_abbrev("__debug_abbrev"); | ||||||||
1461 | static ConstString g_sect_name_dwarf_debug_aranges("__debug_aranges"); | ||||||||
1462 | static ConstString g_sect_name_dwarf_debug_frame("__debug_frame"); | ||||||||
1463 | static ConstString g_sect_name_dwarf_debug_info("__debug_info"); | ||||||||
1464 | static ConstString g_sect_name_dwarf_debug_line("__debug_line"); | ||||||||
1465 | static ConstString g_sect_name_dwarf_debug_loc("__debug_loc"); | ||||||||
1466 | static ConstString g_sect_name_dwarf_debug_loclists("__debug_loclists"); | ||||||||
1467 | static ConstString g_sect_name_dwarf_debug_macinfo("__debug_macinfo"); | ||||||||
1468 | static ConstString g_sect_name_dwarf_debug_names("__debug_names"); | ||||||||
1469 | static ConstString g_sect_name_dwarf_debug_pubnames("__debug_pubnames"); | ||||||||
1470 | static ConstString g_sect_name_dwarf_debug_pubtypes("__debug_pubtypes"); | ||||||||
1471 | static ConstString g_sect_name_dwarf_debug_ranges("__debug_ranges"); | ||||||||
1472 | static ConstString g_sect_name_dwarf_debug_str("__debug_str"); | ||||||||
1473 | static ConstString g_sect_name_dwarf_debug_types("__debug_types"); | ||||||||
1474 | static ConstString g_sect_name_dwarf_apple_names("__apple_names"); | ||||||||
1475 | static ConstString g_sect_name_dwarf_apple_types("__apple_types"); | ||||||||
1476 | static ConstString g_sect_name_dwarf_apple_namespaces("__apple_namespac"); | ||||||||
1477 | static ConstString g_sect_name_dwarf_apple_objc("__apple_objc"); | ||||||||
1478 | static ConstString g_sect_name_eh_frame("__eh_frame"); | ||||||||
1479 | static ConstString g_sect_name_compact_unwind("__unwind_info"); | ||||||||
1480 | static ConstString g_sect_name_text("__text"); | ||||||||
1481 | static ConstString g_sect_name_data("__data"); | ||||||||
1482 | static ConstString g_sect_name_go_symtab("__gosymtab"); | ||||||||
1483 | |||||||||
1484 | if (section_name == g_sect_name_dwarf_debug_abbrev) | ||||||||
1485 | return eSectionTypeDWARFDebugAbbrev; | ||||||||
1486 | if (section_name == g_sect_name_dwarf_debug_aranges) | ||||||||
1487 | return eSectionTypeDWARFDebugAranges; | ||||||||
1488 | if (section_name == g_sect_name_dwarf_debug_frame) | ||||||||
1489 | return eSectionTypeDWARFDebugFrame; | ||||||||
1490 | if (section_name == g_sect_name_dwarf_debug_info) | ||||||||
1491 | return eSectionTypeDWARFDebugInfo; | ||||||||
1492 | if (section_name == g_sect_name_dwarf_debug_line) | ||||||||
1493 | return eSectionTypeDWARFDebugLine; | ||||||||
1494 | if (section_name == g_sect_name_dwarf_debug_loc) | ||||||||
1495 | return eSectionTypeDWARFDebugLoc; | ||||||||
1496 | if (section_name == g_sect_name_dwarf_debug_loclists) | ||||||||
1497 | return eSectionTypeDWARFDebugLocLists; | ||||||||
1498 | if (section_name == g_sect_name_dwarf_debug_macinfo) | ||||||||
1499 | return eSectionTypeDWARFDebugMacInfo; | ||||||||
1500 | if (section_name == g_sect_name_dwarf_debug_names) | ||||||||
1501 | return eSectionTypeDWARFDebugNames; | ||||||||
1502 | if (section_name == g_sect_name_dwarf_debug_pubnames) | ||||||||
1503 | return eSectionTypeDWARFDebugPubNames; | ||||||||
1504 | if (section_name == g_sect_name_dwarf_debug_pubtypes) | ||||||||
1505 | return eSectionTypeDWARFDebugPubTypes; | ||||||||
1506 | if (section_name == g_sect_name_dwarf_debug_ranges) | ||||||||
1507 | return eSectionTypeDWARFDebugRanges; | ||||||||
1508 | if (section_name == g_sect_name_dwarf_debug_str) | ||||||||
1509 | return eSectionTypeDWARFDebugStr; | ||||||||
1510 | if (section_name == g_sect_name_dwarf_debug_types) | ||||||||
1511 | return eSectionTypeDWARFDebugTypes; | ||||||||
1512 | if (section_name == g_sect_name_dwarf_apple_names) | ||||||||
1513 | return eSectionTypeDWARFAppleNames; | ||||||||
1514 | if (section_name == g_sect_name_dwarf_apple_types) | ||||||||
1515 | return eSectionTypeDWARFAppleTypes; | ||||||||
1516 | if (section_name == g_sect_name_dwarf_apple_namespaces) | ||||||||
1517 | return eSectionTypeDWARFAppleNamespaces; | ||||||||
1518 | if (section_name == g_sect_name_dwarf_apple_objc) | ||||||||
1519 | return eSectionTypeDWARFAppleObjC; | ||||||||
1520 | if (section_name == g_sect_name_objc_selrefs) | ||||||||
1521 | return eSectionTypeDataCStringPointers; | ||||||||
1522 | if (section_name == g_sect_name_objc_msgrefs) | ||||||||
1523 | return eSectionTypeDataObjCMessageRefs; | ||||||||
1524 | if (section_name == g_sect_name_eh_frame) | ||||||||
1525 | return eSectionTypeEHFrame; | ||||||||
1526 | if (section_name == g_sect_name_compact_unwind) | ||||||||
1527 | return eSectionTypeCompactUnwind; | ||||||||
1528 | if (section_name == g_sect_name_cfstring) | ||||||||
1529 | return eSectionTypeDataObjCCFStrings; | ||||||||
1530 | if (section_name == g_sect_name_go_symtab) | ||||||||
1531 | return eSectionTypeGoSymtab; | ||||||||
1532 | if (section_name == g_sect_name_objc_data || | ||||||||
1533 | section_name == g_sect_name_objc_classrefs || | ||||||||
1534 | section_name == g_sect_name_objc_superrefs || | ||||||||
1535 | section_name == g_sect_name_objc_const || | ||||||||
1536 | section_name == g_sect_name_objc_classlist) { | ||||||||
1537 | return eSectionTypeDataPointers; | ||||||||
1538 | } | ||||||||
1539 | |||||||||
1540 | switch (mach_sect_type) { | ||||||||
1541 | // TODO: categorize sections by other flags for regular sections | ||||||||
1542 | case S_REGULAR: | ||||||||
1543 | if (section_name == g_sect_name_text) | ||||||||
1544 | return eSectionTypeCode; | ||||||||
1545 | if (section_name == g_sect_name_data) | ||||||||
1546 | return eSectionTypeData; | ||||||||
1547 | return eSectionTypeOther; | ||||||||
1548 | case S_ZEROFILL: | ||||||||
1549 | return eSectionTypeZeroFill; | ||||||||
1550 | case S_CSTRING_LITERALS: // section with only literal C strings | ||||||||
1551 | return eSectionTypeDataCString; | ||||||||
1552 | case S_4BYTE_LITERALS: // section with only 4 byte literals | ||||||||
1553 | return eSectionTypeData4; | ||||||||
1554 | case S_8BYTE_LITERALS: // section with only 8 byte literals | ||||||||
1555 | return eSectionTypeData8; | ||||||||
1556 | case S_LITERAL_POINTERS: // section with only pointers to literals | ||||||||
1557 | return eSectionTypeDataPointers; | ||||||||
1558 | case S_NON_LAZY_SYMBOL_POINTERS: // section with only non-lazy symbol pointers | ||||||||
1559 | return eSectionTypeDataPointers; | ||||||||
1560 | case S_LAZY_SYMBOL_POINTERS: // section with only lazy symbol pointers | ||||||||
1561 | return eSectionTypeDataPointers; | ||||||||
1562 | case S_SYMBOL_STUBS: // section with only symbol stubs, byte size of stub in | ||||||||
1563 | // the reserved2 field | ||||||||
1564 | return eSectionTypeCode; | ||||||||
1565 | case S_MOD_INIT_FUNC_POINTERS: // section with only function pointers for | ||||||||
1566 | // initialization | ||||||||
1567 | return eSectionTypeDataPointers; | ||||||||
1568 | case S_MOD_TERM_FUNC_POINTERS: // section with only function pointers for | ||||||||
1569 | // termination | ||||||||
1570 | return eSectionTypeDataPointers; | ||||||||
1571 | case S_COALESCED: | ||||||||
1572 | return eSectionTypeOther; | ||||||||
1573 | case S_GB_ZEROFILL: | ||||||||
1574 | return eSectionTypeZeroFill; | ||||||||
1575 | case S_INTERPOSING: // section with only pairs of function pointers for | ||||||||
1576 | // interposing | ||||||||
1577 | return eSectionTypeCode; | ||||||||
1578 | case S_16BYTE_LITERALS: // section with only 16 byte literals | ||||||||
1579 | return eSectionTypeData16; | ||||||||
1580 | case S_DTRACE_DOF: | ||||||||
1581 | return eSectionTypeDebug; | ||||||||
1582 | case S_LAZY_DYLIB_SYMBOL_POINTERS: | ||||||||
1583 | return eSectionTypeDataPointers; | ||||||||
1584 | default: | ||||||||
1585 | return eSectionTypeOther; | ||||||||
1586 | } | ||||||||
1587 | } | ||||||||
1588 | |||||||||
1589 | struct ObjectFileMachO::SegmentParsingContext { | ||||||||
1590 | const EncryptedFileRanges EncryptedRanges; | ||||||||
1591 | lldb_private::SectionList &UnifiedList; | ||||||||
1592 | uint32_t NextSegmentIdx = 0; | ||||||||
1593 | uint32_t NextSectionIdx = 0; | ||||||||
1594 | bool FileAddressesChanged = false; | ||||||||
1595 | |||||||||
1596 | SegmentParsingContext(EncryptedFileRanges EncryptedRanges, | ||||||||
1597 | lldb_private::SectionList &UnifiedList) | ||||||||
1598 | : EncryptedRanges(std::move(EncryptedRanges)), UnifiedList(UnifiedList) {} | ||||||||
1599 | }; | ||||||||
1600 | |||||||||
1601 | void ObjectFileMachO::ProcessSegmentCommand( | ||||||||
1602 | const llvm::MachO::load_command &load_cmd_, lldb::offset_t offset, | ||||||||
1603 | uint32_t cmd_idx, SegmentParsingContext &context) { | ||||||||
1604 | llvm::MachO::segment_command_64 load_cmd; | ||||||||
1605 | memcpy(&load_cmd, &load_cmd_, sizeof(load_cmd_)); | ||||||||
1606 | |||||||||
1607 | if (!m_data.GetU8(&offset, (uint8_t *)load_cmd.segname, 16)) | ||||||||
1608 | return; | ||||||||
1609 | |||||||||
1610 | ModuleSP module_sp = GetModule(); | ||||||||
1611 | const bool is_core = GetType() == eTypeCoreFile; | ||||||||
1612 | const bool is_dsym = (m_header.filetype == MH_DSYM); | ||||||||
1613 | bool add_section = true; | ||||||||
1614 | bool add_to_unified = true; | ||||||||
1615 | ConstString const_segname( | ||||||||
1616 | load_cmd.segname, strnlen(load_cmd.segname, sizeof(load_cmd.segname))); | ||||||||
1617 | |||||||||
1618 | SectionSP unified_section_sp( | ||||||||
1619 | context.UnifiedList.FindSectionByName(const_segname)); | ||||||||
1620 | if (is_dsym && unified_section_sp) { | ||||||||
1621 | if (const_segname == GetSegmentNameLINKEDIT()) { | ||||||||
1622 | // We need to keep the __LINKEDIT segment private to this object file | ||||||||
1623 | // only | ||||||||
1624 | add_to_unified = false; | ||||||||
1625 | } else { | ||||||||
1626 | // This is the dSYM file and this section has already been created by the | ||||||||
1627 | // object file, no need to create it. | ||||||||
1628 | add_section = false; | ||||||||
1629 | } | ||||||||
1630 | } | ||||||||
1631 | load_cmd.vmaddr = m_data.GetAddress(&offset); | ||||||||
1632 | load_cmd.vmsize = m_data.GetAddress(&offset); | ||||||||
1633 | load_cmd.fileoff = m_data.GetAddress(&offset); | ||||||||
1634 | load_cmd.filesize = m_data.GetAddress(&offset); | ||||||||
1635 | if (!m_data.GetU32(&offset, &load_cmd.maxprot, 4)) | ||||||||
1636 | return; | ||||||||
1637 | |||||||||
1638 | SanitizeSegmentCommand(load_cmd, cmd_idx); | ||||||||
1639 | |||||||||
1640 | const uint32_t segment_permissions = GetSegmentPermissions(load_cmd); | ||||||||
1641 | const bool segment_is_encrypted = | ||||||||
1642 | (load_cmd.flags & SG_PROTECTED_VERSION_1) != 0; | ||||||||
1643 | |||||||||
1644 | // Keep a list of mach segments around in case we need to get at data that | ||||||||
1645 | // isn't stored in the abstracted Sections. | ||||||||
1646 | m_mach_segments.push_back(load_cmd); | ||||||||
1647 | |||||||||
1648 | // Use a segment ID of the segment index shifted left by 8 so they never | ||||||||
1649 | // conflict with any of the sections. | ||||||||
1650 | SectionSP segment_sp; | ||||||||
1651 | if (add_section && (const_segname || is_core)) { | ||||||||
1652 | segment_sp = std::make_shared<Section>( | ||||||||
1653 | module_sp, // Module to which this section belongs | ||||||||
1654 | this, // Object file to which this sections belongs | ||||||||
1655 | ++context.NextSegmentIdx | ||||||||
1656 | << 8, // Section ID is the 1 based segment index | ||||||||
1657 | // shifted right by 8 bits as not to collide with any of the 256 | ||||||||
1658 | // section IDs that are possible | ||||||||
1659 | const_segname, // Name of this section | ||||||||
1660 | eSectionTypeContainer, // This section is a container of other | ||||||||
1661 | // sections. | ||||||||
1662 | load_cmd.vmaddr, // File VM address == addresses as they are | ||||||||
1663 | // found in the object file | ||||||||
1664 | load_cmd.vmsize, // VM size in bytes of this section | ||||||||
1665 | load_cmd.fileoff, // Offset to the data for this section in | ||||||||
1666 | // the file | ||||||||
1667 | load_cmd.filesize, // Size in bytes of this section as found | ||||||||
1668 | // in the file | ||||||||
1669 | 0, // Segments have no alignment information | ||||||||
1670 | load_cmd.flags); // Flags for this section | ||||||||
1671 | |||||||||
1672 | segment_sp->SetIsEncrypted(segment_is_encrypted); | ||||||||
1673 | m_sections_up->AddSection(segment_sp); | ||||||||
1674 | segment_sp->SetPermissions(segment_permissions); | ||||||||
1675 | if (add_to_unified) | ||||||||
1676 | context.UnifiedList.AddSection(segment_sp); | ||||||||
1677 | } else if (unified_section_sp) { | ||||||||
1678 | if (is_dsym && unified_section_sp->GetFileAddress() != load_cmd.vmaddr) { | ||||||||
1679 | // Check to see if the module was read from memory? | ||||||||
1680 | if (module_sp->GetObjectFile()->IsInMemory()) { | ||||||||
1681 | // We have a module that is in memory and needs to have its file | ||||||||
1682 | // address adjusted. We need to do this because when we load a file | ||||||||
1683 | // from memory, its addresses will be slid already, yet the addresses | ||||||||
1684 | // in the new symbol file will still be unslid. Since everything is | ||||||||
1685 | // stored as section offset, this shouldn't cause any problems. | ||||||||
1686 | |||||||||
1687 | // Make sure we've parsed the symbol table from the ObjectFile before | ||||||||
1688 | // we go around changing its Sections. | ||||||||
1689 | module_sp->GetObjectFile()->GetSymtab(); | ||||||||
1690 | // eh_frame would present the same problems but we parse that on a per- | ||||||||
1691 | // function basis as-needed so it's more difficult to remove its use of | ||||||||
1692 | // the Sections. Realistically, the environments where this code path | ||||||||
1693 | // will be taken will not have eh_frame sections. | ||||||||
1694 | |||||||||
1695 | unified_section_sp->SetFileAddress(load_cmd.vmaddr); | ||||||||
1696 | |||||||||
1697 | // Notify the module that the section addresses have been changed once | ||||||||
1698 | // we're done so any file-address caches can be updated. | ||||||||
1699 | context.FileAddressesChanged = true; | ||||||||
1700 | } | ||||||||
1701 | } | ||||||||
1702 | m_sections_up->AddSection(unified_section_sp); | ||||||||
1703 | } | ||||||||
1704 | |||||||||
1705 | llvm::MachO::section_64 sect64; | ||||||||
1706 | ::memset(§64, 0, sizeof(sect64)); | ||||||||
1707 | // Push a section into our mach sections for the section at index zero | ||||||||
1708 | // (NO_SECT) if we don't have any mach sections yet... | ||||||||
1709 | if (m_mach_sections.empty()) | ||||||||
1710 | m_mach_sections.push_back(sect64); | ||||||||
1711 | uint32_t segment_sect_idx; | ||||||||
1712 | const lldb::user_id_t first_segment_sectID = context.NextSectionIdx + 1; | ||||||||
1713 | |||||||||
1714 | const uint32_t num_u32s = load_cmd.cmd == LC_SEGMENT ? 7 : 8; | ||||||||
1715 | for (segment_sect_idx = 0; segment_sect_idx < load_cmd.nsects; | ||||||||
1716 | ++segment_sect_idx) { | ||||||||
1717 | if (m_data.GetU8(&offset, (uint8_t *)sect64.sectname, | ||||||||
1718 | sizeof(sect64.sectname)) == nullptr) | ||||||||
1719 | break; | ||||||||
1720 | if (m_data.GetU8(&offset, (uint8_t *)sect64.segname, | ||||||||
1721 | sizeof(sect64.segname)) == nullptr) | ||||||||
1722 | break; | ||||||||
1723 | sect64.addr = m_data.GetAddress(&offset); | ||||||||
1724 | sect64.size = m_data.GetAddress(&offset); | ||||||||
1725 | |||||||||
1726 | if (m_data.GetU32(&offset, §64.offset, num_u32s) == nullptr) | ||||||||
1727 | break; | ||||||||
1728 | |||||||||
1729 | if ((m_header.flags & MH_DYLIB_IN_CACHE) && !IsInMemory()) { | ||||||||
1730 | sect64.offset = sect64.addr - m_text_address; | ||||||||
1731 | } | ||||||||
1732 | |||||||||
1733 | // Keep a list of mach sections around in case we need to get at data that | ||||||||
1734 | // isn't stored in the abstracted Sections. | ||||||||
1735 | m_mach_sections.push_back(sect64); | ||||||||
1736 | |||||||||
1737 | if (add_section) { | ||||||||
1738 | ConstString section_name( | ||||||||
1739 | sect64.sectname, strnlen(sect64.sectname, sizeof(sect64.sectname))); | ||||||||
1740 | if (!const_segname) { | ||||||||
1741 | // We have a segment with no name so we need to conjure up segments | ||||||||
1742 | // that correspond to the section's segname if there isn't already such | ||||||||
1743 | // a section. If there is such a section, we resize the section so that | ||||||||
1744 | // it spans all sections. We also mark these sections as fake so | ||||||||
1745 | // address matches don't hit if they land in the gaps between the child | ||||||||
1746 | // sections. | ||||||||
1747 | const_segname.SetTrimmedCStringWithLength(sect64.segname, | ||||||||
1748 | sizeof(sect64.segname)); | ||||||||
1749 | segment_sp = context.UnifiedList.FindSectionByName(const_segname); | ||||||||
1750 | if (segment_sp.get()) { | ||||||||
1751 | Section *segment = segment_sp.get(); | ||||||||
1752 | // Grow the section size as needed. | ||||||||
1753 | const lldb::addr_t sect64_min_addr = sect64.addr; | ||||||||
1754 | const lldb::addr_t sect64_max_addr = sect64_min_addr + sect64.size; | ||||||||
1755 | const lldb::addr_t curr_seg_byte_size = segment->GetByteSize(); | ||||||||
1756 | const lldb::addr_t curr_seg_min_addr = segment->GetFileAddress(); | ||||||||
1757 | const lldb::addr_t curr_seg_max_addr = | ||||||||
1758 | curr_seg_min_addr + curr_seg_byte_size; | ||||||||
1759 | if (sect64_min_addr >= curr_seg_min_addr) { | ||||||||
1760 | const lldb::addr_t new_seg_byte_size = | ||||||||
1761 | sect64_max_addr - curr_seg_min_addr; | ||||||||
1762 | // Only grow the section size if needed | ||||||||
1763 | if (new_seg_byte_size > curr_seg_byte_size) | ||||||||
1764 | segment->SetByteSize(new_seg_byte_size); | ||||||||
1765 | } else { | ||||||||
1766 | // We need to change the base address of the segment and adjust the | ||||||||
1767 | // child section offsets for all existing children. | ||||||||
1768 | const lldb::addr_t slide_amount = | ||||||||
1769 | sect64_min_addr - curr_seg_min_addr; | ||||||||
1770 | segment->Slide(slide_amount, false); | ||||||||
1771 | segment->GetChildren().Slide(-slide_amount, false); | ||||||||
1772 | segment->SetByteSize(curr_seg_max_addr - sect64_min_addr); | ||||||||
1773 | } | ||||||||
1774 | |||||||||
1775 | // Grow the section size as needed. | ||||||||
1776 | if (sect64.offset) { | ||||||||
1777 | const lldb::addr_t segment_min_file_offset = | ||||||||
1778 | segment->GetFileOffset(); | ||||||||
1779 | const lldb::addr_t segment_max_file_offset = | ||||||||
1780 | segment_min_file_offset + segment->GetFileSize(); | ||||||||
1781 | |||||||||
1782 | const lldb::addr_t section_min_file_offset = sect64.offset; | ||||||||
1783 | const lldb::addr_t section_max_file_offset = | ||||||||
1784 | section_min_file_offset + sect64.size; | ||||||||
1785 | const lldb::addr_t new_file_offset = | ||||||||
1786 | std::min(section_min_file_offset, segment_min_file_offset); | ||||||||
1787 | const lldb::addr_t new_file_size = | ||||||||
1788 | std::max(section_max_file_offset, segment_max_file_offset) - | ||||||||
1789 | new_file_offset; | ||||||||
1790 | segment->SetFileOffset(new_file_offset); | ||||||||
1791 | segment->SetFileSize(new_file_size); | ||||||||
1792 | } | ||||||||
1793 | } else { | ||||||||
1794 | // Create a fake section for the section's named segment | ||||||||
1795 | segment_sp = std::make_shared<Section>( | ||||||||
1796 | segment_sp, // Parent section | ||||||||
1797 | module_sp, // Module to which this section belongs | ||||||||
1798 | this, // Object file to which this section belongs | ||||||||
1799 | ++context.NextSegmentIdx | ||||||||
1800 | << 8, // Section ID is the 1 based segment index | ||||||||
1801 | // shifted right by 8 bits as not to | ||||||||
1802 | // collide with any of the 256 section IDs | ||||||||
1803 | // that are possible | ||||||||
1804 | const_segname, // Name of this section | ||||||||
1805 | eSectionTypeContainer, // This section is a container of | ||||||||
1806 | // other sections. | ||||||||
1807 | sect64.addr, // File VM address == addresses as they are | ||||||||
1808 | // found in the object file | ||||||||
1809 | sect64.size, // VM size in bytes of this section | ||||||||
1810 | sect64.offset, // Offset to the data for this section in | ||||||||
1811 | // the file | ||||||||
1812 | sect64.offset ? sect64.size : 0, // Size in bytes of | ||||||||
1813 | // this section as | ||||||||
1814 | // found in the file | ||||||||
1815 | sect64.align, | ||||||||
1816 | load_cmd.flags); // Flags for this section | ||||||||
1817 | segment_sp->SetIsFake(true); | ||||||||
1818 | segment_sp->SetPermissions(segment_permissions); | ||||||||
1819 | m_sections_up->AddSection(segment_sp); | ||||||||
1820 | if (add_to_unified) | ||||||||
1821 | context.UnifiedList.AddSection(segment_sp); | ||||||||
1822 | segment_sp->SetIsEncrypted(segment_is_encrypted); | ||||||||
1823 | } | ||||||||
1824 | } | ||||||||
1825 | assert(segment_sp.get())((void)0); | ||||||||
1826 | |||||||||
1827 | lldb::SectionType sect_type = GetSectionType(sect64.flags, section_name); | ||||||||
1828 | |||||||||
1829 | SectionSP section_sp(new Section( | ||||||||
1830 | segment_sp, module_sp, this, ++context.NextSectionIdx, section_name, | ||||||||
1831 | sect_type, sect64.addr - segment_sp->GetFileAddress(), sect64.size, | ||||||||
1832 | sect64.offset, sect64.offset == 0 ? 0 : sect64.size, sect64.align, | ||||||||
1833 | sect64.flags)); | ||||||||
1834 | // Set the section to be encrypted to match the segment | ||||||||
1835 | |||||||||
1836 | bool section_is_encrypted = false; | ||||||||
1837 | if (!segment_is_encrypted && load_cmd.filesize != 0) | ||||||||
1838 | section_is_encrypted = context.EncryptedRanges.FindEntryThatContains( | ||||||||
1839 | sect64.offset) != nullptr; | ||||||||
1840 | |||||||||
1841 | section_sp->SetIsEncrypted(segment_is_encrypted || section_is_encrypted); | ||||||||
1842 | section_sp->SetPermissions(segment_permissions); | ||||||||
1843 | segment_sp->GetChildren().AddSection(section_sp); | ||||||||
1844 | |||||||||
1845 | if (segment_sp->IsFake()) { | ||||||||
1846 | segment_sp.reset(); | ||||||||
1847 | const_segname.Clear(); | ||||||||
1848 | } | ||||||||
1849 | } | ||||||||
1850 | } | ||||||||
1851 | if (segment_sp && is_dsym) { | ||||||||
1852 | if (first_segment_sectID <= context.NextSectionIdx) { | ||||||||
1853 | lldb::user_id_t sect_uid; | ||||||||
1854 | for (sect_uid = first_segment_sectID; sect_uid <= context.NextSectionIdx; | ||||||||
1855 | ++sect_uid) { | ||||||||
1856 | SectionSP curr_section_sp( | ||||||||
1857 | segment_sp->GetChildren().FindSectionByID(sect_uid)); | ||||||||
1858 | SectionSP next_section_sp; | ||||||||
1859 | if (sect_uid + 1 <= context.NextSectionIdx) | ||||||||
1860 | next_section_sp = | ||||||||
1861 | segment_sp->GetChildren().FindSectionByID(sect_uid + 1); | ||||||||
1862 | |||||||||
1863 | if (curr_section_sp.get()) { | ||||||||
1864 | if (curr_section_sp->GetByteSize() == 0) { | ||||||||
1865 | if (next_section_sp.get() != nullptr) | ||||||||
1866 | curr_section_sp->SetByteSize(next_section_sp->GetFileAddress() - | ||||||||
1867 | curr_section_sp->GetFileAddress()); | ||||||||
1868 | else | ||||||||
1869 | curr_section_sp->SetByteSize(load_cmd.vmsize); | ||||||||
1870 | } | ||||||||
1871 | } | ||||||||
1872 | } | ||||||||
1873 | } | ||||||||
1874 | } | ||||||||
1875 | } | ||||||||
1876 | |||||||||
1877 | void ObjectFileMachO::ProcessDysymtabCommand( | ||||||||
1878 | const llvm::MachO::load_command &load_cmd, lldb::offset_t offset) { | ||||||||
1879 | m_dysymtab.cmd = load_cmd.cmd; | ||||||||
1880 | m_dysymtab.cmdsize = load_cmd.cmdsize; | ||||||||
1881 | m_data.GetU32(&offset, &m_dysymtab.ilocalsym, | ||||||||
1882 | (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2); | ||||||||
1883 | } | ||||||||
1884 | |||||||||
1885 | void ObjectFileMachO::CreateSections(SectionList &unified_section_list) { | ||||||||
1886 | if (m_sections_up) | ||||||||
1887 | return; | ||||||||
1888 | |||||||||
1889 | m_sections_up = std::make_unique<SectionList>(); | ||||||||
1890 | |||||||||
1891 | lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); | ||||||||
1892 | // bool dump_sections = false; | ||||||||
1893 | ModuleSP module_sp(GetModule()); | ||||||||
1894 | |||||||||
1895 | offset = MachHeaderSizeFromMagic(m_header.magic); | ||||||||
1896 | |||||||||
1897 | SegmentParsingContext context(GetEncryptedFileRanges(), unified_section_list); | ||||||||
1898 | llvm::MachO::load_command load_cmd; | ||||||||
1899 | for (uint32_t i = 0; i < m_header.ncmds; ++i) { | ||||||||
1900 | const lldb::offset_t load_cmd_offset = offset; | ||||||||
1901 | if (m_data.GetU32(&offset, &load_cmd, 2) == nullptr) | ||||||||
1902 | break; | ||||||||
1903 | |||||||||
1904 | if (load_cmd.cmd == LC_SEGMENT || load_cmd.cmd == LC_SEGMENT_64) | ||||||||
1905 | ProcessSegmentCommand(load_cmd, offset, i, context); | ||||||||
1906 | else if (load_cmd.cmd == LC_DYSYMTAB) | ||||||||
1907 | ProcessDysymtabCommand(load_cmd, offset); | ||||||||
1908 | |||||||||
1909 | offset = load_cmd_offset + load_cmd.cmdsize; | ||||||||
1910 | } | ||||||||
1911 | |||||||||
1912 | if (context.FileAddressesChanged && module_sp) | ||||||||
1913 | module_sp->SectionFileAddressesChanged(); | ||||||||
1914 | } | ||||||||
1915 | |||||||||
1916 | class MachSymtabSectionInfo { | ||||||||
1917 | public: | ||||||||
1918 | MachSymtabSectionInfo(SectionList *section_list) | ||||||||
1919 | : m_section_list(section_list), m_section_infos() { | ||||||||
1920 | // Get the number of sections down to a depth of 1 to include all segments | ||||||||
1921 | // and their sections, but no other sections that may be added for debug | ||||||||
1922 | // map or | ||||||||
1923 | m_section_infos.resize(section_list->GetNumSections(1)); | ||||||||
1924 | } | ||||||||
1925 | |||||||||
1926 | SectionSP GetSection(uint8_t n_sect, addr_t file_addr) { | ||||||||
1927 | if (n_sect == 0) | ||||||||
1928 | return SectionSP(); | ||||||||
1929 | if (n_sect < m_section_infos.size()) { | ||||||||
1930 | if (!m_section_infos[n_sect].section_sp) { | ||||||||
1931 | SectionSP section_sp(m_section_list->FindSectionByID(n_sect)); | ||||||||
1932 | m_section_infos[n_sect].section_sp = section_sp; | ||||||||
1933 | if (section_sp) { | ||||||||
1934 | m_section_infos[n_sect].vm_range.SetBaseAddress( | ||||||||
1935 | section_sp->GetFileAddress()); | ||||||||
1936 | m_section_infos[n_sect].vm_range.SetByteSize( | ||||||||
1937 | section_sp->GetByteSize()); | ||||||||
1938 | } else { | ||||||||
1939 | std::string filename = "<unknown>"; | ||||||||
1940 | SectionSP first_section_sp(m_section_list->GetSectionAtIndex(0)); | ||||||||
1941 | if (first_section_sp) | ||||||||
1942 | filename = first_section_sp->GetObjectFile()->GetFileSpec().GetPath(); | ||||||||
1943 | |||||||||
1944 | Host::SystemLog(Host::eSystemLogError, | ||||||||
1945 | "error: unable to find section %d for a symbol in " | ||||||||
1946 | "%s, corrupt file?\n", | ||||||||
1947 | n_sect, filename.c_str()); | ||||||||
1948 | } | ||||||||
1949 | } | ||||||||
1950 | if (m_section_infos[n_sect].vm_range.Contains(file_addr)) { | ||||||||
1951 | // Symbol is in section. | ||||||||
1952 | return m_section_infos[n_sect].section_sp; | ||||||||
1953 | } else if (m_section_infos[n_sect].vm_range.GetByteSize() == 0 && | ||||||||
1954 | m_section_infos[n_sect].vm_range.GetBaseAddress() == | ||||||||
1955 | file_addr) { | ||||||||
1956 | // Symbol is in section with zero size, but has the same start address | ||||||||
1957 | // as the section. This can happen with linker symbols (symbols that | ||||||||
1958 | // start with the letter 'l' or 'L'. | ||||||||
1959 | return m_section_infos[n_sect].section_sp; | ||||||||
1960 | } | ||||||||
1961 | } | ||||||||
1962 | return m_section_list->FindSectionContainingFileAddress(file_addr); | ||||||||
1963 | } | ||||||||
1964 | |||||||||
1965 | protected: | ||||||||
1966 | struct SectionInfo { | ||||||||
1967 | SectionInfo() : vm_range(), section_sp() {} | ||||||||
1968 | |||||||||
1969 | VMRange vm_range; | ||||||||
1970 | SectionSP section_sp; | ||||||||
1971 | }; | ||||||||
1972 | SectionList *m_section_list; | ||||||||
1973 | std::vector<SectionInfo> m_section_infos; | ||||||||
1974 | }; | ||||||||
1975 | |||||||||
1976 | #define TRIE_SYMBOL_IS_THUMB(1ULL << 63) (1ULL << 63) | ||||||||
1977 | struct TrieEntry { | ||||||||
1978 | void Dump() const { | ||||||||
1979 | printf("0x%16.16llx 0x%16.16llx 0x%16.16llx \"%s\"", | ||||||||
1980 | static_cast<unsigned long long>(address), | ||||||||
1981 | static_cast<unsigned long long>(flags), | ||||||||
1982 | static_cast<unsigned long long>(other), name.GetCString()); | ||||||||
1983 | if (import_name) | ||||||||
1984 | printf(" -> \"%s\"\n", import_name.GetCString()); | ||||||||
1985 | else | ||||||||
1986 | printf("\n"); | ||||||||
1987 | } | ||||||||
1988 | ConstString name; | ||||||||
1989 | uint64_t address = LLDB_INVALID_ADDRESS0xffffffffffffffffULL; | ||||||||
1990 | uint64_t flags = | ||||||||
1991 | 0; // EXPORT_SYMBOL_FLAGS_REEXPORT, EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER, | ||||||||
1992 | // TRIE_SYMBOL_IS_THUMB | ||||||||
1993 | uint64_t other = 0; | ||||||||
1994 | ConstString import_name; | ||||||||
1995 | }; | ||||||||
1996 | |||||||||
1997 | struct TrieEntryWithOffset { | ||||||||
1998 | lldb::offset_t nodeOffset; | ||||||||
1999 | TrieEntry entry; | ||||||||
2000 | |||||||||
2001 | TrieEntryWithOffset(lldb::offset_t offset) : nodeOffset(offset), entry() {} | ||||||||
2002 | |||||||||
2003 | void Dump(uint32_t idx) const { | ||||||||
2004 | printf("[%3u] 0x%16.16llx: ", idx, | ||||||||
2005 | static_cast<unsigned long long>(nodeOffset)); | ||||||||
2006 | entry.Dump(); | ||||||||
2007 | } | ||||||||
2008 | |||||||||
2009 | bool operator<(const TrieEntryWithOffset &other) const { | ||||||||
2010 | return (nodeOffset < other.nodeOffset); | ||||||||
2011 | } | ||||||||
2012 | }; | ||||||||
2013 | |||||||||
2014 | static bool ParseTrieEntries(DataExtractor &data, lldb::offset_t offset, | ||||||||
2015 | const bool is_arm, addr_t text_seg_base_addr, | ||||||||
2016 | std::vector<llvm::StringRef> &nameSlices, | ||||||||
2017 | std::set<lldb::addr_t> &resolver_addresses, | ||||||||
2018 | std::vector<TrieEntryWithOffset> &reexports, | ||||||||
2019 | std::vector<TrieEntryWithOffset> &ext_symbols) { | ||||||||
2020 | if (!data.ValidOffset(offset)) | ||||||||
2021 | return true; | ||||||||
2022 | |||||||||
2023 | // Terminal node -- end of a branch, possibly add this to | ||||||||
2024 | // the symbol table or resolver table. | ||||||||
2025 | const uint64_t terminalSize = data.GetULEB128(&offset); | ||||||||
2026 | lldb::offset_t children_offset = offset + terminalSize; | ||||||||
2027 | if (terminalSize != 0) { | ||||||||
2028 | TrieEntryWithOffset e(offset); | ||||||||
2029 | e.entry.flags = data.GetULEB128(&offset); | ||||||||
2030 | const char *import_name = nullptr; | ||||||||
2031 | if (e.entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT) { | ||||||||
2032 | e.entry.address = 0; | ||||||||
2033 | e.entry.other = data.GetULEB128(&offset); // dylib ordinal | ||||||||
2034 | import_name = data.GetCStr(&offset); | ||||||||
2035 | } else { | ||||||||
2036 | e.entry.address = data.GetULEB128(&offset); | ||||||||
2037 | if (text_seg_base_addr != LLDB_INVALID_ADDRESS0xffffffffffffffffULL) | ||||||||
2038 | e.entry.address += text_seg_base_addr; | ||||||||
2039 | if (e.entry.flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) { | ||||||||
2040 | e.entry.other = data.GetULEB128(&offset); | ||||||||
2041 | uint64_t resolver_addr = e.entry.other; | ||||||||
2042 | if (text_seg_base_addr != LLDB_INVALID_ADDRESS0xffffffffffffffffULL) | ||||||||
2043 | resolver_addr += text_seg_base_addr; | ||||||||
2044 | if (is_arm) | ||||||||
2045 | resolver_addr &= THUMB_ADDRESS_BIT_MASK0xfffffffffffffffeull; | ||||||||
2046 | resolver_addresses.insert(resolver_addr); | ||||||||
2047 | } else | ||||||||
2048 | e.entry.other = 0; | ||||||||
2049 | } | ||||||||
2050 | bool add_this_entry = false; | ||||||||
2051 | if (Flags(e.entry.flags).Test(EXPORT_SYMBOL_FLAGS_REEXPORT) && | ||||||||
2052 | import_name && import_name[0]) { | ||||||||
2053 | // add symbols that are reexport symbols with a valid import name. | ||||||||
2054 | add_this_entry = true; | ||||||||
2055 | } else if (e.entry.flags == 0 && | ||||||||
2056 | (import_name == nullptr || import_name[0] == '\0')) { | ||||||||
2057 | // add externally visible symbols, in case the nlist record has | ||||||||
2058 | // been stripped/omitted. | ||||||||
2059 | add_this_entry = true; | ||||||||
2060 | } | ||||||||
2061 | if (add_this_entry) { | ||||||||
2062 | std::string name; | ||||||||
2063 | if (!nameSlices.empty()) { | ||||||||
2064 | for (auto name_slice : nameSlices) | ||||||||
2065 | name.append(name_slice.data(), name_slice.size()); | ||||||||
2066 | } | ||||||||
2067 | if (name.size() > 1) { | ||||||||
2068 | // Skip the leading '_' | ||||||||
2069 | e.entry.name.SetCStringWithLength(name.c_str() + 1, name.size() - 1); | ||||||||
2070 | } | ||||||||
2071 | if (import_name) { | ||||||||
2072 | // Skip the leading '_' | ||||||||
2073 | e.entry.import_name.SetCString(import_name + 1); | ||||||||
2074 | } | ||||||||
2075 | if (Flags(e.entry.flags).Test(EXPORT_SYMBOL_FLAGS_REEXPORT)) { | ||||||||
2076 | reexports.push_back(e); | ||||||||
2077 | } else { | ||||||||
2078 | if (is_arm && (e.entry.address & 1)) { | ||||||||
2079 | e.entry.flags |= TRIE_SYMBOL_IS_THUMB(1ULL << 63); | ||||||||
2080 | e.entry.address &= THUMB_ADDRESS_BIT_MASK0xfffffffffffffffeull; | ||||||||
2081 | } | ||||||||
2082 | ext_symbols.push_back(e); | ||||||||
2083 | } | ||||||||
2084 | } | ||||||||
2085 | } | ||||||||
2086 | |||||||||
2087 | const uint8_t childrenCount = data.GetU8(&children_offset); | ||||||||
2088 | for (uint8_t i = 0; i < childrenCount; ++i) { | ||||||||
2089 | const char *cstr = data.GetCStr(&children_offset); | ||||||||
2090 | if (cstr) | ||||||||
2091 | nameSlices.push_back(llvm::StringRef(cstr)); | ||||||||
2092 | else | ||||||||
2093 | return false; // Corrupt data | ||||||||
2094 | lldb::offset_t childNodeOffset = data.GetULEB128(&children_offset); | ||||||||
2095 | if (childNodeOffset) { | ||||||||
2096 | if (!ParseTrieEntries(data, childNodeOffset, is_arm, text_seg_base_addr, | ||||||||
2097 | nameSlices, resolver_addresses, reexports, | ||||||||
2098 | ext_symbols)) { | ||||||||
2099 | return false; | ||||||||
2100 | } | ||||||||
2101 | } | ||||||||
2102 | nameSlices.pop_back(); | ||||||||
2103 | } | ||||||||
2104 | return true; | ||||||||
2105 | } | ||||||||
2106 | |||||||||
2107 | static SymbolType GetSymbolType(const char *&symbol_name, | ||||||||
2108 | bool &demangled_is_synthesized, | ||||||||
2109 | const SectionSP &text_section_sp, | ||||||||
2110 | const SectionSP &data_section_sp, | ||||||||
2111 | const SectionSP &data_dirty_section_sp, | ||||||||
2112 | const SectionSP &data_const_section_sp, | ||||||||
2113 | const SectionSP &symbol_section) { | ||||||||
2114 | SymbolType type = eSymbolTypeInvalid; | ||||||||
2115 | |||||||||
2116 | const char *symbol_sect_name = symbol_section->GetName().AsCString(); | ||||||||
2117 | if (symbol_section->IsDescendant(text_section_sp.get())) { | ||||||||
2118 | if (symbol_section->IsClear(S_ATTR_PURE_INSTRUCTIONS | | ||||||||
2119 | S_ATTR_SELF_MODIFYING_CODE | | ||||||||
2120 | S_ATTR_SOME_INSTRUCTIONS)) | ||||||||
2121 | type = eSymbolTypeData; | ||||||||
2122 | else | ||||||||
2123 | type = eSymbolTypeCode; | ||||||||
2124 | } else if (symbol_section->IsDescendant(data_section_sp.get()) || | ||||||||
2125 | symbol_section->IsDescendant(data_dirty_section_sp.get()) || | ||||||||
2126 | symbol_section->IsDescendant(data_const_section_sp.get())) { | ||||||||
2127 | if (symbol_sect_name && | ||||||||
2128 | ::strstr(symbol_sect_name, "__objc") == symbol_sect_name) { | ||||||||
2129 | type = eSymbolTypeRuntime; | ||||||||
2130 | |||||||||
2131 | if (symbol_name) { | ||||||||
2132 | llvm::StringRef symbol_name_ref(symbol_name); | ||||||||
2133 | if (symbol_name_ref.startswith("OBJC_")) { | ||||||||
2134 | static const llvm::StringRef g_objc_v2_prefix_class("OBJC_CLASS_$_"); | ||||||||
2135 | static const llvm::StringRef g_objc_v2_prefix_metaclass( | ||||||||
2136 | "OBJC_METACLASS_$_"); | ||||||||
2137 | static const llvm::StringRef g_objc_v2_prefix_ivar("OBJC_IVAR_$_"); | ||||||||
2138 | if (symbol_name_ref.startswith(g_objc_v2_prefix_class)) { | ||||||||
2139 | symbol_name = symbol_name + g_objc_v2_prefix_class.size(); | ||||||||
2140 | type = eSymbolTypeObjCClass; | ||||||||
2141 | demangled_is_synthesized = true; | ||||||||
2142 | } else if (symbol_name_ref.startswith(g_objc_v2_prefix_metaclass)) { | ||||||||
2143 | symbol_name = symbol_name + g_objc_v2_prefix_metaclass.size(); | ||||||||
2144 | type = eSymbolTypeObjCMetaClass; | ||||||||
2145 | demangled_is_synthesized = true; | ||||||||
2146 | } else if (symbol_name_ref.startswith(g_objc_v2_prefix_ivar)) { | ||||||||
2147 | symbol_name = symbol_name + g_objc_v2_prefix_ivar.size(); | ||||||||
2148 | type = eSymbolTypeObjCIVar; | ||||||||
2149 | demangled_is_synthesized = true; | ||||||||
2150 | } | ||||||||
2151 | } | ||||||||
2152 | } | ||||||||
2153 | } else if (symbol_sect_name && | ||||||||
2154 | ::strstr(symbol_sect_name, "__gcc_except_tab") == | ||||||||
2155 | symbol_sect_name) { | ||||||||
2156 | type = eSymbolTypeException; | ||||||||
2157 | } else { | ||||||||
2158 | type = eSymbolTypeData; | ||||||||
2159 | } | ||||||||
2160 | } else if (symbol_sect_name && | ||||||||
2161 | ::strstr(symbol_sect_name, "__IMPORT") == symbol_sect_name) { | ||||||||
2162 | type = eSymbolTypeTrampoline; | ||||||||
2163 | } | ||||||||
2164 | return type; | ||||||||
2165 | } | ||||||||
2166 | |||||||||
2167 | // Read the UUID out of a dyld_shared_cache file on-disk. | ||||||||
2168 | UUID ObjectFileMachO::GetSharedCacheUUID(FileSpec dyld_shared_cache, | ||||||||
2169 | const ByteOrder byte_order, | ||||||||
2170 | const uint32_t addr_byte_size) { | ||||||||
2171 | UUID dsc_uuid; | ||||||||
2172 | DataBufferSP DscData = MapFileData( | ||||||||
2173 | dyld_shared_cache, sizeof(struct lldb_copy_dyld_cache_header_v1), 0); | ||||||||
2174 | if (!DscData) | ||||||||
2175 | return dsc_uuid; | ||||||||
2176 | DataExtractor dsc_header_data(DscData, byte_order, addr_byte_size); | ||||||||
2177 | |||||||||
2178 | char version_str[7]; | ||||||||
2179 | lldb::offset_t offset = 0; | ||||||||
2180 | memcpy(version_str, dsc_header_data.GetData(&offset, 6), 6); | ||||||||
2181 | version_str[6] = '\0'; | ||||||||
2182 | if (strcmp(version_str, "dyld_v") == 0) { | ||||||||
2183 | offset = offsetof(struct lldb_copy_dyld_cache_header_v1, uuid)__builtin_offsetof(struct lldb_copy_dyld_cache_header_v1, uuid ); | ||||||||
2184 | dsc_uuid = UUID::fromOptionalData( | ||||||||
2185 | dsc_header_data.GetData(&offset, sizeof(uuid_t)), sizeof(uuid_t)); | ||||||||
2186 | } | ||||||||
2187 | Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS(1u << 20))); | ||||||||
2188 | if (log && dsc_uuid.IsValid()) { | ||||||||
2189 | LLDB_LOGF(log, "Shared cache %s has UUID %s",do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("Shared cache %s has UUID %s", dyld_shared_cache .GetPath().c_str(), dsc_uuid.GetAsString().c_str()); } while ( 0) | ||||||||
2190 | dyld_shared_cache.GetPath().c_str(),do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("Shared cache %s has UUID %s", dyld_shared_cache .GetPath().c_str(), dsc_uuid.GetAsString().c_str()); } while ( 0) | ||||||||
2191 | dsc_uuid.GetAsString().c_str())do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("Shared cache %s has UUID %s", dyld_shared_cache .GetPath().c_str(), dsc_uuid.GetAsString().c_str()); } while ( 0); | ||||||||
2192 | } | ||||||||
2193 | return dsc_uuid; | ||||||||
2194 | } | ||||||||
2195 | |||||||||
2196 | static llvm::Optional<struct nlist_64> | ||||||||
2197 | ParseNList(DataExtractor &nlist_data, lldb::offset_t &nlist_data_offset, | ||||||||
2198 | size_t nlist_byte_size) { | ||||||||
2199 | struct nlist_64 nlist; | ||||||||
2200 | if (!nlist_data.ValidOffsetForDataOfSize(nlist_data_offset, nlist_byte_size)) | ||||||||
2201 | return {}; | ||||||||
2202 | nlist.n_strx = nlist_data.GetU32_unchecked(&nlist_data_offset); | ||||||||
2203 | nlist.n_type = nlist_data.GetU8_unchecked(&nlist_data_offset); | ||||||||
2204 | nlist.n_sect = nlist_data.GetU8_unchecked(&nlist_data_offset); | ||||||||
2205 | nlist.n_desc = nlist_data.GetU16_unchecked(&nlist_data_offset); | ||||||||
2206 | nlist.n_value = nlist_data.GetAddress_unchecked(&nlist_data_offset); | ||||||||
2207 | return nlist; | ||||||||
2208 | } | ||||||||
2209 | |||||||||
2210 | enum { DebugSymbols = true, NonDebugSymbols = false }; | ||||||||
2211 | |||||||||
2212 | size_t ObjectFileMachO::ParseSymtab() { | ||||||||
2213 | LLDB_SCOPED_TIMERF("ObjectFileMachO::ParseSymtab () module = %s",static ::lldb_private::Timer::Category _cat(__PRETTY_FUNCTION__ ); ::lldb_private::Timer _scoped_timer(_cat, "ObjectFileMachO::ParseSymtab () module = %s" , m_file.GetFilename().AsCString("")); do { } while (0); auto _scoped_signpost = llvm::make_scope_exit([&_scoped_timer ]() { ::lldb_private::GetSignposts().endInterval(&_scoped_timer ); }) | ||||||||
| |||||||||
2214 | m_file.GetFilename().AsCString(""))static ::lldb_private::Timer::Category _cat(__PRETTY_FUNCTION__ ); ::lldb_private::Timer _scoped_timer(_cat, "ObjectFileMachO::ParseSymtab () module = %s" , m_file.GetFilename().AsCString("")); do { } while (0); auto _scoped_signpost = llvm::make_scope_exit([&_scoped_timer ]() { ::lldb_private::GetSignposts().endInterval(&_scoped_timer ); }); | ||||||||
2215 | ModuleSP module_sp(GetModule()); | ||||||||
2216 | if (!module_sp) | ||||||||
2217 | return 0; | ||||||||
2218 | |||||||||
2219 | Progress progress(llvm::formatv("Parsing symbol table for {0}", | ||||||||
2220 | m_file.GetFilename().AsCString("<Unknown>"))); | ||||||||
2221 | |||||||||
2222 | llvm::MachO::symtab_command symtab_load_command = {0, 0, 0, 0, 0, 0}; | ||||||||
2223 | llvm::MachO::linkedit_data_command function_starts_load_command = {0, 0, 0, 0}; | ||||||||
2224 | llvm::MachO::dyld_info_command dyld_info = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | ||||||||
2225 | // The data element of type bool indicates that this entry is thumb | ||||||||
2226 | // code. | ||||||||
2227 | typedef AddressDataArray<lldb::addr_t, bool, 100> FunctionStarts; | ||||||||
2228 | |||||||||
2229 | // Record the address of every function/data that we add to the symtab. | ||||||||
2230 | // We add symbols to the table in the order of most information (nlist | ||||||||
2231 | // records) to least (function starts), and avoid duplicating symbols | ||||||||
2232 | // via this set. | ||||||||
2233 | llvm::DenseSet<addr_t> symbols_added; | ||||||||
2234 | |||||||||
2235 | // We are using a llvm::DenseSet for "symbols_added" so we must be sure we | ||||||||
2236 | // do not add the tombstone or empty keys to the set. | ||||||||
2237 | auto add_symbol_addr = [&symbols_added](lldb::addr_t file_addr) { | ||||||||
2238 | // Don't add the tombstone or empty keys. | ||||||||
2239 | if (file_addr == UINT64_MAX0xffffffffffffffffULL || file_addr == UINT64_MAX0xffffffffffffffffULL - 1) | ||||||||
2240 | return; | ||||||||
2241 | symbols_added.insert(file_addr); | ||||||||
2242 | }; | ||||||||
2243 | FunctionStarts function_starts; | ||||||||
2244 | lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); | ||||||||
2245 | uint32_t i; | ||||||||
2246 | FileSpecList dylib_files; | ||||||||
2247 | Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS(1u << 20))); | ||||||||
2248 | llvm::StringRef g_objc_v2_prefix_class("_OBJC_CLASS_$_"); | ||||||||
2249 | llvm::StringRef g_objc_v2_prefix_metaclass("_OBJC_METACLASS_$_"); | ||||||||
2250 | llvm::StringRef g_objc_v2_prefix_ivar("_OBJC_IVAR_$_"); | ||||||||
2251 | |||||||||
2252 | for (i = 0; i < m_header.ncmds; ++i) { | ||||||||
2253 | const lldb::offset_t cmd_offset = offset; | ||||||||
2254 | // Read in the load command and load command size | ||||||||
2255 | llvm::MachO::load_command lc; | ||||||||
2256 | if (m_data.GetU32(&offset, &lc, 2) == nullptr) | ||||||||
2257 | break; | ||||||||
2258 | // Watch for the symbol table load command | ||||||||
2259 | switch (lc.cmd) { | ||||||||
2260 | case LC_SYMTAB: | ||||||||
2261 | symtab_load_command.cmd = lc.cmd; | ||||||||
2262 | symtab_load_command.cmdsize = lc.cmdsize; | ||||||||
2263 | // Read in the rest of the symtab load command | ||||||||
2264 | if (m_data.GetU32(&offset, &symtab_load_command.symoff, 4) == | ||||||||
2265 | nullptr) // fill in symoff, nsyms, stroff, strsize fields | ||||||||
2266 | return 0; | ||||||||
2267 | break; | ||||||||
2268 | |||||||||
2269 | case LC_DYLD_INFO: | ||||||||
2270 | case LC_DYLD_INFO_ONLY: | ||||||||
2271 | if (m_data.GetU32(&offset, &dyld_info.rebase_off, 10)) { | ||||||||
2272 | dyld_info.cmd = lc.cmd; | ||||||||
2273 | dyld_info.cmdsize = lc.cmdsize; | ||||||||
2274 | } else { | ||||||||
2275 | memset(&dyld_info, 0, sizeof(dyld_info)); | ||||||||
2276 | } | ||||||||
2277 | break; | ||||||||
2278 | |||||||||
2279 | case LC_LOAD_DYLIB: | ||||||||
2280 | case LC_LOAD_WEAK_DYLIB: | ||||||||
2281 | case LC_REEXPORT_DYLIB: | ||||||||
2282 | case LC_LOADFVMLIB: | ||||||||
2283 | case LC_LOAD_UPWARD_DYLIB: { | ||||||||
2284 | uint32_t name_offset = cmd_offset + m_data.GetU32(&offset); | ||||||||
2285 | const char *path = m_data.PeekCStr(name_offset); | ||||||||
2286 | if (path) { | ||||||||
2287 | FileSpec file_spec(path); | ||||||||
2288 | // Strip the path if there is @rpath, @executable, etc so we just use | ||||||||
2289 | // the basename | ||||||||
2290 | if (path[0] == '@') | ||||||||
2291 | file_spec.GetDirectory().Clear(); | ||||||||
2292 | |||||||||
2293 | if (lc.cmd == LC_REEXPORT_DYLIB) { | ||||||||
2294 | m_reexported_dylibs.AppendIfUnique(file_spec); | ||||||||
2295 | } | ||||||||
2296 | |||||||||
2297 | dylib_files.Append(file_spec); | ||||||||
2298 | } | ||||||||
2299 | } break; | ||||||||
2300 | |||||||||
2301 | case LC_FUNCTION_STARTS: | ||||||||
2302 | function_starts_load_command.cmd = lc.cmd; | ||||||||
2303 | function_starts_load_command.cmdsize = lc.cmdsize; | ||||||||
2304 | if (m_data.GetU32(&offset, &function_starts_load_command.dataoff, 2) == | ||||||||
2305 | nullptr) // fill in symoff, nsyms, stroff, strsize fields | ||||||||
2306 | memset(&function_starts_load_command, 0, | ||||||||
2307 | sizeof(function_starts_load_command)); | ||||||||
2308 | break; | ||||||||
2309 | |||||||||
2310 | default: | ||||||||
2311 | break; | ||||||||
2312 | } | ||||||||
2313 | offset = cmd_offset + lc.cmdsize; | ||||||||
2314 | } | ||||||||
2315 | |||||||||
2316 | if (!symtab_load_command.cmd) | ||||||||
2317 | return 0; | ||||||||
2318 | |||||||||
2319 | Symtab *symtab = m_symtab_up.get(); | ||||||||
2320 | SectionList *section_list = GetSectionList(); | ||||||||
2321 | if (section_list == nullptr) | ||||||||
2322 | return 0; | ||||||||
2323 | |||||||||
2324 | const uint32_t addr_byte_size = m_data.GetAddressByteSize(); | ||||||||
2325 | const ByteOrder byte_order = m_data.GetByteOrder(); | ||||||||
2326 | bool bit_width_32 = addr_byte_size == 4; | ||||||||
2327 | const size_t nlist_byte_size = | ||||||||
2328 | bit_width_32
| ||||||||
2329 | |||||||||
2330 | DataExtractor nlist_data(nullptr, 0, byte_order, addr_byte_size); | ||||||||
2331 | DataExtractor strtab_data(nullptr, 0, byte_order, addr_byte_size); | ||||||||
2332 | DataExtractor function_starts_data(nullptr, 0, byte_order, addr_byte_size); | ||||||||
2333 | DataExtractor indirect_symbol_index_data(nullptr, 0, byte_order, | ||||||||
2334 | addr_byte_size); | ||||||||
2335 | DataExtractor dyld_trie_data(nullptr, 0, byte_order, addr_byte_size); | ||||||||
2336 | |||||||||
2337 | const addr_t nlist_data_byte_size = | ||||||||
2338 | symtab_load_command.nsyms * nlist_byte_size; | ||||||||
2339 | const addr_t strtab_data_byte_size = symtab_load_command.strsize; | ||||||||
2340 | addr_t strtab_addr = LLDB_INVALID_ADDRESS0xffffffffffffffffULL; | ||||||||
2341 | |||||||||
2342 | ProcessSP process_sp(m_process_wp.lock()); | ||||||||
2343 | Process *process = process_sp.get(); | ||||||||
2344 | |||||||||
2345 | uint32_t memory_module_load_level = eMemoryModuleLoadLevelComplete; | ||||||||
2346 | bool is_shared_cache_image = m_header.flags & MH_DYLIB_IN_CACHE; | ||||||||
2347 | bool is_local_shared_cache_image = is_shared_cache_image && !IsInMemory(); | ||||||||
2348 | SectionSP linkedit_section_sp( | ||||||||
2349 | section_list->FindSectionByName(GetSegmentNameLINKEDIT())); | ||||||||
2350 | |||||||||
2351 | if (process
| ||||||||
2352 | !is_local_shared_cache_image) { | ||||||||
2353 | Target &target = process->GetTarget(); | ||||||||
2354 | |||||||||
2355 | memory_module_load_level = target.GetMemoryModuleLoadLevel(); | ||||||||
2356 | |||||||||
2357 | // Reading mach file from memory in a process or core file... | ||||||||
2358 | |||||||||
2359 | if (linkedit_section_sp) { | ||||||||
2360 | addr_t linkedit_load_addr = | ||||||||
2361 | linkedit_section_sp->GetLoadBaseAddress(&target); | ||||||||
2362 | if (linkedit_load_addr == LLDB_INVALID_ADDRESS0xffffffffffffffffULL) { | ||||||||
2363 | // We might be trying to access the symbol table before the | ||||||||
2364 | // __LINKEDIT's load address has been set in the target. We can't | ||||||||
2365 | // fail to read the symbol table, so calculate the right address | ||||||||
2366 | // manually | ||||||||
2367 | linkedit_load_addr = CalculateSectionLoadAddressForMemoryImage( | ||||||||
2368 | m_memory_addr, GetMachHeaderSection(), linkedit_section_sp.get()); | ||||||||
2369 | } | ||||||||
2370 | |||||||||
2371 | const addr_t linkedit_file_offset = linkedit_section_sp->GetFileOffset(); | ||||||||
2372 | const addr_t symoff_addr = linkedit_load_addr + | ||||||||
2373 | symtab_load_command.symoff - | ||||||||
2374 | linkedit_file_offset; | ||||||||
2375 | strtab_addr = linkedit_load_addr + symtab_load_command.stroff - | ||||||||
2376 | linkedit_file_offset; | ||||||||
2377 | |||||||||
2378 | // Always load dyld - the dynamic linker - from memory if we didn't | ||||||||
2379 | // find a binary anywhere else. lldb will not register | ||||||||
2380 | // dylib/framework/bundle loads/unloads if we don't have the dyld | ||||||||
2381 | // symbols, we force dyld to load from memory despite the user's | ||||||||
2382 | // target.memory-module-load-level setting. | ||||||||
2383 | if (memory_module_load_level == eMemoryModuleLoadLevelComplete || | ||||||||
2384 | m_header.filetype == llvm::MachO::MH_DYLINKER) { | ||||||||
2385 | DataBufferSP nlist_data_sp( | ||||||||
2386 | ReadMemory(process_sp, symoff_addr, nlist_data_byte_size)); | ||||||||
2387 | if (nlist_data_sp) | ||||||||
2388 | nlist_data.SetData(nlist_data_sp, 0, nlist_data_sp->GetByteSize()); | ||||||||
2389 | if (m_dysymtab.nindirectsyms != 0) { | ||||||||
2390 | const addr_t indirect_syms_addr = linkedit_load_addr + | ||||||||
2391 | m_dysymtab.indirectsymoff - | ||||||||
2392 | linkedit_file_offset; | ||||||||
2393 | DataBufferSP indirect_syms_data_sp(ReadMemory( | ||||||||
2394 | process_sp, indirect_syms_addr, m_dysymtab.nindirectsyms * 4)); | ||||||||
2395 | if (indirect_syms_data_sp) | ||||||||
2396 | indirect_symbol_index_data.SetData( | ||||||||
2397 | indirect_syms_data_sp, 0, | ||||||||
2398 | indirect_syms_data_sp->GetByteSize()); | ||||||||
2399 | // If this binary is outside the shared cache, | ||||||||
2400 | // cache the string table. | ||||||||
2401 | // Binaries in the shared cache all share a giant string table, | ||||||||
2402 | // and we can't share the string tables across multiple | ||||||||
2403 | // ObjectFileMachO's, so we'd end up re-reading this mega-strtab | ||||||||
2404 | // for every binary in the shared cache - it would be a big perf | ||||||||
2405 | // problem. For binaries outside the shared cache, it's faster to | ||||||||
2406 | // read the entire strtab at once instead of piece-by-piece as we | ||||||||
2407 | // process the nlist records. | ||||||||
2408 | if (!is_shared_cache_image) { | ||||||||
2409 | DataBufferSP strtab_data_sp( | ||||||||
2410 | ReadMemory(process_sp, strtab_addr, strtab_data_byte_size)); | ||||||||
2411 | if (strtab_data_sp) { | ||||||||
2412 | strtab_data.SetData(strtab_data_sp, 0, | ||||||||
2413 | strtab_data_sp->GetByteSize()); | ||||||||
2414 | } | ||||||||
2415 | } | ||||||||
2416 | } | ||||||||
2417 | if (memory_module_load_level >= eMemoryModuleLoadLevelPartial) { | ||||||||
2418 | if (function_starts_load_command.cmd) { | ||||||||
2419 | const addr_t func_start_addr = | ||||||||
2420 | linkedit_load_addr + function_starts_load_command.dataoff - | ||||||||
2421 | linkedit_file_offset; | ||||||||
2422 | DataBufferSP func_start_data_sp( | ||||||||
2423 | ReadMemory(process_sp, func_start_addr, | ||||||||
2424 | function_starts_load_command.datasize)); | ||||||||
2425 | if (func_start_data_sp) | ||||||||
2426 | function_starts_data.SetData(func_start_data_sp, 0, | ||||||||
2427 | func_start_data_sp->GetByteSize()); | ||||||||
2428 | } | ||||||||
2429 | } | ||||||||
2430 | } | ||||||||
2431 | } | ||||||||
2432 | } else { | ||||||||
2433 | if (is_local_shared_cache_image
| ||||||||
2434 | // The load commands in shared cache images are relative to the | ||||||||
2435 | // beginning of the shared cache, not the library image. The | ||||||||
2436 | // data we get handed when creating the ObjectFileMachO starts | ||||||||
2437 | // at the beginning of a specific library and spans to the end | ||||||||
2438 | // of the cache to be able to reach the shared LINKEDIT | ||||||||
2439 | // segments. We need to convert the load command offsets to be | ||||||||
2440 | // relative to the beginning of our specific image. | ||||||||
2441 | lldb::addr_t linkedit_offset = linkedit_section_sp->GetFileOffset(); | ||||||||
2442 | lldb::offset_t linkedit_slide = | ||||||||
2443 | linkedit_offset - m_linkedit_original_offset; | ||||||||
2444 | symtab_load_command.symoff += linkedit_slide; | ||||||||
2445 | symtab_load_command.stroff += linkedit_slide; | ||||||||
2446 | dyld_info.export_off += linkedit_slide; | ||||||||
2447 | m_dysymtab.indirectsymoff += linkedit_slide; | ||||||||
2448 | function_starts_load_command.dataoff += linkedit_slide; | ||||||||
2449 | } | ||||||||
2450 | |||||||||
2451 | nlist_data.SetData(m_data, symtab_load_command.symoff, | ||||||||
2452 | nlist_data_byte_size); | ||||||||
2453 | strtab_data.SetData(m_data, symtab_load_command.stroff, | ||||||||
2454 | strtab_data_byte_size); | ||||||||
2455 | |||||||||
2456 | if (dyld_info.export_size
| ||||||||
2457 | dyld_trie_data.SetData(m_data, dyld_info.export_off, | ||||||||
2458 | dyld_info.export_size); | ||||||||
2459 | } | ||||||||
2460 | |||||||||
2461 | if (m_dysymtab.nindirectsyms != 0) { | ||||||||
2462 | indirect_symbol_index_data.SetData(m_data, m_dysymtab.indirectsymoff, | ||||||||
2463 | m_dysymtab.nindirectsyms * 4); | ||||||||
2464 | } | ||||||||
2465 | if (function_starts_load_command.cmd
| ||||||||
2466 | function_starts_data.SetData(m_data, function_starts_load_command.dataoff, | ||||||||
2467 | function_starts_load_command.datasize); | ||||||||
2468 | } | ||||||||
2469 | } | ||||||||
2470 | |||||||||
2471 | const bool have_strtab_data = strtab_data.GetByteSize() > 0; | ||||||||
2472 | |||||||||
2473 | ConstString g_segment_name_TEXT = GetSegmentNameTEXT(); | ||||||||
2474 | ConstString g_segment_name_DATA = GetSegmentNameDATA(); | ||||||||
2475 | ConstString g_segment_name_DATA_DIRTY = GetSegmentNameDATA_DIRTY(); | ||||||||
2476 | ConstString g_segment_name_DATA_CONST = GetSegmentNameDATA_CONST(); | ||||||||
2477 | ConstString g_segment_name_OBJC = GetSegmentNameOBJC(); | ||||||||
2478 | ConstString g_section_name_eh_frame = GetSectionNameEHFrame(); | ||||||||
2479 | SectionSP text_section_sp( | ||||||||
2480 | section_list->FindSectionByName(g_segment_name_TEXT)); | ||||||||
2481 | SectionSP data_section_sp( | ||||||||
2482 | section_list->FindSectionByName(g_segment_name_DATA)); | ||||||||
2483 | SectionSP data_dirty_section_sp( | ||||||||
2484 | section_list->FindSectionByName(g_segment_name_DATA_DIRTY)); | ||||||||
2485 | SectionSP data_const_section_sp( | ||||||||
2486 | section_list->FindSectionByName(g_segment_name_DATA_CONST)); | ||||||||
2487 | SectionSP objc_section_sp( | ||||||||
2488 | section_list->FindSectionByName(g_segment_name_OBJC)); | ||||||||
2489 | SectionSP eh_frame_section_sp; | ||||||||
2490 | if (text_section_sp.get()) | ||||||||
2491 | eh_frame_section_sp = text_section_sp->GetChildren().FindSectionByName( | ||||||||
2492 | g_section_name_eh_frame); | ||||||||
2493 | else | ||||||||
2494 | eh_frame_section_sp = | ||||||||
2495 | section_list->FindSectionByName(g_section_name_eh_frame); | ||||||||
2496 | |||||||||
2497 | const bool is_arm = (m_header.cputype == llvm::MachO::CPU_TYPE_ARM); | ||||||||
2498 | const bool always_thumb = GetArchitecture().IsAlwaysThumbInstructions(); | ||||||||
2499 | |||||||||
2500 | // lldb works best if it knows the start address of all functions in a | ||||||||
2501 | // module. Linker symbols or debug info are normally the best source of | ||||||||
2502 | // information for start addr / size but they may be stripped in a released | ||||||||
2503 | // binary. Two additional sources of information exist in Mach-O binaries: | ||||||||
2504 | // LC_FUNCTION_STARTS - a list of ULEB128 encoded offsets of each | ||||||||
2505 | // function's start address in the | ||||||||
2506 | // binary, relative to the text section. | ||||||||
2507 | // eh_frame - the eh_frame FDEs have the start addr & size of | ||||||||
2508 | // each function | ||||||||
2509 | // LC_FUNCTION_STARTS is the fastest source to read in, and is present on | ||||||||
2510 | // all modern binaries. | ||||||||
2511 | // Binaries built to run on older releases may need to use eh_frame | ||||||||
2512 | // information. | ||||||||
2513 | |||||||||
2514 | if (text_section_sp && function_starts_data.GetByteSize()) { | ||||||||
2515 | FunctionStarts::Entry function_start_entry; | ||||||||
2516 | function_start_entry.data = false; | ||||||||
2517 | lldb::offset_t function_start_offset = 0; | ||||||||
2518 | function_start_entry.addr = text_section_sp->GetFileAddress(); | ||||||||
2519 | uint64_t delta; | ||||||||
2520 | while ((delta = function_starts_data.GetULEB128(&function_start_offset)) > | ||||||||
2521 | 0) { | ||||||||
2522 | // Now append the current entry | ||||||||
2523 | function_start_entry.addr += delta; | ||||||||
2524 | if (is_arm) { | ||||||||
2525 | if (function_start_entry.addr & 1) { | ||||||||
2526 | function_start_entry.addr &= THUMB_ADDRESS_BIT_MASK0xfffffffffffffffeull; | ||||||||
2527 | function_start_entry.data = true; | ||||||||
2528 | } else if (always_thumb) { | ||||||||
2529 | function_start_entry.data = true; | ||||||||
2530 | } | ||||||||
2531 | } | ||||||||
2532 | function_starts.Append(function_start_entry); | ||||||||
2533 | } | ||||||||
2534 | } else { | ||||||||
2535 | // If m_type is eTypeDebugInfo, then this is a dSYM - it will have the | ||||||||
2536 | // load command claiming an eh_frame but it doesn't actually have the | ||||||||
2537 | // eh_frame content. And if we have a dSYM, we don't need to do any of | ||||||||
2538 | // this fill-in-the-missing-symbols works anyway - the debug info should | ||||||||
2539 | // give us all the functions in the module. | ||||||||
2540 | if (text_section_sp.get() && eh_frame_section_sp.get() && | ||||||||
2541 | m_type != eTypeDebugInfo) { | ||||||||
2542 | DWARFCallFrameInfo eh_frame(*this, eh_frame_section_sp, | ||||||||
2543 | DWARFCallFrameInfo::EH); | ||||||||
2544 | DWARFCallFrameInfo::FunctionAddressAndSizeVector functions; | ||||||||
2545 | eh_frame.GetFunctionAddressAndSizeVector(functions); | ||||||||
2546 | addr_t text_base_addr = text_section_sp->GetFileAddress(); | ||||||||
2547 | size_t count = functions.GetSize(); | ||||||||
2548 | for (size_t i = 0; i < count; ++i) { | ||||||||
2549 | const DWARFCallFrameInfo::FunctionAddressAndSizeVector::Entry *func = | ||||||||
2550 | functions.GetEntryAtIndex(i); | ||||||||
2551 | if (func) { | ||||||||
2552 | FunctionStarts::Entry function_start_entry; | ||||||||
2553 | function_start_entry.addr = func->base - text_base_addr; | ||||||||
2554 | if (is_arm) { | ||||||||
2555 | if (function_start_entry.addr & 1) { | ||||||||
2556 | function_start_entry.addr &= THUMB_ADDRESS_BIT_MASK0xfffffffffffffffeull; | ||||||||
2557 | function_start_entry.data = true; | ||||||||
2558 | } else if (always_thumb) { | ||||||||
2559 | function_start_entry.data = true; | ||||||||
2560 | } | ||||||||
2561 | } | ||||||||
2562 | function_starts.Append(function_start_entry); | ||||||||
2563 | } | ||||||||
2564 | } | ||||||||
2565 | } | ||||||||
2566 | } | ||||||||
2567 | |||||||||
2568 | const size_t function_starts_count = function_starts.GetSize(); | ||||||||
2569 | |||||||||
2570 | // For user process binaries (executables, dylibs, frameworks, bundles), if | ||||||||
2571 | // we don't have LC_FUNCTION_STARTS/eh_frame section in this binary, we're | ||||||||
2572 | // going to assume the binary has been stripped. Don't allow assembly | ||||||||
2573 | // language instruction emulation because we don't know proper function | ||||||||
2574 | // start boundaries. | ||||||||
2575 | // | ||||||||
2576 | // For all other types of binaries (kernels, stand-alone bare board | ||||||||
2577 | // binaries, kexts), they may not have LC_FUNCTION_STARTS / eh_frame | ||||||||
2578 | // sections - we should not make any assumptions about them based on that. | ||||||||
2579 | if (function_starts_count == 0 && CalculateStrata() == eStrataUser) { | ||||||||
2580 | m_allow_assembly_emulation_unwind_plans = false; | ||||||||
2581 | Log *unwind_or_symbol_log(lldb_private::GetLogIfAnyCategoriesSet( | ||||||||
2582 | LIBLLDB_LOG_SYMBOLS(1u << 20) | LIBLLDB_LOG_UNWIND(1u << 15))); | ||||||||
2583 | |||||||||
2584 | if (unwind_or_symbol_log) | ||||||||
2585 | module_sp->LogMessage( | ||||||||
2586 | unwind_or_symbol_log, | ||||||||
2587 | "no LC_FUNCTION_STARTS, will not allow assembly profiled unwinds"); | ||||||||
2588 | } | ||||||||
2589 | |||||||||
2590 | const user_id_t TEXT_eh_frame_sectID = eh_frame_section_sp.get() | ||||||||
2591 | ? eh_frame_section_sp->GetID() | ||||||||
2592 | : static_cast<user_id_t>(NO_SECT); | ||||||||
2593 | |||||||||
2594 | lldb::offset_t nlist_data_offset = 0; | ||||||||
2595 | |||||||||
2596 | uint32_t N_SO_index = UINT32_MAX0xffffffffU; | ||||||||
2597 | |||||||||
2598 | MachSymtabSectionInfo section_info(section_list); | ||||||||
2599 | std::vector<uint32_t> N_FUN_indexes; | ||||||||
2600 | std::vector<uint32_t> N_NSYM_indexes; | ||||||||
2601 | std::vector<uint32_t> N_INCL_indexes; | ||||||||
2602 | std::vector<uint32_t> N_BRAC_indexes; | ||||||||
2603 | std::vector<uint32_t> N_COMM_indexes; | ||||||||
2604 | typedef std::multimap<uint64_t, uint32_t> ValueToSymbolIndexMap; | ||||||||
2605 | typedef llvm::DenseMap<uint32_t, uint32_t> NListIndexToSymbolIndexMap; | ||||||||
2606 | typedef llvm::DenseMap<const char *, uint32_t> ConstNameToSymbolIndexMap; | ||||||||
2607 | ValueToSymbolIndexMap N_FUN_addr_to_sym_idx; | ||||||||
2608 | ValueToSymbolIndexMap N_STSYM_addr_to_sym_idx; | ||||||||
2609 | ConstNameToSymbolIndexMap N_GSYM_name_to_sym_idx; | ||||||||
2610 | // Any symbols that get merged into another will get an entry in this map | ||||||||
2611 | // so we know | ||||||||
2612 | NListIndexToSymbolIndexMap m_nlist_idx_to_sym_idx; | ||||||||
2613 | uint32_t nlist_idx = 0; | ||||||||
2614 | Symbol *symbol_ptr = nullptr; | ||||||||
2615 | |||||||||
2616 | uint32_t sym_idx = 0; | ||||||||
2617 | Symbol *sym = nullptr; | ||||||||
2618 | size_t num_syms = 0; | ||||||||
2619 | std::string memory_symbol_name; | ||||||||
2620 | uint32_t unmapped_local_symbols_found = 0; | ||||||||
2621 | |||||||||
2622 | std::vector<TrieEntryWithOffset> reexport_trie_entries; | ||||||||
2623 | std::vector<TrieEntryWithOffset> external_sym_trie_entries; | ||||||||
2624 | std::set<lldb::addr_t> resolver_addresses; | ||||||||
2625 | |||||||||
2626 | if (dyld_trie_data.GetByteSize() > 0) { | ||||||||
2627 | ConstString text_segment_name("__TEXT"); | ||||||||
2628 | SectionSP text_segment_sp = | ||||||||
2629 | GetSectionList()->FindSectionByName(text_segment_name); | ||||||||
2630 | lldb::addr_t text_segment_file_addr = LLDB_INVALID_ADDRESS0xffffffffffffffffULL; | ||||||||
2631 | if (text_segment_sp) | ||||||||
2632 | text_segment_file_addr = text_segment_sp->GetFileAddress(); | ||||||||
2633 | std::vector<llvm::StringRef> nameSlices; | ||||||||
2634 | ParseTrieEntries(dyld_trie_data, 0, is_arm, text_segment_file_addr, | ||||||||
2635 | nameSlices, resolver_addresses, reexport_trie_entries, | ||||||||
2636 | external_sym_trie_entries); | ||||||||
2637 | } | ||||||||
2638 | |||||||||
2639 | typedef std::set<ConstString> IndirectSymbols; | ||||||||
2640 | IndirectSymbols indirect_symbol_names; | ||||||||
2641 | |||||||||
2642 | #if TARGET_OS_IPHONE | ||||||||
2643 | |||||||||
2644 | // Some recent builds of the dyld_shared_cache (hereafter: DSC) have been | ||||||||
2645 | // optimized by moving LOCAL symbols out of the memory mapped portion of | ||||||||
2646 | // the DSC. The symbol information has all been retained, but it isn't | ||||||||
2647 | // available in the normal nlist data. However, there *are* duplicate | ||||||||
2648 | // entries of *some* | ||||||||
2649 | // LOCAL symbols in the normal nlist data. To handle this situation | ||||||||
2650 | // correctly, we must first attempt | ||||||||
2651 | // to parse any DSC unmapped symbol information. If we find any, we set a | ||||||||
2652 | // flag that tells the normal nlist parser to ignore all LOCAL symbols. | ||||||||
2653 | |||||||||
2654 | if (m_header.flags & MH_DYLIB_IN_CACHE) { | ||||||||
2655 | // Before we can start mapping the DSC, we need to make certain the | ||||||||
2656 | // target process is actually using the cache we can find. | ||||||||
2657 | |||||||||
2658 | // Next we need to determine the correct path for the dyld shared cache. | ||||||||
2659 | |||||||||
2660 | ArchSpec header_arch = GetArchitecture(); | ||||||||
2661 | char dsc_path[PATH_MAX1024]; | ||||||||
2662 | char dsc_path_development[PATH_MAX1024]; | ||||||||
2663 | |||||||||
2664 | snprintf( | ||||||||
2665 | dsc_path, sizeof(dsc_path), "%s%s%s", | ||||||||
2666 | "/System/Library/Caches/com.apple.dyld/", /* IPHONE_DYLD_SHARED_CACHE_DIR | ||||||||
2667 | */ | ||||||||
2668 | "dyld_shared_cache_", /* DYLD_SHARED_CACHE_BASE_NAME */ | ||||||||
2669 | header_arch.GetArchitectureName()); | ||||||||
2670 | |||||||||
2671 | snprintf( | ||||||||
2672 | dsc_path_development, sizeof(dsc_path), "%s%s%s%s", | ||||||||
2673 | "/System/Library/Caches/com.apple.dyld/", /* IPHONE_DYLD_SHARED_CACHE_DIR | ||||||||
2674 | */ | ||||||||
2675 | "dyld_shared_cache_", /* DYLD_SHARED_CACHE_BASE_NAME */ | ||||||||
2676 | header_arch.GetArchitectureName(), ".development"); | ||||||||
2677 | |||||||||
2678 | FileSpec dsc_nondevelopment_filespec(dsc_path); | ||||||||
2679 | FileSpec dsc_development_filespec(dsc_path_development); | ||||||||
2680 | FileSpec dsc_filespec; | ||||||||
2681 | |||||||||
2682 | UUID dsc_uuid; | ||||||||
2683 | UUID process_shared_cache_uuid; | ||||||||
2684 | addr_t process_shared_cache_base_addr; | ||||||||
2685 | |||||||||
2686 | if (process) { | ||||||||
2687 | GetProcessSharedCacheUUID(process, process_shared_cache_base_addr, | ||||||||
2688 | process_shared_cache_uuid); | ||||||||
2689 | } | ||||||||
2690 | |||||||||
2691 | // First see if we can find an exact match for the inferior process | ||||||||
2692 | // shared cache UUID in the development or non-development shared caches | ||||||||
2693 | // on disk. | ||||||||
2694 | if (process_shared_cache_uuid.IsValid()) { | ||||||||
2695 | if (FileSystem::Instance().Exists(dsc_development_filespec)) { | ||||||||
2696 | UUID dsc_development_uuid = GetSharedCacheUUID( | ||||||||
2697 | dsc_development_filespec, byte_order, addr_byte_size); | ||||||||
2698 | if (dsc_development_uuid.IsValid() && | ||||||||
2699 | dsc_development_uuid == process_shared_cache_uuid) { | ||||||||
2700 | dsc_filespec = dsc_development_filespec; | ||||||||
2701 | dsc_uuid = dsc_development_uuid; | ||||||||
2702 | } | ||||||||
2703 | } | ||||||||
2704 | if (!dsc_uuid.IsValid() && | ||||||||
2705 | FileSystem::Instance().Exists(dsc_nondevelopment_filespec)) { | ||||||||
2706 | UUID dsc_nondevelopment_uuid = GetSharedCacheUUID( | ||||||||
2707 | dsc_nondevelopment_filespec, byte_order, addr_byte_size); | ||||||||
2708 | if (dsc_nondevelopment_uuid.IsValid() && | ||||||||
2709 | dsc_nondevelopment_uuid == process_shared_cache_uuid) { | ||||||||
2710 | dsc_filespec = dsc_nondevelopment_filespec; | ||||||||
2711 | dsc_uuid = dsc_nondevelopment_uuid; | ||||||||
2712 | } | ||||||||
2713 | } | ||||||||
2714 | } | ||||||||
2715 | |||||||||
2716 | // Failing a UUID match, prefer the development dyld_shared cache if both | ||||||||
2717 | // are present. | ||||||||
2718 | if (!FileSystem::Instance().Exists(dsc_filespec)) { | ||||||||
2719 | if (FileSystem::Instance().Exists(dsc_development_filespec)) { | ||||||||
2720 | dsc_filespec = dsc_development_filespec; | ||||||||
2721 | } else { | ||||||||
2722 | dsc_filespec = dsc_nondevelopment_filespec; | ||||||||
2723 | } | ||||||||
2724 | } | ||||||||
2725 | |||||||||
2726 | /* The dyld_cache_header has a pointer to the | ||||||||
2727 | dyld_cache_local_symbols_info structure (localSymbolsOffset). | ||||||||
2728 | The dyld_cache_local_symbols_info structure gives us three things: | ||||||||
2729 | 1. The start and count of the nlist records in the dyld_shared_cache | ||||||||
2730 | file | ||||||||
2731 | 2. The start and size of the strings for these nlist records | ||||||||
2732 | 3. The start and count of dyld_cache_local_symbols_entry entries | ||||||||
2733 | |||||||||
2734 | There is one dyld_cache_local_symbols_entry per dylib/framework in the | ||||||||
2735 | dyld shared cache. | ||||||||
2736 | The "dylibOffset" field is the Mach-O header of this dylib/framework in | ||||||||
2737 | the dyld shared cache. | ||||||||
2738 | The dyld_cache_local_symbols_entry also lists the start of this | ||||||||
2739 | dylib/framework's nlist records | ||||||||
2740 | and the count of how many nlist records there are for this | ||||||||
2741 | dylib/framework. | ||||||||
2742 | */ | ||||||||
2743 | |||||||||
2744 | // Process the dyld shared cache header to find the unmapped symbols | ||||||||
2745 | |||||||||
2746 | DataBufferSP dsc_data_sp = MapFileData( | ||||||||
2747 | dsc_filespec, sizeof(struct lldb_copy_dyld_cache_header_v1), 0); | ||||||||
2748 | if (!dsc_uuid.IsValid()) { | ||||||||
2749 | dsc_uuid = GetSharedCacheUUID(dsc_filespec, byte_order, addr_byte_size); | ||||||||
2750 | } | ||||||||
2751 | if (dsc_data_sp) { | ||||||||
2752 | DataExtractor dsc_header_data(dsc_data_sp, byte_order, addr_byte_size); | ||||||||
2753 | |||||||||
2754 | bool uuid_match = true; | ||||||||
2755 | if (dsc_uuid.IsValid() && process) { | ||||||||
2756 | if (process_shared_cache_uuid.IsValid() && | ||||||||
2757 | dsc_uuid != process_shared_cache_uuid) { | ||||||||
2758 | // The on-disk dyld_shared_cache file is not the same as the one in | ||||||||
2759 | // this process' memory, don't use it. | ||||||||
2760 | uuid_match = false; | ||||||||
2761 | ModuleSP module_sp(GetModule()); | ||||||||
2762 | if (module_sp) | ||||||||
2763 | module_sp->ReportWarning("process shared cache does not match " | ||||||||
2764 | "on-disk dyld_shared_cache file, some " | ||||||||
2765 | "symbol names will be missing."); | ||||||||
2766 | } | ||||||||
2767 | } | ||||||||
2768 | |||||||||
2769 | offset = offsetof(struct lldb_copy_dyld_cache_header_v1, mappingOffset)__builtin_offsetof(struct lldb_copy_dyld_cache_header_v1, mappingOffset ); | ||||||||
2770 | |||||||||
2771 | uint32_t mappingOffset = dsc_header_data.GetU32(&offset); | ||||||||
2772 | |||||||||
2773 | // If the mappingOffset points to a location inside the header, we've | ||||||||
2774 | // opened an old dyld shared cache, and should not proceed further. | ||||||||
2775 | if (uuid_match && | ||||||||
2776 | mappingOffset >= sizeof(struct lldb_copy_dyld_cache_header_v1)) { | ||||||||
2777 | |||||||||
2778 | DataBufferSP dsc_mapping_info_data_sp = MapFileData( | ||||||||
2779 | dsc_filespec, sizeof(struct lldb_copy_dyld_cache_mapping_info), | ||||||||
2780 | mappingOffset); | ||||||||
2781 | |||||||||
2782 | DataExtractor dsc_mapping_info_data(dsc_mapping_info_data_sp, | ||||||||
2783 | byte_order, addr_byte_size); | ||||||||
2784 | offset = 0; | ||||||||
2785 | |||||||||
2786 | // The File addresses (from the in-memory Mach-O load commands) for | ||||||||
2787 | // the shared libraries in the shared library cache need to be | ||||||||
2788 | // adjusted by an offset to match up with the dylibOffset identifying | ||||||||
2789 | // field in the dyld_cache_local_symbol_entry's. This offset is | ||||||||
2790 | // recorded in mapping_offset_value. | ||||||||
2791 | const uint64_t mapping_offset_value = | ||||||||
2792 | dsc_mapping_info_data.GetU64(&offset); | ||||||||
2793 | |||||||||
2794 | offset = | ||||||||
2795 | offsetof(struct lldb_copy_dyld_cache_header_v1, localSymbolsOffset)__builtin_offsetof(struct lldb_copy_dyld_cache_header_v1, localSymbolsOffset ); | ||||||||
2796 | uint64_t localSymbolsOffset = dsc_header_data.GetU64(&offset); | ||||||||
2797 | uint64_t localSymbolsSize = dsc_header_data.GetU64(&offset); | ||||||||
2798 | |||||||||
2799 | if (localSymbolsOffset && localSymbolsSize) { | ||||||||
2800 | // Map the local symbols | ||||||||
2801 | DataBufferSP dsc_local_symbols_data_sp = | ||||||||
2802 | MapFileData(dsc_filespec, localSymbolsSize, localSymbolsOffset); | ||||||||
2803 | |||||||||
2804 | if (dsc_local_symbols_data_sp) { | ||||||||
2805 | DataExtractor dsc_local_symbols_data(dsc_local_symbols_data_sp, | ||||||||
2806 | byte_order, addr_byte_size); | ||||||||
2807 | |||||||||
2808 | offset = 0; | ||||||||
2809 | |||||||||
2810 | typedef llvm::DenseMap<ConstString, uint16_t> UndefinedNameToDescMap; | ||||||||
2811 | typedef llvm::DenseMap<uint32_t, ConstString> SymbolIndexToName; | ||||||||
2812 | UndefinedNameToDescMap undefined_name_to_desc; | ||||||||
2813 | SymbolIndexToName reexport_shlib_needs_fixup; | ||||||||
2814 | |||||||||
2815 | // Read the local_symbols_infos struct in one shot | ||||||||
2816 | struct lldb_copy_dyld_cache_local_symbols_info local_symbols_info; | ||||||||
2817 | dsc_local_symbols_data.GetU32(&offset, | ||||||||
2818 | &local_symbols_info.nlistOffset, 6); | ||||||||
2819 | |||||||||
2820 | SectionSP text_section_sp( | ||||||||
2821 | section_list->FindSectionByName(GetSegmentNameTEXT())); | ||||||||
2822 | |||||||||
2823 | uint32_t header_file_offset = | ||||||||
2824 | (text_section_sp->GetFileAddress() - mapping_offset_value); | ||||||||
2825 | |||||||||
2826 | offset = local_symbols_info.entriesOffset; | ||||||||
2827 | for (uint32_t entry_index = 0; | ||||||||
2828 | entry_index < local_symbols_info.entriesCount; entry_index++) { | ||||||||
2829 | struct lldb_copy_dyld_cache_local_symbols_entry | ||||||||
2830 | local_symbols_entry; | ||||||||
2831 | local_symbols_entry.dylibOffset = | ||||||||
2832 | dsc_local_symbols_data.GetU32(&offset); | ||||||||
2833 | local_symbols_entry.nlistStartIndex = | ||||||||
2834 | dsc_local_symbols_data.GetU32(&offset); | ||||||||
2835 | local_symbols_entry.nlistCount = | ||||||||
2836 | dsc_local_symbols_data.GetU32(&offset); | ||||||||
2837 | |||||||||
2838 | if (header_file_offset == local_symbols_entry.dylibOffset) { | ||||||||
2839 | unmapped_local_symbols_found = local_symbols_entry.nlistCount; | ||||||||
2840 | |||||||||
2841 | // The normal nlist code cannot correctly size the Symbols | ||||||||
2842 | // array, we need to allocate it here. | ||||||||
2843 | sym = symtab->Resize( | ||||||||
2844 | symtab_load_command.nsyms + m_dysymtab.nindirectsyms + | ||||||||
2845 | unmapped_local_symbols_found - m_dysymtab.nlocalsym); | ||||||||
2846 | num_syms = symtab->GetNumSymbols(); | ||||||||
2847 | |||||||||
2848 | nlist_data_offset = | ||||||||
2849 | local_symbols_info.nlistOffset + | ||||||||
2850 | (nlist_byte_size * local_symbols_entry.nlistStartIndex); | ||||||||
2851 | uint32_t string_table_offset = local_symbols_info.stringsOffset; | ||||||||
2852 | |||||||||
2853 | for (uint32_t nlist_index = 0; | ||||||||
2854 | nlist_index < local_symbols_entry.nlistCount; | ||||||||
2855 | nlist_index++) { | ||||||||
2856 | ///////////////////////////// | ||||||||
2857 | { | ||||||||
2858 | llvm::Optional<struct nlist_64> nlist_maybe = | ||||||||
2859 | ParseNList(dsc_local_symbols_data, nlist_data_offset, | ||||||||
2860 | nlist_byte_size); | ||||||||
2861 | if (!nlist_maybe) | ||||||||
2862 | break; | ||||||||
2863 | struct nlist_64 nlist = *nlist_maybe; | ||||||||
2864 | |||||||||
2865 | SymbolType type = eSymbolTypeInvalid; | ||||||||
2866 | const char *symbol_name = dsc_local_symbols_data.PeekCStr( | ||||||||
2867 | string_table_offset + nlist.n_strx); | ||||||||
2868 | |||||||||
2869 | if (symbol_name == NULL__null) { | ||||||||
2870 | // No symbol should be NULL, even the symbols with no | ||||||||
2871 | // string values should have an offset zero which | ||||||||
2872 | // points to an empty C-string | ||||||||
2873 | Host::SystemLog( | ||||||||
2874 | Host::eSystemLogError, | ||||||||
2875 | "error: DSC unmapped local symbol[%u] has invalid " | ||||||||
2876 | "string table offset 0x%x in %s, ignoring symbol\n", | ||||||||
2877 | entry_index, nlist.n_strx, | ||||||||
2878 | module_sp->GetFileSpec().GetPath().c_str()); | ||||||||
2879 | continue; | ||||||||
2880 | } | ||||||||
2881 | if (symbol_name[0] == '\0') | ||||||||
2882 | symbol_name = NULL__null; | ||||||||
2883 | |||||||||
2884 | const char *symbol_name_non_abi_mangled = NULL__null; | ||||||||
2885 | |||||||||
2886 | SectionSP symbol_section; | ||||||||
2887 | uint32_t symbol_byte_size = 0; | ||||||||
2888 | bool add_nlist = true; | ||||||||
2889 | bool is_debug = ((nlist.n_type & N_STAB) != 0); | ||||||||
2890 | bool demangled_is_synthesized = false; | ||||||||
2891 | bool is_gsym = false; | ||||||||
2892 | bool set_value = true; | ||||||||
2893 | |||||||||
2894 | assert(sym_idx < num_syms)((void)0); | ||||||||
2895 | |||||||||
2896 | sym[sym_idx].SetDebug(is_debug); | ||||||||
2897 | |||||||||
2898 | if (is_debug) { | ||||||||
2899 | switch (nlist.n_type) { | ||||||||
2900 | case N_GSYM: | ||||||||
2901 | // global symbol: name,,NO_SECT,type,0 | ||||||||
2902 | // Sometimes the N_GSYM value contains the address. | ||||||||
2903 | |||||||||
2904 | // FIXME: In the .o files, we have a GSYM and a debug | ||||||||
2905 | // symbol for all the ObjC data. They | ||||||||
2906 | // have the same address, but we want to ensure that | ||||||||
2907 | // we always find only the real symbol, 'cause we | ||||||||
2908 | // don't currently correctly attribute the | ||||||||
2909 | // GSYM one to the ObjCClass/Ivar/MetaClass | ||||||||
2910 | // symbol type. This is a temporary hack to make | ||||||||
2911 | // sure the ObjectiveC symbols get treated correctly. | ||||||||
2912 | // To do this right, we should coalesce all the GSYM | ||||||||
2913 | // & global symbols that have the same address. | ||||||||
2914 | |||||||||
2915 | is_gsym = true; | ||||||||
2916 | sym[sym_idx].SetExternal(true); | ||||||||
2917 | |||||||||
2918 | if (symbol_name && symbol_name[0] == '_' && | ||||||||
2919 | symbol_name[1] == 'O') { | ||||||||
2920 | llvm::StringRef symbol_name_ref(symbol_name); | ||||||||
2921 | if (symbol_name_ref.startswith( | ||||||||
2922 | g_objc_v2_prefix_class)) { | ||||||||
2923 | symbol_name_non_abi_mangled = symbol_name + 1; | ||||||||
2924 | symbol_name = | ||||||||
2925 | symbol_name + g_objc_v2_prefix_class.size(); | ||||||||
2926 | type = eSymbolTypeObjCClass; | ||||||||
2927 | demangled_is_synthesized = true; | ||||||||
2928 | |||||||||
2929 | } else if (symbol_name_ref.startswith( | ||||||||
2930 | g_objc_v2_prefix_metaclass)) { | ||||||||
2931 | symbol_name_non_abi_mangled = symbol_name + 1; | ||||||||
2932 | symbol_name = | ||||||||
2933 | symbol_name + g_objc_v2_prefix_metaclass.size(); | ||||||||
2934 | type = eSymbolTypeObjCMetaClass; | ||||||||
2935 | demangled_is_synthesized = true; | ||||||||
2936 | } else if (symbol_name_ref.startswith( | ||||||||
2937 | g_objc_v2_prefix_ivar)) { | ||||||||
2938 | symbol_name_non_abi_mangled = symbol_name + 1; | ||||||||
2939 | symbol_name = | ||||||||
2940 | symbol_name + g_objc_v2_prefix_ivar.size(); | ||||||||
2941 | type = eSymbolTypeObjCIVar; | ||||||||
2942 | demangled_is_synthesized = true; | ||||||||
2943 | } | ||||||||
2944 | } else { | ||||||||
2945 | if (nlist.n_value != 0) | ||||||||
2946 | symbol_section = section_info.GetSection( | ||||||||
2947 | nlist.n_sect, nlist.n_value); | ||||||||
2948 | type = eSymbolTypeData; | ||||||||
2949 | } | ||||||||
2950 | break; | ||||||||
2951 | |||||||||
2952 | case N_FNAME: | ||||||||
2953 | // procedure name (f77 kludge): name,,NO_SECT,0,0 | ||||||||
2954 | type = eSymbolTypeCompiler; | ||||||||
2955 | break; | ||||||||
2956 | |||||||||
2957 | case N_FUN: | ||||||||
2958 | // procedure: name,,n_sect,linenumber,address | ||||||||
2959 | if (symbol_name) { | ||||||||
2960 | type = eSymbolTypeCode; | ||||||||
2961 | symbol_section = section_info.GetSection( | ||||||||
2962 | nlist.n_sect, nlist.n_value); | ||||||||
2963 | |||||||||
2964 | N_FUN_addr_to_sym_idx.insert( | ||||||||
2965 | std::make_pair(nlist.n_value, sym_idx)); | ||||||||
2966 | // We use the current number of symbols in the | ||||||||
2967 | // symbol table in lieu of using nlist_idx in case | ||||||||
2968 | // we ever start trimming entries out | ||||||||
2969 | N_FUN_indexes.push_back(sym_idx); | ||||||||
2970 | } else { | ||||||||
2971 | type = eSymbolTypeCompiler; | ||||||||
2972 | |||||||||
2973 | if (!N_FUN_indexes.empty()) { | ||||||||
2974 | // Copy the size of the function into the | ||||||||
2975 | // original | ||||||||
2976 | // STAB entry so we don't have | ||||||||
2977 | // to hunt for it later | ||||||||
2978 | symtab->SymbolAtIndex(N_FUN_indexes.back()) | ||||||||
2979 | ->SetByteSize(nlist.n_value); | ||||||||
2980 | N_FUN_indexes.pop_back(); | ||||||||
2981 | // We don't really need the end function STAB as | ||||||||
2982 | // it contains the size which we already placed | ||||||||
2983 | // with the original symbol, so don't add it if | ||||||||
2984 | // we want a minimal symbol table | ||||||||
2985 | add_nlist = false; | ||||||||
2986 | } | ||||||||
2987 | } | ||||||||
2988 | break; | ||||||||
2989 | |||||||||
2990 | case N_STSYM: | ||||||||
2991 | // static symbol: name,,n_sect,type,address | ||||||||
2992 | N_STSYM_addr_to_sym_idx.insert( | ||||||||
2993 | std::make_pair(nlist.n_value, sym_idx)); | ||||||||
2994 | symbol_section = section_info.GetSection(nlist.n_sect, | ||||||||
2995 | nlist.n_value); | ||||||||
2996 | if (symbol_name && symbol_name[0]) { | ||||||||
2997 | type = ObjectFile::GetSymbolTypeFromName( | ||||||||
2998 | symbol_name + 1, eSymbolTypeData); | ||||||||
2999 | } | ||||||||
3000 | break; | ||||||||
3001 | |||||||||
3002 | case N_LCSYM: | ||||||||
3003 | // .lcomm symbol: name,,n_sect,type,address | ||||||||
3004 | symbol_section = section_info.GetSection(nlist.n_sect, | ||||||||
3005 | nlist.n_value); | ||||||||
3006 | type = eSymbolTypeCommonBlock; | ||||||||
3007 | break; | ||||||||
3008 | |||||||||
3009 | case N_BNSYM: | ||||||||
3010 | // We use the current number of symbols in the symbol | ||||||||
3011 | // table in lieu of using nlist_idx in case we ever | ||||||||
3012 | // start trimming entries out Skip these if we want | ||||||||
3013 | // minimal symbol tables | ||||||||
3014 | add_nlist = false; | ||||||||
3015 | break; | ||||||||
3016 | |||||||||
3017 | case N_ENSYM: | ||||||||
3018 | // Set the size of the N_BNSYM to the terminating | ||||||||
3019 | // index of this N_ENSYM so that we can always skip | ||||||||
3020 | // the entire symbol if we need to navigate more | ||||||||
3021 | // quickly at the source level when parsing STABS | ||||||||
3022 | // Skip these if we want minimal symbol tables | ||||||||
3023 | add_nlist = false; | ||||||||
3024 | break; | ||||||||
3025 | |||||||||
3026 | case N_OPT: | ||||||||
3027 | // emitted with gcc2_compiled and in gcc source | ||||||||
3028 | type = eSymbolTypeCompiler; | ||||||||
3029 | break; | ||||||||
3030 | |||||||||
3031 | case N_RSYM: | ||||||||
3032 | // register sym: name,,NO_SECT,type,register | ||||||||
3033 | type = eSymbolTypeVariable; | ||||||||
3034 | break; | ||||||||
3035 | |||||||||
3036 | case N_SLINE: | ||||||||
3037 | // src line: 0,,n_sect,linenumber,address | ||||||||
3038 | symbol_section = section_info.GetSection(nlist.n_sect, | ||||||||
3039 | nlist.n_value); | ||||||||
3040 | type = eSymbolTypeLineEntry; | ||||||||
3041 | break; | ||||||||
3042 | |||||||||
3043 | case N_SSYM: | ||||||||
3044 | // structure elt: name,,NO_SECT,type,struct_offset | ||||||||
3045 | type = eSymbolTypeVariableType; | ||||||||
3046 | break; | ||||||||
3047 | |||||||||
3048 | case N_SO: | ||||||||
3049 | // source file name | ||||||||
3050 | type = eSymbolTypeSourceFile; | ||||||||
3051 | if (symbol_name == NULL__null) { | ||||||||
3052 | add_nlist = false; | ||||||||
3053 | if (N_SO_index != UINT32_MAX0xffffffffU) { | ||||||||
3054 | // Set the size of the N_SO to the terminating | ||||||||
3055 | // index of this N_SO so that we can always skip | ||||||||
3056 | // the entire N_SO if we need to navigate more | ||||||||
3057 | // quickly at the source level when parsing STABS | ||||||||
3058 | symbol_ptr = symtab->SymbolAtIndex(N_SO_index); | ||||||||
3059 | symbol_ptr->SetByteSize(sym_idx); | ||||||||
3060 | symbol_ptr->SetSizeIsSibling(true); | ||||||||
3061 | } | ||||||||
3062 | N_NSYM_indexes.clear(); | ||||||||
3063 | N_INCL_indexes.clear(); | ||||||||
3064 | N_BRAC_indexes.clear(); | ||||||||
3065 | N_COMM_indexes.clear(); | ||||||||
3066 | N_FUN_indexes.clear(); | ||||||||
3067 | N_SO_index = UINT32_MAX0xffffffffU; | ||||||||
3068 | } else { | ||||||||
3069 | // We use the current number of symbols in the | ||||||||
3070 | // symbol table in lieu of using nlist_idx in case | ||||||||
3071 | // we ever start trimming entries out | ||||||||
3072 | const bool N_SO_has_full_path = symbol_name[0] == '/'; | ||||||||
3073 | if (N_SO_has_full_path) { | ||||||||
3074 | if ((N_SO_index == sym_idx - 1) && | ||||||||
3075 | ((sym_idx - 1) < num_syms)) { | ||||||||
3076 | // We have two consecutive N_SO entries where | ||||||||
3077 | // the first contains a directory and the | ||||||||
3078 | // second contains a full path. | ||||||||
3079 | sym[sym_idx - 1].GetMangled().SetValue( | ||||||||
3080 | ConstString(symbol_name), false); | ||||||||
3081 | m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1; | ||||||||
3082 | add_nlist = false; | ||||||||
3083 | } else { | ||||||||
3084 | // This is the first entry in a N_SO that | ||||||||
3085 | // contains a directory or | ||||||||
3086 | // a full path to the source file | ||||||||
3087 | N_SO_index = sym_idx; | ||||||||
3088 | } | ||||||||
3089 | } else if ((N_SO_index == sym_idx - 1) && | ||||||||
3090 | ((sym_idx - 1) < num_syms)) { | ||||||||
3091 | // This is usually the second N_SO entry that | ||||||||
3092 | // contains just the filename, so here we combine | ||||||||
3093 | // it with the first one if we are minimizing the | ||||||||
3094 | // symbol table | ||||||||
3095 | const char *so_path = sym[sym_idx - 1] | ||||||||
3096 | .GetMangled() | ||||||||
3097 | .GetDemangledName() | ||||||||
3098 | .AsCString(); | ||||||||
3099 | if (so_path && so_path[0]) { | ||||||||
3100 | std::string full_so_path(so_path); | ||||||||
3101 | const size_t double_slash_pos = | ||||||||
3102 | full_so_path.find("//"); | ||||||||
3103 | if (double_slash_pos != std::string::npos) { | ||||||||
3104 | // The linker has been generating bad N_SO | ||||||||
3105 | // entries with doubled up paths | ||||||||
3106 | // in the format "%s%s" where the first | ||||||||
3107 | // string in the DW_AT_comp_dir, and the | ||||||||
3108 | // second is the directory for the source | ||||||||
3109 | // file so you end up with a path that looks | ||||||||
3110 | // like "/tmp/src//tmp/src/" | ||||||||
3111 | FileSpec so_dir(so_path); | ||||||||
3112 | if (!FileSystem::Instance().Exists(so_dir)) { | ||||||||
3113 | so_dir.SetFile( | ||||||||
3114 | &full_so_path[double_slash_pos + 1], | ||||||||
3115 | FileSpec::Style::native); | ||||||||
3116 | if (FileSystem::Instance().Exists(so_dir)) { | ||||||||
3117 | // Trim off the incorrect path | ||||||||
3118 | full_so_path.erase(0, double_slash_pos + 1); | ||||||||
3119 | } | ||||||||
3120 | } | ||||||||
3121 | } | ||||||||
3122 | if (*full_so_path.rbegin() != '/') | ||||||||
3123 | full_so_path += '/'; | ||||||||
3124 | full_so_path += symbol_name; | ||||||||
3125 | sym[sym_idx - 1].GetMangled().SetValue( | ||||||||
3126 | ConstString(full_so_path.c_str()), false); | ||||||||
3127 | add_nlist = false; | ||||||||
3128 | m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1; | ||||||||
3129 | } | ||||||||
3130 | } else { | ||||||||
3131 | // This could be a relative path to a N_SO | ||||||||
3132 | N_SO_index = sym_idx; | ||||||||
3133 | } | ||||||||
3134 | } | ||||||||
3135 | break; | ||||||||
3136 | |||||||||
3137 | case N_OSO: | ||||||||
3138 | // object file name: name,,0,0,st_mtime | ||||||||
3139 | type = eSymbolTypeObjectFile; | ||||||||
3140 | break; | ||||||||
3141 | |||||||||
3142 | case N_LSYM: | ||||||||
3143 | // local sym: name,,NO_SECT,type,offset | ||||||||
3144 | type = eSymbolTypeLocal; | ||||||||
3145 | break; | ||||||||
3146 | |||||||||
3147 | // INCL scopes | ||||||||
3148 | case N_BINCL: | ||||||||
3149 | // include file beginning: name,,NO_SECT,0,sum We use | ||||||||
3150 | // the current number of symbols in the symbol table | ||||||||
3151 | // in lieu of using nlist_idx in case we ever start | ||||||||
3152 | // trimming entries out | ||||||||
3153 | N_INCL_indexes.push_back(sym_idx); | ||||||||
3154 | type = eSymbolTypeScopeBegin; | ||||||||
3155 | break; | ||||||||
3156 | |||||||||
3157 | case N_EINCL: | ||||||||
3158 | // include file end: name,,NO_SECT,0,0 | ||||||||
3159 | // Set the size of the N_BINCL to the terminating | ||||||||
3160 | // index of this N_EINCL so that we can always skip | ||||||||
3161 | // the entire symbol if we need to navigate more | ||||||||
3162 | // quickly at the source level when parsing STABS | ||||||||
3163 | if (!N_INCL_indexes.empty()) { | ||||||||
3164 | symbol_ptr = | ||||||||
3165 | symtab->SymbolAtIndex(N_INCL_indexes.back()); | ||||||||
3166 | symbol_ptr->SetByteSize(sym_idx + 1); | ||||||||
3167 | symbol_ptr->SetSizeIsSibling(true); | ||||||||
3168 | N_INCL_indexes.pop_back(); | ||||||||
3169 | } | ||||||||
3170 | type = eSymbolTypeScopeEnd; | ||||||||
3171 | break; | ||||||||
3172 | |||||||||
3173 | case N_SOL: | ||||||||
3174 | // #included file name: name,,n_sect,0,address | ||||||||
3175 | type = eSymbolTypeHeaderFile; | ||||||||
3176 | |||||||||
3177 | // We currently don't use the header files on darwin | ||||||||
3178 | add_nlist = false; | ||||||||
3179 | break; | ||||||||
3180 | |||||||||
3181 | case N_PARAMS: | ||||||||
3182 | // compiler parameters: name,,NO_SECT,0,0 | ||||||||
3183 | type = eSymbolTypeCompiler; | ||||||||
3184 | break; | ||||||||
3185 | |||||||||
3186 | case N_VERSION: | ||||||||
3187 | // compiler version: name,,NO_SECT,0,0 | ||||||||
3188 | type = eSymbolTypeCompiler; | ||||||||
3189 | break; | ||||||||
3190 | |||||||||
3191 | case N_OLEVEL: | ||||||||
3192 | // compiler -O level: name,,NO_SECT,0,0 | ||||||||
3193 | type = eSymbolTypeCompiler; | ||||||||
3194 | break; | ||||||||
3195 | |||||||||
3196 | case N_PSYM: | ||||||||
3197 | // parameter: name,,NO_SECT,type,offset | ||||||||
3198 | type = eSymbolTypeVariable; | ||||||||
3199 | break; | ||||||||
3200 | |||||||||
3201 | case N_ENTRY: | ||||||||
3202 | // alternate entry: name,,n_sect,linenumber,address | ||||||||
3203 | symbol_section = section_info.GetSection(nlist.n_sect, | ||||||||
3204 | nlist.n_value); | ||||||||
3205 | type = eSymbolTypeLineEntry; | ||||||||
3206 | break; | ||||||||
3207 | |||||||||
3208 | // Left and Right Braces | ||||||||
3209 | case N_LBRAC: | ||||||||
3210 | // left bracket: 0,,NO_SECT,nesting level,address We | ||||||||
3211 | // use the current number of symbols in the symbol | ||||||||
3212 | // table in lieu of using nlist_idx in case we ever | ||||||||
3213 | // start trimming entries out | ||||||||
3214 | symbol_section = section_info.GetSection(nlist.n_sect, | ||||||||
3215 | nlist.n_value); | ||||||||
3216 | N_BRAC_indexes.push_back(sym_idx); | ||||||||
3217 | type = eSymbolTypeScopeBegin; | ||||||||
3218 | break; | ||||||||
3219 | |||||||||
3220 | case N_RBRAC: | ||||||||
3221 | // right bracket: 0,,NO_SECT,nesting level,address | ||||||||
3222 | // Set the size of the N_LBRAC to the terminating | ||||||||
3223 | // index of this N_RBRAC so that we can always skip | ||||||||
3224 | // the entire symbol if we need to navigate more | ||||||||
3225 | // quickly at the source level when parsing STABS | ||||||||
3226 | symbol_section = section_info.GetSection(nlist.n_sect, | ||||||||
3227 | nlist.n_value); | ||||||||
3228 | if (!N_BRAC_indexes.empty()) { | ||||||||
3229 | symbol_ptr = | ||||||||
3230 | symtab->SymbolAtIndex(N_BRAC_indexes.back()); | ||||||||
3231 | symbol_ptr->SetByteSize(sym_idx + 1); | ||||||||
3232 | symbol_ptr->SetSizeIsSibling(true); | ||||||||
3233 | N_BRAC_indexes.pop_back(); | ||||||||
3234 | } | ||||||||
3235 | type = eSymbolTypeScopeEnd; | ||||||||
3236 | break; | ||||||||
3237 | |||||||||
3238 | case N_EXCL: | ||||||||
3239 | // deleted include file: name,,NO_SECT,0,sum | ||||||||
3240 | type = eSymbolTypeHeaderFile; | ||||||||
3241 | break; | ||||||||
3242 | |||||||||
3243 | // COMM scopes | ||||||||
3244 | case N_BCOMM: | ||||||||
3245 | // begin common: name,,NO_SECT,0,0 | ||||||||
3246 | // We use the current number of symbols in the symbol | ||||||||
3247 | // table in lieu of using nlist_idx in case we ever | ||||||||
3248 | // start trimming entries out | ||||||||
3249 | type = eSymbolTypeScopeBegin; | ||||||||
3250 | N_COMM_indexes.push_back(sym_idx); | ||||||||
3251 | break; | ||||||||
3252 | |||||||||
3253 | case N_ECOML: | ||||||||
3254 | // end common (local name): 0,,n_sect,0,address | ||||||||
3255 | symbol_section = section_info.GetSection(nlist.n_sect, | ||||||||
3256 | nlist.n_value); | ||||||||
3257 | // Fall through | ||||||||
3258 | |||||||||
3259 | case N_ECOMM: | ||||||||
3260 | // end common: name,,n_sect,0,0 | ||||||||
3261 | // Set the size of the N_BCOMM to the terminating | ||||||||
3262 | // index of this N_ECOMM/N_ECOML so that we can | ||||||||
3263 | // always skip the entire symbol if we need to | ||||||||
3264 | // navigate more quickly at the source level when | ||||||||
3265 | // parsing STABS | ||||||||
3266 | if (!N_COMM_indexes.empty()) { | ||||||||
3267 | symbol_ptr = | ||||||||
3268 | symtab->SymbolAtIndex(N_COMM_indexes.back()); | ||||||||
3269 | symbol_ptr->SetByteSize(sym_idx + 1); | ||||||||
3270 | symbol_ptr->SetSizeIsSibling(true); | ||||||||
3271 | N_COMM_indexes.pop_back(); | ||||||||
3272 | } | ||||||||
3273 | type = eSymbolTypeScopeEnd; | ||||||||
3274 | break; | ||||||||
3275 | |||||||||
3276 | case N_LENG: | ||||||||
3277 | // second stab entry with length information | ||||||||
3278 | type = eSymbolTypeAdditional; | ||||||||
3279 | break; | ||||||||
3280 | |||||||||
3281 | default: | ||||||||
3282 | break; | ||||||||
3283 | } | ||||||||
3284 | } else { | ||||||||
3285 | // uint8_t n_pext = N_PEXT & nlist.n_type; | ||||||||
3286 | uint8_t n_type = N_TYPE & nlist.n_type; | ||||||||
3287 | sym[sym_idx].SetExternal((N_EXT & nlist.n_type) != 0); | ||||||||
3288 | |||||||||
3289 | switch (n_type) { | ||||||||
3290 | case N_INDR: { | ||||||||
3291 | const char *reexport_name_cstr = | ||||||||
3292 | strtab_data.PeekCStr(nlist.n_value); | ||||||||
3293 | if (reexport_name_cstr && reexport_name_cstr[0]) { | ||||||||
3294 | type = eSymbolTypeReExported; | ||||||||
3295 | ConstString reexport_name( | ||||||||
3296 | reexport_name_cstr + | ||||||||
3297 | ((reexport_name_cstr[0] == '_') ? 1 : 0)); | ||||||||
3298 | sym[sym_idx].SetReExportedSymbolName(reexport_name); | ||||||||
3299 | set_value = false; | ||||||||
3300 | reexport_shlib_needs_fixup[sym_idx] = reexport_name; | ||||||||
3301 | indirect_symbol_names.insert(ConstString( | ||||||||
3302 | symbol_name + ((symbol_name[0] == '_') ? 1 : 0))); | ||||||||
3303 | } else | ||||||||
3304 | type = eSymbolTypeUndefined; | ||||||||
3305 | } break; | ||||||||
3306 | |||||||||
3307 | case N_UNDF: | ||||||||
3308 | if (symbol_name && symbol_name[0]) { | ||||||||
3309 | ConstString undefined_name( | ||||||||
3310 | symbol_name + ((symbol_name[0] == '_') ? 1 : 0)); | ||||||||
3311 | undefined_name_to_desc[undefined_name] = nlist.n_desc; | ||||||||
3312 | } | ||||||||
3313 | // Fall through | ||||||||
3314 | case N_PBUD: | ||||||||
3315 | type = eSymbolTypeUndefined; | ||||||||
3316 | break; | ||||||||
3317 | |||||||||
3318 | case N_ABS: | ||||||||
3319 | type = eSymbolTypeAbsolute; | ||||||||
3320 | break; | ||||||||
3321 | |||||||||
3322 | case N_SECT: { | ||||||||
3323 | symbol_section = section_info.GetSection(nlist.n_sect, | ||||||||
3324 | nlist.n_value); | ||||||||
3325 | |||||||||
3326 | if (symbol_section == NULL__null) { | ||||||||
3327 | // TODO: warn about this? | ||||||||
3328 | add_nlist = false; | ||||||||
3329 | break; | ||||||||
3330 | } | ||||||||
3331 | |||||||||
3332 | if (TEXT_eh_frame_sectID == nlist.n_sect) { | ||||||||
3333 | type = eSymbolTypeException; | ||||||||
3334 | } else { | ||||||||
3335 | uint32_t section_type = | ||||||||
3336 | symbol_section->Get() & SECTION_TYPE; | ||||||||
3337 | |||||||||
3338 | switch (section_type) { | ||||||||
3339 | case S_CSTRING_LITERALS: | ||||||||
3340 | type = eSymbolTypeData; | ||||||||
3341 | break; // section with only literal C strings | ||||||||
3342 | case S_4BYTE_LITERALS: | ||||||||
3343 | type = eSymbolTypeData; | ||||||||
3344 | break; // section with only 4 byte literals | ||||||||
3345 | case S_8BYTE_LITERALS: | ||||||||
3346 | type = eSymbolTypeData; | ||||||||
3347 | break; // section with only 8 byte literals | ||||||||
3348 | case S_LITERAL_POINTERS: | ||||||||
3349 | type = eSymbolTypeTrampoline; | ||||||||
3350 | break; // section with only pointers to literals | ||||||||
3351 | case S_NON_LAZY_SYMBOL_POINTERS: | ||||||||
3352 | type = eSymbolTypeTrampoline; | ||||||||
3353 | break; // section with only non-lazy symbol | ||||||||
3354 | // pointers | ||||||||
3355 | case S_LAZY_SYMBOL_POINTERS: | ||||||||
3356 | type = eSymbolTypeTrampoline; | ||||||||
3357 | break; // section with only lazy symbol pointers | ||||||||
3358 | case S_SYMBOL_STUBS: | ||||||||
3359 | type = eSymbolTypeTrampoline; | ||||||||
3360 | break; // section with only symbol stubs, byte | ||||||||
3361 | // size of stub in the reserved2 field | ||||||||
3362 | case S_MOD_INIT_FUNC_POINTERS: | ||||||||
3363 | type = eSymbolTypeCode; | ||||||||
3364 | break; // section with only function pointers for | ||||||||
3365 | // initialization | ||||||||
3366 | case S_MOD_TERM_FUNC_POINTERS: | ||||||||
3367 | type = eSymbolTypeCode; | ||||||||
3368 | break; // section with only function pointers for | ||||||||
3369 | // termination | ||||||||
3370 | case S_INTERPOSING: | ||||||||
3371 | type = eSymbolTypeTrampoline; | ||||||||
3372 | break; // section with only pairs of function | ||||||||
3373 | // pointers for interposing | ||||||||
3374 | case S_16BYTE_LITERALS: | ||||||||
3375 | type = eSymbolTypeData; | ||||||||
3376 | break; // section with only 16 byte literals | ||||||||
3377 | case S_DTRACE_DOF: | ||||||||
3378 | type = eSymbolTypeInstrumentation; | ||||||||
3379 | break; | ||||||||
3380 | case S_LAZY_DYLIB_SYMBOL_POINTERS: | ||||||||
3381 | type = eSymbolTypeTrampoline; | ||||||||
3382 | break; | ||||||||
3383 | default: | ||||||||
3384 | switch (symbol_section->GetType()) { | ||||||||
3385 | case lldb::eSectionTypeCode: | ||||||||
3386 | type = eSymbolTypeCode; | ||||||||
3387 | break; | ||||||||
3388 | case eSectionTypeData: | ||||||||
3389 | case eSectionTypeDataCString: // Inlined C string | ||||||||
3390 | // data | ||||||||
3391 | case eSectionTypeDataCStringPointers: // Pointers | ||||||||
3392 | // to C | ||||||||
3393 | // string | ||||||||
3394 | // data | ||||||||
3395 | case eSectionTypeDataSymbolAddress: // Address of | ||||||||
3396 | // a symbol in | ||||||||
3397 | // the symbol | ||||||||
3398 | // table | ||||||||
3399 | case eSectionTypeData4: | ||||||||
3400 | case eSectionTypeData8: | ||||||||
3401 | case eSectionTypeData16: | ||||||||
3402 | type = eSymbolTypeData; | ||||||||
3403 | break; | ||||||||
3404 | default: | ||||||||
3405 | break; | ||||||||
3406 | } | ||||||||
3407 | break; | ||||||||
3408 | } | ||||||||
3409 | |||||||||
3410 | if (type == eSymbolTypeInvalid) { | ||||||||
3411 | const char *symbol_sect_name = | ||||||||
3412 | symbol_section->GetName().AsCString(); | ||||||||
3413 | if (symbol_section->IsDescendant( | ||||||||
3414 | text_section_sp.get())) { | ||||||||
3415 | if (symbol_section->IsClear( | ||||||||
3416 | S_ATTR_PURE_INSTRUCTIONS | | ||||||||
3417 | S_ATTR_SELF_MODIFYING_CODE | | ||||||||
3418 | S_ATTR_SOME_INSTRUCTIONS)) | ||||||||
3419 | type = eSymbolTypeData; | ||||||||
3420 | else | ||||||||
3421 | type = eSymbolTypeCode; | ||||||||
3422 | } else if (symbol_section->IsDescendant( | ||||||||
3423 | data_section_sp.get()) || | ||||||||
3424 | symbol_section->IsDescendant( | ||||||||
3425 | data_dirty_section_sp.get()) || | ||||||||
3426 | symbol_section->IsDescendant( | ||||||||
3427 | data_const_section_sp.get())) { | ||||||||
3428 | if (symbol_sect_name && | ||||||||
3429 | ::strstr(symbol_sect_name, "__objc") == | ||||||||
3430 | symbol_sect_name) { | ||||||||
3431 | type = eSymbolTypeRuntime; | ||||||||
3432 | |||||||||
3433 | if (symbol_name) { | ||||||||
3434 | llvm::StringRef symbol_name_ref(symbol_name); | ||||||||
3435 | if (symbol_name_ref.startswith("_OBJC_")) { | ||||||||
3436 | llvm::StringRef | ||||||||
3437 | g_objc_v2_prefix_class( | ||||||||
3438 | "_OBJC_CLASS_$_"); | ||||||||
3439 | llvm::StringRef | ||||||||
3440 | g_objc_v2_prefix_metaclass( | ||||||||
3441 | "_OBJC_METACLASS_$_"); | ||||||||
3442 | llvm::StringRef | ||||||||
3443 | g_objc_v2_prefix_ivar("_OBJC_IVAR_$_"); | ||||||||
3444 | if (symbol_name_ref.startswith( | ||||||||
3445 | g_objc_v2_prefix_class)) { | ||||||||
3446 | symbol_name_non_abi_mangled = | ||||||||
3447 | symbol_name + 1; | ||||||||
3448 | symbol_name = | ||||||||
3449 | symbol_name + | ||||||||
3450 | g_objc_v2_prefix_class.size(); | ||||||||
3451 | type = eSymbolTypeObjCClass; | ||||||||
3452 | demangled_is_synthesized = true; | ||||||||
3453 | } else if ( | ||||||||
3454 | symbol_name_ref.startswith( | ||||||||
3455 | g_objc_v2_prefix_metaclass)) { | ||||||||
3456 | symbol_name_non_abi_mangled = | ||||||||
3457 | symbol_name + 1; | ||||||||
3458 | symbol_name = | ||||||||
3459 | symbol_name + | ||||||||
3460 | g_objc_v2_prefix_metaclass.size(); | ||||||||
3461 | type = eSymbolTypeObjCMetaClass; | ||||||||
3462 | demangled_is_synthesized = true; | ||||||||
3463 | } else if (symbol_name_ref.startswith( | ||||||||
3464 | g_objc_v2_prefix_ivar)) { | ||||||||
3465 | symbol_name_non_abi_mangled = | ||||||||
3466 | symbol_name + 1; | ||||||||
3467 | symbol_name = | ||||||||
3468 | symbol_name + | ||||||||
3469 | g_objc_v2_prefix_ivar.size(); | ||||||||
3470 | type = eSymbolTypeObjCIVar; | ||||||||
3471 | demangled_is_synthesized = true; | ||||||||
3472 | } | ||||||||
3473 | } | ||||||||
3474 | } | ||||||||
3475 | } else if (symbol_sect_name && | ||||||||
3476 | ::strstr(symbol_sect_name, | ||||||||
3477 | "__gcc_except_tab") == | ||||||||
3478 | symbol_sect_name) { | ||||||||
3479 | type = eSymbolTypeException; | ||||||||
3480 | } else { | ||||||||
3481 | type = eSymbolTypeData; | ||||||||
3482 | } | ||||||||
3483 | } else if (symbol_sect_name && | ||||||||
3484 | ::strstr(symbol_sect_name, "__IMPORT") == | ||||||||
3485 | symbol_sect_name) { | ||||||||
3486 | type = eSymbolTypeTrampoline; | ||||||||
3487 | } else if (symbol_section->IsDescendant( | ||||||||
3488 | objc_section_sp.get())) { | ||||||||
3489 | type = eSymbolTypeRuntime; | ||||||||
3490 | if (symbol_name && symbol_name[0] == '.') { | ||||||||
3491 | llvm::StringRef symbol_name_ref(symbol_name); | ||||||||
3492 | llvm::StringRef | ||||||||
3493 | g_objc_v1_prefix_class(".objc_class_name_"); | ||||||||
3494 | if (symbol_name_ref.startswith( | ||||||||
3495 | g_objc_v1_prefix_class)) { | ||||||||
3496 | symbol_name_non_abi_mangled = symbol_name; | ||||||||
3497 | symbol_name = symbol_name + | ||||||||
3498 | g_objc_v1_prefix_class.size(); | ||||||||
3499 | type = eSymbolTypeObjCClass; | ||||||||
3500 | demangled_is_synthesized = true; | ||||||||
3501 | } | ||||||||
3502 | } | ||||||||
3503 | } | ||||||||
3504 | } | ||||||||
3505 | } | ||||||||
3506 | } break; | ||||||||
3507 | } | ||||||||
3508 | } | ||||||||
3509 | |||||||||
3510 | if (add_nlist) { | ||||||||
3511 | uint64_t symbol_value = nlist.n_value; | ||||||||
3512 | if (symbol_name_non_abi_mangled) { | ||||||||
3513 | sym[sym_idx].GetMangled().SetMangledName( | ||||||||
3514 | ConstString(symbol_name_non_abi_mangled)); | ||||||||
3515 | sym[sym_idx].GetMangled().SetDemangledName( | ||||||||
3516 | ConstString(symbol_name)); | ||||||||
3517 | } else { | ||||||||
3518 | bool symbol_name_is_mangled = false; | ||||||||
3519 | |||||||||
3520 | if (symbol_name && symbol_name[0] == '_') { | ||||||||
3521 | symbol_name_is_mangled = symbol_name[1] == '_'; | ||||||||
3522 | symbol_name++; // Skip the leading underscore | ||||||||
3523 | } | ||||||||
3524 | |||||||||
3525 | if (symbol_name) { | ||||||||
3526 | ConstString const_symbol_name(symbol_name); | ||||||||
3527 | sym[sym_idx].GetMangled().SetValue( | ||||||||
3528 | const_symbol_name, symbol_name_is_mangled); | ||||||||
3529 | if (is_gsym && is_debug) { | ||||||||
3530 | const char *gsym_name = | ||||||||
3531 | sym[sym_idx] | ||||||||
3532 | .GetMangled() | ||||||||
3533 | .GetName(Mangled::ePreferMangled) | ||||||||
3534 | .GetCString(); | ||||||||
3535 | if (gsym_name) | ||||||||
3536 | N_GSYM_name_to_sym_idx[gsym_name] = sym_idx; | ||||||||
3537 | } | ||||||||
3538 | } | ||||||||
3539 | } | ||||||||
3540 | if (symbol_section) { | ||||||||
3541 | const addr_t section_file_addr = | ||||||||
3542 | symbol_section->GetFileAddress(); | ||||||||
3543 | if (symbol_byte_size == 0 && | ||||||||
3544 | function_starts_count > 0) { | ||||||||
3545 | addr_t symbol_lookup_file_addr = nlist.n_value; | ||||||||
3546 | // Do an exact address match for non-ARM addresses, | ||||||||
3547 | // else get the closest since the symbol might be a | ||||||||
3548 | // thumb symbol which has an address with bit zero | ||||||||
3549 | // set | ||||||||
3550 | FunctionStarts::Entry *func_start_entry = | ||||||||
3551 | function_starts.FindEntry(symbol_lookup_file_addr, | ||||||||
3552 | !is_arm); | ||||||||
3553 | if (is_arm && func_start_entry) { | ||||||||
3554 | // Verify that the function start address is the | ||||||||
3555 | // symbol address (ARM) or the symbol address + 1 | ||||||||
3556 | // (thumb) | ||||||||
3557 | if (func_start_entry->addr != | ||||||||
3558 | symbol_lookup_file_addr && | ||||||||
3559 | func_start_entry->addr != | ||||||||
3560 | (symbol_lookup_file_addr + 1)) { | ||||||||
3561 | // Not the right entry, NULL it out... | ||||||||
3562 | func_start_entry = NULL__null; | ||||||||
3563 | } | ||||||||
3564 | } | ||||||||
3565 | if (func_start_entry) { | ||||||||
3566 | func_start_entry->data = true; | ||||||||
3567 | |||||||||
3568 | addr_t symbol_file_addr = func_start_entry->addr; | ||||||||
3569 | uint32_t symbol_flags = 0; | ||||||||
3570 | if (is_arm) { | ||||||||
3571 | if (symbol_file_addr & 1) | ||||||||
3572 | symbol_flags = MACHO_NLIST_ARM_SYMBOL_IS_THUMB0x0008; | ||||||||
3573 | symbol_file_addr &= THUMB_ADDRESS_BIT_MASK0xfffffffffffffffeull; | ||||||||
3574 | } | ||||||||
3575 | |||||||||
3576 | const FunctionStarts::Entry *next_func_start_entry = | ||||||||
3577 | function_starts.FindNextEntry(func_start_entry); | ||||||||
3578 | const addr_t section_end_file_addr = | ||||||||
3579 | section_file_addr + | ||||||||
3580 | symbol_section->GetByteSize(); | ||||||||
3581 | if (next_func_start_entry) { | ||||||||
3582 | addr_t next_symbol_file_addr = | ||||||||
3583 | next_func_start_entry->addr; | ||||||||
3584 | // Be sure the clear the Thumb address bit when | ||||||||
3585 | // we calculate the size from the current and | ||||||||
3586 | // next address | ||||||||
3587 | if (is_arm) | ||||||||
3588 | next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK0xfffffffffffffffeull; | ||||||||
3589 | symbol_byte_size = std::min<lldb::addr_t>( | ||||||||
3590 | next_symbol_file_addr - symbol_file_addr, | ||||||||
3591 | section_end_file_addr - symbol_file_addr); | ||||||||
3592 | } else { | ||||||||
3593 | symbol_byte_size = | ||||||||
3594 | section_end_file_addr - symbol_file_addr; | ||||||||
3595 | } | ||||||||
3596 | } | ||||||||
3597 | } | ||||||||
3598 | symbol_value -= section_file_addr; | ||||||||
3599 | } | ||||||||
3600 | |||||||||
3601 | if (is_debug == false) { | ||||||||
3602 | if (type == eSymbolTypeCode) { | ||||||||
3603 | // See if we can find a N_FUN entry for any code | ||||||||
3604 | // symbols. If we do find a match, and the name | ||||||||
3605 | // matches, then we can merge the two into just the | ||||||||
3606 | // function symbol to avoid duplicate entries in | ||||||||
3607 | // the symbol table | ||||||||
3608 | auto range = | ||||||||
3609 | N_FUN_addr_to_sym_idx.equal_range(nlist.n_value); | ||||||||
3610 | if (range.first != range.second) { | ||||||||
3611 | bool found_it = false; | ||||||||
3612 | for (auto pos = range.first; pos != range.second; | ||||||||
3613 | ++pos) { | ||||||||
3614 | if (sym[sym_idx].GetMangled().GetName( | ||||||||
3615 | Mangled::ePreferMangled) == | ||||||||
3616 | sym[pos->second].GetMangled().GetName( | ||||||||
3617 | Mangled::ePreferMangled)) { | ||||||||
3618 | m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; | ||||||||
3619 | // We just need the flags from the linker | ||||||||
3620 | // symbol, so put these flags | ||||||||
3621 | // into the N_FUN flags to avoid duplicate | ||||||||
3622 | // symbols in the symbol table | ||||||||
3623 | sym[pos->second].SetExternal( | ||||||||
3624 | sym[sym_idx].IsExternal()); | ||||||||
3625 | sym[pos->second].SetFlags(nlist.n_type << 16 | | ||||||||
3626 | nlist.n_desc); | ||||||||
3627 | if (resolver_addresses.find(nlist.n_value) != | ||||||||
3628 | resolver_addresses.end()) | ||||||||
3629 | sym[pos->second].SetType(eSymbolTypeResolver); | ||||||||
3630 | sym[sym_idx].Clear(); | ||||||||
3631 | found_it = true; | ||||||||
3632 | break; | ||||||||
3633 | } | ||||||||
3634 | } | ||||||||
3635 | if (found_it) | ||||||||
3636 | continue; | ||||||||
3637 | } else { | ||||||||
3638 | if (resolver_addresses.find(nlist.n_value) != | ||||||||
3639 | resolver_addresses.end()) | ||||||||
3640 | type = eSymbolTypeResolver; | ||||||||
3641 | } | ||||||||
3642 | } else if (type == eSymbolTypeData || | ||||||||
3643 | type == eSymbolTypeObjCClass || | ||||||||
3644 | type == eSymbolTypeObjCMetaClass || | ||||||||
3645 | type == eSymbolTypeObjCIVar) { | ||||||||
3646 | // See if we can find a N_STSYM entry for any data | ||||||||
3647 | // symbols. If we do find a match, and the name | ||||||||
3648 | // matches, then we can merge the two into just the | ||||||||
3649 | // Static symbol to avoid duplicate entries in the | ||||||||
3650 | // symbol table | ||||||||
3651 | auto range = N_STSYM_addr_to_sym_idx.equal_range( | ||||||||
3652 | nlist.n_value); | ||||||||
3653 | if (range.first != range.second) { | ||||||||
3654 | bool found_it = false; | ||||||||
3655 | for (auto pos = range.first; pos != range.second; | ||||||||
3656 | ++pos) { | ||||||||
3657 | if (sym[sym_idx].GetMangled().GetName( | ||||||||
3658 | Mangled::ePreferMangled) == | ||||||||
3659 | sym[pos->second].GetMangled().GetName( | ||||||||
3660 | Mangled::ePreferMangled)) { | ||||||||
3661 | m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; | ||||||||
3662 | // We just need the flags from the linker | ||||||||
3663 | // symbol, so put these flags | ||||||||
3664 | // into the N_STSYM flags to avoid duplicate | ||||||||
3665 | // symbols in the symbol table | ||||||||
3666 | sym[pos->second].SetExternal( | ||||||||
3667 | sym[sym_idx].IsExternal()); | ||||||||
3668 | sym[pos->second].SetFlags(nlist.n_type << 16 | | ||||||||
3669 | nlist.n_desc); | ||||||||
3670 | sym[sym_idx].Clear(); | ||||||||
3671 | found_it = true; | ||||||||
3672 | break; | ||||||||
3673 | } | ||||||||
3674 | } | ||||||||
3675 | if (found_it) | ||||||||
3676 | continue; | ||||||||
3677 | } else { | ||||||||
3678 | const char *gsym_name = | ||||||||
3679 | sym[sym_idx] | ||||||||
3680 | .GetMangled() | ||||||||
3681 | .GetName(Mangled::ePreferMangled) | ||||||||
3682 | .GetCString(); | ||||||||
3683 | if (gsym_name) { | ||||||||
3684 | // Combine N_GSYM stab entries with the non | ||||||||
3685 | // stab symbol | ||||||||
3686 | ConstNameToSymbolIndexMap::const_iterator pos = | ||||||||
3687 | N_GSYM_name_to_sym_idx.find(gsym_name); | ||||||||
3688 | if (pos != N_GSYM_name_to_sym_idx.end()) { | ||||||||
3689 | const uint32_t GSYM_sym_idx = pos->second; | ||||||||
3690 | m_nlist_idx_to_sym_idx[nlist_idx] = | ||||||||
3691 | GSYM_sym_idx; | ||||||||
3692 | // Copy the address, because often the N_GSYM | ||||||||
3693 | // address has an invalid address of zero | ||||||||
3694 | // when the global is a common symbol | ||||||||
3695 | sym[GSYM_sym_idx].GetAddressRef().SetSection( | ||||||||
3696 | symbol_section); | ||||||||
3697 | sym[GSYM_sym_idx].GetAddressRef().SetOffset( | ||||||||
3698 | symbol_value); | ||||||||
3699 | add_symbol_addr(sym[GSYM_sym_idx] | ||||||||
3700 | .GetAddress() | ||||||||
3701 | .GetFileAddress()); | ||||||||
3702 | // We just need the flags from the linker | ||||||||
3703 | // symbol, so put these flags | ||||||||
3704 | // into the N_GSYM flags to avoid duplicate | ||||||||
3705 | // symbols in the symbol table | ||||||||
3706 | sym[GSYM_sym_idx].SetFlags(nlist.n_type << 16 | | ||||||||
3707 | nlist.n_desc); | ||||||||
3708 | sym[sym_idx].Clear(); | ||||||||
3709 | continue; | ||||||||
3710 | } | ||||||||
3711 | } | ||||||||
3712 | } | ||||||||
3713 | } | ||||||||
3714 | } | ||||||||
3715 | |||||||||
3716 | sym[sym_idx].SetID(nlist_idx); | ||||||||
3717 | sym[sym_idx].SetType(type); | ||||||||
3718 | if (set_value) { | ||||||||
3719 | sym[sym_idx].GetAddressRef().SetSection(symbol_section); | ||||||||
3720 | sym[sym_idx].GetAddressRef().SetOffset(symbol_value); | ||||||||
3721 | add_symbol_addr( | ||||||||
3722 | sym[sym_idx].GetAddress().GetFileAddress()); | ||||||||
3723 | } | ||||||||
3724 | sym[sym_idx].SetFlags(nlist.n_type << 16 | nlist.n_desc); | ||||||||
3725 | |||||||||
3726 | if (symbol_byte_size > 0) | ||||||||
3727 | sym[sym_idx].SetByteSize(symbol_byte_size); | ||||||||
3728 | |||||||||
3729 | if (demangled_is_synthesized) | ||||||||
3730 | sym[sym_idx].SetDemangledNameIsSynthesized(true); | ||||||||
3731 | ++sym_idx; | ||||||||
3732 | } else { | ||||||||
3733 | sym[sym_idx].Clear(); | ||||||||
3734 | } | ||||||||
3735 | } | ||||||||
3736 | ///////////////////////////// | ||||||||
3737 | } | ||||||||
3738 | break; // No more entries to consider | ||||||||
3739 | } | ||||||||
3740 | } | ||||||||
3741 | |||||||||
3742 | for (const auto &pos : reexport_shlib_needs_fixup) { | ||||||||
3743 | const auto undef_pos = undefined_name_to_desc.find(pos.second); | ||||||||
3744 | if (undef_pos != undefined_name_to_desc.end()) { | ||||||||
3745 | const uint8_t dylib_ordinal = | ||||||||
3746 | llvm::MachO::GET_LIBRARY_ORDINAL(undef_pos->second); | ||||||||
3747 | if (dylib_ordinal > 0 && dylib_ordinal < dylib_files.GetSize()) | ||||||||
3748 | sym[pos.first].SetReExportedSymbolSharedLibrary( | ||||||||
3749 | dylib_files.GetFileSpecAtIndex(dylib_ordinal - 1)); | ||||||||
3750 | } | ||||||||
3751 | } | ||||||||
3752 | } | ||||||||
3753 | } | ||||||||
3754 | } | ||||||||
3755 | } | ||||||||
3756 | } | ||||||||
3757 | |||||||||
3758 | // Must reset this in case it was mutated above! | ||||||||
3759 | nlist_data_offset = 0; | ||||||||
3760 | #endif | ||||||||
3761 | |||||||||
3762 | if (nlist_data.GetByteSize() > 0) { | ||||||||
3763 | |||||||||
3764 | // If the sym array was not created while parsing the DSC unmapped | ||||||||
3765 | // symbols, create it now. | ||||||||
3766 | if (sym == nullptr) { | ||||||||
3767 | sym = | ||||||||
3768 | symtab->Resize(symtab_load_command.nsyms + m_dysymtab.nindirectsyms); | ||||||||
3769 | num_syms = symtab->GetNumSymbols(); | ||||||||
3770 | } | ||||||||
3771 | |||||||||
3772 | if (unmapped_local_symbols_found) { | ||||||||
3773 | assert(m_dysymtab.ilocalsym == 0)((void)0); | ||||||||
3774 | nlist_data_offset += (m_dysymtab.nlocalsym * nlist_byte_size); | ||||||||
3775 | nlist_idx = m_dysymtab.nlocalsym; | ||||||||
3776 | } else { | ||||||||
3777 | nlist_idx = 0; | ||||||||
3778 | } | ||||||||
3779 | |||||||||
3780 | typedef llvm::DenseMap<ConstString, uint16_t> UndefinedNameToDescMap; | ||||||||
3781 | typedef llvm::DenseMap<uint32_t, ConstString> SymbolIndexToName; | ||||||||
3782 | UndefinedNameToDescMap undefined_name_to_desc; | ||||||||
3783 | SymbolIndexToName reexport_shlib_needs_fixup; | ||||||||
3784 | |||||||||
3785 | // Symtab parsing is a huge mess. Everything is entangled and the code | ||||||||
3786 | // requires access to a ridiculous amount of variables. LLDB depends | ||||||||
3787 | // heavily on the proper merging of symbols and to get that right we need | ||||||||
3788 | // to make sure we have parsed all the debug symbols first. Therefore we | ||||||||
3789 | // invoke the lambda twice, once to parse only the debug symbols and then | ||||||||
3790 | // once more to parse the remaining symbols. | ||||||||
3791 | auto ParseSymbolLambda = [&](struct nlist_64 &nlist, uint32_t nlist_idx, | ||||||||
3792 | bool debug_only) { | ||||||||
3793 | const bool is_debug = ((nlist.n_type & N_STAB) != 0); | ||||||||
3794 | if (is_debug != debug_only) | ||||||||
3795 | return true; | ||||||||
3796 | |||||||||
3797 | const char *symbol_name_non_abi_mangled = nullptr; | ||||||||
3798 | const char *symbol_name = nullptr; | ||||||||
3799 | |||||||||
3800 | if (have_strtab_data) { | ||||||||
3801 | symbol_name = strtab_data.PeekCStr(nlist.n_strx); | ||||||||
3802 | |||||||||
3803 | if (symbol_name == nullptr) { | ||||||||
3804 | // No symbol should be NULL, even the symbols with no string values | ||||||||
3805 | // should have an offset zero which points to an empty C-string | ||||||||
3806 | Host::SystemLog(Host::eSystemLogError, | ||||||||
3807 | "error: symbol[%u] has invalid string table offset " | ||||||||
3808 | "0x%x in %s, ignoring symbol\n", | ||||||||
3809 | nlist_idx, nlist.n_strx, | ||||||||
3810 | module_sp->GetFileSpec().GetPath().c_str()); | ||||||||
3811 | return true; | ||||||||
3812 | } | ||||||||
3813 | if (symbol_name[0] == '\0') | ||||||||
3814 | symbol_name = nullptr; | ||||||||
3815 | } else { | ||||||||
3816 | const addr_t str_addr = strtab_addr + nlist.n_strx; | ||||||||
3817 | Status str_error; | ||||||||
3818 | if (process->ReadCStringFromMemory(str_addr, memory_symbol_name, | ||||||||
3819 | str_error)) | ||||||||
3820 | symbol_name = memory_symbol_name.c_str(); | ||||||||
3821 | } | ||||||||
3822 | |||||||||
3823 | SymbolType type = eSymbolTypeInvalid; | ||||||||
3824 | SectionSP symbol_section; | ||||||||
3825 | lldb::addr_t symbol_byte_size = 0; | ||||||||
3826 | bool add_nlist = true; | ||||||||
3827 | bool is_gsym = false; | ||||||||
3828 | bool demangled_is_synthesized = false; | ||||||||
3829 | bool set_value = true; | ||||||||
3830 | |||||||||
3831 | assert(sym_idx < num_syms)((void)0); | ||||||||
3832 | sym[sym_idx].SetDebug(is_debug); | ||||||||
3833 | |||||||||
3834 | if (is_debug) { | ||||||||
3835 | switch (nlist.n_type) { | ||||||||
3836 | case N_GSYM: | ||||||||
3837 | // global symbol: name,,NO_SECT,type,0 | ||||||||
3838 | // Sometimes the N_GSYM value contains the address. | ||||||||
3839 | |||||||||
3840 | // FIXME: In the .o files, we have a GSYM and a debug symbol for all | ||||||||
3841 | // the ObjC data. They | ||||||||
3842 | // have the same address, but we want to ensure that we always find | ||||||||
3843 | // only the real symbol, 'cause we don't currently correctly | ||||||||
3844 | // attribute the GSYM one to the ObjCClass/Ivar/MetaClass symbol | ||||||||
3845 | // type. This is a temporary hack to make sure the ObjectiveC | ||||||||
3846 | // symbols get treated correctly. To do this right, we should | ||||||||
3847 | // coalesce all the GSYM & global symbols that have the same | ||||||||
3848 | // address. | ||||||||
3849 | is_gsym = true; | ||||||||
3850 | sym[sym_idx].SetExternal(true); | ||||||||
3851 | |||||||||
3852 | if (symbol_name && symbol_name[0] == '_' && symbol_name[1] == 'O') { | ||||||||
3853 | llvm::StringRef symbol_name_ref(symbol_name); | ||||||||
3854 | if (symbol_name_ref.startswith(g_objc_v2_prefix_class)) { | ||||||||
3855 | symbol_name_non_abi_mangled = symbol_name + 1; | ||||||||
3856 | symbol_name = symbol_name + g_objc_v2_prefix_class.size(); | ||||||||
3857 | type = eSymbolTypeObjCClass; | ||||||||
3858 | demangled_is_synthesized = true; | ||||||||
3859 | |||||||||
3860 | } else if (symbol_name_ref.startswith(g_objc_v2_prefix_metaclass)) { | ||||||||
3861 | symbol_name_non_abi_mangled = symbol_name + 1; | ||||||||
3862 | symbol_name = symbol_name + g_objc_v2_prefix_metaclass.size(); | ||||||||
3863 | type = eSymbolTypeObjCMetaClass; | ||||||||
3864 | demangled_is_synthesized = true; | ||||||||
3865 | } else if (symbol_name_ref.startswith(g_objc_v2_prefix_ivar)) { | ||||||||
3866 | symbol_name_non_abi_mangled = symbol_name + 1; | ||||||||
3867 | symbol_name = symbol_name + g_objc_v2_prefix_ivar.size(); | ||||||||
3868 | type = eSymbolTypeObjCIVar; | ||||||||
3869 | demangled_is_synthesized = true; | ||||||||
3870 | } | ||||||||
3871 | } else { | ||||||||
3872 | if (nlist.n_value != 0) | ||||||||
3873 | symbol_section = | ||||||||
3874 | section_info.GetSection(nlist.n_sect, nlist.n_value); | ||||||||
3875 | type = eSymbolTypeData; | ||||||||
3876 | } | ||||||||
3877 | break; | ||||||||
3878 | |||||||||
3879 | case N_FNAME: | ||||||||
3880 | // procedure name (f77 kludge): name,,NO_SECT,0,0 | ||||||||
3881 | type = eSymbolTypeCompiler; | ||||||||
3882 | break; | ||||||||
3883 | |||||||||
3884 | case N_FUN: | ||||||||
3885 | // procedure: name,,n_sect,linenumber,address | ||||||||
3886 | if (symbol_name) { | ||||||||
3887 | type = eSymbolTypeCode; | ||||||||
3888 | symbol_section = | ||||||||
3889 | section_info.GetSection(nlist.n_sect, nlist.n_value); | ||||||||
3890 | |||||||||
3891 | N_FUN_addr_to_sym_idx.insert( | ||||||||
3892 | std::make_pair(nlist.n_value, sym_idx)); | ||||||||
3893 | // We use the current number of symbols in the symbol table in | ||||||||
3894 | // lieu of using nlist_idx in case we ever start trimming entries | ||||||||
3895 | // out | ||||||||
3896 | N_FUN_indexes.push_back(sym_idx); | ||||||||
3897 | } else { | ||||||||
3898 | type = eSymbolTypeCompiler; | ||||||||
3899 | |||||||||
3900 | if (!N_FUN_indexes.empty()) { | ||||||||
3901 | // Copy the size of the function into the original STAB entry | ||||||||
3902 | // so we don't have to hunt for it later | ||||||||
3903 | symtab->SymbolAtIndex(N_FUN_indexes.back()) | ||||||||
3904 | ->SetByteSize(nlist.n_value); | ||||||||
3905 | N_FUN_indexes.pop_back(); | ||||||||
3906 | // We don't really need the end function STAB as it contains | ||||||||
3907 | // the size which we already placed with the original symbol, | ||||||||
3908 | // so don't add it if we want a minimal symbol table | ||||||||
3909 | add_nlist = false; | ||||||||
3910 | } | ||||||||
3911 | } | ||||||||
3912 | break; | ||||||||
3913 | |||||||||
3914 | case N_STSYM: | ||||||||
3915 | // static symbol: name,,n_sect,type,address | ||||||||
3916 | N_STSYM_addr_to_sym_idx.insert( | ||||||||
3917 | std::make_pair(nlist.n_value, sym_idx)); | ||||||||
3918 | symbol_section = section_info.GetSection(nlist.n_sect, nlist.n_value); | ||||||||
3919 | if (symbol_name && symbol_name[0]) { | ||||||||
3920 | type = ObjectFile::GetSymbolTypeFromName(symbol_name + 1, | ||||||||
3921 | eSymbolTypeData); | ||||||||
3922 | } | ||||||||
3923 | break; | ||||||||
3924 | |||||||||
3925 | case N_LCSYM: | ||||||||
3926 | // .lcomm symbol: name,,n_sect,type,address | ||||||||
3927 | symbol_section = section_info.GetSection(nlist.n_sect, nlist.n_value); | ||||||||
3928 | type = eSymbolTypeCommonBlock; | ||||||||
3929 | break; | ||||||||
3930 | |||||||||
3931 | case N_BNSYM: | ||||||||
3932 | // We use the current number of symbols in the symbol table in lieu | ||||||||
3933 | // of using nlist_idx in case we ever start trimming entries out | ||||||||
3934 | // Skip these if we want minimal symbol tables | ||||||||
3935 | add_nlist = false; | ||||||||
3936 | break; | ||||||||
3937 | |||||||||
3938 | case N_ENSYM: | ||||||||
3939 | // Set the size of the N_BNSYM to the terminating index of this | ||||||||
3940 | // N_ENSYM so that we can always skip the entire symbol if we need | ||||||||
3941 | // to navigate more quickly at the source level when parsing STABS | ||||||||
3942 | // Skip these if we want minimal symbol tables | ||||||||
3943 | add_nlist = false; | ||||||||
3944 | break; | ||||||||
3945 | |||||||||
3946 | case N_OPT: | ||||||||
3947 | // emitted with gcc2_compiled and in gcc source | ||||||||
3948 | type = eSymbolTypeCompiler; | ||||||||
3949 | break; | ||||||||
3950 | |||||||||
3951 | case N_RSYM: | ||||||||
3952 | // register sym: name,,NO_SECT,type,register | ||||||||
3953 | type = eSymbolTypeVariable; | ||||||||
3954 | break; | ||||||||
3955 | |||||||||
3956 | case N_SLINE: | ||||||||
3957 | // src line: 0,,n_sect,linenumber,address | ||||||||
3958 | symbol_section = section_info.GetSection(nlist.n_sect, nlist.n_value); | ||||||||
3959 | type = eSymbolTypeLineEntry; | ||||||||
3960 | break; | ||||||||
3961 | |||||||||
3962 | case N_SSYM: | ||||||||
3963 | // structure elt: name,,NO_SECT,type,struct_offset | ||||||||
3964 | type = eSymbolTypeVariableType; | ||||||||
3965 | break; | ||||||||
3966 | |||||||||
3967 | case N_SO: | ||||||||
3968 | // source file name | ||||||||
3969 | type = eSymbolTypeSourceFile; | ||||||||
3970 | if (symbol_name == nullptr) { | ||||||||
3971 | add_nlist = false; | ||||||||
3972 | if (N_SO_index != UINT32_MAX0xffffffffU) { | ||||||||
3973 | // Set the size of the N_SO to the terminating index of this | ||||||||
3974 | // N_SO so that we can always skip the entire N_SO if we need | ||||||||
3975 | // to navigate more quickly at the source level when parsing | ||||||||
3976 | // STABS | ||||||||
3977 | symbol_ptr = symtab->SymbolAtIndex(N_SO_index); | ||||||||
3978 | symbol_ptr->SetByteSize(sym_idx); | ||||||||
3979 | symbol_ptr->SetSizeIsSibling(true); | ||||||||
3980 | } | ||||||||
3981 | N_NSYM_indexes.clear(); | ||||||||
3982 | N_INCL_indexes.clear(); | ||||||||
3983 | N_BRAC_indexes.clear(); | ||||||||
3984 | N_COMM_indexes.clear(); | ||||||||
3985 | N_FUN_indexes.clear(); | ||||||||
3986 | N_SO_index = UINT32_MAX0xffffffffU; | ||||||||
3987 | } else { | ||||||||
3988 | // We use the current number of symbols in the symbol table in | ||||||||
3989 | // lieu of using nlist_idx in case we ever start trimming entries | ||||||||
3990 | // out | ||||||||
3991 | const bool N_SO_has_full_path = symbol_name[0] == '/'; | ||||||||
3992 | if (N_SO_has_full_path) { | ||||||||
3993 | if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms)) { | ||||||||
3994 | // We have two consecutive N_SO entries where the first | ||||||||
3995 | // contains a directory and the second contains a full path. | ||||||||
3996 | sym[sym_idx - 1].GetMangled().SetValue(ConstString(symbol_name), | ||||||||
3997 | false); | ||||||||
3998 | m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1; | ||||||||
3999 | add_nlist = false; | ||||||||
4000 | } else { | ||||||||
4001 | // This is the first entry in a N_SO that contains a | ||||||||
4002 | // directory or a full path to the source file | ||||||||
4003 | N_SO_index = sym_idx; | ||||||||
4004 | } | ||||||||
4005 | } else if ((N_SO_index == sym_idx - 1) && | ||||||||
4006 | ((sym_idx - 1) < num_syms)) { | ||||||||
4007 | // This is usually the second N_SO entry that contains just the | ||||||||
4008 | // filename, so here we combine it with the first one if we are | ||||||||
4009 | // minimizing the symbol table | ||||||||
4010 | const char *so_path = | ||||||||
4011 | sym[sym_idx - 1].GetMangled().GetDemangledName().AsCString(); | ||||||||
4012 | if (so_path && so_path[0]) { | ||||||||
4013 | std::string full_so_path(so_path); | ||||||||
4014 | const size_t double_slash_pos = full_so_path.find("//"); | ||||||||
4015 | if (double_slash_pos != std::string::npos) { | ||||||||
4016 | // The linker has been generating bad N_SO entries with | ||||||||
4017 | // doubled up paths in the format "%s%s" where the first | ||||||||
4018 | // string in the DW_AT_comp_dir, and the second is the | ||||||||
4019 | // directory for the source file so you end up with a path | ||||||||
4020 | // that looks like "/tmp/src//tmp/src/" | ||||||||
4021 | FileSpec so_dir(so_path); | ||||||||
4022 | if (!FileSystem::Instance().Exists(so_dir)) { | ||||||||
4023 | so_dir.SetFile(&full_so_path[double_slash_pos + 1], | ||||||||
4024 | FileSpec::Style::native); | ||||||||
4025 | if (FileSystem::Instance().Exists(so_dir)) { | ||||||||
4026 | // Trim off the incorrect path | ||||||||
4027 | full_so_path.erase(0, double_slash_pos + 1); | ||||||||
4028 | } | ||||||||
4029 | } | ||||||||
4030 | } | ||||||||
4031 | if (*full_so_path.rbegin() != '/') | ||||||||
4032 | full_so_path += '/'; | ||||||||
4033 | full_so_path += symbol_name; | ||||||||
4034 | sym[sym_idx - 1].GetMangled().SetValue( | ||||||||
4035 | ConstString(full_so_path.c_str()), false); | ||||||||
4036 | add_nlist = false; | ||||||||
4037 | m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1; | ||||||||
4038 | } | ||||||||
4039 | } else { | ||||||||
4040 | // This could be a relative path to a N_SO | ||||||||
4041 | N_SO_index = sym_idx; | ||||||||
4042 | } | ||||||||
4043 | } | ||||||||
4044 | break; | ||||||||
4045 | |||||||||
4046 | case N_OSO: | ||||||||
4047 | // object file name: name,,0,0,st_mtime | ||||||||
4048 | type = eSymbolTypeObjectFile; | ||||||||
4049 | break; | ||||||||
4050 | |||||||||
4051 | case N_LSYM: | ||||||||
4052 | // local sym: name,,NO_SECT,type,offset | ||||||||
4053 | type = eSymbolTypeLocal; | ||||||||
4054 | break; | ||||||||
4055 | |||||||||
4056 | // INCL scopes | ||||||||
4057 | case N_BINCL: | ||||||||
4058 | // include file beginning: name,,NO_SECT,0,sum We use the current | ||||||||
4059 | // number of symbols in the symbol table in lieu of using nlist_idx | ||||||||
4060 | // in case we ever start trimming entries out | ||||||||
4061 | N_INCL_indexes.push_back(sym_idx); | ||||||||
4062 | type = eSymbolTypeScopeBegin; | ||||||||
4063 | break; | ||||||||
4064 | |||||||||
4065 | case N_EINCL: | ||||||||
4066 | // include file end: name,,NO_SECT,0,0 | ||||||||
4067 | // Set the size of the N_BINCL to the terminating index of this | ||||||||
4068 | // N_EINCL so that we can always skip the entire symbol if we need | ||||||||
4069 | // to navigate more quickly at the source level when parsing STABS | ||||||||
4070 | if (!N_INCL_indexes.empty()) { | ||||||||
4071 | symbol_ptr = symtab->SymbolAtIndex(N_INCL_indexes.back()); | ||||||||
4072 | symbol_ptr->SetByteSize(sym_idx + 1); | ||||||||
4073 | symbol_ptr->SetSizeIsSibling(true); | ||||||||
4074 | N_INCL_indexes.pop_back(); | ||||||||
4075 | } | ||||||||
4076 | type = eSymbolTypeScopeEnd; | ||||||||
4077 | break; | ||||||||
4078 | |||||||||
4079 | case N_SOL: | ||||||||
4080 | // #included file name: name,,n_sect,0,address | ||||||||
4081 | type = eSymbolTypeHeaderFile; | ||||||||
4082 | |||||||||
4083 | // We currently don't use the header files on darwin | ||||||||
4084 | add_nlist = false; | ||||||||
4085 | break; | ||||||||
4086 | |||||||||
4087 | case N_PARAMS: | ||||||||
4088 | // compiler parameters: name,,NO_SECT,0,0 | ||||||||
4089 | type = eSymbolTypeCompiler; | ||||||||
4090 | break; | ||||||||
4091 | |||||||||
4092 | case N_VERSION: | ||||||||
4093 | // compiler version: name,,NO_SECT,0,0 | ||||||||
4094 | type = eSymbolTypeCompiler; | ||||||||
4095 | break; | ||||||||
4096 | |||||||||
4097 | case N_OLEVEL: | ||||||||
4098 | // compiler -O level: name,,NO_SECT,0,0 | ||||||||
4099 | type = eSymbolTypeCompiler; | ||||||||
4100 | break; | ||||||||
4101 | |||||||||
4102 | case N_PSYM: | ||||||||
4103 | // parameter: name,,NO_SECT,type,offset | ||||||||
4104 | type = eSymbolTypeVariable; | ||||||||
4105 | break; | ||||||||
4106 | |||||||||
4107 | case N_ENTRY: | ||||||||
4108 | // alternate entry: name,,n_sect,linenumber,address | ||||||||
4109 | symbol_section = section_info.GetSection(nlist.n_sect, nlist.n_value); | ||||||||
4110 | type = eSymbolTypeLineEntry; | ||||||||
4111 | break; | ||||||||
4112 | |||||||||
4113 | // Left and Right Braces | ||||||||
4114 | case N_LBRAC: | ||||||||
4115 | // left bracket: 0,,NO_SECT,nesting level,address We use the | ||||||||
4116 | // current number of symbols in the symbol table in lieu of using | ||||||||
4117 | // nlist_idx in case we ever start trimming entries out | ||||||||
4118 | symbol_section = section_info.GetSection(nlist.n_sect, nlist.n_value); | ||||||||
4119 | N_BRAC_indexes.push_back(sym_idx); | ||||||||
4120 | type = eSymbolTypeScopeBegin; | ||||||||
4121 | break; | ||||||||
4122 | |||||||||
4123 | case N_RBRAC: | ||||||||
4124 | // right bracket: 0,,NO_SECT,nesting level,address Set the size of | ||||||||
4125 | // the N_LBRAC to the terminating index of this N_RBRAC so that we | ||||||||
4126 | // can always skip the entire symbol if we need to navigate more | ||||||||
4127 | // quickly at the source level when parsing STABS | ||||||||
4128 | symbol_section = section_info.GetSection(nlist.n_sect, nlist.n_value); | ||||||||
4129 | if (!N_BRAC_indexes.empty()) { | ||||||||
4130 | symbol_ptr = symtab->SymbolAtIndex(N_BRAC_indexes.back()); | ||||||||
4131 | symbol_ptr->SetByteSize(sym_idx + 1); | ||||||||
4132 | symbol_ptr->SetSizeIsSibling(true); | ||||||||
4133 | N_BRAC_indexes.pop_back(); | ||||||||
4134 | } | ||||||||
4135 | type = eSymbolTypeScopeEnd; | ||||||||
4136 | break; | ||||||||
4137 | |||||||||
4138 | case N_EXCL: | ||||||||
4139 | // deleted include file: name,,NO_SECT,0,sum | ||||||||
4140 | type = eSymbolTypeHeaderFile; | ||||||||
4141 | break; | ||||||||
4142 | |||||||||
4143 | // COMM scopes | ||||||||
4144 | case N_BCOMM: | ||||||||
4145 | // begin common: name,,NO_SECT,0,0 | ||||||||
4146 | // We use the current number of symbols in the symbol table in lieu | ||||||||
4147 | // of using nlist_idx in case we ever start trimming entries out | ||||||||
4148 | type = eSymbolTypeScopeBegin; | ||||||||
4149 | N_COMM_indexes.push_back(sym_idx); | ||||||||
4150 | break; | ||||||||
4151 | |||||||||
4152 | case N_ECOML: | ||||||||
4153 | // end common (local name): 0,,n_sect,0,address | ||||||||
4154 | symbol_section = section_info.GetSection(nlist.n_sect, nlist.n_value); | ||||||||
4155 | LLVM_FALLTHROUGH[[gnu::fallthrough]]; | ||||||||
4156 | |||||||||
4157 | case N_ECOMM: | ||||||||
4158 | // end common: name,,n_sect,0,0 | ||||||||
4159 | // Set the size of the N_BCOMM to the terminating index of this | ||||||||
4160 | // N_ECOMM/N_ECOML so that we can always skip the entire symbol if | ||||||||
4161 | // we need to navigate more quickly at the source level when | ||||||||
4162 | // parsing STABS | ||||||||
4163 | if (!N_COMM_indexes.empty()) { | ||||||||
4164 | symbol_ptr = symtab->SymbolAtIndex(N_COMM_indexes.back()); | ||||||||
4165 | symbol_ptr->SetByteSize(sym_idx + 1); | ||||||||
4166 | symbol_ptr->SetSizeIsSibling(true); | ||||||||
4167 | N_COMM_indexes.pop_back(); | ||||||||
4168 | } | ||||||||
4169 | type = eSymbolTypeScopeEnd; | ||||||||
4170 | break; | ||||||||
4171 | |||||||||
4172 | case N_LENG: | ||||||||
4173 | // second stab entry with length information | ||||||||
4174 | type = eSymbolTypeAdditional; | ||||||||
4175 | break; | ||||||||
4176 | |||||||||
4177 | default: | ||||||||
4178 | break; | ||||||||
4179 | } | ||||||||
4180 | } else { | ||||||||
4181 | uint8_t n_type = N_TYPE & nlist.n_type; | ||||||||
4182 | sym[sym_idx].SetExternal((N_EXT & nlist.n_type) != 0); | ||||||||
4183 | |||||||||
4184 | switch (n_type) { | ||||||||
4185 | case N_INDR: { | ||||||||
4186 | const char *reexport_name_cstr = strtab_data.PeekCStr(nlist.n_value); | ||||||||
4187 | if (reexport_name_cstr && reexport_name_cstr[0]) { | ||||||||
4188 | type = eSymbolTypeReExported; | ||||||||
4189 | ConstString reexport_name(reexport_name_cstr + | ||||||||
4190 | ((reexport_name_cstr[0] == '_') ? 1 : 0)); | ||||||||
4191 | sym[sym_idx].SetReExportedSymbolName(reexport_name); | ||||||||
4192 | set_value = false; | ||||||||
4193 | reexport_shlib_needs_fixup[sym_idx] = reexport_name; | ||||||||
4194 | indirect_symbol_names.insert( | ||||||||
4195 | ConstString(symbol_name + ((symbol_name[0] == '_') ? 1 : 0))); | ||||||||
4196 | } else | ||||||||
4197 | type = eSymbolTypeUndefined; | ||||||||
4198 | } break; | ||||||||
4199 | |||||||||
4200 | case N_UNDF: | ||||||||
4201 | if (symbol_name && symbol_name[0]) { | ||||||||
4202 | ConstString undefined_name(symbol_name + | ||||||||
4203 | ((symbol_name[0] == '_') ? 1 : 0)); | ||||||||
4204 | undefined_name_to_desc[undefined_name] = nlist.n_desc; | ||||||||
4205 | } | ||||||||
4206 | LLVM_FALLTHROUGH[[gnu::fallthrough]]; | ||||||||
4207 | |||||||||
4208 | case N_PBUD: | ||||||||
4209 | type = eSymbolTypeUndefined; | ||||||||
4210 | break; | ||||||||
4211 | |||||||||
4212 | case N_ABS: | ||||||||
4213 | type = eSymbolTypeAbsolute; | ||||||||
4214 | break; | ||||||||
4215 | |||||||||
4216 | case N_SECT: { | ||||||||
4217 | symbol_section = section_info.GetSection(nlist.n_sect, nlist.n_value); | ||||||||
4218 | |||||||||
4219 | if (!symbol_section) { | ||||||||
4220 | // TODO: warn about this? | ||||||||
4221 | add_nlist = false; | ||||||||
4222 | break; | ||||||||
4223 | } | ||||||||
4224 | |||||||||
4225 | if (TEXT_eh_frame_sectID == nlist.n_sect) { | ||||||||
4226 | type = eSymbolTypeException; | ||||||||
4227 | } else { | ||||||||
4228 | uint32_t section_type = symbol_section->Get() & SECTION_TYPE; | ||||||||
4229 | |||||||||
4230 | switch (section_type) { | ||||||||
4231 | case S_CSTRING_LITERALS: | ||||||||
4232 | type = eSymbolTypeData; | ||||||||
4233 | break; // section with only literal C strings | ||||||||
4234 | case S_4BYTE_LITERALS: | ||||||||
4235 | type = eSymbolTypeData; | ||||||||
4236 | break; // section with only 4 byte literals | ||||||||
4237 | case S_8BYTE_LITERALS: | ||||||||
4238 | type = eSymbolTypeData; | ||||||||
4239 | break; // section with only 8 byte literals | ||||||||
4240 | case S_LITERAL_POINTERS: | ||||||||
4241 | type = eSymbolTypeTrampoline; | ||||||||
4242 | break; // section with only pointers to literals | ||||||||
4243 | case S_NON_LAZY_SYMBOL_POINTERS: | ||||||||
4244 | type = eSymbolTypeTrampoline; | ||||||||
4245 | break; // section with only non-lazy symbol pointers | ||||||||
4246 | case S_LAZY_SYMBOL_POINTERS: | ||||||||
4247 | type = eSymbolTypeTrampoline; | ||||||||
4248 | break; // section with only lazy symbol pointers | ||||||||
4249 | case S_SYMBOL_STUBS: | ||||||||
4250 | type = eSymbolTypeTrampoline; | ||||||||
4251 | break; // section with only symbol stubs, byte size of stub in | ||||||||
4252 | // the reserved2 field | ||||||||
4253 | case S_MOD_INIT_FUNC_POINTERS: | ||||||||
4254 | type = eSymbolTypeCode; | ||||||||
4255 | break; // section with only function pointers for initialization | ||||||||
4256 | case S_MOD_TERM_FUNC_POINTERS: | ||||||||
4257 | type = eSymbolTypeCode; | ||||||||
4258 | break; // section with only function pointers for termination | ||||||||
4259 | case S_INTERPOSING: | ||||||||
4260 | type = eSymbolTypeTrampoline; | ||||||||
4261 | break; // section with only pairs of function pointers for | ||||||||
4262 | // interposing | ||||||||
4263 | case S_16BYTE_LITERALS: | ||||||||
4264 | type = eSymbolTypeData; | ||||||||
4265 | break; // section with only 16 byte literals | ||||||||
4266 | case S_DTRACE_DOF: | ||||||||
4267 | type = eSymbolTypeInstrumentation; | ||||||||
4268 | break; | ||||||||
4269 | case S_LAZY_DYLIB_SYMBOL_POINTERS: | ||||||||
4270 | type = eSymbolTypeTrampoline; | ||||||||
4271 | break; | ||||||||
4272 | default: | ||||||||
4273 | switch (symbol_section->GetType()) { | ||||||||
4274 | case lldb::eSectionTypeCode: | ||||||||
4275 | type = eSymbolTypeCode; | ||||||||
4276 | break; | ||||||||
4277 | case eSectionTypeData: | ||||||||
4278 | case eSectionTypeDataCString: // Inlined C string data | ||||||||
4279 | case eSectionTypeDataCStringPointers: // Pointers to C string | ||||||||
4280 | // data | ||||||||
4281 | case eSectionTypeDataSymbolAddress: // Address of a symbol in | ||||||||
4282 | // the symbol table | ||||||||
4283 | case eSectionTypeData4: | ||||||||
4284 | case eSectionTypeData8: | ||||||||
4285 | case eSectionTypeData16: | ||||||||
4286 | type = eSymbolTypeData; | ||||||||
4287 | break; | ||||||||
4288 | default: | ||||||||
4289 | break; | ||||||||
4290 | } | ||||||||
4291 | break; | ||||||||
4292 | } | ||||||||
4293 | |||||||||
4294 | if (type == eSymbolTypeInvalid) { | ||||||||
4295 | const char *symbol_sect_name = | ||||||||
4296 | symbol_section->GetName().AsCString(); | ||||||||
4297 | if (symbol_section->IsDescendant(text_section_sp.get())) { | ||||||||
4298 | if (symbol_section->IsClear(S_ATTR_PURE_INSTRUCTIONS | | ||||||||
4299 | S_ATTR_SELF_MODIFYING_CODE | | ||||||||
4300 | S_ATTR_SOME_INSTRUCTIONS)) | ||||||||
4301 | type = eSymbolTypeData; | ||||||||
4302 | else | ||||||||
4303 | type = eSymbolTypeCode; | ||||||||
4304 | } else if (symbol_section->IsDescendant(data_section_sp.get()) || | ||||||||
4305 | symbol_section->IsDescendant( | ||||||||
4306 | data_dirty_section_sp.get()) || | ||||||||
4307 | symbol_section->IsDescendant( | ||||||||
4308 | data_const_section_sp.get())) { | ||||||||
4309 | if (symbol_sect_name && | ||||||||
4310 | ::strstr(symbol_sect_name, "__objc") == symbol_sect_name) { | ||||||||
4311 | type = eSymbolTypeRuntime; | ||||||||
4312 | |||||||||
4313 | if (symbol_name) { | ||||||||
4314 | llvm::StringRef symbol_name_ref(symbol_name); | ||||||||
4315 | if (symbol_name_ref.startswith("_OBJC_")) { | ||||||||
4316 | llvm::StringRef g_objc_v2_prefix_class( | ||||||||
4317 | "_OBJC_CLASS_$_"); | ||||||||
4318 | llvm::StringRef g_objc_v2_prefix_metaclass( | ||||||||
4319 | "_OBJC_METACLASS_$_"); | ||||||||
4320 | llvm::StringRef g_objc_v2_prefix_ivar( | ||||||||
4321 | "_OBJC_IVAR_$_"); | ||||||||
4322 | if (symbol_name_ref.startswith(g_objc_v2_prefix_class)) { | ||||||||
4323 | symbol_name_non_abi_mangled = symbol_name + 1; | ||||||||
4324 | symbol_name = | ||||||||
4325 | symbol_name + g_objc_v2_prefix_class.size(); | ||||||||
4326 | type = eSymbolTypeObjCClass; | ||||||||
4327 | demangled_is_synthesized = true; | ||||||||
4328 | } else if (symbol_name_ref.startswith( | ||||||||
4329 | g_objc_v2_prefix_metaclass)) { | ||||||||
4330 | symbol_name_non_abi_mangled = symbol_name + 1; | ||||||||
4331 | symbol_name = | ||||||||
4332 | symbol_name + g_objc_v2_prefix_metaclass.size(); | ||||||||
4333 | type = eSymbolTypeObjCMetaClass; | ||||||||
4334 | demangled_is_synthesized = true; | ||||||||
4335 | } else if (symbol_name_ref.startswith( | ||||||||
4336 | g_objc_v2_prefix_ivar)) { | ||||||||
4337 | symbol_name_non_abi_mangled = symbol_name + 1; | ||||||||
4338 | symbol_name = | ||||||||
4339 | symbol_name + g_objc_v2_prefix_ivar.size(); | ||||||||
4340 | type = eSymbolTypeObjCIVar; | ||||||||
4341 | demangled_is_synthesized = true; | ||||||||
4342 | } | ||||||||
4343 | } | ||||||||
4344 | } | ||||||||
4345 | } else if (symbol_sect_name && | ||||||||
4346 | ::strstr(symbol_sect_name, "__gcc_except_tab") == | ||||||||
4347 | symbol_sect_name) { | ||||||||
4348 | type = eSymbolTypeException; | ||||||||
4349 | } else { | ||||||||
4350 | type = eSymbolTypeData; | ||||||||
4351 | } | ||||||||
4352 | } else if (symbol_sect_name && | ||||||||
4353 | ::strstr(symbol_sect_name, "__IMPORT") == | ||||||||
4354 | symbol_sect_name) { | ||||||||
4355 | type = eSymbolTypeTrampoline; | ||||||||
4356 | } else if (symbol_section->IsDescendant(objc_section_sp.get())) { | ||||||||
4357 | type = eSymbolTypeRuntime; | ||||||||
4358 | if (symbol_name && symbol_name[0] == '.') { | ||||||||
4359 | llvm::StringRef symbol_name_ref(symbol_name); | ||||||||
4360 | llvm::StringRef g_objc_v1_prefix_class( | ||||||||
4361 | ".objc_class_name_"); | ||||||||
4362 | if (symbol_name_ref.startswith(g_objc_v1_prefix_class)) { | ||||||||
4363 | symbol_name_non_abi_mangled = symbol_name; | ||||||||
4364 | symbol_name = symbol_name + g_objc_v1_prefix_class.size(); | ||||||||
4365 | type = eSymbolTypeObjCClass; | ||||||||
4366 | demangled_is_synthesized = true; | ||||||||
4367 | } | ||||||||
4368 | } | ||||||||
4369 | } | ||||||||
4370 | } | ||||||||
4371 | } | ||||||||
4372 | } break; | ||||||||
4373 | } | ||||||||
4374 | } | ||||||||
4375 | |||||||||
4376 | if (!add_nlist) { | ||||||||
4377 | sym[sym_idx].Clear(); | ||||||||
4378 | return true; | ||||||||
4379 | } | ||||||||
4380 | |||||||||
4381 | uint64_t symbol_value = nlist.n_value; | ||||||||
4382 | |||||||||
4383 | if (symbol_name_non_abi_mangled) { | ||||||||
4384 | sym[sym_idx].GetMangled().SetMangledName( | ||||||||
4385 | ConstString(symbol_name_non_abi_mangled)); | ||||||||
4386 | sym[sym_idx].GetMangled().SetDemangledName(ConstString(symbol_name)); | ||||||||
4387 | } else { | ||||||||
4388 | bool symbol_name_is_mangled = false; | ||||||||
4389 | |||||||||
4390 | if (symbol_name && symbol_name[0] == '_') { | ||||||||
4391 | symbol_name_is_mangled = symbol_name[1] == '_'; | ||||||||
4392 | symbol_name++; // Skip the leading underscore | ||||||||
4393 | } | ||||||||
4394 | |||||||||
4395 | if (symbol_name) { | ||||||||
4396 | ConstString const_symbol_name(symbol_name); | ||||||||
4397 | sym[sym_idx].GetMangled().SetValue(const_symbol_name, | ||||||||
4398 | symbol_name_is_mangled); | ||||||||
4399 | } | ||||||||
4400 | } | ||||||||
4401 | |||||||||
4402 | if (is_gsym) { | ||||||||
4403 | const char *gsym_name = sym[sym_idx] | ||||||||
4404 | .GetMangled() | ||||||||
4405 | .GetName(Mangled::ePreferMangled) | ||||||||
4406 | .GetCString(); | ||||||||
4407 | if (gsym_name) | ||||||||
4408 | N_GSYM_name_to_sym_idx[gsym_name] = sym_idx; | ||||||||
4409 | } | ||||||||
4410 | |||||||||
4411 | if (symbol_section) { | ||||||||
4412 | const addr_t section_file_addr = symbol_section->GetFileAddress(); | ||||||||
4413 | if (symbol_byte_size == 0 && function_starts_count > 0) { | ||||||||
4414 | addr_t symbol_lookup_file_addr = nlist.n_value; | ||||||||
4415 | // Do an exact address match for non-ARM addresses, else get the | ||||||||
4416 | // closest since the symbol might be a thumb symbol which has an | ||||||||
4417 | // address with bit zero set. | ||||||||
4418 | FunctionStarts::Entry *func_start_entry = | ||||||||
4419 | function_starts.FindEntry(symbol_lookup_file_addr, !is_arm); | ||||||||
4420 | if (is_arm && func_start_entry) { | ||||||||
4421 | // Verify that the function start address is the symbol address | ||||||||
4422 | // (ARM) or the symbol address + 1 (thumb). | ||||||||
4423 | if (func_start_entry->addr != symbol_lookup_file_addr && | ||||||||
4424 | func_start_entry->addr != (symbol_lookup_file_addr + 1)) { | ||||||||
4425 | // Not the right entry, NULL it out... | ||||||||
4426 | func_start_entry = nullptr; | ||||||||
4427 | } | ||||||||
4428 | } | ||||||||
4429 | if (func_start_entry) { | ||||||||
4430 | func_start_entry->data = true; | ||||||||
4431 | |||||||||
4432 | addr_t symbol_file_addr = func_start_entry->addr; | ||||||||
4433 | if (is_arm) | ||||||||
4434 | symbol_file_addr &= THUMB_ADDRESS_BIT_MASK0xfffffffffffffffeull; | ||||||||
4435 | |||||||||
4436 | const FunctionStarts::Entry *next_func_start_entry = | ||||||||
4437 | function_starts.FindNextEntry(func_start_entry); | ||||||||
4438 | const addr_t section_end_file_addr = | ||||||||
4439 | section_file_addr + symbol_section->GetByteSize(); | ||||||||
4440 | if (next_func_start_entry) { | ||||||||
4441 | addr_t next_symbol_file_addr = next_func_start_entry->addr; | ||||||||
4442 | // Be sure the clear the Thumb address bit when we calculate the | ||||||||
4443 | // size from the current and next address | ||||||||
4444 | if (is_arm) | ||||||||
4445 | next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK0xfffffffffffffffeull; | ||||||||
4446 | symbol_byte_size = std::min<lldb::addr_t>( | ||||||||
4447 | next_symbol_file_addr - symbol_file_addr, | ||||||||
4448 | section_end_file_addr - symbol_file_addr); | ||||||||
4449 | } else { | ||||||||
4450 | symbol_byte_size = section_end_file_addr - symbol_file_addr; | ||||||||
4451 | } | ||||||||
4452 | } | ||||||||
4453 | } | ||||||||
4454 | symbol_value -= section_file_addr; | ||||||||
4455 | } | ||||||||
4456 | |||||||||
4457 | if (!is_debug) { | ||||||||
4458 | if (type == eSymbolTypeCode) { | ||||||||
4459 | // See if we can find a N_FUN entry for any code symbols. If we do | ||||||||
4460 | // find a match, and the name matches, then we can merge the two into | ||||||||
4461 | // just the function symbol to avoid duplicate entries in the symbol | ||||||||
4462 | // table. | ||||||||
4463 | std::pair<ValueToSymbolIndexMap::const_iterator, | ||||||||
4464 | ValueToSymbolIndexMap::const_iterator> | ||||||||
4465 | range; | ||||||||
4466 | range = N_FUN_addr_to_sym_idx.equal_range(nlist.n_value); | ||||||||
4467 | if (range.first != range.second) { | ||||||||
4468 | for (ValueToSymbolIndexMap::const_iterator pos = range.first; | ||||||||
4469 | pos != range.second; ++pos) { | ||||||||
4470 | if (sym[sym_idx].GetMangled().GetName(Mangled::ePreferMangled) == | ||||||||
4471 | sym[pos->second].GetMangled().GetName( | ||||||||
4472 | Mangled::ePreferMangled)) { | ||||||||
4473 | m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; | ||||||||
4474 | // We just need the flags from the linker symbol, so put these | ||||||||
4475 | // flags into the N_FUN flags to avoid duplicate symbols in the | ||||||||
4476 | // symbol table. | ||||||||
4477 | sym[pos->second].SetExternal(sym[sym_idx].IsExternal()); | ||||||||
4478 | sym[pos->second].SetFlags(nlist.n_type << 16 | nlist.n_desc); | ||||||||
4479 | if (resolver_addresses.find(nlist.n_value) != | ||||||||
4480 | resolver_addresses.end()) | ||||||||
4481 | sym[pos->second].SetType(eSymbolTypeResolver); | ||||||||
4482 | sym[sym_idx].Clear(); | ||||||||
4483 | return true; | ||||||||
4484 | } | ||||||||
4485 | } | ||||||||
4486 | } else { | ||||||||
4487 | if (resolver_addresses.find(nlist.n_value) != | ||||||||
4488 | resolver_addresses.end()) | ||||||||
4489 | type = eSymbolTypeResolver; | ||||||||
4490 | } | ||||||||
4491 | } else if (type == eSymbolTypeData || type == eSymbolTypeObjCClass || | ||||||||
4492 | type == eSymbolTypeObjCMetaClass || | ||||||||
4493 | type == eSymbolTypeObjCIVar) { | ||||||||
4494 | // See if we can find a N_STSYM entry for any data symbols. If we do | ||||||||
4495 | // find a match, and the name matches, then we can merge the two into | ||||||||
4496 | // just the Static symbol to avoid duplicate entries in the symbol | ||||||||
4497 | // table. | ||||||||
4498 | std::pair<ValueToSymbolIndexMap::const_iterator, | ||||||||
4499 | ValueToSymbolIndexMap::const_iterator> | ||||||||
4500 | range; | ||||||||
4501 | range = N_STSYM_addr_to_sym_idx.equal_range(nlist.n_value); | ||||||||
4502 | if (range.first != range.second) { | ||||||||
4503 | for (ValueToSymbolIndexMap::const_iterator pos = range.first; | ||||||||
4504 | pos != range.second; ++pos) { | ||||||||
4505 | if (sym[sym_idx].GetMangled().GetName(Mangled::ePreferMangled) == | ||||||||
4506 | sym[pos->second].GetMangled().GetName( | ||||||||
4507 | Mangled::ePreferMangled)) { | ||||||||
4508 | m_nlist_idx_to_sym_idx[nlist_idx] = pos->second; | ||||||||
4509 | // We just need the flags from the linker symbol, so put these | ||||||||
4510 | // flags into the N_STSYM flags to avoid duplicate symbols in | ||||||||
4511 | // the symbol table. | ||||||||
4512 | sym[pos->second].SetExternal(sym[sym_idx].IsExternal()); | ||||||||
4513 | sym[pos->second].SetFlags(nlist.n_type << 16 | nlist.n_desc); | ||||||||
4514 | sym[sym_idx].Clear(); | ||||||||
4515 | return true; | ||||||||
4516 | } | ||||||||
4517 | } | ||||||||
4518 | } else { | ||||||||
4519 | // Combine N_GSYM stab entries with the non stab symbol. | ||||||||
4520 | const char *gsym_name = sym[sym_idx] | ||||||||
4521 | .GetMangled() | ||||||||
4522 | .GetName(Mangled::ePreferMangled) | ||||||||
4523 | .GetCString(); | ||||||||
4524 | if (gsym_name) { | ||||||||
4525 | ConstNameToSymbolIndexMap::const_iterator pos = | ||||||||
4526 | N_GSYM_name_to_sym_idx.find(gsym_name); | ||||||||
4527 | if (pos != N_GSYM_name_to_sym_idx.end()) { | ||||||||
4528 | const uint32_t GSYM_sym_idx = pos->second; | ||||||||
4529 | m_nlist_idx_to_sym_idx[nlist_idx] = GSYM_sym_idx; | ||||||||
4530 | // Copy the address, because often the N_GSYM address has an | ||||||||
4531 | // invalid address of zero when the global is a common symbol. | ||||||||
4532 | sym[GSYM_sym_idx].GetAddressRef().SetSection(symbol_section); | ||||||||
4533 | sym[GSYM_sym_idx].GetAddressRef().SetOffset(symbol_value); | ||||||||
4534 | add_symbol_addr( | ||||||||
4535 | sym[GSYM_sym_idx].GetAddress().GetFileAddress()); | ||||||||
4536 | // We just need the flags from the linker symbol, so put these | ||||||||
4537 | // flags into the N_GSYM flags to avoid duplicate symbols in | ||||||||
4538 | // the symbol table. | ||||||||
4539 | sym[GSYM_sym_idx].SetFlags(nlist.n_type << 16 | nlist.n_desc); | ||||||||
4540 | sym[sym_idx].Clear(); | ||||||||
4541 | return true; | ||||||||
4542 | } | ||||||||
4543 | } | ||||||||
4544 | } | ||||||||
4545 | } | ||||||||
4546 | } | ||||||||
4547 | |||||||||
4548 | sym[sym_idx].SetID(nlist_idx); | ||||||||
4549 | sym[sym_idx].SetType(type); | ||||||||
4550 | if (set_value) { | ||||||||
4551 | sym[sym_idx].GetAddressRef().SetSection(symbol_section); | ||||||||
4552 | sym[sym_idx].GetAddressRef().SetOffset(symbol_value); | ||||||||
4553 | if (symbol_section) | ||||||||
4554 | add_symbol_addr(sym[sym_idx].GetAddress().GetFileAddress()); | ||||||||
4555 | } | ||||||||
4556 | sym[sym_idx].SetFlags(nlist.n_type << 16 | nlist.n_desc); | ||||||||
4557 | if (nlist.n_desc & N_WEAK_REF) | ||||||||
4558 | sym[sym_idx].SetIsWeak(true); | ||||||||
4559 | |||||||||
4560 | if (symbol_byte_size > 0) | ||||||||
4561 | sym[sym_idx].SetByteSize(symbol_byte_size); | ||||||||
4562 | |||||||||
4563 | if (demangled_is_synthesized) | ||||||||
4564 | sym[sym_idx].SetDemangledNameIsSynthesized(true); | ||||||||
4565 | |||||||||
4566 | ++sym_idx; | ||||||||
4567 | return true; | ||||||||
4568 | }; | ||||||||
4569 | |||||||||
4570 | // First parse all the nlists but don't process them yet. See the next | ||||||||
4571 | // comment for an explanation why. | ||||||||
4572 | std::vector<struct nlist_64> nlists; | ||||||||
4573 | nlists.reserve(symtab_load_command.nsyms); | ||||||||
4574 | for (; nlist_idx < symtab_load_command.nsyms; ++nlist_idx) { | ||||||||
4575 | if (auto nlist = | ||||||||
4576 | ParseNList(nlist_data, nlist_data_offset, nlist_byte_size)) | ||||||||
4577 | nlists.push_back(*nlist); | ||||||||
4578 | else | ||||||||
4579 | break; | ||||||||
4580 | } | ||||||||
4581 | |||||||||
4582 | // Now parse all the debug symbols. This is needed to merge non-debug | ||||||||
4583 | // symbols in the next step. Non-debug symbols are always coalesced into | ||||||||
4584 | // the debug symbol. Doing this in one step would mean that some symbols | ||||||||
4585 | // won't be merged. | ||||||||
4586 | nlist_idx = 0; | ||||||||
4587 | for (auto &nlist : nlists) { | ||||||||
4588 | if (!ParseSymbolLambda(nlist, nlist_idx++, DebugSymbols)) | ||||||||
4589 | break; | ||||||||
4590 | } | ||||||||
4591 | |||||||||
4592 | // Finally parse all the non debug symbols. | ||||||||
4593 | nlist_idx = 0; | ||||||||
4594 | for (auto &nlist : nlists) { | ||||||||
4595 | if (!ParseSymbolLambda(nlist, nlist_idx++, NonDebugSymbols)) | ||||||||
4596 | break; | ||||||||
4597 | } | ||||||||
4598 | |||||||||
4599 | for (const auto &pos : reexport_shlib_needs_fixup) { | ||||||||
4600 | const auto undef_pos = undefined_name_to_desc.find(pos.second); | ||||||||
4601 | if (undef_pos != undefined_name_to_desc.end()) { | ||||||||
4602 | const uint8_t dylib_ordinal = | ||||||||
4603 | llvm::MachO::GET_LIBRARY_ORDINAL(undef_pos->second); | ||||||||
4604 | if (dylib_ordinal > 0 && dylib_ordinal < dylib_files.GetSize()) | ||||||||
4605 | sym[pos.first].SetReExportedSymbolSharedLibrary( | ||||||||
4606 | dylib_files.GetFileSpecAtIndex(dylib_ordinal - 1)); | ||||||||
4607 | } | ||||||||
4608 | } | ||||||||
4609 | } | ||||||||
4610 | |||||||||
4611 | // Count how many trie symbols we'll add to the symbol table | ||||||||
4612 | int trie_symbol_table_augment_count = 0; | ||||||||
4613 | for (auto &e : external_sym_trie_entries) { | ||||||||
4614 | if (symbols_added.find(e.entry.address) == symbols_added.end()) | ||||||||
4615 | trie_symbol_table_augment_count++; | ||||||||
4616 | } | ||||||||
4617 | |||||||||
4618 | if (num_syms < sym_idx + trie_symbol_table_augment_count) { | ||||||||
4619 | num_syms = sym_idx + trie_symbol_table_augment_count; | ||||||||
4620 | sym = symtab->Resize(num_syms); | ||||||||
4621 | } | ||||||||
4622 | uint32_t synthetic_sym_id = symtab_load_command.nsyms; | ||||||||
4623 | |||||||||
4624 | // Add symbols from the trie to the symbol table. | ||||||||
4625 | for (auto &e : external_sym_trie_entries) { | ||||||||
4626 | if (symbols_added.find(e.entry.address) != symbols_added.end()) | ||||||||
4627 | continue; | ||||||||
4628 | |||||||||
4629 | // Find the section that this trie address is in, use that to annotate | ||||||||
4630 | // symbol type as we add the trie address and name to the symbol table. | ||||||||
4631 | Address symbol_addr; | ||||||||
4632 | if (module_sp->ResolveFileAddress(e.entry.address, symbol_addr)) { | ||||||||
4633 | SectionSP symbol_section(symbol_addr.GetSection()); | ||||||||
4634 | const char *symbol_name = e.entry.name.GetCString(); | ||||||||
4635 | bool demangled_is_synthesized = false; | ||||||||
4636 | SymbolType type = | ||||||||
4637 | GetSymbolType(symbol_name, demangled_is_synthesized, text_section_sp, | ||||||||
4638 | data_section_sp, data_dirty_section_sp, | ||||||||
4639 | data_const_section_sp, symbol_section); | ||||||||
4640 | |||||||||
4641 | sym[sym_idx].SetType(type); | ||||||||
| |||||||||
4642 | if (symbol_section) { | ||||||||
4643 | sym[sym_idx].SetID(synthetic_sym_id++); | ||||||||
4644 | sym[sym_idx].GetMangled().SetMangledName(ConstString(symbol_name)); | ||||||||
4645 | if (demangled_is_synthesized) | ||||||||
4646 | sym[sym_idx].SetDemangledNameIsSynthesized(true); | ||||||||
4647 | sym[sym_idx].SetIsSynthetic(true); | ||||||||
4648 | sym[sym_idx].SetExternal(true); | ||||||||
4649 | sym[sym_idx].GetAddressRef() = symbol_addr; | ||||||||
4650 | add_symbol_addr(symbol_addr.GetFileAddress()); | ||||||||
4651 | if (e.entry.flags & TRIE_SYMBOL_IS_THUMB(1ULL << 63)) | ||||||||
4652 | sym[sym_idx].SetFlags(MACHO_NLIST_ARM_SYMBOL_IS_THUMB0x0008); | ||||||||
4653 | ++sym_idx; | ||||||||
4654 | } | ||||||||
4655 | } | ||||||||
4656 | } | ||||||||
4657 | |||||||||
4658 | if (function_starts_count > 0) { | ||||||||
4659 | uint32_t num_synthetic_function_symbols = 0; | ||||||||
4660 | for (i = 0; i < function_starts_count; ++i) { | ||||||||
4661 | if (symbols_added.find(function_starts.GetEntryRef(i).addr) == | ||||||||
4662 | symbols_added.end()) | ||||||||
4663 | ++num_synthetic_function_symbols; | ||||||||
4664 | } | ||||||||
4665 | |||||||||
4666 | if (num_synthetic_function_symbols > 0) { | ||||||||
4667 | if (num_syms < sym_idx + num_synthetic_function_symbols) { | ||||||||
4668 | num_syms = sym_idx + num_synthetic_function_symbols; | ||||||||
4669 | sym = symtab->Resize(num_syms); | ||||||||
4670 | } | ||||||||
4671 | for (i = 0; i < function_starts_count; ++i) { | ||||||||
4672 | const FunctionStarts::Entry *func_start_entry = | ||||||||
4673 | function_starts.GetEntryAtIndex(i); | ||||||||
4674 | if (symbols_added.find(func_start_entry->addr) == symbols_added.end()) { | ||||||||
4675 | addr_t symbol_file_addr = func_start_entry->addr; | ||||||||
4676 | uint32_t symbol_flags = 0; | ||||||||
4677 | if (func_start_entry->data) | ||||||||
4678 | symbol_flags = MACHO_NLIST_ARM_SYMBOL_IS_THUMB0x0008; | ||||||||
4679 | Address symbol_addr; | ||||||||
4680 | if (module_sp->ResolveFileAddress(symbol_file_addr, symbol_addr)) { | ||||||||
4681 | SectionSP symbol_section(symbol_addr.GetSection()); | ||||||||
4682 | uint32_t symbol_byte_size = 0; | ||||||||
4683 | if (symbol_section) { | ||||||||
4684 | const addr_t section_file_addr = symbol_section->GetFileAddress(); | ||||||||
4685 | const FunctionStarts::Entry *next_func_start_entry = | ||||||||
4686 | function_starts.FindNextEntry(func_start_entry); | ||||||||
4687 | const addr_t section_end_file_addr = | ||||||||
4688 | section_file_addr + symbol_section->GetByteSize(); | ||||||||
4689 | if (next_func_start_entry) { | ||||||||
4690 | addr_t next_symbol_file_addr = next_func_start_entry->addr; | ||||||||
4691 | if (is_arm) | ||||||||
4692 | next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK0xfffffffffffffffeull; | ||||||||
4693 | symbol_byte_size = std::min<lldb::addr_t>( | ||||||||
4694 | next_symbol_file_addr - symbol_file_addr, | ||||||||
4695 | section_end_file_addr - symbol_file_addr); | ||||||||
4696 | } else { | ||||||||
4697 | symbol_byte_size = section_end_file_addr - symbol_file_addr; | ||||||||
4698 | } | ||||||||
4699 | sym[sym_idx].SetID(synthetic_sym_id++); | ||||||||
4700 | // Don't set the name for any synthetic symbols, the Symbol | ||||||||
4701 | // object will generate one if needed when the name is accessed | ||||||||
4702 | // via accessors. | ||||||||
4703 | sym[sym_idx].GetMangled().SetDemangledName(ConstString()); | ||||||||
4704 | sym[sym_idx].SetType(eSymbolTypeCode); | ||||||||
4705 | sym[sym_idx].SetIsSynthetic(true); | ||||||||
4706 | sym[sym_idx].GetAddressRef() = symbol_addr; | ||||||||
4707 | add_symbol_addr(symbol_addr.GetFileAddress()); | ||||||||
4708 | if (symbol_flags) | ||||||||
4709 | sym[sym_idx].SetFlags(symbol_flags); | ||||||||
4710 | if (symbol_byte_size) | ||||||||
4711 | sym[sym_idx].SetByteSize(symbol_byte_size); | ||||||||
4712 | ++sym_idx; | ||||||||
4713 | } | ||||||||
4714 | } | ||||||||
4715 | } | ||||||||
4716 | } | ||||||||
4717 | } | ||||||||
4718 | } | ||||||||
4719 | |||||||||
4720 | // Trim our symbols down to just what we ended up with after removing any | ||||||||
4721 | // symbols. | ||||||||
4722 | if (sym_idx < num_syms) { | ||||||||
4723 | num_syms = sym_idx; | ||||||||
4724 | sym = symtab->Resize(num_syms); | ||||||||
4725 | } | ||||||||
4726 | |||||||||
4727 | // Now synthesize indirect symbols | ||||||||
4728 | if (m_dysymtab.nindirectsyms != 0) { | ||||||||
4729 | if (indirect_symbol_index_data.GetByteSize()) { | ||||||||
4730 | NListIndexToSymbolIndexMap::const_iterator end_index_pos = | ||||||||
4731 | m_nlist_idx_to_sym_idx.end(); | ||||||||
4732 | |||||||||
4733 | for (uint32_t sect_idx = 1; sect_idx < m_mach_sections.size(); | ||||||||
4734 | ++sect_idx) { | ||||||||
4735 | if ((m_mach_sections[sect_idx].flags & SECTION_TYPE) == | ||||||||
4736 | S_SYMBOL_STUBS) { | ||||||||
4737 | uint32_t symbol_stub_byte_size = m_mach_sections[sect_idx].reserved2; | ||||||||
4738 | if (symbol_stub_byte_size == 0) | ||||||||
4739 | continue; | ||||||||
4740 | |||||||||
4741 | const uint32_t num_symbol_stubs = | ||||||||
4742 | m_mach_sections[sect_idx].size / symbol_stub_byte_size; | ||||||||
4743 | |||||||||
4744 | if (num_symbol_stubs == 0) | ||||||||
4745 | continue; | ||||||||
4746 | |||||||||
4747 | const uint32_t symbol_stub_index_offset = | ||||||||
4748 | m_mach_sections[sect_idx].reserved1; | ||||||||
4749 | for (uint32_t stub_idx = 0; stub_idx < num_symbol_stubs; ++stub_idx) { | ||||||||
4750 | const uint32_t symbol_stub_index = | ||||||||
4751 | symbol_stub_index_offset + stub_idx; | ||||||||
4752 | const lldb::addr_t symbol_stub_addr = | ||||||||
4753 | m_mach_sections[sect_idx].addr + | ||||||||
4754 | (stub_idx * symbol_stub_byte_size); | ||||||||
4755 | lldb::offset_t symbol_stub_offset = symbol_stub_index * 4; | ||||||||
4756 | if (indirect_symbol_index_data.ValidOffsetForDataOfSize( | ||||||||
4757 | symbol_stub_offset, 4)) { | ||||||||
4758 | const uint32_t stub_sym_id = | ||||||||
4759 | indirect_symbol_index_data.GetU32(&symbol_stub_offset); | ||||||||
4760 | if (stub_sym_id & (INDIRECT_SYMBOL_ABS | INDIRECT_SYMBOL_LOCAL)) | ||||||||
4761 | continue; | ||||||||
4762 | |||||||||
4763 | NListIndexToSymbolIndexMap::const_iterator index_pos = | ||||||||
4764 | m_nlist_idx_to_sym_idx.find(stub_sym_id); | ||||||||
4765 | Symbol *stub_symbol = nullptr; | ||||||||
4766 | if (index_pos != end_index_pos) { | ||||||||
4767 | // We have a remapping from the original nlist index to a | ||||||||
4768 | // current symbol index, so just look this up by index | ||||||||
4769 | stub_symbol = symtab->SymbolAtIndex(index_pos->second); | ||||||||
4770 | } else { | ||||||||
4771 | // We need to lookup a symbol using the original nlist symbol | ||||||||
4772 | // index since this index is coming from the S_SYMBOL_STUBS | ||||||||
4773 | stub_symbol = symtab->FindSymbolByID(stub_sym_id); | ||||||||
4774 | } | ||||||||
4775 | |||||||||
4776 | if (stub_symbol) { | ||||||||
4777 | Address so_addr(symbol_stub_addr, section_list); | ||||||||
4778 | |||||||||
4779 | if (stub_symbol->GetType() == eSymbolTypeUndefined) { | ||||||||
4780 | // Change the external symbol into a trampoline that makes | ||||||||
4781 | // sense These symbols were N_UNDF N_EXT, and are useless | ||||||||
4782 | // to us, so we can re-use them so we don't have to make up | ||||||||
4783 | // a synthetic symbol for no good reason. | ||||||||
4784 | if (resolver_addresses.find(symbol_stub_addr) == | ||||||||
4785 | resolver_addresses.end()) | ||||||||
4786 | stub_symbol->SetType(eSymbolTypeTrampoline); | ||||||||
4787 | else | ||||||||
4788 | stub_symbol->SetType(eSymbolTypeResolver); | ||||||||
4789 | stub_symbol->SetExternal(false); | ||||||||
4790 | stub_symbol->GetAddressRef() = so_addr; | ||||||||
4791 | stub_symbol->SetByteSize(symbol_stub_byte_size); | ||||||||
4792 | } else { | ||||||||
4793 | // Make a synthetic symbol to describe the trampoline stub | ||||||||
4794 | Mangled stub_symbol_mangled_name(stub_symbol->GetMangled()); | ||||||||
4795 | if (sym_idx >= num_syms) { | ||||||||
4796 | sym = symtab->Resize(++num_syms); | ||||||||
4797 | stub_symbol = nullptr; // this pointer no longer valid | ||||||||
4798 | } | ||||||||
4799 | sym[sym_idx].SetID(synthetic_sym_id++); | ||||||||
4800 | sym[sym_idx].GetMangled() = stub_symbol_mangled_name; | ||||||||
4801 | if (resolver_addresses.find(symbol_stub_addr) == | ||||||||
4802 | resolver_addresses.end()) | ||||||||
4803 | sym[sym_idx].SetType(eSymbolTypeTrampoline); | ||||||||
4804 | else | ||||||||
4805 | sym[sym_idx].SetType(eSymbolTypeResolver); | ||||||||
4806 | sym[sym_idx].SetIsSynthetic(true); | ||||||||
4807 | sym[sym_idx].GetAddressRef() = so_addr; | ||||||||
4808 | add_symbol_addr(so_addr.GetFileAddress()); | ||||||||
4809 | sym[sym_idx].SetByteSize(symbol_stub_byte_size); | ||||||||
4810 | ++sym_idx; | ||||||||
4811 | } | ||||||||
4812 | } else { | ||||||||
4813 | if (log) | ||||||||
4814 | log->Warning("symbol stub referencing symbol table symbol " | ||||||||
4815 | "%u that isn't in our minimal symbol table, " | ||||||||
4816 | "fix this!!!", | ||||||||
4817 | stub_sym_id); | ||||||||
4818 | } | ||||||||
4819 | } | ||||||||
4820 | } | ||||||||
4821 | } | ||||||||
4822 | } | ||||||||
4823 | } | ||||||||
4824 | } | ||||||||
4825 | |||||||||
4826 | if (!reexport_trie_entries.empty()) { | ||||||||
4827 | for (const auto &e : reexport_trie_entries) { | ||||||||
4828 | if (e.entry.import_name) { | ||||||||
4829 | // Only add indirect symbols from the Trie entries if we didn't have | ||||||||
4830 | // a N_INDR nlist entry for this already | ||||||||
4831 | if (indirect_symbol_names.find(e.entry.name) == | ||||||||
4832 | indirect_symbol_names.end()) { | ||||||||
4833 | // Make a synthetic symbol to describe re-exported symbol. | ||||||||
4834 | if (sym_idx >= num_syms) | ||||||||
4835 | sym = symtab->Resize(++num_syms); | ||||||||
4836 | sym[sym_idx].SetID(synthetic_sym_id++); | ||||||||
4837 | sym[sym_idx].GetMangled() = Mangled(e.entry.name); | ||||||||
4838 | sym[sym_idx].SetType(eSymbolTypeReExported); | ||||||||
4839 | sym[sym_idx].SetIsSynthetic(true); | ||||||||
4840 | sym[sym_idx].SetReExportedSymbolName(e.entry.import_name); | ||||||||
4841 | if (e.entry.other > 0 && e.entry.other <= dylib_files.GetSize()) { | ||||||||
4842 | sym[sym_idx].SetReExportedSymbolSharedLibrary( | ||||||||
4843 | dylib_files.GetFileSpecAtIndex(e.entry.other - 1)); | ||||||||
4844 | } | ||||||||
4845 | ++sym_idx; | ||||||||
4846 | } | ||||||||
4847 | } | ||||||||
4848 | } | ||||||||
4849 | } | ||||||||
4850 | |||||||||
4851 | // StreamFile s(stdout, false); | ||||||||
4852 | // s.Printf ("Symbol table before CalculateSymbolSizes():\n"); | ||||||||
4853 | // symtab->Dump(&s, NULL, eSortOrderNone); | ||||||||
4854 | // Set symbol byte sizes correctly since mach-o nlist entries don't have | ||||||||
4855 | // sizes | ||||||||
4856 | symtab->CalculateSymbolSizes(); | ||||||||
4857 | |||||||||
4858 | // s.Printf ("Symbol table after CalculateSymbolSizes():\n"); | ||||||||
4859 | // symtab->Dump(&s, NULL, eSortOrderNone); | ||||||||
4860 | |||||||||
4861 | return symtab->GetNumSymbols(); | ||||||||
4862 | } | ||||||||
4863 | |||||||||
4864 | void ObjectFileMachO::Dump(Stream *s) { | ||||||||
4865 | ModuleSP module_sp(GetModule()); | ||||||||
4866 | if (module_sp) { | ||||||||
4867 | std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); | ||||||||
4868 | s->Printf("%p: ", static_cast<void *>(this)); | ||||||||
4869 | s->Indent(); | ||||||||
4870 | if (m_header.magic == MH_MAGIC_64 || m_header.magic == MH_CIGAM_64) | ||||||||
4871 | s->PutCString("ObjectFileMachO64"); | ||||||||
4872 | else | ||||||||
4873 | s->PutCString("ObjectFileMachO32"); | ||||||||
4874 | |||||||||
4875 | *s << ", file = '" << m_file; | ||||||||
4876 | ModuleSpecList all_specs; | ||||||||
4877 | ModuleSpec base_spec; | ||||||||
4878 | GetAllArchSpecs(m_header, m_data, MachHeaderSizeFromMagic(m_header.magic), | ||||||||
4879 | base_spec, all_specs); | ||||||||
4880 | for (unsigned i = 0, e = all_specs.GetSize(); i != e; ++i) { | ||||||||
4881 | *s << "', triple"; | ||||||||
4882 | if (e) | ||||||||
4883 | s->Printf("[%d]", i); | ||||||||
4884 | *s << " = "; | ||||||||
4885 | *s << all_specs.GetModuleSpecRefAtIndex(i) | ||||||||
4886 | .GetArchitecture() | ||||||||
4887 | .GetTriple() | ||||||||
4888 | .getTriple(); | ||||||||
4889 | } | ||||||||
4890 | *s << "\n"; | ||||||||
4891 | SectionList *sections = GetSectionList(); | ||||||||
4892 | if (sections) | ||||||||
4893 | sections->Dump(s->AsRawOstream(), s->GetIndentLevel(), nullptr, true, | ||||||||
4894 | UINT32_MAX0xffffffffU); | ||||||||
4895 | |||||||||
4896 | if (m_symtab_up) | ||||||||
4897 | m_symtab_up->Dump(s, nullptr, eSortOrderNone); | ||||||||
4898 | } | ||||||||
4899 | } | ||||||||
4900 | |||||||||
4901 | UUID ObjectFileMachO::GetUUID(const llvm::MachO::mach_header &header, | ||||||||
4902 | const lldb_private::DataExtractor &data, | ||||||||
4903 | lldb::offset_t lc_offset) { | ||||||||
4904 | uint32_t i; | ||||||||
4905 | llvm::MachO::uuid_command load_cmd; | ||||||||
4906 | |||||||||
4907 | lldb::offset_t offset = lc_offset; | ||||||||
4908 | for (i = 0; i < header.ncmds; ++i) { | ||||||||
4909 | const lldb::offset_t cmd_offset = offset; | ||||||||
4910 | if (data.GetU32(&offset, &load_cmd, 2) == nullptr) | ||||||||
4911 | break; | ||||||||
4912 | |||||||||
4913 | if (load_cmd.cmd == LC_UUID) { | ||||||||
4914 | const uint8_t *uuid_bytes = data.PeekData(offset, 16); | ||||||||
4915 | |||||||||
4916 | if (uuid_bytes) { | ||||||||
4917 | // OpenCL on Mac OS X uses the same UUID for each of its object files. | ||||||||
4918 | // We pretend these object files have no UUID to prevent crashing. | ||||||||
4919 | |||||||||
4920 | const uint8_t opencl_uuid[] = {0x8c, 0x8e, 0xb3, 0x9b, 0x3b, 0xa8, | ||||||||
4921 | 0x4b, 0x16, 0xb6, 0xa4, 0x27, 0x63, | ||||||||
4922 | 0xbb, 0x14, 0xf0, 0x0d}; | ||||||||
4923 | |||||||||
4924 | if (!memcmp(uuid_bytes, opencl_uuid, 16)) | ||||||||
4925 | return UUID(); | ||||||||
4926 | |||||||||
4927 | return UUID::fromOptionalData(uuid_bytes, 16); | ||||||||
4928 | } | ||||||||
4929 | return UUID(); | ||||||||
4930 | } | ||||||||
4931 | offset = cmd_offset + load_cmd.cmdsize; | ||||||||
4932 | } | ||||||||
4933 | return UUID(); | ||||||||
4934 | } | ||||||||
4935 | |||||||||
4936 | static llvm::StringRef GetOSName(uint32_t cmd) { | ||||||||
4937 | switch (cmd) { | ||||||||
4938 | case llvm::MachO::LC_VERSION_MIN_IPHONEOS: | ||||||||
4939 | return llvm::Triple::getOSTypeName(llvm::Triple::IOS); | ||||||||
4940 | case llvm::MachO::LC_VERSION_MIN_MACOSX: | ||||||||
4941 | return llvm::Triple::getOSTypeName(llvm::Triple::MacOSX); | ||||||||
4942 | case llvm::MachO::LC_VERSION_MIN_TVOS: | ||||||||
4943 | return llvm::Triple::getOSTypeName(llvm::Triple::TvOS); | ||||||||
4944 | case llvm::MachO::LC_VERSION_MIN_WATCHOS: | ||||||||
4945 | return llvm::Triple::getOSTypeName(llvm::Triple::WatchOS); | ||||||||
4946 | default: | ||||||||
4947 | llvm_unreachable("unexpected LC_VERSION load command")__builtin_unreachable(); | ||||||||
4948 | } | ||||||||
4949 | } | ||||||||
4950 | |||||||||
4951 | namespace { | ||||||||
4952 | struct OSEnv { | ||||||||
4953 | llvm::StringRef os_type; | ||||||||
4954 | llvm::StringRef environment; | ||||||||
4955 | OSEnv(uint32_t cmd) { | ||||||||
4956 | switch (cmd) { | ||||||||
4957 | case llvm::MachO::PLATFORM_MACOS: | ||||||||
4958 | os_type = llvm::Triple::getOSTypeName(llvm::Triple::MacOSX); | ||||||||
4959 | return; | ||||||||
4960 | case llvm::MachO::PLATFORM_IOS: | ||||||||
4961 | os_type = llvm::Triple::getOSTypeName(llvm::Triple::IOS); | ||||||||
4962 | return; | ||||||||
4963 | case llvm::MachO::PLATFORM_TVOS: | ||||||||
4964 | os_type = llvm::Triple::getOSTypeName(llvm::Triple::TvOS); | ||||||||
4965 | return; | ||||||||
4966 | case llvm::MachO::PLATFORM_WATCHOS: | ||||||||
4967 | os_type = llvm::Triple::getOSTypeName(llvm::Triple::WatchOS); | ||||||||
4968 | return; | ||||||||
4969 | // NEED_BRIDGEOS_TRIPLE case llvm::MachO::PLATFORM_BRIDGEOS: | ||||||||
4970 | // NEED_BRIDGEOS_TRIPLE os_type = | ||||||||
4971 | // llvm::Triple::getOSTypeName(llvm::Triple::BridgeOS); | ||||||||
4972 | // NEED_BRIDGEOS_TRIPLE return; | ||||||||
4973 | case llvm::MachO::PLATFORM_MACCATALYST: | ||||||||
4974 | os_type = llvm::Triple::getOSTypeName(llvm::Triple::IOS); | ||||||||
4975 | environment = llvm::Triple::getEnvironmentTypeName(llvm::Triple::MacABI); | ||||||||
4976 | return; | ||||||||
4977 | case llvm::MachO::PLATFORM_IOSSIMULATOR: | ||||||||
4978 | os_type = llvm::Triple::getOSTypeName(llvm::Triple::IOS); | ||||||||
4979 | environment = | ||||||||
4980 | llvm::Triple::getEnvironmentTypeName(llvm::Triple::Simulator); | ||||||||
4981 | return; | ||||||||
4982 | case llvm::MachO::PLATFORM_TVOSSIMULATOR: | ||||||||
4983 | os_type = llvm::Triple::getOSTypeName(llvm::Triple::TvOS); | ||||||||
4984 | environment = | ||||||||
4985 | llvm::Triple::getEnvironmentTypeName(llvm::Triple::Simulator); | ||||||||
4986 | return; | ||||||||
4987 | case llvm::MachO::PLATFORM_WATCHOSSIMULATOR: | ||||||||
4988 | os_type = llvm::Triple::getOSTypeName(llvm::Triple::WatchOS); | ||||||||
4989 | environment = | ||||||||
4990 | llvm::Triple::getEnvironmentTypeName(llvm::Triple::Simulator); | ||||||||
4991 | return; | ||||||||
4992 | default: { | ||||||||
4993 | Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_SYMBOLS(1u << 20) | | ||||||||
4994 | LIBLLDB_LOG_PROCESS(1u << 1))); | ||||||||
4995 | LLDB_LOGF(log, "unsupported platform in LC_BUILD_VERSION")do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("unsupported platform in LC_BUILD_VERSION" ); } while (0); | ||||||||
4996 | } | ||||||||
4997 | } | ||||||||
4998 | } | ||||||||
4999 | }; | ||||||||
5000 | |||||||||
5001 | struct MinOS { | ||||||||
5002 | uint32_t major_version, minor_version, patch_version; | ||||||||
5003 | MinOS(uint32_t version) | ||||||||
5004 | : major_version(version >> 16), minor_version((version >> 8) & 0xffu), | ||||||||
5005 | patch_version(version & 0xffu) {} | ||||||||
5006 | }; | ||||||||
5007 | } // namespace | ||||||||
5008 | |||||||||
5009 | void ObjectFileMachO::GetAllArchSpecs(const llvm::MachO::mach_header &header, | ||||||||
5010 | const lldb_private::DataExtractor &data, | ||||||||
5011 | lldb::offset_t lc_offset, | ||||||||
5012 | ModuleSpec &base_spec, | ||||||||
5013 | lldb_private::ModuleSpecList &all_specs) { | ||||||||
5014 | auto &base_arch = base_spec.GetArchitecture(); | ||||||||
5015 | base_arch.SetArchitecture(eArchTypeMachO, header.cputype, header.cpusubtype); | ||||||||
5016 | if (!base_arch.IsValid()) | ||||||||
5017 | return; | ||||||||
5018 | |||||||||
5019 | bool found_any = false; | ||||||||
5020 | auto add_triple = [&](const llvm::Triple &triple) { | ||||||||
5021 | auto spec = base_spec; | ||||||||
5022 | spec.GetArchitecture().GetTriple() = triple; | ||||||||
5023 | if (spec.GetArchitecture().IsValid()) { | ||||||||
5024 | spec.GetUUID() = ObjectFileMachO::GetUUID(header, data, lc_offset); | ||||||||
5025 | all_specs.Append(spec); | ||||||||
5026 | found_any = true; | ||||||||
5027 | } | ||||||||
5028 | }; | ||||||||
5029 | |||||||||
5030 | // Set OS to an unspecified unknown or a "*" so it can match any OS | ||||||||
5031 | llvm::Triple base_triple = base_arch.GetTriple(); | ||||||||
5032 | base_triple.setOS(llvm::Triple::UnknownOS); | ||||||||
5033 | base_triple.setOSName(llvm::StringRef()); | ||||||||
5034 | |||||||||
5035 | if (header.filetype == MH_PRELOAD) { | ||||||||
5036 | if (header.cputype == CPU_TYPE_ARM) { | ||||||||
5037 | // If this is a 32-bit arm binary, and it's a standalone binary, force | ||||||||
5038 | // the Vendor to Apple so we don't accidentally pick up the generic | ||||||||
5039 | // armv7 ABI at runtime. Apple's armv7 ABI always uses r7 for the | ||||||||
5040 | // frame pointer register; most other armv7 ABIs use a combination of | ||||||||
5041 | // r7 and r11. | ||||||||
5042 | base_triple.setVendor(llvm::Triple::Apple); | ||||||||
5043 | } else { | ||||||||
5044 | // Set vendor to an unspecified unknown or a "*" so it can match any | ||||||||
5045 | // vendor This is required for correct behavior of EFI debugging on | ||||||||
5046 | // x86_64 | ||||||||
5047 | base_triple.setVendor(llvm::Triple::UnknownVendor); | ||||||||
5048 | base_triple.setVendorName(llvm::StringRef()); | ||||||||
5049 | } | ||||||||
5050 | return add_triple(base_triple); | ||||||||
5051 | } | ||||||||
5052 | |||||||||
5053 | llvm::MachO::load_command load_cmd; | ||||||||
5054 | |||||||||
5055 | // See if there is an LC_VERSION_MIN_* load command that can give | ||||||||
5056 | // us the OS type. | ||||||||
5057 | lldb::offset_t offset = lc_offset; | ||||||||
5058 | for (uint32_t i = 0; i < header.ncmds; ++i) { | ||||||||
5059 | const lldb::offset_t cmd_offset = offset; | ||||||||
5060 | if (data.GetU32(&offset, &load_cmd, 2) == NULL__null) | ||||||||
5061 | break; | ||||||||
5062 | |||||||||
5063 | llvm::MachO::version_min_command version_min; | ||||||||
5064 | switch (load_cmd.cmd) { | ||||||||
5065 | case llvm::MachO::LC_VERSION_MIN_MACOSX: | ||||||||
5066 | case llvm::MachO::LC_VERSION_MIN_IPHONEOS: | ||||||||
5067 | case llvm::MachO::LC_VERSION_MIN_TVOS: | ||||||||
5068 | case llvm::MachO::LC_VERSION_MIN_WATCHOS: { | ||||||||
5069 | if (load_cmd.cmdsize != sizeof(version_min)) | ||||||||
5070 | break; | ||||||||
5071 | if (data.ExtractBytes(cmd_offset, sizeof(version_min), | ||||||||
5072 | data.GetByteOrder(), &version_min) == 0) | ||||||||
5073 | break; | ||||||||
5074 | MinOS min_os(version_min.version); | ||||||||
5075 | llvm::SmallString<32> os_name; | ||||||||
5076 | llvm::raw_svector_ostream os(os_name); | ||||||||
5077 | os << GetOSName(load_cmd.cmd) << min_os.major_version << '.' | ||||||||
5078 | << min_os.minor_version << '.' << min_os.patch_version; | ||||||||
5079 | |||||||||
5080 | auto triple = base_triple; | ||||||||
5081 | triple.setOSName(os.str()); | ||||||||
5082 | |||||||||
5083 | // Disambiguate legacy simulator platforms. | ||||||||
5084 | if (load_cmd.cmd != llvm::MachO::LC_VERSION_MIN_MACOSX && | ||||||||
5085 | (base_triple.getArch() == llvm::Triple::x86_64 || | ||||||||
5086 | base_triple.getArch() == llvm::Triple::x86)) { | ||||||||
5087 | // The combination of legacy LC_VERSION_MIN load command and | ||||||||
5088 | // x86 architecture always indicates a simulator environment. | ||||||||
5089 | // The combination of LC_VERSION_MIN and arm architecture only | ||||||||
5090 | // appears for native binaries. Back-deploying simulator | ||||||||
5091 | // binaries on Apple Silicon Macs use the modern unambigous | ||||||||
5092 | // LC_BUILD_VERSION load commands; no special handling required. | ||||||||
5093 | triple.setEnvironment(llvm::Triple::Simulator); | ||||||||
5094 | } | ||||||||
5095 | add_triple(triple); | ||||||||
5096 | break; | ||||||||
5097 | } | ||||||||
5098 | default: | ||||||||
5099 | break; | ||||||||
5100 | } | ||||||||
5101 | |||||||||
5102 | offset = cmd_offset + load_cmd.cmdsize; | ||||||||
5103 | } | ||||||||
5104 | |||||||||
5105 | // See if there are LC_BUILD_VERSION load commands that can give | ||||||||
5106 | // us the OS type. | ||||||||
5107 | offset = lc_offset; | ||||||||
5108 | for (uint32_t i = 0; i < header.ncmds; ++i) { | ||||||||
5109 | const lldb::offset_t cmd_offset = offset; | ||||||||
5110 | if (data.GetU32(&offset, &load_cmd, 2) == NULL__null) | ||||||||
5111 | break; | ||||||||
5112 | |||||||||
5113 | do { | ||||||||
5114 | if (load_cmd.cmd == llvm::MachO::LC_BUILD_VERSION) { | ||||||||
5115 | llvm::MachO::build_version_command build_version; | ||||||||
5116 | if (load_cmd.cmdsize < sizeof(build_version)) { | ||||||||
5117 | // Malformed load command. | ||||||||
5118 | break; | ||||||||
5119 | } | ||||||||
5120 | if (data.ExtractBytes(cmd_offset, sizeof(build_version), | ||||||||
5121 | data.GetByteOrder(), &build_version) == 0) | ||||||||
5122 | break; | ||||||||
5123 | MinOS min_os(build_version.minos); | ||||||||
5124 | OSEnv os_env(build_version.platform); | ||||||||
5125 | llvm::SmallString<16> os_name; | ||||||||
5126 | llvm::raw_svector_ostream os(os_name); | ||||||||
5127 | os << os_env.os_type << min_os.major_version << '.' | ||||||||
5128 | << min_os.minor_version << '.' << min_os.patch_version; | ||||||||
5129 | auto triple = base_triple; | ||||||||
5130 | triple.setOSName(os.str()); | ||||||||
5131 | os_name.clear(); | ||||||||
5132 | if (!os_env.environment.empty()) | ||||||||
5133 | triple.setEnvironmentName(os_env.environment); | ||||||||
5134 | add_triple(triple); | ||||||||
5135 | } | ||||||||
5136 | } while (0); | ||||||||
5137 | offset = cmd_offset + load_cmd.cmdsize; | ||||||||
5138 | } | ||||||||
5139 | |||||||||
5140 | if (!found_any) { | ||||||||
5141 | if (header.filetype == MH_KEXT_BUNDLE) { | ||||||||
5142 | base_triple.setVendor(llvm::Triple::Apple); | ||||||||
5143 | add_triple(base_triple); | ||||||||
5144 | } else { | ||||||||
5145 | // We didn't find a LC_VERSION_MIN load command and this isn't a KEXT | ||||||||
5146 | // so lets not say our Vendor is Apple, leave it as an unspecified | ||||||||
5147 | // unknown. | ||||||||
5148 | base_triple.setVendor(llvm::Triple::UnknownVendor); | ||||||||
5149 | base_triple.setVendorName(llvm::StringRef()); | ||||||||
5150 | add_triple(base_triple); | ||||||||
5151 | } | ||||||||
5152 | } | ||||||||
5153 | } | ||||||||
5154 | |||||||||
5155 | ArchSpec ObjectFileMachO::GetArchitecture( | ||||||||
5156 | ModuleSP module_sp, const llvm::MachO::mach_header &header, | ||||||||
5157 | const lldb_private::DataExtractor &data, lldb::offset_t lc_offset) { | ||||||||
5158 | ModuleSpecList all_specs; | ||||||||
5159 | ModuleSpec base_spec; | ||||||||
5160 | GetAllArchSpecs(header, data, MachHeaderSizeFromMagic(header.magic), | ||||||||
5161 | base_spec, all_specs); | ||||||||
5162 | |||||||||
5163 | // If the object file offers multiple alternative load commands, | ||||||||
5164 | // pick the one that matches the module. | ||||||||
5165 | if (module_sp) { | ||||||||
5166 | const ArchSpec &module_arch = module_sp->GetArchitecture(); | ||||||||
5167 | for (unsigned i = 0, e = all_specs.GetSize(); i != e; ++i) { | ||||||||
5168 | ArchSpec mach_arch = | ||||||||
5169 | all_specs.GetModuleSpecRefAtIndex(i).GetArchitecture(); | ||||||||
5170 | if (module_arch.IsCompatibleMatch(mach_arch)) | ||||||||
5171 | return mach_arch; | ||||||||
5172 | } | ||||||||
5173 | } | ||||||||
5174 | |||||||||
5175 | // Return the first arch we found. | ||||||||
5176 | if (all_specs.GetSize() == 0) | ||||||||
5177 | return {}; | ||||||||
5178 | return all_specs.GetModuleSpecRefAtIndex(0).GetArchitecture(); | ||||||||
5179 | } | ||||||||
5180 | |||||||||
5181 | UUID ObjectFileMachO::GetUUID() { | ||||||||
5182 | ModuleSP module_sp(GetModule()); | ||||||||
5183 | if (module_sp) { | ||||||||
5184 | std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); | ||||||||
5185 | lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); | ||||||||
5186 | return GetUUID(m_header, m_data, offset); | ||||||||
5187 | } | ||||||||
5188 | return UUID(); | ||||||||
5189 | } | ||||||||
5190 | |||||||||
5191 | uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) { | ||||||||
5192 | uint32_t count = 0; | ||||||||
5193 | ModuleSP module_sp(GetModule()); | ||||||||
5194 | if (module_sp) { | ||||||||
5195 | std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); | ||||||||
5196 | llvm::MachO::load_command load_cmd; | ||||||||
5197 | lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); | ||||||||
5198 | std::vector<std::string> rpath_paths; | ||||||||
5199 | std::vector<std::string> rpath_relative_paths; | ||||||||
5200 | std::vector<std::string> at_exec_relative_paths; | ||||||||
5201 | uint32_t i; | ||||||||
5202 | for (i = 0; i < m_header.ncmds; ++i) { | ||||||||
5203 | const uint32_t cmd_offset = offset; | ||||||||
5204 | if (m_data.GetU32(&offset, &load_cmd, 2) == nullptr) | ||||||||
5205 | break; | ||||||||
5206 | |||||||||
5207 | switch (load_cmd.cmd) { | ||||||||
5208 | case LC_RPATH: | ||||||||
5209 | case LC_LOAD_DYLIB: | ||||||||
5210 | case LC_LOAD_WEAK_DYLIB: | ||||||||
5211 | case LC_REEXPORT_DYLIB: | ||||||||
5212 | case LC_LOAD_DYLINKER: | ||||||||
5213 | case LC_LOADFVMLIB: | ||||||||
5214 | case LC_LOAD_UPWARD_DYLIB: { | ||||||||
5215 | uint32_t name_offset = cmd_offset + m_data.GetU32(&offset); | ||||||||
5216 | const char *path = m_data.PeekCStr(name_offset); | ||||||||
5217 | if (path) { | ||||||||
5218 | if (load_cmd.cmd == LC_RPATH) | ||||||||
5219 | rpath_paths.push_back(path); | ||||||||
5220 | else { | ||||||||
5221 | if (path[0] == '@') { | ||||||||
5222 | if (strncmp(path, "@rpath", strlen("@rpath")) == 0) | ||||||||
5223 | rpath_relative_paths.push_back(path + strlen("@rpath")); | ||||||||
5224 | else if (strncmp(path, "@executable_path", | ||||||||
5225 | strlen("@executable_path")) == 0) | ||||||||
5226 | at_exec_relative_paths.push_back(path + | ||||||||
5227 | strlen("@executable_path")); | ||||||||
5228 | } else { | ||||||||
5229 | FileSpec file_spec(path); | ||||||||
5230 | if (files.AppendIfUnique(file_spec)) | ||||||||
5231 | count++; | ||||||||
5232 | } | ||||||||
5233 | } | ||||||||
5234 | } | ||||||||
5235 | } break; | ||||||||
5236 | |||||||||
5237 | default: | ||||||||
5238 | break; | ||||||||
5239 | } | ||||||||
5240 | offset = cmd_offset + load_cmd.cmdsize; | ||||||||
5241 | } | ||||||||
5242 | |||||||||
5243 | FileSpec this_file_spec(m_file); | ||||||||
5244 | FileSystem::Instance().Resolve(this_file_spec); | ||||||||
5245 | |||||||||
5246 | if (!rpath_paths.empty()) { | ||||||||
5247 | // Fixup all LC_RPATH values to be absolute paths | ||||||||
5248 | std::string loader_path("@loader_path"); | ||||||||
5249 | std::string executable_path("@executable_path"); | ||||||||
5250 | for (auto &rpath : rpath_paths) { | ||||||||
5251 | if (llvm::StringRef(rpath).startswith(loader_path)) { | ||||||||
5252 | rpath.erase(0, loader_path.size()); | ||||||||
5253 | rpath.insert(0, this_file_spec.GetDirectory().GetCString()); | ||||||||
5254 | } else if (llvm::StringRef(rpath).startswith(executable_path)) { | ||||||||
5255 | rpath.erase(0, executable_path.size()); | ||||||||
5256 | rpath.insert(0, this_file_spec.GetDirectory().GetCString()); | ||||||||
5257 | } | ||||||||
5258 | } | ||||||||
5259 | |||||||||
5260 | for (const auto &rpath_relative_path : rpath_relative_paths) { | ||||||||
5261 | for (const auto &rpath : rpath_paths) { | ||||||||
5262 | std::string path = rpath; | ||||||||
5263 | path += rpath_relative_path; | ||||||||
5264 | // It is OK to resolve this path because we must find a file on disk | ||||||||
5265 | // for us to accept it anyway if it is rpath relative. | ||||||||
5266 | FileSpec file_spec(path); | ||||||||
5267 | FileSystem::Instance().Resolve(file_spec); | ||||||||
5268 | if (FileSystem::Instance().Exists(file_spec) && | ||||||||
5269 | files.AppendIfUnique(file_spec)) { | ||||||||
5270 | count++; | ||||||||
5271 | break; | ||||||||
5272 | } | ||||||||
5273 | } | ||||||||
5274 | } | ||||||||
5275 | } | ||||||||
5276 | |||||||||
5277 | // We may have @executable_paths but no RPATHS. Figure those out here. | ||||||||
5278 | // Only do this if this object file is the executable. We have no way to | ||||||||
5279 | // get back to the actual executable otherwise, so we won't get the right | ||||||||
5280 | // path. | ||||||||
5281 | if (!at_exec_relative_paths.empty() && CalculateType() == eTypeExecutable) { | ||||||||
5282 | FileSpec exec_dir = this_file_spec.CopyByRemovingLastPathComponent(); | ||||||||
5283 | for (const auto &at_exec_relative_path : at_exec_relative_paths) { | ||||||||
5284 | FileSpec file_spec = | ||||||||
5285 | exec_dir.CopyByAppendingPathComponent(at_exec_relative_path); | ||||||||
5286 | if (FileSystem::Instance().Exists(file_spec) && | ||||||||
5287 | files.AppendIfUnique(file_spec)) | ||||||||
5288 | count++; | ||||||||
5289 | } | ||||||||
5290 | } | ||||||||
5291 | } | ||||||||
5292 | return count; | ||||||||
5293 | } | ||||||||
5294 | |||||||||
5295 | lldb_private::Address ObjectFileMachO::GetEntryPointAddress() { | ||||||||
5296 | // If the object file is not an executable it can't hold the entry point. | ||||||||
5297 | // m_entry_point_address is initialized to an invalid address, so we can just | ||||||||
5298 | // return that. If m_entry_point_address is valid it means we've found it | ||||||||
5299 | // already, so return the cached value. | ||||||||
5300 | |||||||||
5301 | if ((!IsExecutable() && !IsDynamicLoader()) || | ||||||||
5302 | m_entry_point_address.IsValid()) { | ||||||||
5303 | return m_entry_point_address; | ||||||||
5304 | } | ||||||||
5305 | |||||||||
5306 | // Otherwise, look for the UnixThread or Thread command. The data for the | ||||||||
5307 | // Thread command is given in /usr/include/mach-o.h, but it is basically: | ||||||||
5308 | // | ||||||||
5309 | // uint32_t flavor - this is the flavor argument you would pass to | ||||||||
5310 | // thread_get_state | ||||||||
5311 | // uint32_t count - this is the count of longs in the thread state data | ||||||||
5312 | // struct XXX_thread_state state - this is the structure from | ||||||||
5313 | // <machine/thread_status.h> corresponding to the flavor. | ||||||||
5314 | // <repeat this trio> | ||||||||
5315 | // | ||||||||
5316 | // So we just keep reading the various register flavors till we find the GPR | ||||||||
5317 | // one, then read the PC out of there. | ||||||||
5318 | // FIXME: We will need to have a "RegisterContext data provider" class at some | ||||||||
5319 | // point that can get all the registers | ||||||||
5320 | // out of data in this form & attach them to a given thread. That should | ||||||||
5321 | // underlie the MacOS X User process plugin, and we'll also need it for the | ||||||||
5322 | // MacOS X Core File process plugin. When we have that we can also use it | ||||||||
5323 | // here. | ||||||||
5324 | // | ||||||||
5325 | // For now we hard-code the offsets and flavors we need: | ||||||||
5326 | // | ||||||||
5327 | // | ||||||||
5328 | |||||||||
5329 | ModuleSP module_sp(GetModule()); | ||||||||
5330 | if (module_sp) { | ||||||||
5331 | std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); | ||||||||
5332 | llvm::MachO::load_command load_cmd; | ||||||||
5333 | lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); | ||||||||
5334 | uint32_t i; | ||||||||
5335 | lldb::addr_t start_address = LLDB_INVALID_ADDRESS0xffffffffffffffffULL; | ||||||||
5336 | bool done = false; | ||||||||
5337 | |||||||||
5338 | for (i = 0; i < m_header.ncmds; ++i) { | ||||||||
5339 | const lldb::offset_t cmd_offset = offset; | ||||||||
5340 | if (m_data.GetU32(&offset, &load_cmd, 2) == nullptr) | ||||||||
5341 | break; | ||||||||
5342 | |||||||||
5343 | switch (load_cmd.cmd) { | ||||||||
5344 | case LC_UNIXTHREAD: | ||||||||
5345 | case LC_THREAD: { | ||||||||
5346 | while (offset < cmd_offset + load_cmd.cmdsize) { | ||||||||
5347 | uint32_t flavor = m_data.GetU32(&offset); | ||||||||
5348 | uint32_t count = m_data.GetU32(&offset); | ||||||||
5349 | if (count == 0) { | ||||||||
5350 | // We've gotten off somehow, log and exit; | ||||||||
5351 | return m_entry_point_address; | ||||||||
5352 | } | ||||||||
5353 | |||||||||
5354 | switch (m_header.cputype) { | ||||||||
5355 | case llvm::MachO::CPU_TYPE_ARM: | ||||||||
5356 | if (flavor == 1 || | ||||||||
5357 | flavor == 9) // ARM_THREAD_STATE/ARM_THREAD_STATE32 | ||||||||
5358 | // from mach/arm/thread_status.h | ||||||||
5359 | { | ||||||||
5360 | offset += 60; // This is the offset of pc in the GPR thread state | ||||||||
5361 | // data structure. | ||||||||
5362 | start_address = m_data.GetU32(&offset); | ||||||||
5363 | done = true; | ||||||||
5364 | } | ||||||||
5365 | break; | ||||||||
5366 | case llvm::MachO::CPU_TYPE_ARM64: | ||||||||
5367 | case llvm::MachO::CPU_TYPE_ARM64_32: | ||||||||
5368 | if (flavor == 6) // ARM_THREAD_STATE64 from mach/arm/thread_status.h | ||||||||
5369 | { | ||||||||
5370 | offset += 256; // This is the offset of pc in the GPR thread state | ||||||||
5371 | // data structure. | ||||||||
5372 | start_address = m_data.GetU64(&offset); | ||||||||
5373 | done = true; | ||||||||
5374 | } | ||||||||
5375 | break; | ||||||||
5376 | case llvm::MachO::CPU_TYPE_I386: | ||||||||
5377 | if (flavor == | ||||||||
5378 | 1) // x86_THREAD_STATE32 from mach/i386/thread_status.h | ||||||||
5379 | { | ||||||||
5380 | offset += 40; // This is the offset of eip in the GPR thread state | ||||||||
5381 | // data structure. | ||||||||
5382 | start_address = m_data.GetU32(&offset); | ||||||||
5383 | done = true; | ||||||||
5384 | } | ||||||||
5385 | break; | ||||||||
5386 | case llvm::MachO::CPU_TYPE_X86_64: | ||||||||
5387 | if (flavor == | ||||||||
5388 | 4) // x86_THREAD_STATE64 from mach/i386/thread_status.h | ||||||||
5389 | { | ||||||||
5390 | offset += 16 * 8; // This is the offset of rip in the GPR thread | ||||||||
5391 | // state data structure. | ||||||||
5392 | start_address = m_data.GetU64(&offset); | ||||||||
5393 | done = true; | ||||||||
5394 | } | ||||||||
5395 | break; | ||||||||
5396 | default: | ||||||||
5397 | return m_entry_point_address; | ||||||||
5398 | } | ||||||||
5399 | // Haven't found the GPR flavor yet, skip over the data for this | ||||||||
5400 | // flavor: | ||||||||
5401 | if (done) | ||||||||
5402 | break; | ||||||||
5403 | offset += count * 4; | ||||||||
5404 | } | ||||||||
5405 | } break; | ||||||||
5406 | case LC_MAIN: { | ||||||||
5407 | ConstString text_segment_name("__TEXT"); | ||||||||
5408 | uint64_t entryoffset = m_data.GetU64(&offset); | ||||||||
5409 | SectionSP text_segment_sp = | ||||||||
5410 | GetSectionList()->FindSectionByName(text_segment_name); | ||||||||
5411 | if (text_segment_sp) { | ||||||||
5412 | done = true; | ||||||||
5413 | start_address = text_segment_sp->GetFileAddress() + entryoffset; | ||||||||
5414 | } | ||||||||
5415 | } break; | ||||||||
5416 | |||||||||
5417 | default: | ||||||||
5418 | break; | ||||||||
5419 | } | ||||||||
5420 | if (done) | ||||||||
5421 | break; | ||||||||
5422 | |||||||||
5423 | // Go to the next load command: | ||||||||
5424 | offset = cmd_offset + load_cmd.cmdsize; | ||||||||
5425 | } | ||||||||
5426 | |||||||||
5427 | if (start_address == LLDB_INVALID_ADDRESS0xffffffffffffffffULL && IsDynamicLoader()) { | ||||||||
5428 | if (GetSymtab()) { | ||||||||
5429 | Symbol *dyld_start_sym = GetSymtab()->FindFirstSymbolWithNameAndType( | ||||||||
5430 | ConstString("_dyld_start"), SymbolType::eSymbolTypeCode, | ||||||||
5431 | Symtab::eDebugAny, Symtab::eVisibilityAny); | ||||||||
5432 | if (dyld_start_sym && dyld_start_sym->GetAddress().IsValid()) { | ||||||||
5433 | start_address = dyld_start_sym->GetAddress().GetFileAddress(); | ||||||||
5434 | } | ||||||||
5435 | } | ||||||||
5436 | } | ||||||||
5437 | |||||||||
5438 | if (start_address != LLDB_INVALID_ADDRESS0xffffffffffffffffULL) { | ||||||||
5439 | // We got the start address from the load commands, so now resolve that | ||||||||
5440 | // address in the sections of this ObjectFile: | ||||||||
5441 | if (!m_entry_point_address.ResolveAddressUsingFileSections( | ||||||||
5442 | start_address, GetSectionList())) { | ||||||||
5443 | m_entry_point_address.Clear(); | ||||||||
5444 | } | ||||||||
5445 | } else { | ||||||||
5446 | // We couldn't read the UnixThread load command - maybe it wasn't there. | ||||||||
5447 | // As a fallback look for the "start" symbol in the main executable. | ||||||||
5448 | |||||||||
5449 | ModuleSP module_sp(GetModule()); | ||||||||
5450 | |||||||||
5451 | if (module_sp) { | ||||||||
5452 | SymbolContextList contexts; | ||||||||
5453 | SymbolContext context; | ||||||||
5454 | module_sp->FindSymbolsWithNameAndType(ConstString("start"), | ||||||||
5455 | eSymbolTypeCode, contexts); | ||||||||
5456 | if (contexts.GetSize()) { | ||||||||
5457 | if (contexts.GetContextAtIndex(0, context)) | ||||||||
5458 | m_entry_point_address = context.symbol->GetAddress(); | ||||||||
5459 | } | ||||||||
5460 | } | ||||||||
5461 | } | ||||||||
5462 | } | ||||||||
5463 | |||||||||
5464 | return m_entry_point_address; | ||||||||
5465 | } | ||||||||
5466 | |||||||||
5467 | lldb_private::Address ObjectFileMachO::GetBaseAddress() { | ||||||||
5468 | lldb_private::Address header_addr; | ||||||||
5469 | SectionList *section_list = GetSectionList(); | ||||||||
5470 | if (section_list) { | ||||||||
5471 | SectionSP text_segment_sp( | ||||||||
5472 | section_list->FindSectionByName(GetSegmentNameTEXT())); | ||||||||
5473 | if (text_segment_sp) { | ||||||||
5474 | header_addr.SetSection(text_segment_sp); | ||||||||
5475 | header_addr.SetOffset(0); | ||||||||
5476 | } | ||||||||
5477 | } | ||||||||
5478 | return header_addr; | ||||||||
5479 | } | ||||||||
5480 | |||||||||
5481 | uint32_t ObjectFileMachO::GetNumThreadContexts() { | ||||||||
5482 | ModuleSP module_sp(GetModule()); | ||||||||
5483 | if (module_sp) { | ||||||||
5484 | std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); | ||||||||
5485 | if (!m_thread_context_offsets_valid) { | ||||||||
5486 | m_thread_context_offsets_valid = true; | ||||||||
5487 | lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); | ||||||||
5488 | FileRangeArray::Entry file_range; | ||||||||
5489 | llvm::MachO::thread_command thread_cmd; | ||||||||
5490 | for (uint32_t i = 0; i < m_header.ncmds; ++i) { | ||||||||
5491 | const uint32_t cmd_offset = offset; | ||||||||
5492 | if (m_data.GetU32(&offset, &thread_cmd, 2) == nullptr) | ||||||||
5493 | break; | ||||||||
5494 | |||||||||
5495 | if (thread_cmd.cmd == LC_THREAD) { | ||||||||
5496 | file_range.SetRangeBase(offset); | ||||||||
5497 | file_range.SetByteSize(thread_cmd.cmdsize - 8); | ||||||||
5498 | m_thread_context_offsets.Append(file_range); | ||||||||
5499 | } | ||||||||
5500 | offset = cmd_offset + thread_cmd.cmdsize; | ||||||||
5501 | } | ||||||||
5502 | } | ||||||||
5503 | } | ||||||||
5504 | return m_thread_context_offsets.GetSize(); | ||||||||
5505 | } | ||||||||
5506 | |||||||||
5507 | std::string ObjectFileMachO::GetIdentifierString() { | ||||||||
5508 | std::string result; | ||||||||
5509 | ModuleSP module_sp(GetModule()); | ||||||||
5510 | if (module_sp) { | ||||||||
5511 | std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); | ||||||||
5512 | |||||||||
5513 | // First, look over the load commands for an LC_NOTE load command with | ||||||||
5514 | // data_owner string "kern ver str" & use that if found. | ||||||||
5515 | lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); | ||||||||
5516 | for (uint32_t i = 0; i < m_header.ncmds; ++i) { | ||||||||
5517 | const uint32_t cmd_offset = offset; | ||||||||
5518 | llvm::MachO::load_command lc; | ||||||||
5519 | if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr) | ||||||||
5520 | break; | ||||||||
5521 | if (lc.cmd == LC_NOTE) { | ||||||||
5522 | char data_owner[17]; | ||||||||
5523 | m_data.CopyData(offset, 16, data_owner); | ||||||||
5524 | data_owner[16] = '\0'; | ||||||||
5525 | offset += 16; | ||||||||
5526 | uint64_t fileoff = m_data.GetU64_unchecked(&offset); | ||||||||
5527 | uint64_t size = m_data.GetU64_unchecked(&offset); | ||||||||
5528 | |||||||||
5529 | // "kern ver str" has a uint32_t version and then a nul terminated | ||||||||
5530 | // c-string. | ||||||||
5531 | if (strcmp("kern ver str", data_owner) == 0) { | ||||||||
5532 | offset = fileoff; | ||||||||
5533 | uint32_t version; | ||||||||
5534 | if (m_data.GetU32(&offset, &version, 1) != nullptr) { | ||||||||
5535 | if (version == 1) { | ||||||||
5536 | uint32_t strsize = size - sizeof(uint32_t); | ||||||||
5537 | char *buf = (char *)malloc(strsize); | ||||||||
5538 | if (buf) { | ||||||||
5539 | m_data.CopyData(offset, strsize, buf); | ||||||||
5540 | buf[strsize - 1] = '\0'; | ||||||||
5541 | result = buf; | ||||||||
5542 | if (buf) | ||||||||
5543 | free(buf); | ||||||||
5544 | return result; | ||||||||
5545 | } | ||||||||
5546 | } | ||||||||
5547 | } | ||||||||
5548 | } | ||||||||
5549 | } | ||||||||
5550 | offset = cmd_offset + lc.cmdsize; | ||||||||
5551 | } | ||||||||
5552 | |||||||||
5553 | // Second, make a pass over the load commands looking for an obsolete | ||||||||
5554 | // LC_IDENT load command. | ||||||||
5555 | offset = MachHeaderSizeFromMagic(m_header.magic); | ||||||||
5556 | for (uint32_t i = 0; i < m_header.ncmds; ++i) { | ||||||||
5557 | const uint32_t cmd_offset = offset; | ||||||||
5558 | llvm::MachO::ident_command ident_command; | ||||||||
5559 | if (m_data.GetU32(&offset, &ident_command, 2) == nullptr) | ||||||||
5560 | break; | ||||||||
5561 | if (ident_command.cmd == LC_IDENT && ident_command.cmdsize != 0) { | ||||||||
5562 | char *buf = (char *)malloc(ident_command.cmdsize); | ||||||||
5563 | if (buf != nullptr && m_data.CopyData(offset, ident_command.cmdsize, | ||||||||
5564 | buf) == ident_command.cmdsize) { | ||||||||
5565 | buf[ident_command.cmdsize - 1] = '\0'; | ||||||||
5566 | result = buf; | ||||||||
5567 | } | ||||||||
5568 | if (buf) | ||||||||
5569 | free(buf); | ||||||||
5570 | } | ||||||||
5571 | offset = cmd_offset + ident_command.cmdsize; | ||||||||
5572 | } | ||||||||
5573 | } | ||||||||
5574 | return result; | ||||||||
5575 | } | ||||||||
5576 | |||||||||
5577 | addr_t ObjectFileMachO::GetAddressMask() { | ||||||||
5578 | addr_t mask = 0; | ||||||||
5579 | ModuleSP module_sp(GetModule()); | ||||||||
5580 | if (module_sp) { | ||||||||
5581 | std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); | ||||||||
5582 | lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); | ||||||||
5583 | for (uint32_t i = 0; i < m_header.ncmds; ++i) { | ||||||||
5584 | const uint32_t cmd_offset = offset; | ||||||||
5585 | llvm::MachO::load_command lc; | ||||||||
5586 | if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr) | ||||||||
5587 | break; | ||||||||
5588 | if (lc.cmd == LC_NOTE) { | ||||||||
5589 | char data_owner[17]; | ||||||||
5590 | m_data.CopyData(offset, 16, data_owner); | ||||||||
5591 | data_owner[16] = '\0'; | ||||||||
5592 | offset += 16; | ||||||||
5593 | uint64_t fileoff = m_data.GetU64_unchecked(&offset); | ||||||||
5594 | |||||||||
5595 | // "addrable bits" has a uint32_t version and a uint32_t | ||||||||
5596 | // number of bits used in addressing. | ||||||||
5597 | if (strcmp("addrable bits", data_owner) == 0) { | ||||||||
5598 | offset = fileoff; | ||||||||
5599 | uint32_t version; | ||||||||
5600 | if (m_data.GetU32(&offset, &version, 1) != nullptr) { | ||||||||
5601 | if (version == 3) { | ||||||||
5602 | uint32_t num_addr_bits = m_data.GetU32_unchecked(&offset); | ||||||||
5603 | if (num_addr_bits != 0) { | ||||||||
5604 | mask = ~((1ULL << num_addr_bits) - 1); | ||||||||
5605 | } | ||||||||
5606 | break; | ||||||||
5607 | } | ||||||||
5608 | } | ||||||||
5609 | } | ||||||||
5610 | } | ||||||||
5611 | offset = cmd_offset + lc.cmdsize; | ||||||||
5612 | } | ||||||||
5613 | } | ||||||||
5614 | return mask; | ||||||||
5615 | } | ||||||||
5616 | |||||||||
5617 | bool ObjectFileMachO::GetCorefileMainBinaryInfo(addr_t &address, UUID &uuid, | ||||||||
5618 | ObjectFile::BinaryType &type) { | ||||||||
5619 | address = LLDB_INVALID_ADDRESS0xffffffffffffffffULL; | ||||||||
5620 | uuid.Clear(); | ||||||||
5621 | ModuleSP module_sp(GetModule()); | ||||||||
5622 | if (module_sp) { | ||||||||
5623 | std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); | ||||||||
5624 | lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); | ||||||||
5625 | for (uint32_t i = 0; i < m_header.ncmds; ++i) { | ||||||||
5626 | const uint32_t cmd_offset = offset; | ||||||||
5627 | llvm::MachO::load_command lc; | ||||||||
5628 | if (m_data.GetU32(&offset, &lc.cmd, 2) == nullptr) | ||||||||
5629 | break; | ||||||||
5630 | if (lc.cmd == LC_NOTE) { | ||||||||
5631 | char data_owner[17]; | ||||||||
5632 | memset(data_owner, 0, sizeof(data_owner)); | ||||||||
5633 | m_data.CopyData(offset, 16, data_owner); | ||||||||
5634 | offset += 16; | ||||||||
5635 | uint64_t fileoff = m_data.GetU64_unchecked(&offset); | ||||||||
5636 | uint64_t size = m_data.GetU64_unchecked(&offset); | ||||||||
5637 | |||||||||
5638 | // "main bin spec" (main binary specification) data payload is | ||||||||
5639 | // formatted: | ||||||||
5640 | // uint32_t version [currently 1] | ||||||||
5641 | // uint32_t type [0 == unspecified, 1 == kernel, | ||||||||
5642 | // 2 == user process, 3 == firmware ] | ||||||||
5643 | // uint64_t address [ UINT64_MAX if address not specified ] | ||||||||
5644 | // uuid_t uuid [ all zero's if uuid not specified ] | ||||||||
5645 | // uint32_t log2_pagesize [ process page size in log base | ||||||||
5646 | // 2, e.g. 4k pages are 12. | ||||||||
5647 | // 0 for unspecified ] | ||||||||
5648 | // uint32_t unused [ for alignment ] | ||||||||
5649 | |||||||||
5650 | if (strcmp("main bin spec", data_owner) == 0 && size >= 32) { | ||||||||
5651 | offset = fileoff; | ||||||||
5652 | uint32_t version; | ||||||||
5653 | if (m_data.GetU32(&offset, &version, 1) != nullptr && version == 1) { | ||||||||
5654 | uint32_t binspec_type = 0; | ||||||||
5655 | uuid_t raw_uuid; | ||||||||
5656 | memset(raw_uuid, 0, sizeof(uuid_t)); | ||||||||
5657 | |||||||||
5658 | if (m_data.GetU32(&offset, &binspec_type, 1) && | ||||||||
5659 | m_data.GetU64(&offset, &address, 1) && | ||||||||
5660 | m_data.CopyData(offset, sizeof(uuid_t), raw_uuid) != 0) { | ||||||||
5661 | uuid = UUID::fromOptionalData(raw_uuid, sizeof(uuid_t)); | ||||||||
5662 | // convert the "main bin spec" type into our | ||||||||
5663 | // ObjectFile::BinaryType enum | ||||||||
5664 | switch (binspec_type) { | ||||||||
5665 | case 0: | ||||||||
5666 | type = eBinaryTypeUnknown; | ||||||||
5667 | break; | ||||||||
5668 | case 1: | ||||||||
5669 | type = eBinaryTypeKernel; | ||||||||
5670 | break; | ||||||||
5671 | case 2: | ||||||||
5672 | type = eBinaryTypeUser; | ||||||||
5673 | break; | ||||||||
5674 | case 3: | ||||||||
5675 | type = eBinaryTypeStandalone; | ||||||||
5676 | break; | ||||||||
5677 | } | ||||||||
5678 | return true; | ||||||||
5679 | } | ||||||||
5680 | } | ||||||||
5681 | } | ||||||||
5682 | } | ||||||||
5683 | offset = cmd_offset + lc.cmdsize; | ||||||||
5684 | } | ||||||||
5685 | } | ||||||||
5686 | return false; | ||||||||
5687 | } | ||||||||
5688 | |||||||||
5689 | lldb::RegisterContextSP | ||||||||
5690 | ObjectFileMachO::GetThreadContextAtIndex(uint32_t idx, | ||||||||
5691 | lldb_private::Thread &thread) { | ||||||||
5692 | lldb::RegisterContextSP reg_ctx_sp; | ||||||||
5693 | |||||||||
5694 | ModuleSP module_sp(GetModule()); | ||||||||
5695 | if (module_sp) { | ||||||||
5696 | std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); | ||||||||
5697 | if (!m_thread_context_offsets_valid) | ||||||||
5698 | GetNumThreadContexts(); | ||||||||
5699 | |||||||||
5700 | const FileRangeArray::Entry *thread_context_file_range = | ||||||||
5701 | m_thread_context_offsets.GetEntryAtIndex(idx); | ||||||||
5702 | if (thread_context_file_range) { | ||||||||
5703 | |||||||||
5704 | DataExtractor data(m_data, thread_context_file_range->GetRangeBase(), | ||||||||
5705 | thread_context_file_range->GetByteSize()); | ||||||||
5706 | |||||||||
5707 | switch (m_header.cputype) { | ||||||||
5708 | case llvm::MachO::CPU_TYPE_ARM64: | ||||||||
5709 | case llvm::MachO::CPU_TYPE_ARM64_32: | ||||||||
5710 | reg_ctx_sp = | ||||||||
5711 | std::make_shared<RegisterContextDarwin_arm64_Mach>(thread, data); | ||||||||
5712 | break; | ||||||||
5713 | |||||||||
5714 | case llvm::MachO::CPU_TYPE_ARM: | ||||||||
5715 | reg_ctx_sp = | ||||||||
5716 | std::make_shared<RegisterContextDarwin_arm_Mach>(thread, data); | ||||||||
5717 | break; | ||||||||
5718 | |||||||||
5719 | case llvm::MachO::CPU_TYPE_I386: | ||||||||
5720 | reg_ctx_sp = | ||||||||
5721 | std::make_shared<RegisterContextDarwin_i386_Mach>(thread, data); | ||||||||
5722 | break; | ||||||||
5723 | |||||||||
5724 | case llvm::MachO::CPU_TYPE_X86_64: | ||||||||
5725 | reg_ctx_sp = | ||||||||
5726 | std::make_shared<RegisterContextDarwin_x86_64_Mach>(thread, data); | ||||||||
5727 | break; | ||||||||
5728 | } | ||||||||
5729 | } | ||||||||
5730 | } | ||||||||
5731 | return reg_ctx_sp; | ||||||||
5732 | } | ||||||||
5733 | |||||||||
5734 | ObjectFile::Type ObjectFileMachO::CalculateType() { | ||||||||
5735 | switch (m_header.filetype) { | ||||||||
5736 | case MH_OBJECT: // 0x1u | ||||||||
5737 | if (GetAddressByteSize() == 4) { | ||||||||
5738 | // 32 bit kexts are just object files, but they do have a valid | ||||||||
5739 | // UUID load command. | ||||||||
5740 | if (GetUUID()) { | ||||||||
5741 | // this checking for the UUID load command is not enough we could | ||||||||
5742 | // eventually look for the symbol named "OSKextGetCurrentIdentifier" as | ||||||||
5743 | // this is required of kexts | ||||||||
5744 | if (m_strata == eStrataInvalid) | ||||||||
5745 | m_strata = eStrataKernel; | ||||||||
5746 | return eTypeSharedLibrary; | ||||||||
5747 | } | ||||||||
5748 | } | ||||||||
5749 | return eTypeObjectFile; | ||||||||
5750 | |||||||||
5751 | case MH_EXECUTE: | ||||||||
5752 | return eTypeExecutable; // 0x2u | ||||||||
5753 | case MH_FVMLIB: | ||||||||
5754 | return eTypeSharedLibrary; // 0x3u | ||||||||
5755 | case MH_CORE: | ||||||||
5756 | return eTypeCoreFile; // 0x4u | ||||||||
5757 | case MH_PRELOAD: | ||||||||
5758 | return eTypeSharedLibrary; // 0x5u | ||||||||
5759 | case MH_DYLIB: | ||||||||
5760 | return eTypeSharedLibrary; // 0x6u | ||||||||
5761 | case MH_DYLINKER: | ||||||||
5762 | return eTypeDynamicLinker; // 0x7u | ||||||||
5763 | case MH_BUNDLE: | ||||||||
5764 | return eTypeSharedLibrary; // 0x8u | ||||||||
5765 | case MH_DYLIB_STUB: | ||||||||
5766 | return eTypeStubLibrary; // 0x9u | ||||||||
5767 | case MH_DSYM: | ||||||||
5768 | return eTypeDebugInfo; // 0xAu | ||||||||
5769 | case MH_KEXT_BUNDLE: | ||||||||
5770 | return eTypeSharedLibrary; // 0xBu | ||||||||
5771 | default: | ||||||||
5772 | break; | ||||||||
5773 | } | ||||||||
5774 | return eTypeUnknown; | ||||||||
5775 | } | ||||||||
5776 | |||||||||
5777 | ObjectFile::Strata ObjectFileMachO::CalculateStrata() { | ||||||||
5778 | switch (m_header.filetype) { | ||||||||
5779 | case MH_OBJECT: // 0x1u | ||||||||
5780 | { | ||||||||
5781 | // 32 bit kexts are just object files, but they do have a valid | ||||||||
5782 | // UUID load command. | ||||||||
5783 | if (GetUUID()) { | ||||||||
5784 | // this checking for the UUID load command is not enough we could | ||||||||
5785 | // eventually look for the symbol named "OSKextGetCurrentIdentifier" as | ||||||||
5786 | // this is required of kexts | ||||||||
5787 | if (m_type == eTypeInvalid) | ||||||||
5788 | m_type = eTypeSharedLibrary; | ||||||||
5789 | |||||||||
5790 | return eStrataKernel; | ||||||||
5791 | } | ||||||||
5792 | } | ||||||||
5793 | return eStrataUnknown; | ||||||||
5794 | |||||||||
5795 | case MH_EXECUTE: // 0x2u | ||||||||
5796 | // Check for the MH_DYLDLINK bit in the flags | ||||||||
5797 | if (m_header.flags & MH_DYLDLINK) { | ||||||||
5798 | return eStrataUser; | ||||||||
5799 | } else { | ||||||||
5800 | SectionList *section_list = GetSectionList(); | ||||||||
5801 | if (section_list) { | ||||||||
5802 | static ConstString g_kld_section_name("__KLD"); | ||||||||
5803 | if (section_list->FindSectionByName(g_kld_section_name)) | ||||||||
5804 | return eStrataKernel; | ||||||||
5805 | } | ||||||||
5806 | } | ||||||||
5807 | return eStrataRawImage; | ||||||||
5808 | |||||||||
5809 | case MH_FVMLIB: | ||||||||
5810 | return eStrataUser; // 0x3u | ||||||||
5811 | case MH_CORE: | ||||||||
5812 | return eStrataUnknown; // 0x4u | ||||||||
5813 | case MH_PRELOAD: | ||||||||
5814 | return eStrataRawImage; // 0x5u | ||||||||
5815 | case MH_DYLIB: | ||||||||
5816 | return eStrataUser; // 0x6u | ||||||||
5817 | case MH_DYLINKER: | ||||||||
5818 | return eStrataUser; // 0x7u | ||||||||
5819 | case MH_BUNDLE: | ||||||||
5820 | return eStrataUser; // 0x8u | ||||||||
5821 | case MH_DYLIB_STUB: | ||||||||
5822 | return eStrataUser; // 0x9u | ||||||||
5823 | case MH_DSYM: | ||||||||
5824 | return eStrataUnknown; // 0xAu | ||||||||
5825 | case MH_KEXT_BUNDLE: | ||||||||
5826 | return eStrataKernel; // 0xBu | ||||||||
5827 | default: | ||||||||
5828 | break; | ||||||||
5829 | } | ||||||||
5830 | return eStrataUnknown; | ||||||||
5831 | } | ||||||||
5832 | |||||||||
5833 | llvm::VersionTuple ObjectFileMachO::GetVersion() { | ||||||||
5834 | ModuleSP module_sp(GetModule()); | ||||||||
5835 | if (module_sp) { | ||||||||
5836 | std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); | ||||||||
5837 | llvm::MachO::dylib_command load_cmd; | ||||||||
5838 | lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic); | ||||||||
5839 | uint32_t version_cmd = 0; | ||||||||
5840 | uint64_t version = 0; | ||||||||
5841 | uint32_t i; | ||||||||
5842 | for (i = 0; i < m_header.ncmds; ++i) { | ||||||||
5843 | const lldb::offset_t cmd_offset = offset; | ||||||||
5844 | if (m_data.GetU32(&offset, &load_cmd, 2) == nullptr) | ||||||||
5845 | break; | ||||||||
5846 | |||||||||
5847 | if (load_cmd.cmd == LC_ID_DYLIB) { | ||||||||
5848 | if (version_cmd == 0) { | ||||||||
5849 | version_cmd = load_cmd.cmd; | ||||||||
5850 | if (m_data.GetU32(&offset, &load_cmd.dylib, 4) == nullptr) | ||||||||
5851 | break; | ||||||||
5852 | version = load_cmd.dylib.current_version; | ||||||||
5853 | } | ||||||||
5854 | break; // Break for now unless there is another more complete version | ||||||||
5855 | // number load command in the future. | ||||||||
5856 | } | ||||||||
5857 | offset = cmd_offset + load_cmd.cmdsize; | ||||||||
5858 | } | ||||||||
5859 | |||||||||
5860 | if (version_cmd == LC_ID_DYLIB) { | ||||||||
5861 | unsigned major = (version & 0xFFFF0000ull) >> 16; | ||||||||
5862 | unsigned minor = (version & 0x0000FF00ull) >> 8; | ||||||||
5863 | unsigned subminor = (version & 0x000000FFull); | ||||||||
5864 | return llvm::VersionTuple(major, minor, subminor); | ||||||||
5865 | } | ||||||||
5866 | } | ||||||||
5867 | return llvm::VersionTuple(); | ||||||||
5868 | } | ||||||||
5869 | |||||||||
5870 | ArchSpec ObjectFileMachO::GetArchitecture() { | ||||||||
5871 | ModuleSP module_sp(GetModule()); | ||||||||
5872 | ArchSpec arch; | ||||||||
5873 | if (module_sp) { | ||||||||
5874 | std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex()); | ||||||||
5875 | |||||||||
5876 | return GetArchitecture(module_sp, m_header, m_data, | ||||||||
5877 | MachHeaderSizeFromMagic(m_header.magic)); | ||||||||
5878 | } | ||||||||
5879 | return arch; | ||||||||
5880 | } | ||||||||
5881 | |||||||||
5882 | void ObjectFileMachO::GetProcessSharedCacheUUID(Process *process, | ||||||||
5883 | addr_t &base_addr, UUID &uuid) { | ||||||||
5884 | uuid.Clear(); | ||||||||
5885 | base_addr = LLDB_INVALID_ADDRESS0xffffffffffffffffULL; | ||||||||
5886 | if (process && process->GetDynamicLoader()) { | ||||||||
5887 | DynamicLoader *dl = process->GetDynamicLoader(); | ||||||||
5888 | LazyBool using_shared_cache; | ||||||||
5889 | LazyBool private_shared_cache; | ||||||||
5890 | dl->GetSharedCacheInformation(base_addr, uuid, using_shared_cache, | ||||||||
5891 | private_shared_cache); | ||||||||
5892 | } | ||||||||
5893 | Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_SYMBOLS(1u << 20) | | ||||||||
5894 | LIBLLDB_LOG_PROCESS(1u << 1))); | ||||||||
5895 | LLDB_LOGF(do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("inferior process shared cache has a UUID of %s, base address 0x%" "llx", uuid.GetAsString().c_str(), base_addr); } while (0) | ||||||||
5896 | log,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("inferior process shared cache has a UUID of %s, base address 0x%" "llx", uuid.GetAsString().c_str(), base_addr); } while (0) | ||||||||
5897 | "inferior process shared cache has a UUID of %s, base address 0x%" PRIx64,do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("inferior process shared cache has a UUID of %s, base address 0x%" "llx", uuid.GetAsString().c_str(), base_addr); } while (0) | ||||||||
5898 | uuid.GetAsString().c_str(), base_addr)do { ::lldb_private::Log *log_private = (log); if (log_private ) log_private->Printf("inferior process shared cache has a UUID of %s, base address 0x%" "llx", uuid.GetAsString().c_str(), base_addr); } while (0); | ||||||||
5899 | } | ||||||||
5900 | |||||||||
5901 | // From dyld SPI header dyld_process_info.h | ||||||||
5902 | typedef void *dyld_process_info; | ||||||||
5903 | struct lldb_copy__dyld_process_cache_info { | ||||||||
5904 | uuid_t cacheUUID; // UUID of cache used by process | ||||||||
5905 | uint64_t cacheBaseAddress; // load address of dyld shared cache | ||||||||
5906 | bool noCache; // process is running without a dyld cache | ||||||||
5907 | bool privateCache; // process is using a private copy of its dyld cache | ||||||||
5908 | }; | ||||||||
5909 | |||||||||
5910 | // #including mach/mach.h pulls in machine.h & CPU_TYPE_ARM etc conflicts with | ||||||||
5911 | // llvm enum definitions llvm::MachO::CPU_TYPE_ARM turning them into compile | ||||||||
5912 | // errors. So we need to use the actual underlying types of task_t and | ||||||||
5913 | // kern_return_t below. | ||||||||
5914 | extern "C" unsigned int /*task_t*/ mach_task_self(); | ||||||||
5915 | |||||||||
5916 | void ObjectFileMachO::GetLLDBSharedCacheUUID(addr_t &base_addr, UUID &uuid) { | ||||||||
5917 | uuid.Clear(); | ||||||||
5918 | base_addr = LLDB_INVALID_ADDRESS0xffffffffffffffffULL; | ||||||||
5919 | |||||||||
5920 | #if defined(__APPLE__) | ||||||||
5921 | uint8_t *(*dyld_get_all_image_infos)(void); | ||||||||
5922 | dyld_get_all_image_infos = | ||||||||
5923 | (uint8_t * (*)()) dlsym(RTLD_DEFAULT, "_dyld_get_all_image_infos"); | ||||||||
5924 | if (dyld_get_all_image_infos) { | ||||||||
5925 | uint8_t *dyld_all_image_infos_address = dyld_get_all_image_infos(); | ||||||||
5926 | if (dyld_all_image_infos_address) { | ||||||||
5927 | uint32_t *version = (uint32_t *) | ||||||||
5928 | dyld_all_image_infos_address; // version <mach-o/dyld_images.h> | ||||||||
5929 | if (*version >= 13) { | ||||||||
5930 | uuid_t *sharedCacheUUID_address = 0; | ||||||||
5931 | int wordsize = sizeof(uint8_t *); | ||||||||
5932 | if (wordsize == 8) { | ||||||||
5933 | sharedCacheUUID_address = | ||||||||
5934 | (uuid_t *)((uint8_t *)dyld_all_image_infos_address + | ||||||||
5935 | 160); // sharedCacheUUID <mach-o/dyld_images.h> | ||||||||
5936 | if (*version >= 15) | ||||||||
5937 | base_addr = | ||||||||
5938 | *(uint64_t | ||||||||
5939 | *)((uint8_t *)dyld_all_image_infos_address + | ||||||||
5940 | 176); // sharedCacheBaseAddress <mach-o/dyld_images.h> | ||||||||
5941 | } else { | ||||||||
5942 | sharedCacheUUID_address = | ||||||||
5943 | (uuid_t *)((uint8_t *)dyld_all_image_infos_address + | ||||||||
5944 | 84); // sharedCacheUUID <mach-o/dyld_images.h> | ||||||||
5945 | if (*version >= 15) { | ||||||||
5946 |