summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
diff options
context:
space:
mode:
authorKate Stone <katherine.stone@apple.com>2016-09-06 20:57:50 +0000
committerKate Stone <katherine.stone@apple.com>2016-09-06 20:57:50 +0000
commitb9c1b51e45b845debb76d8658edabca70ca56079 (patch)
treedfcb5a13ef2b014202340f47036da383eaee74aa /lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
parentd5aa73376966339caad04013510626ec2e42c760 (diff)
downloadbcm5719-llvm-b9c1b51e45b845debb76d8658edabca70ca56079.tar.gz
bcm5719-llvm-b9c1b51e45b845debb76d8658edabca70ca56079.zip
*** This commit represents a complete reformatting of the LLDB source code
*** to conform to clang-format’s LLVM style. This kind of mass change has *** two obvious implications: Firstly, merging this particular commit into a downstream fork may be a huge effort. Alternatively, it may be worth merging all changes up to this commit, performing the same reformatting operation locally, and then discarding the merge for this particular commit. The commands used to accomplish this reformatting were as follows (with current working directory as the root of the repository): find . \( -iname "*.c" -or -iname "*.cpp" -or -iname "*.h" -or -iname "*.mm" \) -exec clang-format -i {} + find . -iname "*.py" -exec autopep8 --in-place --aggressive --aggressive {} + ; The version of clang-format used was 3.9.0, and autopep8 was 1.2.4. Secondly, “blame” style tools will generally point to this commit instead of a meaningful prior commit. There are alternatives available that will attempt to look through this change and find the appropriate prior commit. YMMV. llvm-svn: 280751
Diffstat (limited to 'lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp')
-rw-r--r--lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp11186
1 files changed, 5582 insertions, 5604 deletions
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index 2f34c19048b..69ff3512ce3 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -10,9 +10,13 @@
// C Includes
// C++ Includes
// Other libraries and framework includes
-#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringRef.h"
// Project includes
+#include "Plugins/Process/Utility/RegisterContextDarwin_arm.h"
+#include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h"
+#include "Plugins/Process/Utility/RegisterContextDarwin_i386.h"
+#include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h"
#include "lldb/Core/ArchSpec.h"
#include "lldb/Core/DataBuffer.h"
#include "lldb/Core/Debugger.h"
@@ -28,8 +32,8 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Core/Timer.h"
#include "lldb/Core/UUID.h"
-#include "lldb/Host/Host.h"
#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
#include "lldb/Symbol/DWARFCallFrameInfo.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Target/DynamicLoader.h"
@@ -40,16 +44,13 @@
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadList.h"
-#include "Plugins/Process/Utility/RegisterContextDarwin_arm.h"
-#include "Plugins/Process/Utility/RegisterContextDarwin_arm64.h"
-#include "Plugins/Process/Utility/RegisterContextDarwin_i386.h"
-#include "Plugins/Process/Utility/RegisterContextDarwin_x86_64.h"
#include "lldb/Utility/SafeMachO.h"
#include "ObjectFileMachO.h"
-#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__))
+#if defined(__APPLE__) && \
+ (defined(__arm__) || defined(__arm64__) || defined(__aarch64__))
// GetLLDBSharedCacheUUID() needs to call dlsym()
#include <dlfcn.h>
#endif
@@ -66,3872 +67,2963 @@ using namespace llvm::MachO;
// Some structure definitions needed for parsing the dyld shared cache files
// found on iOS devices.
-struct lldb_copy_dyld_cache_header_v1
-{
- char magic[16]; // e.g. "dyld_v0 i386", "dyld_v1 armv7", etc.
- uint32_t mappingOffset; // file offset to first dyld_cache_mapping_info
- uint32_t mappingCount; // number of dyld_cache_mapping_info entries
- uint32_t imagesOffset;
- uint32_t imagesCount;
- uint64_t dyldBaseAddress;
- uint64_t codeSignatureOffset;
- uint64_t codeSignatureSize;
- uint64_t slideInfoOffset;
- uint64_t slideInfoSize;
- uint64_t localSymbolsOffset;
- uint64_t localSymbolsSize;
- uint8_t uuid[16]; // v1 and above, also recorded in dyld_all_image_infos v13 and later
+struct lldb_copy_dyld_cache_header_v1 {
+ char magic[16]; // e.g. "dyld_v0 i386", "dyld_v1 armv7", etc.
+ uint32_t mappingOffset; // file offset to first dyld_cache_mapping_info
+ uint32_t mappingCount; // number of dyld_cache_mapping_info entries
+ uint32_t imagesOffset;
+ uint32_t imagesCount;
+ uint64_t dyldBaseAddress;
+ uint64_t codeSignatureOffset;
+ uint64_t codeSignatureSize;
+ uint64_t slideInfoOffset;
+ uint64_t slideInfoSize;
+ uint64_t localSymbolsOffset;
+ uint64_t localSymbolsSize;
+ uint8_t uuid[16]; // v1 and above, also recorded in dyld_all_image_infos v13
+ // and later
};
-struct lldb_copy_dyld_cache_mapping_info
-{
- uint64_t address;
- uint64_t size;
- uint64_t fileOffset;
- uint32_t maxProt;
- uint32_t initProt;
+struct lldb_copy_dyld_cache_mapping_info {
+ uint64_t address;
+ uint64_t size;
+ uint64_t fileOffset;
+ uint32_t maxProt;
+ uint32_t initProt;
};
-struct lldb_copy_dyld_cache_local_symbols_info
-{
- uint32_t nlistOffset;
- uint32_t nlistCount;
- uint32_t stringsOffset;
- uint32_t stringsSize;
- uint32_t entriesOffset;
- uint32_t entriesCount;
+struct lldb_copy_dyld_cache_local_symbols_info {
+ uint32_t nlistOffset;
+ uint32_t nlistCount;
+ uint32_t stringsOffset;
+ uint32_t stringsSize;
+ uint32_t entriesOffset;
+ uint32_t entriesCount;
};
-struct lldb_copy_dyld_cache_local_symbols_entry
-{
- uint32_t dylibOffset;
- uint32_t nlistStartIndex;
- uint32_t nlistCount;
+struct lldb_copy_dyld_cache_local_symbols_entry {
+ uint32_t dylibOffset;
+ uint32_t nlistStartIndex;
+ uint32_t nlistCount;
};
-
-class RegisterContextDarwin_x86_64_Mach : public RegisterContextDarwin_x86_64
-{
+class RegisterContextDarwin_x86_64_Mach : public RegisterContextDarwin_x86_64 {
public:
- RegisterContextDarwin_x86_64_Mach (lldb_private::Thread &thread, const DataExtractor &data) :
- RegisterContextDarwin_x86_64 (thread, 0)
- {
- SetRegisterDataFrom_LC_THREAD (data);
- }
+ RegisterContextDarwin_x86_64_Mach(lldb_private::Thread &thread,
+ const DataExtractor &data)
+ : RegisterContextDarwin_x86_64(thread, 0) {
+ SetRegisterDataFrom_LC_THREAD(data);
+ }
- void
- InvalidateAllRegisters() override
- {
- // Do nothing... registers are always valid...
- }
-
- void
- SetRegisterDataFrom_LC_THREAD (const DataExtractor &data)
- {
- lldb::offset_t offset = 0;
- SetError (GPRRegSet, Read, -1);
- SetError (FPURegSet, Read, -1);
- SetError (EXCRegSet, Read, -1);
- bool done = false;
-
- while (!done)
- {
- int flavor = data.GetU32 (&offset);
- if (flavor == 0)
- done = true;
- else
- {
- uint32_t i;
- uint32_t count = data.GetU32 (&offset);
- switch (flavor)
- {
- case GPRRegSet:
- for (i=0; i<count; ++i)
- (&gpr.rax)[i] = data.GetU64(&offset);
- SetError (GPRRegSet, Read, 0);
- done = true;
+ void InvalidateAllRegisters() override {
+ // Do nothing... registers are always valid...
+ }
- break;
- case FPURegSet:
- // TODO: fill in FPU regs....
- //SetError (FPURegSet, Read, -1);
- done = true;
-
- break;
- case EXCRegSet:
- exc.trapno = data.GetU32(&offset);
- exc.err = data.GetU32(&offset);
- exc.faultvaddr = data.GetU64(&offset);
- SetError (EXCRegSet, Read, 0);
- done = true;
- break;
- case 7:
- case 8:
- case 9:
- // fancy flavors that encapsulate of the above
- // flavors...
- break;
+ void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) {
+ lldb::offset_t offset = 0;
+ SetError(GPRRegSet, Read, -1);
+ SetError(FPURegSet, Read, -1);
+ SetError(EXCRegSet, Read, -1);
+ bool done = false;
+
+ while (!done) {
+ int flavor = data.GetU32(&offset);
+ if (flavor == 0)
+ done = true;
+ else {
+ uint32_t i;
+ uint32_t count = data.GetU32(&offset);
+ switch (flavor) {
+ case GPRRegSet:
+ for (i = 0; i < count; ++i)
+ (&gpr.rax)[i] = data.GetU64(&offset);
+ SetError(GPRRegSet, Read, 0);
+ done = true;
+
+ break;
+ case FPURegSet:
+ // TODO: fill in FPU regs....
+ // SetError (FPURegSet, Read, -1);
+ done = true;
+
+ break;
+ case EXCRegSet:
+ exc.trapno = data.GetU32(&offset);
+ exc.err = data.GetU32(&offset);
+ exc.faultvaddr = data.GetU64(&offset);
+ SetError(EXCRegSet, Read, 0);
+ done = true;
+ break;
+ case 7:
+ case 8:
+ case 9:
+ // fancy flavors that encapsulate of the above
+ // flavors...
+ break;
- default:
- done = true;
- break;
- }
- }
+ default:
+ done = true;
+ break;
}
+ }
}
-
- static size_t
- WriteRegister (RegisterContext *reg_ctx, const char *name, const char *alt_name, size_t reg_byte_size, Stream &data)
- {
- const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name);
- if (reg_info == NULL)
- reg_info = reg_ctx->GetRegisterInfoByName(alt_name);
- if (reg_info)
- {
- lldb_private::RegisterValue reg_value;
- if (reg_ctx->ReadRegister(reg_info, reg_value))
- {
- if (reg_info->byte_size >= reg_byte_size)
- data.Write(reg_value.GetBytes(), reg_byte_size);
- else
- {
- data.Write(reg_value.GetBytes(), reg_info->byte_size);
- for (size_t i=0, n = reg_byte_size - reg_info->byte_size; i<n; ++ i)
- data.PutChar(0);
- }
- return reg_byte_size;
- }
- }
- // Just write zeros if all else fails
- for (size_t i=0; i<reg_byte_size; ++ i)
+ }
+
+ static size_t WriteRegister(RegisterContext *reg_ctx, const char *name,
+ const char *alt_name, size_t reg_byte_size,
+ Stream &data) {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name);
+ if (reg_info == NULL)
+ reg_info = reg_ctx->GetRegisterInfoByName(alt_name);
+ if (reg_info) {
+ lldb_private::RegisterValue reg_value;
+ if (reg_ctx->ReadRegister(reg_info, reg_value)) {
+ if (reg_info->byte_size >= reg_byte_size)
+ data.Write(reg_value.GetBytes(), reg_byte_size);
+ else {
+ data.Write(reg_value.GetBytes(), reg_info->byte_size);
+ for (size_t i = 0, n = reg_byte_size - reg_info->byte_size; i < n;
+ ++i)
data.PutChar(0);
+ }
return reg_byte_size;
+ }
}
-
- static bool
- Create_LC_THREAD (Thread *thread, Stream &data)
- {
- RegisterContextSP reg_ctx_sp (thread->GetRegisterContext());
- if (reg_ctx_sp)
- {
- RegisterContext *reg_ctx = reg_ctx_sp.get();
-
- data.PutHex32 (GPRRegSet); // Flavor
- data.PutHex32 (GPRWordCount);
- WriteRegister (reg_ctx, "rax", NULL, 8, data);
- WriteRegister (reg_ctx, "rbx", NULL, 8, data);
- WriteRegister (reg_ctx, "rcx", NULL, 8, data);
- WriteRegister (reg_ctx, "rdx", NULL, 8, data);
- WriteRegister (reg_ctx, "rdi", NULL, 8, data);
- WriteRegister (reg_ctx, "rsi", NULL, 8, data);
- WriteRegister (reg_ctx, "rbp", NULL, 8, data);
- WriteRegister (reg_ctx, "rsp", NULL, 8, data);
- WriteRegister (reg_ctx, "r8", NULL, 8, data);
- WriteRegister (reg_ctx, "r9", NULL, 8, data);
- WriteRegister (reg_ctx, "r10", NULL, 8, data);
- WriteRegister (reg_ctx, "r11", NULL, 8, data);
- WriteRegister (reg_ctx, "r12", NULL, 8, data);
- WriteRegister (reg_ctx, "r13", NULL, 8, data);
- WriteRegister (reg_ctx, "r14", NULL, 8, data);
- WriteRegister (reg_ctx, "r15", NULL, 8, data);
- WriteRegister (reg_ctx, "rip", NULL, 8, data);
- WriteRegister (reg_ctx, "rflags", NULL, 8, data);
- WriteRegister (reg_ctx, "cs", NULL, 8, data);
- WriteRegister (reg_ctx, "fs", NULL, 8, data);
- WriteRegister (reg_ctx, "gs", NULL, 8, data);
-
-// // Write out the FPU registers
-// const size_t fpu_byte_size = sizeof(FPU);
-// size_t bytes_written = 0;
-// data.PutHex32 (FPURegSet);
-// data.PutHex32 (fpu_byte_size/sizeof(uint64_t));
-// bytes_written += data.PutHex32(0); // uint32_t pad[0]
-// bytes_written += data.PutHex32(0); // uint32_t pad[1]
-// bytes_written += WriteRegister (reg_ctx, "fcw", "fctrl", 2, data); // uint16_t fcw; // "fctrl"
-// bytes_written += WriteRegister (reg_ctx, "fsw" , "fstat", 2, data); // uint16_t fsw; // "fstat"
-// bytes_written += WriteRegister (reg_ctx, "ftw" , "ftag", 1, data); // uint8_t ftw; // "ftag"
-// bytes_written += data.PutHex8 (0); // uint8_t pad1;
-// bytes_written += WriteRegister (reg_ctx, "fop" , NULL, 2, data); // uint16_t fop; // "fop"
-// bytes_written += WriteRegister (reg_ctx, "fioff", "ip", 4, data); // uint32_t ip; // "fioff"
-// bytes_written += WriteRegister (reg_ctx, "fiseg", NULL, 2, data); // uint16_t cs; // "fiseg"
-// bytes_written += data.PutHex16 (0); // uint16_t pad2;
-// bytes_written += WriteRegister (reg_ctx, "dp", "fooff" , 4, data); // uint32_t dp; // "fooff"
-// bytes_written += WriteRegister (reg_ctx, "foseg", NULL, 2, data); // uint16_t ds; // "foseg"
-// bytes_written += data.PutHex16 (0); // uint16_t pad3;
-// bytes_written += WriteRegister (reg_ctx, "mxcsr", NULL, 4, data); // uint32_t mxcsr;
-// bytes_written += WriteRegister (reg_ctx, "mxcsrmask", NULL, 4, data);// uint32_t mxcsrmask;
-// bytes_written += WriteRegister (reg_ctx, "stmm0", NULL, sizeof(MMSReg), data);
-// bytes_written += WriteRegister (reg_ctx, "stmm1", NULL, sizeof(MMSReg), data);
-// bytes_written += WriteRegister (reg_ctx, "stmm2", NULL, sizeof(MMSReg), data);
-// bytes_written += WriteRegister (reg_ctx, "stmm3", NULL, sizeof(MMSReg), data);
-// bytes_written += WriteRegister (reg_ctx, "stmm4", NULL, sizeof(MMSReg), data);
-// bytes_written += WriteRegister (reg_ctx, "stmm5", NULL, sizeof(MMSReg), data);
-// bytes_written += WriteRegister (reg_ctx, "stmm6", NULL, sizeof(MMSReg), data);
-// bytes_written += WriteRegister (reg_ctx, "stmm7", NULL, sizeof(MMSReg), data);
-// bytes_written += WriteRegister (reg_ctx, "xmm0" , NULL, sizeof(XMMReg), data);
-// bytes_written += WriteRegister (reg_ctx, "xmm1" , NULL, sizeof(XMMReg), data);
-// bytes_written += WriteRegister (reg_ctx, "xmm2" , NULL, sizeof(XMMReg), data);
-// bytes_written += WriteRegister (reg_ctx, "xmm3" , NULL, sizeof(XMMReg), data);
-// bytes_written += WriteRegister (reg_ctx, "xmm4" , NULL, sizeof(XMMReg), data);
-// bytes_written += WriteRegister (reg_ctx, "xmm5" , NULL, sizeof(XMMReg), data);
-// bytes_written += WriteRegister (reg_ctx, "xmm6" , NULL, sizeof(XMMReg), data);
-// bytes_written += WriteRegister (reg_ctx, "xmm7" , NULL, sizeof(XMMReg), data);
-// bytes_written += WriteRegister (reg_ctx, "xmm8" , NULL, sizeof(XMMReg), data);
-// bytes_written += WriteRegister (reg_ctx, "xmm9" , NULL, sizeof(XMMReg), data);
-// bytes_written += WriteRegister (reg_ctx, "xmm10", NULL, sizeof(XMMReg), data);
-// bytes_written += WriteRegister (reg_ctx, "xmm11", NULL, sizeof(XMMReg), data);
-// bytes_written += WriteRegister (reg_ctx, "xmm12", NULL, sizeof(XMMReg), data);
-// bytes_written += WriteRegister (reg_ctx, "xmm13", NULL, sizeof(XMMReg), data);
-// bytes_written += WriteRegister (reg_ctx, "xmm14", NULL, sizeof(XMMReg), data);
-// bytes_written += WriteRegister (reg_ctx, "xmm15", NULL, sizeof(XMMReg), data);
-//
-// // Fill rest with zeros
-// for (size_t i=0, n = fpu_byte_size - bytes_written; i<n; ++ i)
-// data.PutChar(0);
-
- // Write out the EXC registers
- data.PutHex32 (EXCRegSet);
- data.PutHex32 (EXCWordCount);
- WriteRegister (reg_ctx, "trapno", NULL, 4, data);
- WriteRegister (reg_ctx, "err", NULL, 4, data);
- WriteRegister (reg_ctx, "faultvaddr", NULL, 8, data);
- return true;
- }
- return false;
+ // Just write zeros if all else fails
+ for (size_t i = 0; i < reg_byte_size; ++i)
+ data.PutChar(0);
+ return reg_byte_size;
+ }
+
+ static bool Create_LC_THREAD(Thread *thread, Stream &data) {
+ RegisterContextSP reg_ctx_sp(thread->GetRegisterContext());
+ if (reg_ctx_sp) {
+ RegisterContext *reg_ctx = reg_ctx_sp.get();
+
+ data.PutHex32(GPRRegSet); // Flavor
+ data.PutHex32(GPRWordCount);
+ WriteRegister(reg_ctx, "rax", NULL, 8, data);
+ WriteRegister(reg_ctx, "rbx", NULL, 8, data);
+ WriteRegister(reg_ctx, "rcx", NULL, 8, data);
+ WriteRegister(reg_ctx, "rdx", NULL, 8, data);
+ WriteRegister(reg_ctx, "rdi", NULL, 8, data);
+ WriteRegister(reg_ctx, "rsi", NULL, 8, data);
+ WriteRegister(reg_ctx, "rbp", NULL, 8, data);
+ WriteRegister(reg_ctx, "rsp", NULL, 8, data);
+ WriteRegister(reg_ctx, "r8", NULL, 8, data);
+ WriteRegister(reg_ctx, "r9", NULL, 8, data);
+ WriteRegister(reg_ctx, "r10", NULL, 8, data);
+ WriteRegister(reg_ctx, "r11", NULL, 8, data);
+ WriteRegister(reg_ctx, "r12", NULL, 8, data);
+ WriteRegister(reg_ctx, "r13", NULL, 8, data);
+ WriteRegister(reg_ctx, "r14", NULL, 8, data);
+ WriteRegister(reg_ctx, "r15", NULL, 8, data);
+ WriteRegister(reg_ctx, "rip", NULL, 8, data);
+ WriteRegister(reg_ctx, "rflags", NULL, 8, data);
+ WriteRegister(reg_ctx, "cs", NULL, 8, data);
+ WriteRegister(reg_ctx, "fs", NULL, 8, data);
+ WriteRegister(reg_ctx, "gs", NULL, 8, data);
+
+ // // Write out the FPU registers
+ // const size_t fpu_byte_size = sizeof(FPU);
+ // size_t bytes_written = 0;
+ // data.PutHex32 (FPURegSet);
+ // data.PutHex32 (fpu_byte_size/sizeof(uint64_t));
+ // bytes_written += data.PutHex32(0); // uint32_t pad[0]
+ // bytes_written += data.PutHex32(0); // uint32_t pad[1]
+ // bytes_written += WriteRegister (reg_ctx, "fcw", "fctrl", 2,
+ // data); // uint16_t fcw; // "fctrl"
+ // bytes_written += WriteRegister (reg_ctx, "fsw" , "fstat", 2,
+ // data); // uint16_t fsw; // "fstat"
+ // bytes_written += WriteRegister (reg_ctx, "ftw" , "ftag", 1,
+ // data); // uint8_t ftw; // "ftag"
+ // bytes_written += data.PutHex8 (0); // uint8_t pad1;
+ // bytes_written += WriteRegister (reg_ctx, "fop" , NULL, 2,
+ // data); // uint16_t fop; // "fop"
+ // bytes_written += WriteRegister (reg_ctx, "fioff", "ip", 4,
+ // data); // uint32_t ip; // "fioff"
+ // bytes_written += WriteRegister (reg_ctx, "fiseg", NULL, 2,
+ // data); // uint16_t cs; // "fiseg"
+ // bytes_written += data.PutHex16 (0); // uint16_t pad2;
+ // bytes_written += WriteRegister (reg_ctx, "dp", "fooff" , 4,
+ // data); // uint32_t dp; // "fooff"
+ // bytes_written += WriteRegister (reg_ctx, "foseg", NULL, 2,
+ // data); // uint16_t ds; // "foseg"
+ // bytes_written += data.PutHex16 (0); // uint16_t pad3;
+ // bytes_written += WriteRegister (reg_ctx, "mxcsr", NULL, 4,
+ // data); // uint32_t mxcsr;
+ // bytes_written += WriteRegister (reg_ctx, "mxcsrmask", NULL,
+ // 4, data);// uint32_t mxcsrmask;
+ // bytes_written += WriteRegister (reg_ctx, "stmm0", NULL,
+ // sizeof(MMSReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "stmm1", NULL,
+ // sizeof(MMSReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "stmm2", NULL,
+ // sizeof(MMSReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "stmm3", NULL,
+ // sizeof(MMSReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "stmm4", NULL,
+ // sizeof(MMSReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "stmm5", NULL,
+ // sizeof(MMSReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "stmm6", NULL,
+ // sizeof(MMSReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "stmm7", NULL,
+ // sizeof(MMSReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "xmm0" , NULL,
+ // sizeof(XMMReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "xmm1" , NULL,
+ // sizeof(XMMReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "xmm2" , NULL,
+ // sizeof(XMMReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "xmm3" , NULL,
+ // sizeof(XMMReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "xmm4" , NULL,
+ // sizeof(XMMReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "xmm5" , NULL,
+ // sizeof(XMMReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "xmm6" , NULL,
+ // sizeof(XMMReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "xmm7" , NULL,
+ // sizeof(XMMReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "xmm8" , NULL,
+ // sizeof(XMMReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "xmm9" , NULL,
+ // sizeof(XMMReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "xmm10", NULL,
+ // sizeof(XMMReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "xmm11", NULL,
+ // sizeof(XMMReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "xmm12", NULL,
+ // sizeof(XMMReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "xmm13", NULL,
+ // sizeof(XMMReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "xmm14", NULL,
+ // sizeof(XMMReg), data);
+ // bytes_written += WriteRegister (reg_ctx, "xmm15", NULL,
+ // sizeof(XMMReg), data);
+ //
+ // // Fill rest with zeros
+ // for (size_t i=0, n = fpu_byte_size - bytes_written; i<n; ++
+ // i)
+ // data.PutChar(0);
+
+ // Write out the EXC registers
+ data.PutHex32(EXCRegSet);
+ data.PutHex32(EXCWordCount);
+ WriteRegister(reg_ctx, "trapno", NULL, 4, data);
+ WriteRegister(reg_ctx, "err", NULL, 4, data);
+ WriteRegister(reg_ctx, "faultvaddr", NULL, 8, data);
+ return true;
}
+ return false;
+ }
protected:
- int
- DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override
- {
- return 0;
- }
+ int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return 0; }
- int
- DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override
- {
- return 0;
- }
+ int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return 0; }
- int
- DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override
- {
- return 0;
- }
+ int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return 0; }
- int
- DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override
- {
- return 0;
- }
+ int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override {
+ return 0;
+ }
- int
- DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override
- {
- return 0;
- }
+ int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override {
+ return 0;
+ }
- int
- DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override
- {
- return 0;
- }
+ int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override {
+ return 0;
+ }
};
-class RegisterContextDarwin_i386_Mach : public RegisterContextDarwin_i386
-{
+class RegisterContextDarwin_i386_Mach : public RegisterContextDarwin_i386 {
public:
- RegisterContextDarwin_i386_Mach (lldb_private::Thread &thread, const DataExtractor &data) :
- RegisterContextDarwin_i386 (thread, 0)
- {
- SetRegisterDataFrom_LC_THREAD (data);
- }
-
- void
- InvalidateAllRegisters() override
- {
- // Do nothing... registers are always valid...
- }
+ RegisterContextDarwin_i386_Mach(lldb_private::Thread &thread,
+ const DataExtractor &data)
+ : RegisterContextDarwin_i386(thread, 0) {
+ SetRegisterDataFrom_LC_THREAD(data);
+ }
- void
- SetRegisterDataFrom_LC_THREAD (const DataExtractor &data)
- {
- lldb::offset_t offset = 0;
- SetError (GPRRegSet, Read, -1);
- SetError (FPURegSet, Read, -1);
- SetError (EXCRegSet, Read, -1);
- bool done = false;
-
- while (!done)
- {
- int flavor = data.GetU32 (&offset);
- if (flavor == 0)
- done = true;
- else
- {
- uint32_t i;
- uint32_t count = data.GetU32 (&offset);
- switch (flavor)
- {
- case GPRRegSet:
- for (i=0; i<count; ++i)
- (&gpr.eax)[i] = data.GetU32(&offset);
- SetError (GPRRegSet, Read, 0);
- done = true;
-
- break;
- case FPURegSet:
- // TODO: fill in FPU regs....
- //SetError (FPURegSet, Read, -1);
- done = true;
+ void InvalidateAllRegisters() override {
+ // Do nothing... registers are always valid...
+ }
- break;
- case EXCRegSet:
- exc.trapno = data.GetU32(&offset);
- exc.err = data.GetU32(&offset);
- exc.faultvaddr = data.GetU32(&offset);
- SetError (EXCRegSet, Read, 0);
- done = true;
- break;
- case 7:
- case 8:
- case 9:
- // fancy flavors that encapsulate of the above
- // flavors...
- break;
+ void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) {
+ lldb::offset_t offset = 0;
+ SetError(GPRRegSet, Read, -1);
+ SetError(FPURegSet, Read, -1);
+ SetError(EXCRegSet, Read, -1);
+ bool done = false;
+
+ while (!done) {
+ int flavor = data.GetU32(&offset);
+ if (flavor == 0)
+ done = true;
+ else {
+ uint32_t i;
+ uint32_t count = data.GetU32(&offset);
+ switch (flavor) {
+ case GPRRegSet:
+ for (i = 0; i < count; ++i)
+ (&gpr.eax)[i] = data.GetU32(&offset);
+ SetError(GPRRegSet, Read, 0);
+ done = true;
+
+ break;
+ case FPURegSet:
+ // TODO: fill in FPU regs....
+ // SetError (FPURegSet, Read, -1);
+ done = true;
+
+ break;
+ case EXCRegSet:
+ exc.trapno = data.GetU32(&offset);
+ exc.err = data.GetU32(&offset);
+ exc.faultvaddr = data.GetU32(&offset);
+ SetError(EXCRegSet, Read, 0);
+ done = true;
+ break;
+ case 7:
+ case 8:
+ case 9:
+ // fancy flavors that encapsulate of the above
+ // flavors...
+ break;
- default:
- done = true;
- break;
- }
- }
+ default:
+ done = true;
+ break;
}
+ }
}
-
- static size_t
- WriteRegister (RegisterContext *reg_ctx, const char *name, const char *alt_name, size_t reg_byte_size, Stream &data)
- {
- const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name);
- if (reg_info == NULL)
- reg_info = reg_ctx->GetRegisterInfoByName(alt_name);
- if (reg_info)
- {
- lldb_private::RegisterValue reg_value;
- if (reg_ctx->ReadRegister(reg_info, reg_value))
- {
- if (reg_info->byte_size >= reg_byte_size)
- data.Write(reg_value.GetBytes(), reg_byte_size);
- else
- {
- data.Write(reg_value.GetBytes(), reg_info->byte_size);
- for (size_t i=0, n = reg_byte_size - reg_info->byte_size; i<n; ++ i)
- data.PutChar(0);
- }
- return reg_byte_size;
- }
- }
- // Just write zeros if all else fails
- for (size_t i=0; i<reg_byte_size; ++ i)
+ }
+
+ static size_t WriteRegister(RegisterContext *reg_ctx, const char *name,
+ const char *alt_name, size_t reg_byte_size,
+ Stream &data) {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name);
+ if (reg_info == NULL)
+ reg_info = reg_ctx->GetRegisterInfoByName(alt_name);
+ if (reg_info) {
+ lldb_private::RegisterValue reg_value;
+ if (reg_ctx->ReadRegister(reg_info, reg_value)) {
+ if (reg_info->byte_size >= reg_byte_size)
+ data.Write(reg_value.GetBytes(), reg_byte_size);
+ else {
+ data.Write(reg_value.GetBytes(), reg_info->byte_size);
+ for (size_t i = 0, n = reg_byte_size - reg_info->byte_size; i < n;
+ ++i)
data.PutChar(0);
+ }
return reg_byte_size;
+ }
}
-
- static bool
- Create_LC_THREAD (Thread *thread, Stream &data)
- {
- RegisterContextSP reg_ctx_sp (thread->GetRegisterContext());
- if (reg_ctx_sp)
- {
- RegisterContext *reg_ctx = reg_ctx_sp.get();
-
- data.PutHex32 (GPRRegSet); // Flavor
- data.PutHex32 (GPRWordCount);
- WriteRegister (reg_ctx, "eax", NULL, 4, data);
- WriteRegister (reg_ctx, "ebx", NULL, 4, data);
- WriteRegister (reg_ctx, "ecx", NULL, 4, data);
- WriteRegister (reg_ctx, "edx", NULL, 4, data);
- WriteRegister (reg_ctx, "edi", NULL, 4, data);
- WriteRegister (reg_ctx, "esi", NULL, 4, data);
- WriteRegister (reg_ctx, "ebp", NULL, 4, data);
- WriteRegister (reg_ctx, "esp", NULL, 4, data);
- WriteRegister (reg_ctx, "ss", NULL, 4, data);
- WriteRegister (reg_ctx, "eflags", NULL, 4, data);
- WriteRegister (reg_ctx, "eip", NULL, 4, data);
- WriteRegister (reg_ctx, "cs", NULL, 4, data);
- WriteRegister (reg_ctx, "ds", NULL, 4, data);
- WriteRegister (reg_ctx, "es", NULL, 4, data);
- WriteRegister (reg_ctx, "fs", NULL, 4, data);
- WriteRegister (reg_ctx, "gs", NULL, 4, data);
-
- // Write out the EXC registers
- data.PutHex32 (EXCRegSet);
- data.PutHex32 (EXCWordCount);
- WriteRegister (reg_ctx, "trapno", NULL, 4, data);
- WriteRegister (reg_ctx, "err", NULL, 4, data);
- WriteRegister (reg_ctx, "faultvaddr", NULL, 4, data);
- return true;
- }
- return false;
+ // Just write zeros if all else fails
+ for (size_t i = 0; i < reg_byte_size; ++i)
+ data.PutChar(0);
+ return reg_byte_size;
+ }
+
+ static bool Create_LC_THREAD(Thread *thread, Stream &data) {
+ RegisterContextSP reg_ctx_sp(thread->GetRegisterContext());
+ if (reg_ctx_sp) {
+ RegisterContext *reg_ctx = reg_ctx_sp.get();
+
+ data.PutHex32(GPRRegSet); // Flavor
+ data.PutHex32(GPRWordCount);
+ WriteRegister(reg_ctx, "eax", NULL, 4, data);
+ WriteRegister(reg_ctx, "ebx", NULL, 4, data);
+ WriteRegister(reg_ctx, "ecx", NULL, 4, data);
+ WriteRegister(reg_ctx, "edx", NULL, 4, data);
+ WriteRegister(reg_ctx, "edi", NULL, 4, data);
+ WriteRegister(reg_ctx, "esi", NULL, 4, data);
+ WriteRegister(reg_ctx, "ebp", NULL, 4, data);
+ WriteRegister(reg_ctx, "esp", NULL, 4, data);
+ WriteRegister(reg_ctx, "ss", NULL, 4, data);
+ WriteRegister(reg_ctx, "eflags", NULL, 4, data);
+ WriteRegister(reg_ctx, "eip", NULL, 4, data);
+ WriteRegister(reg_ctx, "cs", NULL, 4, data);
+ WriteRegister(reg_ctx, "ds", NULL, 4, data);
+ WriteRegister(reg_ctx, "es", NULL, 4, data);
+ WriteRegister(reg_ctx, "fs", NULL, 4, data);
+ WriteRegister(reg_ctx, "gs", NULL, 4, data);
+
+ // Write out the EXC registers
+ data.PutHex32(EXCRegSet);
+ data.PutHex32(EXCWordCount);
+ WriteRegister(reg_ctx, "trapno", NULL, 4, data);
+ WriteRegister(reg_ctx, "err", NULL, 4, data);
+ WriteRegister(reg_ctx, "faultvaddr", NULL, 4, data);
+ return true;
}
+ return false;
+ }
protected:
- int
- DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override
- {
- return 0;
- }
+ int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return 0; }
- int
- DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override
- {
- return 0;
- }
+ int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return 0; }
- int
- DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override
- {
- return 0;
- }
+ int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return 0; }
- int
- DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override
- {
- return 0;
- }
+ int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override {
+ return 0;
+ }
- int
- DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override
- {
- return 0;
- }
+ int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override {
+ return 0;
+ }
- int
- DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override
- {
- return 0;
- }
+ int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override {
+ return 0;
+ }
};
-class RegisterContextDarwin_arm_Mach : public RegisterContextDarwin_arm
-{
+class RegisterContextDarwin_arm_Mach : public RegisterContextDarwin_arm {
public:
- RegisterContextDarwin_arm_Mach (lldb_private::Thread &thread, const DataExtractor &data) :
- RegisterContextDarwin_arm (thread, 0)
- {
- SetRegisterDataFrom_LC_THREAD (data);
- }
-
- void
- InvalidateAllRegisters() override
- {
- // Do nothing... registers are always valid...
- }
-
- void
- SetRegisterDataFrom_LC_THREAD (const DataExtractor &data)
- {
- lldb::offset_t offset = 0;
- SetError (GPRRegSet, Read, -1);
- SetError (FPURegSet, Read, -1);
- SetError (EXCRegSet, Read, -1);
- bool done = false;
-
- while (!done)
- {
- int flavor = data.GetU32 (&offset);
- uint32_t count = data.GetU32 (&offset);
- lldb::offset_t next_thread_state = offset + (count * 4);
- switch (flavor)
- {
- case GPRAltRegSet:
- case GPRRegSet:
- for (uint32_t i=0; i<count; ++i)
- {
- gpr.r[i] = data.GetU32(&offset);
- }
-
- // Note that gpr.cpsr is also copied by the above loop; this loop technically extends
- // one element past the end of the gpr.r[] array.
+ RegisterContextDarwin_arm_Mach(lldb_private::Thread &thread,
+ const DataExtractor &data)
+ : RegisterContextDarwin_arm(thread, 0) {
+ SetRegisterDataFrom_LC_THREAD(data);
+ }
- SetError (GPRRegSet, Read, 0);
- offset = next_thread_state;
- break;
+ void InvalidateAllRegisters() override {
+ // Do nothing... registers are always valid...
+ }
- case FPURegSet:
- {
- uint8_t *fpu_reg_buf = (uint8_t*) &fpu.floats.s[0];
- const int fpu_reg_buf_size = sizeof (fpu.floats);
- if (data.ExtractBytes (offset, fpu_reg_buf_size, eByteOrderLittle, fpu_reg_buf) == fpu_reg_buf_size)
- {
- offset += fpu_reg_buf_size;
- fpu.fpscr = data.GetU32(&offset);
- SetError (FPURegSet, Read, 0);
- }
- else
- {
- done = true;
- }
- }
- offset = next_thread_state;
- break;
-
- case EXCRegSet:
- if (count == 3)
- {
- exc.exception = data.GetU32(&offset);
- exc.fsr = data.GetU32(&offset);
- exc.far = data.GetU32(&offset);
- SetError (EXCRegSet, Read, 0);
- }
- done = true;
- offset = next_thread_state;
- break;
-
- // Unknown register set flavor, stop trying to parse.
- default:
- done = true;
- }
+ void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) {
+ lldb::offset_t offset = 0;
+ SetError(GPRRegSet, Read, -1);
+ SetError(FPURegSet, Read, -1);
+ SetError(EXCRegSet, Read, -1);
+ bool done = false;
+
+ while (!done) {
+ int flavor = data.GetU32(&offset);
+ uint32_t count = data.GetU32(&offset);
+ lldb::offset_t next_thread_state = offset + (count * 4);
+ switch (flavor) {
+ case GPRAltRegSet:
+ case GPRRegSet:
+ for (uint32_t i = 0; i < count; ++i) {
+ gpr.r[i] = data.GetU32(&offset);
}
- }
- static size_t
- WriteRegister (RegisterContext *reg_ctx, const char *name, const char *alt_name, size_t reg_byte_size, Stream &data)
- {
- const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name);
- if (reg_info == NULL)
- reg_info = reg_ctx->GetRegisterInfoByName(alt_name);
- if (reg_info)
- {
- lldb_private::RegisterValue reg_value;
- if (reg_ctx->ReadRegister(reg_info, reg_value))
- {
- if (reg_info->byte_size >= reg_byte_size)
- data.Write(reg_value.GetBytes(), reg_byte_size);
- else
- {
- data.Write(reg_value.GetBytes(), reg_info->byte_size);
- for (size_t i=0, n = reg_byte_size - reg_info->byte_size; i<n; ++ i)
- data.PutChar(0);
- }
- return reg_byte_size;
- }
+ // Note that gpr.cpsr is also copied by the above loop; this loop
+ // technically extends
+ // one element past the end of the gpr.r[] array.
+
+ SetError(GPRRegSet, Read, 0);
+ offset = next_thread_state;
+ break;
+
+ case FPURegSet: {
+ uint8_t *fpu_reg_buf = (uint8_t *)&fpu.floats.s[0];
+ const int fpu_reg_buf_size = sizeof(fpu.floats);
+ if (data.ExtractBytes(offset, fpu_reg_buf_size, eByteOrderLittle,
+ fpu_reg_buf) == fpu_reg_buf_size) {
+ offset += fpu_reg_buf_size;
+ fpu.fpscr = data.GetU32(&offset);
+ SetError(FPURegSet, Read, 0);
+ } else {
+ done = true;
}
- // Just write zeros if all else fails
- for (size_t i=0; i<reg_byte_size; ++ i)
+ }
+ offset = next_thread_state;
+ break;
+
+ case EXCRegSet:
+ if (count == 3) {
+ exc.exception = data.GetU32(&offset);
+ exc.fsr = data.GetU32(&offset);
+ exc.far = data.GetU32(&offset);
+ SetError(EXCRegSet, Read, 0);
+ }
+ done = true;
+ offset = next_thread_state;
+ break;
+
+ // Unknown register set flavor, stop trying to parse.
+ default:
+ done = true;
+ }
+ }
+ }
+
+ static size_t WriteRegister(RegisterContext *reg_ctx, const char *name,
+ const char *alt_name, size_t reg_byte_size,
+ Stream &data) {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name);
+ if (reg_info == NULL)
+ reg_info = reg_ctx->GetRegisterInfoByName(alt_name);
+ if (reg_info) {
+ lldb_private::RegisterValue reg_value;
+ if (reg_ctx->ReadRegister(reg_info, reg_value)) {
+ if (reg_info->byte_size >= reg_byte_size)
+ data.Write(reg_value.GetBytes(), reg_byte_size);
+ else {
+ data.Write(reg_value.GetBytes(), reg_info->byte_size);
+ for (size_t i = 0, n = reg_byte_size - reg_info->byte_size; i < n;
+ ++i)
data.PutChar(0);
+ }
return reg_byte_size;
+ }
}
-
- static bool
- Create_LC_THREAD (Thread *thread, Stream &data)
- {
- RegisterContextSP reg_ctx_sp (thread->GetRegisterContext());
- if (reg_ctx_sp)
- {
- RegisterContext *reg_ctx = reg_ctx_sp.get();
-
- data.PutHex32 (GPRRegSet); // Flavor
- data.PutHex32 (GPRWordCount);
- WriteRegister (reg_ctx, "r0", NULL, 4, data);
- WriteRegister (reg_ctx, "r1", NULL, 4, data);
- WriteRegister (reg_ctx, "r2", NULL, 4, data);
- WriteRegister (reg_ctx, "r3", NULL, 4, data);
- WriteRegister (reg_ctx, "r4", NULL, 4, data);
- WriteRegister (reg_ctx, "r5", NULL, 4, data);
- WriteRegister (reg_ctx, "r6", NULL, 4, data);
- WriteRegister (reg_ctx, "r7", NULL, 4, data);
- WriteRegister (reg_ctx, "r8", NULL, 4, data);
- WriteRegister (reg_ctx, "r9", NULL, 4, data);
- WriteRegister (reg_ctx, "r10", NULL, 4, data);
- WriteRegister (reg_ctx, "r11", NULL, 4, data);
- WriteRegister (reg_ctx, "r12", NULL, 4, data);
- WriteRegister (reg_ctx, "sp", NULL, 4, data);
- WriteRegister (reg_ctx, "lr", NULL, 4, data);
- WriteRegister (reg_ctx, "pc", NULL, 4, data);
- WriteRegister (reg_ctx, "cpsr", NULL, 4, data);
-
- // Write out the EXC registers
-// data.PutHex32 (EXCRegSet);
-// data.PutHex32 (EXCWordCount);
-// WriteRegister (reg_ctx, "exception", NULL, 4, data);
-// WriteRegister (reg_ctx, "fsr", NULL, 4, data);
-// WriteRegister (reg_ctx, "far", NULL, 4, data);
- return true;
- }
- return false;
+ // Just write zeros if all else fails
+ for (size_t i = 0; i < reg_byte_size; ++i)
+ data.PutChar(0);
+ return reg_byte_size;
+ }
+
+ static bool Create_LC_THREAD(Thread *thread, Stream &data) {
+ RegisterContextSP reg_ctx_sp(thread->GetRegisterContext());
+ if (reg_ctx_sp) {
+ RegisterContext *reg_ctx = reg_ctx_sp.get();
+
+ data.PutHex32(GPRRegSet); // Flavor
+ data.PutHex32(GPRWordCount);
+ WriteRegister(reg_ctx, "r0", NULL, 4, data);
+ WriteRegister(reg_ctx, "r1", NULL, 4, data);
+ WriteRegister(reg_ctx, "r2", NULL, 4, data);
+ WriteRegister(reg_ctx, "r3", NULL, 4, data);
+ WriteRegister(reg_ctx, "r4", NULL, 4, data);
+ WriteRegister(reg_ctx, "r5", NULL, 4, data);
+ WriteRegister(reg_ctx, "r6", NULL, 4, data);
+ WriteRegister(reg_ctx, "r7", NULL, 4, data);
+ WriteRegister(reg_ctx, "r8", NULL, 4, data);
+ WriteRegister(reg_ctx, "r9", NULL, 4, data);
+ WriteRegister(reg_ctx, "r10", NULL, 4, data);
+ WriteRegister(reg_ctx, "r11", NULL, 4, data);
+ WriteRegister(reg_ctx, "r12", NULL, 4, data);
+ WriteRegister(reg_ctx, "sp", NULL, 4, data);
+ WriteRegister(reg_ctx, "lr", NULL, 4, data);
+ WriteRegister(reg_ctx, "pc", NULL, 4, data);
+ WriteRegister(reg_ctx, "cpsr", NULL, 4, data);
+
+ // Write out the EXC registers
+ // data.PutHex32 (EXCRegSet);
+ // data.PutHex32 (EXCWordCount);
+ // WriteRegister (reg_ctx, "exception", NULL, 4, data);
+ // WriteRegister (reg_ctx, "fsr", NULL, 4, data);
+ // WriteRegister (reg_ctx, "far", NULL, 4, data);
+ return true;
}
+ return false;
+ }
protected:
- int
- DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override
- {
- return -1;
- }
+ int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return -1; }
- int
- DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override
- {
- return -1;
- }
+ int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return -1; }
- int
- DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override
- {
- return -1;
- }
+ int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return -1; }
- int
- DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override
- {
- return -1;
- }
+ int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override { return -1; }
- int
- DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override
- {
- return 0;
- }
+ int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override {
+ return 0;
+ }
- int
- DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override
- {
- return 0;
- }
+ int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override {
+ return 0;
+ }
- int
- DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override
- {
- return 0;
- }
+ int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override {
+ return 0;
+ }
- int
- DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override
- {
- return -1;
- }
+ int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override {
+ return -1;
+ }
};
-class RegisterContextDarwin_arm64_Mach : public RegisterContextDarwin_arm64
-{
+class RegisterContextDarwin_arm64_Mach : public RegisterContextDarwin_arm64 {
public:
- RegisterContextDarwin_arm64_Mach (lldb_private::Thread &thread, const DataExtractor &data) :
- RegisterContextDarwin_arm64 (thread, 0)
- {
- SetRegisterDataFrom_LC_THREAD (data);
- }
-
- void
- InvalidateAllRegisters() override
- {
- // Do nothing... registers are always valid...
- }
-
- void
- SetRegisterDataFrom_LC_THREAD (const DataExtractor &data)
- {
- lldb::offset_t offset = 0;
- SetError (GPRRegSet, Read, -1);
- SetError (FPURegSet, Read, -1);
- SetError (EXCRegSet, Read, -1);
- bool done = false;
- while (!done)
- {
- int flavor = data.GetU32 (&offset);
- uint32_t count = data.GetU32 (&offset);
- lldb::offset_t next_thread_state = offset + (count * 4);
- switch (flavor)
- {
- case GPRRegSet:
- // x0-x29 + fp + lr + sp + pc (== 33 64-bit registers) plus cpsr (1 32-bit register)
- if (count >= (33 * 2) + 1)
- {
- for (uint32_t i=0; i<33; ++i)
- gpr.x[i] = data.GetU64(&offset);
- gpr.cpsr = data.GetU32(&offset);
- SetError (GPRRegSet, Read, 0);
- }
- offset = next_thread_state;
- break;
- case FPURegSet:
- {
- uint8_t *fpu_reg_buf = (uint8_t*) &fpu.v[0];
- const int fpu_reg_buf_size = sizeof (fpu);
- if (fpu_reg_buf_size == count
- && data.ExtractBytes (offset, fpu_reg_buf_size, eByteOrderLittle, fpu_reg_buf) == fpu_reg_buf_size)
- {
- SetError (FPURegSet, Read, 0);
- }
- else
- {
- done = true;
- }
- }
- offset = next_thread_state;
- break;
- case EXCRegSet:
- if (count == 4)
- {
- exc.far = data.GetU64(&offset);
- exc.esr = data.GetU32(&offset);
- exc.exception = data.GetU32(&offset);
- SetError (EXCRegSet, Read, 0);
- }
- offset = next_thread_state;
- break;
- default:
- done = true;
- break;
- }
- }
- }
+ RegisterContextDarwin_arm64_Mach(lldb_private::Thread &thread,
+ const DataExtractor &data)
+ : RegisterContextDarwin_arm64(thread, 0) {
+ SetRegisterDataFrom_LC_THREAD(data);
+ }
- static size_t
- WriteRegister (RegisterContext *reg_ctx, const char *name, const char *alt_name, size_t reg_byte_size, Stream &data)
- {
- const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name);
- if (reg_info == NULL)
- reg_info = reg_ctx->GetRegisterInfoByName(alt_name);
- if (reg_info)
- {
- lldb_private::RegisterValue reg_value;
- if (reg_ctx->ReadRegister(reg_info, reg_value))
- {
- if (reg_info->byte_size >= reg_byte_size)
- data.Write(reg_value.GetBytes(), reg_byte_size);
- else
- {
- data.Write(reg_value.GetBytes(), reg_info->byte_size);
- for (size_t i=0, n = reg_byte_size - reg_info->byte_size; i<n; ++ i)
- data.PutChar(0);
- }
- return reg_byte_size;
- }
+ void InvalidateAllRegisters() override {
+ // Do nothing... registers are always valid...
+ }
+
+ void SetRegisterDataFrom_LC_THREAD(const DataExtractor &data) {
+ lldb::offset_t offset = 0;
+ SetError(GPRRegSet, Read, -1);
+ SetError(FPURegSet, Read, -1);
+ SetError(EXCRegSet, Read, -1);
+ bool done = false;
+ while (!done) {
+ int flavor = data.GetU32(&offset);
+ uint32_t count = data.GetU32(&offset);
+ lldb::offset_t next_thread_state = offset + (count * 4);
+ switch (flavor) {
+ case GPRRegSet:
+ // x0-x29 + fp + lr + sp + pc (== 33 64-bit registers) plus cpsr (1
+ // 32-bit register)
+ if (count >= (33 * 2) + 1) {
+ for (uint32_t i = 0; i < 33; ++i)
+ gpr.x[i] = data.GetU64(&offset);
+ gpr.cpsr = data.GetU32(&offset);
+ SetError(GPRRegSet, Read, 0);
+ }
+ offset = next_thread_state;
+ break;
+ case FPURegSet: {
+ uint8_t *fpu_reg_buf = (uint8_t *)&fpu.v[0];
+ const int fpu_reg_buf_size = sizeof(fpu);
+ if (fpu_reg_buf_size == count &&
+ data.ExtractBytes(offset, fpu_reg_buf_size, eByteOrderLittle,
+ fpu_reg_buf) == fpu_reg_buf_size) {
+ SetError(FPURegSet, Read, 0);
+ } else {
+ done = true;
}
- // Just write zeros if all else fails
- for (size_t i=0; i<reg_byte_size; ++ i)
+ }
+ offset = next_thread_state;
+ break;
+ case EXCRegSet:
+ if (count == 4) {
+ exc.far = data.GetU64(&offset);
+ exc.esr = data.GetU32(&offset);
+ exc.exception = data.GetU32(&offset);
+ SetError(EXCRegSet, Read, 0);
+ }
+ offset = next_thread_state;
+ break;
+ default:
+ done = true;
+ break;
+ }
+ }
+ }
+
+ static size_t WriteRegister(RegisterContext *reg_ctx, const char *name,
+ const char *alt_name, size_t reg_byte_size,
+ Stream &data) {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(name);
+ if (reg_info == NULL)
+ reg_info = reg_ctx->GetRegisterInfoByName(alt_name);
+ if (reg_info) {
+ lldb_private::RegisterValue reg_value;
+ if (reg_ctx->ReadRegister(reg_info, reg_value)) {
+ if (reg_info->byte_size >= reg_byte_size)
+ data.Write(reg_value.GetBytes(), reg_byte_size);
+ else {
+ data.Write(reg_value.GetBytes(), reg_info->byte_size);
+ for (size_t i = 0, n = reg_byte_size - reg_info->byte_size; i < n;
+ ++i)
data.PutChar(0);
+ }
return reg_byte_size;
+ }
}
-
- static bool
- Create_LC_THREAD (Thread *thread, Stream &data)
- {
- RegisterContextSP reg_ctx_sp (thread->GetRegisterContext());
- if (reg_ctx_sp)
- {
- RegisterContext *reg_ctx = reg_ctx_sp.get();
-
- data.PutHex32 (GPRRegSet); // Flavor
- data.PutHex32 (GPRWordCount);
- WriteRegister (reg_ctx, "x0", NULL, 8, data);
- WriteRegister (reg_ctx, "x1", NULL, 8, data);
- WriteRegister (reg_ctx, "x2", NULL, 8, data);
- WriteRegister (reg_ctx, "x3", NULL, 8, data);
- WriteRegister (reg_ctx, "x4", NULL, 8, data);
- WriteRegister (reg_ctx, "x5", NULL, 8, data);
- WriteRegister (reg_ctx, "x6", NULL, 8, data);
- WriteRegister (reg_ctx, "x7", NULL, 8, data);
- WriteRegister (reg_ctx, "x8", NULL, 8, data);
- WriteRegister (reg_ctx, "x9", NULL, 8, data);
- WriteRegister (reg_ctx, "x10", NULL, 8, data);
- WriteRegister (reg_ctx, "x11", NULL, 8, data);
- WriteRegister (reg_ctx, "x12", NULL, 8, data);
- WriteRegister (reg_ctx, "x13", NULL, 8, data);
- WriteRegister (reg_ctx, "x14", NULL, 8, data);
- WriteRegister (reg_ctx, "x15", NULL, 8, data);
- WriteRegister (reg_ctx, "x16", NULL, 8, data);
- WriteRegister (reg_ctx, "x17", NULL, 8, data);
- WriteRegister (reg_ctx, "x18", NULL, 8, data);
- WriteRegister (reg_ctx, "x19", NULL, 8, data);
- WriteRegister (reg_ctx, "x20", NULL, 8, data);
- WriteRegister (reg_ctx, "x21", NULL, 8, data);
- WriteRegister (reg_ctx, "x22", NULL, 8, data);
- WriteRegister (reg_ctx, "x23", NULL, 8, data);
- WriteRegister (reg_ctx, "x24", NULL, 8, data);
- WriteRegister (reg_ctx, "x25", NULL, 8, data);
- WriteRegister (reg_ctx, "x26", NULL, 8, data);
- WriteRegister (reg_ctx, "x27", NULL, 8, data);
- WriteRegister (reg_ctx, "x28", NULL, 8, data);
- WriteRegister (reg_ctx, "fp", NULL, 8, data);
- WriteRegister (reg_ctx, "lr", NULL, 8, data);
- WriteRegister (reg_ctx, "sp", NULL, 8, data);
- WriteRegister (reg_ctx, "pc", NULL, 8, data);
- WriteRegister (reg_ctx, "cpsr", NULL, 4, data);
-
- // Write out the EXC registers
-// data.PutHex32 (EXCRegSet);
-// data.PutHex32 (EXCWordCount);
-// WriteRegister (reg_ctx, "far", NULL, 8, data);
-// WriteRegister (reg_ctx, "esr", NULL, 4, data);
-// WriteRegister (reg_ctx, "exception", NULL, 4, data);
- return true;
- }
- return false;
+ // Just write zeros if all else fails
+ for (size_t i = 0; i < reg_byte_size; ++i)
+ data.PutChar(0);
+ return reg_byte_size;
+ }
+
+ static bool Create_LC_THREAD(Thread *thread, Stream &data) {
+ RegisterContextSP reg_ctx_sp(thread->GetRegisterContext());
+ if (reg_ctx_sp) {
+ RegisterContext *reg_ctx = reg_ctx_sp.get();
+
+ data.PutHex32(GPRRegSet); // Flavor
+ data.PutHex32(GPRWordCount);
+ WriteRegister(reg_ctx, "x0", NULL, 8, data);
+ WriteRegister(reg_ctx, "x1", NULL, 8, data);
+ WriteRegister(reg_ctx, "x2", NULL, 8, data);
+ WriteRegister(reg_ctx, "x3", NULL, 8, data);
+ WriteRegister(reg_ctx, "x4", NULL, 8, data);
+ WriteRegister(reg_ctx, "x5", NULL, 8, data);
+ WriteRegister(reg_ctx, "x6", NULL, 8, data);
+ WriteRegister(reg_ctx, "x7", NULL, 8, data);
+ WriteRegister(reg_ctx, "x8", NULL, 8, data);
+ WriteRegister(reg_ctx, "x9", NULL, 8, data);
+ WriteRegister(reg_ctx, "x10", NULL, 8, data);
+ WriteRegister(reg_ctx, "x11", NULL, 8, data);
+ WriteRegister(reg_ctx, "x12", NULL, 8, data);
+ WriteRegister(reg_ctx, "x13", NULL, 8, data);
+ WriteRegister(reg_ctx, "x14", NULL, 8, data);
+ WriteRegister(reg_ctx, "x15", NULL, 8, data);
+ WriteRegister(reg_ctx, "x16", NULL, 8, data);
+ WriteRegister(reg_ctx, "x17", NULL, 8, data);
+ WriteRegister(reg_ctx, "x18", NULL, 8, data);
+ WriteRegister(reg_ctx, "x19", NULL, 8, data);
+ WriteRegister(reg_ctx, "x20", NULL, 8, data);
+ WriteRegister(reg_ctx, "x21", NULL, 8, data);
+ WriteRegister(reg_ctx, "x22", NULL, 8, data);
+ WriteRegister(reg_ctx, "x23", NULL, 8, data);
+ WriteRegister(reg_ctx, "x24", NULL, 8, data);
+ WriteRegister(reg_ctx, "x25", NULL, 8, data);
+ WriteRegister(reg_ctx, "x26", NULL, 8, data);
+ WriteRegister(reg_ctx, "x27", NULL, 8, data);
+ WriteRegister(reg_ctx, "x28", NULL, 8, data);
+ WriteRegister(reg_ctx, "fp", NULL, 8, data);
+ WriteRegister(reg_ctx, "lr", NULL, 8, data);
+ WriteRegister(reg_ctx, "sp", NULL, 8, data);
+ WriteRegister(reg_ctx, "pc", NULL, 8, data);
+ WriteRegister(reg_ctx, "cpsr", NULL, 4, data);
+
+ // Write out the EXC registers
+ // data.PutHex32 (EXCRegSet);
+ // data.PutHex32 (EXCWordCount);
+ // WriteRegister (reg_ctx, "far", NULL, 8, data);
+ // WriteRegister (reg_ctx, "esr", NULL, 4, data);
+ // WriteRegister (reg_ctx, "exception", NULL, 4, data);
+ return true;
}
+ return false;
+ }
protected:
- int
- DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override
- {
- return -1;
- }
-
- int
- DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override
- {
- return -1;
- }
-
- int
- DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override
- {
- return -1;
- }
+ int DoReadGPR(lldb::tid_t tid, int flavor, GPR &gpr) override { return -1; }
- int
- DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override
- {
- return -1;
- }
-
- int
- DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override
- {
- return 0;
- }
-
- int
- DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override
- {
- return 0;
- }
-
- int
- DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override
- {
- return 0;
- }
-
- int
- DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override
- {
- return -1;
- }
-};
+ int DoReadFPU(lldb::tid_t tid, int flavor, FPU &fpu) override { return -1; }
-static uint32_t
-MachHeaderSizeFromMagic(uint32_t magic)
-{
- switch (magic)
- {
- case MH_MAGIC:
- case MH_CIGAM:
- return sizeof(struct mach_header);
-
- case MH_MAGIC_64:
- case MH_CIGAM_64:
- return sizeof(struct mach_header_64);
- break;
-
- default:
- break;
- }
+ int DoReadEXC(lldb::tid_t tid, int flavor, EXC &exc) override { return -1; }
+
+ int DoReadDBG(lldb::tid_t tid, int flavor, DBG &dbg) override { return -1; }
+
+ int DoWriteGPR(lldb::tid_t tid, int flavor, const GPR &gpr) override {
+ return 0;
+ }
+
+ int DoWriteFPU(lldb::tid_t tid, int flavor, const FPU &fpu) override {
return 0;
+ }
+
+ int DoWriteEXC(lldb::tid_t tid, int flavor, const EXC &exc) override {
+ return 0;
+ }
+
+ int DoWriteDBG(lldb::tid_t tid, int flavor, const DBG &dbg) override {
+ return -1;
+ }
+};
+
+static uint32_t MachHeaderSizeFromMagic(uint32_t magic) {
+ switch (magic) {
+ case MH_MAGIC:
+ case MH_CIGAM:
+ return sizeof(struct mach_header);
+
+ case MH_MAGIC_64:
+ case MH_CIGAM_64:
+ return sizeof(struct mach_header_64);
+ break;
+
+ default:
+ break;
+ }
+ return 0;
}
#define MACHO_NLIST_ARM_SYMBOL_IS_THUMB 0x0008
-void
-ObjectFileMachO::Initialize()
-{
- PluginManager::RegisterPlugin (GetPluginNameStatic(),
- GetPluginDescriptionStatic(),
- CreateInstance,
- CreateMemoryInstance,
- GetModuleSpecifications,
- SaveCore);
+void ObjectFileMachO::Initialize() {
+ PluginManager::RegisterPlugin(
+ GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance,
+ CreateMemoryInstance, GetModuleSpecifications, SaveCore);
}
-void
-ObjectFileMachO::Terminate()
-{
- PluginManager::UnregisterPlugin (CreateInstance);
+void ObjectFileMachO::Terminate() {
+ PluginManager::UnregisterPlugin(CreateInstance);
}
-lldb_private::ConstString
-ObjectFileMachO::GetPluginNameStatic()
-{
- static ConstString g_name("mach-o");
- return g_name;
+lldb_private::ConstString ObjectFileMachO::GetPluginNameStatic() {
+ static ConstString g_name("mach-o");
+ return g_name;
}
-const char *
-ObjectFileMachO::GetPluginDescriptionStatic()
-{
- return "Mach-o object file reader (32 and 64 bit)";
+const char *ObjectFileMachO::GetPluginDescriptionStatic() {
+ return "Mach-o object file reader (32 and 64 bit)";
}
-ObjectFile *
-ObjectFileMachO::CreateInstance (const lldb::ModuleSP &module_sp,
- DataBufferSP& data_sp,
- lldb::offset_t data_offset,
- const FileSpec* file,
- lldb::offset_t file_offset,
- lldb::offset_t length)
-{
- if (!data_sp)
- {
- data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length);
- data_offset = 0;
- }
-
- if (ObjectFileMachO::MagicBytesMatch(data_sp, data_offset, length))
- {
- // Update the data to contain the entire file if it doesn't already
- if (data_sp->GetByteSize() < length)
- {
- data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length);
- data_offset = 0;
- }
- std::unique_ptr<ObjectFile> objfile_ap(new ObjectFileMachO (module_sp, data_sp, data_offset, file, file_offset, length));
- if (objfile_ap.get() && objfile_ap->ParseHeader())
- return objfile_ap.release();
+ObjectFile *ObjectFileMachO::CreateInstance(const lldb::ModuleSP &module_sp,
+ DataBufferSP &data_sp,
+ lldb::offset_t data_offset,
+ const FileSpec *file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length) {
+ if (!data_sp) {
+ data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length);
+ data_offset = 0;
+ }
+
+ if (ObjectFileMachO::MagicBytesMatch(data_sp, data_offset, length)) {
+ // Update the data to contain the entire file if it doesn't already
+ if (data_sp->GetByteSize() < length) {
+ data_sp = file->MemoryMapFileContentsIfLocal(file_offset, length);
+ data_offset = 0;
}
- return NULL;
+ std::unique_ptr<ObjectFile> objfile_ap(new ObjectFileMachO(
+ module_sp, data_sp, data_offset, file, file_offset, length));
+ if (objfile_ap.get() && objfile_ap->ParseHeader())
+ return objfile_ap.release();
+ }
+ return NULL;
}
-ObjectFile *
-ObjectFileMachO::CreateMemoryInstance (const lldb::ModuleSP &module_sp,
- DataBufferSP& data_sp,
- const ProcessSP &process_sp,
- lldb::addr_t header_addr)
-{
- if (ObjectFileMachO::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize()))
- {
- std::unique_ptr<ObjectFile> objfile_ap(new ObjectFileMachO (module_sp, data_sp, process_sp, header_addr));
- if (objfile_ap.get() && objfile_ap->ParseHeader())
- return objfile_ap.release();
- }
- return NULL;
+ObjectFile *ObjectFileMachO::CreateMemoryInstance(
+ const lldb::ModuleSP &module_sp, DataBufferSP &data_sp,
+ const ProcessSP &process_sp, lldb::addr_t header_addr) {
+ if (ObjectFileMachO::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) {
+ std::unique_ptr<ObjectFile> objfile_ap(
+ new ObjectFileMachO(module_sp, data_sp, process_sp, header_addr));
+ if (objfile_ap.get() && objfile_ap->ParseHeader())
+ return objfile_ap.release();
+ }
+ return NULL;
}
-size_t
-ObjectFileMachO::GetModuleSpecifications (const lldb_private::FileSpec& file,
- lldb::DataBufferSP& data_sp,
- lldb::offset_t data_offset,
- lldb::offset_t file_offset,
- lldb::offset_t length,
- lldb_private::ModuleSpecList &specs)
-{
- const size_t initial_count = specs.GetSize();
-
- if (ObjectFileMachO::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize()))
- {
- DataExtractor data;
+size_t ObjectFileMachO::GetModuleSpecifications(
+ const lldb_private::FileSpec &file, lldb::DataBufferSP &data_sp,
+ lldb::offset_t data_offset, lldb::offset_t file_offset,
+ lldb::offset_t length, lldb_private::ModuleSpecList &specs) {
+ const size_t initial_count = specs.GetSize();
+
+ if (ObjectFileMachO::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize())) {
+ DataExtractor data;
+ data.SetData(data_sp);
+ llvm::MachO::mach_header header;
+ if (ParseHeader(data, &data_offset, header)) {
+ size_t header_and_load_cmds =
+ header.sizeofcmds + MachHeaderSizeFromMagic(header.magic);
+ if (header_and_load_cmds >= data_sp->GetByteSize()) {
+ data_sp = file.ReadFileContents(file_offset, header_and_load_cmds);
data.SetData(data_sp);
- llvm::MachO::mach_header header;
- if (ParseHeader (data, &data_offset, header))
- {
- size_t header_and_load_cmds = header.sizeofcmds + MachHeaderSizeFromMagic(header.magic);
- if (header_and_load_cmds >= data_sp->GetByteSize())
- {
- data_sp = file.ReadFileContents(file_offset, header_and_load_cmds);
- data.SetData(data_sp);
- data_offset = MachHeaderSizeFromMagic(header.magic);
- }
- if (data_sp)
- {
- ModuleSpec spec;
- spec.GetFileSpec() = file;
- spec.SetObjectOffset(file_offset);
- spec.SetObjectSize(length);
-
- if (GetArchitecture (header, data, data_offset, spec.GetArchitecture()))
- {
- if (spec.GetArchitecture().IsValid())
- {
- GetUUID (header, data, data_offset, spec.GetUUID());
- specs.Append(spec);
- }
- }
- }
+ data_offset = MachHeaderSizeFromMagic(header.magic);
+ }
+ if (data_sp) {
+ ModuleSpec spec;
+ spec.GetFileSpec() = file;
+ spec.SetObjectOffset(file_offset);
+ spec.SetObjectSize(length);
+
+ if (GetArchitecture(header, data, data_offset,
+ spec.GetArchitecture())) {
+ if (spec.GetArchitecture().IsValid()) {
+ GetUUID(header, data, data_offset, spec.GetUUID());
+ specs.Append(spec);
+ }
}
+ }
}
- return specs.GetSize() - initial_count;
+ }
+ return specs.GetSize() - initial_count;
}
-const ConstString &
-ObjectFileMachO::GetSegmentNameTEXT()
-{
- static ConstString g_segment_name_TEXT ("__TEXT");
- return g_segment_name_TEXT;
+const ConstString &ObjectFileMachO::GetSegmentNameTEXT() {
+ static ConstString g_segment_name_TEXT("__TEXT");
+ return g_segment_name_TEXT;
}
-const ConstString &
-ObjectFileMachO::GetSegmentNameDATA()
-{
- static ConstString g_segment_name_DATA ("__DATA");
- return g_segment_name_DATA;
+const ConstString &ObjectFileMachO::GetSegmentNameDATA() {
+ static ConstString g_segment_name_DATA("__DATA");
+ return g_segment_name_DATA;
}
-const ConstString &
-ObjectFileMachO::GetSegmentNameDATA_DIRTY()
-{
- static ConstString g_segment_name ("__DATA_DIRTY");
- return g_segment_name;
+const ConstString &ObjectFileMachO::GetSegmentNameDATA_DIRTY() {
+ static ConstString g_segment_name("__DATA_DIRTY");
+ return g_segment_name;
}
-const ConstString &
-ObjectFileMachO::GetSegmentNameDATA_CONST()
-{
- static ConstString g_segment_name ("__DATA_CONST");
- return g_segment_name;
+const ConstString &ObjectFileMachO::GetSegmentNameDATA_CONST() {
+ static ConstString g_segment_name("__DATA_CONST");
+ return g_segment_name;
}
-const ConstString &
-ObjectFileMachO::GetSegmentNameOBJC()
-{
- static ConstString g_segment_name_OBJC ("__OBJC");
- return g_segment_name_OBJC;
+const ConstString &ObjectFileMachO::GetSegmentNameOBJC() {
+ static ConstString g_segment_name_OBJC("__OBJC");
+ return g_segment_name_OBJC;
}
-const ConstString &
-ObjectFileMachO::GetSegmentNameLINKEDIT()
-{
- static ConstString g_section_name_LINKEDIT ("__LINKEDIT");
- return g_section_name_LINKEDIT;
+const ConstString &ObjectFileMachO::GetSegmentNameLINKEDIT() {
+ static ConstString g_section_name_LINKEDIT("__LINKEDIT");
+ return g_section_name_LINKEDIT;
}
-const ConstString &
-ObjectFileMachO::GetSectionNameEHFrame()
-{
- static ConstString g_section_name_eh_frame ("__eh_frame");
- return g_section_name_eh_frame;
+const ConstString &ObjectFileMachO::GetSectionNameEHFrame() {
+ static ConstString g_section_name_eh_frame("__eh_frame");
+ return g_section_name_eh_frame;
}
-bool
-ObjectFileMachO::MagicBytesMatch (DataBufferSP& data_sp,
- lldb::addr_t data_offset,
- lldb::addr_t data_length)
-{
- DataExtractor data;
- data.SetData (data_sp, data_offset, data_length);
- lldb::offset_t offset = 0;
- uint32_t magic = data.GetU32(&offset);
- return MachHeaderSizeFromMagic(magic) != 0;
+bool ObjectFileMachO::MagicBytesMatch(DataBufferSP &data_sp,
+ lldb::addr_t data_offset,
+ lldb::addr_t data_length) {
+ DataExtractor data;
+ data.SetData(data_sp, data_offset, data_length);
+ lldb::offset_t offset = 0;
+ uint32_t magic = data.GetU32(&offset);
+ return MachHeaderSizeFromMagic(magic) != 0;
}
ObjectFileMachO::ObjectFileMachO(const lldb::ModuleSP &module_sp,
- DataBufferSP& data_sp,
+ DataBufferSP &data_sp,
lldb::offset_t data_offset,
- const FileSpec* file,
+ const FileSpec *file,
lldb::offset_t file_offset,
- lldb::offset_t length) :
- ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset),
- m_mach_segments(),
- m_mach_sections(),
- m_entry_point_address(),
- m_thread_context_offsets(),
- m_thread_context_offsets_valid(false),
- m_reexported_dylibs (),
- m_allow_assembly_emulation_unwind_plans (true)
-{
- ::memset (&m_header, 0, sizeof(m_header));
- ::memset (&m_dysymtab, 0, sizeof(m_dysymtab));
+ lldb::offset_t length)
+ : ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset),
+ m_mach_segments(), m_mach_sections(), m_entry_point_address(),
+ m_thread_context_offsets(), m_thread_context_offsets_valid(false),
+ m_reexported_dylibs(), m_allow_assembly_emulation_unwind_plans(true) {
+ ::memset(&m_header, 0, sizeof(m_header));
+ ::memset(&m_dysymtab, 0, sizeof(m_dysymtab));
}
-ObjectFileMachO::ObjectFileMachO (const lldb::ModuleSP &module_sp,
- lldb::DataBufferSP& header_data_sp,
- const lldb::ProcessSP &process_sp,
- lldb::addr_t header_addr) :
- ObjectFile(module_sp, process_sp, header_addr, header_data_sp),
- m_mach_segments(),
- m_mach_sections(),
- m_entry_point_address(),
- m_thread_context_offsets(),
- m_thread_context_offsets_valid(false),
- m_reexported_dylibs (),
- m_allow_assembly_emulation_unwind_plans (true)
-{
- ::memset (&m_header, 0, sizeof(m_header));
- ::memset (&m_dysymtab, 0, sizeof(m_dysymtab));
+ObjectFileMachO::ObjectFileMachO(const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP &header_data_sp,
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr)
+ : ObjectFile(module_sp, process_sp, header_addr, header_data_sp),
+ m_mach_segments(), m_mach_sections(), m_entry_point_address(),
+ m_thread_context_offsets(), m_thread_context_offsets_valid(false),
+ m_reexported_dylibs(), m_allow_assembly_emulation_unwind_plans(true) {
+ ::memset(&m_header, 0, sizeof(m_header));
+ ::memset(&m_dysymtab, 0, sizeof(m_dysymtab));
}
-bool
-ObjectFileMachO::ParseHeader (DataExtractor &data,
- lldb::offset_t *data_offset_ptr,
- llvm::MachO::mach_header &header)
-{
- data.SetByteOrder (endian::InlHostByteOrder());
- // Leave magic in the original byte order
- header.magic = data.GetU32(data_offset_ptr);
- bool can_parse = false;
- bool is_64_bit = false;
- switch (header.magic)
- {
- case MH_MAGIC:
- data.SetByteOrder (endian::InlHostByteOrder());
- data.SetAddressByteSize(4);
- can_parse = true;
- break;
-
- case MH_MAGIC_64:
- data.SetByteOrder (endian::InlHostByteOrder());
- data.SetAddressByteSize(8);
- can_parse = true;
- is_64_bit = true;
- break;
-
- case MH_CIGAM:
- data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig ? eByteOrderLittle : eByteOrderBig);
- data.SetAddressByteSize(4);
- can_parse = true;
- break;
-
- case MH_CIGAM_64:
- data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig ? eByteOrderLittle : eByteOrderBig);
- data.SetAddressByteSize(8);
- is_64_bit = true;
- can_parse = true;
- break;
-
- default:
- break;
- }
-
- if (can_parse)
- {
- data.GetU32(data_offset_ptr, &header.cputype, 6);
- if (is_64_bit)
- *data_offset_ptr += 4;
- return true;
- }
- else
- {
- memset(&header, 0, sizeof(header));
- }
- return false;
+bool ObjectFileMachO::ParseHeader(DataExtractor &data,
+ lldb::offset_t *data_offset_ptr,
+ llvm::MachO::mach_header &header) {
+ data.SetByteOrder(endian::InlHostByteOrder());
+ // Leave magic in the original byte order
+ header.magic = data.GetU32(data_offset_ptr);
+ bool can_parse = false;
+ bool is_64_bit = false;
+ switch (header.magic) {
+ case MH_MAGIC:
+ data.SetByteOrder(endian::InlHostByteOrder());
+ data.SetAddressByteSize(4);
+ can_parse = true;
+ break;
+
+ case MH_MAGIC_64:
+ data.SetByteOrder(endian::InlHostByteOrder());
+ data.SetAddressByteSize(8);
+ can_parse = true;
+ is_64_bit = true;
+ break;
+
+ case MH_CIGAM:
+ data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
+ ? eByteOrderLittle
+ : eByteOrderBig);
+ data.SetAddressByteSize(4);
+ can_parse = true;
+ break;
+
+ case MH_CIGAM_64:
+ data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
+ ? eByteOrderLittle
+ : eByteOrderBig);
+ data.SetAddressByteSize(8);
+ is_64_bit = true;
+ can_parse = true;
+ break;
+
+ default:
+ break;
+ }
+
+ if (can_parse) {
+ data.GetU32(data_offset_ptr, &header.cputype, 6);
+ if (is_64_bit)
+ *data_offset_ptr += 4;
+ return true;
+ } else {
+ memset(&header, 0, sizeof(header));
+ }
+ return false;
}
-bool
-ObjectFileMachO::ParseHeader ()
-{
- ModuleSP module_sp(GetModule());
- if (module_sp)
- {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- bool can_parse = false;
- lldb::offset_t offset = 0;
- m_data.SetByteOrder (endian::InlHostByteOrder());
- // Leave magic in the original byte order
- m_header.magic = m_data.GetU32(&offset);
- switch (m_header.magic)
- {
- case MH_MAGIC:
- m_data.SetByteOrder (endian::InlHostByteOrder());
- m_data.SetAddressByteSize(4);
- can_parse = true;
- break;
-
- case MH_MAGIC_64:
- m_data.SetByteOrder (endian::InlHostByteOrder());
- m_data.SetAddressByteSize(8);
- can_parse = true;
- break;
-
- case MH_CIGAM:
- m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig ? eByteOrderLittle : eByteOrderBig);
- m_data.SetAddressByteSize(4);
- can_parse = true;
- break;
-
- case MH_CIGAM_64:
- m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig ? eByteOrderLittle : eByteOrderBig);
- m_data.SetAddressByteSize(8);
- can_parse = true;
- break;
-
- default:
- break;
- }
-
- if (can_parse)
- {
- m_data.GetU32(&offset, &m_header.cputype, 6);
+bool ObjectFileMachO::ParseHeader() {
+ ModuleSP module_sp(GetModule());
+ if (module_sp) {
+ std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
+ bool can_parse = false;
+ lldb::offset_t offset = 0;
+ m_data.SetByteOrder(endian::InlHostByteOrder());
+ // Leave magic in the original byte order
+ m_header.magic = m_data.GetU32(&offset);
+ switch (m_header.magic) {
+ case MH_MAGIC:
+ m_data.SetByteOrder(endian::InlHostByteOrder());
+ m_data.SetAddressByteSize(4);
+ can_parse = true;
+ break;
+
+ case MH_MAGIC_64:
+ m_data.SetByteOrder(endian::InlHostByteOrder());
+ m_data.SetAddressByteSize(8);
+ can_parse = true;
+ break;
+
+ case MH_CIGAM:
+ m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
+ ? eByteOrderLittle
+ : eByteOrderBig);
+ m_data.SetAddressByteSize(4);
+ can_parse = true;
+ break;
+
+ case MH_CIGAM_64:
+ m_data.SetByteOrder(endian::InlHostByteOrder() == eByteOrderBig
+ ? eByteOrderLittle
+ : eByteOrderBig);
+ m_data.SetAddressByteSize(8);
+ can_parse = true;
+ break;
+
+ default:
+ break;
+ }
-
- ArchSpec mach_arch;
-
- if (GetArchitecture (mach_arch))
- {
- // Check if the module has a required architecture
- const ArchSpec &module_arch = module_sp->GetArchitecture();
- if (module_arch.IsValid() && !module_arch.IsCompatibleMatch(mach_arch))
- return false;
-
- if (SetModulesArchitecture (mach_arch))
- {
- const size_t header_and_lc_size = m_header.sizeofcmds + MachHeaderSizeFromMagic(m_header.magic);
- if (m_data.GetByteSize() < header_and_lc_size)
- {
- DataBufferSP data_sp;
- ProcessSP process_sp (m_process_wp.lock());
- if (process_sp)
- {
- data_sp = ReadMemory (process_sp, m_memory_addr, header_and_lc_size);
- }
- else
- {
- // Read in all only the load command data from the file on disk
- data_sp = m_file.ReadFileContents(m_file_offset, header_and_lc_size);
- if (data_sp->GetByteSize() != header_and_lc_size)
- return false;
- }
- if (data_sp)
- m_data.SetData (data_sp);
- }
- }
- return true;
+ if (can_parse) {
+ m_data.GetU32(&offset, &m_header.cputype, 6);
+
+ ArchSpec mach_arch;
+
+ if (GetArchitecture(mach_arch)) {
+ // Check if the module has a required architecture
+ const ArchSpec &module_arch = module_sp->GetArchitecture();
+ if (module_arch.IsValid() && !module_arch.IsCompatibleMatch(mach_arch))
+ return false;
+
+ if (SetModulesArchitecture(mach_arch)) {
+ const size_t header_and_lc_size =
+ m_header.sizeofcmds + MachHeaderSizeFromMagic(m_header.magic);
+ if (m_data.GetByteSize() < header_and_lc_size) {
+ DataBufferSP data_sp;
+ ProcessSP process_sp(m_process_wp.lock());
+ if (process_sp) {
+ data_sp =
+ ReadMemory(process_sp, m_memory_addr, header_and_lc_size);
+ } else {
+ // Read in all only the load command data from the file on disk
+ data_sp =
+ m_file.ReadFileContents(m_file_offset, header_and_lc_size);
+ if (data_sp->GetByteSize() != header_and_lc_size)
+ return false;
}
+ if (data_sp)
+ m_data.SetData(data_sp);
+ }
}
- else
- {
- memset(&m_header, 0, sizeof(struct mach_header));
- }
+ return true;
+ }
+ } else {
+ memset(&m_header, 0, sizeof(struct mach_header));
}
- return false;
+ }
+ return false;
}
-ByteOrder
-ObjectFileMachO::GetByteOrder () const
-{
- return m_data.GetByteOrder ();
+ByteOrder ObjectFileMachO::GetByteOrder() const {
+ return m_data.GetByteOrder();
}
-bool
-ObjectFileMachO::IsExecutable() const
-{
- return m_header.filetype == MH_EXECUTE;
+bool ObjectFileMachO::IsExecutable() const {
+ return m_header.filetype == MH_EXECUTE;
}
-uint32_t
-ObjectFileMachO::GetAddressByteSize () const
-{
- return m_data.GetAddressByteSize ();
+uint32_t ObjectFileMachO::GetAddressByteSize() const {
+ return m_data.GetAddressByteSize();
}
-AddressClass
-ObjectFileMachO::GetAddressClass (lldb::addr_t file_addr)
-{
- Symtab *symtab = GetSymtab();
- if (symtab)
- {
- Symbol *symbol = symtab->FindSymbolContainingFileAddress(file_addr);
- if (symbol)
- {
- if (symbol->ValueIsAddress())
- {
- SectionSP section_sp (symbol->GetAddressRef().GetSection());
- if (section_sp)
- {
- const lldb::SectionType section_type = section_sp->GetType();
- switch (section_type)
- {
- case eSectionTypeInvalid:
- return eAddressClassUnknown;
-
- case eSectionTypeCode:
- if (m_header.cputype == llvm::MachO::CPU_TYPE_ARM)
- {
- // For ARM we have a bit in the n_desc field of the symbol
- // that tells us ARM/Thumb which is bit 0x0008.
- if (symbol->GetFlags() & MACHO_NLIST_ARM_SYMBOL_IS_THUMB)
- return eAddressClassCodeAlternateISA;
- }
- return eAddressClassCode;
-
- case eSectionTypeContainer:
- return eAddressClassUnknown;
-
- case eSectionTypeData:
- case eSectionTypeDataCString:
- case eSectionTypeDataCStringPointers:
- case eSectionTypeDataSymbolAddress:
- case eSectionTypeData4:
- case eSectionTypeData8:
- case eSectionTypeData16:
- case eSectionTypeDataPointers:
- case eSectionTypeZeroFill:
- case eSectionTypeDataObjCMessageRefs:
- case eSectionTypeDataObjCCFStrings:
- case eSectionTypeGoSymtab:
- return eAddressClassData;
-
- case eSectionTypeDebug:
- case eSectionTypeDWARFDebugAbbrev:
- case eSectionTypeDWARFDebugAddr:
- case eSectionTypeDWARFDebugAranges:
- case eSectionTypeDWARFDebugFrame:
- case eSectionTypeDWARFDebugInfo:
- case eSectionTypeDWARFDebugLine:
- case eSectionTypeDWARFDebugLoc:
- case eSectionTypeDWARFDebugMacInfo:
- case eSectionTypeDWARFDebugMacro:
- case eSectionTypeDWARFDebugPubNames:
- case eSectionTypeDWARFDebugPubTypes:
- case eSectionTypeDWARFDebugRanges:
- case eSectionTypeDWARFDebugStr:
- case eSectionTypeDWARFDebugStrOffsets:
- case eSectionTypeDWARFAppleNames:
- case eSectionTypeDWARFAppleTypes:
- case eSectionTypeDWARFAppleNamespaces:
- case eSectionTypeDWARFAppleObjC:
- return eAddressClassDebug;
-
- case eSectionTypeEHFrame:
- case eSectionTypeARMexidx:
- case eSectionTypeARMextab:
- case eSectionTypeCompactUnwind:
- return eAddressClassRuntime;
-
- case eSectionTypeAbsoluteAddress:
- case eSectionTypeELFSymbolTable:
- case eSectionTypeELFDynamicSymbols:
- case eSectionTypeELFRelocationEntries:
- case eSectionTypeELFDynamicLinkInfo:
- case eSectionTypeOther:
- return eAddressClassUnknown;
- }
- }
- }
-
- const SymbolType symbol_type = symbol->GetType();
- switch (symbol_type)
- {
- case eSymbolTypeAny: return eAddressClassUnknown;
- case eSymbolTypeAbsolute: return eAddressClassUnknown;
-
- case eSymbolTypeCode:
- case eSymbolTypeTrampoline:
- case eSymbolTypeResolver:
- if (m_header.cputype == llvm::MachO::CPU_TYPE_ARM)
- {
- // For ARM we have a bit in the n_desc field of the symbol
- // that tells us ARM/Thumb which is bit 0x0008.
- if (symbol->GetFlags() & MACHO_NLIST_ARM_SYMBOL_IS_THUMB)
- return eAddressClassCodeAlternateISA;
- }
- return eAddressClassCode;
-
- case eSymbolTypeData: return eAddressClassData;
- case eSymbolTypeRuntime: return eAddressClassRuntime;
- case eSymbolTypeException: return eAddressClassRuntime;
- case eSymbolTypeSourceFile: return eAddressClassDebug;
- case eSymbolTypeHeaderFile: return eAddressClassDebug;
- case eSymbolTypeObjectFile: return eAddressClassDebug;
- case eSymbolTypeCommonBlock: return eAddressClassDebug;
- case eSymbolTypeBlock: return eAddressClassDebug;
- case eSymbolTypeLocal: return eAddressClassData;
- case eSymbolTypeParam: return eAddressClassData;
- case eSymbolTypeVariable: return eAddressClassData;
- case eSymbolTypeVariableType: return eAddressClassDebug;
- case eSymbolTypeLineEntry: return eAddressClassDebug;
- case eSymbolTypeLineHeader: return eAddressClassDebug;
- case eSymbolTypeScopeBegin: return eAddressClassDebug;
- case eSymbolTypeScopeEnd: return eAddressClassDebug;
- case eSymbolTypeAdditional: return eAddressClassUnknown;
- case eSymbolTypeCompiler: return eAddressClassDebug;
- case eSymbolTypeInstrumentation:return eAddressClassDebug;
- case eSymbolTypeUndefined: return eAddressClassUnknown;
- case eSymbolTypeObjCClass: return eAddressClassRuntime;
- case eSymbolTypeObjCMetaClass: return eAddressClassRuntime;
- case eSymbolTypeObjCIVar: return eAddressClassRuntime;
- case eSymbolTypeReExported: return eAddressClassRuntime;
+AddressClass ObjectFileMachO::GetAddressClass(lldb::addr_t file_addr) {
+ Symtab *symtab = GetSymtab();
+ if (symtab) {
+ Symbol *symbol = symtab->FindSymbolContainingFileAddress(file_addr);
+ if (symbol) {
+ if (symbol->ValueIsAddress()) {
+ SectionSP section_sp(symbol->GetAddressRef().GetSection());
+ if (section_sp) {
+ const lldb::SectionType section_type = section_sp->GetType();
+ switch (section_type) {
+ case eSectionTypeInvalid:
+ return eAddressClassUnknown;
+
+ case eSectionTypeCode:
+ if (m_header.cputype == llvm::MachO::CPU_TYPE_ARM) {
+ // For ARM we have a bit in the n_desc field of the symbol
+ // that tells us ARM/Thumb which is bit 0x0008.
+ if (symbol->GetFlags() & MACHO_NLIST_ARM_SYMBOL_IS_THUMB)
+ return eAddressClassCodeAlternateISA;
}
+ return eAddressClassCode;
+
+ case eSectionTypeContainer:
+ return eAddressClassUnknown;
+
+ case eSectionTypeData:
+ case eSectionTypeDataCString:
+ case eSectionTypeDataCStringPointers:
+ case eSectionTypeDataSymbolAddress:
+ case eSectionTypeData4:
+ case eSectionTypeData8:
+ case eSectionTypeData16:
+ case eSectionTypeDataPointers:
+ case eSectionTypeZeroFill:
+ case eSectionTypeDataObjCMessageRefs:
+ case eSectionTypeDataObjCCFStrings:
+ case eSectionTypeGoSymtab:
+ return eAddressClassData;
+
+ case eSectionTypeDebug:
+ case eSectionTypeDWARFDebugAbbrev:
+ case eSectionTypeDWARFDebugAddr:
+ case eSectionTypeDWARFDebugAranges:
+ case eSectionTypeDWARFDebugFrame:
+ case eSectionTypeDWARFDebugInfo:
+ case eSectionTypeDWARFDebugLine:
+ case eSectionTypeDWARFDebugLoc:
+ case eSectionTypeDWARFDebugMacInfo:
+ case eSectionTypeDWARFDebugMacro:
+ case eSectionTypeDWARFDebugPubNames:
+ case eSectionTypeDWARFDebugPubTypes:
+ case eSectionTypeDWARFDebugRanges:
+ case eSectionTypeDWARFDebugStr:
+ case eSectionTypeDWARFDebugStrOffsets:
+ case eSectionTypeDWARFAppleNames:
+ case eSectionTypeDWARFAppleTypes:
+ case eSectionTypeDWARFAppleNamespaces:
+ case eSectionTypeDWARFAppleObjC:
+ return eAddressClassDebug;
+
+ case eSectionTypeEHFrame:
+ case eSectionTypeARMexidx:
+ case eSectionTypeARMextab:
+ case eSectionTypeCompactUnwind:
+ return eAddressClassRuntime;
+
+ case eSectionTypeAbsoluteAddress:
+ case eSectionTypeELFSymbolTable:
+ case eSectionTypeELFDynamicSymbols:
+ case eSectionTypeELFRelocationEntries:
+ case eSectionTypeELFDynamicLinkInfo:
+ case eSectionTypeOther:
+ return eAddressClassUnknown;
+ }
+ }
+ }
+
+ const SymbolType symbol_type = symbol->GetType();
+ switch (symbol_type) {
+ case eSymbolTypeAny:
+ return eAddressClassUnknown;
+ case eSymbolTypeAbsolute:
+ return eAddressClassUnknown;
+
+ case eSymbolTypeCode:
+ case eSymbolTypeTrampoline:
+ case eSymbolTypeResolver:
+ if (m_header.cputype == llvm::MachO::CPU_TYPE_ARM) {
+ // For ARM we have a bit in the n_desc field of the symbol
+ // that tells us ARM/Thumb which is bit 0x0008.
+ if (symbol->GetFlags() & MACHO_NLIST_ARM_SYMBOL_IS_THUMB)
+ return eAddressClassCodeAlternateISA;
}
+ return eAddressClassCode;
+
+ case eSymbolTypeData:
+ return eAddressClassData;
+ case eSymbolTypeRuntime:
+ return eAddressClassRuntime;
+ case eSymbolTypeException:
+ return eAddressClassRuntime;
+ case eSymbolTypeSourceFile:
+ return eAddressClassDebug;
+ case eSymbolTypeHeaderFile:
+ return eAddressClassDebug;
+ case eSymbolTypeObjectFile:
+ return eAddressClassDebug;
+ case eSymbolTypeCommonBlock:
+ return eAddressClassDebug;
+ case eSymbolTypeBlock:
+ return eAddressClassDebug;
+ case eSymbolTypeLocal:
+ return eAddressClassData;
+ case eSymbolTypeParam:
+ return eAddressClassData;
+ case eSymbolTypeVariable:
+ return eAddressClassData;
+ case eSymbolTypeVariableType:
+ return eAddressClassDebug;
+ case eSymbolTypeLineEntry:
+ return eAddressClassDebug;
+ case eSymbolTypeLineHeader:
+ return eAddressClassDebug;
+ case eSymbolTypeScopeBegin:
+ return eAddressClassDebug;
+ case eSymbolTypeScopeEnd:
+ return eAddressClassDebug;
+ case eSymbolTypeAdditional:
+ return eAddressClassUnknown;
+ case eSymbolTypeCompiler:
+ return eAddressClassDebug;
+ case eSymbolTypeInstrumentation:
+ return eAddressClassDebug;
+ case eSymbolTypeUndefined:
+ return eAddressClassUnknown;
+ case eSymbolTypeObjCClass:
+ return eAddressClassRuntime;
+ case eSymbolTypeObjCMetaClass:
+ return eAddressClassRuntime;
+ case eSymbolTypeObjCIVar:
+ return eAddressClassRuntime;
+ case eSymbolTypeReExported:
+ return eAddressClassRuntime;
+ }
+ }
+ }
+ return eAddressClassUnknown;
+}
+
+Symtab *ObjectFileMachO::GetSymtab() {
+ ModuleSP module_sp(GetModule());
+ if (module_sp) {
+ std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
+ if (m_symtab_ap.get() == NULL) {
+ m_symtab_ap.reset(new Symtab(this));
+ std::lock_guard<std::recursive_mutex> symtab_guard(
+ m_symtab_ap->GetMutex());
+ ParseSymtab();
+ m_symtab_ap->Finalize();
}
- return eAddressClassUnknown;
+ }
+ return m_symtab_ap.get();
}
-Symtab *
-ObjectFileMachO::GetSymtab()
-{
+bool ObjectFileMachO::IsStripped() {
+ if (m_dysymtab.cmd == 0) {
ModuleSP module_sp(GetModule());
- if (module_sp)
- {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- if (m_symtab_ap.get() == NULL)
- {
- m_symtab_ap.reset(new Symtab(this));
- std::lock_guard<std::recursive_mutex> symtab_guard(m_symtab_ap->GetMutex());
- ParseSymtab ();
- m_symtab_ap->Finalize ();
+ if (module_sp) {
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ for (uint32_t i = 0; i < m_header.ncmds; ++i) {
+ const lldb::offset_t load_cmd_offset = offset;
+
+ load_command lc;
+ if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL)
+ break;
+ if (lc.cmd == LC_DYSYMTAB) {
+ m_dysymtab.cmd = lc.cmd;
+ m_dysymtab.cmdsize = lc.cmdsize;
+ if (m_data.GetU32(&offset, &m_dysymtab.ilocalsym,
+ (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2) ==
+ NULL) {
+ // Clear m_dysymtab if we were unable to read all items from the
+ // load command
+ ::memset(&m_dysymtab, 0, sizeof(m_dysymtab));
+ }
}
+ offset = load_cmd_offset + lc.cmdsize;
+ }
}
- return m_symtab_ap.get();
+ }
+ if (m_dysymtab.cmd)
+ return m_dysymtab.nlocalsym <= 1;
+ return false;
}
-bool
-ObjectFileMachO::IsStripped ()
-{
- if (m_dysymtab.cmd == 0)
- {
- ModuleSP module_sp(GetModule());
- if (module_sp)
- {
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- for (uint32_t i=0; i<m_header.ncmds; ++i)
- {
- const lldb::offset_t load_cmd_offset = offset;
-
- load_command lc;
- if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL)
- break;
- if (lc.cmd == LC_DYSYMTAB)
- {
- m_dysymtab.cmd = lc.cmd;
- m_dysymtab.cmdsize = lc.cmdsize;
- if (m_data.GetU32 (&offset, &m_dysymtab.ilocalsym, (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2) == NULL)
- {
- // Clear m_dysymtab if we were unable to read all items from the load command
- ::memset (&m_dysymtab, 0, sizeof(m_dysymtab));
- }
- }
- offset = load_cmd_offset + lc.cmdsize;
- }
+void ObjectFileMachO::CreateSections(SectionList &unified_section_list) {
+ if (!m_sections_ap.get()) {
+ m_sections_ap.reset(new SectionList());
+
+ const bool is_dsym = (m_header.filetype == MH_DSYM);
+ lldb::user_id_t segID = 0;
+ lldb::user_id_t sectID = 0;
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ uint32_t i;
+ const bool is_core = GetType() == eTypeCoreFile;
+ // bool dump_sections = false;
+ ModuleSP module_sp(GetModule());
+ // First look up any LC_ENCRYPTION_INFO load commands
+ typedef RangeArray<uint32_t, uint32_t, 8> EncryptedFileRanges;
+ EncryptedFileRanges encrypted_file_ranges;
+ encryption_info_command encryption_cmd;
+ for (i = 0; i < m_header.ncmds; ++i) {
+ const lldb::offset_t load_cmd_offset = offset;
+ if (m_data.GetU32(&offset, &encryption_cmd, 2) == NULL)
+ break;
+
+ // LC_ENCRYPTION_INFO and LC_ENCRYPTION_INFO_64 have the same sizes for
+ // the 3 fields we care about, so treat them the same.
+ if (encryption_cmd.cmd == LC_ENCRYPTION_INFO ||
+ encryption_cmd.cmd == LC_ENCRYPTION_INFO_64) {
+ if (m_data.GetU32(&offset, &encryption_cmd.cryptoff, 3)) {
+ if (encryption_cmd.cryptid != 0) {
+ EncryptedFileRanges::Entry entry;
+ entry.SetRangeBase(encryption_cmd.cryptoff);
+ entry.SetByteSize(encryption_cmd.cryptsize);
+ encrypted_file_ranges.Append(entry);
+ }
}
+ }
+ offset = load_cmd_offset + encryption_cmd.cmdsize;
}
- if (m_dysymtab.cmd)
- return m_dysymtab.nlocalsym <= 1;
- return false;
-}
-void
-ObjectFileMachO::CreateSections (SectionList &unified_section_list)
-{
- if (!m_sections_ap.get())
- {
- m_sections_ap.reset(new SectionList());
-
- const bool is_dsym = (m_header.filetype == MH_DSYM);
- lldb::user_id_t segID = 0;
- lldb::user_id_t sectID = 0;
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- uint32_t i;
- const bool is_core = GetType() == eTypeCoreFile;
- //bool dump_sections = false;
- ModuleSP module_sp (GetModule());
- // First look up any LC_ENCRYPTION_INFO load commands
- typedef RangeArray<uint32_t, uint32_t, 8> EncryptedFileRanges;
- EncryptedFileRanges encrypted_file_ranges;
- encryption_info_command encryption_cmd;
- for (i=0; i<m_header.ncmds; ++i)
- {
- const lldb::offset_t load_cmd_offset = offset;
- if (m_data.GetU32(&offset, &encryption_cmd, 2) == NULL)
- break;
+ bool section_file_addresses_changed = false;
+
+ offset = MachHeaderSizeFromMagic(m_header.magic);
+
+ struct segment_command_64 load_cmd;
+ for (i = 0; i < m_header.ncmds; ++i) {
+ const lldb::offset_t load_cmd_offset = offset;
+ if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
+
+ if (load_cmd.cmd == LC_SEGMENT || load_cmd.cmd == LC_SEGMENT_64) {
+ if (m_data.GetU8(&offset, (uint8_t *)load_cmd.segname, 16)) {
+ bool add_section = true;
+ bool add_to_unified = true;
+ ConstString const_segname(load_cmd.segname,
+ std::min<size_t>(strlen(load_cmd.segname),
+ sizeof(load_cmd.segname)));
+
+ SectionSP unified_section_sp(
+ unified_section_list.FindSectionByName(const_segname));
+ if (is_dsym && unified_section_sp) {
+ if (const_segname == GetSegmentNameLINKEDIT()) {
+ // We need to keep the __LINKEDIT segment private to this object
+ // file only
+ add_to_unified = false;
+ } else {
+ // This is the dSYM file and this section has already been created
+ // by
+ // the object file, no need to create it.
+ add_section = false;
+ }
+ }
+ load_cmd.vmaddr = m_data.GetAddress(&offset);
+ load_cmd.vmsize = m_data.GetAddress(&offset);
+ load_cmd.fileoff = m_data.GetAddress(&offset);
+ load_cmd.filesize = m_data.GetAddress(&offset);
+ if (m_length != 0 && load_cmd.filesize != 0) {
+ if (load_cmd.fileoff > m_length) {
+ // We have a load command that says it extends past the end of the
+ // file. This is likely
+ // a corrupt file. We don't have any way to return an error
+ // condition here (this method
+ // was likely invoked from something like
+ // ObjectFile::GetSectionList()) -- all we can do
+ // is null out the SectionList vector and if a process has been
+ // set up, dump a message
+ // to stdout. The most common case here is core file debugging
+ // with a truncated file.
+ const char *lc_segment_name = load_cmd.cmd == LC_SEGMENT_64
+ ? "LC_SEGMENT_64"
+ : "LC_SEGMENT";
+ module_sp->ReportWarning(
+ "load command %u %s has a fileoff (0x%" PRIx64
+ ") that extends beyond the end of the file (0x%" PRIx64
+ "), ignoring this section",
+ i, lc_segment_name, load_cmd.fileoff, m_length);
+
+ load_cmd.fileoff = 0;
+ load_cmd.filesize = 0;
+ }
- // LC_ENCRYPTION_INFO and LC_ENCRYPTION_INFO_64 have the same sizes for
- // the 3 fields we care about, so treat them the same.
- if (encryption_cmd.cmd == LC_ENCRYPTION_INFO || encryption_cmd.cmd == LC_ENCRYPTION_INFO_64)
- {
- if (m_data.GetU32(&offset, &encryption_cmd.cryptoff, 3))
- {
- if (encryption_cmd.cryptid != 0)
- {
- EncryptedFileRanges::Entry entry;
- entry.SetRangeBase(encryption_cmd.cryptoff);
- entry.SetByteSize(encryption_cmd.cryptsize);
- encrypted_file_ranges.Append(entry);
- }
+ if (load_cmd.fileoff + load_cmd.filesize > m_length) {
+ // We have a load command that says it extends past the end of the
+ // file. This is likely
+ // a corrupt file. We don't have any way to return an error
+ // condition here (this method
+ // was likely invoked from something like
+ // ObjectFile::GetSectionList()) -- all we can do
+ // is null out the SectionList vector and if a process has been
+ // set up, dump a message
+ // to stdout. The most common case here is core file debugging
+ // with a truncated file.
+ const char *lc_segment_name = load_cmd.cmd == LC_SEGMENT_64
+ ? "LC_SEGMENT_64"
+ : "LC_SEGMENT";
+ GetModule()->ReportWarning(
+ "load command %u %s has a fileoff + filesize (0x%" PRIx64
+ ") that extends beyond the end of the file (0x%" PRIx64
+ "), the segment will be truncated to match",
+ i, lc_segment_name, load_cmd.fileoff + load_cmd.filesize,
+ m_length);
+
+ // Tuncase the length
+ load_cmd.filesize = m_length - load_cmd.fileoff;
+ }
+ }
+ if (m_data.GetU32(&offset, &load_cmd.maxprot, 4)) {
+ const uint32_t segment_permissions =
+ ((load_cmd.initprot & VM_PROT_READ) ? ePermissionsReadable
+ : 0) |
+ ((load_cmd.initprot & VM_PROT_WRITE) ? ePermissionsWritable
+ : 0) |
+ ((load_cmd.initprot & VM_PROT_EXECUTE) ? ePermissionsExecutable
+ : 0);
+
+ const bool segment_is_encrypted =
+ (load_cmd.flags & SG_PROTECTED_VERSION_1) != 0;
+
+ // Keep a list of mach segments around in case we need to
+ // get at data that isn't stored in the abstracted Sections.
+ m_mach_segments.push_back(load_cmd);
+
+ // Use a segment ID of the segment index shifted left by 8 so they
+ // never conflict with any of the sections.
+ SectionSP segment_sp;
+ if (add_section && (const_segname || is_core)) {
+ segment_sp.reset(new Section(
+ module_sp, // Module to which this section belongs
+ this, // Object file to which this sections belongs
+ ++segID << 8, // Section ID is the 1 based segment index
+ // shifted right by 8 bits as not to collide
+ // with any of the 256 section IDs that are
+ // possible
+ const_segname, // Name of this section
+ eSectionTypeContainer, // This section is a container of other
+ // sections.
+ load_cmd.vmaddr, // File VM address == addresses as they are
+ // found in the object file
+ load_cmd.vmsize, // VM size in bytes of this section
+ load_cmd.fileoff, // Offset to the data for this section in
+ // the file
+ load_cmd.filesize, // Size in bytes of this section as found
+ // in the file
+ 0, // Segments have no alignment information
+ load_cmd.flags)); // Flags for this section
+
+ segment_sp->SetIsEncrypted(segment_is_encrypted);
+ m_sections_ap->AddSection(segment_sp);
+ segment_sp->SetPermissions(segment_permissions);
+ if (add_to_unified)
+ unified_section_list.AddSection(segment_sp);
+ } else if (unified_section_sp) {
+ if (is_dsym &&
+ unified_section_sp->GetFileAddress() != load_cmd.vmaddr) {
+ // Check to see if the module was read from memory?
+ if (module_sp->GetObjectFile()->GetHeaderAddress().IsValid()) {
+ // We have a module that is in memory and needs to have its
+ // file address adjusted. We need to do this because when we
+ // load a file from memory, its addresses will be slid
+ // already,
+ // yet the addresses in the new symbol file will still be
+ // unslid.
+ // Since everything is stored as section offset, this
+ // shouldn't
+ // cause any problems.
+
+ // Make sure we've parsed the symbol table from the
+ // ObjectFile before we go around changing its Sections.
+ module_sp->GetObjectFile()->GetSymtab();
+ // eh_frame would present the same problems but we parse that
+ // on
+ // a per-function basis as-needed so it's more difficult to
+ // remove its use of the Sections. Realistically, the
+ // environments
+ // where this code path will be taken will not have eh_frame
+ // sections.
+
+ unified_section_sp->SetFileAddress(load_cmd.vmaddr);
+
+ // Notify the module that the section addresses have been
+ // changed once
+ // we're done so any file-address caches can be updated.
+ section_file_addresses_changed = true;
}
+ }
+ m_sections_ap->AddSection(unified_section_sp);
}
- offset = load_cmd_offset + encryption_cmd.cmdsize;
- }
-
- bool section_file_addresses_changed = false;
- offset = MachHeaderSizeFromMagic(m_header.magic);
+ struct section_64 sect64;
+ ::memset(&sect64, 0, sizeof(sect64));
+ // Push a section into our mach sections for the section at
+ // index zero (NO_SECT) if we don't have any mach sections yet...
+ if (m_mach_sections.empty())
+ m_mach_sections.push_back(sect64);
+ uint32_t segment_sect_idx;
+ const lldb::user_id_t first_segment_sectID = sectID + 1;
+
+ const uint32_t num_u32s = load_cmd.cmd == LC_SEGMENT ? 7 : 8;
+ for (segment_sect_idx = 0; segment_sect_idx < load_cmd.nsects;
+ ++segment_sect_idx) {
+ if (m_data.GetU8(&offset, (uint8_t *)sect64.sectname,
+ sizeof(sect64.sectname)) == NULL)
+ break;
+ if (m_data.GetU8(&offset, (uint8_t *)sect64.segname,
+ sizeof(sect64.segname)) == NULL)
+ break;
+ sect64.addr = m_data.GetAddress(&offset);
+ sect64.size = m_data.GetAddress(&offset);
- struct segment_command_64 load_cmd;
- for (i=0; i<m_header.ncmds; ++i)
- {
- const lldb::offset_t load_cmd_offset = offset;
- if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
+ if (m_data.GetU32(&offset, &sect64.offset, num_u32s) == NULL)
break;
- if (load_cmd.cmd == LC_SEGMENT || load_cmd.cmd == LC_SEGMENT_64)
- {
- if (m_data.GetU8(&offset, (uint8_t*)load_cmd.segname, 16))
- {
- bool add_section = true;
- bool add_to_unified = true;
- ConstString const_segname (load_cmd.segname, std::min<size_t>(strlen(load_cmd.segname), sizeof(load_cmd.segname)));
-
- SectionSP unified_section_sp(unified_section_list.FindSectionByName(const_segname));
- if (is_dsym && unified_section_sp)
- {
- if (const_segname == GetSegmentNameLINKEDIT())
- {
- // We need to keep the __LINKEDIT segment private to this object file only
- add_to_unified = false;
- }
- else
- {
- // This is the dSYM file and this section has already been created by
- // the object file, no need to create it.
- add_section = false;
- }
- }
- load_cmd.vmaddr = m_data.GetAddress(&offset);
- load_cmd.vmsize = m_data.GetAddress(&offset);
- load_cmd.fileoff = m_data.GetAddress(&offset);
- load_cmd.filesize = m_data.GetAddress(&offset);
- if (m_length != 0 && load_cmd.filesize != 0)
- {
- if (load_cmd.fileoff > m_length)
- {
- // We have a load command that says it extends past the end of the file. This is likely
- // a corrupt file. We don't have any way to return an error condition here (this method
- // was likely invoked from something like ObjectFile::GetSectionList()) -- all we can do
- // is null out the SectionList vector and if a process has been set up, dump a message
- // to stdout. The most common case here is core file debugging with a truncated file.
- const char *lc_segment_name = load_cmd.cmd == LC_SEGMENT_64 ? "LC_SEGMENT_64" : "LC_SEGMENT";
- module_sp->ReportWarning("load command %u %s has a fileoff (0x%" PRIx64 ") that extends beyond the end of the file (0x%" PRIx64 "), ignoring this section",
- i,
- lc_segment_name,
- load_cmd.fileoff,
- m_length);
-
- load_cmd.fileoff = 0;
- load_cmd.filesize = 0;
- }
-
- if (load_cmd.fileoff + load_cmd.filesize > m_length)
- {
- // We have a load command that says it extends past the end of the file. This is likely
- // a corrupt file. We don't have any way to return an error condition here (this method
- // was likely invoked from something like ObjectFile::GetSectionList()) -- all we can do
- // is null out the SectionList vector and if a process has been set up, dump a message
- // to stdout. The most common case here is core file debugging with a truncated file.
- const char *lc_segment_name = load_cmd.cmd == LC_SEGMENT_64 ? "LC_SEGMENT_64" : "LC_SEGMENT";
- GetModule()->ReportWarning("load command %u %s has a fileoff + filesize (0x%" PRIx64 ") that extends beyond the end of the file (0x%" PRIx64 "), the segment will be truncated to match",
- i,
- lc_segment_name,
- load_cmd.fileoff + load_cmd.filesize,
- m_length);
-
- // Tuncase the length
- load_cmd.filesize = m_length - load_cmd.fileoff;
- }
+ // Keep a list of mach sections around in case we need to
+ // get at data that isn't stored in the abstracted Sections.
+ m_mach_sections.push_back(sect64);
+
+ if (add_section) {
+ ConstString section_name(
+ sect64.sectname, std::min<size_t>(strlen(sect64.sectname),
+ sizeof(sect64.sectname)));
+ if (!const_segname) {
+ // We have a segment with no name so we need to conjure up
+ // segments that correspond to the section's segname if there
+ // isn't already such a section. If there is such a section,
+ // we resize the section so that it spans all sections.
+ // We also mark these sections as fake so address matches
+ // don't
+ // hit if they land in the gaps between the child sections.
+ const_segname.SetTrimmedCStringWithLength(
+ sect64.segname, sizeof(sect64.segname));
+ segment_sp =
+ unified_section_list.FindSectionByName(const_segname);
+ if (segment_sp.get()) {
+ Section *segment = segment_sp.get();
+ // Grow the section size as needed.
+ const lldb::addr_t sect64_min_addr = sect64.addr;
+ const lldb::addr_t sect64_max_addr =
+ sect64_min_addr + sect64.size;
+ const lldb::addr_t curr_seg_byte_size =
+ segment->GetByteSize();
+ const lldb::addr_t curr_seg_min_addr =
+ segment->GetFileAddress();
+ const lldb::addr_t curr_seg_max_addr =
+ curr_seg_min_addr + curr_seg_byte_size;
+ if (sect64_min_addr >= curr_seg_min_addr) {
+ const lldb::addr_t new_seg_byte_size =
+ sect64_max_addr - curr_seg_min_addr;
+ // Only grow the section size if needed
+ if (new_seg_byte_size > curr_seg_byte_size)
+ segment->SetByteSize(new_seg_byte_size);
+ } else {
+ // We need to change the base address of the segment and
+ // adjust the child section offsets for all existing
+ // children.
+ const lldb::addr_t slide_amount =
+ sect64_min_addr - curr_seg_min_addr;
+ segment->Slide(slide_amount, false);
+ segment->GetChildren().Slide(-slide_amount, false);
+ segment->SetByteSize(curr_seg_max_addr - sect64_min_addr);
}
- if (m_data.GetU32(&offset, &load_cmd.maxprot, 4))
- {
- const uint32_t segment_permissions =
- ((load_cmd.initprot & VM_PROT_READ) ? ePermissionsReadable : 0) |
- ((load_cmd.initprot & VM_PROT_WRITE) ? ePermissionsWritable : 0) |
- ((load_cmd.initprot & VM_PROT_EXECUTE) ? ePermissionsExecutable : 0);
-
- const bool segment_is_encrypted = (load_cmd.flags & SG_PROTECTED_VERSION_1) != 0;
-
- // Keep a list of mach segments around in case we need to
- // get at data that isn't stored in the abstracted Sections.
- m_mach_segments.push_back (load_cmd);
-
- // Use a segment ID of the segment index shifted left by 8 so they
- // never conflict with any of the sections.
- SectionSP segment_sp;
- if (add_section && (const_segname || is_core))
- {
- segment_sp.reset(new Section (module_sp, // Module to which this section belongs
- this, // Object file to which this sections belongs
- ++segID << 8, // Section ID is the 1 based segment index shifted right by 8 bits as not to collide with any of the 256 section IDs that are possible
- const_segname, // Name of this section
- eSectionTypeContainer, // This section is a container of other sections.
- load_cmd.vmaddr, // File VM address == addresses as they are found in the object file
- load_cmd.vmsize, // VM size in bytes of this section
- load_cmd.fileoff, // Offset to the data for this section in the file
- load_cmd.filesize, // Size in bytes of this section as found in the file
- 0, // Segments have no alignment information
- load_cmd.flags)); // Flags for this section
-
- segment_sp->SetIsEncrypted (segment_is_encrypted);
- m_sections_ap->AddSection(segment_sp);
- segment_sp->SetPermissions(segment_permissions);
- if (add_to_unified)
- unified_section_list.AddSection(segment_sp);
- }
- else if (unified_section_sp)
- {
- if (is_dsym && unified_section_sp->GetFileAddress() != load_cmd.vmaddr)
- {
- // Check to see if the module was read from memory?
- if (module_sp->GetObjectFile()->GetHeaderAddress().IsValid())
- {
- // We have a module that is in memory and needs to have its
- // file address adjusted. We need to do this because when we
- // load a file from memory, its addresses will be slid already,
- // yet the addresses in the new symbol file will still be unslid.
- // Since everything is stored as section offset, this shouldn't
- // cause any problems.
-
- // Make sure we've parsed the symbol table from the
- // ObjectFile before we go around changing its Sections.
- module_sp->GetObjectFile()->GetSymtab();
- // eh_frame would present the same problems but we parse that on
- // a per-function basis as-needed so it's more difficult to
- // remove its use of the Sections. Realistically, the environments
- // where this code path will be taken will not have eh_frame sections.
-
- unified_section_sp->SetFileAddress(load_cmd.vmaddr);
-
- // Notify the module that the section addresses have been changed once
- // we're done so any file-address caches can be updated.
- section_file_addresses_changed = true;
- }
- }
- m_sections_ap->AddSection(unified_section_sp);
- }
-
- struct section_64 sect64;
- ::memset (&sect64, 0, sizeof(sect64));
- // Push a section into our mach sections for the section at
- // index zero (NO_SECT) if we don't have any mach sections yet...
- if (m_mach_sections.empty())
- m_mach_sections.push_back(sect64);
- uint32_t segment_sect_idx;
- const lldb::user_id_t first_segment_sectID = sectID + 1;
-
-
- const uint32_t num_u32s = load_cmd.cmd == LC_SEGMENT ? 7 : 8;
- for (segment_sect_idx=0; segment_sect_idx<load_cmd.nsects; ++segment_sect_idx)
- {
- if (m_data.GetU8(&offset, (uint8_t*)sect64.sectname, sizeof(sect64.sectname)) == NULL)
- break;
- if (m_data.GetU8(&offset, (uint8_t*)sect64.segname, sizeof(sect64.segname)) == NULL)
- break;
- sect64.addr = m_data.GetAddress(&offset);
- sect64.size = m_data.GetAddress(&offset);
-
- if (m_data.GetU32(&offset, &sect64.offset, num_u32s) == NULL)
- break;
-
- // Keep a list of mach sections around in case we need to
- // get at data that isn't stored in the abstracted Sections.
- m_mach_sections.push_back (sect64);
-
- if (add_section)
- {
- ConstString section_name (sect64.sectname, std::min<size_t>(strlen(sect64.sectname), sizeof(sect64.sectname)));
- if (!const_segname)
- {
- // We have a segment with no name so we need to conjure up
- // segments that correspond to the section's segname if there
- // isn't already such a section. If there is such a section,
- // we resize the section so that it spans all sections.
- // We also mark these sections as fake so address matches don't
- // hit if they land in the gaps between the child sections.
- const_segname.SetTrimmedCStringWithLength(sect64.segname, sizeof(sect64.segname));
- segment_sp = unified_section_list.FindSectionByName (const_segname);
- if (segment_sp.get())
- {
- Section *segment = segment_sp.get();
- // Grow the section size as needed.
- const lldb::addr_t sect64_min_addr = sect64.addr;
- const lldb::addr_t sect64_max_addr = sect64_min_addr + sect64.size;
- const lldb::addr_t curr_seg_byte_size = segment->GetByteSize();
- const lldb::addr_t curr_seg_min_addr = segment->GetFileAddress();
- const lldb::addr_t curr_seg_max_addr = curr_seg_min_addr + curr_seg_byte_size;
- if (sect64_min_addr >= curr_seg_min_addr)
- {
- const lldb::addr_t new_seg_byte_size = sect64_max_addr - curr_seg_min_addr;
- // Only grow the section size if needed
- if (new_seg_byte_size > curr_seg_byte_size)
- segment->SetByteSize (new_seg_byte_size);
- }
- else
- {
- // We need to change the base address of the segment and
- // adjust the child section offsets for all existing children.
- const lldb::addr_t slide_amount = sect64_min_addr - curr_seg_min_addr;
- segment->Slide(slide_amount, false);
- segment->GetChildren().Slide(-slide_amount, false);
- segment->SetByteSize (curr_seg_max_addr - sect64_min_addr);
- }
-
- // Grow the section size as needed.
- if (sect64.offset)
- {
- const lldb::addr_t segment_min_file_offset = segment->GetFileOffset();
- const lldb::addr_t segment_max_file_offset = segment_min_file_offset + segment->GetFileSize();
-
- const lldb::addr_t section_min_file_offset = sect64.offset;
- const lldb::addr_t section_max_file_offset = section_min_file_offset + sect64.size;
- const lldb::addr_t new_file_offset = std::min (section_min_file_offset, segment_min_file_offset);
- const lldb::addr_t new_file_size = std::max (section_max_file_offset, segment_max_file_offset) - new_file_offset;
- segment->SetFileOffset (new_file_offset);
- segment->SetFileSize (new_file_size);
- }
- }
- else
- {
- // Create a fake section for the section's named segment
- segment_sp.reset(new Section (segment_sp, // Parent section
- module_sp, // Module to which this section belongs
- this, // Object file to which this section belongs
- ++segID << 8, // Section ID is the 1 based segment index shifted right by 8 bits as not to collide with any of the 256 section IDs that are possible
- const_segname, // Name of this section
- eSectionTypeContainer, // This section is a container of other sections.
- sect64.addr, // File VM address == addresses as they are found in the object file
- sect64.size, // VM size in bytes of this section
- sect64.offset, // Offset to the data for this section in the file
- sect64.offset ? sect64.size : 0, // Size in bytes of this section as found in the file
- sect64.align,
- load_cmd.flags)); // Flags for this section
- segment_sp->SetIsFake(true);
- segment_sp->SetPermissions(segment_permissions);
- m_sections_ap->AddSection(segment_sp);
- if (add_to_unified)
- unified_section_list.AddSection(segment_sp);
- segment_sp->SetIsEncrypted (segment_is_encrypted);
- }
- }
- assert (segment_sp.get());
- lldb::SectionType sect_type = eSectionTypeOther;
-
- if (sect64.flags & (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS))
- sect_type = eSectionTypeCode;
- else
- {
- uint32_t mach_sect_type = sect64.flags & SECTION_TYPE;
- static ConstString g_sect_name_objc_data ("__objc_data");
- static ConstString g_sect_name_objc_msgrefs ("__objc_msgrefs");
- static ConstString g_sect_name_objc_selrefs ("__objc_selrefs");
- static ConstString g_sect_name_objc_classrefs ("__objc_classrefs");
- static ConstString g_sect_name_objc_superrefs ("__objc_superrefs");
- static ConstString g_sect_name_objc_const ("__objc_const");
- static ConstString g_sect_name_objc_classlist ("__objc_classlist");
- static ConstString g_sect_name_cfstring ("__cfstring");
-
- static ConstString g_sect_name_dwarf_debug_abbrev ("__debug_abbrev");
- static ConstString g_sect_name_dwarf_debug_aranges ("__debug_aranges");
- static ConstString g_sect_name_dwarf_debug_frame ("__debug_frame");
- static ConstString g_sect_name_dwarf_debug_info ("__debug_info");
- static ConstString g_sect_name_dwarf_debug_line ("__debug_line");
- static ConstString g_sect_name_dwarf_debug_loc ("__debug_loc");
- static ConstString g_sect_name_dwarf_debug_macinfo ("__debug_macinfo");
- static ConstString g_sect_name_dwarf_debug_pubnames ("__debug_pubnames");
- static ConstString g_sect_name_dwarf_debug_pubtypes ("__debug_pubtypes");
- static ConstString g_sect_name_dwarf_debug_ranges ("__debug_ranges");
- static ConstString g_sect_name_dwarf_debug_str ("__debug_str");
- static ConstString g_sect_name_dwarf_apple_names ("__apple_names");
- static ConstString g_sect_name_dwarf_apple_types ("__apple_types");
- static ConstString g_sect_name_dwarf_apple_namespaces ("__apple_namespac");
- static ConstString g_sect_name_dwarf_apple_objc ("__apple_objc");
- static ConstString g_sect_name_eh_frame ("__eh_frame");
- static ConstString g_sect_name_compact_unwind ("__unwind_info");
- static ConstString g_sect_name_text ("__text");
- static ConstString g_sect_name_data ("__data");
- static ConstString g_sect_name_go_symtab ("__gosymtab");
-
- if (section_name == g_sect_name_dwarf_debug_abbrev)
- sect_type = eSectionTypeDWARFDebugAbbrev;
- else if (section_name == g_sect_name_dwarf_debug_aranges)
- sect_type = eSectionTypeDWARFDebugAranges;
- else if (section_name == g_sect_name_dwarf_debug_frame)
- sect_type = eSectionTypeDWARFDebugFrame;
- else if (section_name == g_sect_name_dwarf_debug_info)
- sect_type = eSectionTypeDWARFDebugInfo;
- else if (section_name == g_sect_name_dwarf_debug_line)
- sect_type = eSectionTypeDWARFDebugLine;
- else if (section_name == g_sect_name_dwarf_debug_loc)
- sect_type = eSectionTypeDWARFDebugLoc;
- else if (section_name == g_sect_name_dwarf_debug_macinfo)
- sect_type = eSectionTypeDWARFDebugMacInfo;
- else if (section_name == g_sect_name_dwarf_debug_pubnames)
- sect_type = eSectionTypeDWARFDebugPubNames;
- else if (section_name == g_sect_name_dwarf_debug_pubtypes)
- sect_type = eSectionTypeDWARFDebugPubTypes;
- else if (section_name == g_sect_name_dwarf_debug_ranges)
- sect_type = eSectionTypeDWARFDebugRanges;
- else if (section_name == g_sect_name_dwarf_debug_str)
- sect_type = eSectionTypeDWARFDebugStr;
- else if (section_name == g_sect_name_dwarf_apple_names)
- sect_type = eSectionTypeDWARFAppleNames;
- else if (section_name == g_sect_name_dwarf_apple_types)
- sect_type = eSectionTypeDWARFAppleTypes;
- else if (section_name == g_sect_name_dwarf_apple_namespaces)
- sect_type = eSectionTypeDWARFAppleNamespaces;
- else if (section_name == g_sect_name_dwarf_apple_objc)
- sect_type = eSectionTypeDWARFAppleObjC;
- else if (section_name == g_sect_name_objc_selrefs)
- sect_type = eSectionTypeDataCStringPointers;
- else if (section_name == g_sect_name_objc_msgrefs)
- sect_type = eSectionTypeDataObjCMessageRefs;
- else if (section_name == g_sect_name_eh_frame)
- sect_type = eSectionTypeEHFrame;
- else if (section_name == g_sect_name_compact_unwind)
- sect_type = eSectionTypeCompactUnwind;
- else if (section_name == g_sect_name_cfstring)
- sect_type = eSectionTypeDataObjCCFStrings;
- else if (section_name == g_sect_name_go_symtab)
- sect_type = eSectionTypeGoSymtab;
- else if (section_name == g_sect_name_objc_data ||
- section_name == g_sect_name_objc_classrefs ||
- section_name == g_sect_name_objc_superrefs ||
- section_name == g_sect_name_objc_const ||
- section_name == g_sect_name_objc_classlist)
- {
- sect_type = eSectionTypeDataPointers;
- }
-
- if (sect_type == eSectionTypeOther)
- {
- switch (mach_sect_type)
- {
- // TODO: categorize sections by other flags for regular sections
- case S_REGULAR:
- if (section_name == g_sect_name_text)
- sect_type = eSectionTypeCode;
- else if (section_name == g_sect_name_data)
- sect_type = eSectionTypeData;
- else
- sect_type = eSectionTypeOther;
- break;
- case S_ZEROFILL: sect_type = eSectionTypeZeroFill; break;
- case S_CSTRING_LITERALS: sect_type = eSectionTypeDataCString; break; // section with only literal C strings
- case S_4BYTE_LITERALS: sect_type = eSectionTypeData4; break; // section with only 4 byte literals
- case S_8BYTE_LITERALS: sect_type = eSectionTypeData8; break; // section with only 8 byte literals
- case S_LITERAL_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only pointers to literals
- case S_NON_LAZY_SYMBOL_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only non-lazy symbol pointers
- case S_LAZY_SYMBOL_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only lazy symbol pointers
- case S_SYMBOL_STUBS: sect_type = eSectionTypeCode; break; // section with only symbol stubs, byte size of stub in the reserved2 field
- case S_MOD_INIT_FUNC_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only function pointers for initialization
- case S_MOD_TERM_FUNC_POINTERS: sect_type = eSectionTypeDataPointers; break; // section with only function pointers for termination
- case S_COALESCED: sect_type = eSectionTypeOther; break;
- case S_GB_ZEROFILL: sect_type = eSectionTypeZeroFill; break;
- case S_INTERPOSING: sect_type = eSectionTypeCode; break; // section with only pairs of function pointers for interposing
- case S_16BYTE_LITERALS: sect_type = eSectionTypeData16; break; // section with only 16 byte literals
- case S_DTRACE_DOF: sect_type = eSectionTypeDebug; break;
- case S_LAZY_DYLIB_SYMBOL_POINTERS: sect_type = eSectionTypeDataPointers; break;
- default: break;
- }
- }
- }
-
- SectionSP section_sp(new Section (segment_sp,
- module_sp,
- this,
- ++sectID,
- section_name,
- sect_type,
- sect64.addr - segment_sp->GetFileAddress(),
- sect64.size,
- sect64.offset,
- sect64.offset == 0 ? 0 : sect64.size,
- sect64.align,
- sect64.flags));
- // Set the section to be encrypted to match the segment
-
- bool section_is_encrypted = false;
- if (!segment_is_encrypted && load_cmd.filesize != 0)
- section_is_encrypted = encrypted_file_ranges.FindEntryThatContains(sect64.offset) != NULL;
-
- section_sp->SetIsEncrypted (segment_is_encrypted || section_is_encrypted);
- section_sp->SetPermissions(segment_permissions);
- segment_sp->GetChildren().AddSection(section_sp);
-
- if (segment_sp->IsFake())
- {
- segment_sp.reset();
- const_segname.Clear();
- }
- }
- }
- if (segment_sp && is_dsym)
- {
- if (first_segment_sectID <= sectID)
- {
- lldb::user_id_t sect_uid;
- for (sect_uid = first_segment_sectID; sect_uid <= sectID; ++sect_uid)
- {
- SectionSP curr_section_sp(segment_sp->GetChildren().FindSectionByID (sect_uid));
- SectionSP next_section_sp;
- if (sect_uid + 1 <= sectID)
- next_section_sp = segment_sp->GetChildren().FindSectionByID (sect_uid+1);
-
- if (curr_section_sp.get())
- {
- if (curr_section_sp->GetByteSize() == 0)
- {
- if (next_section_sp.get() != NULL)
- curr_section_sp->SetByteSize ( next_section_sp->GetFileAddress() - curr_section_sp->GetFileAddress() );
- else
- curr_section_sp->SetByteSize ( load_cmd.vmsize );
- }
- }
- }
- }
- }
+ // Grow the section size as needed.
+ if (sect64.offset) {
+ const lldb::addr_t segment_min_file_offset =
+ segment->GetFileOffset();
+ const lldb::addr_t segment_max_file_offset =
+ segment_min_file_offset + segment->GetFileSize();
+
+ const lldb::addr_t section_min_file_offset =
+ sect64.offset;
+ const lldb::addr_t section_max_file_offset =
+ section_min_file_offset + sect64.size;
+ const lldb::addr_t new_file_offset = std::min(
+ section_min_file_offset, segment_min_file_offset);
+ const lldb::addr_t new_file_size =
+ std::max(section_max_file_offset,
+ segment_max_file_offset) -
+ new_file_offset;
+ segment->SetFileOffset(new_file_offset);
+ segment->SetFileSize(new_file_size);
+ }
+ } else {
+ // Create a fake section for the section's named segment
+ segment_sp.reset(new Section(
+ segment_sp, // Parent section
+ module_sp, // Module to which this section belongs
+ this, // Object file to which this section belongs
+ ++segID << 8, // Section ID is the 1 based segment index
+ // shifted right by 8 bits as not to
+ // collide with any of the 256 section IDs
+ // that are possible
+ const_segname, // Name of this section
+ eSectionTypeContainer, // This section is a container of
+ // other sections.
+ sect64.addr, // File VM address == addresses as they are
+ // found in the object file
+ sect64.size, // VM size in bytes of this section
+ sect64.offset, // Offset to the data for this section in
+ // the file
+ sect64.offset ? sect64.size : 0, // Size in bytes of
+ // this section as
+ // found in the file
+ sect64.align,
+ load_cmd.flags)); // Flags for this section
+ segment_sp->SetIsFake(true);
+ segment_sp->SetPermissions(segment_permissions);
+ m_sections_ap->AddSection(segment_sp);
+ if (add_to_unified)
+ unified_section_list.AddSection(segment_sp);
+ segment_sp->SetIsEncrypted(segment_is_encrypted);
+ }
+ }
+ assert(segment_sp.get());
+
+ lldb::SectionType sect_type = eSectionTypeOther;
+
+ if (sect64.flags &
+ (S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS))
+ sect_type = eSectionTypeCode;
+ else {
+ uint32_t mach_sect_type = sect64.flags & SECTION_TYPE;
+ static ConstString g_sect_name_objc_data("__objc_data");
+ static ConstString g_sect_name_objc_msgrefs("__objc_msgrefs");
+ static ConstString g_sect_name_objc_selrefs("__objc_selrefs");
+ static ConstString g_sect_name_objc_classrefs(
+ "__objc_classrefs");
+ static ConstString g_sect_name_objc_superrefs(
+ "__objc_superrefs");
+ static ConstString g_sect_name_objc_const("__objc_const");
+ static ConstString g_sect_name_objc_classlist(
+ "__objc_classlist");
+ static ConstString g_sect_name_cfstring("__cfstring");
+
+ static ConstString g_sect_name_dwarf_debug_abbrev(
+ "__debug_abbrev");
+ static ConstString g_sect_name_dwarf_debug_aranges(
+ "__debug_aranges");
+ static ConstString g_sect_name_dwarf_debug_frame(
+ "__debug_frame");
+ static ConstString g_sect_name_dwarf_debug_info(
+ "__debug_info");
+ static ConstString g_sect_name_dwarf_debug_line(
+ "__debug_line");
+ static ConstString g_sect_name_dwarf_debug_loc("__debug_loc");
+ static ConstString g_sect_name_dwarf_debug_macinfo(
+ "__debug_macinfo");
+ static ConstString g_sect_name_dwarf_debug_pubnames(
+ "__debug_pubnames");
+ static ConstString g_sect_name_dwarf_debug_pubtypes(
+ "__debug_pubtypes");
+ static ConstString g_sect_name_dwarf_debug_ranges(
+ "__debug_ranges");
+ static ConstString g_sect_name_dwarf_debug_str("__debug_str");
+ static ConstString g_sect_name_dwarf_apple_names(
+ "__apple_names");
+ static ConstString g_sect_name_dwarf_apple_types(
+ "__apple_types");
+ static ConstString g_sect_name_dwarf_apple_namespaces(
+ "__apple_namespac");
+ static ConstString g_sect_name_dwarf_apple_objc(
+ "__apple_objc");
+ static ConstString g_sect_name_eh_frame("__eh_frame");
+ static ConstString g_sect_name_compact_unwind(
+ "__unwind_info");
+ static ConstString g_sect_name_text("__text");
+ static ConstString g_sect_name_data("__data");
+ static ConstString g_sect_name_go_symtab("__gosymtab");
+
+ if (section_name == g_sect_name_dwarf_debug_abbrev)
+ sect_type = eSectionTypeDWARFDebugAbbrev;
+ else if (section_name == g_sect_name_dwarf_debug_aranges)
+ sect_type = eSectionTypeDWARFDebugAranges;
+ else if (section_name == g_sect_name_dwarf_debug_frame)
+ sect_type = eSectionTypeDWARFDebugFrame;
+ else if (section_name == g_sect_name_dwarf_debug_info)
+ sect_type = eSectionTypeDWARFDebugInfo;
+ else if (section_name == g_sect_name_dwarf_debug_line)
+ sect_type = eSectionTypeDWARFDebugLine;
+ else if (section_name == g_sect_name_dwarf_debug_loc)
+ sect_type = eSectionTypeDWARFDebugLoc;
+ else if (section_name == g_sect_name_dwarf_debug_macinfo)
+ sect_type = eSectionTypeDWARFDebugMacInfo;
+ else if (section_name == g_sect_name_dwarf_debug_pubnames)
+ sect_type = eSectionTypeDWARFDebugPubNames;
+ else if (section_name == g_sect_name_dwarf_debug_pubtypes)
+ sect_type = eSectionTypeDWARFDebugPubTypes;
+ else if (section_name == g_sect_name_dwarf_debug_ranges)
+ sect_type = eSectionTypeDWARFDebugRanges;
+ else if (section_name == g_sect_name_dwarf_debug_str)
+ sect_type = eSectionTypeDWARFDebugStr;
+ else if (section_name == g_sect_name_dwarf_apple_names)
+ sect_type = eSectionTypeDWARFAppleNames;
+ else if (section_name == g_sect_name_dwarf_apple_types)
+ sect_type = eSectionTypeDWARFAppleTypes;
+ else if (section_name == g_sect_name_dwarf_apple_namespaces)
+ sect_type = eSectionTypeDWARFAppleNamespaces;
+ else if (section_name == g_sect_name_dwarf_apple_objc)
+ sect_type = eSectionTypeDWARFAppleObjC;
+ else if (section_name == g_sect_name_objc_selrefs)
+ sect_type = eSectionTypeDataCStringPointers;
+ else if (section_name == g_sect_name_objc_msgrefs)
+ sect_type = eSectionTypeDataObjCMessageRefs;
+ else if (section_name == g_sect_name_eh_frame)
+ sect_type = eSectionTypeEHFrame;
+ else if (section_name == g_sect_name_compact_unwind)
+ sect_type = eSectionTypeCompactUnwind;
+ else if (section_name == g_sect_name_cfstring)
+ sect_type = eSectionTypeDataObjCCFStrings;
+ else if (section_name == g_sect_name_go_symtab)
+ sect_type = eSectionTypeGoSymtab;
+ else if (section_name == g_sect_name_objc_data ||
+ section_name == g_sect_name_objc_classrefs ||
+ section_name == g_sect_name_objc_superrefs ||
+ section_name == g_sect_name_objc_const ||
+ section_name == g_sect_name_objc_classlist) {
+ sect_type = eSectionTypeDataPointers;
+ }
+
+ if (sect_type == eSectionTypeOther) {
+ switch (mach_sect_type) {
+ // TODO: categorize sections by other flags for regular
+ // sections
+ case S_REGULAR:
+ if (section_name == g_sect_name_text)
+ sect_type = eSectionTypeCode;
+ else if (section_name == g_sect_name_data)
+ sect_type = eSectionTypeData;
+ else
+ sect_type = eSectionTypeOther;
+ break;
+ case S_ZEROFILL:
+ sect_type = eSectionTypeZeroFill;
+ break;
+ case S_CSTRING_LITERALS:
+ sect_type = eSectionTypeDataCString;
+ break; // section with only literal C strings
+ case S_4BYTE_LITERALS:
+ sect_type = eSectionTypeData4;
+ break; // section with only 4 byte literals
+ case S_8BYTE_LITERALS:
+ sect_type = eSectionTypeData8;
+ break; // section with only 8 byte literals
+ case S_LITERAL_POINTERS:
+ sect_type = eSectionTypeDataPointers;
+ break; // section with only pointers to literals
+ case S_NON_LAZY_SYMBOL_POINTERS:
+ sect_type = eSectionTypeDataPointers;
+ break; // section with only non-lazy symbol pointers
+ case S_LAZY_SYMBOL_POINTERS:
+ sect_type = eSectionTypeDataPointers;
+ break; // section with only lazy symbol pointers
+ case S_SYMBOL_STUBS:
+ sect_type = eSectionTypeCode;
+ break; // section with only symbol stubs, byte size of
+ // stub in the reserved2 field
+ case S_MOD_INIT_FUNC_POINTERS:
+ sect_type = eSectionTypeDataPointers;
+ break; // section with only function pointers for
+ // initialization
+ case S_MOD_TERM_FUNC_POINTERS:
+ sect_type = eSectionTypeDataPointers;
+ break; // section with only function pointers for
+ // termination
+ case S_COALESCED:
+ sect_type = eSectionTypeOther;
+ break;
+ case S_GB_ZEROFILL:
+ sect_type = eSectionTypeZeroFill;
+ break;
+ case S_INTERPOSING:
+ sect_type = eSectionTypeCode;
+ break; // section with only pairs of function pointers for
+ // interposing
+ case S_16BYTE_LITERALS:
+ sect_type = eSectionTypeData16;
+ break; // section with only 16 byte literals
+ case S_DTRACE_DOF:
+ sect_type = eSectionTypeDebug;
+ break;
+ case S_LAZY_DYLIB_SYMBOL_POINTERS:
+ sect_type = eSectionTypeDataPointers;
+ break;
+ default:
+ break;
}
+ }
}
+
+ SectionSP section_sp(new Section(
+ segment_sp, module_sp, this, ++sectID, section_name,
+ sect_type, sect64.addr - segment_sp->GetFileAddress(),
+ sect64.size, sect64.offset,
+ sect64.offset == 0 ? 0 : sect64.size, sect64.align,
+ sect64.flags));
+ // Set the section to be encrypted to match the segment
+
+ bool section_is_encrypted = false;
+ if (!segment_is_encrypted && load_cmd.filesize != 0)
+ section_is_encrypted =
+ encrypted_file_ranges.FindEntryThatContains(
+ sect64.offset) != NULL;
+
+ section_sp->SetIsEncrypted(segment_is_encrypted ||
+ section_is_encrypted);
+ section_sp->SetPermissions(segment_permissions);
+ segment_sp->GetChildren().AddSection(section_sp);
+
+ if (segment_sp->IsFake()) {
+ segment_sp.reset();
+ const_segname.Clear();
+ }
+ }
}
- else if (load_cmd.cmd == LC_DYSYMTAB)
- {
- m_dysymtab.cmd = load_cmd.cmd;
- m_dysymtab.cmdsize = load_cmd.cmdsize;
- m_data.GetU32 (&offset, &m_dysymtab.ilocalsym, (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2);
+ if (segment_sp && is_dsym) {
+ if (first_segment_sectID <= sectID) {
+ lldb::user_id_t sect_uid;
+ for (sect_uid = first_segment_sectID; sect_uid <= sectID;
+ ++sect_uid) {
+ SectionSP curr_section_sp(
+ segment_sp->GetChildren().FindSectionByID(sect_uid));
+ SectionSP next_section_sp;
+ if (sect_uid + 1 <= sectID)
+ next_section_sp =
+ segment_sp->GetChildren().FindSectionByID(sect_uid + 1);
+
+ if (curr_section_sp.get()) {
+ if (curr_section_sp->GetByteSize() == 0) {
+ if (next_section_sp.get() != NULL)
+ curr_section_sp->SetByteSize(
+ next_section_sp->GetFileAddress() -
+ curr_section_sp->GetFileAddress());
+ else
+ curr_section_sp->SetByteSize(load_cmd.vmsize);
+ }
+ }
+ }
+ }
}
-
- offset = load_cmd_offset + load_cmd.cmdsize;
+ }
}
+ } else if (load_cmd.cmd == LC_DYSYMTAB) {
+ m_dysymtab.cmd = load_cmd.cmd;
+ m_dysymtab.cmdsize = load_cmd.cmdsize;
+ m_data.GetU32(&offset, &m_dysymtab.ilocalsym,
+ (sizeof(m_dysymtab) / sizeof(uint32_t)) - 2);
+ }
+
+ offset = load_cmd_offset + load_cmd.cmdsize;
+ }
-
- if (section_file_addresses_changed && module_sp.get())
- {
- module_sp->SectionFileAddressesChanged();
- }
+ if (section_file_addresses_changed && module_sp.get()) {
+ module_sp->SectionFileAddressesChanged();
}
+ }
}
-class MachSymtabSectionInfo
-{
+class MachSymtabSectionInfo {
public:
- MachSymtabSectionInfo (SectionList *section_list) :
- m_section_list (section_list),
- m_section_infos()
- {
- // Get the number of sections down to a depth of 1 to include
- // all segments and their sections, but no other sections that
- // may be added for debug map or
- m_section_infos.resize(section_list->GetNumSections(1));
- }
-
- SectionSP
- GetSection (uint8_t n_sect, addr_t file_addr)
- {
- if (n_sect == 0)
- return SectionSP();
- if (n_sect < m_section_infos.size())
- {
- if (!m_section_infos[n_sect].section_sp)
- {
- SectionSP section_sp (m_section_list->FindSectionByID (n_sect));
- m_section_infos[n_sect].section_sp = section_sp;
- if (section_sp)
- {
- m_section_infos[n_sect].vm_range.SetBaseAddress (section_sp->GetFileAddress());
- m_section_infos[n_sect].vm_range.SetByteSize (section_sp->GetByteSize());
- }
- else
- {
- Host::SystemLog (Host::eSystemLogError, "error: unable to find section for section %u\n", n_sect);
- }
- }
- if (m_section_infos[n_sect].vm_range.Contains(file_addr))
- {
- // Symbol is in section.
- return m_section_infos[n_sect].section_sp;
- }
- else if (m_section_infos[n_sect].vm_range.GetByteSize () == 0 &&
- m_section_infos[n_sect].vm_range.GetBaseAddress() == file_addr)
- {
- // Symbol is in section with zero size, but has the same start
- // address as the section. This can happen with linker symbols
- // (symbols that start with the letter 'l' or 'L'.
- return m_section_infos[n_sect].section_sp;
- }
+ MachSymtabSectionInfo(SectionList *section_list)
+ : m_section_list(section_list), m_section_infos() {
+ // Get the number of sections down to a depth of 1 to include
+ // all segments and their sections, but no other sections that
+ // may be added for debug map or
+ m_section_infos.resize(section_list->GetNumSections(1));
+ }
+
+ SectionSP GetSection(uint8_t n_sect, addr_t file_addr) {
+ if (n_sect == 0)
+ return SectionSP();
+ if (n_sect < m_section_infos.size()) {
+ if (!m_section_infos[n_sect].section_sp) {
+ SectionSP section_sp(m_section_list->FindSectionByID(n_sect));
+ m_section_infos[n_sect].section_sp = section_sp;
+ if (section_sp) {
+ m_section_infos[n_sect].vm_range.SetBaseAddress(
+ section_sp->GetFileAddress());
+ m_section_infos[n_sect].vm_range.SetByteSize(
+ section_sp->GetByteSize());
+ } else {
+ Host::SystemLog(Host::eSystemLogError,
+ "error: unable to find section for section %u\n",
+ n_sect);
}
- return m_section_list->FindSectionContainingFileAddress(file_addr);
+ }
+ if (m_section_infos[n_sect].vm_range.Contains(file_addr)) {
+ // Symbol is in section.
+ return m_section_infos[n_sect].section_sp;
+ } else if (m_section_infos[n_sect].vm_range.GetByteSize() == 0 &&
+ m_section_infos[n_sect].vm_range.GetBaseAddress() ==
+ file_addr) {
+ // Symbol is in section with zero size, but has the same start
+ // address as the section. This can happen with linker symbols
+ // (symbols that start with the letter 'l' or 'L'.
+ return m_section_infos[n_sect].section_sp;
+ }
}
+ return m_section_list->FindSectionContainingFileAddress(file_addr);
+ }
protected:
- struct SectionInfo
- {
- SectionInfo () :
- vm_range(),
- section_sp ()
- {
- }
-
- VMRange vm_range;
- SectionSP section_sp;
- };
- SectionList *m_section_list;
- std::vector<SectionInfo> m_section_infos;
+ struct SectionInfo {
+ SectionInfo() : vm_range(), section_sp() {}
+
+ VMRange vm_range;
+ SectionSP section_sp;
+ };
+ SectionList *m_section_list;
+ std::vector<SectionInfo> m_section_infos;
};
-struct TrieEntry
-{
- TrieEntry () :
- name(),
- address(LLDB_INVALID_ADDRESS),
- flags (0),
- other(0),
- import_name()
- {
- }
-
- void
- Clear ()
- {
- name.Clear();
- address = LLDB_INVALID_ADDRESS;
- flags = 0;
- other = 0;
- import_name.Clear();
- }
-
- void
- Dump () const
- {
- printf ("0x%16.16llx 0x%16.16llx 0x%16.16llx \"%s\"",
- static_cast<unsigned long long>(address),
- static_cast<unsigned long long>(flags),
- static_cast<unsigned long long>(other), name.GetCString());
- if (import_name)
- printf (" -> \"%s\"\n", import_name.GetCString());
- else
- printf ("\n");
- }
- ConstString name;
- uint64_t address;
- uint64_t flags;
- uint64_t other;
- ConstString import_name;
+struct TrieEntry {
+ TrieEntry()
+ : name(), address(LLDB_INVALID_ADDRESS), flags(0), other(0),
+ import_name() {}
+
+ void Clear() {
+ name.Clear();
+ address = LLDB_INVALID_ADDRESS;
+ flags = 0;
+ other = 0;
+ import_name.Clear();
+ }
+
+ void Dump() const {
+ printf("0x%16.16llx 0x%16.16llx 0x%16.16llx \"%s\"",
+ static_cast<unsigned long long>(address),
+ static_cast<unsigned long long>(flags),
+ static_cast<unsigned long long>(other), name.GetCString());
+ if (import_name)
+ printf(" -> \"%s\"\n", import_name.GetCString());
+ else
+ printf("\n");
+ }
+ ConstString name;
+ uint64_t address;
+ uint64_t flags;
+ uint64_t other;
+ ConstString import_name;
};
-struct TrieEntryWithOffset
-{
- lldb::offset_t nodeOffset;
- TrieEntry entry;
+struct TrieEntryWithOffset {
+ lldb::offset_t nodeOffset;
+ TrieEntry entry;
- TrieEntryWithOffset (lldb::offset_t offset) :
- nodeOffset (offset),
- entry()
- {
- }
+ TrieEntryWithOffset(lldb::offset_t offset) : nodeOffset(offset), entry() {}
- void
- Dump (uint32_t idx) const
- {
- printf ("[%3u] 0x%16.16llx: ", idx,
- static_cast<unsigned long long>(nodeOffset));
- entry.Dump();
- }
+ void Dump(uint32_t idx) const {
+ printf("[%3u] 0x%16.16llx: ", idx,
+ static_cast<unsigned long long>(nodeOffset));
+ entry.Dump();
+ }
- bool
- operator<(const TrieEntryWithOffset& other) const
- {
- return ( nodeOffset < other.nodeOffset );
- }
+ bool operator<(const TrieEntryWithOffset &other) const {
+ return (nodeOffset < other.nodeOffset);
+ }
};
-static bool
-ParseTrieEntries (DataExtractor &data,
- lldb::offset_t offset,
- const bool is_arm,
- std::vector<llvm::StringRef> &nameSlices,
- std::set<lldb::addr_t> &resolver_addresses,
- std::vector<TrieEntryWithOffset>& output)
-{
- if (!data.ValidOffset(offset))
- return true;
-
- const uint64_t terminalSize = data.GetULEB128(&offset);
- lldb::offset_t children_offset = offset + terminalSize;
- if ( terminalSize != 0 ) {
- TrieEntryWithOffset e (offset);
- e.entry.flags = data.GetULEB128(&offset);
- const char *import_name = NULL;
- if ( e.entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT ) {
- e.entry.address = 0;
- e.entry.other = data.GetULEB128(&offset); // dylib ordinal
- import_name = data.GetCStr(&offset);
- }
- else {
- e.entry.address = data.GetULEB128(&offset);
- if ( e.entry.flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER )
- {
- e.entry.other = data.GetULEB128(&offset);
- uint64_t resolver_addr = e.entry.other;
- if (is_arm)
- resolver_addr &= THUMB_ADDRESS_BIT_MASK;
- resolver_addresses.insert(resolver_addr);
- }
- else
- e.entry.other = 0;
- }
- // Only add symbols that are reexport symbols with a valid import name
- if (EXPORT_SYMBOL_FLAGS_REEXPORT & e.entry.flags && import_name && import_name[0])
- {
- std::string name;
- if (!nameSlices.empty())
- {
- for (auto name_slice: nameSlices)
- name.append(name_slice.data(), name_slice.size());
- }
- if (name.size() > 1)
- {
- // Skip the leading '_'
- e.entry.name.SetCStringWithLength(name.c_str() + 1,name.size() - 1);
- }
- if (import_name)
- {
- // Skip the leading '_'
- e.entry.import_name.SetCString(import_name+1);
- }
- output.push_back(e);
- }
- }
-
- const uint8_t childrenCount = data.GetU8(&children_offset);
- for (uint8_t i=0; i < childrenCount; ++i) {
- const char *cstr = data.GetCStr(&children_offset);
- if (cstr)
- nameSlices.push_back(llvm::StringRef(cstr));
- else
- return false; // Corrupt data
- lldb::offset_t childNodeOffset = data.GetULEB128(&children_offset);
- if (childNodeOffset)
- {
- if (!ParseTrieEntries(data,
- childNodeOffset,
- is_arm,
- nameSlices,
- resolver_addresses,
- output))
- {
- return false;
- }
- }
- nameSlices.pop_back();
- }
+static bool ParseTrieEntries(DataExtractor &data, lldb::offset_t offset,
+ const bool is_arm,
+ std::vector<llvm::StringRef> &nameSlices,
+ std::set<lldb::addr_t> &resolver_addresses,
+ std::vector<TrieEntryWithOffset> &output) {
+ if (!data.ValidOffset(offset))
return true;
+
+ const uint64_t terminalSize = data.GetULEB128(&offset);
+ lldb::offset_t children_offset = offset + terminalSize;
+ if (terminalSize != 0) {
+ TrieEntryWithOffset e(offset);
+ e.entry.flags = data.GetULEB128(&offset);
+ const char *import_name = NULL;
+ if (e.entry.flags & EXPORT_SYMBOL_FLAGS_REEXPORT) {
+ e.entry.address = 0;
+ e.entry.other = data.GetULEB128(&offset); // dylib ordinal
+ import_name = data.GetCStr(&offset);
+ } else {
+ e.entry.address = data.GetULEB128(&offset);
+ if (e.entry.flags & EXPORT_SYMBOL_FLAGS_STUB_AND_RESOLVER) {
+ e.entry.other = data.GetULEB128(&offset);
+ uint64_t resolver_addr = e.entry.other;
+ if (is_arm)
+ resolver_addr &= THUMB_ADDRESS_BIT_MASK;
+ resolver_addresses.insert(resolver_addr);
+ } else
+ e.entry.other = 0;
+ }
+ // Only add symbols that are reexport symbols with a valid import name
+ if (EXPORT_SYMBOL_FLAGS_REEXPORT & e.entry.flags && import_name &&
+ import_name[0]) {
+ std::string name;
+ if (!nameSlices.empty()) {
+ for (auto name_slice : nameSlices)
+ name.append(name_slice.data(), name_slice.size());
+ }
+ if (name.size() > 1) {
+ // Skip the leading '_'
+ e.entry.name.SetCStringWithLength(name.c_str() + 1, name.size() - 1);
+ }
+ if (import_name) {
+ // Skip the leading '_'
+ e.entry.import_name.SetCString(import_name + 1);
+ }
+ output.push_back(e);
+ }
+ }
+
+ const uint8_t childrenCount = data.GetU8(&children_offset);
+ for (uint8_t i = 0; i < childrenCount; ++i) {
+ const char *cstr = data.GetCStr(&children_offset);
+ if (cstr)
+ nameSlices.push_back(llvm::StringRef(cstr));
+ else
+ return false; // Corrupt data
+ lldb::offset_t childNodeOffset = data.GetULEB128(&children_offset);
+ if (childNodeOffset) {
+ if (!ParseTrieEntries(data, childNodeOffset, is_arm, nameSlices,
+ resolver_addresses, output)) {
+ return false;
+ }
+ }
+ nameSlices.pop_back();
+ }
+ return true;
}
// Read the UUID out of a dyld_shared_cache file on-disk.
-UUID
-ObjectFileMachO::GetSharedCacheUUID (FileSpec dyld_shared_cache, const ByteOrder byte_order, const uint32_t addr_byte_size)
-{
- UUID dsc_uuid;
- DataBufferSP dsc_data_sp = dyld_shared_cache.MemoryMapFileContentsIfLocal(0, sizeof(struct lldb_copy_dyld_cache_header_v1));
- if (dsc_data_sp)
- {
- DataExtractor dsc_header_data (dsc_data_sp, byte_order, addr_byte_size);
-
- char version_str[7];
- lldb::offset_t offset = 0;
- memcpy (version_str, dsc_header_data.GetData (&offset, 6), 6);
- version_str[6] = '\0';
- if (strcmp (version_str, "dyld_v") == 0)
- {
- offset = offsetof (struct lldb_copy_dyld_cache_header_v1, uuid);
- uint8_t uuid_bytes[sizeof (uuid_t)];
- memcpy (uuid_bytes, dsc_header_data.GetData (&offset, sizeof (uuid_t)), sizeof (uuid_t));
- dsc_uuid.SetBytes (uuid_bytes);
- }
+UUID ObjectFileMachO::GetSharedCacheUUID(FileSpec dyld_shared_cache,
+ const ByteOrder byte_order,
+ const uint32_t addr_byte_size) {
+ UUID dsc_uuid;
+ DataBufferSP dsc_data_sp = dyld_shared_cache.MemoryMapFileContentsIfLocal(
+ 0, sizeof(struct lldb_copy_dyld_cache_header_v1));
+ if (dsc_data_sp) {
+ DataExtractor dsc_header_data(dsc_data_sp, byte_order, addr_byte_size);
+
+ char version_str[7];
+ lldb::offset_t offset = 0;
+ memcpy(version_str, dsc_header_data.GetData(&offset, 6), 6);
+ version_str[6] = '\0';
+ if (strcmp(version_str, "dyld_v") == 0) {
+ offset = offsetof(struct lldb_copy_dyld_cache_header_v1, uuid);
+ uint8_t uuid_bytes[sizeof(uuid_t)];
+ memcpy(uuid_bytes, dsc_header_data.GetData(&offset, sizeof(uuid_t)),
+ sizeof(uuid_t));
+ dsc_uuid.SetBytes(uuid_bytes);
}
- return dsc_uuid;
+ }
+ return dsc_uuid;
}
-size_t
-ObjectFileMachO::ParseSymtab ()
-{
- Timer scoped_timer(LLVM_PRETTY_FUNCTION,
- "ObjectFileMachO::ParseSymtab () module = %s",
- m_file.GetFilename().AsCString(""));
- ModuleSP module_sp (GetModule());
- if (!module_sp)
- return 0;
-
- struct symtab_command symtab_load_command = { 0, 0, 0, 0, 0, 0 };
- struct linkedit_data_command function_starts_load_command = { 0, 0, 0, 0 };
- struct dyld_info_command dyld_info = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- typedef AddressDataArray<lldb::addr_t, bool, 100> FunctionStarts;
- FunctionStarts function_starts;
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- uint32_t i;
- FileSpecList dylib_files;
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SYMBOLS));
- static const llvm::StringRef g_objc_v2_prefix_class ("_OBJC_CLASS_$_");
- static const llvm::StringRef g_objc_v2_prefix_metaclass ("_OBJC_METACLASS_$_");
- static const llvm::StringRef g_objc_v2_prefix_ivar ("_OBJC_IVAR_$_");
-
- for (i=0; i<m_header.ncmds; ++i)
- {
- const lldb::offset_t cmd_offset = offset;
- // Read in the load command and load command size
- struct load_command lc;
- if (m_data.GetU32(&offset, &lc, 2) == NULL)
- break;
- // Watch for the symbol table load command
- switch (lc.cmd)
- {
- case LC_SYMTAB:
- symtab_load_command.cmd = lc.cmd;
- symtab_load_command.cmdsize = lc.cmdsize;
- // Read in the rest of the symtab load command
- if (m_data.GetU32(&offset, &symtab_load_command.symoff, 4) == 0) // fill in symoff, nsyms, stroff, strsize fields
- return 0;
- if (symtab_load_command.symoff == 0)
- {
- if (log)
- module_sp->LogMessage(log, "LC_SYMTAB.symoff == 0");
- return 0;
- }
-
- if (symtab_load_command.stroff == 0)
- {
- if (log)
- module_sp->LogMessage(log, "LC_SYMTAB.stroff == 0");
- return 0;
- }
-
- if (symtab_load_command.nsyms == 0)
- {
- if (log)
- module_sp->LogMessage(log, "LC_SYMTAB.nsyms == 0");
- return 0;
- }
-
- if (symtab_load_command.strsize == 0)
- {
- if (log)
- module_sp->LogMessage(log, "LC_SYMTAB.strsize == 0");
- return 0;
- }
- break;
-
- case LC_DYLD_INFO:
- case LC_DYLD_INFO_ONLY:
- if (m_data.GetU32(&offset, &dyld_info.rebase_off, 10))
- {
- dyld_info.cmd = lc.cmd;
- dyld_info.cmdsize = lc.cmdsize;
- }
- else
- {
- memset (&dyld_info, 0, sizeof(dyld_info));
- }
- break;
+size_t ObjectFileMachO::ParseSymtab() {
+ Timer scoped_timer(LLVM_PRETTY_FUNCTION,
+ "ObjectFileMachO::ParseSymtab () module = %s",
+ m_file.GetFilename().AsCString(""));
+ ModuleSP module_sp(GetModule());
+ if (!module_sp)
+ return 0;
- case LC_LOAD_DYLIB:
- case LC_LOAD_WEAK_DYLIB:
- case LC_REEXPORT_DYLIB:
- case LC_LOADFVMLIB:
- case LC_LOAD_UPWARD_DYLIB:
- {
- uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
- const char *path = m_data.PeekCStr(name_offset);
- if (path)
- {
- FileSpec file_spec(path, false);
- // Strip the path if there is @rpath, @executable, etc so we just use the basename
- if (path[0] == '@')
- file_spec.GetDirectory().Clear();
-
- if (lc.cmd == LC_REEXPORT_DYLIB)
- {
- m_reexported_dylibs.AppendIfUnique(file_spec);
- }
+ struct symtab_command symtab_load_command = {0, 0, 0, 0, 0, 0};
+ struct linkedit_data_command function_starts_load_command = {0, 0, 0, 0};
+ struct dyld_info_command dyld_info = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ typedef AddressDataArray<lldb::addr_t, bool, 100> FunctionStarts;
+ FunctionStarts function_starts;
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ uint32_t i;
+ FileSpecList dylib_files;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_SYMBOLS));
+ static const llvm::StringRef g_objc_v2_prefix_class("_OBJC_CLASS_$_");
+ static const llvm::StringRef g_objc_v2_prefix_metaclass("_OBJC_METACLASS_$_");
+ static const llvm::StringRef g_objc_v2_prefix_ivar("_OBJC_IVAR_$_");
+
+ for (i = 0; i < m_header.ncmds; ++i) {
+ const lldb::offset_t cmd_offset = offset;
+ // Read in the load command and load command size
+ struct load_command lc;
+ if (m_data.GetU32(&offset, &lc, 2) == NULL)
+ break;
+ // Watch for the symbol table load command
+ switch (lc.cmd) {
+ case LC_SYMTAB:
+ symtab_load_command.cmd = lc.cmd;
+ symtab_load_command.cmdsize = lc.cmdsize;
+ // Read in the rest of the symtab load command
+ if (m_data.GetU32(&offset, &symtab_load_command.symoff, 4) ==
+ 0) // fill in symoff, nsyms, stroff, strsize fields
+ return 0;
+ if (symtab_load_command.symoff == 0) {
+ if (log)
+ module_sp->LogMessage(log, "LC_SYMTAB.symoff == 0");
+ return 0;
+ }
- dylib_files.Append(file_spec);
- }
- }
- break;
+ if (symtab_load_command.stroff == 0) {
+ if (log)
+ module_sp->LogMessage(log, "LC_SYMTAB.stroff == 0");
+ return 0;
+ }
- case LC_FUNCTION_STARTS:
- function_starts_load_command.cmd = lc.cmd;
- function_starts_load_command.cmdsize = lc.cmdsize;
- if (m_data.GetU32(&offset, &function_starts_load_command.dataoff, 2) == NULL) // fill in symoff, nsyms, stroff, strsize fields
- memset (&function_starts_load_command, 0, sizeof(function_starts_load_command));
- break;
+ if (symtab_load_command.nsyms == 0) {
+ if (log)
+ module_sp->LogMessage(log, "LC_SYMTAB.nsyms == 0");
+ return 0;
+ }
- default:
- break;
+ if (symtab_load_command.strsize == 0) {
+ if (log)
+ module_sp->LogMessage(log, "LC_SYMTAB.strsize == 0");
+ return 0;
+ }
+ break;
+
+ case LC_DYLD_INFO:
+ case LC_DYLD_INFO_ONLY:
+ if (m_data.GetU32(&offset, &dyld_info.rebase_off, 10)) {
+ dyld_info.cmd = lc.cmd;
+ dyld_info.cmdsize = lc.cmdsize;
+ } else {
+ memset(&dyld_info, 0, sizeof(dyld_info));
+ }
+ break;
+
+ case LC_LOAD_DYLIB:
+ case LC_LOAD_WEAK_DYLIB:
+ case LC_REEXPORT_DYLIB:
+ case LC_LOADFVMLIB:
+ case LC_LOAD_UPWARD_DYLIB: {
+ uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
+ const char *path = m_data.PeekCStr(name_offset);
+ if (path) {
+ FileSpec file_spec(path, false);
+ // Strip the path if there is @rpath, @executable, etc so we just use
+ // the basename
+ if (path[0] == '@')
+ file_spec.GetDirectory().Clear();
+
+ if (lc.cmd == LC_REEXPORT_DYLIB) {
+ m_reexported_dylibs.AppendIfUnique(file_spec);
}
- offset = cmd_offset + lc.cmdsize;
- }
-
- if (symtab_load_command.cmd)
- {
- Symtab *symtab = m_symtab_ap.get();
- SectionList *section_list = GetSectionList();
- if (section_list == NULL)
- return 0;
-
- const uint32_t addr_byte_size = m_data.GetAddressByteSize();
- const ByteOrder byte_order = m_data.GetByteOrder();
- bool bit_width_32 = addr_byte_size == 4;
- const size_t nlist_byte_size = bit_width_32 ? sizeof(struct nlist) : sizeof(struct nlist_64);
-
- DataExtractor nlist_data (NULL, 0, byte_order, addr_byte_size);
- DataExtractor strtab_data (NULL, 0, byte_order, addr_byte_size);
- DataExtractor function_starts_data (NULL, 0, byte_order, addr_byte_size);
- DataExtractor indirect_symbol_index_data (NULL, 0, byte_order, addr_byte_size);
- DataExtractor dyld_trie_data (NULL, 0, byte_order, addr_byte_size);
-
- const addr_t nlist_data_byte_size = symtab_load_command.nsyms * nlist_byte_size;
- const addr_t strtab_data_byte_size = symtab_load_command.strsize;
- addr_t strtab_addr = LLDB_INVALID_ADDRESS;
-
- ProcessSP process_sp (m_process_wp.lock());
- Process *process = process_sp.get();
-
- uint32_t memory_module_load_level = eMemoryModuleLoadLevelComplete;
-
- if (process && m_header.filetype != llvm::MachO::MH_OBJECT)
- {
- Target &target = process->GetTarget();
-
- memory_module_load_level = target.GetMemoryModuleLoadLevel();
-
- SectionSP linkedit_section_sp(section_list->FindSectionByName(GetSegmentNameLINKEDIT()));
- // Reading mach file from memory in a process or core file...
-
- if (linkedit_section_sp)
- {
- addr_t linkedit_load_addr = linkedit_section_sp->GetLoadBaseAddress(&target);
- if (linkedit_load_addr == LLDB_INVALID_ADDRESS)
- {
- // We might be trying to access the symbol table before the __LINKEDIT's load
- // address has been set in the target. We can't fail to read the symbol table,
- // so calculate the right address manually
- linkedit_load_addr = CalculateSectionLoadAddressForMemoryImage(m_memory_addr, GetMachHeaderSection(), linkedit_section_sp.get());
- }
- const addr_t linkedit_file_offset = linkedit_section_sp->GetFileOffset();
- const addr_t symoff_addr = linkedit_load_addr + symtab_load_command.symoff - linkedit_file_offset;
- strtab_addr = linkedit_load_addr + symtab_load_command.stroff - linkedit_file_offset;
-
- bool data_was_read = false;
-
-#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__))
- if (m_header.flags & 0x80000000u && process->GetAddressByteSize() == sizeof (void*))
- {
- // This mach-o memory file is in the dyld shared cache. If this
- // program is not remote and this is iOS, then this process will
- // share the same shared cache as the process we are debugging and
- // we can read the entire __LINKEDIT from the address space in this
- // process. This is a needed optimization that is used for local iOS
- // debugging only since all shared libraries in the shared cache do
- // not have corresponding files that exist in the file system of the
- // device. They have been combined into a single file. This means we
- // always have to load these files from memory. All of the symbol and
- // string tables from all of the __LINKEDIT sections from the shared
- // libraries in the shared cache have been merged into a single large
- // symbol and string table. Reading all of this symbol and string table
- // data across can slow down debug launch times, so we optimize this by
- // reading the memory for the __LINKEDIT section from this process.
-
- UUID lldb_shared_cache(GetLLDBSharedCacheUUID());
- UUID process_shared_cache(GetProcessSharedCacheUUID(process));
- bool use_lldb_cache = true;
- if (lldb_shared_cache.IsValid() && process_shared_cache.IsValid() && lldb_shared_cache != process_shared_cache)
- {
- use_lldb_cache = false;
- ModuleSP module_sp (GetModule());
- if (module_sp)
- module_sp->ReportWarning ("shared cache in process does not match lldb's own shared cache, startup will be slow.");
-
- }
-
- PlatformSP platform_sp (target.GetPlatform());
- if (platform_sp && platform_sp->IsHost() && use_lldb_cache)
- {
- data_was_read = true;
- nlist_data.SetData((void *)symoff_addr, nlist_data_byte_size, eByteOrderLittle);
- strtab_data.SetData((void *)strtab_addr, strtab_data_byte_size, eByteOrderLittle);
- if (function_starts_load_command.cmd)
- {
- const addr_t func_start_addr = linkedit_load_addr + function_starts_load_command.dataoff - linkedit_file_offset;
- function_starts_data.SetData ((void *)func_start_addr, function_starts_load_command.datasize, eByteOrderLittle);
- }
- }
- }
-#endif
+ dylib_files.Append(file_spec);
+ }
+ } break;
+
+ case LC_FUNCTION_STARTS:
+ function_starts_load_command.cmd = lc.cmd;
+ function_starts_load_command.cmdsize = lc.cmdsize;
+ if (m_data.GetU32(&offset, &function_starts_load_command.dataoff, 2) ==
+ NULL) // fill in symoff, nsyms, stroff, strsize fields
+ memset(&function_starts_load_command, 0,
+ sizeof(function_starts_load_command));
+ break;
+
+ default:
+ break;
+ }
+ offset = cmd_offset + lc.cmdsize;
+ }
- if (!data_was_read)
- {
- // Always load dyld - the dynamic linker - from memory if we didn't find a binary anywhere else.
- // lldb will not register dylib/framework/bundle loads/unloads if we don't have the dyld symbols,
- // we force dyld to load from memory despite the user's target.memory-module-load-level setting.
- if (memory_module_load_level == eMemoryModuleLoadLevelComplete || m_header.filetype == llvm::MachO::MH_DYLINKER)
- {
- DataBufferSP nlist_data_sp (ReadMemory (process_sp, symoff_addr, nlist_data_byte_size));
- if (nlist_data_sp)
- nlist_data.SetData (nlist_data_sp, 0, nlist_data_sp->GetByteSize());
- // Load strings individually from memory when loading from memory since shared cache
- // string tables contain strings for all symbols from all shared cached libraries
- //DataBufferSP strtab_data_sp (ReadMemory (process_sp, strtab_addr, strtab_data_byte_size));
- //if (strtab_data_sp)
- // strtab_data.SetData (strtab_data_sp, 0, strtab_data_sp->GetByteSize());
- if (m_dysymtab.nindirectsyms != 0)
- {
- const addr_t indirect_syms_addr = linkedit_load_addr + m_dysymtab.indirectsymoff - linkedit_file_offset;
- DataBufferSP indirect_syms_data_sp (ReadMemory (process_sp, indirect_syms_addr, m_dysymtab.nindirectsyms * 4));
- if (indirect_syms_data_sp)
- indirect_symbol_index_data.SetData (indirect_syms_data_sp, 0, indirect_syms_data_sp->GetByteSize());
- }
- }
- else if (memory_module_load_level >= eMemoryModuleLoadLevelPartial)
- {
- if (function_starts_load_command.cmd)
- {
- const addr_t func_start_addr = linkedit_load_addr + function_starts_load_command.dataoff - linkedit_file_offset;
- DataBufferSP func_start_data_sp (ReadMemory (process_sp, func_start_addr, function_starts_load_command.datasize));
- if (func_start_data_sp)
- function_starts_data.SetData (func_start_data_sp, 0, func_start_data_sp->GetByteSize());
- }
- }
- }
- }
+ if (symtab_load_command.cmd) {
+ Symtab *symtab = m_symtab_ap.get();
+ SectionList *section_list = GetSectionList();
+ if (section_list == NULL)
+ return 0;
+
+ const uint32_t addr_byte_size = m_data.GetAddressByteSize();
+ const ByteOrder byte_order = m_data.GetByteOrder();
+ bool bit_width_32 = addr_byte_size == 4;
+ const size_t nlist_byte_size =
+ bit_width_32 ? sizeof(struct nlist) : sizeof(struct nlist_64);
+
+ DataExtractor nlist_data(NULL, 0, byte_order, addr_byte_size);
+ DataExtractor strtab_data(NULL, 0, byte_order, addr_byte_size);
+ DataExtractor function_starts_data(NULL, 0, byte_order, addr_byte_size);
+ DataExtractor indirect_symbol_index_data(NULL, 0, byte_order,
+ addr_byte_size);
+ DataExtractor dyld_trie_data(NULL, 0, byte_order, addr_byte_size);
+
+ const addr_t nlist_data_byte_size =
+ symtab_load_command.nsyms * nlist_byte_size;
+ const addr_t strtab_data_byte_size = symtab_load_command.strsize;
+ addr_t strtab_addr = LLDB_INVALID_ADDRESS;
+
+ ProcessSP process_sp(m_process_wp.lock());
+ Process *process = process_sp.get();
+
+ uint32_t memory_module_load_level = eMemoryModuleLoadLevelComplete;
+
+ if (process && m_header.filetype != llvm::MachO::MH_OBJECT) {
+ Target &target = process->GetTarget();
+
+ memory_module_load_level = target.GetMemoryModuleLoadLevel();
+
+ SectionSP linkedit_section_sp(
+ section_list->FindSectionByName(GetSegmentNameLINKEDIT()));
+ // Reading mach file from memory in a process or core file...
+
+ if (linkedit_section_sp) {
+ addr_t linkedit_load_addr =
+ linkedit_section_sp->GetLoadBaseAddress(&target);
+ if (linkedit_load_addr == LLDB_INVALID_ADDRESS) {
+ // We might be trying to access the symbol table before the
+ // __LINKEDIT's load
+ // address has been set in the target. We can't fail to read the
+ // symbol table,
+ // so calculate the right address manually
+ linkedit_load_addr = CalculateSectionLoadAddressForMemoryImage(
+ m_memory_addr, GetMachHeaderSection(), linkedit_section_sp.get());
}
- else
- {
- nlist_data.SetData (m_data,
- symtab_load_command.symoff,
- nlist_data_byte_size);
- strtab_data.SetData (m_data,
- symtab_load_command.stroff,
- strtab_data_byte_size);
-
- if (dyld_info.export_size > 0)
- {
- dyld_trie_data.SetData (m_data,
- dyld_info.export_off,
- dyld_info.export_size);
- }
- if (m_dysymtab.nindirectsyms != 0)
- {
- indirect_symbol_index_data.SetData (m_data,
- m_dysymtab.indirectsymoff,
- m_dysymtab.nindirectsyms * 4);
- }
- if (function_starts_load_command.cmd)
- {
- function_starts_data.SetData (m_data,
- function_starts_load_command.dataoff,
- function_starts_load_command.datasize);
+ const addr_t linkedit_file_offset =
+ linkedit_section_sp->GetFileOffset();
+ const addr_t symoff_addr = linkedit_load_addr +
+ symtab_load_command.symoff -
+ linkedit_file_offset;
+ strtab_addr = linkedit_load_addr + symtab_load_command.stroff -
+ linkedit_file_offset;
+
+ bool data_was_read = false;
+
+#if defined(__APPLE__) && \
+ (defined(__arm__) || defined(__arm64__) || defined(__aarch64__))
+ if (m_header.flags & 0x80000000u &&
+ process->GetAddressByteSize() == sizeof(void *)) {
+ // This mach-o memory file is in the dyld shared cache. If this
+ // program is not remote and this is iOS, then this process will
+ // share the same shared cache as the process we are debugging and
+ // we can read the entire __LINKEDIT from the address space in this
+ // process. This is a needed optimization that is used for local iOS
+ // debugging only since all shared libraries in the shared cache do
+ // not have corresponding files that exist in the file system of the
+ // device. They have been combined into a single file. This means we
+ // always have to load these files from memory. All of the symbol and
+ // string tables from all of the __LINKEDIT sections from the shared
+ // libraries in the shared cache have been merged into a single large
+ // symbol and string table. Reading all of this symbol and string
+ // table
+ // data across can slow down debug launch times, so we optimize this
+ // by
+ // reading the memory for the __LINKEDIT section from this process.
+
+ UUID lldb_shared_cache(GetLLDBSharedCacheUUID());
+ UUID process_shared_cache(GetProcessSharedCacheUUID(process));
+ bool use_lldb_cache = true;
+ if (lldb_shared_cache.IsValid() && process_shared_cache.IsValid() &&
+ lldb_shared_cache != process_shared_cache) {
+ use_lldb_cache = false;
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ module_sp->ReportWarning("shared cache in process does not match "
+ "lldb's own shared cache, startup will "
+ "be slow.");
+ }
+
+ PlatformSP platform_sp(target.GetPlatform());
+ if (platform_sp && platform_sp->IsHost() && use_lldb_cache) {
+ data_was_read = true;
+ nlist_data.SetData((void *)symoff_addr, nlist_data_byte_size,
+ eByteOrderLittle);
+ strtab_data.SetData((void *)strtab_addr, strtab_data_byte_size,
+ eByteOrderLittle);
+ if (function_starts_load_command.cmd) {
+ const addr_t func_start_addr =
+ linkedit_load_addr + function_starts_load_command.dataoff -
+ linkedit_file_offset;
+ function_starts_data.SetData(
+ (void *)func_start_addr,
+ function_starts_load_command.datasize, eByteOrderLittle);
}
+ }
}
+#endif
- if (nlist_data.GetByteSize() == 0 && memory_module_load_level == eMemoryModuleLoadLevelComplete)
- {
- if (log)
- module_sp->LogMessage(log, "failed to read nlist data");
- return 0;
- }
-
- const bool have_strtab_data = strtab_data.GetByteSize() > 0;
- if (!have_strtab_data)
- {
- if (process)
- {
- if (strtab_addr == LLDB_INVALID_ADDRESS)
- {
- if (log)
- module_sp->LogMessage(log, "failed to locate the strtab in memory");
- return 0;
- }
+ if (!data_was_read) {
+ // Always load dyld - the dynamic linker - from memory if we didn't
+ // find a binary anywhere else.
+ // lldb will not register dylib/framework/bundle loads/unloads if we
+ // don't have the dyld symbols,
+ // we force dyld to load from memory despite the user's
+ // target.memory-module-load-level setting.
+ if (memory_module_load_level == eMemoryModuleLoadLevelComplete ||
+ m_header.filetype == llvm::MachO::MH_DYLINKER) {
+ DataBufferSP nlist_data_sp(
+ ReadMemory(process_sp, symoff_addr, nlist_data_byte_size));
+ if (nlist_data_sp)
+ nlist_data.SetData(nlist_data_sp, 0,
+ nlist_data_sp->GetByteSize());
+ // Load strings individually from memory when loading from memory
+ // since shared cache
+ // string tables contain strings for all symbols from all shared
+ // cached libraries
+ // DataBufferSP strtab_data_sp (ReadMemory (process_sp, strtab_addr,
+ // strtab_data_byte_size));
+ // if (strtab_data_sp)
+ // strtab_data.SetData (strtab_data_sp, 0,
+ // strtab_data_sp->GetByteSize());
+ if (m_dysymtab.nindirectsyms != 0) {
+ const addr_t indirect_syms_addr = linkedit_load_addr +
+ m_dysymtab.indirectsymoff -
+ linkedit_file_offset;
+ DataBufferSP indirect_syms_data_sp(
+ ReadMemory(process_sp, indirect_syms_addr,
+ m_dysymtab.nindirectsyms * 4));
+ if (indirect_syms_data_sp)
+ indirect_symbol_index_data.SetData(
+ indirect_syms_data_sp, 0,
+ indirect_syms_data_sp->GetByteSize());
}
- else
- {
- if (log)
- module_sp->LogMessage(log, "failed to read strtab data");
- return 0;
+ } else if (memory_module_load_level >=
+ eMemoryModuleLoadLevelPartial) {
+ if (function_starts_load_command.cmd) {
+ const addr_t func_start_addr =
+ linkedit_load_addr + function_starts_load_command.dataoff -
+ linkedit_file_offset;
+ DataBufferSP func_start_data_sp(
+ ReadMemory(process_sp, func_start_addr,
+ function_starts_load_command.datasize));
+ if (func_start_data_sp)
+ function_starts_data.SetData(func_start_data_sp, 0,
+ func_start_data_sp->GetByteSize());
}
+ }
}
+ }
+ } else {
+ nlist_data.SetData(m_data, symtab_load_command.symoff,
+ nlist_data_byte_size);
+ strtab_data.SetData(m_data, symtab_load_command.stroff,
+ strtab_data_byte_size);
+
+ if (dyld_info.export_size > 0) {
+ dyld_trie_data.SetData(m_data, dyld_info.export_off,
+ dyld_info.export_size);
+ }
+
+ if (m_dysymtab.nindirectsyms != 0) {
+ indirect_symbol_index_data.SetData(m_data, m_dysymtab.indirectsymoff,
+ m_dysymtab.nindirectsyms * 4);
+ }
+ if (function_starts_load_command.cmd) {
+ function_starts_data.SetData(m_data,
+ function_starts_load_command.dataoff,
+ function_starts_load_command.datasize);
+ }
+ }
- const ConstString &g_segment_name_TEXT = GetSegmentNameTEXT();
- const ConstString &g_segment_name_DATA = GetSegmentNameDATA();
- const ConstString &g_segment_name_DATA_DIRTY = GetSegmentNameDATA_DIRTY();
- const ConstString &g_segment_name_DATA_CONST = GetSegmentNameDATA_CONST();
- const ConstString &g_segment_name_OBJC = GetSegmentNameOBJC();
- const ConstString &g_section_name_eh_frame = GetSectionNameEHFrame();
- SectionSP text_section_sp(section_list->FindSectionByName(g_segment_name_TEXT));
- SectionSP data_section_sp(section_list->FindSectionByName(g_segment_name_DATA));
- SectionSP data_dirty_section_sp(section_list->FindSectionByName(g_segment_name_DATA_DIRTY));
- SectionSP data_const_section_sp(section_list->FindSectionByName(g_segment_name_DATA_CONST));
- SectionSP objc_section_sp(section_list->FindSectionByName(g_segment_name_OBJC));
- SectionSP eh_frame_section_sp;
- if (text_section_sp.get())
- eh_frame_section_sp = text_section_sp->GetChildren().FindSectionByName (g_section_name_eh_frame);
- else
- eh_frame_section_sp = section_list->FindSectionByName (g_section_name_eh_frame);
-
- const bool is_arm = (m_header.cputype == llvm::MachO::CPU_TYPE_ARM);
-
- // lldb works best if it knows the start address of all functions in a module.
- // Linker symbols or debug info are normally the best source of information for start addr / size but
- // they may be stripped in a released binary.
- // Two additional sources of information exist in Mach-O binaries:
- // LC_FUNCTION_STARTS - a list of ULEB128 encoded offsets of each function's start address in the
- // binary, relative to the text section.
- // eh_frame - the eh_frame FDEs have the start addr & size of each function
- // LC_FUNCTION_STARTS is the fastest source to read in, and is present on all modern binaries.
- // Binaries built to run on older releases may need to use eh_frame information.
-
- if (text_section_sp && function_starts_data.GetByteSize())
- {
- FunctionStarts::Entry function_start_entry;
- function_start_entry.data = false;
- lldb::offset_t function_start_offset = 0;
- function_start_entry.addr = text_section_sp->GetFileAddress();
- uint64_t delta;
- while ((delta = function_starts_data.GetULEB128(&function_start_offset)) > 0)
- {
- // Now append the current entry
- function_start_entry.addr += delta;
- function_starts.Append(function_start_entry);
- }
- }
- else
- {
- // If m_type is eTypeDebugInfo, then this is a dSYM - it will have the load command claiming an eh_frame
- // but it doesn't actually have the eh_frame content. And if we have a dSYM, we don't need to do any
- // of this fill-in-the-missing-symbols works anyway - the debug info should give us all the functions in
- // the module.
- if (text_section_sp.get() && eh_frame_section_sp.get() && m_type != eTypeDebugInfo)
- {
- DWARFCallFrameInfo eh_frame(*this, eh_frame_section_sp, eRegisterKindEHFrame, true);
- DWARFCallFrameInfo::FunctionAddressAndSizeVector functions;
- eh_frame.GetFunctionAddressAndSizeVector (functions);
- addr_t text_base_addr = text_section_sp->GetFileAddress();
- size_t count = functions.GetSize();
- for (size_t i = 0; i < count; ++i)
- {
- const DWARFCallFrameInfo::FunctionAddressAndSizeVector::Entry *func = functions.GetEntryAtIndex (i);
- if (func)
- {
- FunctionStarts::Entry function_start_entry;
- function_start_entry.addr = func->base - text_base_addr;
- function_starts.Append(function_start_entry);
- }
- }
- }
- }
+ if (nlist_data.GetByteSize() == 0 &&
+ memory_module_load_level == eMemoryModuleLoadLevelComplete) {
+ if (log)
+ module_sp->LogMessage(log, "failed to read nlist data");
+ return 0;
+ }
- const size_t function_starts_count = function_starts.GetSize();
-
- // For user process binaries (executables, dylibs, frameworks, bundles), if we don't have
- // LC_FUNCTION_STARTS/eh_frame section in this binary, we're going to assume the binary
- // has been stripped. Don't allow assembly language instruction emulation because we don't
- // know proper function start boundaries.
- //
- // For all other types of binaries (kernels, stand-alone bare board binaries, kexts), they
- // may not have LC_FUNCTION_STARTS / eh_frame sections - we should not make any assumptions
- // about them based on that.
- if (function_starts_count == 0 && CalculateStrata() == eStrataUser)
- {
- m_allow_assembly_emulation_unwind_plans = false;
- Log *unwind_or_symbol_log (lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_SYMBOLS | LIBLLDB_LOG_UNWIND));
-
- if (unwind_or_symbol_log)
- module_sp->LogMessage(unwind_or_symbol_log, "no LC_FUNCTION_STARTS, will not allow assembly profiled unwinds");
+ const bool have_strtab_data = strtab_data.GetByteSize() > 0;
+ if (!have_strtab_data) {
+ if (process) {
+ if (strtab_addr == LLDB_INVALID_ADDRESS) {
+ if (log)
+ module_sp->LogMessage(log, "failed to locate the strtab in memory");
+ return 0;
}
+ } else {
+ if (log)
+ module_sp->LogMessage(log, "failed to read strtab data");
+ return 0;
+ }
+ }
- const user_id_t TEXT_eh_frame_sectID =
- eh_frame_section_sp.get() ? eh_frame_section_sp->GetID()
- : static_cast<user_id_t>(NO_SECT);
-
- lldb::offset_t nlist_data_offset = 0;
-
- uint32_t N_SO_index = UINT32_MAX;
-
- MachSymtabSectionInfo section_info (section_list);
- std::vector<uint32_t> N_FUN_indexes;
- std::vector<uint32_t> N_NSYM_indexes;
- std::vector<uint32_t> N_INCL_indexes;
- std::vector<uint32_t> N_BRAC_indexes;
- std::vector<uint32_t> N_COMM_indexes;
- typedef std::multimap <uint64_t, uint32_t> ValueToSymbolIndexMap;
- typedef std::map <uint32_t, uint32_t> NListIndexToSymbolIndexMap;
- typedef std::map <const char *, uint32_t> ConstNameToSymbolIndexMap;
- ValueToSymbolIndexMap N_FUN_addr_to_sym_idx;
- ValueToSymbolIndexMap N_STSYM_addr_to_sym_idx;
- ConstNameToSymbolIndexMap N_GSYM_name_to_sym_idx;
- // Any symbols that get merged into another will get an entry
- // in this map so we know
- NListIndexToSymbolIndexMap m_nlist_idx_to_sym_idx;
- uint32_t nlist_idx = 0;
- Symbol *symbol_ptr = NULL;
-
- uint32_t sym_idx = 0;
- Symbol *sym = NULL;
- size_t num_syms = 0;
- std::string memory_symbol_name;
- uint32_t unmapped_local_symbols_found = 0;
-
- std::vector<TrieEntryWithOffset> trie_entries;
- std::set<lldb::addr_t> resolver_addresses;
-
- if (dyld_trie_data.GetByteSize() > 0)
- {
- std::vector<llvm::StringRef> nameSlices;
- ParseTrieEntries (dyld_trie_data,
- 0,
- is_arm,
- nameSlices,
- resolver_addresses,
- trie_entries);
-
- ConstString text_segment_name ("__TEXT");
- SectionSP text_segment_sp = GetSectionList()->FindSectionByName(text_segment_name);
- if (text_segment_sp)
- {
- const lldb::addr_t text_segment_file_addr = text_segment_sp->GetFileAddress();
- if (text_segment_file_addr != LLDB_INVALID_ADDRESS)
- {
- for (auto &e : trie_entries)
- e.entry.address += text_segment_file_addr;
- }
- }
+ const ConstString &g_segment_name_TEXT = GetSegmentNameTEXT();
+ const ConstString &g_segment_name_DATA = GetSegmentNameDATA();
+ const ConstString &g_segment_name_DATA_DIRTY = GetSegmentNameDATA_DIRTY();
+ const ConstString &g_segment_name_DATA_CONST = GetSegmentNameDATA_CONST();
+ const ConstString &g_segment_name_OBJC = GetSegmentNameOBJC();
+ const ConstString &g_section_name_eh_frame = GetSectionNameEHFrame();
+ SectionSP text_section_sp(
+ section_list->FindSectionByName(g_segment_name_TEXT));
+ SectionSP data_section_sp(
+ section_list->FindSectionByName(g_segment_name_DATA));
+ SectionSP data_dirty_section_sp(
+ section_list->FindSectionByName(g_segment_name_DATA_DIRTY));
+ SectionSP data_const_section_sp(
+ section_list->FindSectionByName(g_segment_name_DATA_CONST));
+ SectionSP objc_section_sp(
+ section_list->FindSectionByName(g_segment_name_OBJC));
+ SectionSP eh_frame_section_sp;
+ if (text_section_sp.get())
+ eh_frame_section_sp = text_section_sp->GetChildren().FindSectionByName(
+ g_section_name_eh_frame);
+ else
+ eh_frame_section_sp =
+ section_list->FindSectionByName(g_section_name_eh_frame);
+
+ const bool is_arm = (m_header.cputype == llvm::MachO::CPU_TYPE_ARM);
+
+ // lldb works best if it knows the start address of all functions in a
+ // module.
+ // Linker symbols or debug info are normally the best source of information
+ // for start addr / size but
+ // they may be stripped in a released binary.
+ // Two additional sources of information exist in Mach-O binaries:
+ // LC_FUNCTION_STARTS - a list of ULEB128 encoded offsets of each
+ // function's start address in the
+ // binary, relative to the text section.
+ // eh_frame - the eh_frame FDEs have the start addr & size of
+ // each function
+ // LC_FUNCTION_STARTS is the fastest source to read in, and is present on
+ // all modern binaries.
+ // Binaries built to run on older releases may need to use eh_frame
+ // information.
+
+ if (text_section_sp && function_starts_data.GetByteSize()) {
+ FunctionStarts::Entry function_start_entry;
+ function_start_entry.data = false;
+ lldb::offset_t function_start_offset = 0;
+ function_start_entry.addr = text_section_sp->GetFileAddress();
+ uint64_t delta;
+ while ((delta = function_starts_data.GetULEB128(&function_start_offset)) >
+ 0) {
+ // Now append the current entry
+ function_start_entry.addr += delta;
+ function_starts.Append(function_start_entry);
+ }
+ } else {
+ // If m_type is eTypeDebugInfo, then this is a dSYM - it will have the
+ // load command claiming an eh_frame
+ // but it doesn't actually have the eh_frame content. And if we have a
+ // dSYM, we don't need to do any
+ // of this fill-in-the-missing-symbols works anyway - the debug info
+ // should give us all the functions in
+ // the module.
+ if (text_section_sp.get() && eh_frame_section_sp.get() &&
+ m_type != eTypeDebugInfo) {
+ DWARFCallFrameInfo eh_frame(*this, eh_frame_section_sp,
+ eRegisterKindEHFrame, true);
+ DWARFCallFrameInfo::FunctionAddressAndSizeVector functions;
+ eh_frame.GetFunctionAddressAndSizeVector(functions);
+ addr_t text_base_addr = text_section_sp->GetFileAddress();
+ size_t count = functions.GetSize();
+ for (size_t i = 0; i < count; ++i) {
+ const DWARFCallFrameInfo::FunctionAddressAndSizeVector::Entry *func =
+ functions.GetEntryAtIndex(i);
+ if (func) {
+ FunctionStarts::Entry function_start_entry;
+ function_start_entry.addr = func->base - text_base_addr;
+ function_starts.Append(function_start_entry);
+ }
}
+ }
+ }
- typedef std::set<ConstString> IndirectSymbols;
- IndirectSymbols indirect_symbol_names;
-
-#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__))
-
- // Some recent builds of the dyld_shared_cache (hereafter: DSC) have been optimized by moving LOCAL
- // symbols out of the memory mapped portion of the DSC. The symbol information has all been retained,
- // but it isn't available in the normal nlist data. However, there *are* duplicate entries of *some*
- // LOCAL symbols in the normal nlist data. To handle this situation correctly, we must first attempt
- // to parse any DSC unmapped symbol information. If we find any, we set a flag that tells the normal
- // nlist parser to ignore all LOCAL symbols.
-
- if (m_header.flags & 0x80000000u)
- {
- // Before we can start mapping the DSC, we need to make certain the target process is actually
- // using the cache we can find.
-
- // Next we need to determine the correct path for the dyld shared cache.
-
- ArchSpec header_arch;
- GetArchitecture(header_arch);
- char dsc_path[PATH_MAX];
- char dsc_path_development[PATH_MAX];
-
- snprintf(dsc_path, sizeof(dsc_path), "%s%s%s",
- "/System/Library/Caches/com.apple.dyld/", /* IPHONE_DYLD_SHARED_CACHE_DIR */
- "dyld_shared_cache_", /* DYLD_SHARED_CACHE_BASE_NAME */
- header_arch.GetArchitectureName());
-
- snprintf(dsc_path_development, sizeof(dsc_path), "%s%s%s%s",
- "/System/Library/Caches/com.apple.dyld/", /* IPHONE_DYLD_SHARED_CACHE_DIR */
- "dyld_shared_cache_", /* DYLD_SHARED_CACHE_BASE_NAME */
- header_arch.GetArchitectureName(),
- ".development");
-
- FileSpec dsc_nondevelopment_filespec(dsc_path, false);
- FileSpec dsc_development_filespec(dsc_path_development, false);
- FileSpec dsc_filespec;
-
- UUID dsc_uuid;
- UUID process_shared_cache_uuid;
-
- if (process)
- {
- process_shared_cache_uuid = GetProcessSharedCacheUUID(process);
- }
-
- // First see if we can find an exact match for the inferior process shared cache UUID in
- // the development or non-development shared caches on disk.
- if (process_shared_cache_uuid.IsValid())
- {
- if (dsc_development_filespec.Exists())
- {
- UUID dsc_development_uuid = GetSharedCacheUUID (dsc_development_filespec, byte_order, addr_byte_size);
- if (dsc_development_uuid.IsValid() && dsc_development_uuid == process_shared_cache_uuid)
- {
- dsc_filespec = dsc_development_filespec;
- dsc_uuid = dsc_development_uuid;
- }
- }
- if (!dsc_uuid.IsValid() && dsc_nondevelopment_filespec.Exists())
- {
- UUID dsc_nondevelopment_uuid = GetSharedCacheUUID (dsc_nondevelopment_filespec, byte_order, addr_byte_size);
- if (dsc_nondevelopment_uuid.IsValid() && dsc_nondevelopment_uuid == process_shared_cache_uuid)
- {
- dsc_filespec = dsc_nondevelopment_filespec;
- dsc_uuid = dsc_nondevelopment_uuid;
- }
- }
- }
-
- // Failing a UUID match, prefer the development dyld_shared cache if both are present.
- if (!dsc_filespec.Exists())
- {
- if (dsc_development_filespec.Exists())
- {
- dsc_filespec = dsc_development_filespec;
- }
- else
- {
- dsc_filespec = dsc_nondevelopment_filespec;
- }
- }
-
- /* The dyld_cache_header has a pointer to the dyld_cache_local_symbols_info structure (localSymbolsOffset).
- The dyld_cache_local_symbols_info structure gives us three things:
- 1. The start and count of the nlist records in the dyld_shared_cache file
- 2. The start and size of the strings for these nlist records
- 3. The start and count of dyld_cache_local_symbols_entry entries
-
- There is one dyld_cache_local_symbols_entry per dylib/framework in the dyld shared cache.
- The "dylibOffset" field is the Mach-O header of this dylib/framework in the dyld shared cache.
- The dyld_cache_local_symbols_entry also lists the start of this dylib/framework's nlist records
- and the count of how many nlist records there are for this dylib/framework.
- */
-
- // Process the dyld shared cache header to find the unmapped symbols
-
- DataBufferSP dsc_data_sp = dsc_filespec.MemoryMapFileContentsIfLocal(0, sizeof(struct lldb_copy_dyld_cache_header_v1));
- if (!dsc_uuid.IsValid())
- {
- dsc_uuid = GetSharedCacheUUID (dsc_filespec, byte_order, addr_byte_size);
- }
- if (dsc_data_sp)
- {
- DataExtractor dsc_header_data (dsc_data_sp, byte_order, addr_byte_size);
-
- bool uuid_match = true;
- if (dsc_uuid.IsValid() && process)
- {
- if (process_shared_cache_uuid.IsValid() && dsc_uuid != process_shared_cache_uuid)
- {
- // The on-disk dyld_shared_cache file is not the same as the one in this
- // process' memory, don't use it.
- uuid_match = false;
- ModuleSP module_sp (GetModule());
- if (module_sp)
- module_sp->ReportWarning ("process shared cache does not match on-disk dyld_shared_cache file, some symbol names will be missing.");
- }
- }
-
- offset = offsetof (struct lldb_copy_dyld_cache_header_v1, mappingOffset);
-
- uint32_t mappingOffset = dsc_header_data.GetU32(&offset);
-
- // If the mappingOffset points to a location inside the header, we've
- // opened an old dyld shared cache, and should not proceed further.
- if (uuid_match && mappingOffset >= sizeof(struct lldb_copy_dyld_cache_header_v1))
- {
-
- DataBufferSP dsc_mapping_info_data_sp = dsc_filespec.MemoryMapFileContentsIfLocal(mappingOffset, sizeof (struct lldb_copy_dyld_cache_mapping_info));
- DataExtractor dsc_mapping_info_data(dsc_mapping_info_data_sp, byte_order, addr_byte_size);
- offset = 0;
-
- // The File addresses (from the in-memory Mach-O load commands) for the shared libraries
- // in the shared library cache need to be adjusted by an offset to match up with the
- // dylibOffset identifying field in the dyld_cache_local_symbol_entry's. This offset is
- // recorded in mapping_offset_value.
- const uint64_t mapping_offset_value = dsc_mapping_info_data.GetU64(&offset);
-
- offset = offsetof (struct lldb_copy_dyld_cache_header_v1, localSymbolsOffset);
- uint64_t localSymbolsOffset = dsc_header_data.GetU64(&offset);
- uint64_t localSymbolsSize = dsc_header_data.GetU64(&offset);
+ const size_t function_starts_count = function_starts.GetSize();
- if (localSymbolsOffset && localSymbolsSize)
- {
- // Map the local symbols
- if (DataBufferSP dsc_local_symbols_data_sp = dsc_filespec.MemoryMapFileContentsIfLocal(localSymbolsOffset, localSymbolsSize))
- {
- DataExtractor dsc_local_symbols_data(dsc_local_symbols_data_sp, byte_order, addr_byte_size);
-
- offset = 0;
-
- typedef std::map<ConstString, uint16_t> UndefinedNameToDescMap;
- typedef std::map<uint32_t, ConstString> SymbolIndexToName;
- UndefinedNameToDescMap undefined_name_to_desc;
- SymbolIndexToName reexport_shlib_needs_fixup;
-
-
- // Read the local_symbols_infos struct in one shot
- struct lldb_copy_dyld_cache_local_symbols_info local_symbols_info;
- dsc_local_symbols_data.GetU32(&offset, &local_symbols_info.nlistOffset, 6);
-
- SectionSP text_section_sp(section_list->FindSectionByName(GetSegmentNameTEXT()));
-
- uint32_t header_file_offset = (text_section_sp->GetFileAddress() - mapping_offset_value);
-
- offset = local_symbols_info.entriesOffset;
- for (uint32_t entry_index = 0; entry_index < local_symbols_info.entriesCount; entry_index++)
- {
- struct lldb_copy_dyld_cache_local_symbols_entry local_symbols_entry;
- local_symbols_entry.dylibOffset = dsc_local_symbols_data.GetU32(&offset);
- local_symbols_entry.nlistStartIndex = dsc_local_symbols_data.GetU32(&offset);
- local_symbols_entry.nlistCount = dsc_local_symbols_data.GetU32(&offset);
-
- if (header_file_offset == local_symbols_entry.dylibOffset)
- {
- unmapped_local_symbols_found = local_symbols_entry.nlistCount;
-
- // The normal nlist code cannot correctly size the Symbols array, we need to allocate it here.
- sym = symtab->Resize (symtab_load_command.nsyms + m_dysymtab.nindirectsyms + unmapped_local_symbols_found - m_dysymtab.nlocalsym);
- num_syms = symtab->GetNumSymbols();
-
- nlist_data_offset = local_symbols_info.nlistOffset + (nlist_byte_size * local_symbols_entry.nlistStartIndex);
- uint32_t string_table_offset = local_symbols_info.stringsOffset;
-
- for (uint32_t nlist_index = 0; nlist_index < local_symbols_entry.nlistCount; nlist_index++)
- {
- /////////////////////////////
- {
- struct nlist_64 nlist;
- if (!dsc_local_symbols_data.ValidOffsetForDataOfSize(nlist_data_offset, nlist_byte_size))
- break;
-
- nlist.n_strx = dsc_local_symbols_data.GetU32_unchecked(&nlist_data_offset);
- nlist.n_type = dsc_local_symbols_data.GetU8_unchecked (&nlist_data_offset);
- nlist.n_sect = dsc_local_symbols_data.GetU8_unchecked (&nlist_data_offset);
- nlist.n_desc = dsc_local_symbols_data.GetU16_unchecked (&nlist_data_offset);
- nlist.n_value = dsc_local_symbols_data.GetAddress_unchecked (&nlist_data_offset);
-
- SymbolType type = eSymbolTypeInvalid;
- const char *symbol_name = dsc_local_symbols_data.PeekCStr(string_table_offset + nlist.n_strx);
-
- if (symbol_name == NULL)
- {
- // No symbol should be NULL, even the symbols with no
- // string values should have an offset zero which points
- // to an empty C-string
- Host::SystemLog (Host::eSystemLogError,
- "error: DSC unmapped local symbol[%u] has invalid string table offset 0x%x in %s, ignoring symbol\n",
- entry_index,
- nlist.n_strx,
- module_sp->GetFileSpec().GetPath().c_str());
- continue;
- }
- if (symbol_name[0] == '\0')
- symbol_name = NULL;
-
- const char *symbol_name_non_abi_mangled = NULL;
-
- SectionSP symbol_section;
- uint32_t symbol_byte_size = 0;
- bool add_nlist = true;
- bool is_debug = ((nlist.n_type & N_STAB) != 0);
- bool demangled_is_synthesized = false;
- bool is_gsym = false;
- bool set_value = true;
-
- assert (sym_idx < num_syms);
-
- sym[sym_idx].SetDebug (is_debug);
-
- if (is_debug)
- {
- switch (nlist.n_type)
- {
- case N_GSYM:
- // global symbol: name,,NO_SECT,type,0
- // Sometimes the N_GSYM value contains the address.
-
- // FIXME: In the .o files, we have a GSYM and a debug symbol for all the ObjC data. They
- // have the same address, but we want to ensure that we always find only the real symbol,
- // 'cause we don't currently correctly attribute the GSYM one to the ObjCClass/Ivar/MetaClass
- // symbol type. This is a temporary hack to make sure the ObjectiveC symbols get treated
- // correctly. To do this right, we should coalesce all the GSYM & global symbols that have the
- // same address.
-
- is_gsym = true;
- sym[sym_idx].SetExternal(true);
-
- if (symbol_name && symbol_name[0] == '_' && symbol_name[1] == 'O')
- {
- llvm::StringRef symbol_name_ref(symbol_name);
- if (symbol_name_ref.startswith(g_objc_v2_prefix_class))
- {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name = symbol_name + g_objc_v2_prefix_class.size();
- type = eSymbolTypeObjCClass;
- demangled_is_synthesized = true;
-
- }
- else if (symbol_name_ref.startswith(g_objc_v2_prefix_metaclass))
- {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name = symbol_name + g_objc_v2_prefix_metaclass.size();
- type = eSymbolTypeObjCMetaClass;
- demangled_is_synthesized = true;
- }
- else if (symbol_name_ref.startswith(g_objc_v2_prefix_ivar))
- {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name = symbol_name + g_objc_v2_prefix_ivar.size();
- type = eSymbolTypeObjCIVar;
- demangled_is_synthesized = true;
- }
- }
- else
- {
- if (nlist.n_value != 0)
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
- type = eSymbolTypeData;
- }
- break;
-
- case N_FNAME:
- // procedure name (f77 kludge): name,,NO_SECT,0,0
- type = eSymbolTypeCompiler;
- break;
-
- case N_FUN:
- // procedure: name,,n_sect,linenumber,address
- if (symbol_name)
- {
- type = eSymbolTypeCode;
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
-
- N_FUN_addr_to_sym_idx.insert(std::make_pair(nlist.n_value, sym_idx));
- // We use the current number of symbols in the symbol table in lieu of
- // using nlist_idx in case we ever start trimming entries out
- N_FUN_indexes.push_back(sym_idx);
- }
- else
- {
- type = eSymbolTypeCompiler;
-
- if ( !N_FUN_indexes.empty() )
- {
- // Copy the size of the function into the original STAB entry so we don't have
- // to hunt for it later
- symtab->SymbolAtIndex(N_FUN_indexes.back())->SetByteSize(nlist.n_value);
- N_FUN_indexes.pop_back();
- // We don't really need the end function STAB as it contains the size which
- // we already placed with the original symbol, so don't add it if we want a
- // minimal symbol table
- add_nlist = false;
- }
- }
- break;
-
- case N_STSYM:
- // static symbol: name,,n_sect,type,address
- N_STSYM_addr_to_sym_idx.insert(std::make_pair(nlist.n_value, sym_idx));
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
- if (symbol_name && symbol_name[0])
- {
- type = ObjectFile::GetSymbolTypeFromName(symbol_name+1, eSymbolTypeData);
- }
- break;
-
- case N_LCSYM:
- // .lcomm symbol: name,,n_sect,type,address
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
- type = eSymbolTypeCommonBlock;
- break;
-
- case N_BNSYM:
- // We use the current number of symbols in the symbol table in lieu of
- // using nlist_idx in case we ever start trimming entries out
- // Skip these if we want minimal symbol tables
- add_nlist = false;
- break;
-
- case N_ENSYM:
- // Set the size of the N_BNSYM to the terminating index of this N_ENSYM
- // so that we can always skip the entire symbol if we need to navigate
- // more quickly at the source level when parsing STABS
- // Skip these if we want minimal symbol tables
- add_nlist = false;
- break;
-
- case N_OPT:
- // emitted with gcc2_compiled and in gcc source
- type = eSymbolTypeCompiler;
- break;
-
- case N_RSYM:
- // register sym: name,,NO_SECT,type,register
- type = eSymbolTypeVariable;
- break;
-
- case N_SLINE:
- // src line: 0,,n_sect,linenumber,address
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
- type = eSymbolTypeLineEntry;
- break;
-
- case N_SSYM:
- // structure elt: name,,NO_SECT,type,struct_offset
- type = eSymbolTypeVariableType;
- break;
-
- case N_SO:
- // source file name
- type = eSymbolTypeSourceFile;
- if (symbol_name == NULL)
- {
- add_nlist = false;
- if (N_SO_index != UINT32_MAX)
- {
- // Set the size of the N_SO to the terminating index of this N_SO
- // so that we can always skip the entire N_SO if we need to navigate
- // more quickly at the source level when parsing STABS
- symbol_ptr = symtab->SymbolAtIndex(N_SO_index);
- symbol_ptr->SetByteSize(sym_idx);
- symbol_ptr->SetSizeIsSibling(true);
- }
- N_NSYM_indexes.clear();
- N_INCL_indexes.clear();
- N_BRAC_indexes.clear();
- N_COMM_indexes.clear();
- N_FUN_indexes.clear();
- N_SO_index = UINT32_MAX;
- }
- else
- {
- // We use the current number of symbols in the symbol table in lieu of
- // using nlist_idx in case we ever start trimming entries out
- const bool N_SO_has_full_path = symbol_name[0] == '/';
- if (N_SO_has_full_path)
- {
- if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms))
- {
- // We have two consecutive N_SO entries where the first contains a directory
- // and the second contains a full path.
- sym[sym_idx - 1].GetMangled().SetValue(ConstString(symbol_name), false);
- m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1;
- add_nlist = false;
- }
- else
- {
- // This is the first entry in a N_SO that contains a directory or
- // a full path to the source file
- N_SO_index = sym_idx;
- }
- }
- else if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms))
- {
- // This is usually the second N_SO entry that contains just the filename,
- // so here we combine it with the first one if we are minimizing the symbol table
- const char *so_path = sym[sym_idx - 1].GetMangled().GetDemangledName(lldb::eLanguageTypeUnknown).AsCString();
- if (so_path && so_path[0])
- {
- std::string full_so_path (so_path);
- const size_t double_slash_pos = full_so_path.find("//");
- if (double_slash_pos != std::string::npos)
- {
- // The linker has been generating bad N_SO entries with doubled up paths
- // in the format "%s%s" where the first string in the DW_AT_comp_dir,
- // and the second is the directory for the source file so you end up with
- // a path that looks like "/tmp/src//tmp/src/"
- FileSpec so_dir(so_path, false);
- if (!so_dir.Exists())
- {
- so_dir.SetFile(&full_so_path[double_slash_pos + 1], false);
- if (so_dir.Exists())
- {
- // Trim off the incorrect path
- full_so_path.erase(0, double_slash_pos + 1);
- }
- }
- }
- if (*full_so_path.rbegin() != '/')
- full_so_path += '/';
- full_so_path += symbol_name;
- sym[sym_idx - 1].GetMangled().SetValue(ConstString(full_so_path.c_str()), false);
- add_nlist = false;
- m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1;
- }
- }
- else
- {
- // This could be a relative path to a N_SO
- N_SO_index = sym_idx;
- }
- }
- break;
-
- case N_OSO:
- // object file name: name,,0,0,st_mtime
- type = eSymbolTypeObjectFile;
- break;
-
- case N_LSYM:
- // local sym: name,,NO_SECT,type,offset
- type = eSymbolTypeLocal;
- break;
-
- //----------------------------------------------------------------------
- // INCL scopes
- //----------------------------------------------------------------------
- case N_BINCL:
- // include file beginning: name,,NO_SECT,0,sum
- // We use the current number of symbols in the symbol table in lieu of
- // using nlist_idx in case we ever start trimming entries out
- N_INCL_indexes.push_back(sym_idx);
- type = eSymbolTypeScopeBegin;
- break;
-
- case N_EINCL:
- // include file end: name,,NO_SECT,0,0
- // Set the size of the N_BINCL to the terminating index of this N_EINCL
- // so that we can always skip the entire symbol if we need to navigate
- // more quickly at the source level when parsing STABS
- if ( !N_INCL_indexes.empty() )
- {
- symbol_ptr = symtab->SymbolAtIndex(N_INCL_indexes.back());
- symbol_ptr->SetByteSize(sym_idx + 1);
- symbol_ptr->SetSizeIsSibling(true);
- N_INCL_indexes.pop_back();
- }
- type = eSymbolTypeScopeEnd;
- break;
-
- case N_SOL:
- // #included file name: name,,n_sect,0,address
- type = eSymbolTypeHeaderFile;
-
- // We currently don't use the header files on darwin
- add_nlist = false;
- break;
-
- case N_PARAMS:
- // compiler parameters: name,,NO_SECT,0,0
- type = eSymbolTypeCompiler;
- break;
-
- case N_VERSION:
- // compiler version: name,,NO_SECT,0,0
- type = eSymbolTypeCompiler;
- break;
-
- case N_OLEVEL:
- // compiler -O level: name,,NO_SECT,0,0
- type = eSymbolTypeCompiler;
- break;
-
- case N_PSYM:
- // parameter: name,,NO_SECT,type,offset
- type = eSymbolTypeVariable;
- break;
-
- case N_ENTRY:
- // alternate entry: name,,n_sect,linenumber,address
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
- type = eSymbolTypeLineEntry;
- break;
-
- //----------------------------------------------------------------------
- // Left and Right Braces
- //----------------------------------------------------------------------
- case N_LBRAC:
- // left bracket: 0,,NO_SECT,nesting level,address
- // We use the current number of symbols in the symbol table in lieu of
- // using nlist_idx in case we ever start trimming entries out
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
- N_BRAC_indexes.push_back(sym_idx);
- type = eSymbolTypeScopeBegin;
- break;
-
- case N_RBRAC:
- // right bracket: 0,,NO_SECT,nesting level,address
- // Set the size of the N_LBRAC to the terminating index of this N_RBRAC
- // so that we can always skip the entire symbol if we need to navigate
- // more quickly at the source level when parsing STABS
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
- if ( !N_BRAC_indexes.empty() )
- {
- symbol_ptr = symtab->SymbolAtIndex(N_BRAC_indexes.back());
- symbol_ptr->SetByteSize(sym_idx + 1);
- symbol_ptr->SetSizeIsSibling(true);
- N_BRAC_indexes.pop_back();
- }
- type = eSymbolTypeScopeEnd;
- break;
-
- case N_EXCL:
- // deleted include file: name,,NO_SECT,0,sum
- type = eSymbolTypeHeaderFile;
- break;
-
- //----------------------------------------------------------------------
- // COMM scopes
- //----------------------------------------------------------------------
- case N_BCOMM:
- // begin common: name,,NO_SECT,0,0
- // We use the current number of symbols in the symbol table in lieu of
- // using nlist_idx in case we ever start trimming entries out
- type = eSymbolTypeScopeBegin;
- N_COMM_indexes.push_back(sym_idx);
- break;
-
- case N_ECOML:
- // end common (local name): 0,,n_sect,0,address
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
- // Fall through
-
- case N_ECOMM:
- // end common: name,,n_sect,0,0
- // Set the size of the N_BCOMM to the terminating index of this N_ECOMM/N_ECOML
- // so that we can always skip the entire symbol if we need to navigate
- // more quickly at the source level when parsing STABS
- if ( !N_COMM_indexes.empty() )
- {
- symbol_ptr = symtab->SymbolAtIndex(N_COMM_indexes.back());
- symbol_ptr->SetByteSize(sym_idx + 1);
- symbol_ptr->SetSizeIsSibling(true);
- N_COMM_indexes.pop_back();
- }
- type = eSymbolTypeScopeEnd;
- break;
-
- case N_LENG:
- // second stab entry with length information
- type = eSymbolTypeAdditional;
- break;
-
- default: break;
- }
- }
- else
- {
- //uint8_t n_pext = N_PEXT & nlist.n_type;
- uint8_t n_type = N_TYPE & nlist.n_type;
- sym[sym_idx].SetExternal((N_EXT & nlist.n_type) != 0);
-
- switch (n_type)
- {
- case N_INDR:
- {
- const char *reexport_name_cstr = strtab_data.PeekCStr(nlist.n_value);
- if (reexport_name_cstr && reexport_name_cstr[0])
- {
- type = eSymbolTypeReExported;
- ConstString reexport_name(reexport_name_cstr + ((reexport_name_cstr[0] == '_') ? 1 : 0));
- sym[sym_idx].SetReExportedSymbolName(reexport_name);
- set_value = false;
- reexport_shlib_needs_fixup[sym_idx] = reexport_name;
- indirect_symbol_names.insert(ConstString(symbol_name + ((symbol_name[0] == '_') ? 1 : 0)));
- }
- else
- type = eSymbolTypeUndefined;
- }
- break;
-
- case N_UNDF:
- if (symbol_name && symbol_name[0])
- {
- ConstString undefined_name(symbol_name + ((symbol_name[0] == '_') ? 1 : 0));
- undefined_name_to_desc[undefined_name] = nlist.n_desc;
- }
- // Fall through
- case N_PBUD:
- type = eSymbolTypeUndefined;
- break;
-
- case N_ABS:
- type = eSymbolTypeAbsolute;
- break;
-
- case N_SECT:
- {
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
-
- if (symbol_section == NULL)
- {
- // TODO: warn about this?
- add_nlist = false;
- break;
- }
-
- if (TEXT_eh_frame_sectID == nlist.n_sect)
- {
- type = eSymbolTypeException;
- }
- else
- {
- uint32_t section_type = symbol_section->Get() & SECTION_TYPE;
-
- switch (section_type)
- {
- case S_CSTRING_LITERALS: type = eSymbolTypeData; break; // section with only literal C strings
- case S_4BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 4 byte literals
- case S_8BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 8 byte literals
- case S_LITERAL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only pointers to literals
- case S_NON_LAZY_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only non-lazy symbol pointers
- case S_LAZY_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only lazy symbol pointers
- case S_SYMBOL_STUBS: type = eSymbolTypeTrampoline; break; // section with only symbol stubs, byte size of stub in the reserved2 field
- case S_MOD_INIT_FUNC_POINTERS: type = eSymbolTypeCode; break; // section with only function pointers for initialization
- case S_MOD_TERM_FUNC_POINTERS: type = eSymbolTypeCode; break; // section with only function pointers for termination
- case S_INTERPOSING: type = eSymbolTypeTrampoline; break; // section with only pairs of function pointers for interposing
- case S_16BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 16 byte literals
- case S_DTRACE_DOF: type = eSymbolTypeInstrumentation; break;
- case S_LAZY_DYLIB_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break;
- default:
- switch (symbol_section->GetType())
- {
- case lldb::eSectionTypeCode:
- type = eSymbolTypeCode;
- break;
- case eSectionTypeData:
- case eSectionTypeDataCString: // Inlined C string data
- case eSectionTypeDataCStringPointers: // Pointers to C string data
- case eSectionTypeDataSymbolAddress: // Address of a symbol in the symbol table
- case eSectionTypeData4:
- case eSectionTypeData8:
- case eSectionTypeData16:
- type = eSymbolTypeData;
- break;
- default:
- break;
- }
- break;
- }
-
- if (type == eSymbolTypeInvalid)
- {
- const char *symbol_sect_name = symbol_section->GetName().AsCString();
- if (symbol_section->IsDescendant (text_section_sp.get()))
- {
- if (symbol_section->IsClear(S_ATTR_PURE_INSTRUCTIONS |
- S_ATTR_SELF_MODIFYING_CODE |
- S_ATTR_SOME_INSTRUCTIONS))
- type = eSymbolTypeData;
- else
- type = eSymbolTypeCode;
- }
- else if (symbol_section->IsDescendant(data_section_sp.get()) ||
- symbol_section->IsDescendant(data_dirty_section_sp.get()) ||
- symbol_section->IsDescendant(data_const_section_sp.get()))
- {
- if (symbol_sect_name && ::strstr (symbol_sect_name, "__objc") == symbol_sect_name)
- {
- type = eSymbolTypeRuntime;
-
- if (symbol_name)
- {
- llvm::StringRef symbol_name_ref(symbol_name);
- if (symbol_name_ref.startswith("_OBJC_"))
- {
- static const llvm::StringRef g_objc_v2_prefix_class ("_OBJC_CLASS_$_");
- static const llvm::StringRef g_objc_v2_prefix_metaclass ("_OBJC_METACLASS_$_");
- static const llvm::StringRef g_objc_v2_prefix_ivar ("_OBJC_IVAR_$_");
- if (symbol_name_ref.startswith(g_objc_v2_prefix_class))
- {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name = symbol_name + g_objc_v2_prefix_class.size();
- type = eSymbolTypeObjCClass;
- demangled_is_synthesized = true;
- }
- else if (symbol_name_ref.startswith(g_objc_v2_prefix_metaclass))
- {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name = symbol_name + g_objc_v2_prefix_metaclass.size();
- type = eSymbolTypeObjCMetaClass;
- demangled_is_synthesized = true;
- }
- else if (symbol_name_ref.startswith(g_objc_v2_prefix_ivar))
- {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name = symbol_name + g_objc_v2_prefix_ivar.size();
- type = eSymbolTypeObjCIVar;
- demangled_is_synthesized = true;
- }
- }
- }
- }
- else if (symbol_sect_name && ::strstr (symbol_sect_name, "__gcc_except_tab") == symbol_sect_name)
- {
- type = eSymbolTypeException;
- }
- else
- {
- type = eSymbolTypeData;
- }
- }
- else if (symbol_sect_name && ::strstr (symbol_sect_name, "__IMPORT") == symbol_sect_name)
- {
- type = eSymbolTypeTrampoline;
- }
- else if (symbol_section->IsDescendant(objc_section_sp.get()))
- {
- type = eSymbolTypeRuntime;
- if (symbol_name && symbol_name[0] == '.')
- {
- llvm::StringRef symbol_name_ref(symbol_name);
- static const llvm::StringRef g_objc_v1_prefix_class (".objc_class_name_");
- if (symbol_name_ref.startswith(g_objc_v1_prefix_class))
- {
- symbol_name_non_abi_mangled = symbol_name;
- symbol_name = symbol_name + g_objc_v1_prefix_class.size();
- type = eSymbolTypeObjCClass;
- demangled_is_synthesized = true;
- }
- }
- }
- }
- }
- }
- break;
- }
- }
-
- if (add_nlist)
- {
- uint64_t symbol_value = nlist.n_value;
- if (symbol_name_non_abi_mangled)
- {
- sym[sym_idx].GetMangled().SetMangledName (ConstString(symbol_name_non_abi_mangled));
- sym[sym_idx].GetMangled().SetDemangledName (ConstString(symbol_name));
- }
- else
- {
- bool symbol_name_is_mangled = false;
-
- if (symbol_name && symbol_name[0] == '_')
- {
- symbol_name_is_mangled = symbol_name[1] == '_';
- symbol_name++; // Skip the leading underscore
- }
-
- if (symbol_name)
- {
- ConstString const_symbol_name(symbol_name);
- sym[sym_idx].GetMangled().SetValue(const_symbol_name, symbol_name_is_mangled);
- if (is_gsym && is_debug)
- {
- const char *gsym_name = sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled).GetCString();
- if (gsym_name)
- N_GSYM_name_to_sym_idx[gsym_name] = sym_idx;
- }
- }
- }
- if (symbol_section)
- {
- const addr_t section_file_addr = symbol_section->GetFileAddress();
- if (symbol_byte_size == 0 && function_starts_count > 0)
- {
- addr_t symbol_lookup_file_addr = nlist.n_value;
- // Do an exact address match for non-ARM addresses, else get the closest since
- // the symbol might be a thumb symbol which has an address with bit zero set
- FunctionStarts::Entry *func_start_entry = function_starts.FindEntry (symbol_lookup_file_addr, !is_arm);
- if (is_arm && func_start_entry)
- {
- // Verify that the function start address is the symbol address (ARM)
- // or the symbol address + 1 (thumb)
- if (func_start_entry->addr != symbol_lookup_file_addr &&
- func_start_entry->addr != (symbol_lookup_file_addr + 1))
- {
- // Not the right entry, NULL it out...
- func_start_entry = NULL;
- }
- }
- if (func_start_entry)
- {
- func_start_entry->data = true;
-
- addr_t symbol_file_addr = func_start_entry->addr;
- uint32_t symbol_flags = 0;
- if (is_arm)
- {
- if (symbol_file_addr & 1)
- symbol_flags = MACHO_NLIST_ARM_SYMBOL_IS_THUMB;
- symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
- }
-
- const FunctionStarts::Entry *next_func_start_entry = function_starts.FindNextEntry (func_start_entry);
- const addr_t section_end_file_addr = section_file_addr + symbol_section->GetByteSize();
- if (next_func_start_entry)
- {
- addr_t next_symbol_file_addr = next_func_start_entry->addr;
- // Be sure the clear the Thumb address bit when we calculate the size
- // from the current and next address
- if (is_arm)
- next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
- symbol_byte_size = std::min<lldb::addr_t>(next_symbol_file_addr - symbol_file_addr, section_end_file_addr - symbol_file_addr);
- }
- else
- {
- symbol_byte_size = section_end_file_addr - symbol_file_addr;
- }
- }
- }
- symbol_value -= section_file_addr;
- }
-
- if (is_debug == false)
- {
- if (type == eSymbolTypeCode)
- {
- // See if we can find a N_FUN entry for any code symbols.
- // If we do find a match, and the name matches, then we
- // can merge the two into just the function symbol to avoid
- // duplicate entries in the symbol table
- std::pair<ValueToSymbolIndexMap::const_iterator, ValueToSymbolIndexMap::const_iterator> range;
- range = N_FUN_addr_to_sym_idx.equal_range(nlist.n_value);
- if (range.first != range.second)
- {
- bool found_it = false;
- for (ValueToSymbolIndexMap::const_iterator pos = range.first; pos != range.second; ++pos)
- {
- if (sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled) == sym[pos->second].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled))
- {
- m_nlist_idx_to_sym_idx[nlist_idx] = pos->second;
- // We just need the flags from the linker symbol, so put these flags
- // into the N_FUN flags to avoid duplicate symbols in the symbol table
- sym[pos->second].SetExternal(sym[sym_idx].IsExternal());
- sym[pos->second].SetFlags (nlist.n_type << 16 | nlist.n_desc);
- if (resolver_addresses.find(nlist.n_value) != resolver_addresses.end())
- sym[pos->second].SetType (eSymbolTypeResolver);
- sym[sym_idx].Clear();
- found_it = true;
- break;
- }
- }
- if (found_it)
- continue;
- }
- else
- {
- if (resolver_addresses.find(nlist.n_value) != resolver_addresses.end())
- type = eSymbolTypeResolver;
- }
- }
- else if (type == eSymbolTypeData ||
- type == eSymbolTypeObjCClass ||
- type == eSymbolTypeObjCMetaClass ||
- type == eSymbolTypeObjCIVar )
- {
- // See if we can find a N_STSYM entry for any data symbols.
- // If we do find a match, and the name matches, then we
- // can merge the two into just the Static symbol to avoid
- // duplicate entries in the symbol table
- std::pair<ValueToSymbolIndexMap::const_iterator, ValueToSymbolIndexMap::const_iterator> range;
- range = N_STSYM_addr_to_sym_idx.equal_range(nlist.n_value);
- if (range.first != range.second)
- {
- bool found_it = false;
- for (ValueToSymbolIndexMap::const_iterator pos = range.first; pos != range.second; ++pos)
- {
- if (sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled) == sym[pos->second].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled))
- {
- m_nlist_idx_to_sym_idx[nlist_idx] = pos->second;
- // We just need the flags from the linker symbol, so put these flags
- // into the N_STSYM flags to avoid duplicate symbols in the symbol table
- sym[pos->second].SetExternal(sym[sym_idx].IsExternal());
- sym[pos->second].SetFlags (nlist.n_type << 16 | nlist.n_desc);
- sym[sym_idx].Clear();
- found_it = true;
- break;
- }
- }
- if (found_it)
- continue;
- }
- else
- {
- const char *gsym_name = sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled).GetCString();
- if (gsym_name)
- {
- // Combine N_GSYM stab entries with the non stab symbol
- ConstNameToSymbolIndexMap::const_iterator pos = N_GSYM_name_to_sym_idx.find(gsym_name);
- if (pos != N_GSYM_name_to_sym_idx.end())
- {
- const uint32_t GSYM_sym_idx = pos->second;
- m_nlist_idx_to_sym_idx[nlist_idx] = GSYM_sym_idx;
- // Copy the address, because often the N_GSYM address has an invalid address of zero
- // when the global is a common symbol
- sym[GSYM_sym_idx].GetAddressRef().SetSection (symbol_section);
- sym[GSYM_sym_idx].GetAddressRef().SetOffset (symbol_value);
- // We just need the flags from the linker symbol, so put these flags
- // into the N_GSYM flags to avoid duplicate symbols in the symbol table
- sym[GSYM_sym_idx].SetFlags (nlist.n_type << 16 | nlist.n_desc);
- sym[sym_idx].Clear();
- continue;
- }
- }
- }
- }
- }
-
- sym[sym_idx].SetID (nlist_idx);
- sym[sym_idx].SetType (type);
- if (set_value)
- {
- sym[sym_idx].GetAddressRef().SetSection (symbol_section);
- sym[sym_idx].GetAddressRef().SetOffset (symbol_value);
- }
- sym[sym_idx].SetFlags (nlist.n_type << 16 | nlist.n_desc);
-
- if (symbol_byte_size > 0)
- sym[sym_idx].SetByteSize(symbol_byte_size);
-
- if (demangled_is_synthesized)
- sym[sym_idx].SetDemangledNameIsSynthesized(true);
- ++sym_idx;
- }
- else
- {
- sym[sym_idx].Clear();
- }
-
- }
- /////////////////////////////
- }
- break; // No more entries to consider
- }
- }
+ // For user process binaries (executables, dylibs, frameworks, bundles), if
+ // we don't have
+ // LC_FUNCTION_STARTS/eh_frame section in this binary, we're going to assume
+ // the binary
+ // has been stripped. Don't allow assembly language instruction emulation
+ // because we don't
+ // know proper function start boundaries.
+ //
+ // For all other types of binaries (kernels, stand-alone bare board
+ // binaries, kexts), they
+ // may not have LC_FUNCTION_STARTS / eh_frame sections - we should not make
+ // any assumptions
+ // about them based on that.
+ if (function_starts_count == 0 && CalculateStrata() == eStrataUser) {
+ m_allow_assembly_emulation_unwind_plans = false;
+ Log *unwind_or_symbol_log(lldb_private::GetLogIfAnyCategoriesSet(
+ LIBLLDB_LOG_SYMBOLS | LIBLLDB_LOG_UNWIND));
+
+ if (unwind_or_symbol_log)
+ module_sp->LogMessage(
+ unwind_or_symbol_log,
+ "no LC_FUNCTION_STARTS, will not allow assembly profiled unwinds");
+ }
- for (const auto &pos :reexport_shlib_needs_fixup)
- {
- const auto undef_pos = undefined_name_to_desc.find(pos.second);
- if (undef_pos != undefined_name_to_desc.end())
- {
- const uint8_t dylib_ordinal = llvm::MachO::GET_LIBRARY_ORDINAL(undef_pos->second);
- if (dylib_ordinal > 0 && dylib_ordinal < dylib_files.GetSize())
- sym[pos.first].SetReExportedSymbolSharedLibrary(dylib_files.GetFileSpecAtIndex(dylib_ordinal-1));
- }
- }
- }
- }
- }
- }
+ const user_id_t TEXT_eh_frame_sectID =
+ eh_frame_section_sp.get() ? eh_frame_section_sp->GetID()
+ : static_cast<user_id_t>(NO_SECT);
+
+ lldb::offset_t nlist_data_offset = 0;
+
+ uint32_t N_SO_index = UINT32_MAX;
+
+ MachSymtabSectionInfo section_info(section_list);
+ std::vector<uint32_t> N_FUN_indexes;
+ std::vector<uint32_t> N_NSYM_indexes;
+ std::vector<uint32_t> N_INCL_indexes;
+ std::vector<uint32_t> N_BRAC_indexes;
+ std::vector<uint32_t> N_COMM_indexes;
+ typedef std::multimap<uint64_t, uint32_t> ValueToSymbolIndexMap;
+ typedef std::map<uint32_t, uint32_t> NListIndexToSymbolIndexMap;
+ typedef std::map<const char *, uint32_t> ConstNameToSymbolIndexMap;
+ ValueToSymbolIndexMap N_FUN_addr_to_sym_idx;
+ ValueToSymbolIndexMap N_STSYM_addr_to_sym_idx;
+ ConstNameToSymbolIndexMap N_GSYM_name_to_sym_idx;
+ // Any symbols that get merged into another will get an entry
+ // in this map so we know
+ NListIndexToSymbolIndexMap m_nlist_idx_to_sym_idx;
+ uint32_t nlist_idx = 0;
+ Symbol *symbol_ptr = NULL;
+
+ uint32_t sym_idx = 0;
+ Symbol *sym = NULL;
+ size_t num_syms = 0;
+ std::string memory_symbol_name;
+ uint32_t unmapped_local_symbols_found = 0;
+
+ std::vector<TrieEntryWithOffset> trie_entries;
+ std::set<lldb::addr_t> resolver_addresses;
+
+ if (dyld_trie_data.GetByteSize() > 0) {
+ std::vector<llvm::StringRef> nameSlices;
+ ParseTrieEntries(dyld_trie_data, 0, is_arm, nameSlices,
+ resolver_addresses, trie_entries);
+
+ ConstString text_segment_name("__TEXT");
+ SectionSP text_segment_sp =
+ GetSectionList()->FindSectionByName(text_segment_name);
+ if (text_segment_sp) {
+ const lldb::addr_t text_segment_file_addr =
+ text_segment_sp->GetFileAddress();
+ if (text_segment_file_addr != LLDB_INVALID_ADDRESS) {
+ for (auto &e : trie_entries)
+ e.entry.address += text_segment_file_addr;
}
+ }
+ }
- // Must reset this in case it was mutated above!
- nlist_data_offset = 0;
-#endif
-
- if (nlist_data.GetByteSize() > 0)
- {
-
- // If the sym array was not created while parsing the DSC unmapped
- // symbols, create it now.
- if (sym == NULL)
- {
- sym = symtab->Resize (symtab_load_command.nsyms + m_dysymtab.nindirectsyms);
- num_syms = symtab->GetNumSymbols();
- }
-
- if (unmapped_local_symbols_found)
- {
- assert(m_dysymtab.ilocalsym == 0);
- nlist_data_offset += (m_dysymtab.nlocalsym * nlist_byte_size);
- nlist_idx = m_dysymtab.nlocalsym;
- }
- else
- {
- nlist_idx = 0;
- }
-
- typedef std::map<ConstString, uint16_t> UndefinedNameToDescMap;
- typedef std::map<uint32_t, ConstString> SymbolIndexToName;
- UndefinedNameToDescMap undefined_name_to_desc;
- SymbolIndexToName reexport_shlib_needs_fixup;
- for (; nlist_idx < symtab_load_command.nsyms; ++nlist_idx)
- {
- struct nlist_64 nlist;
- if (!nlist_data.ValidOffsetForDataOfSize(nlist_data_offset, nlist_byte_size))
- break;
-
- nlist.n_strx = nlist_data.GetU32_unchecked(&nlist_data_offset);
- nlist.n_type = nlist_data.GetU8_unchecked (&nlist_data_offset);
- nlist.n_sect = nlist_data.GetU8_unchecked (&nlist_data_offset);
- nlist.n_desc = nlist_data.GetU16_unchecked (&nlist_data_offset);
- nlist.n_value = nlist_data.GetAddress_unchecked (&nlist_data_offset);
-
- SymbolType type = eSymbolTypeInvalid;
- const char *symbol_name = NULL;
-
- if (have_strtab_data)
- {
- symbol_name = strtab_data.PeekCStr(nlist.n_strx);
+ typedef std::set<ConstString> IndirectSymbols;
+ IndirectSymbols indirect_symbol_names;
+
+#if defined(__APPLE__) && \
+ (defined(__arm__) || defined(__arm64__) || defined(__aarch64__))
+
+ // Some recent builds of the dyld_shared_cache (hereafter: DSC) have been
+ // optimized by moving LOCAL
+ // symbols out of the memory mapped portion of the DSC. The symbol
+ // information has all been retained,
+ // but it isn't available in the normal nlist data. However, there *are*
+ // duplicate entries of *some*
+ // LOCAL symbols in the normal nlist data. To handle this situation
+ // correctly, we must first attempt
+ // to parse any DSC unmapped symbol information. If we find any, we set a
+ // flag that tells the normal
+ // nlist parser to ignore all LOCAL symbols.
+
+ if (m_header.flags & 0x80000000u) {
+ // Before we can start mapping the DSC, we need to make certain the target
+ // process is actually
+ // using the cache we can find.
+
+ // Next we need to determine the correct path for the dyld shared cache.
+
+ ArchSpec header_arch;
+ GetArchitecture(header_arch);
+ char dsc_path[PATH_MAX];
+ char dsc_path_development[PATH_MAX];
+
+ snprintf(
+ dsc_path, sizeof(dsc_path), "%s%s%s",
+ "/System/Library/Caches/com.apple.dyld/", /* IPHONE_DYLD_SHARED_CACHE_DIR
+ */
+ "dyld_shared_cache_", /* DYLD_SHARED_CACHE_BASE_NAME */
+ header_arch.GetArchitectureName());
+
+ snprintf(
+ dsc_path_development, sizeof(dsc_path), "%s%s%s%s",
+ "/System/Library/Caches/com.apple.dyld/", /* IPHONE_DYLD_SHARED_CACHE_DIR
+ */
+ "dyld_shared_cache_", /* DYLD_SHARED_CACHE_BASE_NAME */
+ header_arch.GetArchitectureName(),
+ ".development");
+
+ FileSpec dsc_nondevelopment_filespec(dsc_path, false);
+ FileSpec dsc_development_filespec(dsc_path_development, false);
+ FileSpec dsc_filespec;
+
+ UUID dsc_uuid;
+ UUID process_shared_cache_uuid;
+
+ if (process) {
+ process_shared_cache_uuid = GetProcessSharedCacheUUID(process);
+ }
+
+ // First see if we can find an exact match for the inferior process shared
+ // cache UUID in
+ // the development or non-development shared caches on disk.
+ if (process_shared_cache_uuid.IsValid()) {
+ if (dsc_development_filespec.Exists()) {
+ UUID dsc_development_uuid = GetSharedCacheUUID(
+ dsc_development_filespec, byte_order, addr_byte_size);
+ if (dsc_development_uuid.IsValid() &&
+ dsc_development_uuid == process_shared_cache_uuid) {
+ dsc_filespec = dsc_development_filespec;
+ dsc_uuid = dsc_development_uuid;
+ }
+ }
+ if (!dsc_uuid.IsValid() && dsc_nondevelopment_filespec.Exists()) {
+ UUID dsc_nondevelopment_uuid = GetSharedCacheUUID(
+ dsc_nondevelopment_filespec, byte_order, addr_byte_size);
+ if (dsc_nondevelopment_uuid.IsValid() &&
+ dsc_nondevelopment_uuid == process_shared_cache_uuid) {
+ dsc_filespec = dsc_nondevelopment_filespec;
+ dsc_uuid = dsc_nondevelopment_uuid;
+ }
+ }
+ }
+
+ // Failing a UUID match, prefer the development dyld_shared cache if both
+ // are present.
+ if (!dsc_filespec.Exists()) {
+ if (dsc_development_filespec.Exists()) {
+ dsc_filespec = dsc_development_filespec;
+ } else {
+ dsc_filespec = dsc_nondevelopment_filespec;
+ }
+ }
+
+ /* The dyld_cache_header has a pointer to the
+ dyld_cache_local_symbols_info structure (localSymbolsOffset).
+ The dyld_cache_local_symbols_info structure gives us three things:
+ 1. The start and count of the nlist records in the dyld_shared_cache
+ file
+ 2. The start and size of the strings for these nlist records
+ 3. The start and count of dyld_cache_local_symbols_entry entries
+
+ There is one dyld_cache_local_symbols_entry per dylib/framework in the
+ dyld shared cache.
+ The "dylibOffset" field is the Mach-O header of this dylib/framework in
+ the dyld shared cache.
+ The dyld_cache_local_symbols_entry also lists the start of this
+ dylib/framework's nlist records
+ and the count of how many nlist records there are for this
+ dylib/framework.
+ */
+
+ // Process the dyld shared cache header to find the unmapped symbols
+
+ DataBufferSP dsc_data_sp = dsc_filespec.MemoryMapFileContentsIfLocal(
+ 0, sizeof(struct lldb_copy_dyld_cache_header_v1));
+ if (!dsc_uuid.IsValid()) {
+ dsc_uuid = GetSharedCacheUUID(dsc_filespec, byte_order, addr_byte_size);
+ }
+ if (dsc_data_sp) {
+ DataExtractor dsc_header_data(dsc_data_sp, byte_order, addr_byte_size);
+
+ bool uuid_match = true;
+ if (dsc_uuid.IsValid() && process) {
+ if (process_shared_cache_uuid.IsValid() &&
+ dsc_uuid != process_shared_cache_uuid) {
+ // The on-disk dyld_shared_cache file is not the same as the one in
+ // this
+ // process' memory, don't use it.
+ uuid_match = false;
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ module_sp->ReportWarning("process shared cache does not match "
+ "on-disk dyld_shared_cache file, some "
+ "symbol names will be missing.");
+ }
+ }
- if (symbol_name == NULL)
+ offset = offsetof(struct lldb_copy_dyld_cache_header_v1, mappingOffset);
+
+ uint32_t mappingOffset = dsc_header_data.GetU32(&offset);
+
+ // If the mappingOffset points to a location inside the header, we've
+ // opened an old dyld shared cache, and should not proceed further.
+ if (uuid_match &&
+ mappingOffset >= sizeof(struct lldb_copy_dyld_cache_header_v1)) {
+
+ DataBufferSP dsc_mapping_info_data_sp =
+ dsc_filespec.MemoryMapFileContentsIfLocal(
+ mappingOffset,
+ sizeof(struct lldb_copy_dyld_cache_mapping_info));
+ DataExtractor dsc_mapping_info_data(dsc_mapping_info_data_sp,
+ byte_order, addr_byte_size);
+ offset = 0;
+
+ // The File addresses (from the in-memory Mach-O load commands) for
+ // the shared libraries
+ // in the shared library cache need to be adjusted by an offset to
+ // match up with the
+ // dylibOffset identifying field in the
+ // dyld_cache_local_symbol_entry's. This offset is
+ // recorded in mapping_offset_value.
+ const uint64_t mapping_offset_value =
+ dsc_mapping_info_data.GetU64(&offset);
+
+ offset = offsetof(struct lldb_copy_dyld_cache_header_v1,
+ localSymbolsOffset);
+ uint64_t localSymbolsOffset = dsc_header_data.GetU64(&offset);
+ uint64_t localSymbolsSize = dsc_header_data.GetU64(&offset);
+
+ if (localSymbolsOffset && localSymbolsSize) {
+ // Map the local symbols
+ if (DataBufferSP dsc_local_symbols_data_sp =
+ dsc_filespec.MemoryMapFileContentsIfLocal(
+ localSymbolsOffset, localSymbolsSize)) {
+ DataExtractor dsc_local_symbols_data(dsc_local_symbols_data_sp,
+ byte_order, addr_byte_size);
+
+ offset = 0;
+
+ typedef std::map<ConstString, uint16_t> UndefinedNameToDescMap;
+ typedef std::map<uint32_t, ConstString> SymbolIndexToName;
+ UndefinedNameToDescMap undefined_name_to_desc;
+ SymbolIndexToName reexport_shlib_needs_fixup;
+
+ // Read the local_symbols_infos struct in one shot
+ struct lldb_copy_dyld_cache_local_symbols_info local_symbols_info;
+ dsc_local_symbols_data.GetU32(&offset,
+ &local_symbols_info.nlistOffset, 6);
+
+ SectionSP text_section_sp(
+ section_list->FindSectionByName(GetSegmentNameTEXT()));
+
+ uint32_t header_file_offset =
+ (text_section_sp->GetFileAddress() - mapping_offset_value);
+
+ offset = local_symbols_info.entriesOffset;
+ for (uint32_t entry_index = 0;
+ entry_index < local_symbols_info.entriesCount;
+ entry_index++) {
+ struct lldb_copy_dyld_cache_local_symbols_entry
+ local_symbols_entry;
+ local_symbols_entry.dylibOffset =
+ dsc_local_symbols_data.GetU32(&offset);
+ local_symbols_entry.nlistStartIndex =
+ dsc_local_symbols_data.GetU32(&offset);
+ local_symbols_entry.nlistCount =
+ dsc_local_symbols_data.GetU32(&offset);
+
+ if (header_file_offset == local_symbols_entry.dylibOffset) {
+ unmapped_local_symbols_found = local_symbols_entry.nlistCount;
+
+ // The normal nlist code cannot correctly size the Symbols
+ // array, we need to allocate it here.
+ sym = symtab->Resize(
+ symtab_load_command.nsyms + m_dysymtab.nindirectsyms +
+ unmapped_local_symbols_found - m_dysymtab.nlocalsym);
+ num_syms = symtab->GetNumSymbols();
+
+ nlist_data_offset =
+ local_symbols_info.nlistOffset +
+ (nlist_byte_size * local_symbols_entry.nlistStartIndex);
+ uint32_t string_table_offset =
+ local_symbols_info.stringsOffset;
+
+ for (uint32_t nlist_index = 0;
+ nlist_index < local_symbols_entry.nlistCount;
+ nlist_index++) {
+ /////////////////////////////
{
+ struct nlist_64 nlist;
+ if (!dsc_local_symbols_data.ValidOffsetForDataOfSize(
+ nlist_data_offset, nlist_byte_size))
+ break;
+
+ nlist.n_strx = dsc_local_symbols_data.GetU32_unchecked(
+ &nlist_data_offset);
+ nlist.n_type = dsc_local_symbols_data.GetU8_unchecked(
+ &nlist_data_offset);
+ nlist.n_sect = dsc_local_symbols_data.GetU8_unchecked(
+ &nlist_data_offset);
+ nlist.n_desc = dsc_local_symbols_data.GetU16_unchecked(
+ &nlist_data_offset);
+ nlist.n_value =
+ dsc_local_symbols_data.GetAddress_unchecked(
+ &nlist_data_offset);
+
+ SymbolType type = eSymbolTypeInvalid;
+ const char *symbol_name = dsc_local_symbols_data.PeekCStr(
+ string_table_offset + nlist.n_strx);
+
+ if (symbol_name == NULL) {
// No symbol should be NULL, even the symbols with no
// string values should have an offset zero which points
// to an empty C-string
- Host::SystemLog (Host::eSystemLogError,
- "error: symbol[%u] has invalid string table offset 0x%x in %s, ignoring symbol\n",
- nlist_idx,
- nlist.n_strx,
- module_sp->GetFileSpec().GetPath().c_str());
+ Host::SystemLog(
+ Host::eSystemLogError,
+ "error: DSC unmapped local symbol[%u] has invalid "
+ "string table offset 0x%x in %s, ignoring symbol\n",
+ entry_index, nlist.n_strx,
+ module_sp->GetFileSpec().GetPath().c_str());
continue;
- }
- if (symbol_name[0] == '\0')
+ }
+ if (symbol_name[0] == '\0')
symbol_name = NULL;
- }
- else
- {
- const addr_t str_addr = strtab_addr + nlist.n_strx;
- Error str_error;
- if (process->ReadCStringFromMemory(str_addr, memory_symbol_name, str_error))
- symbol_name = memory_symbol_name.c_str();
- }
- const char *symbol_name_non_abi_mangled = NULL;
-
- SectionSP symbol_section;
- lldb::addr_t symbol_byte_size = 0;
- bool add_nlist = true;
- bool is_gsym = false;
- bool is_debug = ((nlist.n_type & N_STAB) != 0);
- bool demangled_is_synthesized = false;
- bool set_value = true;
- assert (sym_idx < num_syms);
-
- sym[sym_idx].SetDebug (is_debug);
-
- if (is_debug)
- {
- switch (nlist.n_type)
- {
- case N_GSYM:
- // global symbol: name,,NO_SECT,type,0
- // Sometimes the N_GSYM value contains the address.
-
- // FIXME: In the .o files, we have a GSYM and a debug symbol for all the ObjC data. They
- // have the same address, but we want to ensure that we always find only the real symbol,
- // 'cause we don't currently correctly attribute the GSYM one to the ObjCClass/Ivar/MetaClass
- // symbol type. This is a temporary hack to make sure the ObjectiveC symbols get treated
- // correctly. To do this right, we should coalesce all the GSYM & global symbols that have the
- // same address.
- is_gsym = true;
- sym[sym_idx].SetExternal(true);
-
- if (symbol_name && symbol_name[0] == '_' && symbol_name[1] == 'O')
- {
+
+ const char *symbol_name_non_abi_mangled = NULL;
+
+ SectionSP symbol_section;
+ uint32_t symbol_byte_size = 0;
+ bool add_nlist = true;
+ bool is_debug = ((nlist.n_type & N_STAB) != 0);
+ bool demangled_is_synthesized = false;
+ bool is_gsym = false;
+ bool set_value = true;
+
+ assert(sym_idx < num_syms);
+
+ sym[sym_idx].SetDebug(is_debug);
+
+ if (is_debug) {
+ switch (nlist.n_type) {
+ case N_GSYM:
+ // global symbol: name,,NO_SECT,type,0
+ // Sometimes the N_GSYM value contains the address.
+
+ // FIXME: In the .o files, we have a GSYM and a debug
+ // symbol for all the ObjC data. They
+ // have the same address, but we want to ensure that
+ // we always find only the real symbol,
+ // 'cause we don't currently correctly attribute the
+ // GSYM one to the ObjCClass/Ivar/MetaClass
+ // symbol type. This is a temporary hack to make sure
+ // the ObjectiveC symbols get treated
+ // correctly. To do this right, we should coalesce
+ // all the GSYM & global symbols that have the
+ // same address.
+
+ is_gsym = true;
+ sym[sym_idx].SetExternal(true);
+
+ if (symbol_name && symbol_name[0] == '_' &&
+ symbol_name[1] == 'O') {
llvm::StringRef symbol_name_ref(symbol_name);
- if (symbol_name_ref.startswith(g_objc_v2_prefix_class))
- {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name = symbol_name + g_objc_v2_prefix_class.size();
- type = eSymbolTypeObjCClass;
- demangled_is_synthesized = true;
-
- }
- else if (symbol_name_ref.startswith(g_objc_v2_prefix_metaclass))
- {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name = symbol_name + g_objc_v2_prefix_metaclass.size();
- type = eSymbolTypeObjCMetaClass;
- demangled_is_synthesized = true;
+ if (symbol_name_ref.startswith(
+ g_objc_v2_prefix_class)) {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name =
+ symbol_name + g_objc_v2_prefix_class.size();
+ type = eSymbolTypeObjCClass;
+ demangled_is_synthesized = true;
+
+ } else if (symbol_name_ref.startswith(
+ g_objc_v2_prefix_metaclass)) {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name = symbol_name +
+ g_objc_v2_prefix_metaclass.size();
+ type = eSymbolTypeObjCMetaClass;
+ demangled_is_synthesized = true;
+ } else if (symbol_name_ref.startswith(
+ g_objc_v2_prefix_ivar)) {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name =
+ symbol_name + g_objc_v2_prefix_ivar.size();
+ type = eSymbolTypeObjCIVar;
+ demangled_is_synthesized = true;
}
- else if (symbol_name_ref.startswith(g_objc_v2_prefix_ivar))
- {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name = symbol_name + g_objc_v2_prefix_ivar.size();
- type = eSymbolTypeObjCIVar;
- demangled_is_synthesized = true;
- }
- }
- else
- {
+ } else {
if (nlist.n_value != 0)
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
+ symbol_section = section_info.GetSection(
+ nlist.n_sect, nlist.n_value);
type = eSymbolTypeData;
- }
- break;
+ }
+ break;
- case N_FNAME:
- // procedure name (f77 kludge): name,,NO_SECT,0,0
- type = eSymbolTypeCompiler;
- break;
+ case N_FNAME:
+ // procedure name (f77 kludge): name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
- case N_FUN:
- // procedure: name,,n_sect,linenumber,address
- if (symbol_name)
- {
+ case N_FUN:
+ // procedure: name,,n_sect,linenumber,address
+ if (symbol_name) {
type = eSymbolTypeCode;
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
-
- N_FUN_addr_to_sym_idx.insert(std::make_pair(nlist.n_value, sym_idx));
- // We use the current number of symbols in the symbol table in lieu of
- // using nlist_idx in case we ever start trimming entries out
+ symbol_section = section_info.GetSection(
+ nlist.n_sect, nlist.n_value);
+
+ N_FUN_addr_to_sym_idx.insert(
+ std::make_pair(nlist.n_value, sym_idx));
+ // We use the current number of symbols in the
+ // symbol table in lieu of
+ // using nlist_idx in case we ever start trimming
+ // entries out
N_FUN_indexes.push_back(sym_idx);
- }
- else
- {
+ } else {
type = eSymbolTypeCompiler;
- if ( !N_FUN_indexes.empty() )
- {
- // Copy the size of the function into the original STAB entry so we don't have
- // to hunt for it later
- symtab->SymbolAtIndex(N_FUN_indexes.back())->SetByteSize(nlist.n_value);
- N_FUN_indexes.pop_back();
- // We don't really need the end function STAB as it contains the size which
- // we already placed with the original symbol, so don't add it if we want a
- // minimal symbol table
- add_nlist = false;
+ if (!N_FUN_indexes.empty()) {
+ // Copy the size of the function into the original
+ // STAB entry so we don't have
+ // to hunt for it later
+ symtab->SymbolAtIndex(N_FUN_indexes.back())
+ ->SetByteSize(nlist.n_value);
+ N_FUN_indexes.pop_back();
+ // We don't really need the end function STAB as
+ // it contains the size which
+ // we already placed with the original symbol, so
+ // don't add it if we want a
+ // minimal symbol table
+ add_nlist = false;
}
- }
- break;
-
- case N_STSYM:
- // static symbol: name,,n_sect,type,address
- N_STSYM_addr_to_sym_idx.insert(std::make_pair(nlist.n_value, sym_idx));
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
- if (symbol_name && symbol_name[0])
- {
- type = ObjectFile::GetSymbolTypeFromName(symbol_name+1, eSymbolTypeData);
- }
- break;
-
- case N_LCSYM:
- // .lcomm symbol: name,,n_sect,type,address
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
- type = eSymbolTypeCommonBlock;
- break;
-
- case N_BNSYM:
- // We use the current number of symbols in the symbol table in lieu of
- // using nlist_idx in case we ever start trimming entries out
- // Skip these if we want minimal symbol tables
- add_nlist = false;
- break;
-
- case N_ENSYM:
- // Set the size of the N_BNSYM to the terminating index of this N_ENSYM
- // so that we can always skip the entire symbol if we need to navigate
- // more quickly at the source level when parsing STABS
- // Skip these if we want minimal symbol tables
- add_nlist = false;
- break;
-
-
- case N_OPT:
- // emitted with gcc2_compiled and in gcc source
- type = eSymbolTypeCompiler;
- break;
-
- case N_RSYM:
- // register sym: name,,NO_SECT,type,register
- type = eSymbolTypeVariable;
- break;
-
- case N_SLINE:
- // src line: 0,,n_sect,linenumber,address
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
- type = eSymbolTypeLineEntry;
- break;
-
- case N_SSYM:
- // structure elt: name,,NO_SECT,type,struct_offset
- type = eSymbolTypeVariableType;
- break;
-
- case N_SO:
- // source file name
- type = eSymbolTypeSourceFile;
- if (symbol_name == NULL)
- {
+ }
+ break;
+
+ case N_STSYM:
+ // static symbol: name,,n_sect,type,address
+ N_STSYM_addr_to_sym_idx.insert(
+ std::make_pair(nlist.n_value, sym_idx));
+ symbol_section = section_info.GetSection(
+ nlist.n_sect, nlist.n_value);
+ if (symbol_name && symbol_name[0]) {
+ type = ObjectFile::GetSymbolTypeFromName(
+ symbol_name + 1, eSymbolTypeData);
+ }
+ break;
+
+ case N_LCSYM:
+ // .lcomm symbol: name,,n_sect,type,address
+ symbol_section = section_info.GetSection(
+ nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeCommonBlock;
+ break;
+
+ case N_BNSYM:
+ // We use the current number of symbols in the symbol
+ // table in lieu of
+ // using nlist_idx in case we ever start trimming
+ // entries out
+ // Skip these if we want minimal symbol tables
+ add_nlist = false;
+ break;
+
+ case N_ENSYM:
+ // Set the size of the N_BNSYM to the terminating
+ // index of this N_ENSYM
+ // so that we can always skip the entire symbol if we
+ // need to navigate
+ // more quickly at the source level when parsing STABS
+ // Skip these if we want minimal symbol tables
+ add_nlist = false;
+ break;
+
+ case N_OPT:
+ // emitted with gcc2_compiled and in gcc source
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_RSYM:
+ // register sym: name,,NO_SECT,type,register
+ type = eSymbolTypeVariable;
+ break;
+
+ case N_SLINE:
+ // src line: 0,,n_sect,linenumber,address
+ symbol_section = section_info.GetSection(
+ nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeLineEntry;
+ break;
+
+ case N_SSYM:
+ // structure elt: name,,NO_SECT,type,struct_offset
+ type = eSymbolTypeVariableType;
+ break;
+
+ case N_SO:
+ // source file name
+ type = eSymbolTypeSourceFile;
+ if (symbol_name == NULL) {
add_nlist = false;
- if (N_SO_index != UINT32_MAX)
- {
- // Set the size of the N_SO to the terminating index of this N_SO
- // so that we can always skip the entire N_SO if we need to navigate
- // more quickly at the source level when parsing STABS
- symbol_ptr = symtab->SymbolAtIndex(N_SO_index);
- symbol_ptr->SetByteSize(sym_idx);
- symbol_ptr->SetSizeIsSibling(true);
+ if (N_SO_index != UINT32_MAX) {
+ // Set the size of the N_SO to the terminating
+ // index of this N_SO
+ // so that we can always skip the entire N_SO if
+ // we need to navigate
+ // more quickly at the source level when parsing
+ // STABS
+ symbol_ptr = symtab->SymbolAtIndex(N_SO_index);
+ symbol_ptr->SetByteSize(sym_idx);
+ symbol_ptr->SetSizeIsSibling(true);
}
N_NSYM_indexes.clear();
N_INCL_indexes.clear();
@@ -3939,2174 +3031,3060 @@ ObjectFileMachO::ParseSymtab ()
N_COMM_indexes.clear();
N_FUN_indexes.clear();
N_SO_index = UINT32_MAX;
- }
- else
- {
- // We use the current number of symbols in the symbol table in lieu of
- // using nlist_idx in case we ever start trimming entries out
- const bool N_SO_has_full_path = symbol_name[0] == '/';
- if (N_SO_has_full_path)
- {
- if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms))
- {
- // We have two consecutive N_SO entries where the first contains a directory
- // and the second contains a full path.
- sym[sym_idx - 1].GetMangled().SetValue(ConstString(symbol_name), false);
- m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1;
- add_nlist = false;
- }
- else
- {
- // This is the first entry in a N_SO that contains a directory or
- // a full path to the source file
- N_SO_index = sym_idx;
- }
- }
- else if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms))
- {
- // This is usually the second N_SO entry that contains just the filename,
- // so here we combine it with the first one if we are minimizing the symbol table
- const char *so_path = sym[sym_idx - 1].GetMangled().GetDemangledName(lldb::eLanguageTypeUnknown).AsCString();
- if (so_path && so_path[0])
- {
- std::string full_so_path (so_path);
- const size_t double_slash_pos = full_so_path.find("//");
- if (double_slash_pos != std::string::npos)
- {
- // The linker has been generating bad N_SO entries with doubled up paths
- // in the format "%s%s" where the first string in the DW_AT_comp_dir,
- // and the second is the directory for the source file so you end up with
- // a path that looks like "/tmp/src//tmp/src/"
- FileSpec so_dir(so_path, false);
- if (!so_dir.Exists())
- {
- so_dir.SetFile(&full_so_path[double_slash_pos + 1], false);
- if (so_dir.Exists())
- {
- // Trim off the incorrect path
- full_so_path.erase(0, double_slash_pos + 1);
- }
- }
+ } else {
+ // We use the current number of symbols in the
+ // symbol table in lieu of
+ // using nlist_idx in case we ever start trimming
+ // entries out
+ const bool N_SO_has_full_path =
+ symbol_name[0] == '/';
+ if (N_SO_has_full_path) {
+ if ((N_SO_index == sym_idx - 1) &&
+ ((sym_idx - 1) < num_syms)) {
+ // We have two consecutive N_SO entries where
+ // the first contains a directory
+ // and the second contains a full path.
+ sym[sym_idx - 1].GetMangled().SetValue(
+ ConstString(symbol_name), false);
+ m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1;
+ add_nlist = false;
+ } else {
+ // This is the first entry in a N_SO that
+ // contains a directory or
+ // a full path to the source file
+ N_SO_index = sym_idx;
+ }
+ } else if ((N_SO_index == sym_idx - 1) &&
+ ((sym_idx - 1) < num_syms)) {
+ // This is usually the second N_SO entry that
+ // contains just the filename,
+ // so here we combine it with the first one if we
+ // are minimizing the symbol table
+ const char *so_path =
+ sym[sym_idx - 1]
+ .GetMangled()
+ .GetDemangledName(
+ lldb::eLanguageTypeUnknown)
+ .AsCString();
+ if (so_path && so_path[0]) {
+ std::string full_so_path(so_path);
+ const size_t double_slash_pos =
+ full_so_path.find("//");
+ if (double_slash_pos != std::string::npos) {
+ // The linker has been generating bad N_SO
+ // entries with doubled up paths
+ // in the format "%s%s" where the first string
+ // in the DW_AT_comp_dir,
+ // and the second is the directory for the
+ // source file so you end up with
+ // a path that looks like "/tmp/src//tmp/src/"
+ FileSpec so_dir(so_path, false);
+ if (!so_dir.Exists()) {
+ so_dir.SetFile(
+ &full_so_path[double_slash_pos + 1],
+ false);
+ if (so_dir.Exists()) {
+ // Trim off the incorrect path
+ full_so_path.erase(0,
+ double_slash_pos + 1);
}
- if (*full_so_path.rbegin() != '/')
- full_so_path += '/';
- full_so_path += symbol_name;
- sym[sym_idx - 1].GetMangled().SetValue(ConstString(full_so_path.c_str()), false);
- add_nlist = false;
- m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1;
+ }
}
+ if (*full_so_path.rbegin() != '/')
+ full_so_path += '/';
+ full_so_path += symbol_name;
+ sym[sym_idx - 1].GetMangled().SetValue(
+ ConstString(full_so_path.c_str()), false);
+ add_nlist = false;
+ m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1;
+ }
+ } else {
+ // This could be a relative path to a N_SO
+ N_SO_index = sym_idx;
}
- else
- {
- // This could be a relative path to a N_SO
- N_SO_index = sym_idx;
- }
- }
- break;
-
- case N_OSO:
- // object file name: name,,0,0,st_mtime
- type = eSymbolTypeObjectFile;
- break;
-
- case N_LSYM:
- // local sym: name,,NO_SECT,type,offset
- type = eSymbolTypeLocal;
- break;
-
- //----------------------------------------------------------------------
- // INCL scopes
- //----------------------------------------------------------------------
- case N_BINCL:
- // include file beginning: name,,NO_SECT,0,sum
- // We use the current number of symbols in the symbol table in lieu of
- // using nlist_idx in case we ever start trimming entries out
- N_INCL_indexes.push_back(sym_idx);
- type = eSymbolTypeScopeBegin;
- break;
-
- case N_EINCL:
- // include file end: name,,NO_SECT,0,0
- // Set the size of the N_BINCL to the terminating index of this N_EINCL
- // so that we can always skip the entire symbol if we need to navigate
- // more quickly at the source level when parsing STABS
- if ( !N_INCL_indexes.empty() )
- {
- symbol_ptr = symtab->SymbolAtIndex(N_INCL_indexes.back());
+ }
+ break;
+
+ case N_OSO:
+ // object file name: name,,0,0,st_mtime
+ type = eSymbolTypeObjectFile;
+ break;
+
+ case N_LSYM:
+ // local sym: name,,NO_SECT,type,offset
+ type = eSymbolTypeLocal;
+ break;
+
+ //----------------------------------------------------------------------
+ // INCL scopes
+ //----------------------------------------------------------------------
+ case N_BINCL:
+ // include file beginning: name,,NO_SECT,0,sum
+ // We use the current number of symbols in the symbol
+ // table in lieu of
+ // using nlist_idx in case we ever start trimming
+ // entries out
+ N_INCL_indexes.push_back(sym_idx);
+ type = eSymbolTypeScopeBegin;
+ break;
+
+ case N_EINCL:
+ // include file end: name,,NO_SECT,0,0
+ // Set the size of the N_BINCL to the terminating
+ // index of this N_EINCL
+ // so that we can always skip the entire symbol if we
+ // need to navigate
+ // more quickly at the source level when parsing STABS
+ if (!N_INCL_indexes.empty()) {
+ symbol_ptr =
+ symtab->SymbolAtIndex(N_INCL_indexes.back());
symbol_ptr->SetByteSize(sym_idx + 1);
symbol_ptr->SetSizeIsSibling(true);
N_INCL_indexes.pop_back();
- }
- type = eSymbolTypeScopeEnd;
- break;
-
- case N_SOL:
- // #included file name: name,,n_sect,0,address
- type = eSymbolTypeHeaderFile;
-
- // We currently don't use the header files on darwin
- add_nlist = false;
- break;
-
- case N_PARAMS:
- // compiler parameters: name,,NO_SECT,0,0
- type = eSymbolTypeCompiler;
- break;
-
- case N_VERSION:
- // compiler version: name,,NO_SECT,0,0
- type = eSymbolTypeCompiler;
- break;
-
- case N_OLEVEL:
- // compiler -O level: name,,NO_SECT,0,0
- type = eSymbolTypeCompiler;
- break;
-
- case N_PSYM:
- // parameter: name,,NO_SECT,type,offset
- type = eSymbolTypeVariable;
- break;
-
- case N_ENTRY:
- // alternate entry: name,,n_sect,linenumber,address
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
- type = eSymbolTypeLineEntry;
- break;
-
- //----------------------------------------------------------------------
- // Left and Right Braces
- //----------------------------------------------------------------------
- case N_LBRAC:
- // left bracket: 0,,NO_SECT,nesting level,address
- // We use the current number of symbols in the symbol table in lieu of
- // using nlist_idx in case we ever start trimming entries out
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
- N_BRAC_indexes.push_back(sym_idx);
- type = eSymbolTypeScopeBegin;
- break;
-
- case N_RBRAC:
- // right bracket: 0,,NO_SECT,nesting level,address
- // Set the size of the N_LBRAC to the terminating index of this N_RBRAC
- // so that we can always skip the entire symbol if we need to navigate
- // more quickly at the source level when parsing STABS
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
- if ( !N_BRAC_indexes.empty() )
- {
- symbol_ptr = symtab->SymbolAtIndex(N_BRAC_indexes.back());
+ }
+ type = eSymbolTypeScopeEnd;
+ break;
+
+ case N_SOL:
+ // #included file name: name,,n_sect,0,address
+ type = eSymbolTypeHeaderFile;
+
+ // We currently don't use the header files on darwin
+ add_nlist = false;
+ break;
+
+ case N_PARAMS:
+ // compiler parameters: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_VERSION:
+ // compiler version: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_OLEVEL:
+ // compiler -O level: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_PSYM:
+ // parameter: name,,NO_SECT,type,offset
+ type = eSymbolTypeVariable;
+ break;
+
+ case N_ENTRY:
+ // alternate entry: name,,n_sect,linenumber,address
+ symbol_section = section_info.GetSection(
+ nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeLineEntry;
+ break;
+
+ //----------------------------------------------------------------------
+ // Left and Right Braces
+ //----------------------------------------------------------------------
+ case N_LBRAC:
+ // left bracket: 0,,NO_SECT,nesting level,address
+ // We use the current number of symbols in the symbol
+ // table in lieu of
+ // using nlist_idx in case we ever start trimming
+ // entries out
+ symbol_section = section_info.GetSection(
+ nlist.n_sect, nlist.n_value);
+ N_BRAC_indexes.push_back(sym_idx);
+ type = eSymbolTypeScopeBegin;
+ break;
+
+ case N_RBRAC:
+ // right bracket: 0,,NO_SECT,nesting level,address
+ // Set the size of the N_LBRAC to the terminating
+ // index of this N_RBRAC
+ // so that we can always skip the entire symbol if we
+ // need to navigate
+ // more quickly at the source level when parsing STABS
+ symbol_section = section_info.GetSection(
+ nlist.n_sect, nlist.n_value);
+ if (!N_BRAC_indexes.empty()) {
+ symbol_ptr =
+ symtab->SymbolAtIndex(N_BRAC_indexes.back());
symbol_ptr->SetByteSize(sym_idx + 1);
symbol_ptr->SetSizeIsSibling(true);
N_BRAC_indexes.pop_back();
- }
- type = eSymbolTypeScopeEnd;
- break;
-
- case N_EXCL:
- // deleted include file: name,,NO_SECT,0,sum
- type = eSymbolTypeHeaderFile;
- break;
-
- //----------------------------------------------------------------------
- // COMM scopes
- //----------------------------------------------------------------------
- case N_BCOMM:
- // begin common: name,,NO_SECT,0,0
- // We use the current number of symbols in the symbol table in lieu of
- // using nlist_idx in case we ever start trimming entries out
- type = eSymbolTypeScopeBegin;
- N_COMM_indexes.push_back(sym_idx);
- break;
-
- case N_ECOML:
- // end common (local name): 0,,n_sect,0,address
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
- LLVM_FALLTHROUGH;
-
- case N_ECOMM:
- // end common: name,,n_sect,0,0
- // Set the size of the N_BCOMM to the terminating index of this N_ECOMM/N_ECOML
- // so that we can always skip the entire symbol if we need to navigate
- // more quickly at the source level when parsing STABS
- if ( !N_COMM_indexes.empty() )
- {
- symbol_ptr = symtab->SymbolAtIndex(N_COMM_indexes.back());
+ }
+ type = eSymbolTypeScopeEnd;
+ break;
+
+ case N_EXCL:
+ // deleted include file: name,,NO_SECT,0,sum
+ type = eSymbolTypeHeaderFile;
+ break;
+
+ //----------------------------------------------------------------------
+ // COMM scopes
+ //----------------------------------------------------------------------
+ case N_BCOMM:
+ // begin common: name,,NO_SECT,0,0
+ // We use the current number of symbols in the symbol
+ // table in lieu of
+ // using nlist_idx in case we ever start trimming
+ // entries out
+ type = eSymbolTypeScopeBegin;
+ N_COMM_indexes.push_back(sym_idx);
+ break;
+
+ case N_ECOML:
+ // end common (local name): 0,,n_sect,0,address
+ symbol_section = section_info.GetSection(
+ nlist.n_sect, nlist.n_value);
+ // Fall through
+
+ case N_ECOMM:
+ // end common: name,,n_sect,0,0
+ // Set the size of the N_BCOMM to the terminating
+ // index of this N_ECOMM/N_ECOML
+ // so that we can always skip the entire symbol if we
+ // need to navigate
+ // more quickly at the source level when parsing STABS
+ if (!N_COMM_indexes.empty()) {
+ symbol_ptr =
+ symtab->SymbolAtIndex(N_COMM_indexes.back());
symbol_ptr->SetByteSize(sym_idx + 1);
symbol_ptr->SetSizeIsSibling(true);
N_COMM_indexes.pop_back();
- }
- type = eSymbolTypeScopeEnd;
- break;
-
- case N_LENG:
- // second stab entry with length information
- type = eSymbolTypeAdditional;
- break;
-
- default: break;
- }
- }
- else
- {
- //uint8_t n_pext = N_PEXT & nlist.n_type;
- uint8_t n_type = N_TYPE & nlist.n_type;
- sym[sym_idx].SetExternal((N_EXT & nlist.n_type) != 0);
+ }
+ type = eSymbolTypeScopeEnd;
+ break;
- switch (n_type)
- {
- case N_INDR:
- {
- const char *reexport_name_cstr = strtab_data.PeekCStr(nlist.n_value);
- if (reexport_name_cstr && reexport_name_cstr[0])
- {
- type = eSymbolTypeReExported;
- ConstString reexport_name(reexport_name_cstr + ((reexport_name_cstr[0] == '_') ? 1 : 0));
- sym[sym_idx].SetReExportedSymbolName(reexport_name);
- set_value = false;
- reexport_shlib_needs_fixup[sym_idx] = reexport_name;
- indirect_symbol_names.insert(ConstString(symbol_name + ((symbol_name[0] == '_') ? 1 : 0)));
- }
- else
- type = eSymbolTypeUndefined;
- }
- break;
+ case N_LENG:
+ // second stab entry with length information
+ type = eSymbolTypeAdditional;
+ break;
- case N_UNDF:
- if (symbol_name && symbol_name[0])
- {
- ConstString undefined_name(symbol_name + ((symbol_name[0] == '_') ? 1 : 0));
- undefined_name_to_desc[undefined_name] = nlist.n_desc;
+ default:
+ break;
}
- LLVM_FALLTHROUGH;
-
- case N_PBUD:
- type = eSymbolTypeUndefined;
- break;
-
- case N_ABS:
- type = eSymbolTypeAbsolute;
- break;
-
- case N_SECT:
- {
- symbol_section = section_info.GetSection (nlist.n_sect, nlist.n_value);
-
- if (!symbol_section)
- {
- // TODO: warn about this?
- add_nlist = false;
+ } else {
+ // uint8_t n_pext = N_PEXT & nlist.n_type;
+ uint8_t n_type = N_TYPE & nlist.n_type;
+ sym[sym_idx].SetExternal((N_EXT & nlist.n_type) != 0);
+
+ switch (n_type) {
+ case N_INDR: {
+ const char *reexport_name_cstr =
+ strtab_data.PeekCStr(nlist.n_value);
+ if (reexport_name_cstr && reexport_name_cstr[0]) {
+ type = eSymbolTypeReExported;
+ ConstString reexport_name(
+ reexport_name_cstr +
+ ((reexport_name_cstr[0] == '_') ? 1 : 0));
+ sym[sym_idx].SetReExportedSymbolName(reexport_name);
+ set_value = false;
+ reexport_shlib_needs_fixup[sym_idx] = reexport_name;
+ indirect_symbol_names.insert(
+ ConstString(symbol_name +
+ ((symbol_name[0] == '_') ? 1 : 0)));
+ } else
+ type = eSymbolTypeUndefined;
+ } break;
+
+ case N_UNDF:
+ if (symbol_name && symbol_name[0]) {
+ ConstString undefined_name(
+ symbol_name +
+ ((symbol_name[0] == '_') ? 1 : 0));
+ undefined_name_to_desc[undefined_name] =
+ nlist.n_desc;
+ }
+ // Fall through
+ case N_PBUD:
+ type = eSymbolTypeUndefined;
+ break;
+
+ case N_ABS:
+ type = eSymbolTypeAbsolute;
+ break;
+
+ case N_SECT: {
+ symbol_section = section_info.GetSection(
+ nlist.n_sect, nlist.n_value);
+
+ if (symbol_section == NULL) {
+ // TODO: warn about this?
+ add_nlist = false;
+ break;
+ }
+
+ if (TEXT_eh_frame_sectID == nlist.n_sect) {
+ type = eSymbolTypeException;
+ } else {
+ uint32_t section_type =
+ symbol_section->Get() & SECTION_TYPE;
+
+ switch (section_type) {
+ case S_CSTRING_LITERALS:
+ type = eSymbolTypeData;
+ break; // section with only literal C strings
+ case S_4BYTE_LITERALS:
+ type = eSymbolTypeData;
+ break; // section with only 4 byte literals
+ case S_8BYTE_LITERALS:
+ type = eSymbolTypeData;
+ break; // section with only 8 byte literals
+ case S_LITERAL_POINTERS:
+ type = eSymbolTypeTrampoline;
+ break; // section with only pointers to literals
+ case S_NON_LAZY_SYMBOL_POINTERS:
+ type = eSymbolTypeTrampoline;
+ break; // section with only non-lazy symbol
+ // pointers
+ case S_LAZY_SYMBOL_POINTERS:
+ type = eSymbolTypeTrampoline;
+ break; // section with only lazy symbol pointers
+ case S_SYMBOL_STUBS:
+ type = eSymbolTypeTrampoline;
+ break; // section with only symbol stubs, byte
+ // size of stub in the reserved2 field
+ case S_MOD_INIT_FUNC_POINTERS:
+ type = eSymbolTypeCode;
+ break; // section with only function pointers for
+ // initialization
+ case S_MOD_TERM_FUNC_POINTERS:
+ type = eSymbolTypeCode;
+ break; // section with only function pointers for
+ // termination
+ case S_INTERPOSING:
+ type = eSymbolTypeTrampoline;
+ break; // section with only pairs of function
+ // pointers for interposing
+ case S_16BYTE_LITERALS:
+ type = eSymbolTypeData;
+ break; // section with only 16 byte literals
+ case S_DTRACE_DOF:
+ type = eSymbolTypeInstrumentation;
+ break;
+ case S_LAZY_DYLIB_SYMBOL_POINTERS:
+ type = eSymbolTypeTrampoline;
+ break;
+ default:
+ switch (symbol_section->GetType()) {
+ case lldb::eSectionTypeCode:
+ type = eSymbolTypeCode;
break;
+ case eSectionTypeData:
+ case eSectionTypeDataCString: // Inlined C string
+ // data
+ case eSectionTypeDataCStringPointers: // Pointers
+ // to C
+ // string
+ // data
+ case eSectionTypeDataSymbolAddress: // Address of
+ // a symbol in
+ // the symbol
+ // table
+ case eSectionTypeData4:
+ case eSectionTypeData8:
+ case eSectionTypeData16:
+ type = eSymbolTypeData;
+ break;
+ default:
+ break;
+ }
+ break;
}
- if (TEXT_eh_frame_sectID == nlist.n_sect)
- {
- type = eSymbolTypeException;
- }
- else
- {
- uint32_t section_type = symbol_section->Get() & SECTION_TYPE;
-
- switch (section_type)
- {
- case S_CSTRING_LITERALS: type = eSymbolTypeData; break; // section with only literal C strings
- case S_4BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 4 byte literals
- case S_8BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 8 byte literals
- case S_LITERAL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only pointers to literals
- case S_NON_LAZY_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only non-lazy symbol pointers
- case S_LAZY_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break; // section with only lazy symbol pointers
- case S_SYMBOL_STUBS: type = eSymbolTypeTrampoline; break; // section with only symbol stubs, byte size of stub in the reserved2 field
- case S_MOD_INIT_FUNC_POINTERS: type = eSymbolTypeCode; break; // section with only function pointers for initialization
- case S_MOD_TERM_FUNC_POINTERS: type = eSymbolTypeCode; break; // section with only function pointers for termination
- case S_INTERPOSING: type = eSymbolTypeTrampoline; break; // section with only pairs of function pointers for interposing
- case S_16BYTE_LITERALS: type = eSymbolTypeData; break; // section with only 16 byte literals
- case S_DTRACE_DOF: type = eSymbolTypeInstrumentation; break;
- case S_LAZY_DYLIB_SYMBOL_POINTERS: type = eSymbolTypeTrampoline; break;
- default:
- switch (symbol_section->GetType())
- {
- case lldb::eSectionTypeCode:
- type = eSymbolTypeCode;
- break;
- case eSectionTypeData:
- case eSectionTypeDataCString: // Inlined C string data
- case eSectionTypeDataCStringPointers: // Pointers to C string data
- case eSectionTypeDataSymbolAddress: // Address of a symbol in the symbol table
- case eSectionTypeData4:
- case eSectionTypeData8:
- case eSectionTypeData16:
- type = eSymbolTypeData;
- break;
- default:
- break;
+ if (type == eSymbolTypeInvalid) {
+ const char *symbol_sect_name =
+ symbol_section->GetName().AsCString();
+ if (symbol_section->IsDescendant(
+ text_section_sp.get())) {
+ if (symbol_section->IsClear(
+ S_ATTR_PURE_INSTRUCTIONS |
+ S_ATTR_SELF_MODIFYING_CODE |
+ S_ATTR_SOME_INSTRUCTIONS))
+ type = eSymbolTypeData;
+ else
+ type = eSymbolTypeCode;
+ } else if (symbol_section->IsDescendant(
+ data_section_sp.get()) ||
+ symbol_section->IsDescendant(
+ data_dirty_section_sp.get()) ||
+ symbol_section->IsDescendant(
+ data_const_section_sp.get())) {
+ if (symbol_sect_name &&
+ ::strstr(symbol_sect_name, "__objc") ==
+ symbol_sect_name) {
+ type = eSymbolTypeRuntime;
+
+ if (symbol_name) {
+ llvm::StringRef symbol_name_ref(
+ symbol_name);
+ if (symbol_name_ref.startswith("_OBJC_")) {
+ static const llvm::StringRef
+ g_objc_v2_prefix_class(
+ "_OBJC_CLASS_$_");
+ static const llvm::StringRef
+ g_objc_v2_prefix_metaclass(
+ "_OBJC_METACLASS_$_");
+ static const llvm::StringRef
+ g_objc_v2_prefix_ivar(
+ "_OBJC_IVAR_$_");
+ if (symbol_name_ref.startswith(
+ g_objc_v2_prefix_class)) {
+ symbol_name_non_abi_mangled =
+ symbol_name + 1;
+ symbol_name =
+ symbol_name +
+ g_objc_v2_prefix_class.size();
+ type = eSymbolTypeObjCClass;
+ demangled_is_synthesized = true;
+ } else if (
+ symbol_name_ref.startswith(
+ g_objc_v2_prefix_metaclass)) {
+ symbol_name_non_abi_mangled =
+ symbol_name + 1;
+ symbol_name =
+ symbol_name +
+ g_objc_v2_prefix_metaclass.size();
+ type = eSymbolTypeObjCMetaClass;
+ demangled_is_synthesized = true;
+ } else if (symbol_name_ref.startswith(
+ g_objc_v2_prefix_ivar)) {
+ symbol_name_non_abi_mangled =
+ symbol_name + 1;
+ symbol_name =
+ symbol_name +
+ g_objc_v2_prefix_ivar.size();
+ type = eSymbolTypeObjCIVar;
+ demangled_is_synthesized = true;
+ }
}
- break;
+ }
+ } else if (symbol_sect_name &&
+ ::strstr(symbol_sect_name,
+ "__gcc_except_tab") ==
+ symbol_sect_name) {
+ type = eSymbolTypeException;
+ } else {
+ type = eSymbolTypeData;
}
-
- if (type == eSymbolTypeInvalid)
- {
- const char *symbol_sect_name = symbol_section->GetName().AsCString();
- if (symbol_section->IsDescendant (text_section_sp.get()))
- {
- if (symbol_section->IsClear(S_ATTR_PURE_INSTRUCTIONS |
- S_ATTR_SELF_MODIFYING_CODE |
- S_ATTR_SOME_INSTRUCTIONS))
- type = eSymbolTypeData;
- else
- type = eSymbolTypeCode;
- }
- else
- if (symbol_section->IsDescendant(data_section_sp.get()) ||
- symbol_section->IsDescendant(data_dirty_section_sp.get()) ||
- symbol_section->IsDescendant(data_const_section_sp.get()))
- {
- if (symbol_sect_name && ::strstr (symbol_sect_name, "__objc") == symbol_sect_name)
- {
- type = eSymbolTypeRuntime;
-
- if (symbol_name)
- {
- llvm::StringRef symbol_name_ref(symbol_name);
- if (symbol_name_ref.startswith("_OBJC_"))
- {
- static const llvm::StringRef g_objc_v2_prefix_class ("_OBJC_CLASS_$_");
- static const llvm::StringRef g_objc_v2_prefix_metaclass ("_OBJC_METACLASS_$_");
- static const llvm::StringRef g_objc_v2_prefix_ivar ("_OBJC_IVAR_$_");
- if (symbol_name_ref.startswith(g_objc_v2_prefix_class))
- {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name = symbol_name + g_objc_v2_prefix_class.size();
- type = eSymbolTypeObjCClass;
- demangled_is_synthesized = true;
- }
- else if (symbol_name_ref.startswith(g_objc_v2_prefix_metaclass))
- {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name = symbol_name + g_objc_v2_prefix_metaclass.size();
- type = eSymbolTypeObjCMetaClass;
- demangled_is_synthesized = true;
- }
- else if (symbol_name_ref.startswith(g_objc_v2_prefix_ivar))
- {
- symbol_name_non_abi_mangled = symbol_name + 1;
- symbol_name = symbol_name + g_objc_v2_prefix_ivar.size();
- type = eSymbolTypeObjCIVar;
- demangled_is_synthesized = true;
- }
- }
- }
- }
- else
- if (symbol_sect_name && ::strstr (symbol_sect_name, "__gcc_except_tab") == symbol_sect_name)
- {
- type = eSymbolTypeException;
- }
- else
- {
- type = eSymbolTypeData;
- }
- }
- else
- if (symbol_sect_name && ::strstr (symbol_sect_name, "__IMPORT") == symbol_sect_name)
- {
- type = eSymbolTypeTrampoline;
- }
- else
- if (symbol_section->IsDescendant(objc_section_sp.get()))
- {
- type = eSymbolTypeRuntime;
- if (symbol_name && symbol_name[0] == '.')
- {
- llvm::StringRef symbol_name_ref(symbol_name);
- static const llvm::StringRef g_objc_v1_prefix_class (".objc_class_name_");
- if (symbol_name_ref.startswith(g_objc_v1_prefix_class))
- {
- symbol_name_non_abi_mangled = symbol_name;
- symbol_name = symbol_name + g_objc_v1_prefix_class.size();
- type = eSymbolTypeObjCClass;
- demangled_is_synthesized = true;
- }
- }
- }
+ } else if (symbol_sect_name &&
+ ::strstr(symbol_sect_name,
+ "__IMPORT") ==
+ symbol_sect_name) {
+ type = eSymbolTypeTrampoline;
+ } else if (symbol_section->IsDescendant(
+ objc_section_sp.get())) {
+ type = eSymbolTypeRuntime;
+ if (symbol_name && symbol_name[0] == '.') {
+ llvm::StringRef symbol_name_ref(symbol_name);
+ static const llvm::StringRef
+ g_objc_v1_prefix_class(
+ ".objc_class_name_");
+ if (symbol_name_ref.startswith(
+ g_objc_v1_prefix_class)) {
+ symbol_name_non_abi_mangled = symbol_name;
+ symbol_name = symbol_name +
+ g_objc_v1_prefix_class.size();
+ type = eSymbolTypeObjCClass;
+ demangled_is_synthesized = true;
+ }
}
+ }
}
+ }
+ } break;
}
- break;
- }
- }
-
- if (add_nlist)
- {
- uint64_t symbol_value = nlist.n_value;
-
- if (symbol_name_non_abi_mangled)
- {
- sym[sym_idx].GetMangled().SetMangledName (ConstString(symbol_name_non_abi_mangled));
- sym[sym_idx].GetMangled().SetDemangledName (ConstString(symbol_name));
- }
- else
- {
- bool symbol_name_is_mangled = false;
-
- if (symbol_name && symbol_name[0] == '_')
- {
+ }
+
+ if (add_nlist) {
+ uint64_t symbol_value = nlist.n_value;
+ if (symbol_name_non_abi_mangled) {
+ sym[sym_idx].GetMangled().SetMangledName(
+ ConstString(symbol_name_non_abi_mangled));
+ sym[sym_idx].GetMangled().SetDemangledName(
+ ConstString(symbol_name));
+ } else {
+ bool symbol_name_is_mangled = false;
+
+ if (symbol_name && symbol_name[0] == '_') {
symbol_name_is_mangled = symbol_name[1] == '_';
- symbol_name++; // Skip the leading underscore
- }
+ symbol_name++; // Skip the leading underscore
+ }
- if (symbol_name)
- {
+ if (symbol_name) {
ConstString const_symbol_name(symbol_name);
- sym[sym_idx].GetMangled().SetValue(const_symbol_name, symbol_name_is_mangled);
+ sym[sym_idx].GetMangled().SetValue(
+ const_symbol_name, symbol_name_is_mangled);
+ if (is_gsym && is_debug) {
+ const char *gsym_name =
+ sym[sym_idx]
+ .GetMangled()
+ .GetName(lldb::eLanguageTypeUnknown,
+ Mangled::ePreferMangled)
+ .GetCString();
+ if (gsym_name)
+ N_GSYM_name_to_sym_idx[gsym_name] = sym_idx;
+ }
+ }
}
- }
-
- if (is_gsym)
- {
- const char *gsym_name = sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled).GetCString();
- if (gsym_name)
- N_GSYM_name_to_sym_idx[gsym_name] = sym_idx;
- }
-
- if (symbol_section)
- {
- const addr_t section_file_addr = symbol_section->GetFileAddress();
- if (symbol_byte_size == 0 && function_starts_count > 0)
- {
+ if (symbol_section) {
+ const addr_t section_file_addr =
+ symbol_section->GetFileAddress();
+ if (symbol_byte_size == 0 &&
+ function_starts_count > 0) {
addr_t symbol_lookup_file_addr = nlist.n_value;
- // Do an exact address match for non-ARM addresses, else get the closest since
- // the symbol might be a thumb symbol which has an address with bit zero set
- FunctionStarts::Entry *func_start_entry = function_starts.FindEntry (symbol_lookup_file_addr, !is_arm);
- if (is_arm && func_start_entry)
- {
- // Verify that the function start address is the symbol address (ARM)
- // or the symbol address + 1 (thumb)
- if (func_start_entry->addr != symbol_lookup_file_addr &&
- func_start_entry->addr != (symbol_lookup_file_addr + 1))
- {
- // Not the right entry, NULL it out...
- func_start_entry = NULL;
- }
+ // Do an exact address match for non-ARM addresses,
+ // else get the closest since
+ // the symbol might be a thumb symbol which has an
+ // address with bit zero set
+ FunctionStarts::Entry *func_start_entry =
+ function_starts.FindEntry(
+ symbol_lookup_file_addr, !is_arm);
+ if (is_arm && func_start_entry) {
+ // Verify that the function start address is the
+ // symbol address (ARM)
+ // or the symbol address + 1 (thumb)
+ if (func_start_entry->addr !=
+ symbol_lookup_file_addr &&
+ func_start_entry->addr !=
+ (symbol_lookup_file_addr + 1)) {
+ // Not the right entry, NULL it out...
+ func_start_entry = NULL;
+ }
}
- if (func_start_entry)
- {
- func_start_entry->data = true;
-
- addr_t symbol_file_addr = func_start_entry->addr;
+ if (func_start_entry) {
+ func_start_entry->data = true;
+
+ addr_t symbol_file_addr = func_start_entry->addr;
+ uint32_t symbol_flags = 0;
+ if (is_arm) {
+ if (symbol_file_addr & 1)
+ symbol_flags =
+ MACHO_NLIST_ARM_SYMBOL_IS_THUMB;
+ symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
+ }
+
+ const FunctionStarts::Entry
+ *next_func_start_entry =
+ function_starts.FindNextEntry(
+ func_start_entry);
+ const addr_t section_end_file_addr =
+ section_file_addr +
+ symbol_section->GetByteSize();
+ if (next_func_start_entry) {
+ addr_t next_symbol_file_addr =
+ next_func_start_entry->addr;
+ // Be sure the clear the Thumb address bit when
+ // we calculate the size
+ // from the current and next address
if (is_arm)
- symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
-
- const FunctionStarts::Entry *next_func_start_entry = function_starts.FindNextEntry (func_start_entry);
- const addr_t section_end_file_addr = section_file_addr + symbol_section->GetByteSize();
- if (next_func_start_entry)
- {
- addr_t next_symbol_file_addr = next_func_start_entry->addr;
- // Be sure the clear the Thumb address bit when we calculate the size
- // from the current and next address
- if (is_arm)
- next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
- symbol_byte_size = std::min<lldb::addr_t>(next_symbol_file_addr - symbol_file_addr, section_end_file_addr - symbol_file_addr);
- }
- else
- {
- symbol_byte_size = section_end_file_addr - symbol_file_addr;
- }
+ next_symbol_file_addr &=
+ THUMB_ADDRESS_BIT_MASK;
+ symbol_byte_size = std::min<lldb::addr_t>(
+ next_symbol_file_addr - symbol_file_addr,
+ section_end_file_addr - symbol_file_addr);
+ } else {
+ symbol_byte_size =
+ section_end_file_addr - symbol_file_addr;
+ }
}
+ }
+ symbol_value -= section_file_addr;
}
- symbol_value -= section_file_addr;
- }
- if (is_debug == false)
- {
- if (type == eSymbolTypeCode)
- {
- // See if we can find a N_FUN entry for any code symbols.
- // If we do find a match, and the name matches, then we
- // can merge the two into just the function symbol to avoid
+ if (is_debug == false) {
+ if (type == eSymbolTypeCode) {
+ // See if we can find a N_FUN entry for any code
+ // symbols.
+ // If we do find a match, and the name matches, then
+ // we
+ // can merge the two into just the function symbol
+ // to avoid
// duplicate entries in the symbol table
- std::pair<ValueToSymbolIndexMap::const_iterator, ValueToSymbolIndexMap::const_iterator> range;
- range = N_FUN_addr_to_sym_idx.equal_range(nlist.n_value);
- if (range.first != range.second)
- {
- bool found_it = false;
- for (ValueToSymbolIndexMap::const_iterator pos = range.first; pos != range.second; ++pos)
- {
- if (sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled) == sym[pos->second].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled))
- {
- m_nlist_idx_to_sym_idx[nlist_idx] = pos->second;
- // We just need the flags from the linker symbol, so put these flags
- // into the N_FUN flags to avoid duplicate symbols in the symbol table
- sym[pos->second].SetExternal(sym[sym_idx].IsExternal());
- sym[pos->second].SetFlags (nlist.n_type << 16 | nlist.n_desc);
- if (resolver_addresses.find(nlist.n_value) != resolver_addresses.end())
- sym[pos->second].SetType (eSymbolTypeResolver);
- sym[sym_idx].Clear();
- found_it = true;
- break;
- }
+ std::pair<ValueToSymbolIndexMap::const_iterator,
+ ValueToSymbolIndexMap::const_iterator>
+ range;
+ range = N_FUN_addr_to_sym_idx.equal_range(
+ nlist.n_value);
+ if (range.first != range.second) {
+ bool found_it = false;
+ for (ValueToSymbolIndexMap::const_iterator pos =
+ range.first;
+ pos != range.second; ++pos) {
+ if (sym[sym_idx].GetMangled().GetName(
+ lldb::eLanguageTypeUnknown,
+ Mangled::ePreferMangled) ==
+ sym[pos->second].GetMangled().GetName(
+ lldb::eLanguageTypeUnknown,
+ Mangled::ePreferMangled)) {
+ m_nlist_idx_to_sym_idx[nlist_idx] =
+ pos->second;
+ // We just need the flags from the linker
+ // symbol, so put these flags
+ // into the N_FUN flags to avoid duplicate
+ // symbols in the symbol table
+ sym[pos->second].SetExternal(
+ sym[sym_idx].IsExternal());
+ sym[pos->second].SetFlags(nlist.n_type << 16 |
+ nlist.n_desc);
+ if (resolver_addresses.find(nlist.n_value) !=
+ resolver_addresses.end())
+ sym[pos->second].SetType(
+ eSymbolTypeResolver);
+ sym[sym_idx].Clear();
+ found_it = true;
+ break;
}
- if (found_it)
- continue;
- }
- else
- {
- if (resolver_addresses.find(nlist.n_value) != resolver_addresses.end())
- type = eSymbolTypeResolver;
+ }
+ if (found_it)
+ continue;
+ } else {
+ if (resolver_addresses.find(nlist.n_value) !=
+ resolver_addresses.end())
+ type = eSymbolTypeResolver;
}
- }
- else if (type == eSymbolTypeData ||
- type == eSymbolTypeObjCClass ||
- type == eSymbolTypeObjCMetaClass ||
- type == eSymbolTypeObjCIVar )
- {
- // See if we can find a N_STSYM entry for any data symbols.
- // If we do find a match, and the name matches, then we
- // can merge the two into just the Static symbol to avoid
+ } else if (type == eSymbolTypeData ||
+ type == eSymbolTypeObjCClass ||
+ type == eSymbolTypeObjCMetaClass ||
+ type == eSymbolTypeObjCIVar) {
+ // See if we can find a N_STSYM entry for any data
+ // symbols.
+ // If we do find a match, and the name matches, then
+ // we
+ // can merge the two into just the Static symbol to
+ // avoid
// duplicate entries in the symbol table
- std::pair<ValueToSymbolIndexMap::const_iterator, ValueToSymbolIndexMap::const_iterator> range;
- range = N_STSYM_addr_to_sym_idx.equal_range(nlist.n_value);
- if (range.first != range.second)
- {
- bool found_it = false;
- for (ValueToSymbolIndexMap::const_iterator pos = range.first; pos != range.second; ++pos)
- {
- if (sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled) == sym[pos->second].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled))
- {
- m_nlist_idx_to_sym_idx[nlist_idx] = pos->second;
- // We just need the flags from the linker symbol, so put these flags
- // into the N_STSYM flags to avoid duplicate symbols in the symbol table
- sym[pos->second].SetExternal(sym[sym_idx].IsExternal());
- sym[pos->second].SetFlags (nlist.n_type << 16 | nlist.n_desc);
- sym[sym_idx].Clear();
- found_it = true;
- break;
- }
+ std::pair<ValueToSymbolIndexMap::const_iterator,
+ ValueToSymbolIndexMap::const_iterator>
+ range;
+ range = N_STSYM_addr_to_sym_idx.equal_range(
+ nlist.n_value);
+ if (range.first != range.second) {
+ bool found_it = false;
+ for (ValueToSymbolIndexMap::const_iterator pos =
+ range.first;
+ pos != range.second; ++pos) {
+ if (sym[sym_idx].GetMangled().GetName(
+ lldb::eLanguageTypeUnknown,
+ Mangled::ePreferMangled) ==
+ sym[pos->second].GetMangled().GetName(
+ lldb::eLanguageTypeUnknown,
+ Mangled::ePreferMangled)) {
+ m_nlist_idx_to_sym_idx[nlist_idx] =
+ pos->second;
+ // We just need the flags from the linker
+ // symbol, so put these flags
+ // into the N_STSYM flags to avoid duplicate
+ // symbols in the symbol table
+ sym[pos->second].SetExternal(
+ sym[sym_idx].IsExternal());
+ sym[pos->second].SetFlags(nlist.n_type << 16 |
+ nlist.n_desc);
+ sym[sym_idx].Clear();
+ found_it = true;
+ break;
}
- if (found_it)
- continue;
- }
- else
- {
- // Combine N_GSYM stab entries with the non stab symbol
- const char *gsym_name = sym[sym_idx].GetMangled().GetName(lldb::eLanguageTypeUnknown, Mangled::ePreferMangled).GetCString();
- if (gsym_name)
- {
- ConstNameToSymbolIndexMap::const_iterator pos = N_GSYM_name_to_sym_idx.find(gsym_name);
- if (pos != N_GSYM_name_to_sym_idx.end())
- {
- const uint32_t GSYM_sym_idx = pos->second;
- m_nlist_idx_to_sym_idx[nlist_idx] = GSYM_sym_idx;
- // Copy the address, because often the N_GSYM address has an invalid address of zero
- // when the global is a common symbol
- sym[GSYM_sym_idx].GetAddressRef().SetSection (symbol_section);
- sym[GSYM_sym_idx].GetAddressRef().SetOffset (symbol_value);
- // We just need the flags from the linker symbol, so put these flags
- // into the N_GSYM flags to avoid duplicate symbols in the symbol table
- sym[GSYM_sym_idx].SetFlags (nlist.n_type << 16 | nlist.n_desc);
- sym[sym_idx].Clear();
- continue;
- }
+ }
+ if (found_it)
+ continue;
+ } else {
+ const char *gsym_name =
+ sym[sym_idx]
+ .GetMangled()
+ .GetName(lldb::eLanguageTypeUnknown,
+ Mangled::ePreferMangled)
+ .GetCString();
+ if (gsym_name) {
+ // Combine N_GSYM stab entries with the non stab
+ // symbol
+ ConstNameToSymbolIndexMap::const_iterator pos =
+ N_GSYM_name_to_sym_idx.find(gsym_name);
+ if (pos != N_GSYM_name_to_sym_idx.end()) {
+ const uint32_t GSYM_sym_idx = pos->second;
+ m_nlist_idx_to_sym_idx[nlist_idx] =
+ GSYM_sym_idx;
+ // Copy the address, because often the N_GSYM
+ // address has an invalid address of zero
+ // when the global is a common symbol
+ sym[GSYM_sym_idx].GetAddressRef().SetSection(
+ symbol_section);
+ sym[GSYM_sym_idx].GetAddressRef().SetOffset(
+ symbol_value);
+ // We just need the flags from the linker
+ // symbol, so put these flags
+ // into the N_GSYM flags to avoid duplicate
+ // symbols in the symbol table
+ sym[GSYM_sym_idx].SetFlags(
+ nlist.n_type << 16 | nlist.n_desc);
+ sym[sym_idx].Clear();
+ continue;
}
+ }
}
+ }
}
- }
- sym[sym_idx].SetID (nlist_idx);
- sym[sym_idx].SetType (type);
- if (set_value)
- {
- sym[sym_idx].GetAddressRef().SetSection (symbol_section);
- sym[sym_idx].GetAddressRef().SetOffset (symbol_value);
- }
- sym[sym_idx].SetFlags (nlist.n_type << 16 | nlist.n_desc);
-
- if (symbol_byte_size > 0)
- sym[sym_idx].SetByteSize(symbol_byte_size);
+ sym[sym_idx].SetID(nlist_idx);
+ sym[sym_idx].SetType(type);
+ if (set_value) {
+ sym[sym_idx].GetAddressRef().SetSection(
+ symbol_section);
+ sym[sym_idx].GetAddressRef().SetOffset(symbol_value);
+ }
+ sym[sym_idx].SetFlags(nlist.n_type << 16 |
+ nlist.n_desc);
- if (demangled_is_synthesized)
- sym[sym_idx].SetDemangledNameIsSynthesized(true);
+ if (symbol_byte_size > 0)
+ sym[sym_idx].SetByteSize(symbol_byte_size);
- ++sym_idx;
- }
- else
- {
- sym[sym_idx].Clear();
+ if (demangled_is_synthesized)
+ sym[sym_idx].SetDemangledNameIsSynthesized(true);
+ ++sym_idx;
+ } else {
+ sym[sym_idx].Clear();
+ }
+ }
+ /////////////////////////////
+ }
+ break; // No more entries to consider
}
- }
+ }
- for (const auto &pos :reexport_shlib_needs_fixup)
- {
+ for (const auto &pos : reexport_shlib_needs_fixup) {
const auto undef_pos = undefined_name_to_desc.find(pos.second);
- if (undef_pos != undefined_name_to_desc.end())
- {
- const uint8_t dylib_ordinal = llvm::MachO::GET_LIBRARY_ORDINAL(undef_pos->second);
- if (dylib_ordinal > 0 && dylib_ordinal < dylib_files.GetSize())
- sym[pos.first].SetReExportedSymbolSharedLibrary(dylib_files.GetFileSpecAtIndex(dylib_ordinal-1));
+ if (undef_pos != undefined_name_to_desc.end()) {
+ const uint8_t dylib_ordinal =
+ llvm::MachO::GET_LIBRARY_ORDINAL(undef_pos->second);
+ if (dylib_ordinal > 0 &&
+ dylib_ordinal < dylib_files.GetSize())
+ sym[pos.first].SetReExportedSymbolSharedLibrary(
+ dylib_files.GetFileSpecAtIndex(dylib_ordinal - 1));
}
+ }
}
+ }
}
+ }
+ }
- uint32_t synthetic_sym_id = symtab_load_command.nsyms;
+ // Must reset this in case it was mutated above!
+ nlist_data_offset = 0;
+#endif
- if (function_starts_count > 0)
- {
- uint32_t num_synthetic_function_symbols = 0;
- for (i=0; i<function_starts_count; ++i)
- {
- if (function_starts.GetEntryRef (i).data == false)
- ++num_synthetic_function_symbols;
+ if (nlist_data.GetByteSize() > 0) {
+
+ // If the sym array was not created while parsing the DSC unmapped
+ // symbols, create it now.
+ if (sym == NULL) {
+ sym = symtab->Resize(symtab_load_command.nsyms +
+ m_dysymtab.nindirectsyms);
+ num_syms = symtab->GetNumSymbols();
+ }
+
+ if (unmapped_local_symbols_found) {
+ assert(m_dysymtab.ilocalsym == 0);
+ nlist_data_offset += (m_dysymtab.nlocalsym * nlist_byte_size);
+ nlist_idx = m_dysymtab.nlocalsym;
+ } else {
+ nlist_idx = 0;
+ }
+
+ typedef std::map<ConstString, uint16_t> UndefinedNameToDescMap;
+ typedef std::map<uint32_t, ConstString> SymbolIndexToName;
+ UndefinedNameToDescMap undefined_name_to_desc;
+ SymbolIndexToName reexport_shlib_needs_fixup;
+ for (; nlist_idx < symtab_load_command.nsyms; ++nlist_idx) {
+ struct nlist_64 nlist;
+ if (!nlist_data.ValidOffsetForDataOfSize(nlist_data_offset,
+ nlist_byte_size))
+ break;
+
+ nlist.n_strx = nlist_data.GetU32_unchecked(&nlist_data_offset);
+ nlist.n_type = nlist_data.GetU8_unchecked(&nlist_data_offset);
+ nlist.n_sect = nlist_data.GetU8_unchecked(&nlist_data_offset);
+ nlist.n_desc = nlist_data.GetU16_unchecked(&nlist_data_offset);
+ nlist.n_value = nlist_data.GetAddress_unchecked(&nlist_data_offset);
+
+ SymbolType type = eSymbolTypeInvalid;
+ const char *symbol_name = NULL;
+
+ if (have_strtab_data) {
+ symbol_name = strtab_data.PeekCStr(nlist.n_strx);
+
+ if (symbol_name == NULL) {
+ // No symbol should be NULL, even the symbols with no
+ // string values should have an offset zero which points
+ // to an empty C-string
+ Host::SystemLog(Host::eSystemLogError,
+ "error: symbol[%u] has invalid string table offset "
+ "0x%x in %s, ignoring symbol\n",
+ nlist_idx, nlist.n_strx,
+ module_sp->GetFileSpec().GetPath().c_str());
+ continue;
+ }
+ if (symbol_name[0] == '\0')
+ symbol_name = NULL;
+ } else {
+ const addr_t str_addr = strtab_addr + nlist.n_strx;
+ Error str_error;
+ if (process->ReadCStringFromMemory(str_addr, memory_symbol_name,
+ str_error))
+ symbol_name = memory_symbol_name.c_str();
+ }
+ const char *symbol_name_non_abi_mangled = NULL;
+
+ SectionSP symbol_section;
+ lldb::addr_t symbol_byte_size = 0;
+ bool add_nlist = true;
+ bool is_gsym = false;
+ bool is_debug = ((nlist.n_type & N_STAB) != 0);
+ bool demangled_is_synthesized = false;
+ bool set_value = true;
+ assert(sym_idx < num_syms);
+
+ sym[sym_idx].SetDebug(is_debug);
+
+ if (is_debug) {
+ switch (nlist.n_type) {
+ case N_GSYM:
+ // global symbol: name,,NO_SECT,type,0
+ // Sometimes the N_GSYM value contains the address.
+
+ // FIXME: In the .o files, we have a GSYM and a debug symbol for all
+ // the ObjC data. They
+ // have the same address, but we want to ensure that we always find
+ // only the real symbol,
+ // 'cause we don't currently correctly attribute the GSYM one to the
+ // ObjCClass/Ivar/MetaClass
+ // symbol type. This is a temporary hack to make sure the
+ // ObjectiveC symbols get treated
+ // correctly. To do this right, we should coalesce all the GSYM &
+ // global symbols that have the
+ // same address.
+ is_gsym = true;
+ sym[sym_idx].SetExternal(true);
+
+ if (symbol_name && symbol_name[0] == '_' && symbol_name[1] == 'O') {
+ llvm::StringRef symbol_name_ref(symbol_name);
+ if (symbol_name_ref.startswith(g_objc_v2_prefix_class)) {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name = symbol_name + g_objc_v2_prefix_class.size();
+ type = eSymbolTypeObjCClass;
+ demangled_is_synthesized = true;
+
+ } else if (symbol_name_ref.startswith(
+ g_objc_v2_prefix_metaclass)) {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name = symbol_name + g_objc_v2_prefix_metaclass.size();
+ type = eSymbolTypeObjCMetaClass;
+ demangled_is_synthesized = true;
+ } else if (symbol_name_ref.startswith(g_objc_v2_prefix_ivar)) {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name = symbol_name + g_objc_v2_prefix_ivar.size();
+ type = eSymbolTypeObjCIVar;
+ demangled_is_synthesized = true;
+ }
+ } else {
+ if (nlist.n_value != 0)
+ symbol_section =
+ section_info.GetSection(nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeData;
}
+ break;
- if (num_synthetic_function_symbols > 0)
- {
- if (num_syms < sym_idx + num_synthetic_function_symbols)
- {
- num_syms = sym_idx + num_synthetic_function_symbols;
- sym = symtab->Resize (num_syms);
- }
- for (i=0; i<function_starts_count; ++i)
- {
- const FunctionStarts::Entry *func_start_entry = function_starts.GetEntryAtIndex (i);
- if (func_start_entry->data == false)
- {
- addr_t symbol_file_addr = func_start_entry->addr;
- uint32_t symbol_flags = 0;
- if (is_arm)
- {
- if (symbol_file_addr & 1)
- symbol_flags = MACHO_NLIST_ARM_SYMBOL_IS_THUMB;
- symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
- }
- Address symbol_addr;
- if (module_sp->ResolveFileAddress (symbol_file_addr, symbol_addr))
- {
- SectionSP symbol_section (symbol_addr.GetSection());
- uint32_t symbol_byte_size = 0;
- if (symbol_section)
- {
- const addr_t section_file_addr = symbol_section->GetFileAddress();
- const FunctionStarts::Entry *next_func_start_entry = function_starts.FindNextEntry (func_start_entry);
- const addr_t section_end_file_addr = section_file_addr + symbol_section->GetByteSize();
- if (next_func_start_entry)
- {
- addr_t next_symbol_file_addr = next_func_start_entry->addr;
- if (is_arm)
- next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
- symbol_byte_size = std::min<lldb::addr_t>(next_symbol_file_addr - symbol_file_addr, section_end_file_addr - symbol_file_addr);
- }
- else
- {
- symbol_byte_size = section_end_file_addr - symbol_file_addr;
- }
- sym[sym_idx].SetID (synthetic_sym_id++);
- sym[sym_idx].GetMangled().SetDemangledName(GetNextSyntheticSymbolName());
- sym[sym_idx].SetType (eSymbolTypeCode);
- sym[sym_idx].SetIsSynthetic (true);
- sym[sym_idx].GetAddressRef() = symbol_addr;
- if (symbol_flags)
- sym[sym_idx].SetFlags (symbol_flags);
- if (symbol_byte_size)
- sym[sym_idx].SetByteSize (symbol_byte_size);
- ++sym_idx;
- }
- }
- }
- }
+ case N_FNAME:
+ // procedure name (f77 kludge): name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_FUN:
+ // procedure: name,,n_sect,linenumber,address
+ if (symbol_name) {
+ type = eSymbolTypeCode;
+ symbol_section =
+ section_info.GetSection(nlist.n_sect, nlist.n_value);
+
+ N_FUN_addr_to_sym_idx.insert(
+ std::make_pair(nlist.n_value, sym_idx));
+ // We use the current number of symbols in the symbol table in
+ // lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ N_FUN_indexes.push_back(sym_idx);
+ } else {
+ type = eSymbolTypeCompiler;
+
+ if (!N_FUN_indexes.empty()) {
+ // Copy the size of the function into the original STAB entry so
+ // we don't have
+ // to hunt for it later
+ symtab->SymbolAtIndex(N_FUN_indexes.back())
+ ->SetByteSize(nlist.n_value);
+ N_FUN_indexes.pop_back();
+ // We don't really need the end function STAB as it contains the
+ // size which
+ // we already placed with the original symbol, so don't add it
+ // if we want a
+ // minimal symbol table
+ add_nlist = false;
+ }
}
- }
+ break;
- // Trim our symbols down to just what we ended up with after
- // removing any symbols.
- if (sym_idx < num_syms)
- {
- num_syms = sym_idx;
- sym = symtab->Resize (num_syms);
- }
+ case N_STSYM:
+ // static symbol: name,,n_sect,type,address
+ N_STSYM_addr_to_sym_idx.insert(
+ std::make_pair(nlist.n_value, sym_idx));
+ symbol_section =
+ section_info.GetSection(nlist.n_sect, nlist.n_value);
+ if (symbol_name && symbol_name[0]) {
+ type = ObjectFile::GetSymbolTypeFromName(symbol_name + 1,
+ eSymbolTypeData);
+ }
+ break;
- // Now synthesize indirect symbols
- if (m_dysymtab.nindirectsyms != 0)
- {
- if (indirect_symbol_index_data.GetByteSize())
- {
- NListIndexToSymbolIndexMap::const_iterator end_index_pos = m_nlist_idx_to_sym_idx.end();
+ case N_LCSYM:
+ // .lcomm symbol: name,,n_sect,type,address
+ symbol_section =
+ section_info.GetSection(nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeCommonBlock;
+ break;
- for (uint32_t sect_idx = 1; sect_idx < m_mach_sections.size(); ++sect_idx)
- {
- if ((m_mach_sections[sect_idx].flags & SECTION_TYPE) == S_SYMBOL_STUBS)
- {
- uint32_t symbol_stub_byte_size = m_mach_sections[sect_idx].reserved2;
- if (symbol_stub_byte_size == 0)
- continue;
-
- const uint32_t num_symbol_stubs = m_mach_sections[sect_idx].size / symbol_stub_byte_size;
-
- if (num_symbol_stubs == 0)
- continue;
-
- const uint32_t symbol_stub_index_offset = m_mach_sections[sect_idx].reserved1;
- for (uint32_t stub_idx = 0; stub_idx < num_symbol_stubs; ++stub_idx)
- {
- const uint32_t symbol_stub_index = symbol_stub_index_offset + stub_idx;
- const lldb::addr_t symbol_stub_addr = m_mach_sections[sect_idx].addr + (stub_idx * symbol_stub_byte_size);
- lldb::offset_t symbol_stub_offset = symbol_stub_index * 4;
- if (indirect_symbol_index_data.ValidOffsetForDataOfSize(symbol_stub_offset, 4))
- {
- const uint32_t stub_sym_id = indirect_symbol_index_data.GetU32 (&symbol_stub_offset);
- if (stub_sym_id & (INDIRECT_SYMBOL_ABS | INDIRECT_SYMBOL_LOCAL))
- continue;
-
- NListIndexToSymbolIndexMap::const_iterator index_pos = m_nlist_idx_to_sym_idx.find (stub_sym_id);
- Symbol *stub_symbol = NULL;
- if (index_pos != end_index_pos)
- {
- // We have a remapping from the original nlist index to
- // a current symbol index, so just look this up by index
- stub_symbol = symtab->SymbolAtIndex (index_pos->second);
- }
- else
- {
- // We need to lookup a symbol using the original nlist
- // symbol index since this index is coming from the
- // S_SYMBOL_STUBS
- stub_symbol = symtab->FindSymbolByID (stub_sym_id);
- }
+ case N_BNSYM:
+ // We use the current number of symbols in the symbol table in lieu
+ // of
+ // using nlist_idx in case we ever start trimming entries out
+ // Skip these if we want minimal symbol tables
+ add_nlist = false;
+ break;
- if (stub_symbol)
- {
- Address so_addr(symbol_stub_addr, section_list);
-
- if (stub_symbol->GetType() == eSymbolTypeUndefined)
- {
- // Change the external symbol into a trampoline that makes sense
- // These symbols were N_UNDF N_EXT, and are useless to us, so we
- // can re-use them so we don't have to make up a synthetic symbol
- // for no good reason.
- if (resolver_addresses.find(symbol_stub_addr) == resolver_addresses.end())
- stub_symbol->SetType (eSymbolTypeTrampoline);
- else
- stub_symbol->SetType (eSymbolTypeResolver);
- stub_symbol->SetExternal (false);
- stub_symbol->GetAddressRef() = so_addr;
- stub_symbol->SetByteSize (symbol_stub_byte_size);
- }
- else
- {
- // Make a synthetic symbol to describe the trampoline stub
- Mangled stub_symbol_mangled_name(stub_symbol->GetMangled());
- if (sym_idx >= num_syms)
- {
- sym = symtab->Resize (++num_syms);
- stub_symbol = NULL; // this pointer no longer valid
- }
- sym[sym_idx].SetID (synthetic_sym_id++);
- sym[sym_idx].GetMangled() = stub_symbol_mangled_name;
- if (resolver_addresses.find(symbol_stub_addr) == resolver_addresses.end())
- sym[sym_idx].SetType (eSymbolTypeTrampoline);
- else
- sym[sym_idx].SetType (eSymbolTypeResolver);
- sym[sym_idx].SetIsSynthetic (true);
- sym[sym_idx].GetAddressRef() = so_addr;
- sym[sym_idx].SetByteSize (symbol_stub_byte_size);
- ++sym_idx;
- }
- }
- else
- {
- if (log)
- log->Warning ("symbol stub referencing symbol table symbol %u that isn't in our minimal symbol table, fix this!!!", stub_sym_id);
- }
- }
- }
- }
- }
- }
- }
+ case N_ENSYM:
+ // Set the size of the N_BNSYM to the terminating index of this
+ // N_ENSYM
+ // so that we can always skip the entire symbol if we need to
+ // navigate
+ // more quickly at the source level when parsing STABS
+ // Skip these if we want minimal symbol tables
+ add_nlist = false;
+ break;
- if (!trie_entries.empty())
- {
- for (const auto &e : trie_entries)
- {
- if (e.entry.import_name)
- {
- // Only add indirect symbols from the Trie entries if we
- // didn't have a N_INDR nlist entry for this already
- if (indirect_symbol_names.find(e.entry.name) == indirect_symbol_names.end())
- {
- // Make a synthetic symbol to describe re-exported symbol.
- if (sym_idx >= num_syms)
- sym = symtab->Resize (++num_syms);
- sym[sym_idx].SetID (synthetic_sym_id++);
- sym[sym_idx].GetMangled() = Mangled(e.entry.name);
- sym[sym_idx].SetType (eSymbolTypeReExported);
- sym[sym_idx].SetIsSynthetic (true);
- sym[sym_idx].SetReExportedSymbolName(e.entry.import_name);
- if (e.entry.other > 0 && e.entry.other <= dylib_files.GetSize())
- {
- sym[sym_idx].SetReExportedSymbolSharedLibrary(dylib_files.GetFileSpecAtIndex(e.entry.other-1));
- }
- ++sym_idx;
+ case N_OPT:
+ // emitted with gcc2_compiled and in gcc source
+ type = eSymbolTypeCompiler;
+ break;
+
+ case N_RSYM:
+ // register sym: name,,NO_SECT,type,register
+ type = eSymbolTypeVariable;
+ break;
+
+ case N_SLINE:
+ // src line: 0,,n_sect,linenumber,address
+ symbol_section =
+ section_info.GetSection(nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeLineEntry;
+ break;
+
+ case N_SSYM:
+ // structure elt: name,,NO_SECT,type,struct_offset
+ type = eSymbolTypeVariableType;
+ break;
+
+ case N_SO:
+ // source file name
+ type = eSymbolTypeSourceFile;
+ if (symbol_name == NULL) {
+ add_nlist = false;
+ if (N_SO_index != UINT32_MAX) {
+ // Set the size of the N_SO to the terminating index of this
+ // N_SO
+ // so that we can always skip the entire N_SO if we need to
+ // navigate
+ // more quickly at the source level when parsing STABS
+ symbol_ptr = symtab->SymbolAtIndex(N_SO_index);
+ symbol_ptr->SetByteSize(sym_idx);
+ symbol_ptr->SetSizeIsSibling(true);
+ }
+ N_NSYM_indexes.clear();
+ N_INCL_indexes.clear();
+ N_BRAC_indexes.clear();
+ N_COMM_indexes.clear();
+ N_FUN_indexes.clear();
+ N_SO_index = UINT32_MAX;
+ } else {
+ // We use the current number of symbols in the symbol table in
+ // lieu of
+ // using nlist_idx in case we ever start trimming entries out
+ const bool N_SO_has_full_path = symbol_name[0] == '/';
+ if (N_SO_has_full_path) {
+ if ((N_SO_index == sym_idx - 1) && ((sym_idx - 1) < num_syms)) {
+ // We have two consecutive N_SO entries where the first
+ // contains a directory
+ // and the second contains a full path.
+ sym[sym_idx - 1].GetMangled().SetValue(
+ ConstString(symbol_name), false);
+ m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1;
+ add_nlist = false;
+ } else {
+ // This is the first entry in a N_SO that contains a directory
+ // or
+ // a full path to the source file
+ N_SO_index = sym_idx;
+ }
+ } else if ((N_SO_index == sym_idx - 1) &&
+ ((sym_idx - 1) < num_syms)) {
+ // This is usually the second N_SO entry that contains just the
+ // filename,
+ // so here we combine it with the first one if we are minimizing
+ // the symbol table
+ const char *so_path =
+ sym[sym_idx - 1]
+ .GetMangled()
+ .GetDemangledName(lldb::eLanguageTypeUnknown)
+ .AsCString();
+ if (so_path && so_path[0]) {
+ std::string full_so_path(so_path);
+ const size_t double_slash_pos = full_so_path.find("//");
+ if (double_slash_pos != std::string::npos) {
+ // The linker has been generating bad N_SO entries with
+ // doubled up paths
+ // in the format "%s%s" where the first string in the
+ // DW_AT_comp_dir,
+ // and the second is the directory for the source file so
+ // you end up with
+ // a path that looks like "/tmp/src//tmp/src/"
+ FileSpec so_dir(so_path, false);
+ if (!so_dir.Exists()) {
+ so_dir.SetFile(&full_so_path[double_slash_pos + 1],
+ false);
+ if (so_dir.Exists()) {
+ // Trim off the incorrect path
+ full_so_path.erase(0, double_slash_pos + 1);
+ }
}
+ }
+ if (*full_so_path.rbegin() != '/')
+ full_so_path += '/';
+ full_so_path += symbol_name;
+ sym[sym_idx - 1].GetMangled().SetValue(
+ ConstString(full_so_path.c_str()), false);
+ add_nlist = false;
+ m_nlist_idx_to_sym_idx[nlist_idx] = sym_idx - 1;
}
+ } else {
+ // This could be a relative path to a N_SO
+ N_SO_index = sym_idx;
+ }
}
- }
-
-// StreamFile s(stdout, false);
-// s.Printf ("Symbol table before CalculateSymbolSizes():\n");
-// symtab->Dump(&s, NULL, eSortOrderNone);
- // Set symbol byte sizes correctly since mach-o nlist entries don't have sizes
- symtab->CalculateSymbolSizes();
+ break;
-// s.Printf ("Symbol table after CalculateSymbolSizes():\n");
-// symtab->Dump(&s, NULL, eSortOrderNone);
+ case N_OSO:
+ // object file name: name,,0,0,st_mtime
+ type = eSymbolTypeObjectFile;
+ break;
- return symtab->GetNumSymbols();
- }
- return 0;
-}
+ case N_LSYM:
+ // local sym: name,,NO_SECT,type,offset
+ type = eSymbolTypeLocal;
+ break;
-void
-ObjectFileMachO::Dump (Stream *s)
-{
- ModuleSP module_sp(GetModule());
- if (module_sp)
- {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- s->Printf("%p: ", static_cast<void*>(this));
- s->Indent();
- if (m_header.magic == MH_MAGIC_64 || m_header.magic == MH_CIGAM_64)
- s->PutCString("ObjectFileMachO64");
- else
- s->PutCString("ObjectFileMachO32");
+ //----------------------------------------------------------------------
+ // INCL scopes
+ //----------------------------------------------------------------------
+ case N_BINCL:
+ // include file beginning: name,,NO_SECT,0,sum
+ // We use the current number of symbols in the symbol table in lieu
+ // of
+ // using nlist_idx in case we ever start trimming entries out
+ N_INCL_indexes.push_back(sym_idx);
+ type = eSymbolTypeScopeBegin;
+ break;
- ArchSpec header_arch;
- GetArchitecture(header_arch);
+ case N_EINCL:
+ // include file end: name,,NO_SECT,0,0
+ // Set the size of the N_BINCL to the terminating index of this
+ // N_EINCL
+ // so that we can always skip the entire symbol if we need to
+ // navigate
+ // more quickly at the source level when parsing STABS
+ if (!N_INCL_indexes.empty()) {
+ symbol_ptr = symtab->SymbolAtIndex(N_INCL_indexes.back());
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ N_INCL_indexes.pop_back();
+ }
+ type = eSymbolTypeScopeEnd;
+ break;
- *s << ", file = '" << m_file << "', arch = " << header_arch.GetArchitectureName() << "\n";
+ case N_SOL:
+ // #included file name: name,,n_sect,0,address
+ type = eSymbolTypeHeaderFile;
- SectionList *sections = GetSectionList();
- if (sections)
- sections->Dump(s, NULL, true, UINT32_MAX);
+ // We currently don't use the header files on darwin
+ add_nlist = false;
+ break;
- if (m_symtab_ap.get())
- m_symtab_ap->Dump(s, NULL, eSortOrderNone);
- }
-}
+ case N_PARAMS:
+ // compiler parameters: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
-bool
-ObjectFileMachO::GetUUID (const llvm::MachO::mach_header &header,
- const lldb_private::DataExtractor &data,
- lldb::offset_t lc_offset,
- lldb_private::UUID& uuid)
-{
- uint32_t i;
- struct uuid_command load_cmd;
+ case N_VERSION:
+ // compiler version: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
+ break;
- lldb::offset_t offset = lc_offset;
- for (i=0; i<header.ncmds; ++i)
- {
- const lldb::offset_t cmd_offset = offset;
- if (data.GetU32(&offset, &load_cmd, 2) == NULL)
+ case N_OLEVEL:
+ // compiler -O level: name,,NO_SECT,0,0
+ type = eSymbolTypeCompiler;
break;
-
- if (load_cmd.cmd == LC_UUID)
- {
- const uint8_t *uuid_bytes = data.PeekData(offset, 16);
-
- if (uuid_bytes)
- {
- // OpenCL on Mac OS X uses the same UUID for each of its object files.
- // We pretend these object files have no UUID to prevent crashing.
-
- const uint8_t opencl_uuid[] = { 0x8c, 0x8e, 0xb3, 0x9b,
- 0x3b, 0xa8,
- 0x4b, 0x16,
- 0xb6, 0xa4,
- 0x27, 0x63, 0xbb, 0x14, 0xf0, 0x0d };
-
- if (!memcmp(uuid_bytes, opencl_uuid, 16))
- return false;
-
- uuid.SetBytes (uuid_bytes);
- return true;
- }
- return false;
- }
- offset = cmd_offset + load_cmd.cmdsize;
- }
- return false;
-}
-bool
-ObjectFileMachO::GetArchitecture (const llvm::MachO::mach_header &header,
- const lldb_private::DataExtractor &data,
- lldb::offset_t lc_offset,
- ArchSpec &arch)
-{
- arch.SetArchitecture (eArchTypeMachO, header.cputype, header.cpusubtype);
-
- if (arch.IsValid())
- {
- llvm::Triple &triple = arch.GetTriple();
-
- // Set OS to an unspecified unknown or a "*" so it can match any OS
- triple.setOS(llvm::Triple::UnknownOS);
- triple.setOSName(llvm::StringRef());
-
- if (header.filetype == MH_PRELOAD)
- {
- if (header.cputype == CPU_TYPE_ARM)
- {
- // If this is a 32-bit arm binary, and it's a standalone binary,
- // force the Vendor to Apple so we don't accidentally pick up
- // the generic armv7 ABI at runtime. Apple's armv7 ABI always uses
- // r7 for the frame pointer register; most other armv7 ABIs use a
- // combination of r7 and r11.
- triple.setVendor(llvm::Triple::Apple);
- }
- else
- {
- // Set vendor to an unspecified unknown or a "*" so it can match any vendor
- // This is required for correct behavior of EFI debugging on x86_64
- triple.setVendor(llvm::Triple::UnknownVendor);
- triple.setVendorName(llvm::StringRef());
+ case N_PSYM:
+ // parameter: name,,NO_SECT,type,offset
+ type = eSymbolTypeVariable;
+ break;
+
+ case N_ENTRY:
+ // alternate entry: name,,n_sect,linenumber,address
+ symbol_section =
+ section_info.GetSection(nlist.n_sect, nlist.n_value);
+ type = eSymbolTypeLineEntry;
+ break;
+
+ //----------------------------------------------------------------------
+ // Left and Right Braces
+ //----------------------------------------------------------------------
+ case N_LBRAC:
+ // left bracket: 0,,NO_SECT,nesting level,address
+ // We use the current number of symbols in the symbol table in lieu
+ // of
+ // using nlist_idx in case we ever start trimming entries out
+ symbol_section =
+ section_info.GetSection(nlist.n_sect, nlist.n_value);
+ N_BRAC_indexes.push_back(sym_idx);
+ type = eSymbolTypeScopeBegin;
+ break;
+
+ case N_RBRAC:
+ // right bracket: 0,,NO_SECT,nesting level,address
+ // Set the size of the N_LBRAC to the terminating index of this
+ // N_RBRAC
+ // so that we can always skip the entire symbol if we need to
+ // navigate
+ // more quickly at the source level when parsing STABS
+ symbol_section =
+ section_info.GetSection(nlist.n_sect, nlist.n_value);
+ if (!N_BRAC_indexes.empty()) {
+ symbol_ptr = symtab->SymbolAtIndex(N_BRAC_indexes.back());
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ N_BRAC_indexes.pop_back();
}
- return true;
- }
- else
- {
- struct load_command load_cmd;
+ type = eSymbolTypeScopeEnd;
+ break;
- lldb::offset_t offset = lc_offset;
- for (uint32_t i=0; i<header.ncmds; ++i)
- {
- const lldb::offset_t cmd_offset = offset;
- if (data.GetU32(&offset, &load_cmd, 2) == NULL)
- break;
-
- switch (load_cmd.cmd)
- {
- case llvm::MachO::LC_VERSION_MIN_IPHONEOS:
- triple.setOS (llvm::Triple::IOS);
- return true;
-
- case llvm::MachO::LC_VERSION_MIN_MACOSX:
- triple.setOS (llvm::Triple::MacOSX);
- return true;
-
- case llvm::MachO::LC_VERSION_MIN_TVOS:
- triple.setOS (llvm::Triple::TvOS);
- return true;
-
- case llvm::MachO::LC_VERSION_MIN_WATCHOS:
- triple.setOS (llvm::Triple::WatchOS);
- return true;
+ case N_EXCL:
+ // deleted include file: name,,NO_SECT,0,sum
+ type = eSymbolTypeHeaderFile;
+ break;
- default:
- break;
- }
+ //----------------------------------------------------------------------
+ // COMM scopes
+ //----------------------------------------------------------------------
+ case N_BCOMM:
+ // begin common: name,,NO_SECT,0,0
+ // We use the current number of symbols in the symbol table in lieu
+ // of
+ // using nlist_idx in case we ever start trimming entries out
+ type = eSymbolTypeScopeBegin;
+ N_COMM_indexes.push_back(sym_idx);
+ break;
- offset = cmd_offset + load_cmd.cmdsize;
+ case N_ECOML:
+ // end common (local name): 0,,n_sect,0,address
+ symbol_section =
+ section_info.GetSection(nlist.n_sect, nlist.n_value);
+ LLVM_FALLTHROUGH;
+
+ case N_ECOMM:
+ // end common: name,,n_sect,0,0
+ // Set the size of the N_BCOMM to the terminating index of this
+ // N_ECOMM/N_ECOML
+ // so that we can always skip the entire symbol if we need to
+ // navigate
+ // more quickly at the source level when parsing STABS
+ if (!N_COMM_indexes.empty()) {
+ symbol_ptr = symtab->SymbolAtIndex(N_COMM_indexes.back());
+ symbol_ptr->SetByteSize(sym_idx + 1);
+ symbol_ptr->SetSizeIsSibling(true);
+ N_COMM_indexes.pop_back();
}
-
- if (header.filetype != MH_KEXT_BUNDLE)
- {
- // We didn't find a LC_VERSION_MIN load command and this isn't a KEXT
- // so lets not say our Vendor is Apple, leave it as an unspecified unknown
- triple.setVendor(llvm::Triple::UnknownVendor);
- triple.setVendorName(llvm::StringRef());
+ type = eSymbolTypeScopeEnd;
+ break;
+
+ case N_LENG:
+ // second stab entry with length information
+ type = eSymbolTypeAdditional;
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ // uint8_t n_pext = N_PEXT & nlist.n_type;
+ uint8_t n_type = N_TYPE & nlist.n_type;
+ sym[sym_idx].SetExternal((N_EXT & nlist.n_type) != 0);
+
+ switch (n_type) {
+ case N_INDR: {
+ const char *reexport_name_cstr =
+ strtab_data.PeekCStr(nlist.n_value);
+ if (reexport_name_cstr && reexport_name_cstr[0]) {
+ type = eSymbolTypeReExported;
+ ConstString reexport_name(
+ reexport_name_cstr +
+ ((reexport_name_cstr[0] == '_') ? 1 : 0));
+ sym[sym_idx].SetReExportedSymbolName(reexport_name);
+ set_value = false;
+ reexport_shlib_needs_fixup[sym_idx] = reexport_name;
+ indirect_symbol_names.insert(
+ ConstString(symbol_name + ((symbol_name[0] == '_') ? 1 : 0)));
+ } else
+ type = eSymbolTypeUndefined;
+ } break;
+
+ case N_UNDF:
+ if (symbol_name && symbol_name[0]) {
+ ConstString undefined_name(symbol_name +
+ ((symbol_name[0] == '_') ? 1 : 0));
+ undefined_name_to_desc[undefined_name] = nlist.n_desc;
}
- }
- }
- return arch.IsValid();
-}
+ LLVM_FALLTHROUGH;
-bool
-ObjectFileMachO::GetUUID (lldb_private::UUID* uuid)
-{
- ModuleSP module_sp(GetModule());
- if (module_sp)
- {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- return GetUUID (m_header, m_data, offset, *uuid);
- }
- return false;
-}
+ case N_PBUD:
+ type = eSymbolTypeUndefined;
+ break;
-uint32_t
-ObjectFileMachO::GetDependentModules (FileSpecList& files)
-{
- uint32_t count = 0;
- ModuleSP module_sp(GetModule());
- if (module_sp)
- {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- struct load_command load_cmd;
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- std::vector<std::string> rpath_paths;
- std::vector<std::string> rpath_relative_paths;
- const bool resolve_path = false; // Don't resolve the dependent file paths since they may not reside on this system
- uint32_t i;
- for (i=0; i<m_header.ncmds; ++i)
- {
- const uint32_t cmd_offset = offset;
- if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
- break;
+ case N_ABS:
+ type = eSymbolTypeAbsolute;
+ break;
- switch (load_cmd.cmd)
- {
- case LC_RPATH:
- case LC_LOAD_DYLIB:
- case LC_LOAD_WEAK_DYLIB:
- case LC_REEXPORT_DYLIB:
- case LC_LOAD_DYLINKER:
- case LC_LOADFVMLIB:
- case LC_LOAD_UPWARD_DYLIB:
- {
- uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
- const char *path = m_data.PeekCStr(name_offset);
- if (path)
- {
- if (load_cmd.cmd == LC_RPATH)
- rpath_paths.push_back(path);
- else
- {
- if (path[0] == '@')
- {
- if (strncmp(path, "@rpath", strlen("@rpath")) == 0)
- rpath_relative_paths.push_back(path + strlen("@rpath"));
- }
- else
- {
- FileSpec file_spec(path, resolve_path);
- if (files.AppendIfUnique(file_spec))
- count++;
- }
+ case N_SECT: {
+ symbol_section =
+ section_info.GetSection(nlist.n_sect, nlist.n_value);
+
+ if (!symbol_section) {
+ // TODO: warn about this?
+ add_nlist = false;
+ break;
+ }
+
+ if (TEXT_eh_frame_sectID == nlist.n_sect) {
+ type = eSymbolTypeException;
+ } else {
+ uint32_t section_type = symbol_section->Get() & SECTION_TYPE;
+
+ switch (section_type) {
+ case S_CSTRING_LITERALS:
+ type = eSymbolTypeData;
+ break; // section with only literal C strings
+ case S_4BYTE_LITERALS:
+ type = eSymbolTypeData;
+ break; // section with only 4 byte literals
+ case S_8BYTE_LITERALS:
+ type = eSymbolTypeData;
+ break; // section with only 8 byte literals
+ case S_LITERAL_POINTERS:
+ type = eSymbolTypeTrampoline;
+ break; // section with only pointers to literals
+ case S_NON_LAZY_SYMBOL_POINTERS:
+ type = eSymbolTypeTrampoline;
+ break; // section with only non-lazy symbol pointers
+ case S_LAZY_SYMBOL_POINTERS:
+ type = eSymbolTypeTrampoline;
+ break; // section with only lazy symbol pointers
+ case S_SYMBOL_STUBS:
+ type = eSymbolTypeTrampoline;
+ break; // section with only symbol stubs, byte size of stub in
+ // the reserved2 field
+ case S_MOD_INIT_FUNC_POINTERS:
+ type = eSymbolTypeCode;
+ break; // section with only function pointers for initialization
+ case S_MOD_TERM_FUNC_POINTERS:
+ type = eSymbolTypeCode;
+ break; // section with only function pointers for termination
+ case S_INTERPOSING:
+ type = eSymbolTypeTrampoline;
+ break; // section with only pairs of function pointers for
+ // interposing
+ case S_16BYTE_LITERALS:
+ type = eSymbolTypeData;
+ break; // section with only 16 byte literals
+ case S_DTRACE_DOF:
+ type = eSymbolTypeInstrumentation;
+ break;
+ case S_LAZY_DYLIB_SYMBOL_POINTERS:
+ type = eSymbolTypeTrampoline;
+ break;
+ default:
+ switch (symbol_section->GetType()) {
+ case lldb::eSectionTypeCode:
+ type = eSymbolTypeCode;
+ break;
+ case eSectionTypeData:
+ case eSectionTypeDataCString: // Inlined C string data
+ case eSectionTypeDataCStringPointers: // Pointers to C string
+ // data
+ case eSectionTypeDataSymbolAddress: // Address of a symbol in
+ // the symbol table
+ case eSectionTypeData4:
+ case eSectionTypeData8:
+ case eSectionTypeData16:
+ type = eSymbolTypeData;
+ break;
+ default:
+ break;
+ }
+ break;
+ }
+
+ if (type == eSymbolTypeInvalid) {
+ const char *symbol_sect_name =
+ symbol_section->GetName().AsCString();
+ if (symbol_section->IsDescendant(text_section_sp.get())) {
+ if (symbol_section->IsClear(S_ATTR_PURE_INSTRUCTIONS |
+ S_ATTR_SELF_MODIFYING_CODE |
+ S_ATTR_SOME_INSTRUCTIONS))
+ type = eSymbolTypeData;
+ else
+ type = eSymbolTypeCode;
+ } else if (symbol_section->IsDescendant(
+ data_section_sp.get()) ||
+ symbol_section->IsDescendant(
+ data_dirty_section_sp.get()) ||
+ symbol_section->IsDescendant(
+ data_const_section_sp.get())) {
+ if (symbol_sect_name &&
+ ::strstr(symbol_sect_name, "__objc") ==
+ symbol_sect_name) {
+ type = eSymbolTypeRuntime;
+
+ if (symbol_name) {
+ llvm::StringRef symbol_name_ref(symbol_name);
+ if (symbol_name_ref.startswith("_OBJC_")) {
+ static const llvm::StringRef g_objc_v2_prefix_class(
+ "_OBJC_CLASS_$_");
+ static const llvm::StringRef g_objc_v2_prefix_metaclass(
+ "_OBJC_METACLASS_$_");
+ static const llvm::StringRef g_objc_v2_prefix_ivar(
+ "_OBJC_IVAR_$_");
+ if (symbol_name_ref.startswith(
+ g_objc_v2_prefix_class)) {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name =
+ symbol_name + g_objc_v2_prefix_class.size();
+ type = eSymbolTypeObjCClass;
+ demangled_is_synthesized = true;
+ } else if (symbol_name_ref.startswith(
+ g_objc_v2_prefix_metaclass)) {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name =
+ symbol_name + g_objc_v2_prefix_metaclass.size();
+ type = eSymbolTypeObjCMetaClass;
+ demangled_is_synthesized = true;
+ } else if (symbol_name_ref.startswith(
+ g_objc_v2_prefix_ivar)) {
+ symbol_name_non_abi_mangled = symbol_name + 1;
+ symbol_name =
+ symbol_name + g_objc_v2_prefix_ivar.size();
+ type = eSymbolTypeObjCIVar;
+ demangled_is_synthesized = true;
}
+ }
+ }
+ } else if (symbol_sect_name &&
+ ::strstr(symbol_sect_name, "__gcc_except_tab") ==
+ symbol_sect_name) {
+ type = eSymbolTypeException;
+ } else {
+ type = eSymbolTypeData;
+ }
+ } else if (symbol_sect_name &&
+ ::strstr(symbol_sect_name, "__IMPORT") ==
+ symbol_sect_name) {
+ type = eSymbolTypeTrampoline;
+ } else if (symbol_section->IsDescendant(
+ objc_section_sp.get())) {
+ type = eSymbolTypeRuntime;
+ if (symbol_name && symbol_name[0] == '.') {
+ llvm::StringRef symbol_name_ref(symbol_name);
+ static const llvm::StringRef g_objc_v1_prefix_class(
+ ".objc_class_name_");
+ if (symbol_name_ref.startswith(g_objc_v1_prefix_class)) {
+ symbol_name_non_abi_mangled = symbol_name;
+ symbol_name = symbol_name + g_objc_v1_prefix_class.size();
+ type = eSymbolTypeObjCClass;
+ demangled_is_synthesized = true;
}
+ }
}
- break;
-
- default:
- break;
+ }
}
- offset = cmd_offset + load_cmd.cmdsize;
+ } break;
+ }
}
- if (!rpath_paths.empty())
- {
- // Fixup all LC_RPATH values to be absolute paths
- FileSpec this_file_spec(m_file);
- this_file_spec.ResolvePath();
- std::string loader_path("@loader_path");
- std::string executable_path("@executable_path");
- for (auto &rpath : rpath_paths)
- {
- if (rpath.find(loader_path) == 0)
- {
- rpath.erase(0, loader_path.size());
- rpath.insert(0, this_file_spec.GetDirectory().GetCString());
+ if (add_nlist) {
+ uint64_t symbol_value = nlist.n_value;
+
+ if (symbol_name_non_abi_mangled) {
+ sym[sym_idx].GetMangled().SetMangledName(
+ ConstString(symbol_name_non_abi_mangled));
+ sym[sym_idx].GetMangled().SetDemangledName(
+ ConstString(symbol_name));
+ } else {
+ bool symbol_name_is_mangled = false;
+
+ if (symbol_name && symbol_name[0] == '_') {
+ symbol_name_is_mangled = symbol_name[1] == '_';
+ symbol_name++; // Skip the leading underscore
+ }
+
+ if (symbol_name) {
+ ConstString const_symbol_name(symbol_name);
+ sym[sym_idx].GetMangled().SetValue(const_symbol_name,
+ symbol_name_is_mangled);
+ }
+ }
+
+ if (is_gsym) {
+ const char *gsym_name = sym[sym_idx]
+ .GetMangled()
+ .GetName(lldb::eLanguageTypeUnknown,
+ Mangled::ePreferMangled)
+ .GetCString();
+ if (gsym_name)
+ N_GSYM_name_to_sym_idx[gsym_name] = sym_idx;
+ }
+
+ if (symbol_section) {
+ const addr_t section_file_addr = symbol_section->GetFileAddress();
+ if (symbol_byte_size == 0 && function_starts_count > 0) {
+ addr_t symbol_lookup_file_addr = nlist.n_value;
+ // Do an exact address match for non-ARM addresses, else get the
+ // closest since
+ // the symbol might be a thumb symbol which has an address with
+ // bit zero set
+ FunctionStarts::Entry *func_start_entry =
+ function_starts.FindEntry(symbol_lookup_file_addr, !is_arm);
+ if (is_arm && func_start_entry) {
+ // Verify that the function start address is the symbol address
+ // (ARM)
+ // or the symbol address + 1 (thumb)
+ if (func_start_entry->addr != symbol_lookup_file_addr &&
+ func_start_entry->addr != (symbol_lookup_file_addr + 1)) {
+ // Not the right entry, NULL it out...
+ func_start_entry = NULL;
}
- else if (rpath.find(executable_path) == 0)
- {
- rpath.erase(0, executable_path.size());
- rpath.insert(0, this_file_spec.GetDirectory().GetCString());
+ }
+ if (func_start_entry) {
+ func_start_entry->data = true;
+
+ addr_t symbol_file_addr = func_start_entry->addr;
+ if (is_arm)
+ symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
+
+ const FunctionStarts::Entry *next_func_start_entry =
+ function_starts.FindNextEntry(func_start_entry);
+ const addr_t section_end_file_addr =
+ section_file_addr + symbol_section->GetByteSize();
+ if (next_func_start_entry) {
+ addr_t next_symbol_file_addr = next_func_start_entry->addr;
+ // Be sure the clear the Thumb address bit when we calculate
+ // the size
+ // from the current and next address
+ if (is_arm)
+ next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
+ symbol_byte_size = std::min<lldb::addr_t>(
+ next_symbol_file_addr - symbol_file_addr,
+ section_end_file_addr - symbol_file_addr);
+ } else {
+ symbol_byte_size = section_end_file_addr - symbol_file_addr;
}
+ }
}
-
- for (const auto &rpath_relative_path : rpath_relative_paths)
- {
- for (const auto &rpath : rpath_paths)
- {
- std::string path = rpath;
- path += rpath_relative_path;
- // It is OK to resolve this path because we must find a file on
- // disk for us to accept it anyway if it is rpath relative.
- FileSpec file_spec(path, true);
- // Remove any redundant parts of the path (like "../foo") since
- // LC_RPATH values often contain "..".
- file_spec.NormalizePath ();
- if (file_spec.Exists() && files.AppendIfUnique(file_spec))
- {
- count++;
- break;
- }
+ symbol_value -= section_file_addr;
+ }
+
+ if (is_debug == false) {
+ if (type == eSymbolTypeCode) {
+ // See if we can find a N_FUN entry for any code symbols.
+ // If we do find a match, and the name matches, then we
+ // can merge the two into just the function symbol to avoid
+ // duplicate entries in the symbol table
+ std::pair<ValueToSymbolIndexMap::const_iterator,
+ ValueToSymbolIndexMap::const_iterator>
+ range;
+ range = N_FUN_addr_to_sym_idx.equal_range(nlist.n_value);
+ if (range.first != range.second) {
+ bool found_it = false;
+ for (ValueToSymbolIndexMap::const_iterator pos = range.first;
+ pos != range.second; ++pos) {
+ if (sym[sym_idx].GetMangled().GetName(
+ lldb::eLanguageTypeUnknown,
+ Mangled::ePreferMangled) ==
+ sym[pos->second].GetMangled().GetName(
+ lldb::eLanguageTypeUnknown,
+ Mangled::ePreferMangled)) {
+ m_nlist_idx_to_sym_idx[nlist_idx] = pos->second;
+ // We just need the flags from the linker symbol, so put
+ // these flags
+ // into the N_FUN flags to avoid duplicate symbols in the
+ // symbol table
+ sym[pos->second].SetExternal(sym[sym_idx].IsExternal());
+ sym[pos->second].SetFlags(nlist.n_type << 16 |
+ nlist.n_desc);
+ if (resolver_addresses.find(nlist.n_value) !=
+ resolver_addresses.end())
+ sym[pos->second].SetType(eSymbolTypeResolver);
+ sym[sym_idx].Clear();
+ found_it = true;
+ break;
+ }
}
+ if (found_it)
+ continue;
+ } else {
+ if (resolver_addresses.find(nlist.n_value) !=
+ resolver_addresses.end())
+ type = eSymbolTypeResolver;
+ }
+ } else if (type == eSymbolTypeData ||
+ type == eSymbolTypeObjCClass ||
+ type == eSymbolTypeObjCMetaClass ||
+ type == eSymbolTypeObjCIVar) {
+ // See if we can find a N_STSYM entry for any data symbols.
+ // If we do find a match, and the name matches, then we
+ // can merge the two into just the Static symbol to avoid
+ // duplicate entries in the symbol table
+ std::pair<ValueToSymbolIndexMap::const_iterator,
+ ValueToSymbolIndexMap::const_iterator>
+ range;
+ range = N_STSYM_addr_to_sym_idx.equal_range(nlist.n_value);
+ if (range.first != range.second) {
+ bool found_it = false;
+ for (ValueToSymbolIndexMap::const_iterator pos = range.first;
+ pos != range.second; ++pos) {
+ if (sym[sym_idx].GetMangled().GetName(
+ lldb::eLanguageTypeUnknown,
+ Mangled::ePreferMangled) ==
+ sym[pos->second].GetMangled().GetName(
+ lldb::eLanguageTypeUnknown,
+ Mangled::ePreferMangled)) {
+ m_nlist_idx_to_sym_idx[nlist_idx] = pos->second;
+ // We just need the flags from the linker symbol, so put
+ // these flags
+ // into the N_STSYM flags to avoid duplicate symbols in the
+ // symbol table
+ sym[pos->second].SetExternal(sym[sym_idx].IsExternal());
+ sym[pos->second].SetFlags(nlist.n_type << 16 |
+ nlist.n_desc);
+ sym[sym_idx].Clear();
+ found_it = true;
+ break;
+ }
+ }
+ if (found_it)
+ continue;
+ } else {
+ // Combine N_GSYM stab entries with the non stab symbol
+ const char *gsym_name = sym[sym_idx]
+ .GetMangled()
+ .GetName(lldb::eLanguageTypeUnknown,
+ Mangled::ePreferMangled)
+ .GetCString();
+ if (gsym_name) {
+ ConstNameToSymbolIndexMap::const_iterator pos =
+ N_GSYM_name_to_sym_idx.find(gsym_name);
+ if (pos != N_GSYM_name_to_sym_idx.end()) {
+ const uint32_t GSYM_sym_idx = pos->second;
+ m_nlist_idx_to_sym_idx[nlist_idx] = GSYM_sym_idx;
+ // Copy the address, because often the N_GSYM address has an
+ // invalid address of zero
+ // when the global is a common symbol
+ sym[GSYM_sym_idx].GetAddressRef().SetSection(
+ symbol_section);
+ sym[GSYM_sym_idx].GetAddressRef().SetOffset(symbol_value);
+ // We just need the flags from the linker symbol, so put
+ // these flags
+ // into the N_GSYM flags to avoid duplicate symbols in the
+ // symbol table
+ sym[GSYM_sym_idx].SetFlags(nlist.n_type << 16 |
+ nlist.n_desc);
+ sym[sym_idx].Clear();
+ continue;
+ }
+ }
+ }
}
- }
- }
- return count;
-}
+ }
-lldb_private::Address
-ObjectFileMachO::GetEntryPointAddress ()
-{
- // If the object file is not an executable it can't hold the entry point. m_entry_point_address
- // is initialized to an invalid address, so we can just return that.
- // If m_entry_point_address is valid it means we've found it already, so return the cached value.
+ sym[sym_idx].SetID(nlist_idx);
+ sym[sym_idx].SetType(type);
+ if (set_value) {
+ sym[sym_idx].GetAddressRef().SetSection(symbol_section);
+ sym[sym_idx].GetAddressRef().SetOffset(symbol_value);
+ }
+ sym[sym_idx].SetFlags(nlist.n_type << 16 | nlist.n_desc);
- if (!IsExecutable() || m_entry_point_address.IsValid())
- return m_entry_point_address;
+ if (symbol_byte_size > 0)
+ sym[sym_idx].SetByteSize(symbol_byte_size);
- // Otherwise, look for the UnixThread or Thread command. The data for the Thread command is given in
- // /usr/include/mach-o.h, but it is basically:
- //
- // uint32_t flavor - this is the flavor argument you would pass to thread_get_state
- // uint32_t count - this is the count of longs in the thread state data
- // struct XXX_thread_state state - this is the structure from <machine/thread_status.h> corresponding to the flavor.
- // <repeat this trio>
- //
- // So we just keep reading the various register flavors till we find the GPR one, then read the PC out of there.
- // FIXME: We will need to have a "RegisterContext data provider" class at some point that can get all the registers
- // out of data in this form & attach them to a given thread. That should underlie the MacOS X User process plugin,
- // and we'll also need it for the MacOS X Core File process plugin. When we have that we can also use it here.
- //
- // For now we hard-code the offsets and flavors we need:
- //
- //
+ if (demangled_is_synthesized)
+ sym[sym_idx].SetDemangledNameIsSynthesized(true);
- ModuleSP module_sp(GetModule());
- if (module_sp)
- {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- struct load_command load_cmd;
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- uint32_t i;
- lldb::addr_t start_address = LLDB_INVALID_ADDRESS;
- bool done = false;
+ ++sym_idx;
+ } else {
+ sym[sym_idx].Clear();
+ }
+ }
+
+ for (const auto &pos : reexport_shlib_needs_fixup) {
+ const auto undef_pos = undefined_name_to_desc.find(pos.second);
+ if (undef_pos != undefined_name_to_desc.end()) {
+ const uint8_t dylib_ordinal =
+ llvm::MachO::GET_LIBRARY_ORDINAL(undef_pos->second);
+ if (dylib_ordinal > 0 && dylib_ordinal < dylib_files.GetSize())
+ sym[pos.first].SetReExportedSymbolSharedLibrary(
+ dylib_files.GetFileSpecAtIndex(dylib_ordinal - 1));
+ }
+ }
+ }
- for (i=0; i<m_header.ncmds; ++i)
- {
- const lldb::offset_t cmd_offset = offset;
- if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
- break;
+ uint32_t synthetic_sym_id = symtab_load_command.nsyms;
- switch (load_cmd.cmd)
- {
- case LC_UNIXTHREAD:
- case LC_THREAD:
- {
- while (offset < cmd_offset + load_cmd.cmdsize)
- {
- uint32_t flavor = m_data.GetU32(&offset);
- uint32_t count = m_data.GetU32(&offset);
- if (count == 0)
- {
- // We've gotten off somehow, log and exit;
- return m_entry_point_address;
- }
+ if (function_starts_count > 0) {
+ uint32_t num_synthetic_function_symbols = 0;
+ for (i = 0; i < function_starts_count; ++i) {
+ if (function_starts.GetEntryRef(i).data == false)
+ ++num_synthetic_function_symbols;
+ }
- switch (m_header.cputype)
- {
- case llvm::MachO::CPU_TYPE_ARM:
- if (flavor == 1 || flavor == 9) // ARM_THREAD_STATE/ARM_THREAD_STATE32 from mach/arm/thread_status.h
- {
- offset += 60; // This is the offset of pc in the GPR thread state data structure.
- start_address = m_data.GetU32(&offset);
- done = true;
- }
- break;
- case llvm::MachO::CPU_TYPE_ARM64:
- if (flavor == 6) // ARM_THREAD_STATE64 from mach/arm/thread_status.h
- {
- offset += 256; // This is the offset of pc in the GPR thread state data structure.
- start_address = m_data.GetU64(&offset);
- done = true;
- }
- break;
- case llvm::MachO::CPU_TYPE_I386:
- if (flavor == 1) // x86_THREAD_STATE32 from mach/i386/thread_status.h
- {
- offset += 40; // This is the offset of eip in the GPR thread state data structure.
- start_address = m_data.GetU32(&offset);
- done = true;
- }
- break;
- case llvm::MachO::CPU_TYPE_X86_64:
- if (flavor == 4) // x86_THREAD_STATE64 from mach/i386/thread_status.h
- {
- offset += 16 * 8; // This is the offset of rip in the GPR thread state data structure.
- start_address = m_data.GetU64(&offset);
- done = true;
- }
- break;
- default:
- return m_entry_point_address;
- }
- // Haven't found the GPR flavor yet, skip over the data for this flavor:
- if (done)
- break;
- offset += count * 4;
- }
- }
- break;
- case LC_MAIN:
- {
- ConstString text_segment_name ("__TEXT");
- uint64_t entryoffset = m_data.GetU64(&offset);
- SectionSP text_segment_sp = GetSectionList()->FindSectionByName(text_segment_name);
- if (text_segment_sp)
- {
- done = true;
- start_address = text_segment_sp->GetFileAddress() + entryoffset;
- }
+ if (num_synthetic_function_symbols > 0) {
+ if (num_syms < sym_idx + num_synthetic_function_symbols) {
+ num_syms = sym_idx + num_synthetic_function_symbols;
+ sym = symtab->Resize(num_syms);
+ }
+ for (i = 0; i < function_starts_count; ++i) {
+ const FunctionStarts::Entry *func_start_entry =
+ function_starts.GetEntryAtIndex(i);
+ if (func_start_entry->data == false) {
+ addr_t symbol_file_addr = func_start_entry->addr;
+ uint32_t symbol_flags = 0;
+ if (is_arm) {
+ if (symbol_file_addr & 1)
+ symbol_flags = MACHO_NLIST_ARM_SYMBOL_IS_THUMB;
+ symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
+ }
+ Address symbol_addr;
+ if (module_sp->ResolveFileAddress(symbol_file_addr, symbol_addr)) {
+ SectionSP symbol_section(symbol_addr.GetSection());
+ uint32_t symbol_byte_size = 0;
+ if (symbol_section) {
+ const addr_t section_file_addr =
+ symbol_section->GetFileAddress();
+ const FunctionStarts::Entry *next_func_start_entry =
+ function_starts.FindNextEntry(func_start_entry);
+ const addr_t section_end_file_addr =
+ section_file_addr + symbol_section->GetByteSize();
+ if (next_func_start_entry) {
+ addr_t next_symbol_file_addr = next_func_start_entry->addr;
+ if (is_arm)
+ next_symbol_file_addr &= THUMB_ADDRESS_BIT_MASK;
+ symbol_byte_size = std::min<lldb::addr_t>(
+ next_symbol_file_addr - symbol_file_addr,
+ section_end_file_addr - symbol_file_addr);
+ } else {
+ symbol_byte_size = section_end_file_addr - symbol_file_addr;
}
- break;
-
- default:
- break;
+ sym[sym_idx].SetID(synthetic_sym_id++);
+ sym[sym_idx].GetMangled().SetDemangledName(
+ GetNextSyntheticSymbolName());
+ sym[sym_idx].SetType(eSymbolTypeCode);
+ sym[sym_idx].SetIsSynthetic(true);
+ sym[sym_idx].GetAddressRef() = symbol_addr;
+ if (symbol_flags)
+ sym[sym_idx].SetFlags(symbol_flags);
+ if (symbol_byte_size)
+ sym[sym_idx].SetByteSize(symbol_byte_size);
+ ++sym_idx;
+ }
}
- if (done)
- break;
-
- // Go to the next load command:
- offset = cmd_offset + load_cmd.cmdsize;
+ }
}
+ }
+ }
- if (start_address != LLDB_INVALID_ADDRESS)
- {
- // We got the start address from the load commands, so now resolve that address in the sections
- // of this ObjectFile:
- if (!m_entry_point_address.ResolveAddressUsingFileSections (start_address, GetSectionList()))
- {
- m_entry_point_address.Clear();
- }
- }
- else
- {
- // We couldn't read the UnixThread load command - maybe it wasn't there. As a fallback look for the
- // "start" symbol in the main executable.
+ // Trim our symbols down to just what we ended up with after
+ // removing any symbols.
+ if (sym_idx < num_syms) {
+ num_syms = sym_idx;
+ sym = symtab->Resize(num_syms);
+ }
- ModuleSP module_sp (GetModule());
+ // Now synthesize indirect symbols
+ if (m_dysymtab.nindirectsyms != 0) {
+ if (indirect_symbol_index_data.GetByteSize()) {
+ NListIndexToSymbolIndexMap::const_iterator end_index_pos =
+ m_nlist_idx_to_sym_idx.end();
+
+ for (uint32_t sect_idx = 1; sect_idx < m_mach_sections.size();
+ ++sect_idx) {
+ if ((m_mach_sections[sect_idx].flags & SECTION_TYPE) ==
+ S_SYMBOL_STUBS) {
+ uint32_t symbol_stub_byte_size =
+ m_mach_sections[sect_idx].reserved2;
+ if (symbol_stub_byte_size == 0)
+ continue;
+
+ const uint32_t num_symbol_stubs =
+ m_mach_sections[sect_idx].size / symbol_stub_byte_size;
+
+ if (num_symbol_stubs == 0)
+ continue;
+
+ const uint32_t symbol_stub_index_offset =
+ m_mach_sections[sect_idx].reserved1;
+ for (uint32_t stub_idx = 0; stub_idx < num_symbol_stubs;
+ ++stub_idx) {
+ const uint32_t symbol_stub_index =
+ symbol_stub_index_offset + stub_idx;
+ const lldb::addr_t symbol_stub_addr =
+ m_mach_sections[sect_idx].addr +
+ (stub_idx * symbol_stub_byte_size);
+ lldb::offset_t symbol_stub_offset = symbol_stub_index * 4;
+ if (indirect_symbol_index_data.ValidOffsetForDataOfSize(
+ symbol_stub_offset, 4)) {
+ const uint32_t stub_sym_id =
+ indirect_symbol_index_data.GetU32(&symbol_stub_offset);
+ if (stub_sym_id & (INDIRECT_SYMBOL_ABS | INDIRECT_SYMBOL_LOCAL))
+ continue;
+
+ NListIndexToSymbolIndexMap::const_iterator index_pos =
+ m_nlist_idx_to_sym_idx.find(stub_sym_id);
+ Symbol *stub_symbol = NULL;
+ if (index_pos != end_index_pos) {
+ // We have a remapping from the original nlist index to
+ // a current symbol index, so just look this up by index
+ stub_symbol = symtab->SymbolAtIndex(index_pos->second);
+ } else {
+ // We need to lookup a symbol using the original nlist
+ // symbol index since this index is coming from the
+ // S_SYMBOL_STUBS
+ stub_symbol = symtab->FindSymbolByID(stub_sym_id);
+ }
- if (module_sp)
- {
- SymbolContextList contexts;
- SymbolContext context;
- if (module_sp->FindSymbolsWithNameAndType(ConstString ("start"), eSymbolTypeCode, contexts))
- {
- if (contexts.GetContextAtIndex(0, context))
- m_entry_point_address = context.symbol->GetAddress();
+ if (stub_symbol) {
+ Address so_addr(symbol_stub_addr, section_list);
+
+ if (stub_symbol->GetType() == eSymbolTypeUndefined) {
+ // Change the external symbol into a trampoline that makes
+ // sense
+ // These symbols were N_UNDF N_EXT, and are useless to us,
+ // so we
+ // can re-use them so we don't have to make up a synthetic
+ // symbol
+ // for no good reason.
+ if (resolver_addresses.find(symbol_stub_addr) ==
+ resolver_addresses.end())
+ stub_symbol->SetType(eSymbolTypeTrampoline);
+ else
+ stub_symbol->SetType(eSymbolTypeResolver);
+ stub_symbol->SetExternal(false);
+ stub_symbol->GetAddressRef() = so_addr;
+ stub_symbol->SetByteSize(symbol_stub_byte_size);
+ } else {
+ // Make a synthetic symbol to describe the trampoline stub
+ Mangled stub_symbol_mangled_name(stub_symbol->GetMangled());
+ if (sym_idx >= num_syms) {
+ sym = symtab->Resize(++num_syms);
+ stub_symbol = NULL; // this pointer no longer valid
+ }
+ sym[sym_idx].SetID(synthetic_sym_id++);
+ sym[sym_idx].GetMangled() = stub_symbol_mangled_name;
+ if (resolver_addresses.find(symbol_stub_addr) ==
+ resolver_addresses.end())
+ sym[sym_idx].SetType(eSymbolTypeTrampoline);
+ else
+ sym[sym_idx].SetType(eSymbolTypeResolver);
+ sym[sym_idx].SetIsSynthetic(true);
+ sym[sym_idx].GetAddressRef() = so_addr;
+ sym[sym_idx].SetByteSize(symbol_stub_byte_size);
+ ++sym_idx;
+ }
+ } else {
+ if (log)
+ log->Warning("symbol stub referencing symbol table symbol "
+ "%u that isn't in our minimal symbol table, "
+ "fix this!!!",
+ stub_sym_id);
}
+ }
}
+ }
}
+ }
}
- return m_entry_point_address;
-}
-
-lldb_private::Address
-ObjectFileMachO::GetHeaderAddress ()
-{
- lldb_private::Address header_addr;
- SectionList *section_list = GetSectionList();
- if (section_list)
- {
- SectionSP text_segment_sp (section_list->FindSectionByName (GetSegmentNameTEXT()));
- if (text_segment_sp)
- {
- header_addr.SetSection (text_segment_sp);
- header_addr.SetOffset (0);
+ if (!trie_entries.empty()) {
+ for (const auto &e : trie_entries) {
+ if (e.entry.import_name) {
+ // Only add indirect symbols from the Trie entries if we
+ // didn't have a N_INDR nlist entry for this already
+ if (indirect_symbol_names.find(e.entry.name) ==
+ indirect_symbol_names.end()) {
+ // Make a synthetic symbol to describe re-exported symbol.
+ if (sym_idx >= num_syms)
+ sym = symtab->Resize(++num_syms);
+ sym[sym_idx].SetID(synthetic_sym_id++);
+ sym[sym_idx].GetMangled() = Mangled(e.entry.name);
+ sym[sym_idx].SetType(eSymbolTypeReExported);
+ sym[sym_idx].SetIsSynthetic(true);
+ sym[sym_idx].SetReExportedSymbolName(e.entry.import_name);
+ if (e.entry.other > 0 && e.entry.other <= dylib_files.GetSize()) {
+ sym[sym_idx].SetReExportedSymbolSharedLibrary(
+ dylib_files.GetFileSpecAtIndex(e.entry.other - 1));
+ }
+ ++sym_idx;
+ }
}
+ }
}
- return header_addr;
+
+ // StreamFile s(stdout, false);
+ // s.Printf ("Symbol table before CalculateSymbolSizes():\n");
+ // symtab->Dump(&s, NULL, eSortOrderNone);
+ // Set symbol byte sizes correctly since mach-o nlist entries don't have
+ // sizes
+ symtab->CalculateSymbolSizes();
+
+ // s.Printf ("Symbol table after CalculateSymbolSizes():\n");
+ // symtab->Dump(&s, NULL, eSortOrderNone);
+
+ return symtab->GetNumSymbols();
+ }
+ return 0;
}
-uint32_t
-ObjectFileMachO::GetNumThreadContexts ()
-{
- ModuleSP module_sp(GetModule());
- if (module_sp)
- {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- if (!m_thread_context_offsets_valid)
- {
- m_thread_context_offsets_valid = true;
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- FileRangeArray::Entry file_range;
- thread_command thread_cmd;
- for (uint32_t i=0; i<m_header.ncmds; ++i)
- {
- const uint32_t cmd_offset = offset;
- if (m_data.GetU32(&offset, &thread_cmd, 2) == NULL)
- break;
+void ObjectFileMachO::Dump(Stream *s) {
+ ModuleSP module_sp(GetModule());
+ if (module_sp) {
+ std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
+ s->Printf("%p: ", static_cast<void *>(this));
+ s->Indent();
+ if (m_header.magic == MH_MAGIC_64 || m_header.magic == MH_CIGAM_64)
+ s->PutCString("ObjectFileMachO64");
+ else
+ s->PutCString("ObjectFileMachO32");
- if (thread_cmd.cmd == LC_THREAD)
- {
- file_range.SetRangeBase (offset);
- file_range.SetByteSize (thread_cmd.cmdsize - 8);
- m_thread_context_offsets.Append (file_range);
- }
- offset = cmd_offset + thread_cmd.cmdsize;
- }
- }
- }
- return m_thread_context_offsets.GetSize();
+ ArchSpec header_arch;
+ GetArchitecture(header_arch);
+
+ *s << ", file = '" << m_file
+ << "', arch = " << header_arch.GetArchitectureName() << "\n";
+
+ SectionList *sections = GetSectionList();
+ if (sections)
+ sections->Dump(s, NULL, true, UINT32_MAX);
+
+ if (m_symtab_ap.get())
+ m_symtab_ap->Dump(s, NULL, eSortOrderNone);
+ }
}
-lldb::RegisterContextSP
-ObjectFileMachO::GetThreadContextAtIndex (uint32_t idx, lldb_private::Thread &thread)
-{
- lldb::RegisterContextSP reg_ctx_sp;
+bool ObjectFileMachO::GetUUID(const llvm::MachO::mach_header &header,
+ const lldb_private::DataExtractor &data,
+ lldb::offset_t lc_offset,
+ lldb_private::UUID &uuid) {
+ uint32_t i;
+ struct uuid_command load_cmd;
- ModuleSP module_sp(GetModule());
- if (module_sp)
- {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- if (!m_thread_context_offsets_valid)
- GetNumThreadContexts ();
+ lldb::offset_t offset = lc_offset;
+ for (i = 0; i < header.ncmds; ++i) {
+ const lldb::offset_t cmd_offset = offset;
+ if (data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
- const FileRangeArray::Entry *thread_context_file_range = m_thread_context_offsets.GetEntryAtIndex (idx);
- if (thread_context_file_range)
- {
+ if (load_cmd.cmd == LC_UUID) {
+ const uint8_t *uuid_bytes = data.PeekData(offset, 16);
- DataExtractor data (m_data,
- thread_context_file_range->GetRangeBase(),
- thread_context_file_range->GetByteSize());
+ if (uuid_bytes) {
+ // OpenCL on Mac OS X uses the same UUID for each of its object files.
+ // We pretend these object files have no UUID to prevent crashing.
- switch (m_header.cputype)
- {
- case llvm::MachO::CPU_TYPE_ARM64:
- reg_ctx_sp.reset (new RegisterContextDarwin_arm64_Mach (thread, data));
- break;
-
- case llvm::MachO::CPU_TYPE_ARM:
- reg_ctx_sp.reset (new RegisterContextDarwin_arm_Mach (thread, data));
- break;
+ const uint8_t opencl_uuid[] = {0x8c, 0x8e, 0xb3, 0x9b, 0x3b, 0xa8,
+ 0x4b, 0x16, 0xb6, 0xa4, 0x27, 0x63,
+ 0xbb, 0x14, 0xf0, 0x0d};
- case llvm::MachO::CPU_TYPE_I386:
- reg_ctx_sp.reset (new RegisterContextDarwin_i386_Mach (thread, data));
- break;
+ if (!memcmp(uuid_bytes, opencl_uuid, 16))
+ return false;
- case llvm::MachO::CPU_TYPE_X86_64:
- reg_ctx_sp.reset (new RegisterContextDarwin_x86_64_Mach (thread, data));
- break;
- }
+ uuid.SetBytes(uuid_bytes);
+ return true;
+ }
+ return false;
+ }
+ offset = cmd_offset + load_cmd.cmdsize;
+ }
+ return false;
+}
+
+bool ObjectFileMachO::GetArchitecture(const llvm::MachO::mach_header &header,
+ const lldb_private::DataExtractor &data,
+ lldb::offset_t lc_offset,
+ ArchSpec &arch) {
+ arch.SetArchitecture(eArchTypeMachO, header.cputype, header.cpusubtype);
+
+ if (arch.IsValid()) {
+ llvm::Triple &triple = arch.GetTriple();
+
+ // Set OS to an unspecified unknown or a "*" so it can match any OS
+ triple.setOS(llvm::Triple::UnknownOS);
+ triple.setOSName(llvm::StringRef());
+
+ if (header.filetype == MH_PRELOAD) {
+ if (header.cputype == CPU_TYPE_ARM) {
+ // If this is a 32-bit arm binary, and it's a standalone binary,
+ // force the Vendor to Apple so we don't accidentally pick up
+ // the generic armv7 ABI at runtime. Apple's armv7 ABI always uses
+ // r7 for the frame pointer register; most other armv7 ABIs use a
+ // combination of r7 and r11.
+ triple.setVendor(llvm::Triple::Apple);
+ } else {
+ // Set vendor to an unspecified unknown or a "*" so it can match any
+ // vendor
+ // This is required for correct behavior of EFI debugging on x86_64
+ triple.setVendor(llvm::Triple::UnknownVendor);
+ triple.setVendorName(llvm::StringRef());
+ }
+ return true;
+ } else {
+ struct load_command load_cmd;
+
+ lldb::offset_t offset = lc_offset;
+ for (uint32_t i = 0; i < header.ncmds; ++i) {
+ const lldb::offset_t cmd_offset = offset;
+ if (data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
+
+ switch (load_cmd.cmd) {
+ case llvm::MachO::LC_VERSION_MIN_IPHONEOS:
+ triple.setOS(llvm::Triple::IOS);
+ return true;
+
+ case llvm::MachO::LC_VERSION_MIN_MACOSX:
+ triple.setOS(llvm::Triple::MacOSX);
+ return true;
+
+ case llvm::MachO::LC_VERSION_MIN_TVOS:
+ triple.setOS(llvm::Triple::TvOS);
+ return true;
+
+ case llvm::MachO::LC_VERSION_MIN_WATCHOS:
+ triple.setOS(llvm::Triple::WatchOS);
+ return true;
+
+ default:
+ break;
}
+
+ offset = cmd_offset + load_cmd.cmdsize;
+ }
+
+ if (header.filetype != MH_KEXT_BUNDLE) {
+ // We didn't find a LC_VERSION_MIN load command and this isn't a KEXT
+ // so lets not say our Vendor is Apple, leave it as an unspecified
+ // unknown
+ triple.setVendor(llvm::Triple::UnknownVendor);
+ triple.setVendorName(llvm::StringRef());
+ }
}
- return reg_ctx_sp;
+ }
+ return arch.IsValid();
}
-ObjectFile::Type
-ObjectFileMachO::CalculateType()
-{
- switch (m_header.filetype)
- {
- case MH_OBJECT: // 0x1u
- if (GetAddressByteSize () == 4)
- {
- // 32 bit kexts are just object files, but they do have a valid
- // UUID load command.
- UUID uuid;
- if (GetUUID(&uuid))
- {
- // this checking for the UUID load command is not enough
- // we could eventually look for the symbol named
- // "OSKextGetCurrentIdentifier" as this is required of kexts
- if (m_strata == eStrataInvalid)
- m_strata = eStrataKernel;
- return eTypeSharedLibrary;
- }
+bool ObjectFileMachO::GetUUID(lldb_private::UUID *uuid) {
+ ModuleSP module_sp(GetModule());
+ if (module_sp) {
+ std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ return GetUUID(m_header, m_data, offset, *uuid);
+ }
+ return false;
+}
+
+uint32_t ObjectFileMachO::GetDependentModules(FileSpecList &files) {
+ uint32_t count = 0;
+ ModuleSP module_sp(GetModule());
+ if (module_sp) {
+ std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
+ struct load_command load_cmd;
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ std::vector<std::string> rpath_paths;
+ std::vector<std::string> rpath_relative_paths;
+ const bool resolve_path = false; // Don't resolve the dependent file paths
+ // since they may not reside on this system
+ uint32_t i;
+ for (i = 0; i < m_header.ncmds; ++i) {
+ const uint32_t cmd_offset = offset;
+ if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
+
+ switch (load_cmd.cmd) {
+ case LC_RPATH:
+ case LC_LOAD_DYLIB:
+ case LC_LOAD_WEAK_DYLIB:
+ case LC_REEXPORT_DYLIB:
+ case LC_LOAD_DYLINKER:
+ case LC_LOADFVMLIB:
+ case LC_LOAD_UPWARD_DYLIB: {
+ uint32_t name_offset = cmd_offset + m_data.GetU32(&offset);
+ const char *path = m_data.PeekCStr(name_offset);
+ if (path) {
+ if (load_cmd.cmd == LC_RPATH)
+ rpath_paths.push_back(path);
+ else {
+ if (path[0] == '@') {
+ if (strncmp(path, "@rpath", strlen("@rpath")) == 0)
+ rpath_relative_paths.push_back(path + strlen("@rpath"));
+ } else {
+ FileSpec file_spec(path, resolve_path);
+ if (files.AppendIfUnique(file_spec))
+ count++;
}
- return eTypeObjectFile;
-
- case MH_EXECUTE: return eTypeExecutable; // 0x2u
- case MH_FVMLIB: return eTypeSharedLibrary; // 0x3u
- case MH_CORE: return eTypeCoreFile; // 0x4u
- case MH_PRELOAD: return eTypeSharedLibrary; // 0x5u
- case MH_DYLIB: return eTypeSharedLibrary; // 0x6u
- case MH_DYLINKER: return eTypeDynamicLinker; // 0x7u
- case MH_BUNDLE: return eTypeSharedLibrary; // 0x8u
- case MH_DYLIB_STUB: return eTypeStubLibrary; // 0x9u
- case MH_DSYM: return eTypeDebugInfo; // 0xAu
- case MH_KEXT_BUNDLE: return eTypeSharedLibrary; // 0xBu
- default:
+ }
+ }
+ } break;
+
+ default:
+ break;
+ }
+ offset = cmd_offset + load_cmd.cmdsize;
+ }
+
+ if (!rpath_paths.empty()) {
+ // Fixup all LC_RPATH values to be absolute paths
+ FileSpec this_file_spec(m_file);
+ this_file_spec.ResolvePath();
+ std::string loader_path("@loader_path");
+ std::string executable_path("@executable_path");
+ for (auto &rpath : rpath_paths) {
+ if (rpath.find(loader_path) == 0) {
+ rpath.erase(0, loader_path.size());
+ rpath.insert(0, this_file_spec.GetDirectory().GetCString());
+ } else if (rpath.find(executable_path) == 0) {
+ rpath.erase(0, executable_path.size());
+ rpath.insert(0, this_file_spec.GetDirectory().GetCString());
+ }
+ }
+
+ for (const auto &rpath_relative_path : rpath_relative_paths) {
+ for (const auto &rpath : rpath_paths) {
+ std::string path = rpath;
+ path += rpath_relative_path;
+ // It is OK to resolve this path because we must find a file on
+ // disk for us to accept it anyway if it is rpath relative.
+ FileSpec file_spec(path, true);
+ // Remove any redundant parts of the path (like "../foo") since
+ // LC_RPATH values often contain "..".
+ file_spec.NormalizePath();
+ if (file_spec.Exists() && files.AppendIfUnique(file_spec)) {
+ count++;
break;
+ }
+ }
+ }
}
- return eTypeUnknown;
+ }
+ return count;
}
-ObjectFile::Strata
-ObjectFileMachO::CalculateStrata()
-{
- switch (m_header.filetype)
- {
- case MH_OBJECT: // 0x1u
+lldb_private::Address ObjectFileMachO::GetEntryPointAddress() {
+ // If the object file is not an executable it can't hold the entry point.
+ // m_entry_point_address
+ // is initialized to an invalid address, so we can just return that.
+ // If m_entry_point_address is valid it means we've found it already, so
+ // return the cached value.
+
+ if (!IsExecutable() || m_entry_point_address.IsValid())
+ return m_entry_point_address;
+
+ // Otherwise, look for the UnixThread or Thread command. The data for the
+ // Thread command is given in
+ // /usr/include/mach-o.h, but it is basically:
+ //
+ // uint32_t flavor - this is the flavor argument you would pass to
+ // thread_get_state
+ // uint32_t count - this is the count of longs in the thread state data
+ // struct XXX_thread_state state - this is the structure from
+ // <machine/thread_status.h> corresponding to the flavor.
+ // <repeat this trio>
+ //
+ // So we just keep reading the various register flavors till we find the GPR
+ // one, then read the PC out of there.
+ // FIXME: We will need to have a "RegisterContext data provider" class at some
+ // point that can get all the registers
+ // out of data in this form & attach them to a given thread. That should
+ // underlie the MacOS X User process plugin,
+ // and we'll also need it for the MacOS X Core File process plugin. When we
+ // have that we can also use it here.
+ //
+ // For now we hard-code the offsets and flavors we need:
+ //
+ //
+
+ ModuleSP module_sp(GetModule());
+ if (module_sp) {
+ std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
+ struct load_command load_cmd;
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ uint32_t i;
+ lldb::addr_t start_address = LLDB_INVALID_ADDRESS;
+ bool done = false;
+
+ for (i = 0; i < m_header.ncmds; ++i) {
+ const lldb::offset_t cmd_offset = offset;
+ if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
+
+ switch (load_cmd.cmd) {
+ case LC_UNIXTHREAD:
+ case LC_THREAD: {
+ while (offset < cmd_offset + load_cmd.cmdsize) {
+ uint32_t flavor = m_data.GetU32(&offset);
+ uint32_t count = m_data.GetU32(&offset);
+ if (count == 0) {
+ // We've gotten off somehow, log and exit;
+ return m_entry_point_address;
+ }
+
+ switch (m_header.cputype) {
+ case llvm::MachO::CPU_TYPE_ARM:
+ if (flavor == 1 ||
+ flavor == 9) // ARM_THREAD_STATE/ARM_THREAD_STATE32 from
+ // mach/arm/thread_status.h
{
- // 32 bit kexts are just object files, but they do have a valid
- // UUID load command.
- UUID uuid;
- if (GetUUID(&uuid))
- {
- // this checking for the UUID load command is not enough
- // we could eventually look for the symbol named
- // "OSKextGetCurrentIdentifier" as this is required of kexts
- if (m_type == eTypeInvalid)
- m_type = eTypeSharedLibrary;
-
- return eStrataKernel;
- }
+ offset += 60; // This is the offset of pc in the GPR thread state
+ // data structure.
+ start_address = m_data.GetU32(&offset);
+ done = true;
}
- return eStrataUnknown;
-
- case MH_EXECUTE: // 0x2u
- // Check for the MH_DYLDLINK bit in the flags
- if (m_header.flags & MH_DYLDLINK)
+ break;
+ case llvm::MachO::CPU_TYPE_ARM64:
+ if (flavor == 6) // ARM_THREAD_STATE64 from mach/arm/thread_status.h
{
- return eStrataUser;
+ offset += 256; // This is the offset of pc in the GPR thread state
+ // data structure.
+ start_address = m_data.GetU64(&offset);
+ done = true;
}
- else
+ break;
+ case llvm::MachO::CPU_TYPE_I386:
+ if (flavor ==
+ 1) // x86_THREAD_STATE32 from mach/i386/thread_status.h
{
- SectionList *section_list = GetSectionList();
- if (section_list)
- {
- static ConstString g_kld_section_name ("__KLD");
- if (section_list->FindSectionByName(g_kld_section_name))
- return eStrataKernel;
- }
+ offset += 40; // This is the offset of eip in the GPR thread state
+ // data structure.
+ start_address = m_data.GetU32(&offset);
+ done = true;
}
- return eStrataRawImage;
-
- case MH_FVMLIB: return eStrataUser; // 0x3u
- case MH_CORE: return eStrataUnknown; // 0x4u
- case MH_PRELOAD: return eStrataRawImage; // 0x5u
- case MH_DYLIB: return eStrataUser; // 0x6u
- case MH_DYLINKER: return eStrataUser; // 0x7u
- case MH_BUNDLE: return eStrataUser; // 0x8u
- case MH_DYLIB_STUB: return eStrataUser; // 0x9u
- case MH_DSYM: return eStrataUnknown; // 0xAu
- case MH_KEXT_BUNDLE: return eStrataKernel; // 0xBu
- default:
break;
+ case llvm::MachO::CPU_TYPE_X86_64:
+ if (flavor ==
+ 4) // x86_THREAD_STATE64 from mach/i386/thread_status.h
+ {
+ offset += 16 * 8; // This is the offset of rip in the GPR thread
+ // state data structure.
+ start_address = m_data.GetU64(&offset);
+ done = true;
+ }
+ break;
+ default:
+ return m_entry_point_address;
+ }
+ // Haven't found the GPR flavor yet, skip over the data for this
+ // flavor:
+ if (done)
+ break;
+ offset += count * 4;
+ }
+ } break;
+ case LC_MAIN: {
+ ConstString text_segment_name("__TEXT");
+ uint64_t entryoffset = m_data.GetU64(&offset);
+ SectionSP text_segment_sp =
+ GetSectionList()->FindSectionByName(text_segment_name);
+ if (text_segment_sp) {
+ done = true;
+ start_address = text_segment_sp->GetFileAddress() + entryoffset;
+ }
+ } break;
+
+ default:
+ break;
+ }
+ if (done)
+ break;
+
+ // Go to the next load command:
+ offset = cmd_offset + load_cmd.cmdsize;
}
- return eStrataUnknown;
+
+ if (start_address != LLDB_INVALID_ADDRESS) {
+ // We got the start address from the load commands, so now resolve that
+ // address in the sections
+ // of this ObjectFile:
+ if (!m_entry_point_address.ResolveAddressUsingFileSections(
+ start_address, GetSectionList())) {
+ m_entry_point_address.Clear();
+ }
+ } else {
+ // We couldn't read the UnixThread load command - maybe it wasn't there.
+ // As a fallback look for the
+ // "start" symbol in the main executable.
+
+ ModuleSP module_sp(GetModule());
+
+ if (module_sp) {
+ SymbolContextList contexts;
+ SymbolContext context;
+ if (module_sp->FindSymbolsWithNameAndType(ConstString("start"),
+ eSymbolTypeCode, contexts)) {
+ if (contexts.GetContextAtIndex(0, context))
+ m_entry_point_address = context.symbol->GetAddress();
+ }
+ }
+ }
+ }
+
+ return m_entry_point_address;
}
-uint32_t
-ObjectFileMachO::GetVersion (uint32_t *versions, uint32_t num_versions)
-{
- ModuleSP module_sp(GetModule());
- if (module_sp)
- {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- struct dylib_command load_cmd;
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- uint32_t version_cmd = 0;
- uint64_t version = 0;
- uint32_t i;
- for (i=0; i<m_header.ncmds; ++i)
- {
- const lldb::offset_t cmd_offset = offset;
- if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
- break;
+lldb_private::Address ObjectFileMachO::GetHeaderAddress() {
+ lldb_private::Address header_addr;
+ SectionList *section_list = GetSectionList();
+ if (section_list) {
+ SectionSP text_segment_sp(
+ section_list->FindSectionByName(GetSegmentNameTEXT()));
+ if (text_segment_sp) {
+ header_addr.SetSection(text_segment_sp);
+ header_addr.SetOffset(0);
+ }
+ }
+ return header_addr;
+}
- if (load_cmd.cmd == LC_ID_DYLIB)
- {
- if (version_cmd == 0)
- {
- version_cmd = load_cmd.cmd;
- if (m_data.GetU32(&offset, &load_cmd.dylib, 4) == NULL)
- break;
- version = load_cmd.dylib.current_version;
- }
- break; // Break for now unless there is another more complete version
- // number load command in the future.
- }
- offset = cmd_offset + load_cmd.cmdsize;
+uint32_t ObjectFileMachO::GetNumThreadContexts() {
+ ModuleSP module_sp(GetModule());
+ if (module_sp) {
+ std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
+ if (!m_thread_context_offsets_valid) {
+ m_thread_context_offsets_valid = true;
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ FileRangeArray::Entry file_range;
+ thread_command thread_cmd;
+ for (uint32_t i = 0; i < m_header.ncmds; ++i) {
+ const uint32_t cmd_offset = offset;
+ if (m_data.GetU32(&offset, &thread_cmd, 2) == NULL)
+ break;
+
+ if (thread_cmd.cmd == LC_THREAD) {
+ file_range.SetRangeBase(offset);
+ file_range.SetByteSize(thread_cmd.cmdsize - 8);
+ m_thread_context_offsets.Append(file_range);
}
+ offset = cmd_offset + thread_cmd.cmdsize;
+ }
+ }
+ }
+ return m_thread_context_offsets.GetSize();
+}
- if (version_cmd == LC_ID_DYLIB)
- {
- if (versions != NULL && num_versions > 0)
- {
- if (num_versions > 0)
- versions[0] = (version & 0xFFFF0000ull) >> 16;
- if (num_versions > 1)
- versions[1] = (version & 0x0000FF00ull) >> 8;
- if (num_versions > 2)
- versions[2] = (version & 0x000000FFull);
- // Fill in an remaining version numbers with invalid values
- for (i=3; i<num_versions; ++i)
- versions[i] = UINT32_MAX;
- }
- // The LC_ID_DYLIB load command has a version with 3 version numbers
- // in it, so always return 3
- return 3;
- }
+lldb::RegisterContextSP
+ObjectFileMachO::GetThreadContextAtIndex(uint32_t idx,
+ lldb_private::Thread &thread) {
+ lldb::RegisterContextSP reg_ctx_sp;
+
+ ModuleSP module_sp(GetModule());
+ if (module_sp) {
+ std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
+ if (!m_thread_context_offsets_valid)
+ GetNumThreadContexts();
+
+ const FileRangeArray::Entry *thread_context_file_range =
+ m_thread_context_offsets.GetEntryAtIndex(idx);
+ if (thread_context_file_range) {
+
+ DataExtractor data(m_data, thread_context_file_range->GetRangeBase(),
+ thread_context_file_range->GetByteSize());
+
+ switch (m_header.cputype) {
+ case llvm::MachO::CPU_TYPE_ARM64:
+ reg_ctx_sp.reset(new RegisterContextDarwin_arm64_Mach(thread, data));
+ break;
+
+ case llvm::MachO::CPU_TYPE_ARM:
+ reg_ctx_sp.reset(new RegisterContextDarwin_arm_Mach(thread, data));
+ break;
+
+ case llvm::MachO::CPU_TYPE_I386:
+ reg_ctx_sp.reset(new RegisterContextDarwin_i386_Mach(thread, data));
+ break;
+
+ case llvm::MachO::CPU_TYPE_X86_64:
+ reg_ctx_sp.reset(new RegisterContextDarwin_x86_64_Mach(thread, data));
+ break;
+ }
}
- return false;
+ }
+ return reg_ctx_sp;
}
-bool
-ObjectFileMachO::GetArchitecture (ArchSpec &arch)
-{
- ModuleSP module_sp(GetModule());
- if (module_sp)
- {
- std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
- return GetArchitecture (m_header, m_data, MachHeaderSizeFromMagic(m_header.magic), arch);
+ObjectFile::Type ObjectFileMachO::CalculateType() {
+ switch (m_header.filetype) {
+ case MH_OBJECT: // 0x1u
+ if (GetAddressByteSize() == 4) {
+ // 32 bit kexts are just object files, but they do have a valid
+ // UUID load command.
+ UUID uuid;
+ if (GetUUID(&uuid)) {
+ // this checking for the UUID load command is not enough
+ // we could eventually look for the symbol named
+ // "OSKextGetCurrentIdentifier" as this is required of kexts
+ if (m_strata == eStrataInvalid)
+ m_strata = eStrataKernel;
+ return eTypeSharedLibrary;
+ }
}
- return false;
+ return eTypeObjectFile;
+
+ case MH_EXECUTE:
+ return eTypeExecutable; // 0x2u
+ case MH_FVMLIB:
+ return eTypeSharedLibrary; // 0x3u
+ case MH_CORE:
+ return eTypeCoreFile; // 0x4u
+ case MH_PRELOAD:
+ return eTypeSharedLibrary; // 0x5u
+ case MH_DYLIB:
+ return eTypeSharedLibrary; // 0x6u
+ case MH_DYLINKER:
+ return eTypeDynamicLinker; // 0x7u
+ case MH_BUNDLE:
+ return eTypeSharedLibrary; // 0x8u
+ case MH_DYLIB_STUB:
+ return eTypeStubLibrary; // 0x9u
+ case MH_DSYM:
+ return eTypeDebugInfo; // 0xAu
+ case MH_KEXT_BUNDLE:
+ return eTypeSharedLibrary; // 0xBu
+ default:
+ break;
+ }
+ return eTypeUnknown;
}
-UUID
-ObjectFileMachO::GetProcessSharedCacheUUID (Process *process)
-{
+ObjectFile::Strata ObjectFileMachO::CalculateStrata() {
+ switch (m_header.filetype) {
+ case MH_OBJECT: // 0x1u
+ {
+ // 32 bit kexts are just object files, but they do have a valid
+ // UUID load command.
UUID uuid;
- if (process && process->GetDynamicLoader())
- {
- DynamicLoader *dl = process->GetDynamicLoader();
- addr_t load_address;
- LazyBool using_shared_cache;
- LazyBool private_shared_cache;
- dl->GetSharedCacheInformation (load_address, uuid, using_shared_cache, private_shared_cache);
+ if (GetUUID(&uuid)) {
+ // this checking for the UUID load command is not enough
+ // we could eventually look for the symbol named
+ // "OSKextGetCurrentIdentifier" as this is required of kexts
+ if (m_type == eTypeInvalid)
+ m_type = eTypeSharedLibrary;
+
+ return eStrataKernel;
}
- return uuid;
+ }
+ return eStrataUnknown;
+
+ case MH_EXECUTE: // 0x2u
+ // Check for the MH_DYLDLINK bit in the flags
+ if (m_header.flags & MH_DYLDLINK) {
+ return eStrataUser;
+ } else {
+ SectionList *section_list = GetSectionList();
+ if (section_list) {
+ static ConstString g_kld_section_name("__KLD");
+ if (section_list->FindSectionByName(g_kld_section_name))
+ return eStrataKernel;
+ }
+ }
+ return eStrataRawImage;
+
+ case MH_FVMLIB:
+ return eStrataUser; // 0x3u
+ case MH_CORE:
+ return eStrataUnknown; // 0x4u
+ case MH_PRELOAD:
+ return eStrataRawImage; // 0x5u
+ case MH_DYLIB:
+ return eStrataUser; // 0x6u
+ case MH_DYLINKER:
+ return eStrataUser; // 0x7u
+ case MH_BUNDLE:
+ return eStrataUser; // 0x8u
+ case MH_DYLIB_STUB:
+ return eStrataUser; // 0x9u
+ case MH_DSYM:
+ return eStrataUnknown; // 0xAu
+ case MH_KEXT_BUNDLE:
+ return eStrataKernel; // 0xBu
+ default:
+ break;
+ }
+ return eStrataUnknown;
}
-UUID
-ObjectFileMachO::GetLLDBSharedCacheUUID ()
-{
- UUID uuid;
-#if defined (__APPLE__) && (defined (__arm__) || defined (__arm64__) || defined (__aarch64__))
- uint8_t *(*dyld_get_all_image_infos)(void);
- dyld_get_all_image_infos = (uint8_t*(*)()) dlsym (RTLD_DEFAULT, "_dyld_get_all_image_infos");
- if (dyld_get_all_image_infos)
- {
- uint8_t *dyld_all_image_infos_address = dyld_get_all_image_infos();
- if (dyld_all_image_infos_address)
- {
- uint32_t *version = (uint32_t*) dyld_all_image_infos_address; // version <mach-o/dyld_images.h>
- if (*version >= 13)
- {
- uuid_t *sharedCacheUUID_address = 0;
- int wordsize = sizeof (uint8_t *);
- if (wordsize == 8)
- {
- sharedCacheUUID_address = (uuid_t*) ((uint8_t*) dyld_all_image_infos_address + 160); // sharedCacheUUID <mach-o/dyld_images.h>
- }
- else
- {
- sharedCacheUUID_address = (uuid_t*) ((uint8_t*) dyld_all_image_infos_address + 84); // sharedCacheUUID <mach-o/dyld_images.h>
- }
- uuid.SetBytes (sharedCacheUUID_address);
- }
+uint32_t ObjectFileMachO::GetVersion(uint32_t *versions,
+ uint32_t num_versions) {
+ ModuleSP module_sp(GetModule());
+ if (module_sp) {
+ std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
+ struct dylib_command load_cmd;
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ uint32_t version_cmd = 0;
+ uint64_t version = 0;
+ uint32_t i;
+ for (i = 0; i < m_header.ncmds; ++i) {
+ const lldb::offset_t cmd_offset = offset;
+ if (m_data.GetU32(&offset, &load_cmd, 2) == NULL)
+ break;
+
+ if (load_cmd.cmd == LC_ID_DYLIB) {
+ if (version_cmd == 0) {
+ version_cmd = load_cmd.cmd;
+ if (m_data.GetU32(&offset, &load_cmd.dylib, 4) == NULL)
+ break;
+ version = load_cmd.dylib.current_version;
}
+ break; // Break for now unless there is another more complete version
+ // number load command in the future.
+ }
+ offset = cmd_offset + load_cmd.cmdsize;
}
-#endif
- return uuid;
+
+ if (version_cmd == LC_ID_DYLIB) {
+ if (versions != NULL && num_versions > 0) {
+ if (num_versions > 0)
+ versions[0] = (version & 0xFFFF0000ull) >> 16;
+ if (num_versions > 1)
+ versions[1] = (version & 0x0000FF00ull) >> 8;
+ if (num_versions > 2)
+ versions[2] = (version & 0x000000FFull);
+ // Fill in an remaining version numbers with invalid values
+ for (i = 3; i < num_versions; ++i)
+ versions[i] = UINT32_MAX;
+ }
+ // The LC_ID_DYLIB load command has a version with 3 version numbers
+ // in it, so always return 3
+ return 3;
+ }
+ }
+ return false;
}
-uint32_t
-ObjectFileMachO::GetMinimumOSVersion (uint32_t *versions, uint32_t num_versions)
-{
- if (m_min_os_versions.empty())
- {
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- bool success = false;
- for (uint32_t i=0; success == false && i < m_header.ncmds; ++i)
- {
- const lldb::offset_t load_cmd_offset = offset;
-
- version_min_command lc;
- if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL)
- break;
- if (lc.cmd == llvm::MachO::LC_VERSION_MIN_MACOSX
- || lc.cmd == llvm::MachO::LC_VERSION_MIN_IPHONEOS
- || lc.cmd == llvm::MachO::LC_VERSION_MIN_TVOS
- || lc.cmd == llvm::MachO::LC_VERSION_MIN_WATCHOS)
- {
- if (m_data.GetU32 (&offset, &lc.version, (sizeof(lc) / sizeof(uint32_t)) - 2))
- {
- const uint32_t xxxx = lc.version >> 16;
- const uint32_t yy = (lc.version >> 8) & 0xffu;
- const uint32_t zz = lc.version & 0xffu;
- if (xxxx)
- {
- m_min_os_versions.push_back(xxxx);
- m_min_os_versions.push_back(yy);
- m_min_os_versions.push_back(zz);
- }
- success = true;
- }
- }
- offset = load_cmd_offset + lc.cmdsize;
- }
-
- if (success == false)
- {
- // Push an invalid value so we don't keep trying to
- m_min_os_versions.push_back(UINT32_MAX);
+bool ObjectFileMachO::GetArchitecture(ArchSpec &arch) {
+ ModuleSP module_sp(GetModule());
+ if (module_sp) {
+ std::lock_guard<std::recursive_mutex> guard(module_sp->GetMutex());
+ return GetArchitecture(m_header, m_data,
+ MachHeaderSizeFromMagic(m_header.magic), arch);
+ }
+ return false;
+}
+
+UUID ObjectFileMachO::GetProcessSharedCacheUUID(Process *process) {
+ UUID uuid;
+ if (process && process->GetDynamicLoader()) {
+ DynamicLoader *dl = process->GetDynamicLoader();
+ addr_t load_address;
+ LazyBool using_shared_cache;
+ LazyBool private_shared_cache;
+ dl->GetSharedCacheInformation(load_address, uuid, using_shared_cache,
+ private_shared_cache);
+ }
+ return uuid;
+}
+
+UUID ObjectFileMachO::GetLLDBSharedCacheUUID() {
+ UUID uuid;
+#if defined(__APPLE__) && \
+ (defined(__arm__) || defined(__arm64__) || defined(__aarch64__))
+ uint8_t *(*dyld_get_all_image_infos)(void);
+ dyld_get_all_image_infos =
+ (uint8_t * (*)())dlsym(RTLD_DEFAULT, "_dyld_get_all_image_infos");
+ if (dyld_get_all_image_infos) {
+ uint8_t *dyld_all_image_infos_address = dyld_get_all_image_infos();
+ if (dyld_all_image_infos_address) {
+ uint32_t *version = (uint32_t *)
+ dyld_all_image_infos_address; // version <mach-o/dyld_images.h>
+ if (*version >= 13) {
+ uuid_t *sharedCacheUUID_address = 0;
+ int wordsize = sizeof(uint8_t *);
+ if (wordsize == 8) {
+ sharedCacheUUID_address =
+ (uuid_t *)((uint8_t *)dyld_all_image_infos_address +
+ 160); // sharedCacheUUID <mach-o/dyld_images.h>
+ } else {
+ sharedCacheUUID_address =
+ (uuid_t *)((uint8_t *)dyld_all_image_infos_address +
+ 84); // sharedCacheUUID <mach-o/dyld_images.h>
}
+ uuid.SetBytes(sharedCacheUUID_address);
+ }
}
-
- if (m_min_os_versions.size() > 1 || m_min_os_versions[0] != UINT32_MAX)
- {
- if (versions != NULL && num_versions > 0)
- {
- for (size_t i=0; i<num_versions; ++i)
- {
- if (i < m_min_os_versions.size())
- versions[i] = m_min_os_versions[i];
- else
- versions[i] = 0;
- }
+ }
+#endif
+ return uuid;
+}
+
+uint32_t ObjectFileMachO::GetMinimumOSVersion(uint32_t *versions,
+ uint32_t num_versions) {
+ if (m_min_os_versions.empty()) {
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ bool success = false;
+ for (uint32_t i = 0; success == false && i < m_header.ncmds; ++i) {
+ const lldb::offset_t load_cmd_offset = offset;
+
+ version_min_command lc;
+ if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL)
+ break;
+ if (lc.cmd == llvm::MachO::LC_VERSION_MIN_MACOSX ||
+ lc.cmd == llvm::MachO::LC_VERSION_MIN_IPHONEOS ||
+ lc.cmd == llvm::MachO::LC_VERSION_MIN_TVOS ||
+ lc.cmd == llvm::MachO::LC_VERSION_MIN_WATCHOS) {
+ if (m_data.GetU32(&offset, &lc.version,
+ (sizeof(lc) / sizeof(uint32_t)) - 2)) {
+ const uint32_t xxxx = lc.version >> 16;
+ const uint32_t yy = (lc.version >> 8) & 0xffu;
+ const uint32_t zz = lc.version & 0xffu;
+ if (xxxx) {
+ m_min_os_versions.push_back(xxxx);
+ m_min_os_versions.push_back(yy);
+ m_min_os_versions.push_back(zz);
+ }
+ success = true;
}
- return m_min_os_versions.size();
+ }
+ offset = load_cmd_offset + lc.cmdsize;
+ }
+
+ if (success == false) {
+ // Push an invalid value so we don't keep trying to
+ m_min_os_versions.push_back(UINT32_MAX);
}
- // Call the superclasses version that will empty out the data
- return ObjectFile::GetMinimumOSVersion (versions, num_versions);
+ }
+
+ if (m_min_os_versions.size() > 1 || m_min_os_versions[0] != UINT32_MAX) {
+ if (versions != NULL && num_versions > 0) {
+ for (size_t i = 0; i < num_versions; ++i) {
+ if (i < m_min_os_versions.size())
+ versions[i] = m_min_os_versions[i];
+ else
+ versions[i] = 0;
+ }
+ }
+ return m_min_os_versions.size();
+ }
+ // Call the superclasses version that will empty out the data
+ return ObjectFile::GetMinimumOSVersion(versions, num_versions);
}
-uint32_t
-ObjectFileMachO::GetSDKVersion(uint32_t *versions, uint32_t num_versions)
-{
- if (m_sdk_versions.empty())
- {
- lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
- bool success = false;
- for (uint32_t i=0; success == false && i < m_header.ncmds; ++i)
- {
- const lldb::offset_t load_cmd_offset = offset;
-
- version_min_command lc;
- if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL)
- break;
- if (lc.cmd == llvm::MachO::LC_VERSION_MIN_MACOSX
- || lc.cmd == llvm::MachO::LC_VERSION_MIN_IPHONEOS
- || lc.cmd == llvm::MachO::LC_VERSION_MIN_TVOS
- || lc.cmd == llvm::MachO::LC_VERSION_MIN_WATCHOS)
- {
- if (m_data.GetU32 (&offset, &lc.version, (sizeof(lc) / sizeof(uint32_t)) - 2))
- {
- const uint32_t xxxx = lc.sdk >> 16;
- const uint32_t yy = (lc.sdk >> 8) & 0xffu;
- const uint32_t zz = lc.sdk & 0xffu;
- if (xxxx)
- {
- m_sdk_versions.push_back(xxxx);
- m_sdk_versions.push_back(yy);
- m_sdk_versions.push_back(zz);
- }
- success = true;
- }
- }
- offset = load_cmd_offset + lc.cmdsize;
- }
-
- if (success == false)
- {
- // Push an invalid value so we don't keep trying to
- m_sdk_versions.push_back(UINT32_MAX);
+uint32_t ObjectFileMachO::GetSDKVersion(uint32_t *versions,
+ uint32_t num_versions) {
+ if (m_sdk_versions.empty()) {
+ lldb::offset_t offset = MachHeaderSizeFromMagic(m_header.magic);
+ bool success = false;
+ for (uint32_t i = 0; success == false && i < m_header.ncmds; ++i) {
+ const lldb::offset_t load_cmd_offset = offset;
+
+ version_min_command lc;
+ if (m_data.GetU32(&offset, &lc.cmd, 2) == NULL)
+ break;
+ if (lc.cmd == llvm::MachO::LC_VERSION_MIN_MACOSX ||
+ lc.cmd == llvm::MachO::LC_VERSION_MIN_IPHONEOS ||
+ lc.cmd == llvm::MachO::LC_VERSION_MIN_TVOS ||
+ lc.cmd == llvm::MachO::LC_VERSION_MIN_WATCHOS) {
+ if (m_data.GetU32(&offset, &lc.version,
+ (sizeof(lc) / sizeof(uint32_t)) - 2)) {
+ const uint32_t xxxx = lc.sdk >> 16;
+ const uint32_t yy = (lc.sdk >> 8) & 0xffu;
+ const uint32_t zz = lc.sdk & 0xffu;
+ if (xxxx) {
+ m_sdk_versions.push_back(xxxx);
+ m_sdk_versions.push_back(yy);
+ m_sdk_versions.push_back(zz);
+ }
+ success = true;
}
+ }
+ offset = load_cmd_offset + lc.cmdsize;
}
-
- if (m_sdk_versions.size() > 1 || m_sdk_versions[0] != UINT32_MAX)
- {
- if (versions != NULL && num_versions > 0)
- {
- for (size_t i=0; i<num_versions; ++i)
- {
- if (i < m_sdk_versions.size())
- versions[i] = m_sdk_versions[i];
- else
- versions[i] = 0;
- }
- }
- return m_sdk_versions.size();
+
+ if (success == false) {
+ // Push an invalid value so we don't keep trying to
+ m_sdk_versions.push_back(UINT32_MAX);
+ }
+ }
+
+ if (m_sdk_versions.size() > 1 || m_sdk_versions[0] != UINT32_MAX) {
+ if (versions != NULL && num_versions > 0) {
+ for (size_t i = 0; i < num_versions; ++i) {
+ if (i < m_sdk_versions.size())
+ versions[i] = m_sdk_versions[i];
+ else
+ versions[i] = 0;
+ }
}
- // Call the superclasses version that will empty out the data
- return ObjectFile::GetSDKVersion (versions, num_versions);
+ return m_sdk_versions.size();
+ }
+ // Call the superclasses version that will empty out the data
+ return ObjectFile::GetSDKVersion(versions, num_versions);
}
-bool
-ObjectFileMachO::GetIsDynamicLinkEditor()
-{
- return m_header.filetype == llvm::MachO::MH_DYLINKER;
+bool ObjectFileMachO::GetIsDynamicLinkEditor() {
+ return m_header.filetype == llvm::MachO::MH_DYLINKER;
}
-bool
-ObjectFileMachO::AllowAssemblyEmulationUnwindPlans ()
-{
- return m_allow_assembly_emulation_unwind_plans;
+bool ObjectFileMachO::AllowAssemblyEmulationUnwindPlans() {
+ return m_allow_assembly_emulation_unwind_plans;
}
//------------------------------------------------------------------
// PluginInterface protocol
//------------------------------------------------------------------
-lldb_private::ConstString
-ObjectFileMachO::GetPluginName()
-{
- return GetPluginNameStatic();
+lldb_private::ConstString ObjectFileMachO::GetPluginName() {
+ return GetPluginNameStatic();
}
-uint32_t
-ObjectFileMachO::GetPluginVersion()
-{
- return 1;
-}
+uint32_t ObjectFileMachO::GetPluginVersion() { return 1; }
-Section *
-ObjectFileMachO::GetMachHeaderSection()
-{
- // Find the first address of the mach header which is the first non-zero
- // file sized section whose file offset is zero. This is the base file address
- // of the mach-o file which can be subtracted from the vmaddr of the other
- // segments found in memory and added to the load address
- ModuleSP module_sp = GetModule();
- if (module_sp)
- {
- SectionList *section_list = GetSectionList ();
- if (section_list)
- {
- lldb::addr_t mach_base_file_addr = LLDB_INVALID_ADDRESS;
- const size_t num_sections = section_list->GetSize();
-
- for (size_t sect_idx = 0;
- sect_idx < num_sections && mach_base_file_addr == LLDB_INVALID_ADDRESS;
- ++sect_idx)
- {
- Section *section = section_list->GetSectionAtIndex (sect_idx).get();
- if (section &&
- section->GetFileSize() > 0 &&
- section->GetFileOffset() == 0 &&
- section->IsThreadSpecific() == false &&
- module_sp.get() == section->GetModule().get())
- {
- return section;
- }
- }
+Section *ObjectFileMachO::GetMachHeaderSection() {
+ // Find the first address of the mach header which is the first non-zero
+ // file sized section whose file offset is zero. This is the base file address
+ // of the mach-o file which can be subtracted from the vmaddr of the other
+ // segments found in memory and added to the load address
+ ModuleSP module_sp = GetModule();
+ if (module_sp) {
+ SectionList *section_list = GetSectionList();
+ if (section_list) {
+ lldb::addr_t mach_base_file_addr = LLDB_INVALID_ADDRESS;
+ const size_t num_sections = section_list->GetSize();
+
+ for (size_t sect_idx = 0; sect_idx < num_sections &&
+ mach_base_file_addr == LLDB_INVALID_ADDRESS;
+ ++sect_idx) {
+ Section *section = section_list->GetSectionAtIndex(sect_idx).get();
+ if (section && section->GetFileSize() > 0 &&
+ section->GetFileOffset() == 0 &&
+ section->IsThreadSpecific() == false &&
+ module_sp.get() == section->GetModule().get()) {
+ return section;
}
+ }
}
- return nullptr;
+ }
+ return nullptr;
}
-lldb::addr_t
-ObjectFileMachO::CalculateSectionLoadAddressForMemoryImage(lldb::addr_t mach_header_load_address, const Section *mach_header_section, const Section *section)
-{
- ModuleSP module_sp = GetModule();
- if (module_sp && mach_header_section && section && mach_header_load_address != LLDB_INVALID_ADDRESS)
- {
- lldb::addr_t mach_header_file_addr = mach_header_section->GetFileAddress();
- if (mach_header_file_addr != LLDB_INVALID_ADDRESS)
- {
- if (section &&
- section->GetFileSize() > 0 &&
- section->IsThreadSpecific() == false &&
- module_sp.get() == section->GetModule().get())
- {
- // Ignore __LINKEDIT and __DWARF segments
- if (section->GetName() == GetSegmentNameLINKEDIT())
- {
- // Only map __LINKEDIT if we have an in memory image and this isn't
- // a kernel binary like a kext or mach_kernel.
- const bool is_memory_image = (bool)m_process_wp.lock();
- const Strata strata = GetStrata();
- if (is_memory_image == false || strata == eStrataKernel)
- return LLDB_INVALID_ADDRESS;
- }
- return section->GetFileAddress() - mach_header_file_addr + mach_header_load_address;
- }
+lldb::addr_t ObjectFileMachO::CalculateSectionLoadAddressForMemoryImage(
+ lldb::addr_t mach_header_load_address, const Section *mach_header_section,
+ const Section *section) {
+ ModuleSP module_sp = GetModule();
+ if (module_sp && mach_header_section && section &&
+ mach_header_load_address != LLDB_INVALID_ADDRESS) {
+ lldb::addr_t mach_header_file_addr = mach_header_section->GetFileAddress();
+ if (mach_header_file_addr != LLDB_INVALID_ADDRESS) {
+ if (section && section->GetFileSize() > 0 &&
+ section->IsThreadSpecific() == false &&
+ module_sp.get() == section->GetModule().get()) {
+ // Ignore __LINKEDIT and __DWARF segments
+ if (section->GetName() == GetSegmentNameLINKEDIT()) {
+ // Only map __LINKEDIT if we have an in memory image and this isn't
+ // a kernel binary like a kext or mach_kernel.
+ const bool is_memory_image = (bool)m_process_wp.lock();
+ const Strata strata = GetStrata();
+ if (is_memory_image == false || strata == eStrataKernel)
+ return LLDB_INVALID_ADDRESS;
}
+ return section->GetFileAddress() - mach_header_file_addr +
+ mach_header_load_address;
+ }
}
- return LLDB_INVALID_ADDRESS;
+ }
+ return LLDB_INVALID_ADDRESS;
}
-bool
-ObjectFileMachO::SetLoadAddress (Target &target,
- lldb::addr_t value,
- bool value_is_offset)
-{
- ModuleSP module_sp = GetModule();
- if (module_sp)
- {
- size_t num_loaded_sections = 0;
- SectionList *section_list = GetSectionList ();
- if (section_list)
- {
- const size_t num_sections = section_list->GetSize();
-
- if (value_is_offset)
- {
- // "value" is an offset to apply to each top level segment
- for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx)
- {
- // Iterate through the object file sections to find all
- // of the sections that size on disk (to avoid __PAGEZERO)
- // and load them
- SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx));
- if (section_sp &&
- section_sp->GetFileSize() > 0 &&
- section_sp->IsThreadSpecific() == false &&
- module_sp.get() == section_sp->GetModule().get())
- {
- // Ignore __LINKEDIT and __DWARF segments
- if (section_sp->GetName() == GetSegmentNameLINKEDIT())
- {
- // Only map __LINKEDIT if we have an in memory image and this isn't
- // a kernel binary like a kext or mach_kernel.
- const bool is_memory_image = (bool)m_process_wp.lock();
- const Strata strata = GetStrata();
- if (is_memory_image == false || strata == eStrataKernel)
- continue;
- }
- if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress() + value))
- ++num_loaded_sections;
- }
- }
+bool ObjectFileMachO::SetLoadAddress(Target &target, lldb::addr_t value,
+ bool value_is_offset) {
+ ModuleSP module_sp = GetModule();
+ if (module_sp) {
+ size_t num_loaded_sections = 0;
+ SectionList *section_list = GetSectionList();
+ if (section_list) {
+ const size_t num_sections = section_list->GetSize();
+
+ if (value_is_offset) {
+ // "value" is an offset to apply to each top level segment
+ for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
+ // Iterate through the object file sections to find all
+ // of the sections that size on disk (to avoid __PAGEZERO)
+ // and load them
+ SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
+ if (section_sp && section_sp->GetFileSize() > 0 &&
+ section_sp->IsThreadSpecific() == false &&
+ module_sp.get() == section_sp->GetModule().get()) {
+ // Ignore __LINKEDIT and __DWARF segments
+ if (section_sp->GetName() == GetSegmentNameLINKEDIT()) {
+ // Only map __LINKEDIT if we have an in memory image and this
+ // isn't
+ // a kernel binary like a kext or mach_kernel.
+ const bool is_memory_image = (bool)m_process_wp.lock();
+ const Strata strata = GetStrata();
+ if (is_memory_image == false || strata == eStrataKernel)
+ continue;
}
- else
- {
- // "value" is the new base address of the mach_header, adjust each
- // section accordingly
-
- Section *mach_header_section = GetMachHeaderSection();
- if (mach_header_section)
- {
- for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx)
- {
- SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx));
-
- lldb::addr_t section_load_addr = CalculateSectionLoadAddressForMemoryImage(value, mach_header_section, section_sp.get());
- if (section_load_addr != LLDB_INVALID_ADDRESS)
- {
- if (target.GetSectionLoadList().SetSectionLoadAddress (section_sp, section_load_addr))
- ++num_loaded_sections;
- }
- }
- }
+ if (target.GetSectionLoadList().SetSectionLoadAddress(
+ section_sp, section_sp->GetFileAddress() + value))
+ ++num_loaded_sections;
+ }
+ }
+ } else {
+ // "value" is the new base address of the mach_header, adjust each
+ // section accordingly
+
+ Section *mach_header_section = GetMachHeaderSection();
+ if (mach_header_section) {
+ for (size_t sect_idx = 0; sect_idx < num_sections; ++sect_idx) {
+ SectionSP section_sp(section_list->GetSectionAtIndex(sect_idx));
+
+ lldb::addr_t section_load_addr =
+ CalculateSectionLoadAddressForMemoryImage(
+ value, mach_header_section, section_sp.get());
+ if (section_load_addr != LLDB_INVALID_ADDRESS) {
+ if (target.GetSectionLoadList().SetSectionLoadAddress(
+ section_sp, section_load_addr))
+ ++num_loaded_sections;
}
+ }
}
- return num_loaded_sections > 0;
+ }
}
- return false;
+ return num_loaded_sections > 0;
+ }
+ return false;
}
-bool
-ObjectFileMachO::SaveCore (const lldb::ProcessSP &process_sp,
- const FileSpec &outfile,
- Error &error)
-{
- if (process_sp)
- {
- Target &target = process_sp->GetTarget();
- const ArchSpec target_arch = target.GetArchitecture();
- const llvm::Triple &target_triple = target_arch.GetTriple();
- if (target_triple.getVendor() == llvm::Triple::Apple &&
- (target_triple.getOS() == llvm::Triple::MacOSX
- || target_triple.getOS() == llvm::Triple::IOS
- || target_triple.getOS() == llvm::Triple::WatchOS
- || target_triple.getOS() == llvm::Triple::TvOS))
- {
- bool make_core = false;
- switch (target_arch.GetMachine())
- {
- case llvm::Triple::aarch64:
- case llvm::Triple::arm:
- case llvm::Triple::thumb:
- case llvm::Triple::x86:
- case llvm::Triple::x86_64:
- make_core = true;
- break;
- default:
- error.SetErrorStringWithFormat ("unsupported core architecture: %s", target_triple.str().c_str());
- break;
+bool ObjectFileMachO::SaveCore(const lldb::ProcessSP &process_sp,
+ const FileSpec &outfile, Error &error) {
+ if (process_sp) {
+ Target &target = process_sp->GetTarget();
+ const ArchSpec target_arch = target.GetArchitecture();
+ const llvm::Triple &target_triple = target_arch.GetTriple();
+ if (target_triple.getVendor() == llvm::Triple::Apple &&
+ (target_triple.getOS() == llvm::Triple::MacOSX ||
+ target_triple.getOS() == llvm::Triple::IOS ||
+ target_triple.getOS() == llvm::Triple::WatchOS ||
+ target_triple.getOS() == llvm::Triple::TvOS)) {
+ bool make_core = false;
+ switch (target_arch.GetMachine()) {
+ case llvm::Triple::aarch64:
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ make_core = true;
+ break;
+ default:
+ error.SetErrorStringWithFormat("unsupported core architecture: %s",
+ target_triple.str().c_str());
+ break;
+ }
+
+ if (make_core) {
+ std::vector<segment_command_64> segment_load_commands;
+ // uint32_t range_info_idx = 0;
+ MemoryRegionInfo range_info;
+ Error range_error = process_sp->GetMemoryRegionInfo(0, range_info);
+ const uint32_t addr_byte_size = target_arch.GetAddressByteSize();
+ const ByteOrder byte_order = target_arch.GetByteOrder();
+ if (range_error.Success()) {
+ while (range_info.GetRange().GetRangeBase() != LLDB_INVALID_ADDRESS) {
+ const addr_t addr = range_info.GetRange().GetRangeBase();
+ const addr_t size = range_info.GetRange().GetByteSize();
+
+ if (size == 0)
+ break;
+
+ // Calculate correct protections
+ uint32_t prot = 0;
+ if (range_info.GetReadable() == MemoryRegionInfo::eYes)
+ prot |= VM_PROT_READ;
+ if (range_info.GetWritable() == MemoryRegionInfo::eYes)
+ prot |= VM_PROT_WRITE;
+ if (range_info.GetExecutable() == MemoryRegionInfo::eYes)
+ prot |= VM_PROT_EXECUTE;
+
+ // printf ("[%3u] [0x%16.16" PRIx64 " -
+ // 0x%16.16" PRIx64 ") %c%c%c\n",
+ // range_info_idx,
+ // addr,
+ // size,
+ // (prot & VM_PROT_READ ) ? 'r' :
+ // '-',
+ // (prot & VM_PROT_WRITE ) ? 'w' :
+ // '-',
+ // (prot & VM_PROT_EXECUTE) ? 'x' :
+ // '-');
+
+ if (prot != 0) {
+ uint32_t cmd_type = LC_SEGMENT_64;
+ uint32_t segment_size = sizeof(segment_command_64);
+ if (addr_byte_size == 4) {
+ cmd_type = LC_SEGMENT;
+ segment_size = sizeof(segment_command);
+ }
+ segment_command_64 segment = {
+ cmd_type, // uint32_t cmd;
+ segment_size, // uint32_t cmdsize;
+ {0}, // char segname[16];
+ addr, // uint64_t vmaddr; // uint32_t for 32-bit Mach-O
+ size, // uint64_t vmsize; // uint32_t for 32-bit Mach-O
+ 0, // uint64_t fileoff; // uint32_t for 32-bit Mach-O
+ size, // uint64_t filesize; // uint32_t for 32-bit Mach-O
+ prot, // uint32_t maxprot;
+ prot, // uint32_t initprot;
+ 0, // uint32_t nsects;
+ 0}; // uint32_t flags;
+ segment_load_commands.push_back(segment);
+ } else {
+ // No protections and a size of 1 used to be returned from old
+ // debugservers when we asked about a region that was past the
+ // last memory region and it indicates the end...
+ if (size == 1)
+ break;
}
-
- if (make_core)
- {
- std::vector<segment_command_64> segment_load_commands;
-// uint32_t range_info_idx = 0;
- MemoryRegionInfo range_info;
- Error range_error = process_sp->GetMemoryRegionInfo(0, range_info);
- const uint32_t addr_byte_size = target_arch.GetAddressByteSize();
- const ByteOrder byte_order = target_arch.GetByteOrder();
- if (range_error.Success())
- {
- while (range_info.GetRange().GetRangeBase() != LLDB_INVALID_ADDRESS)
- {
- const addr_t addr = range_info.GetRange().GetRangeBase();
- const addr_t size = range_info.GetRange().GetByteSize();
- if (size == 0)
- break;
-
- // Calculate correct protections
- uint32_t prot = 0;
- if (range_info.GetReadable() == MemoryRegionInfo::eYes)
- prot |= VM_PROT_READ;
- if (range_info.GetWritable() == MemoryRegionInfo::eYes)
- prot |= VM_PROT_WRITE;
- if (range_info.GetExecutable() == MemoryRegionInfo::eYes)
- prot |= VM_PROT_EXECUTE;
-
-// printf ("[%3u] [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ") %c%c%c\n",
-// range_info_idx,
-// addr,
-// size,
-// (prot & VM_PROT_READ ) ? 'r' : '-',
-// (prot & VM_PROT_WRITE ) ? 'w' : '-',
-// (prot & VM_PROT_EXECUTE) ? 'x' : '-');
-
- if (prot != 0)
- {
- uint32_t cmd_type = LC_SEGMENT_64;
- uint32_t segment_size = sizeof (segment_command_64);
- if (addr_byte_size == 4)
- {
- cmd_type = LC_SEGMENT;
- segment_size = sizeof (segment_command);
- }
- segment_command_64 segment = {
- cmd_type, // uint32_t cmd;
- segment_size, // uint32_t cmdsize;
- {0}, // char segname[16];
- addr, // uint64_t vmaddr; // uint32_t for 32-bit Mach-O
- size, // uint64_t vmsize; // uint32_t for 32-bit Mach-O
- 0, // uint64_t fileoff; // uint32_t for 32-bit Mach-O
- size, // uint64_t filesize; // uint32_t for 32-bit Mach-O
- prot, // uint32_t maxprot;
- prot, // uint32_t initprot;
- 0, // uint32_t nsects;
- 0 }; // uint32_t flags;
- segment_load_commands.push_back(segment);
- }
- else
- {
- // No protections and a size of 1 used to be returned from old
- // debugservers when we asked about a region that was past the
- // last memory region and it indicates the end...
- if (size == 1)
- break;
- }
-
- range_error = process_sp->GetMemoryRegionInfo(range_info.GetRange().GetRangeEnd(), range_info);
- if (range_error.Fail())
- break;
- }
-
- StreamString buffer (Stream::eBinary,
- addr_byte_size,
- byte_order);
+ range_error = process_sp->GetMemoryRegionInfo(
+ range_info.GetRange().GetRangeEnd(), range_info);
+ if (range_error.Fail())
+ break;
+ }
+
+ StreamString buffer(Stream::eBinary, addr_byte_size, byte_order);
+
+ mach_header_64 mach_header;
+ if (addr_byte_size == 8) {
+ mach_header.magic = MH_MAGIC_64;
+ } else {
+ mach_header.magic = MH_MAGIC;
+ }
+ mach_header.cputype = target_arch.GetMachOCPUType();
+ mach_header.cpusubtype = target_arch.GetMachOCPUSubType();
+ mach_header.filetype = MH_CORE;
+ mach_header.ncmds = segment_load_commands.size();
+ mach_header.flags = 0;
+ mach_header.reserved = 0;
+ ThreadList &thread_list = process_sp->GetThreadList();
+ const uint32_t num_threads = thread_list.GetSize();
+
+ // Make an array of LC_THREAD data items. Each one contains
+ // the contents of the LC_THREAD load command. The data doesn't
+ // contain the load command + load command size, we will
+ // add the load command and load command size as we emit the data.
+ std::vector<StreamString> LC_THREAD_datas(num_threads);
+ for (auto &LC_THREAD_data : LC_THREAD_datas) {
+ LC_THREAD_data.GetFlags().Set(Stream::eBinary);
+ LC_THREAD_data.SetAddressByteSize(addr_byte_size);
+ LC_THREAD_data.SetByteOrder(byte_order);
+ }
+ for (uint32_t thread_idx = 0; thread_idx < num_threads;
+ ++thread_idx) {
+ ThreadSP thread_sp(thread_list.GetThreadAtIndex(thread_idx));
+ if (thread_sp) {
+ switch (mach_header.cputype) {
+ case llvm::MachO::CPU_TYPE_ARM64:
+ RegisterContextDarwin_arm64_Mach::Create_LC_THREAD(
+ thread_sp.get(), LC_THREAD_datas[thread_idx]);
+ break;
- mach_header_64 mach_header;
- if (addr_byte_size == 8)
- {
- mach_header.magic = MH_MAGIC_64;
- }
- else
- {
- mach_header.magic = MH_MAGIC;
- }
- mach_header.cputype = target_arch.GetMachOCPUType();
- mach_header.cpusubtype = target_arch.GetMachOCPUSubType();
- mach_header.filetype = MH_CORE;
- mach_header.ncmds = segment_load_commands.size();
- mach_header.flags = 0;
- mach_header.reserved = 0;
- ThreadList &thread_list = process_sp->GetThreadList();
- const uint32_t num_threads = thread_list.GetSize();
-
- // Make an array of LC_THREAD data items. Each one contains
- // the contents of the LC_THREAD load command. The data doesn't
- // contain the load command + load command size, we will
- // add the load command and load command size as we emit the data.
- std::vector<StreamString> LC_THREAD_datas(num_threads);
- for (auto &LC_THREAD_data : LC_THREAD_datas)
- {
- LC_THREAD_data.GetFlags().Set(Stream::eBinary);
- LC_THREAD_data.SetAddressByteSize(addr_byte_size);
- LC_THREAD_data.SetByteOrder(byte_order);
- }
- for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx)
- {
- ThreadSP thread_sp (thread_list.GetThreadAtIndex(thread_idx));
- if (thread_sp)
- {
- switch (mach_header.cputype)
- {
- case llvm::MachO::CPU_TYPE_ARM64:
- RegisterContextDarwin_arm64_Mach::Create_LC_THREAD (thread_sp.get(), LC_THREAD_datas[thread_idx]);
- break;
-
- case llvm::MachO::CPU_TYPE_ARM:
- RegisterContextDarwin_arm_Mach::Create_LC_THREAD (thread_sp.get(), LC_THREAD_datas[thread_idx]);
- break;
-
- case llvm::MachO::CPU_TYPE_I386:
- RegisterContextDarwin_i386_Mach::Create_LC_THREAD (thread_sp.get(), LC_THREAD_datas[thread_idx]);
- break;
-
- case llvm::MachO::CPU_TYPE_X86_64:
- RegisterContextDarwin_x86_64_Mach::Create_LC_THREAD (thread_sp.get(), LC_THREAD_datas[thread_idx]);
- break;
- }
-
- }
- }
-
- // The size of the load command is the size of the segments...
- if (addr_byte_size == 8)
- {
- mach_header.sizeofcmds = segment_load_commands.size() * sizeof (struct segment_command_64);
- }
- else
- {
- mach_header.sizeofcmds = segment_load_commands.size() * sizeof (struct segment_command);
- }
-
- // and the size of all LC_THREAD load command
- for (const auto &LC_THREAD_data : LC_THREAD_datas)
- {
- ++mach_header.ncmds;
- mach_header.sizeofcmds += 8 + LC_THREAD_data.GetSize();
- }
+ case llvm::MachO::CPU_TYPE_ARM:
+ RegisterContextDarwin_arm_Mach::Create_LC_THREAD(
+ thread_sp.get(), LC_THREAD_datas[thread_idx]);
+ break;
- printf ("mach_header: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x\n",
- mach_header.magic,
- mach_header.cputype,
- mach_header.cpusubtype,
- mach_header.filetype,
- mach_header.ncmds,
- mach_header.sizeofcmds,
- mach_header.flags,
- mach_header.reserved);
-
- // Write the mach header
- buffer.PutHex32(mach_header.magic);
- buffer.PutHex32(mach_header.cputype);
- buffer.PutHex32(mach_header.cpusubtype);
- buffer.PutHex32(mach_header.filetype);
- buffer.PutHex32(mach_header.ncmds);
- buffer.PutHex32(mach_header.sizeofcmds);
- buffer.PutHex32(mach_header.flags);
- if (addr_byte_size == 8)
- {
- buffer.PutHex32(mach_header.reserved);
- }
-
- // Skip the mach header and all load commands and align to the next
- // 0x1000 byte boundary
- addr_t file_offset = buffer.GetSize() + mach_header.sizeofcmds;
- if (file_offset & 0x00000fff)
- {
- file_offset += 0x00001000ull;
- file_offset &= (~0x00001000ull + 1);
- }
-
- for (auto &segment : segment_load_commands)
- {
- segment.fileoff = file_offset;
- file_offset += segment.filesize;
- }
-
- // Write out all of the LC_THREAD load commands
- for (const auto &LC_THREAD_data : LC_THREAD_datas)
- {
- const size_t LC_THREAD_data_size = LC_THREAD_data.GetSize();
- buffer.PutHex32(LC_THREAD);
- buffer.PutHex32(8 + LC_THREAD_data_size); // cmd + cmdsize + data
- buffer.Write(LC_THREAD_data.GetData(), LC_THREAD_data_size);
- }
+ case llvm::MachO::CPU_TYPE_I386:
+ RegisterContextDarwin_i386_Mach::Create_LC_THREAD(
+ thread_sp.get(), LC_THREAD_datas[thread_idx]);
+ break;
- // Write out all of the segment load commands
- for (const auto &segment : segment_load_commands)
- {
- printf ("0x%8.8x 0x%8.8x [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ") [0x%16.16" PRIx64 " 0x%16.16" PRIx64 ") 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x]\n",
- segment.cmd,
- segment.cmdsize,
- segment.vmaddr,
- segment.vmaddr + segment.vmsize,
- segment.fileoff,
- segment.filesize,
- segment.maxprot,
- segment.initprot,
- segment.nsects,
- segment.flags);
-
- buffer.PutHex32(segment.cmd);
- buffer.PutHex32(segment.cmdsize);
- buffer.PutRawBytes(segment.segname, sizeof(segment.segname));
- if (addr_byte_size == 8)
- {
- buffer.PutHex64(segment.vmaddr);
- buffer.PutHex64(segment.vmsize);
- buffer.PutHex64(segment.fileoff);
- buffer.PutHex64(segment.filesize);
- }
- else
- {
- buffer.PutHex32(static_cast<uint32_t>(segment.vmaddr));
- buffer.PutHex32(static_cast<uint32_t>(segment.vmsize));
- buffer.PutHex32(static_cast<uint32_t>(segment.fileoff));
- buffer.PutHex32(static_cast<uint32_t>(segment.filesize));
- }
- buffer.PutHex32(segment.maxprot);
- buffer.PutHex32(segment.initprot);
- buffer.PutHex32(segment.nsects);
- buffer.PutHex32(segment.flags);
- }
-
- File core_file;
- std::string core_file_path(outfile.GetPath());
- error = core_file.Open(core_file_path.c_str(),
- File::eOpenOptionWrite |
- File::eOpenOptionTruncate |
- File::eOpenOptionCanCreate);
- if (error.Success())
- {
- // Read 1 page at a time
- uint8_t bytes[0x1000];
- // Write the mach header and load commands out to the core file
- size_t bytes_written = buffer.GetString().size();
- error = core_file.Write(buffer.GetString().data(), bytes_written);
- if (error.Success())
- {
- // Now write the file data for all memory segments in the process
- for (const auto &segment : segment_load_commands)
- {
- if (core_file.SeekFromStart(segment.fileoff) == -1)
- {
- error.SetErrorStringWithFormat("unable to seek to offset 0x%" PRIx64 " in '%s'", segment.fileoff, core_file_path.c_str());
- break;
- }
-
- printf ("Saving %" PRId64 " bytes of data for memory region at 0x%" PRIx64 "\n", segment.vmsize, segment.vmaddr);
- addr_t bytes_left = segment.vmsize;
- addr_t addr = segment.vmaddr;
- Error memory_read_error;
- while (bytes_left > 0 && error.Success())
- {
- const size_t bytes_to_read = bytes_left > sizeof(bytes) ? sizeof(bytes) : bytes_left;
- const size_t bytes_read = process_sp->ReadMemory(addr, bytes, bytes_to_read, memory_read_error);
- if (bytes_read == bytes_to_read)
- {
- size_t bytes_written = bytes_read;
- error = core_file.Write(bytes, bytes_written);
- bytes_left -= bytes_read;
- addr += bytes_read;
- }
- else
- {
- // Some pages within regions are not readable, those
- // should be zero filled
- memset (bytes, 0, bytes_to_read);
- size_t bytes_written = bytes_to_read;
- error = core_file.Write(bytes, bytes_written);
- bytes_left -= bytes_to_read;
- addr += bytes_to_read;
- }
- }
- }
- }
- }
+ case llvm::MachO::CPU_TYPE_X86_64:
+ RegisterContextDarwin_x86_64_Mach::Create_LC_THREAD(
+ thread_sp.get(), LC_THREAD_datas[thread_idx]);
+ break;
+ }
+ }
+ }
+
+ // The size of the load command is the size of the segments...
+ if (addr_byte_size == 8) {
+ mach_header.sizeofcmds = segment_load_commands.size() *
+ sizeof(struct segment_command_64);
+ } else {
+ mach_header.sizeofcmds =
+ segment_load_commands.size() * sizeof(struct segment_command);
+ }
+
+ // and the size of all LC_THREAD load command
+ for (const auto &LC_THREAD_data : LC_THREAD_datas) {
+ ++mach_header.ncmds;
+ mach_header.sizeofcmds += 8 + LC_THREAD_data.GetSize();
+ }
+
+ printf("mach_header: 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x "
+ "0x%8.8x 0x%8.8x\n",
+ mach_header.magic, mach_header.cputype, mach_header.cpusubtype,
+ mach_header.filetype, mach_header.ncmds,
+ mach_header.sizeofcmds, mach_header.flags,
+ mach_header.reserved);
+
+ // Write the mach header
+ buffer.PutHex32(mach_header.magic);
+ buffer.PutHex32(mach_header.cputype);
+ buffer.PutHex32(mach_header.cpusubtype);
+ buffer.PutHex32(mach_header.filetype);
+ buffer.PutHex32(mach_header.ncmds);
+ buffer.PutHex32(mach_header.sizeofcmds);
+ buffer.PutHex32(mach_header.flags);
+ if (addr_byte_size == 8) {
+ buffer.PutHex32(mach_header.reserved);
+ }
+
+ // Skip the mach header and all load commands and align to the next
+ // 0x1000 byte boundary
+ addr_t file_offset = buffer.GetSize() + mach_header.sizeofcmds;
+ if (file_offset & 0x00000fff) {
+ file_offset += 0x00001000ull;
+ file_offset &= (~0x00001000ull + 1);
+ }
+
+ for (auto &segment : segment_load_commands) {
+ segment.fileoff = file_offset;
+ file_offset += segment.filesize;
+ }
+
+ // Write out all of the LC_THREAD load commands
+ for (const auto &LC_THREAD_data : LC_THREAD_datas) {
+ const size_t LC_THREAD_data_size = LC_THREAD_data.GetSize();
+ buffer.PutHex32(LC_THREAD);
+ buffer.PutHex32(8 + LC_THREAD_data_size); // cmd + cmdsize + data
+ buffer.Write(LC_THREAD_data.GetData(), LC_THREAD_data_size);
+ }
+
+ // Write out all of the segment load commands
+ for (const auto &segment : segment_load_commands) {
+ printf("0x%8.8x 0x%8.8x [0x%16.16" PRIx64 " - 0x%16.16" PRIx64
+ ") [0x%16.16" PRIx64 " 0x%16.16" PRIx64
+ ") 0x%8.8x 0x%8.8x 0x%8.8x 0x%8.8x]\n",
+ segment.cmd, segment.cmdsize, segment.vmaddr,
+ segment.vmaddr + segment.vmsize, segment.fileoff,
+ segment.filesize, segment.maxprot, segment.initprot,
+ segment.nsects, segment.flags);
+
+ buffer.PutHex32(segment.cmd);
+ buffer.PutHex32(segment.cmdsize);
+ buffer.PutRawBytes(segment.segname, sizeof(segment.segname));
+ if (addr_byte_size == 8) {
+ buffer.PutHex64(segment.vmaddr);
+ buffer.PutHex64(segment.vmsize);
+ buffer.PutHex64(segment.fileoff);
+ buffer.PutHex64(segment.filesize);
+ } else {
+ buffer.PutHex32(static_cast<uint32_t>(segment.vmaddr));
+ buffer.PutHex32(static_cast<uint32_t>(segment.vmsize));
+ buffer.PutHex32(static_cast<uint32_t>(segment.fileoff));
+ buffer.PutHex32(static_cast<uint32_t>(segment.filesize));
+ }
+ buffer.PutHex32(segment.maxprot);
+ buffer.PutHex32(segment.initprot);
+ buffer.PutHex32(segment.nsects);
+ buffer.PutHex32(segment.flags);
+ }
+
+ File core_file;
+ std::string core_file_path(outfile.GetPath());
+ error = core_file.Open(core_file_path.c_str(),
+ File::eOpenOptionWrite |
+ File::eOpenOptionTruncate |
+ File::eOpenOptionCanCreate);
+ if (error.Success()) {
+ // Read 1 page at a time
+ uint8_t bytes[0x1000];
+ // Write the mach header and load commands out to the core file
+ size_t bytes_written = buffer.GetString().size();
+ error = core_file.Write(buffer.GetString().data(), bytes_written);
+ if (error.Success()) {
+ // Now write the file data for all memory segments in the process
+ for (const auto &segment : segment_load_commands) {
+ if (core_file.SeekFromStart(segment.fileoff) == -1) {
+ error.SetErrorStringWithFormat(
+ "unable to seek to offset 0x%" PRIx64 " in '%s'",
+ segment.fileoff, core_file_path.c_str());
+ break;
}
- else
- {
- error.SetErrorString("process doesn't support getting memory region info");
+
+ printf("Saving %" PRId64
+ " bytes of data for memory region at 0x%" PRIx64 "\n",
+ segment.vmsize, segment.vmaddr);
+ addr_t bytes_left = segment.vmsize;
+ addr_t addr = segment.vmaddr;
+ Error memory_read_error;
+ while (bytes_left > 0 && error.Success()) {
+ const size_t bytes_to_read =
+ bytes_left > sizeof(bytes) ? sizeof(bytes) : bytes_left;
+ const size_t bytes_read = process_sp->ReadMemory(
+ addr, bytes, bytes_to_read, memory_read_error);
+ if (bytes_read == bytes_to_read) {
+ size_t bytes_written = bytes_read;
+ error = core_file.Write(bytes, bytes_written);
+ bytes_left -= bytes_read;
+ addr += bytes_read;
+ } else {
+ // Some pages within regions are not readable, those
+ // should be zero filled
+ memset(bytes, 0, bytes_to_read);
+ size_t bytes_written = bytes_to_read;
+ error = core_file.Write(bytes, bytes_written);
+ bytes_left -= bytes_to_read;
+ addr += bytes_to_read;
+ }
}
+ }
}
- return true; // This is the right plug to handle saving core files for this process
+ }
+ } else {
+ error.SetErrorString(
+ "process doesn't support getting memory region info");
}
+ }
+ return true; // This is the right plug to handle saving core files for
+ // this process
}
- return false;
+ }
+ return false;
}
OpenPOWER on IntegriCloud