aboutsummaryrefslogtreecommitdiff
path: root/source/Plugins
diff options
context:
space:
mode:
Diffstat (limited to 'source/Plugins')
-rw-r--r--source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp861
-rw-r--r--source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h138
-rw-r--r--source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp977
-rw-r--r--source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h139
-rw-r--r--source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp1288
-rw-r--r--source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h138
-rw-r--r--source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp864
-rw-r--r--source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h166
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp177
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h115
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp336
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h230
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp481
-rw-r--r--source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h170
-rw-r--r--source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp209
-rw-r--r--source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h88
-rw-r--r--source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp13625
-rw-r--r--source/Plugins/Instruction/ARM/EmulateInstructionARM.h990
-rw-r--r--source/Plugins/Instruction/ARM/EmulationStateARM.cpp406
-rw-r--r--source/Plugins/Instruction/ARM/EmulationStateARM.h100
-rw-r--r--source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp461
-rw-r--r--source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h101
-rw-r--r--source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp585
-rw-r--r--source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h229
-rw-r--r--source/Plugins/ObjectFile/ELF/ELFHeader.cpp465
-rw-r--r--source/Plugins/ObjectFile/ELF/ELFHeader.h433
-rw-r--r--source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp1893
-rw-r--r--source/Plugins/ObjectFile/ELF/ObjectFileELF.h333
-rw-r--r--source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp417
-rw-r--r--source/Plugins/OperatingSystem/Python/OperatingSystemPython.h109
-rw-r--r--source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp648
-rw-r--r--source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h162
-rw-r--r--source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp418
-rw-r--r--source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h147
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp132
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessFreeBSD.h82
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessMonitor.cpp1677
-rw-r--r--source/Plugins/Process/FreeBSD/ProcessMonitor.h322
-rw-r--r--source/Plugins/Process/POSIX/POSIXStopInfo.cpp89
-rw-r--r--source/Plugins/Process/POSIX/POSIXStopInfo.h120
-rw-r--r--source/Plugins/Process/POSIX/POSIXThread.cpp578
-rw-r--r--source/Plugins/Process/POSIX/POSIXThread.h133
-rw-r--r--source/Plugins/Process/POSIX/ProcessMessage.cpp258
-rw-r--r--source/Plugins/Process/POSIX/ProcessMessage.h207
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIX.cpp911
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIX.h211
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp193
-rw-r--r--source/Plugins/Process/POSIX/ProcessPOSIXLog.h111
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp136
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h32
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp180
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h32
-rw-r--r--source/Plugins/Process/POSIX/RegisterContextPOSIX.h70
-rw-r--r--source/Plugins/Process/POSIX/RegisterContext_i386.cpp551
-rw-r--r--source/Plugins/Process/POSIX/RegisterContext_i386.h169
-rw-r--r--source/Plugins/Process/POSIX/RegisterContext_x86.h110
-rw-r--r--source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp1563
-rw-r--r--source/Plugins/Process/POSIX/RegisterContext_x86_64.h347
-rw-r--r--source/Plugins/Process/Utility/ARMDefines.h110
-rw-r--r--source/Plugins/Process/Utility/ARMUtils.h394
-rw-r--r--source/Plugins/Process/Utility/DynamicRegisterInfo.cpp279
-rw-r--r--source/Plugins/Process/Utility/DynamicRegisterInfo.h85
-rw-r--r--source/Plugins/Process/Utility/InferiorCallPOSIX.cpp274
-rw-r--r--source/Plugins/Process/Utility/InferiorCallPOSIX.h43
-rw-r--r--source/Plugins/Process/Utility/InstructionUtils.h136
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp1226
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_arm.h333
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp980
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_i386.h269
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp1066
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h274
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDummy.cpp137
-rw-r--r--source/Plugins/Process/Utility/RegisterContextDummy.h77
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLLDB.cpp1541
-rw-r--r--source/Plugins/Process/Utility/RegisterContextLLDB.h212
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp206
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h77
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_arm.cpp87
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_arm.h56
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_i386.cpp72
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_i386.h49
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp72
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMach_x86_64.h49
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMemory.cpp174
-rw-r--r--source/Plugins/Process/Utility/RegisterContextMemory.h102
-rw-r--r--source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp261
-rw-r--r--source/Plugins/Process/Utility/RegisterContextThreadMemory.h114
-rw-r--r--source/Plugins/Process/Utility/StopInfoMachException.cpp482
-rw-r--r--source/Plugins/Process/Utility/StopInfoMachException.h77
-rw-r--r--source/Plugins/Process/Utility/ThreadMemory.cpp140
-rw-r--r--source/Plugins/Process/Utility/ThreadMemory.h152
-rw-r--r--source/Plugins/Process/Utility/UnwindLLDB.cpp322
-rw-r--r--source/Plugins/Process/Utility/UnwindLLDB.h125
-rw-r--r--source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp275
-rw-r--r--source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h74
-rw-r--r--source/Plugins/Process/elf-core/ProcessElfCore.cpp619
-rw-r--r--source/Plugins/Process/elf-core/ProcessElfCore.h171
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.cpp68
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.h47
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.cpp68
-rw-r--r--source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.h54
-rw-r--r--source/Plugins/Process/elf-core/ThreadElfCore.cpp176
-rw-r--r--source/Plugins/Process/elf-core/ThreadElfCore.h174
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp643
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h268
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp2348
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h430
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp839
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h147
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp971
-rw-r--r--source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h311
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp3291
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemote.h396
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp196
-rw-r--r--source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h57
-rw-r--r--source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp214
-rw-r--r--source/Plugins/Process/gdb-remote/ThreadGDBRemote.h107
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp211
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h81
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFAttribute.h45
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp1027
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h210
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp62
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h51
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp202
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h74
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp274
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h76
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp177
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h94
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp797
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h89
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp2317
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h457
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp1436
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h225
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp48
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h29
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp132
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h57
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp296
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h38
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp166
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h99
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp192
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h46
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp104
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h109
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp497
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFDefines.h116
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp599
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFFormValue.h81
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp172
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h24
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp94
-rw-r--r--source/Plugins/SymbolFile/DWARF/DWARFLocationList.h34
-rw-r--r--source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h933
-rw-r--r--source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp232
-rw-r--r--source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h89
-rw-r--r--source/Plugins/SymbolFile/DWARF/NameToDIE.cpp87
-rw-r--r--source/Plugins/SymbolFile/DWARF/NameToDIE.h65
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp7973
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h622
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp1586
-rw-r--r--source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h420
-rw-r--r--source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp94
-rw-r--r--source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h175
-rw-r--r--source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp407
-rw-r--r--source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h142
-rw-r--r--source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp199
-rw-r--r--source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h58
-rw-r--r--source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp670
-rw-r--r--source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h185
-rw-r--r--source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp973
-rw-r--r--source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h73
175 files changed, 83931 insertions, 0 deletions
diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
new file mode 100644
index 000000000000..4685c3e759e0
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.cpp
@@ -0,0 +1,861 @@
+//===-- ABIMacOSX_arm.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ABIMacOSX_arm.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "llvm/ADT/Triple.h"
+
+#include "Utility/ARM_DWARF_Registers.h"
+#include "Utility/ARM_GCC_Registers.h"
+#include "Plugins/Process/Utility/ARMDefines.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static RegisterInfo g_register_infos[] =
+{
+ // NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+ // ========== ======= == === ============= ============ ======================= =================== =========================== ======================= ====================== ========== ===============
+ { "r0", "arg1", 4, 0, eEncodingUint , eFormatHex, { gcc_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1, gdb_arm_r0, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r1", "arg2", 4, 0, eEncodingUint , eFormatHex, { gcc_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2, gdb_arm_r1, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r2", "arg3", 4, 0, eEncodingUint , eFormatHex, { gcc_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3, gdb_arm_r2, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r3", "arg4", 4, 0, eEncodingUint , eFormatHex, { gcc_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4, gdb_arm_r3, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r4", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, gdb_arm_r4, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r5", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, gdb_arm_r5, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r6", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, gdb_arm_r6, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r7", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, gdb_arm_r7, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r8", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, gdb_arm_r8, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r9", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, gdb_arm_r9, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r10", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, gdb_arm_r10, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r11", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM, gdb_arm_r11, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r12", NULL, 4, 0, eEncodingUint , eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, gdb_arm_r12, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "sp", "r13", 4, 0, eEncodingUint , eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, gdb_arm_sp, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "lr", "r14", 4, 0, eEncodingUint , eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_arm_lr, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "pc", "r15", 4, 0, eEncodingUint , eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, gdb_arm_pc, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "cpsr", "psr", 4, 0, eEncodingUint , eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, gdb_arm_cpsr, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s0", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, gdb_arm_s0, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s1", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, gdb_arm_s1, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s2", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, gdb_arm_s2, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s3", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, gdb_arm_s3, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s4", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, gdb_arm_s4, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s5", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, gdb_arm_s5, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s6", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, gdb_arm_s6, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s7", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, gdb_arm_s7, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s8", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, gdb_arm_s8, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s9", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, gdb_arm_s9, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s10", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, gdb_arm_s10, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s11", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, gdb_arm_s11, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s12", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, gdb_arm_s12, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s13", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, gdb_arm_s13, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s14", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, gdb_arm_s14, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s15", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, gdb_arm_s15, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s16", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, gdb_arm_s16, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s17", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, gdb_arm_s17, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s18", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, gdb_arm_s18, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s19", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, gdb_arm_s19, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s20", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, gdb_arm_s20, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s21", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, gdb_arm_s21, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s22", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, gdb_arm_s22, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s23", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, gdb_arm_s23, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s24", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, gdb_arm_s24, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s25", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, gdb_arm_s25, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s26", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, gdb_arm_s26, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s27", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, gdb_arm_s27, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s28", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, gdb_arm_s28, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s29", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, gdb_arm_s29, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s30", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, gdb_arm_s30, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "s31", NULL, 4, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, gdb_arm_s31, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fpscr", NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, gdb_arm_fpscr, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d0", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d0, LLDB_INVALID_REGNUM, gdb_arm_d0, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d1", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d1, LLDB_INVALID_REGNUM, gdb_arm_d1, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d2", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d2, LLDB_INVALID_REGNUM, gdb_arm_d2, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d3", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d3, LLDB_INVALID_REGNUM, gdb_arm_d3, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d4", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d4, LLDB_INVALID_REGNUM, gdb_arm_d4, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d5", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d5, LLDB_INVALID_REGNUM, gdb_arm_d5, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d6", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d6, LLDB_INVALID_REGNUM, gdb_arm_d6, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d7", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d7, LLDB_INVALID_REGNUM, gdb_arm_d7, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d8", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d8, LLDB_INVALID_REGNUM, gdb_arm_d8, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d9", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d9, LLDB_INVALID_REGNUM, gdb_arm_d9, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d10", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d10, LLDB_INVALID_REGNUM, gdb_arm_d10, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d11", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d11, LLDB_INVALID_REGNUM, gdb_arm_d11, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d12", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d12, LLDB_INVALID_REGNUM, gdb_arm_d12, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d13", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d13, LLDB_INVALID_REGNUM, gdb_arm_d13, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d14", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d14, LLDB_INVALID_REGNUM, gdb_arm_d14, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d15", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d15, LLDB_INVALID_REGNUM, gdb_arm_d15, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d16", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM, gdb_arm_d16, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d17", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM, gdb_arm_d17, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d18", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM, gdb_arm_d18, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d19", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM, gdb_arm_d19, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d20", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM, gdb_arm_d20, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d21", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM, gdb_arm_d21, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d22", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM, gdb_arm_d22, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d23", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM, gdb_arm_d23, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d24", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM, gdb_arm_d24, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d25", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM, gdb_arm_d25, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d26", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM, gdb_arm_d26, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d27", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM, gdb_arm_d27, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d28", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM, gdb_arm_d28, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d29", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM, gdb_arm_d29, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d30", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM, gdb_arm_d30, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "d31", NULL, 8, 0, eEncodingIEEE754 , eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM, gdb_arm_d31, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r8_usr", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r8_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r9_usr", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r9_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r10_usr", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r10_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r11_usr", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r11_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r12_usr", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r12_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13_usr", "sp_usr", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14_usr", "lr_usr", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_usr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r8_fiq", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r8_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r9_fiq", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r9_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r10_fiq", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r10_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r11_fiq", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r11_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r12_fiq", NULL, 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r12_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13_fiq", "sp_fiq", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14_fiq", "lr_fiq", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_fiq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13_irq", "sp_irq", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_irq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14_irq", "lr_irq", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_irq, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13_abt", "sp_abt", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_abt, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14_abt", "lr_abt", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_abt, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13_und", "sp_und", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_und, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14_und", "lr_und", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_und, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13_svc", "sp_svc", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r13_svc, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14_svc", "lr_svc", 4, 0, eEncodingUint , eFormatHex, { LLDB_INVALID_REGNUM, dwarf_r14_svc, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL}
+};
+static const uint32_t k_num_register_infos = sizeof(g_register_infos)/sizeof(RegisterInfo);
+static bool g_register_info_names_constified = false;
+
+const lldb_private::RegisterInfo *
+ABIMacOSX_arm::GetRegisterInfoArray (uint32_t &count)
+{
+ // Make the C-string names and alt_names for the register infos into const
+ // C-string values by having the ConstString unique the names in the global
+ // constant C-string pool.
+ if (!g_register_info_names_constified)
+ {
+ g_register_info_names_constified = true;
+ for (uint32_t i=0; i<k_num_register_infos; ++i)
+ {
+ if (g_register_infos[i].name)
+ g_register_infos[i].name = ConstString(g_register_infos[i].name).GetCString();
+ if (g_register_infos[i].alt_name)
+ g_register_infos[i].alt_name = ConstString(g_register_infos[i].alt_name).GetCString();
+ }
+ }
+ count = k_num_register_infos;
+ return g_register_infos;
+}
+
+
+size_t
+ABIMacOSX_arm::GetRedZoneSize () const
+{
+ return 0;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+ABISP
+ABIMacOSX_arm::CreateInstance (const ArchSpec &arch)
+{
+ static ABISP g_abi_sp;
+ const llvm::Triple::ArchType arch_type = arch.GetTriple().getArch();
+ if ((arch_type == llvm::Triple::arm) ||
+ (arch_type == llvm::Triple::thumb))
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABIMacOSX_arm);
+ return g_abi_sp;
+ }
+ return ABISP();
+}
+
+bool
+ABIMacOSX_arm::PrepareTrivialCall (Thread &thread,
+ addr_t sp,
+ addr_t function_addr,
+ addr_t return_addr,
+ addr_t *arg1_ptr,
+ addr_t *arg2_ptr,
+ addr_t *arg3_ptr,
+ addr_t *arg4_ptr,
+ addr_t *arg5_ptr,
+ addr_t *arg6_ptr) const
+{
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return false;
+
+ const uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ const uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ const uint32_t ra_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
+
+ RegisterValue reg_value;
+
+ if (arg1_ptr)
+ {
+ reg_value.SetUInt32(*arg1_ptr);
+ if (!reg_ctx->WriteRegister (reg_ctx->GetRegisterInfoByName("r0"), reg_value))
+ return false;
+
+ if (arg2_ptr)
+ {
+ reg_value.SetUInt32(*arg2_ptr);
+ if (!reg_ctx->WriteRegister (reg_ctx->GetRegisterInfoByName("r1"), reg_value))
+ return false;
+
+ if (arg3_ptr)
+ {
+ reg_value.SetUInt32(*arg3_ptr);
+ if (!reg_ctx->WriteRegister (reg_ctx->GetRegisterInfoByName("r2"), reg_value))
+ return false;
+ if (arg4_ptr)
+ {
+ reg_value.SetUInt32(*arg4_ptr);
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("r3");
+ if (!reg_ctx->WriteRegister (reg_info, reg_value))
+ return false;
+ if (arg5_ptr)
+ {
+ // Keep the stack 8 byte aligned, not that we need to
+ sp -= 8;
+ sp &= ~(8ull-1ull);
+ reg_value.SetUInt32(*arg5_ptr);
+ if (reg_ctx->WriteRegisterValueToMemory (reg_info, sp, reg_info->byte_size, reg_value).Fail())
+ return false;
+ if (arg6_ptr)
+ {
+ reg_value.SetUInt32(*arg6_ptr);
+ if (reg_ctx->WriteRegisterValueToMemory (reg_info, sp + 4, reg_info->byte_size, reg_value).Fail())
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ TargetSP target_sp (thread.CalculateTarget());
+ Address so_addr;
+
+ // Figure out if our return address is ARM or Thumb by using the
+ // Address::GetCallableLoadAddress(Target*) which will figure out the ARM
+ // thumb-ness and set the correct address bits for us.
+ so_addr.SetLoadAddress (return_addr, target_sp.get());
+ return_addr = so_addr.GetCallableLoadAddress (target_sp.get());
+
+ // Set "lr" to the return address
+ if (!reg_ctx->WriteRegisterFromUnsigned (ra_reg_num, return_addr))
+ return false;
+
+ // Set "sp" to the requested value
+ if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_num, sp))
+ return false;
+
+ // If bit zero or 1 is set, this must be a thumb function, no need to figure
+ // this out from the symbols.
+ so_addr.SetLoadAddress (function_addr, target_sp.get());
+ function_addr = so_addr.GetCallableLoadAddress (target_sp.get());
+
+ const RegisterInfo *cpsr_reg_info = reg_ctx->GetRegisterInfoByName("cpsr");
+ const uint32_t curr_cpsr = reg_ctx->ReadRegisterAsUnsigned(cpsr_reg_info, 0);
+
+ // Make a new CPSR and mask out any Thumb IT (if/then) bits
+ uint32_t new_cpsr = curr_cpsr & ~MASK_CPSR_IT_MASK;
+ // If bit zero or 1 is set, this must be thumb...
+ if (function_addr & 1ull)
+ new_cpsr |= MASK_CPSR_T; // Set T bit in CPSR
+ else
+ new_cpsr &= ~MASK_CPSR_T; // Clear T bit in CPSR
+
+ if (new_cpsr != curr_cpsr)
+ {
+ if (!reg_ctx->WriteRegisterFromUnsigned (cpsr_reg_info, new_cpsr))
+ return false;
+ }
+
+ function_addr &= ~1ull; // clear bit zero since the CPSR will take care of the mode for us
+
+ // Set "pc" to the address requested
+ if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_num, function_addr))
+ return false;
+
+ return true;
+}
+
+bool
+ABIMacOSX_arm::GetArgumentValues (Thread &thread,
+ ValueList &values) const
+{
+ uint32_t num_values = values.GetSize();
+
+
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ // For now, assume that the types in the AST values come from the Target's
+ // scratch AST.
+
+ // Extract the register context so we can read arguments from registers
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+
+ if (!reg_ctx)
+ return false;
+
+ addr_t sp = 0;
+
+ for (uint32_t value_idx = 0; value_idx < num_values; ++value_idx)
+ {
+ // We currently only support extracting values with Clang QualTypes.
+ // Do we care about others?
+ Value *value = values.GetValueAtIndex(value_idx);
+
+ if (!value)
+ return false;
+
+ ClangASTType clang_type = value->GetClangType();
+ if (clang_type)
+ {
+ bool is_signed = false;
+ size_t bit_width = 0;
+ if (clang_type.IsIntegerType (is_signed))
+ {
+ bit_width = clang_type.GetBitSize();
+ }
+ else if (clang_type.IsPointerOrReferenceType ())
+ {
+ bit_width = clang_type.GetBitSize();
+ }
+ else
+ {
+ // We only handle integer, pointer and reference types currently...
+ return false;
+ }
+
+ if (bit_width <= (exe_ctx.GetProcessRef().GetAddressByteSize() * 8))
+ {
+ if (value_idx < 4)
+ {
+ // Arguments 1-4 are in r0-r3...
+ const RegisterInfo *arg_reg_info = NULL;
+ // Search by generic ID first, then fall back to by name
+ uint32_t arg_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + value_idx);
+ if (arg_reg_num != LLDB_INVALID_REGNUM)
+ {
+ arg_reg_info = reg_ctx->GetRegisterInfoAtIndex(arg_reg_num);
+ }
+ else
+ {
+ switch (value_idx)
+ {
+ case 0: arg_reg_info = reg_ctx->GetRegisterInfoByName("r0"); break;
+ case 1: arg_reg_info = reg_ctx->GetRegisterInfoByName("r1"); break;
+ case 2: arg_reg_info = reg_ctx->GetRegisterInfoByName("r2"); break;
+ case 3: arg_reg_info = reg_ctx->GetRegisterInfoByName("r3"); break;
+ }
+ }
+
+ if (arg_reg_info)
+ {
+ RegisterValue reg_value;
+
+ if (reg_ctx->ReadRegister(arg_reg_info, reg_value))
+ {
+ if (is_signed)
+ reg_value.SignExtend(bit_width);
+ if (!reg_value.GetScalarValue(value->GetScalar()))
+ return false;
+ continue;
+ }
+ }
+ return false;
+ }
+ else
+ {
+ if (sp == 0)
+ {
+ // Read the stack pointer if it already hasn't been read
+ sp = reg_ctx->GetSP(0);
+ if (sp == 0)
+ return false;
+ }
+
+ // Arguments 5 on up are on the stack
+ const uint32_t arg_byte_size = (bit_width + (8-1)) / 8;
+ Error error;
+ if (!exe_ctx.GetProcessRef().ReadScalarIntegerFromMemory(sp, arg_byte_size, is_signed, value->GetScalar(), error))
+ return false;
+
+ sp += arg_byte_size;
+ }
+ }
+ }
+ }
+ return true;
+}
+
+ValueObjectSP
+ABIMacOSX_arm::GetReturnValueObjectImpl (Thread &thread,
+ lldb_private::ClangASTType &clang_type) const
+{
+ Value value;
+ ValueObjectSP return_valobj_sp;
+
+ if (!clang_type)
+ return return_valobj_sp;
+
+ clang::ASTContext *ast_context = clang_type.GetASTContext();
+ if (!ast_context)
+ return return_valobj_sp;
+
+ //value.SetContext (Value::eContextTypeClangType, clang_type.GetOpaqueQualType());
+ value.SetClangType (clang_type);
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return return_valobj_sp;
+
+ bool is_signed;
+
+ // Get the pointer to the first stack argument so we have a place to start
+ // when reading data
+
+ const RegisterInfo *r0_reg_info = reg_ctx->GetRegisterInfoByName("r0", 0);
+ if (clang_type.IsIntegerType (is_signed))
+ {
+ size_t bit_width = clang_type.GetBitSize();
+
+ switch (bit_width)
+ {
+ default:
+ return return_valobj_sp;
+ case 64:
+ {
+ const RegisterInfo *r1_reg_info = reg_ctx->GetRegisterInfoByName("r1", 0);
+ uint64_t raw_value;
+ raw_value = reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX;
+ raw_value |= ((uint64_t)(reg_ctx->ReadRegisterAsUnsigned(r1_reg_info, 0) & UINT32_MAX)) << 32;
+ if (is_signed)
+ value.GetScalar() = (int64_t)raw_value;
+ else
+ value.GetScalar() = (uint64_t)raw_value;
+ }
+ break;
+ case 32:
+ if (is_signed)
+ value.GetScalar() = (int32_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX);
+ else
+ value.GetScalar() = (uint32_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX);
+ break;
+ case 16:
+ if (is_signed)
+ value.GetScalar() = (int16_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT16_MAX);
+ else
+ value.GetScalar() = (uint16_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT16_MAX);
+ break;
+ case 8:
+ if (is_signed)
+ value.GetScalar() = (int8_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT8_MAX);
+ else
+ value.GetScalar() = (uint8_t)(reg_ctx->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT8_MAX);
+ break;
+ }
+ }
+ else if (clang_type.IsPointerType ())
+ {
+ uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(r0_reg_info, 0) & UINT32_MAX;
+ value.GetScalar() = ptr;
+ }
+ else
+ {
+ // not handled yet
+ return return_valobj_sp;
+ }
+
+ // If we get here, we have a valid Value, so make our ValueObject out of it:
+
+ return_valobj_sp = ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+ return return_valobj_sp;
+}
+
+Error
+ABIMacOSX_arm::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp)
+{
+ Error error;
+ if (!new_value_sp)
+ {
+ error.SetErrorString("Empty value object for return value.");
+ return error;
+ }
+
+ ClangASTType clang_type = new_value_sp->GetClangType();
+ if (!clang_type)
+ {
+ error.SetErrorString ("Null clang type for return value.");
+ return error;
+ }
+
+ Thread *thread = frame_sp->GetThread().get();
+
+ bool is_signed;
+ uint32_t count;
+ bool is_complex;
+
+ RegisterContext *reg_ctx = thread->GetRegisterContext().get();
+
+ bool set_it_simple = false;
+ if (clang_type.IsIntegerType (is_signed) || clang_type.IsPointerType())
+ {
+ DataExtractor data;
+ size_t num_bytes = new_value_sp->GetData(data);
+ lldb::offset_t offset = 0;
+ if (num_bytes <= 8)
+ {
+ const RegisterInfo *r0_info = reg_ctx->GetRegisterInfoByName("r0", 0);
+ if (num_bytes <= 4)
+ {
+ uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (r0_info, raw_value))
+ set_it_simple = true;
+ }
+ else
+ {
+ uint32_t raw_value = data.GetMaxU32(&offset, 4);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (r0_info, raw_value))
+ {
+ const RegisterInfo *r1_info = reg_ctx->GetRegisterInfoByName("r1", 0);
+ uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (r1_info, raw_value))
+ set_it_simple = true;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("We don't support returning longer than 64 bit integer values at present.");
+ }
+ }
+ else if (clang_type.IsFloatingPointType (count, is_complex))
+ {
+ if (is_complex)
+ error.SetErrorString ("We don't support returning complex values at present");
+ else
+ error.SetErrorString ("We don't support returning float values at present");
+ }
+
+ if (!set_it_simple)
+ error.SetErrorString ("We only support setting simple integer return types at present.");
+
+ return error;
+}
+
+bool
+ABIMacOSX_arm::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
+{
+ uint32_t reg_kind = unwind_plan.GetRegisterKind();
+ uint32_t lr_reg_num = LLDB_INVALID_REGNUM;
+ uint32_t sp_reg_num = LLDB_INVALID_REGNUM;
+ uint32_t pc_reg_num = LLDB_INVALID_REGNUM;
+
+ switch (reg_kind)
+ {
+ case eRegisterKindDWARF:
+ case eRegisterKindGCC:
+ lr_reg_num = dwarf_lr;
+ sp_reg_num = dwarf_sp;
+ pc_reg_num = dwarf_pc;
+ break;
+
+ case eRegisterKindGeneric:
+ lr_reg_num = LLDB_REGNUM_GENERIC_RA;
+ sp_reg_num = LLDB_REGNUM_GENERIC_SP;
+ pc_reg_num = LLDB_REGNUM_GENERIC_PC;
+ break;
+ }
+
+ if (lr_reg_num == LLDB_INVALID_REGNUM ||
+ sp_reg_num == LLDB_INVALID_REGNUM ||
+ pc_reg_num == LLDB_INVALID_REGNUM)
+ return false;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+
+ // Our Call Frame Address is the stack pointer value
+ row->SetCFARegister (sp_reg_num);
+
+ // The previous PC is in the LR
+ row->SetRegisterLocationToRegister(pc_reg_num, lr_reg_num, true);
+ unwind_plan.AppendRow (row);
+
+ // All other registers are the same.
+
+ unwind_plan.SetSourceName ("arm at-func-entry default");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+
+ return true;
+}
+
+bool
+ABIMacOSX_arm::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
+{
+ uint32_t fp_reg_num = dwarf_r7; // apple uses r7 for all frames. Normal arm uses r11;
+ uint32_t pc_reg_num = dwarf_pc;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ const int32_t ptr_size = 4;
+
+ unwind_plan.Clear ();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+ row->SetCFARegister (fp_reg_num);
+ row->SetCFAOffset (2 * ptr_size);
+ row->SetOffset (0);
+
+ row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
+ row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
+
+ unwind_plan.AppendRow (row);
+ unwind_plan.SetSourceName ("arm-apple-ios default unwind plan");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+
+ return true;
+}
+
+// ARMv7 on iOS general purpose reg rules:
+// r0-r3 not preserved (used for argument passing)
+// r4-r6 preserved
+// r7 preserved (frame pointer)
+// r8 preserved
+// r9 not preserved (usable as volatile scratch register with iOS 3.x and later)
+// r10-r11 preserved
+// r12 not presrved
+// r13 preserved (stack pointer)
+// r14 not preserved (link register)
+// r15 preserved (pc)
+// cpsr not preserved (different rules for different bits)
+
+// ARMv7 on iOS floating point rules:
+// d0-d7 not preserved (aka s0-s15, q0-q3)
+// d8-d15 preserved (aka s16-s31, q4-q7)
+// d16-d31 not preserved (aka q8-q15)
+
+bool
+ABIMacOSX_arm::RegisterIsVolatile (const RegisterInfo *reg_info)
+{
+ if (reg_info)
+ {
+ // Volatile registers include: r0, r1, r2, r3, r9, r12, r13
+ const char *name = reg_info->name;
+ if (name[0] == 'r')
+ {
+ switch (name[1])
+ {
+ case '0': return name[2] == '\0'; // r0
+ case '1':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // r1
+ case '2':
+ case '3':
+ return name[2] == '\0'; // r12 - r13
+ default:
+ break;
+ }
+ break;
+
+ case '2': return name[2] == '\0'; // r2
+ case '3': return name[2] == '\0'; // r3
+ case '9': return name[2] == '\0'; // r9 (apple-ios only...)
+
+ break;
+ }
+ }
+ else if (name[0] == 'd')
+ {
+ switch (name[1])
+ {
+ case '0':
+ return name[2] == '\0'; // d0 is volatile
+
+ case '1':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // d1 is volatile
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return name[3] == '\0'; // d16 - d19 are volatile
+ default:
+ break;
+ }
+ break;
+
+ case '2':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // d2 is volatile
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return name[3] == '\0'; // d20 - d29 are volatile
+ default:
+ break;
+ }
+ break;
+
+ case '3':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // d3 is volatile
+ case '0':
+ case '1':
+ return name[3] == '\0'; // d30 - d31 are volatile
+ default:
+ break;
+ }
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ return name[2] == '\0'; // d4 - d7 are volatile
+
+ default:
+ break;
+ }
+ }
+ else if (name[0] == 's')
+ {
+ switch (name[1])
+ {
+ case '0':
+ return name[2] == '\0'; // s0 is volatile
+
+ case '1':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // s1 is volatile
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ return name[3] == '\0'; // s10 - s15 are volatile
+ default:
+ break;
+ }
+ break;
+
+ case '2':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // s2 is volatile
+ default:
+ break;
+ }
+ break;
+
+ case '3':
+ switch (name[2])
+ {
+ case '\0':
+ return true; // s3 is volatile
+ default:
+ break;
+ }
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return name[2] == '\0'; // s4 - s9 are volatile
+
+ default:
+ break;
+ }
+ }
+ else if (name[0] == 's' && name[1] == 'p' && name[2] == '\0')
+ return true;
+ }
+ return false;
+}
+
+void
+ABIMacOSX_arm::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "Mac OS X ABI for arm targets",
+ CreateInstance);
+}
+
+void
+ABIMacOSX_arm::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+lldb_private::ConstString
+ABIMacOSX_arm::GetPluginNameStatic()
+{
+ static ConstString g_name("macosx-arm");
+ return g_name;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ABIMacOSX_arm::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ABIMacOSX_arm::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h
new file mode 100644
index 000000000000..27cea85aaf6f
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-arm/ABIMacOSX_arm.h
@@ -0,0 +1,138 @@
+//===-- ABIMacOSX_arm.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ABIMacOSX_arm_h_
+#define liblldb_ABIMacOSX_arm_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+
+class ABIMacOSX_arm : public lldb_private::ABI
+{
+public:
+ ~ABIMacOSX_arm() { }
+
+ virtual size_t
+ GetRedZoneSize () const;
+
+ virtual bool
+ PrepareTrivialCall (lldb_private::Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t func_addr,
+ lldb::addr_t returnAddress,
+ lldb::addr_t *arg1_ptr = NULL,
+ lldb::addr_t *arg2_ptr = NULL,
+ lldb::addr_t *arg3_ptr = NULL,
+ lldb::addr_t *arg4_ptr = NULL,
+ lldb::addr_t *arg5_ptr = NULL,
+ lldb::addr_t *arg6_ptr = NULL) const;
+
+ virtual bool
+ GetArgumentValues (lldb_private::Thread &thread,
+ lldb_private::ValueList &values) const;
+
+ virtual lldb_private::Error
+ SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value);
+
+protected:
+ virtual lldb::ValueObjectSP
+ GetReturnValueObjectImpl (lldb_private::Thread &thread,
+ lldb_private::ClangASTType &ast_type) const;
+
+public:
+ virtual bool
+ CreateFunctionEntryUnwindPlan (lldb_private::UnwindPlan &unwind_plan);
+
+ virtual bool
+ CreateDefaultUnwindPlan (lldb_private::UnwindPlan &unwind_plan);
+
+ virtual bool
+ RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info);
+
+ virtual bool
+ StackUsesFrames ()
+ {
+ return true;
+ }
+
+ virtual bool
+ CallFrameAddressIsValid (lldb::addr_t cfa)
+ {
+ // Make sure the stack call frame addresses are are 4 byte aligned
+ if (cfa & (4ull - 1ull))
+ return false; // Not 4 byte aligned
+ if (cfa == 0)
+ return false; // Zero is not a valid stack address
+ return true;
+ }
+
+ virtual bool
+ CodeAddressIsValid (lldb::addr_t pc)
+ {
+ // Just make sure the address is a valid 32 bit address. Bit zero
+ // might be set due to Thumb function calls, so don't enforce 2 byte
+ // alignment
+ return pc <= UINT32_MAX;
+ }
+
+ virtual lldb::addr_t
+ FixCodeAddress (lldb::addr_t pc)
+ {
+ // ARM uses bit zero to signify a code address is thumb, so we must
+ // strip bit zero in any code addresses.
+ return pc & ~(lldb::addr_t)1;
+ }
+
+ virtual bool
+ FunctionCallsChangeCFA ()
+ {
+ return false;
+ }
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoArray (uint32_t &count);
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb::ABISP
+ CreateInstance (const lldb_private::ArchSpec &arch);
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+protected:
+private:
+ ABIMacOSX_arm() :
+ lldb_private::ABI()
+ {
+ // Call CreateInstance instead.
+ }
+};
+
+#endif // liblldb_ABIMacOSX_arm_h_
diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
new file mode 100644
index 000000000000..deb531d937a0
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.cpp
@@ -0,0 +1,977 @@
+//===-- ABIMacOSX_i386.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ABIMacOSX_i386.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "llvm/ADT/Triple.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum
+{
+ gcc_eax = 0,
+ gcc_ecx,
+ gcc_edx,
+ gcc_ebx,
+ gcc_ebp,
+ gcc_esp,
+ gcc_esi,
+ gcc_edi,
+ gcc_eip,
+ gcc_eflags
+};
+
+enum
+{
+ dwarf_eax = 0,
+ dwarf_ecx,
+ dwarf_edx,
+ dwarf_ebx,
+ dwarf_esp,
+ dwarf_ebp,
+ dwarf_esi,
+ dwarf_edi,
+ dwarf_eip,
+ dwarf_eflags,
+ dwarf_stmm0 = 11,
+ dwarf_stmm1,
+ dwarf_stmm2,
+ dwarf_stmm3,
+ dwarf_stmm4,
+ dwarf_stmm5,
+ dwarf_stmm6,
+ dwarf_stmm7,
+ dwarf_xmm0 = 21,
+ dwarf_xmm1,
+ dwarf_xmm2,
+ dwarf_xmm3,
+ dwarf_xmm4,
+ dwarf_xmm5,
+ dwarf_xmm6,
+ dwarf_xmm7,
+ dwarf_ymm0 = dwarf_xmm0,
+ dwarf_ymm1 = dwarf_xmm1,
+ dwarf_ymm2 = dwarf_xmm2,
+ dwarf_ymm3 = dwarf_xmm3,
+ dwarf_ymm4 = dwarf_xmm4,
+ dwarf_ymm5 = dwarf_xmm5,
+ dwarf_ymm6 = dwarf_xmm6,
+ dwarf_ymm7 = dwarf_xmm7
+};
+
+enum
+{
+ gdb_eax = 0,
+ gdb_ecx = 1,
+ gdb_edx = 2,
+ gdb_ebx = 3,
+ gdb_esp = 4,
+ gdb_ebp = 5,
+ gdb_esi = 6,
+ gdb_edi = 7,
+ gdb_eip = 8,
+ gdb_eflags = 9,
+ gdb_cs = 10,
+ gdb_ss = 11,
+ gdb_ds = 12,
+ gdb_es = 13,
+ gdb_fs = 14,
+ gdb_gs = 15,
+ gdb_stmm0 = 16,
+ gdb_stmm1 = 17,
+ gdb_stmm2 = 18,
+ gdb_stmm3 = 19,
+ gdb_stmm4 = 20,
+ gdb_stmm5 = 21,
+ gdb_stmm6 = 22,
+ gdb_stmm7 = 23,
+ gdb_fctrl = 24, gdb_fcw = gdb_fctrl,
+ gdb_fstat = 25, gdb_fsw = gdb_fstat,
+ gdb_ftag = 26, gdb_ftw = gdb_ftag,
+ gdb_fiseg = 27, gdb_fpu_cs = gdb_fiseg,
+ gdb_fioff = 28, gdb_ip = gdb_fioff,
+ gdb_foseg = 29, gdb_fpu_ds = gdb_foseg,
+ gdb_fooff = 30, gdb_dp = gdb_fooff,
+ gdb_fop = 31,
+ gdb_xmm0 = 32,
+ gdb_xmm1 = 33,
+ gdb_xmm2 = 34,
+ gdb_xmm3 = 35,
+ gdb_xmm4 = 36,
+ gdb_xmm5 = 37,
+ gdb_xmm6 = 38,
+ gdb_xmm7 = 39,
+ gdb_mxcsr = 40,
+ gdb_mm0 = 41,
+ gdb_mm1 = 42,
+ gdb_mm2 = 43,
+ gdb_mm3 = 44,
+ gdb_mm4 = 45,
+ gdb_mm5 = 46,
+ gdb_mm6 = 47,
+ gdb_mm7 = 48,
+ gdb_ymm0 = gdb_xmm0,
+ gdb_ymm1 = gdb_xmm1,
+ gdb_ymm2 = gdb_xmm2,
+ gdb_ymm3 = gdb_xmm3,
+ gdb_ymm4 = gdb_xmm4,
+ gdb_ymm5 = gdb_xmm5,
+ gdb_ymm6 = gdb_xmm6,
+ gdb_ymm7 = gdb_xmm7
+};
+
+
+static RegisterInfo g_register_infos[] =
+{
+ // NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+ // ====== ======= == === ============= ============ ===================== ===================== ============================ ==================== ====================== ========== ===============
+ { "eax", NULL, 4, 0, eEncodingUint , eFormatHex , { gcc_eax , dwarf_eax , LLDB_INVALID_REGNUM , gdb_eax , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ebx" , NULL, 4, 0, eEncodingUint , eFormatHex , { gcc_ebx , dwarf_ebx , LLDB_INVALID_REGNUM , gdb_ebx , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ecx" , NULL, 4, 0, eEncodingUint , eFormatHex , { gcc_ecx , dwarf_ecx , LLDB_REGNUM_GENERIC_ARG4 , gdb_ecx , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "edx" , NULL, 4, 0, eEncodingUint , eFormatHex , { gcc_edx , dwarf_edx , LLDB_REGNUM_GENERIC_ARG3 , gdb_edx , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "esi" , NULL, 4, 0, eEncodingUint , eFormatHex , { gcc_esi , dwarf_esi , LLDB_REGNUM_GENERIC_ARG2 , gdb_esi , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "edi" , NULL, 4, 0, eEncodingUint , eFormatHex , { gcc_edi , dwarf_edi , LLDB_REGNUM_GENERIC_ARG1 , gdb_edi , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ebp" , "fp", 4, 0, eEncodingUint , eFormatHex , { gcc_ebp , dwarf_ebp , LLDB_REGNUM_GENERIC_FP , gdb_ebp , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "esp" , "sp", 4, 0, eEncodingUint , eFormatHex , { gcc_esp , dwarf_esp , LLDB_REGNUM_GENERIC_SP , gdb_esp , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "eip" , "pc", 4, 0, eEncodingUint , eFormatHex , { gcc_eip , dwarf_eip , LLDB_REGNUM_GENERIC_PC , gdb_eip , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "eflags", NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_REGNUM_GENERIC_FLAGS , gdb_eflags , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "cs" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_cs , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ss" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ss , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ds" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ds , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "es" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_es , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fs" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fs , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "gs" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_gs , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm0" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm0 , LLDB_INVALID_REGNUM , gdb_stmm0 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm1" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm1 , LLDB_INVALID_REGNUM , gdb_stmm1 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm2" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm2 , LLDB_INVALID_REGNUM , gdb_stmm2 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm3" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm3 , LLDB_INVALID_REGNUM , gdb_stmm3 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm4" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm4 , LLDB_INVALID_REGNUM , gdb_stmm4 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm5" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm5 , LLDB_INVALID_REGNUM , gdb_stmm5 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm6" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm6 , LLDB_INVALID_REGNUM , gdb_stmm6 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm7" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_stmm7 , LLDB_INVALID_REGNUM , gdb_stmm7 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fctrl" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fctrl , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fstat" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fstat , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ftag" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ftag , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fiseg" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fiseg , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fioff" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fioff , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "foseg" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_foseg , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fooff" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fooff , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fop" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fop , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm0" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm0 , LLDB_INVALID_REGNUM , gdb_xmm0 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm1" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm1 , LLDB_INVALID_REGNUM , gdb_xmm1 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm2" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm2 , LLDB_INVALID_REGNUM , gdb_xmm2 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm3" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm3 , LLDB_INVALID_REGNUM , gdb_xmm3 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm4" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm4 , LLDB_INVALID_REGNUM , gdb_xmm4 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm5" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm5 , LLDB_INVALID_REGNUM , gdb_xmm5 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm6" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm6 , LLDB_INVALID_REGNUM , gdb_xmm6 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm7" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_xmm7 , LLDB_INVALID_REGNUM , gdb_xmm7 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "mxcsr" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_mxcsr , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm0" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm0 , LLDB_INVALID_REGNUM , gdb_ymm0 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm1" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm1 , LLDB_INVALID_REGNUM , gdb_ymm1 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm2" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm2 , LLDB_INVALID_REGNUM , gdb_ymm2 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm3" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm3 , LLDB_INVALID_REGNUM , gdb_ymm3 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm4" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm4 , LLDB_INVALID_REGNUM , gdb_ymm4 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm5" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm5 , LLDB_INVALID_REGNUM , gdb_ymm5 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm6" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm6 , LLDB_INVALID_REGNUM , gdb_ymm6 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm7" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM , dwarf_ymm7 , LLDB_INVALID_REGNUM , gdb_ymm7 , LLDB_INVALID_REGNUM }, NULL, NULL}
+};
+
+static const uint32_t k_num_register_infos = sizeof(g_register_infos)/sizeof(RegisterInfo);
+static bool g_register_info_names_constified = false;
+
+const lldb_private::RegisterInfo *
+ABIMacOSX_i386::GetRegisterInfoArray (uint32_t &count)
+{
+ // Make the C-string names and alt_names for the register infos into const
+ // C-string values by having the ConstString unique the names in the global
+ // constant C-string pool.
+ if (!g_register_info_names_constified)
+ {
+ g_register_info_names_constified = true;
+ for (uint32_t i=0; i<k_num_register_infos; ++i)
+ {
+ if (g_register_infos[i].name)
+ g_register_infos[i].name = ConstString(g_register_infos[i].name).GetCString();
+ if (g_register_infos[i].alt_name)
+ g_register_infos[i].alt_name = ConstString(g_register_infos[i].alt_name).GetCString();
+ }
+ }
+ count = k_num_register_infos;
+ return g_register_infos;
+}
+
+size_t
+ABIMacOSX_i386::GetRedZoneSize () const
+{
+ return 0;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+ABISP
+ABIMacOSX_i386::CreateInstance (const ArchSpec &arch)
+{
+ static ABISP g_abi_sp;
+ if (arch.GetTriple().getArch() == llvm::Triple::x86)
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABIMacOSX_i386);
+ return g_abi_sp;
+ }
+ return ABISP();
+}
+
+bool
+ABIMacOSX_i386::PrepareTrivialCall (Thread &thread,
+ addr_t sp,
+ addr_t func_addr,
+ addr_t return_addr,
+ addr_t *arg1_ptr,
+ addr_t *arg2_ptr,
+ addr_t *arg3_ptr,
+ addr_t *arg4_ptr,
+ addr_t *arg5_ptr,
+ addr_t *arg6_ptr) const
+{
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return false;
+ uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+
+ // When writing a register value down to memory, the register info used
+ // to write memory just needs to have the correct size of a 32 bit register,
+ // the actual register it pertains to is not important, just the size needs
+ // to be correct. Here we use "eax"...
+ const RegisterInfo *reg_info_32 = reg_ctx->GetRegisterInfoByName("eax");
+ if (!reg_info_32)
+ return false; // TODO this should actually never happen
+
+ // Make room for the argument(s) on the stack
+
+ Error error;
+ RegisterValue reg_value;
+
+ // Write any arguments onto the stack
+ if (arg1_ptr)
+ {
+ sp -= 4;
+ if (arg2_ptr)
+ {
+ sp -= 4;
+ if (arg3_ptr)
+ {
+ sp -= 4;
+ if (arg4_ptr)
+ {
+ sp -= 4;
+ if (arg5_ptr)
+ {
+ sp -= 4;
+ if (arg6_ptr)
+ {
+ sp -= 4;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Align the SP
+ sp &= ~(16ull-1ull); // 16-byte alignment
+
+ if (arg1_ptr)
+ {
+ reg_value.SetUInt32(*arg1_ptr);
+ error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
+ sp,
+ reg_info_32->byte_size,
+ reg_value);
+ if (error.Fail())
+ return false;
+
+ if (arg2_ptr)
+ {
+ reg_value.SetUInt32(*arg2_ptr);
+ // The register info used to write memory just needs to have the correct
+ // size of a 32 bit register, the actual register it pertains to is not
+ // important, just the size needs to be correct. Here we use "eax"...
+ error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
+ sp + 4,
+ reg_info_32->byte_size,
+ reg_value);
+ if (error.Fail())
+ return false;
+
+ if (arg3_ptr)
+ {
+ reg_value.SetUInt32(*arg3_ptr);
+ // The register info used to write memory just needs to have the correct
+ // size of a 32 bit register, the actual register it pertains to is not
+ // important, just the size needs to be correct. Here we use "eax"...
+ error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
+ sp + 8,
+ reg_info_32->byte_size,
+ reg_value);
+ if (error.Fail())
+ return false;
+
+ if (arg4_ptr)
+ {
+ reg_value.SetUInt32(*arg4_ptr);
+ // The register info used to write memory just needs to have the correct
+ // size of a 32 bit register, the actual register it pertains to is not
+ // important, just the size needs to be correct. Here we use "eax"...
+ error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
+ sp + 12,
+ reg_info_32->byte_size,
+ reg_value);
+ if (error.Fail())
+ return false;
+ if (arg5_ptr)
+ {
+ reg_value.SetUInt32(*arg5_ptr);
+ // The register info used to write memory just needs to have the correct
+ // size of a 32 bit register, the actual register it pertains to is not
+ // important, just the size needs to be correct. Here we use "eax"...
+ error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
+ sp + 16,
+ reg_info_32->byte_size,
+ reg_value);
+ if (error.Fail())
+ return false;
+ if (arg6_ptr)
+ {
+ reg_value.SetUInt32(*arg6_ptr);
+ // The register info used to write memory just needs to have the correct
+ // size of a 32 bit register, the actual register it pertains to is not
+ // important, just the size needs to be correct. Here we use "eax"...
+ error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
+ sp + 20,
+ reg_info_32->byte_size,
+ reg_value);
+ if (error.Fail())
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ // The return address is pushed onto the stack (yes after we just set the
+ // alignment above!).
+ sp -= 4;
+ reg_value.SetUInt32(return_addr);
+ error = reg_ctx->WriteRegisterValueToMemory (reg_info_32,
+ sp,
+ reg_info_32->byte_size,
+ reg_value);
+ if (error.Fail())
+ return false;
+
+ // %esp is set to the actual stack value.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_num, sp))
+ return false;
+
+ // %eip is set to the address of the called function.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_num, func_addr))
+ return false;
+
+ return true;
+}
+
+bool
+ABIMacOSX_i386::PrepareNormalCall (Thread &thread,
+ addr_t sp,
+ addr_t func_addr,
+ addr_t return_addr,
+ ValueList &args) const
+{
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return false;
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Error error;
+ uint32_t fp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ uint32_t pc_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ uint32_t sp_reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+
+ // Do the argument layout
+
+ std::vector <uint32_t> argLayout; // 4-byte chunks, as discussed in the ABI Function Call Guide
+
+ size_t numArgs = args.GetSize();
+ size_t index;
+
+ for (index = 0; index < numArgs; ++index)
+ {
+ Value *val = args.GetValueAtIndex(index);
+
+ if (!val)
+ return false;
+
+ switch (val->GetValueType())
+ {
+ case Value::eValueTypeScalar:
+ {
+ Scalar &scalar = val->GetScalar();
+ switch (scalar.GetType())
+ {
+ case Scalar::e_void:
+ return false;
+ case Scalar::e_sint:
+ case Scalar::e_uint:
+ case Scalar::e_slong:
+ case Scalar::e_ulong:
+ case Scalar::e_slonglong:
+ case Scalar::e_ulonglong:
+ {
+ uint64_t data = scalar.ULongLong();
+
+ switch (scalar.GetByteSize())
+ {
+ default:
+ return false;
+ case 1:
+ argLayout.push_back((uint32_t)(data & 0xffull));
+ break;
+ case 2:
+ argLayout.push_back((uint32_t)(data & 0xffffull));
+ break;
+ case 4:
+ argLayout.push_back((uint32_t)(data & 0xffffffffull));
+ break;
+ case 8:
+ argLayout.push_back((uint32_t)(data & 0xffffffffull));
+ argLayout.push_back((uint32_t)(data >> 32));
+ break;
+ }
+ }
+ break;
+ case Scalar::e_float:
+ {
+ float data = scalar.Float();
+ uint32_t dataRaw = *((uint32_t*)(&data));
+ argLayout.push_back(dataRaw);
+ }
+ break;
+ case Scalar::e_double:
+ {
+ double data = scalar.Double();
+ uint32_t *dataRaw = ((uint32_t*)(&data));
+ argLayout.push_back(dataRaw[0]);
+ argLayout.push_back(dataRaw[1]);
+ }
+ break;
+ case Scalar::e_long_double:
+ {
+ long double data = scalar.Double();
+ uint32_t *dataRaw = ((uint32_t*)(&data));
+ while ((argLayout.size() * 4) & 0xf)
+ argLayout.push_back(0);
+ argLayout.push_back(dataRaw[0]);
+ argLayout.push_back(dataRaw[1]);
+ argLayout.push_back(dataRaw[2]);
+ argLayout.push_back(dataRaw[3]);
+ }
+ break;
+ }
+ }
+ break;
+ case Value::eValueTypeHostAddress:
+ {
+ ClangASTType clang_type (val->GetClangType());
+ if (clang_type)
+ {
+ uint32_t cstr_length = 0;
+ if (clang_type.IsCStringType (cstr_length))
+ {
+ const char *cstr = (const char*)val->GetScalar().ULongLong();
+ cstr_length = strlen(cstr);
+
+ // Push the string onto the stack immediately.
+
+ sp -= (cstr_length + 1);
+
+ if (process->WriteMemory(sp, cstr, cstr_length + 1, error) != (cstr_length + 1))
+ return false;
+
+ // Put the address of the string into the argument array.
+
+ argLayout.push_back((uint32_t)(sp & 0xffffffff));
+ }
+ else
+ {
+ return false;
+ }
+ }
+ break;
+ }
+ break;
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeLoadAddress:
+ default:
+ return false;
+ }
+ }
+
+ // Make room for the arguments on the stack
+
+ sp -= 4 * argLayout.size();
+
+ // Align the SP
+
+ sp &= ~(16ull-1ull); // 16-byte alignment
+
+ // Write the arguments on the stack
+
+ size_t numChunks = argLayout.size();
+
+ for (index = 0; index < numChunks; ++index)
+ if (process->WriteMemory(sp + (index * 4), &argLayout[index], sizeof(uint32_t), error) != sizeof(uint32_t))
+ return false;
+
+ // The return address is pushed onto the stack.
+
+ sp -= 4;
+ uint32_t returnAddressU32 = return_addr;
+ if (process->WriteMemory (sp, &returnAddressU32, sizeof(returnAddressU32), error) != sizeof(returnAddressU32))
+ return false;
+
+ // %esp is set to the actual stack value.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(sp_reg_num, sp))
+ return false;
+
+ // %ebp is set to a fake value, in our case 0x0x00000000
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(fp_reg_num, 0x00000000))
+ return false;
+
+ // %eip is set to the address of the called function.
+
+ if (!reg_ctx->WriteRegisterFromUnsigned(pc_reg_num, func_addr))
+ return false;
+
+ return true;
+}
+
+static bool
+ReadIntegerArgument (Scalar &scalar,
+ unsigned int bit_width,
+ bool is_signed,
+ Process *process,
+ addr_t &current_stack_argument)
+{
+
+ uint32_t byte_size = (bit_width + (8-1))/8;
+ Error error;
+ if (process->ReadScalarIntegerFromMemory(current_stack_argument, byte_size, is_signed, scalar, error))
+ {
+ current_stack_argument += byte_size;
+ return true;
+ }
+ return false;
+}
+
+bool
+ABIMacOSX_i386::GetArgumentValues (Thread &thread,
+ ValueList &values) const
+{
+ unsigned int num_values = values.GetSize();
+ unsigned int value_index;
+
+ // Get the pointer to the first stack argument so we have a place to start
+ // when reading data
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+
+ if (!reg_ctx)
+ return false;
+
+ addr_t sp = reg_ctx->GetSP(0);
+
+ if (!sp)
+ return false;
+
+ addr_t current_stack_argument = sp + 4; // jump over return address
+
+ for (value_index = 0;
+ value_index < num_values;
+ ++value_index)
+ {
+ Value *value = values.GetValueAtIndex(value_index);
+
+ if (!value)
+ return false;
+
+ // We currently only support extracting values with Clang QualTypes.
+ // Do we care about others?
+ ClangASTType clang_type (value->GetClangType());
+ if (clang_type)
+ {
+ bool is_signed;
+
+ if (clang_type.IsIntegerType (is_signed))
+ {
+ ReadIntegerArgument(value->GetScalar(),
+ clang_type.GetBitSize(),
+ is_signed,
+ thread.GetProcess().get(),
+ current_stack_argument);
+ }
+ else if (clang_type.IsPointerType())
+ {
+ ReadIntegerArgument(value->GetScalar(),
+ clang_type.GetBitSize(),
+ false,
+ thread.GetProcess().get(),
+ current_stack_argument);
+ }
+ }
+ }
+
+ return true;
+}
+
+Error
+ABIMacOSX_i386::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp)
+{
+ Error error;
+ if (!new_value_sp)
+ {
+ error.SetErrorString("Empty value object for return value.");
+ return error;
+ }
+
+ ClangASTType clang_type = new_value_sp->GetClangType();
+ if (!clang_type)
+ {
+ error.SetErrorString ("Null clang type for return value.");
+ return error;
+ }
+
+ Thread *thread = frame_sp->GetThread().get();
+
+ bool is_signed;
+ uint32_t count;
+ bool is_complex;
+
+ RegisterContext *reg_ctx = thread->GetRegisterContext().get();
+
+ bool set_it_simple = false;
+ if (clang_type.IsIntegerType (is_signed) || clang_type.IsPointerType())
+ {
+ DataExtractor data;
+ size_t num_bytes = new_value_sp->GetData(data);
+ lldb::offset_t offset = 0;
+ if (num_bytes <= 8)
+ {
+ const RegisterInfo *eax_info = reg_ctx->GetRegisterInfoByName("eax", 0);
+ if (num_bytes <= 4)
+ {
+ uint32_t raw_value = data.GetMaxU32(&offset, num_bytes);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (eax_info, raw_value))
+ set_it_simple = true;
+ }
+ else
+ {
+ uint32_t raw_value = data.GetMaxU32(&offset, 4);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (eax_info, raw_value))
+ {
+ const RegisterInfo *edx_info = reg_ctx->GetRegisterInfoByName("edx", 0);
+ uint32_t raw_value = data.GetMaxU32(&offset, num_bytes - offset);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (edx_info, raw_value))
+ set_it_simple = true;
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("We don't support returning longer than 64 bit integer values at present.");
+ }
+ }
+ else if (clang_type.IsFloatingPointType (count, is_complex))
+ {
+ if (is_complex)
+ error.SetErrorString ("We don't support returning complex values at present");
+ else
+ error.SetErrorString ("We don't support returning float values at present");
+ }
+
+ if (!set_it_simple)
+ error.SetErrorString ("We only support setting simple integer return types at present.");
+
+ return error;
+}
+
+ValueObjectSP
+ABIMacOSX_i386::GetReturnValueObjectImpl (Thread &thread,
+ ClangASTType &clang_type) const
+{
+ Value value;
+ ValueObjectSP return_valobj_sp;
+
+ if (!clang_type)
+ return return_valobj_sp;
+
+ //value.SetContext (Value::eContextTypeClangType, clang_type.GetOpaqueQualType());
+ value.SetClangType (clang_type);
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return return_valobj_sp;
+
+ bool is_signed;
+
+ if (clang_type.IsIntegerType (is_signed))
+ {
+ size_t bit_width = clang_type.GetBitSize();
+
+ unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
+ unsigned edx_id = reg_ctx->GetRegisterInfoByName("edx", 0)->kinds[eRegisterKindLLDB];
+
+ switch (bit_width)
+ {
+ default:
+ case 128:
+ // Scalar can't hold 128-bit literals, so we don't handle this
+ return return_valobj_sp;
+ case 64:
+ uint64_t raw_value;
+ raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff;
+ raw_value |= (thread.GetRegisterContext()->ReadRegisterAsUnsigned(edx_id, 0) & 0xffffffff) << 32;
+ if (is_signed)
+ value.GetScalar() = (int64_t)raw_value;
+ else
+ value.GetScalar() = (uint64_t)raw_value;
+ break;
+ case 32:
+ if (is_signed)
+ value.GetScalar() = (int32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff);
+ else
+ value.GetScalar() = (uint32_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff);
+ break;
+ case 16:
+ if (is_signed)
+ value.GetScalar() = (int16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffff);
+ else
+ value.GetScalar() = (uint16_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffff);
+ break;
+ case 8:
+ if (is_signed)
+ value.GetScalar() = (int8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xff);
+ else
+ value.GetScalar() = (uint8_t)(thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xff);
+ break;
+ }
+ }
+ else if (clang_type.IsPointerType ())
+ {
+ unsigned eax_id = reg_ctx->GetRegisterInfoByName("eax", 0)->kinds[eRegisterKindLLDB];
+ uint32_t ptr = thread.GetRegisterContext()->ReadRegisterAsUnsigned(eax_id, 0) & 0xffffffff;
+ value.GetScalar() = ptr;
+ }
+ else
+ {
+ // not handled yet
+ return return_valobj_sp;
+ }
+
+ // If we get here, we have a valid Value, so make our ValueObject out of it:
+
+ return_valobj_sp = ValueObjectConstResult::Create(thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+ return return_valobj_sp;
+}
+
+bool
+ABIMacOSX_i386::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
+{
+ uint32_t reg_kind = unwind_plan.GetRegisterKind();
+ uint32_t sp_reg_num = LLDB_INVALID_REGNUM;
+ uint32_t pc_reg_num = LLDB_INVALID_REGNUM;
+
+ switch (reg_kind)
+ {
+ case eRegisterKindDWARF:
+ sp_reg_num = dwarf_esp;
+ pc_reg_num = dwarf_eip;
+ break;
+
+ case eRegisterKindGCC:
+ sp_reg_num = gcc_esp;
+ pc_reg_num = gcc_eip;
+ break;
+
+ case eRegisterKindGDB:
+ sp_reg_num = gdb_esp;
+ pc_reg_num = gdb_eip;
+ break;
+
+ case eRegisterKindGeneric:
+ sp_reg_num = LLDB_REGNUM_GENERIC_SP;
+ pc_reg_num = LLDB_REGNUM_GENERIC_PC;
+ break;
+ }
+
+ if (sp_reg_num == LLDB_INVALID_REGNUM ||
+ pc_reg_num == LLDB_INVALID_REGNUM)
+ return false;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ row->SetCFARegister (sp_reg_num);
+ row->SetCFAOffset (4);
+ row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -4, false);
+ unwind_plan.AppendRow (row);
+ unwind_plan.SetSourceName ("i386 at-func-entry default");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ return true;
+}
+
+bool
+ABIMacOSX_i386::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
+{
+ uint32_t fp_reg_num = dwarf_ebp;
+ uint32_t sp_reg_num = dwarf_esp;
+ uint32_t pc_reg_num = dwarf_eip;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ const int32_t ptr_size = 4;
+
+ unwind_plan.Clear ();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+ row->SetCFARegister (fp_reg_num);
+ row->SetCFAOffset (2 * ptr_size);
+ row->SetOffset (0);
+
+ row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
+ row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
+ row->SetRegisterLocationToAtCFAPlusOffset(sp_reg_num, ptr_size * 0, true);
+
+ unwind_plan.AppendRow (row);
+ unwind_plan.SetSourceName ("i386 default unwind plan");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+ return true;
+}
+
+bool
+ABIMacOSX_i386::RegisterIsVolatile (const RegisterInfo *reg_info)
+{
+ return !RegisterIsCalleeSaved (reg_info);
+}
+
+// v. http://developer.apple.com/library/mac/#documentation/developertools/Conceptual/LowLevelABI/130-IA-32_Function_Calling_Conventions/IA32.html#//apple_ref/doc/uid/TP40002492-SW4
+
+bool
+ABIMacOSX_i386::RegisterIsCalleeSaved (const RegisterInfo *reg_info)
+{
+ if (reg_info)
+ {
+ // Saved registers are ebx, ebp, esi, edi, esp, eip
+ const char *name = reg_info->name;
+ if (name[0] == 'e')
+ {
+ switch (name[1])
+ {
+ case 'b':
+ if (name[2] == 'x' || name[2] == 'p')
+ return name[3] == '\0';
+ break;
+ case 'd':
+ if (name[2] == 'i')
+ return name[3] == '\0';
+ break;
+ case 'i':
+ if (name[2] == 'p')
+ return name[3] == '\0';
+ break;
+ case 's':
+ if (name[2] == 'i' || name[2] == 'p')
+ return name[3] == '\0';
+ break;
+ }
+ }
+ if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp
+ return true;
+ if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp
+ return true;
+ if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc
+ return true;
+ }
+ return false;
+}
+
+void
+ABIMacOSX_i386::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "Mac OS X ABI for i386 targets",
+ CreateInstance);
+}
+
+void
+ABIMacOSX_i386::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+lldb_private::ConstString
+ABIMacOSX_i386::GetPluginNameStatic ()
+{
+ static ConstString g_short_name("abi.macosx-i386");
+ return g_short_name;
+
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ABIMacOSX_i386::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ABIMacOSX_i386::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
new file mode 100644
index 000000000000..8c2d945e6342
--- /dev/null
+++ b/source/Plugins/ABI/MacOSX-i386/ABIMacOSX_i386.h
@@ -0,0 +1,139 @@
+//===-- ABIMacOSX_i386.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ABIMacOSX_i386_h_
+#define liblldb_ABIMacOSX_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Core/Value.h"
+
+class ABIMacOSX_i386 :
+ public lldb_private::ABI
+{
+public:
+
+ ~ABIMacOSX_i386() { }
+
+ virtual size_t
+ GetRedZoneSize () const;
+
+ virtual bool
+ PrepareTrivialCall (lldb_private::Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t func_addr,
+ lldb::addr_t return_addr,
+ lldb::addr_t *arg1_ptr = NULL,
+ lldb::addr_t *arg2_ptr = NULL,
+ lldb::addr_t *arg3_ptr = NULL,
+ lldb::addr_t *arg4_ptr = NULL,
+ lldb::addr_t *arg5_ptr = NULL,
+ lldb::addr_t *arg6_ptr = NULL) const;
+
+ virtual bool
+ PrepareNormalCall (lldb_private::Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t func_addr,
+ lldb::addr_t return_addr,
+ lldb_private::ValueList &args) const;
+
+ virtual bool
+ GetArgumentValues (lldb_private::Thread &thread,
+ lldb_private::ValueList &values) const;
+
+ virtual lldb_private::Error
+ SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value);
+
+protected:
+ virtual lldb::ValueObjectSP
+ GetReturnValueObjectImpl (lldb_private::Thread &thread,
+ lldb_private::ClangASTType &ast_type) const;
+
+public:
+
+ virtual bool
+ CreateFunctionEntryUnwindPlan (lldb_private::UnwindPlan &unwind_plan);
+
+ virtual bool
+ CreateDefaultUnwindPlan (lldb_private::UnwindPlan &unwind_plan);
+
+ virtual bool
+ RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info);
+
+ virtual bool
+ StackUsesFrames ()
+ {
+ return true;
+ }
+
+ virtual bool
+ CallFrameAddressIsValid (lldb::addr_t cfa)
+ {
+ // Make sure the stack call frame addresses are are 8 byte aligned
+ if (cfa & (8ull - 1ull))
+ return false; // Not 8 byte aligned
+ if (cfa == 0)
+ return false; // Zero is not a valid stack address
+ return true;
+ }
+
+ virtual bool
+ CodeAddressIsValid (lldb::addr_t pc)
+ {
+ // Just make sure the address is a valid 32 bit address.
+ return pc <= UINT32_MAX;
+ }
+
+ virtual bool
+ FunctionCallsChangeCFA ()
+ {
+ return true;
+ }
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoArray (uint32_t &count);
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb::ABISP
+ CreateInstance (const lldb_private::ArchSpec &arch);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ static lldb_private::ConstString
+ GetPluginNameStatic ();
+
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+protected:
+ bool
+ RegisterIsCalleeSaved (const lldb_private::RegisterInfo *reg_info);
+
+private:
+ ABIMacOSX_i386() : lldb_private::ABI() { } // Call CreateInstance instead.
+};
+
+
+#endif // liblldb_ABI_h_
diff --git a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
new file mode 100644
index 000000000000..a904d8b649ca
--- /dev/null
+++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.cpp
@@ -0,0 +1,1288 @@
+//===-- ABISysV_x86_64.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ABISysV_x86_64.h"
+
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectRegister.h"
+#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Thread.h"
+
+#include "llvm/ADT/Triple.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum gcc_dwarf_regnums
+{
+ gcc_dwarf_rax = 0,
+ gcc_dwarf_rdx,
+ gcc_dwarf_rcx,
+ gcc_dwarf_rbx,
+ gcc_dwarf_rsi,
+ gcc_dwarf_rdi,
+ gcc_dwarf_rbp,
+ gcc_dwarf_rsp,
+ gcc_dwarf_r8,
+ gcc_dwarf_r9,
+ gcc_dwarf_r10,
+ gcc_dwarf_r11,
+ gcc_dwarf_r12,
+ gcc_dwarf_r13,
+ gcc_dwarf_r14,
+ gcc_dwarf_r15,
+ gcc_dwarf_rip,
+ gcc_dwarf_xmm0,
+ gcc_dwarf_xmm1,
+ gcc_dwarf_xmm2,
+ gcc_dwarf_xmm3,
+ gcc_dwarf_xmm4,
+ gcc_dwarf_xmm5,
+ gcc_dwarf_xmm6,
+ gcc_dwarf_xmm7,
+ gcc_dwarf_xmm8,
+ gcc_dwarf_xmm9,
+ gcc_dwarf_xmm10,
+ gcc_dwarf_xmm11,
+ gcc_dwarf_xmm12,
+ gcc_dwarf_xmm13,
+ gcc_dwarf_xmm14,
+ gcc_dwarf_xmm15,
+ gcc_dwarf_stmm0,
+ gcc_dwarf_stmm1,
+ gcc_dwarf_stmm2,
+ gcc_dwarf_stmm3,
+ gcc_dwarf_stmm4,
+ gcc_dwarf_stmm5,
+ gcc_dwarf_stmm6,
+ gcc_dwarf_stmm7,
+ gcc_dwarf_ymm0,
+ gcc_dwarf_ymm1,
+ gcc_dwarf_ymm2,
+ gcc_dwarf_ymm3,
+ gcc_dwarf_ymm4,
+ gcc_dwarf_ymm5,
+ gcc_dwarf_ymm6,
+ gcc_dwarf_ymm7,
+ gcc_dwarf_ymm8,
+ gcc_dwarf_ymm9,
+ gcc_dwarf_ymm10,
+ gcc_dwarf_ymm11,
+ gcc_dwarf_ymm12,
+ gcc_dwarf_ymm13,
+ gcc_dwarf_ymm14,
+ gcc_dwarf_ymm15
+};
+
+enum gdb_regnums
+{
+ gdb_rax = 0,
+ gdb_rbx = 1,
+ gdb_rcx = 2,
+ gdb_rdx = 3,
+ gdb_rsi = 4,
+ gdb_rdi = 5,
+ gdb_rbp = 6,
+ gdb_rsp = 7,
+ gdb_r8 = 8,
+ gdb_r9 = 9,
+ gdb_r10 = 10,
+ gdb_r11 = 11,
+ gdb_r12 = 12,
+ gdb_r13 = 13,
+ gdb_r14 = 14,
+ gdb_r15 = 15,
+ gdb_rip = 16,
+ gdb_rflags = 17,
+ gdb_cs = 18,
+ gdb_ss = 19,
+ gdb_ds = 20,
+ gdb_es = 21,
+ gdb_fs = 22,
+ gdb_gs = 23,
+ gdb_stmm0 = 24,
+ gdb_stmm1 = 25,
+ gdb_stmm2 = 26,
+ gdb_stmm3 = 27,
+ gdb_stmm4 = 28,
+ gdb_stmm5 = 29,
+ gdb_stmm6 = 30,
+ gdb_stmm7 = 31,
+ gdb_fctrl = 32, gdb_fcw = gdb_fctrl,
+ gdb_fstat = 33, gdb_fsw = gdb_fstat,
+ gdb_ftag = 34, gdb_ftw = gdb_ftag,
+ gdb_fiseg = 35, gdb_fpu_cs = gdb_fiseg,
+ gdb_fioff = 36, gdb_ip = gdb_fioff,
+ gdb_foseg = 37, gdb_fpu_ds = gdb_foseg,
+ gdb_fooff = 38, gdb_dp = gdb_fooff,
+ gdb_fop = 39,
+ gdb_xmm0 = 40,
+ gdb_xmm1 = 41,
+ gdb_xmm2 = 42,
+ gdb_xmm3 = 43,
+ gdb_xmm4 = 44,
+ gdb_xmm5 = 45,
+ gdb_xmm6 = 46,
+ gdb_xmm7 = 47,
+ gdb_xmm8 = 48,
+ gdb_xmm9 = 49,
+ gdb_xmm10 = 50,
+ gdb_xmm11 = 51,
+ gdb_xmm12 = 52,
+ gdb_xmm13 = 53,
+ gdb_xmm14 = 54,
+ gdb_xmm15 = 55,
+ gdb_mxcsr = 56,
+ gdb_ymm0 = 57,
+ gdb_ymm1 = 58,
+ gdb_ymm2 = 59,
+ gdb_ymm3 = 60,
+ gdb_ymm4 = 61,
+ gdb_ymm5 = 62,
+ gdb_ymm6 = 63,
+ gdb_ymm7 = 64,
+ gdb_ymm8 = 65,
+ gdb_ymm9 = 66,
+ gdb_ymm10 = 67,
+ gdb_ymm11 = 68,
+ gdb_ymm12 = 69,
+ gdb_ymm13 = 70,
+ gdb_ymm14 = 71,
+ gdb_ymm15 = 72
+};
+
+
+static RegisterInfo g_register_infos[] =
+{
+ // NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+ // ======== ======= == === ============= =================== ======================= ===================== =========================== ===================== ====================== ========== ===============
+ { "rax" , NULL, 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rax , gcc_dwarf_rax , LLDB_INVALID_REGNUM , gdb_rax , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rbx" , NULL, 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rbx , gcc_dwarf_rbx , LLDB_INVALID_REGNUM , gdb_rbx , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rcx" , "arg4", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rcx , gcc_dwarf_rcx , LLDB_REGNUM_GENERIC_ARG4 , gdb_rcx , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rdx" , "arg3", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rdx , gcc_dwarf_rdx , LLDB_REGNUM_GENERIC_ARG3 , gdb_rdx , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rsi" , "arg2", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rsi , gcc_dwarf_rsi , LLDB_REGNUM_GENERIC_ARG2 , gdb_rsi , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rdi" , "arg1", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rdi , gcc_dwarf_rdi , LLDB_REGNUM_GENERIC_ARG1 , gdb_rdi , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rbp" , "fp", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rbp , gcc_dwarf_rbp , LLDB_REGNUM_GENERIC_FP , gdb_rbp , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rsp" , "sp", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rsp , gcc_dwarf_rsp , LLDB_REGNUM_GENERIC_SP , gdb_rsp , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r8" , "arg5", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_r8 , gcc_dwarf_r8 , LLDB_REGNUM_GENERIC_ARG5 , gdb_r8 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r9" , "arg6", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_r9 , gcc_dwarf_r9 , LLDB_REGNUM_GENERIC_ARG6 , gdb_r9 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r10" , NULL, 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_r10 , gcc_dwarf_r10 , LLDB_INVALID_REGNUM , gdb_r10 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r11" , NULL, 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_r11 , gcc_dwarf_r11 , LLDB_INVALID_REGNUM , gdb_r11 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r12" , NULL, 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_r12 , gcc_dwarf_r12 , LLDB_INVALID_REGNUM , gdb_r12 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r13" , NULL, 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_r13 , gcc_dwarf_r13 , LLDB_INVALID_REGNUM , gdb_r13 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r14" , NULL, 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_r14 , gcc_dwarf_r14 , LLDB_INVALID_REGNUM , gdb_r14 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "r15" , NULL, 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_r15 , gcc_dwarf_r15 , LLDB_INVALID_REGNUM , gdb_r15 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rip" , "pc", 8, 0, eEncodingUint , eFormatHex , { gcc_dwarf_rip , gcc_dwarf_rip , LLDB_REGNUM_GENERIC_PC , gdb_rip , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "rflags", NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_REGNUM_GENERIC_FLAGS , gdb_rflags , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "cs" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_cs , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ss" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ss , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ds" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ds , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "es" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_es , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fs" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fs , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "gs" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_gs , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm0" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_stmm0 , gcc_dwarf_stmm0 , LLDB_INVALID_REGNUM , gdb_stmm0 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm1" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_stmm1 , gcc_dwarf_stmm1 , LLDB_INVALID_REGNUM , gdb_stmm1 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm2" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_stmm2 , gcc_dwarf_stmm2 , LLDB_INVALID_REGNUM , gdb_stmm2 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm3" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_stmm3 , gcc_dwarf_stmm3 , LLDB_INVALID_REGNUM , gdb_stmm3 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm4" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_stmm4 , gcc_dwarf_stmm4 , LLDB_INVALID_REGNUM , gdb_stmm4 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm5" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_stmm5 , gcc_dwarf_stmm5 , LLDB_INVALID_REGNUM , gdb_stmm5 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm6" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_stmm6 , gcc_dwarf_stmm6 , LLDB_INVALID_REGNUM , gdb_stmm6 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "stmm7" , NULL, 10, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_stmm7 , gcc_dwarf_stmm7 , LLDB_INVALID_REGNUM , gdb_stmm7 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fctrl" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fctrl , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fstat" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fstat , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ftag" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_ftag , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fiseg" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fiseg , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fioff" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fioff , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "foseg" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_foseg , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fooff" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fooff , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "fop" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_fop , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm0" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm0 , gcc_dwarf_xmm0 , LLDB_INVALID_REGNUM , gdb_xmm0 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm1" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm1 , gcc_dwarf_xmm1 , LLDB_INVALID_REGNUM , gdb_xmm1 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm2" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm2 , gcc_dwarf_xmm2 , LLDB_INVALID_REGNUM , gdb_xmm2 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm3" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm3 , gcc_dwarf_xmm3 , LLDB_INVALID_REGNUM , gdb_xmm3 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm4" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm4 , gcc_dwarf_xmm4 , LLDB_INVALID_REGNUM , gdb_xmm4 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm5" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm5 , gcc_dwarf_xmm5 , LLDB_INVALID_REGNUM , gdb_xmm5 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm6" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm6 , gcc_dwarf_xmm6 , LLDB_INVALID_REGNUM , gdb_xmm6 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm7" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm7 , gcc_dwarf_xmm7 , LLDB_INVALID_REGNUM , gdb_xmm7 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm8" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm8 , gcc_dwarf_xmm8 , LLDB_INVALID_REGNUM , gdb_xmm8 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm9" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm9 , gcc_dwarf_xmm9 , LLDB_INVALID_REGNUM , gdb_xmm9 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm10" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm10 , gcc_dwarf_xmm10 , LLDB_INVALID_REGNUM , gdb_xmm10 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm11" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm11 , gcc_dwarf_xmm11 , LLDB_INVALID_REGNUM , gdb_xmm11 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm12" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm12 , gcc_dwarf_xmm12 , LLDB_INVALID_REGNUM , gdb_xmm12 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm13" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm13 , gcc_dwarf_xmm13 , LLDB_INVALID_REGNUM , gdb_xmm13 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm14" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm14 , gcc_dwarf_xmm14 , LLDB_INVALID_REGNUM , gdb_xmm14 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "xmm15" , NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_xmm15 , gcc_dwarf_xmm15 , LLDB_INVALID_REGNUM , gdb_xmm15 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "mxcsr" , NULL, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , gdb_mxcsr , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm0" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm0 , gcc_dwarf_ymm0 , LLDB_INVALID_REGNUM , gdb_ymm0 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm1" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm1 , gcc_dwarf_ymm1 , LLDB_INVALID_REGNUM , gdb_ymm1 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm2" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm2 , gcc_dwarf_ymm2 , LLDB_INVALID_REGNUM , gdb_ymm2 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm3" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm3 , gcc_dwarf_ymm3 , LLDB_INVALID_REGNUM , gdb_ymm3 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm4" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm4 , gcc_dwarf_ymm4 , LLDB_INVALID_REGNUM , gdb_ymm4 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm5" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm5 , gcc_dwarf_ymm5 , LLDB_INVALID_REGNUM , gdb_ymm5 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm6" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm6 , gcc_dwarf_ymm6 , LLDB_INVALID_REGNUM , gdb_ymm6 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm7" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm7 , gcc_dwarf_ymm7 , LLDB_INVALID_REGNUM , gdb_ymm7 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm8" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm8 , gcc_dwarf_ymm8 , LLDB_INVALID_REGNUM , gdb_ymm8 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm9" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm9 , gcc_dwarf_ymm9 , LLDB_INVALID_REGNUM , gdb_ymm9 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm10" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm10 , gcc_dwarf_ymm10 , LLDB_INVALID_REGNUM , gdb_ymm10 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm11" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm11 , gcc_dwarf_ymm11 , LLDB_INVALID_REGNUM , gdb_ymm11 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm12" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm12 , gcc_dwarf_ymm12 , LLDB_INVALID_REGNUM , gdb_ymm12 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm13" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm13 , gcc_dwarf_ymm13 , LLDB_INVALID_REGNUM , gdb_ymm13 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm14" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm14 , gcc_dwarf_ymm14 , LLDB_INVALID_REGNUM , gdb_ymm14 , LLDB_INVALID_REGNUM }, NULL, NULL},
+ { "ymm15" , NULL, 32, 0, eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_ymm15 , gcc_dwarf_ymm15 , LLDB_INVALID_REGNUM , gdb_ymm15 , LLDB_INVALID_REGNUM }, NULL, NULL}
+};
+
+static const uint32_t k_num_register_infos = sizeof(g_register_infos)/sizeof(RegisterInfo);
+static bool g_register_info_names_constified = false;
+
+const lldb_private::RegisterInfo *
+ABISysV_x86_64::GetRegisterInfoArray (uint32_t &count)
+{
+ // Make the C-string names and alt_names for the register infos into const
+ // C-string values by having the ConstString unique the names in the global
+ // constant C-string pool.
+ if (!g_register_info_names_constified)
+ {
+ g_register_info_names_constified = true;
+ for (uint32_t i=0; i<k_num_register_infos; ++i)
+ {
+ if (g_register_infos[i].name)
+ g_register_infos[i].name = ConstString(g_register_infos[i].name).GetCString();
+ if (g_register_infos[i].alt_name)
+ g_register_infos[i].alt_name = ConstString(g_register_infos[i].alt_name).GetCString();
+ }
+ }
+ count = k_num_register_infos;
+ return g_register_infos;
+}
+
+
+size_t
+ABISysV_x86_64::GetRedZoneSize () const
+{
+ return 128;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+ABISP
+ABISysV_x86_64::CreateInstance (const ArchSpec &arch)
+{
+ static ABISP g_abi_sp;
+ if (arch.GetTriple().getArch() == llvm::Triple::x86_64)
+ {
+ if (!g_abi_sp)
+ g_abi_sp.reset (new ABISysV_x86_64);
+ return g_abi_sp;
+ }
+ return ABISP();
+}
+
+bool
+ABISysV_x86_64::PrepareTrivialCall (Thread &thread,
+ addr_t sp,
+ addr_t func_addr,
+ addr_t return_addr,
+ addr_t *arg1_ptr,
+ addr_t *arg2_ptr,
+ addr_t *arg3_ptr,
+ addr_t *arg4_ptr,
+ addr_t *arg5_ptr,
+ addr_t *arg6_ptr) const
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
+
+ if (log)
+ {
+ StreamString s;
+ s.Printf("ABISysV_x86_64::PrepareTrivialCall (tid = 0x%" PRIx64 ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 ", return_addr = 0x%" PRIx64,
+ thread.GetID(),
+ (uint64_t)sp,
+ (uint64_t)func_addr,
+ (uint64_t)return_addr);
+
+ if (arg1_ptr)
+ {
+ s.Printf (", arg1 = 0x%" PRIx64, (uint64_t)*arg1_ptr);
+ if (arg2_ptr)
+ {
+ s.Printf (", arg2 = 0x%" PRIx64, (uint64_t)*arg2_ptr);
+ if (arg3_ptr)
+ {
+ s.Printf (", arg3 = 0x%" PRIx64, (uint64_t)*arg3_ptr);
+ if (arg4_ptr)
+ {
+ s.Printf (", arg4 = 0x%" PRIx64, (uint64_t)*arg4_ptr);
+ if (arg5_ptr)
+ {
+ s.Printf (", arg5 = 0x%" PRIx64, (uint64_t)*arg5_ptr);
+ if (arg6_ptr)
+ s.Printf (", arg6 = 0x%" PRIx64, (uint64_t)*arg6_ptr);
+ }
+ }
+ }
+ }
+ }
+ s.PutCString (")");
+ log->PutCString(s.GetString().c_str());
+ }
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return false;
+
+ const RegisterInfo *reg_info = NULL;
+ if (arg1_ptr)
+ {
+ reg_info = reg_ctx->GetRegisterInfoByName("rdi", 0);
+ if (log)
+ log->Printf("About to write arg1 (0x%" PRIx64 ") into %s", (uint64_t)*arg1_ptr, reg_info->name);
+
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg1_ptr))
+ return false;
+
+ if (arg2_ptr)
+ {
+ reg_info = reg_ctx->GetRegisterInfoByName("rsi", 0);
+ if (log)
+ log->Printf("About to write arg2 (0x%" PRIx64 ") into %s", (uint64_t)*arg2_ptr, reg_info->name);
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg2_ptr))
+ return false;
+
+ if (arg3_ptr)
+ {
+ reg_info = reg_ctx->GetRegisterInfoByName("rdx", 0);
+ if (log)
+ log->Printf("About to write arg3 (0x%" PRIx64 ") into %s", (uint64_t)*arg3_ptr, reg_info->name);
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg3_ptr))
+ return false;
+
+ if (arg4_ptr)
+ {
+ reg_info = reg_ctx->GetRegisterInfoByName("rcx", 0);
+ if (log)
+ log->Printf("About to write arg4 (0x%" PRIx64 ") into %s", (uint64_t)*arg4_ptr, reg_info->name);
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg4_ptr))
+ return false;
+
+ if (arg5_ptr)
+ {
+ reg_info = reg_ctx->GetRegisterInfoByName("r8", 0);
+ if (log)
+ log->Printf("About to write arg5 (0x%" PRIx64 ") into %s", (uint64_t)*arg5_ptr, reg_info->name);
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg5_ptr))
+ return false;
+
+ if (arg6_ptr)
+ {
+ reg_info = reg_ctx->GetRegisterInfoByName("r9", 0);
+ if (log)
+ log->Printf("About to write arg6 (0x%" PRIx64 ") into %s", (uint64_t)*arg6_ptr, reg_info->name);
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_info, *arg6_ptr))
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ // First, align the SP
+
+ if (log)
+ log->Printf("16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64, (uint64_t)sp, (uint64_t)(sp & ~0xfull));
+
+ sp &= ~(0xfull); // 16-byte alignment
+
+ // The return address is pushed onto the stack (yes after the alignment...)
+ sp -= 8;
+
+ RegisterValue reg_value;
+ reg_value.SetUInt64 (return_addr);
+
+ if (log)
+ log->Printf("Pushing the return address onto the stack: new SP 0x%" PRIx64 ", return address 0x%" PRIx64, (uint64_t)sp, (uint64_t)return_addr);
+
+ const RegisterInfo *pc_reg_info = reg_ctx->GetRegisterInfoByName("rip");
+ Error error (reg_ctx->WriteRegisterValueToMemory(pc_reg_info, sp, pc_reg_info->byte_size, reg_value));
+ if (error.Fail())
+ return false;
+
+ // %rsp is set to the actual stack value.
+
+ if (log)
+ log->Printf("Writing SP (0x%" PRIx64 ") down", (uint64_t)sp);
+
+ if (!reg_ctx->WriteRegisterFromUnsigned (reg_ctx->GetRegisterInfoByName("rsp"), sp))
+ return false;
+
+ // %rip is set to the address of the called function.
+
+ if (log)
+ log->Printf("Writing new IP (0x%" PRIx64 ") down", (uint64_t)func_addr);
+
+ if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_info, func_addr))
+ return false;
+
+ return true;
+}
+
+static bool ReadIntegerArgument(Scalar &scalar,
+ unsigned int bit_width,
+ bool is_signed,
+ Thread &thread,
+ uint32_t *argument_register_ids,
+ unsigned int &current_argument_register,
+ addr_t &current_stack_argument)
+{
+ if (bit_width > 64)
+ return false; // Scalar can't hold large integer arguments
+
+ if (current_argument_register < 6)
+ {
+ scalar = thread.GetRegisterContext()->ReadRegisterAsUnsigned(argument_register_ids[current_argument_register], 0);
+ current_argument_register++;
+ if (is_signed)
+ scalar.SignExtend (bit_width);
+ }
+ else
+ {
+ uint32_t byte_size = (bit_width + (8-1))/8;
+ Error error;
+ if (thread.GetProcess()->ReadScalarIntegerFromMemory(current_stack_argument, byte_size, is_signed, scalar, error))
+ {
+ current_stack_argument += byte_size;
+ return true;
+ }
+ return false;
+ }
+ return true;
+}
+
+bool
+ABISysV_x86_64::GetArgumentValues (Thread &thread,
+ ValueList &values) const
+{
+ unsigned int num_values = values.GetSize();
+ unsigned int value_index;
+
+ // Extract the register context so we can read arguments from registers
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+
+ if (!reg_ctx)
+ return false;
+
+ // Get the pointer to the first stack argument so we have a place to start
+ // when reading data
+
+ addr_t sp = reg_ctx->GetSP(0);
+
+ if (!sp)
+ return false;
+
+ addr_t current_stack_argument = sp + 8; // jump over return address
+
+ uint32_t argument_register_ids[6];
+
+ argument_register_ids[0] = reg_ctx->GetRegisterInfoByName("rdi", 0)->kinds[eRegisterKindLLDB];
+ argument_register_ids[1] = reg_ctx->GetRegisterInfoByName("rsi", 0)->kinds[eRegisterKindLLDB];
+ argument_register_ids[2] = reg_ctx->GetRegisterInfoByName("rdx", 0)->kinds[eRegisterKindLLDB];
+ argument_register_ids[3] = reg_ctx->GetRegisterInfoByName("rcx", 0)->kinds[eRegisterKindLLDB];
+ argument_register_ids[4] = reg_ctx->GetRegisterInfoByName("r8", 0)->kinds[eRegisterKindLLDB];
+ argument_register_ids[5] = reg_ctx->GetRegisterInfoByName("r9", 0)->kinds[eRegisterKindLLDB];
+
+ unsigned int current_argument_register = 0;
+
+ for (value_index = 0;
+ value_index < num_values;
+ ++value_index)
+ {
+ Value *value = values.GetValueAtIndex(value_index);
+
+ if (!value)
+ return false;
+
+ // We currently only support extracting values with Clang QualTypes.
+ // Do we care about others?
+ ClangASTType clang_type = value->GetClangType();
+ if (!clang_type)
+ return false;
+ bool is_signed;
+
+ if (clang_type.IsIntegerType (is_signed))
+ {
+ ReadIntegerArgument(value->GetScalar(),
+ clang_type.GetBitSize(),
+ is_signed,
+ thread,
+ argument_register_ids,
+ current_argument_register,
+ current_stack_argument);
+ }
+ else if (clang_type.IsPointerType ())
+ {
+ ReadIntegerArgument(value->GetScalar(),
+ clang_type.GetBitSize(),
+ false,
+ thread,
+ argument_register_ids,
+ current_argument_register,
+ current_stack_argument);
+ }
+ }
+
+ return true;
+}
+
+Error
+ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp)
+{
+ Error error;
+ if (!new_value_sp)
+ {
+ error.SetErrorString("Empty value object for return value.");
+ return error;
+ }
+
+ ClangASTType clang_type = new_value_sp->GetClangType();
+ if (!clang_type)
+ {
+ error.SetErrorString ("Null clang type for return value.");
+ return error;
+ }
+
+ Thread *thread = frame_sp->GetThread().get();
+
+ bool is_signed;
+ uint32_t count;
+ bool is_complex;
+
+ RegisterContext *reg_ctx = thread->GetRegisterContext().get();
+
+ bool set_it_simple = false;
+ if (clang_type.IsIntegerType (is_signed) || clang_type.IsPointerType())
+ {
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("rax", 0);
+
+ DataExtractor data;
+ size_t num_bytes = new_value_sp->GetData(data);
+ lldb::offset_t offset = 0;
+ if (num_bytes <= 8)
+ {
+ uint64_t raw_value = data.GetMaxU64(&offset, num_bytes);
+
+ if (reg_ctx->WriteRegisterFromUnsigned (reg_info, raw_value))
+ set_it_simple = true;
+ }
+ else
+ {
+ error.SetErrorString("We don't support returning longer than 64 bit integer values at present.");
+ }
+
+ }
+ else if (clang_type.IsFloatingPointType (count, is_complex))
+ {
+ if (is_complex)
+ error.SetErrorString ("We don't support returning complex values at present");
+ else
+ {
+ size_t bit_width = clang_type.GetBitSize();
+ if (bit_width <= 64)
+ {
+ const RegisterInfo *xmm0_info = reg_ctx->GetRegisterInfoByName("xmm0", 0);
+ RegisterValue xmm0_value;
+ DataExtractor data;
+ size_t num_bytes = new_value_sp->GetData(data);
+
+ unsigned char buffer[16];
+ ByteOrder byte_order = data.GetByteOrder();
+
+ data.CopyByteOrderedData (0, num_bytes, buffer, 16, byte_order);
+ xmm0_value.SetBytes(buffer, 16, byte_order);
+ reg_ctx->WriteRegister(xmm0_info, xmm0_value);
+ set_it_simple = true;
+ }
+ else
+ {
+ // FIXME - don't know how to do 80 bit long doubles yet.
+ error.SetErrorString ("We don't support returning float values > 64 bits at present");
+ }
+ }
+ }
+
+ if (!set_it_simple)
+ {
+ // Okay we've got a structure or something that doesn't fit in a simple register.
+ // We should figure out where it really goes, but we don't support this yet.
+ error.SetErrorString ("We only support setting simple integer and float return types at present.");
+ }
+
+ return error;
+}
+
+
+ValueObjectSP
+ABISysV_x86_64::GetReturnValueObjectSimple (Thread &thread,
+ ClangASTType &return_clang_type) const
+{
+ ValueObjectSP return_valobj_sp;
+ Value value;
+
+ if (!return_clang_type)
+ return return_valobj_sp;
+
+ //value.SetContext (Value::eContextTypeClangType, return_value_type);
+ value.SetClangType (return_clang_type);
+
+ RegisterContext *reg_ctx = thread.GetRegisterContext().get();
+ if (!reg_ctx)
+ return return_valobj_sp;
+
+ const uint32_t type_flags = return_clang_type.GetTypeInfo ();
+ if (type_flags & ClangASTType::eTypeIsScalar)
+ {
+ value.SetValueType(Value::eValueTypeScalar);
+
+ bool success = false;
+ if (type_flags & ClangASTType::eTypeIsInteger)
+ {
+ // Extract the register context so we can read arguments from registers
+
+ const size_t byte_size = return_clang_type.GetByteSize();
+ uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(reg_ctx->GetRegisterInfoByName("rax", 0), 0);
+ const bool is_signed = (type_flags & ClangASTType::eTypeIsSigned) != 0;
+ switch (byte_size)
+ {
+ default:
+ break;
+
+ case sizeof(uint64_t):
+ if (is_signed)
+ value.GetScalar() = (int64_t)(raw_value);
+ else
+ value.GetScalar() = (uint64_t)(raw_value);
+ success = true;
+ break;
+
+ case sizeof(uint32_t):
+ if (is_signed)
+ value.GetScalar() = (int32_t)(raw_value & UINT32_MAX);
+ else
+ value.GetScalar() = (uint32_t)(raw_value & UINT32_MAX);
+ success = true;
+ break;
+
+ case sizeof(uint16_t):
+ if (is_signed)
+ value.GetScalar() = (int16_t)(raw_value & UINT16_MAX);
+ else
+ value.GetScalar() = (uint16_t)(raw_value & UINT16_MAX);
+ success = true;
+ break;
+
+ case sizeof(uint8_t):
+ if (is_signed)
+ value.GetScalar() = (int8_t)(raw_value & UINT8_MAX);
+ else
+ value.GetScalar() = (uint8_t)(raw_value & UINT8_MAX);
+ success = true;
+ break;
+ }
+ }
+ else if (type_flags & ClangASTType::eTypeIsFloat)
+ {
+ if (type_flags & ClangASTType::eTypeIsComplex)
+ {
+ // Don't handle complex yet.
+ }
+ else
+ {
+ const size_t byte_size = return_clang_type.GetByteSize();
+ if (byte_size <= sizeof(long double))
+ {
+ const RegisterInfo *xmm0_info = reg_ctx->GetRegisterInfoByName("xmm0", 0);
+ RegisterValue xmm0_value;
+ if (reg_ctx->ReadRegister (xmm0_info, xmm0_value))
+ {
+ DataExtractor data;
+ if (xmm0_value.GetData(data))
+ {
+ lldb::offset_t offset = 0;
+ if (byte_size == sizeof(float))
+ {
+ value.GetScalar() = (float) data.GetFloat(&offset);
+ success = true;
+ }
+ else if (byte_size == sizeof(double))
+ {
+ value.GetScalar() = (double) data.GetDouble(&offset);
+ success = true;
+ }
+ else if (byte_size == sizeof(long double))
+ {
+ // Don't handle long double since that can be encoded as 80 bit floats...
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (success)
+ return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+
+ }
+ else if (type_flags & ClangASTType::eTypeIsPointer)
+ {
+ unsigned rax_id = reg_ctx->GetRegisterInfoByName("rax", 0)->kinds[eRegisterKindLLDB];
+ value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0);
+ value.SetValueType(Value::eValueTypeScalar);
+ return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(),
+ value,
+ ConstString(""));
+ }
+ else if (type_flags & ClangASTType::eTypeIsVector)
+ {
+ const size_t byte_size = return_clang_type.GetByteSize();
+ if (byte_size > 0)
+ {
+
+ const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("ymm0", 0);
+ if (altivec_reg == NULL)
+ {
+ altivec_reg = reg_ctx->GetRegisterInfoByName("xmm0", 0);
+ if (altivec_reg == NULL)
+ altivec_reg = reg_ctx->GetRegisterInfoByName("mm0", 0);
+ }
+
+ if (altivec_reg)
+ {
+ if (byte_size <= altivec_reg->byte_size)
+ {
+ ProcessSP process_sp (thread.GetProcess());
+ if (process_sp)
+ {
+ std::unique_ptr<DataBufferHeap> heap_data_ap (new DataBufferHeap(byte_size, 0));
+ const ByteOrder byte_order = process_sp->GetByteOrder();
+ RegisterValue reg_value;
+ if (reg_ctx->ReadRegister(altivec_reg, reg_value))
+ {
+ Error error;
+ if (reg_value.GetAsMemoryData (altivec_reg,
+ heap_data_ap->GetBytes(),
+ heap_data_ap->GetByteSize(),
+ byte_order,
+ error))
+ {
+ DataExtractor data (DataBufferSP (heap_data_ap.release()),
+ byte_order,
+ process_sp->GetTarget().GetArchitecture().GetAddressByteSize());
+ return_valobj_sp = ValueObjectConstResult::Create (&thread,
+ return_clang_type,
+ ConstString(""),
+ data);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return return_valobj_sp;
+}
+
+ValueObjectSP
+ABISysV_x86_64::GetReturnValueObjectImpl (Thread &thread, ClangASTType &return_clang_type) const
+{
+ ValueObjectSP return_valobj_sp;
+
+ if (!return_clang_type)
+ return return_valobj_sp;
+
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ return_valobj_sp = GetReturnValueObjectSimple(thread, return_clang_type);
+ if (return_valobj_sp)
+ return return_valobj_sp;
+
+ RegisterContextSP reg_ctx_sp = thread.GetRegisterContext();
+ if (!reg_ctx_sp)
+ return return_valobj_sp;
+
+ const size_t bit_width = return_clang_type.GetBitSize();
+ if (return_clang_type.IsAggregateType())
+ {
+ Target *target = exe_ctx.GetTargetPtr();
+ bool is_memory = true;
+ if (bit_width <= 128)
+ {
+ ByteOrder target_byte_order = target->GetArchitecture().GetByteOrder();
+ DataBufferSP data_sp (new DataBufferHeap(16, 0));
+ DataExtractor return_ext (data_sp,
+ target_byte_order,
+ target->GetArchitecture().GetAddressByteSize());
+
+ const RegisterInfo *rax_info = reg_ctx_sp->GetRegisterInfoByName("rax", 0);
+ const RegisterInfo *rdx_info = reg_ctx_sp->GetRegisterInfoByName("rdx", 0);
+ const RegisterInfo *xmm0_info = reg_ctx_sp->GetRegisterInfoByName("xmm0", 0);
+ const RegisterInfo *xmm1_info = reg_ctx_sp->GetRegisterInfoByName("xmm1", 0);
+
+ RegisterValue rax_value, rdx_value, xmm0_value, xmm1_value;
+ reg_ctx_sp->ReadRegister (rax_info, rax_value);
+ reg_ctx_sp->ReadRegister (rdx_info, rdx_value);
+ reg_ctx_sp->ReadRegister (xmm0_info, xmm0_value);
+ reg_ctx_sp->ReadRegister (xmm1_info, xmm1_value);
+
+ DataExtractor rax_data, rdx_data, xmm0_data, xmm1_data;
+
+ rax_value.GetData(rax_data);
+ rdx_value.GetData(rdx_data);
+ xmm0_value.GetData(xmm0_data);
+ xmm1_value.GetData(xmm1_data);
+
+ uint32_t fp_bytes = 0; // Tracks how much of the xmm registers we've consumed so far
+ uint32_t integer_bytes = 0; // Tracks how much of the rax/rds registers we've consumed so far
+
+ const uint32_t num_children = return_clang_type.GetNumFields ();
+
+ // Since we are in the small struct regime, assume we are not in memory.
+ is_memory = false;
+
+ for (uint32_t idx = 0; idx < num_children; idx++)
+ {
+ std::string name;
+ uint64_t field_bit_offset = 0;
+ bool is_signed;
+ bool is_complex;
+ uint32_t count;
+
+ ClangASTType field_clang_type = return_clang_type.GetFieldAtIndex (idx, name, &field_bit_offset, NULL, NULL);
+ const size_t field_bit_width = field_clang_type.GetBitSize();
+
+ // If there are any unaligned fields, this is stored in memory.
+ if (field_bit_offset % field_bit_width != 0)
+ {
+ is_memory = true;
+ break;
+ }
+
+ uint32_t field_byte_width = field_bit_width/8;
+ uint32_t field_byte_offset = field_bit_offset/8;
+
+
+ DataExtractor *copy_from_extractor = NULL;
+ uint32_t copy_from_offset = 0;
+
+ if (field_clang_type.IsIntegerType (is_signed) || field_clang_type.IsPointerType ())
+ {
+ if (integer_bytes < 8)
+ {
+ if (integer_bytes + field_byte_width <= 8)
+ {
+ // This is in RAX, copy from register to our result structure:
+ copy_from_extractor = &rax_data;
+ copy_from_offset = integer_bytes;
+ integer_bytes += field_byte_width;
+ }
+ else
+ {
+ // The next field wouldn't fit in the remaining space, so we pushed it to rdx.
+ copy_from_extractor = &rdx_data;
+ copy_from_offset = 0;
+ integer_bytes = 8 + field_byte_width;
+
+ }
+ }
+ else if (integer_bytes + field_byte_width <= 16)
+ {
+ copy_from_extractor = &rdx_data;
+ copy_from_offset = integer_bytes - 8;
+ integer_bytes += field_byte_width;
+ }
+ else
+ {
+ // The last field didn't fit. I can't see how that would happen w/o the overall size being
+ // greater than 16 bytes. For now, return a NULL return value object.
+ return return_valobj_sp;
+ }
+ }
+ else if (field_clang_type.IsFloatingPointType (count, is_complex))
+ {
+ // Structs with long doubles are always passed in memory.
+ if (field_bit_width == 128)
+ {
+ is_memory = true;
+ break;
+ }
+ else if (field_bit_width == 64)
+ {
+ // These have to be in a single xmm register.
+ if (fp_bytes == 0)
+ copy_from_extractor = &xmm0_data;
+ else
+ copy_from_extractor = &xmm1_data;
+
+ copy_from_offset = 0;
+ fp_bytes += field_byte_width;
+ }
+ else if (field_bit_width == 32)
+ {
+ // This one is kind of complicated. If we are in an "eightbyte" with another float, we'll
+ // be stuffed into an xmm register with it. If we are in an "eightbyte" with one or more ints,
+ // then we will be stuffed into the appropriate GPR with them.
+ bool in_gpr;
+ if (field_byte_offset % 8 == 0)
+ {
+ // We are at the beginning of one of the eightbytes, so check the next element (if any)
+ if (idx == num_children - 1)
+ in_gpr = false;
+ else
+ {
+ uint64_t next_field_bit_offset = 0;
+ ClangASTType next_field_clang_type = return_clang_type.GetFieldAtIndex (idx + 1,
+ name,
+ &next_field_bit_offset,
+ NULL,
+ NULL);
+ if (next_field_clang_type.IsIntegerType (is_signed))
+ in_gpr = true;
+ else
+ {
+ copy_from_offset = 0;
+ in_gpr = false;
+ }
+ }
+
+ }
+ else if (field_byte_offset % 4 == 0)
+ {
+ // We are inside of an eightbyte, so see if the field before us is floating point:
+ // This could happen if somebody put padding in the structure.
+ if (idx == 0)
+ in_gpr = false;
+ else
+ {
+ uint64_t prev_field_bit_offset = 0;
+ ClangASTType prev_field_clang_type = return_clang_type.GetFieldAtIndex (idx - 1,
+ name,
+ &prev_field_bit_offset,
+ NULL,
+ NULL);
+ if (prev_field_clang_type.IsIntegerType (is_signed))
+ in_gpr = true;
+ else
+ {
+ copy_from_offset = 4;
+ in_gpr = false;
+ }
+ }
+
+ }
+ else
+ {
+ is_memory = true;
+ continue;
+ }
+
+ // Okay, we've figured out whether we are in GPR or XMM, now figure out which one.
+ if (in_gpr)
+ {
+ if (integer_bytes < 8)
+ {
+ // This is in RAX, copy from register to our result structure:
+ copy_from_extractor = &rax_data;
+ copy_from_offset = integer_bytes;
+ integer_bytes += field_byte_width;
+ }
+ else
+ {
+ copy_from_extractor = &rdx_data;
+ copy_from_offset = integer_bytes - 8;
+ integer_bytes += field_byte_width;
+ }
+ }
+ else
+ {
+ if (fp_bytes < 8)
+ copy_from_extractor = &xmm0_data;
+ else
+ copy_from_extractor = &xmm1_data;
+
+ fp_bytes += field_byte_width;
+ }
+ }
+ }
+
+ // These two tests are just sanity checks. If I somehow get the
+ // type calculation wrong above it is better to just return nothing
+ // than to assert or crash.
+ if (!copy_from_extractor)
+ return return_valobj_sp;
+ if (copy_from_offset + field_byte_width > copy_from_extractor->GetByteSize())
+ return return_valobj_sp;
+
+ copy_from_extractor->CopyByteOrderedData (copy_from_offset,
+ field_byte_width,
+ data_sp->GetBytes() + field_byte_offset,
+ field_byte_width,
+ target_byte_order);
+ }
+
+ if (!is_memory)
+ {
+ // The result is in our data buffer. Let's make a variable object out of it:
+ return_valobj_sp = ValueObjectConstResult::Create (&thread,
+ return_clang_type,
+ ConstString(""),
+ return_ext);
+ }
+ }
+
+
+ // FIXME: This is just taking a guess, rax may very well no longer hold the return storage location.
+ // If we are going to do this right, when we make a new frame we should check to see if it uses a memory
+ // return, and if we are at the first instruction and if so stash away the return location. Then we would
+ // only return the memory return value if we know it is valid.
+
+ if (is_memory)
+ {
+ unsigned rax_id = reg_ctx_sp->GetRegisterInfoByName("rax", 0)->kinds[eRegisterKindLLDB];
+ lldb::addr_t storage_addr = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0);
+ return_valobj_sp = ValueObjectMemory::Create (&thread,
+ "",
+ Address (storage_addr, NULL),
+ return_clang_type);
+ }
+ }
+
+ return return_valobj_sp;
+}
+
+bool
+ABISysV_x86_64::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
+{
+ uint32_t reg_kind = unwind_plan.GetRegisterKind();
+ uint32_t sp_reg_num = LLDB_INVALID_REGNUM;
+ uint32_t pc_reg_num = LLDB_INVALID_REGNUM;
+
+ switch (reg_kind)
+ {
+ case eRegisterKindDWARF:
+ case eRegisterKindGCC:
+ sp_reg_num = gcc_dwarf_rsp;
+ pc_reg_num = gcc_dwarf_rip;
+ break;
+
+ case eRegisterKindGDB:
+ sp_reg_num = gdb_rsp;
+ pc_reg_num = gdb_rip;
+ break;
+
+ case eRegisterKindGeneric:
+ sp_reg_num = LLDB_REGNUM_GENERIC_SP;
+ pc_reg_num = LLDB_REGNUM_GENERIC_PC;
+ break;
+ }
+
+ if (sp_reg_num == LLDB_INVALID_REGNUM ||
+ pc_reg_num == LLDB_INVALID_REGNUM)
+ return false;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ row->SetCFARegister (sp_reg_num);
+ row->SetCFAOffset (8);
+ row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -8, false);
+ unwind_plan.AppendRow (row);
+ unwind_plan.SetSourceName ("x86_64 at-func-entry default");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ return true;
+}
+
+bool
+ABISysV_x86_64::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
+{
+ uint32_t reg_kind = unwind_plan.GetRegisterKind();
+ uint32_t fp_reg_num = LLDB_INVALID_REGNUM;
+ uint32_t sp_reg_num = LLDB_INVALID_REGNUM;
+ uint32_t pc_reg_num = LLDB_INVALID_REGNUM;
+
+ switch (reg_kind)
+ {
+ case eRegisterKindDWARF:
+ case eRegisterKindGCC:
+ fp_reg_num = gcc_dwarf_rbp;
+ sp_reg_num = gcc_dwarf_rsp;
+ pc_reg_num = gcc_dwarf_rip;
+ break;
+
+ case eRegisterKindGDB:
+ fp_reg_num = gdb_rbp;
+ sp_reg_num = gdb_rsp;
+ pc_reg_num = gdb_rip;
+ break;
+
+ case eRegisterKindGeneric:
+ fp_reg_num = LLDB_REGNUM_GENERIC_FP;
+ sp_reg_num = LLDB_REGNUM_GENERIC_SP;
+ pc_reg_num = LLDB_REGNUM_GENERIC_PC;
+ break;
+ }
+
+ if (fp_reg_num == LLDB_INVALID_REGNUM ||
+ sp_reg_num == LLDB_INVALID_REGNUM ||
+ pc_reg_num == LLDB_INVALID_REGNUM)
+ return false;
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+
+ const int32_t ptr_size = 8;
+ row->SetCFARegister (LLDB_REGNUM_GENERIC_FP);
+ row->SetCFAOffset (2 * ptr_size);
+ row->SetOffset (0);
+
+ row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
+ row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
+ row->SetRegisterLocationToAtCFAPlusOffset(sp_reg_num, ptr_size * 0, true);
+
+ unwind_plan.AppendRow (row);
+ unwind_plan.SetSourceName ("x86_64 default unwind plan");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+ return true;
+}
+
+bool
+ABISysV_x86_64::RegisterIsVolatile (const RegisterInfo *reg_info)
+{
+ return !RegisterIsCalleeSaved (reg_info);
+}
+
+
+
+// See "Register Usage" in the
+// "System V Application Binary Interface"
+// "AMD64 Architecture Processor Supplement"
+// (or "x86-64(tm) Architecture Processor Supplement" in earlier revisions)
+// (this doc is also commonly referred to as the x86-64/AMD64 psABI)
+// Edited by Michael Matz, Jan Hubicka, Andreas Jaeger, and Mark Mitchell
+// current version is 0.99.6 released 2012-07-02 at http://refspecs.linuxfoundation.org/elf/x86-64-abi-0.99.pdf
+
+bool
+ABISysV_x86_64::RegisterIsCalleeSaved (const RegisterInfo *reg_info)
+{
+ if (reg_info)
+ {
+ // Preserved registers are :
+ // rbx, rsp, rbp, r12, r13, r14, r15
+ // mxcsr (partially preserved)
+ // x87 control word
+
+ const char *name = reg_info->name;
+ if (name[0] == 'r')
+ {
+ switch (name[1])
+ {
+ case '1': // r12, r13, r14, r15
+ if (name[2] >= '2' && name[2] <= '5')
+ return name[3] == '\0';
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ // Accept shorter-variant versions, rbx/ebx, rip/ eip, etc.
+ if (name[0] == 'r' || name[0] == 'e')
+ {
+ switch (name[1])
+ {
+ case 'b': // rbp, rbx
+ if (name[2] == 'p' || name[2] == 'x')
+ return name[3] == '\0';
+ break;
+
+ case 'i': // rip
+ if (name[2] == 'p')
+ return name[3] == '\0';
+ break;
+
+ case 's': // rsp
+ if (name[2] == 'p')
+ return name[3] == '\0';
+ break;
+
+ }
+ }
+ if (name[0] == 's' && name[1] == 'p' && name[2] == '\0') // sp
+ return true;
+ if (name[0] == 'f' && name[1] == 'p' && name[2] == '\0') // fp
+ return true;
+ if (name[0] == 'p' && name[1] == 'c' && name[2] == '\0') // pc
+ return true;
+ }
+ return false;
+}
+
+
+
+void
+ABISysV_x86_64::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "System V ABI for x86_64 targets",
+ CreateInstance);
+}
+
+void
+ABISysV_x86_64::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+lldb_private::ConstString
+ABISysV_x86_64::GetPluginNameStatic()
+{
+ static ConstString g_name("sysv-x86_64");
+ return g_name;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ABISysV_x86_64::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ABISysV_x86_64::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
new file mode 100644
index 000000000000..b10181960e89
--- /dev/null
+++ b/source/Plugins/ABI/SysV-x86_64/ABISysV_x86_64.h
@@ -0,0 +1,138 @@
+//===-- ABISysV_x86_64.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ABISysV_x86_64_h_
+#define liblldb_ABISysV_x86_64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/ABI.h"
+
+class ABISysV_x86_64 :
+ public lldb_private::ABI
+{
+public:
+
+ ~ABISysV_x86_64()
+ {
+ }
+
+ virtual size_t
+ GetRedZoneSize () const;
+
+ virtual bool
+ PrepareTrivialCall (lldb_private::Thread &thread,
+ lldb::addr_t sp,
+ lldb::addr_t functionAddress,
+ lldb::addr_t returnAddress,
+ lldb::addr_t *arg1_ptr = NULL,
+ lldb::addr_t *arg2_ptr = NULL,
+ lldb::addr_t *arg3_ptr = NULL,
+ lldb::addr_t *arg4_ptr = NULL,
+ lldb::addr_t *arg5_ptr = NULL,
+ lldb::addr_t *arg6_ptr = NULL) const;
+
+ virtual bool
+ GetArgumentValues (lldb_private::Thread &thread,
+ lldb_private::ValueList &values) const;
+
+ virtual lldb_private::Error
+ SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value);
+
+protected:
+ lldb::ValueObjectSP
+ GetReturnValueObjectSimple (lldb_private::Thread &thread,
+ lldb_private::ClangASTType &ast_type) const;
+
+public:
+ virtual lldb::ValueObjectSP
+ GetReturnValueObjectImpl (lldb_private::Thread &thread,
+ lldb_private::ClangASTType &type) const;
+
+ virtual bool
+ CreateFunctionEntryUnwindPlan (lldb_private::UnwindPlan &unwind_plan);
+
+ virtual bool
+ CreateDefaultUnwindPlan (lldb_private::UnwindPlan &unwind_plan);
+
+ virtual bool
+ RegisterIsVolatile (const lldb_private::RegisterInfo *reg_info);
+
+ virtual bool
+ StackUsesFrames ()
+ {
+ return true;
+ }
+
+ virtual bool
+ CallFrameAddressIsValid (lldb::addr_t cfa)
+ {
+ // Make sure the stack call frame addresses are are 8 byte aligned
+ if (cfa & (8ull - 1ull))
+ return false; // Not 8 byte aligned
+ if (cfa == 0)
+ return false; // Zero is not a valid stack address
+ return true;
+ }
+
+ virtual bool
+ CodeAddressIsValid (lldb::addr_t pc)
+ {
+ // We have a 64 bit address space, so anything is valid as opcodes
+ // aren't fixed width...
+ return true;
+ }
+
+ virtual bool
+ FunctionCallsChangeCFA ()
+ {
+ return true;
+ }
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoArray (uint32_t &count);
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb::ABISP
+ CreateInstance (const lldb_private::ArchSpec &arch);
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+protected:
+ void
+ CreateRegisterMapIfNeeded ();
+
+ bool
+ RegisterIsCalleeSaved (const lldb_private::RegisterInfo *reg_info);
+
+private:
+ ABISysV_x86_64() : lldb_private::ABI() { } // Call CreateInstance instead.
+};
+
+#endif // liblldb_ABI_h_
diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
new file mode 100644
index 000000000000..e920d70cd596
--- /dev/null
+++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.cpp
@@ -0,0 +1,864 @@
+//===-- DisassemblerLLVMC.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DisassemblerLLVMC.h"
+
+#include "llvm-c/Disassembler.h"
+#include "llvm/ADT/OwningPtr.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCDisassembler.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCInstrInfo.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCRelocationInfo.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryObject.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+#include "llvm/ADT/SmallString.h"
+
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/StackFrame.h"
+
+#include <regex.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+class InstructionLLVMC : public lldb_private::Instruction
+{
+public:
+ InstructionLLVMC (DisassemblerLLVMC &disasm,
+ const lldb_private::Address &address,
+ AddressClass addr_class) :
+ Instruction (address, addr_class),
+ m_disasm_sp (disasm.shared_from_this()),
+ m_does_branch (eLazyBoolCalculate),
+ m_is_valid (false),
+ m_using_file_addr (false)
+ {
+ }
+
+ virtual
+ ~InstructionLLVMC ()
+ {
+ }
+
+ virtual bool
+ DoesBranch ()
+ {
+ if (m_does_branch == eLazyBoolCalculate)
+ {
+ GetDisassemblerLLVMC().Lock(this, NULL);
+ DataExtractor data;
+ if (m_opcode.GetData(data))
+ {
+ bool is_alternate_isa;
+ lldb::addr_t pc = m_address.GetFileAddress();
+
+ DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = GetDisasmToUse (is_alternate_isa);
+ const uint8_t *opcode_data = data.GetDataStart();
+ const size_t opcode_data_len = data.GetByteSize();
+ llvm::MCInst inst;
+ const size_t inst_size = mc_disasm_ptr->GetMCInst (opcode_data,
+ opcode_data_len,
+ pc,
+ inst);
+ // Be conservative, if we didn't understand the instruction, say it might branch...
+ if (inst_size == 0)
+ m_does_branch = eLazyBoolYes;
+ else
+ {
+ const bool can_branch = mc_disasm_ptr->CanBranch(inst);
+ if (can_branch)
+ m_does_branch = eLazyBoolYes;
+ else
+ m_does_branch = eLazyBoolNo;
+ }
+ }
+ GetDisassemblerLLVMC().Unlock();
+ }
+ return m_does_branch == eLazyBoolYes;
+ }
+
+ DisassemblerLLVMC::LLVMCDisassembler *
+ GetDisasmToUse (bool &is_alternate_isa)
+ {
+ is_alternate_isa = false;
+ DisassemblerLLVMC &llvm_disasm = GetDisassemblerLLVMC();
+ if (llvm_disasm.m_alternate_disasm_ap.get() != NULL)
+ {
+ const AddressClass address_class = GetAddressClass ();
+
+ if (address_class == eAddressClassCodeAlternateISA)
+ {
+ is_alternate_isa = true;
+ return llvm_disasm.m_alternate_disasm_ap.get();
+ }
+ }
+ return llvm_disasm.m_disasm_ap.get();
+ }
+
+ virtual size_t
+ Decode (const lldb_private::Disassembler &disassembler,
+ const lldb_private::DataExtractor &data,
+ lldb::offset_t data_offset)
+ {
+ // All we have to do is read the opcode which can be easy for some
+ // architectures
+ bool got_op = false;
+ DisassemblerLLVMC &llvm_disasm = GetDisassemblerLLVMC();
+ const ArchSpec &arch = llvm_disasm.GetArchitecture();
+
+ const uint32_t min_op_byte_size = arch.GetMinimumOpcodeByteSize();
+ const uint32_t max_op_byte_size = arch.GetMaximumOpcodeByteSize();
+ if (min_op_byte_size == max_op_byte_size)
+ {
+ // Fixed size instructions, just read that amount of data.
+ if (!data.ValidOffsetForDataOfSize(data_offset, min_op_byte_size))
+ return false;
+
+ switch (min_op_byte_size)
+ {
+ case 1:
+ m_opcode.SetOpcode8 (data.GetU8 (&data_offset));
+ got_op = true;
+ break;
+
+ case 2:
+ m_opcode.SetOpcode16 (data.GetU16 (&data_offset));
+ got_op = true;
+ break;
+
+ case 4:
+ m_opcode.SetOpcode32 (data.GetU32 (&data_offset));
+ got_op = true;
+ break;
+
+ case 8:
+ m_opcode.SetOpcode64 (data.GetU64 (&data_offset));
+ got_op = true;
+ break;
+
+ default:
+ m_opcode.SetOpcodeBytes(data.PeekData(data_offset, min_op_byte_size), min_op_byte_size);
+ got_op = true;
+ break;
+ }
+ }
+ if (!got_op)
+ {
+ bool is_alternate_isa = false;
+ DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr = GetDisasmToUse (is_alternate_isa);
+
+ const llvm::Triple::ArchType machine = arch.GetMachine();
+ if (machine == llvm::Triple::arm || machine == llvm::Triple::thumb)
+ {
+ if (machine == llvm::Triple::thumb || is_alternate_isa)
+ {
+ uint32_t thumb_opcode = data.GetU16(&data_offset);
+ if ((thumb_opcode & 0xe000) != 0xe000 || ((thumb_opcode & 0x1800u) == 0))
+ {
+ m_opcode.SetOpcode16 (thumb_opcode);
+ m_is_valid = true;
+ }
+ else
+ {
+ thumb_opcode <<= 16;
+ thumb_opcode |= data.GetU16(&data_offset);
+ m_opcode.SetOpcode16_2 (thumb_opcode);
+ m_is_valid = true;
+ }
+ }
+ else
+ {
+ m_opcode.SetOpcode32 (data.GetU32(&data_offset));
+ m_is_valid = true;
+ }
+ }
+ else
+ {
+ // The opcode isn't evenly sized, so we need to actually use the llvm
+ // disassembler to parse it and get the size.
+ uint8_t *opcode_data = const_cast<uint8_t *>(data.PeekData (data_offset, 1));
+ const size_t opcode_data_len = data.BytesLeft(data_offset);
+ const addr_t pc = m_address.GetFileAddress();
+ llvm::MCInst inst;
+
+ llvm_disasm.Lock(this, NULL);
+ const size_t inst_size = mc_disasm_ptr->GetMCInst(opcode_data,
+ opcode_data_len,
+ pc,
+ inst);
+ llvm_disasm.Unlock();
+ if (inst_size == 0)
+ m_opcode.Clear();
+ else
+ {
+ m_opcode.SetOpcodeBytes(opcode_data, inst_size);
+ m_is_valid = true;
+ }
+ }
+ }
+ return m_opcode.GetByteSize();
+ }
+
+ void
+ AppendComment (std::string &description)
+ {
+ if (m_comment.empty())
+ m_comment.swap (description);
+ else
+ {
+ m_comment.append(", ");
+ m_comment.append(description);
+ }
+ }
+
+ virtual void
+ CalculateMnemonicOperandsAndComment (const lldb_private::ExecutionContext *exe_ctx)
+ {
+ DataExtractor data;
+ const AddressClass address_class = GetAddressClass ();
+
+ if (m_opcode.GetData(data))
+ {
+ char out_string[512];
+
+ DisassemblerLLVMC &llvm_disasm = GetDisassemblerLLVMC();
+
+ DisassemblerLLVMC::LLVMCDisassembler *mc_disasm_ptr;
+
+ if (address_class == eAddressClassCodeAlternateISA)
+ mc_disasm_ptr = llvm_disasm.m_alternate_disasm_ap.get();
+ else
+ mc_disasm_ptr = llvm_disasm.m_disasm_ap.get();
+
+ lldb::addr_t pc = m_address.GetFileAddress();
+ m_using_file_addr = true;
+
+ const bool data_from_file = GetDisassemblerLLVMC().m_data_from_file;
+ bool use_hex_immediates = true;
+ Disassembler::HexImmediateStyle hex_style = Disassembler::eHexStyleC;
+
+ if (exe_ctx)
+ {
+ Target *target = exe_ctx->GetTargetPtr();
+ if (target)
+ {
+ use_hex_immediates = target->GetUseHexImmediates();
+ hex_style = target->GetHexImmediateStyle();
+
+ if (!data_from_file)
+ {
+ const lldb::addr_t load_addr = m_address.GetLoadAddress(target);
+ if (load_addr != LLDB_INVALID_ADDRESS)
+ {
+ pc = load_addr;
+ m_using_file_addr = false;
+ }
+ }
+ }
+ }
+
+ llvm_disasm.Lock(this, exe_ctx);
+
+ const uint8_t *opcode_data = data.GetDataStart();
+ const size_t opcode_data_len = data.GetByteSize();
+ llvm::MCInst inst;
+ size_t inst_size = mc_disasm_ptr->GetMCInst (opcode_data,
+ opcode_data_len,
+ pc,
+ inst);
+
+ if (inst_size > 0)
+ {
+ mc_disasm_ptr->SetStyle(use_hex_immediates, hex_style);
+ mc_disasm_ptr->PrintMCInst(inst, out_string, sizeof(out_string));
+ }
+
+ llvm_disasm.Unlock();
+
+ if (inst_size == 0)
+ {
+ m_comment.assign ("unknown opcode");
+ inst_size = m_opcode.GetByteSize();
+ StreamString mnemonic_strm;
+ lldb::offset_t offset = 0;
+ switch (inst_size)
+ {
+ case 1:
+ {
+ const uint8_t uval8 = data.GetU8 (&offset);
+ m_opcode.SetOpcode8 (uval8);
+ m_opcode_name.assign (".byte");
+ mnemonic_strm.Printf("0x%2.2x", uval8);
+ }
+ break;
+ case 2:
+ {
+ const uint16_t uval16 = data.GetU16(&offset);
+ m_opcode.SetOpcode16(uval16);
+ m_opcode_name.assign (".short");
+ mnemonic_strm.Printf("0x%4.4x", uval16);
+ }
+ break;
+ case 4:
+ {
+ const uint32_t uval32 = data.GetU32(&offset);
+ m_opcode.SetOpcode32(uval32);
+ m_opcode_name.assign (".long");
+ mnemonic_strm.Printf("0x%8.8x", uval32);
+ }
+ break;
+ case 8:
+ {
+ const uint64_t uval64 = data.GetU64(&offset);
+ m_opcode.SetOpcode64(uval64);
+ m_opcode_name.assign (".quad");
+ mnemonic_strm.Printf("0x%16.16" PRIx64, uval64);
+ }
+ break;
+ default:
+ if (inst_size == 0)
+ return;
+ else
+ {
+ const uint8_t *bytes = data.PeekData(offset, inst_size);
+ if (bytes == NULL)
+ return;
+ m_opcode_name.assign (".byte");
+ m_opcode.SetOpcodeBytes(bytes, inst_size);
+ mnemonic_strm.Printf("0x%2.2x", bytes[0]);
+ for (uint32_t i=1; i<inst_size; ++i)
+ mnemonic_strm.Printf(" 0x%2.2x", bytes[i]);
+ }
+ break;
+ }
+ m_mnemonics.swap(mnemonic_strm.GetString());
+ return;
+ }
+ else
+ {
+ if (m_does_branch == eLazyBoolCalculate)
+ {
+ const bool can_branch = mc_disasm_ptr->CanBranch(inst);
+ if (can_branch)
+ m_does_branch = eLazyBoolYes;
+ else
+ m_does_branch = eLazyBoolNo;
+
+ }
+ }
+
+ if (!s_regex_compiled)
+ {
+ ::regcomp(&s_regex, "[ \t]*([^ ^\t]+)[ \t]*([^ ^\t].*)?", REG_EXTENDED);
+ s_regex_compiled = true;
+ }
+
+ ::regmatch_t matches[3];
+
+ if (!::regexec(&s_regex, out_string, sizeof(matches) / sizeof(::regmatch_t), matches, 0))
+ {
+ if (matches[1].rm_so != -1)
+ m_opcode_name.assign(out_string + matches[1].rm_so, matches[1].rm_eo - matches[1].rm_so);
+ if (matches[2].rm_so != -1)
+ m_mnemonics.assign(out_string + matches[2].rm_so, matches[2].rm_eo - matches[2].rm_so);
+ }
+ }
+ }
+
+ bool
+ IsValid () const
+ {
+ return m_is_valid;
+ }
+
+ bool
+ UsingFileAddress() const
+ {
+ return m_using_file_addr;
+ }
+ size_t
+ GetByteSize () const
+ {
+ return m_opcode.GetByteSize();
+ }
+
+ DisassemblerLLVMC &
+ GetDisassemblerLLVMC ()
+ {
+ return *(DisassemblerLLVMC *)m_disasm_sp.get();
+ }
+protected:
+
+ DisassemblerSP m_disasm_sp; // for ownership
+ LazyBool m_does_branch;
+ bool m_is_valid;
+ bool m_using_file_addr;
+
+ static bool s_regex_compiled;
+ static ::regex_t s_regex;
+};
+
+bool InstructionLLVMC::s_regex_compiled = false;
+::regex_t InstructionLLVMC::s_regex;
+
+DisassemblerLLVMC::LLVMCDisassembler::LLVMCDisassembler (const char *triple, unsigned flavor, DisassemblerLLVMC &owner):
+ m_is_valid(true)
+{
+ std::string Error;
+ const llvm::Target *curr_target = llvm::TargetRegistry::lookupTarget(triple, Error);
+ if (!curr_target)
+ {
+ m_is_valid = false;
+ return;
+ }
+
+ m_instr_info_ap.reset(curr_target->createMCInstrInfo());
+ m_reg_info_ap.reset (curr_target->createMCRegInfo(triple));
+
+ std::string features_str;
+
+ m_subtarget_info_ap.reset(curr_target->createMCSubtargetInfo(triple, "",
+ features_str));
+
+ m_asm_info_ap.reset(curr_target->createMCAsmInfo(*curr_target->createMCRegInfo(triple), triple));
+
+ if (m_instr_info_ap.get() == NULL || m_reg_info_ap.get() == NULL || m_subtarget_info_ap.get() == NULL || m_asm_info_ap.get() == NULL)
+ {
+ m_is_valid = false;
+ return;
+ }
+
+ m_context_ap.reset(new llvm::MCContext(m_asm_info_ap.get(), m_reg_info_ap.get(), 0));
+
+ m_disasm_ap.reset(curr_target->createMCDisassembler(*m_subtarget_info_ap.get()));
+ if (m_disasm_ap.get() && m_context_ap.get())
+ {
+ llvm::OwningPtr<llvm::MCRelocationInfo> RelInfo(curr_target->createMCRelocationInfo(triple, *m_context_ap.get()));
+ if (!RelInfo)
+ {
+ m_is_valid = false;
+ return;
+ }
+ m_disasm_ap->setupForSymbolicDisassembly(NULL,
+ DisassemblerLLVMC::SymbolLookupCallback,
+ (void *) &owner,
+ m_context_ap.get(),
+ RelInfo);
+
+ unsigned asm_printer_variant;
+ if (flavor == ~0U)
+ asm_printer_variant = m_asm_info_ap->getAssemblerDialect();
+ else
+ {
+ asm_printer_variant = flavor;
+ }
+
+ m_instr_printer_ap.reset(curr_target->createMCInstPrinter(asm_printer_variant,
+ *m_asm_info_ap.get(),
+ *m_instr_info_ap.get(),
+ *m_reg_info_ap.get(),
+ *m_subtarget_info_ap.get()));
+ if (m_instr_printer_ap.get() == NULL)
+ {
+ m_disasm_ap.reset();
+ m_is_valid = false;
+ }
+ }
+ else
+ m_is_valid = false;
+}
+
+DisassemblerLLVMC::LLVMCDisassembler::~LLVMCDisassembler()
+{
+}
+
+namespace {
+ // This is the memory object we use in GetInstruction.
+ class LLDBDisasmMemoryObject : public llvm::MemoryObject {
+ const uint8_t *m_bytes;
+ uint64_t m_size;
+ uint64_t m_base_PC;
+ public:
+ LLDBDisasmMemoryObject(const uint8_t *bytes, uint64_t size, uint64_t basePC) :
+ m_bytes(bytes), m_size(size), m_base_PC(basePC) {}
+
+ uint64_t getBase() const { return m_base_PC; }
+ uint64_t getExtent() const { return m_size; }
+
+ int readByte(uint64_t addr, uint8_t *byte) const {
+ if (addr - m_base_PC >= m_size)
+ return -1;
+ *byte = m_bytes[addr - m_base_PC];
+ return 0;
+ }
+ };
+} // End Anonymous Namespace
+
+uint64_t
+DisassemblerLLVMC::LLVMCDisassembler::GetMCInst (const uint8_t *opcode_data,
+ size_t opcode_data_len,
+ lldb::addr_t pc,
+ llvm::MCInst &mc_inst)
+{
+ LLDBDisasmMemoryObject memory_object (opcode_data, opcode_data_len, pc);
+ llvm::MCDisassembler::DecodeStatus status;
+
+ uint64_t new_inst_size;
+ status = m_disasm_ap->getInstruction(mc_inst,
+ new_inst_size,
+ memory_object,
+ pc,
+ llvm::nulls(),
+ llvm::nulls());
+ if (status == llvm::MCDisassembler::Success)
+ return new_inst_size;
+ else
+ return 0;
+}
+
+uint64_t
+DisassemblerLLVMC::LLVMCDisassembler::PrintMCInst (llvm::MCInst &mc_inst,
+ char *dst,
+ size_t dst_len)
+{
+ llvm::StringRef unused_annotations;
+ llvm::SmallString<64> inst_string;
+ llvm::raw_svector_ostream inst_stream(inst_string);
+ m_instr_printer_ap->printInst (&mc_inst, inst_stream, unused_annotations);
+ inst_stream.flush();
+ const size_t output_size = std::min(dst_len - 1, inst_string.size());
+ std::memcpy(dst, inst_string.data(), output_size);
+ dst[output_size] = '\0';
+
+ return output_size;
+}
+
+void
+DisassemblerLLVMC::LLVMCDisassembler::SetStyle (bool use_hex_immed, HexImmediateStyle hex_style)
+{
+ m_instr_printer_ap->setPrintImmHex(use_hex_immed);
+ switch(hex_style)
+ {
+ case eHexStyleC: m_instr_printer_ap->setPrintImmHex(llvm::HexStyle::C); break;
+ case eHexStyleAsm: m_instr_printer_ap->setPrintImmHex(llvm::HexStyle::Asm); break;
+ }
+}
+
+bool
+DisassemblerLLVMC::LLVMCDisassembler::CanBranch (llvm::MCInst &mc_inst)
+{
+ return m_instr_info_ap->get(mc_inst.getOpcode()).mayAffectControlFlow(mc_inst, *m_reg_info_ap.get());
+}
+
+bool
+DisassemblerLLVMC::FlavorValidForArchSpec (const lldb_private::ArchSpec &arch, const char *flavor)
+{
+ llvm::Triple triple = arch.GetTriple();
+ if (flavor == NULL || strcmp (flavor, "default") == 0)
+ return true;
+
+ if (triple.getArch() == llvm::Triple::x86 || triple.getArch() == llvm::Triple::x86_64)
+ {
+ if (strcmp (flavor, "intel") == 0 || strcmp (flavor, "att") == 0)
+ return true;
+ else
+ return false;
+ }
+ else
+ return false;
+}
+
+
+Disassembler *
+DisassemblerLLVMC::CreateInstance (const ArchSpec &arch, const char *flavor)
+{
+ if (arch.GetTriple().getArch() != llvm::Triple::UnknownArch)
+ {
+ std::unique_ptr<DisassemblerLLVMC> disasm_ap (new DisassemblerLLVMC(arch, flavor));
+
+ if (disasm_ap.get() && disasm_ap->IsValid())
+ return disasm_ap.release();
+ }
+ return NULL;
+}
+
+DisassemblerLLVMC::DisassemblerLLVMC (const ArchSpec &arch, const char *flavor_string) :
+ Disassembler(arch, flavor_string),
+ m_exe_ctx (NULL),
+ m_inst (NULL),
+ m_data_from_file (false)
+{
+ if (!FlavorValidForArchSpec (arch, m_flavor.c_str()))
+ {
+ m_flavor.assign("default");
+ }
+
+ const char *triple = arch.GetTriple().getTriple().c_str();
+ unsigned flavor = ~0U;
+
+ // So far the only supported flavor is "intel" on x86. The base class will set this
+ // correctly coming in.
+ if (arch.GetTriple().getArch() == llvm::Triple::x86
+ || arch.GetTriple().getArch() == llvm::Triple::x86_64)
+ {
+ if (m_flavor == "intel")
+ {
+ flavor = 1;
+ }
+ else if (m_flavor == "att")
+ {
+ flavor = 0;
+ }
+ }
+
+ ArchSpec thumb_arch(arch);
+ if (arch.GetTriple().getArch() == llvm::Triple::arm)
+ {
+ std::string thumb_arch_name (thumb_arch.GetTriple().getArchName().str());
+ // Replace "arm" with "thumb" so we get all thumb variants correct
+ if (thumb_arch_name.size() > 3)
+ {
+ thumb_arch_name.erase(0,3);
+ thumb_arch_name.insert(0, "thumb");
+ }
+ else
+ {
+ thumb_arch_name = "thumbv7";
+ }
+ thumb_arch.GetTriple().setArchName(llvm::StringRef(thumb_arch_name.c_str()));
+ }
+
+ // Cortex-M3 devices (e.g. armv7m) can only execute thumb (T2) instructions,
+ // so hardcode the primary disassembler to thumb mode.
+ if (arch.GetTriple().getArch() == llvm::Triple::arm
+ && (arch.GetCore() == ArchSpec::Core::eCore_arm_armv7m || arch.GetCore() == ArchSpec::Core::eCore_arm_armv7em))
+ {
+ triple = thumb_arch.GetTriple().getTriple().c_str();
+ }
+
+ m_disasm_ap.reset (new LLVMCDisassembler(triple, flavor, *this));
+ if (!m_disasm_ap->IsValid())
+ {
+ // We use m_disasm_ap.get() to tell whether we are valid or not, so if this isn't good for some reason,
+ // we reset it, and then we won't be valid and FindPlugin will fail and we won't get used.
+ m_disasm_ap.reset();
+ }
+
+ // For arm CPUs that can execute arm or thumb instructions, also create a thumb instruction disassembler.
+ if (arch.GetTriple().getArch() == llvm::Triple::arm)
+ {
+ std::string thumb_triple(thumb_arch.GetTriple().getTriple());
+ m_alternate_disasm_ap.reset(new LLVMCDisassembler(thumb_triple.c_str(), flavor, *this));
+ if (!m_alternate_disasm_ap->IsValid())
+ {
+ m_disasm_ap.reset();
+ m_alternate_disasm_ap.reset();
+ }
+ }
+}
+
+DisassemblerLLVMC::~DisassemblerLLVMC()
+{
+}
+
+size_t
+DisassemblerLLVMC::DecodeInstructions (const Address &base_addr,
+ const DataExtractor& data,
+ lldb::offset_t data_offset,
+ size_t num_instructions,
+ bool append,
+ bool data_from_file)
+{
+ if (!append)
+ m_instruction_list.Clear();
+
+ if (!IsValid())
+ return 0;
+
+ m_data_from_file = data_from_file;
+ uint32_t data_cursor = data_offset;
+ const size_t data_byte_size = data.GetByteSize();
+ uint32_t instructions_parsed = 0;
+ Address inst_addr(base_addr);
+
+ while (data_cursor < data_byte_size && instructions_parsed < num_instructions)
+ {
+
+ AddressClass address_class = eAddressClassCode;
+
+ if (m_alternate_disasm_ap.get() != NULL)
+ address_class = inst_addr.GetAddressClass ();
+
+ InstructionSP inst_sp(new InstructionLLVMC(*this,
+ inst_addr,
+ address_class));
+
+ if (!inst_sp)
+ break;
+
+ uint32_t inst_size = inst_sp->Decode(*this, data, data_cursor);
+
+ if (inst_size == 0)
+ break;
+
+ m_instruction_list.Append(inst_sp);
+ data_cursor += inst_size;
+ inst_addr.Slide(inst_size);
+ instructions_parsed++;
+ }
+
+ return data_cursor - data_offset;
+}
+
+void
+DisassemblerLLVMC::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "Disassembler that uses LLVM MC to disassemble i386, x86_64 and ARM.",
+ CreateInstance);
+
+ llvm::InitializeAllTargetInfos();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmParsers();
+ llvm::InitializeAllDisassemblers();
+}
+
+void
+DisassemblerLLVMC::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+ConstString
+DisassemblerLLVMC::GetPluginNameStatic()
+{
+ static ConstString g_name("llvm-mc");
+ return g_name;
+}
+
+int DisassemblerLLVMC::OpInfoCallback (void *disassembler,
+ uint64_t pc,
+ uint64_t offset,
+ uint64_t size,
+ int tag_type,
+ void *tag_bug)
+{
+ return static_cast<DisassemblerLLVMC*>(disassembler)->OpInfo (pc,
+ offset,
+ size,
+ tag_type,
+ tag_bug);
+}
+
+const char *DisassemblerLLVMC::SymbolLookupCallback (void *disassembler,
+ uint64_t value,
+ uint64_t *type,
+ uint64_t pc,
+ const char **name)
+{
+ return static_cast<DisassemblerLLVMC*>(disassembler)->SymbolLookup(value,
+ type,
+ pc,
+ name);
+}
+
+int DisassemblerLLVMC::OpInfo (uint64_t PC,
+ uint64_t Offset,
+ uint64_t Size,
+ int tag_type,
+ void *tag_bug)
+{
+ switch (tag_type)
+ {
+ default:
+ break;
+ case 1:
+ bzero (tag_bug, sizeof(::LLVMOpInfo1));
+ break;
+ }
+ return 0;
+}
+
+const char *DisassemblerLLVMC::SymbolLookup (uint64_t value,
+ uint64_t *type_ptr,
+ uint64_t pc,
+ const char **name)
+{
+ if (*type_ptr)
+ {
+ if (m_exe_ctx && m_inst)
+ {
+ //std::string remove_this_prior_to_checkin;
+ Target *target = m_exe_ctx ? m_exe_ctx->GetTargetPtr() : NULL;
+ Address value_so_addr;
+ if (m_inst->UsingFileAddress())
+ {
+ ModuleSP module_sp(m_inst->GetAddress().GetModule());
+ if (module_sp)
+ module_sp->ResolveFileAddress(value, value_so_addr);
+ }
+ else if (target && !target->GetSectionLoadList().IsEmpty())
+ {
+ target->GetSectionLoadList().ResolveLoadAddress(value, value_so_addr);
+ }
+
+ if (value_so_addr.IsValid() && value_so_addr.GetSection())
+ {
+ StreamString ss;
+
+ value_so_addr.Dump (&ss,
+ target,
+ Address::DumpStyleResolvedDescriptionNoModule,
+ Address::DumpStyleSectionNameOffset);
+
+ if (!ss.GetString().empty())
+ {
+ m_inst->AppendComment(ss.GetString());
+ }
+ }
+ }
+ }
+
+ *type_ptr = LLVMDisassembler_ReferenceType_InOut_None;
+ *name = NULL;
+ return NULL;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+ConstString
+DisassemblerLLVMC::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+DisassemblerLLVMC::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
new file mode 100644
index 000000000000..c567791866d5
--- /dev/null
+++ b/source/Plugins/Disassembler/llvm/DisassemblerLLVMC.h
@@ -0,0 +1,166 @@
+//===-- DisassemblerLLVMC.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_DisassemblerLLVMC_h_
+#define liblldb_DisassemblerLLVMC_h_
+
+#include <string>
+
+#include "llvm-c/Disassembler.h"
+
+// Opaque references to C++ Objects in LLVM's MC.
+namespace llvm
+{
+ class MCContext;
+ class MCInst;
+ class MCInstrInfo;
+ class MCRegisterInfo;
+ class MCDisassembler;
+ class MCInstPrinter;
+ class MCAsmInfo;
+ class MCSubtargetInfo;
+}
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/Mutex.h"
+
+class InstructionLLVMC;
+
+class DisassemblerLLVMC : public lldb_private::Disassembler
+{
+ // Since we need to make two actual MC Disassemblers for ARM (ARM & THUMB), and there's a bit of goo to set up and own
+ // in the MC disassembler world, I added this class to manage the actual disassemblers.
+ class LLVMCDisassembler
+ {
+ public:
+ LLVMCDisassembler (const char *triple, unsigned flavor, DisassemblerLLVMC &owner);
+
+ ~LLVMCDisassembler();
+
+ uint64_t GetMCInst (const uint8_t *opcode_data, size_t opcode_data_len, lldb::addr_t pc, llvm::MCInst &mc_inst);
+ uint64_t PrintMCInst (llvm::MCInst &mc_inst, char *output_buffer, size_t out_buffer_len);
+ void SetStyle (bool use_hex_immed, HexImmediateStyle hex_style);
+ bool CanBranch (llvm::MCInst &mc_inst);
+ bool IsValid()
+ {
+ return m_is_valid;
+ }
+
+ private:
+ bool m_is_valid;
+ std::unique_ptr<llvm::MCContext> m_context_ap;
+ std::unique_ptr<llvm::MCAsmInfo> m_asm_info_ap;
+ std::unique_ptr<llvm::MCSubtargetInfo> m_subtarget_info_ap;
+ std::unique_ptr<llvm::MCInstrInfo> m_instr_info_ap;
+ std::unique_ptr<llvm::MCRegisterInfo> m_reg_info_ap;
+ std::unique_ptr<llvm::MCInstPrinter> m_instr_printer_ap;
+ std::unique_ptr<llvm::MCDisassembler> m_disasm_ap;
+ };
+
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static lldb_private::Disassembler *
+ CreateInstance(const lldb_private::ArchSpec &arch, const char *flavor);
+
+ DisassemblerLLVMC(const lldb_private::ArchSpec &arch, const char *flavor /* = NULL */);
+
+ virtual
+ ~DisassemblerLLVMC();
+
+ virtual size_t
+ DecodeInstructions (const lldb_private::Address &base_addr,
+ const lldb_private::DataExtractor& data,
+ lldb::offset_t data_offset,
+ size_t num_instructions,
+ bool append,
+ bool data_from_file);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+protected:
+ friend class InstructionLLVMC;
+
+ virtual bool
+ FlavorValidForArchSpec (const lldb_private::ArchSpec &arch, const char *flavor);
+
+ bool
+ IsValid()
+ {
+ return (m_disasm_ap.get() != NULL && m_disasm_ap->IsValid());
+ }
+
+ int OpInfo(uint64_t PC,
+ uint64_t Offset,
+ uint64_t Size,
+ int TagType,
+ void *TagBug);
+
+ const char *SymbolLookup (uint64_t ReferenceValue,
+ uint64_t *ReferenceType,
+ uint64_t ReferencePC,
+ const char **ReferenceName);
+
+ static int OpInfoCallback (void *DisInfo,
+ uint64_t PC,
+ uint64_t Offset,
+ uint64_t Size,
+ int TagType,
+ void *TagBug);
+
+ static const char *SymbolLookupCallback(void *DisInfo,
+ uint64_t ReferenceValue,
+ uint64_t *ReferenceType,
+ uint64_t ReferencePC,
+ const char **ReferenceName);
+
+ void Lock(InstructionLLVMC *inst,
+ const lldb_private::ExecutionContext *exe_ctx)
+ {
+ m_mutex.Lock();
+ m_inst = inst;
+ m_exe_ctx = exe_ctx;
+ }
+
+ void Unlock()
+ {
+ m_inst = NULL;
+ m_exe_ctx = NULL;
+ m_mutex.Unlock();
+ }
+
+ const lldb_private::ExecutionContext *m_exe_ctx;
+ InstructionLLVMC *m_inst;
+ lldb_private::Mutex m_mutex;
+ bool m_data_from_file;
+
+ std::unique_ptr<LLVMCDisassembler> m_disasm_ap;
+ std::unique_ptr<LLVMCDisassembler> m_alternate_disasm_ap;
+};
+
+#endif // liblldb_DisassemblerLLVM_h_
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp
new file mode 100644
index 000000000000..2604ae670164
--- /dev/null
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.cpp
@@ -0,0 +1,177 @@
+//===-- AuxVector.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Target/Process.h"
+
+#if defined(__linux__) or defined(__FreeBSD__)
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+#endif
+
+#include "AuxVector.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static bool
+GetMaxU64(DataExtractor &data,
+ lldb::offset_t *offset_ptr,
+ uint64_t *value,
+ unsigned int byte_size)
+{
+ lldb::offset_t saved_offset = *offset_ptr;
+ *value = data.GetMaxU64(offset_ptr, byte_size);
+ return *offset_ptr != saved_offset;
+}
+
+static bool
+ParseAuxvEntry(DataExtractor &data,
+ AuxVector::Entry &entry,
+ lldb::offset_t *offset_ptr,
+ unsigned int byte_size)
+{
+ if (!GetMaxU64(data, offset_ptr, &entry.type, byte_size))
+ return false;
+
+ if (!GetMaxU64(data, offset_ptr, &entry.value, byte_size))
+ return false;
+
+ return true;
+}
+
+DataBufferSP
+AuxVector::GetAuxvData()
+{
+#if defined(__linux__) or defined(__FreeBSD__)
+ if (m_process->GetPluginName() == ProcessElfCore::GetPluginNameStatic())
+ return static_cast<ProcessElfCore *>(m_process)->GetAuxvData();
+#endif
+ return lldb_private::Host::GetAuxvData(m_process);
+}
+
+void
+AuxVector::ParseAuxv(DataExtractor &data)
+{
+ const unsigned int byte_size = m_process->GetAddressByteSize();
+ lldb::offset_t offset = 0;
+
+ for (;;)
+ {
+ Entry entry;
+
+ if (!ParseAuxvEntry(data, entry, &offset, byte_size))
+ break;
+
+ if (entry.type == AT_NULL)
+ break;
+
+ if (entry.type == AT_IGNORE)
+ continue;
+
+ m_auxv.push_back(entry);
+ }
+}
+
+AuxVector::AuxVector(Process *process)
+ : m_process(process)
+{
+ DataExtractor data;
+ Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
+
+ data.SetData(GetAuxvData());
+ data.SetByteOrder(m_process->GetByteOrder());
+ data.SetAddressByteSize(m_process->GetAddressByteSize());
+
+ ParseAuxv(data);
+
+ if (log)
+ DumpToLog(log);
+}
+
+AuxVector::iterator
+AuxVector::FindEntry(EntryType type) const
+{
+ for (iterator I = begin(); I != end(); ++I)
+ {
+ if (I->type == static_cast<uint64_t>(type))
+ return I;
+ }
+
+ return end();
+}
+
+void
+AuxVector::DumpToLog(Log *log) const
+{
+ if (!log)
+ return;
+
+ log->PutCString("AuxVector: ");
+ for (iterator I = begin(); I != end(); ++I)
+ {
+ log->Printf(" %s [%" PRIu64 "]: %" PRIx64, GetEntryName(*I), I->type, I->value);
+ }
+}
+
+const char *
+AuxVector::GetEntryName(EntryType type)
+{
+ const char *name = "AT_???";
+
+#define ENTRY_NAME(_type) _type: name = #_type
+ switch (type)
+ {
+ case ENTRY_NAME(AT_NULL); break;
+ case ENTRY_NAME(AT_IGNORE); break;
+ case ENTRY_NAME(AT_EXECFD); break;
+ case ENTRY_NAME(AT_PHDR); break;
+ case ENTRY_NAME(AT_PHENT); break;
+ case ENTRY_NAME(AT_PHNUM); break;
+ case ENTRY_NAME(AT_PAGESZ); break;
+ case ENTRY_NAME(AT_BASE); break;
+ case ENTRY_NAME(AT_FLAGS); break;
+ case ENTRY_NAME(AT_ENTRY); break;
+ case ENTRY_NAME(AT_NOTELF); break;
+ case ENTRY_NAME(AT_UID); break;
+ case ENTRY_NAME(AT_EUID); break;
+ case ENTRY_NAME(AT_GID); break;
+ case ENTRY_NAME(AT_EGID); break;
+ case ENTRY_NAME(AT_CLKTCK); break;
+ case ENTRY_NAME(AT_PLATFORM); break;
+ case ENTRY_NAME(AT_HWCAP); break;
+ case ENTRY_NAME(AT_FPUCW); break;
+ case ENTRY_NAME(AT_DCACHEBSIZE); break;
+ case ENTRY_NAME(AT_ICACHEBSIZE); break;
+ case ENTRY_NAME(AT_UCACHEBSIZE); break;
+ case ENTRY_NAME(AT_IGNOREPPC); break;
+ case ENTRY_NAME(AT_SECURE); break;
+ case ENTRY_NAME(AT_BASE_PLATFORM); break;
+ case ENTRY_NAME(AT_RANDOM); break;
+ case ENTRY_NAME(AT_EXECFN); break;
+ case ENTRY_NAME(AT_SYSINFO); break;
+ case ENTRY_NAME(AT_SYSINFO_EHDR); break;
+ case ENTRY_NAME(AT_L1I_CACHESHAPE); break;
+ case ENTRY_NAME(AT_L1D_CACHESHAPE); break;
+ case ENTRY_NAME(AT_L2_CACHESHAPE); break;
+ case ENTRY_NAME(AT_L3_CACHESHAPE); break;
+ }
+#undef ENTRY_NAME
+
+ return name;
+}
+
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h
new file mode 100644
index 000000000000..2d39eddcacc6
--- /dev/null
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/AuxVector.h
@@ -0,0 +1,115 @@
+//===-- AuxVector.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_AuxVector_H_
+#define liblldb_AuxVector_H_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+#include "lldb/lldb-forward.h"
+
+namespace lldb_private {
+class DataExtractor;
+}
+
+/// @class AuxVector
+/// @brief Represents a processes auxiliary vector.
+///
+/// When a process is loaded on Linux a vector of values is placed onto the
+/// stack communicating operating system specific information. On construction
+/// this class locates and parses this information and provides a simple
+/// read-only interface to the entries found.
+class AuxVector {
+
+public:
+ AuxVector(lldb_private::Process *process);
+
+ struct Entry {
+ uint64_t type;
+ uint64_t value;
+
+ Entry() : type(0), value(0) { }
+ };
+
+ /// Constants describing the type of entry.
+ /// On Linux, running "LD_SHOW_AUXV=1 ./executable" will spew AUX information.
+ enum EntryType {
+ AT_NULL = 0, ///< End of auxv.
+ AT_IGNORE = 1, ///< Ignore entry.
+ AT_EXECFD = 2, ///< File descriptor of program.
+ AT_PHDR = 3, ///< Program headers.
+ AT_PHENT = 4, ///< Size of program header.
+ AT_PHNUM = 5, ///< Number of program headers.
+ AT_PAGESZ = 6, ///< Page size.
+ AT_BASE = 7, ///< Interpreter base address.
+ AT_FLAGS = 8, ///< Flags.
+ AT_ENTRY = 9, ///< Program entry point.
+ AT_NOTELF = 10, ///< Set if program is not an ELF.
+ AT_UID = 11, ///< UID.
+ AT_EUID = 12, ///< Effective UID.
+ AT_GID = 13, ///< GID.
+ AT_EGID = 14, ///< Effective GID.
+ AT_CLKTCK = 17, ///< Clock frequency (e.g. times(2)).
+ AT_PLATFORM = 15, ///< String identifying platform.
+ AT_HWCAP = 16, ///< Machine dependent hints about processor capabilities.
+ AT_FPUCW = 18, ///< Used FPU control word.
+ AT_DCACHEBSIZE = 19, ///< Data cache block size.
+ AT_ICACHEBSIZE = 20, ///< Instruction cache block size.
+ AT_UCACHEBSIZE = 21, ///< Unified cache block size.
+ AT_IGNOREPPC = 22, ///< Entry should be ignored.
+ AT_SECURE = 23, ///< Boolean, was exec setuid-like?
+ AT_BASE_PLATFORM = 24, ///< String identifying real platforms.
+ AT_RANDOM = 25, ///< Address of 16 random bytes.
+ AT_EXECFN = 31, ///< Filename of executable.
+ AT_SYSINFO = 32, ///< Pointer to the global system page used for system calls and other nice things.
+ AT_SYSINFO_EHDR = 33,
+ AT_L1I_CACHESHAPE = 34, ///< Shapes of the caches.
+ AT_L1D_CACHESHAPE = 35,
+ AT_L2_CACHESHAPE = 36,
+ AT_L3_CACHESHAPE = 37,
+ };
+
+private:
+ typedef std::vector<Entry> EntryVector;
+
+public:
+ typedef EntryVector::const_iterator iterator;
+
+ iterator begin() const { return m_auxv.begin(); }
+ iterator end() const { return m_auxv.end(); }
+
+ iterator
+ FindEntry(EntryType type) const;
+
+ static const char *
+ GetEntryName(const Entry &entry) {
+ return GetEntryName(static_cast<EntryType>(entry.type));
+ }
+
+ static const char *
+ GetEntryName(EntryType type);
+
+ void
+ DumpToLog(lldb_private::Log *log) const;
+
+private:
+ lldb_private::Process *m_process;
+ EntryVector m_auxv;
+
+ lldb::DataBufferSP
+ GetAuxvData();
+
+ void
+ ParseAuxv(lldb_private::DataExtractor &data);
+};
+
+#endif
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
new file mode 100644
index 000000000000..3e1b52938f49
--- /dev/null
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
@@ -0,0 +1,336 @@
+//===-- DYLDRendezvous.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+#include "DYLDRendezvous.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+/// Locates the address of the rendezvous structure. Returns the address on
+/// success and LLDB_INVALID_ADDRESS on failure.
+static addr_t
+ResolveRendezvousAddress(Process *process)
+{
+ addr_t info_location;
+ addr_t info_addr;
+ Error error;
+ size_t size;
+
+ info_location = process->GetImageInfoAddress();
+
+ if (info_location == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ info_addr = 0;
+ size = process->DoReadMemory(info_location, &info_addr,
+ process->GetAddressByteSize(), error);
+ if (size != process->GetAddressByteSize() || error.Fail())
+ return LLDB_INVALID_ADDRESS;
+
+ if (info_addr == 0)
+ return LLDB_INVALID_ADDRESS;
+
+ return info_addr;
+}
+
+DYLDRendezvous::DYLDRendezvous(Process *process)
+ : m_process(process),
+ m_rendezvous_addr(LLDB_INVALID_ADDRESS),
+ m_current(),
+ m_previous(),
+ m_soentries(),
+ m_added_soentries(),
+ m_removed_soentries()
+{
+ // Cache a copy of the executable path
+ if (m_process)
+ {
+ Module *exe_mod = m_process->GetTarget().GetExecutableModulePointer();
+ if (exe_mod)
+ exe_mod->GetFileSpec().GetPath(m_exe_path, PATH_MAX);
+ }
+}
+
+bool
+DYLDRendezvous::Resolve()
+{
+ const size_t word_size = 4;
+ Rendezvous info;
+ size_t address_size;
+ size_t padding;
+ addr_t info_addr;
+ addr_t cursor;
+
+ address_size = m_process->GetAddressByteSize();
+ padding = address_size - word_size;
+
+ if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
+ cursor = info_addr = ResolveRendezvousAddress(m_process);
+ else
+ cursor = info_addr = m_rendezvous_addr;
+
+ if (cursor == LLDB_INVALID_ADDRESS)
+ return false;
+
+ if (!(cursor = ReadMemory(cursor, &info.version, word_size)))
+ return false;
+
+ if (!(cursor = ReadMemory(cursor + padding, &info.map_addr, address_size)))
+ return false;
+
+ if (!(cursor = ReadMemory(cursor, &info.brk, address_size)))
+ return false;
+
+ if (!(cursor = ReadMemory(cursor, &info.state, word_size)))
+ return false;
+
+ if (!(cursor = ReadMemory(cursor + padding, &info.ldbase, address_size)))
+ return false;
+
+ // The rendezvous was successfully read. Update our internal state.
+ m_rendezvous_addr = info_addr;
+ m_previous = m_current;
+ m_current = info;
+
+ return UpdateSOEntries();
+}
+
+bool
+DYLDRendezvous::IsValid()
+{
+ return m_rendezvous_addr != LLDB_INVALID_ADDRESS;
+}
+
+bool
+DYLDRendezvous::UpdateSOEntries()
+{
+ SOEntry entry;
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ // When the previous and current states are consistent this is the first
+ // time we have been asked to update. Just take a snapshot of the currently
+ // loaded modules.
+ if (m_previous.state == eConsistent && m_current.state == eConsistent)
+ return TakeSnapshot(m_soentries);
+
+ // If we are about to add or remove a shared object clear out the current
+ // state and take a snapshot of the currently loaded images.
+ if (m_current.state == eAdd || m_current.state == eDelete)
+ {
+ assert(m_previous.state == eConsistent);
+ m_soentries.clear();
+ m_added_soentries.clear();
+ m_removed_soentries.clear();
+ return TakeSnapshot(m_soentries);
+ }
+ assert(m_current.state == eConsistent);
+
+ // Otherwise check the previous state to determine what to expect and update
+ // accordingly.
+ if (m_previous.state == eAdd)
+ return UpdateSOEntriesForAddition();
+ else if (m_previous.state == eDelete)
+ return UpdateSOEntriesForDeletion();
+
+ return false;
+}
+
+bool
+DYLDRendezvous::UpdateSOEntriesForAddition()
+{
+ SOEntry entry;
+ iterator pos;
+
+ assert(m_previous.state == eAdd);
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next)
+ {
+ if (!ReadSOEntryFromMemory(cursor, entry))
+ return false;
+
+ // Only add shared libraries and not the executable.
+ // On Linux this is indicated by an empty path in the entry.
+ // On FreeBSD it is the name of the executable.
+ if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
+ continue;
+
+ pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
+ if (pos == m_soentries.end())
+ {
+ m_soentries.push_back(entry);
+ m_added_soentries.push_back(entry);
+ }
+ }
+
+ return true;
+}
+
+bool
+DYLDRendezvous::UpdateSOEntriesForDeletion()
+{
+ SOEntryList entry_list;
+ iterator pos;
+
+ assert(m_previous.state == eDelete);
+
+ if (!TakeSnapshot(entry_list))
+ return false;
+
+ for (iterator I = begin(); I != end(); ++I)
+ {
+ pos = std::find(entry_list.begin(), entry_list.end(), *I);
+ if (pos == entry_list.end())
+ m_removed_soentries.push_back(*I);
+ }
+
+ m_soentries = entry_list;
+ return true;
+}
+
+bool
+DYLDRendezvous::TakeSnapshot(SOEntryList &entry_list)
+{
+ SOEntry entry;
+
+ if (m_current.map_addr == 0)
+ return false;
+
+ for (addr_t cursor = m_current.map_addr; cursor != 0; cursor = entry.next)
+ {
+ if (!ReadSOEntryFromMemory(cursor, entry))
+ return false;
+
+ // Only add shared libraries and not the executable.
+ // On Linux this is indicated by an empty path in the entry.
+ // On FreeBSD it is the name of the executable.
+ if (entry.path.empty() || ::strcmp(entry.path.c_str(), m_exe_path) == 0)
+ continue;
+
+ entry_list.push_back(entry);
+ }
+
+ return true;
+}
+
+addr_t
+DYLDRendezvous::ReadMemory(addr_t addr, void *dst, size_t size)
+{
+ size_t bytes_read;
+ Error error;
+
+ bytes_read = m_process->DoReadMemory(addr, dst, size, error);
+ if (bytes_read != size || error.Fail())
+ return 0;
+
+ return addr + bytes_read;
+}
+
+std::string
+DYLDRendezvous::ReadStringFromMemory(addr_t addr)
+{
+ std::string str;
+ Error error;
+ size_t size;
+ char c;
+
+ if (addr == LLDB_INVALID_ADDRESS)
+ return std::string();
+
+ for (;;) {
+ size = m_process->DoReadMemory(addr, &c, 1, error);
+ if (size != 1 || error.Fail())
+ return std::string();
+ if (c == 0)
+ break;
+ else {
+ str.push_back(c);
+ addr++;
+ }
+ }
+
+ return str;
+}
+
+bool
+DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry)
+{
+ size_t address_size = m_process->GetAddressByteSize();
+
+ entry.clear();
+
+ if (!(addr = ReadMemory(addr, &entry.base_addr, address_size)))
+ return false;
+
+ if (!(addr = ReadMemory(addr, &entry.path_addr, address_size)))
+ return false;
+
+ if (!(addr = ReadMemory(addr, &entry.dyn_addr, address_size)))
+ return false;
+
+ if (!(addr = ReadMemory(addr, &entry.next, address_size)))
+ return false;
+
+ if (!(addr = ReadMemory(addr, &entry.prev, address_size)))
+ return false;
+
+ entry.path = ReadStringFromMemory(entry.path_addr);
+
+ return true;
+}
+
+void
+DYLDRendezvous::DumpToLog(Log *log) const
+{
+ int state = GetState();
+
+ if (!log)
+ return;
+
+ log->PutCString("DYLDRendezvous:");
+ log->Printf(" Address: %" PRIx64, GetRendezvousAddress());
+ log->Printf(" Version: %" PRIu64, GetVersion());
+ log->Printf(" Link : %" PRIx64, GetLinkMapAddress());
+ log->Printf(" Break : %" PRIx64, GetBreakAddress());
+ log->Printf(" LDBase : %" PRIx64, GetLDBase());
+ log->Printf(" State : %s",
+ (state == eConsistent) ? "consistent" :
+ (state == eAdd) ? "add" :
+ (state == eDelete) ? "delete" : "unknown");
+
+ iterator I = begin();
+ iterator E = end();
+
+ if (I != E)
+ log->PutCString("DYLDRendezvous SOEntries:");
+
+ for (int i = 1; I != E; ++I, ++i)
+ {
+ log->Printf("\n SOEntry [%d] %s", i, I->path.c_str());
+ log->Printf(" Base : %" PRIx64, I->base_addr);
+ log->Printf(" Path : %" PRIx64, I->path_addr);
+ log->Printf(" Dyn : %" PRIx64, I->dyn_addr);
+ log->Printf(" Next : %" PRIx64, I->next);
+ log->Printf(" Prev : %" PRIx64, I->prev);
+ }
+}
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h
new file mode 100644
index 000000000000..67e7228a38de
--- /dev/null
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h
@@ -0,0 +1,230 @@
+//===-- DYLDRendezvous.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_Rendezvous_H_
+#define liblldb_Rendezvous_H_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <string>
+
+// Other libraries and framework includes
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+class Process;
+}
+
+/// @class DYLDRendezvous
+/// @brief Interface to the runtime linker.
+///
+/// A structure is present in a processes memory space which is updated by the
+/// runtime liker each time a module is loaded or unloaded. This class provides
+/// an interface to this structure and maintains a consistent snapshot of the
+/// currently loaded modules.
+class DYLDRendezvous {
+
+ // This structure is used to hold the contents of the debug rendezvous
+ // information (struct r_debug) as found in the inferiors memory. Note that
+ // the layout of this struct is not binary compatible, it is simply large
+ // enough to hold the information on both 32 and 64 bit platforms.
+ struct Rendezvous {
+ uint64_t version;
+ lldb::addr_t map_addr;
+ lldb::addr_t brk;
+ uint64_t state;
+ lldb::addr_t ldbase;
+
+ Rendezvous()
+ : version(0), map_addr(0), brk(0), state(0), ldbase(0) { }
+ };
+
+public:
+ DYLDRendezvous(lldb_private::Process *process);
+
+ /// Update the internal snapshot of runtime linker rendezvous and recompute
+ /// the currently loaded modules.
+ ///
+ /// This method should be called once one start up, then once each time the
+ /// runtime linker enters the function given by GetBreakAddress().
+ ///
+ /// @returns true on success and false on failure.
+ ///
+ /// @see GetBreakAddress().
+ bool
+ Resolve();
+
+ /// @returns true if this rendezvous has been located in the inferiors
+ /// address space and false otherwise.
+ bool
+ IsValid();
+
+ /// @returns the address of the rendezvous structure in the inferiors
+ /// address space.
+ lldb::addr_t
+ GetRendezvousAddress() const { return m_rendezvous_addr; }
+
+ /// @returns the version of the rendezvous protocol being used.
+ uint64_t
+ GetVersion() const { return m_current.version; }
+
+ /// @returns address in the inferiors address space containing the linked
+ /// list of shared object descriptors.
+ lldb::addr_t
+ GetLinkMapAddress() const { return m_current.map_addr; }
+
+ /// A breakpoint should be set at this address and Resolve called on each
+ /// hit.
+ ///
+ /// @returns the address of a function called by the runtime linker each
+ /// time a module is loaded/unloaded, or about to be loaded/unloaded.
+ ///
+ /// @see Resolve()
+ lldb::addr_t
+ GetBreakAddress() const { return m_current.brk; }
+
+ /// Returns the current state of the rendezvous structure.
+ uint64_t
+ GetState() const { return m_current.state; }
+
+ /// @returns the base address of the runtime linker in the inferiors address
+ /// space.
+ lldb::addr_t
+ GetLDBase() const { return m_current.ldbase; }
+
+ /// @returns true if modules have been loaded into the inferior since the
+ /// last call to Resolve().
+ bool
+ ModulesDidLoad() const { return !m_added_soentries.empty(); }
+
+ /// @returns true if modules have been unloaded from the inferior since the
+ /// last call to Resolve().
+ bool
+ ModulesDidUnload() const { return !m_removed_soentries.empty(); }
+
+ void
+ DumpToLog(lldb_private::Log *log) const;
+
+ /// @brief Constants describing the state of the rendezvous.
+ ///
+ /// @see GetState().
+ enum RendezvousState {
+ eConsistent,
+ eAdd,
+ eDelete
+ };
+
+ /// @brief Structure representing the shared objects currently loaded into
+ /// the inferior process.
+ ///
+ /// This object is a rough analogue to the struct link_map object which
+ /// actually lives in the inferiors memory.
+ struct SOEntry {
+ lldb::addr_t base_addr; ///< Base address of the loaded object.
+ lldb::addr_t path_addr; ///< String naming the shared object.
+ lldb::addr_t dyn_addr; ///< Dynamic section of shared object.
+ lldb::addr_t next; ///< Address of next so_entry.
+ lldb::addr_t prev; ///< Address of previous so_entry.
+ std::string path; ///< File name of shared object.
+
+ SOEntry() { clear(); }
+
+ bool operator ==(const SOEntry &entry) {
+ return this->path == entry.path;
+ }
+
+ void clear() {
+ base_addr = 0;
+ path_addr = 0;
+ dyn_addr = 0;
+ next = 0;
+ prev = 0;
+ path.clear();
+ }
+ };
+
+protected:
+ typedef std::list<SOEntry> SOEntryList;
+
+public:
+ typedef SOEntryList::const_iterator iterator;
+
+ /// Iterators over all currently loaded modules.
+ iterator begin() const { return m_soentries.begin(); }
+ iterator end() const { return m_soentries.end(); }
+
+ /// Iterators over all modules loaded into the inferior since the last call
+ /// to Resolve().
+ iterator loaded_begin() const { return m_added_soentries.begin(); }
+ iterator loaded_end() const { return m_added_soentries.end(); }
+
+ /// Iterators over all modules unloaded from the inferior since the last
+ /// call to Resolve().
+ iterator unloaded_begin() const { return m_removed_soentries.begin(); }
+ iterator unloaded_end() const { return m_removed_soentries.end(); }
+
+protected:
+ lldb_private::Process *m_process;
+
+ // Cached copy of executable pathname
+ char m_exe_path[PATH_MAX];
+
+ /// Location of the r_debug structure in the inferiors address space.
+ lldb::addr_t m_rendezvous_addr;
+
+ /// Current and previous snapshots of the rendezvous structure.
+ Rendezvous m_current;
+ Rendezvous m_previous;
+
+ /// List of SOEntry objects corresponding to the current link map state.
+ SOEntryList m_soentries;
+
+ /// List of SOEntry's added to the link map since the last call to Resolve().
+ SOEntryList m_added_soentries;
+
+ /// List of SOEntry's removed from the link map since the last call to
+ /// Resolve().
+ SOEntryList m_removed_soentries;
+
+ /// Reads @p size bytes from the inferiors address space starting at @p
+ /// addr.
+ ///
+ /// @returns addr + size if the read was successful and false otherwise.
+ lldb::addr_t
+ ReadMemory(lldb::addr_t addr, void *dst, size_t size);
+
+ /// Reads a null-terminated C string from the memory location starting at @p
+ /// addr.
+ std::string
+ ReadStringFromMemory(lldb::addr_t addr);
+
+ /// Reads an SOEntry starting at @p addr.
+ bool
+ ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry);
+
+ /// Updates the current set of SOEntries, the set of added entries, and the
+ /// set of removed entries.
+ bool
+ UpdateSOEntries();
+
+ bool
+ UpdateSOEntriesForAddition();
+
+ bool
+ UpdateSOEntriesForDeletion();
+
+ /// Reads the current list of shared objects according to the link map
+ /// supplied by the runtime linker.
+ bool
+ TakeSnapshot(SOEntryList &entry_list);
+};
+
+#endif
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
new file mode 100644
index 000000000000..91c7cd3dfca7
--- /dev/null
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -0,0 +1,481 @@
+//===-- DynamicLoaderPOSIX.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlanRunToAddress.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+
+#include "AuxVector.h"
+#include "DynamicLoaderPOSIXDYLD.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+DynamicLoaderPOSIXDYLD::Initialize()
+{
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+DynamicLoaderPOSIXDYLD::Terminate()
+{
+}
+
+lldb_private::ConstString
+DynamicLoaderPOSIXDYLD::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+lldb_private::ConstString
+DynamicLoaderPOSIXDYLD::GetPluginNameStatic()
+{
+ static ConstString g_name("linux-dyld");
+ return g_name;
+}
+
+const char *
+DynamicLoaderPOSIXDYLD::GetPluginDescriptionStatic()
+{
+ return "Dynamic loader plug-in that watches for shared library "
+ "loads/unloads in POSIX processes.";
+}
+
+void
+DynamicLoaderPOSIXDYLD::GetPluginCommandHelp(const char *command, Stream *strm)
+{
+}
+
+uint32_t
+DynamicLoaderPOSIXDYLD::GetPluginVersion()
+{
+ return 1;
+}
+
+DynamicLoader *
+DynamicLoaderPOSIXDYLD::CreateInstance(Process *process, bool force)
+{
+ bool create = force;
+ if (!create)
+ {
+ const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple();
+ if (triple_ref.getOS() == llvm::Triple::Linux ||
+ triple_ref.getOS() == llvm::Triple::FreeBSD)
+ create = true;
+ }
+
+ if (create)
+ return new DynamicLoaderPOSIXDYLD (process);
+ return NULL;
+}
+
+DynamicLoaderPOSIXDYLD::DynamicLoaderPOSIXDYLD(Process *process)
+ : DynamicLoader(process),
+ m_rendezvous(process),
+ m_load_offset(LLDB_INVALID_ADDRESS),
+ m_entry_point(LLDB_INVALID_ADDRESS),
+ m_auxv(),
+ m_dyld_bid(LLDB_INVALID_BREAK_ID)
+{
+}
+
+DynamicLoaderPOSIXDYLD::~DynamicLoaderPOSIXDYLD()
+{
+ if (m_dyld_bid != LLDB_INVALID_BREAK_ID)
+ {
+ m_process->GetTarget().RemoveBreakpointByID (m_dyld_bid);
+ m_dyld_bid = LLDB_INVALID_BREAK_ID;
+ }
+}
+
+void
+DynamicLoaderPOSIXDYLD::DidAttach()
+{
+ ModuleSP executable;
+ addr_t load_offset;
+
+ m_auxv.reset(new AuxVector(m_process));
+
+ executable = GetTargetExecutable();
+ load_offset = ComputeLoadOffset();
+
+ if (executable.get() && load_offset != LLDB_INVALID_ADDRESS)
+ {
+ ModuleList module_list;
+ module_list.Append(executable);
+ UpdateLoadedSections(executable, load_offset);
+ LoadAllCurrentModules();
+ m_process->GetTarget().ModulesDidLoad(module_list);
+ }
+}
+
+void
+DynamicLoaderPOSIXDYLD::DidLaunch()
+{
+ ModuleSP executable;
+ addr_t load_offset;
+
+ m_auxv.reset(new AuxVector(m_process));
+
+ executable = GetTargetExecutable();
+ load_offset = ComputeLoadOffset();
+
+ if (executable.get() && load_offset != LLDB_INVALID_ADDRESS)
+ {
+ ModuleList module_list;
+ module_list.Append(executable);
+ UpdateLoadedSections(executable, load_offset);
+ ProbeEntry();
+ m_process->GetTarget().ModulesDidLoad(module_list);
+ }
+}
+
+ModuleSP
+DynamicLoaderPOSIXDYLD::GetTargetExecutable()
+{
+ Target &target = m_process->GetTarget();
+ ModuleSP executable = target.GetExecutableModule();
+
+ if (executable.get())
+ {
+ if (executable->GetFileSpec().Exists())
+ {
+ ModuleSpec module_spec (executable->GetFileSpec(), executable->GetArchitecture());
+ ModuleSP module_sp (new Module (module_spec));
+
+ // Check if the executable has changed and set it to the target executable if they differ.
+ if (module_sp.get() && module_sp->GetUUID().IsValid() && executable->GetUUID().IsValid())
+ {
+ if (module_sp->GetUUID() != executable->GetUUID())
+ executable.reset();
+ }
+ else if (executable->FileHasChanged())
+ {
+ executable.reset();
+ }
+
+ if (!executable.get())
+ {
+ executable = target.GetSharedModule(module_spec);
+ if (executable.get() != target.GetExecutableModulePointer())
+ {
+ // Don't load dependent images since we are in dyld where we will know
+ // and find out about all images that are loaded
+ const bool get_dependent_images = false;
+ target.SetExecutableModule(executable, get_dependent_images);
+ }
+ }
+ }
+ }
+ return executable;
+}
+
+Error
+DynamicLoaderPOSIXDYLD::ExecutePluginCommand(Args &command, Stream *strm)
+{
+ return Error();
+}
+
+Log *
+DynamicLoaderPOSIXDYLD::EnablePluginLogging(Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+Error
+DynamicLoaderPOSIXDYLD::CanLoadImage()
+{
+ return Error();
+}
+
+void
+DynamicLoaderPOSIXDYLD::UpdateLoadedSections(ModuleSP module, addr_t base_addr)
+{
+ ObjectFile *obj_file = module->GetObjectFile();
+ SectionList *sections = obj_file->GetSectionList();
+ SectionLoadList &load_list = m_process->GetTarget().GetSectionLoadList();
+ const size_t num_sections = sections->GetSize();
+
+ for (unsigned i = 0; i < num_sections; ++i)
+ {
+ SectionSP section_sp (sections->GetSectionAtIndex(i));
+ lldb::addr_t new_load_addr = section_sp->GetFileAddress() + base_addr;
+ lldb::addr_t old_load_addr = load_list.GetSectionLoadAddress(section_sp);
+
+ // If the file address of the section is zero then this is not an
+ // allocatable/loadable section (property of ELF sh_addr). Skip it.
+ if (new_load_addr == base_addr)
+ continue;
+
+ if (old_load_addr == LLDB_INVALID_ADDRESS ||
+ old_load_addr != new_load_addr)
+ load_list.SetSectionLoadAddress(section_sp, new_load_addr);
+ }
+}
+
+void
+DynamicLoaderPOSIXDYLD::ProbeEntry()
+{
+ Breakpoint *entry_break;
+ addr_t entry;
+
+ if ((entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS)
+ return;
+
+ entry_break = m_process->GetTarget().CreateBreakpoint(entry, true).get();
+ entry_break->SetCallback(EntryBreakpointHit, this, true);
+ entry_break->SetBreakpointKind("shared-library-event");
+}
+
+// The runtime linker has run and initialized the rendezvous structure once the
+// process has hit its entry point. When we hit the corresponding breakpoint we
+// interrogate the rendezvous structure to get the load addresses of all
+// dependent modules for the process. Similarly, we can discover the runtime
+// linker function and setup a breakpoint to notify us of any dynamically loaded
+// modules (via dlopen).
+bool
+DynamicLoaderPOSIXDYLD::EntryBreakpointHit(void *baton,
+ StoppointCallbackContext *context,
+ user_id_t break_id,
+ user_id_t break_loc_id)
+{
+ DynamicLoaderPOSIXDYLD* dyld_instance;
+
+ dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton);
+ dyld_instance->LoadAllCurrentModules();
+ dyld_instance->SetRendezvousBreakpoint();
+ return false; // Continue running.
+}
+
+void
+DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint()
+{
+ addr_t break_addr = m_rendezvous.GetBreakAddress();
+ Target &target = m_process->GetTarget();
+
+ if (m_dyld_bid == LLDB_INVALID_BREAK_ID)
+ {
+ Breakpoint *dyld_break = target.CreateBreakpoint (break_addr, true).get();
+ dyld_break->SetCallback(RendezvousBreakpointHit, this, true);
+ dyld_break->SetBreakpointKind ("shared-library-event");
+ m_dyld_bid = dyld_break->GetID();
+ }
+
+ // Make sure our breakpoint is at the right address.
+ assert (target.GetBreakpointByID(m_dyld_bid)->FindLocationByAddress(break_addr)->GetBreakpoint().GetID() == m_dyld_bid);
+}
+
+bool
+DynamicLoaderPOSIXDYLD::RendezvousBreakpointHit(void *baton,
+ StoppointCallbackContext *context,
+ user_id_t break_id,
+ user_id_t break_loc_id)
+{
+ DynamicLoaderPOSIXDYLD* dyld_instance;
+
+ dyld_instance = static_cast<DynamicLoaderPOSIXDYLD*>(baton);
+ dyld_instance->RefreshModules();
+
+ // Return true to stop the target, false to just let the target run.
+ return dyld_instance->GetStopWhenImagesChange();
+}
+
+void
+DynamicLoaderPOSIXDYLD::RefreshModules()
+{
+ if (!m_rendezvous.Resolve())
+ return;
+
+ DYLDRendezvous::iterator I;
+ DYLDRendezvous::iterator E;
+
+ ModuleList &loaded_modules = m_process->GetTarget().GetImages();
+
+ if (m_rendezvous.ModulesDidLoad())
+ {
+ ModuleList new_modules;
+
+ E = m_rendezvous.loaded_end();
+ for (I = m_rendezvous.loaded_begin(); I != E; ++I)
+ {
+ FileSpec file(I->path.c_str(), true);
+ ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr);
+ if (module_sp.get())
+ loaded_modules.AppendIfNeeded(module_sp);
+ }
+ }
+
+ if (m_rendezvous.ModulesDidUnload())
+ {
+ ModuleList old_modules;
+
+ E = m_rendezvous.unloaded_end();
+ for (I = m_rendezvous.unloaded_begin(); I != E; ++I)
+ {
+ FileSpec file(I->path.c_str(), true);
+ ModuleSpec module_spec (file);
+ ModuleSP module_sp =
+ loaded_modules.FindFirstModule (module_spec);
+ if (module_sp.get())
+ old_modules.Append(module_sp);
+ }
+ loaded_modules.Remove(old_modules);
+ }
+}
+
+ThreadPlanSP
+DynamicLoaderPOSIXDYLD::GetStepThroughTrampolinePlan(Thread &thread, bool stop)
+{
+ ThreadPlanSP thread_plan_sp;
+
+ StackFrame *frame = thread.GetStackFrameAtIndex(0).get();
+ const SymbolContext &context = frame->GetSymbolContext(eSymbolContextSymbol);
+ Symbol *sym = context.symbol;
+
+ if (sym == NULL || !sym->IsTrampoline())
+ return thread_plan_sp;
+
+ const ConstString &sym_name = sym->GetMangled().GetName(Mangled::ePreferMangled);
+ if (!sym_name)
+ return thread_plan_sp;
+
+ SymbolContextList target_symbols;
+ Target &target = thread.GetProcess()->GetTarget();
+ const ModuleList &images = target.GetImages();
+
+ images.FindSymbolsWithNameAndType(sym_name, eSymbolTypeCode, target_symbols);
+ size_t num_targets = target_symbols.GetSize();
+ if (!num_targets)
+ return thread_plan_sp;
+
+ typedef std::vector<lldb::addr_t> AddressVector;
+ AddressVector addrs;
+ for (size_t i = 0; i < num_targets; ++i)
+ {
+ SymbolContext context;
+ AddressRange range;
+ if (target_symbols.GetContextAtIndex(i, context))
+ {
+ context.GetAddressRange(eSymbolContextEverything, 0, false, range);
+ lldb::addr_t addr = range.GetBaseAddress().GetLoadAddress(&target);
+ if (addr != LLDB_INVALID_ADDRESS)
+ addrs.push_back(addr);
+ }
+ }
+
+ if (addrs.size() > 0)
+ {
+ AddressVector::iterator start = addrs.begin();
+ AddressVector::iterator end = addrs.end();
+
+ std::sort(start, end);
+ addrs.erase(std::unique(start, end), end);
+ thread_plan_sp.reset(new ThreadPlanRunToAddress(thread, addrs, stop));
+ }
+
+ return thread_plan_sp;
+}
+
+void
+DynamicLoaderPOSIXDYLD::LoadAllCurrentModules()
+{
+ DYLDRendezvous::iterator I;
+ DYLDRendezvous::iterator E;
+ ModuleList module_list;
+
+ if (!m_rendezvous.Resolve())
+ return;
+
+ for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I)
+ {
+ FileSpec file(I->path.c_str(), false);
+ ModuleSP module_sp = LoadModuleAtAddress(file, I->base_addr);
+ if (module_sp.get())
+ module_list.Append(module_sp);
+ }
+
+ m_process->GetTarget().ModulesDidLoad(module_list);
+}
+
+ModuleSP
+DynamicLoaderPOSIXDYLD::LoadModuleAtAddress(const FileSpec &file, addr_t base_addr)
+{
+ Target &target = m_process->GetTarget();
+ ModuleList &modules = target.GetImages();
+ ModuleSP module_sp;
+
+ ModuleSpec module_spec (file, target.GetArchitecture());
+ if ((module_sp = modules.FindFirstModule (module_spec)))
+ {
+ UpdateLoadedSections(module_sp, base_addr);
+ }
+ else if ((module_sp = target.GetSharedModule(module_spec)))
+ {
+ UpdateLoadedSections(module_sp, base_addr);
+ }
+
+ return module_sp;
+}
+
+addr_t
+DynamicLoaderPOSIXDYLD::ComputeLoadOffset()
+{
+ addr_t virt_entry;
+
+ if (m_load_offset != LLDB_INVALID_ADDRESS)
+ return m_load_offset;
+
+ if ((virt_entry = GetEntryPoint()) == LLDB_INVALID_ADDRESS)
+ return LLDB_INVALID_ADDRESS;
+
+ ModuleSP module = m_process->GetTarget().GetExecutableModule();
+ if (!module)
+ return LLDB_INVALID_ADDRESS;
+
+ ObjectFile *exe = module->GetObjectFile();
+ Address file_entry = exe->GetEntryPointAddress();
+
+ if (!file_entry.IsValid())
+ return LLDB_INVALID_ADDRESS;
+
+ m_load_offset = virt_entry - file_entry.GetFileAddress();
+ return m_load_offset;
+}
+
+addr_t
+DynamicLoaderPOSIXDYLD::GetEntryPoint()
+{
+ if (m_entry_point != LLDB_INVALID_ADDRESS)
+ return m_entry_point;
+
+ if (m_auxv.get() == NULL)
+ return LLDB_INVALID_ADDRESS;
+
+ AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AT_ENTRY);
+
+ if (I == m_auxv->end())
+ return LLDB_INVALID_ADDRESS;
+
+ m_entry_point = static_cast<addr_t>(I->value);
+ return m_entry_point;
+}
diff --git a/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
new file mode 100644
index 000000000000..0476e45d0465
--- /dev/null
+++ b/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
@@ -0,0 +1,170 @@
+//===-- DynamicLoaderPOSIX.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_DynamicLoaderPOSIX_H_
+#define liblldb_DynamicLoaderPOSIX_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Breakpoint/StoppointCallbackContext.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "DYLDRendezvous.h"
+
+class AuxVector;
+
+class DynamicLoaderPOSIXDYLD : public lldb_private::DynamicLoader
+{
+public:
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::DynamicLoader *
+ CreateInstance(lldb_private::Process *process, bool force);
+
+ DynamicLoaderPOSIXDYLD(lldb_private::Process *process);
+
+ virtual
+ ~DynamicLoaderPOSIXDYLD();
+
+ //------------------------------------------------------------------
+ // DynamicLoader protocol
+ //------------------------------------------------------------------
+
+ virtual void
+ DidAttach();
+
+ virtual void
+ DidLaunch();
+
+ virtual lldb::ThreadPlanSP
+ GetStepThroughTrampolinePlan(lldb_private::Thread &thread,
+ bool stop_others);
+
+ virtual lldb_private::Error
+ CanLoadImage();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp(const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand(lldb_private::Args &command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging(lldb_private::Stream *strm, lldb_private::Args &command);
+
+protected:
+ /// Runtime linker rendezvous structure.
+ DYLDRendezvous m_rendezvous;
+
+ /// Virtual load address of the inferior process.
+ lldb::addr_t m_load_offset;
+
+ /// Virtual entry address of the inferior process.
+ lldb::addr_t m_entry_point;
+
+ /// Auxiliary vector of the inferior process.
+ std::unique_ptr<AuxVector> m_auxv;
+
+ /// Rendezvous breakpoint.
+ lldb::break_id_t m_dyld_bid;
+
+ /// Enables a breakpoint on a function called by the runtime
+ /// linker each time a module is loaded or unloaded.
+ void
+ SetRendezvousBreakpoint();
+
+ /// Callback routine which updates the current list of loaded modules based
+ /// on the information supplied by the runtime linker.
+ static bool
+ RendezvousBreakpointHit(void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ /// Helper method for RendezvousBreakpointHit. Updates LLDB's current set
+ /// of loaded modules.
+ void
+ RefreshModules();
+
+ /// Updates the load address of every allocatable section in @p module.
+ ///
+ /// @param module The module to traverse.
+ ///
+ /// @param base_addr The virtual base address @p module is loaded at.
+ void
+ UpdateLoadedSections(lldb::ModuleSP module,
+ lldb::addr_t base_addr = 0);
+
+ /// Locates or creates a module given by @p file and updates/loads the
+ /// resulting module at the virtual base address @p base_addr.
+ lldb::ModuleSP
+ LoadModuleAtAddress(const lldb_private::FileSpec &file, lldb::addr_t base_addr);
+
+ /// Resolves the entry point for the current inferior process and sets a
+ /// breakpoint at that address.
+ void
+ ProbeEntry();
+
+ /// Callback routine invoked when we hit the breakpoint on process entry.
+ ///
+ /// This routine is responsible for resolving the load addresses of all
+ /// dependent modules required by the inferior and setting up the rendezvous
+ /// breakpoint.
+ static bool
+ EntryBreakpointHit(void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ /// Helper for the entry breakpoint callback. Resolves the load addresses
+ /// of all dependent modules.
+ void
+ LoadAllCurrentModules();
+
+ /// Computes a value for m_load_offset returning the computed address on
+ /// success and LLDB_INVALID_ADDRESS on failure.
+ lldb::addr_t
+ ComputeLoadOffset();
+
+ /// Computes a value for m_entry_point returning the computed address on
+ /// success and LLDB_INVALID_ADDRESS on failure.
+ lldb::addr_t
+ GetEntryPoint();
+
+ /// Checks to see if the target module has changed, updates the target
+ /// accordingly and returns the target executable module.
+ lldb::ModuleSP
+ GetTargetExecutable();
+
+private:
+ DISALLOW_COPY_AND_ASSIGN(DynamicLoaderPOSIXDYLD);
+};
+
+#endif // liblldb_DynamicLoaderPOSIXDYLD_H_
diff --git a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp
new file mode 100644
index 000000000000..274ba328ad1f
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.cpp
@@ -0,0 +1,209 @@
+//===-- DynamicLoaderStatic.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/Target.h"
+
+#include "DynamicLoaderStatic.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Create an instance of this class. This function is filled into
+// the plugin info class that gets handed out by the plugin factory and
+// allows the lldb to instantiate an instance of this class.
+//----------------------------------------------------------------------
+DynamicLoader *
+DynamicLoaderStatic::CreateInstance (Process* process, bool force)
+{
+ bool create = force;
+ if (!create)
+ {
+ const llvm::Triple &triple_ref = process->GetTarget().GetArchitecture().GetTriple();
+ const llvm::Triple::OSType os_type = triple_ref.getOS();
+ if ((os_type == llvm::Triple::UnknownOS))
+ create = true;
+ }
+
+ if (!create)
+ {
+ Module *exe_module = process->GetTarget().GetExecutableModulePointer();
+ if (exe_module)
+ {
+ ObjectFile *object_file = exe_module->GetObjectFile();
+ if (object_file)
+ {
+ create = (object_file->GetStrata() == ObjectFile::eStrataRawImage);
+ }
+ }
+ }
+
+ if (create)
+ return new DynamicLoaderStatic (process);
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+DynamicLoaderStatic::DynamicLoaderStatic (Process* process) :
+ DynamicLoader(process)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+DynamicLoaderStatic::~DynamicLoaderStatic()
+{
+}
+
+//------------------------------------------------------------------
+/// Called after attaching a process.
+///
+/// Allow DynamicLoader plug-ins to execute some code after
+/// attaching to a process.
+//------------------------------------------------------------------
+void
+DynamicLoaderStatic::DidAttach ()
+{
+ LoadAllImagesAtFileAddresses();
+}
+
+//------------------------------------------------------------------
+/// Called after attaching a process.
+///
+/// Allow DynamicLoader plug-ins to execute some code after
+/// attaching to a process.
+//------------------------------------------------------------------
+void
+DynamicLoaderStatic::DidLaunch ()
+{
+ LoadAllImagesAtFileAddresses();
+}
+
+void
+DynamicLoaderStatic::LoadAllImagesAtFileAddresses ()
+{
+ const ModuleList &module_list = m_process->GetTarget().GetImages();
+
+ ModuleList loaded_module_list;
+
+ // Disable JIT for static dynamic loader targets
+ m_process->SetCanJIT(false);
+
+ Mutex::Locker mutex_locker(module_list.GetMutex());
+
+ const size_t num_modules = module_list.GetSize();
+ for (uint32_t idx = 0; idx < num_modules; ++idx)
+ {
+ ModuleSP module_sp (module_list.GetModuleAtIndexUnlocked (idx));
+ if (module_sp)
+ {
+ bool changed = false;
+ ObjectFile *image_object_file = module_sp->GetObjectFile();
+ if (image_object_file)
+ {
+ SectionList *section_list = image_object_file->GetSectionList ();
+ if (section_list)
+ {
+ // All sections listed in the dyld image info structure will all
+ // either be fixed up already, or they will all be off by a single
+ // slide amount that is determined by finding the first segment
+ // that is at file offset zero which also has bytes (a file size
+ // that is greater than zero) in the object file.
+
+ // Determine the slide amount (if any)
+ const size_t num_sections = section_list->GetSize();
+ size_t sect_idx = 0;
+ for (sect_idx = 0; sect_idx < num_sections; ++sect_idx)
+ {
+ // Iterate through the object file sections to find the
+ // first section that starts of file offset zero and that
+ // has bytes in the file...
+ SectionSP section_sp (section_list->GetSectionAtIndex (sect_idx));
+ if (section_sp)
+ {
+ if (m_process->GetTarget().GetSectionLoadList().SetSectionLoadAddress (section_sp, section_sp->GetFileAddress()))
+ changed = true;
+ }
+ }
+ }
+ }
+
+ if (changed)
+ loaded_module_list.AppendIfNeeded (module_sp);
+ }
+ }
+
+ m_process->GetTarget().ModulesDidLoad (loaded_module_list);
+}
+
+ThreadPlanSP
+DynamicLoaderStatic::GetStepThroughTrampolinePlan (Thread &thread, bool stop_others)
+{
+ return ThreadPlanSP();
+}
+
+Error
+DynamicLoaderStatic::CanLoadImage ()
+{
+ Error error;
+ error.SetErrorString ("can't load images on with a static debug session");
+ return error;
+}
+
+void
+DynamicLoaderStatic::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+DynamicLoaderStatic::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+DynamicLoaderStatic::GetPluginNameStatic()
+{
+ static ConstString g_name("static");
+ return g_name;
+}
+
+const char *
+DynamicLoaderStatic::GetPluginDescriptionStatic()
+{
+ return "Dynamic loader plug-in that will load any images at the static addresses contained in each image.";
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+DynamicLoaderStatic::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+DynamicLoaderStatic::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h
new file mode 100644
index 000000000000..a99435fa32ad
--- /dev/null
+++ b/source/Plugins/DynamicLoader/Static/DynamicLoaderStatic.h
@@ -0,0 +1,88 @@
+//===-- DynamicLoaderStatic.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_DynamicLoaderStatic_h_
+#define liblldb_DynamicLoaderStatic_h_
+
+// C Includes
+// C++ Includes
+#include <map>
+#include <vector>
+#include <string>
+
+// Other libraries and framework includes
+#include "llvm/Support/MachO.h"
+
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/UUID.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Target/Process.h"
+
+class DynamicLoaderStatic : public lldb_private::DynamicLoader
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::DynamicLoader *
+ CreateInstance (lldb_private::Process *process, bool force);
+
+ DynamicLoaderStatic (lldb_private::Process *process);
+
+ virtual
+ ~DynamicLoaderStatic ();
+ //------------------------------------------------------------------
+ /// Called after attaching a process.
+ ///
+ /// Allow DynamicLoader plug-ins to execute some code after
+ /// attaching to a process.
+ //------------------------------------------------------------------
+ virtual void
+ DidAttach ();
+
+ virtual void
+ DidLaunch ();
+
+ virtual lldb::ThreadPlanSP
+ GetStepThroughTrampolinePlan (lldb_private::Thread &thread,
+ bool stop_others);
+
+ virtual lldb_private::Error
+ CanLoadImage ();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+private:
+ void
+ LoadAllImagesAtFileAddresses ();
+
+ DISALLOW_COPY_AND_ASSIGN (DynamicLoaderStatic);
+};
+
+#endif // liblldb_DynamicLoaderStatic_h_
diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
new file mode 100644
index 000000000000..2dd04dd8733d
--- /dev/null
+++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp
@@ -0,0 +1,13625 @@
+//===-- EmulateInstructionARM.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <stdlib.h>
+
+#include "EmulateInstructionARM.h"
+#include "EmulationStateARM.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Interpreter/OptionValueArray.h"
+#include "lldb/Interpreter/OptionValueDictionary.h"
+#include "lldb/Symbol/UnwindPlan.h"
+
+#include "Plugins/Process/Utility/ARMDefines.h"
+#include "Plugins/Process/Utility/ARMUtils.h"
+#include "Utility/ARM_DWARF_Registers.h"
+
+#include "llvm/Support/MathExtras.h" // for SignExtend32 template function
+ // and countTrailingZeros function
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Convenient macro definitions.
+#define APSR_C Bit32(m_opcode_cpsr, CPSR_C_POS)
+#define APSR_V Bit32(m_opcode_cpsr, CPSR_V_POS)
+
+#define AlignPC(pc_val) (pc_val & 0xFFFFFFFC)
+
+//----------------------------------------------------------------------
+//
+// ITSession implementation
+//
+//----------------------------------------------------------------------
+
+// A8.6.50
+// Valid return values are {1, 2, 3, 4}, with 0 signifying an error condition.
+static uint32_t
+CountITSize (uint32_t ITMask) {
+ // First count the trailing zeros of the IT mask.
+ uint32_t TZ = llvm::countTrailingZeros(ITMask);
+ if (TZ > 3)
+ {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ printf("Encoding error: IT Mask '0000'\n");
+#endif
+ return 0;
+ }
+ return (4 - TZ);
+}
+
+// Init ITState. Note that at least one bit is always 1 in mask.
+bool ITSession::InitIT(uint32_t bits7_0)
+{
+ ITCounter = CountITSize(Bits32(bits7_0, 3, 0));
+ if (ITCounter == 0)
+ return false;
+
+ // A8.6.50 IT
+ unsigned short FirstCond = Bits32(bits7_0, 7, 4);
+ if (FirstCond == 0xF)
+ {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ printf("Encoding error: IT FirstCond '1111'\n");
+#endif
+ return false;
+ }
+ if (FirstCond == 0xE && ITCounter != 1)
+ {
+#ifdef LLDB_CONFIGURATION_DEBUG
+ printf("Encoding error: IT FirstCond '1110' && Mask != '1000'\n");
+#endif
+ return false;
+ }
+
+ ITState = bits7_0;
+ return true;
+}
+
+// Update ITState if necessary.
+void ITSession::ITAdvance()
+{
+ //assert(ITCounter);
+ --ITCounter;
+ if (ITCounter == 0)
+ ITState = 0;
+ else
+ {
+ unsigned short NewITState4_0 = Bits32(ITState, 4, 0) << 1;
+ SetBits32(ITState, 4, 0, NewITState4_0);
+ }
+}
+
+// Return true if we're inside an IT Block.
+bool ITSession::InITBlock()
+{
+ return ITCounter != 0;
+}
+
+// Return true if we're the last instruction inside an IT Block.
+bool ITSession::LastInITBlock()
+{
+ return ITCounter == 1;
+}
+
+// Get condition bits for the current thumb instruction.
+uint32_t ITSession::GetCond()
+{
+ if (InITBlock())
+ return Bits32(ITState, 7, 4);
+ else
+ return COND_AL;
+}
+
+// ARM constants used during decoding
+#define REG_RD 0
+#define LDM_REGLIST 1
+#define SP_REG 13
+#define LR_REG 14
+#define PC_REG 15
+#define PC_REGLIST_BIT 0x8000
+
+#define ARMv4 (1u << 0)
+#define ARMv4T (1u << 1)
+#define ARMv5T (1u << 2)
+#define ARMv5TE (1u << 3)
+#define ARMv5TEJ (1u << 4)
+#define ARMv6 (1u << 5)
+#define ARMv6K (1u << 6)
+#define ARMv6T2 (1u << 7)
+#define ARMv7 (1u << 8)
+#define ARMv7S (1u << 9)
+#define ARMv8 (1u << 10)
+#define ARMvAll (0xffffffffu)
+
+#define ARMV4T_ABOVE (ARMv4T|ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv7S|ARMv8)
+#define ARMV5_ABOVE (ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv7S|ARMv8)
+#define ARMV5TE_ABOVE (ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv7S|ARMv8)
+#define ARMV5J_ABOVE (ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv7S|ARMv8)
+#define ARMV6_ABOVE (ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv7S|ARMv8)
+#define ARMV6T2_ABOVE (ARMv6T2|ARMv7|ARMv7S|ARMv8)
+#define ARMV7_ABOVE (ARMv7|ARMv7S|ARMv8)
+
+#define No_VFP 0
+#define VFPv1 (1u << 1)
+#define VFPv2 (1u << 2)
+#define VFPv3 (1u << 3)
+#define AdvancedSIMD (1u << 4)
+
+#define VFPv1_ABOVE (VFPv1 | VFPv2 | VFPv3 | AdvancedSIMD)
+#define VFPv2_ABOVE (VFPv2 | VFPv3 | AdvancedSIMD)
+#define VFPv2v3 (VFPv2 | VFPv3)
+
+//----------------------------------------------------------------------
+//
+// EmulateInstructionARM implementation
+//
+//----------------------------------------------------------------------
+
+void
+EmulateInstructionARM::Initialize ()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic (),
+ GetPluginDescriptionStatic (),
+ CreateInstance);
+}
+
+void
+EmulateInstructionARM::Terminate ()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+ConstString
+EmulateInstructionARM::GetPluginNameStatic ()
+{
+ static ConstString g_name("arm");
+ return g_name;
+}
+
+const char *
+EmulateInstructionARM::GetPluginDescriptionStatic ()
+{
+ return "Emulate instructions for the ARM architecture.";
+}
+
+EmulateInstruction *
+EmulateInstructionARM::CreateInstance (const ArchSpec &arch, InstructionType inst_type)
+{
+ if (EmulateInstructionARM::SupportsEmulatingIntructionsOfTypeStatic(inst_type))
+ {
+ if (arch.GetTriple().getArch() == llvm::Triple::arm)
+ {
+ std::unique_ptr<EmulateInstructionARM> emulate_insn_ap (new EmulateInstructionARM (arch));
+
+ if (emulate_insn_ap.get())
+ return emulate_insn_ap.release();
+ }
+ else if (arch.GetTriple().getArch() == llvm::Triple::thumb)
+ {
+ std::unique_ptr<EmulateInstructionARM> emulate_insn_ap (new EmulateInstructionARM (arch));
+
+ if (emulate_insn_ap.get())
+ return emulate_insn_ap.release();
+ }
+ }
+
+ return NULL;
+}
+
+bool
+EmulateInstructionARM::SetTargetTriple (const ArchSpec &arch)
+{
+ if (arch.GetTriple().getArch () == llvm::Triple::arm)
+ return true;
+ else if (arch.GetTriple().getArch () == llvm::Triple::thumb)
+ return true;
+
+ return false;
+}
+
+// Write "bits (32) UNKNOWN" to memory address "address". Helper function for many ARM instructions.
+bool
+EmulateInstructionARM::WriteBits32UnknownToMemory (addr_t address)
+{
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextWriteMemoryRandomBits;
+ context.SetNoArgs ();
+
+ uint32_t random_data = rand ();
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ if (!MemAWrite (context, address, random_data, addr_byte_size))
+ return false;
+
+ return true;
+}
+
+// Write "bits (32) UNKNOWN" to register n. Helper function for many ARM instructions.
+bool
+EmulateInstructionARM::WriteBits32Unknown (int n)
+{
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextWriteRegisterRandomBits;
+ context.SetNoArgs ();
+
+ bool success;
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data))
+ return false;
+
+ return true;
+}
+
+bool
+EmulateInstructionARM::GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num, RegisterInfo &reg_info)
+{
+ if (reg_kind == eRegisterKindGeneric)
+ {
+ switch (reg_num)
+ {
+ case LLDB_REGNUM_GENERIC_PC: reg_kind = eRegisterKindDWARF; reg_num = dwarf_pc; break;
+ case LLDB_REGNUM_GENERIC_SP: reg_kind = eRegisterKindDWARF; reg_num = dwarf_sp; break;
+ case LLDB_REGNUM_GENERIC_FP: reg_kind = eRegisterKindDWARF; reg_num = dwarf_r7; break;
+ case LLDB_REGNUM_GENERIC_RA: reg_kind = eRegisterKindDWARF; reg_num = dwarf_lr; break;
+ case LLDB_REGNUM_GENERIC_FLAGS: reg_kind = eRegisterKindDWARF; reg_num = dwarf_cpsr; break;
+ default: return false;
+ }
+ }
+
+ if (reg_kind == eRegisterKindDWARF)
+ return GetARMDWARFRegisterInfo(reg_num, reg_info);
+ return false;
+}
+
+uint32_t
+EmulateInstructionARM::GetFramePointerRegisterNumber () const
+{
+ if (m_opcode_mode == eModeThumb)
+ {
+ switch (m_arch.GetTriple().getOS())
+ {
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ case llvm::Triple::IOS:
+ return 7;
+ default:
+ break;
+ }
+ }
+ return 11;
+}
+
+uint32_t
+EmulateInstructionARM::GetFramePointerDWARFRegisterNumber () const
+{
+ if (m_opcode_mode == eModeThumb)
+ {
+ switch (m_arch.GetTriple().getOS())
+ {
+ case llvm::Triple::Darwin:
+ case llvm::Triple::MacOSX:
+ case llvm::Triple::IOS:
+ return dwarf_r7;
+ default:
+ break;
+ }
+ }
+ return dwarf_r11;
+}
+
+// Push Multiple Registers stores multiple registers to the stack, storing to
+// consecutive memory locations ending just below the address in SP, and updates
+// SP to point to the start of the stored data.
+bool
+EmulateInstructionARM::EmulatePUSH (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ NullCheckIfThumbEE(13);
+ address = SP - 4*BitCount(registers);
+
+ for (i = 0 to 14)
+ {
+ if (registers<i> == '1')
+ {
+ if i == 13 && i != LowestSetBit(registers) // Only possible for encoding A1
+ MemA[address,4] = bits(32) UNKNOWN;
+ else
+ MemA[address,4] = R[i];
+ address = address + 4;
+ }
+ }
+
+ if (registers<15> == '1') // Only possible for encoding A1 or A2
+ MemA[address,4] = PCStoreValue();
+
+ SP = SP - 4*BitCount(registers);
+ }
+#endif
+
+ bool conditional = false;
+ bool success = false;
+ if (ConditionPassed(opcode, &conditional))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ uint32_t registers = 0;
+ uint32_t Rt; // the source register
+ switch (encoding) {
+ case eEncodingT1:
+ registers = Bits32(opcode, 7, 0);
+ // The M bit represents LR.
+ if (Bit32(opcode, 8))
+ registers |= (1u << 14);
+ // if BitCount(registers) < 1 then UNPREDICTABLE;
+ if (BitCount(registers) < 1)
+ return false;
+ break;
+ case eEncodingT2:
+ // Ignore bits 15 & 13.
+ registers = Bits32(opcode, 15, 0) & ~0xa000;
+ // if BitCount(registers) < 2 then UNPREDICTABLE;
+ if (BitCount(registers) < 2)
+ return false;
+ break;
+ case eEncodingT3:
+ Rt = Bits32(opcode, 15, 12);
+ // if BadReg(t) then UNPREDICTABLE;
+ if (BadReg(Rt))
+ return false;
+ registers = (1u << Rt);
+ break;
+ case eEncodingA1:
+ registers = Bits32(opcode, 15, 0);
+ // Instead of return false, let's handle the following case as well,
+ // which amounts to pushing one reg onto the full descending stacks.
+ // if BitCount(register_list) < 2 then SEE STMDB / STMFD;
+ break;
+ case eEncodingA2:
+ Rt = Bits32(opcode, 15, 12);
+ // if t == 13 then UNPREDICTABLE;
+ if (Rt == dwarf_sp)
+ return false;
+ registers = (1u << Rt);
+ break;
+ default:
+ return false;
+ }
+ addr_t sp_offset = addr_byte_size * BitCount (registers);
+ addr_t addr = sp - sp_offset;
+ uint32_t i;
+
+ EmulateInstruction::Context context;
+ if (conditional)
+ context.type = EmulateInstruction::eContextRegisterStore;
+ else
+ context.type = EmulateInstruction::eContextPushRegisterOnStack;
+ RegisterInfo reg_info;
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+ for (i=0; i<15; ++i)
+ {
+ if (BitIsSet (registers, i))
+ {
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + i, reg_info);
+ context.SetRegisterToRegisterPlusOffset (reg_info, sp_reg, addr - sp);
+ uint32_t reg_value = ReadCoreReg(i, &success);
+ if (!success)
+ return false;
+ if (!MemAWrite (context, addr, reg_value, addr_byte_size))
+ return false;
+ addr += addr_byte_size;
+ }
+ }
+
+ if (BitIsSet (registers, 15))
+ {
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, reg_info);
+ context.SetRegisterToRegisterPlusOffset (reg_info, sp_reg, addr - sp);
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ if (!success)
+ return false;
+ if (!MemAWrite (context, addr, pc, addr_byte_size))
+ return false;
+ }
+
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ context.SetImmediateSigned (-sp_offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
+ return false;
+ }
+ return true;
+}
+
+// Pop Multiple Registers loads multiple registers from the stack, loading from
+// consecutive memory locations staring at the address in SP, and updates
+// SP to point just above the loaded data.
+bool
+EmulateInstructionARM::EmulatePOP (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations(); NullCheckIfThumbEE(13);
+ address = SP;
+ for i = 0 to 14
+ if registers<i> == '1' then
+ R[i] = if UnalignedAllowed then MemU[address,4] else MemA[address,4]; address = address + 4;
+ if registers<15> == '1' then
+ if UnalignedAllowed then
+ LoadWritePC(MemU[address,4]);
+ else
+ LoadWritePC(MemA[address,4]);
+ if registers<13> == '0' then SP = SP + 4*BitCount(registers);
+ if registers<13> == '1' then SP = bits(32) UNKNOWN;
+ }
+#endif
+
+ bool success = false;
+
+ bool conditional = false;
+ if (ConditionPassed(opcode, &conditional))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ uint32_t registers = 0;
+ uint32_t Rt; // the destination register
+ switch (encoding) {
+ case eEncodingT1:
+ registers = Bits32(opcode, 7, 0);
+ // The P bit represents PC.
+ if (Bit32(opcode, 8))
+ registers |= (1u << 15);
+ // if BitCount(registers) < 1 then UNPREDICTABLE;
+ if (BitCount(registers) < 1)
+ return false;
+ break;
+ case eEncodingT2:
+ // Ignore bit 13.
+ registers = Bits32(opcode, 15, 0) & ~0x2000;
+ // if BitCount(registers) < 2 || (P == '1' && M == '1') then UNPREDICTABLE;
+ if (BitCount(registers) < 2 || (Bit32(opcode, 15) && Bit32(opcode, 14)))
+ return false;
+ // if registers<15> == '1' && InITBlock() && !LastInITBlock() then UNPREDICTABLE;
+ if (BitIsSet(registers, 15) && InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ case eEncodingT3:
+ Rt = Bits32(opcode, 15, 12);
+ // if t == 13 || (t == 15 && InITBlock() && !LastInITBlock()) then UNPREDICTABLE;
+ if (Rt == 13)
+ return false;
+ if (Rt == 15 && InITBlock() && !LastInITBlock())
+ return false;
+ registers = (1u << Rt);
+ break;
+ case eEncodingA1:
+ registers = Bits32(opcode, 15, 0);
+ // Instead of return false, let's handle the following case as well,
+ // which amounts to popping one reg from the full descending stacks.
+ // if BitCount(register_list) < 2 then SEE LDM / LDMIA / LDMFD;
+
+ // if registers<13> == '1' && ArchVersion() >= 7 then UNPREDICTABLE;
+ if (BitIsSet(opcode, 13) && ArchVersion() >= ARMv7)
+ return false;
+ break;
+ case eEncodingA2:
+ Rt = Bits32(opcode, 15, 12);
+ // if t == 13 then UNPREDICTABLE;
+ if (Rt == dwarf_sp)
+ return false;
+ registers = (1u << Rt);
+ break;
+ default:
+ return false;
+ }
+ addr_t sp_offset = addr_byte_size * BitCount (registers);
+ addr_t addr = sp;
+ uint32_t i, data;
+
+ EmulateInstruction::Context context;
+ if (conditional)
+ context.type = EmulateInstruction::eContextRegisterLoad;
+ else
+ context.type = EmulateInstruction::eContextPopRegisterOffStack;
+
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+
+ for (i=0; i<15; ++i)
+ {
+ if (BitIsSet (registers, i))
+ {
+ context.SetRegisterPlusOffset (sp_reg, addr - sp);
+ data = MemARead(context, addr, 4, 0, &success);
+ if (!success)
+ return false;
+ if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_r0 + i, data))
+ return false;
+ addr += addr_byte_size;
+ }
+ }
+
+ if (BitIsSet (registers, 15))
+ {
+ context.SetRegisterPlusOffset (sp_reg, addr - sp);
+ data = MemARead(context, addr, 4, 0, &success);
+ if (!success)
+ return false;
+ // In ARMv5T and above, this is an interworking branch.
+ if (!LoadWritePC(context, data))
+ return false;
+ //addr += addr_byte_size;
+ }
+
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ context.SetImmediateSigned (sp_offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
+ return false;
+ }
+ return true;
+}
+
+// Set r7 or ip to point to saved value residing within the stack.
+// ADD (SP plus immediate)
+bool
+EmulateInstructionARM::EmulateADDRdSPImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(SP, imm32, '0');
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ uint32_t Rd; // the destination register
+ uint32_t imm32;
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = 7;
+ imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32)
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+ break;
+ default:
+ return false;
+ }
+ addr_t sp_offset = imm32;
+ addr_t addr = sp + sp_offset; // a pointer to the stack area
+
+ EmulateInstruction::Context context;
+ context.type = eContextSetFramePointer;
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+ context.SetRegisterPlusOffset (sp_reg, sp_offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, addr))
+ return false;
+ }
+ return true;
+}
+
+// Set r7 or ip to the current stack pointer.
+// MOV (register)
+bool
+EmulateInstructionARM::EmulateMOVRdSP (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ result = R[m];
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ // APSR.C unchanged
+ // APSR.V unchanged
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ uint32_t Rd; // the destination register
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = 7;
+ break;
+ case eEncodingA1:
+ Rd = 12;
+ break;
+ default:
+ return false;
+ }
+
+ EmulateInstruction::Context context;
+ if (Rd == GetFramePointerRegisterNumber())
+ context.type = EmulateInstruction::eContextSetFramePointer;
+ else
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+ context.SetRegisterPlusOffset (sp_reg, 0);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, sp))
+ return false;
+ }
+ return true;
+}
+
+// Move from high register (r8-r15) to low register (r0-r7).
+// MOV (register)
+bool
+EmulateInstructionARM::EmulateMOVLowHigh (const uint32_t opcode, const ARMEncoding encoding)
+{
+ return EmulateMOVRdRm (opcode, encoding);
+}
+
+// Move from register to register.
+// MOV (register)
+bool
+EmulateInstructionARM::EmulateMOVRdRm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ result = R[m];
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ // APSR.C unchanged
+ // APSR.V unchanged
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rm; // the source register
+ uint32_t Rd; // the destination register
+ bool setflags;
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 6, 3);
+ setflags = false;
+ if (Rd == 15 && InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = true;
+ if (InITBlock())
+ return false;
+ break;
+ case eEncodingT3:
+ Rd = Bits32(opcode, 11, 8);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ // if setflags && (BadReg(d) || BadReg(m)) then UNPREDICTABLE;
+ if (setflags && (BadReg(Rd) || BadReg(Rm)))
+ return false;
+ // if !setflags && (d == 15 || m == 15 || (d == 13 && m == 13)) then UNPREDICTABLE;
+ if (!setflags && (Rd == 15 || Rm == 15 || (Rd == 13 && Rm == 13)))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ uint32_t result = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ // The context specifies that Rm is to be moved into Rd.
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterLoad;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg);
+ context.SetRegister (dwarf_reg);
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags))
+ return false;
+ }
+ return true;
+}
+
+// Move (immediate) writes an immediate value to the destination register. It
+// can optionally update the condition flags based on the value.
+// MOV (immediate)
+bool
+EmulateInstructionARM::EmulateMOVRdImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ result = imm32;
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+ }
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd; // the destination register
+ uint32_t imm32; // the immediate value to be written to Rd
+ uint32_t carry = 0; // the carry bit after ThumbExpandImm_C or ARMExpandImm_C.
+ // for setflags == false, this value is a don't care
+ // initialized to 0 to silence the static analyzer
+ bool setflags;
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 10, 8);
+ setflags = !InITBlock();
+ imm32 = Bits32(opcode, 7, 0); // imm32 = ZeroExtend(imm8, 32)
+ carry = APSR_C;
+
+ break;
+
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm_C(opcode, APSR_C, carry);
+ if (BadReg(Rd))
+ return false;
+
+ break;
+
+ case eEncodingT3:
+ {
+ // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm4:i:imm3:imm8, 32);
+ Rd = Bits32 (opcode, 11, 8);
+ setflags = false;
+ uint32_t imm4 = Bits32 (opcode, 19, 16);
+ uint32_t imm3 = Bits32 (opcode, 14, 12);
+ uint32_t i = Bit32 (opcode, 26);
+ uint32_t imm8 = Bits32 (opcode, 7, 0);
+ imm32 = (imm4 << 12) | (i << 11) | (imm3 << 8) | imm8;
+
+ // if BadReg(d) then UNPREDICTABLE;
+ if (BadReg (Rd))
+ return false;
+ }
+ break;
+
+ case eEncodingA1:
+ // d = UInt(Rd); setflags = (S == Ô1Õ); (imm32, carry) = ARMExpandImm_C(imm12, APSR.C);
+ Rd = Bits32 (opcode, 15, 12);
+ setflags = BitIsSet (opcode, 20);
+ imm32 = ARMExpandImm_C (opcode, APSR_C, carry);
+
+ // if Rd == Ô1111Õ && S == Ô1Õ then SEE SUBS PC, LR and related instructions;
+ if ((Rd == 15) && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+
+ break;
+
+ case eEncodingA2:
+ {
+ // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm4:imm12, 32);
+ Rd = Bits32 (opcode, 15, 12);
+ setflags = false;
+ uint32_t imm4 = Bits32 (opcode, 19, 16);
+ uint32_t imm12 = Bits32 (opcode, 11, 0);
+ imm32 = (imm4 << 12) | imm12;
+
+ // if d == 15 then UNPREDICTABLE;
+ if (Rd == 15)
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ }
+ uint32_t result = imm32;
+
+ // The context specifies that an immediate is to be moved into Rd.
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// MUL multiplies two register values. The least significant 32 bits of the result are written to the destination
+// register. These 32 bits do not depend on whether the source register values are considered to be signed values or
+// unsigned values.
+//
+// Optionally, it can update the condition flags based on the result. In the Thumb instruction set, this option is
+// limited to only a few forms of the instruction.
+bool
+EmulateInstructionARM::EmulateMUL (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ operand1 = SInt(R[n]); // operand1 = UInt(R[n]) produces the same final results
+ operand2 = SInt(R[m]); // operand2 = UInt(R[m]) produces the same final results
+ result = operand1 * operand2;
+ R[d] = result<31:0>;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ if ArchVersion() == 4 then
+ APSR.C = bit UNKNOWN;
+ // else APSR.C unchanged
+ // APSR.V always unchanged
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t n;
+ uint32_t m;
+ bool setflags;
+
+ // EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rdm); n = UInt(Rn); m = UInt(Rdm); setflags = !InITBlock();
+ d = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 2, 0);
+ setflags = !InITBlock();
+
+ // if ArchVersion() < 6 && d == n then UNPREDICTABLE;
+ if ((ArchVersion() < ARMv6) && (d == n))
+ return false;
+
+ break;
+
+ case eEncodingT2:
+ // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = FALSE;
+ d = Bits32 (opcode, 11, 8);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+ setflags = false;
+
+ // if BadReg(d) || BadReg(n) || BadReg(m) then UNPREDICTABLE;
+ if (BadReg (d) || BadReg (n) || BadReg (m))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == '1');
+ d = Bits32 (opcode, 19, 16);
+ n = Bits32 (opcode, 3, 0);
+ m = Bits32 (opcode, 11, 8);
+ setflags = BitIsSet (opcode, 20);
+
+ // if d == 15 || n == 15 || m == 15 then UNPREDICTABLE;
+ if ((d == 15) || (n == 15) || (m == 15))
+ return false;
+
+ // if ArchVersion() < 6 && d == n then UNPREDICTABLE;
+ if ((ArchVersion() < ARMv6) && (d == n))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ bool success = false;
+
+ // operand1 = SInt(R[n]); // operand1 = UInt(R[n]) produces the same final results
+ uint64_t operand1 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ // operand2 = SInt(R[m]); // operand2 = UInt(R[m]) produces the same final results
+ uint64_t operand2 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ // result = operand1 * operand2;
+ uint64_t result = operand1 * operand2;
+
+ // R[d] = result<31:0>;
+ RegisterInfo op1_reg;
+ RegisterInfo op2_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, op1_reg);
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, op2_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextArithmetic;
+ context.SetRegisterRegisterOperands (op1_reg, op2_reg);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, (0x0000ffff & result)))
+ return false;
+
+ // if setflags then
+ if (setflags)
+ {
+ // APSR.N = result<31>;
+ // APSR.Z = IsZeroBit(result);
+ m_new_inst_cpsr = m_opcode_cpsr;
+ SetBit32 (m_new_inst_cpsr, CPSR_N_POS, Bit32 (result, 31));
+ SetBit32 (m_new_inst_cpsr, CPSR_Z_POS, result == 0 ? 1 : 0);
+ if (m_new_inst_cpsr != m_opcode_cpsr)
+ {
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
+ return false;
+ }
+
+ // if ArchVersion() == 4 then
+ // APSR.C = bit UNKNOWN;
+ }
+ }
+ return true;
+}
+
+// Bitwise NOT (immediate) writes the bitwise inverse of an immediate value to the destination register.
+// It can optionally update the condition flags based on the value.
+bool
+EmulateInstructionARM::EmulateMVNImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ result = NOT(imm32);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+ }
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd; // the destination register
+ uint32_t imm32; // the output after ThumbExpandImm_C or ARMExpandImm_C
+ uint32_t carry; // the carry bit after ThumbExpandImm_C or ARMExpandImm_C
+ bool setflags;
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 11, 8);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm_C(opcode, APSR_C, carry);
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm_C(opcode, APSR_C, carry);
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ uint32_t result = ~imm32;
+
+ // The context specifies that an immediate is to be moved into Rd.
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// Bitwise NOT (register) writes the bitwise inverse of a register value to the destination register.
+// It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateMVNReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
+ result = NOT(shifted);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+ }
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rm; // the source register
+ uint32_t Rd; // the destination register
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ bool setflags;
+ uint32_t carry; // the carry bit after the shift operation
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ if (InITBlock())
+ return false;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ // if (BadReg(d) || BadReg(m)) then UNPREDICTABLE;
+ if (BadReg(Rd) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+ break;
+ default:
+ return false;
+ }
+ bool success = false;
+ uint32_t value = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift_C(value, shift_t, shift_n, APSR_C, carry, &success);
+ if (!success)
+ return false;
+ uint32_t result = ~shifted;
+
+ // The context specifies that an immediate is to be moved into Rd.
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// PC relative immediate load into register, possibly followed by ADD (SP plus register).
+// LDR (literal)
+bool
+EmulateInstructionARM::EmulateLDRRtPCRelative (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ base = Align(PC,4);
+ address = if add then (base + imm32) else (base - imm32);
+ data = MemU[address,4];
+ if t == 15 then
+ if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
+ elsif UnalignedSupport() || address<1:0> = '00' then
+ R[t] = data;
+ else // Can only apply before ARMv7
+ if CurrentInstrSet() == InstrSet_ARM then
+ R[t] = ROR(data, 8*UInt(address<1:0>));
+ else
+ R[t] = bits(32) UNKNOWN;
+ }
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ bool success = false;
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ if (!success)
+ return false;
+
+ // PC relative immediate load context
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ RegisterInfo pc_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, pc_reg);
+ context.SetRegisterPlusOffset (pc_reg, 0);
+
+ uint32_t Rt; // the destination register
+ uint32_t imm32; // immediate offset from the PC
+ bool add; // +imm32 or -imm32?
+ addr_t base; // the base address
+ addr_t address; // the PC relative address
+ uint32_t data; // the literal data value from the PC relative load
+ switch (encoding) {
+ case eEncodingT1:
+ Rt = Bits32(opcode, 10, 8);
+ imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32);
+ add = true;
+ break;
+ case eEncodingT2:
+ Rt = Bits32(opcode, 15, 12);
+ imm32 = Bits32(opcode, 11, 0) << 2; // imm32 = ZeroExtend(imm12, 32);
+ add = BitIsSet(opcode, 23);
+ if (Rt == 15 && InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ base = Align(pc, 4);
+ if (add)
+ address = base + imm32;
+ else
+ address = base - imm32;
+
+ context.SetRegisterPlusOffset(pc_reg, address - base);
+ data = MemURead(context, address, 4, 0, &success);
+ if (!success)
+ return false;
+
+ if (Rt == 15)
+ {
+ if (Bits32(address, 1, 0) == 0)
+ {
+ // In ARMv5T and above, this is an interworking branch.
+ if (!LoadWritePC(context, data))
+ return false;
+ }
+ else
+ return false;
+ }
+ else if (UnalignedSupport() || Bits32(address, 1, 0) == 0)
+ {
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rt, data))
+ return false;
+ }
+ else // We don't handle ARM for now.
+ return false;
+
+ }
+ return true;
+}
+
+// An add operation to adjust the SP.
+// ADD (SP plus immediate)
+bool
+EmulateInstructionARM::EmulateADDSPImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(SP, imm32, '0');
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ uint32_t imm32; // the immediate operand
+ uint32_t d;
+ //bool setflags = false; // Add this back if/when support eEncodingT3 eEncodingA1
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm8:'00', 32);
+ d = Bits32 (opcode, 10, 8);
+ imm32 = (Bits32 (opcode, 7, 0) << 2);
+
+ break;
+
+ case eEncodingT2:
+ // d = 13; setflags = FALSE; imm32 = ZeroExtend(imm7:'00', 32);
+ d = 13;
+ imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
+
+ break;
+
+ default:
+ return false;
+ }
+ addr_t sp_offset = imm32;
+ addr_t addr = sp + sp_offset; // the adjusted stack pointer value
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+ context.SetRegisterPlusOffset (sp_reg, sp_offset);
+
+ if (d == 15)
+ {
+ if (!ALUWritePC (context, addr))
+ return false;
+ }
+ else
+ {
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, addr))
+ return false;
+
+ // Add this back if/when support eEncodingT3 eEncodingA1
+ //if (setflags)
+ //{
+ // APSR.N = result<31>;
+ // APSR.Z = IsZeroBit(result);
+ // APSR.C = carry;
+ // APSR.V = overflow;
+ //}
+ }
+ }
+ return true;
+}
+
+// An add operation to adjust the SP.
+// ADD (SP plus register)
+bool
+EmulateInstructionARM::EmulateADDSPRm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(SP, shifted, '0');
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ uint32_t Rm; // the second operand
+ switch (encoding) {
+ case eEncodingT2:
+ Rm = Bits32(opcode, 6, 3);
+ break;
+ default:
+ return false;
+ }
+ int32_t reg_value = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ addr_t addr = (int32_t)sp + reg_value; // the adjusted stack pointer value
+
+ EmulateInstruction::Context context;
+ context.type = eContextArithmetic;
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+
+ RegisterInfo other_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, other_reg);
+ context.SetRegisterRegisterOperands (sp_reg, other_reg);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr))
+ return false;
+ }
+ return true;
+}
+
+// Branch with Link and Exchange Instruction Sets (immediate) calls a subroutine
+// at a PC-relative address, and changes instruction set from ARM to Thumb, or
+// from Thumb to ARM.
+// BLX (immediate)
+bool
+EmulateInstructionARM::EmulateBLXImmediate (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ if CurrentInstrSet() == InstrSet_ARM then
+ LR = PC - 4;
+ else
+ LR = PC<31:1> : '1';
+ if targetInstrSet == InstrSet_ARM then
+ targetAddress = Align(PC,4) + imm32;
+ else
+ targetAddress = PC + imm32;
+ SelectInstrSet(targetInstrSet);
+ BranchWritePC(targetAddress);
+ }
+#endif
+
+ bool success = true;
+
+ if (ConditionPassed(opcode))
+ {
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ if (!success)
+ return false;
+ addr_t lr; // next instruction address
+ addr_t target; // target address
+ int32_t imm32; // PC-relative offset
+ switch (encoding) {
+ case eEncodingT1:
+ {
+ lr = pc | 1u; // return address
+ uint32_t S = Bit32(opcode, 26);
+ uint32_t imm10 = Bits32(opcode, 25, 16);
+ uint32_t J1 = Bit32(opcode, 13);
+ uint32_t J2 = Bit32(opcode, 11);
+ uint32_t imm11 = Bits32(opcode, 10, 0);
+ uint32_t I1 = !(J1 ^ S);
+ uint32_t I2 = !(J2 ^ S);
+ uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
+ imm32 = llvm::SignExtend32<25>(imm25);
+ target = pc + imm32;
+ context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
+ if (InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ }
+ case eEncodingT2:
+ {
+ lr = pc | 1u; // return address
+ uint32_t S = Bit32(opcode, 26);
+ uint32_t imm10H = Bits32(opcode, 25, 16);
+ uint32_t J1 = Bit32(opcode, 13);
+ uint32_t J2 = Bit32(opcode, 11);
+ uint32_t imm10L = Bits32(opcode, 10, 1);
+ uint32_t I1 = !(J1 ^ S);
+ uint32_t I2 = !(J2 ^ S);
+ uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10H << 12) | (imm10L << 2);
+ imm32 = llvm::SignExtend32<25>(imm25);
+ target = Align(pc, 4) + imm32;
+ context.SetISAAndImmediateSigned (eModeARM, 4 + imm32);
+ if (InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ }
+ case eEncodingA1:
+ lr = pc - 4; // return address
+ imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2);
+ target = Align(pc, 4) + imm32;
+ context.SetISAAndImmediateSigned (eModeARM, 8 + imm32);
+ break;
+ case eEncodingA2:
+ lr = pc - 4; // return address
+ imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2 | Bits32(opcode, 24, 24) << 1);
+ target = pc + imm32;
+ context.SetISAAndImmediateSigned (eModeThumb, 8 + imm32);
+ break;
+ default:
+ return false;
+ }
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
+ return false;
+ if (!BranchWritePC(context, target))
+ return false;
+ }
+ return true;
+}
+
+// Branch with Link and Exchange (register) calls a subroutine at an address and
+// instruction set specified by a register.
+// BLX (register)
+bool
+EmulateInstructionARM::EmulateBLXRm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ target = R[m];
+ if CurrentInstrSet() == InstrSet_ARM then
+ next_instr_addr = PC - 4;
+ LR = next_instr_addr;
+ else
+ next_instr_addr = PC - 2;
+ LR = next_instr_addr<31:1> : '1';
+ BXWritePC(target);
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextAbsoluteBranchRegister;
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ addr_t lr; // next instruction address
+ if (!success)
+ return false;
+ uint32_t Rm; // the register with the target address
+ switch (encoding) {
+ case eEncodingT1:
+ lr = (pc - 2) | 1u; // return address
+ Rm = Bits32(opcode, 6, 3);
+ // if m == 15 then UNPREDICTABLE;
+ if (Rm == 15)
+ return false;
+ if (InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ case eEncodingA1:
+ lr = pc - 4; // return address
+ Rm = Bits32(opcode, 3, 0);
+ // if m == 15 then UNPREDICTABLE;
+ if (Rm == 15)
+ return false;
+ break;
+ default:
+ return false;
+ }
+ addr_t target = ReadCoreReg (Rm, &success);
+ if (!success)
+ return false;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg);
+ context.SetRegister (dwarf_reg);
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
+ return false;
+ if (!BXWritePC(context, target))
+ return false;
+ }
+ return true;
+}
+
+// Branch and Exchange causes a branch to an address and instruction set specified by a register.
+bool
+EmulateInstructionARM::EmulateBXRm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ BXWritePC(R[m]);
+ }
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextAbsoluteBranchRegister;
+ uint32_t Rm; // the register with the target address
+ switch (encoding) {
+ case eEncodingT1:
+ Rm = Bits32(opcode, 6, 3);
+ if (InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ case eEncodingA1:
+ Rm = Bits32(opcode, 3, 0);
+ break;
+ default:
+ return false;
+ }
+ bool success = false;
+ addr_t target = ReadCoreReg (Rm, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg);
+ context.SetRegister (dwarf_reg);
+ if (!BXWritePC(context, target))
+ return false;
+ }
+ return true;
+}
+
+// Branch and Exchange Jazelle attempts to change to Jazelle state. If the attempt fails, it branches to an
+// address and instruction set specified by a register as though it were a BX instruction.
+//
+// TODO: Emulate Jazelle architecture?
+// We currently assume that switching to Jazelle state fails, thus treating BXJ as a BX operation.
+bool
+EmulateInstructionARM::EmulateBXJRm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ if JMCR.JE == '0' || CurrentInstrSet() == InstrSet_ThumbEE then
+ BXWritePC(R[m]);
+ else
+ if JazelleAcceptsExecution() then
+ SwitchToJazelleExecution();
+ else
+ SUBARCHITECTURE_DEFINED handler call;
+ }
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextAbsoluteBranchRegister;
+ uint32_t Rm; // the register with the target address
+ switch (encoding) {
+ case eEncodingT1:
+ Rm = Bits32(opcode, 19, 16);
+ if (BadReg(Rm))
+ return false;
+ if (InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ case eEncodingA1:
+ Rm = Bits32(opcode, 3, 0);
+ if (Rm == 15)
+ return false;
+ break;
+ default:
+ return false;
+ }
+ bool success = false;
+ addr_t target = ReadCoreReg (Rm, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, dwarf_reg);
+ context.SetRegister (dwarf_reg);
+ if (!BXWritePC(context, target))
+ return false;
+ }
+ return true;
+}
+
+// Set r7 to point to some ip offset.
+// SUB (immediate)
+bool
+EmulateInstructionARM::EmulateSUBR7IPImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1');
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+ }
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ bool success = false;
+ const addr_t ip = ReadCoreReg (12, &success);
+ if (!success)
+ return false;
+ uint32_t imm32;
+ switch (encoding) {
+ case eEncodingA1:
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+ break;
+ default:
+ return false;
+ }
+ addr_t ip_offset = imm32;
+ addr_t addr = ip - ip_offset; // the adjusted ip value
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r12, dwarf_reg);
+ context.SetRegisterPlusOffset (dwarf_reg, -ip_offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r7, addr))
+ return false;
+ }
+ return true;
+}
+
+// Set ip to point to some stack offset.
+// SUB (SP minus immediate)
+bool
+EmulateInstructionARM::EmulateSUBIPSPImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1');
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+ }
+#endif
+
+ if (ConditionPassed(opcode))
+ {
+ bool success = false;
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ uint32_t imm32;
+ switch (encoding) {
+ case eEncodingA1:
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+ break;
+ default:
+ return false;
+ }
+ addr_t sp_offset = imm32;
+ addr_t addr = sp - sp_offset; // the adjusted stack pointer value
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, dwarf_reg);
+ context.SetRegisterPlusOffset (dwarf_reg, -sp_offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r12, addr))
+ return false;
+ }
+ return true;
+}
+
+// This instruction subtracts an immediate value from the SP value, and writes
+// the result to the destination register.
+//
+// If Rd == 13 => A sub operation to adjust the SP -- allocate space for local storage.
+bool
+EmulateInstructionARM::EmulateSUBSPImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), '1');
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+ }
+#endif
+
+ bool success = false;
+ if (ConditionPassed(opcode))
+ {
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+
+ uint32_t Rd;
+ bool setflags;
+ uint32_t imm32;
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = 13;
+ setflags = false;
+ imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32)
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
+ if (Rd == 15 && setflags)
+ return EmulateCMPImm(opcode, eEncodingT2);
+ if (Rd == 15 && !setflags)
+ return false;
+ break;
+ case eEncodingT3:
+ Rd = Bits32(opcode, 11, 8);
+ setflags = false;
+ imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32)
+ if (Rd == 15)
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ AddWithCarryResult res = AddWithCarry(sp, ~imm32, 1);
+
+ EmulateInstruction::Context context;
+ if (Rd == 13)
+ {
+ uint64_t imm64 = imm32; // Need to expand it to 64 bits before attempting to negate it, or the wrong
+ // value gets passed down to context.SetImmediateSigned.
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ context.SetImmediateSigned (-imm64); // the stack pointer offset
+ }
+ else
+ {
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+ }
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+ }
+ return true;
+}
+
+// A store operation to the stack that also updates the SP.
+bool
+EmulateInstructionARM::EmulateSTRRtSP (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ MemU[address,4] = if t == 15 then PCStoreValue() else R[t];
+ if wback then R[n] = offset_addr;
+ }
+#endif
+
+ bool conditional = false;
+ bool success = false;
+ if (ConditionPassed(opcode, &conditional))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ uint32_t Rt; // the source register
+ uint32_t imm12;
+ uint32_t Rn; // This function assumes Rn is the SP, but we should verify that.
+
+ bool index;
+ bool add;
+ bool wback;
+ switch (encoding) {
+ case eEncodingA1:
+ Rt = Bits32(opcode, 15, 12);
+ imm12 = Bits32(opcode, 11, 0);
+ Rn = Bits32 (opcode, 19, 16);
+
+ if (Rn != 13) // 13 is the SP reg on ARM. Verify that Rn == SP.
+ return false;
+
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21));
+
+ if (wback && ((Rn == 15) || (Rn == Rt)))
+ return false;
+ break;
+ default:
+ return false;
+ }
+ addr_t offset_addr;
+ if (add)
+ offset_addr = sp + imm12;
+ else
+ offset_addr = sp - imm12;
+
+ addr_t addr;
+ if (index)
+ addr = offset_addr;
+ else
+ addr = sp;
+
+ EmulateInstruction::Context context;
+ if (conditional)
+ context.type = EmulateInstruction::eContextRegisterStore;
+ else
+ context.type = EmulateInstruction::eContextPushRegisterOnStack;
+ RegisterInfo sp_reg;
+ RegisterInfo dwarf_reg;
+
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rt, dwarf_reg);
+ context.SetRegisterToRegisterPlusOffset ( dwarf_reg, sp_reg, addr - sp);
+ if (Rt != 15)
+ {
+ uint32_t reg_value = ReadCoreReg(Rt, &success);
+ if (!success)
+ return false;
+ if (!MemUWrite (context, addr, reg_value, addr_byte_size))
+ return false;
+ }
+ else
+ {
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ if (!success)
+ return false;
+ if (!MemUWrite (context, addr, pc, addr_byte_size))
+ return false;
+ }
+
+
+ if (wback)
+ {
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ context.SetImmediateSigned (addr - sp);
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// Vector Push stores multiple extension registers to the stack.
+// It also updates SP to point to the start of the stored data.
+bool
+EmulateInstructionARM::EmulateVPUSH (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
+ address = SP - imm32;
+ SP = SP - imm32;
+ if single_regs then
+ for r = 0 to regs-1
+ MemA[address,4] = S[d+r]; address = address+4;
+ else
+ for r = 0 to regs-1
+ // Store as two word-aligned words in the correct order for current endianness.
+ MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>;
+ MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>;
+ address = address+8;
+ }
+#endif
+
+ bool success = false;
+ bool conditional = false;
+ if (ConditionPassed(opcode, &conditional))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ bool single_regs;
+ uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register
+ uint32_t imm32; // stack offset
+ uint32_t regs; // number of registers
+ switch (encoding) {
+ case eEncodingT1:
+ case eEncodingA1:
+ single_regs = false;
+ d = Bit32(opcode, 22) << 4 | Bits32(opcode, 15, 12);
+ imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
+ // If UInt(imm8) is odd, see "FSTMX".
+ regs = Bits32(opcode, 7, 0) / 2;
+ // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
+ if (regs == 0 || regs > 16 || (d + regs) > 32)
+ return false;
+ break;
+ case eEncodingT2:
+ case eEncodingA2:
+ single_regs = true;
+ d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22);
+ imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
+ regs = Bits32(opcode, 7, 0);
+ // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
+ if (regs == 0 || regs > 16 || (d + regs) > 32)
+ return false;
+ break;
+ default:
+ return false;
+ }
+ uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
+ uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
+ addr_t sp_offset = imm32;
+ addr_t addr = sp - sp_offset;
+ uint32_t i;
+
+ EmulateInstruction::Context context;
+ if (conditional)
+ context.type = EmulateInstruction::eContextRegisterStore;
+ else
+ context.type = EmulateInstruction::eContextPushRegisterOnStack;
+ RegisterInfo dwarf_reg;
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+ for (i=0; i<regs; ++i)
+ {
+ GetRegisterInfo (eRegisterKindDWARF, start_reg + d + i, dwarf_reg);
+ context.SetRegisterToRegisterPlusOffset ( dwarf_reg, sp_reg, addr - sp);
+ // uint64_t to accommodate 64-bit registers.
+ uint64_t reg_value = ReadRegisterUnsigned (&dwarf_reg, 0, &success);
+ if (!success)
+ return false;
+ if (!MemAWrite (context, addr, reg_value, reg_byte_size))
+ return false;
+ addr += reg_byte_size;
+ }
+
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ context.SetImmediateSigned (-sp_offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset))
+ return false;
+ }
+ return true;
+}
+
+// Vector Pop loads multiple extension registers from the stack.
+// It also updates SP to point just above the loaded data.
+bool
+EmulateInstructionARM::EmulateVPOP (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13);
+ address = SP;
+ SP = SP + imm32;
+ if single_regs then
+ for r = 0 to regs-1
+ S[d+r] = MemA[address,4]; address = address+4;
+ else
+ for r = 0 to regs-1
+ word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8;
+ // Combine the word-aligned words in the correct order for current endianness.
+ D[d+r] = if BigEndian() then word1:word2 else word2:word1;
+ }
+#endif
+
+ bool success = false;
+ bool conditional = false;
+ if (ConditionPassed(opcode, &conditional))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ const addr_t sp = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+ bool single_regs;
+ uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register
+ uint32_t imm32; // stack offset
+ uint32_t regs; // number of registers
+ switch (encoding) {
+ case eEncodingT1:
+ case eEncodingA1:
+ single_regs = false;
+ d = Bit32(opcode, 22) << 4 | Bits32(opcode, 15, 12);
+ imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
+ // If UInt(imm8) is odd, see "FLDMX".
+ regs = Bits32(opcode, 7, 0) / 2;
+ // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
+ if (regs == 0 || regs > 16 || (d + regs) > 32)
+ return false;
+ break;
+ case eEncodingT2:
+ case eEncodingA2:
+ single_regs = true;
+ d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22);
+ imm32 = Bits32(opcode, 7, 0) * addr_byte_size;
+ regs = Bits32(opcode, 7, 0);
+ // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
+ if (regs == 0 || regs > 16 || (d + regs) > 32)
+ return false;
+ break;
+ default:
+ return false;
+ }
+ uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
+ uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2;
+ addr_t sp_offset = imm32;
+ addr_t addr = sp;
+ uint32_t i;
+ uint64_t data; // uint64_t to accomodate 64-bit registers.
+
+ EmulateInstruction::Context context;
+ if (conditional)
+ context.type = EmulateInstruction::eContextRegisterLoad;
+ else
+ context.type = EmulateInstruction::eContextPopRegisterOffStack;
+ RegisterInfo dwarf_reg;
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+ for (i=0; i<regs; ++i)
+ {
+ GetRegisterInfo (eRegisterKindDWARF, start_reg + d + i, dwarf_reg);
+ context.SetRegisterPlusOffset (sp_reg, addr - sp);
+ data = MemARead(context, addr, reg_byte_size, 0, &success);
+ if (!success)
+ return false;
+ if (!WriteRegisterUnsigned(context, &dwarf_reg, data))
+ return false;
+ addr += reg_byte_size;
+ }
+
+ context.type = EmulateInstruction::eContextAdjustStackPointer;
+ context.SetImmediateSigned (sp_offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset))
+ return false;
+ }
+ return true;
+}
+
+// SVC (previously SWI)
+bool
+EmulateInstructionARM::EmulateSVC (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ CallSupervisor();
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ addr_t lr; // next instruction address
+ if (!success)
+ return false;
+ uint32_t imm32; // the immediate constant
+ uint32_t mode; // ARM or Thumb mode
+ switch (encoding) {
+ case eEncodingT1:
+ lr = (pc + 2) | 1u; // return address
+ imm32 = Bits32(opcode, 7, 0);
+ mode = eModeThumb;
+ break;
+ case eEncodingA1:
+ lr = pc + 4; // return address
+ imm32 = Bits32(opcode, 23, 0);
+ mode = eModeARM;
+ break;
+ default:
+ return false;
+ }
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextSupervisorCall;
+ context.SetISAAndImmediate (mode, imm32);
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr))
+ return false;
+ }
+ return true;
+}
+
+// If Then makes up to four following instructions (the IT block) conditional.
+bool
+EmulateInstructionARM::EmulateIT (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ EncodingSpecificOperations();
+ ITSTATE.IT<7:0> = firstcond:mask;
+#endif
+
+ m_it_session.InitIT(Bits32(opcode, 7, 0));
+ return true;
+}
+
+bool
+EmulateInstructionARM::EmulateNop (const uint32_t opcode, const ARMEncoding encoding)
+{
+ // NOP, nothing to do...
+ return true;
+}
+
+// Branch causes a branch to a target address.
+bool
+EmulateInstructionARM::EmulateB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations();
+ BranchWritePC(PC + imm32);
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ if (!success)
+ return false;
+ addr_t target; // target address
+ int32_t imm32; // PC-relative offset
+ switch (encoding) {
+ case eEncodingT1:
+ // The 'cond' field is handled in EmulateInstructionARM::CurrentCond().
+ imm32 = llvm::SignExtend32<9>(Bits32(opcode, 7, 0) << 1);
+ target = pc + imm32;
+ context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
+ break;
+ case eEncodingT2:
+ imm32 = llvm::SignExtend32<12>(Bits32(opcode, 10, 0));
+ target = pc + imm32;
+ context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
+ break;
+ case eEncodingT3:
+ // The 'cond' field is handled in EmulateInstructionARM::CurrentCond().
+ {
+ uint32_t S = Bit32(opcode, 26);
+ uint32_t imm6 = Bits32(opcode, 21, 16);
+ uint32_t J1 = Bit32(opcode, 13);
+ uint32_t J2 = Bit32(opcode, 11);
+ uint32_t imm11 = Bits32(opcode, 10, 0);
+ uint32_t imm21 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1);
+ imm32 = llvm::SignExtend32<21>(imm21);
+ target = pc + imm32;
+ context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
+ break;
+ }
+ case eEncodingT4:
+ {
+ uint32_t S = Bit32(opcode, 26);
+ uint32_t imm10 = Bits32(opcode, 25, 16);
+ uint32_t J1 = Bit32(opcode, 13);
+ uint32_t J2 = Bit32(opcode, 11);
+ uint32_t imm11 = Bits32(opcode, 10, 0);
+ uint32_t I1 = !(J1 ^ S);
+ uint32_t I2 = !(J2 ^ S);
+ uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1);
+ imm32 = llvm::SignExtend32<25>(imm25);
+ target = pc + imm32;
+ context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
+ break;
+ }
+ case eEncodingA1:
+ imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2);
+ target = pc + imm32;
+ context.SetISAAndImmediateSigned (eModeARM, 8 + imm32);
+ break;
+ default:
+ return false;
+ }
+ if (!BranchWritePC(context, target))
+ return false;
+ }
+ return true;
+}
+
+// Compare and Branch on Nonzero and Compare and Branch on Zero compare the value in a register with
+// zero and conditionally branch forward a constant value. They do not affect the condition flags.
+// CBNZ, CBZ
+bool
+EmulateInstructionARM::EmulateCB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ EncodingSpecificOperations();
+ if nonzero ^ IsZero(R[n]) then
+ BranchWritePC(PC + imm32);
+#endif
+
+ bool success = false;
+
+ // Read the register value from the operand register Rn.
+ uint32_t reg_val = ReadCoreReg(Bits32(opcode, 2, 0), &success);
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ if (!success)
+ return false;
+
+ addr_t target; // target address
+ uint32_t imm32; // PC-relative offset to branch forward
+ bool nonzero;
+ switch (encoding) {
+ case eEncodingT1:
+ imm32 = Bit32(opcode, 9) << 6 | Bits32(opcode, 7, 3) << 1;
+ nonzero = BitIsSet(opcode, 11);
+ target = pc + imm32;
+ context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32);
+ break;
+ default:
+ return false;
+ }
+ if (nonzero ^ (reg_val == 0))
+ if (!BranchWritePC(context, target))
+ return false;
+
+ return true;
+}
+
+// Table Branch Byte causes a PC-relative forward branch using a table of single byte offsets.
+// A base register provides a pointer to the table, and a second register supplies an index into the table.
+// The branch length is twice the value of the byte returned from the table.
+//
+// Table Branch Halfword causes a PC-relative forward branch using a table of single halfword offsets.
+// A base register provides a pointer to the table, and a second register supplies an index into the table.
+// The branch length is twice the value of the halfword returned from the table.
+// TBB, TBH
+bool
+EmulateInstructionARM::EmulateTB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ if is_tbh then
+ halfwords = UInt(MemU[R[n]+LSL(R[m],1), 2]);
+ else
+ halfwords = UInt(MemU[R[n]+R[m], 1]);
+ BranchWritePC(PC + 2*halfwords);
+#endif
+
+ bool success = false;
+
+ uint32_t Rn; // the base register which contains the address of the table of branch lengths
+ uint32_t Rm; // the index register which contains an integer pointing to a byte/halfword in the table
+ bool is_tbh; // true if table branch halfword
+ switch (encoding) {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ is_tbh = BitIsSet(opcode, 4);
+ if (Rn == 13 || BadReg(Rm))
+ return false;
+ if (InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ // Read the address of the table from the operand register Rn.
+ // The PC can be used, in which case the table immediately follows this instruction.
+ uint32_t base = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ // the table index
+ uint32_t index = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ // the offsetted table address
+ addr_t addr = base + (is_tbh ? index*2 : index);
+
+ // PC-relative offset to branch forward
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextTableBranchReadMemory;
+ uint32_t offset = MemURead(context, addr, is_tbh ? 2 : 1, 0, &success) * 2;
+ if (!success)
+ return false;
+
+ const uint32_t pc = ReadCoreReg(PC_REG, &success);
+ if (!success)
+ return false;
+
+ // target address
+ addr_t target = pc + offset;
+ context.type = EmulateInstruction::eContextRelativeBranchImmediate;
+ context.SetISAAndImmediateSigned (eModeThumb, 4 + offset);
+
+ if (!BranchWritePC(context, target))
+ return false;
+
+ return true;
+}
+
+// This instruction adds an immediate value to a register value, and writes the result to the destination register.
+// It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateADDImmThumb (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t n;
+ bool setflags;
+ uint32_t imm32;
+ uint32_t carry_out;
+
+ //EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); n = UInt(Rn); setflags = !InITBlock(); imm32 = ZeroExtend(imm3, 32);
+ d = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ setflags = !InITBlock();
+ imm32 = Bits32 (opcode, 8,6);
+
+ break;
+
+ case eEncodingT2:
+ // d = UInt(Rdn); n = UInt(Rdn); setflags = !InITBlock(); imm32 = ZeroExtend(imm8, 32);
+ d = Bits32 (opcode, 10, 8);
+ n = Bits32 (opcode, 10, 8);
+ setflags = !InITBlock();
+ imm32 = Bits32 (opcode, 7, 0);
+
+ break;
+
+ case eEncodingT3:
+ // if Rd == '1111' && S == '1' then SEE CMN (immediate);
+ // if Rn == '1101' then SEE ADD (SP plus immediate);
+ // d = UInt(Rd); n = UInt(Rn); setflags = (S == '1'); imm32 = ThumbExpandImm(i:imm3:imm8);
+ d = Bits32 (opcode, 11, 8);
+ n = Bits32 (opcode, 19, 16);
+ setflags = BitIsSet (opcode, 20);
+ imm32 = ThumbExpandImm_C (opcode, APSR_C, carry_out);
+
+ // if BadReg(d) || n == 15 then UNPREDICTABLE;
+ if (BadReg (d) || (n == 15))
+ return false;
+
+ break;
+
+ case eEncodingT4:
+ {
+ // if Rn == '1111' then SEE ADR;
+ // if Rn == '1101' then SEE ADD (SP plus immediate);
+ // d = UInt(Rd); n = UInt(Rn); setflags = FALSE; imm32 = ZeroExtend(i:imm3:imm8, 32);
+ d = Bits32 (opcode, 11, 8);
+ n = Bits32 (opcode, 19, 16);
+ setflags = false;
+ uint32_t i = Bit32 (opcode, 26);
+ uint32_t imm3 = Bits32 (opcode, 14, 12);
+ uint32_t imm8 = Bits32 (opcode, 7, 0);
+ imm32 = (i << 11) | (imm3 << 8) | imm8;
+
+ // if BadReg(d) then UNPREDICTABLE;
+ if (BadReg (d))
+ return false;
+
+ break;
+ }
+ default:
+ return false;
+ }
+
+ uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ //(result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
+ AddWithCarryResult res = AddWithCarry (Rn, imm32, 0);
+
+ RegisterInfo reg_n;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, reg_n);
+
+ EmulateInstruction::Context context;
+ context.type = eContextArithmetic;
+ context.SetRegisterPlusOffset (reg_n, imm32);
+
+ //R[d] = result;
+ //if setflags then
+ //APSR.N = result<31>;
+ //APSR.Z = IsZeroBit(result);
+ //APSR.C = carry;
+ //APSR.V = overflow;
+ if (!WriteCoreRegOptionalFlags (context, res.result, d, setflags, res.carry_out, res.overflow))
+ return false;
+
+ }
+ return true;
+}
+
+// This instruction adds an immediate value to a register value, and writes the result to the destination
+// register. It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateADDImmARM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn;
+ uint32_t imm32; // the immediate value to be added to the value obtained from Rn
+ bool setflags;
+ switch (encoding)
+ {
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(val1, imm32, 0);
+
+ EmulateInstruction::Context context;
+ context.type = eContextArithmetic;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, Rn, dwarf_reg);
+ context.SetRegisterPlusOffset (dwarf_reg, imm32);
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+ }
+ return true;
+}
+
+// This instruction adds a register value and an optionally-shifted register value, and writes the result
+// to the destination register. It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateADDReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(R[n], shifted, '0');
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn, Rm;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ bool setflags;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 2, 0);
+ Rn = Bits32(opcode, 5, 3);
+ Rm = Bits32(opcode, 8, 6);
+ setflags = !InITBlock();
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rd = Rn = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 6, 3);
+ setflags = false;
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ if (Rn == 15 && Rm == 15)
+ return false;
+ if (Rd == 15 && InITBlock() && !LastInITBlock())
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the second operand.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+ AddWithCarryResult res = AddWithCarry(val1, shifted, 0);
+
+ EmulateInstruction::Context context;
+ context.type = eContextArithmetic;
+ RegisterInfo op1_reg;
+ RegisterInfo op2_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rn, op1_reg);
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rm, op2_reg);
+ context.SetRegisterRegisterOperands (op1_reg, op2_reg);
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+ }
+ return true;
+}
+
+// Compare Negative (immediate) adds a register value and an immediate value.
+// It updates the condition flags based on the result, and discards the result.
+bool
+EmulateInstructionARM::EmulateCMNImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(R[n], imm32, '0');
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rn; // the first operand
+ uint32_t imm32; // the immediate value to be compared with
+ switch (encoding) {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 19, 16);
+ imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
+ if (Rn == 15)
+ return false;
+ break;
+ case eEncodingA1:
+ Rn = Bits32(opcode, 19, 16);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from the operand register Rn.
+ uint32_t reg_val = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(reg_val, imm32, 0);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+ if (!WriteFlags(context, res.result, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Compare Negative (register) adds a register value and an optionally-shifted register value.
+// It updates the condition flags based on the result, and discards the result.
+bool
+EmulateInstructionARM::EmulateCMNReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(R[n], shifted, '0');
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rn; // the first operand
+ uint32_t Rm; // the second operand
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ switch (encoding) {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ // if n == 15 || BadReg(m) then UNPREDICTABLE;
+ if (Rn == 15 || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from register Rn.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the register value from register Rm.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+ AddWithCarryResult res = AddWithCarry(val1, shifted, 0);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs();
+ if (!WriteFlags(context, res.result, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Compare (immediate) subtracts an immediate value from a register value.
+// It updates the condition flags based on the result, and discards the result.
+bool
+EmulateInstructionARM::EmulateCMPImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1');
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rn; // the first operand
+ uint32_t imm32; // the immediate value to be compared with
+ switch (encoding) {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 10, 8);
+ imm32 = Bits32(opcode, 7, 0);
+ break;
+ case eEncodingT2:
+ Rn = Bits32(opcode, 19, 16);
+ imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
+ if (Rn == 15)
+ return false;
+ break;
+ case eEncodingA1:
+ Rn = Bits32(opcode, 19, 16);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from the operand register Rn.
+ uint32_t reg_val = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+ if (!WriteFlags(context, res.result, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Compare (register) subtracts an optionally-shifted register value from a register value.
+// It updates the condition flags based on the result, and discards the result.
+bool
+EmulateInstructionARM::EmulateCMPReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), '1');
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rn; // the first operand
+ uint32_t Rm; // the second operand
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ switch (encoding) {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rn = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 6, 3);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ if (Rn < 8 && Rm < 8)
+ return false;
+ if (Rn == 15 || Rm == 15)
+ return false;
+ break;
+ case eEncodingA1:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from register Rn.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the register value from register Rm.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+ AddWithCarryResult res = AddWithCarry(val1, ~shifted, 1);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs();
+ if (!WriteFlags(context, res.result, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Arithmetic Shift Right (immediate) shifts a register value right by an immediate number of bits,
+// shifting in copies of its sign bit, and writes the result to the destination register. It can
+// optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateASRImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry) = Shift_C(R[m], SRType_ASR, shift_n, APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftImm (opcode, encoding, SRType_ASR);
+}
+
+// Arithmetic Shift Right (register) shifts a register value right by a variable number of bits,
+// shifting in copies of its sign bit, and writes the result to the destination register.
+// The variable number of bits is read from the bottom byte of a register. It can optionally update
+// the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateASRReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shift_n = UInt(R[m]<7:0>);
+ (result, carry) = Shift_C(R[m], SRType_ASR, shift_n, APSR.C);
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftReg (opcode, encoding, SRType_ASR);
+}
+
+// Logical Shift Left (immediate) shifts a register value left by an immediate number of bits,
+// shifting in zeros, and writes the result to the destination register. It can optionally
+// update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateLSLImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry) = Shift_C(R[m], SRType_LSL, shift_n, APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftImm (opcode, encoding, SRType_LSL);
+}
+
+// Logical Shift Left (register) shifts a register value left by a variable number of bits,
+// shifting in zeros, and writes the result to the destination register. The variable number
+// of bits is read from the bottom byte of a register. It can optionally update the condition
+// flags based on the result.
+bool
+EmulateInstructionARM::EmulateLSLReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shift_n = UInt(R[m]<7:0>);
+ (result, carry) = Shift_C(R[m], SRType_LSL, shift_n, APSR.C);
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftReg (opcode, encoding, SRType_LSL);
+}
+
+// Logical Shift Right (immediate) shifts a register value right by an immediate number of bits,
+// shifting in zeros, and writes the result to the destination register. It can optionally
+// update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateLSRImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry) = Shift_C(R[m], SRType_LSR, shift_n, APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftImm (opcode, encoding, SRType_LSR);
+}
+
+// Logical Shift Right (register) shifts a register value right by a variable number of bits,
+// shifting in zeros, and writes the result to the destination register. The variable number
+// of bits is read from the bottom byte of a register. It can optionally update the condition
+// flags based on the result.
+bool
+EmulateInstructionARM::EmulateLSRReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shift_n = UInt(R[m]<7:0>);
+ (result, carry) = Shift_C(R[m], SRType_LSR, shift_n, APSR.C);
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftReg (opcode, encoding, SRType_LSR);
+}
+
+// Rotate Right (immediate) provides the value of the contents of a register rotated by a constant value.
+// The bits that are rotated off the right end are inserted into the vacated bit positions on the left.
+// It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateRORImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry) = Shift_C(R[m], SRType_ROR, shift_n, APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftImm (opcode, encoding, SRType_ROR);
+}
+
+// Rotate Right (register) provides the value of the contents of a register rotated by a variable number of bits.
+// The bits that are rotated off the right end are inserted into the vacated bit positions on the left.
+// The variable number of bits is read from the bottom byte of a register. It can optionally update the condition
+// flags based on the result.
+bool
+EmulateInstructionARM::EmulateRORReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shift_n = UInt(R[m]<7:0>);
+ (result, carry) = Shift_C(R[m], SRType_ROR, shift_n, APSR.C);
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftReg (opcode, encoding, SRType_ROR);
+}
+
+// Rotate Right with Extend provides the value of the contents of a register shifted right by one place,
+// with the carry flag shifted into bit [31].
+//
+// RRX can optionally update the condition flags based on the result.
+// In that case, bit [0] is shifted into the carry flag.
+bool
+EmulateInstructionARM::EmulateRRX (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry) = Shift_C(R[m], SRType_RRX, 1, APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ return EmulateShiftImm (opcode, encoding, SRType_RRX);
+}
+
+bool
+EmulateInstructionARM::EmulateShiftImm (const uint32_t opcode, const ARMEncoding encoding, ARM_ShifterType shift_type)
+{
+// assert(shift_type == SRType_ASR
+// || shift_type == SRType_LSL
+// || shift_type == SRType_LSR
+// || shift_type == SRType_ROR
+// || shift_type == SRType_RRX);
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd; // the destination register
+ uint32_t Rm; // the first operand register
+ uint32_t imm5; // encoding for the shift amount
+ uint32_t carry; // the carry bit after the shift operation
+ bool setflags;
+
+ // Special case handling!
+ // A8.6.139 ROR (immediate) -- Encoding T1
+ ARMEncoding use_encoding = encoding;
+ if (shift_type == SRType_ROR && use_encoding == eEncodingT1)
+ {
+ // Morph the T1 encoding from the ARM Architecture Manual into T2 encoding to
+ // have the same decoding of bit fields as the other Thumb2 shift operations.
+ use_encoding = eEncodingT2;
+ }
+
+ switch (use_encoding) {
+ case eEncodingT1:
+ // Due to the above special case handling!
+ if (shift_type == SRType_ROR)
+ return false;
+
+ Rd = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ imm5 = Bits32(opcode, 10, 6);
+ break;
+ case eEncodingT2:
+ // A8.6.141 RRX
+ // There's no imm form of RRX instructions.
+ if (shift_type == SRType_RRX)
+ return false;
+
+ Rd = Bits32(opcode, 11, 8);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ imm5 = Bits32(opcode, 14, 12) << 2 | Bits32(opcode, 7, 6);
+ if (BadReg(Rd) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ imm5 = Bits32(opcode, 11, 7);
+ break;
+ default:
+ return false;
+ }
+
+ // A8.6.139 ROR (immediate)
+ if (shift_type == SRType_ROR && imm5 == 0)
+ shift_type = SRType_RRX;
+
+ // Get the first operand.
+ uint32_t value = ReadCoreReg (Rm, &success);
+ if (!success)
+ return false;
+
+ // Decode the shift amount if not RRX.
+ uint32_t amt = (shift_type == SRType_RRX ? 1 : DecodeImmShift(shift_type, imm5));
+
+ uint32_t result = Shift_C(value, shift_type, amt, APSR_C, carry, &success);
+ if (!success)
+ return false;
+
+ // The context specifies that an immediate is to be moved into Rd.
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+bool
+EmulateInstructionARM::EmulateShiftReg (const uint32_t opcode, const ARMEncoding encoding, ARM_ShifterType shift_type)
+{
+ // assert(shift_type == SRType_ASR
+ // || shift_type == SRType_LSL
+ // || shift_type == SRType_LSR
+ // || shift_type == SRType_ROR);
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand register
+ uint32_t Rm; // the register whose bottom byte contains the amount to shift by
+ uint32_t carry; // the carry bit after the shift operation
+ bool setflags;
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 2, 0);
+ Rn = Rd;
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 3, 0);
+ Rm = Bits32(opcode, 11, 8);
+ setflags = BitIsSet(opcode, 20);
+ if (Rd == 15 || Rn == 15 || Rm == 15)
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ // Get the first operand.
+ uint32_t value = ReadCoreReg (Rn, &success);
+ if (!success)
+ return false;
+ // Get the Rm register content.
+ uint32_t val = ReadCoreReg (Rm, &success);
+ if (!success)
+ return false;
+
+ // Get the shift amount.
+ uint32_t amt = Bits32(val, 7, 0);
+
+ uint32_t result = Shift_C(value, shift_type, amt, APSR_C, carry, &success);
+ if (!success)
+ return false;
+
+ // The context specifies that an immediate is to be moved into Rd.
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// LDM loads multiple registers from consecutive memory locations, using an
+// address from a base register. Optionally the address just above the highest of those locations
+// can be written back to the base register.
+bool
+EmulateInstructionARM::EmulateLDM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed()
+ EncodingSpecificOperations(); NullCheckIfThumbEE (n);
+ address = R[n];
+
+ for i = 0 to 14
+ if registers<i> == '1' then
+ R[i] = MemA[address, 4]; address = address + 4;
+ if registers<15> == '1' then
+ LoadWritePC (MemA[address, 4]);
+
+ if wback && registers<n> == '0' then R[n] = R[n] + 4 * BitCount (registers);
+ if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
+
+#endif
+
+ bool success = false;
+ bool conditional = false;
+ if (ConditionPassed(opcode, &conditional))
+ {
+ uint32_t n;
+ uint32_t registers = 0;
+ bool wback;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // n = UInt(Rn); registers = '00000000':register_list; wback = (registers<n> == '0');
+ n = Bits32 (opcode, 10, 8);
+ registers = Bits32 (opcode, 7, 0);
+ registers = registers & 0x00ff; // Make sure the top 8 bits are zeros.
+ wback = BitIsClear (registers, n);
+ // if BitCount(registers) < 1 then UNPREDICTABLE;
+ if (BitCount(registers) < 1)
+ return false;
+ break;
+ case eEncodingT2:
+ // if W == '1' && Rn == '1101' then SEE POP;
+ // n = UInt(Rn); registers = P:M:'0':register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ registers = registers & 0xdfff; // Make sure bit 13 is zero.
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 2 || (P == '1' && M == '1') then UNPREDICTABLE;
+ if ((n == 15)
+ || (BitCount (registers) < 2)
+ || (BitIsSet (opcode, 14) && BitIsSet (opcode, 15)))
+ return false;
+
+ // if registers<15> == '1' && InITBlock() && !LastInITBlock() then UNPREDICTABLE;
+ if (BitIsSet (registers, 15) && InITBlock() && !LastInITBlock())
+ return false;
+
+ // if wback && registers<n> == '1' then UNPREDICTABLE;
+ if (wback
+ && BitIsSet (registers, n))
+ return false;
+ break;
+
+ case eEncodingA1:
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ wback = BitIsSet (opcode, 21);
+ if ((n == 15)
+ || (BitCount (registers) < 1))
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ int32_t offset = 0;
+ const addr_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg);
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+
+ for (int i = 0; i < 14; ++i)
+ {
+ if (BitIsSet (registers, i))
+ {
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+ if (wback && (n == 13)) // Pop Instruction
+ {
+ if (conditional)
+ context.type = EmulateInstruction::eContextRegisterLoad;
+ else
+ context.type = EmulateInstruction::eContextPopRegisterOffStack;
+ }
+
+ // R[i] = MemA [address, 4]; address = address + 4;
+ uint32_t data = MemARead (context, base_address + offset, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
+ return false;
+
+ offset += addr_byte_size;
+ }
+ }
+
+ if (BitIsSet (registers, 15))
+ {
+ //LoadWritePC (MemA [address, 4]);
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+ uint32_t data = MemARead (context, base_address + offset, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+ // In ARMv5T and above, this is an interworking branch.
+ if (!LoadWritePC(context, data))
+ return false;
+ }
+
+ if (wback && BitIsClear (registers, n))
+ {
+ // R[n] = R[n] + 4 * BitCount (registers)
+ int32_t offset = addr_byte_size * BitCount (registers);
+ context.type = EmulateInstruction::eContextAdjustBaseRegister;
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, base_address + offset))
+ return false;
+ }
+ if (wback && BitIsSet (registers, n))
+ // R[n] bits(32) UNKNOWN;
+ return WriteBits32Unknown (n);
+ }
+ return true;
+}
+
+// LDMDA loads multiple registers from consecutive memory locations using an address from a base register.
+// The consecutive memory locations end at this address and the address just below the lowest of those locations
+// can optionally be written back to the base register.
+bool
+EmulateInstructionARM::EmulateLDMDA (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ address = R[n] - 4*BitCount(registers) + 4;
+
+ for i = 0 to 14
+ if registers<i> == '1' then
+ R[i] = MemA[address,4]; address = address + 4;
+
+ if registers<15> == '1' then
+ LoadWritePC(MemA[address,4]);
+
+ if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers);
+ if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t n;
+ uint32_t registers = 0;
+ bool wback;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ // EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // n = UInt(Rn); registers = register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
+ if ((n == 15) || (BitCount (registers) < 1))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+ // address = R[n] - 4*BitCount(registers) + 4;
+
+ int32_t offset = 0;
+ addr_t Rn = ReadCoreReg (n, &success);
+
+ if (!success)
+ return false;
+
+ addr_t address = Rn - (addr_byte_size * BitCount (registers)) + addr_byte_size;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg);
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+
+ // for i = 0 to 14
+ for (int i = 0; i < 14; ++i)
+ {
+ // if registers<i> == '1' then
+ if (BitIsSet (registers, i))
+ {
+ // R[i] = MemA[address,4]; address = address + 4;
+ context.SetRegisterPlusOffset (dwarf_reg, Rn - (address + offset));
+ uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
+ return false;
+ offset += addr_byte_size;
+ }
+ }
+
+ // if registers<15> == '1' then
+ // LoadWritePC(MemA[address,4]);
+ if (BitIsSet (registers, 15))
+ {
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+ uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+ // In ARMv5T and above, this is an interworking branch.
+ if (!LoadWritePC(context, data))
+ return false;
+ }
+
+ // if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers);
+ if (wback && BitIsClear (registers, n))
+ {
+ if (!success)
+ return false;
+
+ offset = (addr_byte_size * BitCount (registers)) * -1;
+ context.type = EmulateInstruction::eContextAdjustBaseRegister;
+ context.SetImmediateSigned (offset);
+ addr_t addr = Rn + offset;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr))
+ return false;
+ }
+
+ // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN;
+ if (wback && BitIsSet (registers, n))
+ return WriteBits32Unknown (n);
+ }
+ return true;
+}
+
+// LDMDB loads multiple registers from consecutive memory locations using an address from a base register. The
+// consecutive memory lcoations end just below this address, and the address of the lowest of those locations can
+// be optionally written back to the base register.
+bool
+EmulateInstructionARM::EmulateLDMDB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ address = R[n] - 4*BitCount(registers);
+
+ for i = 0 to 14
+ if registers<i> == '1' then
+ R[i] = MemA[address,4]; address = address + 4;
+ if registers<15> == '1' then
+ LoadWritePC(MemA[address,4]);
+
+ if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers);
+ if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t n;
+ uint32_t registers = 0;
+ bool wback;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // n = UInt(Rn); registers = P:M:'0':register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ registers = registers & 0xdfff; // Make sure bit 13 is a zero.
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 2 || (P == '1' && M == '1') then UNPREDICTABLE;
+ if ((n == 15)
+ || (BitCount (registers) < 2)
+ || (BitIsSet (opcode, 14) && BitIsSet (opcode, 15)))
+ return false;
+
+ // if registers<15> == '1' && InITBlock() && !LastInITBlock() then UNPREDICTABLE;
+ if (BitIsSet (registers, 15) && InITBlock() && !LastInITBlock())
+ return false;
+
+ // if wback && registers<n> == '1' then UNPREDICTABLE;
+ if (wback && BitIsSet (registers, n))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // n = UInt(Rn); registers = register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
+ if ((n == 15) || (BitCount (registers) < 1))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // address = R[n] - 4*BitCount(registers);
+
+ int32_t offset = 0;
+ addr_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+
+ if (!success)
+ return false;
+
+ addr_t address = Rn - (addr_byte_size * BitCount (registers));
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg);
+ context.SetRegisterPlusOffset (dwarf_reg, Rn - address);
+
+ for (int i = 0; i < 14; ++i)
+ {
+ if (BitIsSet (registers, i))
+ {
+ // R[i] = MemA[address,4]; address = address + 4;
+ context.SetRegisterPlusOffset (dwarf_reg, Rn - (address + offset));
+ uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
+ return false;
+
+ offset += addr_byte_size;
+ }
+ }
+
+ // if registers<15> == '1' then
+ // LoadWritePC(MemA[address,4]);
+ if (BitIsSet (registers, 15))
+ {
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+ uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+ // In ARMv5T and above, this is an interworking branch.
+ if (!LoadWritePC(context, data))
+ return false;
+ }
+
+ // if wback && registers<n> == '0' then R[n] = R[n] - 4*BitCount(registers);
+ if (wback && BitIsClear (registers, n))
+ {
+ if (!success)
+ return false;
+
+ offset = (addr_byte_size * BitCount (registers)) * -1;
+ context.type = EmulateInstruction::eContextAdjustBaseRegister;
+ context.SetImmediateSigned (offset);
+ addr_t addr = Rn + offset;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr))
+ return false;
+ }
+
+ // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
+ if (wback && BitIsSet (registers, n))
+ return WriteBits32Unknown (n);
+ }
+ return true;
+}
+
+// LDMIB loads multiple registers from consecutive memory locations using an address from a base register. The
+// consecutive memory locations start just above this address, and thea ddress of the last of those locations can
+// optinoally be written back to the base register.
+bool
+EmulateInstructionARM::EmulateLDMIB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ address = R[n] + 4;
+
+ for i = 0 to 14
+ if registers<i> == '1' then
+ R[i] = MemA[address,4]; address = address + 4;
+ if registers<15> == '1' then
+ LoadWritePC(MemA[address,4]);
+
+ if wback && registers<n> == '0' then R[n] = R[n] + 4*BitCount(registers);
+ if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t n;
+ uint32_t registers = 0;
+ bool wback;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // n = UInt(Rn); registers = register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
+ if ((n == 15) || (BitCount (registers) < 1))
+ return false;
+
+ break;
+ default:
+ return false;
+ }
+ // address = R[n] + 4;
+
+ int32_t offset = 0;
+ addr_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+
+ if (!success)
+ return false;
+
+ addr_t address = Rn + addr_byte_size;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterPlusOffset;
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, dwarf_reg);
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+
+ for (int i = 0; i < 14; ++i)
+ {
+ if (BitIsSet (registers, i))
+ {
+ // R[i] = MemA[address,4]; address = address + 4;
+
+ context.SetRegisterPlusOffset (dwarf_reg, offset + addr_byte_size);
+ uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data))
+ return false;
+
+ offset += addr_byte_size;
+ }
+ }
+
+ // if registers<15> == '1' then
+ // LoadWritePC(MemA[address,4]);
+ if (BitIsSet (registers, 15))
+ {
+ context.SetRegisterPlusOffset (dwarf_reg, offset);
+ uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+ // In ARMv5T and above, this is an interworking branch.
+ if (!LoadWritePC(context, data))
+ return false;
+ }
+
+ // if wback && registers<n> == '0' then R[n] = R[n] + 4*BitCount(registers);
+ if (wback && BitIsClear (registers, n))
+ {
+ if (!success)
+ return false;
+
+ offset = addr_byte_size * BitCount (registers);
+ context.type = EmulateInstruction::eContextAdjustBaseRegister;
+ context.SetImmediateSigned (offset);
+ addr_t addr = Rn + offset;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr))
+ return false;
+ }
+
+ // if wback && registers<n> == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1
+ if (wback && BitIsSet (registers, n))
+ return WriteBits32Unknown (n);
+ }
+ return true;
+}
+
+// Load Register (immediate) calculates an address from a base register value and
+// an immediate offset, loads a word from memory, and writes to a register.
+// LDR (immediate, Thumb)
+bool
+EmulateInstructionARM::EmulateLDRRtRnImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if (ConditionPassed())
+ {
+ EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ data = MemU[address,4];
+ if wback then R[n] = offset_addr;
+ if t == 15 then
+ if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
+ elsif UnalignedSupport() || address<1:0> = '00' then
+ R[t] = data;
+ else R[t] = bits(32) UNKNOWN; // Can only apply before ARMv7
+ }
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rt; // the destination register
+ uint32_t Rn; // the base register
+ uint32_t imm32; // the immediate offset used to form the address
+ addr_t offset_addr; // the offset address
+ addr_t address; // the calculated address
+ uint32_t data; // the literal data value from memory load
+ bool add, index, wback;
+ switch (encoding) {
+ case eEncodingT1:
+ Rt = Bits32(opcode, 2, 0);
+ Rn = Bits32(opcode, 5, 3);
+ imm32 = Bits32(opcode, 10, 6) << 2; // imm32 = ZeroExtend(imm5:'00', 32);
+ // index = TRUE; add = TRUE; wback = FALSE
+ add = true;
+ index = true;
+ wback = false;
+
+ break;
+
+ case eEncodingT2:
+ // t = UInt(Rt); n = 13; imm32 = ZeroExtend(imm8:'00', 32);
+ Rt = Bits32 (opcode, 10, 8);
+ Rn = 13;
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ break;
+
+ case eEncodingT3:
+ // if Rn == '1111' then SEE LDR (literal);
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ Rt = Bits32 (opcode, 15, 12);
+ Rn = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // if t == 15 && InITBlock() && !LastInITBlock() then UNPREDICTABLE;
+ if ((Rt == 15) && InITBlock() && !LastInITBlock())
+ return false;
+
+ break;
+
+ case eEncodingT4:
+ // if Rn == '1111' then SEE LDR (literal);
+ // if P == '1' && U == '1' && W == '0' then SEE LDRT;
+ // if Rn == '1101' && P == '0' && U == '1' && W == '1' && imm8 == '00000100' then SEE POP;
+ // if P == '0' && W == '0' then UNDEFINED;
+ if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8))
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
+ Rt = Bits32 (opcode, 15, 12);
+ Rn = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (W == '1');
+ index = BitIsSet (opcode, 10);
+ add = BitIsSet (opcode, 9);
+ wback = BitIsSet (opcode, 8);
+
+ // if (wback && n == t) || (t == 15 && InITBlock() && !LastInITBlock()) then UNPREDICTABLE;
+ if ((wback && (Rn == Rt)) || ((Rt == 15) && InITBlock() && !LastInITBlock()))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+ uint32_t base = ReadCoreReg (Rn, &success);
+ if (!success)
+ return false;
+ if (add)
+ offset_addr = base + imm32;
+ else
+ offset_addr = base - imm32;
+
+ address = (index ? offset_addr : base);
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + Rn, base_reg);
+ if (wback)
+ {
+ EmulateInstruction::Context ctx;
+ ctx.type = EmulateInstruction::eContextAdjustBaseRegister;
+ ctx.SetRegisterPlusOffset (base_reg, (int32_t) (offset_addr - base));
+
+ if (!WriteRegisterUnsigned (ctx, eRegisterKindDWARF, dwarf_r0 + Rn, offset_addr))
+ return false;
+ }
+
+ // Prepare to write to the Rt register.
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, (int32_t) (offset_addr - base));
+
+ // Read memory from the address.
+ data = MemURead(context, address, 4, 0, &success);
+ if (!success)
+ return false;
+
+ if (Rt == 15)
+ {
+ if (Bits32(address, 1, 0) == 0)
+ {
+ if (!LoadWritePC(context, data))
+ return false;
+ }
+ else
+ return false;
+ }
+ else if (UnalignedSupport() || Bits32(address, 1, 0) == 0)
+ {
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rt, data))
+ return false;
+ }
+ else
+ WriteBits32Unknown (Rt);
+ }
+ return true;
+}
+
+// STM (Store Multiple Increment After) stores multiple registers to consecutive memory locations using an address
+// from a base register. The consecutive memory locations start at this address, and teh address just above the last
+// of those locations can optionally be written back to the base register.
+bool
+EmulateInstructionARM::EmulateSTM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ address = R[n];
+
+ for i = 0 to 14
+ if registers<i> == '1' then
+ if i == n && wback && i != LowestSetBit(registers) then
+ MemA[address,4] = bits(32) UNKNOWN; // Only possible for encodings T1 and A1
+ else
+ MemA[address,4] = R[i];
+ address = address + 4;
+
+ if registers<15> == '1' then // Only possible for encoding A1
+ MemA[address,4] = PCStoreValue();
+ if wback then R[n] = R[n] + 4*BitCount(registers);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t n;
+ uint32_t registers = 0;
+ bool wback;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // n = UInt(Rn); registers = '00000000':register_list; wback = TRUE;
+ n = Bits32 (opcode, 10, 8);
+ registers = Bits32 (opcode, 7, 0);
+ registers = registers & 0x00ff; // Make sure the top 8 bits are zeros.
+ wback = true;
+
+ // if BitCount(registers) < 1 then UNPREDICTABLE;
+ if (BitCount (registers) < 1)
+ return false;
+
+ break;
+
+ case eEncodingT2:
+ // n = UInt(Rn); registers = '0':M:'0':register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ registers = registers & 0x5fff; // Make sure bits 15 & 13 are zeros.
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 2 then UNPREDICTABLE;
+ if ((n == 15) || (BitCount (registers) < 2))
+ return false;
+
+ // if wback && registers<n> == '1' then UNPREDICTABLE;
+ if (wback && BitIsSet (registers, n))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // n = UInt(Rn); registers = register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
+ if ((n == 15) || (BitCount (registers) < 1))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // address = R[n];
+ int32_t offset = 0;
+ const addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterStore;
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ // for i = 0 to 14
+ uint32_t lowest_set_bit = 14;
+ for (uint32_t i = 0; i < 14; ++i)
+ {
+ // if registers<i> == '1' then
+ if (BitIsSet (registers, i))
+ {
+ if (i < lowest_set_bit)
+ lowest_set_bit = i;
+ // if i == n && wback && i != LowestSetBit(registers) then
+ if ((i == n) && wback && (i != lowest_set_bit))
+ // MemA[address,4] = bits(32) UNKNOWN; // Only possible for encodings T1 and A1
+ WriteBits32UnknownToMemory (address + offset);
+ else
+ {
+ // MemA[address,4] = R[i];
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + i, 0, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + i, data_reg);
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, offset);
+ if (!MemAWrite (context, address + offset, data, addr_byte_size))
+ return false;
+ }
+
+ // address = address + 4;
+ offset += addr_byte_size;
+ }
+ }
+
+ // if registers<15> == '1' then // Only possible for encoding A1
+ // MemA[address,4] = PCStoreValue();
+ if (BitIsSet (registers, 15))
+ {
+ RegisterInfo pc_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, pc_reg);
+ context.SetRegisterPlusOffset (pc_reg, 8);
+ const uint32_t pc = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+
+ if (!MemAWrite (context, address + offset, pc, addr_byte_size))
+ return false;
+ }
+
+ // if wback then R[n] = R[n] + 4*BitCount(registers);
+ if (wback)
+ {
+ offset = addr_byte_size * BitCount (registers);
+ context.type = EmulateInstruction::eContextAdjustBaseRegister;
+ context.SetImmediateSigned (offset);
+ addr_t data = address + offset;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data))
+ return false;
+ }
+ }
+ return true;
+}
+
+// STMDA (Store Multiple Decrement After) stores multiple registers to consecutive memory locations using an address
+// from a base register. The consecutive memory locations end at this address, and the address just below the lowest
+// of those locations can optionally be written back to the base register.
+bool
+EmulateInstructionARM::EmulateSTMDA (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ address = R[n] - 4*BitCount(registers) + 4;
+
+ for i = 0 to 14
+ if registers<i> == '1' then
+ if i == n && wback && i != LowestSetBit(registers) then
+ MemA[address,4] = bits(32) UNKNOWN;
+ else
+ MemA[address,4] = R[i];
+ address = address + 4;
+
+ if registers<15> == '1' then
+ MemA[address,4] = PCStoreValue();
+
+ if wback then R[n] = R[n] - 4*BitCount(registers);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t n;
+ uint32_t registers = 0;
+ bool wback;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ // EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // n = UInt(Rn); registers = register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
+ if ((n == 15) || (BitCount (registers) < 1))
+ return false;
+ break;
+ default:
+ return false;
+ }
+
+ // address = R[n] - 4*BitCount(registers) + 4;
+ int32_t offset = 0;
+ addr_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ addr_t address = Rn - (addr_byte_size * BitCount (registers)) + 4;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterStore;
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ // for i = 0 to 14
+ uint32_t lowest_bit_set = 14;
+ for (uint32_t i = 0; i < 14; ++i)
+ {
+ // if registers<i> == '1' then
+ if (BitIsSet (registers, i))
+ {
+ if (i < lowest_bit_set)
+ lowest_bit_set = i;
+ //if i == n && wback && i != LowestSetBit(registers) then
+ if ((i == n) && wback && (i != lowest_bit_set))
+ // MemA[address,4] = bits(32) UNKNOWN;
+ WriteBits32UnknownToMemory (address + offset);
+ else
+ {
+ // MemA[address,4] = R[i];
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + i, 0, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + i, data_reg);
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, Rn - (address + offset));
+ if (!MemAWrite (context, address + offset, data, addr_byte_size))
+ return false;
+ }
+
+ // address = address + 4;
+ offset += addr_byte_size;
+ }
+ }
+
+ // if registers<15> == '1' then
+ // MemA[address,4] = PCStoreValue();
+ if (BitIsSet (registers, 15))
+ {
+ RegisterInfo pc_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, pc_reg);
+ context.SetRegisterPlusOffset (pc_reg, 8);
+ const uint32_t pc = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+
+ if (!MemAWrite (context, address + offset, pc, addr_byte_size))
+ return false;
+ }
+
+ // if wback then R[n] = R[n] - 4*BitCount(registers);
+ if (wback)
+ {
+ offset = (addr_byte_size * BitCount (registers)) * -1;
+ context.type = EmulateInstruction::eContextAdjustBaseRegister;
+ context.SetImmediateSigned (offset);
+ addr_t data = Rn + offset;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data))
+ return false;
+ }
+ }
+ return true;
+}
+
+// STMDB (Store Multiple Decrement Before) stores multiple registers to consecutive memory locations using an address
+// from a base register. The consecutive memory locations end just below this address, and the address of the first of
+// those locations can optionally be written back to the base register.
+bool
+EmulateInstructionARM::EmulateSTMDB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ address = R[n] - 4*BitCount(registers);
+
+ for i = 0 to 14
+ if registers<i> == '1' then
+ if i == n && wback && i != LowestSetBit(registers) then
+ MemA[address,4] = bits(32) UNKNOWN; // Only possible for encoding A1
+ else
+ MemA[address,4] = R[i];
+ address = address + 4;
+
+ if registers<15> == '1' then // Only possible for encoding A1
+ MemA[address,4] = PCStoreValue();
+
+ if wback then R[n] = R[n] - 4*BitCount(registers);
+#endif
+
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t n;
+ uint32_t registers = 0;
+ bool wback;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if W == '1' && Rn == '1101' then SEE PUSH;
+ if ((BitIsSet (opcode, 21)) && (Bits32 (opcode, 19, 16) == 13))
+ {
+ // See PUSH
+ }
+ // n = UInt(Rn); registers = '0':M:'0':register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ registers = registers & 0x5fff; // Make sure bits 15 & 13 are zeros.
+ wback = BitIsSet (opcode, 21);
+ // if n == 15 || BitCount(registers) < 2 then UNPREDICTABLE;
+ if ((n == 15) || BitCount (registers) < 2)
+ return false;
+ // if wback && registers<n> == '1' then UNPREDICTABLE;
+ if (wback && BitIsSet (registers, n))
+ return false;
+ break;
+
+ case eEncodingA1:
+ // if W == '1' && Rn == '1101Õ && BitCount(register_list) >= 2 then SEE PUSH;
+ if (BitIsSet (opcode, 21) && (Bits32 (opcode, 19, 16) == 13) && BitCount (Bits32 (opcode, 15, 0)) >= 2)
+ {
+ // See Push
+ }
+ // n = UInt(Rn); registers = register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ wback = BitIsSet (opcode, 21);
+ // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
+ if ((n == 15) || BitCount (registers) < 1)
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ // address = R[n] - 4*BitCount(registers);
+
+ int32_t offset = 0;
+ addr_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ addr_t address = Rn - (addr_byte_size * BitCount (registers));
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterStore;
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ // for i = 0 to 14
+ uint32_t lowest_set_bit = 14;
+ for (uint32_t i = 0; i < 14; ++i)
+ {
+ // if registers<i> == '1' then
+ if (BitIsSet (registers, i))
+ {
+ if (i < lowest_set_bit)
+ lowest_set_bit = i;
+ // if i == n && wback && i != LowestSetBit(registers) then
+ if ((i == n) && wback && (i != lowest_set_bit))
+ // MemA[address,4] = bits(32) UNKNOWN; // Only possible for encoding A1
+ WriteBits32UnknownToMemory (address + offset);
+ else
+ {
+ // MemA[address,4] = R[i];
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + i, 0, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + i, data_reg);
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, Rn - (address + offset));
+ if (!MemAWrite (context, address + offset, data, addr_byte_size))
+ return false;
+ }
+
+ // address = address + 4;
+ offset += addr_byte_size;
+ }
+ }
+
+ // if registers<15> == '1' then // Only possible for encoding A1
+ // MemA[address,4] = PCStoreValue();
+ if (BitIsSet (registers, 15))
+ {
+ RegisterInfo pc_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, pc_reg);
+ context.SetRegisterPlusOffset (pc_reg, 8);
+ const uint32_t pc = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+
+ if (!MemAWrite (context, address + offset, pc, addr_byte_size))
+ return false;
+ }
+
+ // if wback then R[n] = R[n] - 4*BitCount(registers);
+ if (wback)
+ {
+ offset = (addr_byte_size * BitCount (registers)) * -1;
+ context.type = EmulateInstruction::eContextAdjustBaseRegister;
+ context.SetImmediateSigned (offset);
+ addr_t data = Rn + offset;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data))
+ return false;
+ }
+ }
+ return true;
+}
+
+// STMIB (Store Multiple Increment Before) stores multiple registers to consecutive memory locations using an address
+// from a base register. The consecutive memory locations start just above this address, and the address of the last
+// of those locations can optionally be written back to the base register.
+bool
+EmulateInstructionARM::EmulateSTMIB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ address = R[n] + 4;
+
+ for i = 0 to 14
+ if registers<i> == '1' then
+ if i == n && wback && i != LowestSetBit(registers) then
+ MemA[address,4] = bits(32) UNKNOWN;
+ else
+ MemA[address,4] = R[i];
+ address = address + 4;
+
+ if registers<15> == '1' then
+ MemA[address,4] = PCStoreValue();
+
+ if wback then R[n] = R[n] + 4*BitCount(registers);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t n;
+ uint32_t registers = 0;
+ bool wback;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ // EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // n = UInt(Rn); registers = register_list; wback = (W == '1');
+ n = Bits32 (opcode, 19, 16);
+ registers = Bits32 (opcode, 15, 0);
+ wback = BitIsSet (opcode, 21);
+
+ // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE;
+ if ((n == 15) && (BitCount (registers) < 1))
+ return false;
+ break;
+ default:
+ return false;
+ }
+ // address = R[n] + 4;
+
+ int32_t offset = 0;
+ addr_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ addr_t address = Rn + addr_byte_size;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextRegisterStore;
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t lowest_set_bit = 14;
+ // for i = 0 to 14
+ for (uint32_t i = 0; i < 14; ++i)
+ {
+ // if registers<i> == '1' then
+ if (BitIsSet (registers, i))
+ {
+ if (i < lowest_set_bit)
+ lowest_set_bit = i;
+ // if i == n && wback && i != LowestSetBit(registers) then
+ if ((i == n) && wback && (i != lowest_set_bit))
+ // MemA[address,4] = bits(32) UNKNOWN;
+ WriteBits32UnknownToMemory (address + offset);
+ // else
+ else
+ {
+ // MemA[address,4] = R[i];
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + i, 0, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + i, data_reg);
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, offset + addr_byte_size);
+ if (!MemAWrite (context, address + offset, data, addr_byte_size))
+ return false;
+ }
+
+ // address = address + 4;
+ offset += addr_byte_size;
+ }
+ }
+
+ // if registers<15> == '1' then
+ // MemA[address,4] = PCStoreValue();
+ if (BitIsSet (registers, 15))
+ {
+ RegisterInfo pc_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_pc, pc_reg);
+ context.SetRegisterPlusOffset (pc_reg, 8);
+ const uint32_t pc = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+
+ if (!MemAWrite (context, address + offset, pc, addr_byte_size))
+ return false;
+ }
+
+ // if wback then R[n] = R[n] + 4*BitCount(registers);
+ if (wback)
+ {
+ offset = addr_byte_size * BitCount (registers);
+ context.type = EmulateInstruction::eContextAdjustBaseRegister;
+ context.SetImmediateSigned (offset);
+ addr_t data = Rn + offset;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data))
+ return false;
+ }
+ }
+ return true;
+}
+
+// STR (store immediate) calcualtes an address from a base register value and an immediate offset, and stores a word
+// from a register to memory. It can use offset, post-indexed, or pre-indexed addressing.
+bool
+EmulateInstructionARM::EmulateSTRThumb (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ if UnalignedSupport() || address<1:0> == '00' then
+ MemU[address,4] = R[t];
+ else // Can only occur before ARMv7
+ MemU[address,4] = bits(32) UNKNOWN;
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+ // EncodingSpecificOperations (); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5:'00', 32);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ imm32 = Bits32 (opcode, 10, 6) << 2;
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = false;
+ wback = false;
+ break;
+
+ case eEncodingT2:
+ // t = UInt(Rt); n = 13; imm32 = ZeroExtend(imm8:'00', 32);
+ t = Bits32 (opcode, 10, 8);
+ n = 13;
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+ break;
+
+ case eEncodingT3:
+ // if Rn == '1111' then UNDEFINED;
+ if (Bits32 (opcode, 19, 16) == 15)
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // if t == 15 then UNPREDICTABLE;
+ if (t == 15)
+ return false;
+ break;
+
+ case eEncodingT4:
+ // if P == '1' && U == '1' && W == '0' then SEE STRT;
+ // if Rn == '1101' && P == '1' && U == '0' && W == '1' && imm8 == '00000100' then SEE PUSH;
+ // if Rn == '1111' || (P == '0' && W == '0') then UNDEFINED;
+ if ((Bits32 (opcode, 19, 16) == 15)
+ || (BitIsClear (opcode, 10) && BitIsClear (opcode, 8)))
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (W == '1');
+ index = BitIsSet (opcode, 10);
+ add = BitIsSet (opcode, 9);
+ wback = BitIsSet (opcode, 8);
+
+ // if t == 15 || (wback && n == t) then UNPREDICTABLE;
+ if ((t == 15) || (wback && (n == t)))
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ addr_t offset_addr;
+ addr_t address;
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ uint32_t base_address = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ if (add)
+ offset_addr = base_address + imm32;
+ else
+ offset_addr = base_address - imm32;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = base_address;
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ // if UnalignedSupport() || address<1:0> == '00' then
+ if (UnalignedSupport () || (BitIsClear (address, 1) && BitIsClear (address, 0)))
+ {
+ // MemU[address,4] = R[t];
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + t, 0, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+ int32_t offset = address - base_address;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, offset);
+ if (!MemUWrite (context, address, data, addr_byte_size))
+ return false;
+ }
+ else
+ {
+ // MemU[address,4] = bits(32) UNKNOWN;
+ WriteBits32UnknownToMemory (address);
+ }
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextRegisterLoad;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// STR (Store Register) calculates an address from a base register value and an offset register value, stores a
+// word from a register to memory. The offset register value can optionally be shifted.
+bool
+EmulateInstructionARM::EmulateSTRRegister (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ address = if index then offset_addr else R[n];
+ if t == 15 then // Only possible for encoding A1
+ data = PCStoreValue();
+ else
+ data = R[t];
+ if UnalignedSupport() || address<1:0> == '00' || CurrentInstrSet() == InstrSet_ARM then
+ MemU[address,4] = data;
+ else // Can only occur before ARMv7
+ MemU[address,4] = bits(32) UNKNOWN;
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ uint32_t t;
+ uint32_t n;
+ uint32_t m;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+ bool index;
+ bool add;
+ bool wback;
+
+ // EncodingSpecificOperations (); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation in ThumbEE";
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 8, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+
+ case eEncodingT2:
+ // if Rn == '1111' then UNDEFINED;
+ if (Bits32 (opcode, 19, 16) == 15)
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
+ shift_t = SRType_LSL;
+ shift_n = Bits32 (opcode, 5, 4);
+
+ // if t == 15 || BadReg(m) then UNPREDICTABLE;
+ if ((t == 15) || (BadReg (m)))
+ return false;
+ break;
+
+ case eEncodingA1:
+ {
+ // if P == '0' && W == '1' then SEE STRT;
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21));
+
+ // (shift_t, shift_n) = DecodeImmShift(type, imm5);
+ uint32_t typ = Bits32 (opcode, 6, 5);
+ uint32_t imm5 = Bits32 (opcode, 11, 7);
+ shift_n = DecodeImmShift(typ, imm5, shift_t);
+
+ // if m == 15 then UNPREDICTABLE;
+ if (m == 15)
+ return false;
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+
+ break;
+ }
+ default:
+ return false;
+ }
+
+ addr_t offset_addr;
+ addr_t address;
+ int32_t offset = 0;
+
+ addr_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ uint32_t Rm_data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ // offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ offset = Shift (Rm_data, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ if (add)
+ offset_addr = base_address + offset;
+ else
+ offset_addr = base_address - offset;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = base_address;
+
+ uint32_t data;
+ // if t == 15 then // Only possible for encoding A1
+ if (t == 15)
+ // data = PCStoreValue();
+ data = ReadCoreReg (PC_REG, &success);
+ else
+ // data = R[t];
+ data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + t, 0, &success);
+
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+
+ // if UnalignedSupport() || address<1:0> == '00' || CurrentInstrSet() == InstrSet_ARM then
+ if (UnalignedSupport ()
+ || (BitIsClear (address, 1) && BitIsClear (address, 0))
+ || CurrentInstrSet() == eModeARM)
+ {
+ // MemU[address,4] = data;
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - base_address);
+ if (!MemUWrite (context, address, data, addr_byte_size))
+ return false;
+
+ }
+ else
+ // MemU[address,4] = bits(32) UNKNOWN;
+ WriteBits32UnknownToMemory (address);
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextRegisterLoad;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+
+ }
+ return true;
+}
+
+bool
+EmulateInstructionARM::EmulateSTRBThumb (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ MemU[address,1] = R[t]<7:0>;
+ if wback then R[n] = offset_addr;
+#endif
+
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5, 32);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ imm32 = Bits32 (opcode, 10, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+ break;
+
+ case eEncodingT2:
+ // if Rn == '1111' then UNDEFINED;
+ if (Bits32 (opcode, 19, 16) == 15)
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // if BadReg(t) then UNPREDICTABLE;
+ if (BadReg (t))
+ return false;
+ break;
+
+ case eEncodingT3:
+ // if P == '1' && U == '1' && W == '0' then SEE STRBT;
+ // if Rn == '1111' || (P == '0' && W == '0') then UNDEFINED;
+ if (Bits32 (opcode, 19, 16) == 15)
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (W == '1');
+ index = BitIsSet (opcode, 10);
+ add = BitIsSet (opcode, 9);
+ wback = BitIsSet (opcode, 8);
+
+ // if BadReg(t) || (wback && n == t) then UNPREDICTABLE
+ if ((BadReg (t)) || (wback && (n == t)))
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ addr_t offset_addr;
+ addr_t address;
+ addr_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ if (add)
+ offset_addr = base_address + imm32;
+ else
+ offset_addr = base_address - imm32;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = base_address;
+
+ // MemU[address,1] = R[t]<7:0>
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - base_address);
+
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + t, 0, &success);
+ if (!success)
+ return false;
+
+ data = Bits32 (data, 7, 0);
+
+ if (!MemUWrite (context, address, data, 1))
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextRegisterLoad;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+
+ }
+
+ return true;
+}
+
+// STRH (register) calculates an address from a base register value and an offset register value, and stores a
+// halfword from a register to memory. The offset register alue can be shifted left by 0, 1, 2, or 3 bits.
+bool
+EmulateInstructionARM::EmulateSTRHRegister (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ address = if index then offset_addr else R[n];
+ if UnalignedSupport() || address<0> == '0' then
+ MemU[address,2] = R[t]<15:0>;
+ else // Can only occur before ARMv7
+ MemU[address,2] = bits(16) UNKNOWN;
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t m;
+ bool index;
+ bool add;
+ bool wback;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation in ThumbEE";
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 8, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ break;
+
+ case eEncodingT2:
+ // if Rn == '1111' then UNDEFINED;
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+ if (n == 15)
+ return false;
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
+ shift_t = SRType_LSL;
+ shift_n = Bits32 (opcode, 5, 4);
+
+ // if BadReg(t) || BadReg(m) then UNPREDICTABLE;
+ if (BadReg (t) || BadReg (m))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // if P == '0' && W == '1' then SEE STRHT;
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21));
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ // if t == 15 || m == 15 then UNPREDICTABLE;
+ if ((t == 15) || (m == 15))
+ return false;
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ uint32_t offset = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ addr_t offset_addr;
+ if (add)
+ offset_addr = Rn + offset;
+ else
+ offset_addr = Rn - offset;
+
+ // address = if index then offset_addr else R[n];
+ addr_t address;
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ RegisterInfo offset_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
+
+ // if UnalignedSupport() || address<0> == '0' then
+ if (UnalignedSupport() || BitIsClear (address, 0))
+ {
+ // MemU[address,2] = R[t]<15:0>;
+ uint32_t Rt = ReadCoreReg (t, &success);
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ RegisterInfo offset_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+ context.SetRegisterToRegisterPlusIndirectOffset (base_reg, offset_reg, data_reg);
+
+ if (!MemUWrite (context, address, Bits32 (Rt, 15, 0), 2))
+ return false;
+ }
+ else // Can only occur before ARMv7
+ {
+ // MemU[address,2] = bits(16) UNKNOWN;
+ }
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// Add with Carry (immediate) adds an immediate value and the carry flag value to a register value,
+// and writes the result to the destination register. It can optionally update the condition flags
+// based on the result.
+bool
+EmulateInstructionARM::EmulateADCImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(R[n], imm32, APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn;
+ uint32_t imm32; // the immediate value to be added to the value obtained from Rn
+ bool setflags;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
+ if (BadReg(Rd) || BadReg(Rn))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ int32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(val1, imm32, APSR_C);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+ }
+ return true;
+}
+
+// Add with Carry (register) adds a register value, the carry flag value, and an optionally-shifted
+// register value, and writes the result to the destination register. It can optionally update the
+// condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateADCReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(R[n], shifted, APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn, Rm;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ bool setflags;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ int32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the second operand.
+ int32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+ AddWithCarryResult res = AddWithCarry(val1, shifted, APSR_C);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+ }
+ return true;
+}
+
+// This instruction adds an immediate value to the PC value to form a PC-relative address,
+// and writes the result to the destination register.
+bool
+EmulateInstructionARM::EmulateADR (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ result = if add then (Align(PC,4) + imm32) else (Align(PC,4) - imm32);
+ if d == 15 then // Can only occur for ARM encodings
+ ALUWritePC(result);
+ else
+ R[d] = result;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd;
+ uint32_t imm32; // the immediate value to be added/subtracted to/from the PC
+ bool add;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 10, 8);
+ imm32 = ThumbImm8Scaled(opcode); // imm32 = ZeroExtend(imm8:'00', 32)
+ add = true;
+ break;
+ case eEncodingT2:
+ case eEncodingT3:
+ Rd = Bits32(opcode, 11, 8);
+ imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32)
+ add = (Bits32(opcode, 24, 21) == 0); // 0b0000 => ADD; 0b0101 => SUB
+ if (BadReg(Rd))
+ return false;
+ break;
+ case eEncodingA1:
+ case eEncodingA2:
+ Rd = Bits32(opcode, 15, 12);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+ add = (Bits32(opcode, 24, 21) == 0x4); // 0b0100 => ADD; 0b0010 => SUB
+ break;
+ default:
+ return false;
+ }
+
+ // Read the PC value.
+ uint32_t pc = ReadCoreReg(PC_REG, &success);
+ if (!success)
+ return false;
+
+ uint32_t result = (add ? Align(pc, 4) + imm32 : Align(pc, 4) - imm32);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreReg(context, result, Rd))
+ return false;
+ }
+ return true;
+}
+
+// This instruction performs a bitwise AND of a register value and an immediate value, and writes the result
+// to the destination register. It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateANDImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ result = R[n] AND imm32;
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn;
+ uint32_t imm32; // the immediate value to be ANDed to the value obtained from Rn
+ bool setflags;
+ uint32_t carry; // the carry bit after ARM/Thumb Expand operation
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
+ // if Rd == '1111' && S == '1' then SEE TST (immediate);
+ if (Rd == 15 && setflags)
+ return EmulateTSTImm(opcode, eEncodingT1);
+ if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
+
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ uint32_t result = val1 & imm32;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// This instruction performs a bitwise AND of a register value and an optionally-shifted register value,
+// and writes the result to the destination register. It can optionally update the condition flags
+// based on the result.
+bool
+EmulateInstructionARM::EmulateANDReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
+ result = R[n] AND shifted;
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn, Rm;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ bool setflags;
+ uint32_t carry;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ // if Rd == '1111' && S == '1' then SEE TST (register);
+ if (Rd == 15 && setflags)
+ return EmulateTSTReg(opcode, eEncodingT2);
+ if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the second operand.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
+ if (!success)
+ return false;
+ uint32_t result = val1 & shifted;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// Bitwise Bit Clear (immediate) performs a bitwise AND of a register value and the complement of an
+// immediate value, and writes the result to the destination register. It can optionally update the
+// condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateBICImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ result = R[n] AND NOT(imm32);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn;
+ uint32_t imm32; // the immediate value to be bitwise inverted and ANDed to the value obtained from Rn
+ bool setflags;
+ uint32_t carry; // the carry bit after ARM/Thumb Expand operation
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
+ if (BadReg(Rd) || BadReg(Rn))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ uint32_t result = val1 & ~imm32;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// Bitwise Bit Clear (register) performs a bitwise AND of a register value and the complement of an
+// optionally-shifted register value, and writes the result to the destination register.
+// It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateBICReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
+ result = R[n] AND NOT(shifted);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn, Rm;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ bool setflags;
+ uint32_t carry;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the second operand.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
+ if (!success)
+ return false;
+ uint32_t result = val1 & ~shifted;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// LDR (immediate, ARM) calculates an address from a base register value and an immediate offset, loads a word
+// from memory, and writes it to a register. It can use offset, post-indexed, or pre-indexed addressing.
+bool
+EmulateInstructionARM::EmulateLDRImmediateARM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ data = MemU[address,4];
+ if wback then R[n] = offset_addr;
+ if t == 15 then
+ if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
+ elsif UnalignedSupport() || address<1:0> = '00' then
+ R[t] = data;
+ else // Can only apply before ARMv7
+ R[t] = ROR(data, 8*UInt(address<1:0>));
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // if Rn == '1111' then SEE LDR (literal);
+ // if P == '0' && W == '1' then SEE LDRT;
+ // if Rn == '1101' && P == '0' && U == '1' && W == '0' && imm12 == '000000000100' then SEE POP;
+ // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21));
+
+ // if wback && n == t then UNPREDICTABLE;
+ if (wback && (n == t))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ addr_t address;
+ addr_t offset_addr;
+ addr_t base_address = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ if (add)
+ offset_addr = base_address + imm32;
+ else
+ offset_addr = base_address - imm32;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = base_address;
+
+ // data = MemU[address,4];
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - base_address);
+
+ uint64_t data = MemURead (context, address, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+
+ // if t == 15 then
+ if (t == 15)
+ {
+ // if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
+ if (BitIsClear (address, 1) && BitIsClear (address, 0))
+ {
+ // LoadWritePC (data);
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - base_address);
+ LoadWritePC (context, data);
+ }
+ else
+ return false;
+ }
+ // elsif UnalignedSupport() || address<1:0> = '00' then
+ else if (UnalignedSupport() || (BitIsClear (address, 1) && BitIsClear (address, 0)))
+ {
+ // R[t] = data;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - base_address);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+ }
+ // else // Can only apply before ARMv7
+ else
+ {
+ // R[t] = ROR(data, 8*UInt(address<1:0>));
+ data = ROR (data, Bits32 (address, 1, 0), &success);
+ if (!success)
+ return false;
+ context.type = eContextRegisterLoad;
+ context.SetImmediate (data);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+ }
+
+ }
+ return true;
+}
+
+// LDR (register) calculates an address from a base register value and an offset register value, loads a word
+// from memory, and writes it to a resgister. The offset register value can optionally be shifted.
+bool
+EmulateInstructionARM::EmulateLDRRegister (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ address = if index then offset_addr else R[n];
+ data = MemU[address,4];
+ if wback then R[n] = offset_addr;
+ if t == 15 then
+ if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
+ elsif UnalignedSupport() || address<1:0> = '00' then
+ R[t] = data;
+ else // Can only apply before ARMv7
+ if CurrentInstrSet() == InstrSet_ARM then
+ R[t] = ROR(data, 8*UInt(address<1:0>));
+ else
+ R[t] = bits(32) UNKNOWN;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ uint32_t t;
+ uint32_t n;
+ uint32_t m;
+ bool index;
+ bool add;
+ bool wback;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation in ThumbEE";
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 8, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ break;
+
+ case eEncodingT2:
+ // if Rn == '1111' then SEE LDR (literal);
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
+ shift_t = SRType_LSL;
+ shift_n = Bits32 (opcode, 5, 4);
+
+ // if BadReg(m) then UNPREDICTABLE;
+ if (BadReg (m))
+ return false;
+
+ // if t == 15 && InITBlock() && !LastInITBlock() then UNPREDICTABLE;
+ if ((t == 15) && InITBlock() && !LastInITBlock())
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ {
+ // if P == '0' && W == '1' then SEE LDRT;
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21));
+
+ // (shift_t, shift_n) = DecodeImmShift(type, imm5);
+ uint32_t type = Bits32 (opcode, 6, 5);
+ uint32_t imm5 = Bits32 (opcode, 11, 7);
+ shift_n = DecodeImmShift (type, imm5, shift_t);
+
+ // if m == 15 then UNPREDICTABLE;
+ if (m == 15)
+ return false;
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+ }
+ break;
+
+
+ default:
+ return false;
+ }
+
+ uint32_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ uint32_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ addr_t address;
+
+ // offset = Shift(R[m], shift_t, shift_n, APSR.C); -- Note "The APSR is an application level alias for the CPSR".
+ addr_t offset = Shift (Rm, shift_t, shift_n, Bit32 (m_opcode_cpsr, APSR_C), &success);
+ if (!success)
+ return false;
+
+ // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ if (add)
+ offset_addr = Rn + offset;
+ else
+ offset_addr = Rn - offset;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // data = MemU[address,4];
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+
+ uint64_t data = MemURead (context, address, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+
+ // if t == 15 then
+ if (t == 15)
+ {
+ // if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE;
+ if (BitIsClear (address, 1) && BitIsClear (address, 0))
+ {
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+ LoadWritePC (context, data);
+ }
+ else
+ return false;
+ }
+ // elsif UnalignedSupport() || address<1:0> = '00' then
+ else if (UnalignedSupport () || (BitIsClear (address, 1) && BitIsClear (address, 0)))
+ {
+ // R[t] = data;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+ }
+ else // Can only apply before ARMv7
+ {
+ // if CurrentInstrSet() == InstrSet_ARM then
+ if (CurrentInstrSet () == eModeARM)
+ {
+ // R[t] = ROR(data, 8*UInt(address<1:0>));
+ data = ROR (data, Bits32 (address, 1, 0), &success);
+ if (!success)
+ return false;
+ context.type = eContextRegisterLoad;
+ context.SetImmediate (data);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+ }
+ else
+ {
+ // R[t] = bits(32) UNKNOWN;
+ WriteBits32Unknown (t);
+ }
+ }
+ }
+ return true;
+}
+
+// LDRB (immediate, Thumb)
+bool
+EmulateInstructionARM::EmulateLDRBImmediate (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ R[t] = ZeroExtend(MemU[address,1], 32);
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5, 32);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ imm32 = Bits32 (opcode, 10, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback= false;
+
+ break;
+
+ case eEncodingT2:
+ // if Rt == '1111' then SEE PLD;
+ // if Rn == '1111' then SEE LDRB (literal);
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // if t == 13 then UNPREDICTABLE;
+ if (t == 13)
+ return false;
+
+ break;
+
+ case eEncodingT3:
+ // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLD;
+ // if Rn == '1111' then SEE LDRB (literal);
+ // if P == '1' && U == '1' && W == '0' then SEE LDRBT;
+ // if P == '0' && W == '0' then UNDEFINED;
+ if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8))
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (W == '1');
+ index = BitIsSet (opcode, 10);
+ add = BitIsSet (opcode, 9);
+ wback = BitIsSet (opcode, 8);
+
+ // if BadReg(t) || (wback && n == t) then UNPREDICTABLE;
+ if (BadReg (t) || (wback && (n == t)))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ uint32_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ addr_t address;
+ addr_t offset_addr;
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ if (add)
+ offset_addr = Rn + imm32;
+ else
+ offset_addr = Rn - imm32;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // R[t] = ZeroExtend(MemU[address,1], 32);
+ RegisterInfo base_reg;
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+
+ uint64_t data = MemURead (context, address, 1, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// LDRB (literal) calculates an address from the PC value and an immediate offset, loads a byte from memory,
+// zero-extends it to form a 32-bit word and writes it to a register.
+bool
+EmulateInstructionARM::EmulateLDRBLiteral (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ base = Align(PC,4);
+ address = if add then (base + imm32) else (base - imm32);
+ R[t] = ZeroExtend(MemU[address,1], 32);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t imm32;
+ bool add;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if Rt == '1111' then SEE PLD;
+ // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1');
+ t = Bits32 (opcode, 15, 12);
+ imm32 = Bits32 (opcode, 11, 0);
+ add = BitIsSet (opcode, 23);
+
+ // if t == 13 then UNPREDICTABLE;
+ if (t == 13)
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // t == UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1');
+ t = Bits32 (opcode, 15, 12);
+ imm32 = Bits32 (opcode, 11, 0);
+ add = BitIsSet (opcode, 23);
+
+ // if t == 15 then UNPREDICTABLE;
+ if (t == 15)
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ // base = Align(PC,4);
+ uint32_t pc_val = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+
+ uint32_t base = AlignPC (pc_val);
+
+ addr_t address;
+ // address = if add then (base + imm32) else (base - imm32);
+ if (add)
+ address = base + imm32;
+ else
+ address = base - imm32;
+
+ // R[t] = ZeroExtend(MemU[address,1], 32);
+ EmulateInstruction::Context context;
+ context.type = eContextRelativeBranchImmediate;
+ context.SetImmediate (address - base);
+
+ uint64_t data = MemURead (context, address, 1, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+ }
+ return true;
+}
+
+// LDRB (register) calculates an address from a base register value and an offset rigister value, loads a byte from
+// memory, zero-extends it to form a 32-bit word, and writes it to a register. The offset register value can
+// optionally be shifted.
+bool
+EmulateInstructionARM::EmulateLDRBRegister (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ address = if index then offset_addr else R[n];
+ R[t] = ZeroExtend(MemU[address,1],32);
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t m;
+ bool index;
+ bool add;
+ bool wback;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 8, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+
+ case eEncodingT2:
+ // if Rt == '1111' then SEE PLD;
+ // if Rn == '1111' then SEE LDRB (literal);
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
+ shift_t = SRType_LSL;
+ shift_n = Bits32 (opcode, 5, 4);
+
+ // if t == 13 || BadReg(m) then UNPREDICTABLE;
+ if ((t == 13) || BadReg (m))
+ return false;
+ break;
+
+ case eEncodingA1:
+ {
+ // if P == '0' && W == '1' then SEE LDRBT;
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21));
+
+ // (shift_t, shift_n) = DecodeImmShift(type, imm5);
+ uint32_t type = Bits32 (opcode, 6, 5);
+ uint32_t imm5 = Bits32 (opcode, 11, 7);
+ shift_n = DecodeImmShift (type, imm5, shift_t);
+
+ // if t == 15 || m == 15 then UNPREDICTABLE;
+ if ((t == 15) || (m == 15))
+ return false;
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ addr_t offset_addr;
+ addr_t address;
+
+ // offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ uint32_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ addr_t offset = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ uint32_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ if (add)
+ offset_addr = Rn + offset;
+ else
+ offset_addr = Rn - offset;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // R[t] = ZeroExtend(MemU[address,1],32);
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+
+ uint64_t data = MemURead (context, address, 1, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// LDRH (immediate, Thumb) calculates an address from a base register value and an immediate offset, loads a
+// halfword from memory, zero-extends it to form a 32-bit word, and writes it to a register. It can use offset,
+// post-indexed, or pre-indexed addressing.
+bool
+EmulateInstructionARM::EmulateLDRHImmediate (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ data = MemU[address,2];
+ if wback then R[n] = offset_addr;
+ if UnalignedSupport() || address<0> = '0' then
+ R[t] = ZeroExtend(data, 32);
+ else // Can only apply before ARMv7
+ R[t] = bits(32) UNKNOWN;
+#endif
+
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5:'0', 32);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ imm32 = Bits32 (opcode, 10, 6) << 1;
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ break;
+
+ case eEncodingT2:
+ // if Rt == '1111' then SEE "Unallocated memory hints";
+ // if Rn == '1111' then SEE LDRH (literal);
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // if t == 13 then UNPREDICTABLE;
+ if (t == 13)
+ return false;
+ break;
+
+ case eEncodingT3:
+ // if Rn == '1111' then SEE LDRH (literal);
+ // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE "Unallocated memory hints";
+ // if P == '1' && U == '1' && W == '0' then SEE LDRHT;
+ // if P == '0' && W == '0' then UNDEFINED;
+ if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8))
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (W == '1');
+ index = BitIsSet (opcode, 10);
+ add = BitIsSet (opcode, 9);
+ wback = BitIsSet (opcode, 8);
+
+ // if BadReg(t) || (wback && n == t) then UNPREDICTABLE;
+ if (BadReg (t) || (wback && (n == t)))
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ uint32_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ addr_t address;
+
+ if (add)
+ offset_addr = Rn + imm32;
+ else
+ offset_addr = Rn - imm32;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // data = MemU[address,2];
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+
+ uint64_t data = MemURead (context, address, 2, 0, &success);
+ if (!success)
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+
+ // if UnalignedSupport() || address<0> = '0' then
+ if (UnalignedSupport () || BitIsClear (address, 0))
+ {
+ // R[t] = ZeroExtend(data, 32);
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+ }
+ else // Can only apply before ARMv7
+ {
+ // R[t] = bits(32) UNKNOWN;
+ WriteBits32Unknown (t);
+ }
+ }
+ return true;
+}
+
+// LDRH (literal) caculates an address from the PC value and an immediate offset, loads a halfword from memory,
+// zero-extends it to form a 32-bit word, and writes it to a register.
+bool
+EmulateInstructionARM::EmulateLDRHLiteral (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ base = Align(PC,4);
+ address = if add then (base + imm32) else (base - imm32);
+ data = MemU[address,2];
+ if UnalignedSupport() || address<0> = '0' then
+ R[t] = ZeroExtend(data, 32);
+ else // Can only apply before ARMv7
+ R[t] = bits(32) UNKNOWN;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t imm32;
+ bool add;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if Rt == '1111' then SEE "Unallocated memory hints";
+ // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1');
+ t = Bits32 (opcode, 15, 12);
+ imm32 = Bits32 (opcode, 11, 0);
+ add = BitIsSet (opcode, 23);
+
+ // if t == 13 then UNPREDICTABLE;
+ if (t == 13)
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ {
+ uint32_t imm4H = Bits32 (opcode, 11, 8);
+ uint32_t imm4L = Bits32 (opcode, 3, 0);
+
+ // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1');
+ t = Bits32 (opcode, 15, 12);
+ imm32 = (imm4H << 4) | imm4L;
+ add = BitIsSet (opcode, 23);
+
+ // if t == 15 then UNPREDICTABLE;
+ if (t == 15)
+ return false;
+ break;
+ }
+
+ default:
+ return false;
+ }
+
+ // base = Align(PC,4);
+ uint64_t pc_value = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+
+ addr_t base = AlignPC (pc_value);
+ addr_t address;
+
+ // address = if add then (base + imm32) else (base - imm32);
+ if (add)
+ address = base + imm32;
+ else
+ address = base - imm32;
+
+ // data = MemU[address,2];
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - base);
+
+ uint64_t data = MemURead (context, address, 2, 0, &success);
+ if (!success)
+ return false;
+
+
+ // if UnalignedSupport() || address<0> = '0' then
+ if (UnalignedSupport () || BitIsClear (address, 0))
+ {
+ // R[t] = ZeroExtend(data, 32);
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - base);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+
+ }
+ else // Can only apply before ARMv7
+ {
+ // R[t] = bits(32) UNKNOWN;
+ WriteBits32Unknown (t);
+ }
+ }
+ return true;
+}
+
+// LDRH (literal) calculates an address from a base register value and an offset register value, loads a halfword
+// from memory, zero-extends it to form a 32-bit word, and writes it to a register. The offset register value can
+// be shifted left by 0, 1, 2, or 3 bits.
+bool
+EmulateInstructionARM::EmulateLDRHRegister (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ address = if index then offset_addr else R[n];
+ data = MemU[address,2];
+ if wback then R[n] = offset_addr;
+ if UnalignedSupport() || address<0> = '0' then
+ R[t] = ZeroExtend(data, 32);
+ else // Can only apply before ARMv7
+ R[t] = bits(32) UNKNOWN;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t m;
+ bool index;
+ bool add;
+ bool wback;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation in ThumbEE";
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 8, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ break;
+
+ case eEncodingT2:
+ // if Rn == '1111' then SEE LDRH (literal);
+ // if Rt == '1111' then SEE "Unallocated memory hints";
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
+ shift_t = SRType_LSL;
+ shift_n = Bits32 (opcode, 5, 4);
+
+ // if t == 13 || BadReg(m) then UNPREDICTABLE;
+ if ((t == 13) || BadReg (m))
+ return false;
+ break;
+
+ case eEncodingA1:
+ // if P == '0' && W == '1' then SEE LDRHT;
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21));
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ // if t == 15 || m == 15 then UNPREDICTABLE;
+ if ((t == 15) || (m == 15))
+ return false;
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // offset = Shift(R[m], shift_t, shift_n, APSR.C);
+
+ uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ addr_t offset = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ addr_t address;
+
+ // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ if (add)
+ offset_addr = Rn + offset;
+ else
+ offset_addr = Rn - offset;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // data = MemU[address,2];
+ RegisterInfo base_reg;
+ RegisterInfo offset_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusIndirectOffset (base_reg, offset_reg);
+ uint64_t data = MemURead (context, address, 2, 0, &success);
+ if (!success)
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+
+ // if UnalignedSupport() || address<0> = '0' then
+ if (UnalignedSupport() || BitIsClear (address, 0))
+ {
+ // R[t] = ZeroExtend(data, 32);
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusIndirectOffset (base_reg, offset_reg);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+ }
+ else // Can only apply before ARMv7
+ {
+ // R[t] = bits(32) UNKNOWN;
+ WriteBits32Unknown (t);
+ }
+ }
+ return true;
+}
+
+// LDRSB (immediate) calculates an address from a base register value and an immediate offset, loads a byte from
+// memory, sign-extends it to form a 32-bit word, and writes it to a register. It can use offset, post-indexed,
+// or pre-indexed addressing.
+bool
+EmulateInstructionARM::EmulateLDRSBImmediate (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ R[t] = SignExtend(MemU[address,1], 32);
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if Rt == '1111' then SEE PLI;
+ // if Rn == '1111' then SEE LDRSB (literal);
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // if t == 13 then UNPREDICTABLE;
+ if (t == 13)
+ return false;
+
+ break;
+
+ case eEncodingT2:
+ // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLI;
+ // if Rn == '1111' then SEE LDRSB (literal);
+ // if P == '1' && U == '1' && W == '0' then SEE LDRSBT;
+ // if P == '0' && W == '0' then UNDEFINED;
+ if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8))
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (W == '1');
+ index = BitIsSet (opcode, 10);
+ add = BitIsSet (opcode, 9);
+ wback = BitIsSet (opcode, 8);
+
+ // if BadReg(t) || (wback && n == t) then UNPREDICTABLE;
+ if (((t == 13) || ((t == 15)
+ && (BitIsClear (opcode, 10) || BitIsSet (opcode, 9) || BitIsSet (opcode, 8))))
+ || (wback && (n == t)))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ {
+ // if Rn == '1111' then SEE LDRSB (literal);
+ // if P == '0' && W == '1' then SEE LDRSBT;
+ // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+
+ uint32_t imm4H = Bits32 (opcode, 11, 8);
+ uint32_t imm4L = Bits32 (opcode, 3, 0);
+ imm32 = (imm4H << 4) | imm4L;
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21));
+
+ // if t == 15 || (wback && n == t) then UNPREDICTABLE;
+ if ((t == 15) || (wback && (n == t)))
+ return false;
+
+ break;
+ }
+
+ default:
+ return false;
+ }
+
+ uint64_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ addr_t address;
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ if (add)
+ offset_addr = Rn + imm32;
+ else
+ offset_addr = Rn - imm32;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // R[t] = SignExtend(MemU[address,1], 32);
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+
+ uint64_t unsigned_data = MemURead (context, address, 1, 0, &success);
+ if (!success)
+ return false;
+
+ int64_t signed_data = llvm::SignExtend64<8>(unsigned_data);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data))
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+// LDRSB (literal) calculates an address from the PC value and an immediate offset, loads a byte from memory,
+// sign-extends it to form a 32-bit word, and writes tit to a register.
+bool
+EmulateInstructionARM::EmulateLDRSBLiteral (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ base = Align(PC,4);
+ address = if add then (base + imm32) else (base - imm32);
+ R[t] = SignExtend(MemU[address,1], 32);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t imm32;
+ bool add;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if Rt == '1111' then SEE PLI;
+ // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1');
+ t = Bits32 (opcode, 15, 12);
+ imm32 = Bits32 (opcode, 11, 0);
+ add = BitIsSet (opcode, 23);
+
+ // if t == 13 then UNPREDICTABLE;
+ if (t == 13)
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ {
+ // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1');
+ t = Bits32 (opcode, 15, 12);
+ uint32_t imm4H = Bits32 (opcode, 11, 8);
+ uint32_t imm4L = Bits32 (opcode, 3, 0);
+ imm32 = (imm4H << 4) | imm4L;
+ add = BitIsSet (opcode, 23);
+
+ // if t == 15 then UNPREDICTABLE;
+ if (t == 15)
+ return false;
+
+ break;
+ }
+
+ default:
+ return false;
+ }
+
+ // base = Align(PC,4);
+ uint64_t pc_value = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+ uint64_t base = AlignPC (pc_value);
+
+ // address = if add then (base + imm32) else (base - imm32);
+ addr_t address;
+ if (add)
+ address = base + imm32;
+ else
+ address = base - imm32;
+
+ // R[t] = SignExtend(MemU[address,1], 32);
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - base);
+
+ uint64_t unsigned_data = MemURead (context, address, 1, 0, &success);
+ if (!success)
+ return false;
+
+ int64_t signed_data = llvm::SignExtend64<8>(unsigned_data);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data))
+ return false;
+ }
+ return true;
+}
+
+// LDRSB (register) calculates an address from a base register value and an offset register value, loadsa byte from
+// memory, sign-extends it to form a 32-bit word, and writes it to a register. The offset register value can be
+// shifted left by 0, 1, 2, or 3 bits.
+bool
+EmulateInstructionARM::EmulateLDRSBRegister (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ address = if index then offset_addr else R[n];
+ R[t] = SignExtend(MemU[address,1], 32);
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t m;
+ bool index;
+ bool add;
+ bool wback;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 8, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ break;
+
+ case eEncodingT2:
+ // if Rt == '1111' then SEE PLI;
+ // if Rn == '1111' then SEE LDRSB (literal);
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
+ shift_t = SRType_LSL;
+ shift_n = Bits32 (opcode, 5, 4);
+
+ // if t == 13 || BadReg(m) then UNPREDICTABLE;
+ if ((t == 13) || BadReg (m))
+ return false;
+ break;
+
+ case eEncodingA1:
+ // if P == '0' && W == '1' then SEE LDRSBT;
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ // if t == 15 || m == 15 then UNPREDICTABLE;
+ if ((t == 15) || (m == 15))
+ return false;
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ // offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ addr_t offset = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ addr_t address;
+
+ // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ if (add)
+ offset_addr = Rn + offset;
+ else
+ offset_addr = Rn - offset;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // R[t] = SignExtend(MemU[address,1], 32);
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ RegisterInfo offset_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusIndirectOffset (base_reg, offset_reg);
+
+ uint64_t unsigned_data = MemURead (context, address, 1, 0, &success);
+ if (!success)
+ return false;
+
+ int64_t signed_data = llvm::SignExtend64<8>(unsigned_data);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data))
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// LDRSH (immediate) calculates an address from a base register value and an immediate offset, loads a halfword from
+// memory, sign-extends it to form a 32-bit word, and writes it to a register. It can use offset, post-indexed, or
+// pre-indexed addressing.
+bool
+EmulateInstructionARM::EmulateLDRSHImmediate (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ data = MemU[address,2];
+ if wback then R[n] = offset_addr;
+ if UnalignedSupport() || address<0> = '0' then
+ R[t] = SignExtend(data, 32);
+ else // Can only apply before ARMv7
+ R[t] = bits(32) UNKNOWN;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if Rn == '1111' then SEE LDRSH (literal);
+ // if Rt == '1111' then SEE "Unallocated memory hints";
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // if t == 13 then UNPREDICTABLE;
+ if (t == 13)
+ return false;
+
+ break;
+
+ case eEncodingT2:
+ // if Rn == '1111' then SEE LDRSH (literal);
+ // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE "Unallocated memory hints";
+ // if P == '1' && U == '1' && W == '0' then SEE LDRSHT;
+ // if P == '0' && W == '0' then UNDEFINED;
+ if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8))
+ return false;
+
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (W == '1');
+ index = BitIsSet (opcode, 10);
+ add = BitIsSet (opcode, 9);
+ wback = BitIsSet (opcode, 8);
+
+ // if BadReg(t) || (wback && n == t) then UNPREDICTABLE;
+ if (BadReg (t) || (wback && (n == t)))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ {
+ // if Rn == '1111' then SEE LDRSH (literal);
+ // if P == '0' && W == '1' then SEE LDRSHT;
+ // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ uint32_t imm4H = Bits32 (opcode, 11,8);
+ uint32_t imm4L = Bits32 (opcode, 3, 0);
+ imm32 = (imm4H << 4) | imm4L;
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ // if t == 15 || (wback && n == t) then UNPREDICTABLE;
+ if ((t == 15) || (wback && (n == t)))
+ return false;
+
+ break;
+ }
+
+ default:
+ return false;
+ }
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ if (add)
+ offset_addr = Rn + imm32;
+ else
+ offset_addr = Rn - imm32;
+
+ // address = if index then offset_addr else R[n];
+ addr_t address;
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // data = MemU[address,2];
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+
+ uint64_t data = MemURead (context, address, 2, 0, &success);
+ if (!success)
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+
+ // if UnalignedSupport() || address<0> = '0' then
+ if (UnalignedSupport() || BitIsClear (address, 0))
+ {
+ // R[t] = SignExtend(data, 32);
+ int64_t signed_data = llvm::SignExtend64<16>(data);
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data))
+ return false;
+ }
+ else // Can only apply before ARMv7
+ {
+ // R[t] = bits(32) UNKNOWN;
+ WriteBits32Unknown (t);
+ }
+ }
+ return true;
+}
+
+// LDRSH (literal) calculates an address from the PC value and an immediate offset, loads a halfword from memory,
+// sign-extends it to from a 32-bit word, and writes it to a register.
+bool
+EmulateInstructionARM::EmulateLDRSHLiteral (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ base = Align(PC,4);
+ address = if add then (base + imm32) else (base - imm32);
+ data = MemU[address,2];
+ if UnalignedSupport() || address<0> = '0' then
+ R[t] = SignExtend(data, 32);
+ else // Can only apply before ARMv7
+ R[t] = bits(32) UNKNOWN;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t imm32;
+ bool add;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(15);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if Rt == '1111' then SEE "Unallocated memory hints";
+ // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1');
+ t = Bits32 (opcode, 15, 12);
+ imm32 = Bits32 (opcode, 11, 0);
+ add = BitIsSet (opcode, 23);
+
+ // if t == 13 then UNPREDICTABLE;
+ if (t == 13)
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ {
+ // t == UInt(Rt); imm32 = ZeroExtend(imm4H:imm4L, 32); add = (U == '1');
+ t = Bits32 (opcode, 15, 12);
+ uint32_t imm4H = Bits32 (opcode, 11, 8);
+ uint32_t imm4L = Bits32 (opcode, 3, 0);
+ imm32 = (imm4H << 4) | imm4L;
+ add = BitIsSet (opcode, 23);
+
+ // if t == 15 then UNPREDICTABLE;
+ if (t == 15)
+ return false;
+
+ break;
+ }
+ default:
+ return false;
+ }
+
+ // base = Align(PC,4);
+ uint64_t pc_value = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+
+ uint64_t base = AlignPC (pc_value);
+
+ addr_t address;
+ // address = if add then (base + imm32) else (base - imm32);
+ if (add)
+ address = base + imm32;
+ else
+ address = base - imm32;
+
+ // data = MemU[address,2];
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, imm32);
+
+ uint64_t data = MemURead (context, address, 2, 0, &success);
+ if (!success)
+ return false;
+
+ // if UnalignedSupport() || address<0> = '0' then
+ if (UnalignedSupport() || BitIsClear (address, 0))
+ {
+ // R[t] = SignExtend(data, 32);
+ int64_t signed_data = llvm::SignExtend64<16>(data);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data))
+ return false;
+ }
+ else // Can only apply before ARMv7
+ {
+ // R[t] = bits(32) UNKNOWN;
+ WriteBits32Unknown (t);
+ }
+ }
+ return true;
+}
+
+// LDRSH (register) calculates an address from a base register value and an offset register value, loads a halfword
+// from memory, sign-extends it to form a 32-bit word, and writes it to a register. The offset register value can be
+// shifted left by 0, 1, 2, or 3 bits.
+bool
+EmulateInstructionARM::EmulateLDRSHRegister (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ address = if index then offset_addr else R[n];
+ data = MemU[address,2];
+ if wback then R[n] = offset_addr;
+ if UnalignedSupport() || address<0> = '0' then
+ R[t] = SignExtend(data, 32);
+ else // Can only apply before ARMv7
+ R[t] = bits(32) UNKNOWN;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t m;
+ bool index;
+ bool add;
+ bool wback;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+
+ // EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation in ThumbEE";
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 8, 6);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ break;
+
+ case eEncodingT2:
+ // if Rn == '1111' then SEE LDRSH (literal);
+ // if Rt == '1111' then SEE "Unallocated memory hints";
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = TRUE; add = TRUE; wback = FALSE;
+ index = true;
+ add = true;
+ wback = false;
+
+ // (shift_t, shift_n) = (SRType_LSL, UInt(imm2));
+ shift_t = SRType_LSL;
+ shift_n = Bits32 (opcode, 5, 4);
+
+ // if t == 13 || BadReg(m) then UNPREDICTABLE;
+ if ((t == 13) || BadReg (m))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // if P == '0' && W == '1' then SEE LDRSHT;
+ // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == '1'); add = (U == '1'); wback = (P == '0') || (W == '1');
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ // if t == 15 || m == 15 then UNPREDICTABLE;
+ if ((t == 15) || (m == 15))
+ return false;
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ // offset = Shift(R[m], shift_t, shift_n, APSR.C);
+ addr_t offset = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ addr_t address;
+
+ // offset_addr = if add then (R[n] + offset) else (R[n] - offset);
+ if (add)
+ offset_addr = Rn + offset;
+ else
+ offset_addr = Rn - offset;
+
+ // address = if index then offset_addr else R[n];
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // data = MemU[address,2];
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ RegisterInfo offset_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusIndirectOffset (base_reg, offset_reg);
+
+ uint64_t data = MemURead (context, address, 2, 0, &success);
+ if (!success)
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+
+ // if UnalignedSupport() || address<0> = '0' then
+ if (UnalignedSupport() || BitIsClear (address, 0))
+ {
+ // R[t] = SignExtend(data, 32);
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusIndirectOffset (base_reg, offset_reg);
+
+ int64_t signed_data = llvm::SignExtend64<16>(data);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, (uint64_t) signed_data))
+ return false;
+ }
+ else // Can only apply before ARMv7
+ {
+ // R[t] = bits(32) UNKNOWN;
+ WriteBits32Unknown (t);
+ }
+ }
+ return true;
+}
+
+// SXTB extracts an 8-bit value from a register, sign-extends it to 32 bits, and writes the result to the destination
+// register. You can specifiy a rotation by 0, 8, 16, or 24 bits before extracting the 8-bit value.
+bool
+EmulateInstructionARM::EmulateSXTB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ rotated = ROR(R[m], rotation);
+ R[d] = SignExtend(rotated<7:0>, 32);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t m;
+ uint32_t rotation;
+
+ // EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); m = UInt(Rm); rotation = 0;
+ d = Bits32 (opcode, 2, 0);
+ m = Bits32 (opcode, 5, 3);
+ rotation = 0;
+
+ break;
+
+ case eEncodingT2:
+ // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
+ d = Bits32 (opcode, 11, 8);
+ m = Bits32 (opcode, 3, 0);
+ rotation = Bits32 (opcode, 5, 4) << 3;
+
+ // if BadReg(d) || BadReg(m) then UNPREDICTABLE;
+ if (BadReg (d) || BadReg (m))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
+ d = Bits32 (opcode, 15, 12);
+ m = Bits32 (opcode, 3, 0);
+ rotation = Bits32 (opcode, 11, 10) << 3;
+
+ // if d == 15 || m == 15 then UNPREDICTABLE;
+ if ((d == 15) || (m == 15))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ // rotated = ROR(R[m], rotation);
+ uint64_t rotated = ROR (Rm, rotation, &success);
+ if (!success)
+ return false;
+
+ // R[d] = SignExtend(rotated<7:0>, 32);
+ int64_t data = llvm::SignExtend64<8>(rotated);
+
+ RegisterInfo source_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, source_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegister (source_reg);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, (uint64_t) data))
+ return false;
+ }
+ return true;
+}
+
+// SXTH extracts a 16-bit value from a register, sign-extends it to 32 bits, and writes the result to the destination
+// register. You can specify a rotation by 0, 8, 16, or 24 bits before extracting the 16-bit value.
+bool
+EmulateInstructionARM::EmulateSXTH (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ rotated = ROR(R[m], rotation);
+ R[d] = SignExtend(rotated<15:0>, 32);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t m;
+ uint32_t rotation;
+
+ // EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); m = UInt(Rm); rotation = 0;
+ d = Bits32 (opcode, 2, 0);
+ m = Bits32 (opcode, 5, 3);
+ rotation = 0;
+
+ break;
+
+ case eEncodingT2:
+ // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
+ d = Bits32 (opcode, 11, 8);
+ m = Bits32 (opcode, 3, 0);
+ rotation = Bits32 (opcode, 5, 4) << 3;
+
+ // if BadReg(d) || BadReg(m) then UNPREDICTABLE;
+ if (BadReg (d) || BadReg (m))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
+ d = Bits32 (opcode, 15, 12);
+ m = Bits32 (opcode, 3, 0);
+ rotation = Bits32 (opcode, 11, 10) << 3;
+
+ // if d == 15 || m == 15 then UNPREDICTABLE;
+ if ((d == 15) || (m == 15))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ // rotated = ROR(R[m], rotation);
+ uint64_t rotated = ROR (Rm, rotation, &success);
+ if (!success)
+ return false;
+
+ // R[d] = SignExtend(rotated<15:0>, 32);
+ RegisterInfo source_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, source_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegister (source_reg);
+
+ int64_t data = llvm::SignExtend64<16> (rotated);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, (uint64_t) data))
+ return false;
+ }
+
+ return true;
+}
+
+// UXTB extracts an 8-bit value from a register, zero-extneds it to 32 bits, and writes the result to the destination
+// register. You can specify a rotation by 0, 8, 16, or 24 bits before extracting the 8-bit value.
+bool
+EmulateInstructionARM::EmulateUXTB (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ rotated = ROR(R[m], rotation);
+ R[d] = ZeroExtend(rotated<7:0>, 32);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t m;
+ uint32_t rotation;
+
+ // EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); m = UInt(Rm); rotation = 0;
+ d = Bits32 (opcode, 2, 0);
+ m = Bits32 (opcode, 5, 3);
+ rotation = 0;
+
+ break;
+
+ case eEncodingT2:
+ // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
+ d = Bits32 (opcode, 11, 8);
+ m = Bits32 (opcode, 3, 0);
+ rotation = Bits32 (opcode, 5, 4) << 3;
+
+ // if BadReg(d) || BadReg(m) then UNPREDICTABLE;
+ if (BadReg (d) || BadReg (m))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
+ d = Bits32 (opcode, 15, 12);
+ m = Bits32 (opcode, 3, 0);
+ rotation = Bits32 (opcode, 11, 10) << 3;
+
+ // if d == 15 || m == 15 then UNPREDICTABLE;
+ if ((d == 15) || (m == 15))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ // rotated = ROR(R[m], rotation);
+ uint64_t rotated = ROR (Rm, rotation, &success);
+ if (!success)
+ return false;
+
+ // R[d] = ZeroExtend(rotated<7:0>, 32);
+ RegisterInfo source_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, source_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegister (source_reg);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, Bits32 (rotated, 7, 0)))
+ return false;
+ }
+ return true;
+}
+
+// UXTH extracts a 16-bit value from a register, zero-extends it to 32 bits, and writes the result to the destination
+// register. You can specify a rotation by 0, 8, 16, or 24 bits before extracting the 16-bit value.
+bool
+EmulateInstructionARM::EmulateUXTH (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ rotated = ROR(R[m], rotation);
+ R[d] = ZeroExtend(rotated<15:0>, 32);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t m;
+ uint32_t rotation;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); m = UInt(Rm); rotation = 0;
+ d = Bits32 (opcode, 2, 0);
+ m = Bits32 (opcode, 5, 3);
+ rotation = 0;
+
+ break;
+
+ case eEncodingT2:
+ // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
+ d = Bits32 (opcode, 11, 8);
+ m = Bits32 (opcode, 3, 0);
+ rotation = Bits32 (opcode, 5, 4) << 3;
+
+ // if BadReg(d) || BadReg(m) then UNPREDICTABLE;
+ if (BadReg (d) || BadReg (m))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // d = UInt(Rd); m = UInt(Rm); rotation = UInt(rotate:'000');
+ d = Bits32 (opcode, 15, 12);
+ m = Bits32 (opcode, 3, 0);
+ rotation = Bits32 (opcode, 11, 10) << 3;
+
+ // if d == 15 || m == 15 then UNPREDICTABLE;
+ if ((d == 15) || (m == 15))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ uint64_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success);
+ if (!success)
+ return false;
+
+ // rotated = ROR(R[m], rotation);
+ uint64_t rotated = ROR (Rm, rotation, &success);
+ if (!success)
+ return false;
+
+ // R[d] = ZeroExtend(rotated<15:0>, 32);
+ RegisterInfo source_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, source_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegister (source_reg);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, Bits32 (rotated, 15, 0)))
+ return false;
+ }
+ return true;
+}
+
+// RFE (Return From Exception) loads the PC and the CPSR from the word at the specified address and the following
+// word respectively.
+bool
+EmulateInstructionARM::EmulateRFE (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ if !CurrentModeIsPrivileged() || CurrentInstrSet() == InstrSet_ThumbEE then
+ UNPREDICTABLE;
+ else
+ address = if increment then R[n] else R[n]-8;
+ if wordhigher then address = address+4;
+ CPSRWriteByInstr(MemA[address+4,4], '1111', TRUE);
+ BranchWritePC(MemA[address,4]);
+ if wback then R[n] = if increment then R[n]+8 else R[n]-8;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t n;
+ bool wback;
+ bool increment;
+ bool wordhigher;
+
+ // EncodingSpecificOperations();
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // n = UInt(Rn); wback = (W == '1'); increment = FALSE; wordhigher = FALSE;
+ n = Bits32 (opcode, 19, 16);
+ wback = BitIsSet (opcode, 21);
+ increment = false;
+ wordhigher = false;
+
+ // if n == 15 then UNPREDICTABLE;
+ if (n == 15)
+ return false;
+
+ // if InITBlock() && !LastInITBlock() then UNPREDICTABLE;
+ if (InITBlock() && !LastInITBlock())
+ return false;
+
+ break;
+
+ case eEncodingT2:
+ // n = UInt(Rn); wback = (W == '1'); increment = TRUE; wordhigher = FALSE;
+ n = Bits32 (opcode, 19, 16);
+ wback = BitIsSet (opcode, 21);
+ increment = true;
+ wordhigher = false;
+
+ // if n == 15 then UNPREDICTABLE;
+ if (n == 15)
+ return false;
+
+ // if InITBlock() && !LastInITBlock() then UNPREDICTABLE;
+ if (InITBlock() && !LastInITBlock())
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // n = UInt(Rn);
+ n = Bits32 (opcode, 19, 16);
+
+ // wback = (W == '1'); inc = (U == '1'); wordhigher = (P == U);
+ wback = BitIsSet (opcode, 21);
+ increment = BitIsSet (opcode, 23);
+ wordhigher = (Bit32 (opcode, 24) == Bit32 (opcode, 23));
+
+ // if n == 15 then UNPREDICTABLE;
+ if (n == 15)
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // if !CurrentModeIsPrivileged() || CurrentInstrSet() == InstrSet_ThumbEE then
+ if (!CurrentModeIsPrivileged ())
+ // UNPREDICTABLE;
+ return false;
+ else
+ {
+ uint64_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success);
+ if (!success)
+ return false;
+
+ addr_t address;
+ // address = if increment then R[n] else R[n]-8;
+ if (increment)
+ address = Rn;
+ else
+ address = Rn - 8;
+
+ // if wordhigher then address = address+4;
+ if (wordhigher)
+ address = address + 4;
+
+ // CPSRWriteByInstr(MemA[address+4,4], '1111', TRUE);
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextReturnFromException;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+
+ uint64_t data = MemARead (context, address + 4, 4, 0, &success);
+ if (!success)
+ return false;
+
+ CPSRWriteByInstr (data, 15, true);
+
+ // BranchWritePC(MemA[address,4]);
+ uint64_t data2 = MemARead (context, address, 4, 0, &success);
+ if (!success)
+ return false;
+
+ BranchWritePC (context, data2);
+
+ // if wback then R[n] = if increment then R[n]+8 else R[n]-8;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ if (increment)
+ {
+ context.SetOffset (8);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, Rn + 8))
+ return false;
+ }
+ else
+ {
+ context.SetOffset (-8);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, Rn - 8))
+ return false;
+ }
+ } // if wback
+ }
+ } // if ConditionPassed()
+ return true;
+}
+
+// Bitwise Exclusive OR (immediate) performs a bitwise exclusive OR of a register value and an immediate value,
+// and writes the result to the destination register. It can optionally update the condition flags based on
+// the result.
+bool
+EmulateInstructionARM::EmulateEORImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ result = R[n] EOR imm32;
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn;
+ uint32_t imm32; // the immediate value to be ORed to the value obtained from Rn
+ bool setflags;
+ uint32_t carry; // the carry bit after ARM/Thumb Expand operation
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
+ // if Rd == '1111' && S == '1' then SEE TEQ (immediate);
+ if (Rd == 15 && setflags)
+ return EmulateTEQImm (opcode, eEncodingT1);
+ if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ uint32_t result = val1 ^ imm32;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// Bitwise Exclusive OR (register) performs a bitwise exclusive OR of a register value and an
+// optionally-shifted register value, and writes the result to the destination register.
+// It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateEORReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
+ result = R[n] EOR shifted;
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn, Rm;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ bool setflags;
+ uint32_t carry;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ // if Rd == '1111' && S == '1' then SEE TEQ (register);
+ if (Rd == 15 && setflags)
+ return EmulateTEQReg (opcode, eEncodingT1);
+ if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the second operand.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
+ if (!success)
+ return false;
+ uint32_t result = val1 ^ shifted;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// Bitwise OR (immediate) performs a bitwise (inclusive) OR of a register value and an immediate value, and
+// writes the result to the destination register. It can optionally update the condition flags based
+// on the result.
+bool
+EmulateInstructionARM::EmulateORRImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ result = R[n] OR imm32;
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn;
+ uint32_t imm32; // the immediate value to be ORed to the value obtained from Rn
+ bool setflags;
+ uint32_t carry; // the carry bit after ARM/Thumb Expand operation
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
+ // if Rn == '1111' then SEE MOV (immediate);
+ if (Rn == 15)
+ return EmulateMOVRdImm (opcode, eEncodingT2);
+ if (BadReg(Rd) || Rn == 13)
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
+
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ uint32_t result = val1 | imm32;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// Bitwise OR (register) performs a bitwise (inclusive) OR of a register value and an optionally-shifted register
+// value, and writes the result to the destination register. It can optionally update the condition flags based
+// on the result.
+bool
+EmulateInstructionARM::EmulateORRReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
+ result = R[n] OR shifted;
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rd, Rn, Rm;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ bool setflags;
+ uint32_t carry;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rd = Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ // if Rn == '1111' then SEE MOV (register);
+ if (Rn == 15)
+ return EmulateMOVRdRm (opcode, eEncodingT3);
+ if (BadReg(Rd) || Rn == 13 || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the second operand.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
+ if (!success)
+ return false;
+ uint32_t result = val1 | shifted;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry))
+ return false;
+ }
+ return true;
+}
+
+// Reverse Subtract (immediate) subtracts a register value from an immediate value, and writes the result to
+// the destination register. It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateRSBImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(NOT(R[n]), imm32, '1');
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand
+ bool setflags;
+ uint32_t imm32; // the immediate value to be added to the value obtained from Rn
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 2, 0);
+ Rn = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ imm32 = 0;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
+ if (BadReg(Rd) || BadReg(Rn))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from the operand register Rn.
+ uint32_t reg_val = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(~reg_val, imm32, 1);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Reverse Subtract (register) subtracts a register value from an optionally-shifted register value, and writes the
+// result to the destination register. It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateRSBReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(NOT(R[n]), shifted, '1');
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand
+ uint32_t Rm; // the second operand
+ bool setflags;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ // if (BadReg(d) || BadReg(m)) then UNPREDICTABLE;
+ if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from register Rn.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the register value from register Rm.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+ AddWithCarryResult res = AddWithCarry(~val1, shifted, 1);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs();
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Reverse Subtract with Carry (immediate) subtracts a register value and the value of NOT (Carry flag) from
+// an immediate value, and writes the result to the destination register. It can optionally update the condition
+// flags based on the result.
+bool
+EmulateInstructionARM::EmulateRSCImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(NOT(R[n]), imm32, APSR.C);
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand
+ bool setflags;
+ uint32_t imm32; // the immediate value to be added to the value obtained from Rn
+ switch (encoding) {
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from the operand register Rn.
+ uint32_t reg_val = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(~reg_val, imm32, APSR_C);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Reverse Subtract with Carry (register) subtracts a register value and the value of NOT (Carry flag) from an
+// optionally-shifted register value, and writes the result to the destination register. It can optionally update the
+// condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateRSCReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(NOT(R[n]), shifted, APSR.C);
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand
+ uint32_t Rm; // the second operand
+ bool setflags;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ switch (encoding) {
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from register Rn.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the register value from register Rm.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+ AddWithCarryResult res = AddWithCarry(~val1, shifted, APSR_C);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs();
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Subtract with Carry (immediate) subtracts an immediate value and the value of
+// NOT (Carry flag) from a register value, and writes the result to the destination register.
+// It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateSBCImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand
+ bool setflags;
+ uint32_t imm32; // the immediate value to be added to the value obtained from Rn
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
+ if (BadReg(Rd) || BadReg(Rn))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from the operand register Rn.
+ uint32_t reg_val = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, APSR_C);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Subtract with Carry (register) subtracts an optionally-shifted register value and the value of
+// NOT (Carry flag) from a register value, and writes the result to the destination register.
+// It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateSBCReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), APSR.C);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand
+ uint32_t Rm; // the second operand
+ bool setflags;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ setflags = BitIsSet(opcode, 20);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from register Rn.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the register value from register Rm.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+ AddWithCarryResult res = AddWithCarry(val1, ~shifted, APSR_C);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs();
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// This instruction subtracts an immediate value from a register value, and writes the result
+// to the destination register. It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateSUBImmThumb (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1');
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand
+ bool setflags;
+ uint32_t imm32; // the immediate value to be subtracted from the value obtained from Rn
+ switch (encoding) {
+ case eEncodingT1:
+ Rd = Bits32(opcode, 2, 0);
+ Rn = Bits32(opcode, 5, 3);
+ setflags = !InITBlock();
+ imm32 = Bits32(opcode, 8, 6); // imm32 = ZeroExtend(imm3, 32)
+ break;
+ case eEncodingT2:
+ Rd = Rn = Bits32(opcode, 10, 8);
+ setflags = !InITBlock();
+ imm32 = Bits32(opcode, 7, 0); // imm32 = ZeroExtend(imm8, 32)
+ break;
+ case eEncodingT3:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8)
+
+ // if Rd == '1111' && S == '1' then SEE CMP (immediate);
+ if (Rd == 15 && setflags)
+ return EmulateCMPImm (opcode, eEncodingT2);
+
+ // if Rn == '1101' then SEE SUB (SP minus immediate);
+ if (Rn == 13)
+ return EmulateSUBSPImm (opcode, eEncodingT2);
+
+ // if d == 13 || (d == 15 && S == '0') || n == 15 then UNPREDICTABLE;
+ if (Rd == 13 || (Rd == 15 && !setflags) || Rn == 15)
+ return false;
+ break;
+ case eEncodingT4:
+ Rd = Bits32(opcode, 11, 8);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32)
+
+ // if Rn == '1111' then SEE ADR;
+ if (Rn == 15)
+ return EmulateADR (opcode, eEncodingT2);
+
+ // if Rn == '1101' then SEE SUB (SP minus immediate);
+ if (Rn == 13)
+ return EmulateSUBSPImm (opcode, eEncodingT3);
+
+ if (BadReg(Rd))
+ return false;
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from the operand register Rn.
+ uint32_t reg_val = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// This instruction subtracts an immediate value from a register value, and writes the result
+// to the destination register. It can optionally update the condition flags based on the result.
+bool
+EmulateInstructionARM::EmulateSUBImmARM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1');
+ if d == 15 then
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ uint32_t Rd; // the destination register
+ uint32_t Rn; // the first operand
+ bool setflags;
+ uint32_t imm32; // the immediate value to be subtracted from the value obtained from Rn
+ switch (encoding) {
+ case eEncodingA1:
+ Rd = Bits32(opcode, 15, 12);
+ Rn = Bits32(opcode, 19, 16);
+ setflags = BitIsSet(opcode, 20);
+ imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12)
+
+ // if Rn == '1111' && S == '0' then SEE ADR;
+ if (Rn == 15 && !setflags)
+ return EmulateADR (opcode, eEncodingA2);
+
+ // if Rn == '1101' then SEE SUB (SP minus immediate);
+ if (Rn == 13)
+ return EmulateSUBSPImm (opcode, eEncodingA1);
+
+ // if Rd == '1111' && S == '1' then SEE SUBS PC, LR and related instructions;
+ if (Rd == 15 && setflags)
+ return EmulateSUBSPcLrEtc (opcode, encoding);
+ break;
+ default:
+ return false;
+ }
+ // Read the register value from the operand register Rn.
+ uint32_t reg_val = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1);
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow))
+ return false;
+
+ return true;
+}
+
+// Test Equivalence (immediate) performs a bitwise exclusive OR operation on a register value and an
+// immediate value. It updates the condition flags based on the result, and discards the result.
+bool
+EmulateInstructionARM::EmulateTEQImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ result = R[n] EOR imm32;
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rn;
+ uint32_t imm32; // the immediate value to be ANDed to the value obtained from Rn
+ uint32_t carry; // the carry bit after ARM/Thumb Expand operation
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 19, 16);
+ imm32 = ThumbExpandImm_C (opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
+ if (BadReg(Rn))
+ return false;
+ break;
+ case eEncodingA1:
+ Rn = Bits32(opcode, 19, 16);
+ imm32 = ARMExpandImm_C (opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ uint32_t result = val1 ^ imm32;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteFlags(context, result, carry))
+ return false;
+ }
+ return true;
+}
+
+// Test Equivalence (register) performs a bitwise exclusive OR operation on a register value and an
+// optionally-shifted register value. It updates the condition flags based on the result, and discards
+// the result.
+bool
+EmulateInstructionARM::EmulateTEQReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
+ result = R[n] EOR shifted;
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rn, Rm;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ uint32_t carry;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ if (BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the second operand.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
+ if (!success)
+ return false;
+ uint32_t result = val1 ^ shifted;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteFlags(context, result, carry))
+ return false;
+ }
+ return true;
+}
+
+// Test (immediate) performs a bitwise AND operation on a register value and an immediate value.
+// It updates the condition flags based on the result, and discards the result.
+bool
+EmulateInstructionARM::EmulateTSTImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ result = R[n] AND imm32;
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rn;
+ uint32_t imm32; // the immediate value to be ANDed to the value obtained from Rn
+ uint32_t carry; // the carry bit after ARM/Thumb Expand operation
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 19, 16);
+ imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C)
+ if (BadReg(Rn))
+ return false;
+ break;
+ case eEncodingA1:
+ Rn = Bits32(opcode, 19, 16);
+ imm32 = ARMExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C)
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ uint32_t result = val1 & imm32;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteFlags(context, result, carry))
+ return false;
+ }
+ return true;
+}
+
+// Test (register) performs a bitwise AND operation on a register value and an optionally-shifted register value.
+// It updates the condition flags based on the result, and discards the result.
+bool
+EmulateInstructionARM::EmulateTSTReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ // ARM pseudo code...
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C);
+ result = R[n] AND shifted;
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ // APSR.V unchanged
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t Rn, Rm;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n; // the shift applied to the value read from Rm
+ uint32_t carry;
+ switch (encoding)
+ {
+ case eEncodingT1:
+ Rn = Bits32(opcode, 2, 0);
+ Rm = Bits32(opcode, 5, 3);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+ break;
+ case eEncodingT2:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ shift_n = DecodeImmShiftThumb(opcode, shift_t);
+ if (BadReg(Rn) || BadReg(Rm))
+ return false;
+ break;
+ case eEncodingA1:
+ Rn = Bits32(opcode, 19, 16);
+ Rm = Bits32(opcode, 3, 0);
+ shift_n = DecodeImmShiftARM(opcode, shift_t);
+ break;
+ default:
+ return false;
+ }
+
+ // Read the first operand.
+ uint32_t val1 = ReadCoreReg(Rn, &success);
+ if (!success)
+ return false;
+
+ // Read the second operand.
+ uint32_t val2 = ReadCoreReg(Rm, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry, &success);
+ if (!success)
+ return false;
+ uint32_t result = val1 & shifted;
+
+ EmulateInstruction::Context context;
+ context.type = EmulateInstruction::eContextImmediate;
+ context.SetNoArgs ();
+
+ if (!WriteFlags(context, result, carry))
+ return false;
+ }
+ return true;
+}
+
+// A8.6.216 SUB (SP minus register)
+bool
+EmulateInstructionARM::EmulateSUBSPReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(SP, NOT(shifted), Ô1Õ);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t m;
+ bool setflags;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); m = UInt(Rm); setflags = (S == Ô1Õ);
+ d = Bits32 (opcode, 11, 8);
+ m = Bits32 (opcode, 3, 0);
+ setflags = BitIsSet (opcode, 20);
+
+ // (shift_t, shift_n) = DecodeImmShift(type, imm3:imm2);
+ shift_n = DecodeImmShiftThumb (opcode, shift_t);
+
+ // if d == 13 && (shift_t != SRType_LSL || shift_n > 3) then UNPREDICTABLE;
+ if ((d == 13) && ((shift_t != SRType_LSL) || (shift_n > 3)))
+ return false;
+
+ // if d == 15 || BadReg(m) then UNPREDICTABLE;
+ if ((d == 15) || BadReg (m))
+ return false;
+ break;
+
+ case eEncodingA1:
+ // d = UInt(Rd); m = UInt(Rm); setflags = (S == Ô1Õ);
+ d = Bits32 (opcode, 15, 12);
+ m = Bits32 (opcode, 3, 0);
+ setflags = BitIsSet (opcode, 20);
+
+ // if Rd == Ô1111Õ && S == Ô1Õ then SEE SUBS PC, LR and related instructions;
+ if (d == 15 && setflags)
+ EmulateSUBSPcLrEtc (opcode, encoding);
+
+ // (shift_t, shift_n) = DecodeImmShift(type, imm5);
+ shift_n = DecodeImmShiftARM (opcode, shift_t);
+ break;
+
+ default:
+ return false;
+ }
+
+ // shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ // (result, carry, overflow) = AddWithCarry(SP, NOT(shifted), Ô1Õ);
+ uint32_t sp_val = ReadCoreReg (SP_REG, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry (sp_val, ~shifted, 1);
+
+ EmulateInstruction::Context context;
+ context.type = eContextArithmetic;
+ RegisterInfo sp_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg);
+ RegisterInfo dwarf_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, dwarf_reg);
+ context.SetRegisterRegisterOperands (sp_reg, dwarf_reg);
+
+ if (!WriteCoreRegOptionalFlags(context, res.result, dwarf_r0 + d, setflags, res.carry_out, res.overflow))
+ return false;
+ }
+ return true;
+}
+
+
+// A8.6.7 ADD (register-shifted register)
+bool
+EmulateInstructionARM::EmulateADDRegShift (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shift_n = UInt(R[s]<7:0>);
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(R[n], shifted, Ô0Õ);
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t n;
+ uint32_t m;
+ uint32_t s;
+ bool setflags;
+ ARM_ShifterType shift_t;
+
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); s = UInt(Rs);
+ d = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+ s = Bits32 (opcode, 11, 8);
+
+ // setflags = (S == Ô1Õ); shift_t = DecodeRegShift(type);
+ setflags = BitIsSet (opcode, 20);
+ shift_t = DecodeRegShift (Bits32 (opcode, 6, 5));
+
+ // if d == 15 || n == 15 || m == 15 || s == 15 then UNPREDICTABLE;
+ if ((d == 15) || (m == 15) || (m == 15) || (s == 15))
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ // shift_n = UInt(R[s]<7:0>);
+ uint32_t Rs = ReadCoreReg (s, &success);
+ if (!success)
+ return false;
+
+ uint32_t shift_n = Bits32 (Rs, 7, 0);
+
+ // shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ // (result, carry, overflow) = AddWithCarry(R[n], shifted, Ô0Õ);
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry (Rn, shifted, 0);
+
+ // R[d] = result;
+ EmulateInstruction::Context context;
+ context.type = eContextArithmetic;
+ RegisterInfo reg_n;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, reg_n);
+ RegisterInfo reg_m;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, reg_m);
+
+ context.SetRegisterRegisterOperands (reg_n, reg_m);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, res.result))
+ return false;
+
+ // if setflags then
+ // APSR.N = result<31>;
+ // APSR.Z = IsZeroBit(result);
+ // APSR.C = carry;
+ // APSR.V = overflow;
+ if (setflags)
+ return WriteFlags (context, res.result, res.carry_out, res.overflow);
+ }
+ return true;
+}
+
+// A8.6.213 SUB (register)
+bool
+EmulateInstructionARM::EmulateSUBReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), Ô1Õ);
+ if d == 15 then // Can only occur for ARM encoding
+ ALUWritePC(result); // setflags is always FALSE here
+ else
+ R[d] = result;
+ if setflags then
+ APSR.N = result<31>;
+ APSR.Z = IsZeroBit(result);
+ APSR.C = carry;
+ APSR.V = overflow;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t n;
+ uint32_t m;
+ bool setflags;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = !InITBlock();
+ d = Bits32 (opcode, 2, 0);
+ n = Bits32 (opcode, 5, 3);
+ m = Bits32 (opcode, 8, 6);
+ setflags = !InITBlock();
+
+ // (shift_t, shift_n) = (SRType_LSL, 0);
+ shift_t = SRType_LSL;
+ shift_n = 0;
+
+ break;
+
+ case eEncodingT2:
+ // if Rd == Ô1111Õ && S == Ô1Õ then SEE CMP (register);
+ // if Rn == Ô1101Õ then SEE SUB (SP minus register);
+ // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == Ô1Õ);
+ d = Bits32 (opcode, 11, 8);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+ setflags = BitIsSet (opcode, 20);
+
+ // (shift_t, shift_n) = DecodeImmShift(type, imm3:imm2);
+ shift_n = DecodeImmShiftThumb (opcode, shift_t);
+
+ // if d == 13 || (d == 15 && S == '0') || n == 15 || BadReg(m) then UNPREDICTABLE;
+ if ((d == 13) || ((d == 15) && BitIsClear (opcode, 20)) || (n == 15) || BadReg (m))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // if Rn == Ô1101Õ then SEE SUB (SP minus register);
+ // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == Ô1Õ);
+ d = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+ setflags = BitIsSet (opcode, 20);
+
+ // if Rd == Ô1111Õ && S == Ô1Õ then SEE SUBS PC, LR and related instructions;
+ if ((d == 15) && setflags)
+ EmulateSUBSPcLrEtc (opcode, encoding);
+
+ // (shift_t, shift_n) = DecodeImmShift(type, imm5);
+ shift_n = DecodeImmShiftARM (opcode, shift_t);
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // shifted = Shift(R[m], shift_t, shift_n, APSR.C);
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t shifted = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+
+ // (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), Ô1Õ);
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult res = AddWithCarry (Rn, ~shifted, 1);
+
+ // if d == 15 then // Can only occur for ARM encoding
+ // ALUWritePC(result); // setflags is always FALSE here
+ // else
+ // R[d] = result;
+ // if setflags then
+ // APSR.N = result<31>;
+ // APSR.Z = IsZeroBit(result);
+ // APSR.C = carry;
+ // APSR.V = overflow;
+
+ EmulateInstruction::Context context;
+ context.type = eContextArithmetic;
+ RegisterInfo reg_n;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, reg_n);
+ RegisterInfo reg_m;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, reg_m);
+ context.SetRegisterRegisterOperands (reg_n, reg_m);
+
+ if (!WriteCoreRegOptionalFlags (context, res.result, dwarf_r0 + d, setflags, res.carry_out, res.overflow))
+ return false;
+ }
+ return true;
+}
+
+// A8.6.202 STREX
+// Store Register Exclusive calculates an address from a base register value and an immediate offset, and stores a
+// word from a register to memory if the executing processor has exclusive access to the memory addressed.
+bool
+EmulateInstructionARM::EmulateSTREX (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ address = R[n] + imm32;
+ if ExclusiveMonitorsPass(address,4) then
+ MemA[address,4] = R[t];
+ R[d] = 0;
+ else
+ R[d] = 1;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t d;
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // d = UInt(Rd); t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ d = Bits32 (opcode, 11, 8);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // if BadReg(d) || BadReg(t) || n == 15 then UNPREDICTABLE;
+ if (BadReg (d) || BadReg (t) || (n == 15))
+ return false;
+
+ // if d == n || d == t then UNPREDICTABLE;
+ if ((d == n) || (d == t))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // d = UInt(Rd); t = UInt(Rt); n = UInt(Rn); imm32 = Zeros(32); // Zero offset
+ d = Bits32 (opcode, 15, 12);
+ t = Bits32 (opcode, 3, 0);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = 0;
+
+ // if d == 15 || t == 15 || n == 15 then UNPREDICTABLE;
+ if ((d == 15) || (t == 15) || (n == 15))
+ return false;
+
+ // if d == n || d == t then UNPREDICTABLE;
+ if ((d == n) || (d == t))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // address = R[n] + imm32;
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ addr_t address = Rn + imm32;
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, imm32);
+
+ // if ExclusiveMonitorsPass(address,4) then
+ // if (ExclusiveMonitorsPass (address, addr_byte_size)) -- For now, for the sake of emulation, we will say this
+ // always return true.
+ if (true)
+ {
+ // MemA[address,4] = R[t];
+ uint32_t Rt = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + t, 0, &success);
+ if (!success)
+ return false;
+
+ if (!MemAWrite (context, address, Rt, addr_byte_size))
+ return false;
+
+ // R[d] = 0;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, 0))
+ return false;
+ }
+ else
+ {
+ // R[d] = 1;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, 1))
+ return false;
+ }
+ }
+ return true;
+}
+
+// A8.6.197 STRB (immediate, ARM)
+bool
+EmulateInstructionARM::EmulateSTRBImmARM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ MemU[address,1] = R[t]<7:0>;
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // if P == Ô0Õ && W == Ô1Õ then SEE STRBT;
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ);
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ // if t == 15 then UNPREDICTABLE;
+ if (t == 15)
+ return false;
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ if (add)
+ offset_addr = Rn + imm32;
+ else
+ offset_addr = Rn - imm32;
+
+ // address = if index then offset_addr else R[n];
+ addr_t address;
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ // MemU[address,1] = R[t]<7:0>;
+ uint32_t Rt = ReadCoreReg (t, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+
+ if (!MemUWrite (context, address, Bits32 (Rt, 7, 0), 1))
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// A8.6.194 STR (immediate, ARM)
+bool
+EmulateInstructionARM::EmulateSTRImmARM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ MemU[address,4] = if t == 15 then PCStoreValue() else R[t];
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // if P == Ô0Õ && W == Ô1Õ then SEE STRT;
+ // if Rn == Ô1101Õ && P == Ô1Õ && U == Ô0Õ && W == Ô1Õ && imm12 == Ô000000000100Õ then SEE PUSH;
+ // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32);
+ t = Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 11, 0);
+
+ // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ);
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ // if wback && (n == 15 || n == t) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t)))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ if (add)
+ offset_addr = Rn + imm32;
+ else
+ offset_addr = Rn - imm32;
+
+ // address = if index then offset_addr else R[n];
+ addr_t address;
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+
+ // MemU[address,4] = if t == 15 then PCStoreValue() else R[t];
+ uint32_t Rt = ReadCoreReg (t, &success);
+ if (!success)
+ return false;
+
+ if (t == 15)
+ {
+ uint32_t pc_value = ReadCoreReg (PC_REG, &success);
+ if (!success)
+ return false;
+
+ if (!MemUWrite (context, address, pc_value, addr_byte_size))
+ return false;
+ }
+ else
+ {
+ if (!MemUWrite (context, address, Rt, addr_byte_size))
+ return false;
+ }
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetImmediate (offset_addr);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// A8.6.66 LDRD (immediate)
+// Load Register Dual (immediate) calculates an address from a base register value and an immediate offset, loads two
+// words from memory, and writes them to two registers. It can use offset, post-indexed, or pre-indexed addressing.
+bool
+EmulateInstructionARM::EmulateLDRDImmediate (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ R[t] = MemA[address,4];
+ R[t2] = MemA[address+4,4];
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t t2;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ //if P == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ;
+ //if Rn == Ô1111Õ then SEE LDRD (literal);
+ //t = UInt(Rt); t2 = UInt(Rt2); n = UInt(Rn); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ t = Bits32 (opcode, 15, 12);
+ t2 = Bits32 (opcode, 11, 8);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ //index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (W == Ô1Õ);
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsSet (opcode, 21);
+
+ //if wback && (n == t || n == t2) then UNPREDICTABLE;
+ if (wback && ((n == t) || (n == t2)))
+ return false;
+
+ //if BadReg(t) || BadReg(t2) || t == t2 then UNPREDICTABLE;
+ if (BadReg (t) || BadReg (t2) || (t == t2))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ //if Rn == Ô1111Õ then SEE LDRD (literal);
+ //if Rt<0> == Ô1Õ then UNPREDICTABLE;
+ //t = UInt(Rt); t2 = t+1; n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32);
+ t = Bits32 (opcode, 15, 12);
+ if (BitIsSet (t, 0))
+ return false;
+ t2 = t + 1;
+ n = Bits32 (opcode, 19, 16);
+ imm32 = (Bits32 (opcode, 11, 8) << 4) | Bits32 (opcode, 3, 0);
+
+ //index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ);
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ //if P == Ô0Õ && W == Ô1Õ then UNPREDICTABLE;
+ if (BitIsClear (opcode, 24) && BitIsSet (opcode, 21))
+ return false;
+
+ //if wback && (n == t || n == t2) then UNPREDICTABLE;
+ if (wback && ((n == t) || (n == t2)))
+ return false;
+
+ //if t2 == 15 then UNPREDICTABLE;
+ if (t2 == 15)
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ //offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ addr_t offset_addr;
+ if (add)
+ offset_addr = Rn + imm32;
+ else
+ offset_addr = Rn - imm32;
+
+ //address = if index then offset_addr else R[n];
+ addr_t address;
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ //R[t] = MemA[address,4];
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ uint32_t data = MemARead (context, address, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+
+ //R[t2] = MemA[address+4,4];
+
+ context.SetRegisterPlusOffset (base_reg, (address + 4) - Rn);
+ data = MemARead (context, address + 4, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t2, data))
+ return false;
+
+ //if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// A8.6.68 LDRD (register)
+// Load Register Dual (register) calculates an address from a base register value and a register offset, loads two
+// words from memory, and writes them to two registers. It can use offset, post-indexed or pre-indexed addressing.
+bool
+EmulateInstructionARM::EmulateLDRDRegister (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]);
+ address = if index then offset_addr else R[n];
+ R[t] = MemA[address,4];
+ R[t2] = MemA[address+4,4];
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t t2;
+ uint32_t n;
+ uint32_t m;
+ bool index;
+ bool add;
+ bool wback;
+
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // if Rt<0> == Ô1Õ then UNPREDICTABLE;
+ // t = UInt(Rt); t2 = t+1; n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ if (BitIsSet (t, 0))
+ return false;
+ t2 = t + 1;
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ);
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ // if P == Ô0Õ && W == Ô1Õ then UNPREDICTABLE;
+ if (BitIsClear (opcode, 24) && BitIsSet (opcode, 21))
+ return false;
+
+ // if t2 == 15 || m == 15 || m == t || m == t2 then UNPREDICTABLE;
+ if ((t2 == 15) || (m == 15) || (m == t) || (m == t2))
+ return false;
+
+ // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t) || (n == t2)))
+ return false;
+
+ // if ArchVersion() < 6 && wback && m == n then UNPREDICTABLE;
+ if ((ArchVersion() < 6) && wback && (m == n))
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+ RegisterInfo offset_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
+
+ // offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]);
+ addr_t offset_addr;
+ if (add)
+ offset_addr = Rn + Rm;
+ else
+ offset_addr = Rn - Rm;
+
+ // address = if index then offset_addr else R[n];
+ addr_t address;
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusIndirectOffset (base_reg, offset_reg);
+
+ // R[t] = MemA[address,4];
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ uint32_t data = MemARead (context, address, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data))
+ return false;
+
+ // R[t2] = MemA[address+4,4];
+
+ data = MemARead (context, address + 4, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t2, data))
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+// A8.6.200 STRD (immediate)
+// Store Register Dual (immediate) calculates an address from a base register value and an immediate offset, and
+// stores two words from two registers to memory. It can use offset, post-indexed, or pre-indexed addressing.
+bool
+EmulateInstructionARM::EmulateSTRDImm (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); NullCheckIfThumbEE(n);
+ offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ address = if index then offset_addr else R[n];
+ MemA[address,4] = R[t];
+ MemA[address+4,4] = R[t2];
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t t2;
+ uint32_t n;
+ uint32_t imm32;
+ bool index;
+ bool add;
+ bool wback;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if P == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ;
+ // t = UInt(Rt); t2 = UInt(Rt2); n = UInt(Rn); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ t = Bits32 (opcode, 15, 12);
+ t2 = Bits32 (opcode, 11, 8);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (W == Ô1Õ);
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsSet (opcode, 21);
+
+ // if wback && (n == t || n == t2) then UNPREDICTABLE;
+ if (wback && ((n == t) || (n == t2)))
+ return false;
+
+ // if n == 15 || BadReg(t) || BadReg(t2) then UNPREDICTABLE;
+ if ((n == 15) || BadReg (t) || BadReg (t2))
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // if Rt<0> == Ô1Õ then UNPREDICTABLE;
+ // t = UInt(Rt); t2 = t+1; n = UInt(Rn); imm32 = ZeroExtend(imm4H:imm4L, 32);
+ t = Bits32 (opcode, 15, 12);
+ if (BitIsSet (t, 0))
+ return false;
+
+ t2 = t + 1;
+ n = Bits32 (opcode, 19, 16);
+ imm32 = (Bits32 (opcode, 11, 8) << 4) | Bits32 (opcode, 3, 0);
+
+ // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ);
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ // if P == Ô0Õ && W == Ô1Õ then UNPREDICTABLE;
+ if (BitIsClear (opcode, 24) && BitIsSet (opcode, 21))
+ return false;
+
+ // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t) || (n == t2)))
+ return false;
+
+ // if t2 == 15 then UNPREDICTABLE;
+ if (t2 == 15)
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ //offset_addr = if add then (R[n] + imm32) else (R[n] - imm32);
+ addr_t offset_addr;
+ if (add)
+ offset_addr = Rn + imm32;
+ else
+ offset_addr = Rn - imm32;
+
+ //address = if index then offset_addr else R[n];
+ addr_t address;
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+
+ //MemA[address,4] = R[t];
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+
+ uint32_t data = ReadCoreReg (t, &success);
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ if (!MemAWrite (context, address, data, addr_byte_size))
+ return false;
+
+ //MemA[address+4,4] = R[t2];
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t2, data_reg);
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, (address + 4) - Rn);
+
+ data = ReadCoreReg (t2, &success);
+ if (!success)
+ return false;
+
+ if (!MemAWrite (context, address + 4, data, addr_byte_size))
+ return false;
+
+ //if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+ }
+ }
+ return true;
+}
+
+
+// A8.6.201 STRD (register)
+bool
+EmulateInstructionARM::EmulateSTRDReg (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]);
+ address = if index then offset_addr else R[n];
+ MemA[address,4] = R[t];
+ MemA[address+4,4] = R[t2];
+ if wback then R[n] = offset_addr;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ uint32_t t;
+ uint32_t t2;
+ uint32_t n;
+ uint32_t m;
+ bool index;
+ bool add;
+ bool wback;
+
+ switch (encoding)
+ {
+ case eEncodingA1:
+ // if Rt<0> == Ô1Õ then UNPREDICTABLE;
+ // t = UInt(Rt); t2 = t+1; n = UInt(Rn); m = UInt(Rm);
+ t = Bits32 (opcode, 15, 12);
+ if (BitIsSet (t, 0))
+ return false;
+
+ t2 = t+1;
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // index = (P == Ô1Õ); add = (U == Ô1Õ); wback = (P == Ô0Õ) || (W == Ô1Õ);
+ index = BitIsSet (opcode, 24);
+ add = BitIsSet (opcode, 23);
+ wback = BitIsClear (opcode, 24) || BitIsSet (opcode, 21);
+
+ // if P == Ô0Õ && W == Ô1Õ then UNPREDICTABLE;
+ if (BitIsClear (opcode, 24) && BitIsSet (opcode, 21))
+ return false;
+
+ // if t2 == 15 || m == 15 then UNPREDICTABLE;
+ if ((t2 == 15) || (m == 15))
+ return false;
+
+ // if wback && (n == 15 || n == t || n == t2) then UNPREDICTABLE;
+ if (wback && ((n == 15) || (n == t) || (n == t2)))
+ return false;
+
+ // if ArchVersion() < 6 && wback && m == n then UNPREDICTABLE;
+ if ((ArchVersion() < 6) && wback && (m == n))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+ RegisterInfo offset_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + m, offset_reg);
+ RegisterInfo data_reg;
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ // offset_addr = if add then (R[n] + R[m]) else (R[n] - R[m]);
+ addr_t offset_addr;
+ if (add)
+ offset_addr = Rn + Rm;
+ else
+ offset_addr = Rn - Rm;
+
+ // address = if index then offset_addr else R[n];
+ addr_t address;
+ if (index)
+ address = offset_addr;
+ else
+ address = Rn;
+ // MemA[address,4] = R[t];
+ uint32_t Rt = ReadCoreReg (t, &success);
+ if (!success)
+ return false;
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t, data_reg);
+ context.SetRegisterToRegisterPlusIndirectOffset (base_reg, offset_reg, data_reg);
+
+ const uint32_t addr_byte_size = GetAddressByteSize();
+
+ if (!MemAWrite (context, address, Rt, addr_byte_size))
+ return false;
+
+ // MemA[address+4,4] = R[t2];
+ uint32_t Rt2 = ReadCoreReg (t2, &success);
+ if (!success)
+ return false;
+
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + t2, data_reg);
+
+ context.SetRegisterToRegisterPlusIndirectOffset (base_reg, offset_reg, data_reg);
+
+ if (!MemAWrite (context, address + 4, Rt2, addr_byte_size))
+ return false;
+
+ // if wback then R[n] = offset_addr;
+ if (wback)
+ {
+ context.type = eContextAdjustBaseRegister;
+ context.SetAddress (offset_addr);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr))
+ return false;
+
+ }
+ }
+ return true;
+}
+
+// A8.6.319 VLDM
+// Vector Load Multiple loads multiple extension registers from consecutive memory locations using an address from
+// an ARM core register.
+bool
+EmulateInstructionARM::EmulateVLDM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n);
+ address = if add then R[n] else R[n]-imm32;
+ if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32;
+ for r = 0 to regs-1
+ if single_regs then
+ S[d+r] = MemA[address,4]; address = address+4;
+ else
+ word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8;
+ // Combine the word-aligned words in the correct order for current endianness.
+ D[d+r] = if BigEndian() then word1:word2 else word2:word1;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed(opcode))
+ {
+ bool single_regs;
+ bool add;
+ bool wback;
+ uint32_t d;
+ uint32_t n;
+ uint32_t imm32;
+ uint32_t regs;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ // if P == Ô0Õ && U == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ;
+ // if P == Ô0Õ && U == Ô1Õ && W == Ô1Õ && Rn == Ô1101Õ then SEE VPOP;
+ // if P == Ô1Õ && W == Ô0Õ then SEE VLDR;
+ // if P == U && W == Ô1Õ then UNDEFINED;
+ if ((Bit32 (opcode, 24) == Bit32 (opcode, 23)) && BitIsSet (opcode, 21))
+ return false;
+
+ // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with !), 101 (DB with !)
+ // single_regs = FALSE; add = (U == Ô1Õ); wback = (W == Ô1Õ);
+ single_regs = false;
+ add = BitIsSet (opcode, 23);
+ wback = BitIsSet (opcode, 21);
+
+ // d = UInt(D:Vd); n = UInt(Rn); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // regs = UInt(imm8) DIV 2; // If UInt(imm8) is odd, see ÒFLDMXÓ.
+ regs = Bits32 (opcode, 7, 0) / 2;
+
+ // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then UNPREDICTABLE;
+ if (n == 15 && (wback || CurrentInstrSet() != eModeARM))
+ return false;
+
+ // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
+ if ((regs == 0) || (regs > 16) || ((d + regs) > 32))
+ return false;
+
+ break;
+
+ case eEncodingT2:
+ case eEncodingA2:
+ // if P == Ô0Õ && U == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ;
+ // if P == Ô0Õ && U == Ô1Õ && W == Ô1Õ && Rn == Ô1101Õ then SEE VPOP;
+ // if P == Ô1Õ && W == Ô0Õ then SEE VLDR;
+ // if P == U && W == Ô1Õ then UNDEFINED;
+ if ((Bit32 (opcode, 24) == Bit32 (opcode, 23)) && BitIsSet (opcode, 21))
+ return false;
+
+ // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with !), 101 (DB with !)
+ // single_regs = TRUE; add = (U == Ô1Õ); wback = (W == Ô1Õ); d = UInt(Vd:D); n = UInt(Rn);
+ single_regs = true;
+ add = BitIsSet (opcode, 23);
+ wback = BitIsSet (opcode, 21);
+ d = (Bits32 (opcode, 15, 12) << 1) | Bit32 (opcode, 22);
+ n = Bits32 (opcode, 19, 16);
+
+ // imm32 = ZeroExtend(imm8:Õ00Õ, 32); regs = UInt(imm8);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+ regs = Bits32 (opcode, 7, 0);
+
+ // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then UNPREDICTABLE;
+ if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM)))
+ return false;
+
+ // if regs == 0 || (d+regs) > 32 then UNPREDICTABLE;
+ if ((regs == 0) || ((d + regs) > 32))
+ return false;
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // address = if add then R[n] else R[n]-imm32;
+ addr_t address;
+ if (add)
+ address = Rn;
+ else
+ address = Rn - imm32;
+
+ // if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32;
+ EmulateInstruction::Context context;
+
+ if (wback)
+ {
+ uint32_t value;
+ if (add)
+ value = Rn + imm32;
+ else
+ value = Rn - imm32;
+
+ context.type = eContextAdjustBaseRegister;
+ context.SetImmediateSigned (value - Rn);
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, value))
+ return false;
+
+ }
+
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
+
+ context.type = eContextRegisterLoad;
+
+ // for r = 0 to regs-1
+ for (uint32_t r = 0; r < regs; ++r)
+ {
+ if (single_regs)
+ {
+ // S[d+r] = MemA[address,4]; address = address+4;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+
+ uint32_t data = MemARead (context, address, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, start_reg + d + r, data))
+ return false;
+
+ address = address + 4;
+ }
+ else
+ {
+ // word1 = MemA[address,4]; word2 = MemA[address+4,4]; address = address+8;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+ uint32_t word1 = MemARead (context, address, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ context.SetRegisterPlusOffset (base_reg, (address + 4) - Rn);
+ uint32_t word2 = MemARead (context, address + 4, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ address = address + 8;
+ // // Combine the word-aligned words in the correct order for current endianness.
+ // D[d+r] = if BigEndian() then word1:word2 else word2:word1;
+ uint64_t data;
+ if (GetByteOrder() == eByteOrderBig)
+ {
+ data = word1;
+ data = (data << 32) | word2;
+ }
+ else
+ {
+ data = word2;
+ data = (data << 32) | word1;
+ }
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, start_reg + d + r, data))
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+// A8.6.399 VSTM
+// Vector Store Multiple stores multiple extension registers to consecutive memory locations using an address from an
+// ARM core register.
+bool
+EmulateInstructionARM::EmulateVSTM (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n);
+ address = if add then R[n] else R[n]-imm32;
+ if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32;
+ for r = 0 to regs-1
+ if single_regs then
+ MemA[address,4] = S[d+r]; address = address+4;
+ else
+ // Store as two word-aligned words in the correct order for current endianness.
+ MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>;
+ MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>;
+ address = address+8;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ bool single_regs;
+ bool add;
+ bool wback;
+ uint32_t d;
+ uint32_t n;
+ uint32_t imm32;
+ uint32_t regs;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ // if P == Ô0Õ && U == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ;
+ // if P == Ô1Õ && U == Ô0Õ && W == Ô1Õ && Rn == Ô1101Õ then SEE VPUSH;
+ // if P == Ô1Õ && W == Ô0Õ then SEE VSTR;
+ // if P == U && W == Ô1Õ then UNDEFINED;
+ if ((Bit32 (opcode, 24) == Bit32 (opcode, 23)) && BitIsSet (opcode, 21))
+ return false;
+
+ // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with !), 101 (DB with !)
+ // single_regs = FALSE; add = (U == Ô1Õ); wback = (W == Ô1Õ);
+ single_regs = false;
+ add = BitIsSet (opcode, 23);
+ wback = BitIsSet (opcode, 21);
+
+ // d = UInt(D:Vd); n = UInt(Rn); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // regs = UInt(imm8) DIV 2; // If UInt(imm8) is odd, see ÒFSTMXÓ.
+ regs = Bits32 (opcode, 7, 0) / 2;
+
+ // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then UNPREDICTABLE;
+ if ((n == 15) && (wback || (CurrentInstrSet() != eModeARM)))
+ return false;
+
+ // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE;
+ if ((regs == 0) || (regs > 16) || ((d + regs) > 32))
+ return false;
+
+ break;
+
+ case eEncodingT2:
+ case eEncodingA2:
+ // if P == Ô0Õ && U == Ô0Õ && W == Ô0Õ then SEE ÒRelated encodingsÓ;
+ // if P == Ô1Õ && U == Ô0Õ && W == Ô1Õ && Rn == Ô1101Õ then SEE VPUSH;
+ // if P == Ô1Õ && W == Ô0Õ then SEE VSTR;
+ // if P == U && W == Ô1Õ then UNDEFINED;
+ if ((Bit32 (opcode, 24) == Bit32 (opcode, 23)) && BitIsSet (opcode, 21))
+ return false;
+
+ // // Remaining combinations are PUW = 010 (IA without !), 011 (IA with !), 101 (DB with !)
+ // single_regs = TRUE; add = (U == Ô1Õ); wback = (W == Ô1Õ); d = UInt(Vd:D); n = UInt(Rn);
+ single_regs = true;
+ add = BitIsSet (opcode, 23);
+ wback = BitIsSet (opcode, 21);
+ d = (Bits32 (opcode, 15, 12) << 1) | Bit32 (opcode, 22);
+ n = Bits32 (opcode, 19, 16);
+
+ // imm32 = ZeroExtend(imm8:Õ00Õ, 32); regs = UInt(imm8);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+ regs = Bits32 (opcode, 7, 0);
+
+ // if n == 15 && (wback || CurrentInstrSet() != InstrSet_ARM) then UNPREDICTABLE;
+ if ((n == 15) && (wback || (CurrentInstrSet () != eModeARM)))
+ return false;
+
+ // if regs == 0 || (d+regs) > 32 then UNPREDICTABLE;
+ if ((regs == 0) || ((d + regs) > 32))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // address = if add then R[n] else R[n]-imm32;
+ addr_t address;
+ if (add)
+ address = Rn;
+ else
+ address = Rn - imm32;
+
+ EmulateInstruction::Context context;
+ // if wback then R[n] = if add then R[n]+imm32 else R[n]-imm32;
+ if (wback)
+ {
+ uint32_t value;
+ if (add)
+ value = Rn + imm32;
+ else
+ value = Rn - imm32;
+
+ context.type = eContextAdjustBaseRegister;
+ context.SetRegisterPlusOffset (base_reg, value - Rn);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, value))
+ return false;
+ }
+
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0;
+
+ context.type = eContextRegisterStore;
+ // for r = 0 to regs-1
+ for (uint32_t r = 0; r < regs; ++r)
+ {
+
+ if (single_regs)
+ {
+ // MemA[address,4] = S[d+r]; address = address+4;
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, start_reg + d + r, 0, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, start_reg + d + r, data_reg);
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+ if (!MemAWrite (context, address, data, addr_byte_size))
+ return false;
+
+ address = address + 4;
+ }
+ else
+ {
+ // // Store as two word-aligned words in the correct order for current endianness.
+ // MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>;
+ // MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>;
+ uint64_t data = ReadRegisterUnsigned (eRegisterKindDWARF, start_reg + d + r, 0, &success);
+ if (!success)
+ return false;
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, start_reg + d + r, data_reg);
+
+ if (GetByteOrder() == eByteOrderBig)
+ {
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+ if (!MemAWrite (context, address, Bits64 (data, 63, 32), addr_byte_size))
+ return false;
+
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, (address + 4) - Rn);
+ if (!MemAWrite (context, address+ 4, Bits64 (data, 31, 0), addr_byte_size))
+ return false;
+ }
+ else
+ {
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+ if (!MemAWrite (context, address, Bits64 (data, 31, 0), addr_byte_size))
+ return false;
+
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, (address + 4) - Rn);
+ if (!MemAWrite (context, address + 4, Bits64 (data, 63, 32), addr_byte_size))
+ return false;
+ }
+ // address = address+8;
+ address = address + 8;
+ }
+ }
+ }
+ return true;
+}
+
+// A8.6.320
+// This instruciton loads a single extension register fronm memory, using an address from an ARM core register, with
+// an optional offset.
+bool
+EmulateInstructionARM::EmulateVLDR (const uint32_t opcode, ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n);
+ base = if n == 15 then Align(PC,4) else R[n];
+ address = if add then (base + imm32) else (base - imm32);
+ if single_reg then
+ S[d] = MemA[address,4];
+ else
+ word1 = MemA[address,4]; word2 = MemA[address+4,4];
+ // Combine the word-aligned words in the correct order for current endianness.
+ D[d] = if BigEndian() then word1:word2 else word2:word1;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ bool single_reg;
+ bool add;
+ uint32_t imm32;
+ uint32_t d;
+ uint32_t n;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ // single_reg = FALSE; add = (U == Ô1Õ); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ single_reg = false;
+ add = BitIsSet (opcode, 23);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // d = UInt(D:Vd); n = UInt(Rn);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+
+ break;
+
+ case eEncodingT2:
+ case eEncodingA2:
+ // single_reg = TRUE; add = (U == Ô1Õ); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ single_reg = true;
+ add = BitIsSet (opcode, 23);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // d = UInt(Vd:D); n = UInt(Rn);
+ d = (Bits32 (opcode, 15, 12) << 1) | Bit32 (opcode, 22);
+ n = Bits32 (opcode, 19, 16);
+
+ break;
+
+ default:
+ return false;
+ }
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // base = if n == 15 then Align(PC,4) else R[n];
+ uint32_t base;
+ if (n == 15)
+ base = AlignPC (Rn);
+ else
+ base = Rn;
+
+ // address = if add then (base + imm32) else (base - imm32);
+ addr_t address;
+ if (add)
+ address = base + imm32;
+ else
+ address = base - imm32;
+
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ uint32_t start_reg = single_reg ? dwarf_s0 : dwarf_d0;
+
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - base);
+
+ if (single_reg)
+ {
+ // S[d] = MemA[address,4];
+ uint32_t data = MemARead (context, address, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, start_reg + d, data))
+ return false;
+ }
+ else
+ {
+ // word1 = MemA[address,4]; word2 = MemA[address+4,4];
+ uint32_t word1 = MemARead (context, address, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+
+ context.SetRegisterPlusOffset (base_reg, (address + 4) - base);
+ uint32_t word2 = MemARead (context, address + 4, addr_byte_size, 0, &success);
+ if (!success)
+ return false;
+ // // Combine the word-aligned words in the correct order for current endianness.
+ // D[d] = if BigEndian() then word1:word2 else word2:word1;
+ uint64_t data64;
+ if (GetByteOrder() == eByteOrderBig)
+ {
+ data64 = word1;
+ data64 = (data64 << 32) | word2;
+ }
+ else
+ {
+ data64 = word2;
+ data64 = (data64 << 32) | word1;
+ }
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, start_reg + d, data64))
+ return false;
+ }
+ }
+ return true;
+}
+
+// A8.6.400 VSTR
+// This instruction stores a signle extension register to memory, using an address from an ARM core register, with an
+// optional offset.
+bool
+EmulateInstructionARM::EmulateVSTR (const uint32_t opcode, ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(n);
+ address = if add then (R[n] + imm32) else (R[n] - imm32);
+ if single_reg then
+ MemA[address,4] = S[d];
+ else
+ // Store as two word-aligned words in the correct order for current endianness.
+ MemA[address,4] = if BigEndian() then D[d]<63:32> else D[d]<31:0>;
+ MemA[address+4,4] = if BigEndian() then D[d]<31:0> else D[d]<63:32>;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ bool single_reg;
+ bool add;
+ uint32_t imm32;
+ uint32_t d;
+ uint32_t n;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ // single_reg = FALSE; add = (U == Ô1Õ); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ single_reg = false;
+ add = BitIsSet (opcode, 23);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // d = UInt(D:Vd); n = UInt(Rn);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+
+ // if n == 15 && CurrentInstrSet() != InstrSet_ARM then UNPREDICTABLE;
+ if ((n == 15) && (CurrentInstrSet() != eModeARM))
+ return false;
+
+ break;
+
+ case eEncodingT2:
+ case eEncodingA2:
+ // single_reg = TRUE; add = (U == Ô1Õ); imm32 = ZeroExtend(imm8:Õ00Õ, 32);
+ single_reg = true;
+ add = BitIsSet (opcode, 23);
+ imm32 = Bits32 (opcode, 7, 0) << 2;
+
+ // d = UInt(Vd:D); n = UInt(Rn);
+ d = (Bits32 (opcode, 15, 12) << 1) | Bit32 (opcode, 22);
+ n = Bits32 (opcode, 19, 16);
+
+ // if n == 15 && CurrentInstrSet() != InstrSet_ARM then UNPREDICTABLE;
+ if ((n == 15) && (CurrentInstrSet() != eModeARM))
+ return false;
+
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // address = if add then (R[n] + imm32) else (R[n] - imm32);
+ addr_t address;
+ if (add)
+ address = Rn + imm32;
+ else
+ address = Rn - imm32;
+
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ uint32_t start_reg = single_reg ? dwarf_s0 : dwarf_d0;
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, start_reg + d, data_reg);
+ EmulateInstruction::Context context;
+ context.type = eContextRegisterStore;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+
+ if (single_reg)
+ {
+ // MemA[address,4] = S[d];
+ uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, start_reg + d, 0, &success);
+ if (!success)
+ return false;
+
+ if (!MemAWrite (context, address, data, addr_byte_size))
+ return false;
+ }
+ else
+ {
+ // // Store as two word-aligned words in the correct order for current endianness.
+ // MemA[address,4] = if BigEndian() then D[d]<63:32> else D[d]<31:0>;
+ // MemA[address+4,4] = if BigEndian() then D[d]<31:0> else D[d]<63:32>;
+ uint64_t data = ReadRegisterUnsigned (eRegisterKindDWARF, start_reg + d, 0, &success);
+ if (!success)
+ return false;
+
+ if (GetByteOrder() == eByteOrderBig)
+ {
+ if (!MemAWrite (context, address, Bits64 (data, 63, 32), addr_byte_size))
+ return false;
+
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, (address + 4) - Rn);
+ if (!MemAWrite (context, address + 4, Bits64 (data, 31, 0), addr_byte_size))
+ return false;
+ }
+ else
+ {
+ if (!MemAWrite (context, address, Bits64 (data, 31, 0), addr_byte_size))
+ return false;
+
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, (address + 4) - Rn);
+ if (!MemAWrite (context, address + 4, Bits64 (data, 63, 32), addr_byte_size))
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+// A8.6.307 VLDI1 (multiple single elements)
+// This instruction loads elements from memory into one, two, three or four registers, without de-interleaving. Every
+// element of each register is loaded.
+bool
+EmulateInstructionARM::EmulateVLD1Multiple (const uint32_t opcode, ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n);
+ address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs);
+ for r = 0 to regs-1
+ for e = 0 to elements-1
+ Elem[D[d+r],e,esize] = MemU[address,ebytes];
+ address = address + ebytes;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ uint32_t regs;
+ uint32_t alignment;
+ uint32_t ebytes;
+ uint32_t esize;
+ uint32_t elements;
+ uint32_t d;
+ uint32_t n;
+ uint32_t m;
+ bool wback;
+ bool register_index;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ {
+ // case type of
+ // when Ô0111Õ
+ // regs = 1; if align<1> == Ô1Õ then UNDEFINED;
+ // when Ô1010Õ
+ // regs = 2; if align == Ô11Õ then UNDEFINED;
+ // when Ô0110Õ
+ // regs = 3; if align<1> == Ô1Õ then UNDEFINED;
+ // when Ô0010Õ
+ // regs = 4;
+ // otherwise
+ // SEE ÒRelated encodingsÓ;
+ uint32_t type = Bits32 (opcode, 11, 8);
+ uint32_t align = Bits32 (opcode, 5, 4);
+ if (type == 7) // '0111'
+ {
+ regs = 1;
+ if (BitIsSet (align, 1))
+ return false;
+ }
+ else if (type == 10) // '1010'
+ {
+ regs = 2;
+ if (align == 3)
+ return false;
+
+ }
+ else if (type == 6) // '0110'
+ {
+ regs = 3;
+ if (BitIsSet (align, 1))
+ return false;
+ }
+ else if (type == 2) // '0010'
+ {
+ regs = 4;
+ }
+ else
+ return false;
+
+ // alignment = if align == Ô00Õ then 1 else 4 << UInt(align);
+ if (align == 0)
+ alignment = 1;
+ else
+ alignment = 4 << align;
+
+ // ebytes = 1 << UInt(size); esize = 8 * ebytes; elements = 8 DIV ebytes;
+ ebytes = 1 << Bits32 (opcode, 7, 6);
+ esize = 8 * ebytes;
+ elements = 8 / ebytes;
+
+ // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 15);
+ m = Bits32 (opcode, 3, 0);
+
+ // wback = (m != 15); register_index = (m != 15 && m != 13);
+ wback = (m != 15);
+ register_index = ((m != 15) && (m != 13));
+
+ // if d+regs > 32 then UNPREDICTABLE;
+ if ((d + regs) > 32)
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ addr_t address = Rn;
+ if ((address % alignment) != 0)
+ return false;
+
+ EmulateInstruction::Context context;
+ // if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs);
+ if (wback)
+ {
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t offset;
+ if (register_index)
+ offset = Rm;
+ else
+ offset = 8 * regs;
+
+ uint32_t value = Rn + offset;
+ context.type = eContextAdjustBaseRegister;
+ context.SetRegisterPlusOffset (base_reg, offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, value))
+ return false;
+
+ }
+
+ // for r = 0 to regs-1
+ for (uint32_t r = 0; r < regs; ++r)
+ {
+ // for e = 0 to elements-1
+ uint64_t assembled_data = 0;
+ for (uint32_t e = 0; e < elements; ++e)
+ {
+ // Elem[D[d+r],e,esize] = MemU[address,ebytes];
+ context.type = eContextRegisterLoad;
+ context.SetRegisterPlusOffset (base_reg, address - Rn);
+ uint64_t data = MemURead (context, address, ebytes, 0, &success);
+ if (!success)
+ return false;
+
+ assembled_data = (data << (e * esize)) | assembled_data; // New data goes to the left of existing data
+
+ // address = address + ebytes;
+ address = address + ebytes;
+ }
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_d0 + d + r, assembled_data))
+ return false;
+ }
+ }
+ return true;
+}
+
+// A8.6.308 VLD1 (single element to one lane)
+//
+bool
+EmulateInstructionARM::EmulateVLD1Single (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n);
+ address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
+ Elem[D[d],index,esize] = MemU[address,ebytes];
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ uint32_t ebytes;
+ uint32_t esize;
+ uint32_t index;
+ uint32_t alignment;
+ uint32_t d;
+ uint32_t n;
+ uint32_t m;
+ bool wback;
+ bool register_index;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ {
+ uint32_t size = Bits32 (opcode, 11, 10);
+ uint32_t index_align = Bits32 (opcode, 7, 4);
+ // if size == Ô11Õ then SEE VLD1 (single element to all lanes);
+ if (size == 3)
+ return EmulateVLD1SingleAll (opcode, encoding);
+ // case size of
+ if (size == 0) // when '00'
+ {
+ // if index_align<0> != Ô0Õ then UNDEFINED;
+ if (BitIsClear (index_align, 0))
+ return false;
+
+ // ebytes = 1; esize = 8; index = UInt(index_align<3:1>); alignment = 1;
+ ebytes = 1;
+ esize = 8;
+ index = Bits32 (index_align, 3, 1);
+ alignment = 1;
+ }
+ else if (size == 1) // when Ô01Õ
+ {
+ // if index_align<1> != Ô0Õ then UNDEFINED;
+ if (BitIsClear (index_align, 1))
+ return false;
+
+ // ebytes = 2; esize = 16; index = UInt(index_align<3:2>);
+ ebytes = 2;
+ esize = 16;
+ index = Bits32 (index_align, 3, 2);
+
+ // alignment = if index_align<0> == Ô0Õ then 1 else 2;
+ if (BitIsClear (index_align, 0))
+ alignment = 1;
+ else
+ alignment = 2;
+ }
+ else if (size == 2) // when Ô10Õ
+ {
+ // if index_align<2> != Ô0Õ then UNDEFINED;
+ if (BitIsClear (index_align, 2))
+ return false;
+
+ // if index_align<1:0> != Ô00Õ && index_align<1:0> != Ô11Õ then UNDEFINED;
+ if ((Bits32 (index_align, 1, 0) != 0) && (Bits32 (index_align, 1, 0) != 3))
+ return false;
+
+ // ebytes = 4; esize = 32; index = UInt(index_align<3>);
+ ebytes = 4;
+ esize = 32;
+ index = Bit32 (index_align, 3);
+
+ // alignment = if index_align<1:0> == Ô00Õ then 1 else 4;
+ if (Bits32 (index_align, 1, 0) == 0)
+ alignment = 1;
+ else
+ alignment = 4;
+ }
+ else
+ {
+ return false;
+ }
+ // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // wback = (m != 15); register_index = (m != 15 && m != 13); if n == 15 then UNPREDICTABLE;
+ wback = (m != 15);
+ register_index = ((m != 15) && (m != 13));
+
+ if (n == 15)
+ return false;
+
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ addr_t address = Rn;
+ if ((address % alignment) != 0)
+ return false;
+
+ EmulateInstruction::Context context;
+ // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
+ if (wback)
+ {
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t offset;
+ if (register_index)
+ offset = Rm;
+ else
+ offset = ebytes;
+
+ uint32_t value = Rn + offset;
+
+ context.type = eContextAdjustBaseRegister;
+ context.SetRegisterPlusOffset (base_reg, offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, value))
+ return false;
+ }
+
+ // Elem[D[d],index,esize] = MemU[address,ebytes];
+ uint32_t element = MemURead (context, address, esize, 0, &success);
+ if (!success)
+ return false;
+
+ element = element << (index * esize);
+
+ uint64_t reg_data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_d0 + d, 0, &success);
+ if (!success)
+ return false;
+
+ uint64_t all_ones = -1;
+ uint64_t mask = all_ones << ((index+1) * esize); // mask is all 1's to left of where 'element' goes, & all 0's
+ // at element & to the right of element.
+ if (index > 0)
+ mask = mask | Bits64 (all_ones, (index * esize) - 1, 0); // add 1's to the right of where 'element' goes.
+ // now mask should be 0's where element goes & 1's
+ // everywhere else.
+
+ uint64_t masked_reg = reg_data & mask; // Take original reg value & zero out 'element' bits
+ reg_data = masked_reg & element; // Put 'element' into those bits in reg_data.
+
+ context.type = eContextRegisterLoad;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, reg_data))
+ return false;
+ }
+ return true;
+}
+
+// A8.6.391 VST1 (multiple single elements)
+// Vector Store (multiple single elements) stores elements to memory from one, two, three, or four regsiters, without
+// interleaving. Every element of each register is stored.
+bool
+EmulateInstructionARM::EmulateVST1Multiple (const uint32_t opcode, ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n);
+ address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs);
+ for r = 0 to regs-1
+ for e = 0 to elements-1
+ MemU[address,ebytes] = Elem[D[d+r],e,esize];
+ address = address + ebytes;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ uint32_t regs;
+ uint32_t alignment;
+ uint32_t ebytes;
+ uint32_t esize;
+ uint32_t elements;
+ uint32_t d;
+ uint32_t n;
+ uint32_t m;
+ bool wback;
+ bool register_index;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ {
+ uint32_t type = Bits32 (opcode, 11, 8);
+ uint32_t align = Bits32 (opcode, 5, 4);
+
+ // case type of
+ if (type == 7) // when Ô0111Õ
+ {
+ // regs = 1; if align<1> == Ô1Õ then UNDEFINED;
+ regs = 1;
+ if (BitIsSet (align, 1))
+ return false;
+ }
+ else if (type == 10) // when Ô1010Õ
+ {
+ // regs = 2; if align == Ô11Õ then UNDEFINED;
+ regs = 2;
+ if (align == 3)
+ return false;
+ }
+ else if (type == 6) // when Ô0110Õ
+ {
+ // regs = 3; if align<1> == Ô1Õ then UNDEFINED;
+ regs = 3;
+ if (BitIsSet (align, 1))
+ return false;
+ }
+ else if (type == 2) // when Ô0010Õ
+ // regs = 4;
+ regs = 4;
+ else // otherwise
+ // SEE ÒRelated encodingsÓ;
+ return false;
+
+ // alignment = if align == Ô00Õ then 1 else 4 << UInt(align);
+ if (align == 0)
+ alignment = 1;
+ else
+ alignment = 4 << align;
+
+ // ebytes = 1 << UInt(size); esize = 8 * ebytes; elements = 8 DIV ebytes;
+ ebytes = 1 << Bits32 (opcode,7, 6);
+ esize = 8 * ebytes;
+ elements = 8 / ebytes;
+
+ // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // wback = (m != 15); register_index = (m != 15 && m != 13);
+ wback = (m != 15);
+ register_index = ((m != 15) && (m != 13));
+
+ // if d+regs > 32 then UNPREDICTABLE; if n == 15 then UNPREDICTABLE;
+ if ((d + regs) > 32)
+ return false;
+
+ if (n == 15)
+ return false;
+
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ addr_t address = Rn;
+ if ((address % alignment) != 0)
+ return false;
+
+ EmulateInstruction::Context context;
+ // if wback then R[n] = R[n] + (if register_index then R[m] else 8*regs);
+ if (wback)
+ {
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t offset;
+ if (register_index)
+ offset = Rm;
+ else
+ offset = 8 * regs;
+
+ context.type = eContextAdjustBaseRegister;
+ context.SetRegisterPlusOffset (base_reg, offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, Rn + offset))
+ return false;
+ }
+
+ RegisterInfo data_reg;
+ context.type = eContextRegisterStore;
+ // for r = 0 to regs-1
+ for (uint32_t r = 0; r < regs; ++r)
+ {
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_d0 + d + r, data_reg);
+ uint64_t register_data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_d0 + d + r, 0, &success);
+ if (!success)
+ return false;
+
+ // for e = 0 to elements-1
+ for (uint32_t e = 0; e < elements; ++e)
+ {
+ // MemU[address,ebytes] = Elem[D[d+r],e,esize];
+ uint64_t word = Bits64 (register_data, ((e + 1) * esize) - 1, e * esize);
+
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+ if (!MemUWrite (context, address, word, ebytes))
+ return false;
+
+ // address = address + ebytes;
+ address = address + ebytes;
+ }
+ }
+ }
+ return true;
+}
+
+// A8.6.392 VST1 (single element from one lane)
+// This instruction stores one element to memory from one element of a register.
+bool
+EmulateInstructionARM::EmulateVST1Single (const uint32_t opcode, ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n);
+ address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
+ MemU[address,ebytes] = Elem[D[d],index,esize];
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ uint32_t ebytes;
+ uint32_t esize;
+ uint32_t index;
+ uint32_t alignment;
+ uint32_t d;
+ uint32_t n;
+ uint32_t m;
+ bool wback;
+ bool register_index;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ {
+ uint32_t size = Bits32 (opcode, 11, 10);
+ uint32_t index_align = Bits32 (opcode, 7, 4);
+
+ // if size == Ô11Õ then UNDEFINED;
+ if (size == 3)
+ return false;
+
+ // case size of
+ if (size == 0) // when Ô00Õ
+ {
+ // if index_align<0> != Ô0Õ then UNDEFINED;
+ if (BitIsClear (index_align, 0))
+ return false;
+ // ebytes = 1; esize = 8; index = UInt(index_align<3:1>); alignment = 1;
+ ebytes = 1;
+ esize = 8;
+ index = Bits32 (index_align, 3, 1);
+ alignment = 1;
+ }
+ else if (size == 1) // when Ô01Õ
+ {
+ // if index_align<1> != Ô0Õ then UNDEFINED;
+ if (BitIsClear (index_align, 1))
+ return false;
+
+ // ebytes = 2; esize = 16; index = UInt(index_align<3:2>);
+ ebytes = 2;
+ esize = 16;
+ index = Bits32 (index_align, 3, 2);
+
+ // alignment = if index_align<0> == Ô0Õ then 1 else 2;
+ if (BitIsClear (index_align, 0))
+ alignment = 1;
+ else
+ alignment = 2;
+ }
+ else if (size == 2) // when Ô10Õ
+ {
+ // if index_align<2> != Ô0Õ then UNDEFINED;
+ if (BitIsClear (index_align, 2))
+ return false;
+
+ // if index_align<1:0> != Ô00Õ && index_align<1:0> != Ô11Õ then UNDEFINED;
+ if ((Bits32 (index_align, 1, 0) != 0) && (Bits32 (index_align, 1, 0) != 3))
+ return false;
+
+ // ebytes = 4; esize = 32; index = UInt(index_align<3>);
+ ebytes = 4;
+ esize = 32;
+ index = Bit32 (index_align, 3);
+
+ // alignment = if index_align<1:0> == Ô00Õ then 1 else 4;
+ if (Bits32 (index_align, 1, 0) == 0)
+ alignment = 1;
+ else
+ alignment = 4;
+ }
+ else
+ {
+ return false;
+ }
+ // d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ // wback = (m != 15); register_index = (m != 15 && m != 13); if n == 15 then UNPREDICTABLE;
+ wback = (m != 15);
+ register_index = ((m != 15) && (m != 13));
+
+ if (n == 15)
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ addr_t address = Rn;
+ if ((address % alignment) != 0)
+ return false;
+
+ EmulateInstruction::Context context;
+ // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
+ if (wback)
+ {
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t offset;
+ if (register_index)
+ offset = Rm;
+ else
+ offset = ebytes;
+
+ context.type = eContextAdjustBaseRegister;
+ context.SetRegisterPlusOffset (base_reg, offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, Rn + offset))
+ return false;
+ }
+
+ // MemU[address,ebytes] = Elem[D[d],index,esize];
+ uint64_t register_data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_d0 + d, 0, &success);
+ if (!success)
+ return false;
+
+ uint64_t word = Bits64 (register_data, ((index + 1) * esize) - 1, index * esize);
+
+ RegisterInfo data_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_d0 + d, data_reg);
+ context.type = eContextRegisterStore;
+ context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn);
+
+ if (!MemUWrite (context, address, word, ebytes))
+ return false;
+ }
+ return true;
+}
+
+// A8.6.309 VLD1 (single element to all lanes)
+// This instruction loads one element from memory into every element of one or two vectors.
+bool
+EmulateInstructionARM::EmulateVLD1SingleAll (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations(); CheckAdvSIMDEnabled(); NullCheckIfThumbEE(n);
+ address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
+ replicated_element = Replicate(MemU[address,ebytes], elements);
+ for r = 0 to regs-1
+ D[d+r] = replicated_element;
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ uint32_t ebytes;
+ uint32_t elements;
+ uint32_t regs;
+ uint32_t alignment;
+ uint32_t d;
+ uint32_t n;
+ uint32_t m;
+ bool wback;
+ bool register_index;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ case eEncodingA1:
+ {
+ //if size == Ô11Õ || (size == Ô00Õ && a == Ô1Õ) then UNDEFINED;
+ uint32_t size = Bits32 (opcode, 7, 6);
+ if ((size == 3) || ((size == 0) && BitIsSet (opcode, 4)))
+ return false;
+
+ //ebytes = 1 << UInt(size); elements = 8 DIV ebytes; regs = if T == Ô0Õ then 1 else 2;
+ ebytes = 1 << size;
+ elements = 8 / ebytes;
+ if (BitIsClear (opcode, 5))
+ regs = 1;
+ else
+ regs = 2;
+
+ //alignment = if a == Ô0Õ then 1 else ebytes;
+ if (BitIsClear (opcode, 4))
+ alignment = 1;
+ else
+ alignment = ebytes;
+
+ //d = UInt(D:Vd); n = UInt(Rn); m = UInt(Rm);
+ d = (Bit32 (opcode, 22) << 4) | Bits32 (opcode, 15, 12);
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+
+ //wback = (m != 15); register_index = (m != 15 && m != 13);
+ wback = (m != 15);
+ register_index = ((m != 15) && (m != 13));
+
+ //if d+regs > 32 then UNPREDICTABLE; if n == 15 then UNPREDICTABLE;
+ if ((d + regs) > 32)
+ return false;
+
+ if (n == 15)
+ return false;
+ }
+ break;
+
+ default:
+ return false;
+ }
+
+ RegisterInfo base_reg;
+ GetRegisterInfo (eRegisterKindDWARF, dwarf_r0 + n, base_reg);
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ // address = R[n]; if (address MOD alignment) != 0 then GenerateAlignmentException();
+ addr_t address = Rn;
+ if ((address % alignment) != 0)
+ return false;
+
+ EmulateInstruction::Context context;
+ // if wback then R[n] = R[n] + (if register_index then R[m] else ebytes);
+ if (wback)
+ {
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ uint32_t offset;
+ if (register_index)
+ offset = Rm;
+ else
+ offset = ebytes;
+
+ context.type = eContextAdjustBaseRegister;
+ context.SetRegisterPlusOffset (base_reg, offset);
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, Rn + offset))
+ return false;
+ }
+
+ // replicated_element = Replicate(MemU[address,ebytes], elements);
+
+ context.type = eContextRegisterLoad;
+ uint64_t word = MemURead (context, address, ebytes, 0, &success);
+ if (!success)
+ return false;
+
+ uint64_t replicated_element = 0;
+ uint32_t esize = ebytes * 8;
+ for (uint32_t e = 0; e < elements; ++e)
+ replicated_element = (replicated_element << esize) | Bits64 (word, esize - 1, 0);
+
+ // for r = 0 to regs-1
+ for (uint32_t r = 0; r < regs; ++r)
+ {
+ // D[d+r] = replicated_element;
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_d0 + d + r, replicated_element))
+ return false;
+ }
+ }
+ return true;
+}
+
+// B6.2.13 SUBS PC, LR and related instructions
+//The SUBS PC, LR, #<const? instruction provides an exception return without the use of the stack. It subtracts the
+// immediate constant from the LR, branches to the resulting address, and also copies the SPSR to the CPSR.
+bool
+EmulateInstructionARM::EmulateSUBSPcLrEtc (const uint32_t opcode, const ARMEncoding encoding)
+{
+#if 0
+ if ConditionPassed() then
+ EncodingSpecificOperations();
+ if CurrentInstrSet() == InstrSet_ThumbEE then
+ UNPREDICTABLE;
+ operand2 = if register_form then Shift(R[m], shift_t, shift_n, APSR.C) else imm32;
+ case opcode of
+ when Ô0000Õ result = R[n] AND operand2; // AND
+ when Ô0001Õ result = R[n] EOR operand2; // EOR
+ when Ô0010Õ (result, -, -) = AddWithCarry(R[n], NOT(operand2), Ô1Õ); // SUB
+ when Ô0011Õ (result, -, -) = AddWithCarry(NOT(R[n]), operand2, Ô1Õ); // RSB
+ when Ô0100Õ (result, -, -) = AddWithCarry(R[n], operand2, Ô0Õ); // ADD
+ when Ô0101Õ (result, -, -) = AddWithCarry(R[n], operand2, APSR.c); // ADC
+ when Ô0110Õ (result, -, -) = AddWithCarry(R[n], NOT(operand2), APSR.C); // SBC
+ when Ô0111Õ (result, -, -) = AddWithCarry(NOT(R[n]), operand2, APSR.C); // RSC
+ when Ô1100Õ result = R[n] OR operand2; // ORR
+ when Ô1101Õ result = operand2; // MOV
+ when Ô1110Õ result = R[n] AND NOT(operand2); // BIC
+ when Ô1111Õ result = NOT(operand2); // MVN
+ CPSRWriteByInstr(SPSR[], Ô1111Õ, TRUE);
+ BranchWritePC(result);
+#endif
+
+ bool success = false;
+
+ if (ConditionPassed (opcode))
+ {
+ uint32_t n;
+ uint32_t m;
+ uint32_t imm32;
+ bool register_form;
+ ARM_ShifterType shift_t;
+ uint32_t shift_n;
+ uint32_t code;
+
+ switch (encoding)
+ {
+ case eEncodingT1:
+ // if CurrentInstrSet() == InstrSet_ThumbEE then UNPREDICTABLE
+ // n = 14; imm32 = ZeroExtend(imm8, 32); register_form = FALSE; opcode = Ô0010Õ; // = SUB
+ n = 14;
+ imm32 = Bits32 (opcode, 7, 0);
+ register_form = false;
+ code = 2;
+
+ // if InITBlock() && !LastInITBlock() then UNPREDICTABLE;
+ if (InITBlock() && !LastInITBlock())
+ return false;
+
+ break;
+
+ case eEncodingA1:
+ // n = UInt(Rn); imm32 = ARMExpandImm(imm12); register_form = FALSE;
+ n = Bits32 (opcode, 19, 16);
+ imm32 = ARMExpandImm (opcode);
+ register_form = false;
+ code = Bits32 (opcode, 24, 21);
+
+ break;
+
+ case eEncodingA2:
+ // n = UInt(Rn); m = UInt(Rm); register_form = TRUE;
+ n = Bits32 (opcode, 19, 16);
+ m = Bits32 (opcode, 3, 0);
+ register_form = true;
+
+ // (shift_t, shift_n) = DecodeImmShift(type, imm5);
+ shift_n = DecodeImmShiftARM (opcode, shift_t);
+
+ break;
+
+ default:
+ return false;
+ }
+
+ // operand2 = if register_form then Shift(R[m], shift_t, shift_n, APSR.C) else imm32;
+ uint32_t operand2;
+ if (register_form)
+ {
+ uint32_t Rm = ReadCoreReg (m, &success);
+ if (!success)
+ return false;
+
+ operand2 = Shift (Rm, shift_t, shift_n, APSR_C, &success);
+ if (!success)
+ return false;
+ }
+ else
+ {
+ operand2 = imm32;
+ }
+
+ uint32_t Rn = ReadCoreReg (n, &success);
+ if (!success)
+ return false;
+
+ AddWithCarryResult result;
+
+ // case opcode of
+ switch (code)
+ {
+ case 0: // when Ô0000Õ
+ // result = R[n] AND operand2; // AND
+ result.result = Rn & operand2;
+ break;
+
+ case 1: // when Ô0001Õ
+ // result = R[n] EOR operand2; // EOR
+ result.result = Rn ^ operand2;
+ break;
+
+ case 2: // when Ô0010Õ
+ // (result, -, -) = AddWithCarry(R[n], NOT(operand2), Ô1Õ); // SUB
+ result = AddWithCarry (Rn, ~(operand2), 1);
+ break;
+
+ case 3: // when Ô0011Õ
+ // (result, -, -) = AddWithCarry(NOT(R[n]), operand2, Ô1Õ); // RSB
+ result = AddWithCarry (~(Rn), operand2, 1);
+ break;
+
+ case 4: // when Ô0100Õ
+ // (result, -, -) = AddWithCarry(R[n], operand2, Ô0Õ); // ADD
+ result = AddWithCarry (Rn, operand2, 0);
+ break;
+
+ case 5: // when Ô0101Õ
+ // (result, -, -) = AddWithCarry(R[n], operand2, APSR.c); // ADC
+ result = AddWithCarry (Rn, operand2, APSR_C);
+ break;
+
+ case 6: // when Ô0110Õ
+ // (result, -, -) = AddWithCarry(R[n], NOT(operand2), APSR.C); // SBC
+ result = AddWithCarry (Rn, ~(operand2), APSR_C);
+ break;
+
+ case 7: // when Ô0111Õ
+ // (result, -, -) = AddWithCarry(NOT(R[n]), operand2, APSR.C); // RSC
+ result = AddWithCarry (~(Rn), operand2, APSR_C);
+ break;
+
+ case 10: // when Ô1100Õ
+ // result = R[n] OR operand2; // ORR
+ result.result = Rn | operand2;
+ break;
+
+ case 11: // when Ô1101Õ
+ // result = operand2; // MOV
+ result.result = operand2;
+ break;
+
+ case 12: // when Ô1110Õ
+ // result = R[n] AND NOT(operand2); // BIC
+ result.result = Rn & ~(operand2);
+ break;
+
+ case 15: // when Ô1111Õ
+ // result = NOT(operand2); // MVN
+ result.result = ~(operand2);
+ break;
+
+ default:
+ return false;
+ }
+ // CPSRWriteByInstr(SPSR[], Ô1111Õ, TRUE);
+
+ // For now, in emulation mode, we don't have access to the SPSR, so we will use the CPSR instead, and hope for
+ // the best.
+ uint32_t spsr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_cpsr, 0, &success);
+ if (!success)
+ return false;
+
+ CPSRWriteByInstr (spsr, 15, true);
+
+ // BranchWritePC(result);
+ EmulateInstruction::Context context;
+ context.type = eContextAdjustPC;
+ context.SetImmediate (result.result);
+
+ BranchWritePC (context, result.result);
+ }
+ return true;
+}
+
+EmulateInstructionARM::ARMOpcode*
+EmulateInstructionARM::GetARMOpcodeForInstruction (const uint32_t opcode, uint32_t arm_isa)
+{
+ static ARMOpcode
+ g_arm_opcodes[] =
+ {
+ //----------------------------------------------------------------------
+ // Prologue instructions
+ //----------------------------------------------------------------------
+
+ // push register(s)
+ { 0x0fff0000, 0x092d0000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulatePUSH, "push <registers>" },
+ { 0x0fff0fff, 0x052d0004, ARMvAll, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulatePUSH, "push <register>" },
+
+ // set r7 to point to a stack offset
+ { 0x0ffff000, 0x028d7000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDRdSPImm, "add r7, sp, #<const>" },
+ { 0x0ffff000, 0x024c7000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBR7IPImm, "sub r7, ip, #<const>"},
+ // copy the stack pointer to ip
+ { 0x0fffffff, 0x01a0c00d, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdSP, "mov ip, sp" },
+ { 0x0ffff000, 0x028dc000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDRdSPImm, "add ip, sp, #<const>" },
+ { 0x0ffff000, 0x024dc000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBIPSPImm, "sub ip, sp, #<const>"},
+
+ // adjust the stack pointer
+ { 0x0ffff000, 0x024dd000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "sub sp, sp, #<const>"},
+ { 0x0fef0010, 0x004d0000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPReg, "sub{s}<c> <Rd>, sp, <Rm>{,<shift>}" },
+
+ // push one register
+ // if Rn == '1101' && imm12 == '000000000100' then SEE PUSH;
+ { 0x0e5f0000, 0x040d0000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRRtSP, "str Rt, [sp, #-imm12]!" },
+
+ // vector push consecutive extension register(s)
+ { 0x0fbf0f00, 0x0d2d0b00, ARMV6T2_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
+ { 0x0fbf0f00, 0x0d2d0a00, ARMV6T2_ABOVE, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
+
+ //----------------------------------------------------------------------
+ // Epilogue instructions
+ //----------------------------------------------------------------------
+
+ { 0x0fff0000, 0x08bd0000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulatePOP, "pop <registers>"},
+ { 0x0fff0fff, 0x049d0004, ARMvAll, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulatePOP, "pop <register>"},
+ { 0x0fbf0f00, 0x0cbd0b00, ARMV6T2_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
+ { 0x0fbf0f00, 0x0cbd0a00, ARMV6T2_ABOVE, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"},
+
+ //----------------------------------------------------------------------
+ // Supervisor Call (previously Software Interrupt)
+ //----------------------------------------------------------------------
+ { 0x0f000000, 0x0f000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSVC, "svc #imm24"},
+
+ //----------------------------------------------------------------------
+ // Branch instructions
+ //----------------------------------------------------------------------
+ { 0x0f000000, 0x0a000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateB, "b #imm24"},
+ // To resolve ambiguity, "blx <label>" should come before "bl <label>".
+ { 0xfe000000, 0xfa000000, ARMV5_ABOVE, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
+ { 0x0f000000, 0x0b000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
+ { 0x0ffffff0, 0x012fff30, ARMV5_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
+ // for example, "bx lr"
+ { 0x0ffffff0, 0x012fff10, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBXRm, "bx <Rm>"},
+ // bxj
+ { 0x0ffffff0, 0x012fff20, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBXJRm, "bxj <Rm>"},
+
+ //----------------------------------------------------------------------
+ // Data-processing instructions
+ //----------------------------------------------------------------------
+ // adc (immediate)
+ { 0x0fe00000, 0x02a00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADCImm, "adc{s}<c> <Rd>, <Rn>, #const"},
+ // adc (register)
+ { 0x0fe00010, 0x00a00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADCReg, "adc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // add (immediate)
+ { 0x0fe00000, 0x02800000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDImmARM, "add{s}<c> <Rd>, <Rn>, #const"},
+ // add (register)
+ { 0x0fe00010, 0x00800000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDReg, "add{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // add (register-shifted register)
+ { 0x0fe00090, 0x00800010, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDRegShift, "add{s}<c> <Rd>, <Rn>, <Rm>, <type> <RS>"},
+ // adr
+ { 0x0fff0000, 0x028f0000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"},
+ { 0x0fff0000, 0x024f0000, ARMvAll, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateADR, "sub<c> <Rd>, PC, #<const>"},
+ // and (immediate)
+ { 0x0fe00000, 0x02000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateANDImm, "and{s}<c> <Rd>, <Rn>, #const"},
+ // and (register)
+ { 0x0fe00010, 0x00000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateANDReg, "and{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // bic (immediate)
+ { 0x0fe00000, 0x03c00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBICImm, "bic{s}<c> <Rd>, <Rn>, #const"},
+ // bic (register)
+ { 0x0fe00010, 0x01c00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBICReg, "bic{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // eor (immediate)
+ { 0x0fe00000, 0x02200000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateEORImm, "eor{s}<c> <Rd>, <Rn>, #const"},
+ // eor (register)
+ { 0x0fe00010, 0x00200000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateEORReg, "eor{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // orr (immediate)
+ { 0x0fe00000, 0x03800000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateORRImm, "orr{s}<c> <Rd>, <Rn>, #const"},
+ // orr (register)
+ { 0x0fe00010, 0x01800000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateORRReg, "orr{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // rsb (immediate)
+ { 0x0fe00000, 0x02600000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSBImm, "rsb{s}<c> <Rd>, <Rn>, #<const>"},
+ // rsb (register)
+ { 0x0fe00010, 0x00600000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSBReg, "rsb{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // rsc (immediate)
+ { 0x0fe00000, 0x02e00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSCImm, "rsc{s}<c> <Rd>, <Rn>, #<const>"},
+ // rsc (register)
+ { 0x0fe00010, 0x00e00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSCReg, "rsc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // sbc (immediate)
+ { 0x0fe00000, 0x02c00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSBCImm, "sbc{s}<c> <Rd>, <Rn>, #<const>"},
+ // sbc (register)
+ { 0x0fe00010, 0x00c00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSBCReg, "sbc{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // sub (immediate, ARM)
+ { 0x0fe00000, 0x02400000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBImmARM, "sub{s}<c> <Rd>, <Rn>, #<const>"},
+ // sub (sp minus immediate)
+ { 0x0fef0000, 0x024d0000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "sub{s}<c> <Rd>, sp, #<const>"},
+ // sub (register)
+ { 0x0fe00010, 0x00400000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBReg, "sub{s}<c> <Rd>, <Rn>, <Rm>{,<shift>}"},
+ // teq (immediate)
+ { 0x0ff0f000, 0x03300000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTEQImm, "teq<c> <Rn>, #const"},
+ // teq (register)
+ { 0x0ff0f010, 0x01300000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTEQReg, "teq<c> <Rn>, <Rm> {,<shift>}"},
+ // tst (immediate)
+ { 0x0ff0f000, 0x03100000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTSTImm, "tst<c> <Rn>, #const"},
+ // tst (register)
+ { 0x0ff0f010, 0x01100000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTSTReg, "tst<c> <Rn>, <Rm> {,<shift>}"},
+
+ // mov (immediate)
+ { 0x0fef0000, 0x03a00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdImm, "mov{s}<c> <Rd>, #<const>"},
+ { 0x0ff00000, 0x03000000, ARMV6T2_ABOVE, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdImm, "movw<c> <Rd>, #<imm16>" },
+ // mov (register)
+ { 0x0fef0ff0, 0x01a00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdRm, "mov{s}<c> <Rd>, <Rm>"},
+ // mvn (immediate)
+ { 0x0fef0000, 0x03e00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMVNImm, "mvn{s}<c> <Rd>, #<const>"},
+ // mvn (register)
+ { 0x0fef0010, 0x01e00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMVNReg, "mvn{s}<c> <Rd>, <Rm> {,<shift>}"},
+ // cmn (immediate)
+ { 0x0ff0f000, 0x03700000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMNImm, "cmn<c> <Rn>, #<const>"},
+ // cmn (register)
+ { 0x0ff0f010, 0x01700000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMNReg, "cmn<c> <Rn>, <Rm> {,<shift>}"},
+ // cmp (immediate)
+ { 0x0ff0f000, 0x03500000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMPImm, "cmp<c> <Rn>, #<const>"},
+ // cmp (register)
+ { 0x0ff0f010, 0x01500000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm> {,<shift>}"},
+ // asr (immediate)
+ { 0x0fef0070, 0x01a00040, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateASRImm, "asr{s}<c> <Rd>, <Rm>, #imm"},
+ // asr (register)
+ { 0x0fef00f0, 0x01a00050, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateASRReg, "asr{s}<c> <Rd>, <Rn>, <Rm>"},
+ // lsl (immediate)
+ { 0x0fef0070, 0x01a00000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSLImm, "lsl{s}<c> <Rd>, <Rm>, #imm"},
+ // lsl (register)
+ { 0x0fef00f0, 0x01a00010, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSLReg, "lsl{s}<c> <Rd>, <Rn>, <Rm>"},
+ // lsr (immediate)
+ { 0x0fef0070, 0x01a00020, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSRImm, "lsr{s}<c> <Rd>, <Rm>, #imm"},
+ // lsr (register)
+ { 0x0fef00f0, 0x01a00050, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSRReg, "lsr{s}<c> <Rd>, <Rn>, <Rm>"},
+ // rrx is a special case encoding of ror (immediate)
+ { 0x0fef0ff0, 0x01a00060, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRRX, "rrx{s}<c> <Rd>, <Rm>"},
+ // ror (immediate)
+ { 0x0fef0070, 0x01a00060, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRORImm, "ror{s}<c> <Rd>, <Rm>, #imm"},
+ // ror (register)
+ { 0x0fef00f0, 0x01a00070, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRORReg, "ror{s}<c> <Rd>, <Rn>, <Rm>"},
+ // mul
+ { 0x0fe000f0, 0x00000090, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMUL, "mul{s}<c> <Rd>,<R>,<Rm>" },
+
+ // subs pc, lr and related instructions
+ { 0x0e10f000, 0x0210f000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPcLrEtc, "<opc>S<c> PC,#<const> | <Rn>,#<const>" },
+ { 0x0e10f010, 0x0010f000, ARMvAll, eEncodingA2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPcLrEtc, "<opc>S<c> PC,<Rn>,<Rm{,<shift>}" },
+
+ //----------------------------------------------------------------------
+ // Load instructions
+ //----------------------------------------------------------------------
+ { 0x0fd00000, 0x08900000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>" },
+ { 0x0fd00000, 0x08100000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDMDA, "ldmda<c> <Rn>{!} <registers>" },
+ { 0x0fd00000, 0x09100000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>" },
+ { 0x0fd00000, 0x09900000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDMIB, "ldmib<c> <Rn<{!} <registers>" },
+ { 0x0e500000, 0x04100000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRImmediateARM, "ldr<c> <Rt> [<Rn> {#+/-<imm12>}]" },
+ { 0x0e500010, 0x06100000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRRegister, "ldr<c> <Rt> [<Rn> +/-<Rm> {<shift>}] {!}" },
+ { 0x0e5f0000, 0x045f0000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBLiteral, "ldrb<c> <Rt>, [...]"},
+ { 0xfe500010, 0x06500000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBRegister, "ldrb<c> <Rt>, [<Rn>,+/-<Rm>{, <shift>}]{!}" },
+ { 0x0e5f00f0, 0x005f00b0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHLiteral, "ldrh<c> <Rt>, <label>" },
+ { 0x0e5000f0, 0x001000b0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHRegister, "ldrh<c> <Rt>,[<Rn>,+/-<Rm>]{!}" },
+ { 0x0e5000f0, 0x005000d0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBImmediate, "ldrsb<c> <Rt>, [<Rn>{,#+/-<imm8>}]" },
+ { 0x0e5f00f0, 0x005f00d0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBLiteral, "ldrsb<c> <Rt> <label>" },
+ { 0x0e5000f0, 0x001000d0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBRegister, "ldrsb<c> <Rt>,[<Rn>,+/-<Rm>]{!}" },
+ { 0x0e5000f0, 0x005000f0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHImmediate, "ldrsh<c> <Rt>,[<Rn>{,#+/-<imm8>}]"},
+ { 0x0e5f00f0, 0x005f00f0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHLiteral, "ldrsh<c> <Rt>,<label>" },
+ { 0x0e5000f0, 0x001000f0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHRegister, "ldrsh<c> <Rt>,[<Rn>,+/-<Rm>]{!}" },
+ { 0x0e5000f0, 0x004000d0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRDImmediate, "ldrd<c> <Rt>, <Rt2>, [<Rn>,#+/-<imm8>]!"},
+ { 0x0e500ff0, 0x000000d0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRDRegister, "ldrd<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}"},
+ { 0x0e100f00, 0x0c100b00, ARMvAll, eEncodingA1, VFPv2_ABOVE, eSize32, &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>"},
+ { 0x0e100f00, 0x0c100a00, ARMvAll, eEncodingA2, VFPv2v3, eSize32, &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>"},
+ { 0x0f300f00, 0x0d100b00, ARMvAll, eEncodingA1, VFPv2_ABOVE, eSize32, &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Dd>, [<Rn>{,#+/-<imm>}]"},
+ { 0x0f300f00, 0x0d100a00, ARMvAll, eEncodingA2, VFPv2v3, eSize32, &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Sd>, [<Rn>{,#+/-<imm>}]"},
+ { 0xffb00000, 0xf4200000, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1Multiple, "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
+ { 0xffb00300, 0xf4a00000, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1Single, "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
+ { 0xffb00f00, 0xf4a00c00, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1SingleAll, "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
+
+ //----------------------------------------------------------------------
+ // Store instructions
+ //----------------------------------------------------------------------
+ { 0x0fd00000, 0x08800000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTM, "stm<c> <Rn>{!} <registers>" },
+ { 0x0fd00000, 0x08000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTMDA, "stmda<c> <Rn>{!} <registers>" },
+ { 0x0fd00000, 0x09000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTMDB, "stmdb<c> <Rn>{!} <registers>" },
+ { 0x0fd00000, 0x09800000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTMIB, "stmib<c> <Rn>{!} <registers>" },
+ { 0x0e500010, 0x06000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRRegister, "str<c> <Rt> [<Rn> +/-<Rm> {<shift>}]{!}" },
+ { 0x0e5000f0, 0x000000b0, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRHRegister, "strh<c> <Rt>,[<Rn>,+/-<Rm>[{!}" },
+ { 0x0ff00ff0, 0x01800f90, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTREX, "strex<c> <Rd>, <Rt>, [<Rn>]"},
+ { 0x0e500000, 0x04400000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRBImmARM, "strb<c> <Rt>,[<Rn>,#+/-<imm12>]!"},
+ { 0x0e500000, 0x04000000, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRImmARM, "str<c> <Rt>,[<Rn>,#+/-<imm12>]!"},
+ { 0x0e5000f0, 0x004000f0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRDImm, "strd<c> <Rt>, <Rt2>, [<Rn> #+/-<imm8>]!"},
+ { 0x0e500ff0, 0x000000f0, ARMV5TE_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRDReg, "strd<c> <Rt>, <Rt2>, [<Rn>, +/-<Rm>]{!}"},
+ { 0x0e100f00, 0x0c000b00, ARMvAll, eEncodingA1, VFPv2_ABOVE, eSize32, &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!} <list>"},
+ { 0x0e100f00, 0x0c000a00, ARMvAll, eEncodingA2, VFPv2v3, eSize32, &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!} <list>"},
+ { 0x0f300f00, 0x0d000b00, ARMvAll, eEncodingA1, VFPv2_ABOVE, eSize32, &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Dd> [<Rn>{,#+/-<imm>}]"},
+ { 0x0f300f00, 0x0d000a00, ARMvAll, eEncodingA2, VFPv2v3, eSize32, &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Sd> [<Rn>{,#+/-<imm>}]"},
+ { 0xffb00000, 0xf4000000, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVST1Multiple, "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
+ { 0xffb00300, 0xf4800000, ARMvAll, eEncodingA1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVST1Single, "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
+
+ //----------------------------------------------------------------------
+ // Other instructions
+ //----------------------------------------------------------------------
+ { 0x0fff00f0, 0x06af00f0, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSXTB, "sxtb<c> <Rd>,<Rm>{,<rotation>}" },
+ { 0x0fff00f0, 0x06bf0070, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSXTH, "sxth<c> <Rd>,<Rm>{,<rotation>}" },
+ { 0x0fff00f0, 0x06ef0070, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateUXTB, "uxtb<c> <Rd>,<Rm>{,<rotation>}" },
+ { 0x0fff00f0, 0x06ff0070, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateUXTH, "uxth<c> <Rd>,<Rm>{,<rotation>}" },
+ { 0xfe500000, 0xf8100000, ARMV6_ABOVE, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRFE, "rfe{<amode>} <Rn>{!}" }
+
+ };
+ static const size_t k_num_arm_opcodes = sizeof(g_arm_opcodes)/sizeof(ARMOpcode);
+
+ for (size_t i=0; i<k_num_arm_opcodes; ++i)
+ {
+ if ((g_arm_opcodes[i].mask & opcode) == g_arm_opcodes[i].value &&
+ (g_arm_opcodes[i].variants & arm_isa) != 0)
+ return &g_arm_opcodes[i];
+ }
+ return NULL;
+}
+
+
+EmulateInstructionARM::ARMOpcode*
+EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode, uint32_t arm_isa)
+{
+
+ static ARMOpcode
+ g_thumb_opcodes[] =
+ {
+ //----------------------------------------------------------------------
+ // Prologue instructions
+ //----------------------------------------------------------------------
+
+ // push register(s)
+ { 0xfffffe00, 0x0000b400, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulatePUSH, "push <registers>" },
+ { 0xffff0000, 0xe92d0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulatePUSH, "push.w <registers>" },
+ { 0xffff0fff, 0xf84d0d04, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulatePUSH, "push.w <register>" },
+
+ // set r7 to point to a stack offset
+ { 0xffffff00, 0x0000af00, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDRdSPImm, "add r7, sp, #imm" },
+ // copy the stack pointer to r7
+ { 0xffffffff, 0x0000466f, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMOVRdSP, "mov r7, sp" },
+ // move from high register to low register (comes after "mov r7, sp" to resolve ambiguity)
+ { 0xffffffc0, 0x00004640, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMOVLowHigh, "mov r0-r7, r8-r15" },
+
+ // PC-relative load into register (see also EmulateADDSPRm)
+ { 0xfffff800, 0x00004800, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRRtPCRelative, "ldr <Rt>, [PC, #imm]"},
+
+ // adjust the stack pointer
+ { 0xffffff87, 0x00004485, ARMvAll, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDSPRm, "add sp, <Rm>"},
+ { 0xffffff80, 0x0000b080, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSUBSPImm, "sub sp, sp, #imm"},
+ { 0xfbef8f00, 0xf1ad0d00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "sub.w sp, sp, #<const>"},
+ { 0xfbff8f00, 0xf2ad0d00, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "subw sp, sp, #imm12"},
+ { 0xffef8000, 0xebad0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPReg, "sub{s}<c> <Rd>, sp, <Rm>{,<shift>}" },
+
+ // vector push consecutive extension register(s)
+ { 0xffbf0f00, 0xed2d0b00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 <list>"},
+ { 0xffbf0f00, 0xed2d0a00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 <list>"},
+
+ //----------------------------------------------------------------------
+ // Epilogue instructions
+ //----------------------------------------------------------------------
+
+ { 0xfffff800, 0x0000a800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDSPImm, "add<c> <Rd>, sp, #imm"},
+ { 0xffffff80, 0x0000b000, ARMvAll, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDSPImm, "add sp, #imm"},
+ { 0xfffffe00, 0x0000bc00, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulatePOP, "pop <registers>"},
+ { 0xffff0000, 0xe8bd0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulatePOP, "pop.w <registers>" },
+ { 0xffff0fff, 0xf85d0d04, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulatePOP, "pop.w <register>" },
+ { 0xffbf0f00, 0xecbd0b00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 <list>"},
+ { 0xffbf0f00, 0xecbd0a00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 <list>"},
+
+ //----------------------------------------------------------------------
+ // Supervisor Call (previously Software Interrupt)
+ //----------------------------------------------------------------------
+ { 0xffffff00, 0x0000df00, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSVC, "svc #imm8"},
+
+ //----------------------------------------------------------------------
+ // If Then makes up to four following instructions conditional.
+ //----------------------------------------------------------------------
+ // The next 5 opcode _must_ come before the if then instruction
+ { 0xffffffff, 0x0000bf00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateNop, "nop"},
+ { 0xffffffff, 0x0000bf10, ARMV7_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateNop, "nop YIELD (yield hint)"},
+ { 0xffffffff, 0x0000bf20, ARMV7_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateNop, "nop WFE (wait for event hint)"},
+ { 0xffffffff, 0x0000bf30, ARMV7_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateNop, "nop WFI (wait for interrupt hint)"},
+ { 0xffffffff, 0x0000bf40, ARMV7_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateNop, "nop SEV (send event hint)"},
+ { 0xffffff00, 0x0000bf00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateIT, "it{<x>{<y>{<z>}}} <firstcond>"},
+
+ //----------------------------------------------------------------------
+ // Branch instructions
+ //----------------------------------------------------------------------
+ // To resolve ambiguity, "b<c> #imm8" should come after "svc #imm8".
+ { 0xfffff000, 0x0000d000, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateB, "b<c> #imm8 (outside IT)"},
+ { 0xfffff800, 0x0000e000, ARMvAll, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateB, "b<c> #imm11 (outside or last in IT)"},
+ { 0xf800d000, 0xf0008000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateB, "b<c>.w #imm8 (outside IT)"},
+ { 0xf800d000, 0xf0009000, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, &EmulateInstructionARM::EmulateB, "b<c>.w #imm8 (outside or last in IT)"},
+ // J1 == J2 == 1
+ { 0xf800d000, 0xf000d000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "bl <label>"},
+ // J1 == J2 == 1
+ { 0xf800d001, 0xf000c000, ARMV5_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateBLXImmediate, "blx <label>"},
+ { 0xffffff87, 0x00004780, ARMV5_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateBLXRm, "blx <Rm>"},
+ // for example, "bx lr"
+ { 0xffffff87, 0x00004700, ARMvAll, eEncodingA1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBXRm, "bx <Rm>"},
+ // bxj
+ { 0xfff0ffff, 0xf3c08f00, ARMV5J_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBXJRm, "bxj <Rm>"},
+ // compare and branch
+ { 0xfffff500, 0x0000b100, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateCB, "cb{n}z <Rn>, <label>"},
+ // table branch byte
+ { 0xfff0fff0, 0xe8d0f000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTB, "tbb<c> <Rn>, <Rm>"},
+ // table branch halfword
+ { 0xfff0fff0, 0xe8d0f010, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTB, "tbh<c> <Rn>, <Rm>, lsl #1"},
+
+ //----------------------------------------------------------------------
+ // Data-processing instructions
+ //----------------------------------------------------------------------
+ // adc (immediate)
+ { 0xfbe08000, 0xf1400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateADCImm, "adc{s}<c> <Rd>, <Rn>, #<const>"},
+ // adc (register)
+ { 0xffffffc0, 0x00004140, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADCReg, "adcs|adc<c> <Rdn>, <Rm>"},
+ { 0xffe08000, 0xeb400000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateADCReg, "adc{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // add (register)
+ { 0xfffffe00, 0x00001800, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDReg, "adds|add<c> <Rd>, <Rn>, <Rm>"},
+ // Make sure "add sp, <Rm>" comes before this instruction, so there's no ambiguity decoding the two.
+ { 0xffffff00, 0x00004400, ARMvAll, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDReg, "add<c> <Rdn>, <Rm>"},
+ // adr
+ { 0xfffff800, 0x0000a000, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"},
+ { 0xfbff8000, 0xf2af0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateADR, "sub<c> <Rd>, PC, #<const>"},
+ { 0xfbff8000, 0xf20f0000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"},
+ // and (immediate)
+ { 0xfbe08000, 0xf0000000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateANDImm, "and{s}<c> <Rd>, <Rn>, #<const>"},
+ // and (register)
+ { 0xffffffc0, 0x00004000, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateANDReg, "ands|and<c> <Rdn>, <Rm>"},
+ { 0xffe08000, 0xea000000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateANDReg, "and{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // bic (immediate)
+ { 0xfbe08000, 0xf0200000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateBICImm, "bic{s}<c> <Rd>, <Rn>, #<const>"},
+ // bic (register)
+ { 0xffffffc0, 0x00004380, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateBICReg, "bics|bic<c> <Rdn>, <Rm>"},
+ { 0xffe08000, 0xea200000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateBICReg, "bic{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // eor (immediate)
+ { 0xfbe08000, 0xf0800000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateEORImm, "eor{s}<c> <Rd>, <Rn>, #<const>"},
+ // eor (register)
+ { 0xffffffc0, 0x00004040, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateEORReg, "eors|eor<c> <Rdn>, <Rm>"},
+ { 0xffe08000, 0xea800000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateEORReg, "eor{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // orr (immediate)
+ { 0xfbe08000, 0xf0400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateORRImm, "orr{s}<c> <Rd>, <Rn>, #<const>"},
+ // orr (register)
+ { 0xffffffc0, 0x00004300, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateORRReg, "orrs|orr<c> <Rdn>, <Rm>"},
+ { 0xffe08000, 0xea400000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateORRReg, "orr{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // rsb (immediate)
+ { 0xffffffc0, 0x00004240, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateRSBImm, "rsbs|rsb<c> <Rd>, <Rn>, #0"},
+ { 0xfbe08000, 0xf1c00000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSBImm, "rsb{s}<c>.w <Rd>, <Rn>, #<const>"},
+ // rsb (register)
+ { 0xffe08000, 0xea400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRSBReg, "rsb{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // sbc (immediate)
+ { 0xfbe08000, 0xf1600000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSBCImm, "sbc{s}<c> <Rd>, <Rn>, #<const>"},
+ // sbc (register)
+ { 0xffffffc0, 0x00004180, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSBCReg, "sbcs|sbc<c> <Rdn>, <Rm>"},
+ { 0xffe08000, 0xeb600000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSBCReg, "sbc{s}<c>.w <Rd>, <Rn>, <Rm> {,<shift>}"},
+ // add (immediate, Thumb)
+ { 0xfffffe00, 0x00001c00, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDImmThumb, "adds|add<c> <Rd>,<Rn>,#<imm3>" },
+ { 0xfffff800, 0x00003000, ARMV4T_ABOVE, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateADDImmThumb, "adds|add<c> <Rdn>,#<imm8>" },
+ { 0xfbe08000, 0xf1000000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDImmThumb, "add{s}<c>.w <Rd>,<Rn>,#<const>" },
+ { 0xfbf08000, 0xf2000000, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, &EmulateInstructionARM::EmulateADDImmThumb, "addw<c> <Rd>,<Rn>,#<imm12>" },
+ // sub (immediate, Thumb)
+ { 0xfffffe00, 0x00001e00, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSUBImmThumb, "subs|sub<c> <Rd>, <Rn> #imm3"},
+ { 0xfffff800, 0x00003800, ARMvAll, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateSUBImmThumb, "subs|sub<c> <Rdn>, #imm8"},
+ { 0xfbe08000, 0xf1a00000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBImmThumb, "sub{s}<c>.w <Rd>, <Rn>, #<const>"},
+ { 0xfbf08000, 0xf2a00000, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBImmThumb, "subw<c> <Rd>, <Rn>, #imm12"},
+ // sub (sp minus immediate)
+ { 0xfbef8000, 0xf1ad0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "sub{s}.w <Rd>, sp, #<const>"},
+ { 0xfbff8000, 0xf2ad0000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "subw<c> <Rd>, sp, #imm12"},
+ // sub (register)
+ { 0xfffffe00, 0x00001a00, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSUBReg, "subs|sub<c> <Rd>, <Rn>, <Rm>"},
+ { 0xffe08000, 0xeba00000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBReg, "sub{s}<c>.w <Rd>, <Rn>, <Rm>{,<shift>}"},
+ // teq (immediate)
+ { 0xfbf08f00, 0xf0900f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTEQImm, "teq<c> <Rn>, #<const>"},
+ // teq (register)
+ { 0xfff08f00, 0xea900f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTEQReg, "teq<c> <Rn>, <Rm> {,<shift>}"},
+ // tst (immediate)
+ { 0xfbf08f00, 0xf0100f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateTSTImm, "tst<c> <Rn>, #<const>"},
+ // tst (register)
+ { 0xffffffc0, 0x00004200, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateTSTReg, "tst<c> <Rdn>, <Rm>"},
+ { 0xfff08f00, 0xea100f00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateTSTReg, "tst<c>.w <Rn>, <Rm> {,<shift>}"},
+
+
+ // move from high register to high register
+ { 0xffffff00, 0x00004600, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMOVRdRm, "mov<c> <Rd>, <Rm>"},
+ // move from low register to low register
+ { 0xffffffc0, 0x00000000, ARMvAll, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateMOVRdRm, "movs <Rd>, <Rm>"},
+ // mov{s}<c>.w <Rd>, <Rm>
+ { 0xffeff0f0, 0xea4f0000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdRm, "mov{s}<c>.w <Rd>, <Rm>"},
+ // move immediate
+ { 0xfffff800, 0x00002000, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMOVRdImm, "movs|mov<c> <Rd>, #imm8"},
+ { 0xfbef8000, 0xf04f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdImm, "mov{s}<c>.w <Rd>, #<const>"},
+ { 0xfbf08000, 0xf2400000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateMOVRdImm, "movw<c> <Rd>,#<imm16>"},
+ // mvn (immediate)
+ { 0xfbef8000, 0xf06f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateMVNImm, "mvn{s} <Rd>, #<const>"},
+ // mvn (register)
+ { 0xffffffc0, 0x000043c0, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMVNReg, "mvns|mvn<c> <Rd>, <Rm>"},
+ { 0xffef8000, 0xea6f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateMVNReg, "mvn{s}<c>.w <Rd>, <Rm> {,<shift>}"},
+ // cmn (immediate)
+ { 0xfbf08f00, 0xf1100f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMNImm, "cmn<c> <Rn>, #<const>"},
+ // cmn (register)
+ { 0xffffffc0, 0x000042c0, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMNReg, "cmn<c> <Rn>, <Rm>"},
+ { 0xfff08f00, 0xeb100f00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMNReg, "cmn<c> <Rn>, <Rm> {,<shift>}"},
+ // cmp (immediate)
+ { 0xfffff800, 0x00002800, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPImm, "cmp<c> <Rn>, #imm8"},
+ { 0xfbf08f00, 0xf1b00f00, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateCMPImm, "cmp<c>.w <Rn>, #<const>"},
+ // cmp (register) (Rn and Rm both from r0-r7)
+ { 0xffffffc0, 0x00004280, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm>"},
+ // cmp (register) (Rn and Rm not both from r0-r7)
+ { 0xffffff00, 0x00004500, ARMvAll, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPReg, "cmp<c> <Rn>, <Rm>"},
+ // asr (immediate)
+ { 0xfffff800, 0x00001000, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateASRImm, "asrs|asr<c> <Rd>, <Rm>, #imm"},
+ { 0xffef8030, 0xea4f0020, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateASRImm, "asr{s}<c>.w <Rd>, <Rm>, #imm"},
+ // asr (register)
+ { 0xffffffc0, 0x00004100, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateASRReg, "asrs|asr<c> <Rdn>, <Rm>"},
+ { 0xffe0f0f0, 0xfa40f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateASRReg, "asr{s}<c>.w <Rd>, <Rn>, <Rm>"},
+ // lsl (immediate)
+ { 0xfffff800, 0x00000000, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLSLImm, "lsls|lsl<c> <Rd>, <Rm>, #imm"},
+ { 0xffef8030, 0xea4f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSLImm, "lsl{s}<c>.w <Rd>, <Rm>, #imm"},
+ // lsl (register)
+ { 0xffffffc0, 0x00004080, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLSLReg, "lsls|lsl<c> <Rdn>, <Rm>"},
+ { 0xffe0f0f0, 0xfa00f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSLReg, "lsl{s}<c>.w <Rd>, <Rn>, <Rm>"},
+ // lsr (immediate)
+ { 0xfffff800, 0x00000800, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLSRImm, "lsrs|lsr<c> <Rd>, <Rm>, #imm"},
+ { 0xffef8030, 0xea4f0010, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSRImm, "lsr{s}<c>.w <Rd>, <Rm>, #imm"},
+ // lsr (register)
+ { 0xffffffc0, 0x000040c0, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLSRReg, "lsrs|lsr<c> <Rdn>, <Rm>"},
+ { 0xffe0f0f0, 0xfa20f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLSRReg, "lsr{s}<c>.w <Rd>, <Rn>, <Rm>"},
+ // rrx is a special case encoding of ror (immediate)
+ { 0xffeff0f0, 0xea4f0030, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRRX, "rrx{s}<c>.w <Rd>, <Rm>"},
+ // ror (immediate)
+ { 0xffef8030, 0xea4f0030, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRORImm, "ror{s}<c>.w <Rd>, <Rm>, #imm"},
+ // ror (register)
+ { 0xffffffc0, 0x000041c0, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateRORReg, "rors|ror<c> <Rdn>, <Rm>"},
+ { 0xffe0f0f0, 0xfa60f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateRORReg, "ror{s}<c>.w <Rd>, <Rn>, <Rm>"},
+ // mul
+ { 0xffffffc0, 0x00004340, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateMUL, "muls <Rdm>,<Rn>,<Rdm>" },
+ // mul
+ { 0xfff0f0f0, 0xfb00f000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateMUL, "mul<c> <Rd>,<Rn>,<Rm>" },
+
+ // subs pc, lr and related instructions
+ { 0xffffff00, 0xf3de8f00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSUBSPcLrEtc, "SUBS<c> PC, LR, #<imm8>" },
+
+ //----------------------------------------------------------------------
+ // RFE instructions *** IMPORTANT *** THESE MUST BE LISTED **BEFORE** THE LDM.. Instructions in this table;
+ // otherwise the wrong instructions will be selected.
+ //----------------------------------------------------------------------
+
+ { 0xffd0ffff, 0xe810c000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateRFE, "rfedb<c> <Rn>{!}" },
+ { 0xffd0ffff, 0xe990c000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateRFE, "rfe{ia}<c> <Rn>{!}" },
+
+ //----------------------------------------------------------------------
+ // Load instructions
+ //----------------------------------------------------------------------
+ { 0xfffff800, 0x0000c800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDM, "ldm<c> <Rn>{!} <registers>" },
+ { 0xffd02000, 0xe8900000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDM, "ldm<c>.w <Rn>{!} <registers>" },
+ { 0xffd00000, 0xe9100000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDMDB, "ldmdb<c> <Rn>{!} <registers>" },
+ { 0xfffff800, 0x00006800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c> <Rt>, [<Rn>{,#imm}]"},
+ { 0xfffff800, 0x00009800, ARMV4T_ABOVE, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c> <Rt>, [SP{,#imm}]"},
+ { 0xfff00000, 0xf8d00000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c>.w <Rt>, [<Rn>{,#imm12}]"},
+ { 0xfff00800, 0xf8500800, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr<c> <Rt>, [<Rn>{,#+/-<imm8>}]{!}"},
+ // Thumb2 PC-relative load into register
+ { 0xff7f0000, 0xf85f0000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRRtPCRelative, "ldr<c>.w <Rt>, [PC, +/-#imm}]"},
+ { 0xfffffe00, 0x00005800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRRegister, "ldr<c> <Rt>, [<Rn>, <Rm>]" },
+ { 0xfff00fc0, 0xf8500000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRRegister, "ldr<c>.w <Rt>, [<Rn>,<Rm>{,LSL #<imm2>}]" },
+ { 0xfffff800, 0x00007800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRBImmediate, "ldrb<c> <Rt>,[<Rn>{,#<imm5>}]" },
+ { 0xfff00000, 0xf8900000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBImmediate, "ldrb<c>.w <Rt>,[<Rn>{,#<imm12>}]" },
+ { 0xfff00800, 0xf8100800, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBImmediate, "ldrb<c> <Rt>,[<Rn>, #+/-<imm8>]{!}" },
+ { 0xff7f0000, 0xf81f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBLiteral, "ldrb<c> <Rt>,[...]" },
+ { 0xfffffe00, 0x00005c00, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRBRegister, "ldrb<c> <Rt>,[<Rn>,<Rm>]" },
+ { 0xfff00fc0, 0xf8100000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRBRegister, "ldrb<c>.w <Rt>,[<Rn>,<Rm>{,LSL #imm2>}]" },
+ { 0xfffff800, 0x00008800, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRHImmediate, "ldrh<c> <Rt>, [<Rn>{,#<imm>}]" },
+ { 0xfff00000, 0xf8b00000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHImmediate, "ldrh<c>.w <Rt>,[<Rn>{,#<imm12>}]" },
+ { 0xfff00800, 0xf8300800, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHImmediate, "ldrh<c> <Rt>,[<Rn>,#+/-<imm8>]{!}" },
+ { 0xff7f0000, 0xf83f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHLiteral, "ldrh<c> <Rt>, <label>" },
+ { 0xfffffe00, 0x00005a00, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRHRegister, "ldrh<c> <Rt>, [<Rn>,<Rm>]" },
+ { 0xfff00fc0, 0xf8300000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRHRegister, "ldrh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]" },
+ { 0xfff00000, 0xf9900000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBImmediate, "ldrsb<c> <Rt>,[<Rn>,#<imm12>]" },
+ { 0xfff00800, 0xf9100800, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBImmediate, "ldrsb<c> <Rt>,[<Rn>,#+/-<imm8>]" },
+ { 0xff7f0000, 0xf91f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBLiteral, "ldrsb<c> <Rt>, <label>" },
+ { 0xfffffe00, 0x00005600, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRSBRegister, "ldrsb<c> <Rt>,[<Rn>,<Rm>]" },
+ { 0xfff00fc0, 0xf9100000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSBRegister, "ldrsb<c>.w <Rt>,[<Rn>,<Rm>{,LSL #imm2>}]" },
+ { 0xfff00000, 0xf9b00000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHImmediate, "ldrsh<c> <Rt>,[<Rn>,#<imm12>]" },
+ { 0xfff00800, 0xf9300800, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHImmediate, "ldrsh<c> <Rt>,[<Rn>,#+/-<imm8>]" },
+ { 0xff7f0000, 0xf93f0000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHLiteral, "ldrsh<c> <Rt>,<label>" },
+ { 0xfffffe00, 0x00005e00, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateLDRSHRegister, "ldrsh<c> <Rt>,[<Rn>,<Rm>]" },
+ { 0xfff00fc0, 0xf9300000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRSHRegister, "ldrsh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]" },
+ { 0xfe500000, 0xe8500000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateLDRDImmediate, "ldrd<c> <Rt>, <Rt2>, [<Rn>,#+/-<imm>]!"},
+ { 0xfe100f00, 0xec100b00, ARMvAll, eEncodingT1, VFPv2_ABOVE, eSize32, &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>"},
+ { 0xfe100f00, 0xec100a00, ARMvAll, eEncodingT2, VFPv2v3, eSize32, &EmulateInstructionARM::EmulateVLDM, "vldm{mode}<c> <Rn>{!}, <list>" },
+ { 0xffe00f00, 0xed100b00, ARMvAll, eEncodingT1, VFPv2_ABOVE, eSize32, &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Dd>, [<Rn>{,#+/-<imm>}]"},
+ { 0xff300f00, 0xed100a00, ARMvAll, eEncodingT2, VFPv2v3, eSize32, &EmulateInstructionARM::EmulateVLDR, "vldr<c> <Sd>, {<Rn>{,#+/-<imm>}]"},
+ { 0xffb00000, 0xf9200000, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1Multiple, "vld1<c>.<size> <list>, [<Rn>{@<align>}],<Rm>"},
+ { 0xffb00300, 0xf9a00000, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1Single, "vld1<c>.<size> <list>, [<Rn>{@<align>}],<Rm>"},
+ { 0xffb00f00, 0xf9a00c00, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVLD1SingleAll, "vld1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
+
+ //----------------------------------------------------------------------
+ // Store instructions
+ //----------------------------------------------------------------------
+ { 0xfffff800, 0x0000c000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTM, "stm<c> <Rn>{!} <registers>" },
+ { 0xffd00000, 0xe8800000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTM, "stm<c>.w <Rn>{!} <registers>" },
+ { 0xffd00000, 0xe9000000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTMDB, "stmdb<c> <Rn>{!} <registers>" },
+ { 0xfffff800, 0x00006000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTRThumb, "str<c> <Rt>, [<Rn>{,#<imm>}]" },
+ { 0xfffff800, 0x00009000, ARMV4T_ABOVE, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTRThumb, "str<c> <Rt>, [SP,#<imm>]" },
+ { 0xfff00000, 0xf8c00000, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRThumb, "str<c>.w <Rt>, [<Rn>,#<imm12>]" },
+ { 0xfff00800, 0xf8400800, ARMV6T2_ABOVE, eEncodingT4, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRThumb, "str<c> <Rt>, [<Rn>,#+/-<imm8>]" },
+ { 0xfffffe00, 0x00005000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTRRegister, "str<c> <Rt> ,{<Rn>, <Rm>]" },
+ { 0xfff00fc0, 0xf8400000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRRegister, "str<c>.w <Rt>, [<Rn>, <Rm> {lsl #imm2>}]" },
+ { 0xfffff800, 0x00007000, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTRBThumb, "strb<c> <Rt>, [<Rn>, #<imm5>]" },
+ { 0xfff00000, 0xf8800000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRBThumb, "strb<c>.w <Rt>, [<Rn>, #<imm12>]" },
+ { 0xfff00800, 0xf8000800, ARMV6T2_ABOVE, eEncodingT3, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRBThumb, "strb<c> <Rt> ,[<Rn>, #+/-<imm8>]{!}" },
+ { 0xfffffe00, 0x00005200, ARMV4T_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSTRHRegister, "strh<c> <Rt>,[<Rn>,<Rm>]" },
+ { 0xfff00fc0, 0xf8200000, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRHRegister, "strh<c>.w <Rt>,[<Rn>,<Rm>{,LSL #<imm2>}]" },
+ { 0xfff00000, 0xe8400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTREX, "strex<c> <Rd>, <Rt>, [<Rn{,#<imm>}]" },
+ { 0xfe500000, 0xe8400000, ARMV6T2_ABOVE, eEncodingT1, No_VFP, eSize32, &EmulateInstructionARM::EmulateSTRDImm, "strd<c> <Rt>, <Rt2>, [<Rn>, #+/-<imm>]!"},
+ { 0xfe100f00, 0xec000b00, ARMvAll, eEncodingT1, VFPv2_ABOVE, eSize32, &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!}, <list>"},
+ { 0xfea00f00, 0xec000a00, ARMvAll, eEncodingT2, VFPv2v3, eSize32, &EmulateInstructionARM::EmulateVSTM, "vstm{mode}<c> <Rn>{!}, <list>"},
+ { 0xff300f00, 0xed000b00, ARMvAll, eEncodingT1, VFPv2_ABOVE, eSize32, &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Dd>, [<Rn>{,#+/-<imm>}]"},
+ { 0xff300f00, 0xed000a00, ARMvAll, eEncodingT2, VFPv2v3, eSize32, &EmulateInstructionARM::EmulateVSTR, "vstr<c> <Sd>, [<Rn>{,#+/-<imm>}]"},
+ { 0xffb00000, 0xf9000000, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVST1Multiple, "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
+ { 0xffb00300, 0xf9800000, ARMvAll, eEncodingT1, AdvancedSIMD, eSize32, &EmulateInstructionARM::EmulateVST1Single, "vst1<c>.<size> <list>, [<Rn>{@<align>}], <Rm>"},
+
+ //----------------------------------------------------------------------
+ // Other instructions
+ //----------------------------------------------------------------------
+ { 0xffffffc0, 0x0000b240, ARMV6_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSXTB, "sxtb<c> <Rd>,<Rm>" },
+ { 0xfffff080, 0xfa4ff080, ARMV6_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSXTB, "sxtb<c>.w <Rd>,<Rm>{,<rotation>}" },
+ { 0xffffffc0, 0x0000b200, ARMV6_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateSXTH, "sxth<c> <Rd>,<Rm>" },
+ { 0xfffff080, 0xfa0ff080, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateSXTH, "sxth<c>.w <Rd>,<Rm>{,<rotation>}" },
+ { 0xffffffc0, 0x0000b2c0, ARMV6_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateUXTB, "uxtb<c> <Rd>,<Rm>" },
+ { 0xfffff080, 0xfa5ff080, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateUXTB, "uxtb<c>.w <Rd>,<Rm>{,<rotation>}" },
+ { 0xffffffc0, 0x0000b280, ARMV6_ABOVE, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateUXTH, "uxth<c> <Rd>,<Rm>" },
+ { 0xfffff080, 0xfa1ff080, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateUXTH, "uxth<c>.w <Rd>,<Rm>{,<rotation>}" },
+ };
+
+ const size_t k_num_thumb_opcodes = sizeof(g_thumb_opcodes)/sizeof(ARMOpcode);
+ for (size_t i=0; i<k_num_thumb_opcodes; ++i)
+ {
+ if ((g_thumb_opcodes[i].mask & opcode) == g_thumb_opcodes[i].value &&
+ (g_thumb_opcodes[i].variants & arm_isa) != 0)
+ return &g_thumb_opcodes[i];
+ }
+ return NULL;
+}
+
+bool
+EmulateInstructionARM::SetArchitecture (const ArchSpec &arch)
+{
+ m_arch = arch;
+ m_arm_isa = 0;
+ const char *arch_cstr = arch.GetArchitectureName ();
+ if (arch_cstr)
+ {
+ if (0 == ::strcasecmp(arch_cstr, "armv4t")) m_arm_isa = ARMv4T;
+ else if (0 == ::strcasecmp(arch_cstr, "armv5tej")) m_arm_isa = ARMv5TEJ;
+ else if (0 == ::strcasecmp(arch_cstr, "armv5te")) m_arm_isa = ARMv5TE;
+ else if (0 == ::strcasecmp(arch_cstr, "armv5t")) m_arm_isa = ARMv5T;
+ else if (0 == ::strcasecmp(arch_cstr, "armv6k")) m_arm_isa = ARMv6K;
+ else if (0 == ::strcasecmp(arch_cstr, "armv6t2")) m_arm_isa = ARMv6T2;
+ else if (0 == ::strcasecmp(arch_cstr, "armv7s")) m_arm_isa = ARMv7S;
+ else if (0 == ::strcasecmp(arch_cstr, "arm")) m_arm_isa = ARMvAll;
+ else if (0 == ::strcasecmp(arch_cstr, "thumb")) m_arm_isa = ARMvAll;
+ else if (0 == ::strncasecmp(arch_cstr,"armv4", 5)) m_arm_isa = ARMv4;
+ else if (0 == ::strncasecmp(arch_cstr,"armv6", 5)) m_arm_isa = ARMv6;
+ else if (0 == ::strncasecmp(arch_cstr,"armv7", 5)) m_arm_isa = ARMv7;
+ else if (0 == ::strncasecmp(arch_cstr,"armv8", 5)) m_arm_isa = ARMv8;
+ }
+ return m_arm_isa != 0;
+}
+
+bool
+EmulateInstructionARM::SetInstruction (const Opcode &insn_opcode, const Address &inst_addr, Target *target)
+{
+ if (EmulateInstruction::SetInstruction (insn_opcode, inst_addr, target))
+ {
+ if (m_arch.GetTriple().getArch() == llvm::Triple::thumb)
+ m_opcode_mode = eModeThumb;
+ else
+ {
+ AddressClass addr_class = inst_addr.GetAddressClass();
+
+ if ((addr_class == eAddressClassCode) || (addr_class == eAddressClassUnknown))
+ m_opcode_mode = eModeARM;
+ else if (addr_class == eAddressClassCodeAlternateISA)
+ m_opcode_mode = eModeThumb;
+ else
+ return false;
+ }
+ if (m_opcode_mode == eModeThumb)
+ m_opcode_cpsr = CPSR_MODE_USR | MASK_CPSR_T;
+ else
+ m_opcode_cpsr = CPSR_MODE_USR;
+ return true;
+ }
+ return false;
+}
+
+bool
+EmulateInstructionARM::ReadInstruction ()
+{
+ bool success = false;
+ m_opcode_cpsr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, 0, &success);
+ if (success)
+ {
+ addr_t pc = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success);
+ if (success)
+ {
+ Context read_inst_context;
+ read_inst_context.type = eContextReadOpcode;
+ read_inst_context.SetNoArgs ();
+
+ if (m_opcode_cpsr & MASK_CPSR_T)
+ {
+ m_opcode_mode = eModeThumb;
+ uint32_t thumb_opcode = MemARead(read_inst_context, pc, 2, 0, &success);
+
+ if (success)
+ {
+ if ((thumb_opcode & 0xe000) != 0xe000 || ((thumb_opcode & 0x1800u) == 0))
+ {
+ m_opcode.SetOpcode16 (thumb_opcode);
+ }
+ else
+ {
+ m_opcode.SetOpcode32 ((thumb_opcode << 16) | MemARead(read_inst_context, pc + 2, 2, 0, &success));
+ }
+ }
+ }
+ else
+ {
+ m_opcode_mode = eModeARM;
+ m_opcode.SetOpcode32 (MemARead(read_inst_context, pc, 4, 0, &success));
+ }
+ }
+ }
+ if (!success)
+ {
+ m_opcode_mode = eModeInvalid;
+ m_addr = LLDB_INVALID_ADDRESS;
+ }
+ return success;
+}
+
+uint32_t
+EmulateInstructionARM::ArchVersion ()
+{
+ return m_arm_isa;
+}
+
+bool
+EmulateInstructionARM::ConditionPassed (const uint32_t opcode, bool *is_conditional)
+{
+ // If we are ignoring conditions, then always return true.
+ // this allows us to iterate over disassembly code and still
+ // emulate an instruction even if we don't have all the right
+ // bits set in the CPSR register...
+ if (m_ignore_conditions)
+ return true;
+
+ if (is_conditional)
+ *is_conditional = true;
+
+ const uint32_t cond = CurrentCond (opcode);
+
+ if (cond == UINT32_MAX)
+ return false;
+
+ bool result = false;
+ switch (UnsignedBits(cond, 3, 1))
+ {
+ case 0:
+ if (m_opcode_cpsr == 0)
+ result = true;
+ else
+ result = (m_opcode_cpsr & MASK_CPSR_Z) != 0;
+ break;
+ case 1:
+ if (m_opcode_cpsr == 0)
+ result = true;
+ else
+ result = (m_opcode_cpsr & MASK_CPSR_C) != 0;
+ break;
+ case 2:
+ if (m_opcode_cpsr == 0)
+ result = true;
+ else
+ result = (m_opcode_cpsr & MASK_CPSR_N) != 0;
+ break;
+ case 3:
+ if (m_opcode_cpsr == 0)
+ result = true;
+ else
+ result = (m_opcode_cpsr & MASK_CPSR_V) != 0;
+ break;
+ case 4:
+ if (m_opcode_cpsr == 0)
+ result = true;
+ else
+ result = ((m_opcode_cpsr & MASK_CPSR_C) != 0) && ((m_opcode_cpsr & MASK_CPSR_Z) == 0);
+ break;
+ case 5:
+ if (m_opcode_cpsr == 0)
+ result = true;
+ else
+ {
+ bool n = (m_opcode_cpsr & MASK_CPSR_N);
+ bool v = (m_opcode_cpsr & MASK_CPSR_V);
+ result = n == v;
+ }
+ break;
+ case 6:
+ if (m_opcode_cpsr == 0)
+ result = true;
+ else
+ {
+ bool n = (m_opcode_cpsr & MASK_CPSR_N);
+ bool v = (m_opcode_cpsr & MASK_CPSR_V);
+ result = n == v && ((m_opcode_cpsr & MASK_CPSR_Z) == 0);
+ }
+ break;
+ case 7:
+ // Always execute (cond == 0b1110, or the special 0b1111 which gives
+ // opcodes different meanings, but always means execution happpens.
+ if (is_conditional)
+ *is_conditional = false;
+ result = true;
+ break;
+ }
+
+ if (cond & 1)
+ result = !result;
+ return result;
+}
+
+uint32_t
+EmulateInstructionARM::CurrentCond (const uint32_t opcode)
+{
+ switch (m_opcode_mode)
+ {
+ case eModeInvalid:
+ break;
+
+ case eModeARM:
+ return UnsignedBits(opcode, 31, 28);
+
+ case eModeThumb:
+ // For T1 and T3 encodings of the Branch instruction, it returns the 4-bit
+ // 'cond' field of the encoding.
+ {
+ const uint32_t byte_size = m_opcode.GetByteSize();
+ if (byte_size == 2)
+ {
+ if (Bits32(opcode, 15, 12) == 0x0d && Bits32(opcode, 11, 7) != 0x0f)
+ return Bits32(opcode, 11, 7);
+ }
+ else if (byte_size == 4)
+ {
+ if (Bits32(opcode, 31, 27) == 0x1e &&
+ Bits32(opcode, 15, 14) == 0x02 &&
+ Bits32(opcode, 12, 12) == 0x00 &&
+ Bits32(opcode, 25, 22) <= 0x0d)
+ {
+ return Bits32(opcode, 25, 22);
+ }
+ }
+ else
+ // We have an invalid thumb instruction, let's bail out.
+ break;
+
+ return m_it_session.GetCond();
+ }
+ }
+ return UINT32_MAX; // Return invalid value
+}
+
+bool
+EmulateInstructionARM::InITBlock()
+{
+ return CurrentInstrSet() == eModeThumb && m_it_session.InITBlock();
+}
+
+bool
+EmulateInstructionARM::LastInITBlock()
+{
+ return CurrentInstrSet() == eModeThumb && m_it_session.LastInITBlock();
+}
+
+bool
+EmulateInstructionARM::BadMode (uint32_t mode)
+{
+
+ switch (mode)
+ {
+ case 16: return false; // '10000'
+ case 17: return false; // '10001'
+ case 18: return false; // '10010'
+ case 19: return false; // '10011'
+ case 22: return false; // '10110'
+ case 23: return false; // '10111'
+ case 27: return false; // '11011'
+ case 31: return false; // '11111'
+ default: return true;
+ }
+ return true;
+}
+
+bool
+EmulateInstructionARM::CurrentModeIsPrivileged ()
+{
+ uint32_t mode = Bits32 (m_opcode_cpsr, 4, 0);
+
+ if (BadMode (mode))
+ return false;
+
+ if (mode == 16)
+ return false;
+
+ return true;
+}
+
+void
+EmulateInstructionARM::CPSRWriteByInstr (uint32_t value, uint32_t bytemask, bool affect_execstate)
+{
+ bool privileged = CurrentModeIsPrivileged();
+
+ uint32_t tmp_cpsr = Bits32 (m_opcode_cpsr, 23, 20) << 20;
+
+ if (BitIsSet (bytemask, 3))
+ {
+ tmp_cpsr = tmp_cpsr | (Bits32 (value, 31, 27) << 27);
+ if (affect_execstate)
+ tmp_cpsr = tmp_cpsr | (Bits32 (value, 26, 24) << 24);
+ }
+
+ if (BitIsSet (bytemask, 2))
+ {
+ tmp_cpsr = tmp_cpsr | (Bits32 (value, 19, 16) << 16);
+ }
+
+ if (BitIsSet (bytemask, 1))
+ {
+ if (affect_execstate)
+ tmp_cpsr = tmp_cpsr | (Bits32 (value, 15, 10) << 10);
+ tmp_cpsr = tmp_cpsr | (Bit32 (value, 9) << 9);
+ if (privileged)
+ tmp_cpsr = tmp_cpsr | (Bit32 (value, 8) << 8);
+ }
+
+ if (BitIsSet (bytemask, 0))
+ {
+ if (privileged)
+ tmp_cpsr = tmp_cpsr | (Bits32 (value, 7, 6) << 6);
+ if (affect_execstate)
+ tmp_cpsr = tmp_cpsr | (Bit32 (value, 5) << 5);
+ if (privileged)
+ tmp_cpsr = tmp_cpsr | Bits32 (value, 4, 0);
+ }
+
+ m_opcode_cpsr = tmp_cpsr;
+}
+
+
+bool
+EmulateInstructionARM::BranchWritePC (const Context &context, uint32_t addr)
+{
+ addr_t target;
+
+ // Check the current instruction set.
+ if (CurrentInstrSet() == eModeARM)
+ target = addr & 0xfffffffc;
+ else
+ target = addr & 0xfffffffe;
+
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target))
+ return false;
+
+ return true;
+}
+
+// As a side effect, BXWritePC sets context.arg2 to eModeARM or eModeThumb by inspecting addr.
+bool
+EmulateInstructionARM::BXWritePC (Context &context, uint32_t addr)
+{
+ addr_t target;
+ // If the CPSR is changed due to switching between ARM and Thumb ISETSTATE,
+ // we want to record it and issue a WriteRegister callback so the clients
+ // can track the mode changes accordingly.
+ bool cpsr_changed = false;
+
+ if (BitIsSet(addr, 0))
+ {
+ if (CurrentInstrSet() != eModeThumb)
+ {
+ SelectInstrSet(eModeThumb);
+ cpsr_changed = true;
+ }
+ target = addr & 0xfffffffe;
+ context.SetISA (eModeThumb);
+ }
+ else if (BitIsClear(addr, 1))
+ {
+ if (CurrentInstrSet() != eModeARM)
+ {
+ SelectInstrSet(eModeARM);
+ cpsr_changed = true;
+ }
+ target = addr & 0xfffffffc;
+ context.SetISA (eModeARM);
+ }
+ else
+ return false; // address<1:0> == '10' => UNPREDICTABLE
+
+ if (cpsr_changed)
+ {
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
+ return false;
+ }
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, target))
+ return false;
+
+ return true;
+}
+
+// Dispatches to either BXWritePC or BranchWritePC based on architecture versions.
+bool
+EmulateInstructionARM::LoadWritePC (Context &context, uint32_t addr)
+{
+ if (ArchVersion() >= ARMv5T)
+ return BXWritePC(context, addr);
+ else
+ return BranchWritePC((const Context)context, addr);
+}
+
+// Dispatches to either BXWritePC or BranchWritePC based on architecture versions and current instruction set.
+bool
+EmulateInstructionARM::ALUWritePC (Context &context, uint32_t addr)
+{
+ if (ArchVersion() >= ARMv7 && CurrentInstrSet() == eModeARM)
+ return BXWritePC(context, addr);
+ else
+ return BranchWritePC((const Context)context, addr);
+}
+
+EmulateInstructionARM::Mode
+EmulateInstructionARM::CurrentInstrSet ()
+{
+ return m_opcode_mode;
+}
+
+// Set the 'T' bit of our CPSR. The m_opcode_mode gets updated when the next
+// ReadInstruction() is performed. This function has a side effect of updating
+// the m_new_inst_cpsr member variable if necessary.
+bool
+EmulateInstructionARM::SelectInstrSet (Mode arm_or_thumb)
+{
+ m_new_inst_cpsr = m_opcode_cpsr;
+ switch (arm_or_thumb)
+ {
+ default:
+ return false;
+ case eModeARM:
+ // Clear the T bit.
+ m_new_inst_cpsr &= ~MASK_CPSR_T;
+ break;
+ case eModeThumb:
+ // Set the T bit.
+ m_new_inst_cpsr |= MASK_CPSR_T;
+ break;
+ }
+ return true;
+}
+
+// This function returns TRUE if the processor currently provides support for
+// unaligned memory accesses, or FALSE otherwise. This is always TRUE in ARMv7,
+// controllable by the SCTLR.U bit in ARMv6, and always FALSE before ARMv6.
+bool
+EmulateInstructionARM::UnalignedSupport()
+{
+ return (ArchVersion() >= ARMv7);
+}
+
+// The main addition and subtraction instructions can produce status information
+// about both unsigned carry and signed overflow conditions. This status
+// information can be used to synthesize multi-word additions and subtractions.
+EmulateInstructionARM::AddWithCarryResult
+EmulateInstructionARM::AddWithCarry (uint32_t x, uint32_t y, uint8_t carry_in)
+{
+ uint32_t result;
+ uint8_t carry_out;
+ uint8_t overflow;
+
+ uint64_t unsigned_sum = x + y + carry_in;
+ int64_t signed_sum = (int32_t)x + (int32_t)y + (int32_t)carry_in;
+
+ result = UnsignedBits(unsigned_sum, 31, 0);
+// carry_out = (result == unsigned_sum ? 0 : 1);
+ overflow = ((int32_t)result == signed_sum ? 0 : 1);
+
+ if (carry_in)
+ carry_out = ((int32_t) x >= (int32_t) (~y)) ? 1 : 0;
+ else
+ carry_out = ((int32_t) x > (int32_t) y) ? 1 : 0;
+
+ AddWithCarryResult res = { result, carry_out, overflow };
+ return res;
+}
+
+uint32_t
+EmulateInstructionARM::ReadCoreReg(uint32_t num, bool *success)
+{
+ uint32_t reg_kind, reg_num;
+ switch (num)
+ {
+ case SP_REG:
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_SP;
+ break;
+ case LR_REG:
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_RA;
+ break;
+ case PC_REG:
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_PC;
+ break;
+ default:
+ if (num < SP_REG)
+ {
+ reg_kind = eRegisterKindDWARF;
+ reg_num = dwarf_r0 + num;
+ }
+ else
+ {
+ //assert(0 && "Invalid register number");
+ *success = false;
+ return UINT32_MAX;
+ }
+ break;
+ }
+
+ // Read our register.
+ uint32_t val = ReadRegisterUnsigned (reg_kind, reg_num, 0, success);
+
+ // When executing an ARM instruction , PC reads as the address of the current
+ // instruction plus 8.
+ // When executing a Thumb instruction , PC reads as the address of the current
+ // instruction plus 4.
+ if (num == 15)
+ {
+ if (CurrentInstrSet() == eModeARM)
+ val += 8;
+ else
+ val += 4;
+ }
+
+ return val;
+}
+
+// Write the result to the ARM core register Rd, and optionally update the
+// condition flags based on the result.
+//
+// This helper method tries to encapsulate the following pseudocode from the
+// ARM Architecture Reference Manual:
+//
+// if d == 15 then // Can only occur for encoding A1
+// ALUWritePC(result); // setflags is always FALSE here
+// else
+// R[d] = result;
+// if setflags then
+// APSR.N = result<31>;
+// APSR.Z = IsZeroBit(result);
+// APSR.C = carry;
+// // APSR.V unchanged
+//
+// In the above case, the API client does not pass in the overflow arg, which
+// defaults to ~0u.
+bool
+EmulateInstructionARM::WriteCoreRegOptionalFlags (Context &context,
+ const uint32_t result,
+ const uint32_t Rd,
+ bool setflags,
+ const uint32_t carry,
+ const uint32_t overflow)
+{
+ if (Rd == 15)
+ {
+ if (!ALUWritePC (context, result))
+ return false;
+ }
+ else
+ {
+ uint32_t reg_kind, reg_num;
+ switch (Rd)
+ {
+ case SP_REG:
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_SP;
+ break;
+ case LR_REG:
+ reg_kind = eRegisterKindGeneric;
+ reg_num = LLDB_REGNUM_GENERIC_RA;
+ break;
+ default:
+ reg_kind = eRegisterKindDWARF;
+ reg_num = dwarf_r0 + Rd;
+ }
+ if (!WriteRegisterUnsigned (context, reg_kind, reg_num, result))
+ return false;
+ if (setflags)
+ return WriteFlags (context, result, carry, overflow);
+ }
+ return true;
+}
+
+// This helper method tries to encapsulate the following pseudocode from the
+// ARM Architecture Reference Manual:
+//
+// APSR.N = result<31>;
+// APSR.Z = IsZeroBit(result);
+// APSR.C = carry;
+// APSR.V = overflow
+//
+// Default arguments can be specified for carry and overflow parameters, which means
+// not to update the respective flags.
+bool
+EmulateInstructionARM::WriteFlags (Context &context,
+ const uint32_t result,
+ const uint32_t carry,
+ const uint32_t overflow)
+{
+ m_new_inst_cpsr = m_opcode_cpsr;
+ SetBit32(m_new_inst_cpsr, CPSR_N_POS, Bit32(result, CPSR_N_POS));
+ SetBit32(m_new_inst_cpsr, CPSR_Z_POS, result == 0 ? 1 : 0);
+ if (carry != ~0u)
+ SetBit32(m_new_inst_cpsr, CPSR_C_POS, carry);
+ if (overflow != ~0u)
+ SetBit32(m_new_inst_cpsr, CPSR_V_POS, overflow);
+ if (m_new_inst_cpsr != m_opcode_cpsr)
+ {
+ if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS, m_new_inst_cpsr))
+ return false;
+ }
+ return true;
+}
+
+bool
+EmulateInstructionARM::EvaluateInstruction (uint32_t evaluate_options)
+{
+ // Advance the ITSTATE bits to their values for the next instruction.
+ if (m_opcode_mode == eModeThumb && m_it_session.InITBlock())
+ m_it_session.ITAdvance();
+
+ ARMOpcode *opcode_data = NULL;
+
+ if (m_opcode_mode == eModeThumb)
+ opcode_data = GetThumbOpcodeForInstruction (m_opcode.GetOpcode32(), m_arm_isa);
+ else if (m_opcode_mode == eModeARM)
+ opcode_data = GetARMOpcodeForInstruction (m_opcode.GetOpcode32(), m_arm_isa);
+
+ if (opcode_data == NULL)
+ return false;
+
+ const bool auto_advance_pc = evaluate_options & eEmulateInstructionOptionAutoAdvancePC;
+ m_ignore_conditions = evaluate_options & eEmulateInstructionOptionIgnoreConditions;
+
+ bool success = false;
+ if (m_opcode_cpsr == 0 || m_ignore_conditions == false)
+ {
+ m_opcode_cpsr = ReadRegisterUnsigned (eRegisterKindDWARF,
+ dwarf_cpsr,
+ 0,
+ &success);
+ }
+
+ // Only return false if we are unable to read the CPSR if we care about conditions
+ if (success == false && m_ignore_conditions == false)
+ return false;
+
+ uint32_t orig_pc_value = 0;
+ if (auto_advance_pc)
+ {
+ orig_pc_value = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc, 0, &success);
+ if (!success)
+ return false;
+ }
+
+ // Call the Emulate... function.
+ success = (this->*opcode_data->callback) (m_opcode.GetOpcode32(), opcode_data->encoding);
+ if (!success)
+ return false;
+
+ if (auto_advance_pc)
+ {
+ uint32_t after_pc_value = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc, 0, &success);
+ if (!success)
+ return false;
+
+ if (auto_advance_pc && (after_pc_value == orig_pc_value))
+ {
+ if (opcode_data->size == eSize32)
+ after_pc_value += 4;
+ else if (opcode_data->size == eSize16)
+ after_pc_value += 2;
+
+ EmulateInstruction::Context context;
+ context.type = eContextAdvancePC;
+ context.SetNoArgs();
+ if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc, after_pc_value))
+ return false;
+
+ }
+ }
+ return true;
+}
+
+bool
+EmulateInstructionARM::TestEmulation (Stream *out_stream, ArchSpec &arch, OptionValueDictionary *test_data)
+{
+ if (!test_data)
+ {
+ out_stream->Printf ("TestEmulation: Missing test data.\n");
+ return false;
+ }
+
+ static ConstString opcode_key ("opcode");
+ static ConstString before_key ("before_state");
+ static ConstString after_key ("after_state");
+
+ OptionValueSP value_sp = test_data->GetValueForKey (opcode_key);
+
+ uint32_t test_opcode;
+ if ((value_sp.get() == NULL) || (value_sp->GetType() != OptionValue::eTypeUInt64))
+ {
+ out_stream->Printf ("TestEmulation: Error reading opcode from test file.\n");
+ return false;
+ }
+ test_opcode = value_sp->GetUInt64Value ();
+
+ if (arch.GetTriple().getArch() == llvm::Triple::arm)
+ {
+ m_opcode_mode = eModeARM;
+ m_opcode.SetOpcode32 (test_opcode);
+ }
+ else if (arch.GetTriple().getArch() == llvm::Triple::thumb)
+ {
+ m_opcode_mode = eModeThumb;
+ if (test_opcode < 0x10000)
+ m_opcode.SetOpcode16 (test_opcode);
+ else
+ m_opcode.SetOpcode32 (test_opcode);
+
+ }
+ else
+ {
+ out_stream->Printf ("TestEmulation: Invalid arch.\n");
+ return false;
+ }
+
+ EmulationStateARM before_state;
+ EmulationStateARM after_state;
+
+ value_sp = test_data->GetValueForKey (before_key);
+ if ((value_sp.get() == NULL) || (value_sp->GetType() != OptionValue::eTypeDictionary))
+ {
+ out_stream->Printf ("TestEmulation: Failed to find 'before' state.\n");
+ return false;
+ }
+
+ OptionValueDictionary *state_dictionary = value_sp->GetAsDictionary ();
+ if (!before_state.LoadStateFromDictionary (state_dictionary))
+ {
+ out_stream->Printf ("TestEmulation: Failed loading 'before' state.\n");
+ return false;
+ }
+
+ value_sp = test_data->GetValueForKey (after_key);
+ if ((value_sp.get() == NULL) || (value_sp->GetType() != OptionValue::eTypeDictionary))
+ {
+ out_stream->Printf ("TestEmulation: Failed to find 'after' state.\n");
+ return false;
+ }
+
+ state_dictionary = value_sp->GetAsDictionary ();
+ if (!after_state.LoadStateFromDictionary (state_dictionary))
+ {
+ out_stream->Printf ("TestEmulation: Failed loading 'after' state.\n");
+ return false;
+ }
+
+ SetBaton ((void *) &before_state);
+ SetCallbacks (&EmulationStateARM::ReadPseudoMemory,
+ &EmulationStateARM::WritePseudoMemory,
+ &EmulationStateARM::ReadPseudoRegister,
+ &EmulationStateARM::WritePseudoRegister);
+
+ bool success = EvaluateInstruction (eEmulateInstructionOptionAutoAdvancePC);
+ if (!success)
+ {
+ out_stream->Printf ("TestEmulation: EvaluateInstruction() failed.\n");
+ return false;
+ }
+
+ success = before_state.CompareState (after_state);
+ if (!success)
+ out_stream->Printf ("TestEmulation: 'before' and 'after' states do not match.\n");
+
+ return success;
+}
+//
+//
+//const char *
+//EmulateInstructionARM::GetRegisterName (uint32_t reg_kind, uint32_t reg_num)
+//{
+// if (reg_kind == eRegisterKindGeneric)
+// {
+// switch (reg_num)
+// {
+// case LLDB_REGNUM_GENERIC_PC: return "pc";
+// case LLDB_REGNUM_GENERIC_SP: return "sp";
+// case LLDB_REGNUM_GENERIC_FP: return "fp";
+// case LLDB_REGNUM_GENERIC_RA: return "lr";
+// case LLDB_REGNUM_GENERIC_FLAGS: return "cpsr";
+// default: return NULL;
+// }
+// }
+// else if (reg_kind == eRegisterKindDWARF)
+// {
+// return GetARMDWARFRegisterName (reg_num);
+// }
+// return NULL;
+//}
+//
+bool
+EmulateInstructionARM::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan)
+{
+ unwind_plan.Clear();
+ unwind_plan.SetRegisterKind (eRegisterKindDWARF);
+
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+
+ // Our previous Call Frame Address is the stack pointer
+ row->SetCFARegister (dwarf_sp);
+
+ // Our previous PC is in the LR
+ row->SetRegisterLocationToRegister(dwarf_pc, dwarf_lr, true);
+ unwind_plan.AppendRow (row);
+
+ // All other registers are the same.
+
+ unwind_plan.SetSourceName ("EmulateInstructionARM");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
+ return true;
+}
diff --git a/source/Plugins/Instruction/ARM/EmulateInstructionARM.h b/source/Plugins/Instruction/ARM/EmulateInstructionARM.h
new file mode 100644
index 000000000000..b926dc0deb4a
--- /dev/null
+++ b/source/Plugins/Instruction/ARM/EmulateInstructionARM.h
@@ -0,0 +1,990 @@
+//===-- lldb_EmulateInstructionARM.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_EmulateInstructionARM_h_
+#define lldb_EmulateInstructionARM_h_
+
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "Plugins/Process/Utility/ARMDefines.h"
+
+namespace lldb_private {
+
+// ITSession - Keep track of the IT Block progression.
+class ITSession
+{
+public:
+ ITSession() : ITCounter(0), ITState(0) {}
+ ~ITSession() {}
+
+ // InitIT - Initializes ITCounter/ITState.
+ bool InitIT(uint32_t bits7_0);
+
+ // ITAdvance - Updates ITCounter/ITState as IT Block progresses.
+ void ITAdvance();
+
+ // InITBlock - Returns true if we're inside an IT Block.
+ bool InITBlock();
+
+ // LastInITBlock - Returns true if we're the last instruction inside an IT Block.
+ bool LastInITBlock();
+
+ // GetCond - Gets condition bits for the current thumb instruction.
+ uint32_t GetCond();
+
+private:
+ uint32_t ITCounter; // Possible values: 0, 1, 2, 3, 4.
+ uint32_t ITState; // A2.5.2 Consists of IT[7:5] and IT[4:0] initially.
+};
+
+class EmulateInstructionARM : public EmulateInstruction
+{
+public:
+ typedef enum
+ {
+ eEncodingA1,
+ eEncodingA2,
+ eEncodingA3,
+ eEncodingA4,
+ eEncodingA5,
+ eEncodingT1,
+ eEncodingT2,
+ eEncodingT3,
+ eEncodingT4,
+ eEncodingT5
+ } ARMEncoding;
+
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic ();
+
+ static const char *
+ GetPluginDescriptionStatic ();
+
+ static lldb_private::EmulateInstruction *
+ CreateInstance (const lldb_private::ArchSpec &arch,
+ InstructionType inst_type);
+
+ static bool
+ SupportsEmulatingIntructionsOfTypeStatic (InstructionType inst_type)
+ {
+ switch (inst_type)
+ {
+ case eInstructionTypeAny:
+ case eInstructionTypePrologueEpilogue:
+ case eInstructionTypePCModifying:
+ return true;
+
+ case eInstructionTypeAll:
+ return false;
+ }
+ return false;
+ }
+
+ virtual lldb_private::ConstString
+ GetPluginName()
+ {
+ return GetPluginNameStatic();
+ }
+
+ virtual uint32_t
+ GetPluginVersion()
+ {
+ return 1;
+ }
+
+ bool
+ SetTargetTriple (const ArchSpec &arch);
+
+ enum Mode
+ {
+ eModeInvalid = -1,
+ eModeARM,
+ eModeThumb
+ };
+
+ EmulateInstructionARM (const ArchSpec &arch) :
+ EmulateInstruction (arch),
+ m_arm_isa (0),
+ m_opcode_mode (eModeInvalid),
+ m_opcode_cpsr (0),
+ m_it_session (),
+ m_ignore_conditions (false)
+ {
+ SetArchitecture (arch);
+ }
+
+// EmulateInstructionARM (const ArchSpec &arch,
+// bool ignore_conditions,
+// void *baton,
+// ReadMemory read_mem_callback,
+// WriteMemory write_mem_callback,
+// ReadRegister read_reg_callback,
+// WriteRegister write_reg_callback) :
+// EmulateInstruction (arch,
+// ignore_conditions,
+// baton,
+// read_mem_callback,
+// write_mem_callback,
+// read_reg_callback,
+// write_reg_callback),
+// m_arm_isa (0),
+// m_opcode_mode (eModeInvalid),
+// m_opcode_cpsr (0),
+// m_it_session ()
+// {
+// }
+
+ virtual bool
+ SupportsEmulatingIntructionsOfType (InstructionType inst_type)
+ {
+ return SupportsEmulatingIntructionsOfTypeStatic (inst_type);
+ }
+
+ virtual bool
+ SetArchitecture (const ArchSpec &arch);
+
+ virtual bool
+ ReadInstruction ();
+
+ virtual bool
+ SetInstruction (const Opcode &insn_opcode, const Address &inst_addr, Target *target);
+
+ virtual bool
+ EvaluateInstruction (uint32_t evaluate_options);
+
+ virtual bool
+ TestEmulation (Stream *out_stream, ArchSpec &arch, OptionValueDictionary *test_data);
+
+ virtual bool
+ GetRegisterInfo (uint32_t reg_kind, uint32_t reg_num, RegisterInfo &reg_info);
+
+
+ virtual bool
+ CreateFunctionEntryUnwind (UnwindPlan &unwind_plan);
+
+ uint32_t
+ ArchVersion();
+
+ bool
+ ConditionPassed (const uint32_t opcode,
+ bool *is_conditional = NULL); // Filled in with true if the opcode is a conditional opcode
+ // Filled in with false if the opcode is always executed
+
+ uint32_t
+ CurrentCond (const uint32_t opcode);
+
+ // InITBlock - Returns true if we're in Thumb mode and inside an IT Block.
+ bool InITBlock();
+
+ // LastInITBlock - Returns true if we're in Thumb mode and the last instruction inside an IT Block.
+ bool LastInITBlock();
+
+ bool
+ BadMode (uint32_t mode);
+
+ bool
+ CurrentModeIsPrivileged ();
+
+ void
+ CPSRWriteByInstr (uint32_t value, uint32_t bytemask, bool affect_execstate);
+
+ bool
+ BranchWritePC(const Context &context, uint32_t addr);
+
+ bool
+ BXWritePC(Context &context, uint32_t addr);
+
+ bool
+ LoadWritePC(Context &context, uint32_t addr);
+
+ bool
+ ALUWritePC(Context &context, uint32_t addr);
+
+ Mode
+ CurrentInstrSet();
+
+ bool
+ SelectInstrSet(Mode arm_or_thumb);
+
+ bool
+ WriteBits32Unknown (int n);
+
+ bool
+ WriteBits32UnknownToMemory (lldb::addr_t address);
+
+ bool
+ UnalignedSupport();
+
+ typedef struct
+ {
+ uint32_t result;
+ uint8_t carry_out;
+ uint8_t overflow;
+ } AddWithCarryResult;
+
+ AddWithCarryResult
+ AddWithCarry(uint32_t x, uint32_t y, uint8_t carry_in);
+
+ // Helper method to read the content of an ARM core register.
+ uint32_t
+ ReadCoreReg (uint32_t regnum, bool *success);
+
+ // See A8.6.96 MOV (immediate) Operation.
+ // Default arguments are specified for carry and overflow parameters, which means
+ // not to update the respective flags even if setflags is true.
+ bool
+ WriteCoreRegOptionalFlags (Context &context,
+ const uint32_t result,
+ const uint32_t Rd,
+ bool setflags,
+ const uint32_t carry = ~0u,
+ const uint32_t overflow = ~0u);
+
+ bool
+ WriteCoreReg (Context &context,
+ const uint32_t result,
+ const uint32_t Rd)
+ {
+ // Don't set the flags.
+ return WriteCoreRegOptionalFlags(context, result, Rd, false);
+ }
+
+ // See A8.6.35 CMP (immediate) Operation.
+ // Default arguments are specified for carry and overflow parameters, which means
+ // not to update the respective flags.
+ bool
+ WriteFlags (Context &context,
+ const uint32_t result,
+ const uint32_t carry = ~0u,
+ const uint32_t overflow = ~0u);
+
+ inline uint64_t
+ MemARead (EmulateInstruction::Context &context,
+ lldb::addr_t address,
+ uint32_t size,
+ uint64_t fail_value,
+ bool *success_ptr)
+ {
+ // This is a stub function corresponding to "MemA[]" in the ARM manual pseudocode, for
+ // aligned reads from memory. Since we are not trying to write a full hardware simulator, and since
+ // we are running in User mode (rather than Kernel mode) and therefore won't have access to many of the
+ // system registers we would need in order to fully implement this function, we will just call
+ // ReadMemoryUnsigned from here. In the future, if we decide we do need to do more faithful emulation of
+ // the hardware, we can update this function appropriately.
+
+ return ReadMemoryUnsigned (context, address, size, fail_value, success_ptr);
+ }
+
+ inline bool
+ MemAWrite (EmulateInstruction::Context &context,
+ lldb::addr_t address,
+ uint64_t data_val,
+ uint32_t size)
+
+ {
+ // This is a stub function corresponding to "MemA[]" in the ARM manual pseudocode, for
+ // aligned writes to memory. Since we are not trying to write a full hardware simulator, and since
+ // we are running in User mode (rather than Kernel mode) and therefore won't have access to many of the
+ // system registers we would need in order to fully implement this function, we will just call
+ // WriteMemoryUnsigned from here. In the future, if we decide we do need to do more faithful emulation of
+ // the hardware, we can update this function appropriately.
+
+ return WriteMemoryUnsigned (context, address, data_val, size);
+ }
+
+
+ inline uint64_t
+ MemURead (EmulateInstruction::Context &context,
+ lldb::addr_t address,
+ uint32_t size,
+ uint64_t fail_value,
+ bool *success_ptr)
+ {
+ // This is a stub function corresponding to "MemU[]" in the ARM manual pseudocode, for
+ // unaligned reads from memory. Since we are not trying to write a full hardware simulator, and since
+ // we are running in User mode (rather than Kernel mode) and therefore won't have access to many of the
+ // system registers we would need in order to fully implement this function, we will just call
+ // ReadMemoryUnsigned from here. In the future, if we decide we do need to do more faithful emulation of
+ // the hardware, we can update this function appropriately.
+
+ return ReadMemoryUnsigned (context, address, size, fail_value, success_ptr);
+ }
+
+ inline bool
+ MemUWrite (EmulateInstruction::Context &context,
+ lldb::addr_t address,
+ uint64_t data_val,
+ uint32_t size)
+
+ {
+ // This is a stub function corresponding to "MemU[]" in the ARM manual pseudocode, for
+ // unaligned writes to memory. Since we are not trying to write a full hardware simulator, and since
+ // we are running in User mode (rather than Kernel mode) and therefore won't have access to many of the
+ // system registers we would need in order to fully implement this function, we will just call
+ // WriteMemoryUnsigned from here. In the future, if we decide we do need to do more faithful emulation of
+ // the hardware, we can update this function appropriately.
+
+ return WriteMemoryUnsigned (context, address, data_val, size);
+ }
+
+protected:
+
+ // Typedef for the callback function used during the emulation.
+ // Pass along (ARMEncoding)encoding as the callback data.
+ typedef enum
+ {
+ eSize16,
+ eSize32
+ } ARMInstrSize;
+
+ typedef struct
+ {
+ uint32_t mask;
+ uint32_t value;
+ uint32_t variants;
+ EmulateInstructionARM::ARMEncoding encoding;
+ uint32_t vfp_variants;
+ ARMInstrSize size;
+ bool (EmulateInstructionARM::*callback) (const uint32_t opcode, const EmulateInstructionARM::ARMEncoding encoding);
+ const char *name;
+ } ARMOpcode;
+
+ uint32_t
+ GetFramePointerRegisterNumber () const;
+
+ uint32_t
+ GetFramePointerDWARFRegisterNumber () const;
+
+ static ARMOpcode*
+ GetARMOpcodeForInstruction (const uint32_t opcode, uint32_t isa_mask);
+
+ static ARMOpcode*
+ GetThumbOpcodeForInstruction (const uint32_t opcode, uint32_t isa_mask);
+
+ // A8.6.123 PUSH
+ bool
+ EmulatePUSH (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.122 POP
+ bool
+ EmulatePOP (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.8 ADD (SP plus immediate)
+ bool
+ EmulateADDRdSPImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.97 MOV (register) -- Rd == r7|ip and Rm == sp
+ bool
+ EmulateMOVRdSP (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.97 MOV (register) -- move from r8-r15 to r0-r7
+ bool
+ EmulateMOVLowHigh (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.59 LDR (literal)
+ bool
+ EmulateLDRRtPCRelative (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.8 ADD (SP plus immediate)
+ bool
+ EmulateADDSPImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.9 ADD (SP plus register)
+ bool
+ EmulateADDSPRm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.23 BL, BLX (immediate)
+ bool
+ EmulateBLXImmediate (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.24 BLX (register)
+ bool
+ EmulateBLXRm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.25 BX
+ bool
+ EmulateBXRm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.26 BXJ
+ bool
+ EmulateBXJRm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.212 SUB (immediate, ARM) -- Rd == r7 and Rm == ip
+ bool
+ EmulateSUBR7IPImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.215 SUB (SP minus immediate) -- Rd == ip
+ bool
+ EmulateSUBIPSPImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.215 SUB (SP minus immediate)
+ bool
+ EmulateSUBSPImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.216 SUB (SP minus register)
+ bool
+ EmulateSUBSPReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.194 STR (immediate, ARM) -- Rn == sp
+ bool
+ EmulateSTRRtSP (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.355 VPUSH
+ bool
+ EmulateVPUSH (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.354 VPOP
+ bool
+ EmulateVPOP (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.218 SVC (previously SWI)
+ bool
+ EmulateSVC (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.50 IT
+ bool
+ EmulateIT (const uint32_t opcode, const ARMEncoding encoding);
+
+ // NOP
+ bool
+ EmulateNop (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.16 B
+ bool
+ EmulateB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.27 CBNZ, CBZ
+ bool
+ EmulateCB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.226 TBB, TBH
+ bool
+ EmulateTB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.4 ADD (immediate, Thumb)
+ bool
+ EmulateADDImmThumb (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.5 ADD (immediate, ARM)
+ bool
+ EmulateADDImmARM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.6 ADD (register)
+ bool
+ EmulateADDReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.7 ADD (register-shifted register)
+ bool
+ EmulateADDRegShift (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.97 MOV (register)
+ bool
+ EmulateMOVRdRm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.96 MOV (immediate)
+ bool
+ EmulateMOVRdImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.35 CMP (immediate)
+ bool
+ EmulateCMPImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.36 CMP (register)
+ bool
+ EmulateCMPReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.14 ASR (immediate)
+ bool
+ EmulateASRImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.15 ASR (register)
+ bool
+ EmulateASRReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.88 LSL (immediate)
+ bool
+ EmulateLSLImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.89 LSL (register)
+ bool
+ EmulateLSLReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.90 LSR (immediate)
+ bool
+ EmulateLSRImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.91 LSR (register)
+ bool
+ EmulateLSRReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.139 ROR (immediate)
+ bool
+ EmulateRORImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.140 ROR (register)
+ bool
+ EmulateRORReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.141 RRX
+ bool
+ EmulateRRX (const uint32_t opcode, const ARMEncoding encoding);
+
+ // Helper method for ASR, LSL, LSR, ROR (immediate), and RRX
+ bool
+ EmulateShiftImm (const uint32_t opcode, const ARMEncoding encoding, ARM_ShifterType shift_type);
+
+ // Helper method for ASR, LSL, LSR, and ROR (register)
+ bool
+ EmulateShiftReg (const uint32_t opcode, const ARMEncoding encoding, ARM_ShifterType shift_type);
+
+ // LOAD FUNCTIONS
+
+ // A8.6.53 LDM/LDMIA/LDMFD
+ bool
+ EmulateLDM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.54 LDMDA/LDMFA
+ bool
+ EmulateLDMDA (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.55 LDMDB/LDMEA
+ bool
+ EmulateLDMDB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.56 LDMIB/LDMED
+ bool
+ EmulateLDMIB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.57 LDR (immediate, Thumb) -- Encoding T1
+ bool
+ EmulateLDRRtRnImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.58 LDR (immediate, ARM) - Encoding A1
+ bool
+ EmulateLDRImmediateARM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.59 LDR (literal)
+ bool
+ EmulateLDRLiteral (const uint32_t, const ARMEncoding encoding);
+
+ // A8.6.60 LDR (register) - Encoding T1, T2, A1
+ bool
+ EmulateLDRRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.61 LDRB (immediate, Thumb) - Encoding T1, T2, T3
+ bool
+ EmulateLDRBImmediate (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.62 LDRB (immediate, ARM)
+ bool
+ EmulateLDRBImmediateARM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.63 LDRB (literal) - Encoding T1, A1
+ bool
+ EmulateLDRBLiteral (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.64 LDRB (register) - Encoding T1, T2, A1
+ bool
+ EmulateLDRBRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.65 LDRBT
+ bool
+ EmulateLDRBT (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.66 LDRD (immediate)
+ bool
+ EmulateLDRDImmediate (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.67
+ bool
+ EmulateLDRDLiteral (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.68 LDRD (register)
+ bool
+ EmulateLDRDRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.69 LDREX
+ bool
+ EmulateLDREX (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.70 LDREXB
+ bool
+ EmulateLDREXB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.71 LDREXD
+ bool
+ EmulateLDREXD (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.72 LDREXH
+ bool
+ EmulateLDREXH (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.73 LDRH (immediate, Thumb) - Encoding T1, T2, T3
+ bool
+ EmulateLDRHImmediate (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.74 LDRS (immediate, ARM)
+ bool
+ EmulateLDRHImmediateARM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.75 LDRH (literal) - Encoding T1, A1
+ bool
+ EmulateLDRHLiteral (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.76 LDRH (register) - Encoding T1, T2, A1
+ bool
+ EmulateLDRHRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.77 LDRHT
+ bool
+ EmulateLDRHT (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.78 LDRSB (immediate) - Encoding T1, T2, A1
+ bool
+ EmulateLDRSBImmediate (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.79 LDRSB (literal) - Encoding T1, A1
+ bool
+ EmulateLDRSBLiteral (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.80 LDRSB (register) - Encoding T1, T2, A1
+ bool
+ EmulateLDRSBRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.81 LDRSBT
+ bool
+ EmulateLDRSBT (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.82 LDRSH (immediate) - Encoding T1, T2, A1
+ bool
+ EmulateLDRSHImmediate (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.83 LDRSH (literal) - Encoding T1, A1
+ bool
+ EmulateLDRSHLiteral (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.84 LDRSH (register) - Encoding T1, T2, A1
+ bool
+ EmulateLDRSHRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.85 LDRSHT
+ bool
+ EmulateLDRSHT (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.86
+ bool
+ EmulateLDRT (const uint32_t opcode, const ARMEncoding encoding);
+
+
+ // STORE FUNCTIONS
+
+ // A8.6.189 STM/STMIA/STMEA
+ bool
+ EmulateSTM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.190 STMDA/STMED
+ bool
+ EmulateSTMDA (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.191 STMDB/STMFD
+ bool
+ EmulateSTMDB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.192 STMIB/STMFA
+ bool
+ EmulateSTMIB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.193 STR (immediate, Thumb)
+ bool
+ EmulateSTRThumb(const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.194 STR (immediate, ARM)
+ bool
+ EmulateSTRImmARM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.195 STR (register)
+ bool
+ EmulateSTRRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.196 STRB (immediate, Thumb)
+ bool
+ EmulateSTRBThumb (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.197 STRB (immediate, ARM)
+ bool
+ EmulateSTRBImmARM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.198 STRB (register)
+ bool
+ EmulateSTRBReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.199 STRBT
+ bool
+ EmulateSTRBT (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.200 STRD (immediate)
+ bool
+ EmulateSTRDImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.201 STRD (register)
+ bool
+ EmulateSTRDReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.202 STREX
+ bool
+ EmulateSTREX (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.203 STREXB
+ bool
+ EmulateSTREXB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.204 STREXD
+ bool
+ EmulateSTREXD (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.205 STREXH
+ bool
+ EmulateSTREXH (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.206 STRH (immediate, Thumb)
+ bool
+ EmulateSTRHImmThumb (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.207 STRH (immediate, ARM)
+ bool
+ EmulateSTRHImmARM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.208 STRH (register)
+ bool
+ EmulateSTRHRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.209 STRHT
+ bool
+ EmulateSTRHT (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.210 STRT
+ bool
+ EmulateSTRT (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.1 ADC (immediate)
+ bool
+ EmulateADCImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.2 ADC (Register)
+ bool
+ EmulateADCReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.10 ADR
+ bool
+ EmulateADR (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.11 AND (immediate)
+ bool
+ EmulateANDImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.12 AND (register)
+ bool
+ EmulateANDReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.19 BIC (immediate)
+ bool
+ EmulateBICImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.20 BIC (register)
+ bool
+ EmulateBICReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.26 BXJ
+ bool
+ EmulateBXJ (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.32 CMN (immediate)
+ bool
+ EmulateCMNImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.33 CMN (register)
+ bool
+ EmulateCMNReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.44 EOR (immediate)
+ bool
+ EmulateEORImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.45 EOR (register)
+ bool
+ EmulateEORReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.105 MUL
+ bool
+ EmulateMUL (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.106 MVN (immediate)
+ bool
+ EmulateMVNImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.107 MVN (register)
+ bool
+ EmulateMVNReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.113 ORR (immediate)
+ bool
+ EmulateORRImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.114 ORR (register)
+ bool
+ EmulateORRReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.117 PLD (immediate, literal) - Encoding T1, T2, T3, A1
+ bool
+ EmulatePLDImmediate (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.119 PLI (immediate,literal) - Encoding T3, A1
+ bool
+ EmulatePLIImmediate (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.120 PLI (register) - Encoding T1, A1
+ bool
+ EmulatePLIRegister (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.141 RSB (immediate)
+ bool
+ EmulateRSBImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.142 RSB (register)
+ bool
+ EmulateRSBReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.144 RSC (immediate)
+ bool
+ EmulateRSCImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.145 RSC (register)
+ bool
+ EmulateRSCReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.150 SBC (immediate)
+ bool
+ EmulateSBCImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.151 SBC (register)
+ bool
+ EmulateSBCReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.211 SUB (immediate, Thumb)
+ bool
+ EmulateSUBImmThumb (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.212 SUB (immediate, ARM)
+ bool
+ EmulateSUBImmARM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.213 SUB (register)
+ bool
+ EmulateSUBReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.214 SUB (register-shifted register)
+ bool
+ EmulateSUBRegShift (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.222 SXTB - Encoding T1
+ bool
+ EmulateSXTB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.224 SXTH - EncodingT1
+ bool
+ EmulateSXTH (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.227 TEQ (immediate) - Encoding A1
+ bool
+ EmulateTEQImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.228 TEQ (register) - Encoding A1
+ bool
+ EmulateTEQReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.230 TST (immediate) - Encoding A1
+ bool
+ EmulateTSTImm (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.231 TST (register) - Encoding T1, A1
+ bool
+ EmulateTSTReg (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.262 UXTB - Encoding T1
+ bool
+ EmulateUXTB (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.264 UXTH - Encoding T1
+ bool
+ EmulateUXTH (const uint32_t opcode, const ARMEncoding encoding);
+
+ // B6.1.8 RFE
+ bool
+ EmulateRFE (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.319 VLDM
+ bool
+ EmulateVLDM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.399 VSTM
+ bool
+ EmulateVSTM (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.307 VLD1 (multiple single elements)
+ bool
+ EmulateVLD1Multiple (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.308 VLD1 (single element to one lane)
+ bool
+ EmulateVLD1Single (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.309 VLD1 (single element to all lanes)
+ bool
+ EmulateVLD1SingleAll (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.391 VST1 (multiple single elements)
+ bool
+ EmulateVST1Multiple (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.392 VST1 (single element from one lane)
+ bool
+ EmulateVST1Single (const uint32_t opcode, const ARMEncoding encoding);
+
+ // A8.6.317 VLDR
+ bool
+ EmulateVLDR (const uint32_t opcode, const ARMEncoding encoding);
+
+
+ // A8.6.400 VSTR
+ bool
+ EmulateVSTR (const uint32_t opcode, const ARMEncoding encoding);
+
+ // B6.2.13 SUBS PC, LR and related instructions
+ bool
+ EmulateSUBSPcLrEtc (const uint32_t opcode, const ARMEncoding encoding);
+
+ uint32_t m_arm_isa;
+ Mode m_opcode_mode;
+ uint32_t m_opcode_cpsr;
+ uint32_t m_new_inst_cpsr; // This can get updated by the opcode.
+ ITSession m_it_session;
+ bool m_ignore_conditions;
+};
+
+} // namespace lldb_private
+
+#endif // lldb_EmulateInstructionARM_h_
diff --git a/source/Plugins/Instruction/ARM/EmulationStateARM.cpp b/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
new file mode 100644
index 000000000000..bad4118971e0
--- /dev/null
+++ b/source/Plugins/Instruction/ARM/EmulationStateARM.cpp
@@ -0,0 +1,406 @@
+//===-- EmulationStateARM.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "EmulationStateARM.h"
+
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Interpreter/OptionValueArray.h"
+#include "lldb/Interpreter/OptionValueDictionary.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "Utility/ARM_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+EmulationStateARM::EmulationStateARM () :
+ m_gpr (),
+ m_vfp_regs (),
+ m_memory ()
+{
+ ClearPseudoRegisters();
+}
+
+EmulationStateARM::~EmulationStateARM ()
+{
+}
+
+bool
+EmulationStateARM::LoadPseudoRegistersFromFrame (StackFrame &frame)
+{
+ RegisterContext *reg_ctx = frame.GetRegisterContext().get();
+ bool success = true;
+ uint32_t reg_num;
+
+ for (int i = dwarf_r0; i < dwarf_r0 + 17; ++i)
+ {
+ reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindDWARF, i);
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex (reg_num);
+ RegisterValue reg_value;
+ if (reg_ctx->ReadRegister (reg_info, reg_value))
+ {
+ m_gpr[i - dwarf_r0] = reg_value.GetAsUInt32();
+ }
+ else
+ success = false;
+ }
+
+ for (int i = dwarf_d0; i < dwarf_d0 + 32; ++i)
+ {
+ reg_num = reg_ctx->ConvertRegisterKindToRegisterNumber (eRegisterKindDWARF, i);
+ RegisterValue reg_value;
+ const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex (reg_num);
+
+ if (reg_ctx->ReadRegister (reg_info, reg_value))
+ {
+ uint32_t idx = i - dwarf_d0;
+ if (i < 16)
+ m_vfp_regs.sd_regs[idx].d_reg = reg_value.GetAsUInt64();
+ else
+ m_vfp_regs.d_regs[idx - 16] = reg_value.GetAsUInt64();
+ }
+ else
+ success = false;
+ }
+
+ return success;
+}
+
+bool
+EmulationStateARM::StorePseudoRegisterValue (uint32_t reg_num, uint64_t value)
+{
+ if ((dwarf_r0 <= reg_num) && (reg_num <= dwarf_cpsr))
+ m_gpr[reg_num - dwarf_r0] = (uint32_t) value;
+ else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31))
+ {
+ uint32_t idx = reg_num - dwarf_s0;
+ m_vfp_regs.sd_regs[idx / 2].s_reg[idx % 2] = (uint32_t) value;
+ }
+ else if ((dwarf_d0 <= reg_num) && (reg_num <= dwarf_d31))
+ {
+ if ((reg_num - dwarf_d0) < 16)
+ {
+ m_vfp_regs.sd_regs[reg_num - dwarf_d0].d_reg = value;
+ }
+ else
+ m_vfp_regs.d_regs[reg_num - dwarf_d16] = value;
+ }
+ else
+ return false;
+
+ return true;
+}
+
+uint64_t
+EmulationStateARM::ReadPseudoRegisterValue (uint32_t reg_num, bool &success)
+{
+ uint64_t value = 0;
+ success = true;
+
+ if ((dwarf_r0 <= reg_num) && (reg_num <= dwarf_cpsr))
+ value = m_gpr[reg_num - dwarf_r0];
+ else if ((dwarf_s0 <= reg_num) && (reg_num <= dwarf_s31))
+ {
+ uint32_t idx = reg_num - dwarf_s0;
+ value = m_vfp_regs.sd_regs[idx / 2].s_reg[idx % 2];
+ }
+ else if ((dwarf_d0 <= reg_num) && (reg_num <= dwarf_d31))
+ {
+ if ((reg_num - dwarf_d0) < 16)
+ value = m_vfp_regs.sd_regs[reg_num - dwarf_d0].d_reg;
+ else
+ value = m_vfp_regs.d_regs[reg_num - dwarf_d16];
+ }
+ else
+ success = false;
+
+ return value;
+}
+
+void
+EmulationStateARM::ClearPseudoRegisters ()
+{
+ for (int i = 0; i < 17; ++i)
+ m_gpr[i] = 0;
+
+ for (int i = 0; i < 16; ++i)
+ m_vfp_regs.sd_regs[i].d_reg = 0;
+
+ for (int i = 0; i < 16; ++i)
+ m_vfp_regs.d_regs[i] = 0;
+}
+
+void
+EmulationStateARM::ClearPseudoMemory ()
+{
+ m_memory.clear();
+}
+
+bool
+EmulationStateARM::StoreToPseudoAddress (lldb::addr_t p_address, uint64_t value, uint32_t size)
+{
+ if (size > 8)
+ return false;
+
+ if (size <= 4)
+ m_memory[p_address] = value;
+ else if (size == 8)
+ {
+ m_memory[p_address] = (value << 32) >> 32;
+ m_memory[p_address + 4] = value << 32;
+ }
+ return true;
+}
+
+uint32_t
+EmulationStateARM::ReadFromPseudoAddress (lldb::addr_t p_address, uint32_t size, bool &success)
+{
+ std::map<lldb::addr_t,uint32_t>::iterator pos;
+ uint32_t ret_val = 0;
+
+ success = true;
+ pos = m_memory.find(p_address);
+ if (pos != m_memory.end())
+ ret_val = pos->second;
+ else
+ success = false;
+
+ return ret_val;
+}
+
+size_t
+EmulationStateARM::ReadPseudoMemory (EmulateInstruction *instruction,
+ void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t length)
+{
+ if (!baton)
+ return 0;
+
+ bool success = true;
+ EmulationStateARM *pseudo_state = (EmulationStateARM *) baton;
+ if (length <= 4)
+ {
+ uint32_t value = pseudo_state->ReadFromPseudoAddress (addr, length, success);
+ if (!success)
+ return 0;
+
+ *((uint32_t *) dst) = value;
+ }
+ else if (length == 8)
+ {
+ uint32_t value1 = pseudo_state->ReadFromPseudoAddress (addr, 4, success);
+ if (!success)
+ return 0;
+
+ uint32_t value2 = pseudo_state->ReadFromPseudoAddress (addr + 4, 4, success);
+ if (!success)
+ return 0;
+
+ uint64_t value64 = value2;
+ value64 = (value64 << 32) | value1;
+ *((uint64_t *) dst) = value64;
+ }
+ else
+ success = false;
+
+ if (success)
+ return length;
+
+ return 0;
+}
+
+size_t
+EmulationStateARM::WritePseudoMemory (EmulateInstruction *instruction,
+ void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length)
+{
+ if (!baton)
+ return 0;
+
+ bool success;
+ EmulationStateARM *pseudo_state = (EmulationStateARM *) baton;
+ uint64_t value = *((uint64_t *) dst);
+ success = pseudo_state->StoreToPseudoAddress (addr, value, length);
+ if (success)
+ return length;
+
+ return 0;
+}
+
+bool
+EmulationStateARM::ReadPseudoRegister (EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value)
+{
+ if (!baton || !reg_info)
+ return false;
+
+ bool success = true;
+ EmulationStateARM *pseudo_state = (EmulationStateARM *) baton;
+ const uint32_t dwarf_reg_num = reg_info->kinds[eRegisterKindDWARF];
+ assert (dwarf_reg_num != LLDB_INVALID_REGNUM);
+ uint64_t reg_uval = pseudo_state->ReadPseudoRegisterValue (dwarf_reg_num, success);
+
+ if (success)
+ success = reg_value.SetUInt(reg_uval, reg_info->byte_size);
+ return success;
+
+}
+
+bool
+EmulationStateARM::WritePseudoRegister (EmulateInstruction *instruction,
+ void *baton,
+ const EmulateInstruction::Context &context,
+ const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value)
+{
+ if (!baton || !reg_info)
+ return false;
+
+ EmulationStateARM *pseudo_state = (EmulationStateARM *) baton;
+ const uint32_t dwarf_reg_num = reg_info->kinds[eRegisterKindDWARF];
+ assert (dwarf_reg_num != LLDB_INVALID_REGNUM);
+ return pseudo_state->StorePseudoRegisterValue (dwarf_reg_num, reg_value.GetAsUInt64());
+}
+
+bool
+EmulationStateARM::CompareState (EmulationStateARM &other_state)
+{
+ bool match = true;
+
+ for (int i = 0; match && i < 17; ++i)
+ {
+ if (m_gpr[i] != other_state.m_gpr[i])
+ match = false;
+ }
+
+ for (int i = 0; match && i < 16; ++i)
+ {
+ if (m_vfp_regs.sd_regs[i].s_reg[0] != other_state.m_vfp_regs.sd_regs[i].s_reg[0])
+ match = false;
+
+ if (m_vfp_regs.sd_regs[i].s_reg[1] != other_state.m_vfp_regs.sd_regs[i].s_reg[1])
+ match = false;
+ }
+
+ for (int i = 0; match && i < 32; ++i)
+ {
+ if (i < 16)
+ {
+ if (m_vfp_regs.sd_regs[i].d_reg != other_state.m_vfp_regs.sd_regs[i].d_reg)
+ match = false;
+ }
+ else
+ {
+ if (m_vfp_regs.d_regs[i - 16] != other_state.m_vfp_regs.d_regs[i - 16])
+ match = false;
+ }
+ }
+
+ return match;
+}
+
+bool
+EmulationStateARM::LoadStateFromDictionary (OptionValueDictionary *test_data)
+{
+ static ConstString memory_key ("memory");
+ static ConstString registers_key ("registers");
+
+ if (!test_data)
+ return false;
+
+ OptionValueSP value_sp = test_data->GetValueForKey (memory_key);
+
+ // Load memory, if present.
+
+ if (value_sp.get() != NULL)
+ {
+ static ConstString address_key ("address");
+ static ConstString data_key ("data");
+ uint64_t start_address = 0;
+
+ OptionValueDictionary *mem_dict = value_sp->GetAsDictionary();
+ value_sp = mem_dict->GetValueForKey (address_key);
+ if (value_sp.get() == NULL)
+ return false;
+ else
+ start_address = value_sp->GetUInt64Value ();
+
+ value_sp = mem_dict->GetValueForKey (data_key);
+ OptionValueArray *mem_array = value_sp->GetAsArray();
+ if (!mem_array)
+ return false;
+
+ uint32_t num_elts = mem_array->GetSize();
+ uint32_t address = (uint32_t) start_address;
+
+ for (uint32_t i = 0; i < num_elts; ++i)
+ {
+ value_sp = mem_array->GetValueAtIndex (i);
+ if (value_sp.get() == NULL)
+ return false;
+ uint64_t value = value_sp->GetUInt64Value();
+ StoreToPseudoAddress (address, value, 4);
+ address = address + 4;
+ }
+ }
+
+ value_sp = test_data->GetValueForKey (registers_key);
+ if (value_sp.get() == NULL)
+ return false;
+
+
+ // Load General Registers
+
+ OptionValueDictionary *reg_dict = value_sp->GetAsDictionary ();
+
+ StreamString sstr;
+ for (int i = 0; i < 16; ++i)
+ {
+ sstr.Clear();
+ sstr.Printf ("r%d", i);
+ ConstString reg_name (sstr.GetData());
+ value_sp = reg_dict->GetValueForKey (reg_name);
+ if (value_sp.get() == NULL)
+ return false;
+ uint64_t reg_value = value_sp->GetUInt64Value();
+ StorePseudoRegisterValue (dwarf_r0 + i, reg_value);
+ }
+
+ static ConstString cpsr_name ("cpsr");
+ value_sp = reg_dict->GetValueForKey (cpsr_name);
+ if (value_sp.get() == NULL)
+ return false;
+ StorePseudoRegisterValue (dwarf_cpsr, value_sp->GetUInt64Value());
+
+ // Load s/d Registers
+ for (int i = 0; i < 32; ++i)
+ {
+ sstr.Clear();
+ sstr.Printf ("s%d", i);
+ ConstString reg_name (sstr.GetData());
+ value_sp = reg_dict->GetValueForKey (reg_name);
+ if (value_sp.get() == NULL)
+ return false;
+ uint64_t reg_value = value_sp->GetUInt64Value();
+ StorePseudoRegisterValue (dwarf_s0 + i, reg_value);
+ }
+
+ return true;
+}
+
diff --git a/source/Plugins/Instruction/ARM/EmulationStateARM.h b/source/Plugins/Instruction/ARM/EmulationStateARM.h
new file mode 100644
index 000000000000..8d84abc75614
--- /dev/null
+++ b/source/Plugins/Instruction/ARM/EmulationStateARM.h
@@ -0,0 +1,100 @@
+//===-- lldb_EmulationStateARM.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_EmulationStateARM_h_
+#define lldb_EmulationStateARM_h_
+
+#include <map>
+
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/Opcode.h"
+
+class EmulationStateARM {
+public:
+
+ EmulationStateARM ();
+
+ virtual
+ ~EmulationStateARM ();
+
+ bool
+ StorePseudoRegisterValue (uint32_t reg_num, uint64_t value);
+
+ uint64_t
+ ReadPseudoRegisterValue (uint32_t reg_num, bool &success);
+
+ bool
+ StoreToPseudoAddress (lldb::addr_t p_address, uint64_t value, uint32_t size);
+
+ uint32_t
+ ReadFromPseudoAddress (lldb::addr_t p_address, uint32_t size, bool &success);
+
+ void
+ ClearPseudoRegisters ();
+
+ void
+ ClearPseudoMemory ();
+
+ bool
+ LoadPseudoRegistersFromFrame (lldb_private::StackFrame &frame);
+
+ bool
+ LoadStateFromDictionary (lldb_private::OptionValueDictionary *test_data);
+
+ bool
+ CompareState (EmulationStateARM &other_state);
+
+ static size_t
+ ReadPseudoMemory (lldb_private::EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t length);
+
+ static size_t
+ WritePseudoMemory (lldb_private::EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length);
+
+ static bool
+ ReadPseudoRegister (lldb_private::EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ static bool
+ WritePseudoRegister (lldb_private::EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::EmulateInstruction::Context &context,
+ const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value);
+private:
+ uint32_t m_gpr[17];
+ struct sd_regs
+ {
+ union
+ {
+ uint32_t s_reg[2];
+ uint64_t d_reg;
+ } sd_regs[16]; // sregs 0 - 31 & dregs 0 - 15
+
+ uint64_t d_regs[16]; // dregs 16-31
+
+ } m_vfp_regs;
+
+ std::map<lldb::addr_t, uint32_t> m_memory; // Eventually will want to change uint32_t to a data buffer heap type.
+
+ DISALLOW_COPY_AND_ASSIGN (EmulationStateARM);
+};
+
+#endif // lldb_EmulationStateARM_h_
diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
new file mode 100644
index 000000000000..247d7b0e7fe4
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
@@ -0,0 +1,461 @@
+//===-- ItaniumABILanguageRuntime.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ItaniumABILanguageRuntime.h"
+
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/TypeList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include <vector>
+
+using namespace lldb;
+using namespace lldb_private;
+
+static const char *vtable_demangled_prefix = "vtable for ";
+
+bool
+ItaniumABILanguageRuntime::CouldHaveDynamicValue (ValueObject &in_value)
+{
+ const bool check_cxx = true;
+ const bool check_objc = false;
+ return in_value.GetClangType().IsPossibleDynamicType (NULL, check_cxx, check_objc);
+}
+
+bool
+ItaniumABILanguageRuntime::GetDynamicTypeAndAddress (ValueObject &in_value,
+ lldb::DynamicValueType use_dynamic,
+ TypeAndOrName &class_type_or_name,
+ Address &dynamic_address)
+{
+ // For Itanium, if the type has a vtable pointer in the object, it will be at offset 0
+ // in the object. That will point to the "address point" within the vtable (not the beginning of the
+ // vtable.) We can then look up the symbol containing this "address point" and that symbol's name
+ // demangled will contain the full class name.
+ // The second pointer above the "address point" is the "offset_to_top". We'll use that to get the
+ // start of the value object which holds the dynamic type.
+ //
+
+ class_type_or_name.Clear();
+
+ // Only a pointer or reference type can have a different dynamic and static type:
+ if (CouldHaveDynamicValue (in_value))
+ {
+ // First job, pull out the address at 0 offset from the object.
+ AddressType address_type;
+ lldb::addr_t original_ptr = in_value.GetPointerValue(&address_type);
+ if (original_ptr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ ExecutionContext exe_ctx (in_value.GetExecutionContextRef());
+
+ Target *target = exe_ctx.GetTargetPtr();
+ Process *process = exe_ctx.GetProcessPtr();
+
+ char memory_buffer[16];
+ DataExtractor data(memory_buffer, sizeof(memory_buffer),
+ process->GetByteOrder(),
+ process->GetAddressByteSize());
+ size_t address_byte_size = process->GetAddressByteSize();
+ Error error;
+ size_t bytes_read = process->ReadMemory (original_ptr,
+ memory_buffer,
+ address_byte_size,
+ error);
+ if (!error.Success() || (bytes_read != address_byte_size))
+ {
+ return false;
+ }
+
+ lldb::offset_t offset = 0;
+ lldb::addr_t vtable_address_point = data.GetAddress (&offset);
+
+ if (offset == 0)
+ return false;
+
+ // Now find the symbol that contains this address:
+
+ SymbolContext sc;
+ Address address_point_address;
+ if (target && !target->GetSectionLoadList().IsEmpty())
+ {
+ if (target->GetSectionLoadList().ResolveLoadAddress (vtable_address_point, address_point_address))
+ {
+ target->GetImages().ResolveSymbolContextForAddress (address_point_address, eSymbolContextSymbol, sc);
+ Symbol *symbol = sc.symbol;
+ if (symbol != NULL)
+ {
+ const char *name = symbol->GetMangled().GetDemangledName().AsCString();
+ if (strstr(name, vtable_demangled_prefix) == name)
+ {
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has vtable symbol '%s'\n",
+ original_ptr,
+ in_value.GetTypeName().GetCString(),
+ name);
+ // We are a C++ class, that's good. Get the class name and look it up:
+ const char *class_name = name + strlen(vtable_demangled_prefix);
+ class_type_or_name.SetName (class_name);
+ const bool exact_match = true;
+ TypeList class_types;
+
+ uint32_t num_matches = 0;
+ // First look in the module that the vtable symbol came from
+ // and look for a single exact match.
+ if (sc.module_sp)
+ {
+ num_matches = sc.module_sp->FindTypes (sc,
+ ConstString(class_name),
+ exact_match,
+ 1,
+ class_types);
+ }
+
+ // If we didn't find a symbol, then move on to the entire
+ // module list in the target and get as many unique matches
+ // as possible
+ if (num_matches == 0)
+ {
+ num_matches = target->GetImages().FindTypes (sc,
+ ConstString(class_name),
+ exact_match,
+ UINT32_MAX,
+ class_types);
+ }
+
+ lldb::TypeSP type_sp;
+ if (num_matches == 0)
+ {
+ if (log)
+ log->Printf("0x%16.16" PRIx64 ": is not dynamic\n", original_ptr);
+ return false;
+ }
+ if (num_matches == 1)
+ {
+ type_sp = class_types.GetTypeAtIndex(0);
+ if (log)
+ log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has dynamic type: uid={0x%" PRIx64 "}, type-name='%s'\n",
+ original_ptr,
+ in_value.GetTypeName().AsCString(),
+ type_sp->GetID(),
+ type_sp->GetName().GetCString());
+
+ class_type_or_name.SetTypeSP(class_types.GetTypeAtIndex(0));
+ }
+ else if (num_matches > 1)
+ {
+ size_t i;
+ if (log)
+ {
+ for (i = 0; i < num_matches; i++)
+ {
+ type_sp = class_types.GetTypeAtIndex(i);
+ if (type_sp)
+ {
+ if (log)
+ log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types: uid={0x%" PRIx64 "}, type-name='%s'\n",
+ original_ptr,
+ in_value.GetTypeName().AsCString(),
+ type_sp->GetID(),
+ type_sp->GetName().GetCString());
+ }
+ }
+ }
+
+ for (i = 0; i < num_matches; i++)
+ {
+ type_sp = class_types.GetTypeAtIndex(i);
+ if (type_sp)
+ {
+ if (type_sp->GetClangFullType().IsCXXClassType())
+ {
+ if (log)
+ log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, picking this one: uid={0x%" PRIx64 "}, type-name='%s'\n",
+ original_ptr,
+ in_value.GetTypeName().AsCString(),
+ type_sp->GetID(),
+ type_sp->GetName().GetCString());
+ class_type_or_name.SetTypeSP(type_sp);
+ break;
+ }
+ }
+ }
+
+ if (i == num_matches)
+ {
+ if (log)
+ log->Printf ("0x%16.16" PRIx64 ": static-type = '%s' has multiple matching dynamic types, didn't find a C++ match\n",
+ original_ptr,
+ in_value.GetTypeName().AsCString());
+ return false;
+ }
+ }
+
+ // There can only be one type with a given name,
+ // so we've just found duplicate definitions, and this
+ // one will do as well as any other.
+ // We don't consider something to have a dynamic type if
+ // it is the same as the static type. So compare against
+ // the value we were handed.
+ if (type_sp)
+ {
+ if (ClangASTContext::AreTypesSame (in_value.GetClangType(),
+ type_sp->GetClangFullType()))
+ {
+ // The dynamic type we found was the same type,
+ // so we don't have a dynamic type here...
+ return false;
+ }
+
+ // The offset_to_top is two pointers above the address.
+ Address offset_to_top_address = address_point_address;
+ int64_t slide = -2 * ((int64_t) target->GetArchitecture().GetAddressByteSize());
+ offset_to_top_address.Slide (slide);
+
+ Error error;
+ lldb::addr_t offset_to_top_location = offset_to_top_address.GetLoadAddress(target);
+
+ size_t bytes_read = process->ReadMemory (offset_to_top_location,
+ memory_buffer,
+ address_byte_size,
+ error);
+
+ if (!error.Success() || (bytes_read != address_byte_size))
+ {
+ return false;
+ }
+
+ offset = 0;
+ int64_t offset_to_top = data.GetMaxS64(&offset, process->GetAddressByteSize());
+
+ // So the dynamic type is a value that starts at offset_to_top
+ // above the original address.
+ lldb::addr_t dynamic_addr = original_ptr + offset_to_top;
+ if (!target->GetSectionLoadList().ResolveLoadAddress (dynamic_addr, dynamic_address))
+ {
+ dynamic_address.SetRawAddress(dynamic_addr);
+ }
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return class_type_or_name.IsEmpty() == false;
+}
+
+bool
+ItaniumABILanguageRuntime::IsVTableName (const char *name)
+{
+ if (name == NULL)
+ return false;
+
+ // Can we maybe ask Clang about this?
+ if (strstr (name, "_vptr$") == name)
+ return true;
+ else
+ return false;
+}
+
+//------------------------------------------------------------------
+// Static Functions
+//------------------------------------------------------------------
+LanguageRuntime *
+ItaniumABILanguageRuntime::CreateInstance (Process *process, lldb::LanguageType language)
+{
+ // FIXME: We have to check the process and make sure we actually know that this process supports
+ // the Itanium ABI.
+ if (language == eLanguageTypeC_plus_plus)
+ return new ItaniumABILanguageRuntime (process);
+ else
+ return NULL;
+}
+
+void
+ItaniumABILanguageRuntime::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ "Itanium ABI for the C++ language",
+ CreateInstance);
+}
+
+void
+ItaniumABILanguageRuntime::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+lldb_private::ConstString
+ItaniumABILanguageRuntime::GetPluginNameStatic()
+{
+ static ConstString g_name("itanium");
+ return g_name;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ItaniumABILanguageRuntime::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ItaniumABILanguageRuntime::GetPluginVersion()
+{
+ return 1;
+}
+
+BreakpointResolverSP
+ItaniumABILanguageRuntime::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp)
+{
+ return CreateExceptionResolver (bkpt, catch_bp, throw_bp, false);
+}
+
+BreakpointResolverSP
+ItaniumABILanguageRuntime::CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp, bool for_expressions)
+{
+ // One complication here is that most users DON'T want to stop at __cxa_allocate_expression, but until we can do
+ // anything better with predicting unwinding the expression parser does. So we have two forms of the exception
+ // breakpoints, one for expressions that leaves out __cxa_allocate_exception, and one that includes it.
+ // The SetExceptionBreakpoints does the latter, the CreateExceptionBreakpoint in the runtime the former.
+ static const char *g_catch_name = "__cxa_begin_catch";
+ static const char *g_throw_name1 = "__cxa_throw";
+ static const char *g_throw_name2 = "__cxa_rethrow";
+ static const char *g_exception_throw_name = "__cxa_allocate_exception";
+ std::vector<const char *> exception_names;
+ exception_names.reserve(4);
+ if (catch_bp)
+ exception_names.push_back(g_catch_name);
+
+ if (throw_bp)
+ {
+ exception_names.push_back(g_throw_name1);
+ exception_names.push_back(g_throw_name2);
+ }
+
+ if (for_expressions)
+ exception_names.push_back(g_exception_throw_name);
+
+ BreakpointResolverSP resolver_sp (new BreakpointResolverName (bkpt,
+ exception_names.data(),
+ exception_names.size(),
+ eFunctionNameTypeBase,
+ eLazyBoolNo));
+
+ return resolver_sp;
+}
+
+
+
+lldb::SearchFilterSP
+ItaniumABILanguageRuntime::CreateExceptionSearchFilter ()
+{
+ Target &target = m_process->GetTarget();
+
+ if (target.GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple)
+ {
+ // Limit the number of modules that are searched for these breakpoints for
+ // Apple binaries.
+ FileSpecList filter_modules;
+ filter_modules.Append(FileSpec("libc++abi.dylib", false));
+ filter_modules.Append(FileSpec("libSystem.B.dylib", false));
+ return target.GetSearchFilterForModuleList(&filter_modules);
+ }
+ else
+ {
+ return LanguageRuntime::CreateExceptionSearchFilter();
+ }
+}
+
+lldb::BreakpointSP
+ItaniumABILanguageRuntime::CreateExceptionBreakpoint (bool catch_bp,
+ bool throw_bp,
+ bool for_expressions,
+ bool is_internal)
+{
+ Target &target = m_process->GetTarget();
+ FileSpecList filter_modules;
+ BreakpointResolverSP exception_resolver_sp = CreateExceptionResolver (NULL, catch_bp, throw_bp, for_expressions);
+ SearchFilterSP filter_sp (CreateExceptionSearchFilter ());
+ return target.CreateBreakpoint (filter_sp, exception_resolver_sp, is_internal);
+}
+
+void
+ItaniumABILanguageRuntime::SetExceptionBreakpoints ()
+{
+ if (!m_process)
+ return;
+
+ const bool catch_bp = false;
+ const bool throw_bp = true;
+ const bool is_internal = true;
+ const bool for_expressions = true;
+
+ // For the exception breakpoints set by the Expression parser, we'll be a little more aggressive and
+ // stop at exception allocation as well.
+
+ if (m_cxx_exception_bp_sp)
+ {
+ m_cxx_exception_bp_sp->SetEnabled (true);
+ }
+ else
+ {
+ m_cxx_exception_bp_sp = CreateExceptionBreakpoint (catch_bp, throw_bp, for_expressions, is_internal);
+ if (m_cxx_exception_bp_sp)
+ m_cxx_exception_bp_sp->SetBreakpointKind("c++ exception");
+ }
+
+}
+
+void
+ItaniumABILanguageRuntime::ClearExceptionBreakpoints ()
+{
+ if (!m_process)
+ return;
+
+ if (m_cxx_exception_bp_sp)
+ {
+ m_cxx_exception_bp_sp->SetEnabled (false);
+ }
+}
+
+bool
+ItaniumABILanguageRuntime::ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason)
+{
+ if (!m_process)
+ return false;
+
+ if (!stop_reason ||
+ stop_reason->GetStopReason() != eStopReasonBreakpoint)
+ return false;
+
+ uint64_t break_site_id = stop_reason->GetValue();
+ return m_process->GetBreakpointSiteList().BreakpointSiteContainsBreakpoint(break_site_id,
+ m_cxx_exception_bp_sp->GetID());
+
+}
diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
new file mode 100644
index 000000000000..6b2c437de252
--- /dev/null
+++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
@@ -0,0 +1,101 @@
+//===-- ItaniumABILanguageRuntime.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ItaniumABILanguageRuntime_h_
+#define liblldb_ItaniumABILanguageRuntime_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Breakpoint/BreakpointResolver.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
+#include "lldb/Core/Value.h"
+
+namespace lldb_private {
+
+ class ItaniumABILanguageRuntime :
+ public lldb_private::CPPLanguageRuntime
+ {
+ public:
+ ~ItaniumABILanguageRuntime() { }
+
+ virtual bool
+ IsVTableName (const char *name);
+
+ virtual bool
+ GetDynamicTypeAndAddress (ValueObject &in_value,
+ lldb::DynamicValueType use_dynamic,
+ TypeAndOrName &class_type_or_name,
+ Address &address);
+
+ virtual bool
+ CouldHaveDynamicValue (ValueObject &in_value);
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::LanguageRuntime *
+ CreateInstance (Process *process, lldb::LanguageType language);
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ SetExceptionBreakpoints ();
+
+ virtual void
+ ClearExceptionBreakpoints ();
+
+ virtual bool
+ ExceptionBreakpointsExplainStop (lldb::StopInfoSP stop_reason);
+
+ virtual lldb::BreakpointResolverSP
+ CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp);
+
+ virtual lldb::SearchFilterSP
+ CreateExceptionSearchFilter ();
+
+ protected:
+
+ lldb::BreakpointResolverSP
+ CreateExceptionResolver (Breakpoint *bkpt, bool catch_bp, bool throw_bp, bool for_expressions);
+
+ lldb::BreakpointSP
+ CreateExceptionBreakpoint(bool catch_bp,
+ bool throw_bp,
+ bool for_expressions,
+ bool is_internal);
+
+ private:
+ ItaniumABILanguageRuntime(Process *process) : lldb_private::CPPLanguageRuntime(process) { } // Call CreateInstance instead.
+
+ lldb::BreakpointSP m_cxx_exception_bp_sp;
+ };
+
+} // namespace lldb_private
+
+#endif // liblldb_ItaniumABILanguageRuntime_h_
diff --git a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
new file mode 100644
index 000000000000..1ec5f3d733a0
--- /dev/null
+++ b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.cpp
@@ -0,0 +1,585 @@
+//===-- ObjectContainerBSDArchive.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjectContainerBSDArchive.h"
+
+#include <ar.h>
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+ObjectContainerBSDArchive::Object::Object() :
+ ar_name(),
+ ar_date(0),
+ ar_uid(0),
+ ar_gid(0),
+ ar_mode(0),
+ ar_size(0),
+ ar_file_offset(0),
+ ar_file_size(0)
+{
+}
+
+void
+ObjectContainerBSDArchive::Object::Clear()
+{
+ ar_name.Clear();
+ ar_date = 0;
+ ar_uid = 0;
+ ar_gid = 0;
+ ar_mode = 0;
+ ar_size = 0;
+ ar_file_offset = 0;
+ ar_file_size = 0;
+}
+
+lldb::offset_t
+ObjectContainerBSDArchive::Object::Extract (const DataExtractor& data, lldb::offset_t offset)
+{
+ size_t ar_name_len = 0;
+ std::string str;
+ char *err;
+ str.assign ((const char *)data.GetData(&offset, 16), 16);
+ if (str.find("#1/") == 0)
+ {
+ // If the name is longer than 16 bytes, or contains an embedded space
+ // then it will use this format where the length of the name is
+ // here and the name characters are after this header.
+ ar_name_len = strtoul(str.c_str() + 3, &err, 10);
+ }
+ else
+ {
+ // Strip off any spaces (if the object file name contains spaces it
+ // will use the extended format above).
+ str.erase (str.find(' '));
+ ar_name.SetCString(str.c_str());
+ }
+
+ str.assign ((const char *)data.GetData(&offset, 12), 12);
+ ar_date = strtoul(str.c_str(), &err, 10);
+
+ str.assign ((const char *)data.GetData(&offset, 6), 6);
+ ar_uid = strtoul(str.c_str(), &err, 10);
+
+ str.assign ((const char *)data.GetData(&offset, 6), 6);
+ ar_gid = strtoul(str.c_str(), &err, 10);
+
+ str.assign ((const char *)data.GetData(&offset, 8), 8);
+ ar_mode = strtoul(str.c_str(), &err, 8);
+
+ str.assign ((const char *)data.GetData(&offset, 10), 10);
+ ar_size = strtoul(str.c_str(), &err, 10);
+
+ str.assign ((const char *)data.GetData(&offset, 2), 2);
+ if (str == ARFMAG)
+ {
+ if (ar_name_len > 0)
+ {
+ str.assign ((const char *)data.GetData(&offset, ar_name_len), ar_name_len);
+ ar_name.SetCString (str.c_str());
+ }
+ ar_file_offset = offset;
+ ar_file_size = ar_size - ar_name_len;
+ return offset;
+ }
+ return LLDB_INVALID_OFFSET;
+}
+
+ObjectContainerBSDArchive::Archive::Archive
+(
+ const lldb_private::ArchSpec &arch,
+ const lldb_private::TimeValue &time,
+ lldb::offset_t file_offset,
+ lldb_private::DataExtractor &data
+) :
+ m_arch (arch),
+ m_time (time),
+ m_file_offset (file_offset),
+ m_objects(),
+ m_data (data)
+{
+}
+
+ObjectContainerBSDArchive::Archive::~Archive ()
+{
+}
+
+size_t
+ObjectContainerBSDArchive::Archive::ParseObjects ()
+{
+ DataExtractor &data = m_data;
+ std::string str;
+ lldb::offset_t offset = 0;
+ str.assign((const char *)data.GetData(&offset, SARMAG), SARMAG);
+ if (str == ARMAG)
+ {
+ Object obj;
+ do
+ {
+ offset = obj.Extract (data, offset);
+ if (offset == LLDB_INVALID_OFFSET)
+ break;
+ size_t obj_idx = m_objects.size();
+ m_objects.push_back(obj);
+ // Insert all of the C strings out of order for now...
+ m_object_name_to_index_map.Append (obj.ar_name.GetCString(), obj_idx);
+ offset += obj.ar_file_size;
+ obj.Clear();
+ } while (data.ValidOffset(offset));
+
+ // Now sort all of the object name pointers
+ m_object_name_to_index_map.Sort ();
+ }
+ return m_objects.size();
+}
+
+ObjectContainerBSDArchive::Object *
+ObjectContainerBSDArchive::Archive::FindObject (const ConstString &object_name, const TimeValue &object_mod_time)
+{
+ const ObjectNameToIndexMap::Entry *match = m_object_name_to_index_map.FindFirstValueForName (object_name.GetCString());
+ if (match)
+ {
+ if (object_mod_time.IsValid())
+ {
+ const uint64_t object_date = object_mod_time.GetAsSecondsSinceJan1_1970();
+ if (m_objects[match->value].ar_date == object_date)
+ return &m_objects[match->value];
+ const ObjectNameToIndexMap::Entry *next_match = m_object_name_to_index_map.FindNextValueForName (match);
+ while (next_match)
+ {
+ if (m_objects[next_match->value].ar_date == object_date)
+ return &m_objects[next_match->value];
+ next_match = m_object_name_to_index_map.FindNextValueForName (next_match);
+ }
+ }
+ else
+ {
+ return &m_objects[match->value];
+ }
+ }
+ return NULL;
+}
+
+
+ObjectContainerBSDArchive::Archive::shared_ptr
+ObjectContainerBSDArchive::Archive::FindCachedArchive (const FileSpec &file, const ArchSpec &arch, const TimeValue &time, lldb::offset_t file_offset)
+{
+ Mutex::Locker locker(Archive::GetArchiveCacheMutex ());
+ shared_ptr archive_sp;
+ Archive::Map &archive_map = Archive::GetArchiveCache ();
+ Archive::Map::iterator pos = archive_map.find (file);
+ // Don't cache a value for "archive_map.end()" below since we might
+ // delete an archive entry...
+ while (pos != archive_map.end() && pos->first == file)
+ {
+ bool match = true;
+ if (arch.IsValid() && pos->second->GetArchitecture().IsCompatibleMatch(arch) == false)
+ match = false;
+ else if (file_offset != LLDB_INVALID_OFFSET && pos->second->GetFileOffset() != file_offset)
+ match = false;
+ if (match)
+ {
+ if (pos->second->GetModificationTime() == time)
+ {
+ return pos->second;
+ }
+ else
+ {
+ // We have a file at the same path with the same architecture
+ // whose modification time doesn't match. It doesn't make sense
+ // for us to continue to use this BSD archive since we cache only
+ // the object info which consists of file time info and also the
+ // file offset and file size of any contianed objects. Since
+ // this information is now out of date, we won't get the correct
+ // information if we go and extract the file data, so we should
+ // remove the old and outdated entry.
+ archive_map.erase (pos);
+ pos = archive_map.find (file);
+ continue; // Continue to next iteration so we don't increment pos below...
+ }
+ }
+ ++pos;
+ }
+ return archive_sp;
+}
+
+ObjectContainerBSDArchive::Archive::shared_ptr
+ObjectContainerBSDArchive::Archive::ParseAndCacheArchiveForFile
+(
+ const FileSpec &file,
+ const ArchSpec &arch,
+ const TimeValue &time,
+ lldb::offset_t file_offset,
+ DataExtractor &data
+)
+{
+ shared_ptr archive_sp(new Archive (arch, time, file_offset, data));
+ if (archive_sp)
+ {
+ const size_t num_objects = archive_sp->ParseObjects ();
+ if (num_objects > 0)
+ {
+ Mutex::Locker locker(Archive::GetArchiveCacheMutex ());
+ Archive::GetArchiveCache().insert(std::make_pair(file, archive_sp));
+ }
+ else
+ {
+ archive_sp.reset();
+ }
+ }
+ return archive_sp;
+}
+
+ObjectContainerBSDArchive::Archive::Map &
+ObjectContainerBSDArchive::Archive::GetArchiveCache ()
+{
+ static Archive::Map g_archive_map;
+ return g_archive_map;
+}
+
+Mutex &
+ObjectContainerBSDArchive::Archive::GetArchiveCacheMutex ()
+{
+ static Mutex g_archive_map_mutex (Mutex::eMutexTypeRecursive);
+ return g_archive_map_mutex;
+}
+
+
+void
+ObjectContainerBSDArchive::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance,
+ GetModuleSpecifications);
+}
+
+void
+ObjectContainerBSDArchive::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+ObjectContainerBSDArchive::GetPluginNameStatic()
+{
+ static ConstString g_name("bsd-archive");
+ return g_name;
+}
+
+const char *
+ObjectContainerBSDArchive::GetPluginDescriptionStatic()
+{
+ return "BSD Archive object container reader.";
+}
+
+
+ObjectContainer *
+ObjectContainerBSDArchive::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)
+{
+ ConstString object_name (module_sp->GetObjectName());
+ if (object_name)
+ {
+ if (data_sp)
+ {
+ // We have data, which means this is the first 512 bytes of the file
+ // Check to see if the magic bytes match and if they do, read the entire
+ // table of contents for the archive and cache it
+ DataExtractor data;
+ data.SetData (data_sp, data_offset, length);
+ if (file && data_sp && ObjectContainerBSDArchive::MagicBytesMatch(data))
+ {
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "ObjectContainerBSDArchive::CreateInstance (module = %s, file = %p, file_offset = 0x%8.8" PRIx64 ", file_size = 0x%8.8" PRIx64 ")",
+ module_sp->GetFileSpec().GetPath().c_str(),
+ file, (uint64_t) file_offset, (uint64_t) length);
+
+ // Map the entire .a file to be sure that we don't lose any data if the file
+ // gets updated by a new build while this .a file is being used for debugging
+ DataBufferSP archive_data_sp (file->MemoryMapFileContents(file_offset, length));
+ lldb::offset_t archive_data_offset = 0;
+
+ Archive::shared_ptr archive_sp (Archive::FindCachedArchive (*file,
+ module_sp->GetArchitecture(),
+ module_sp->GetModificationTime(),
+ file_offset));
+ std::unique_ptr<ObjectContainerBSDArchive> container_ap(new ObjectContainerBSDArchive (module_sp,
+ archive_data_sp,
+ archive_data_offset,
+ file,
+ file_offset,
+ length));
+
+ if (container_ap.get())
+ {
+ if (archive_sp)
+ {
+ // We already have this archive in our cache, use it
+ container_ap->SetArchive (archive_sp);
+ return container_ap.release();
+ }
+ else if (container_ap->ParseHeader())
+ return container_ap.release();
+ }
+ }
+ }
+ else
+ {
+ // No data, just check for a cached archive
+ Archive::shared_ptr archive_sp (Archive::FindCachedArchive (*file,
+ module_sp->GetArchitecture(),
+ module_sp->GetModificationTime(),
+ file_offset));
+ if (archive_sp)
+ {
+ std::unique_ptr<ObjectContainerBSDArchive> container_ap(new ObjectContainerBSDArchive (module_sp, data_sp, data_offset, file, file_offset, length));
+
+ if (container_ap.get())
+ {
+ // We already have this archive in our cache, use it
+ container_ap->SetArchive (archive_sp);
+ return container_ap.release();
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+
+
+bool
+ObjectContainerBSDArchive::MagicBytesMatch (const DataExtractor &data)
+{
+ uint32_t offset = 0;
+ const char* armag = (const char* )data.PeekData (offset, sizeof(ar_hdr));
+ if (armag && ::strncmp(armag, ARMAG, SARMAG) == 0)
+ {
+ armag += offsetof(struct ar_hdr, ar_fmag) + SARMAG;
+ if (strncmp(armag, ARFMAG, 2) == 0)
+ return true;
+ }
+ return false;
+}
+
+ObjectContainerBSDArchive::ObjectContainerBSDArchive
+(
+ const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec *file,
+ lldb::offset_t file_offset,
+ lldb::offset_t size
+) :
+ ObjectContainer (module_sp, file, file_offset, size, data_sp, data_offset),
+ m_archive_sp ()
+{
+}
+void
+ObjectContainerBSDArchive::SetArchive (Archive::shared_ptr &archive_sp)
+{
+ m_archive_sp = archive_sp;
+}
+
+
+
+ObjectContainerBSDArchive::~ObjectContainerBSDArchive()
+{
+}
+
+bool
+ObjectContainerBSDArchive::ParseHeader ()
+{
+ if (m_archive_sp.get() == NULL)
+ {
+ if (m_data.GetByteSize() > 0)
+ {
+ ModuleSP module_sp (GetModule());
+ if (module_sp)
+ {
+ m_archive_sp = Archive::ParseAndCacheArchiveForFile (m_file,
+ module_sp->GetArchitecture(),
+ module_sp->GetModificationTime(),
+ m_offset,
+ m_data);
+ }
+ // Clear the m_data that contains the entire archive
+ // data and let our m_archive_sp hold onto the data.
+ m_data.Clear();
+ }
+ }
+ return m_archive_sp.get() != NULL;
+}
+
+void
+ObjectContainerBSDArchive::Dump (Stream *s) const
+{
+ s->Printf("%p: ", this);
+ s->Indent();
+ const size_t num_archs = GetNumArchitectures();
+ const size_t num_objects = GetNumObjects();
+ s->Printf("ObjectContainerBSDArchive, num_archs = %lu, num_objects = %lu", num_archs, num_objects);
+ uint32_t i;
+ ArchSpec arch;
+ s->IndentMore();
+ for (i=0; i<num_archs; i++)
+ {
+ s->Indent();
+ GetArchitectureAtIndex(i, arch);
+ s->Printf("arch[%u] = %s\n", i, arch.GetArchitectureName());
+ }
+ for (i=0; i<num_objects; i++)
+ {
+ s->Indent();
+ s->Printf("object[%u] = %s\n", i, GetObjectNameAtIndex (i));
+ }
+ s->IndentLess();
+ s->EOL();
+}
+
+ObjectFileSP
+ObjectContainerBSDArchive::GetObjectFile (const FileSpec *file)
+{
+ ModuleSP module_sp (GetModule());
+ if (module_sp)
+ {
+ if (module_sp->GetObjectName() && m_archive_sp)
+ {
+ Object *object = m_archive_sp->FindObject (module_sp->GetObjectName(),
+ module_sp->GetObjectModificationTime());
+ if (object)
+ {
+ lldb::offset_t data_offset = object->ar_file_offset;
+ return ObjectFile::FindPlugin (module_sp,
+ file,
+ m_offset + object->ar_file_offset,
+ object->ar_file_size,
+ m_archive_sp->GetData().GetSharedDataBuffer(),
+ data_offset);
+ }
+ }
+ }
+ return ObjectFileSP();
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ObjectContainerBSDArchive::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectContainerBSDArchive::GetPluginVersion()
+{
+ return 1;
+}
+
+
+size_t
+ObjectContainerBSDArchive::GetModuleSpecifications (const lldb_private::FileSpec& file,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ lldb::offset_t file_offset,
+ lldb::offset_t file_size,
+ lldb_private::ModuleSpecList &specs)
+{
+
+ // We have data, which means this is the first 512 bytes of the file
+ // Check to see if the magic bytes match and if they do, read the entire
+ // table of contents for the archive and cache it
+ DataExtractor data;
+ data.SetData (data_sp, data_offset, data_sp->GetByteSize());
+ if (file && data_sp && ObjectContainerBSDArchive::MagicBytesMatch(data))
+ {
+ const size_t initial_count = specs.GetSize();
+ TimeValue file_mod_time = file.GetModificationTime();
+ Archive::shared_ptr archive_sp (Archive::FindCachedArchive (file, ArchSpec(), file_mod_time, file_offset));
+ bool set_archive_arch = false;
+ if (!archive_sp)
+ {
+ set_archive_arch = true;
+ DataBufferSP data_sp (file.MemoryMapFileContents(file_offset, file_size));
+ data.SetData (data_sp, 0, data_sp->GetByteSize());
+ archive_sp = Archive::ParseAndCacheArchiveForFile(file, ArchSpec(), file_mod_time, file_offset, data);
+ }
+
+ if (archive_sp)
+ {
+ const size_t num_objects = archive_sp->GetNumObjects();
+ for (size_t idx = 0; idx < num_objects; ++idx)
+ {
+ const Object *object = archive_sp->GetObjectAtIndex (idx);
+ if (object)
+ {
+ const lldb::offset_t object_file_offset = file_offset + object->ar_file_offset;
+ if (object->ar_file_offset < file_size && file_size > object_file_offset)
+ {
+ if (ObjectFile::GetModuleSpecifications(file,
+ object_file_offset,
+ file_size - object_file_offset,
+ specs))
+ {
+ ModuleSpec &spec = specs.GetModuleSpecRefAtIndex (specs.GetSize() - 1);
+ TimeValue object_mod_time;
+ object_mod_time.OffsetWithSeconds(object->ar_date);
+ spec.GetObjectName () = object->ar_name;
+ spec.SetObjectOffset(object_file_offset);
+ spec.GetObjectModificationTime () = object_mod_time;
+ }
+ }
+ }
+ }
+ }
+ const size_t end_count = specs.GetSize();
+ size_t num_specs_added = end_count - initial_count;
+ if (set_archive_arch && num_specs_added > 0)
+ {
+ // The archive was created but we didn't have an architecture
+ // so we need to set it
+ for (size_t i=initial_count; i<end_count; ++ i)
+ {
+ ModuleSpec module_spec;
+ if (specs.GetModuleSpecAtIndex(i, module_spec))
+ {
+ if (module_spec.GetArchitecture().IsValid())
+ {
+ archive_sp->SetArchitecture (module_spec.GetArchitecture());
+ break;
+ }
+ }
+ }
+ }
+ return num_specs_added;
+ }
+ return 0;
+}
diff --git a/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
new file mode 100644
index 000000000000..8093c580ff97
--- /dev/null
+++ b/source/Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h
@@ -0,0 +1,229 @@
+//===-- ObjectContainerBSDArchive.h -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ObjectContainerBSDArchive_h_
+#define liblldb_ObjectContainerBSDArchive_h_
+
+#include "lldb/Symbol/ObjectContainer.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Host/TimeValue.h"
+
+class ObjectContainerBSDArchive :
+ public lldb_private::ObjectContainer
+{
+public:
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::ObjectContainer *
+ CreateInstance (const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec *file,
+ lldb::offset_t offset,
+ lldb::offset_t length);
+
+ static size_t
+ 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);
+
+ static bool
+ MagicBytesMatch (const lldb_private::DataExtractor &data);
+
+ //------------------------------------------------------------------
+ // Member Functions
+ //------------------------------------------------------------------
+ ObjectContainerBSDArchive (const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec *file,
+ lldb::offset_t offset,
+ lldb::offset_t length);
+
+ virtual
+ ~ObjectContainerBSDArchive();
+
+ virtual bool
+ ParseHeader ();
+
+ virtual size_t
+ GetNumObjects () const
+ {
+ if (m_archive_sp)
+ return m_archive_sp->GetNumObjects();
+ return 0;
+ }
+ virtual void
+ Dump (lldb_private::Stream *s) const;
+
+ virtual lldb::ObjectFileSP
+ GetObjectFile (const lldb_private::FileSpec *file);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+protected:
+
+ struct Object
+ {
+ Object();
+
+ void
+ Clear();
+
+ lldb::offset_t
+ Extract (const lldb_private::DataExtractor& data, lldb::offset_t offset);
+
+ lldb_private::ConstString ar_name; // name
+ uint32_t ar_date; // modification time
+ uint16_t ar_uid; // user id
+ uint16_t ar_gid; // group id
+ uint16_t ar_mode; // octal file permissions
+ uint32_t ar_size; // size in bytes
+ lldb::offset_t ar_file_offset; // file offset in bytes from the beginning of the file of the object data
+ lldb::offset_t ar_file_size; // length of the object data
+
+ typedef std::vector<Object> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+ };
+
+ class Archive
+ {
+ public:
+ typedef std::shared_ptr<Archive> shared_ptr;
+ typedef std::multimap<lldb_private::FileSpec, shared_ptr> Map;
+
+ static Map &
+ GetArchiveCache ();
+
+ static lldb_private::Mutex &
+ GetArchiveCacheMutex ();
+
+ static Archive::shared_ptr
+ FindCachedArchive (const lldb_private::FileSpec &file,
+ const lldb_private::ArchSpec &arch,
+ const lldb_private::TimeValue &mod_time,
+ lldb::offset_t file_offset);
+
+ static Archive::shared_ptr
+ ParseAndCacheArchiveForFile (const lldb_private::FileSpec &file,
+ const lldb_private::ArchSpec &arch,
+ const lldb_private::TimeValue &mod_time,
+ lldb::offset_t file_offset,
+ lldb_private::DataExtractor &data);
+
+ Archive (const lldb_private::ArchSpec &arch,
+ const lldb_private::TimeValue &mod_time,
+ lldb::offset_t file_offset,
+ lldb_private::DataExtractor &data);
+
+ ~Archive ();
+
+ size_t
+ GetNumObjects () const
+ {
+ return m_objects.size();
+ }
+
+ const Object *
+ GetObjectAtIndex (size_t idx)
+ {
+ if (idx < m_objects.size())
+ return &m_objects[idx];
+ return NULL;
+ }
+
+ size_t
+ ParseObjects ();
+
+ Object *
+ FindObject (const lldb_private::ConstString &object_name,
+ const lldb_private::TimeValue &object_mod_time);
+
+ lldb::offset_t
+ GetFileOffset () const
+ {
+ return m_file_offset;
+ }
+
+ const lldb_private::TimeValue &
+ GetModificationTime()
+ {
+ return m_time;
+ }
+
+ const lldb_private::ArchSpec &
+ GetArchitecture () const
+ {
+ return m_arch;
+ }
+
+ void
+ SetArchitecture (const lldb_private::ArchSpec &arch)
+ {
+ m_arch = arch;
+ }
+
+ bool
+ HasNoExternalReferences() const;
+
+ lldb_private::DataExtractor &
+ GetData ()
+ {
+ return m_data;
+ }
+
+ protected:
+ typedef lldb_private::UniqueCStringMap<uint32_t> ObjectNameToIndexMap;
+ //----------------------------------------------------------------------
+ // Member Variables
+ //----------------------------------------------------------------------
+ lldb_private::ArchSpec m_arch;
+ lldb_private::TimeValue m_time;
+ lldb::offset_t m_file_offset;
+ Object::collection m_objects;
+ ObjectNameToIndexMap m_object_name_to_index_map;
+ lldb_private::DataExtractor m_data; ///< The data for this object container so we don't lose data if the .a files gets modified
+ };
+
+ void
+ SetArchive (Archive::shared_ptr &archive_sp);
+
+ Archive::shared_ptr m_archive_sp;
+};
+
+#endif // liblldb_ObjectContainerBSDArchive_h_
diff --git a/source/Plugins/ObjectFile/ELF/ELFHeader.cpp b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
new file mode 100644
index 000000000000..a63a01d7ed7a
--- /dev/null
+++ b/source/Plugins/ObjectFile/ELF/ELFHeader.cpp
@@ -0,0 +1,465 @@
+//===-- ELFHeader.cpp ----------------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstring>
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Stream.h"
+
+#include "ELFHeader.h"
+
+using namespace elf;
+using namespace lldb;
+using namespace llvm::ELF;
+
+//------------------------------------------------------------------------------
+// Static utility functions.
+//
+// GetMaxU64 and GetMaxS64 wrap the similarly named methods from DataExtractor
+// with error handling code and provide for parsing a sequence of values.
+static bool
+GetMaxU64(const lldb_private::DataExtractor &data,
+ lldb::offset_t *offset,
+ uint64_t *value,
+ uint32_t byte_size)
+{
+ const lldb::offset_t saved_offset = *offset;
+ *value = data.GetMaxU64(offset, byte_size);
+ return *offset != saved_offset;
+}
+
+static bool
+GetMaxU64(const lldb_private::DataExtractor &data,
+ lldb::offset_t *offset,
+ uint64_t *value,
+ uint32_t byte_size,
+ uint32_t count)
+{
+ lldb::offset_t saved_offset = *offset;
+
+ for (uint32_t i = 0; i < count; ++i, ++value)
+ {
+ if (GetMaxU64(data, offset, value, byte_size) == false)
+ {
+ *offset = saved_offset;
+ return false;
+ }
+ }
+ return true;
+}
+
+static bool
+GetMaxS64(const lldb_private::DataExtractor &data,
+ lldb::offset_t *offset,
+ int64_t *value,
+ uint32_t byte_size)
+{
+ const lldb::offset_t saved_offset = *offset;
+ *value = data.GetMaxS64(offset, byte_size);
+ return *offset != saved_offset;
+}
+
+static bool
+GetMaxS64(const lldb_private::DataExtractor &data,
+ lldb::offset_t *offset,
+ int64_t *value,
+ uint32_t byte_size,
+ uint32_t count)
+{
+ lldb::offset_t saved_offset = *offset;
+
+ for (uint32_t i = 0; i < count; ++i, ++value)
+ {
+ if (GetMaxS64(data, offset, value, byte_size) == false)
+ {
+ *offset = saved_offset;
+ return false;
+ }
+ }
+ return true;
+}
+
+//------------------------------------------------------------------------------
+// ELFHeader
+
+ELFHeader::ELFHeader()
+{
+ memset(this, 0, sizeof(ELFHeader));
+}
+
+ByteOrder
+ELFHeader::GetByteOrder() const
+{
+ if (e_ident[EI_DATA] == ELFDATA2MSB)
+ return eByteOrderBig;
+ if (e_ident[EI_DATA] == ELFDATA2LSB)
+ return eByteOrderLittle;
+ return eByteOrderInvalid;
+}
+
+bool
+ELFHeader::Parse(lldb_private::DataExtractor &data, lldb::offset_t *offset)
+{
+ // Read e_ident. This provides byte order and address size info.
+ if (data.GetU8(offset, &e_ident, EI_NIDENT) == NULL)
+ return false;
+
+ const unsigned byte_size = Is32Bit() ? 4 : 8;
+ data.SetByteOrder(GetByteOrder());
+ data.SetAddressByteSize(byte_size);
+
+ // Read e_type and e_machine.
+ if (data.GetU16(offset, &e_type, 2) == NULL)
+ return false;
+
+ // Read e_version.
+ if (data.GetU32(offset, &e_version, 1) == NULL)
+ return false;
+
+ // Read e_entry, e_phoff and e_shoff.
+ if (GetMaxU64(data, offset, &e_entry, byte_size, 3) == false)
+ return false;
+
+ // Read e_flags.
+ if (data.GetU32(offset, &e_flags, 1) == NULL)
+ return false;
+
+ // Read e_ehsize, e_phentsize, e_phnum, e_shentsize, e_shnum and
+ // e_shstrndx.
+ if (data.GetU16(offset, &e_ehsize, 6) == NULL)
+ return false;
+
+ return true;
+}
+
+bool
+ELFHeader::MagicBytesMatch(const uint8_t *magic)
+{
+ return memcmp(magic, ElfMagic, strlen(ElfMagic)) == 0;
+}
+
+unsigned
+ELFHeader::AddressSizeInBytes(const uint8_t *magic)
+{
+ unsigned address_size = 0;
+
+ switch (magic[EI_CLASS])
+ {
+ case ELFCLASS32:
+ address_size = 4;
+ break;
+
+ case ELFCLASS64:
+ address_size = 8;
+ break;
+ }
+ return address_size;
+}
+
+unsigned
+ELFHeader::GetRelocationJumpSlotType() const
+{
+ unsigned slot = 0;
+
+ switch (e_machine)
+ {
+ default:
+ assert(false && "architecture not supported");
+ break;
+ case EM_386:
+ case EM_486:
+ slot = R_386_JUMP_SLOT;
+ break;
+ case EM_X86_64:
+ slot = R_X86_64_JUMP_SLOT;
+ break;
+ case EM_ARM:
+ slot = R_ARM_JUMP_SLOT;
+ break;
+ }
+
+ return slot;
+}
+
+//------------------------------------------------------------------------------
+// ELFSectionHeader
+
+ELFSectionHeader::ELFSectionHeader()
+{
+ memset(this, 0, sizeof(ELFSectionHeader));
+}
+
+bool
+ELFSectionHeader::Parse(const lldb_private::DataExtractor &data,
+ lldb::offset_t *offset)
+{
+ const unsigned byte_size = data.GetAddressByteSize();
+
+ // Read sh_name and sh_type.
+ if (data.GetU32(offset, &sh_name, 2) == NULL)
+ return false;
+
+ // Read sh_flags.
+ if (GetMaxU64(data, offset, &sh_flags, byte_size) == false)
+ return false;
+
+ // Read sh_addr, sh_off and sh_size.
+ if (GetMaxU64(data, offset, &sh_addr, byte_size, 3) == false)
+ return false;
+
+ // Read sh_link and sh_info.
+ if (data.GetU32(offset, &sh_link, 2) == NULL)
+ return false;
+
+ // Read sh_addralign and sh_entsize.
+ if (GetMaxU64(data, offset, &sh_addralign, byte_size, 2) == false)
+ return false;
+
+ return true;
+}
+
+//------------------------------------------------------------------------------
+// ELFSymbol
+
+ELFSymbol::ELFSymbol()
+{
+ memset(this, 0, sizeof(ELFSymbol));
+}
+
+#define ENUM_TO_CSTR(e) case e: return #e
+
+const char *
+ELFSymbol::bindingToCString(unsigned char binding)
+{
+ switch (binding)
+ {
+ ENUM_TO_CSTR(STB_LOCAL);
+ ENUM_TO_CSTR(STB_GLOBAL);
+ ENUM_TO_CSTR(STB_WEAK);
+ ENUM_TO_CSTR(STB_LOOS);
+ ENUM_TO_CSTR(STB_HIOS);
+ ENUM_TO_CSTR(STB_LOPROC);
+ ENUM_TO_CSTR(STB_HIPROC);
+ }
+ return "";
+}
+
+const char *
+ELFSymbol::typeToCString(unsigned char type)
+{
+ switch (type)
+ {
+ ENUM_TO_CSTR(STT_NOTYPE);
+ ENUM_TO_CSTR(STT_OBJECT);
+ ENUM_TO_CSTR(STT_FUNC);
+ ENUM_TO_CSTR(STT_SECTION);
+ ENUM_TO_CSTR(STT_FILE);
+ ENUM_TO_CSTR(STT_COMMON);
+ ENUM_TO_CSTR(STT_TLS);
+ ENUM_TO_CSTR(STT_LOOS);
+ ENUM_TO_CSTR(STT_HIOS);
+ ENUM_TO_CSTR(STT_GNU_IFUNC);
+ ENUM_TO_CSTR(STT_LOPROC);
+ ENUM_TO_CSTR(STT_HIPROC);
+ }
+ return "";
+}
+
+const char *
+ELFSymbol::sectionIndexToCString (elf_half shndx,
+ const lldb_private::SectionList *section_list)
+{
+ switch (shndx)
+ {
+ ENUM_TO_CSTR(SHN_UNDEF);
+ ENUM_TO_CSTR(SHN_LOPROC);
+ ENUM_TO_CSTR(SHN_HIPROC);
+ ENUM_TO_CSTR(SHN_LOOS);
+ ENUM_TO_CSTR(SHN_HIOS);
+ ENUM_TO_CSTR(SHN_ABS);
+ ENUM_TO_CSTR(SHN_COMMON);
+ ENUM_TO_CSTR(SHN_XINDEX);
+ default:
+ {
+ const lldb_private::Section *section = section_list->GetSectionAtIndex(shndx).get();
+ if (section)
+ return section->GetName().AsCString("");
+ }
+ break;
+ }
+ return "";
+}
+
+void
+ELFSymbol::Dump (lldb_private::Stream *s,
+ uint32_t idx,
+ const lldb_private::DataExtractor *strtab_data,
+ const lldb_private::SectionList *section_list)
+{
+ s->Printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 " 0x%8.8x 0x%2.2x (%-10s %-13s) 0x%2.2x 0x%4.4x (%-10s) %s\n",
+ idx,
+ st_value,
+ st_size,
+ st_name,
+ st_info,
+ bindingToCString (getBinding()),
+ typeToCString (getType()),
+ st_other,
+ st_shndx,
+ sectionIndexToCString (st_shndx, section_list),
+ strtab_data ? strtab_data->PeekCStr(st_name) : "");
+}
+
+bool
+ELFSymbol::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
+{
+ const unsigned byte_size = data.GetAddressByteSize();
+ const bool parsing_32 = byte_size == 4;
+
+ // Read st_name.
+ if (data.GetU32(offset, &st_name, 1) == NULL)
+ return false;
+
+ if (parsing_32)
+ {
+ // Read st_value and st_size.
+ if (GetMaxU64(data, offset, &st_value, byte_size, 2) == false)
+ return false;
+
+ // Read st_info and st_other.
+ if (data.GetU8(offset, &st_info, 2) == NULL)
+ return false;
+
+ // Read st_shndx.
+ if (data.GetU16(offset, &st_shndx, 1) == NULL)
+ return false;
+ }
+ else
+ {
+ // Read st_info and st_other.
+ if (data.GetU8(offset, &st_info, 2) == NULL)
+ return false;
+
+ // Read st_shndx.
+ if (data.GetU16(offset, &st_shndx, 1) == NULL)
+ return false;
+
+ // Read st_value and st_size.
+ if (data.GetU64(offset, &st_value, 2) == NULL)
+ return false;
+ }
+ return true;
+}
+
+//------------------------------------------------------------------------------
+// ELFProgramHeader
+
+ELFProgramHeader::ELFProgramHeader()
+{
+ memset(this, 0, sizeof(ELFProgramHeader));
+}
+
+bool
+ELFProgramHeader::Parse(const lldb_private::DataExtractor &data,
+ lldb::offset_t *offset)
+{
+ const uint32_t byte_size = data.GetAddressByteSize();
+ const bool parsing_32 = byte_size == 4;
+
+ // Read p_type;
+ if (data.GetU32(offset, &p_type, 1) == NULL)
+ return false;
+
+ if (parsing_32) {
+ // Read p_offset, p_vaddr, p_paddr, p_filesz and p_memsz.
+ if (GetMaxU64(data, offset, &p_offset, byte_size, 5) == false)
+ return false;
+
+ // Read p_flags.
+ if (data.GetU32(offset, &p_flags, 1) == NULL)
+ return false;
+
+ // Read p_align.
+ if (GetMaxU64(data, offset, &p_align, byte_size) == false)
+ return false;
+ }
+ else {
+ // Read p_flags.
+ if (data.GetU32(offset, &p_flags, 1) == NULL)
+ return false;
+
+ // Read p_offset, p_vaddr, p_paddr, p_filesz, p_memsz and p_align.
+ if (GetMaxU64(data, offset, &p_offset, byte_size, 6) == false)
+ return false;
+ }
+
+ return true;
+}
+
+//------------------------------------------------------------------------------
+// ELFDynamic
+
+ELFDynamic::ELFDynamic()
+{
+ memset(this, 0, sizeof(ELFDynamic));
+}
+
+bool
+ELFDynamic::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
+{
+ const unsigned byte_size = data.GetAddressByteSize();
+ return GetMaxS64(data, offset, &d_tag, byte_size, 2);
+}
+
+//------------------------------------------------------------------------------
+// ELFRel
+
+ELFRel::ELFRel()
+{
+ memset(this, 0, sizeof(ELFRel));
+}
+
+bool
+ELFRel::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
+{
+ const unsigned byte_size = data.GetAddressByteSize();
+
+ // Read r_offset and r_info.
+ if (GetMaxU64(data, offset, &r_offset, byte_size, 2) == false)
+ return false;
+
+ return true;
+}
+
+//------------------------------------------------------------------------------
+// ELFRela
+
+ELFRela::ELFRela()
+{
+ memset(this, 0, sizeof(ELFRela));
+}
+
+bool
+ELFRela::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
+{
+ const unsigned byte_size = data.GetAddressByteSize();
+
+ // Read r_offset and r_info.
+ if (GetMaxU64(data, offset, &r_offset, byte_size, 2) == false)
+ return false;
+
+ // Read r_addend;
+ if (GetMaxS64(data, offset, &r_addend, byte_size) == false)
+ return false;
+
+ return true;
+}
+
+
diff --git a/source/Plugins/ObjectFile/ELF/ELFHeader.h b/source/Plugins/ObjectFile/ELF/ELFHeader.h
new file mode 100644
index 000000000000..aa2c16b6168c
--- /dev/null
+++ b/source/Plugins/ObjectFile/ELF/ELFHeader.h
@@ -0,0 +1,433 @@
+//===-- ELFHeader.h ------------------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+/// @file
+/// @brief Generic structures and typedefs for ELF files.
+///
+/// This file provides definitions for the various entities comprising an ELF
+/// file. The structures are generic in the sense that they do not correspond
+/// to the exact binary layout of an ELF, but can be used to hold the
+/// information present in both 32 and 64 bit variants of the format. Each
+/// entity provides a \c Parse method which is capable of transparently reading
+/// both 32 and 64 bit instances of the object.
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ELFHeader_h_
+#define liblldb_ELFHeader_h_
+
+#include "llvm/Support/ELF.h"
+
+#include "lldb/lldb-enumerations.h"
+
+namespace lldb_private
+{
+class DataExtractor;
+} // End namespace lldb_private.
+
+namespace elf
+{
+
+//------------------------------------------------------------------------------
+/// @name ELF type definitions.
+///
+/// Types used to represent the various components of ELF structures. All types
+/// are signed or unsigned integral types wide enough to hold values from both
+/// 32 and 64 bit ELF variants.
+//@{
+typedef uint64_t elf_addr;
+typedef uint64_t elf_off;
+typedef uint16_t elf_half;
+typedef uint32_t elf_word;
+typedef int32_t elf_sword;
+typedef uint64_t elf_size;
+typedef uint64_t elf_xword;
+typedef int64_t elf_sxword;
+//@}
+
+//------------------------------------------------------------------------------
+/// @class ELFHeader
+/// @brief Generic representation of an ELF file header.
+///
+/// This object is used to identify the general attributes on an ELF file and to
+/// locate additional sections within the file.
+struct ELFHeader
+{
+ unsigned char e_ident[llvm::ELF::EI_NIDENT]; ///< ELF file identification.
+ elf_addr e_entry; ///< Virtual address program entry point.
+ elf_off e_phoff; ///< File offset of program header table.
+ elf_off e_shoff; ///< File offset of section header table.
+ elf_word e_flags; ///< Processor specific flags.
+ elf_word e_version; ///< Version of object file (always 1).
+ elf_half e_type; ///< Object file type.
+ elf_half e_machine; ///< Target architecture.
+ elf_half e_ehsize; ///< Byte size of the ELF header.
+ elf_half e_phentsize; ///< Size of a program header table entry.
+ elf_half e_phnum; ///< Number of program header entries.
+ elf_half e_shentsize; ///< Size of a section header table entry.
+ elf_half e_shnum; ///< Number of section header entries.
+ elf_half e_shstrndx; ///< String table section index.
+
+ ELFHeader();
+
+ //--------------------------------------------------------------------------
+ /// Returns true if this is a 32 bit ELF file header.
+ ///
+ /// @return
+ /// True if this is a 32 bit ELF file header.
+ bool Is32Bit() const {
+ return e_ident[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS32;
+ }
+
+ //--------------------------------------------------------------------------
+ /// Returns true if this is a 64 bit ELF file header.
+ ///
+ /// @return
+ /// True if this is a 64 bit ELF file header.
+ bool Is64Bit() const {
+ return e_ident[llvm::ELF::EI_CLASS] == llvm::ELF::ELFCLASS64;
+ }
+
+ //--------------------------------------------------------------------------
+ /// The byte order of this ELF file header.
+ ///
+ /// @return
+ /// The byte order of this ELF file as described by the header.
+ lldb::ByteOrder
+ GetByteOrder() const;
+
+ //--------------------------------------------------------------------------
+ /// The jump slot relocation type of this ELF.
+ unsigned
+ GetRelocationJumpSlotType() const;
+
+ //--------------------------------------------------------------------------
+ /// Parse an ELFHeader entry starting at position \p offset and
+ /// update the data extractor with the address size and byte order
+ /// attributes as defined by the header.
+ ///
+ /// @param[in,out] data
+ /// The DataExtractor to read from. Updated with the address size and
+ /// byte order attributes appropriate to this header.
+ ///
+ /// @param[in,out] offset
+ /// Pointer to an offset in the data. On return the offset will be
+ /// advanced by the number of bytes read.
+ ///
+ /// @return
+ /// True if the ELFHeader was successfully read and false
+ /// otherwise.
+ bool
+ Parse(lldb_private::DataExtractor &data, lldb::offset_t *offset);
+
+ //--------------------------------------------------------------------------
+ /// Examines at most EI_NIDENT bytes starting from the given pointer and
+ /// determines if the magic ELF identification exists.
+ ///
+ /// @return
+ /// True if the given sequence of bytes identifies an ELF file.
+ static bool
+ MagicBytesMatch(const uint8_t *magic);
+
+ //--------------------------------------------------------------------------
+ /// Examines at most EI_NIDENT bytes starting from the given address and
+ /// determines the address size of the underlying ELF file. This function
+ /// should only be called on an pointer for which MagicBytesMatch returns
+ /// true.
+ ///
+ /// @return
+ /// The number of bytes forming an address in the ELF file (either 4 or
+ /// 8), else zero if the address size could not be determined.
+ static unsigned
+ AddressSizeInBytes(const uint8_t *magic);
+};
+
+//------------------------------------------------------------------------------
+/// @class ELFSectionHeader
+/// @brief Generic representation of an ELF section header.
+struct ELFSectionHeader
+{
+ elf_word sh_name; ///< Section name string index.
+ elf_word sh_type; ///< Section type.
+ elf_xword sh_flags; ///< Section attributes.
+ elf_addr sh_addr; ///< Virtual address of the section in memory.
+ elf_off sh_offset; ///< Start of section from beginning of file.
+ elf_xword sh_size; ///< Number of bytes occupied in the file.
+ elf_word sh_link; ///< Index of associated section.
+ elf_word sh_info; ///< Extra section info (overloaded).
+ elf_xword sh_addralign; ///< Power of two alignment constraint.
+ elf_xword sh_entsize; ///< Byte size of each section entry.
+
+ ELFSectionHeader();
+
+ //--------------------------------------------------------------------------
+ /// Parse an ELFSectionHeader entry from the given DataExtracter starting at
+ /// position \p offset.
+ ///
+ /// @param[in] data
+ /// The DataExtractor to read from. The address size of the extractor
+ /// determines if a 32 or 64 bit object should be read.
+ ///
+ /// @param[in,out] offset
+ /// Pointer to an offset in the data. On return the offset will be
+ /// advanced by the number of bytes read.
+ ///
+ /// @return
+ /// True if the ELFSectionHeader was successfully read and false
+ /// otherwise.
+ bool
+ Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
+};
+
+//------------------------------------------------------------------------------
+/// @class ELFProgramHeader
+/// @brief Generic representation of an ELF program header.
+struct ELFProgramHeader
+{
+ elf_word p_type; ///< Type of program segment.
+ elf_word p_flags; ///< Segment attributes.
+ elf_off p_offset; ///< Start of segment from beginning of file.
+ elf_addr p_vaddr; ///< Virtual address of segment in memory.
+ elf_addr p_paddr; ///< Physical address (for non-VM systems).
+ elf_xword p_filesz; ///< Byte size of the segment in file.
+ elf_xword p_memsz; ///< Byte size of the segment in memory.
+ elf_xword p_align; ///< Segment alignment constraint.
+
+ ELFProgramHeader();
+
+ /// Parse an ELFProgramHeader entry from the given DataExtractor starting at
+ /// position \p offset. The address size of the DataExtractor determines if
+ /// a 32 or 64 bit object is to be parsed.
+ ///
+ /// @param[in] data
+ /// The DataExtractor to read from. The address size of the extractor
+ /// determines if a 32 or 64 bit object should be read.
+ ///
+ /// @param[in,out] offset
+ /// Pointer to an offset in the data. On return the offset will be
+ /// advanced by the number of bytes read.
+ ///
+ /// @return
+ /// True if the ELFProgramHeader was successfully read and false
+ /// otherwise.
+ bool
+ Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
+};
+
+//------------------------------------------------------------------------------
+/// @class ELFSymbol
+/// @brief Represents a symbol within an ELF symbol table.
+struct ELFSymbol
+{
+ elf_addr st_value; ///< Absolute or relocatable address.
+ elf_xword st_size; ///< Size of the symbol or zero.
+ elf_word st_name; ///< Symbol name string index.
+ unsigned char st_info; ///< Symbol type and binding attributes.
+ unsigned char st_other; ///< Reserved for future use.
+ elf_half st_shndx; ///< Section to which this symbol applies.
+
+ ELFSymbol();
+
+ /// Returns the binding attribute of the st_info member.
+ unsigned char getBinding() const { return st_info >> 4; }
+
+ /// Returns the type attribute of the st_info member.
+ unsigned char getType() const { return st_info & 0x0F; }
+
+ /// Sets the binding and type of the st_info member.
+ void setBindingAndType(unsigned char binding, unsigned char type) {
+ st_info = (binding << 4) + (type & 0x0F);
+ }
+
+ static const char *
+ bindingToCString(unsigned char binding);
+
+ static const char *
+ typeToCString(unsigned char type);
+
+ static const char *
+ sectionIndexToCString(elf_half shndx,
+ const lldb_private::SectionList *section_list);
+
+ /// Parse an ELFSymbol entry from the given DataExtractor starting at
+ /// position \p offset. The address size of the DataExtractor determines if
+ /// a 32 or 64 bit object is to be parsed.
+ ///
+ /// @param[in] data
+ /// The DataExtractor to read from. The address size of the extractor
+ /// determines if a 32 or 64 bit object should be read.
+ ///
+ /// @param[in,out] offset
+ /// Pointer to an offset in the data. On return the offset will be
+ /// advanced by the number of bytes read.
+ ///
+ /// @return
+ /// True if the ELFSymbol was successfully read and false otherwise.
+ bool
+ Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
+
+ void
+ Dump (lldb_private::Stream *s,
+ uint32_t idx,
+ const lldb_private::DataExtractor *strtab_data,
+ const lldb_private::SectionList *section_list);
+};
+
+//------------------------------------------------------------------------------
+/// @class ELFDynamic
+/// @brief Represents an entry in an ELF dynamic table.
+struct ELFDynamic
+{
+ elf_sxword d_tag; ///< Type of dynamic table entry.
+ union
+ {
+ elf_xword d_val; ///< Integer value of the table entry.
+ elf_addr d_ptr; ///< Pointer value of the table entry.
+ };
+
+ ELFDynamic();
+
+ /// Parse an ELFDynamic entry from the given DataExtractor starting at
+ /// position \p offset. The address size of the DataExtractor determines if
+ /// a 32 or 64 bit object is to be parsed.
+ ///
+ /// @param[in] data
+ /// The DataExtractor to read from. The address size of the extractor
+ /// determines if a 32 or 64 bit object should be read.
+ ///
+ /// @param[in,out] offset
+ /// Pointer to an offset in the data. On return the offset will be
+ /// advanced by the number of bytes read.
+ ///
+ /// @return
+ /// True if the ELFDynamic entry was successfully read and false
+ /// otherwise.
+ bool
+ Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
+};
+
+//------------------------------------------------------------------------------
+/// @class ELFRel
+/// @brief Represents a relocation entry with an implicit addend.
+struct ELFRel
+{
+ elf_addr r_offset; ///< Address of reference.
+ elf_xword r_info; ///< symbol index and type of relocation.
+
+ ELFRel();
+
+ /// Parse an ELFRel entry from the given DataExtractor starting at position
+ /// \p offset. The address size of the DataExtractor determines if a 32 or
+ /// 64 bit object is to be parsed.
+ ///
+ /// @param[in] data
+ /// The DataExtractor to read from. The address size of the extractor
+ /// determines if a 32 or 64 bit object should be read.
+ ///
+ /// @param[in,out] offset
+ /// Pointer to an offset in the data. On return the offset will be
+ /// advanced by the number of bytes read.
+ ///
+ /// @return
+ /// True if the ELFRel entry was successfully read and false otherwise.
+ bool
+ Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
+
+ /// Returns the type when the given entry represents a 32-bit relocation.
+ static unsigned
+ RelocType32(const ELFRel &rel)
+ {
+ return rel.r_info & 0x0ff;
+ }
+
+ /// Returns the type when the given entry represents a 64-bit relocation.
+ static unsigned
+ RelocType64(const ELFRel &rel)
+ {
+ return rel.r_info & 0xffffffff;
+ }
+
+ /// Returns the symbol index when the given entry represents a 32-bit
+ /// reloction.
+ static unsigned
+ RelocSymbol32(const ELFRel &rel)
+ {
+ return rel.r_info >> 8;
+ }
+
+ /// Returns the symbol index when the given entry represents a 64-bit
+ /// reloction.
+ static unsigned
+ RelocSymbol64(const ELFRel &rel)
+ {
+ return rel.r_info >> 32;
+ }
+};
+
+//------------------------------------------------------------------------------
+/// @class ELFRela
+/// @brief Represents a relocation entry with an explicit addend.
+struct ELFRela
+{
+ elf_addr r_offset; ///< Address of reference.
+ elf_xword r_info; ///< Symbol index and type of relocation.
+ elf_sxword r_addend; ///< Constant part of expression.
+
+ ELFRela();
+
+ /// Parse an ELFRela entry from the given DataExtractor starting at position
+ /// \p offset. The address size of the DataExtractor determines if a 32 or
+ /// 64 bit object is to be parsed.
+ ///
+ /// @param[in] data
+ /// The DataExtractor to read from. The address size of the extractor
+ /// determines if a 32 or 64 bit object should be read.
+ ///
+ /// @param[in,out] offset
+ /// Pointer to an offset in the data. On return the offset will be
+ /// advanced by the number of bytes read.
+ ///
+ /// @return
+ /// True if the ELFRela entry was successfully read and false otherwise.
+ bool
+ Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
+
+ /// Returns the type when the given entry represents a 32-bit relocation.
+ static unsigned
+ RelocType32(const ELFRela &rela)
+ {
+ return rela.r_info & 0x0ff;
+ }
+
+ /// Returns the type when the given entry represents a 64-bit relocation.
+ static unsigned
+ RelocType64(const ELFRela &rela)
+ {
+ return rela.r_info & 0xffffffff;
+ }
+
+ /// Returns the symbol index when the given entry represents a 32-bit
+ /// reloction.
+ static unsigned
+ RelocSymbol32(const ELFRela &rela)
+ {
+ return rela.r_info >> 8;
+ }
+
+ /// Returns the symbol index when the given entry represents a 64-bit
+ /// reloction.
+ static unsigned
+ RelocSymbol64(const ELFRela &rela)
+ {
+ return rela.r_info >> 32;
+ }
+};
+
+} // End namespace elf.
+
+#endif // #ifndef liblldb_ELFHeader_h_
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
new file mode 100644
index 000000000000..2e9f6903280c
--- /dev/null
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.cpp
@@ -0,0 +1,1893 @@
+//===-- ObjectFileELF.cpp ------------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ObjectFileELF.h"
+
+#include <cassert>
+#include <algorithm>
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBuffer.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Host/Host.h"
+
+#include "llvm/ADT/PointerUnion.h"
+
+#define CASE_AND_STREAM(s, def, width) \
+ case def: s->Printf("%-*s", width, #def); break;
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace elf;
+using namespace llvm::ELF;
+
+namespace {
+//===----------------------------------------------------------------------===//
+/// @class ELFRelocation
+/// @brief Generic wrapper for ELFRel and ELFRela.
+///
+/// This helper class allows us to parse both ELFRel and ELFRela relocation
+/// entries in a generic manner.
+class ELFRelocation
+{
+public:
+
+ /// Constructs an ELFRelocation entry with a personality as given by @p
+ /// type.
+ ///
+ /// @param type Either DT_REL or DT_RELA. Any other value is invalid.
+ ELFRelocation(unsigned type);
+
+ ~ELFRelocation();
+
+ bool
+ Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset);
+
+ static unsigned
+ RelocType32(const ELFRelocation &rel);
+
+ static unsigned
+ RelocType64(const ELFRelocation &rel);
+
+ static unsigned
+ RelocSymbol32(const ELFRelocation &rel);
+
+ static unsigned
+ RelocSymbol64(const ELFRelocation &rel);
+
+private:
+ typedef llvm::PointerUnion<ELFRel*, ELFRela*> RelocUnion;
+
+ RelocUnion reloc;
+};
+
+ELFRelocation::ELFRelocation(unsigned type)
+{
+ if (type == DT_REL)
+ reloc = new ELFRel();
+ else if (type == DT_RELA)
+ reloc = new ELFRela();
+ else {
+ assert(false && "unexpected relocation type");
+ reloc = static_cast<ELFRel*>(NULL);
+ }
+}
+
+ELFRelocation::~ELFRelocation()
+{
+ if (reloc.is<ELFRel*>())
+ delete reloc.get<ELFRel*>();
+ else
+ delete reloc.get<ELFRela*>();
+}
+
+bool
+ELFRelocation::Parse(const lldb_private::DataExtractor &data, lldb::offset_t *offset)
+{
+ if (reloc.is<ELFRel*>())
+ return reloc.get<ELFRel*>()->Parse(data, offset);
+ else
+ return reloc.get<ELFRela*>()->Parse(data, offset);
+}
+
+unsigned
+ELFRelocation::RelocType32(const ELFRelocation &rel)
+{
+ if (rel.reloc.is<ELFRel*>())
+ return ELFRel::RelocType32(*rel.reloc.get<ELFRel*>());
+ else
+ return ELFRela::RelocType32(*rel.reloc.get<ELFRela*>());
+}
+
+unsigned
+ELFRelocation::RelocType64(const ELFRelocation &rel)
+{
+ if (rel.reloc.is<ELFRel*>())
+ return ELFRel::RelocType64(*rel.reloc.get<ELFRel*>());
+ else
+ return ELFRela::RelocType64(*rel.reloc.get<ELFRela*>());
+}
+
+unsigned
+ELFRelocation::RelocSymbol32(const ELFRelocation &rel)
+{
+ if (rel.reloc.is<ELFRel*>())
+ return ELFRel::RelocSymbol32(*rel.reloc.get<ELFRel*>());
+ else
+ return ELFRela::RelocSymbol32(*rel.reloc.get<ELFRela*>());
+}
+
+unsigned
+ELFRelocation::RelocSymbol64(const ELFRelocation &rel)
+{
+ if (rel.reloc.is<ELFRel*>())
+ return ELFRel::RelocSymbol64(*rel.reloc.get<ELFRel*>());
+ else
+ return ELFRela::RelocSymbol64(*rel.reloc.get<ELFRela*>());
+}
+
+} // end anonymous namespace
+
+//------------------------------------------------------------------
+// Static methods.
+//------------------------------------------------------------------
+void
+ObjectFileELF::Initialize()
+{
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance,
+ CreateMemoryInstance,
+ GetModuleSpecifications);
+}
+
+void
+ObjectFileELF::Terminate()
+{
+ PluginManager::UnregisterPlugin(CreateInstance);
+}
+
+lldb_private::ConstString
+ObjectFileELF::GetPluginNameStatic()
+{
+ static ConstString g_name("elf");
+ return g_name;
+}
+
+const char *
+ObjectFileELF::GetPluginDescriptionStatic()
+{
+ return "ELF object file reader.";
+}
+
+ObjectFile *
+ObjectFileELF::CreateInstance (const lldb::ModuleSP &module_sp,
+ DataBufferSP &data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec* file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length)
+{
+ if (!data_sp)
+ {
+ data_sp = file->MemoryMapFileContents(file_offset, length);
+ data_offset = 0;
+ }
+
+ if (data_sp && data_sp->GetByteSize() > (llvm::ELF::EI_NIDENT + data_offset))
+ {
+ const uint8_t *magic = data_sp->GetBytes() + data_offset;
+ if (ELFHeader::MagicBytesMatch(magic))
+ {
+ // Update the data to contain the entire file if it doesn't already
+ if (data_sp->GetByteSize() < length) {
+ data_sp = file->MemoryMapFileContents(file_offset, length);
+ data_offset = 0;
+ magic = data_sp->GetBytes();
+ }
+ unsigned address_size = ELFHeader::AddressSizeInBytes(magic);
+ if (address_size == 4 || address_size == 8)
+ {
+ std::unique_ptr<ObjectFileELF> objfile_ap(new ObjectFileELF(module_sp, data_sp, data_offset, file, file_offset, length));
+ ArchSpec spec;
+ if (objfile_ap->GetArchitecture(spec) &&
+ objfile_ap->SetModulesArchitecture(spec))
+ return objfile_ap.release();
+ }
+ }
+ }
+ return NULL;
+}
+
+
+ObjectFile*
+ObjectFileELF::CreateMemoryInstance (const lldb::ModuleSP &module_sp,
+ DataBufferSP& data_sp,
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr)
+{
+ return NULL;
+}
+
+bool
+ObjectFileELF::MagicBytesMatch (DataBufferSP& data_sp,
+ lldb::addr_t data_offset,
+ lldb::addr_t data_length)
+{
+ if (data_sp && data_sp->GetByteSize() > (llvm::ELF::EI_NIDENT + data_offset))
+ {
+ const uint8_t *magic = data_sp->GetBytes() + data_offset;
+ return ELFHeader::MagicBytesMatch(magic);
+ }
+ return false;
+}
+
+/*
+ * crc function from http://svnweb.freebsd.org/base/head/sys/libkern/crc32.c
+ *
+ * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or
+ * code or tables extracted from it, as desired without restriction.
+ */
+static uint32_t
+calc_gnu_debuglink_crc32(const void *buf, size_t size)
+{
+ static const uint32_t g_crc32_tab[] =
+ {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+ 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+ 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+ 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+ 0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+ 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+ 0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+ 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+ 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+ 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+ 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+ 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+ 0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+ 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+ 0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+ 0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+ 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+ 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+ };
+ const uint8_t *p = (const uint8_t *)buf;
+ uint32_t crc;
+
+ crc = ~0U;
+ while (size--)
+ crc = g_crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
+ return crc ^ ~0U;
+}
+
+size_t
+ObjectFileELF::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 (ObjectFileELF::MagicBytesMatch(data_sp, 0, data_sp->GetByteSize()))
+ {
+ DataExtractor data;
+ data.SetData(data_sp);
+ elf::ELFHeader header;
+ if (header.Parse(data, &data_offset))
+ {
+ if (data_sp)
+ {
+ ModuleSpec spec;
+ spec.GetFileSpec() = file;
+ spec.GetArchitecture().SetArchitecture(eArchTypeELF,
+ header.e_machine,
+ LLDB_INVALID_CPUTYPE);
+ if (spec.GetArchitecture().IsValid())
+ {
+ // We could parse the ABI tag information (in .note, .notes, or .note.ABI-tag) to get the
+ // machine information. However, this info isn't guaranteed to exist or be correct. Details:
+ // http://refspecs.linuxfoundation.org/LSB_1.2.0/gLSB/noteabitag.html
+ // Instead of passing potentially incorrect information down the pipeline, grab
+ // the host information and use it.
+ spec.GetArchitecture().GetTriple().setOSName (Host::GetOSString().GetCString());
+ spec.GetArchitecture().GetTriple().setVendorName(Host::GetVendorString().GetCString());
+
+ // Try to get the UUID from the section list. Usually that's at the end, so
+ // map the file in if we don't have it already.
+ size_t section_header_end = header.e_shoff + header.e_shnum * header.e_shentsize;
+ if (section_header_end > data_sp->GetByteSize())
+ {
+ data_sp = file.MemoryMapFileContents (file_offset, section_header_end);
+ data.SetData(data_sp);
+ }
+
+ uint32_t gnu_debuglink_crc = 0;
+ std::string gnu_debuglink_file;
+ SectionHeaderColl section_headers;
+ lldb_private::UUID &uuid = spec.GetUUID();
+ GetSectionHeaderInfo(section_headers, data, header, uuid, gnu_debuglink_file, gnu_debuglink_crc);
+
+ if (!uuid.IsValid())
+ {
+ if (!gnu_debuglink_crc)
+ {
+ // Need to map entire file into memory to calculate the crc.
+ data_sp = file.MemoryMapFileContents (file_offset, SIZE_MAX);
+ data.SetData(data_sp);
+ gnu_debuglink_crc = calc_gnu_debuglink_crc32 (data.GetDataStart(), data.GetByteSize());
+ }
+ if (gnu_debuglink_crc)
+ {
+ // Use 4 bytes of crc from the .gnu_debuglink section.
+ uint32_t uuidt[4] = { gnu_debuglink_crc, 0, 0, 0 };
+ uuid.SetBytes (uuidt, sizeof(uuidt));
+ }
+ }
+
+ specs.Append(spec);
+ }
+ }
+ }
+ }
+
+ return specs.GetSize() - initial_count;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+ObjectFileELF::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ObjectFileELF::GetPluginVersion()
+{
+ return m_plugin_version;
+}
+//------------------------------------------------------------------
+// ObjectFile protocol
+//------------------------------------------------------------------
+
+ObjectFileELF::ObjectFileELF (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) :
+ ObjectFile(module_sp, file, file_offset, length, data_sp, data_offset),
+ m_header(),
+ m_program_headers(),
+ m_section_headers(),
+ m_filespec_ap()
+{
+ if (file)
+ m_file = *file;
+ ::memset(&m_header, 0, sizeof(m_header));
+ m_gnu_debuglink_crc = 0;
+ m_gnu_debuglink_file.clear();
+}
+
+ObjectFileELF::~ObjectFileELF()
+{
+}
+
+bool
+ObjectFileELF::IsExecutable() const
+{
+ return m_header.e_entry != 0;
+}
+
+ByteOrder
+ObjectFileELF::GetByteOrder() const
+{
+ if (m_header.e_ident[EI_DATA] == ELFDATA2MSB)
+ return eByteOrderBig;
+ if (m_header.e_ident[EI_DATA] == ELFDATA2LSB)
+ return eByteOrderLittle;
+ return eByteOrderInvalid;
+}
+
+uint32_t
+ObjectFileELF::GetAddressByteSize() const
+{
+ return m_data.GetAddressByteSize();
+}
+
+size_t
+ObjectFileELF::SectionIndex(const SectionHeaderCollIter &I)
+{
+ return std::distance(m_section_headers.begin(), I) + 1u;
+}
+
+size_t
+ObjectFileELF::SectionIndex(const SectionHeaderCollConstIter &I) const
+{
+ return std::distance(m_section_headers.begin(), I) + 1u;
+}
+
+bool
+ObjectFileELF::ParseHeader()
+{
+ lldb::offset_t offset = 0;
+ return m_header.Parse(m_data, &offset);
+}
+
+bool
+ObjectFileELF::GetUUID(lldb_private::UUID* uuid)
+{
+ // Need to parse the section list to get the UUIDs, so make sure that's been done.
+ if (!ParseSectionHeaders())
+ return false;
+
+ if (m_uuid.IsValid())
+ {
+ // We have the full build id uuid.
+ *uuid = m_uuid;
+ return true;
+ }
+ else
+ {
+ if (!m_gnu_debuglink_crc)
+ m_gnu_debuglink_crc = calc_gnu_debuglink_crc32 (m_data.GetDataStart(), m_data.GetByteSize());
+ if (m_gnu_debuglink_crc)
+ {
+ // Use 4 bytes of crc from the .gnu_debuglink section.
+ uint32_t uuidt[4] = { m_gnu_debuglink_crc, 0, 0, 0 };
+ uuid->SetBytes (uuidt, sizeof(uuidt));
+ return true;
+ }
+ }
+
+ return false;
+}
+
+lldb_private::FileSpecList
+ObjectFileELF::GetDebugSymbolFilePaths()
+{
+ FileSpecList file_spec_list;
+
+ if (!m_gnu_debuglink_file.empty())
+ {
+ FileSpec file_spec (m_gnu_debuglink_file.c_str(), false);
+ file_spec_list.Append (file_spec);
+ }
+ return file_spec_list;
+}
+
+uint32_t
+ObjectFileELF::GetDependentModules(FileSpecList &files)
+{
+ size_t num_modules = ParseDependentModules();
+ uint32_t num_specs = 0;
+
+ for (unsigned i = 0; i < num_modules; ++i)
+ {
+ if (files.AppendIfUnique(m_filespec_ap->GetFileSpecAtIndex(i)))
+ num_specs++;
+ }
+
+ return num_specs;
+}
+
+Address
+ObjectFileELF::GetImageInfoAddress()
+{
+ if (!ParseDynamicSymbols())
+ return Address();
+
+ SectionList *section_list = GetSectionList();
+ if (!section_list)
+ return Address();
+
+ // Find the SHT_DYNAMIC (.dynamic) section.
+ SectionSP dynsym_section_sp (section_list->FindSectionByType (eSectionTypeELFDynamicLinkInfo, true));
+ if (!dynsym_section_sp)
+ return Address();
+ assert (dynsym_section_sp->GetObjectFile() == this);
+
+ user_id_t dynsym_id = dynsym_section_sp->GetID();
+ const ELFSectionHeaderInfo *dynsym_hdr = GetSectionHeaderByIndex(dynsym_id);
+ if (!dynsym_hdr)
+ return Address();
+
+ for (size_t i = 0; i < m_dynamic_symbols.size(); ++i)
+ {
+ ELFDynamic &symbol = m_dynamic_symbols[i];
+
+ if (symbol.d_tag == DT_DEBUG)
+ {
+ // Compute the offset as the number of previous entries plus the
+ // size of d_tag.
+ addr_t offset = i * dynsym_hdr->sh_entsize + GetAddressByteSize();
+ return Address(dynsym_section_sp, offset);
+ }
+ }
+
+ return Address();
+}
+
+lldb_private::Address
+ObjectFileELF::GetEntryPointAddress ()
+{
+ if (m_entry_point_address.IsValid())
+ return m_entry_point_address;
+
+ if (!ParseHeader() || !IsExecutable())
+ return m_entry_point_address;
+
+ SectionList *section_list = GetSectionList();
+ addr_t offset = m_header.e_entry;
+
+ if (!section_list)
+ m_entry_point_address.SetOffset(offset);
+ else
+ m_entry_point_address.ResolveAddressUsingFileSections(offset, section_list);
+ return m_entry_point_address;
+}
+
+//----------------------------------------------------------------------
+// ParseDependentModules
+//----------------------------------------------------------------------
+size_t
+ObjectFileELF::ParseDependentModules()
+{
+ if (m_filespec_ap.get())
+ return m_filespec_ap->GetSize();
+
+ m_filespec_ap.reset(new FileSpecList());
+
+ if (!ParseSectionHeaders())
+ return 0;
+
+ SectionList *section_list = GetSectionList();
+ if (!section_list)
+ return 0;
+
+ // Find the SHT_DYNAMIC section.
+ Section *dynsym = section_list->FindSectionByType (eSectionTypeELFDynamicLinkInfo, true).get();
+ if (!dynsym)
+ return 0;
+ assert (dynsym->GetObjectFile() == this);
+
+ const ELFSectionHeaderInfo *header = GetSectionHeaderByIndex (dynsym->GetID());
+ if (!header)
+ return 0;
+ // sh_link: section header index of string table used by entries in the section.
+ Section *dynstr = section_list->FindSectionByID (header->sh_link + 1).get();
+ if (!dynstr)
+ return 0;
+
+ DataExtractor dynsym_data;
+ DataExtractor dynstr_data;
+ if (ReadSectionData(dynsym, dynsym_data) &&
+ ReadSectionData(dynstr, dynstr_data))
+ {
+ ELFDynamic symbol;
+ const lldb::offset_t section_size = dynsym_data.GetByteSize();
+ lldb::offset_t offset = 0;
+
+ // The only type of entries we are concerned with are tagged DT_NEEDED,
+ // yielding the name of a required library.
+ while (offset < section_size)
+ {
+ if (!symbol.Parse(dynsym_data, &offset))
+ break;
+
+ if (symbol.d_tag != DT_NEEDED)
+ continue;
+
+ uint32_t str_index = static_cast<uint32_t>(symbol.d_val);
+ const char *lib_name = dynstr_data.PeekCStr(str_index);
+ m_filespec_ap->Append(FileSpec(lib_name, true));
+ }
+ }
+
+ return m_filespec_ap->GetSize();
+}
+
+//----------------------------------------------------------------------
+// ParseProgramHeaders
+//----------------------------------------------------------------------
+size_t
+ObjectFileELF::ParseProgramHeaders()
+{
+ // We have already parsed the program headers
+ if (!m_program_headers.empty())
+ return m_program_headers.size();
+
+ // If there are no program headers to read we are done.
+ if (m_header.e_phnum == 0)
+ return 0;
+
+ m_program_headers.resize(m_header.e_phnum);
+ if (m_program_headers.size() != m_header.e_phnum)
+ return 0;
+
+ const size_t ph_size = m_header.e_phnum * m_header.e_phentsize;
+ const elf_off ph_offset = m_header.e_phoff;
+ DataExtractor data;
+ if (GetData (ph_offset, ph_size, data) != ph_size)
+ return 0;
+
+ uint32_t idx;
+ lldb::offset_t offset;
+ for (idx = 0, offset = 0; idx < m_header.e_phnum; ++idx)
+ {
+ if (m_program_headers[idx].Parse(data, &offset) == false)
+ break;
+ }
+
+ if (idx < m_program_headers.size())
+ m_program_headers.resize(idx);
+
+ return m_program_headers.size();
+}
+
+static bool
+ParseNoteGNUBuildID(DataExtractor &data, lldb_private::UUID &uuid)
+{
+ // Try to parse the note section (ie .note.gnu.build-id|.notes|.note|...) and get the build id.
+ // BuildID documentation: https://fedoraproject.org/wiki/Releases/FeatureBuildId
+ struct
+ {
+ uint32_t name_len; // Length of note name
+ uint32_t desc_len; // Length of note descriptor
+ uint32_t type; // Type of note (1 is ABI_TAG, 3 is BUILD_ID)
+ } notehdr;
+ lldb::offset_t offset = 0;
+ static const uint32_t g_gnu_build_id = 3; // NT_GNU_BUILD_ID from elf.h
+
+ while (true)
+ {
+ if (data.GetU32 (&offset, &notehdr, 3) == NULL)
+ return false;
+
+ notehdr.name_len = llvm::RoundUpToAlignment (notehdr.name_len, 4);
+ notehdr.desc_len = llvm::RoundUpToAlignment (notehdr.desc_len, 4);
+
+ lldb::offset_t offset_next_note = offset + notehdr.name_len + notehdr.desc_len;
+
+ // 16 bytes is UUID|MD5, 20 bytes is SHA1
+ if ((notehdr.type == g_gnu_build_id) && (notehdr.name_len == 4) &&
+ (notehdr.desc_len == 16 || notehdr.desc_len == 20))
+ {
+ char name[4];
+ if (data.GetU8 (&offset, name, 4) == NULL)
+ return false;
+ if (!strcmp(name, "GNU"))
+ {
+ uint8_t uuidbuf[20];
+ if (data.GetU8 (&offset, &uuidbuf, notehdr.desc_len) == NULL)
+ return false;
+ uuid.SetBytes (uuidbuf, notehdr.desc_len);
+ return true;
+ }
+ }
+ offset = offset_next_note;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// GetSectionHeaderInfo
+//----------------------------------------------------------------------
+size_t
+ObjectFileELF::GetSectionHeaderInfo(SectionHeaderColl &section_headers,
+ lldb_private::DataExtractor &object_data,
+ const elf::ELFHeader &header,
+ lldb_private::UUID &uuid,
+ std::string &gnu_debuglink_file,
+ uint32_t &gnu_debuglink_crc)
+{
+ // We have already parsed the section headers
+ if (!section_headers.empty())
+ return section_headers.size();
+
+ // If there are no section headers we are done.
+ if (header.e_shnum == 0)
+ return 0;
+
+ section_headers.resize(header.e_shnum);
+ if (section_headers.size() != header.e_shnum)
+ return 0;
+
+ const size_t sh_size = header.e_shnum * header.e_shentsize;
+ const elf_off sh_offset = header.e_shoff;
+ DataExtractor sh_data;
+ if (sh_data.SetData (object_data, sh_offset, sh_size) != sh_size)
+ return 0;
+
+ uint32_t idx;
+ lldb::offset_t offset;
+ for (idx = 0, offset = 0; idx < header.e_shnum; ++idx)
+ {
+ if (section_headers[idx].Parse(sh_data, &offset) == false)
+ break;
+ }
+ if (idx < section_headers.size())
+ section_headers.resize(idx);
+
+ const unsigned strtab_idx = header.e_shstrndx;
+ if (strtab_idx && strtab_idx < section_headers.size())
+ {
+ const ELFSectionHeaderInfo &sheader = section_headers[strtab_idx];
+ const size_t byte_size = sheader.sh_size;
+ const Elf64_Off offset = sheader.sh_offset;
+ lldb_private::DataExtractor shstr_data;
+
+ if (shstr_data.SetData (object_data, offset, byte_size) == byte_size)
+ {
+ for (SectionHeaderCollIter I = section_headers.begin();
+ I != section_headers.end(); ++I)
+ {
+ static ConstString g_sect_name_gnu_debuglink (".gnu_debuglink");
+ const ELFSectionHeaderInfo &header = *I;
+ const uint64_t section_size = header.sh_type == SHT_NOBITS ? 0 : header.sh_size;
+ ConstString name(shstr_data.PeekCStr(I->sh_name));
+
+ I->section_name = name;
+
+ if (name == g_sect_name_gnu_debuglink)
+ {
+ DataExtractor data;
+ if (section_size && (data.SetData (object_data, header.sh_offset, section_size) == section_size))
+ {
+ lldb::offset_t gnu_debuglink_offset = 0;
+ gnu_debuglink_file = data.GetCStr (&gnu_debuglink_offset);
+ gnu_debuglink_offset = llvm::RoundUpToAlignment (gnu_debuglink_offset, 4);
+ data.GetU32 (&gnu_debuglink_offset, &gnu_debuglink_crc, 1);
+ }
+ }
+
+ if (header.sh_type == SHT_NOTE && !uuid.IsValid())
+ {
+ DataExtractor data;
+ if (section_size && (data.SetData (object_data, header.sh_offset, section_size) == section_size))
+ {
+ ParseNoteGNUBuildID (data, uuid);
+ }
+ }
+ }
+
+ return section_headers.size();
+ }
+ }
+
+ section_headers.clear();
+ return 0;
+}
+
+size_t
+ObjectFileELF::GetProgramHeaderCount()
+{
+ return ParseProgramHeaders();
+}
+
+const elf::ELFProgramHeader *
+ObjectFileELF::GetProgramHeaderByIndex(lldb::user_id_t id)
+{
+ if (!id || !ParseProgramHeaders())
+ return NULL;
+
+ if (--id < m_program_headers.size())
+ return &m_program_headers[id];
+
+ return NULL;
+}
+
+DataExtractor
+ObjectFileELF::GetSegmentDataByIndex(lldb::user_id_t id)
+{
+ const elf::ELFProgramHeader *segment_header = GetProgramHeaderByIndex(id);
+ if (segment_header == NULL)
+ return DataExtractor();
+ return DataExtractor(m_data, segment_header->p_offset, segment_header->p_filesz);
+}
+
+//----------------------------------------------------------------------
+// ParseSectionHeaders
+//----------------------------------------------------------------------
+size_t
+ObjectFileELF::ParseSectionHeaders()
+{
+ return GetSectionHeaderInfo(m_section_headers, m_data, m_header, m_uuid, m_gnu_debuglink_file, m_gnu_debuglink_crc);
+}
+
+const ObjectFileELF::ELFSectionHeaderInfo *
+ObjectFileELF::GetSectionHeaderByIndex(lldb::user_id_t id)
+{
+ if (!id || !ParseSectionHeaders())
+ return NULL;
+
+ if (--id < m_section_headers.size())
+ return &m_section_headers[id];
+
+ return NULL;
+}
+
+void
+ObjectFileELF::CreateSections(SectionList &unified_section_list)
+{
+ if (!m_sections_ap.get() && ParseSectionHeaders())
+ {
+ m_sections_ap.reset(new SectionList());
+
+ for (SectionHeaderCollIter I = m_section_headers.begin();
+ I != m_section_headers.end(); ++I)
+ {
+ const ELFSectionHeaderInfo &header = *I;
+
+ ConstString& name = I->section_name;
+ const uint64_t file_size = header.sh_type == SHT_NOBITS ? 0 : header.sh_size;
+ const uint64_t vm_size = header.sh_flags & SHF_ALLOC ? header.sh_size : 0;
+
+ static ConstString g_sect_name_text (".text");
+ static ConstString g_sect_name_data (".data");
+ static ConstString g_sect_name_bss (".bss");
+ static ConstString g_sect_name_tdata (".tdata");
+ static ConstString g_sect_name_tbss (".tbss");
+ 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_eh_frame (".eh_frame");
+
+ SectionType sect_type = eSectionTypeOther;
+
+ bool is_thread_specific = false;
+
+ if (name == g_sect_name_text) sect_type = eSectionTypeCode;
+ else if (name == g_sect_name_data) sect_type = eSectionTypeData;
+ else if (name == g_sect_name_bss) sect_type = eSectionTypeZeroFill;
+ else if (name == g_sect_name_tdata)
+ {
+ sect_type = eSectionTypeData;
+ is_thread_specific = true;
+ }
+ else if (name == g_sect_name_tbss)
+ {
+ sect_type = eSectionTypeZeroFill;
+ is_thread_specific = true;
+ }
+ // .debug_abbrev – Abbreviations used in the .debug_info section
+ // .debug_aranges – Lookup table for mapping addresses to compilation units
+ // .debug_frame – Call frame information
+ // .debug_info – The core DWARF information section
+ // .debug_line – Line number information
+ // .debug_loc – Location lists used in DW_AT_location attributes
+ // .debug_macinfo – Macro information
+ // .debug_pubnames – Lookup table for mapping object and function names to compilation units
+ // .debug_pubtypes – Lookup table for mapping type names to compilation units
+ // .debug_ranges – Address ranges used in DW_AT_ranges attributes
+ // .debug_str – String table used in .debug_info
+ // MISSING? .gnu_debugdata - "mini debuginfo / MiniDebugInfo" section, http://sourceware.org/gdb/onlinedocs/gdb/MiniDebugInfo.html
+ // MISSING? .debug-index - http://src.chromium.org/viewvc/chrome/trunk/src/build/gdb-add-index?pathrev=144644
+ // MISSING? .debug_types - Type descriptions from DWARF 4? See http://gcc.gnu.org/wiki/DwarfSeparateTypeInfo
+ else if (name == g_sect_name_dwarf_debug_abbrev) sect_type = eSectionTypeDWARFDebugAbbrev;
+ else if (name == g_sect_name_dwarf_debug_aranges) sect_type = eSectionTypeDWARFDebugAranges;
+ else if (name == g_sect_name_dwarf_debug_frame) sect_type = eSectionTypeDWARFDebugFrame;
+ else if (name == g_sect_name_dwarf_debug_info) sect_type = eSectionTypeDWARFDebugInfo;
+ else if (name == g_sect_name_dwarf_debug_line) sect_type = eSectionTypeDWARFDebugLine;
+ else if (name == g_sect_name_dwarf_debug_loc) sect_type = eSectionTypeDWARFDebugLoc;
+ else if (name == g_sect_name_dwarf_debug_macinfo) sect_type = eSectionTypeDWARFDebugMacInfo;
+ else if (name == g_sect_name_dwarf_debug_pubnames) sect_type = eSectionTypeDWARFDebugPubNames;
+ else if (name == g_sect_name_dwarf_debug_pubtypes) sect_type = eSectionTypeDWARFDebugPubTypes;
+ else if (name == g_sect_name_dwarf_debug_ranges) sect_type = eSectionTypeDWARFDebugRanges;
+ else if (name == g_sect_name_dwarf_debug_str) sect_type = eSectionTypeDWARFDebugStr;
+ else if (name == g_sect_name_eh_frame) sect_type = eSectionTypeEHFrame;
+
+ switch (header.sh_type)
+ {
+ case SHT_SYMTAB:
+ assert (sect_type == eSectionTypeOther);
+ sect_type = eSectionTypeELFSymbolTable;
+ break;
+ case SHT_DYNSYM:
+ assert (sect_type == eSectionTypeOther);
+ sect_type = eSectionTypeELFDynamicSymbols;
+ break;
+ case SHT_RELA:
+ case SHT_REL:
+ assert (sect_type == eSectionTypeOther);
+ sect_type = eSectionTypeELFRelocationEntries;
+ break;
+ case SHT_DYNAMIC:
+ assert (sect_type == eSectionTypeOther);
+ sect_type = eSectionTypeELFDynamicLinkInfo;
+ break;
+ }
+
+ SectionSP section_sp (new Section(GetModule(), // Module to which this section belongs.
+ this, // ObjectFile to which this section belongs and should read section data from.
+ SectionIndex(I), // Section ID.
+ name, // Section name.
+ sect_type, // Section type.
+ header.sh_addr, // VM address.
+ vm_size, // VM size in bytes of this section.
+ header.sh_offset, // Offset of this section in the file.
+ file_size, // Size of the section as found in the file.
+ header.sh_flags)); // Flags for this section.
+
+ if (is_thread_specific)
+ section_sp->SetIsThreadSpecific (is_thread_specific);
+ m_sections_ap->AddSection(section_sp);
+ }
+ }
+
+ if (m_sections_ap.get())
+ {
+ if (GetType() == eTypeDebugInfo)
+ {
+ static const SectionType g_sections[] =
+ {
+ eSectionTypeDWARFDebugAranges,
+ eSectionTypeDWARFDebugInfo,
+ eSectionTypeDWARFDebugAbbrev,
+ eSectionTypeDWARFDebugFrame,
+ eSectionTypeDWARFDebugLine,
+ eSectionTypeDWARFDebugStr,
+ eSectionTypeDWARFDebugLoc,
+ eSectionTypeDWARFDebugMacInfo,
+ eSectionTypeDWARFDebugPubNames,
+ eSectionTypeDWARFDebugPubTypes,
+ eSectionTypeDWARFDebugRanges,
+ eSectionTypeELFSymbolTable,
+ };
+ SectionList *elf_section_list = m_sections_ap.get();
+ for (size_t idx = 0; idx < sizeof(g_sections) / sizeof(g_sections[0]); ++idx)
+ {
+ SectionType section_type = g_sections[idx];
+ SectionSP section_sp (elf_section_list->FindSectionByType (section_type, true));
+ if (section_sp)
+ {
+ SectionSP module_section_sp (unified_section_list.FindSectionByType (section_type, true));
+ if (module_section_sp)
+ unified_section_list.ReplaceSection (module_section_sp->GetID(), section_sp);
+ else
+ unified_section_list.AddSection (section_sp);
+ }
+ }
+ }
+ else
+ {
+ unified_section_list = *m_sections_ap;
+ }
+ }
+}
+
+// private
+unsigned
+ObjectFileELF::ParseSymbols (Symtab *symtab,
+ user_id_t start_id,
+ SectionList *section_list,
+ const size_t num_symbols,
+ const DataExtractor &symtab_data,
+ const DataExtractor &strtab_data)
+{
+ ELFSymbol symbol;
+ lldb::offset_t offset = 0;
+
+ static ConstString text_section_name(".text");
+ static ConstString init_section_name(".init");
+ static ConstString fini_section_name(".fini");
+ static ConstString ctors_section_name(".ctors");
+ static ConstString dtors_section_name(".dtors");
+
+ static ConstString data_section_name(".data");
+ static ConstString rodata_section_name(".rodata");
+ static ConstString rodata1_section_name(".rodata1");
+ static ConstString data2_section_name(".data1");
+ static ConstString bss_section_name(".bss");
+
+ //StreamFile strm(stdout, false);
+ unsigned i;
+ for (i = 0; i < num_symbols; ++i)
+ {
+ if (symbol.Parse(symtab_data, &offset) == false)
+ break;
+
+ const char *symbol_name = strtab_data.PeekCStr(symbol.st_name);
+
+ // No need to add symbols that have no names
+ if (symbol_name == NULL || symbol_name[0] == '\0')
+ continue;
+
+ //symbol.Dump (&strm, i, &strtab_data, section_list);
+
+ SectionSP symbol_section_sp;
+ SymbolType symbol_type = eSymbolTypeInvalid;
+ Elf64_Half symbol_idx = symbol.st_shndx;
+
+ switch (symbol_idx)
+ {
+ case SHN_ABS:
+ symbol_type = eSymbolTypeAbsolute;
+ break;
+ case SHN_UNDEF:
+ symbol_type = eSymbolTypeUndefined;
+ break;
+ default:
+ symbol_section_sp = section_list->GetSectionAtIndex(symbol_idx);
+ break;
+ }
+
+ // If a symbol is undefined do not process it further even if it has a STT type
+ if (symbol_type != eSymbolTypeUndefined)
+ {
+ switch (symbol.getType())
+ {
+ default:
+ case STT_NOTYPE:
+ // The symbol's type is not specified.
+ break;
+
+ case STT_OBJECT:
+ // The symbol is associated with a data object, such as a variable,
+ // an array, etc.
+ symbol_type = eSymbolTypeData;
+ break;
+
+ case STT_FUNC:
+ // The symbol is associated with a function or other executable code.
+ symbol_type = eSymbolTypeCode;
+ break;
+
+ case STT_SECTION:
+ // The symbol is associated with a section. Symbol table entries of
+ // this type exist primarily for relocation and normally have
+ // STB_LOCAL binding.
+ break;
+
+ case STT_FILE:
+ // Conventionally, the symbol's name gives the name of the source
+ // file associated with the object file. A file symbol has STB_LOCAL
+ // binding, its section index is SHN_ABS, and it precedes the other
+ // STB_LOCAL symbols for the file, if it is present.
+ symbol_type = eSymbolTypeSourceFile;
+ break;
+
+ case STT_GNU_IFUNC:
+ // The symbol is associated with an indirect function. The actual
+ // function will be resolved if it is referenced.
+ symbol_type = eSymbolTypeResolver;
+ break;
+ }
+ }
+
+ if (symbol_type == eSymbolTypeInvalid)
+ {
+ if (symbol_section_sp)
+ {
+ const ConstString &sect_name = symbol_section_sp->GetName();
+ if (sect_name == text_section_name ||
+ sect_name == init_section_name ||
+ sect_name == fini_section_name ||
+ sect_name == ctors_section_name ||
+ sect_name == dtors_section_name)
+ {
+ symbol_type = eSymbolTypeCode;
+ }
+ else if (sect_name == data_section_name ||
+ sect_name == data2_section_name ||
+ sect_name == rodata_section_name ||
+ sect_name == rodata1_section_name ||
+ sect_name == bss_section_name)
+ {
+ symbol_type = eSymbolTypeData;
+ }
+ }
+ }
+
+ // If the symbol section we've found has no data (SHT_NOBITS), then check the module section
+ // list. This can happen if we're parsing the debug file and it has no .text section, for example.
+ if (symbol_section_sp && (symbol_section_sp->GetFileSize() == 0))
+ {
+ ModuleSP module_sp(GetModule());
+ if (module_sp)
+ {
+ SectionList *module_section_list = module_sp->GetSectionList();
+ if (module_section_list && module_section_list != section_list)
+ {
+ const ConstString &sect_name = symbol_section_sp->GetName();
+ lldb::SectionSP section_sp (module_section_list->FindSectionByName (sect_name));
+ if (section_sp && section_sp->GetFileSize())
+ {
+ symbol_section_sp = section_sp;
+ }
+ }
+ }
+ }
+
+ uint64_t symbol_value = symbol.st_value;
+ if (symbol_section_sp)
+ symbol_value -= symbol_section_sp->GetFileAddress();
+ bool is_global = symbol.getBinding() == STB_GLOBAL;
+ uint32_t flags = symbol.st_other << 8 | symbol.st_info;
+ bool is_mangled = symbol_name ? (symbol_name[0] == '_' && symbol_name[1] == 'Z') : false;
+ Symbol dc_symbol(
+ i + start_id, // ID is the original symbol table index.
+ symbol_name, // Symbol name.
+ is_mangled, // Is the symbol name mangled?
+ symbol_type, // Type of this symbol
+ is_global, // Is this globally visible?
+ false, // Is this symbol debug info?
+ false, // Is this symbol a trampoline?
+ false, // Is this symbol artificial?
+ symbol_section_sp, // Section in which this symbol is defined or null.
+ symbol_value, // Offset in section or symbol value.
+ symbol.st_size, // Size in bytes of this symbol.
+ true, // Size is valid
+ flags); // Symbol flags.
+ symtab->AddSymbol(dc_symbol);
+ }
+
+ return i;
+}
+
+unsigned
+ObjectFileELF::ParseSymbolTable(Symtab *symbol_table, user_id_t start_id, lldb_private::Section *symtab)
+{
+ if (symtab->GetObjectFile() != this)
+ {
+ // If the symbol table section is owned by a different object file, have it do the
+ // parsing.
+ ObjectFileELF *obj_file_elf = static_cast<ObjectFileELF *>(symtab->GetObjectFile());
+ return obj_file_elf->ParseSymbolTable (symbol_table, start_id, symtab);
+ }
+
+ // Get section list for this object file.
+ SectionList *section_list = m_sections_ap.get();
+ if (!section_list)
+ return 0;
+
+ user_id_t symtab_id = symtab->GetID();
+ const ELFSectionHeaderInfo *symtab_hdr = GetSectionHeaderByIndex(symtab_id);
+ assert(symtab_hdr->sh_type == SHT_SYMTAB ||
+ symtab_hdr->sh_type == SHT_DYNSYM);
+
+ // sh_link: section header index of associated string table.
+ // Section ID's are ones based.
+ user_id_t strtab_id = symtab_hdr->sh_link + 1;
+ Section *strtab = section_list->FindSectionByID(strtab_id).get();
+
+ unsigned num_symbols = 0;
+ if (symtab && strtab)
+ {
+ assert (symtab->GetObjectFile() == this);
+ assert (strtab->GetObjectFile() == this);
+
+ DataExtractor symtab_data;
+ DataExtractor strtab_data;
+ if (ReadSectionData(symtab, symtab_data) &&
+ ReadSectionData(strtab, strtab_data))
+ {
+ size_t num_symbols = symtab_data.GetByteSize() / symtab_hdr->sh_entsize;
+
+ num_symbols = ParseSymbols(symbol_table, start_id,
+ section_list, num_symbols,
+ symtab_data, strtab_data);
+ }
+ }
+
+ return num_symbols;
+}
+
+size_t
+ObjectFileELF::ParseDynamicSymbols()
+{
+ if (m_dynamic_symbols.size())
+ return m_dynamic_symbols.size();
+
+ SectionList *section_list = GetSectionList();
+ if (!section_list)
+ return 0;
+
+ // Find the SHT_DYNAMIC section.
+ Section *dynsym = section_list->FindSectionByType (eSectionTypeELFDynamicLinkInfo, true).get();
+ if (!dynsym)
+ return 0;
+ assert (dynsym->GetObjectFile() == this);
+
+ ELFDynamic symbol;
+ DataExtractor dynsym_data;
+ if (ReadSectionData(dynsym, dynsym_data))
+ {
+ const lldb::offset_t section_size = dynsym_data.GetByteSize();
+ lldb::offset_t cursor = 0;
+
+ while (cursor < section_size)
+ {
+ if (!symbol.Parse(dynsym_data, &cursor))
+ break;
+
+ m_dynamic_symbols.push_back(symbol);
+ }
+ }
+
+ return m_dynamic_symbols.size();
+}
+
+const ELFDynamic *
+ObjectFileELF::FindDynamicSymbol(unsigned tag)
+{
+ if (!ParseDynamicSymbols())
+ return NULL;
+
+ DynamicSymbolCollIter I = m_dynamic_symbols.begin();
+ DynamicSymbolCollIter E = m_dynamic_symbols.end();
+ for ( ; I != E; ++I)
+ {
+ ELFDynamic *symbol = &*I;
+
+ if (symbol->d_tag == tag)
+ return symbol;
+ }
+
+ return NULL;
+}
+
+unsigned
+ObjectFileELF::PLTRelocationType()
+{
+ const ELFDynamic *symbol = FindDynamicSymbol(DT_PLTREL);
+
+ if (symbol)
+ return symbol->d_val;
+
+ return 0;
+}
+
+static unsigned
+ParsePLTRelocations(Symtab *symbol_table,
+ user_id_t start_id,
+ unsigned rel_type,
+ const ELFHeader *hdr,
+ const ELFSectionHeader *rel_hdr,
+ const ELFSectionHeader *plt_hdr,
+ const ELFSectionHeader *sym_hdr,
+ const lldb::SectionSP &plt_section_sp,
+ DataExtractor &rel_data,
+ DataExtractor &symtab_data,
+ DataExtractor &strtab_data)
+{
+ ELFRelocation rel(rel_type);
+ ELFSymbol symbol;
+ lldb::offset_t offset = 0;
+ const elf_xword plt_entsize = plt_hdr->sh_entsize;
+ const elf_xword num_relocations = rel_hdr->sh_size / rel_hdr->sh_entsize;
+
+ typedef unsigned (*reloc_info_fn)(const ELFRelocation &rel);
+ reloc_info_fn reloc_type;
+ reloc_info_fn reloc_symbol;
+
+ if (hdr->Is32Bit())
+ {
+ reloc_type = ELFRelocation::RelocType32;
+ reloc_symbol = ELFRelocation::RelocSymbol32;
+ }
+ else
+ {
+ reloc_type = ELFRelocation::RelocType64;
+ reloc_symbol = ELFRelocation::RelocSymbol64;
+ }
+
+ unsigned slot_type = hdr->GetRelocationJumpSlotType();
+ unsigned i;
+ for (i = 0; i < num_relocations; ++i)
+ {
+ if (rel.Parse(rel_data, &offset) == false)
+ break;
+
+ if (reloc_type(rel) != slot_type)
+ continue;
+
+ lldb::offset_t symbol_offset = reloc_symbol(rel) * sym_hdr->sh_entsize;
+ uint64_t plt_index = (i + 1) * plt_entsize;
+
+ if (!symbol.Parse(symtab_data, &symbol_offset))
+ break;
+
+ const char *symbol_name = strtab_data.PeekCStr(symbol.st_name);
+ bool is_mangled = symbol_name ? (symbol_name[0] == '_' && symbol_name[1] == 'Z') : false;
+
+ Symbol jump_symbol(
+ i + start_id, // Symbol table index
+ symbol_name, // symbol name.
+ is_mangled, // is the symbol name mangled?
+ eSymbolTypeTrampoline, // Type of this symbol
+ false, // Is this globally visible?
+ false, // Is this symbol debug info?
+ true, // Is this symbol a trampoline?
+ true, // Is this symbol artificial?
+ plt_section_sp, // Section in which this symbol is defined or null.
+ plt_index, // Offset in section or symbol value.
+ plt_entsize, // Size in bytes of this symbol.
+ true, // Size is valid
+ 0); // Symbol flags.
+
+ symbol_table->AddSymbol(jump_symbol);
+ }
+
+ return i;
+}
+
+unsigned
+ObjectFileELF::ParseTrampolineSymbols(Symtab *symbol_table,
+ user_id_t start_id,
+ const ELFSectionHeaderInfo *rel_hdr,
+ user_id_t rel_id)
+{
+ assert(rel_hdr->sh_type == SHT_RELA || rel_hdr->sh_type == SHT_REL);
+
+ // The link field points to the associated symbol table. The info field
+ // points to the section holding the plt.
+ user_id_t symtab_id = rel_hdr->sh_link;
+ user_id_t plt_id = rel_hdr->sh_info;
+
+ if (!symtab_id || !plt_id)
+ return 0;
+
+ // Section ID's are ones based;
+ symtab_id++;
+ plt_id++;
+
+ const ELFSectionHeaderInfo *plt_hdr = GetSectionHeaderByIndex(plt_id);
+ if (!plt_hdr)
+ return 0;
+
+ const ELFSectionHeaderInfo *sym_hdr = GetSectionHeaderByIndex(symtab_id);
+ if (!sym_hdr)
+ return 0;
+
+ SectionList *section_list = m_sections_ap.get();
+ if (!section_list)
+ return 0;
+
+ Section *rel_section = section_list->FindSectionByID(rel_id).get();
+ if (!rel_section)
+ return 0;
+
+ SectionSP plt_section_sp (section_list->FindSectionByID(plt_id));
+ if (!plt_section_sp)
+ return 0;
+
+ Section *symtab = section_list->FindSectionByID(symtab_id).get();
+ if (!symtab)
+ return 0;
+
+ // sh_link points to associated string table.
+ Section *strtab = section_list->FindSectionByID(sym_hdr->sh_link + 1).get();
+ if (!strtab)
+ return 0;
+
+ DataExtractor rel_data;
+ if (!ReadSectionData(rel_section, rel_data))
+ return 0;
+
+ DataExtractor symtab_data;
+ if (!ReadSectionData(symtab, symtab_data))
+ return 0;
+
+ DataExtractor strtab_data;
+ if (!ReadSectionData(strtab, strtab_data))
+ return 0;
+
+ unsigned rel_type = PLTRelocationType();
+ if (!rel_type)
+ return 0;
+
+ return ParsePLTRelocations (symbol_table,
+ start_id,
+ rel_type,
+ &m_header,
+ rel_hdr,
+ plt_hdr,
+ sym_hdr,
+ plt_section_sp,
+ rel_data,
+ symtab_data,
+ strtab_data);
+}
+
+Symtab *
+ObjectFileELF::GetSymtab()
+{
+ ModuleSP module_sp(GetModule());
+ if (!module_sp)
+ return NULL;
+
+ // We always want to use the main object file so we (hopefully) only have one cached copy
+ // of our symtab, dynamic sections, etc.
+ ObjectFile *module_obj_file = module_sp->GetObjectFile();
+ if (module_obj_file && module_obj_file != this)
+ return module_obj_file->GetSymtab();
+
+ if (m_symtab_ap.get() == NULL)
+ {
+ SectionList *section_list = GetSectionList();
+ if (!section_list)
+ return NULL;
+
+ uint64_t symbol_id = 0;
+ lldb_private::Mutex::Locker locker(module_sp->GetMutex());
+
+ m_symtab_ap.reset(new Symtab(this));
+
+ // Sharable objects and dynamic executables usually have 2 distinct symbol
+ // tables, one named ".symtab", and the other ".dynsym". The dynsym is a smaller
+ // version of the symtab that only contains global symbols. The information found
+ // in the dynsym is therefore also found in the symtab, while the reverse is not
+ // necessarily true.
+ Section *symtab = section_list->FindSectionByType (eSectionTypeELFSymbolTable, true).get();
+ if (!symtab)
+ {
+ // The symtab section is non-allocable and can be stripped, so if it doesn't exist
+ // then use the dynsym section which should always be there.
+ symtab = section_list->FindSectionByType (eSectionTypeELFDynamicSymbols, true).get();
+ }
+ if (symtab)
+ symbol_id += ParseSymbolTable (m_symtab_ap.get(), symbol_id, symtab);
+
+ // Synthesize trampoline symbols to help navigate the PLT.
+ const ELFDynamic *symbol = FindDynamicSymbol(DT_JMPREL);
+ if (symbol)
+ {
+ addr_t addr = symbol->d_ptr;
+ Section *reloc_section = section_list->FindSectionContainingFileAddress(addr).get();
+ if (reloc_section)
+ {
+ user_id_t reloc_id = reloc_section->GetID();
+ const ELFSectionHeaderInfo *reloc_header = GetSectionHeaderByIndex(reloc_id);
+ assert(reloc_header);
+
+ ParseTrampolineSymbols (m_symtab_ap.get(), symbol_id, reloc_header, reloc_id);
+ }
+ }
+ }
+ return m_symtab_ap.get();
+}
+
+bool
+ObjectFileELF::IsStripped ()
+{
+ // TODO: determine this for ELF
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// Dump
+//
+// Dump the specifics of the runtime file container (such as any headers
+// segments, sections, etc).
+//----------------------------------------------------------------------
+void
+ObjectFileELF::Dump(Stream *s)
+{
+ DumpELFHeader(s, m_header);
+ s->EOL();
+ DumpELFProgramHeaders(s);
+ s->EOL();
+ DumpELFSectionHeaders(s);
+ s->EOL();
+ SectionList *section_list = GetSectionList();
+ if (section_list)
+ section_list->Dump(s, NULL, true, UINT32_MAX);
+ Symtab *symtab = GetSymtab();
+ if (symtab)
+ symtab->Dump(s, NULL, eSortOrderNone);
+ s->EOL();
+ DumpDependentModules(s);
+ s->EOL();
+}
+
+//----------------------------------------------------------------------
+// DumpELFHeader
+//
+// Dump the ELF header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFHeader(Stream *s, const ELFHeader &header)
+{
+ s->PutCString("ELF Header\n");
+ s->Printf("e_ident[EI_MAG0 ] = 0x%2.2x\n", header.e_ident[EI_MAG0]);
+ s->Printf("e_ident[EI_MAG1 ] = 0x%2.2x '%c'\n",
+ header.e_ident[EI_MAG1], header.e_ident[EI_MAG1]);
+ s->Printf("e_ident[EI_MAG2 ] = 0x%2.2x '%c'\n",
+ header.e_ident[EI_MAG2], header.e_ident[EI_MAG2]);
+ s->Printf("e_ident[EI_MAG3 ] = 0x%2.2x '%c'\n",
+ header.e_ident[EI_MAG3], header.e_ident[EI_MAG3]);
+
+ s->Printf("e_ident[EI_CLASS ] = 0x%2.2x\n", header.e_ident[EI_CLASS]);
+ s->Printf("e_ident[EI_DATA ] = 0x%2.2x ", header.e_ident[EI_DATA]);
+ DumpELFHeader_e_ident_EI_DATA(s, header.e_ident[EI_DATA]);
+ s->Printf ("\ne_ident[EI_VERSION] = 0x%2.2x\n", header.e_ident[EI_VERSION]);
+ s->Printf ("e_ident[EI_PAD ] = 0x%2.2x\n", header.e_ident[EI_PAD]);
+
+ s->Printf("e_type = 0x%4.4x ", header.e_type);
+ DumpELFHeader_e_type(s, header.e_type);
+ s->Printf("\ne_machine = 0x%4.4x\n", header.e_machine);
+ s->Printf("e_version = 0x%8.8x\n", header.e_version);
+ s->Printf("e_entry = 0x%8.8" PRIx64 "\n", header.e_entry);
+ s->Printf("e_phoff = 0x%8.8" PRIx64 "\n", header.e_phoff);
+ s->Printf("e_shoff = 0x%8.8" PRIx64 "\n", header.e_shoff);
+ s->Printf("e_flags = 0x%8.8x\n", header.e_flags);
+ s->Printf("e_ehsize = 0x%4.4x\n", header.e_ehsize);
+ s->Printf("e_phentsize = 0x%4.4x\n", header.e_phentsize);
+ s->Printf("e_phnum = 0x%4.4x\n", header.e_phnum);
+ s->Printf("e_shentsize = 0x%4.4x\n", header.e_shentsize);
+ s->Printf("e_shnum = 0x%4.4x\n", header.e_shnum);
+ s->Printf("e_shstrndx = 0x%4.4x\n", header.e_shstrndx);
+}
+
+//----------------------------------------------------------------------
+// DumpELFHeader_e_type
+//
+// Dump an token value for the ELF header member e_type
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFHeader_e_type(Stream *s, elf_half e_type)
+{
+ switch (e_type)
+ {
+ case ET_NONE: *s << "ET_NONE"; break;
+ case ET_REL: *s << "ET_REL"; break;
+ case ET_EXEC: *s << "ET_EXEC"; break;
+ case ET_DYN: *s << "ET_DYN"; break;
+ case ET_CORE: *s << "ET_CORE"; break;
+ default:
+ break;
+ }
+}
+
+//----------------------------------------------------------------------
+// DumpELFHeader_e_ident_EI_DATA
+//
+// Dump an token value for the ELF header member e_ident[EI_DATA]
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFHeader_e_ident_EI_DATA(Stream *s, unsigned char ei_data)
+{
+ switch (ei_data)
+ {
+ case ELFDATANONE: *s << "ELFDATANONE"; break;
+ case ELFDATA2LSB: *s << "ELFDATA2LSB - Little Endian"; break;
+ case ELFDATA2MSB: *s << "ELFDATA2MSB - Big Endian"; break;
+ default:
+ break;
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DumpELFProgramHeader
+//
+// Dump a single ELF program header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFProgramHeader(Stream *s, const ELFProgramHeader &ph)
+{
+ DumpELFProgramHeader_p_type(s, ph.p_type);
+ s->Printf(" %8.8" PRIx64 " %8.8" PRIx64 " %8.8" PRIx64, ph.p_offset, ph.p_vaddr, ph.p_paddr);
+ s->Printf(" %8.8" PRIx64 " %8.8" PRIx64 " %8.8x (", ph.p_filesz, ph.p_memsz, ph.p_flags);
+
+ DumpELFProgramHeader_p_flags(s, ph.p_flags);
+ s->Printf(") %8.8" PRIx64, ph.p_align);
+}
+
+//----------------------------------------------------------------------
+// DumpELFProgramHeader_p_type
+//
+// Dump an token value for the ELF program header member p_type which
+// describes the type of the program header
+// ----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFProgramHeader_p_type(Stream *s, elf_word p_type)
+{
+ const int kStrWidth = 15;
+ switch (p_type)
+ {
+ CASE_AND_STREAM(s, PT_NULL , kStrWidth);
+ CASE_AND_STREAM(s, PT_LOAD , kStrWidth);
+ CASE_AND_STREAM(s, PT_DYNAMIC , kStrWidth);
+ CASE_AND_STREAM(s, PT_INTERP , kStrWidth);
+ CASE_AND_STREAM(s, PT_NOTE , kStrWidth);
+ CASE_AND_STREAM(s, PT_SHLIB , kStrWidth);
+ CASE_AND_STREAM(s, PT_PHDR , kStrWidth);
+ CASE_AND_STREAM(s, PT_TLS , kStrWidth);
+ CASE_AND_STREAM(s, PT_GNU_EH_FRAME, kStrWidth);
+ default:
+ s->Printf("0x%8.8x%*s", p_type, kStrWidth - 10, "");
+ break;
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DumpELFProgramHeader_p_flags
+//
+// Dump an token value for the ELF program header member p_flags
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFProgramHeader_p_flags(Stream *s, elf_word p_flags)
+{
+ *s << ((p_flags & PF_X) ? "PF_X" : " ")
+ << (((p_flags & PF_X) && (p_flags & PF_W)) ? '+' : ' ')
+ << ((p_flags & PF_W) ? "PF_W" : " ")
+ << (((p_flags & PF_W) && (p_flags & PF_R)) ? '+' : ' ')
+ << ((p_flags & PF_R) ? "PF_R" : " ");
+}
+
+//----------------------------------------------------------------------
+// DumpELFProgramHeaders
+//
+// Dump all of the ELF program header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFProgramHeaders(Stream *s)
+{
+ if (ParseProgramHeaders())
+ {
+ s->PutCString("Program Headers\n");
+ s->PutCString("IDX p_type p_offset p_vaddr p_paddr "
+ "p_filesz p_memsz p_flags p_align\n");
+ s->PutCString("==== --------------- -------- -------- -------- "
+ "-------- -------- ------------------------- --------\n");
+
+ uint32_t idx = 0;
+ for (ProgramHeaderCollConstIter I = m_program_headers.begin();
+ I != m_program_headers.end(); ++I, ++idx)
+ {
+ s->Printf("[%2u] ", idx);
+ ObjectFileELF::DumpELFProgramHeader(s, *I);
+ s->EOL();
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// DumpELFSectionHeader
+//
+// Dump a single ELF section header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFSectionHeader(Stream *s, const ELFSectionHeaderInfo &sh)
+{
+ s->Printf("%8.8x ", sh.sh_name);
+ DumpELFSectionHeader_sh_type(s, sh.sh_type);
+ s->Printf(" %8.8" PRIx64 " (", sh.sh_flags);
+ DumpELFSectionHeader_sh_flags(s, sh.sh_flags);
+ s->Printf(") %8.8" PRIx64 " %8.8" PRIx64 " %8.8" PRIx64, sh.sh_addr, sh.sh_offset, sh.sh_size);
+ s->Printf(" %8.8x %8.8x", sh.sh_link, sh.sh_info);
+ s->Printf(" %8.8" PRIx64 " %8.8" PRIx64, sh.sh_addralign, sh.sh_entsize);
+}
+
+//----------------------------------------------------------------------
+// DumpELFSectionHeader_sh_type
+//
+// Dump an token value for the ELF section header member sh_type which
+// describes the type of the section
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFSectionHeader_sh_type(Stream *s, elf_word sh_type)
+{
+ const int kStrWidth = 12;
+ switch (sh_type)
+ {
+ CASE_AND_STREAM(s, SHT_NULL , kStrWidth);
+ CASE_AND_STREAM(s, SHT_PROGBITS , kStrWidth);
+ CASE_AND_STREAM(s, SHT_SYMTAB , kStrWidth);
+ CASE_AND_STREAM(s, SHT_STRTAB , kStrWidth);
+ CASE_AND_STREAM(s, SHT_RELA , kStrWidth);
+ CASE_AND_STREAM(s, SHT_HASH , kStrWidth);
+ CASE_AND_STREAM(s, SHT_DYNAMIC , kStrWidth);
+ CASE_AND_STREAM(s, SHT_NOTE , kStrWidth);
+ CASE_AND_STREAM(s, SHT_NOBITS , kStrWidth);
+ CASE_AND_STREAM(s, SHT_REL , kStrWidth);
+ CASE_AND_STREAM(s, SHT_SHLIB , kStrWidth);
+ CASE_AND_STREAM(s, SHT_DYNSYM , kStrWidth);
+ CASE_AND_STREAM(s, SHT_LOPROC , kStrWidth);
+ CASE_AND_STREAM(s, SHT_HIPROC , kStrWidth);
+ CASE_AND_STREAM(s, SHT_LOUSER , kStrWidth);
+ CASE_AND_STREAM(s, SHT_HIUSER , kStrWidth);
+ default:
+ s->Printf("0x%8.8x%*s", sh_type, kStrWidth - 10, "");
+ break;
+ }
+}
+
+//----------------------------------------------------------------------
+// DumpELFSectionHeader_sh_flags
+//
+// Dump an token value for the ELF section header member sh_flags
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFSectionHeader_sh_flags(Stream *s, elf_xword sh_flags)
+{
+ *s << ((sh_flags & SHF_WRITE) ? "WRITE" : " ")
+ << (((sh_flags & SHF_WRITE) && (sh_flags & SHF_ALLOC)) ? '+' : ' ')
+ << ((sh_flags & SHF_ALLOC) ? "ALLOC" : " ")
+ << (((sh_flags & SHF_ALLOC) && (sh_flags & SHF_EXECINSTR)) ? '+' : ' ')
+ << ((sh_flags & SHF_EXECINSTR) ? "EXECINSTR" : " ");
+}
+
+//----------------------------------------------------------------------
+// DumpELFSectionHeaders
+//
+// Dump all of the ELF section header to the specified output stream
+//----------------------------------------------------------------------
+void
+ObjectFileELF::DumpELFSectionHeaders(Stream *s)
+{
+ if (!ParseSectionHeaders())
+ return;
+
+ s->PutCString("Section Headers\n");
+ s->PutCString("IDX name type flags "
+ "addr offset size link info addralgn "
+ "entsize Name\n");
+ s->PutCString("==== -------- ------------ -------------------------------- "
+ "-------- -------- -------- -------- -------- -------- "
+ "-------- ====================\n");
+
+ uint32_t idx = 0;
+ for (SectionHeaderCollConstIter I = m_section_headers.begin();
+ I != m_section_headers.end(); ++I, ++idx)
+ {
+ s->Printf("[%2u] ", idx);
+ ObjectFileELF::DumpELFSectionHeader(s, *I);
+ const char* section_name = I->section_name.AsCString("");
+ if (section_name)
+ *s << ' ' << section_name << "\n";
+ }
+}
+
+void
+ObjectFileELF::DumpDependentModules(lldb_private::Stream *s)
+{
+ size_t num_modules = ParseDependentModules();
+
+ if (num_modules > 0)
+ {
+ s->PutCString("Dependent Modules:\n");
+ for (unsigned i = 0; i < num_modules; ++i)
+ {
+ const FileSpec &spec = m_filespec_ap->GetFileSpecAtIndex(i);
+ s->Printf(" %s\n", spec.GetFilename().GetCString());
+ }
+ }
+}
+
+bool
+ObjectFileELF::GetArchitecture (ArchSpec &arch)
+{
+ if (!ParseHeader())
+ return false;
+
+ arch.SetArchitecture (eArchTypeELF, m_header.e_machine, LLDB_INVALID_CPUTYPE);
+ arch.GetTriple().setOSName (Host::GetOSString().GetCString());
+ arch.GetTriple().setVendorName(Host::GetVendorString().GetCString());
+ return true;
+}
+
+ObjectFile::Type
+ObjectFileELF::CalculateType()
+{
+ switch (m_header.e_type)
+ {
+ case llvm::ELF::ET_NONE:
+ // 0 - No file type
+ return eTypeUnknown;
+
+ case llvm::ELF::ET_REL:
+ // 1 - Relocatable file
+ return eTypeObjectFile;
+
+ case llvm::ELF::ET_EXEC:
+ // 2 - Executable file
+ return eTypeExecutable;
+
+ case llvm::ELF::ET_DYN:
+ // 3 - Shared object file
+ return eTypeSharedLibrary;
+
+ case ET_CORE:
+ // 4 - Core file
+ return eTypeCoreFile;
+
+ default:
+ break;
+ }
+ return eTypeUnknown;
+}
+
+ObjectFile::Strata
+ObjectFileELF::CalculateStrata()
+{
+ switch (m_header.e_type)
+ {
+ case llvm::ELF::ET_NONE:
+ // 0 - No file type
+ return eStrataUnknown;
+
+ case llvm::ELF::ET_REL:
+ // 1 - Relocatable file
+ return eStrataUnknown;
+
+ case llvm::ELF::ET_EXEC:
+ // 2 - Executable file
+ // TODO: is there any way to detect that an executable is a kernel
+ // related executable by inspecting the program headers, section
+ // headers, symbols, or any other flag bits???
+ return eStrataUser;
+
+ case llvm::ELF::ET_DYN:
+ // 3 - Shared object file
+ // TODO: is there any way to detect that an shared library is a kernel
+ // related executable by inspecting the program headers, section
+ // headers, symbols, or any other flag bits???
+ return eStrataUnknown;
+
+ case ET_CORE:
+ // 4 - Core file
+ // TODO: is there any way to detect that an core file is a kernel
+ // related executable by inspecting the program headers, section
+ // headers, symbols, or any other flag bits???
+ return eStrataUnknown;
+
+ default:
+ break;
+ }
+ return eStrataUnknown;
+}
+
diff --git a/source/Plugins/ObjectFile/ELF/ObjectFileELF.h b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
new file mode 100644
index 000000000000..2365101f4275
--- /dev/null
+++ b/source/Plugins/ObjectFile/ELF/ObjectFileELF.h
@@ -0,0 +1,333 @@
+//===-- ObjectFileELF.h --------------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ObjectFileELF_h_
+#define liblldb_ObjectFileELF_h_
+
+#include <stdint.h>
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Core/UUID.h"
+
+#include "ELFHeader.h"
+
+//------------------------------------------------------------------------------
+/// @class ObjectFileELF
+/// @brief Generic ELF object file reader.
+///
+/// This class provides a generic ELF (32/64 bit) reader plugin implementing the
+/// ObjectFile protocol.
+class ObjectFileELF :
+ public lldb_private::ObjectFile
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::ObjectFile *
+ CreateInstance(const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec* file,
+ lldb::offset_t file_offset,
+ lldb::offset_t length);
+
+ static lldb_private::ObjectFile *
+ CreateMemoryInstance (const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ const lldb::ProcessSP &process_sp,
+ lldb::addr_t header_addr);
+
+ static size_t
+ 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);
+
+ static bool
+ MagicBytesMatch (lldb::DataBufferSP& data_sp,
+ lldb::addr_t offset,
+ lldb::addr_t length);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ //------------------------------------------------------------------
+ // ObjectFile Protocol.
+ //------------------------------------------------------------------
+ virtual
+ ~ObjectFileELF();
+
+ virtual bool
+ ParseHeader();
+
+ virtual lldb::ByteOrder
+ GetByteOrder() const;
+
+ virtual bool
+ IsExecutable () const;
+
+ virtual uint32_t
+ GetAddressByteSize() const;
+
+ virtual lldb_private::Symtab *
+ GetSymtab();
+
+ virtual bool
+ IsStripped ();
+
+ virtual void
+ CreateSections (lldb_private::SectionList &unified_section_list);
+
+ virtual void
+ Dump(lldb_private::Stream *s);
+
+ virtual bool
+ GetArchitecture (lldb_private::ArchSpec &arch);
+
+ virtual bool
+ GetUUID(lldb_private::UUID* uuid);
+
+ virtual lldb_private::FileSpecList
+ GetDebugSymbolFilePaths();
+
+ virtual uint32_t
+ GetDependentModules(lldb_private::FileSpecList& files);
+
+ virtual lldb_private::Address
+ GetImageInfoAddress();
+
+ virtual lldb_private::Address
+ GetEntryPointAddress ();
+
+ virtual ObjectFile::Type
+ CalculateType();
+
+ virtual ObjectFile::Strata
+ CalculateStrata();
+
+ // Returns number of program headers found in the ELF file.
+ size_t
+ GetProgramHeaderCount();
+
+ // Returns the program header with the given index.
+ const elf::ELFProgramHeader *
+ GetProgramHeaderByIndex(lldb::user_id_t id);
+
+ // Returns segment data for the given index.
+ lldb_private::DataExtractor
+ GetSegmentDataByIndex(lldb::user_id_t id);
+
+private:
+ ObjectFileELF(const lldb::ModuleSP &module_sp,
+ lldb::DataBufferSP& data_sp,
+ lldb::offset_t data_offset,
+ const lldb_private::FileSpec* file,
+ lldb::offset_t offset,
+ lldb::offset_t length);
+
+ typedef std::vector<elf::ELFProgramHeader> ProgramHeaderColl;
+ typedef ProgramHeaderColl::iterator ProgramHeaderCollIter;
+ typedef ProgramHeaderColl::const_iterator ProgramHeaderCollConstIter;
+
+ struct ELFSectionHeaderInfo : public elf::ELFSectionHeader
+ {
+ lldb_private::ConstString section_name;
+ };
+ typedef std::vector<ELFSectionHeaderInfo> SectionHeaderColl;
+ typedef SectionHeaderColl::iterator SectionHeaderCollIter;
+ typedef SectionHeaderColl::const_iterator SectionHeaderCollConstIter;
+
+ typedef std::vector<elf::ELFDynamic> DynamicSymbolColl;
+ typedef DynamicSymbolColl::iterator DynamicSymbolCollIter;
+ typedef DynamicSymbolColl::const_iterator DynamicSymbolCollConstIter;
+
+ /// Version of this reader common to all plugins based on this class.
+ static const uint32_t m_plugin_version = 1;
+
+ /// ELF file header.
+ elf::ELFHeader m_header;
+
+ /// ELF build ID.
+ lldb_private::UUID m_uuid;
+
+ /// ELF .gnu_debuglink file and crc data if available.
+ std::string m_gnu_debuglink_file;
+ uint32_t m_gnu_debuglink_crc;
+
+ /// Collection of program headers.
+ ProgramHeaderColl m_program_headers;
+
+ /// Collection of section headers.
+ SectionHeaderColl m_section_headers;
+
+ /// Collection of symbols from the dynamic table.
+ DynamicSymbolColl m_dynamic_symbols;
+
+ /// List of file specifications corresponding to the modules (shared
+ /// libraries) on which this object file depends.
+ mutable std::unique_ptr<lldb_private::FileSpecList> m_filespec_ap;
+
+ /// Cached value of the entry point for this module.
+ lldb_private::Address m_entry_point_address;
+
+ /// Returns a 1 based index of the given section header.
+ size_t
+ SectionIndex(const SectionHeaderCollIter &I);
+
+ /// Returns a 1 based index of the given section header.
+ size_t
+ SectionIndex(const SectionHeaderCollConstIter &I) const;
+
+ /// Parses all section headers present in this object file and populates
+ /// m_program_headers. This method will compute the header list only once.
+ /// Returns the number of headers parsed.
+ size_t
+ ParseProgramHeaders();
+
+ /// Parses all section headers present in this object file and populates
+ /// m_section_headers. This method will compute the header list only once.
+ /// Returns the number of headers parsed.
+ size_t
+ ParseSectionHeaders();
+
+ /// Parses the elf section headers and returns the uuid, debug link name, crc.
+ static size_t
+ GetSectionHeaderInfo(SectionHeaderColl &section_headers,
+ lldb_private::DataExtractor &data,
+ const elf::ELFHeader &header,
+ lldb_private::UUID &uuid,
+ std::string &gnu_debuglink_file,
+ uint32_t &gnu_debuglink_crc);
+
+ /// Scans the dynamic section and locates all dependent modules (shared
+ /// libraries) populating m_filespec_ap. This method will compute the
+ /// dependent module list only once. Returns the number of dependent
+ /// modules parsed.
+ size_t
+ ParseDependentModules();
+
+ /// Parses the dynamic symbol table and populates m_dynamic_symbols. The
+ /// vector retains the order as found in the object file. Returns the
+ /// number of dynamic symbols parsed.
+ size_t
+ ParseDynamicSymbols();
+
+ /// Populates m_symtab_ap will all non-dynamic linker symbols. This method
+ /// will parse the symbols only once. Returns the number of symbols parsed.
+ unsigned
+ ParseSymbolTable(lldb_private::Symtab *symbol_table,
+ lldb::user_id_t start_id,
+ lldb_private::Section *symtab);
+
+ /// Helper routine for ParseSymbolTable().
+ unsigned
+ ParseSymbols(lldb_private::Symtab *symbol_table,
+ lldb::user_id_t start_id,
+ lldb_private::SectionList *section_list,
+ const size_t num_symbols,
+ const lldb_private::DataExtractor &symtab_data,
+ const lldb_private::DataExtractor &strtab_data);
+
+ /// Scans the relocation entries and adds a set of artificial symbols to the
+ /// given symbol table for each PLT slot. Returns the number of symbols
+ /// added.
+ unsigned
+ ParseTrampolineSymbols(lldb_private::Symtab *symbol_table,
+ lldb::user_id_t start_id,
+ const ELFSectionHeaderInfo *rela_hdr,
+ lldb::user_id_t section_id);
+
+ /// Returns the section header with the given id or NULL.
+ const ELFSectionHeaderInfo *
+ GetSectionHeaderByIndex(lldb::user_id_t id);
+
+ /// @name ELF header dump routines
+ //@{
+ static void
+ DumpELFHeader(lldb_private::Stream *s, const elf::ELFHeader& header);
+
+ static void
+ DumpELFHeader_e_ident_EI_DATA(lldb_private::Stream *s,
+ unsigned char ei_data);
+
+ static void
+ DumpELFHeader_e_type(lldb_private::Stream *s, elf::elf_half e_type);
+ //@}
+
+ /// @name ELF program header dump routines
+ //@{
+ void
+ DumpELFProgramHeaders(lldb_private::Stream *s);
+
+ static void
+ DumpELFProgramHeader(lldb_private::Stream *s,
+ const elf::ELFProgramHeader &ph);
+
+ static void
+ DumpELFProgramHeader_p_type(lldb_private::Stream *s, elf::elf_word p_type);
+
+ static void
+ DumpELFProgramHeader_p_flags(lldb_private::Stream *s,
+ elf::elf_word p_flags);
+ //@}
+
+ /// @name ELF section header dump routines
+ //@{
+ void
+ DumpELFSectionHeaders(lldb_private::Stream *s);
+
+ static void
+ DumpELFSectionHeader(lldb_private::Stream *s,
+ const ELFSectionHeaderInfo& sh);
+
+ static void
+ DumpELFSectionHeader_sh_type(lldb_private::Stream *s,
+ elf::elf_word sh_type);
+
+ static void
+ DumpELFSectionHeader_sh_flags(lldb_private::Stream *s,
+ elf::elf_xword sh_flags);
+ //@}
+
+ /// ELF dependent module dump routine.
+ void
+ DumpDependentModules(lldb_private::Stream *s);
+
+ const elf::ELFDynamic *
+ FindDynamicSymbol(unsigned tag);
+
+ unsigned
+ PLTRelocationType();
+};
+
+#endif // #ifndef liblldb_ObjectFileELF_h_
diff --git a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
new file mode 100644
index 000000000000..4cfe38e5840f
--- /dev/null
+++ b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.cpp
@@ -0,0 +1,417 @@
+//===-- OperatingSystemPython.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#ifndef LLDB_DISABLE_PYTHON
+
+#include "OperatingSystemPython.h"
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/ValueObjectVariable.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/PythonDataObjects.h"
+#include "lldb/Symbol/ClangNamespaceDecl.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/VariableList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadList.h"
+#include "lldb/Target/Thread.h"
+#include "Plugins/Process/Utility/DynamicRegisterInfo.h"
+#include "Plugins/Process/Utility/RegisterContextDummy.h"
+#include "Plugins/Process/Utility/RegisterContextMemory.h"
+#include "Plugins/Process/Utility/ThreadMemory.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+OperatingSystemPython::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+OperatingSystemPython::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+OperatingSystem *
+OperatingSystemPython::CreateInstance (Process *process, bool force)
+{
+ // Python OperatingSystem plug-ins must be requested by name, so force must be true
+ FileSpec python_os_plugin_spec (process->GetPythonOSPluginPath());
+ if (python_os_plugin_spec && python_os_plugin_spec.Exists())
+ {
+ std::unique_ptr<OperatingSystemPython> os_ap (new OperatingSystemPython (process, python_os_plugin_spec));
+ if (os_ap.get() && os_ap->IsValid())
+ return os_ap.release();
+ }
+ return NULL;
+}
+
+
+ConstString
+OperatingSystemPython::GetPluginNameStatic()
+{
+ static ConstString g_name("python");
+ return g_name;
+}
+
+const char *
+OperatingSystemPython::GetPluginDescriptionStatic()
+{
+ return "Operating system plug-in that gathers OS information from a python class that implements the necessary OperatingSystem functionality.";
+}
+
+
+OperatingSystemPython::OperatingSystemPython (lldb_private::Process *process, const FileSpec &python_module_path) :
+ OperatingSystem (process),
+ m_thread_list_valobj_sp (),
+ m_register_info_ap (),
+ m_interpreter (NULL),
+ m_python_object_sp ()
+{
+ if (!process)
+ return;
+ TargetSP target_sp = process->CalculateTarget();
+ if (!target_sp)
+ return;
+ m_interpreter = target_sp->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (m_interpreter)
+ {
+
+ std::string os_plugin_class_name (python_module_path.GetFilename().AsCString(""));
+ if (!os_plugin_class_name.empty())
+ {
+ const bool init_session = false;
+ const bool allow_reload = true;
+ char python_module_path_cstr[PATH_MAX];
+ python_module_path.GetPath(python_module_path_cstr, sizeof(python_module_path_cstr));
+ Error error;
+ if (m_interpreter->LoadScriptingModule (python_module_path_cstr, allow_reload, init_session, error))
+ {
+ // Strip the ".py" extension if there is one
+ size_t py_extension_pos = os_plugin_class_name.rfind(".py");
+ if (py_extension_pos != std::string::npos)
+ os_plugin_class_name.erase (py_extension_pos);
+ // Add ".OperatingSystemPlugIn" to the module name to get a string like "modulename.OperatingSystemPlugIn"
+ os_plugin_class_name += ".OperatingSystemPlugIn";
+ ScriptInterpreterObjectSP object_sp = m_interpreter->OSPlugin_CreatePluginObject(os_plugin_class_name.c_str(), process->CalculateProcess());
+ if (object_sp && object_sp->GetObject())
+ m_python_object_sp = object_sp;
+ }
+ }
+ }
+}
+
+OperatingSystemPython::~OperatingSystemPython ()
+{
+}
+
+DynamicRegisterInfo *
+OperatingSystemPython::GetDynamicRegisterInfo ()
+{
+ if (m_register_info_ap.get() == NULL)
+ {
+ if (!m_interpreter || !m_python_object_sp)
+ return NULL;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OS));
+
+ if (log)
+ log->Printf ("OperatingSystemPython::GetDynamicRegisterInfo() fetching thread register definitions from python for pid %" PRIu64, m_process->GetID());
+
+ PythonDictionary dictionary(m_interpreter->OSPlugin_RegisterInfo(m_python_object_sp));
+ if (!dictionary)
+ return NULL;
+
+ m_register_info_ap.reset (new DynamicRegisterInfo (dictionary));
+ assert (m_register_info_ap->GetNumRegisters() > 0);
+ assert (m_register_info_ap->GetNumRegisterSets() > 0);
+ }
+ return m_register_info_ap.get();
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+ConstString
+OperatingSystemPython::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+OperatingSystemPython::GetPluginVersion()
+{
+ return 1;
+}
+
+bool
+OperatingSystemPython::UpdateThreadList (ThreadList &old_thread_list,
+ ThreadList &core_thread_list,
+ ThreadList &new_thread_list)
+{
+ if (!m_interpreter || !m_python_object_sp)
+ return false;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OS));
+
+ // First thing we have to do is get the API lock, and the run lock. We're going to change the thread
+ // content of the process, and we're going to use python, which requires the API lock to do it.
+ // So get & hold that. This is a recursive lock so we can grant it to any Python code called on the stack below us.
+ Target &target = m_process->GetTarget();
+ Mutex::Locker api_locker (target.GetAPIMutex());
+
+ if (log)
+ log->Printf ("OperatingSystemPython::UpdateThreadList() fetching thread data from python for pid %" PRIu64, m_process->GetID());
+
+ // The threads that are in "new_thread_list" upon entry are the threads from the
+ // lldb_private::Process subclass, no memory threads will be in this list.
+
+ auto lock = m_interpreter->AcquireInterpreterLock(); // to make sure threads_list stays alive
+ PythonList threads_list(m_interpreter->OSPlugin_ThreadsInfo(m_python_object_sp));
+ if (threads_list)
+ {
+ if (log)
+ {
+ StreamString strm;
+ threads_list.Dump(strm);
+ log->Printf("threads_list = %s", strm.GetString().c_str());
+ }
+ uint32_t i;
+ const uint32_t num_threads = threads_list.GetSize();
+ if (num_threads > 0)
+ {
+ for (i=0; i<num_threads; ++i)
+ {
+ PythonDictionary thread_dict(threads_list.GetItemAtIndex(i));
+ if (thread_dict)
+ {
+ ThreadSP thread_sp (CreateThreadFromThreadInfo (thread_dict, core_thread_list, old_thread_list, NULL));
+ if (thread_sp)
+ new_thread_list.AddThread(thread_sp);
+ }
+ }
+ }
+ }
+
+ // No new threads added from the thread info array gotten from python, just
+ // display the core threads.
+ if (new_thread_list.GetSize(false) == 0)
+ new_thread_list = core_thread_list;
+
+ return new_thread_list.GetSize(false) > 0;
+}
+
+ThreadSP
+OperatingSystemPython::CreateThreadFromThreadInfo (PythonDictionary &thread_dict,
+ ThreadList &core_thread_list,
+ ThreadList &old_thread_list,
+ bool *did_create_ptr)
+{
+ ThreadSP thread_sp;
+ if (thread_dict)
+ {
+ PythonString tid_pystr("tid");
+ const tid_t tid = thread_dict.GetItemForKeyAsInteger (tid_pystr, LLDB_INVALID_THREAD_ID);
+ if (tid != LLDB_INVALID_THREAD_ID)
+ {
+ PythonString core_pystr("core");
+ PythonString name_pystr("name");
+ PythonString queue_pystr("queue");
+ //PythonString state_pystr("state");
+ //PythonString stop_reason_pystr("stop_reason");
+ PythonString reg_data_addr_pystr ("register_data_addr");
+
+ const uint32_t core_number = thread_dict.GetItemForKeyAsInteger (core_pystr, UINT32_MAX);
+ const addr_t reg_data_addr = thread_dict.GetItemForKeyAsInteger (reg_data_addr_pystr, LLDB_INVALID_ADDRESS);
+ const char *name = thread_dict.GetItemForKeyAsString (name_pystr);
+ const char *queue = thread_dict.GetItemForKeyAsString (queue_pystr);
+ //const char *state = thread_dict.GetItemForKeyAsString (state_pystr);
+ //const char *stop_reason = thread_dict.GetItemForKeyAsString (stop_reason_pystr);
+
+ // See if a thread already exists for "tid"
+ thread_sp = old_thread_list.FindThreadByID (tid, false);
+ if (thread_sp)
+ {
+ // A thread already does exist for "tid", make sure it was an operating system
+ // plug-in generated thread.
+ if (!IsOperatingSystemPluginThread(thread_sp))
+ {
+ // We have thread ID overlap between the protocol threads and the
+ // operating system threads, clear the thread so we create an
+ // operating system thread for this.
+ thread_sp.reset();
+ }
+ }
+
+ if (!thread_sp)
+ {
+ if (did_create_ptr)
+ *did_create_ptr = true;
+ thread_sp.reset (new ThreadMemory (*m_process,
+ tid,
+ name,
+ queue,
+ reg_data_addr));
+
+ }
+
+ if (core_number < core_thread_list.GetSize(false))
+ {
+ ThreadSP core_thread_sp (core_thread_list.GetThreadAtIndex(core_number, false));
+ if (core_thread_sp)
+ {
+ ThreadSP backing_core_thread_sp (core_thread_sp->GetBackingThread());
+ if (backing_core_thread_sp)
+ {
+ thread_sp->SetBackingThread(backing_core_thread_sp);
+ }
+ else
+ {
+ thread_sp->SetBackingThread(core_thread_sp);
+ }
+ }
+ }
+ }
+ }
+ return thread_sp;
+}
+
+
+
+void
+OperatingSystemPython::ThreadWasSelected (Thread *thread)
+{
+}
+
+RegisterContextSP
+OperatingSystemPython::CreateRegisterContextForThread (Thread *thread, addr_t reg_data_addr)
+{
+ RegisterContextSP reg_ctx_sp;
+ if (!m_interpreter || !m_python_object_sp || !thread)
+ return reg_ctx_sp;
+
+ if (!IsOperatingSystemPluginThread(thread->shared_from_this()))
+ return reg_ctx_sp;
+
+ // First thing we have to do is get the API lock, and the run lock. We're going to change the thread
+ // content of the process, and we're going to use python, which requires the API lock to do it.
+ // So get & hold that. This is a recursive lock so we can grant it to any Python code called on the stack below us.
+ Target &target = m_process->GetTarget();
+ Mutex::Locker api_locker (target.GetAPIMutex());
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ auto lock = m_interpreter->AcquireInterpreterLock(); // to make sure python objects stays alive
+ if (reg_data_addr != LLDB_INVALID_ADDRESS)
+ {
+ // The registers data is in contiguous memory, just create the register
+ // context using the address provided
+ if (log)
+ log->Printf ("OperatingSystemPython::CreateRegisterContextForThread (tid = 0x%" PRIx64 ", 0x%" PRIx64 ", reg_data_addr = 0x%" PRIx64 ") creating memory register context",
+ thread->GetID(),
+ thread->GetProtocolID(),
+ reg_data_addr);
+ reg_ctx_sp.reset (new RegisterContextMemory (*thread, 0, *GetDynamicRegisterInfo (), reg_data_addr));
+ }
+ else
+ {
+ // No register data address is provided, query the python plug-in to let
+ // it make up the data as it sees fit
+ if (log)
+ log->Printf ("OperatingSystemPython::CreateRegisterContextForThread (tid = 0x%" PRIx64 ", 0x%" PRIx64 ") fetching register data from python",
+ thread->GetID(),
+ thread->GetProtocolID());
+
+ PythonString reg_context_data(m_interpreter->OSPlugin_RegisterContextData (m_python_object_sp, thread->GetID()));
+ if (reg_context_data)
+ {
+ DataBufferSP data_sp (new DataBufferHeap (reg_context_data.GetString(),
+ reg_context_data.GetSize()));
+ if (data_sp->GetByteSize())
+ {
+ RegisterContextMemory *reg_ctx_memory = new RegisterContextMemory (*thread, 0, *GetDynamicRegisterInfo (), LLDB_INVALID_ADDRESS);
+ if (reg_ctx_memory)
+ {
+ reg_ctx_sp.reset(reg_ctx_memory);
+ reg_ctx_memory->SetAllRegisterData (data_sp);
+ }
+ }
+ }
+ }
+ // if we still have no register data, fallback on a dummy context to avoid crashing
+ if (!reg_ctx_sp)
+ {
+ if (log)
+ log->Printf ("OperatingSystemPython::CreateRegisterContextForThread (tid = 0x%" PRIx64 ") forcing a dummy register context", thread->GetID());
+ reg_ctx_sp.reset(new RegisterContextDummy(*thread,0,target.GetArchitecture().GetAddressByteSize()));
+ }
+ return reg_ctx_sp;
+}
+
+StopInfoSP
+OperatingSystemPython::CreateThreadStopReason (lldb_private::Thread *thread)
+{
+ // We should have gotten the thread stop info from the dictionary of data for
+ // the thread in the initial call to get_thread_info(), this should have been
+ // cached so we can return it here
+ StopInfoSP stop_info_sp; //(StopInfo::CreateStopReasonWithSignal (*thread, SIGSTOP));
+ return stop_info_sp;
+}
+
+lldb::ThreadSP
+OperatingSystemPython::CreateThread (lldb::tid_t tid, addr_t context)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ if (log)
+ log->Printf ("OperatingSystemPython::CreateThread (tid = 0x%" PRIx64 ", context = 0x%" PRIx64 ") fetching register data from python", tid, context);
+
+ if (m_interpreter && m_python_object_sp)
+ {
+ // First thing we have to do is get the API lock, and the run lock. We're going to change the thread
+ // content of the process, and we're going to use python, which requires the API lock to do it.
+ // So get & hold that. This is a recursive lock so we can grant it to any Python code called on the stack below us.
+ Target &target = m_process->GetTarget();
+ Mutex::Locker api_locker (target.GetAPIMutex());
+
+ auto lock = m_interpreter->AcquireInterpreterLock(); // to make sure thread_info_dict stays alive
+ PythonDictionary thread_info_dict (m_interpreter->OSPlugin_CreateThread(m_python_object_sp, tid, context));
+ if (thread_info_dict)
+ {
+ ThreadList core_threads(m_process);
+ ThreadList &thread_list = m_process->GetThreadList();
+ bool did_create = false;
+ ThreadSP thread_sp (CreateThreadFromThreadInfo (thread_info_dict, core_threads, thread_list, &did_create));
+ if (did_create)
+ thread_list.AddThread(thread_sp);
+ return thread_sp;
+ }
+ }
+ return ThreadSP();
+}
+
+
+
+#endif // #ifndef LLDB_DISABLE_PYTHON
diff --git a/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h
new file mode 100644
index 000000000000..077039e50d56
--- /dev/null
+++ b/source/Plugins/OperatingSystem/Python/OperatingSystemPython.h
@@ -0,0 +1,109 @@
+//===-- OperatingSystemPython.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLDB_DISABLE_PYTHON
+
+#ifndef liblldb_OperatingSystemPython_h_
+#define liblldb_OperatingSystemPython_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Target/OperatingSystem.h"
+
+class DynamicRegisterInfo;
+
+class OperatingSystemPython : public lldb_private::OperatingSystem
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static lldb_private::OperatingSystem *
+ CreateInstance (lldb_private::Process *process, bool force);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Class Methods
+ //------------------------------------------------------------------
+ OperatingSystemPython (lldb_private::Process *process,
+ const lldb_private::FileSpec &python_module_path);
+
+ virtual
+ ~OperatingSystemPython ();
+
+ //------------------------------------------------------------------
+ // lldb_private::PluginInterface Methods
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ //------------------------------------------------------------------
+ // lldb_private::OperatingSystem Methods
+ //------------------------------------------------------------------
+ virtual bool
+ UpdateThreadList (lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &real_thread_list,
+ lldb_private::ThreadList &new_thread_list);
+
+ virtual void
+ ThreadWasSelected (lldb_private::Thread *thread);
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForThread (lldb_private::Thread *thread,
+ lldb::addr_t reg_data_addr);
+
+ virtual lldb::StopInfoSP
+ CreateThreadStopReason (lldb_private::Thread *thread);
+
+ //------------------------------------------------------------------
+ // Method for lazy creation of threads on demand
+ //------------------------------------------------------------------
+ virtual lldb::ThreadSP
+ CreateThread (lldb::tid_t tid, lldb::addr_t context);
+
+protected:
+
+ bool IsValid() const
+ {
+ return m_python_object_sp && m_python_object_sp->GetObject() != NULL;
+ }
+
+ lldb::ThreadSP
+ CreateThreadFromThreadInfo (lldb_private::PythonDictionary &thread_dict,
+ lldb_private::ThreadList &core_thread_list,
+ lldb_private::ThreadList &old_thread_list,
+ bool *did_create_ptr);
+
+ DynamicRegisterInfo *
+ GetDynamicRegisterInfo ();
+
+ lldb::ValueObjectSP m_thread_list_valobj_sp;
+ std::unique_ptr<DynamicRegisterInfo> m_register_info_ap;
+ lldb_private::ScriptInterpreter *m_interpreter;
+ lldb::ScriptInterpreterObjectSP m_python_object_sp;
+
+};
+
+#endif // #ifndef liblldb_OperatingSystemPython_h_
+#endif // #ifndef LLDB_DISABLE_PYTHON
diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
new file mode 100644
index 000000000000..dc0917255d9b
--- /dev/null
+++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp
@@ -0,0 +1,648 @@
+//===-- PlatformFreeBSD.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "PlatformFreeBSD.h"
+
+// C Includes
+#include <stdio.h>
+#include <sys/utsname.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Host/Host.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+Platform *
+PlatformFreeBSD::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
+{
+ // The only time we create an instance is when we are creating a remote
+ // freebsd platform
+ const bool is_host = false;
+
+ bool create = force;
+ if (create == false && arch && arch->IsValid())
+ {
+ const llvm::Triple &triple = arch->GetTriple();
+ switch (triple.getVendor())
+ {
+ case llvm::Triple::PC:
+ create = true;
+ break;
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+ // Only accept "unknown" for the vendor if the host is BSD and
+ // it "unknown" wasn't specified (it was just returned becasue it
+ // was NOT specified)
+ case llvm::Triple::UnknownArch:
+ create = !arch->TripleVendorWasSpecified();
+ break;
+#endif
+ default:
+ break;
+ }
+
+ if (create)
+ {
+ switch (triple.getOS())
+ {
+ case llvm::Triple::FreeBSD:
+ case llvm::Triple::KFreeBSD:
+ break;
+
+#if defined(__FreeBSD__) || defined(__OpenBSD__)
+ // Only accept "unknown" for the OS if the host is BSD and
+ // it "unknown" wasn't specified (it was just returned becasue it
+ // was NOT specified)
+ case llvm::Triple::UnknownOS:
+ create = arch->TripleOSWasSpecified();
+ break;
+#endif
+ default:
+ create = false;
+ break;
+ }
+ }
+ }
+ if (create)
+ return new PlatformFreeBSD (is_host);
+ return NULL;
+
+}
+
+lldb_private::ConstString
+PlatformFreeBSD::GetPluginNameStatic (bool is_host)
+{
+ if (is_host)
+ {
+ static ConstString g_host_name(Platform::GetHostPlatformName ());
+ return g_host_name;
+ }
+ else
+ {
+ static ConstString g_remote_name("remote-freebsd");
+ return g_remote_name;
+ }
+}
+
+const char *
+PlatformFreeBSD::GetDescriptionStatic (bool is_host)
+{
+ if (is_host)
+ return "Local FreeBSD user platform plug-in.";
+ else
+ return "Remote FreeBSD user platform plug-in.";
+}
+
+static uint32_t g_initialize_count = 0;
+
+void
+PlatformFreeBSD::Initialize ()
+{
+ if (g_initialize_count++ == 0)
+ {
+#if defined (__FreeBSD__)
+ // Force a host flag to true for the default platform object.
+ PlatformSP default_platform_sp (new PlatformFreeBSD(true));
+ default_platform_sp->SetSystemArchitecture (Host::GetArchitecture());
+ Platform::SetDefaultPlatform (default_platform_sp);
+#endif
+ PluginManager::RegisterPlugin(PlatformFreeBSD::GetPluginNameStatic(false),
+ PlatformFreeBSD::GetDescriptionStatic(false),
+ PlatformFreeBSD::CreateInstance);
+ }
+}
+
+void
+PlatformFreeBSD::Terminate ()
+{
+ if (g_initialize_count > 0 && --g_initialize_count == 0)
+ PluginManager::UnregisterPlugin (PlatformFreeBSD::CreateInstance);
+}
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformFreeBSD::PlatformFreeBSD (bool is_host) :
+Platform(is_host)
+{
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformFreeBSD::~PlatformFreeBSD()
+{
+}
+
+
+Error
+PlatformFreeBSD::ResolveExecutable (const FileSpec &exe_file,
+ const ArchSpec &exe_arch,
+ lldb::ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr)
+{
+ Error error;
+ // Nothing special to do here, just use the actual file and architecture
+
+ char exe_path[PATH_MAX];
+ FileSpec resolved_exe_file (exe_file);
+
+ if (IsHost())
+ {
+ // If we have "ls" as the exe_file, resolve the executable location based on
+ // the current path variables
+ if (!resolved_exe_file.Exists())
+ {
+ exe_file.GetPath(exe_path, sizeof(exe_path));
+ resolved_exe_file.SetFile(exe_path, true);
+ }
+
+ if (!resolved_exe_file.Exists())
+ resolved_exe_file.ResolveExecutableLocation ();
+
+ if (resolved_exe_file.Exists())
+ error.Clear();
+ else
+ {
+ exe_file.GetPath(exe_path, sizeof(exe_path));
+ error.SetErrorStringWithFormat("unable to find executable for '%s'", exe_path);
+ }
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ {
+ error = m_remote_platform_sp->ResolveExecutable (exe_file,
+ exe_arch,
+ exe_module_sp,
+ module_search_paths_ptr);
+ }
+ else
+ {
+ // We may connect to a process and use the provided executable (Don't use local $PATH).
+
+ // Resolve any executable within a bundle on MacOSX
+ Host::ResolveExecutableInBundle (resolved_exe_file);
+
+ if (resolved_exe_file.Exists()) {
+ error.Clear();
+ }
+ else
+ {
+ exe_file.GetPath(exe_path, sizeof(exe_path));
+ error.SetErrorStringWithFormat("the platform is not currently connected, and '%s' doesn't exist in the system root.", exe_path);
+ }
+ }
+ }
+
+
+ if (error.Success())
+ {
+ ModuleSpec module_spec (resolved_exe_file, exe_arch);
+ if (module_spec.GetArchitecture().IsValid())
+ {
+ error = ModuleList::GetSharedModule (module_spec,
+ exe_module_sp,
+ module_search_paths_ptr,
+ NULL,
+ NULL);
+
+ if (!exe_module_sp || exe_module_sp->GetObjectFile() == NULL)
+ {
+ exe_module_sp.reset();
+ error.SetErrorStringWithFormat ("'%s' doesn't contain the architecture %s",
+ exe_file.GetPath().c_str(),
+ exe_arch.GetArchitectureName());
+ }
+ }
+ else
+ {
+ // No valid architecture was specified, ask the platform for
+ // the architectures that we should be using (in the correct order)
+ // and see if we can find a match that way
+ StreamString arch_names;
+ ArchSpec platform_arch;
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, platform_arch); ++idx)
+ {
+ error = ModuleList::GetSharedModule (module_spec,
+ exe_module_sp,
+ module_search_paths_ptr,
+ NULL,
+ NULL);
+ // Did we find an executable using one of the
+ if (error.Success())
+ {
+ if (exe_module_sp && exe_module_sp->GetObjectFile())
+ break;
+ else
+ error.SetErrorToGenericError();
+ }
+
+ if (idx > 0)
+ arch_names.PutCString (", ");
+ arch_names.PutCString (platform_arch.GetArchitectureName());
+ }
+
+ if (error.Fail() || !exe_module_sp)
+ {
+ error.SetErrorStringWithFormat ("'%s' doesn't contain any '%s' platform architectures: %s",
+ exe_file.GetPath().c_str(),
+ GetPluginName().GetCString(),
+ arch_names.GetString().c_str());
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("'%s' does not exist",
+ exe_file.GetPath().c_str());
+ }
+
+ return error;
+}
+
+size_t
+PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site)
+{
+ ArchSpec arch = target.GetArchitecture();
+ const uint8_t *trap_opcode = NULL;
+ size_t trap_opcode_size = 0;
+
+ switch (arch.GetCore())
+ {
+ default:
+ assert(false && "Unhandled architecture in PlatformFreeBSD::GetSoftwareBreakpointTrapOpcode()");
+ break;
+
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_64_x86_64:
+ {
+ static const uint8_t g_i386_opcode[] = { 0xCC };
+ trap_opcode = g_i386_opcode;
+ trap_opcode_size = sizeof(g_i386_opcode);
+ }
+ break;
+ }
+
+ if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size))
+ return trap_opcode_size;
+
+ return 0;
+}
+
+bool
+PlatformFreeBSD::GetRemoteOSVersion ()
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetOSVersion (m_major_os_version,
+ m_minor_os_version,
+ m_update_os_version);
+ return false;
+}
+
+bool
+PlatformFreeBSD::GetRemoteOSBuildString (std::string &s)
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetRemoteOSBuildString (s);
+ s.clear();
+ return false;
+}
+
+bool
+PlatformFreeBSD::GetRemoteOSKernelDescription (std::string &s)
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetRemoteOSKernelDescription (s);
+ s.clear();
+ return false;
+}
+
+// Remote Platform subclasses need to override this function
+ArchSpec
+PlatformFreeBSD::GetRemoteSystemArchitecture ()
+{
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetRemoteSystemArchitecture ();
+ return ArchSpec();
+}
+
+
+const char *
+PlatformFreeBSD::GetHostname ()
+{
+ if (IsHost())
+ return Platform::GetHostname();
+
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetHostname ();
+ return NULL;
+}
+
+bool
+PlatformFreeBSD::IsConnected () const
+{
+ if (IsHost())
+ return true;
+ else if (m_remote_platform_sp)
+ return m_remote_platform_sp->IsConnected();
+ return false;
+}
+
+Error
+PlatformFreeBSD::ConnectRemote (Args& args)
+{
+ Error error;
+ if (IsHost())
+ {
+ error.SetErrorStringWithFormat ("can't connect to the host platform '%s', always connected", GetPluginName().GetCString());
+ }
+ else
+ {
+ if (!m_remote_platform_sp)
+ m_remote_platform_sp = Platform::Create ("remote-gdb-server", error);
+
+ if (m_remote_platform_sp)
+ {
+ if (error.Success())
+ {
+ if (m_remote_platform_sp)
+ {
+ error = m_remote_platform_sp->ConnectRemote (args);
+ }
+ else
+ {
+ error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
+ }
+ }
+ }
+ else
+ error.SetErrorString ("failed to create a 'remote-gdb-server' platform");
+
+ if (error.Fail())
+ m_remote_platform_sp.reset();
+ }
+
+ return error;
+}
+
+Error
+PlatformFreeBSD::DisconnectRemote ()
+{
+ Error error;
+
+ if (IsHost())
+ {
+ error.SetErrorStringWithFormat ("can't disconnect from the host platform '%s', always connected", GetPluginName().GetCString());
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ error = m_remote_platform_sp->DisconnectRemote ();
+ else
+ error.SetErrorString ("the platform is not currently connected");
+ }
+ return error;
+}
+
+bool
+PlatformFreeBSD::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ bool success = false;
+ if (IsHost())
+ {
+ success = Platform::GetProcessInfo (pid, process_info);
+ }
+ else if (m_remote_platform_sp)
+ {
+ success = m_remote_platform_sp->GetProcessInfo (pid, process_info);
+ }
+ return success;
+}
+
+
+
+uint32_t
+PlatformFreeBSD::FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos)
+{
+ uint32_t match_count = 0;
+ if (IsHost())
+ {
+ // Let the base class figure out the host details
+ match_count = Platform::FindProcesses (match_info, process_infos);
+ }
+ else
+ {
+ // If we are remote, we can only return results if we are connected
+ if (m_remote_platform_sp)
+ match_count = m_remote_platform_sp->FindProcesses (match_info, process_infos);
+ }
+ return match_count;
+}
+
+Error
+PlatformFreeBSD::LaunchProcess (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ if (IsHost())
+ {
+ error = Platform::LaunchProcess (launch_info);
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ error = m_remote_platform_sp->LaunchProcess (launch_info);
+ else
+ error.SetErrorString ("the platform is not currently connected");
+ }
+ return error;
+}
+
+lldb::ProcessSP
+PlatformFreeBSD::Attach(ProcessAttachInfo &attach_info,
+ Debugger &debugger,
+ Target *target,
+ Listener &listener,
+ Error &error)
+{
+ lldb::ProcessSP process_sp;
+ if (IsHost())
+ {
+ if (target == NULL)
+ {
+ TargetSP new_target_sp;
+ ArchSpec emptyArchSpec;
+
+ error = debugger.GetTargetList().CreateTarget (debugger,
+ NULL,
+ emptyArchSpec,
+ false,
+ m_remote_platform_sp,
+ new_target_sp);
+ target = new_target_sp.get();
+ }
+ else
+ error.Clear();
+
+ if (target && error.Success())
+ {
+ debugger.GetTargetList().SetSelectedTarget(target);
+ // The freebsd always currently uses the GDB remote debugger plug-in
+ // so even when debugging locally we are debugging remotely!
+ // Just like the darwin plugin.
+ process_sp = target->CreateProcess (listener, "gdb-remote", NULL);
+
+ if (process_sp)
+ error = process_sp->Attach (attach_info);
+ }
+ }
+ else
+ {
+ if (m_remote_platform_sp)
+ process_sp = m_remote_platform_sp->Attach (attach_info, debugger, target, listener, error);
+ else
+ error.SetErrorString ("the platform is not currently connected");
+ }
+ return process_sp;
+}
+
+const char *
+PlatformFreeBSD::GetUserName (uint32_t uid)
+{
+ // Check the cache in Platform in case we have already looked this uid up
+ const char *user_name = Platform::GetUserName(uid);
+ if (user_name)
+ return user_name;
+
+ if (IsRemote() && m_remote_platform_sp)
+ return m_remote_platform_sp->GetUserName(uid);
+ return NULL;
+}
+
+const char *
+PlatformFreeBSD::GetGroupName (uint32_t gid)
+{
+ const char *group_name = Platform::GetGroupName(gid);
+ if (group_name)
+ return group_name;
+
+ if (IsRemote() && m_remote_platform_sp)
+ return m_remote_platform_sp->GetGroupName(gid);
+ return NULL;
+}
+
+
+// From PlatformMacOSX only
+Error
+PlatformFreeBSD::GetFile (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file)
+{
+ if (IsRemote())
+ {
+ if (m_remote_platform_sp)
+ return m_remote_platform_sp->GetFile (platform_file, uuid_ptr, local_file);
+ }
+
+ // Default to the local case
+ local_file = platform_file;
+ return Error();
+}
+
+Error
+PlatformFreeBSD::GetSharedModule (const ModuleSpec &module_spec,
+ ModuleSP &module_sp,
+ const FileSpecList *module_search_paths_ptr,
+ ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr)
+{
+ Error error;
+ module_sp.reset();
+
+ if (IsRemote())
+ {
+ // If we have a remote platform always, let it try and locate
+ // the shared module first.
+ if (m_remote_platform_sp)
+ {
+ error = m_remote_platform_sp->GetSharedModule (module_spec,
+ module_sp,
+ module_search_paths_ptr,
+ old_module_sp_ptr,
+ did_create_ptr);
+ }
+ }
+
+ if (!module_sp)
+ {
+ // Fall back to the local platform and find the file locally
+ error = Platform::GetSharedModule (module_spec,
+ module_sp,
+ module_search_paths_ptr,
+ old_module_sp_ptr,
+ did_create_ptr);
+ }
+ if (module_sp)
+ module_sp->SetPlatformFileSpec(module_spec.GetFileSpec());
+ return error;
+}
+
+
+bool
+PlatformFreeBSD::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
+{
+ // From macosx;s plugin code. For FreeBSD we may want to support more archs.
+ if (idx == 0)
+ {
+ arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture);
+ return arch.IsValid();
+ }
+ else if (idx == 1)
+ {
+ ArchSpec platform_arch (Host::GetArchitecture (Host::eSystemDefaultArchitecture));
+ ArchSpec platform_arch64 (Host::GetArchitecture (Host::eSystemDefaultArchitecture64));
+ if (platform_arch.IsExactMatch(platform_arch64))
+ {
+ // This freebsd platform supports both 32 and 64 bit. Since we already
+ // returned the 64 bit arch for idx == 0, return the 32 bit arch
+ // for idx == 1
+ arch = Host::GetArchitecture (Host::eSystemDefaultArchitecture32);
+ return arch.IsValid();
+ }
+ }
+ return false;
+}
+
+void
+PlatformFreeBSD::GetStatus (Stream &strm)
+{
+ struct utsname un;
+
+ if (uname(&un)) {
+ strm << "FreeBSD";
+ return;
+ }
+
+ strm << "Host: " << un.sysname << ' ' << un.release << ' ' << un.version << '\n';
+ Platform::GetStatus(strm);
+}
diff --git a/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
new file mode 100644
index 000000000000..4aa158eb6e87
--- /dev/null
+++ b/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.h
@@ -0,0 +1,162 @@
+//===-- PlatformFreeBSD.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_PlatformFreeBSD_h_
+#define liblldb_PlatformFreeBSD_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Platform.h"
+
+class PlatformFreeBSD : public lldb_private::Platform
+{
+public:
+ // Mostly taken from PlatformDarwin and PlatformMacOSX
+
+ //------------------------------------------------------------
+ // Class functions
+ //------------------------------------------------------------
+ static lldb_private::Platform*
+ CreateInstance (bool force, const lldb_private::ArchSpec *arch);
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic (bool is_host);
+
+ static const char *
+ GetDescriptionStatic (bool is_host);
+
+ //------------------------------------------------------------
+ // Class Methods
+ //------------------------------------------------------------
+ PlatformFreeBSD (bool is_host);
+
+ virtual
+ ~PlatformFreeBSD();
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName()
+ {
+ return GetPluginNameStatic (IsHost());
+ }
+
+ virtual uint32_t
+ GetPluginVersion()
+ {
+ return 1;
+ }
+
+ virtual const char *
+ GetDescription ()
+ {
+ return GetDescriptionStatic(IsHost());
+ }
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ virtual lldb_private::Error
+ ResolveExecutable (const lldb_private::FileSpec &exe_file,
+ const lldb_private::ArchSpec &arch,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr);
+
+ virtual size_t
+ GetSoftwareBreakpointTrapOpcode (lldb_private::Target &target,
+ lldb_private::BreakpointSite *bp_site);
+
+ virtual bool
+ GetRemoteOSVersion ();
+
+ virtual bool
+ GetRemoteOSBuildString (std::string &s);
+
+ virtual bool
+ GetRemoteOSKernelDescription (std::string &s);
+
+ // Remote Platform subclasses need to override this function
+ virtual lldb_private::ArchSpec
+ GetRemoteSystemArchitecture ();
+
+ virtual bool
+ IsConnected () const;
+
+ virtual lldb_private::Error
+ ConnectRemote (lldb_private::Args& args);
+
+ virtual lldb_private::Error
+ DisconnectRemote ();
+
+ virtual const char *
+ GetHostname ();
+
+ virtual const char *
+ GetUserName (uint32_t uid);
+
+ virtual const char *
+ GetGroupName (uint32_t gid);
+
+ virtual bool
+ GetProcessInfo (lldb::pid_t pid,
+ lldb_private::ProcessInstanceInfo &proc_info);
+
+ virtual uint32_t
+ FindProcesses (const lldb_private::ProcessInstanceInfoMatch &match_info,
+ lldb_private::ProcessInstanceInfoList &process_infos);
+
+ virtual lldb_private::Error
+ LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info);
+
+ virtual lldb::ProcessSP
+ Attach(lldb_private::ProcessAttachInfo &attach_info,
+ lldb_private::Debugger &debugger,
+ lldb_private::Target *target,
+ lldb_private::Listener &listener,
+ lldb_private::Error &error);
+
+ // FreeBSD processes can not be launched by spawning and attaching.
+ virtual bool
+ CanDebugProcess () { return false; }
+
+ // Only on PlatformMacOSX:
+ virtual lldb_private::Error
+ GetFile (const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID* uuid, lldb_private::FileSpec &local_file);
+
+ lldb_private::Error
+ GetSharedModule (const lldb_private::ModuleSpec &module_spec,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr,
+ lldb::ModuleSP *old_module_sp_ptr,
+ bool *did_create_ptr);
+
+ virtual bool
+ GetSupportedArchitectureAtIndex (uint32_t idx, lldb_private::ArchSpec &arch);
+
+ virtual void
+ GetStatus (lldb_private::Stream &strm);
+
+protected:
+ lldb::PlatformSP m_remote_platform_sp; // Allow multiple ways to connect to a remote freebsd OS
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformFreeBSD);
+};
+
+#endif // liblldb_PlatformFreeBSD_h_
diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
new file mode 100644
index 000000000000..684d1921e920
--- /dev/null
+++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.cpp
@@ -0,0 +1,418 @@
+//===-- PlatformRemoteGDBServer.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "PlatformRemoteGDBServer.h"
+
+// C Includes
+#include <sys/sysctl.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+static bool g_initialized = false;
+
+void
+PlatformRemoteGDBServer::Initialize ()
+{
+ if (g_initialized == false)
+ {
+ g_initialized = true;
+ PluginManager::RegisterPlugin (PlatformRemoteGDBServer::GetPluginNameStatic(),
+ PlatformRemoteGDBServer::GetDescriptionStatic(),
+ PlatformRemoteGDBServer::CreateInstance);
+ }
+}
+
+void
+PlatformRemoteGDBServer::Terminate ()
+{
+ if (g_initialized)
+ {
+ g_initialized = false;
+ PluginManager::UnregisterPlugin (PlatformRemoteGDBServer::CreateInstance);
+ }
+}
+
+Platform*
+PlatformRemoteGDBServer::CreateInstance (bool force, const lldb_private::ArchSpec *arch)
+{
+ bool create = force;
+ if (!create)
+ {
+ create = !arch->TripleVendorWasSpecified() && !arch->TripleOSWasSpecified();
+ }
+ if (create)
+ return new PlatformRemoteGDBServer ();
+ return NULL;
+}
+
+
+lldb_private::ConstString
+PlatformRemoteGDBServer::GetPluginNameStatic()
+{
+ static ConstString g_name("remote-gdb-server");
+ return g_name;
+}
+
+const char *
+PlatformRemoteGDBServer::GetDescriptionStatic()
+{
+ return "A platform that uses the GDB remote protocol as the communication transport.";
+}
+
+const char *
+PlatformRemoteGDBServer::GetDescription ()
+{
+ if (m_platform_description.empty())
+ {
+ if (IsConnected())
+ {
+ // Send the get description packet
+ }
+ }
+
+ if (!m_platform_description.empty())
+ return m_platform_description.c_str();
+ return GetDescriptionStatic();
+}
+
+Error
+PlatformRemoteGDBServer::ResolveExecutable (const FileSpec &exe_file,
+ const ArchSpec &exe_arch,
+ lldb::ModuleSP &exe_module_sp,
+ const FileSpecList *module_search_paths_ptr)
+{
+ Error error;
+ error.SetErrorString ("PlatformRemoteGDBServer::ResolveExecutable() is unimplemented");
+ return error;
+}
+
+Error
+PlatformRemoteGDBServer::GetFile (const FileSpec &platform_file,
+ const UUID *uuid_ptr,
+ FileSpec &local_file)
+{
+ // Default to the local case
+ local_file = platform_file;
+ return Error();
+}
+
+//------------------------------------------------------------------
+/// Default Constructor
+//------------------------------------------------------------------
+PlatformRemoteGDBServer::PlatformRemoteGDBServer () :
+ Platform(false), // This is a remote platform
+ m_gdb_client(true)
+{
+}
+
+//------------------------------------------------------------------
+/// Destructor.
+///
+/// The destructor is virtual since this class is designed to be
+/// inherited from by the plug-in instance.
+//------------------------------------------------------------------
+PlatformRemoteGDBServer::~PlatformRemoteGDBServer()
+{
+}
+
+bool
+PlatformRemoteGDBServer::GetSupportedArchitectureAtIndex (uint32_t idx, ArchSpec &arch)
+{
+ return false;
+}
+
+size_t
+PlatformRemoteGDBServer::GetSoftwareBreakpointTrapOpcode (Target &target, BreakpointSite *bp_site)
+{
+ // This isn't needed if the z/Z packets are supported in the GDB remote
+ // server. But we might need a packet to detect this.
+ return 0;
+}
+
+bool
+PlatformRemoteGDBServer::GetRemoteOSVersion ()
+{
+ uint32_t major, minor, update;
+ if (m_gdb_client.GetOSVersion (major, minor, update))
+ {
+ m_major_os_version = major;
+ m_minor_os_version = minor;
+ m_update_os_version = update;
+ return true;
+ }
+ return false;
+}
+
+bool
+PlatformRemoteGDBServer::GetRemoteOSBuildString (std::string &s)
+{
+ return m_gdb_client.GetOSBuildString (s);
+}
+
+bool
+PlatformRemoteGDBServer::GetRemoteOSKernelDescription (std::string &s)
+{
+ return m_gdb_client.GetOSKernelDescription (s);
+}
+
+// Remote Platform subclasses need to override this function
+ArchSpec
+PlatformRemoteGDBServer::GetRemoteSystemArchitecture ()
+{
+ return m_gdb_client.GetSystemArchitecture();
+}
+
+bool
+PlatformRemoteGDBServer::IsConnected () const
+{
+ return m_gdb_client.IsConnected();
+}
+
+Error
+PlatformRemoteGDBServer::ConnectRemote (Args& args)
+{
+ Error error;
+ if (IsConnected())
+ {
+ error.SetErrorStringWithFormat ("the platform is already connected to '%s', execute 'platform disconnect' to close the current connection",
+ GetHostname());
+ }
+ else
+ {
+ if (args.GetArgumentCount() == 1)
+ {
+ const char *url = args.GetArgumentAtIndex(0);
+ m_gdb_client.SetConnection (new ConnectionFileDescriptor());
+ const ConnectionStatus status = m_gdb_client.Connect(url, &error);
+ if (status == eConnectionStatusSuccess)
+ {
+ if (m_gdb_client.HandshakeWithServer(&error))
+ {
+ m_gdb_client.QueryNoAckModeSupported();
+ m_gdb_client.GetHostInfo();
+#if 0
+ m_gdb_client.TestPacketSpeed(10000);
+#endif
+ }
+ else
+ {
+ m_gdb_client.Disconnect();
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString ("\"platform connect\" takes a single argument: <connect-url>");
+ }
+ }
+
+ return error;
+}
+
+Error
+PlatformRemoteGDBServer::DisconnectRemote ()
+{
+ Error error;
+ m_gdb_client.Disconnect(&error);
+ return error;
+}
+
+const char *
+PlatformRemoteGDBServer::GetHostname ()
+{
+ m_gdb_client.GetHostname (m_name);
+ if (m_name.empty())
+ return NULL;
+ return m_name.c_str();
+}
+
+const char *
+PlatformRemoteGDBServer::GetUserName (uint32_t uid)
+{
+ // Try and get a cache user name first
+ const char *cached_user_name = Platform::GetUserName(uid);
+ if (cached_user_name)
+ return cached_user_name;
+ std::string name;
+ if (m_gdb_client.GetUserName(uid, name))
+ return SetCachedUserName(uid, name.c_str(), name.size());
+
+ SetUserNameNotFound(uid); // Negative cache so we don't keep sending packets
+ return NULL;
+}
+
+const char *
+PlatformRemoteGDBServer::GetGroupName (uint32_t gid)
+{
+ const char *cached_group_name = Platform::GetGroupName(gid);
+ if (cached_group_name)
+ return cached_group_name;
+ std::string name;
+ if (m_gdb_client.GetGroupName(gid, name))
+ return SetCachedGroupName(gid, name.c_str(), name.size());
+
+ SetGroupNameNotFound(gid); // Negative cache so we don't keep sending packets
+ return NULL;
+}
+
+uint32_t
+PlatformRemoteGDBServer::FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos)
+{
+ return m_gdb_client.FindProcesses (match_info, process_infos);
+}
+
+bool
+PlatformRemoteGDBServer::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ return m_gdb_client.GetProcessInfo (pid, process_info);
+}
+
+
+Error
+PlatformRemoteGDBServer::LaunchProcess (ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+
+ m_gdb_client.SetSTDIN ("/dev/null");
+ m_gdb_client.SetSTDOUT ("/dev/null");
+ m_gdb_client.SetSTDERR ("/dev/null");
+ m_gdb_client.SetDisableASLR (launch_info.GetFlags().Test (eLaunchFlagDisableASLR));
+
+ const char *working_dir = launch_info.GetWorkingDirectory();
+ if (working_dir && working_dir[0])
+ {
+ m_gdb_client.SetWorkingDir (working_dir);
+ }
+
+ // Send the environment and the program + arguments after we connect
+ const char **argv = launch_info.GetArguments().GetConstArgumentVector();
+ const char **envp = launch_info.GetEnvironmentEntries().GetConstArgumentVector();
+
+ if (envp)
+ {
+ const char *env_entry;
+ for (int i=0; (env_entry = envp[i]); ++i)
+ {
+ if (m_gdb_client.SendEnvironmentPacket(env_entry) != 0)
+ break;
+ }
+ }
+ const uint32_t old_packet_timeout = m_gdb_client.SetPacketTimeout (5);
+ int arg_packet_err = m_gdb_client.SendArgumentsPacket (argv);
+ m_gdb_client.SetPacketTimeout (old_packet_timeout);
+ if (arg_packet_err == 0)
+ {
+ std::string error_str;
+ if (m_gdb_client.GetLaunchSuccess (error_str))
+ {
+ pid = m_gdb_client.GetCurrentProcessID ();
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ launch_info.SetProcessID (pid);
+ }
+ else
+ {
+ error.SetErrorString (error_str.c_str());
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'A' packet returned an error: %i", arg_packet_err);
+ }
+ return error;
+}
+
+lldb::ProcessSP
+PlatformRemoteGDBServer::Attach (lldb_private::ProcessAttachInfo &attach_info,
+ Debugger &debugger,
+ Target *target, // Can be NULL, if NULL create a new target, else use existing one
+ Listener &listener,
+ Error &error)
+{
+ lldb::ProcessSP process_sp;
+ if (IsRemote())
+ {
+ if (IsConnected())
+ {
+ uint16_t port = m_gdb_client.LaunchGDBserverAndGetPort();
+
+ if (port == 0)
+ {
+ error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ());
+ }
+ else
+ {
+ if (target == NULL)
+ {
+ TargetSP new_target_sp;
+
+ error = debugger.GetTargetList().CreateTarget (debugger,
+ NULL,
+ NULL,
+ false,
+ NULL,
+ new_target_sp);
+ target = new_target_sp.get();
+ }
+ else
+ error.Clear();
+
+ if (target && error.Success())
+ {
+ debugger.GetTargetList().SetSelectedTarget(target);
+
+ // The darwin always currently uses the GDB remote debugger plug-in
+ // so even when debugging locally we are debugging remotely!
+ process_sp = target->CreateProcess (listener, "gdb-remote", NULL);
+
+ if (process_sp)
+ {
+ char connect_url[256];
+ const int connect_url_len = ::snprintf (connect_url,
+ sizeof(connect_url),
+ "connect://%s:%u",
+ GetHostname (),
+ port);
+ assert (connect_url_len < (int)sizeof(connect_url));
+ error = process_sp->ConnectRemote (NULL, connect_url);
+ if (error.Success())
+ error = process_sp->Attach(attach_info);
+ }
+ }
+ }
+ }
+ else
+ {
+ error.SetErrorString("not connected to remote gdb server");
+ }
+ }
+ return process_sp;
+}
+
+
diff --git a/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
new file mode 100644
index 000000000000..22b3dd49be54
--- /dev/null
+++ b/source/Plugins/Platform/gdb-server/PlatformRemoteGDBServer.h
@@ -0,0 +1,147 @@
+//===-- PlatformRemoteGDBServer.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_PlatformRemoteGDBServer_h_
+#define liblldb_PlatformRemoteGDBServer_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Platform.h"
+#include "../../Process/gdb-remote/GDBRemoteCommunicationClient.h"
+
+class PlatformRemoteGDBServer : public lldb_private::Platform
+{
+public:
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ static lldb_private::Platform*
+ CreateInstance (bool force, const lldb_private::ArchSpec *arch);
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetDescriptionStatic();
+
+
+ PlatformRemoteGDBServer ();
+
+ virtual
+ ~PlatformRemoteGDBServer();
+
+ //------------------------------------------------------------
+ // lldb_private::PluginInterface functions
+ //------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName()
+ {
+ return GetPluginNameStatic();
+ }
+
+ virtual uint32_t
+ GetPluginVersion()
+ {
+ return 1;
+ }
+
+
+ //------------------------------------------------------------
+ // lldb_private::Platform functions
+ //------------------------------------------------------------
+ virtual lldb_private::Error
+ ResolveExecutable (const lldb_private::FileSpec &exe_file,
+ const lldb_private::ArchSpec &arch,
+ lldb::ModuleSP &module_sp,
+ const lldb_private::FileSpecList *module_search_paths_ptr);
+
+ virtual const char *
+ GetDescription ();
+
+ virtual lldb_private::Error
+ GetFile (const lldb_private::FileSpec &platform_file,
+ const lldb_private::UUID *uuid_ptr,
+ lldb_private::FileSpec &local_file);
+
+ virtual bool
+ GetProcessInfo (lldb::pid_t pid,
+ lldb_private::ProcessInstanceInfo &proc_info);
+
+ virtual uint32_t
+ FindProcesses (const lldb_private::ProcessInstanceInfoMatch &match_info,
+ lldb_private::ProcessInstanceInfoList &process_infos);
+
+ virtual lldb_private::Error
+ LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info);
+
+ virtual lldb::ProcessSP
+ Attach (lldb_private::ProcessAttachInfo &attach_info,
+ lldb_private::Debugger &debugger,
+ lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one
+ lldb_private::Listener &listener,
+ lldb_private::Error &error);
+
+ virtual bool
+ GetSupportedArchitectureAtIndex (uint32_t idx, lldb_private::ArchSpec &arch);
+
+ virtual size_t
+ GetSoftwareBreakpointTrapOpcode (lldb_private::Target &target,
+ lldb_private::BreakpointSite *bp_site);
+
+ virtual bool
+ GetRemoteOSVersion ();
+
+ virtual bool
+ GetRemoteOSBuildString (std::string &s);
+
+ virtual bool
+ GetRemoteOSKernelDescription (std::string &s);
+
+ // Remote Platform subclasses need to override this function
+ virtual lldb_private::ArchSpec
+ GetRemoteSystemArchitecture ();
+
+ // Remote subclasses should override this and return a valid instance
+ // name if connected.
+ virtual const char *
+ GetHostname ();
+
+ virtual const char *
+ GetUserName (uint32_t uid);
+
+ virtual const char *
+ GetGroupName (uint32_t gid);
+
+ virtual bool
+ IsConnected () const;
+
+ virtual lldb_private::Error
+ ConnectRemote (lldb_private::Args& args);
+
+ virtual lldb_private::Error
+ DisconnectRemote ();
+
+protected:
+ GDBRemoteCommunicationClient m_gdb_client;
+ std::string m_platform_description; // After we connect we can get a more complete description of what we are connected to
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (PlatformRemoteGDBServer);
+
+};
+
+#endif // liblldb_PlatformRemoteGDBServer_h_
diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
new file mode 100644
index 000000000000..ea26d972b860
--- /dev/null
+++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.cpp
@@ -0,0 +1,132 @@
+//===-- ProcessFreeBSD.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <errno.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Target.h"
+
+#include "ProcessFreeBSD.h"
+#include "ProcessPOSIXLog.h"
+#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
+#include "ProcessMonitor.h"
+#include "POSIXThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------------------
+// Static functions.
+
+lldb::ProcessSP
+ProcessFreeBSD::CreateInstance(Target& target,
+ Listener &listener,
+ const FileSpec *crash_file_path)
+{
+ lldb::ProcessSP process_sp;
+ if (crash_file_path == NULL)
+ process_sp.reset(new ProcessFreeBSD (target, listener));
+ return process_sp;
+}
+
+void
+ProcessFreeBSD::Initialize()
+{
+ static bool g_initialized = false;
+
+ if (!g_initialized)
+ {
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+ Log::Callbacks log_callbacks = {
+ ProcessPOSIXLog::DisableLog,
+ ProcessPOSIXLog::EnableLog,
+ ProcessPOSIXLog::ListLogCategories
+ };
+
+ Log::RegisterLogChannel (ProcessFreeBSD::GetPluginNameStatic(), log_callbacks);
+ ProcessPOSIXLog::RegisterPluginName(GetPluginNameStatic());
+ g_initialized = true;
+ }
+}
+
+lldb_private::ConstString
+ProcessFreeBSD::GetPluginNameStatic()
+{
+ static ConstString g_name("freebsd");
+ return g_name;
+}
+
+const char *
+ProcessFreeBSD::GetPluginDescriptionStatic()
+{
+ return "Process plugin for FreeBSD";
+}
+
+//------------------------------------------------------------------------------
+// ProcessInterface protocol.
+
+lldb_private::ConstString
+ProcessFreeBSD::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessFreeBSD::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ProcessFreeBSD::GetPluginCommandHelp(const char *command, Stream *strm)
+{
+}
+
+Error
+ProcessFreeBSD::ExecutePluginCommand(Args &command, Stream *strm)
+{
+ return Error(1, eErrorTypeGeneric);
+}
+
+Log *
+ProcessFreeBSD::EnablePluginLogging(Stream *strm, Args &command)
+{
+ return NULL;
+}
+
+//------------------------------------------------------------------------------
+// Constructors and destructors.
+
+ProcessFreeBSD::ProcessFreeBSD(Target& target, Listener &listener)
+ : ProcessPOSIX(target, listener)
+{
+}
+
+void
+ProcessFreeBSD::Terminate()
+{
+}
+
+bool
+ProcessFreeBSD::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ // XXX haxx
+ new_thread_list = old_thread_list;
+
+ return false;
+}
diff --git a/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
new file mode 100644
index 000000000000..5f79b74cad30
--- /dev/null
+++ b/source/Plugins/Process/FreeBSD/ProcessFreeBSD.h
@@ -0,0 +1,82 @@
+//===-- ProcessFreeBSD.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessFreeBSD_H_
+#define liblldb_ProcessFreeBSD_H_
+
+// C Includes
+
+// C++ Includes
+#include <queue>
+
+// Other libraries and framework includes
+#include "lldb/Target/Process.h"
+#include "lldb/Target/ThreadList.h"
+#include "ProcessMessage.h"
+#include "ProcessPOSIX.h"
+
+class ProcessMonitor;
+
+class ProcessFreeBSD :
+ public ProcessPOSIX
+{
+
+public:
+ //------------------------------------------------------------------
+ // Static functions.
+ //------------------------------------------------------------------
+ static lldb::ProcessSP
+ CreateInstance(lldb_private::Target& target,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec *crash_file_path);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Constructors and destructors
+ //------------------------------------------------------------------
+ ProcessFreeBSD(lldb_private::Target& target,
+ lldb_private::Listener &listener);
+
+ virtual bool
+ UpdateThreadList(lldb_private::ThreadList &old_thread_list, lldb_private::ThreadList &new_thread_list);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ GetPluginCommandHelp(const char *command, lldb_private::Stream *strm);
+
+ virtual lldb_private::Error
+ ExecutePluginCommand(lldb_private::Args &command,
+ lldb_private::Stream *strm);
+
+ virtual lldb_private::Log *
+ EnablePluginLogging(lldb_private::Stream *strm,
+ lldb_private::Args &command);
+
+};
+
+#endif // liblldb_MacOSXProcess_H_
diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
new file mode 100644
index 000000000000..9fd51d2d640a
--- /dev/null
+++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp
@@ -0,0 +1,1677 @@
+//===-- ProcessMonitor.cpp ------------------------------------ -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <errno.h>
+#include <poll.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/PseudoTerminal.h"
+
+
+#include "POSIXThread.h"
+#include "ProcessFreeBSD.h"
+#include "ProcessPOSIXLog.h"
+#include "ProcessMonitor.h"
+
+extern "C" {
+ extern char ** environ;
+ }
+
+using namespace lldb;
+using namespace lldb_private;
+
+// We disable the tracing of ptrace calls for integration builds to
+// avoid the additional indirection and checks.
+#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+// Wrapper for ptrace to catch errors and log calls.
+
+const char *
+Get_PT_IO_OP(int op)
+{
+ switch (op) {
+ case PIOD_READ_D: return "READ_D";
+ case PIOD_WRITE_D: return "WRITE_D";
+ case PIOD_READ_I: return "READ_I";
+ case PIOD_WRITE_I: return "WRITE_I";
+ default: return "Unknown op";
+ }
+}
+
+// Wrapper for ptrace to catch errors and log calls.
+// Note that ptrace sets errno on error because -1 is reserved as a valid result.
+extern long
+PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data,
+ const char* reqName, const char* file, int line)
+{
+ long int result;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PTRACE));
+
+ if (log) {
+ log->Printf("ptrace(%s, %lu, %p, %x) called from file %s line %d",
+ reqName, pid, addr, data, file, line);
+ if (req == PT_IO) {
+ struct ptrace_io_desc *pi = (struct ptrace_io_desc *) addr;
+
+ log->Printf("PT_IO: op=%s offs=%zx size=%ld",
+ Get_PT_IO_OP(pi->piod_op), (size_t)pi->piod_offs, pi->piod_len);
+ }
+ }
+
+ //PtraceDisplayBytes(req, data);
+
+ errno = 0;
+ result = ptrace(req, pid, (caddr_t) addr, data);
+
+ //PtraceDisplayBytes(req, data);
+
+ if (log && errno != 0)
+ {
+ const char* str;
+ switch (errno)
+ {
+ case ESRCH: str = "ESRCH"; break;
+ case EINVAL: str = "EINVAL"; break;
+ case EBUSY: str = "EBUSY"; break;
+ case EPERM: str = "EPERM"; break;
+ default: str = "<unknown>";
+ }
+ log->Printf("ptrace() failed; errno=%d (%s)", errno, str);
+ }
+
+#ifdef __amd64__
+ if (log) {
+ if (req == PT_GETREGS) {
+ struct reg *r = (struct reg *) addr;
+
+ log->Printf("PT_GETREGS: ip=0x%lx", r->r_rip);
+ log->Printf("PT_GETREGS: sp=0x%lx", r->r_rsp);
+ log->Printf("PT_GETREGS: bp=0x%lx", r->r_rbp);
+ log->Printf("PT_GETREGS: ax=0x%lx", r->r_rax);
+ }
+ }
+#endif
+
+ return result;
+}
+
+// Wrapper for ptrace when logging is not required.
+// Sets errno to 0 prior to calling ptrace.
+extern long
+PtraceWrapper(int req, lldb::pid_t pid, void *addr, int data)
+{
+ long result = 0;
+ errno = 0;
+ result = ptrace(req, pid, (caddr_t)addr, data);
+ return result;
+}
+
+#define PTRACE(req, pid, addr, data) \
+ PtraceWrapper((req), (pid), (addr), (data), #req, __FILE__, __LINE__)
+#else
+ PtraceWrapper((req), (pid), (addr), (data))
+#endif
+
+//------------------------------------------------------------------------------
+// Static implementations of ProcessMonitor::ReadMemory and
+// ProcessMonitor::WriteMemory. This enables mutual recursion between these
+// functions without needed to go thru the thread funnel.
+
+static size_t
+DoReadMemory(lldb::pid_t pid, lldb::addr_t vm_addr, void *buf, size_t size,
+ Error &error)
+{
+ struct ptrace_io_desc pi_desc;
+
+ pi_desc.piod_op = PIOD_READ_D;
+ pi_desc.piod_offs = (void *)vm_addr;
+ pi_desc.piod_addr = buf;
+ pi_desc.piod_len = size;
+
+ if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0)
+ error.SetErrorToErrno();
+ return pi_desc.piod_len;
+}
+
+static size_t
+DoWriteMemory(lldb::pid_t pid, lldb::addr_t vm_addr, const void *buf,
+ size_t size, Error &error)
+{
+ struct ptrace_io_desc pi_desc;
+
+ pi_desc.piod_op = PIOD_WRITE_D;
+ pi_desc.piod_offs = (void *)vm_addr;
+ pi_desc.piod_addr = (void *)buf;
+ pi_desc.piod_len = size;
+
+ if (PTRACE(PT_IO, pid, (caddr_t)&pi_desc, 0) < 0)
+ error.SetErrorToErrno();
+ return pi_desc.piod_len;
+}
+
+// Simple helper function to ensure flags are enabled on the given file
+// descriptor.
+static bool
+EnsureFDFlags(int fd, int flags, Error &error)
+{
+ int status;
+
+ if ((status = fcntl(fd, F_GETFL)) == -1)
+ {
+ error.SetErrorToErrno();
+ return false;
+ }
+
+ if (fcntl(fd, F_SETFL, status | flags) == -1)
+ {
+ error.SetErrorToErrno();
+ return false;
+ }
+
+ return true;
+}
+
+//------------------------------------------------------------------------------
+/// @class Operation
+/// @brief Represents a ProcessMonitor operation.
+///
+/// Under FreeBSD, it is not possible to ptrace() from any other thread but the
+/// one that spawned or attached to the process from the start. Therefore, when
+/// a ProcessMonitor is asked to deliver or change the state of an inferior
+/// process the operation must be "funneled" to a specific thread to perform the
+/// task. The Operation class provides an abstract base for all services the
+/// ProcessMonitor must perform via the single virtual function Execute, thus
+/// encapsulating the code that needs to run in the privileged context.
+class Operation
+{
+public:
+ virtual ~Operation() {}
+ virtual void Execute(ProcessMonitor *monitor) = 0;
+};
+
+//------------------------------------------------------------------------------
+/// @class ReadOperation
+/// @brief Implements ProcessMonitor::ReadMemory.
+class ReadOperation : public Operation
+{
+public:
+ ReadOperation(lldb::addr_t addr, void *buff, size_t size,
+ Error &error, size_t &result)
+ : m_addr(addr), m_buff(buff), m_size(size),
+ m_error(error), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::addr_t m_addr;
+ void *m_buff;
+ size_t m_size;
+ Error &m_error;
+ size_t &m_result;
+};
+
+void
+ReadOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ m_result = DoReadMemory(pid, m_addr, m_buff, m_size, m_error);
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteOperation
+/// @brief Implements ProcessMonitor::WriteMemory.
+class WriteOperation : public Operation
+{
+public:
+ WriteOperation(lldb::addr_t addr, const void *buff, size_t size,
+ Error &error, size_t &result)
+ : m_addr(addr), m_buff(buff), m_size(size),
+ m_error(error), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::addr_t m_addr;
+ const void *m_buff;
+ size_t m_size;
+ Error &m_error;
+ size_t &m_result;
+};
+
+void
+WriteOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ m_result = DoWriteMemory(pid, m_addr, m_buff, m_size, m_error);
+}
+
+//------------------------------------------------------------------------------
+/// @class ReadRegOperation
+/// @brief Implements ProcessMonitor::ReadRegisterValue.
+class ReadRegOperation : public Operation
+{
+public:
+ ReadRegOperation(lldb::tid_t tid, unsigned offset, unsigned size,
+ RegisterValue &value, bool &result)
+ : m_tid(tid), m_offset(offset), m_size(size),
+ m_value(value), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ unsigned m_offset;
+ unsigned m_size;
+ RegisterValue &m_value;
+ bool &m_result;
+};
+
+void
+ReadRegOperation::Execute(ProcessMonitor *monitor)
+{
+ struct reg regs;
+ int rc;
+
+ if ((rc = PTRACE(PT_GETREGS, m_tid, (caddr_t)&regs, 0)) < 0) {
+ m_result = false;
+ } else {
+ if (m_size == sizeof(uintptr_t))
+ m_value = *(uintptr_t *)(((caddr_t)&regs) + m_offset);
+ else
+ memcpy(&m_value, (((caddr_t)&regs) + m_offset), m_size);
+ m_result = true;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteRegOperation
+/// @brief Implements ProcessMonitor::WriteRegisterValue.
+class WriteRegOperation : public Operation
+{
+public:
+ WriteRegOperation(lldb::tid_t tid, unsigned offset,
+ const RegisterValue &value, bool &result)
+ : m_tid(tid), m_offset(offset),
+ m_value(value), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ unsigned m_offset;
+ const RegisterValue &m_value;
+ bool &m_result;
+};
+
+void
+WriteRegOperation::Execute(ProcessMonitor *monitor)
+{
+ struct reg regs;
+
+ if (PTRACE(PT_GETREGS, m_tid, (caddr_t)&regs, 0) < 0) {
+ m_result = false;
+ return;
+ }
+ *(uintptr_t *)(((caddr_t)&regs) + m_offset) = (uintptr_t)m_value.GetAsUInt64();
+ if (PTRACE(PT_SETREGS, m_tid, (caddr_t)&regs, 0) < 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class ReadGPROperation
+/// @brief Implements ProcessMonitor::ReadGPR.
+class ReadGPROperation : public Operation
+{
+public:
+ ReadGPROperation(lldb::tid_t tid, void *buf, bool &result)
+ : m_tid(tid), m_buf(buf), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ bool &m_result;
+};
+
+void
+ReadGPROperation::Execute(ProcessMonitor *monitor)
+{
+ int rc;
+
+ errno = 0;
+ rc = PTRACE(PT_GETREGS, m_tid, (caddr_t)m_buf, 0);
+ if (errno != 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class ReadFPROperation
+/// @brief Implements ProcessMonitor::ReadFPR.
+class ReadFPROperation : public Operation
+{
+public:
+ ReadFPROperation(lldb::tid_t tid, void *buf, bool &result)
+ : m_tid(tid), m_buf(buf), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ bool &m_result;
+};
+
+void
+ReadFPROperation::Execute(ProcessMonitor *monitor)
+{
+ if (PTRACE(PT_GETFPREGS, m_tid, (caddr_t)m_buf, 0) < 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteGPROperation
+/// @brief Implements ProcessMonitor::WriteGPR.
+class WriteGPROperation : public Operation
+{
+public:
+ WriteGPROperation(lldb::tid_t tid, void *buf, bool &result)
+ : m_tid(tid), m_buf(buf), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ bool &m_result;
+};
+
+void
+WriteGPROperation::Execute(ProcessMonitor *monitor)
+{
+ if (PTRACE(PT_SETREGS, m_tid, (caddr_t)m_buf, 0) < 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class WriteFPROperation
+/// @brief Implements ProcessMonitor::WriteFPR.
+class WriteFPROperation : public Operation
+{
+public:
+ WriteFPROperation(lldb::tid_t tid, void *buf, bool &result)
+ : m_tid(tid), m_buf(buf), m_result(result)
+ { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_buf;
+ bool &m_result;
+};
+
+void
+WriteFPROperation::Execute(ProcessMonitor *monitor)
+{
+ if (PTRACE(PT_SETFPREGS, m_tid, (caddr_t)m_buf, 0) < 0)
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class ResumeOperation
+/// @brief Implements ProcessMonitor::Resume.
+class ResumeOperation : public Operation
+{
+public:
+ ResumeOperation(lldb::tid_t tid, uint32_t signo, bool &result) :
+ m_tid(tid), m_signo(signo), m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ uint32_t m_signo;
+ bool &m_result;
+};
+
+void
+ResumeOperation::Execute(ProcessMonitor *monitor)
+{
+ int data = 0;
+
+ if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
+ data = m_signo;
+
+ if (PTRACE(PT_CONTINUE, m_tid, (caddr_t)1, data))
+ {
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ResumeOperation (%" PRIu64 ") failed: %s", m_tid, strerror(errno));
+ m_result = false;
+ }
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class SingleStepOperation
+/// @brief Implements ProcessMonitor::SingleStep.
+class SingleStepOperation : public Operation
+{
+public:
+ SingleStepOperation(lldb::tid_t tid, uint32_t signo, bool &result)
+ : m_tid(tid), m_signo(signo), m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ uint32_t m_signo;
+ bool &m_result;
+};
+
+void
+SingleStepOperation::Execute(ProcessMonitor *monitor)
+{
+ int data = 0;
+
+ if (m_signo != LLDB_INVALID_SIGNAL_NUMBER)
+ data = m_signo;
+
+ if (PTRACE(PT_STEP, m_tid, NULL, data))
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class LwpInfoOperation
+/// @brief Implements ProcessMonitor::GetLwpInfo.
+class LwpInfoOperation : public Operation
+{
+public:
+ LwpInfoOperation(lldb::tid_t tid, void *info, bool &result, int &ptrace_err)
+ : m_tid(tid), m_info(info), m_result(result), m_err(ptrace_err) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ void *m_info;
+ bool &m_result;
+ int &m_err;
+};
+
+void
+LwpInfoOperation::Execute(ProcessMonitor *monitor)
+{
+ struct ptrace_lwpinfo plwp;
+
+ if (PTRACE(PT_LWPINFO, m_tid, (caddr_t)&plwp, sizeof(plwp))) {
+ m_result = false;
+ m_err = errno;
+ } else {
+ memcpy(m_info, &plwp, sizeof(plwp));
+ m_result = true;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// @class EventMessageOperation
+/// @brief Implements ProcessMonitor::GetEventMessage.
+class EventMessageOperation : public Operation
+{
+public:
+ EventMessageOperation(lldb::tid_t tid, unsigned long *message, bool &result)
+ : m_tid(tid), m_message(message), m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ lldb::tid_t m_tid;
+ unsigned long *m_message;
+ bool &m_result;
+};
+
+void
+EventMessageOperation::Execute(ProcessMonitor *monitor)
+{
+ struct ptrace_lwpinfo plwp;
+
+ if (PTRACE(PT_LWPINFO, m_tid, (caddr_t)&plwp, sizeof(plwp)))
+ m_result = false;
+ else {
+ if (plwp.pl_flags & PL_FLAG_FORKED) {
+ m_message = (unsigned long *)plwp.pl_child_pid;
+ m_result = true;
+ } else
+ m_result = false;
+ }
+}
+
+//------------------------------------------------------------------------------
+/// @class KillOperation
+/// @brief Implements ProcessMonitor::BringProcessIntoLimbo.
+class KillOperation : public Operation
+{
+public:
+ KillOperation(bool &result) : m_result(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ bool &m_result;
+};
+
+void
+KillOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ if (PTRACE(PT_KILL, pid, NULL, 0))
+ m_result = false;
+ else
+ m_result = true;
+}
+
+//------------------------------------------------------------------------------
+/// @class DetachOperation
+/// @brief Implements ProcessMonitor::BringProcessIntoLimbo.
+class DetachOperation : public Operation
+{
+public:
+ DetachOperation(Error &result) : m_error(result) { }
+
+ void Execute(ProcessMonitor *monitor);
+
+private:
+ Error &m_error;
+};
+
+void
+DetachOperation::Execute(ProcessMonitor *monitor)
+{
+ lldb::pid_t pid = monitor->GetPID();
+
+ if (PTRACE(PT_DETACH, pid, NULL, 0) < 0)
+ m_error.SetErrorToErrno();
+
+}
+
+ProcessMonitor::OperationArgs::OperationArgs(ProcessMonitor *monitor)
+ : m_monitor(monitor)
+{
+ sem_init(&m_semaphore, 0, 0);
+}
+
+ProcessMonitor::OperationArgs::~OperationArgs()
+{
+ sem_destroy(&m_semaphore);
+}
+
+ProcessMonitor::LaunchArgs::LaunchArgs(ProcessMonitor *monitor,
+ lldb_private::Module *module,
+ char const **argv,
+ char const **envp,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_dir)
+ : OperationArgs(monitor),
+ m_module(module),
+ m_argv(argv),
+ m_envp(envp),
+ m_stdin_path(stdin_path),
+ m_stdout_path(stdout_path),
+ m_stderr_path(stderr_path),
+ m_working_dir(working_dir) { }
+
+ProcessMonitor::LaunchArgs::~LaunchArgs()
+{ }
+
+ProcessMonitor::AttachArgs::AttachArgs(ProcessMonitor *monitor,
+ lldb::pid_t pid)
+ : OperationArgs(monitor), m_pid(pid) { }
+
+ProcessMonitor::AttachArgs::~AttachArgs()
+{ }
+
+//------------------------------------------------------------------------------
+/// The basic design of the ProcessMonitor is built around two threads.
+///
+/// One thread (@see SignalThread) simply blocks on a call to waitpid() looking
+/// for changes in the debugee state. When a change is detected a
+/// ProcessMessage is sent to the associated ProcessFreeBSD instance. This thread
+/// "drives" state changes in the debugger.
+///
+/// The second thread (@see OperationThread) is responsible for two things 1)
+/// launching or attaching to the inferior process, and then 2) servicing
+/// operations such as register reads/writes, stepping, etc. See the comments
+/// on the Operation class for more info as to why this is needed.
+ProcessMonitor::ProcessMonitor(ProcessPOSIX *process,
+ Module *module,
+ const char *argv[],
+ const char *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_dir,
+ lldb_private::Error &error)
+ : m_process(static_cast<ProcessFreeBSD *>(process)),
+ m_operation_thread(LLDB_INVALID_HOST_THREAD),
+ m_monitor_thread(LLDB_INVALID_HOST_THREAD),
+ m_pid(LLDB_INVALID_PROCESS_ID),
+ m_server_mutex(Mutex::eMutexTypeRecursive),
+ m_terminal_fd(-1),
+ m_client_fd(-1),
+ m_server_fd(-1)
+{
+ std::unique_ptr<LaunchArgs> args;
+
+ args.reset(new LaunchArgs(this, module, argv, envp,
+ stdin_path, stdout_path, stderr_path, working_dir));
+
+
+ // Server/client descriptors.
+ if (!EnableIPC())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Monitor failed to initialize.");
+ }
+
+ StartLaunchOpThread(args.get(), error);
+ if (!error.Success())
+ return;
+
+WAIT_AGAIN:
+ // Wait for the operation thread to initialize.
+ if (sem_wait(&args->m_semaphore))
+ {
+ if (errno == EINTR)
+ goto WAIT_AGAIN;
+ else
+ {
+ error.SetErrorToErrno();
+ return;
+ }
+ }
+
+ // Check that the launch was a success.
+ if (!args->m_error.Success())
+ {
+ StopOpThread();
+ error = args->m_error;
+ return;
+ }
+
+ // Finally, start monitoring the child process for change in state.
+ m_monitor_thread = Host::StartMonitoringChildProcess(
+ ProcessMonitor::MonitorCallback, this, GetPID(), true);
+ if (!IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Process launch failed.");
+ return;
+ }
+}
+
+ProcessMonitor::ProcessMonitor(ProcessPOSIX *process,
+ lldb::pid_t pid,
+ lldb_private::Error &error)
+ : m_process(static_cast<ProcessFreeBSD *>(process)),
+ m_operation_thread(LLDB_INVALID_HOST_THREAD),
+ m_monitor_thread(LLDB_INVALID_HOST_THREAD),
+ m_pid(pid),
+ m_server_mutex(Mutex::eMutexTypeRecursive),
+ m_terminal_fd(-1),
+ m_client_fd(-1),
+ m_server_fd(-1)
+{
+ std::unique_ptr<AttachArgs> args;
+
+ args.reset(new AttachArgs(this, pid));
+
+ // Server/client descriptors.
+ if (!EnableIPC())
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Monitor failed to initialize.");
+ }
+
+ StartAttachOpThread(args.get(), error);
+ if (!error.Success())
+ return;
+
+WAIT_AGAIN:
+ // Wait for the operation thread to initialize.
+ if (sem_wait(&args->m_semaphore))
+ {
+ if (errno == EINTR)
+ goto WAIT_AGAIN;
+ else
+ {
+ error.SetErrorToErrno();
+ return;
+ }
+ }
+
+ // Check that the attach was a success.
+ if (!args->m_error.Success())
+ {
+ StopOpThread();
+ error = args->m_error;
+ return;
+ }
+
+ // Finally, start monitoring the child process for change in state.
+ m_monitor_thread = Host::StartMonitoringChildProcess(
+ ProcessMonitor::MonitorCallback, this, GetPID(), true);
+ if (!IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
+ {
+ error.SetErrorToGenericError();
+ error.SetErrorString("Process attach failed.");
+ return;
+ }
+}
+
+ProcessMonitor::~ProcessMonitor()
+{
+ StopMonitor();
+}
+
+//------------------------------------------------------------------------------
+// Thread setup and tear down.
+void
+ProcessMonitor::StartLaunchOpThread(LaunchArgs *args, Error &error)
+{
+ static const char *g_thread_name = "lldb.process.freebsd.operation";
+
+ if (IS_VALID_LLDB_HOST_THREAD(m_operation_thread))
+ return;
+
+ m_operation_thread =
+ Host::ThreadCreate(g_thread_name, LaunchOpThread, args, &error);
+}
+
+void *
+ProcessMonitor::LaunchOpThread(void *arg)
+{
+ LaunchArgs *args = static_cast<LaunchArgs*>(arg);
+
+ if (!Launch(args)) {
+ sem_post(&args->m_semaphore);
+ return NULL;
+ }
+
+ ServeOperation(args);
+ return NULL;
+}
+
+bool
+ProcessMonitor::Launch(LaunchArgs *args)
+{
+ ProcessMonitor *monitor = args->m_monitor;
+ ProcessFreeBSD &process = monitor->GetProcess();
+ lldb::ProcessSP processSP = process.shared_from_this();
+ const char **argv = args->m_argv;
+ const char **envp = args->m_envp;
+ const char *stdin_path = args->m_stdin_path;
+ const char *stdout_path = args->m_stdout_path;
+ const char *stderr_path = args->m_stderr_path;
+ const char *working_dir = args->m_working_dir;
+
+ lldb_utility::PseudoTerminal terminal;
+ const size_t err_len = 1024;
+ char err_str[err_len];
+ lldb::pid_t pid;
+
+ lldb::ThreadSP inferior;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ // Propagate the environment if one is not supplied.
+ if (envp == NULL || envp[0] == NULL)
+ envp = const_cast<const char **>(environ);
+
+ // Pseudo terminal setup.
+ if (!terminal.OpenFirstAvailableMaster(O_RDWR | O_NOCTTY, err_str, err_len))
+ {
+ args->m_error.SetErrorToGenericError();
+ args->m_error.SetErrorString("Could not open controlling TTY.");
+ goto FINISH;
+ }
+
+ if ((pid = terminal.Fork(err_str, err_len)) == -1)
+ {
+ args->m_error.SetErrorToGenericError();
+ args->m_error.SetErrorString("Process fork failed.");
+ goto FINISH;
+ }
+
+ // Recognized child exit status codes.
+ enum {
+ ePtraceFailed = 1,
+ eDupStdinFailed,
+ eDupStdoutFailed,
+ eDupStderrFailed,
+ eChdirFailed,
+ eExecFailed
+ };
+
+ // Child process.
+ if (pid == 0)
+ {
+ // Trace this process.
+ if (PTRACE(PT_TRACE_ME, 0, NULL, 0) < 0)
+ exit(ePtraceFailed);
+
+ // Do not inherit setgid powers.
+ setgid(getgid());
+
+ // Let us have our own process group.
+ setpgid(0, 0);
+
+ // Dup file descriptors if needed.
+ //
+ // FIXME: If two or more of the paths are the same we needlessly open
+ // the same file multiple times.
+ if (stdin_path != NULL && stdin_path[0])
+ if (!DupDescriptor(stdin_path, STDIN_FILENO, O_RDONLY))
+ exit(eDupStdinFailed);
+
+ if (stdout_path != NULL && stdout_path[0])
+ if (!DupDescriptor(stdout_path, STDOUT_FILENO, O_WRONLY | O_CREAT))
+ exit(eDupStdoutFailed);
+
+ if (stderr_path != NULL && stderr_path[0])
+ if (!DupDescriptor(stderr_path, STDERR_FILENO, O_WRONLY | O_CREAT))
+ exit(eDupStderrFailed);
+
+ // Change working directory
+ if (working_dir != NULL && working_dir[0])
+ if (0 != ::chdir(working_dir))
+ exit(eChdirFailed);
+
+ // Execute. We should never return.
+ execve(argv[0],
+ const_cast<char *const *>(argv),
+ const_cast<char *const *>(envp));
+ exit(eExecFailed);
+ }
+
+ // Wait for the child process to to trap on its call to execve.
+ ::pid_t wpid;
+ int status;
+ if ((wpid = waitpid(pid, &status, 0)) < 0)
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+ else if (WIFEXITED(status))
+ {
+ // open, dup or execve likely failed for some reason.
+ args->m_error.SetErrorToGenericError();
+ switch (WEXITSTATUS(status))
+ {
+ case ePtraceFailed:
+ args->m_error.SetErrorString("Child ptrace failed.");
+ break;
+ case eDupStdinFailed:
+ args->m_error.SetErrorString("Child open stdin failed.");
+ break;
+ case eDupStdoutFailed:
+ args->m_error.SetErrorString("Child open stdout failed.");
+ break;
+ case eDupStderrFailed:
+ args->m_error.SetErrorString("Child open stderr failed.");
+ break;
+ case eChdirFailed:
+ args->m_error.SetErrorString("Child failed to set working directory.");
+ break;
+ case eExecFailed:
+ args->m_error.SetErrorString("Child exec failed.");
+ break;
+ default:
+ args->m_error.SetErrorString("Child returned unknown exit status.");
+ break;
+ }
+ goto FINISH;
+ }
+ assert(WIFSTOPPED(status) && wpid == pid &&
+ "Could not sync with inferior process.");
+
+#ifdef notyet
+ // Have the child raise an event on exit. This is used to keep the child in
+ // limbo until it is destroyed.
+ if (PTRACE(PTRACE_SETOPTIONS, pid, NULL, PTRACE_O_TRACEEXIT) < 0)
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+#endif
+ // Release the master terminal descriptor and pass it off to the
+ // ProcessMonitor instance. Similarly stash the inferior pid.
+ monitor->m_terminal_fd = terminal.ReleaseMasterFileDescriptor();
+ monitor->m_pid = pid;
+
+ // Set the terminal fd to be in non blocking mode (it simplifies the
+ // implementation of ProcessFreeBSD::GetSTDOUT to have a non-blocking
+ // descriptor to read from).
+ if (!EnsureFDFlags(monitor->m_terminal_fd, O_NONBLOCK, args->m_error))
+ goto FINISH;
+
+ // Update the process thread list with this new thread.
+ inferior.reset(process.CreateNewPOSIXThread(*processSP, pid));
+ if (log)
+ log->Printf ("ProcessMonitor::%s() adding pid = %" PRIu64, __FUNCTION__, pid);
+ process.GetThreadList().AddThread(inferior);
+
+ // Let our process instance know the thread has stopped.
+ process.SendMessage(ProcessMessage::Trace(pid));
+
+FINISH:
+ return args->m_error.Success();
+}
+
+bool
+ProcessMonitor::EnableIPC()
+{
+ int fd[2];
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd))
+ return false;
+
+ m_client_fd = fd[0];
+ m_server_fd = fd[1];
+ return true;
+}
+
+void
+ProcessMonitor::StartAttachOpThread(AttachArgs *args, lldb_private::Error &error)
+{
+ static const char *g_thread_name = "lldb.process.freebsd.operation";
+
+ if (IS_VALID_LLDB_HOST_THREAD(m_operation_thread))
+ return;
+
+ m_operation_thread =
+ Host::ThreadCreate(g_thread_name, AttachOpThread, args, &error);
+}
+
+void *
+ProcessMonitor::AttachOpThread(void *arg)
+{
+ AttachArgs *args = static_cast<AttachArgs*>(arg);
+
+ if (!Attach(args))
+ return NULL;
+
+ ServeOperation(args);
+ return NULL;
+}
+
+bool
+ProcessMonitor::Attach(AttachArgs *args)
+{
+ lldb::pid_t pid = args->m_pid;
+
+ ProcessMonitor *monitor = args->m_monitor;
+ ProcessFreeBSD &process = monitor->GetProcess();
+ lldb::ProcessSP processSP = process.shared_from_this();
+ ThreadList &tl = process.GetThreadList();
+ lldb::ThreadSP inferior;
+
+ if (pid <= 1)
+ {
+ args->m_error.SetErrorToGenericError();
+ args->m_error.SetErrorString("Attaching to process 1 is not allowed.");
+ goto FINISH;
+ }
+
+ // Attach to the requested process.
+ if (PTRACE(PT_ATTACH, pid, NULL, 0) < 0)
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+
+ int status;
+ if ((status = waitpid(pid, NULL, 0)) < 0)
+ {
+ args->m_error.SetErrorToErrno();
+ goto FINISH;
+ }
+
+ // Update the process thread list with the attached thread.
+ inferior.reset(process.CreateNewPOSIXThread(*processSP, pid));
+ tl.AddThread(inferior);
+
+ // Let our process instance know the thread has stopped.
+ process.SendMessage(ProcessMessage::Trace(pid));
+
+ FINISH:
+ return args->m_error.Success();
+}
+
+bool
+ProcessMonitor::MonitorCallback(void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signal,
+ int status)
+{
+ ProcessMessage message;
+ ProcessMonitor *monitor = static_cast<ProcessMonitor*>(callback_baton);
+ ProcessFreeBSD *process = monitor->m_process;
+ assert(process);
+ bool stop_monitoring;
+ struct ptrace_lwpinfo plwp;
+ int ptrace_err;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ if (exited)
+ {
+ if (log)
+ log->Printf ("ProcessMonitor::%s() got exit signal, tid = %" PRIu64, __FUNCTION__, pid);
+ message = ProcessMessage::Exit(pid, status);
+ process->SendMessage(message);
+ return pid == process->GetID();
+ }
+
+ if (!monitor->GetLwpInfo(pid, &plwp, ptrace_err))
+ stop_monitoring = true; // pid is gone. Bail.
+ else {
+ switch (plwp.pl_siginfo.si_signo)
+ {
+ case SIGTRAP:
+ message = MonitorSIGTRAP(monitor, &plwp.pl_siginfo, pid);
+ break;
+
+ default:
+ message = MonitorSignal(monitor, &plwp.pl_siginfo, pid);
+ break;
+ }
+
+ process->SendMessage(message);
+ stop_monitoring = message.GetKind() == ProcessMessage::eExitMessage;
+ }
+
+ return stop_monitoring;
+}
+
+ProcessMessage
+ProcessMonitor::MonitorSIGTRAP(ProcessMonitor *monitor,
+ const siginfo_t *info, lldb::pid_t pid)
+{
+ ProcessMessage message;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ assert(monitor);
+ assert(info && info->si_signo == SIGTRAP && "Unexpected child signal!");
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "Unexpected SIGTRAP code!");
+ break;
+
+ case (SIGTRAP /* | (PTRACE_EVENT_EXIT << 8) */):
+ {
+ // The inferior process is about to exit. Maintain the process in a
+ // state of "limbo" until we are explicitly commanded to detach,
+ // destroy, resume, etc.
+ unsigned long data = 0;
+ if (!monitor->GetEventMessage(pid, &data))
+ data = -1;
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received exit? event, data = %lx, pid = %" PRIu64, __FUNCTION__, data, pid);
+ message = ProcessMessage::Limbo(pid, (data >> 8));
+ break;
+ }
+
+ case 0:
+ case TRAP_TRACE:
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received trace event, pid = %" PRIu64, __FUNCTION__, pid);
+ message = ProcessMessage::Trace(pid);
+ break;
+
+ case SI_KERNEL:
+ case TRAP_BRKPT:
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received breakpoint event, pid = %" PRIu64, __FUNCTION__, pid);
+ message = ProcessMessage::Break(pid);
+ break;
+ }
+
+ return message;
+}
+
+ProcessMessage
+ProcessMonitor::MonitorSignal(ProcessMonitor *monitor,
+ const siginfo_t *info, lldb::pid_t pid)
+{
+ ProcessMessage message;
+ int signo = info->si_signo;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ // POSIX says that process behaviour is undefined after it ignores a SIGFPE,
+ // SIGILL, SIGSEGV, or SIGBUS *unless* that signal was generated by a
+ // kill(2) or raise(3). Similarly for tgkill(2) on FreeBSD.
+ //
+ // IOW, user generated signals never generate what we consider to be a
+ // "crash".
+ //
+ // Similarly, ACK signals generated by this monitor.
+ if (info->si_code == SI_USER)
+ {
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received signal %s with code %s, pid = %d",
+ __FUNCTION__,
+ monitor->m_process->GetUnixSignals().GetSignalAsCString (signo),
+ "SI_USER",
+ info->si_pid);
+ if (info->si_pid == getpid())
+ return ProcessMessage::SignalDelivered(pid, signo);
+ else
+ return ProcessMessage::Signal(pid, signo);
+ }
+
+ if (log)
+ log->Printf ("ProcessMonitor::%s() received signal %s", __FUNCTION__, monitor->m_process->GetUnixSignals().GetSignalAsCString (signo));
+
+ if (signo == SIGSEGV) {
+ lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+ ProcessMessage::CrashReason reason = GetCrashReasonForSIGSEGV(info);
+ return ProcessMessage::Crash(pid, reason, signo, fault_addr);
+ }
+
+ if (signo == SIGILL) {
+ lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+ ProcessMessage::CrashReason reason = GetCrashReasonForSIGILL(info);
+ return ProcessMessage::Crash(pid, reason, signo, fault_addr);
+ }
+
+ if (signo == SIGFPE) {
+ lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+ ProcessMessage::CrashReason reason = GetCrashReasonForSIGFPE(info);
+ return ProcessMessage::Crash(pid, reason, signo, fault_addr);
+ }
+
+ if (signo == SIGBUS) {
+ lldb::addr_t fault_addr = reinterpret_cast<lldb::addr_t>(info->si_addr);
+ ProcessMessage::CrashReason reason = GetCrashReasonForSIGBUS(info);
+ return ProcessMessage::Crash(pid, reason, signo, fault_addr);
+ }
+
+ // Everything else is "normal" and does not require any special action on
+ // our part.
+ return ProcessMessage::Signal(pid, signo);
+}
+
+ProcessMessage::CrashReason
+ProcessMonitor::GetCrashReasonForSIGSEGV(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGSEGV);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGSEGV");
+ break;
+ case SEGV_MAPERR:
+ reason = ProcessMessage::eInvalidAddress;
+ break;
+ case SEGV_ACCERR:
+ reason = ProcessMessage::ePrivilegedAddress;
+ break;
+ }
+
+ return reason;
+}
+
+ProcessMessage::CrashReason
+ProcessMonitor::GetCrashReasonForSIGILL(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGILL);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGILL");
+ break;
+ case ILL_ILLOPC:
+ reason = ProcessMessage::eIllegalOpcode;
+ break;
+ case ILL_ILLOPN:
+ reason = ProcessMessage::eIllegalOperand;
+ break;
+ case ILL_ILLADR:
+ reason = ProcessMessage::eIllegalAddressingMode;
+ break;
+ case ILL_ILLTRP:
+ reason = ProcessMessage::eIllegalTrap;
+ break;
+ case ILL_PRVOPC:
+ reason = ProcessMessage::ePrivilegedOpcode;
+ break;
+ case ILL_PRVREG:
+ reason = ProcessMessage::ePrivilegedRegister;
+ break;
+ case ILL_COPROC:
+ reason = ProcessMessage::eCoprocessorError;
+ break;
+ case ILL_BADSTK:
+ reason = ProcessMessage::eInternalStackError;
+ break;
+ }
+
+ return reason;
+}
+
+ProcessMessage::CrashReason
+ProcessMonitor::GetCrashReasonForSIGFPE(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGFPE);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGFPE");
+ break;
+ case FPE_INTDIV:
+ reason = ProcessMessage::eIntegerDivideByZero;
+ break;
+ case FPE_INTOVF:
+ reason = ProcessMessage::eIntegerOverflow;
+ break;
+ case FPE_FLTDIV:
+ reason = ProcessMessage::eFloatDivideByZero;
+ break;
+ case FPE_FLTOVF:
+ reason = ProcessMessage::eFloatOverflow;
+ break;
+ case FPE_FLTUND:
+ reason = ProcessMessage::eFloatUnderflow;
+ break;
+ case FPE_FLTRES:
+ reason = ProcessMessage::eFloatInexactResult;
+ break;
+ case FPE_FLTINV:
+ reason = ProcessMessage::eFloatInvalidOperation;
+ break;
+ case FPE_FLTSUB:
+ reason = ProcessMessage::eFloatSubscriptRange;
+ break;
+ }
+
+ return reason;
+}
+
+ProcessMessage::CrashReason
+ProcessMonitor::GetCrashReasonForSIGBUS(const siginfo_t *info)
+{
+ ProcessMessage::CrashReason reason;
+ assert(info->si_signo == SIGBUS);
+
+ reason = ProcessMessage::eInvalidCrashReason;
+
+ switch (info->si_code)
+ {
+ default:
+ assert(false && "unexpected si_code for SIGBUS");
+ break;
+ case BUS_ADRALN:
+ reason = ProcessMessage::eIllegalAlignment;
+ break;
+ case BUS_ADRERR:
+ reason = ProcessMessage::eIllegalAddress;
+ break;
+ case BUS_OBJERR:
+ reason = ProcessMessage::eHardwareError;
+ break;
+ }
+
+ return reason;
+}
+
+void
+ProcessMonitor::ServeOperation(OperationArgs *args)
+{
+ int status;
+ pollfd fdset;
+
+ ProcessMonitor *monitor = args->m_monitor;
+
+ fdset.fd = monitor->m_server_fd;
+ fdset.events = POLLIN | POLLPRI;
+ fdset.revents = 0;
+
+ // We are finised with the arguments and are ready to go. Sync with the
+ // parent thread and start serving operations on the inferior.
+ sem_post(&args->m_semaphore);
+
+ for (;;)
+ {
+ if ((status = poll(&fdset, 1, -1)) < 0)
+ {
+ switch (errno)
+ {
+ default:
+ assert(false && "Unexpected poll() failure!");
+ continue;
+
+ case EINTR: continue; // Just poll again.
+ case EBADF: return; // Connection terminated.
+ }
+ }
+
+ assert(status == 1 && "Too many descriptors!");
+
+ if (fdset.revents & POLLIN)
+ {
+ Operation *op = NULL;
+
+ READ_AGAIN:
+ if ((status = read(fdset.fd, &op, sizeof(op))) < 0)
+ {
+ // There is only one acceptable failure.
+ assert(errno == EINTR);
+ goto READ_AGAIN;
+ }
+ if (status == 0)
+ continue; // Poll again. The connection probably terminated.
+ assert(status == sizeof(op));
+ op->Execute(monitor);
+ write(fdset.fd, &op, sizeof(op));
+ }
+ }
+}
+
+void
+ProcessMonitor::DoOperation(Operation *op)
+{
+ int status;
+ Operation *ack = NULL;
+ Mutex::Locker lock(m_server_mutex);
+
+ // FIXME: Do proper error checking here.
+ write(m_client_fd, &op, sizeof(op));
+
+READ_AGAIN:
+ if ((status = read(m_client_fd, &ack, sizeof(ack))) < 0)
+ {
+ // If interrupted by a signal handler try again. Otherwise the monitor
+ // thread probably died and we have a stale file descriptor -- abort the
+ // operation.
+ if (errno == EINTR)
+ goto READ_AGAIN;
+ return;
+ }
+
+ assert(status == sizeof(ack));
+ assert(ack == op && "Invalid monitor thread response!");
+}
+
+size_t
+ProcessMonitor::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ Error &error)
+{
+ size_t result;
+ ReadOperation op(vm_addr, buf, size, error, result);
+ DoOperation(&op);
+ return result;
+}
+
+size_t
+ProcessMonitor::WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+ lldb_private::Error &error)
+{
+ size_t result;
+ WriteOperation op(vm_addr, buf, size, error, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char* reg_name,
+ unsigned size, RegisterValue &value)
+{
+ bool result;
+ ReadRegOperation op(tid, offset, size, value, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::WriteRegisterValue(lldb::tid_t tid, unsigned offset,
+ const char* reg_name, const RegisterValue &value)
+{
+ bool result;
+ WriteRegOperation op(tid, offset, value, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ ReadGPROperation op(tid, buf, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ ReadFPROperation op(tid, buf, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
+{
+ return false;
+}
+
+bool
+ProcessMonitor::WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ WriteGPROperation op(tid, buf, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+ bool result;
+ WriteFPROperation op(tid, buf, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
+{
+ return false;
+}
+
+bool
+ProcessMonitor::Resume(lldb::tid_t tid, uint32_t signo)
+{
+ bool result;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ProcessMonitor::%s() resuming thread = %" PRIu64 " with signal %s", __FUNCTION__, tid,
+ m_process->GetUnixSignals().GetSignalAsCString (signo));
+ ResumeOperation op(tid, signo, result);
+ DoOperation(&op);
+ if (log)
+ log->Printf ("ProcessMonitor::%s() resuming result = %s", __FUNCTION__, result ? "true" : "false");
+ return result;
+}
+
+bool
+ProcessMonitor::SingleStep(lldb::tid_t tid, uint32_t signo)
+{
+ bool result;
+ SingleStepOperation op(tid, signo, result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::BringProcessIntoLimbo()
+{
+ bool result;
+ KillOperation op(result);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &ptrace_err)
+{
+ bool result;
+ LwpInfoOperation op(tid, lwpinfo, result, ptrace_err);
+ DoOperation(&op);
+ return result;
+}
+
+bool
+ProcessMonitor::GetEventMessage(lldb::tid_t tid, unsigned long *message)
+{
+ bool result;
+ EventMessageOperation op(tid, message, result);
+ DoOperation(&op);
+ return result;
+}
+
+lldb_private::Error
+ProcessMonitor::Detach(lldb::tid_t tid)
+{
+ lldb_private::Error error;
+ if (tid != LLDB_INVALID_THREAD_ID)
+ {
+ DetachOperation op(error);
+ DoOperation(&op);
+ }
+ return error;
+}
+
+bool
+ProcessMonitor::DupDescriptor(const char *path, int fd, int flags)
+{
+ int target_fd = open(path, flags, 0666);
+
+ if (target_fd == -1)
+ return false;
+
+ return (dup2(target_fd, fd) == -1) ? false : true;
+}
+
+void
+ProcessMonitor::StopMonitoringChildProcess()
+{
+ lldb::thread_result_t thread_result;
+
+ if (IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
+ {
+ Host::ThreadCancel(m_monitor_thread, NULL);
+ Host::ThreadJoin(m_monitor_thread, &thread_result, NULL);
+ m_monitor_thread = LLDB_INVALID_HOST_THREAD;
+ }
+}
+
+void
+ProcessMonitor::StopMonitor()
+{
+ StopMonitoringChildProcess();
+ StopOpThread();
+ CloseFD(m_terminal_fd);
+ CloseFD(m_client_fd);
+ CloseFD(m_server_fd);
+}
+
+void
+ProcessMonitor::StopOpThread()
+{
+ lldb::thread_result_t result;
+
+ if (!IS_VALID_LLDB_HOST_THREAD(m_operation_thread))
+ return;
+
+ Host::ThreadCancel(m_operation_thread, NULL);
+ Host::ThreadJoin(m_operation_thread, &result, NULL);
+ m_operation_thread = LLDB_INVALID_HOST_THREAD;
+}
+
+void
+ProcessMonitor::CloseFD(int &fd)
+{
+ if (fd != -1)
+ {
+ close(fd);
+ fd = -1;
+ }
+}
diff --git a/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/source/Plugins/Process/FreeBSD/ProcessMonitor.h
new file mode 100644
index 000000000000..ce66c03f2f8c
--- /dev/null
+++ b/source/Plugins/Process/FreeBSD/ProcessMonitor.h
@@ -0,0 +1,322 @@
+//===-- ProcessMonitor.h -------------------------------------- -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessMonitor_H_
+#define liblldb_ProcessMonitor_H_
+
+// C Includes
+#include <semaphore.h>
+#include <signal.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/lldb-types.h"
+#include "lldb/Host/Mutex.h"
+
+namespace lldb_private
+{
+class Error;
+class Module;
+class Scalar;
+} // End lldb_private namespace.
+
+class ProcessFreeBSD;
+class Operation;
+
+/// @class ProcessMonitor
+/// @brief Manages communication with the inferior (debugee) process.
+///
+/// Upon construction, this class prepares and launches an inferior process for
+/// debugging.
+///
+/// Changes in the inferior process state are propagated to the associated
+/// ProcessFreeBSD instance by calling ProcessFreeBSD::SendMessage with the
+/// appropriate ProcessMessage events.
+///
+/// A purposely minimal set of operations are provided to interrogate and change
+/// the inferior process state.
+class ProcessMonitor
+{
+public:
+
+ /// Launches an inferior process ready for debugging. Forms the
+ /// implementation of Process::DoLaunch.
+ ProcessMonitor(ProcessPOSIX *process,
+ lldb_private::Module *module,
+ char const *argv[],
+ char const *envp[],
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_dir,
+ lldb_private::Error &error);
+
+ ProcessMonitor(ProcessPOSIX *process,
+ lldb::pid_t pid,
+ lldb_private::Error &error);
+
+ ~ProcessMonitor();
+
+ /// Provides the process number of debugee.
+ lldb::pid_t
+ GetPID() const { return m_pid; }
+
+ /// Returns the process associated with this ProcessMonitor.
+ ProcessFreeBSD &
+ GetProcess() { return *m_process; }
+
+ /// Returns a file descriptor to the controlling terminal of the inferior
+ /// process.
+ ///
+ /// Reads from this file descriptor yield both the standard output and
+ /// standard error of this debugee. Even if stderr and stdout were
+ /// redirected on launch it may still happen that data is available on this
+ /// descriptor (if the inferior process opens /dev/tty, for example).
+ ///
+ /// If this monitor was attached to an existing process this method returns
+ /// -1.
+ int
+ GetTerminalFD() const { return m_terminal_fd; }
+
+ /// Reads @p size bytes from address @vm_adder in the inferior process
+ /// address space.
+ ///
+ /// This method is provided to implement Process::DoReadMemory.
+ size_t
+ ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+ lldb_private::Error &error);
+
+ /// Writes @p size bytes from address @p vm_adder in the inferior process
+ /// address space.
+ ///
+ /// This method is provided to implement Process::DoWriteMemory.
+ size_t
+ WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+ lldb_private::Error &error);
+
+ /// Reads the contents from the register identified by the given (architecture
+ /// dependent) offset.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
+ unsigned size, lldb_private::RegisterValue &value);
+
+ /// Writes the given value to the register identified by the given
+ /// (architecture dependent) offset.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ WriteRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
+ const lldb_private::RegisterValue &value);
+
+ /// Reads all general purpose registers into the specified buffer.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Reads all floating point registers into the specified buffer.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Reads the specified register set into the specified buffer.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset);
+
+ /// Writes all general purpose registers into the specified buffer.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Writes all floating point registers into the specified buffer.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+ /// Writes the specified register set into the specified buffer.
+ ///
+ /// This method is provided for use by RegisterContextFreeBSD derivatives.
+ /// FIXME: The FreeBSD implementation of this function should use tid in order
+ /// to enable support for debugging threaded programs.
+ bool
+ WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset);
+
+ /// Writes a ptrace_lwpinfo structure corresponding to the given thread ID
+ /// to the memory region pointed to by @p lwpinfo.
+ bool
+ GetLwpInfo(lldb::tid_t tid, void *lwpinfo, int &error_no);
+
+ /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG)
+ /// corresponding to the given thread IDto the memory pointed to by @p
+ /// message.
+ bool
+ GetEventMessage(lldb::tid_t tid, unsigned long *message);
+
+ /// Resumes the given thread. If @p signo is anything but
+ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+ bool
+ Resume(lldb::tid_t tid, uint32_t signo);
+
+ /// Single steps the given thread. If @p signo is anything but
+ /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+ bool
+ SingleStep(lldb::tid_t tid, uint32_t signo);
+
+ /// Sends the inferior process a PTRACE_KILL signal. The inferior will
+ /// still exists and can be interrogated. Once resumed it will exit as
+ /// though it received a SIGKILL.
+ bool
+ BringProcessIntoLimbo();
+
+ lldb_private::Error
+ Detach(lldb::tid_t tid);
+
+ void
+ StopMonitor();
+
+private:
+ ProcessFreeBSD *m_process;
+
+ lldb::thread_t m_operation_thread;
+ lldb::thread_t m_monitor_thread;
+ lldb::pid_t m_pid;
+
+
+ lldb_private::Mutex m_server_mutex;
+ int m_terminal_fd;
+ int m_client_fd;
+ int m_server_fd;
+
+ struct OperationArgs
+ {
+ OperationArgs(ProcessMonitor *monitor);
+
+ ~OperationArgs();
+
+ ProcessMonitor *m_monitor; // The monitor performing the attach.
+ sem_t m_semaphore; // Posted to once operation complete.
+ lldb_private::Error m_error; // Set if process operation failed.
+ };
+
+ /// @class LauchArgs
+ ///
+ /// @brief Simple structure to pass data to the thread responsible for
+ /// launching a child process.
+ struct LaunchArgs : OperationArgs
+ {
+ LaunchArgs(ProcessMonitor *monitor,
+ lldb_private::Module *module,
+ char const **argv,
+ char const **envp,
+ const char *stdin_path,
+ const char *stdout_path,
+ const char *stderr_path,
+ const char *working_dir);
+
+ ~LaunchArgs();
+
+ lldb_private::Module *m_module; // The executable image to launch.
+ char const **m_argv; // Process arguments.
+ char const **m_envp; // Process environment.
+ const char *m_stdin_path; // Redirect stdin or NULL.
+ const char *m_stdout_path; // Redirect stdout or NULL.
+ const char *m_stderr_path; // Redirect stderr or NULL.
+ const char *m_working_dir; // Working directory or NULL.
+ };
+
+ void
+ StartLaunchOpThread(LaunchArgs *args, lldb_private::Error &error);
+
+ static void *
+ LaunchOpThread(void *arg);
+
+ static bool
+ Launch(LaunchArgs *args);
+
+ bool
+ EnableIPC();
+
+ struct AttachArgs : OperationArgs
+ {
+ AttachArgs(ProcessMonitor *monitor,
+ lldb::pid_t pid);
+
+ ~AttachArgs();
+
+ lldb::pid_t m_pid; // pid of the process to be attached.
+ };
+
+ void
+ StartAttachOpThread(AttachArgs *args, lldb_private::Error &error);
+
+ static void *
+ AttachOpThread(void *args);
+
+ static bool
+ Attach(AttachArgs *args);
+
+ static void
+ ServeOperation(OperationArgs *args);
+
+ static bool
+ DupDescriptor(const char *path, int fd, int flags);
+
+ static bool
+ MonitorCallback(void *callback_baton,
+ lldb::pid_t pid, bool exited, int signal, int status);
+
+ static ProcessMessage
+ MonitorSIGTRAP(ProcessMonitor *monitor,
+ const siginfo_t *info, lldb::pid_t pid);
+
+ static ProcessMessage
+ MonitorSignal(ProcessMonitor *monitor,
+ const siginfo_t *info, lldb::pid_t pid);
+
+ static ProcessMessage::CrashReason
+ GetCrashReasonForSIGSEGV(const siginfo_t *info);
+
+ static ProcessMessage::CrashReason
+ GetCrashReasonForSIGILL(const siginfo_t *info);
+
+ static ProcessMessage::CrashReason
+ GetCrashReasonForSIGFPE(const siginfo_t *info);
+
+ static ProcessMessage::CrashReason
+ GetCrashReasonForSIGBUS(const siginfo_t *info);
+
+ void
+ DoOperation(Operation *op);
+
+ /// Stops the child monitor thread.
+ void
+ StopMonitoringChildProcess();
+
+ /// Stops the operation thread used to attach/launch a process.
+ void
+ StopOpThread();
+
+ void
+ CloseFD(int &fd);
+};
+
+#endif // #ifndef liblldb_ProcessMonitor_H_
diff --git a/source/Plugins/Process/POSIX/POSIXStopInfo.cpp b/source/Plugins/Process/POSIX/POSIXStopInfo.cpp
new file mode 100644
index 000000000000..6e2c140682ba
--- /dev/null
+++ b/source/Plugins/Process/POSIX/POSIXStopInfo.cpp
@@ -0,0 +1,89 @@
+//===-- POSIXStopInfo.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "POSIXStopInfo.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+//===----------------------------------------------------------------------===//
+// POSIXLimboStopInfo
+
+POSIXLimboStopInfo::~POSIXLimboStopInfo() { }
+
+lldb::StopReason
+POSIXLimboStopInfo::GetStopReason() const
+{
+ return lldb::eStopReasonThreadExiting;
+}
+
+const char *
+POSIXLimboStopInfo::GetDescription()
+{
+ return "thread exiting";
+}
+
+bool
+POSIXLimboStopInfo::ShouldStop(Event *event_ptr)
+{
+ return false;
+}
+
+bool
+POSIXLimboStopInfo::ShouldNotify(Event *event_ptr)
+{
+ return false;
+}
+
+//===----------------------------------------------------------------------===//
+// POSIXCrashStopInfo
+
+POSIXCrashStopInfo::~POSIXCrashStopInfo() { }
+
+lldb::StopReason
+POSIXCrashStopInfo::GetStopReason() const
+{
+ return lldb::eStopReasonException;
+}
+
+const char *
+POSIXCrashStopInfo::GetDescription()
+{
+ return ProcessMessage::GetCrashReasonString(m_crash_reason, m_fault_addr);
+}
+
+//===----------------------------------------------------------------------===//
+// POSIXNewThreadStopInfo
+
+POSIXNewThreadStopInfo::~POSIXNewThreadStopInfo() { }
+
+lldb::StopReason
+POSIXNewThreadStopInfo::GetStopReason() const
+{
+ return lldb::eStopReasonNone;
+}
+
+const char *
+POSIXNewThreadStopInfo::GetDescription()
+{
+ return "thread spawned";
+}
+
+bool
+POSIXNewThreadStopInfo::ShouldStop(Event *event_ptr)
+{
+ return false;
+}
+
+bool
+POSIXNewThreadStopInfo::ShouldNotify(Event *event_ptr)
+{
+ return false;
+}
diff --git a/source/Plugins/Process/POSIX/POSIXStopInfo.h b/source/Plugins/Process/POSIX/POSIXStopInfo.h
new file mode 100644
index 000000000000..cbf309e53506
--- /dev/null
+++ b/source/Plugins/Process/POSIX/POSIXStopInfo.h
@@ -0,0 +1,120 @@
+//===-- POSIXStopInfo.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_POSIXStopInfo_H_
+#define liblldb_POSIXStopInfo_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/StopInfo.h"
+
+#include "POSIXThread.h"
+#include "ProcessMessage.h"
+
+//===----------------------------------------------------------------------===//
+/// @class POSIXStopInfo
+/// @brief Simple base class for all POSIX-specific StopInfo objects.
+///
+class POSIXStopInfo
+ : public lldb_private::StopInfo
+{
+public:
+ POSIXStopInfo(lldb_private::Thread &thread, uint32_t status)
+ : StopInfo(thread, status)
+ { }
+};
+
+//===----------------------------------------------------------------------===//
+/// @class POSIXLimboStopInfo
+/// @brief Represents the stop state of a process ready to exit.
+///
+class POSIXLimboStopInfo
+ : public POSIXStopInfo
+{
+public:
+ POSIXLimboStopInfo(POSIXThread &thread)
+ : POSIXStopInfo(thread, 0)
+ { }
+
+ ~POSIXLimboStopInfo();
+
+ lldb::StopReason
+ GetStopReason() const;
+
+ const char *
+ GetDescription();
+
+ bool
+ ShouldStop(lldb_private::Event *event_ptr);
+
+ bool
+ ShouldNotify(lldb_private::Event *event_ptr);
+};
+
+
+//===----------------------------------------------------------------------===//
+/// @class POSIXCrashStopInfo
+/// @brief Represents the stop state of process that is ready to crash.
+///
+class POSIXCrashStopInfo
+ : public POSIXStopInfo
+{
+public:
+ POSIXCrashStopInfo(POSIXThread &thread, uint32_t status,
+ ProcessMessage::CrashReason reason,
+ lldb::addr_t fault_addr)
+ : POSIXStopInfo(thread, status),
+ m_crash_reason(reason),
+ m_fault_addr(fault_addr)
+ { }
+
+ ~POSIXCrashStopInfo();
+
+ lldb::StopReason
+ GetStopReason() const;
+
+ const char *
+ GetDescription();
+
+private:
+ ProcessMessage::CrashReason m_crash_reason;
+ lldb::addr_t m_fault_addr;
+};
+
+//===----------------------------------------------------------------------===//
+/// @class POSIXNewThreadStopInfo
+/// @brief Represents the stop state of process when a new thread is spawned.
+///
+
+class POSIXNewThreadStopInfo
+ : public POSIXStopInfo
+{
+public:
+ POSIXNewThreadStopInfo (POSIXThread &thread)
+ : POSIXStopInfo (thread, 0)
+ { }
+
+ ~POSIXNewThreadStopInfo();
+
+ lldb::StopReason
+ GetStopReason() const;
+
+ const char *
+ GetDescription();
+
+ bool
+ ShouldStop(lldb_private::Event *event_ptr);
+
+ bool
+ ShouldNotify(lldb_private::Event *event_ptr);
+};
+
+#endif
diff --git a/source/Plugins/Process/POSIX/POSIXThread.cpp b/source/Plugins/Process/POSIX/POSIXThread.cpp
new file mode 100644
index 000000000000..93c296679df2
--- /dev/null
+++ b/source/Plugins/Process/POSIX/POSIXThread.cpp
@@ -0,0 +1,578 @@
+//===-- POSIXThread.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+// C Includes
+#include <errno.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadSpec.h"
+#include "POSIXStopInfo.h"
+#include "POSIXThread.h"
+#include "ProcessPOSIX.h"
+#include "ProcessPOSIXLog.h"
+#include "ProcessMonitor.h"
+#include "RegisterContext_i386.h"
+#include "RegisterContext_x86_64.h"
+#include "RegisterContextPOSIX.h"
+#include "RegisterContextLinux_x86_64.h"
+#include "RegisterContextFreeBSD_x86_64.h"
+
+#include "UnwindLLDB.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+POSIXThread::POSIXThread(Process &process, lldb::tid_t tid)
+ : Thread(process, tid),
+ m_frame_ap (),
+ m_breakpoint (),
+ m_thread_name_valid (false),
+ m_thread_name ()
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("POSIXThread::%s (tid = %" PRIi64 ")", __FUNCTION__, tid);
+
+ // Set the current watchpoints for this thread.
+ Target &target = GetProcess()->GetTarget();
+ const WatchpointList &wp_list = target.GetWatchpointList();
+ size_t wp_size = wp_list.GetSize();
+
+ for (uint32_t wp_idx = 0; wp_idx < wp_size; wp_idx++)
+ {
+ lldb::WatchpointSP wp = wp_list.GetByIndex(wp_idx);
+ if (wp.get() && wp->IsEnabled())
+ {
+ assert(EnableHardwareWatchpoint(wp.get()));
+ }
+ }
+}
+
+POSIXThread::~POSIXThread()
+{
+ DestroyThread();
+}
+
+ProcessMonitor &
+POSIXThread::GetMonitor()
+{
+ ProcessSP base = GetProcess();
+ ProcessPOSIX &process = static_cast<ProcessPOSIX&>(*base);
+ return process.GetMonitor();
+}
+
+void
+POSIXThread::RefreshStateAfterStop()
+{
+ // Invalidate all registers in our register context. We don't set "force" to
+ // true because the stop reply packet might have had some register values
+ // that were expedited and these will already be copied into the register
+ // context by the time this function gets called. The KDPRegisterContext
+ // class has been made smart enough to detect when it needs to invalidate
+ // which registers are valid by putting hooks in the register read and
+ // register supply functions where they check the process stop ID and do
+ // the right thing.
+ //if (StateIsStoppedState(GetState())
+ {
+ const bool force = false;
+ GetRegisterContext()->InvalidateIfNeeded (force);
+ }
+ // FIXME: This should probably happen somewhere else.
+ SetResumeState(eStateRunning);
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to running", __FUNCTION__, GetID());
+}
+
+const char *
+POSIXThread::GetInfo()
+{
+ return NULL;
+}
+
+void
+POSIXThread::SetName (const char *name)
+{
+ m_thread_name_valid = (name && name[0]);
+ if (m_thread_name_valid)
+ m_thread_name.assign (name);
+ else
+ m_thread_name.clear();
+}
+
+const char *
+POSIXThread::GetName ()
+{
+ if (!m_thread_name_valid)
+ {
+ SetName(Host::GetThreadName(GetProcess()->GetID(), GetID()).c_str());
+ m_thread_name_valid = true;
+ }
+
+ if (m_thread_name.empty())
+ return NULL;
+ return m_thread_name.c_str();
+}
+
+lldb::RegisterContextSP
+POSIXThread::GetRegisterContext()
+{
+ if (!m_reg_context_sp)
+ {
+ ArchSpec arch = Host::GetArchitecture();
+
+ switch (arch.GetCore())
+ {
+ default:
+ assert(false && "CPU type not supported!");
+ break;
+
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_32_i486:
+ case ArchSpec::eCore_x86_32_i486sx:
+ m_reg_context_sp.reset(new RegisterContext_i386(*this, 0));
+ break;
+
+ case ArchSpec::eCore_x86_64_x86_64:
+ switch (arch.GetTriple().getOS())
+ {
+ case llvm::Triple::FreeBSD:
+ m_reg_context_sp.reset(new RegisterContextFreeBSD_x86_64(*this, 0));
+ break;
+ case llvm::Triple::Linux:
+ m_reg_context_sp.reset(new RegisterContextLinux_x86_64(*this, 0));
+ break;
+ default:
+ assert(false && "OS not supported");
+ break;
+ }
+ break;
+ }
+ }
+ return m_reg_context_sp;
+}
+
+lldb::RegisterContextSP
+POSIXThread::CreateRegisterContextForFrame(lldb_private::StackFrame *frame)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("POSIXThread::%s ()", __FUNCTION__);
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex();
+
+ if (concrete_frame_idx == 0)
+ reg_ctx_sp = GetRegisterContext();
+ else
+ {
+ assert(GetUnwinder());
+ reg_ctx_sp = GetUnwinder()->CreateRegisterContextForFrame(frame);
+ }
+
+ return reg_ctx_sp;
+}
+
+bool
+POSIXThread::CalculateStopInfo()
+{
+ SetStopInfo (m_stop_info_sp);
+ return true;
+}
+
+Unwind *
+POSIXThread::GetUnwinder()
+{
+ if (m_unwinder_ap.get() == NULL)
+ m_unwinder_ap.reset(new UnwindLLDB(*this));
+
+ return m_unwinder_ap.get();
+}
+
+void
+POSIXThread::WillResume(lldb::StateType resume_state)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s (tid = %" PRIi64 ") setting thread resume state to %s", __FUNCTION__, GetID(), StateAsCString(resume_state));
+ // TODO: the line below shouldn't really be done, but
+ // the POSIXThread might rely on this so I will leave this in for now
+ SetResumeState(resume_state);
+}
+
+void
+POSIXThread::DidStop()
+{
+ // Don't set the thread state to stopped unless we really stopped.
+}
+
+bool
+POSIXThread::Resume()
+{
+ lldb::StateType resume_state = GetResumeState();
+ ProcessMonitor &monitor = GetMonitor();
+ bool status;
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s (), resume_state = %s", __FUNCTION__,
+ StateAsCString(resume_state));
+
+ switch (resume_state)
+ {
+ default:
+ assert(false && "Unexpected state for resume!");
+ status = false;
+ break;
+
+ case lldb::eStateRunning:
+ SetState(resume_state);
+ status = monitor.Resume(GetID(), GetResumeSignal());
+ break;
+
+ case lldb::eStateStepping:
+ SetState(resume_state);
+ status = monitor.SingleStep(GetID(), GetResumeSignal());
+ break;
+ case lldb::eStateStopped:
+ case lldb::eStateSuspended:
+ status = true;
+ break;
+ }
+
+ return status;
+}
+
+void
+POSIXThread::Notify(const ProcessMessage &message)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s () message kind = '%s' for tid %" PRIu64,
+ __FUNCTION__, message.PrintKind(), GetID());
+
+ switch (message.GetKind())
+ {
+ default:
+ assert(false && "Unexpected message kind!");
+ break;
+
+ case ProcessMessage::eExitMessage:
+ // Nothing to be done.
+ break;
+
+ case ProcessMessage::eLimboMessage:
+ LimboNotify(message);
+ break;
+
+ case ProcessMessage::eSignalMessage:
+ SignalNotify(message);
+ break;
+
+ case ProcessMessage::eSignalDeliveredMessage:
+ SignalDeliveredNotify(message);
+ break;
+
+ case ProcessMessage::eTraceMessage:
+ TraceNotify(message);
+ break;
+
+ case ProcessMessage::eBreakpointMessage:
+ BreakNotify(message);
+ break;
+
+ case ProcessMessage::eWatchpointMessage:
+ WatchNotify(message);
+ break;
+
+ case ProcessMessage::eCrashMessage:
+ CrashNotify(message);
+ break;
+
+ case ProcessMessage::eNewThreadMessage:
+ ThreadNotify(message);
+ break;
+ }
+}
+
+bool
+POSIXThread::EnableHardwareWatchpoint(Watchpoint *wp)
+{
+ bool wp_set = false;
+ if (wp)
+ {
+ addr_t wp_addr = wp->GetLoadAddress();
+ size_t wp_size = wp->GetByteSize();
+ bool wp_read = wp->WatchpointRead();
+ bool wp_write = wp->WatchpointWrite();
+ uint32_t wp_hw_index = wp->GetHardwareIndex();
+ RegisterContextPOSIX* reg_ctx = GetRegisterContextPOSIX();
+ if (reg_ctx)
+ wp_set = reg_ctx->SetHardwareWatchpointWithIndex(wp_addr, wp_size,
+ wp_read, wp_write,
+ wp_hw_index);
+ }
+ return wp_set;
+}
+
+bool
+POSIXThread::DisableHardwareWatchpoint(Watchpoint *wp)
+{
+ bool result = false;
+ if (wp)
+ {
+ lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
+ if (reg_ctx_sp.get())
+ result = reg_ctx_sp->ClearHardwareWatchpoint(wp->GetHardwareIndex());
+ }
+ return result;
+}
+
+uint32_t
+POSIXThread::NumSupportedHardwareWatchpoints()
+{
+ lldb::RegisterContextSP reg_ctx_sp = GetRegisterContext();
+ if (reg_ctx_sp.get())
+ return reg_ctx_sp->NumSupportedHardwareWatchpoints();
+ return 0;
+}
+
+uint32_t
+POSIXThread::FindVacantWatchpointIndex()
+{
+ uint32_t hw_index = LLDB_INVALID_INDEX32;
+ uint32_t num_hw_wps = NumSupportedHardwareWatchpoints();
+ uint32_t wp_idx;
+ RegisterContextPOSIX* reg_ctx = GetRegisterContextPOSIX();
+ if (reg_ctx)
+ {
+ for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++)
+ {
+ if (reg_ctx->IsWatchpointVacant(wp_idx))
+ {
+ hw_index = wp_idx;
+ break;
+ }
+ }
+ }
+ return hw_index;
+}
+
+void
+POSIXThread::BreakNotify(const ProcessMessage &message)
+{
+ bool status;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+
+ assert(GetRegisterContext());
+ status = GetRegisterContextPOSIX()->UpdateAfterBreakpoint();
+ assert(status && "Breakpoint update failed!");
+
+ // With our register state restored, resolve the breakpoint object
+ // corresponding to our current PC.
+ assert(GetRegisterContext());
+ lldb::addr_t pc = GetRegisterContext()->GetPC();
+ if (log)
+ log->Printf ("POSIXThread::%s () PC=0x%8.8" PRIx64, __FUNCTION__, pc);
+ lldb::BreakpointSiteSP bp_site(GetProcess()->GetBreakpointSiteList().FindByAddress(pc));
+
+ // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ if (bp_site && bp_site->ValidForThisThread(this))
+ {
+ lldb::break_id_t bp_id = bp_site->GetID();
+ if (GetProcess()->GetThreadList().SetSelectedThreadByID(GetID()))
+ SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID(*this, bp_id));
+ else
+ assert(false && "Invalid thread ID during BreakNotify.");
+ }
+ else
+ {
+ const ThreadSpec *spec = bp_site ?
+ bp_site->GetOwnerAtIndex(0)->GetOptionsNoCreate()->GetThreadSpecNoCreate() : 0;
+
+ if (spec && spec->TIDMatches(*this))
+ assert(false && "BreakpointSite is invalid for the current ThreadSpec.");
+ else
+ {
+ if (!m_stop_info_sp) {
+ StopInfoSP invalid_stop_info_sp;
+ SetStopInfo (invalid_stop_info_sp);
+ }
+ }
+ }
+}
+
+void
+POSIXThread::WatchNotify(const ProcessMessage &message)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+
+ lldb::addr_t halt_addr = message.GetHWAddress();
+ if (log)
+ log->Printf ("POSIXThread::%s () Hardware Watchpoint Address = 0x%8.8"
+ PRIx64, __FUNCTION__, halt_addr);
+
+ RegisterContextPOSIX* reg_ctx = GetRegisterContextPOSIX();
+ if (reg_ctx)
+ {
+ uint32_t num_hw_wps = reg_ctx->NumSupportedHardwareWatchpoints();
+ uint32_t wp_idx;
+ for (wp_idx = 0; wp_idx < num_hw_wps; wp_idx++)
+ {
+ if (reg_ctx->IsWatchpointHit(wp_idx))
+ {
+ // Clear the watchpoint hit here
+ reg_ctx->ClearWatchpointHits();
+ break;
+ }
+ }
+
+ if (wp_idx == num_hw_wps)
+ return;
+
+ Target &target = GetProcess()->GetTarget();
+ lldb::addr_t wp_monitor_addr = reg_ctx->GetWatchpointAddress(wp_idx);
+ const WatchpointList &wp_list = target.GetWatchpointList();
+ lldb::WatchpointSP wp_sp = wp_list.FindByAddress(wp_monitor_addr);
+
+ assert(wp_sp.get() && "No watchpoint found");
+ SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID(*this,
+ wp_sp->GetID()));
+ }
+}
+
+void
+POSIXThread::TraceNotify(const ProcessMessage &message)
+{
+ SetStopInfo (StopInfo::CreateStopReasonToTrace(*this));
+}
+
+void
+POSIXThread::LimboNotify(const ProcessMessage &message)
+{
+ SetStopInfo (lldb::StopInfoSP(new POSIXLimboStopInfo(*this)));
+}
+
+void
+POSIXThread::SignalNotify(const ProcessMessage &message)
+{
+ int signo = message.GetSignal();
+
+ SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo));
+ SetResumeSignal(signo);
+}
+
+void
+POSIXThread::SignalDeliveredNotify(const ProcessMessage &message)
+{
+ int signo = message.GetSignal();
+
+ SetStopInfo (StopInfo::CreateStopReasonWithSignal(*this, signo));
+ SetResumeSignal(signo);
+}
+
+void
+POSIXThread::CrashNotify(const ProcessMessage &message)
+{
+ // FIXME: Update stop reason as per bugzilla 14598
+ int signo = message.GetSignal();
+
+ assert(message.GetKind() == ProcessMessage::eCrashMessage);
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log)
+ log->Printf ("POSIXThread::%s () signo = %i, reason = '%s'",
+ __FUNCTION__, signo, message.PrintCrashReason());
+
+ SetStopInfo (lldb::StopInfoSP(new POSIXCrashStopInfo(*this, signo,
+ message.GetCrashReason(),
+ message.GetFaultAddress())));
+ SetResumeSignal(signo);
+}
+
+void
+POSIXThread::ThreadNotify(const ProcessMessage &message)
+{
+ SetStopInfo (lldb::StopInfoSP(new POSIXNewThreadStopInfo(*this)));
+}
+
+unsigned
+POSIXThread::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg = LLDB_INVALID_REGNUM;
+ ArchSpec arch = Host::GetArchitecture();
+
+ switch (arch.GetCore())
+ {
+ default:
+ llvm_unreachable("CPU type not supported!");
+ break;
+
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_32_i486:
+ case ArchSpec::eCore_x86_32_i486sx:
+ case ArchSpec::eCore_x86_64_x86_64:
+ {
+ RegisterContextSP base = GetRegisterContext();
+ if (base) {
+ RegisterContextPOSIX &context = static_cast<RegisterContextPOSIX &>(*base);
+ reg = context.GetRegisterIndexFromOffset(offset);
+ }
+ }
+ break;
+ }
+ return reg;
+}
+
+const char *
+POSIXThread::GetRegisterName(unsigned reg)
+{
+ const char * name = nullptr;
+ ArchSpec arch = Host::GetArchitecture();
+
+ switch (arch.GetCore())
+ {
+ default:
+ assert(false && "CPU type not supported!");
+ break;
+
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_32_i486:
+ case ArchSpec::eCore_x86_32_i486sx:
+ case ArchSpec::eCore_x86_64_x86_64:
+ name = GetRegisterContext()->GetRegisterName(reg);
+ break;
+ }
+ return name;
+}
+
+const char *
+POSIXThread::GetRegisterNameFromOffset(unsigned offset)
+{
+ return GetRegisterName(GetRegisterIndexFromOffset(offset));
+}
+
diff --git a/source/Plugins/Process/POSIX/POSIXThread.h b/source/Plugins/Process/POSIX/POSIXThread.h
new file mode 100644
index 000000000000..d051d23860df
--- /dev/null
+++ b/source/Plugins/Process/POSIX/POSIXThread.h
@@ -0,0 +1,133 @@
+//===-- POSIXThread.h -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_POSIXThread_H_
+#define liblldb_POSIXThread_H_
+
+// C Includes
+// C++ Includes
+#include <memory>
+#include <string>
+
+// Other libraries and framework includes
+#include "lldb/Target/Thread.h"
+#include "RegisterContextPOSIX.h"
+
+class ProcessMessage;
+class ProcessMonitor;
+class RegisterContextPOSIX;
+
+//------------------------------------------------------------------------------
+// @class POSIXThread
+// @brief Abstraction of a POSIX thread.
+class POSIXThread
+ : public lldb_private::Thread
+{
+public:
+ POSIXThread(lldb_private::Process &process, lldb::tid_t tid);
+
+ virtual ~POSIXThread();
+
+ void
+ RefreshStateAfterStop();
+
+ virtual void
+ WillResume(lldb::StateType resume_state);
+
+ // This notifies the thread when a private stop occurs.
+ virtual void
+ DidStop ();
+
+ const char *
+ GetInfo();
+
+ void
+ SetName (const char *name);
+
+ const char *
+ GetName ();
+
+ virtual lldb::RegisterContextSP
+ GetRegisterContext();
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ //--------------------------------------------------------------------------
+ // These functions provide a mapping from the register offset
+ // back to the register index or name for use in debugging or log
+ // output.
+
+ unsigned
+ GetRegisterIndexFromOffset(unsigned offset);
+
+ const char *
+ GetRegisterName(unsigned reg);
+
+ const char *
+ GetRegisterNameFromOffset(unsigned offset);
+
+ //--------------------------------------------------------------------------
+ // These methods form a specialized interface to POSIX threads.
+ //
+ bool Resume();
+
+ void Notify(const ProcessMessage &message);
+
+ //--------------------------------------------------------------------------
+ // These methods provide an interface to watchpoints
+ //
+ bool EnableHardwareWatchpoint(lldb_private::Watchpoint *wp);
+
+ bool DisableHardwareWatchpoint(lldb_private::Watchpoint *wp);
+
+ uint32_t NumSupportedHardwareWatchpoints();
+
+ uint32_t FindVacantWatchpointIndex();
+
+protected:
+ RegisterContextPOSIX *
+ GetRegisterContextPOSIX ()
+ {
+ if (!m_reg_context_sp)
+ m_reg_context_sp = GetRegisterContext();
+#if 0
+ return dynamic_cast<RegisterContextPOSIX*>(m_reg_context_sp.get());
+#endif
+ return (RegisterContextPOSIX *)m_reg_context_sp.get();
+ }
+
+ std::unique_ptr<lldb_private::StackFrame> m_frame_ap;
+
+ lldb::BreakpointSiteSP m_breakpoint;
+
+ bool m_thread_name_valid;
+ std::string m_thread_name;
+
+ ProcessMonitor &
+ GetMonitor();
+
+ virtual bool
+ CalculateStopInfo();
+
+ void BreakNotify(const ProcessMessage &message);
+ void WatchNotify(const ProcessMessage &message);
+ virtual void TraceNotify(const ProcessMessage &message);
+ void LimboNotify(const ProcessMessage &message);
+ void SignalNotify(const ProcessMessage &message);
+ void SignalDeliveredNotify(const ProcessMessage &message);
+ void CrashNotify(const ProcessMessage &message);
+ void ThreadNotify(const ProcessMessage &message);
+ void ExitNotify(const ProcessMessage &message);
+
+ lldb_private::Unwind *
+ GetUnwinder();
+};
+
+#endif // #ifndef liblldb_POSIXThread_H_
diff --git a/source/Plugins/Process/POSIX/ProcessMessage.cpp b/source/Plugins/Process/POSIX/ProcessMessage.cpp
new file mode 100644
index 000000000000..60a29e07cea8
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessMessage.cpp
@@ -0,0 +1,258 @@
+//===-- ProcessMessage.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessMessage.h"
+
+#include <sstream>
+
+using namespace lldb_private;
+
+namespace {
+
+inline void AppendFaultAddr(std::string& str, lldb::addr_t addr)
+{
+ std::stringstream ss;
+ ss << " (fault address: 0x" << std::hex << addr << ")";
+ str += ss.str();
+}
+
+}
+
+const char *
+ProcessMessage::GetCrashReasonString(CrashReason reason, lldb::addr_t fault_addr)
+{
+ static std::string str;
+
+ switch (reason)
+ {
+ default:
+ assert(false && "invalid CrashReason");
+ break;
+
+ case eInvalidAddress:
+ str = "invalid address";
+ AppendFaultAddr(str, fault_addr);
+ break;
+ case ePrivilegedAddress:
+ str = "address access protected";
+ AppendFaultAddr(str, fault_addr);
+ break;
+ case eIllegalOpcode:
+ str = "illegal instruction";
+ break;
+ case eIllegalOperand:
+ str = "illegal instruction operand";
+ break;
+ case eIllegalAddressingMode:
+ str = "illegal addressing mode";
+ break;
+ case eIllegalTrap:
+ str = "illegal trap";
+ break;
+ case ePrivilegedOpcode:
+ str = "privileged instruction";
+ break;
+ case ePrivilegedRegister:
+ str = "privileged register";
+ break;
+ case eCoprocessorError:
+ str = "coprocessor error";
+ break;
+ case eInternalStackError:
+ str = "internal stack error";
+ break;
+ case eIllegalAlignment:
+ str = "illegal alignment";
+ break;
+ case eIllegalAddress:
+ str = "illegal address";
+ break;
+ case eHardwareError:
+ str = "hardware error";
+ break;
+ case eIntegerDivideByZero:
+ str = "integer divide by zero";
+ break;
+ case eIntegerOverflow:
+ str = "integer overflow";
+ break;
+ case eFloatDivideByZero:
+ str = "floating point divide by zero";
+ break;
+ case eFloatOverflow:
+ str = "floating point overflow";
+ break;
+ case eFloatUnderflow:
+ str = "floating point underflow";
+ break;
+ case eFloatInexactResult:
+ str = "inexact floating point result";
+ break;
+ case eFloatInvalidOperation:
+ str = "invalid floating point operation";
+ break;
+ case eFloatSubscriptRange:
+ str = "invalid floating point subscript range";
+ break;
+ }
+
+ return str.c_str();
+}
+
+const char *
+ProcessMessage::PrintCrashReason(CrashReason reason)
+{
+#ifdef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+ // Just return the code in asci for integration builds.
+ chcar str[8];
+ sprintf(str, "%d", reason);
+#else
+ const char *str = NULL;
+
+ switch (reason)
+ {
+ case eInvalidCrashReason:
+ str = "eInvalidCrashReason";
+ break;
+
+ // SIGSEGV crash reasons.
+ case eInvalidAddress:
+ str = "eInvalidAddress";
+ break;
+ case ePrivilegedAddress:
+ str = "ePrivilegedAddress";
+ break;
+
+ // SIGILL crash reasons.
+ case eIllegalOpcode:
+ str = "eIllegalOpcode";
+ break;
+ case eIllegalOperand:
+ str = "eIllegalOperand";
+ break;
+ case eIllegalAddressingMode:
+ str = "eIllegalAddressingMode";
+ break;
+ case eIllegalTrap:
+ str = "eIllegalTrap";
+ break;
+ case ePrivilegedOpcode:
+ str = "ePrivilegedOpcode";
+ break;
+ case ePrivilegedRegister:
+ str = "ePrivilegedRegister";
+ break;
+ case eCoprocessorError:
+ str = "eCoprocessorError";
+ break;
+ case eInternalStackError:
+ str = "eInternalStackError";
+ break;
+
+ // SIGBUS crash reasons:
+ case eIllegalAlignment:
+ str = "eIllegalAlignment";
+ break;
+ case eIllegalAddress:
+ str = "eIllegalAddress";
+ break;
+ case eHardwareError:
+ str = "eHardwareError";
+ break;
+
+ // SIGFPE crash reasons:
+ case eIntegerDivideByZero:
+ str = "eIntegerDivideByZero";
+ break;
+ case eIntegerOverflow:
+ str = "eIntegerOverflow";
+ break;
+ case eFloatDivideByZero:
+ str = "eFloatDivideByZero";
+ break;
+ case eFloatOverflow:
+ str = "eFloatOverflow";
+ break;
+ case eFloatUnderflow:
+ str = "eFloatUnderflow";
+ break;
+ case eFloatInexactResult:
+ str = "eFloatInexactResult";
+ break;
+ case eFloatInvalidOperation:
+ str = "eFloatInvalidOperation";
+ break;
+ case eFloatSubscriptRange:
+ str = "eFloatSubscriptRange";
+ break;
+ }
+#endif
+
+ return str;
+}
+
+const char *
+ProcessMessage::PrintCrashReason() const
+{
+ return PrintCrashReason(m_crash_reason);
+}
+
+const char *
+ProcessMessage::PrintKind(Kind kind)
+{
+#ifdef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+ // Just return the code in asci for integration builds.
+ chcar str[8];
+ sprintf(str, "%d", reason);
+#else
+ const char *str = NULL;
+
+ switch (kind)
+ {
+ case eInvalidMessage:
+ str = "eInvalidMessage";
+ break;
+ case eExitMessage:
+ str = "eExitMessage";
+ break;
+ case eLimboMessage:
+ str = "eLimboMessage";
+ break;
+ case eSignalMessage:
+ str = "eSignalMessage";
+ break;
+ case eSignalDeliveredMessage:
+ str = "eSignalDeliveredMessage";
+ break;
+ case eTraceMessage:
+ str = "eTraceMessage";
+ break;
+ case eBreakpointMessage:
+ str = "eBreakpointMessage";
+ break;
+ case eWatchpointMessage:
+ str = "eWatchpointMessage";
+ break;
+ case eCrashMessage:
+ str = "eCrashMessage";
+ break;
+ case eNewThreadMessage:
+ str = "eNewThreadMessage";
+ break;
+ }
+#endif
+
+ return str;
+}
+
+const char *
+ProcessMessage::PrintKind() const
+{
+ return PrintKind(m_kind);
+}
diff --git a/source/Plugins/Process/POSIX/ProcessMessage.h b/source/Plugins/Process/POSIX/ProcessMessage.h
new file mode 100644
index 000000000000..c6c460c13445
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessMessage.h
@@ -0,0 +1,207 @@
+//===-- ProcessMessage.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessMessage_H_
+#define liblldb_ProcessMessage_H_
+
+#include <cassert>
+
+#include "lldb/lldb-defines.h"
+#include "lldb/lldb-types.h"
+
+class ProcessMessage
+{
+public:
+
+ /// The type of signal this message can correspond to.
+ enum Kind
+ {
+ eInvalidMessage,
+ eExitMessage,
+ eLimboMessage,
+ eSignalMessage,
+ eSignalDeliveredMessage,
+ eTraceMessage,
+ eBreakpointMessage,
+ eWatchpointMessage,
+ eCrashMessage,
+ eNewThreadMessage
+ };
+
+ enum CrashReason
+ {
+ eInvalidCrashReason,
+
+ // SIGSEGV crash reasons.
+ eInvalidAddress,
+ ePrivilegedAddress,
+
+ // SIGILL crash reasons.
+ eIllegalOpcode,
+ eIllegalOperand,
+ eIllegalAddressingMode,
+ eIllegalTrap,
+ ePrivilegedOpcode,
+ ePrivilegedRegister,
+ eCoprocessorError,
+ eInternalStackError,
+
+ // SIGBUS crash reasons,
+ eIllegalAlignment,
+ eIllegalAddress,
+ eHardwareError,
+
+ // SIGFPE crash reasons,
+ eIntegerDivideByZero,
+ eIntegerOverflow,
+ eFloatDivideByZero,
+ eFloatOverflow,
+ eFloatUnderflow,
+ eFloatInexactResult,
+ eFloatInvalidOperation,
+ eFloatSubscriptRange
+ };
+
+ ProcessMessage()
+ : m_tid(LLDB_INVALID_PROCESS_ID),
+ m_kind(eInvalidMessage),
+ m_crash_reason(eInvalidCrashReason),
+ m_status(0),
+ m_addr(0) { }
+
+ Kind GetKind() const { return m_kind; }
+
+ lldb::tid_t GetTID() const { return m_tid; }
+
+ /// Indicates that the thread @p tid is about to exit with status @p status.
+ static ProcessMessage Limbo(lldb::tid_t tid, int status) {
+ return ProcessMessage(tid, eLimboMessage, status);
+ }
+
+ /// Indicates that the thread @p tid had the signal @p signum delivered.
+ static ProcessMessage Signal(lldb::tid_t tid, int signum) {
+ return ProcessMessage(tid, eSignalMessage, signum);
+ }
+
+ /// Indicates that a signal @p signum generated by the debugging process was
+ /// delivered to the thread @p tid.
+ static ProcessMessage SignalDelivered(lldb::tid_t tid, int signum) {
+ return ProcessMessage(tid, eSignalDeliveredMessage, signum);
+ }
+
+ /// Indicates that the thread @p tid encountered a trace point.
+ static ProcessMessage Trace(lldb::tid_t tid) {
+ return ProcessMessage(tid, eTraceMessage);
+ }
+
+ /// Indicates that the thread @p tid encountered a break point.
+ static ProcessMessage Break(lldb::tid_t tid) {
+ return ProcessMessage(tid, eBreakpointMessage);
+ }
+
+ static ProcessMessage Watch(lldb::tid_t tid, lldb::addr_t wp_addr) {
+ return ProcessMessage(tid, eWatchpointMessage, 0, wp_addr);
+ }
+
+ /// Indicates that the thread @p tid crashed.
+ static ProcessMessage Crash(lldb::pid_t pid, CrashReason reason,
+ int signo, lldb::addr_t fault_addr) {
+ ProcessMessage message(pid, eCrashMessage, signo, fault_addr);
+ message.m_crash_reason = reason;
+ return message;
+ }
+
+ /// Indicates that the thread @p child_tid was spawned.
+ static ProcessMessage NewThread(lldb::tid_t parent_tid, lldb::tid_t child_tid) {
+ return ProcessMessage(parent_tid, eNewThreadMessage, child_tid);
+ }
+
+ /// Indicates that the thread @p tid is about to exit with status @p status.
+ static ProcessMessage Exit(lldb::tid_t tid, int status) {
+ return ProcessMessage(tid, eExitMessage, status);
+ }
+
+ int GetExitStatus() const {
+ assert(GetKind() == eExitMessage || GetKind() == eLimboMessage);
+ return m_status;
+ }
+
+ int GetSignal() const {
+ assert(GetKind() == eSignalMessage || GetKind() == eCrashMessage ||
+ GetKind() == eSignalDeliveredMessage);
+ return m_status;
+ }
+
+ int GetStopStatus() const {
+ assert(GetKind() == eSignalMessage);
+ return m_status;
+ }
+
+ CrashReason GetCrashReason() const {
+ assert(GetKind() == eCrashMessage);
+ return m_crash_reason;
+ }
+
+ lldb::addr_t GetFaultAddress() const {
+ assert(GetKind() == eCrashMessage);
+ return m_addr;
+ }
+
+ lldb::addr_t GetHWAddress() const {
+ assert(GetKind() == eWatchpointMessage || GetKind() == eTraceMessage);
+ return m_addr;
+ }
+
+ lldb::tid_t GetChildTID() const {
+ assert(GetKind() == eNewThreadMessage);
+ return m_child_tid;
+ }
+
+ static const char *
+ GetCrashReasonString(CrashReason reason, lldb::addr_t fault_addr);
+
+ const char *
+ PrintCrashReason() const;
+
+ static const char *
+ PrintCrashReason(CrashReason reason);
+
+ const char *
+ PrintKind() const;
+
+ static const char *
+ PrintKind(Kind);
+
+private:
+ ProcessMessage(lldb::tid_t tid, Kind kind,
+ int status = 0, lldb::addr_t addr = 0)
+ : m_tid(tid),
+ m_kind(kind),
+ m_crash_reason(eInvalidCrashReason),
+ m_status(status),
+ m_addr(addr),
+ m_child_tid(0) { }
+
+ ProcessMessage(lldb::tid_t tid, Kind kind, lldb::tid_t child_tid)
+ : m_tid(tid),
+ m_kind(kind),
+ m_crash_reason(eInvalidCrashReason),
+ m_status(0),
+ m_addr(0),
+ m_child_tid(child_tid) { }
+
+ lldb::tid_t m_tid;
+ Kind m_kind : 8;
+ CrashReason m_crash_reason : 8;
+ int m_status;
+ lldb::addr_t m_addr;
+ lldb::tid_t m_child_tid;
+};
+
+#endif // #ifndef liblldb_ProcessMessage_H_
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
new file mode 100644
index 000000000000..f04631ddf914
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
@@ -0,0 +1,911 @@
+//===-- ProcessPOSIX.cpp ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+// C Includes
+#include <errno.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Target.h"
+
+#include "ProcessPOSIX.h"
+#include "ProcessPOSIXLog.h"
+#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
+#include "ProcessMonitor.h"
+#include "POSIXThread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//------------------------------------------------------------------------------
+// Static functions.
+#if 0
+Process*
+ProcessPOSIX::CreateInstance(Target& target, Listener &listener)
+{
+ return new ProcessPOSIX(target, listener);
+}
+
+
+void
+ProcessPOSIX::Initialize()
+{
+ static bool g_initialized = false;
+
+ if (!g_initialized)
+ {
+ g_initialized = true;
+ PluginManager::RegisterPlugin(GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+
+ Log::Callbacks log_callbacks = {
+ ProcessPOSIXLog::DisableLog,
+ ProcessPOSIXLog::EnableLog,
+ ProcessPOSIXLog::ListLogCategories
+ };
+
+ Log::RegisterLogChannel (ProcessPOSIX::GetPluginNameStatic(), log_callbacks);
+ }
+}
+#endif
+
+//------------------------------------------------------------------------------
+// Constructors and destructors.
+
+ProcessPOSIX::ProcessPOSIX(Target& target, Listener &listener)
+ : Process(target, listener),
+ m_byte_order(lldb::endian::InlHostByteOrder()),
+ m_monitor(NULL),
+ m_module(NULL),
+ m_message_mutex (Mutex::eMutexTypeRecursive),
+ m_exit_now(false),
+ m_seen_initial_stop()
+{
+ // FIXME: Putting this code in the ctor and saving the byte order in a
+ // member variable is a hack to avoid const qual issues in GetByteOrder.
+ lldb::ModuleSP module = GetTarget().GetExecutableModule();
+ if (module && module->GetObjectFile())
+ m_byte_order = module->GetObjectFile()->GetByteOrder();
+}
+
+ProcessPOSIX::~ProcessPOSIX()
+{
+ delete m_monitor;
+}
+
+//------------------------------------------------------------------------------
+// Process protocol.
+void
+ProcessPOSIX::Finalize()
+{
+ Process::Finalize();
+
+ if (m_monitor)
+ m_monitor->StopMonitor();
+}
+
+bool
+ProcessPOSIX::CanDebug(Target &target, bool plugin_specified_by_name)
+{
+ // For now we are just making sure the file exists for a given module
+ ModuleSP exe_module_sp(target.GetExecutableModule());
+ if (exe_module_sp.get())
+ return exe_module_sp->GetFileSpec().Exists();
+ // If there is no executable module, we return true since we might be preparing to attach.
+ return true;
+}
+
+Error
+ProcessPOSIX::DoAttachToProcessWithID(lldb::pid_t pid)
+{
+ Error error;
+ assert(m_monitor == NULL);
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessPOSIX::%s(pid = %" PRIi64 ")", __FUNCTION__, GetID());
+
+ m_monitor = new ProcessMonitor(this, pid, error);
+
+ if (!error.Success())
+ return error;
+
+ PlatformSP platform_sp (m_target.GetPlatform ());
+ assert (platform_sp.get());
+ if (!platform_sp)
+ return error; // FIXME: Detatch?
+
+ // Find out what we can about this process
+ ProcessInstanceInfo process_info;
+ platform_sp->GetProcessInfo (pid, process_info);
+
+ // Resolve the executable module
+ ModuleSP exe_module_sp;
+ FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
+ error = platform_sp->ResolveExecutable(process_info.GetExecutableFile(),
+ m_target.GetArchitecture(),
+ exe_module_sp,
+ executable_search_paths.GetSize() ? &executable_search_paths : NULL);
+ if (!error.Success())
+ return error;
+
+ // Fix the target architecture if necessary
+ const ArchSpec &module_arch = exe_module_sp->GetArchitecture();
+ if (module_arch.IsValid() && !m_target.GetArchitecture().IsExactMatch(module_arch))
+ m_target.SetArchitecture(module_arch);
+
+ // Initialize the target module list
+ m_target.SetExecutableModule (exe_module_sp, true);
+
+ SetSTDIOFileDescriptor(m_monitor->GetTerminalFD());
+
+ SetID(pid);
+
+ return error;
+}
+
+Error
+ProcessPOSIX::DoAttachToProcessWithID (lldb::pid_t pid, const ProcessAttachInfo &attach_info)
+{
+ return DoAttachToProcessWithID(pid);
+}
+
+Error
+ProcessPOSIX::WillLaunch(Module* module)
+{
+ Error error;
+ return error;
+}
+
+const char *
+ProcessPOSIX::GetFilePath(
+ const lldb_private::ProcessLaunchInfo::FileAction *file_action,
+ const char *default_path)
+{
+ const char *pts_name = "/dev/pts/";
+ const char *path = NULL;
+
+ if (file_action)
+ {
+ if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
+ path = file_action->GetPath();
+ // By default the stdio paths passed in will be pseudo-terminal
+ // (/dev/pts). If so, convert to using a different default path
+ // instead to redirect I/O to the debugger console. This should
+ // also handle user overrides to /dev/null or a different file.
+ if (::strncmp(path, pts_name, ::strlen(pts_name)) == 0)
+ path = default_path;
+ }
+
+ return path;
+}
+
+Error
+ProcessPOSIX::DoLaunch (Module *module,
+ const ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ assert(m_monitor == NULL);
+
+ const char* working_dir = launch_info.GetWorkingDirectory();
+ if (working_dir) {
+ FileSpec WorkingDir(working_dir, true);
+ if (!WorkingDir || WorkingDir.GetFileType() != FileSpec::eFileTypeDirectory)
+ {
+ error.SetErrorStringWithFormat("No such file or directory: %s", working_dir);
+ return error;
+ }
+ }
+
+ SetPrivateState(eStateLaunching);
+
+ const lldb_private::ProcessLaunchInfo::FileAction *file_action;
+
+ // Default of NULL will mean to use existing open file descriptors
+ const char *stdin_path = NULL;
+ const char *stdout_path = NULL;
+ const char *stderr_path = NULL;
+
+ file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
+ stdin_path = GetFilePath(file_action, stdin_path);
+
+ file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
+ stdout_path = GetFilePath(file_action, stdout_path);
+
+ file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
+ stderr_path = GetFilePath(file_action, stderr_path);
+
+ m_monitor = new ProcessMonitor (this,
+ module,
+ launch_info.GetArguments().GetConstArgumentVector(),
+ launch_info.GetEnvironmentEntries().GetConstArgumentVector(),
+ stdin_path,
+ stdout_path,
+ stderr_path,
+ working_dir,
+ error);
+
+ m_module = module;
+
+ if (!error.Success())
+ return error;
+
+ SetSTDIOFileDescriptor(m_monitor->GetTerminalFD());
+
+ SetID(m_monitor->GetPID());
+ return error;
+}
+
+void
+ProcessPOSIX::DidLaunch()
+{
+}
+
+Error
+ProcessPOSIX::DoResume()
+{
+ StateType state = GetPrivateState();
+
+ assert(state == eStateStopped);
+
+ SetPrivateState(eStateRunning);
+
+ bool did_resume = false;
+
+ Mutex::Locker lock(m_thread_list.GetMutex());
+
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ did_resume = thread->Resume() || did_resume;
+ }
+ assert(did_resume && "Process resume failed!");
+
+ return Error();
+}
+
+addr_t
+ProcessPOSIX::GetImageInfoAddress()
+{
+ Target *target = &GetTarget();
+ ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
+ Address addr = obj_file->GetImageInfoAddress();
+
+ if (addr.IsValid())
+ return addr.GetLoadAddress(target);
+ else
+ return LLDB_INVALID_ADDRESS;
+}
+
+Error
+ProcessPOSIX::DoHalt(bool &caused_stop)
+{
+ Error error;
+
+ if (IsStopped())
+ {
+ caused_stop = false;
+ }
+ else if (kill(GetID(), SIGSTOP))
+ {
+ caused_stop = false;
+ error.SetErrorToErrno();
+ }
+ else
+ {
+ caused_stop = true;
+ }
+ return error;
+}
+
+Error
+ProcessPOSIX::DoDetach(bool keep_stopped)
+{
+ Error error;
+ if (keep_stopped)
+ {
+ // FIXME: If you want to implement keep_stopped,
+ // this would be the place to do it.
+ error.SetErrorString("Detaching with keep_stopped true is not currently supported on this platform.");
+ return error;
+ }
+
+ Mutex::Locker lock(m_thread_list.GetMutex());
+
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ error = m_monitor->Detach(thread->GetID());
+ }
+
+ if (error.Success())
+ SetPrivateState(eStateDetached);
+
+ return error;
+}
+
+Error
+ProcessPOSIX::DoSignal(int signal)
+{
+ Error error;
+
+ if (kill(GetID(), signal))
+ error.SetErrorToErrno();
+
+ return error;
+}
+
+Error
+ProcessPOSIX::DoDestroy()
+{
+ Error error;
+
+ if (!HasExited())
+ {
+ // Drive the exit event to completion (do not keep the inferior in
+ // limbo).
+ m_exit_now = true;
+
+ if ((m_monitor == NULL || kill(m_monitor->GetPID(), SIGKILL)) && error.Success())
+ {
+ error.SetErrorToErrno();
+ return error;
+ }
+
+ SetPrivateState(eStateExited);
+ }
+
+ return error;
+}
+
+void
+ProcessPOSIX::SendMessage(const ProcessMessage &message)
+{
+ Mutex::Locker lock(m_message_mutex);
+
+ Mutex::Locker thread_lock(m_thread_list.GetMutex());
+
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.FindThreadByID(message.GetTID(), false).get());
+
+ switch (message.GetKind())
+ {
+ case ProcessMessage::eInvalidMessage:
+ return;
+
+ case ProcessMessage::eLimboMessage:
+ assert(thread);
+ thread->SetState(eStateStopped);
+ if (message.GetTID() == GetID())
+ {
+ m_exit_status = message.GetExitStatus();
+ if (m_exit_now)
+ {
+ SetPrivateState(eStateExited);
+ m_monitor->Detach(GetID());
+ }
+ else
+ {
+ StopAllThreads(message.GetTID());
+ SetPrivateState(eStateStopped);
+ }
+ }
+ else
+ {
+ StopAllThreads(message.GetTID());
+ SetPrivateState(eStateStopped);
+ }
+ break;
+
+ case ProcessMessage::eExitMessage:
+ assert(thread);
+ thread->SetState(eStateExited);
+ // FIXME: I'm not sure we need to do this.
+ if (message.GetTID() == GetID())
+ {
+ m_exit_status = message.GetExitStatus();
+ SetExitStatus(m_exit_status, NULL);
+ }
+ else if (!IsAThreadRunning())
+ SetPrivateState(eStateStopped);
+ break;
+
+ case ProcessMessage::eSignalMessage:
+ case ProcessMessage::eSignalDeliveredMessage:
+ if (message.GetSignal() == SIGSTOP &&
+ AddThreadForInitialStopIfNeeded(message.GetTID()))
+ return;
+ // Intentional fall-through
+
+ case ProcessMessage::eBreakpointMessage:
+ case ProcessMessage::eTraceMessage:
+ case ProcessMessage::eWatchpointMessage:
+ case ProcessMessage::eNewThreadMessage:
+ case ProcessMessage::eCrashMessage:
+ assert(thread);
+ thread->SetState(eStateStopped);
+ StopAllThreads(message.GetTID());
+ SetPrivateState(eStateStopped);
+ break;
+ }
+
+ m_message_queue.push(message);
+}
+
+void
+ProcessPOSIX::StopAllThreads(lldb::tid_t stop_tid)
+{
+ // FIXME: Will this work the same way on FreeBSD and Linux?
+}
+
+bool
+ProcessPOSIX::AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid)
+{
+ bool added_to_set = false;
+ ThreadStopSet::iterator it = m_seen_initial_stop.find(stop_tid);
+ if (it == m_seen_initial_stop.end())
+ {
+ m_seen_initial_stop.insert(stop_tid);
+ added_to_set = true;
+ }
+ return added_to_set;
+}
+
+POSIXThread *
+ProcessPOSIX::CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid)
+{
+ return new POSIXThread(process, tid);
+}
+
+void
+ProcessPOSIX::RefreshStateAfterStop()
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessPOSIX::%s(), message_queue size = %d", __FUNCTION__, (int)m_message_queue.size());
+
+ Mutex::Locker lock(m_message_mutex);
+
+ // This method used to only handle one message. Changing it to loop allows
+ // it to handle the case where we hit a breakpoint while handling a different
+ // breakpoint.
+ while (!m_message_queue.empty())
+ {
+ ProcessMessage &message = m_message_queue.front();
+
+ // Resolve the thread this message corresponds to and pass it along.
+ lldb::tid_t tid = message.GetTID();
+ if (log)
+ log->Printf ("ProcessPOSIX::%s(), message_queue size = %d, pid = %" PRIi64, __FUNCTION__, (int)m_message_queue.size(), tid);
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ GetThreadList().FindThreadByID(tid, false).get());
+
+ if (message.GetKind() == ProcessMessage::eNewThreadMessage)
+ {
+ if (log)
+ log->Printf ("ProcessPOSIX::%s() adding thread, tid = %" PRIi64, __FUNCTION__, message.GetChildTID());
+ lldb::tid_t child_tid = message.GetChildTID();
+ ThreadSP thread_sp;
+ thread_sp.reset(CreateNewPOSIXThread(*this, child_tid));
+
+ Mutex::Locker lock(m_thread_list.GetMutex());
+
+ m_thread_list.AddThread(thread_sp);
+ }
+
+ m_thread_list.RefreshStateAfterStop();
+
+ if (thread)
+ thread->Notify(message);
+
+ if (message.GetKind() == ProcessMessage::eExitMessage)
+ {
+ // FIXME: We should tell the user about this, but the limbo message is probably better for that.
+ if (log)
+ log->Printf ("ProcessPOSIX::%s() removing thread, tid = %" PRIi64, __FUNCTION__, tid);
+
+ Mutex::Locker lock(m_thread_list.GetMutex());
+
+ ThreadSP thread_sp = m_thread_list.RemoveThreadByID(tid, false);
+ thread_sp.reset();
+ m_seen_initial_stop.erase(tid);
+ }
+
+ m_message_queue.pop();
+ }
+}
+
+bool
+ProcessPOSIX::IsAlive()
+{
+ StateType state = GetPrivateState();
+ return state != eStateDetached
+ && state != eStateExited
+ && state != eStateInvalid
+ && state != eStateUnloaded;
+}
+
+size_t
+ProcessPOSIX::DoReadMemory(addr_t vm_addr,
+ void *buf, size_t size, Error &error)
+{
+ assert(m_monitor);
+ return m_monitor->ReadMemory(vm_addr, buf, size, error);
+}
+
+size_t
+ProcessPOSIX::DoWriteMemory(addr_t vm_addr, const void *buf, size_t size,
+ Error &error)
+{
+ assert(m_monitor);
+ return m_monitor->WriteMemory(vm_addr, buf, size, error);
+}
+
+addr_t
+ProcessPOSIX::DoAllocateMemory(size_t size, uint32_t permissions,
+ Error &error)
+{
+ addr_t allocated_addr = LLDB_INVALID_ADDRESS;
+
+ unsigned prot = 0;
+ if (permissions & lldb::ePermissionsReadable)
+ prot |= eMmapProtRead;
+ if (permissions & lldb::ePermissionsWritable)
+ prot |= eMmapProtWrite;
+ if (permissions & lldb::ePermissionsExecutable)
+ prot |= eMmapProtExec;
+
+ if (InferiorCallMmap(this, allocated_addr, 0, size, prot,
+ eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0)) {
+ m_addr_to_mmap_size[allocated_addr] = size;
+ error.Clear();
+ } else {
+ allocated_addr = LLDB_INVALID_ADDRESS;
+ error.SetErrorStringWithFormat("unable to allocate %zu bytes of memory with permissions %s", size, GetPermissionsAsCString (permissions));
+ }
+
+ return allocated_addr;
+}
+
+Error
+ProcessPOSIX::DoDeallocateMemory(lldb::addr_t addr)
+{
+ Error error;
+ MMapMap::iterator pos = m_addr_to_mmap_size.find(addr);
+ if (pos != m_addr_to_mmap_size.end() &&
+ InferiorCallMunmap(this, addr, pos->second))
+ m_addr_to_mmap_size.erase (pos);
+ else
+ error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr);
+
+ return error;
+}
+
+addr_t
+ProcessPOSIX::ResolveIndirectFunction(const Address *address, Error &error)
+{
+ addr_t function_addr = LLDB_INVALID_ADDRESS;
+ if (address == NULL) {
+ error.SetErrorStringWithFormat("unable to determine direct function call for NULL address");
+ } else if (!InferiorCall(this, address, function_addr)) {
+ function_addr = LLDB_INVALID_ADDRESS;
+ error.SetErrorStringWithFormat("unable to determine direct function call for indirect function %s",
+ address->CalculateSymbolContextSymbol()->GetName().AsCString());
+ }
+ return function_addr;
+}
+
+size_t
+ProcessPOSIX::GetSoftwareBreakpointTrapOpcode(BreakpointSite* bp_site)
+{
+ static const uint8_t g_i386_opcode[] = { 0xCC };
+
+ ArchSpec arch = GetTarget().GetArchitecture();
+ const uint8_t *opcode = NULL;
+ size_t opcode_size = 0;
+
+ switch (arch.GetCore())
+ {
+ default:
+ assert(false && "CPU type not supported!");
+ break;
+
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_64_x86_64:
+ opcode = g_i386_opcode;
+ opcode_size = sizeof(g_i386_opcode);
+ break;
+ }
+
+ bp_site->SetTrapOpcode(opcode, opcode_size);
+ return opcode_size;
+}
+
+Error
+ProcessPOSIX::EnableBreakpointSite(BreakpointSite *bp_site)
+{
+ return EnableSoftwareBreakpoint(bp_site);
+}
+
+Error
+ProcessPOSIX::DisableBreakpointSite(BreakpointSite *bp_site)
+{
+ return DisableSoftwareBreakpoint(bp_site);
+}
+
+Error
+ProcessPOSIX::EnableWatchpoint(Watchpoint *wp, bool notify)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+ addr_t addr = wp->GetLoadAddress();
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64 ")",
+ watchID);
+ if (wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessPOSIX::EnableWatchpoint(watchID = %" PRIu64
+ ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.",
+ watchID, (uint64_t)addr);
+ return error;
+ }
+
+ // Try to find a vacant watchpoint slot in the inferiors' main thread
+ uint32_t wp_hw_index = LLDB_INVALID_INDEX32;
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(0, false).get());
+
+ if (thread)
+ wp_hw_index = thread->FindVacantWatchpointIndex();
+
+ if (wp_hw_index == LLDB_INVALID_INDEX32)
+ {
+ error.SetErrorString("Setting hardware watchpoint failed.");
+ }
+ else
+ {
+ wp->SetHardwareIndex(wp_hw_index);
+ bool wp_enabled = true;
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ if (thread)
+ wp_enabled &= thread->EnableHardwareWatchpoint(wp);
+ else
+ wp_enabled = false;
+ }
+ if (wp_enabled)
+ {
+ wp->SetEnabled(true, notify);
+ return error;
+ }
+ else
+ {
+ // Watchpoint enabling failed on at least one
+ // of the threads so roll back all of them
+ DisableWatchpoint(wp, false);
+ error.SetErrorString("Setting hardware watchpoint failed");
+ }
+ }
+ }
+ else
+ error.SetErrorString("Watchpoint argument was NULL.");
+ return error;
+}
+
+Error
+ProcessPOSIX::DisableWatchpoint(Watchpoint *wp, bool notify)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+ addr_t addr = wp->GetLoadAddress();
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64 ")",
+ watchID);
+ if (!wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessPOSIX::DisableWatchpoint(watchID = %" PRIu64
+ ") addr = 0x%8.8" PRIx64 ": watchpoint already disabled.",
+ watchID, (uint64_t)addr);
+ // This is needed (for now) to keep watchpoints disabled correctly
+ wp->SetEnabled(false, notify);
+ return error;
+ }
+
+ if (wp->IsHardware())
+ {
+ bool wp_disabled = true;
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ if (thread)
+ wp_disabled &= thread->DisableHardwareWatchpoint(wp);
+ else
+ wp_disabled = false;
+ }
+ if (wp_disabled)
+ {
+ wp->SetHardwareIndex(LLDB_INVALID_INDEX32);
+ wp->SetEnabled(false, notify);
+ return error;
+ }
+ else
+ error.SetErrorString("Disabling hardware watchpoint failed");
+ }
+ }
+ else
+ error.SetErrorString("Watchpoint argument was NULL.");
+ return error;
+}
+
+Error
+ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num)
+{
+ Error error;
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(0, false).get());
+ if (thread)
+ num = thread->NumSupportedHardwareWatchpoints();
+ else
+ error.SetErrorString("Process does not exist.");
+ return error;
+}
+
+Error
+ProcessPOSIX::GetWatchpointSupportInfo(uint32_t &num, bool &after)
+{
+ Error error = GetWatchpointSupportInfo(num);
+ // Watchpoints trigger and halt the inferior after
+ // the corresponding instruction has been executed.
+ after = true;
+ return error;
+}
+
+uint32_t
+ProcessPOSIX::UpdateThreadListIfNeeded()
+{
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ // Do not allow recursive updates.
+ return m_thread_list.GetSize(false);
+}
+
+bool
+ProcessPOSIX::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessPOSIX::%s() (pid = %" PRIi64 ")", __FUNCTION__, GetID());
+
+ // Update the process thread list with this new thread.
+ // FIXME: We should be using tid, not pid.
+ assert(m_monitor);
+ ThreadSP thread_sp (old_thread_list.FindThreadByID (GetID(), false));
+ if (!thread_sp) {
+ thread_sp.reset(CreateNewPOSIXThread(*this, GetID()));
+ }
+
+ if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
+ log->Printf ("ProcessPOSIX::%s() updated pid = %" PRIi64, __FUNCTION__, GetID());
+ new_thread_list.AddThread(thread_sp);
+
+ return new_thread_list.GetSize(false) > 0;
+}
+
+ByteOrder
+ProcessPOSIX::GetByteOrder() const
+{
+ // FIXME: We should be able to extract this value directly. See comment in
+ // ProcessPOSIX().
+ return m_byte_order;
+}
+
+size_t
+ProcessPOSIX::PutSTDIN(const char *buf, size_t len, Error &error)
+{
+ ssize_t status;
+ if ((status = write(m_monitor->GetTerminalFD(), buf, len)) < 0)
+ {
+ error.SetErrorToErrno();
+ return 0;
+ }
+ return status;
+}
+
+UnixSignals &
+ProcessPOSIX::GetUnixSignals()
+{
+ return m_signals;
+}
+
+//------------------------------------------------------------------------------
+// Utility functions.
+
+bool
+ProcessPOSIX::HasExited()
+{
+ switch (GetPrivateState())
+ {
+ default:
+ break;
+
+ case eStateDetached:
+ case eStateExited:
+ return true;
+ }
+
+ return false;
+}
+
+bool
+ProcessPOSIX::IsStopped()
+{
+ switch (GetPrivateState())
+ {
+ default:
+ break;
+
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ return true;
+ }
+
+ return false;
+}
+
+bool
+ProcessPOSIX::IsAThreadRunning()
+{
+ bool is_running = false;
+ Mutex::Locker lock(m_thread_list.GetMutex());
+ uint32_t thread_count = m_thread_list.GetSize(false);
+ for (uint32_t i = 0; i < thread_count; ++i)
+ {
+ POSIXThread *thread = static_cast<POSIXThread*>(
+ m_thread_list.GetThreadAtIndex(i, false).get());
+ StateType thread_state = thread->GetState();
+ if (thread_state == eStateRunning || thread_state == eStateStepping)
+ {
+ is_running = true;
+ break;
+ }
+ }
+ return is_running;
+}
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.h b/source/Plugins/Process/POSIX/ProcessPOSIX.h
new file mode 100644
index 000000000000..48b19bac47e7
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessPOSIX.h
@@ -0,0 +1,211 @@
+//===-- ProcessPOSIX.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessPOSIX_H_
+#define liblldb_ProcessPOSIX_H_
+
+// C Includes
+
+// C++ Includes
+#include <queue>
+#include <set>
+
+// Other libraries and framework includes
+#include "lldb/Target/Process.h"
+#include "lldb/Target/UnixSignals.h"
+#include "ProcessMessage.h"
+
+class ProcessMonitor;
+class POSIXThread;
+
+class ProcessPOSIX :
+ public lldb_private::Process
+{
+public:
+
+ //------------------------------------------------------------------
+ // Constructors and destructors
+ //------------------------------------------------------------------
+ ProcessPOSIX(lldb_private::Target& target,
+ lldb_private::Listener &listener);
+
+ virtual
+ ~ProcessPOSIX();
+
+ //------------------------------------------------------------------
+ // Process protocol.
+ //------------------------------------------------------------------
+ virtual void
+ Finalize();
+
+ virtual bool
+ CanDebug(lldb_private::Target &target, bool plugin_specified_by_name);
+
+ virtual lldb_private::Error
+ WillLaunch(lldb_private::Module *module);
+
+ virtual lldb_private::Error
+ DoAttachToProcessWithID(lldb::pid_t pid);
+
+ virtual lldb_private::Error
+ DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info);
+
+ virtual lldb_private::Error
+ DoLaunch (lldb_private::Module *exe_module,
+ const lldb_private::ProcessLaunchInfo &launch_info);
+
+ virtual void
+ DidLaunch();
+
+ virtual lldb_private::Error
+ DoResume();
+
+ virtual lldb_private::Error
+ DoHalt(bool &caused_stop);
+
+ virtual lldb_private::Error
+ DoDetach(bool keep_stopped);
+
+ virtual lldb_private::Error
+ DoSignal(int signal);
+
+ virtual lldb_private::Error
+ DoDestroy();
+
+ virtual void
+ RefreshStateAfterStop();
+
+ virtual bool
+ IsAlive();
+
+ virtual size_t
+ DoReadMemory(lldb::addr_t vm_addr,
+ void *buf,
+ size_t size,
+ lldb_private::Error &error);
+
+ virtual size_t
+ DoWriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+ lldb_private::Error &error);
+
+ virtual lldb::addr_t
+ DoAllocateMemory(size_t size, uint32_t permissions,
+ lldb_private::Error &error);
+
+ virtual lldb_private::Error
+ DoDeallocateMemory(lldb::addr_t ptr);
+
+ virtual lldb::addr_t
+ ResolveIndirectFunction(const lldb_private::Address *address, lldb_private::Error &error);
+
+ virtual size_t
+ GetSoftwareBreakpointTrapOpcode(lldb_private::BreakpointSite* bp_site);
+
+ virtual lldb_private::Error
+ EnableBreakpointSite(lldb_private::BreakpointSite *bp_site);
+
+ virtual lldb_private::Error
+ DisableBreakpointSite(lldb_private::BreakpointSite *bp_site);
+
+ virtual lldb_private::Error
+ EnableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true);
+
+ virtual lldb_private::Error
+ DisableWatchpoint(lldb_private::Watchpoint *wp, bool notify = true);
+
+ virtual lldb_private::Error
+ GetWatchpointSupportInfo(uint32_t &num);
+
+ virtual lldb_private::Error
+ GetWatchpointSupportInfo(uint32_t &num, bool &after);
+
+ virtual uint32_t
+ UpdateThreadListIfNeeded();
+
+ virtual bool
+ UpdateThreadList(lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list) = 0;
+
+ virtual lldb::ByteOrder
+ GetByteOrder() const;
+
+ virtual lldb::addr_t
+ GetImageInfoAddress();
+
+ virtual size_t
+ PutSTDIN(const char *buf, size_t len, lldb_private::Error &error);
+
+ //--------------------------------------------------------------------------
+ // ProcessPOSIX internal API.
+
+ /// Registers the given message with this process.
+ void SendMessage(const ProcessMessage &message);
+
+ ProcessMonitor &
+ GetMonitor() { assert(m_monitor); return *m_monitor; }
+
+ lldb_private::UnixSignals &
+ GetUnixSignals();
+
+ const char *
+ GetFilePath(const lldb_private::ProcessLaunchInfo::FileAction *file_action,
+ const char *default_path);
+
+ /// Stops all threads in the process.
+ /// The \p stop_tid parameter indicates the thread which initiated the stop.
+ virtual void
+ StopAllThreads(lldb::tid_t stop_tid);
+
+ /// Adds the thread to the list of threads for which we have received the initial stopping signal.
+ /// The \p stop_tid paramter indicates the thread which the stop happened for.
+ bool
+ AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid);
+
+ virtual POSIXThread *
+ CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid);
+
+protected:
+ /// Target byte order.
+ lldb::ByteOrder m_byte_order;
+
+ /// Process monitor;
+ ProcessMonitor *m_monitor;
+
+ /// The module we are executing.
+ lldb_private::Module *m_module;
+
+ /// Message queue notifying this instance of inferior process state changes.
+ lldb_private::Mutex m_message_mutex;
+ std::queue<ProcessMessage> m_message_queue;
+
+ /// Drive any exit events to completion.
+ bool m_exit_now;
+
+ /// OS-specific signal set.
+ lldb_private::UnixSignals m_signals;
+
+ /// Returns true if the process has exited.
+ bool HasExited();
+
+ /// Returns true if the process is stopped.
+ bool IsStopped();
+
+ /// Returns true if at least one running is currently running
+ bool IsAThreadRunning();
+
+ typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap;
+ MMapMap m_addr_to_mmap_size;
+
+ typedef std::set<lldb::tid_t> ThreadStopSet;
+ /// Every thread begins with a stop signal. This keeps track
+ /// of the threads for which we have received the stop signal.
+ ThreadStopSet m_seen_initial_stop;
+};
+
+#endif // liblldb_MacOSXProcess_H_
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp b/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp
new file mode 100644
index 000000000000..624ca87b883a
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessPOSIXLog.cpp
@@ -0,0 +1,193 @@
+//===-- ProcessPOSIXLog.cpp ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessPOSIXLog.h"
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/StreamFile.h"
+
+#include "ProcessPOSIX.h"
+#include "ProcessPOSIXLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+// We want to avoid global constructors where code needs to be run so here we
+// control access to our static g_log_sp by hiding it in a singleton function
+// that will construct the static g_log_sp the first time this function is
+// called.
+static bool g_log_enabled = false;
+static Log * g_log = NULL;
+static Log *
+GetLog ()
+{
+ if (!g_log_enabled)
+ return NULL;
+ return g_log;
+}
+
+
+Log *
+ProcessPOSIXLog::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log(GetLog ());
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().Get();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+static uint32_t
+GetFlagBits (const char *arg)
+{
+ if (::strcasecmp (arg, "all") == 0 ) return POSIX_LOG_ALL;
+ else if (::strcasecmp (arg, "async") == 0 ) return POSIX_LOG_ASYNC;
+ else if (::strncasecmp (arg, "break", 5) == 0 ) return POSIX_LOG_BREAKPOINTS;
+ else if (::strncasecmp (arg, "comm", 4) == 0 ) return POSIX_LOG_COMM;
+ else if (::strcasecmp (arg, "default") == 0 ) return POSIX_LOG_DEFAULT;
+ else if (::strcasecmp (arg, "packets") == 0 ) return POSIX_LOG_PACKETS;
+ else if (::strcasecmp (arg, "memory") == 0 ) return POSIX_LOG_MEMORY;
+ else if (::strcasecmp (arg, "data-short") == 0 ) return POSIX_LOG_MEMORY_DATA_SHORT;
+ else if (::strcasecmp (arg, "data-long") == 0 ) return POSIX_LOG_MEMORY_DATA_LONG;
+ else if (::strcasecmp (arg, "process") == 0 ) return POSIX_LOG_PROCESS;
+ else if (::strcasecmp (arg, "ptrace") == 0 ) return POSIX_LOG_PTRACE;
+ else if (::strcasecmp (arg, "registers") == 0 ) return POSIX_LOG_REGISTERS;
+ else if (::strcasecmp (arg, "step") == 0 ) return POSIX_LOG_STEP;
+ else if (::strcasecmp (arg, "thread") == 0 ) return POSIX_LOG_THREAD;
+ else if (::strcasecmp (arg, "verbose") == 0 ) return POSIX_LOG_VERBOSE;
+ else if (::strncasecmp (arg, "watch", 5) == 0 ) return POSIX_LOG_WATCHPOINTS;
+ return 0;
+}
+
+void
+ProcessPOSIXLog::DisableLog (const char **args, Stream *feedback_strm)
+{
+ Log *log (GetLog ());
+ if (log)
+ {
+ uint32_t flag_bits = 0;
+
+ flag_bits = log->GetMask().Get();
+ for (; args[0]; args++)
+ {
+ const char *arg = args[0];
+ uint32_t bits = GetFlagBits(arg);
+
+ if (bits)
+ {
+ flag_bits &= ~bits;
+ }
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ ListLogCategories (feedback_strm);
+ }
+ }
+
+ log->GetMask().Reset (flag_bits);
+ if (flag_bits == 0)
+ g_log_enabled = false;
+ }
+
+ return;
+}
+
+Log *
+ProcessPOSIXLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const char **args, Stream *feedback_strm)
+{
+ // Try see if there already is a log - that way we can reuse its settings.
+ // We could reuse the log in toto, but we don't know that the stream is the same.
+ uint32_t flag_bits = 0;
+ if (g_log)
+ flag_bits = g_log->GetMask().Get();
+
+ // Now make a new log with this stream if one was provided
+ if (log_stream_sp)
+ {
+ if (g_log)
+ g_log->SetStream(log_stream_sp);
+ else
+ g_log = new Log(log_stream_sp);
+ }
+
+ if (g_log)
+ {
+ bool got_unknown_category = false;
+ for (; args[0]; args++)
+ {
+ const char *arg = args[0];
+ uint32_t bits = GetFlagBits(arg);
+
+ if (bits)
+ {
+ flag_bits |= bits;
+ }
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ if (got_unknown_category == false)
+ {
+ got_unknown_category = true;
+ ListLogCategories (feedback_strm);
+ }
+ }
+ }
+ if (flag_bits == 0)
+ flag_bits = POSIX_LOG_DEFAULT;
+ g_log->GetMask().Reset(flag_bits);
+ g_log->GetOptions().Reset(log_options);
+ g_log_enabled = true;
+ }
+ return g_log;
+}
+
+void
+ProcessPOSIXLog::ListLogCategories (Stream *strm)
+{
+ strm->Printf ("Logging categories for '%s':\n"
+ " all - turn on all available logging categories\n"
+ " async - log asynchronous activity\n"
+ " break - log breakpoints\n"
+ " communication - log communication activity\n"
+ " default - enable the default set of logging categories for liblldb\n"
+ " packets - log gdb remote packets\n"
+ " memory - log memory reads and writes\n"
+ " data-short - log memory bytes for memory reads and writes for short transactions only\n"
+ " data-long - log memory bytes for memory reads and writes for all transactions\n"
+ " process - log process events and activities\n"
+#ifndef LLDB_CONFIGURATION_BUILDANDINTEGRATION
+ " ptrace - log all calls to ptrace\n"
+#endif
+ " registers - log register read/writes\n"
+ " thread - log thread events and activities\n"
+ " step - log step related activities\n"
+ " verbose - enable verbose logging\n"
+ " watch - log watchpoint related activities\n", ProcessPOSIXLog::m_pluginname);
+}
+
+
+void
+ProcessPOSIXLog::LogIf (uint32_t mask, const char *format, ...)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (mask));
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
+
+int ProcessPOSIXLog::m_nestinglevel;
+const char *ProcessPOSIXLog::m_pluginname = "";
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIXLog.h b/source/Plugins/Process/POSIX/ProcessPOSIXLog.h
new file mode 100644
index 000000000000..a1e2e3747d21
--- /dev/null
+++ b/source/Plugins/Process/POSIX/ProcessPOSIXLog.h
@@ -0,0 +1,111 @@
+//===-- ProcessPOSIXLog.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessPOSIXLog_h_
+#define liblldb_ProcessPOSIXLog_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/Core/Log.h"
+
+#define POSIX_LOG_VERBOSE (1u << 0)
+#define POSIX_LOG_PROCESS (1u << 1)
+#define POSIX_LOG_THREAD (1u << 2)
+#define POSIX_LOG_PACKETS (1u << 3)
+#define POSIX_LOG_MEMORY (1u << 4) // Log memory reads/writes calls
+#define POSIX_LOG_MEMORY_DATA_SHORT (1u << 5) // Log short memory reads/writes bytes
+#define POSIX_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes
+#define POSIX_LOG_BREAKPOINTS (1u << 7)
+#define POSIX_LOG_WATCHPOINTS (1u << 8)
+#define POSIX_LOG_STEP (1u << 9)
+#define POSIX_LOG_COMM (1u << 10)
+#define POSIX_LOG_ASYNC (1u << 11)
+#define POSIX_LOG_PTRACE (1u << 12)
+#define POSIX_LOG_REGISTERS (1u << 13)
+#define POSIX_LOG_ALL (UINT32_MAX)
+#define POSIX_LOG_DEFAULT POSIX_LOG_PACKETS
+
+// The size which determines "short memory reads/writes".
+#define POSIX_LOG_MEMORY_SHORT_BYTES (4 * sizeof(ptrdiff_t))
+
+class ProcessPOSIXLog
+{
+ static int m_nestinglevel;
+ static const char *m_pluginname;
+
+public:
+ static void
+ RegisterPluginName(const char *pluginName)
+ {
+ m_pluginname = pluginName;
+ }
+
+ static void
+ RegisterPluginName(lldb_private::ConstString pluginName)
+ {
+ m_pluginname = pluginName.GetCString();
+ }
+
+ static lldb_private::Log *
+ GetLogIfAllCategoriesSet(uint32_t mask = 0);
+
+ static void
+ DisableLog (const char **args, lldb_private::Stream *feedback_strm);
+
+ static lldb_private::Log *
+ EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options,
+ const char **args, lldb_private::Stream *feedback_strm);
+
+ static void
+ ListLogCategories (lldb_private::Stream *strm);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+
+ // The following functions can be used to enable the client to limit
+ // logging to only the top level function calls. This is useful for
+ // recursive functions. FIXME: not thread safe!
+ // Example:
+ // void NestingFunc() {
+ // LogSP log (ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_ALL));
+ // if (log)
+ // {
+ // ProcessPOSIXLog::IncNestLevel();
+ // if (ProcessPOSIXLog::AtTopNestLevel())
+ // log->Print(msg);
+ // }
+ // NestingFunc();
+ // if (log)
+ // ProcessPOSIXLog::DecNestLevel();
+ // }
+
+ static bool
+ AtTopNestLevel()
+ {
+ return m_nestinglevel == 1;
+ }
+
+ static void
+ IncNestLevel()
+ {
+ ++m_nestinglevel;
+ }
+
+ static void
+ DecNestLevel()
+ {
+ --m_nestinglevel;
+ assert(m_nestinglevel >= 0);
+ }
+};
+
+#endif // liblldb_ProcessPOSIXLog_h_
diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp
new file mode 100644
index 000000000000..0fb9dc1cb3dc
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.cpp
@@ -0,0 +1,136 @@
+//===-- RegisterContextFreeBSD_x86_64.h ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "RegisterContextFreeBSD_x86_64.h"
+#include <vector>
+
+using namespace lldb_private;
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) \
+ (offsetof(GPR, regname))
+
+// Update the FreeBSD specific information (offset and size).
+#define UPDATE_GPR_INFO(reg) \
+do { \
+ GetRegisterContext()[gpr_##reg].byte_size = sizeof(GPR::reg); \
+ GetRegisterContext()[gpr_##reg].byte_offset = GPR_OFFSET(reg); \
+} while(false);
+
+#define UPDATE_I386_GPR_INFO(i386_reg, reg) \
+do { \
+ GetRegisterContext()[gpr_##i386_reg].byte_offset = GPR_OFFSET(reg); \
+} while(false);
+
+typedef struct _GPR
+{
+ uint64_t r15;
+ uint64_t r14;
+ uint64_t r13;
+ uint64_t r12;
+ uint64_t r11;
+ uint64_t r10;
+ uint64_t r9;
+ uint64_t r8;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rbp;
+ uint64_t rbx;
+ uint64_t rdx;
+ uint64_t rcx;
+ uint64_t rax;
+ uint32_t trapno;
+ uint16_t fs;
+ uint16_t gs;
+ uint32_t err;
+ uint16_t es;
+ uint16_t ds;
+ uint64_t rip;
+ uint64_t cs;
+ uint64_t rflags;
+ uint64_t rsp;
+ uint64_t ss;
+} GPR;
+
+// Use a singleton function to avoid global constructors in shared libraries.
+static std::vector<RegisterInfo> & GetRegisterContext () {
+ static std::vector<RegisterInfo> g_register_infos;
+ return g_register_infos;
+}
+
+
+RegisterContextFreeBSD_x86_64::RegisterContextFreeBSD_x86_64(Thread &thread, uint32_t concrete_frame_idx):
+ RegisterContext_x86_64(thread, concrete_frame_idx)
+{
+}
+
+size_t
+RegisterContextFreeBSD_x86_64::GetGPRSize()
+{
+ return sizeof(GPR);
+}
+
+const RegisterInfo *
+RegisterContextFreeBSD_x86_64::GetRegisterInfo()
+{
+ // Allocate RegisterInfo only once
+ if (GetRegisterContext().empty())
+ {
+ // Copy the register information from base class
+ const RegisterInfo *base_info = RegisterContext_x86_64::GetRegisterInfo();
+ if (base_info)
+ {
+ GetRegisterContext().insert(GetRegisterContext().end(), &base_info[0], &base_info[k_num_registers]);
+ // Update the FreeBSD specific register information (offset and size).
+ UpdateRegisterInfo();
+ }
+ }
+ return &GetRegisterContext()[0];
+}
+
+void
+RegisterContextFreeBSD_x86_64::UpdateRegisterInfo()
+{
+ UPDATE_GPR_INFO(rax);
+ UPDATE_GPR_INFO(rbx);
+ UPDATE_GPR_INFO(rcx);
+ UPDATE_GPR_INFO(rdx);
+ UPDATE_GPR_INFO(rdi);
+ UPDATE_GPR_INFO(rsi);
+ UPDATE_GPR_INFO(rbp);
+ UPDATE_GPR_INFO(rsp);
+ UPDATE_GPR_INFO(r8);
+ UPDATE_GPR_INFO(r9);
+ UPDATE_GPR_INFO(r10);
+ UPDATE_GPR_INFO(r11);
+ UPDATE_GPR_INFO(r12);
+ UPDATE_GPR_INFO(r13);
+ UPDATE_GPR_INFO(r14);
+ UPDATE_GPR_INFO(r15);
+ UPDATE_GPR_INFO(rip);
+ UPDATE_GPR_INFO(rflags);
+ UPDATE_GPR_INFO(cs);
+ UPDATE_GPR_INFO(fs);
+ UPDATE_GPR_INFO(gs);
+ UPDATE_GPR_INFO(ss);
+ UPDATE_GPR_INFO(ds);
+ UPDATE_GPR_INFO(es);
+
+ UPDATE_I386_GPR_INFO(eax, rax);
+ UPDATE_I386_GPR_INFO(ebx, rbx);
+ UPDATE_I386_GPR_INFO(ecx, rcx);
+ UPDATE_I386_GPR_INFO(edx, rdx);
+ UPDATE_I386_GPR_INFO(edi, rdi);
+ UPDATE_I386_GPR_INFO(esi, rsi);
+ UPDATE_I386_GPR_INFO(ebp, rbp);
+ UPDATE_I386_GPR_INFO(esp, rsp);
+ UPDATE_I386_GPR_INFO(eip, rip);
+ UPDATE_I386_GPR_INFO(eflags, rflags);
+}
+
diff --git a/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h
new file mode 100644
index 000000000000..ffff40a9c65b
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h
@@ -0,0 +1,32 @@
+//===-- RegisterContextFreeBSD_x86_64.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextFreeBSD_x86_64_H_
+#define liblldb_RegisterContextFreeBSD_x86_64_H_
+
+#include "Plugins/Process/POSIX/RegisterContext_x86_64.h"
+
+class RegisterContextFreeBSD_x86_64:
+ public RegisterContext_x86_64
+{
+public:
+ RegisterContextFreeBSD_x86_64(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ size_t
+ GetGPRSize();
+
+protected:
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfo();
+
+ virtual void
+ UpdateRegisterInfo();
+};
+
+#endif
diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp b/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp
new file mode 100644
index 000000000000..c1aea2a41a1f
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.cpp
@@ -0,0 +1,180 @@
+//===-- RegisterContextLinux_x86_64.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#include "llvm/Support/Compiler.h"
+#include "RegisterContextLinux_x86_64.h"
+#include <vector>
+
+using namespace lldb_private;
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) \
+ (offsetof(GPR, regname))
+
+// Update the Linux specific information (offset and size).
+#define UPDATE_GPR_INFO(reg) \
+do { \
+ GetRegisterContext()[gpr_##reg].byte_size = sizeof(GPR::reg); \
+ GetRegisterContext()[gpr_##reg].byte_offset = GPR_OFFSET(reg); \
+} while(false);
+
+#define UPDATE_I386_GPR_INFO(i386_reg, reg) \
+do { \
+ GetRegisterContext()[gpr_##i386_reg].byte_offset = GPR_OFFSET(reg); \
+} while(false);
+
+#define DR_OFFSET(reg_index) \
+ (LLVM_EXTENSION offsetof(UserArea, u_debugreg[reg_index]))
+
+#define UPDATE_DR_INFO(reg_index) \
+do { \
+ GetRegisterContext()[dr##reg_index].byte_size = sizeof(UserArea::u_debugreg[0]); \
+ GetRegisterContext()[dr##reg_index].byte_offset = DR_OFFSET(reg_index); \
+} while(false);
+
+typedef struct _GPR
+{
+ uint64_t r15;
+ uint64_t r14;
+ uint64_t r13;
+ uint64_t r12;
+ uint64_t rbp;
+ uint64_t rbx;
+ uint64_t r11;
+ uint64_t r10;
+ uint64_t r9;
+ uint64_t r8;
+ uint64_t rax;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rsi;
+ uint64_t rdi;
+ uint64_t orig_ax;
+ uint64_t rip;
+ uint64_t cs;
+ uint64_t rflags;
+ uint64_t rsp;
+ uint64_t ss;
+ uint64_t fs_base;
+ uint64_t gs_base;
+ uint64_t ds;
+ uint64_t es;
+ uint64_t fs;
+ uint64_t gs;
+} GPR;
+
+typedef RegisterContext_x86_64::FXSAVE FXSAVE;
+
+struct UserArea
+{
+ GPR gpr; // General purpose registers.
+ int32_t fpvalid; // True if FPU is being used.
+ int32_t pad0;
+ FXSAVE i387; // General purpose floating point registers (see FPR for extended register sets).
+ uint64_t tsize; // Text segment size.
+ uint64_t dsize; // Data segment size.
+ uint64_t ssize; // Stack segment size.
+ uint64_t start_code; // VM address of text.
+ uint64_t start_stack; // VM address of stack bottom (top in rsp).
+ int64_t signal; // Signal causing core dump.
+ int32_t reserved; // Unused.
+ int32_t pad1;
+ uint64_t ar0; // Location of GPR's.
+ FXSAVE* fpstate; // Location of FPR's.
+ uint64_t magic; // Identifier for core dumps.
+ char u_comm[32]; // Command causing core dump.
+ uint64_t u_debugreg[8]; // Debug registers (DR0 - DR7).
+ uint64_t error_code; // CPU error code.
+ uint64_t fault_address; // Control register CR3.
+};
+
+// Use a singleton function to avoid global constructors in shared libraries.
+static std::vector<RegisterInfo> & GetRegisterContext () {
+ static std::vector<RegisterInfo> g_register_infos;
+ return g_register_infos;
+}
+
+RegisterContextLinux_x86_64::RegisterContextLinux_x86_64(Thread &thread, uint32_t concrete_frame_idx):
+ RegisterContext_x86_64(thread, concrete_frame_idx)
+{
+}
+
+size_t
+RegisterContextLinux_x86_64::GetGPRSize()
+{
+ return sizeof(GPR);
+}
+
+const RegisterInfo *
+RegisterContextLinux_x86_64::GetRegisterInfo()
+{
+ // Allocate RegisterInfo only once
+ if (GetRegisterContext().empty())
+ {
+ // Copy the register information from base class
+ const RegisterInfo *base_info = RegisterContext_x86_64::GetRegisterInfo();
+ if (base_info)
+ {
+ GetRegisterContext().insert(GetRegisterContext().end(), &base_info[0], &base_info[k_num_registers]);
+ // Update the Linux specific register information (offset and size).
+ UpdateRegisterInfo();
+ }
+ }
+ return &GetRegisterContext()[0];
+}
+
+void
+RegisterContextLinux_x86_64::UpdateRegisterInfo()
+{
+ UPDATE_GPR_INFO(rax);
+ UPDATE_GPR_INFO(rbx);
+ UPDATE_GPR_INFO(rcx);
+ UPDATE_GPR_INFO(rdx);
+ UPDATE_GPR_INFO(rdi);
+ UPDATE_GPR_INFO(rsi);
+ UPDATE_GPR_INFO(rbp);
+ UPDATE_GPR_INFO(rsp);
+ UPDATE_GPR_INFO(r8);
+ UPDATE_GPR_INFO(r9);
+ UPDATE_GPR_INFO(r10);
+ UPDATE_GPR_INFO(r11);
+ UPDATE_GPR_INFO(r12);
+ UPDATE_GPR_INFO(r13);
+ UPDATE_GPR_INFO(r14);
+ UPDATE_GPR_INFO(r15);
+ UPDATE_GPR_INFO(rip);
+ UPDATE_GPR_INFO(rflags);
+ UPDATE_GPR_INFO(cs);
+ UPDATE_GPR_INFO(fs);
+ UPDATE_GPR_INFO(gs);
+ UPDATE_GPR_INFO(ss);
+ UPDATE_GPR_INFO(ds);
+ UPDATE_GPR_INFO(es);
+
+ UPDATE_I386_GPR_INFO(eax, rax);
+ UPDATE_I386_GPR_INFO(ebx, rbx);
+ UPDATE_I386_GPR_INFO(ecx, rcx);
+ UPDATE_I386_GPR_INFO(edx, rdx);
+ UPDATE_I386_GPR_INFO(edi, rdi);
+ UPDATE_I386_GPR_INFO(esi, rsi);
+ UPDATE_I386_GPR_INFO(ebp, rbp);
+ UPDATE_I386_GPR_INFO(esp, rsp);
+ UPDATE_I386_GPR_INFO(eip, rip);
+ UPDATE_I386_GPR_INFO(eflags, rflags);
+
+ UPDATE_DR_INFO(0);
+ UPDATE_DR_INFO(1);
+ UPDATE_DR_INFO(2);
+ UPDATE_DR_INFO(3);
+ UPDATE_DR_INFO(4);
+ UPDATE_DR_INFO(5);
+ UPDATE_DR_INFO(6);
+ UPDATE_DR_INFO(7);
+}
+
diff --git a/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h b/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h
new file mode 100644
index 000000000000..1509ef55b8dc
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextLinux_x86_64.h
@@ -0,0 +1,32 @@
+//===-- RegisterContextLinux_x86_64.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextLinux_x86_64_H_
+#define liblldb_RegisterContextLinux_x86_64_H_
+
+#include "Plugins/Process/POSIX/RegisterContext_x86_64.h"
+
+class RegisterContextLinux_x86_64:
+ public RegisterContext_x86_64
+{
+public:
+ RegisterContextLinux_x86_64(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ size_t
+ GetGPRSize();
+
+protected:
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfo();
+
+ virtual void
+ UpdateRegisterInfo();
+};
+
+#endif
diff --git a/source/Plugins/Process/POSIX/RegisterContextPOSIX.h b/source/Plugins/Process/POSIX/RegisterContextPOSIX.h
new file mode 100644
index 000000000000..63ae01e83a90
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContextPOSIX.h
@@ -0,0 +1,70 @@
+//===-- RegisterContextPOSIX.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextPOSIX_H_
+#define liblldb_RegisterContextPOSIX_H_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Target/RegisterContext.h"
+
+//------------------------------------------------------------------------------
+/// @class RegisterContextPOSIX
+///
+/// @brief Extends RegisterClass with a few virtual operations useful on POSIX.
+class RegisterContextPOSIX
+ : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextPOSIX(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx)
+ : RegisterContext(thread, concrete_frame_idx)
+ { m_watchpoints_initialized = false; }
+
+ /// Updates the register state of the associated thread after hitting a
+ /// breakpoint (if that make sense for the architecture). Default
+ /// implementation simply returns true for architectures which do not
+ /// require any update.
+ ///
+ /// @return
+ /// True if the operation succeeded and false otherwise.
+ virtual bool UpdateAfterBreakpoint() { return true; }
+
+ /// Determines the index in lldb's register file given a kernel byte offset.
+ virtual unsigned
+ GetRegisterIndexFromOffset(unsigned offset) { return LLDB_INVALID_REGNUM; }
+
+ // Checks to see if a watchpoint specified by hw_index caused the inferior
+ // to stop.
+ virtual bool
+ IsWatchpointHit (uint32_t hw_index) { return false; }
+
+ // Resets any watchpoints that have been hit.
+ virtual bool
+ ClearWatchpointHits () { return false; }
+
+ // Returns the watchpoint address associated with a watchpoint hardware
+ // index.
+ virtual lldb::addr_t
+ GetWatchpointAddress (uint32_t hw_index) { return LLDB_INVALID_ADDRESS; }
+
+ virtual bool
+ IsWatchpointVacant (uint32_t hw_index) { return false; }
+
+ virtual bool
+ SetHardwareWatchpointWithIndex (lldb::addr_t addr, size_t size,
+ bool read, bool write,
+ uint32_t hw_index) { return false; }
+
+protected:
+ bool m_watchpoints_initialized;
+};
+
+#endif // #ifndef liblldb_RegisterContextPOSIX_H_
diff --git a/source/Plugins/Process/POSIX/RegisterContext_i386.cpp b/source/Plugins/Process/POSIX/RegisterContext_i386.cpp
new file mode 100644
index 000000000000..49676bd3fc73
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContext_i386.cpp
@@ -0,0 +1,551 @@
+//===-- RegisterContextPOSIX_i386.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+#include "ProcessPOSIX.h"
+#include "ProcessPOSIXLog.h"
+#include "ProcessMonitor.h"
+#include "RegisterContext_i386.h"
+#include "RegisterContext_x86.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+enum
+{
+ k_first_gpr,
+ gpr_eax = k_first_gpr,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_ss,
+ gpr_eflags,
+#ifdef __FreeBSD__
+ gpr_orig_ax,
+#endif
+ gpr_eip,
+ gpr_cs,
+ gpr_ds,
+ gpr_es,
+ gpr_fs,
+ gpr_gs,
+ k_last_gpr = gpr_gs,
+
+ k_first_fpr,
+ fpu_fcw = k_first_fpr,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_foo,
+ fpu_fos,
+ fpu_mxcsr,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ k_last_fpr = fpu_xmm7,
+
+ k_num_registers,
+ k_num_gpr_registers = k_last_gpr - k_first_gpr + 1,
+ k_num_fpu_registers = k_last_fpr - k_first_fpr + 1
+};
+
+// Number of register sets provided by this context.
+enum
+{
+ k_num_register_sets = 2
+};
+
+static const
+uint32_t g_gpr_regnums[k_num_gpr_registers] =
+{
+ gpr_eax,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_ss,
+ gpr_eflags,
+#ifdef __FreeBSD__
+ gpr_orig_ax,
+#endif
+ gpr_eip,
+ gpr_cs,
+ gpr_ds,
+ gpr_es,
+ gpr_fs,
+ gpr_gs,
+};
+
+static const uint32_t
+g_fpu_regnums[k_num_fpu_registers] =
+{
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_foo,
+ fpu_fos,
+ fpu_mxcsr,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+};
+
+static const RegisterSet
+g_reg_sets[k_num_register_sets] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums }
+};
+
+// Computes the offset of the given GPR in the user data area.
+#define GPR_OFFSET(regname) \
+ (offsetof(RegisterContext_i386::UserArea, regs) + \
+ offsetof(RegisterContext_i386::GPR, regname))
+
+// Computes the offset of the given FPR in the user data area.
+#define FPR_OFFSET(regname) \
+ (offsetof(RegisterContext_i386::UserArea, i387) + \
+ offsetof(RegisterContext_i386::FPU, regname))
+
+// Number of bytes needed to represent a GPR.
+#define GPR_SIZE(reg) sizeof(((RegisterContext_i386::GPR*)NULL)->reg)
+
+// Number of bytes needed to represent a FPR.
+#define FPR_SIZE(reg) sizeof(((RegisterContext_i386::FPU*)NULL)->reg)
+
+// Number of bytes needed to represent the i'th FP register.
+#define FP_SIZE sizeof(((RegisterContext_i386::MMSReg*)NULL)->bytes)
+
+// Number of bytes needed to represent an XMM register.
+#define XMM_SIZE sizeof(RegisterContext_i386::XMMReg)
+
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, GPR_SIZE(reg), GPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg }, NULL, NULL }
+
+#define DEFINE_FPR(reg, kind1, kind2, kind3, kind4) \
+ { #reg, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, fpu_##reg }, NULL, NULL }
+
+#define DEFINE_FP(reg, i) \
+ { #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { dwarf_##reg##i, dwarf_##reg##i, \
+ LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i }, NULL, NULL }
+
+#define DEFINE_XMM(reg, i) \
+ { #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { dwarf_##reg##i, dwarf_##reg##i, \
+ LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i }, NULL, NULL }
+
+static RegisterInfo
+g_register_infos[k_num_registers] =
+{
+ // General purpose registers.
+ DEFINE_GPR(eax, NULL, gcc_eax, dwarf_eax, LLDB_INVALID_REGNUM, gdb_eax),
+ DEFINE_GPR(ebx, NULL, gcc_ebx, dwarf_ebx, LLDB_INVALID_REGNUM, gdb_ebx),
+ DEFINE_GPR(ecx, NULL, gcc_ecx, dwarf_ecx, LLDB_INVALID_REGNUM, gdb_ecx),
+ DEFINE_GPR(edx, NULL, gcc_edx, dwarf_edx, LLDB_INVALID_REGNUM, gdb_edx),
+ DEFINE_GPR(edi, NULL, gcc_edi, dwarf_edi, LLDB_INVALID_REGNUM, gdb_edi),
+ DEFINE_GPR(esi, NULL, gcc_esi, dwarf_esi, LLDB_INVALID_REGNUM, gdb_esi),
+ DEFINE_GPR(ebp, "fp", gcc_ebp, dwarf_ebp, LLDB_INVALID_REGNUM, gdb_ebp),
+ DEFINE_GPR(esp, "sp", gcc_esp, dwarf_esp, LLDB_INVALID_REGNUM, gdb_esp),
+ DEFINE_GPR(ss, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ss),
+ DEFINE_GPR(eflags, "flags", gcc_eflags, dwarf_eflags, LLDB_INVALID_REGNUM, gdb_eflags),
+ DEFINE_GPR(eip, "pc", gcc_eip, dwarf_eip, LLDB_INVALID_REGNUM, gdb_eip),
+ DEFINE_GPR(cs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_cs),
+ DEFINE_GPR(ds, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ds),
+ DEFINE_GPR(es, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_es),
+ DEFINE_GPR(fs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fs),
+ DEFINE_GPR(gs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gs),
+
+ // Floating point registers.
+ DEFINE_FPR(fcw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fcw),
+ DEFINE_FPR(fsw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fsw),
+ DEFINE_FPR(ftw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ftw),
+ DEFINE_FPR(fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fop),
+ DEFINE_FPR(ip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_ip),
+ DEFINE_FPR(cs, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_cs),
+ DEFINE_FPR(foo, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_dp),
+ DEFINE_FPR(fos, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ds),
+ DEFINE_FPR(mxcsr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_mxcsr),
+
+ DEFINE_FP(stmm, 0),
+ DEFINE_FP(stmm, 1),
+ DEFINE_FP(stmm, 2),
+ DEFINE_FP(stmm, 3),
+ DEFINE_FP(stmm, 4),
+ DEFINE_FP(stmm, 5),
+ DEFINE_FP(stmm, 6),
+ DEFINE_FP(stmm, 7),
+
+ // XMM registers
+ DEFINE_XMM(xmm, 0),
+ DEFINE_XMM(xmm, 1),
+ DEFINE_XMM(xmm, 2),
+ DEFINE_XMM(xmm, 3),
+ DEFINE_XMM(xmm, 4),
+ DEFINE_XMM(xmm, 5),
+ DEFINE_XMM(xmm, 6),
+ DEFINE_XMM(xmm, 7),
+
+};
+
+#ifndef NDEBUG
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+#endif
+
+static unsigned GetRegOffset(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register number.");
+ return g_register_infos[reg].byte_offset;
+}
+
+static unsigned GetRegSize(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register number.");
+ return g_register_infos[reg].byte_size;
+}
+
+RegisterContext_i386::RegisterContext_i386(Thread &thread,
+ uint32_t concrete_frame_idx)
+ : RegisterContextPOSIX(thread, concrete_frame_idx)
+{
+}
+
+RegisterContext_i386::~RegisterContext_i386()
+{
+}
+
+ProcessMonitor &
+RegisterContext_i386::GetMonitor()
+{
+ ProcessSP base = CalculateProcess();
+ ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
+ return process->GetMonitor();
+}
+
+void
+RegisterContext_i386::Invalidate()
+{
+}
+
+void
+RegisterContext_i386::InvalidateAllRegisters()
+{
+}
+
+size_t
+RegisterContext_i386::GetRegisterCount()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContext_i386::GetRegisterInfoAtIndex(size_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ else
+ return NULL;
+}
+
+size_t
+RegisterContext_i386::GetRegisterSetCount()
+{
+ return k_num_register_sets;
+}
+
+const RegisterSet *
+RegisterContext_i386::GetRegisterSet(size_t set)
+{
+ if (set < k_num_register_sets)
+ return &g_reg_sets[set];
+ else
+ return NULL;
+}
+
+unsigned
+RegisterContext_i386::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg;
+ for (reg = 0; reg < k_num_registers; reg++)
+ {
+ if (g_register_infos[reg].byte_offset == offset)
+ break;
+ }
+ assert(reg < k_num_registers && "Invalid register offset.");
+ return reg;
+}
+
+const char *
+RegisterContext_i386::GetRegisterName(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register offset.");
+ return g_register_infos[reg].name;
+}
+
+bool
+RegisterContext_i386::ReadRegister(const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadRegisterValue(m_thread.GetID(), GetRegOffset(reg),
+ GetRegisterName(reg), GetRegSize(reg), value);
+}
+
+bool
+RegisterContext_i386::ReadAllRegisterValues(DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool RegisterContext_i386::WriteRegister(const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteRegisterValue(m_thread.GetID(), GetRegOffset(reg),
+ GetRegisterName(reg), value);
+}
+
+bool
+RegisterContext_i386::WriteAllRegisterValues(const DataBufferSP &data)
+{
+ return false;
+}
+
+bool
+RegisterContext_i386::UpdateAfterBreakpoint()
+{
+ // PC points one byte past the int3 responsible for the breakpoint.
+ lldb::addr_t pc;
+
+ if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
+ return false;
+
+ SetPC(pc - 1);
+ return true;
+}
+
+uint32_t
+RegisterContext_i386::ConvertRegisterKindToRegisterNumber(uint32_t kind,
+ uint32_t num)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (num)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_eip;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_esp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_ebp;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_eflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (num)
+ {
+ case dwarf_eax: return gpr_eax;
+ case dwarf_edx: return gpr_edx;
+ case dwarf_ecx: return gpr_ecx;
+ case dwarf_ebx: return gpr_ebx;
+ case dwarf_esi: return gpr_esi;
+ case dwarf_edi: return gpr_edi;
+ case dwarf_ebp: return gpr_ebp;
+ case dwarf_esp: return gpr_esp;
+ case dwarf_eip: return gpr_eip;
+ case dwarf_xmm0: return fpu_xmm0;
+ case dwarf_xmm1: return fpu_xmm1;
+ case dwarf_xmm2: return fpu_xmm2;
+ case dwarf_xmm3: return fpu_xmm3;
+ case dwarf_xmm4: return fpu_xmm4;
+ case dwarf_xmm5: return fpu_xmm5;
+ case dwarf_xmm6: return fpu_xmm6;
+ case dwarf_xmm7: return fpu_xmm7;
+ case dwarf_stmm0: return fpu_stmm0;
+ case dwarf_stmm1: return fpu_stmm1;
+ case dwarf_stmm2: return fpu_stmm2;
+ case dwarf_stmm3: return fpu_stmm3;
+ case dwarf_stmm4: return fpu_stmm4;
+ case dwarf_stmm5: return fpu_stmm5;
+ case dwarf_stmm6: return fpu_stmm6;
+ case dwarf_stmm7: return fpu_stmm7;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGDB)
+ {
+ switch (num)
+ {
+ case gdb_eax : return gpr_eax;
+ case gdb_ebx : return gpr_ebx;
+ case gdb_ecx : return gpr_ecx;
+ case gdb_edx : return gpr_edx;
+ case gdb_esi : return gpr_esi;
+ case gdb_edi : return gpr_edi;
+ case gdb_ebp : return gpr_ebp;
+ case gdb_esp : return gpr_esp;
+ case gdb_eip : return gpr_eip;
+ case gdb_eflags : return gpr_eflags;
+ case gdb_cs : return gpr_cs;
+ case gdb_ss : return gpr_ss;
+ case gdb_ds : return gpr_ds;
+ case gdb_es : return gpr_es;
+ case gdb_fs : return gpr_fs;
+ case gdb_gs : return gpr_gs;
+ case gdb_stmm0 : return fpu_stmm0;
+ case gdb_stmm1 : return fpu_stmm1;
+ case gdb_stmm2 : return fpu_stmm2;
+ case gdb_stmm3 : return fpu_stmm3;
+ case gdb_stmm4 : return fpu_stmm4;
+ case gdb_stmm5 : return fpu_stmm5;
+ case gdb_stmm6 : return fpu_stmm6;
+ case gdb_stmm7 : return fpu_stmm7;
+ case gdb_fcw : return fpu_fcw;
+ case gdb_fsw : return fpu_fsw;
+ case gdb_ftw : return fpu_ftw;
+ case gdb_fpu_cs : return fpu_cs;
+ case gdb_ip : return fpu_ip;
+ case gdb_fpu_ds : return fpu_fos;
+ case gdb_dp : return fpu_foo;
+ case gdb_fop : return fpu_fop;
+ case gdb_xmm0 : return fpu_xmm0;
+ case gdb_xmm1 : return fpu_xmm1;
+ case gdb_xmm2 : return fpu_xmm2;
+ case gdb_xmm3 : return fpu_xmm3;
+ case gdb_xmm4 : return fpu_xmm4;
+ case gdb_xmm5 : return fpu_xmm5;
+ case gdb_xmm6 : return fpu_xmm6;
+ case gdb_xmm7 : return fpu_xmm7;
+ case gdb_mxcsr : return fpu_mxcsr;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return num;
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
+bool
+RegisterContext_i386::HardwareSingleStep(bool enable)
+{
+ enum { TRACE_BIT = 0x100 };
+ uint64_t eflags;
+
+ if ((eflags = ReadRegisterAsUnsigned(gpr_eflags, -1UL)) == -1UL)
+ return false;
+
+ if (enable)
+ {
+ if (eflags & TRACE_BIT)
+ return true;
+
+ eflags |= TRACE_BIT;
+ }
+ else
+ {
+ if (!(eflags & TRACE_BIT))
+ return false;
+
+ eflags &= ~TRACE_BIT;
+ }
+
+ return WriteRegisterFromUnsigned(gpr_eflags, eflags);
+}
+
+void
+RegisterContext_i386::LogGPR(const char *title)
+{
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_REGISTERS));
+ if (log)
+ {
+ if (title)
+ log->Printf ("%s", title);
+ for (uint32_t i=0; i<k_num_gpr_registers; i++)
+ {
+ uint32_t reg = gpr_eax + i;
+ log->Printf("%12s = 0x%8.8" PRIx64, g_register_infos[reg].name, ((uint64_t*)&user.regs)[reg]);
+ }
+ }
+}
+
+bool
+RegisterContext_i386::ReadGPR()
+{
+ bool result;
+
+ ProcessMonitor &monitor = GetMonitor();
+ result = monitor.ReadGPR(m_thread.GetID(), &user.regs, sizeof(user.regs));
+ LogGPR("RegisterContext_i386::ReadGPR()");
+ return result;
+}
+
+bool
+RegisterContext_i386::ReadFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadFPR(m_thread.GetID(), &user.i387, sizeof(user.i387));
+}
diff --git a/source/Plugins/Process/POSIX/RegisterContext_i386.h b/source/Plugins/Process/POSIX/RegisterContext_i386.h
new file mode 100644
index 000000000000..96066c47b815
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContext_i386.h
@@ -0,0 +1,169 @@
+//===-- RegisterContext_i386.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContext_i386_h_
+#define liblldb_RegisterContext_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Log.h"
+#include "RegisterContextPOSIX.h"
+
+class RegisterContext_i386 : public RegisterContextPOSIX
+{
+public:
+ RegisterContext_i386(lldb_private::Thread &thread,
+ uint32_t concreate_frame_idx);
+
+ ~RegisterContext_i386();
+
+ void
+ Invalidate();
+
+ void
+ InvalidateAllRegisters();
+
+ size_t
+ GetRegisterCount();
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex(size_t reg);
+
+ size_t
+ GetRegisterSetCount();
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet(size_t set);
+
+ unsigned
+ GetRegisterIndexFromOffset(unsigned offset);
+
+ const char *
+ GetRegisterName(unsigned reg);
+
+ bool
+ ReadRegisterValue(uint32_t reg, lldb_private::Scalar &value);
+
+ bool
+ ReadRegisterBytes(uint32_t reg, lldb_private::DataExtractor &data);
+
+ virtual bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ bool
+ WriteRegisterValue(uint32_t reg, const lldb_private::Scalar &value);
+
+ bool
+ WriteRegisterBytes(uint32_t reg, lldb_private::DataExtractor &data,
+ uint32_t data_offset = 0);
+
+ virtual bool
+ WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+ bool
+ UpdateAfterBreakpoint();
+
+ struct GPR
+ {
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t esi;
+ uint32_t edi;
+ uint32_t ebp;
+ uint32_t eax;
+ uint32_t ds;
+ uint32_t es;
+ uint32_t fs;
+ uint32_t gs;
+ uint32_t orig_ax;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t eflags;
+ uint32_t esp;
+ uint32_t ss;
+ };
+
+ struct MMSReg
+ {
+ uint8_t bytes[8];
+ };
+
+ struct XMMReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ uint16_t fcw;
+ uint16_t fsw;
+ uint16_t ftw;
+ uint16_t fop;
+ uint32_t ip;
+ uint32_t cs;
+ uint32_t foo;
+ uint32_t fos;
+ uint32_t mxcsr;
+ uint32_t reserved;
+ MMSReg stmm[8];
+ XMMReg xmm[8];
+ uint32_t pad[56];
+ };
+
+ // A user area like this no longer exists on FreeBSD
+ // making this a Linux artifact. Nonetheless, it is safe
+ // leaving it here while the code is being cleaned up and generalized.
+
+ struct UserArea
+ {
+ GPR regs; // General purpose registers.
+ int32_t fpvalid; // True if FPU is being used.
+ FPU i387; // FPU registers.
+ uint32_t tsize; // Text segment size.
+ uint32_t dsize; // Data segment size.
+ uint32_t ssize; // Stack segment size.
+ uint32_t start_code; // VM address of text.
+ uint32_t start_stack; // VM address of stack bottom (top in rsp).
+ int32_t signal; // Signal causing core dump.
+ int32_t reserved; // Unused.
+ uint32_t ar0; // Location of GPR's.
+ FPU* fpstate; // Location of FPR's.
+ uint32_t magic; // Identifier for core dumps.
+ char u_comm[32]; // Command causing core dump.
+ uint32_t u_debugreg[8]; // Debug registers (DR0 - DR7).
+ };
+private:
+ UserArea user;
+
+ ProcessMonitor &GetMonitor();
+
+ void LogGPR(const char *title);
+
+ bool ReadGPR();
+ bool ReadFPR();
+};
+
+#endif // #ifndef liblldb_RegisterContext_i386_h_
diff --git a/source/Plugins/Process/POSIX/RegisterContext_x86.h b/source/Plugins/Process/POSIX/RegisterContext_x86.h
new file mode 100644
index 000000000000..61a25c407758
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContext_x86.h
@@ -0,0 +1,110 @@
+//===-- RegisterContext_x86.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContext_x86_H_
+#define liblldb_RegisterContext_x86_H_
+
+enum
+{
+ gcc_eax = 0,
+ gcc_ecx,
+ gcc_edx,
+ gcc_ebx,
+ gcc_ebp,
+ gcc_esp,
+ gcc_esi,
+ gcc_edi,
+ gcc_eip,
+ gcc_eflags
+};
+
+enum
+{
+ dwarf_eax = 0,
+ dwarf_ecx,
+ dwarf_edx,
+ dwarf_ebx,
+ dwarf_esp,
+ dwarf_ebp,
+ dwarf_esi,
+ dwarf_edi,
+ dwarf_eip,
+ dwarf_eflags,
+ dwarf_stmm0 = 11,
+ dwarf_stmm1,
+ dwarf_stmm2,
+ dwarf_stmm3,
+ dwarf_stmm4,
+ dwarf_stmm5,
+ dwarf_stmm6,
+ dwarf_stmm7,
+ dwarf_xmm0 = 21,
+ dwarf_xmm1,
+ dwarf_xmm2,
+ dwarf_xmm3,
+ dwarf_xmm4,
+ dwarf_xmm5,
+ dwarf_xmm6,
+ dwarf_xmm7
+};
+
+enum
+{
+ gdb_eax = 0,
+ gdb_ecx = 1,
+ gdb_edx = 2,
+ gdb_ebx = 3,
+ gdb_esp = 4,
+ gdb_ebp = 5,
+ gdb_esi = 6,
+ gdb_edi = 7,
+ gdb_eip = 8,
+ gdb_eflags = 9,
+ gdb_cs = 10,
+ gdb_ss = 11,
+ gdb_ds = 12,
+ gdb_es = 13,
+ gdb_fs = 14,
+ gdb_gs = 15,
+ gdb_stmm0 = 16,
+ gdb_stmm1 = 17,
+ gdb_stmm2 = 18,
+ gdb_stmm3 = 19,
+ gdb_stmm4 = 20,
+ gdb_stmm5 = 21,
+ gdb_stmm6 = 22,
+ gdb_stmm7 = 23,
+ gdb_fcw = 24,
+ gdb_fsw = 25,
+ gdb_ftw = 26,
+ gdb_fpu_cs = 27,
+ gdb_ip = 28,
+ gdb_fpu_ds = 29,
+ gdb_dp = 30,
+ gdb_fop = 31,
+ gdb_xmm0 = 32,
+ gdb_xmm1 = 33,
+ gdb_xmm2 = 34,
+ gdb_xmm3 = 35,
+ gdb_xmm4 = 36,
+ gdb_xmm5 = 37,
+ gdb_xmm6 = 38,
+ gdb_xmm7 = 39,
+ gdb_mxcsr = 40,
+ gdb_mm0 = 41,
+ gdb_mm1 = 42,
+ gdb_mm2 = 43,
+ gdb_mm3 = 44,
+ gdb_mm4 = 45,
+ gdb_mm5 = 46,
+ gdb_mm6 = 47,
+ gdb_mm7 = 48
+};
+
+#endif
diff --git a/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp b/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp
new file mode 100644
index 000000000000..617b18484e5a
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContext_x86_64.cpp
@@ -0,0 +1,1563 @@
+//===-- RegisterContext_x86_64.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cstring>
+#include <errno.h>
+#include <stdint.h>
+
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+#include "ProcessPOSIX.h"
+#if defined(__linux__) or defined(__FreeBSD__)
+#include "ProcessMonitor.h"
+#endif
+#include "RegisterContext_i386.h"
+#include "RegisterContext_x86.h"
+#include "RegisterContext_x86_64.h"
+#include "Plugins/Process/elf-core/ProcessElfCore.h"
+
+using namespace lldb_private;
+using namespace lldb;
+
+// Support ptrace extensions even when compiled without required kernel support
+#ifndef NT_X86_XSTATE
+ #define NT_X86_XSTATE 0x202
+#endif
+
+enum
+{
+ gcc_dwarf_gpr_rax = 0,
+ gcc_dwarf_gpr_rdx,
+ gcc_dwarf_gpr_rcx,
+ gcc_dwarf_gpr_rbx,
+ gcc_dwarf_gpr_rsi,
+ gcc_dwarf_gpr_rdi,
+ gcc_dwarf_gpr_rbp,
+ gcc_dwarf_gpr_rsp,
+ gcc_dwarf_gpr_r8,
+ gcc_dwarf_gpr_r9,
+ gcc_dwarf_gpr_r10,
+ gcc_dwarf_gpr_r11,
+ gcc_dwarf_gpr_r12,
+ gcc_dwarf_gpr_r13,
+ gcc_dwarf_gpr_r14,
+ gcc_dwarf_gpr_r15,
+ gcc_dwarf_gpr_rip,
+ gcc_dwarf_fpu_xmm0,
+ gcc_dwarf_fpu_xmm1,
+ gcc_dwarf_fpu_xmm2,
+ gcc_dwarf_fpu_xmm3,
+ gcc_dwarf_fpu_xmm4,
+ gcc_dwarf_fpu_xmm5,
+ gcc_dwarf_fpu_xmm6,
+ gcc_dwarf_fpu_xmm7,
+ gcc_dwarf_fpu_xmm8,
+ gcc_dwarf_fpu_xmm9,
+ gcc_dwarf_fpu_xmm10,
+ gcc_dwarf_fpu_xmm11,
+ gcc_dwarf_fpu_xmm12,
+ gcc_dwarf_fpu_xmm13,
+ gcc_dwarf_fpu_xmm14,
+ gcc_dwarf_fpu_xmm15,
+ gcc_dwarf_fpu_stmm0,
+ gcc_dwarf_fpu_stmm1,
+ gcc_dwarf_fpu_stmm2,
+ gcc_dwarf_fpu_stmm3,
+ gcc_dwarf_fpu_stmm4,
+ gcc_dwarf_fpu_stmm5,
+ gcc_dwarf_fpu_stmm6,
+ gcc_dwarf_fpu_stmm7,
+ gcc_dwarf_fpu_ymm0,
+ gcc_dwarf_fpu_ymm1,
+ gcc_dwarf_fpu_ymm2,
+ gcc_dwarf_fpu_ymm3,
+ gcc_dwarf_fpu_ymm4,
+ gcc_dwarf_fpu_ymm5,
+ gcc_dwarf_fpu_ymm6,
+ gcc_dwarf_fpu_ymm7,
+ gcc_dwarf_fpu_ymm8,
+ gcc_dwarf_fpu_ymm9,
+ gcc_dwarf_fpu_ymm10,
+ gcc_dwarf_fpu_ymm11,
+ gcc_dwarf_fpu_ymm12,
+ gcc_dwarf_fpu_ymm13,
+ gcc_dwarf_fpu_ymm14,
+ gcc_dwarf_fpu_ymm15
+};
+
+enum
+{
+ gdb_gpr_rax = 0,
+ gdb_gpr_rbx = 1,
+ gdb_gpr_rcx = 2,
+ gdb_gpr_rdx = 3,
+ gdb_gpr_rsi = 4,
+ gdb_gpr_rdi = 5,
+ gdb_gpr_rbp = 6,
+ gdb_gpr_rsp = 7,
+ gdb_gpr_r8 = 8,
+ gdb_gpr_r9 = 9,
+ gdb_gpr_r10 = 10,
+ gdb_gpr_r11 = 11,
+ gdb_gpr_r12 = 12,
+ gdb_gpr_r13 = 13,
+ gdb_gpr_r14 = 14,
+ gdb_gpr_r15 = 15,
+ gdb_gpr_rip = 16,
+ gdb_gpr_rflags = 17,
+ gdb_gpr_cs = 18,
+ gdb_gpr_ss = 19,
+ gdb_gpr_ds = 20,
+ gdb_gpr_es = 21,
+ gdb_gpr_fs = 22,
+ gdb_gpr_gs = 23,
+ gdb_fpu_stmm0 = 24,
+ gdb_fpu_stmm1 = 25,
+ gdb_fpu_stmm2 = 26,
+ gdb_fpu_stmm3 = 27,
+ gdb_fpu_stmm4 = 28,
+ gdb_fpu_stmm5 = 29,
+ gdb_fpu_stmm6 = 30,
+ gdb_fpu_stmm7 = 31,
+ gdb_fpu_fcw = 32,
+ gdb_fpu_fsw = 33,
+ gdb_fpu_ftw = 34,
+ gdb_fpu_cs_64 = 35,
+ gdb_fpu_ip = 36,
+ gdb_fpu_ds_64 = 37,
+ gdb_fpu_dp = 38,
+ gdb_fpu_fop = 39,
+ gdb_fpu_xmm0 = 40,
+ gdb_fpu_xmm1 = 41,
+ gdb_fpu_xmm2 = 42,
+ gdb_fpu_xmm3 = 43,
+ gdb_fpu_xmm4 = 44,
+ gdb_fpu_xmm5 = 45,
+ gdb_fpu_xmm6 = 46,
+ gdb_fpu_xmm7 = 47,
+ gdb_fpu_xmm8 = 48,
+ gdb_fpu_xmm9 = 49,
+ gdb_fpu_xmm10 = 50,
+ gdb_fpu_xmm11 = 51,
+ gdb_fpu_xmm12 = 52,
+ gdb_fpu_xmm13 = 53,
+ gdb_fpu_xmm14 = 54,
+ gdb_fpu_xmm15 = 55,
+ gdb_fpu_mxcsr = 56,
+ gdb_fpu_ymm0 = 57,
+ gdb_fpu_ymm1 = 58,
+ gdb_fpu_ymm2 = 59,
+ gdb_fpu_ymm3 = 60,
+ gdb_fpu_ymm4 = 61,
+ gdb_fpu_ymm5 = 62,
+ gdb_fpu_ymm6 = 63,
+ gdb_fpu_ymm7 = 64,
+ gdb_fpu_ymm8 = 65,
+ gdb_fpu_ymm9 = 66,
+ gdb_fpu_ymm10 = 67,
+ gdb_fpu_ymm11 = 68,
+ gdb_fpu_ymm12 = 69,
+ gdb_fpu_ymm13 = 70,
+ gdb_fpu_ymm14 = 71,
+ gdb_fpu_ymm15 = 72
+};
+
+static const
+uint32_t g_gpr_regnums[k_num_gpr_registers] =
+{
+ gpr_rax,
+ gpr_rbx,
+ gpr_rcx,
+ gpr_rdx,
+ gpr_rdi,
+ gpr_rsi,
+ gpr_rbp,
+ gpr_rsp,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_r14,
+ gpr_r15,
+ gpr_rip,
+ gpr_rflags,
+ gpr_cs,
+ gpr_fs,
+ gpr_gs,
+ gpr_ss,
+ gpr_ds,
+ gpr_es,
+ gpr_eax,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_eip,
+ gpr_eflags
+};
+
+static const uint32_t
+g_fpu_regnums[k_num_fpr_registers] =
+{
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ fpu_xmm8,
+ fpu_xmm9,
+ fpu_xmm10,
+ fpu_xmm11,
+ fpu_xmm12,
+ fpu_xmm13,
+ fpu_xmm14,
+ fpu_xmm15
+};
+
+static const uint32_t
+g_avx_regnums[k_num_avx_registers] =
+{
+ fpu_ymm0,
+ fpu_ymm1,
+ fpu_ymm2,
+ fpu_ymm3,
+ fpu_ymm4,
+ fpu_ymm5,
+ fpu_ymm6,
+ fpu_ymm7,
+ fpu_ymm8,
+ fpu_ymm9,
+ fpu_ymm10,
+ fpu_ymm11,
+ fpu_ymm12,
+ fpu_ymm13,
+ fpu_ymm14,
+ fpu_ymm15
+};
+
+// Number of register sets provided by this context.
+enum
+{
+ k_num_extended_register_sets = 1,
+ k_num_register_sets = 3
+};
+
+static const RegisterSet
+g_reg_sets[k_num_register_sets] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums },
+ { "Floating Point Registers", "fpu", k_num_fpr_registers, g_fpu_regnums },
+ { "Advanced Vector Extensions", "avx", k_num_avx_registers, g_avx_regnums }
+};
+
+// Computes the offset of the given FPR in the extended data area.
+#define FPR_OFFSET(regname) \
+ (offsetof(RegisterContext_x86_64::FPR, xstate) + \
+ offsetof(RegisterContext_x86_64::FXSAVE, regname))
+
+// Computes the offset of the YMM register assembled from register halves.
+#define YMM_OFFSET(regname) \
+ (offsetof(RegisterContext_x86_64::YMM, regname))
+
+// Number of bytes needed to represent a i386 GPR
+#define GPR_i386_SIZE(reg) sizeof(((RegisterContext_i386::GPR*)NULL)->reg)
+
+// Number of bytes needed to represent a FPR.
+#define FPR_SIZE(reg) sizeof(((RegisterContext_x86_64::FXSAVE*)NULL)->reg)
+
+// Number of bytes needed to represent the i'th FP register.
+#define FP_SIZE sizeof(((RegisterContext_x86_64::MMSReg*)NULL)->bytes)
+
+// Number of bytes needed to represent an XMM register.
+#define XMM_SIZE sizeof(RegisterContext_x86_64::XMMReg)
+
+// Number of bytes needed to represent a YMM register.
+#define YMM_SIZE sizeof(RegisterContext_x86_64::YMMReg)
+
+// Note that the size and offset will be updated by platform-specific classes.
+#define DEFINE_GPR(reg, alt, kind1, kind2, kind3, kind4) \
+ { #reg, alt, 0, 0, eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg }, NULL, NULL }
+
+// Dummy data for RegisterInfo::value_regs as expected by DumpRegisterSet.
+static uint32_t value_regs = LLDB_INVALID_REGNUM;
+
+#define DEFINE_GPR_i386(reg_i386, reg_x86_64, alt, kind1, kind2, kind3, kind4) \
+ { #reg_i386, alt, GPR_i386_SIZE(reg_i386), 0, eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, gpr_##reg_i386 }, &value_regs, NULL }
+
+#define DEFINE_FPR(reg, kind1, kind2, kind3, kind4) \
+ { #reg, NULL, FPR_SIZE(reg), FPR_OFFSET(reg), eEncodingUint, \
+ eFormatHex, { kind1, kind2, kind3, kind4, fpu_##reg }, NULL, NULL }
+
+#define DEFINE_FP(reg, i) \
+ { #reg#i, NULL, FP_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \
+ LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL }
+
+#define DEFINE_XMM(reg, i) \
+ { #reg#i, NULL, XMM_SIZE, LLVM_EXTENSION FPR_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \
+ LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL }
+
+#define DEFINE_YMM(reg, i) \
+ { #reg#i, NULL, YMM_SIZE, LLVM_EXTENSION YMM_OFFSET(reg[i]), \
+ eEncodingVector, eFormatVectorOfUInt8, \
+ { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, \
+ LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL }
+
+#define DEFINE_DR(reg, i) \
+ { #reg#i, NULL, 0, 0, eEncodingUint, eFormatHex, \
+ { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, \
+ LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, NULL, NULL }
+
+#define REG_CONTEXT_SIZE (GetGPRSize() + sizeof(RegisterContext_x86_64::FPR))
+
+static RegisterInfo
+g_register_infos[k_num_registers] =
+{
+ // General purpose registers.
+ DEFINE_GPR(rax, NULL, gcc_dwarf_gpr_rax, gcc_dwarf_gpr_rax, LLDB_INVALID_REGNUM, gdb_gpr_rax),
+ DEFINE_GPR(rbx, NULL, gcc_dwarf_gpr_rbx, gcc_dwarf_gpr_rbx, LLDB_INVALID_REGNUM, gdb_gpr_rbx),
+ DEFINE_GPR(rcx, NULL, gcc_dwarf_gpr_rcx, gcc_dwarf_gpr_rcx, LLDB_INVALID_REGNUM, gdb_gpr_rcx),
+ DEFINE_GPR(rdx, NULL, gcc_dwarf_gpr_rdx, gcc_dwarf_gpr_rdx, LLDB_INVALID_REGNUM, gdb_gpr_rdx),
+ DEFINE_GPR(rdi, NULL, gcc_dwarf_gpr_rdi, gcc_dwarf_gpr_rdi, LLDB_INVALID_REGNUM, gdb_gpr_rdi),
+ DEFINE_GPR(rsi, NULL, gcc_dwarf_gpr_rsi, gcc_dwarf_gpr_rsi, LLDB_INVALID_REGNUM, gdb_gpr_rsi),
+ DEFINE_GPR(rbp, "fp", gcc_dwarf_gpr_rbp, gcc_dwarf_gpr_rbp, LLDB_REGNUM_GENERIC_FP, gdb_gpr_rbp),
+ DEFINE_GPR(rsp, "sp", gcc_dwarf_gpr_rsp, gcc_dwarf_gpr_rsp, LLDB_REGNUM_GENERIC_SP, gdb_gpr_rsp),
+ DEFINE_GPR(r8, NULL, gcc_dwarf_gpr_r8, gcc_dwarf_gpr_r8, LLDB_INVALID_REGNUM, gdb_gpr_r8),
+ DEFINE_GPR(r9, NULL, gcc_dwarf_gpr_r9, gcc_dwarf_gpr_r9, LLDB_INVALID_REGNUM, gdb_gpr_r9),
+ DEFINE_GPR(r10, NULL, gcc_dwarf_gpr_r10, gcc_dwarf_gpr_r10, LLDB_INVALID_REGNUM, gdb_gpr_r10),
+ DEFINE_GPR(r11, NULL, gcc_dwarf_gpr_r11, gcc_dwarf_gpr_r11, LLDB_INVALID_REGNUM, gdb_gpr_r11),
+ DEFINE_GPR(r12, NULL, gcc_dwarf_gpr_r12, gcc_dwarf_gpr_r12, LLDB_INVALID_REGNUM, gdb_gpr_r12),
+ DEFINE_GPR(r13, NULL, gcc_dwarf_gpr_r13, gcc_dwarf_gpr_r13, LLDB_INVALID_REGNUM, gdb_gpr_r13),
+ DEFINE_GPR(r14, NULL, gcc_dwarf_gpr_r14, gcc_dwarf_gpr_r14, LLDB_INVALID_REGNUM, gdb_gpr_r14),
+ DEFINE_GPR(r15, NULL, gcc_dwarf_gpr_r15, gcc_dwarf_gpr_r15, LLDB_INVALID_REGNUM, gdb_gpr_r15),
+ DEFINE_GPR(rip, "pc", gcc_dwarf_gpr_rip, gcc_dwarf_gpr_rip, LLDB_REGNUM_GENERIC_PC, gdb_gpr_rip),
+ DEFINE_GPR(rflags, "flags", LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS, gdb_gpr_rflags),
+ DEFINE_GPR(cs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_cs),
+ DEFINE_GPR(fs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_fs),
+ DEFINE_GPR(gs, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_gs),
+ DEFINE_GPR(ss, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_ss),
+ DEFINE_GPR(ds, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_ds),
+ DEFINE_GPR(es, NULL, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_gpr_es),
+ // i386 registers
+ DEFINE_GPR_i386(eax, rax, NULL, gcc_eax, dwarf_eax, LLDB_INVALID_REGNUM, gdb_eax),
+ DEFINE_GPR_i386(ebx, rbx, NULL, gcc_ebx, dwarf_ebx, LLDB_INVALID_REGNUM, gdb_ebx),
+ DEFINE_GPR_i386(ecx, rcx, NULL, gcc_ecx, dwarf_ecx, LLDB_INVALID_REGNUM, gdb_ecx),
+ DEFINE_GPR_i386(edx, rdx, NULL, gcc_edx, dwarf_edx, LLDB_INVALID_REGNUM, gdb_edx),
+ DEFINE_GPR_i386(edi, rdi, NULL, gcc_edi, dwarf_edi, LLDB_INVALID_REGNUM, gdb_edi),
+ DEFINE_GPR_i386(esi, rsi, NULL, gcc_esi, dwarf_esi, LLDB_INVALID_REGNUM, gdb_esi),
+ DEFINE_GPR_i386(ebp, rbp, "fp", gcc_ebp, dwarf_ebp, LLDB_REGNUM_GENERIC_FP, gdb_ebp),
+ DEFINE_GPR_i386(esp, rsp, "sp", gcc_esp, dwarf_esp, LLDB_REGNUM_GENERIC_SP, gdb_esp),
+ DEFINE_GPR_i386(eip, rip, "pc", gcc_eip, dwarf_eip, LLDB_REGNUM_GENERIC_PC, gdb_eip),
+ DEFINE_GPR_i386(eflags, rflags, "flags", gcc_eflags, dwarf_eflags, LLDB_REGNUM_GENERIC_FLAGS, gdb_eflags),
+ // i387 Floating point registers.
+ DEFINE_FPR(fcw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_fcw),
+ DEFINE_FPR(fsw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_fsw),
+ DEFINE_FPR(ftw, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ftw),
+ DEFINE_FPR(fop, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_fop),
+ DEFINE_FPR(ip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ip),
+ // FIXME: Extract segment from ip.
+ DEFINE_FPR(ip, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_cs_64),
+ DEFINE_FPR(dp, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_dp),
+ // FIXME: Extract segment from dp.
+ DEFINE_FPR(dp, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_ds_64),
+ DEFINE_FPR(mxcsr, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, gdb_fpu_mxcsr),
+ DEFINE_FPR(mxcsrmask, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM),
+
+ // FP registers.
+ DEFINE_FP(stmm, 0),
+ DEFINE_FP(stmm, 1),
+ DEFINE_FP(stmm, 2),
+ DEFINE_FP(stmm, 3),
+ DEFINE_FP(stmm, 4),
+ DEFINE_FP(stmm, 5),
+ DEFINE_FP(stmm, 6),
+ DEFINE_FP(stmm, 7),
+
+ // XMM registers
+ DEFINE_XMM(xmm, 0),
+ DEFINE_XMM(xmm, 1),
+ DEFINE_XMM(xmm, 2),
+ DEFINE_XMM(xmm, 3),
+ DEFINE_XMM(xmm, 4),
+ DEFINE_XMM(xmm, 5),
+ DEFINE_XMM(xmm, 6),
+ DEFINE_XMM(xmm, 7),
+ DEFINE_XMM(xmm, 8),
+ DEFINE_XMM(xmm, 9),
+ DEFINE_XMM(xmm, 10),
+ DEFINE_XMM(xmm, 11),
+ DEFINE_XMM(xmm, 12),
+ DEFINE_XMM(xmm, 13),
+ DEFINE_XMM(xmm, 14),
+ DEFINE_XMM(xmm, 15),
+
+ // Copy of YMM registers assembled from xmm and ymmh
+ DEFINE_YMM(ymm, 0),
+ DEFINE_YMM(ymm, 1),
+ DEFINE_YMM(ymm, 2),
+ DEFINE_YMM(ymm, 3),
+ DEFINE_YMM(ymm, 4),
+ DEFINE_YMM(ymm, 5),
+ DEFINE_YMM(ymm, 6),
+ DEFINE_YMM(ymm, 7),
+ DEFINE_YMM(ymm, 8),
+ DEFINE_YMM(ymm, 9),
+ DEFINE_YMM(ymm, 10),
+ DEFINE_YMM(ymm, 11),
+ DEFINE_YMM(ymm, 12),
+ DEFINE_YMM(ymm, 13),
+ DEFINE_YMM(ymm, 14),
+ DEFINE_YMM(ymm, 15),
+
+ // Debug registers for lldb internal use
+ DEFINE_DR(dr, 0),
+ DEFINE_DR(dr, 1),
+ DEFINE_DR(dr, 2),
+ DEFINE_DR(dr, 3),
+ DEFINE_DR(dr, 4),
+ DEFINE_DR(dr, 5),
+ DEFINE_DR(dr, 6),
+ DEFINE_DR(dr, 7)
+};
+
+static bool IsGPR(unsigned reg)
+{
+ return reg <= k_last_gpr; // GPR's come first.
+}
+
+static bool IsAVX(unsigned reg)
+{
+ return (k_first_avx <= reg && reg <= k_last_avx);
+}
+static bool IsFPR(unsigned reg)
+{
+ return (k_first_fpr <= reg && reg <= k_last_fpr);
+}
+
+
+bool RegisterContext_x86_64::IsFPR(unsigned reg, FPRType fpr_type)
+{
+ bool generic_fpr = ::IsFPR(reg);
+ if (fpr_type == eXSAVE)
+ return generic_fpr || IsAVX(reg);
+
+ return generic_fpr;
+}
+
+RegisterContext_x86_64::RegisterContext_x86_64(Thread &thread,
+ uint32_t concrete_frame_idx)
+ : RegisterContextPOSIX(thread, concrete_frame_idx)
+{
+ // Initialize m_iovec to point to the buffer and buffer size
+ // using the conventions of Berkeley style UIO structures, as required
+ // by PTRACE extensions.
+ m_iovec.iov_base = &m_fpr.xstate.xsave;
+ m_iovec.iov_len = sizeof(m_fpr.xstate.xsave);
+
+ ::memset(&m_fpr, 0, sizeof(RegisterContext_x86_64::FPR));
+
+ // elf-core yet to support ReadFPR()
+ ProcessSP base = CalculateProcess();
+ if (base.get()->GetPluginName() == ProcessElfCore::GetPluginNameStatic())
+ return;
+
+ // TODO: Use assembly to call cpuid on the inferior and query ebx or ecx
+ m_fpr_type = eXSAVE; // extended floating-point registers, if available
+ if (false == ReadFPR())
+ m_fpr_type = eFXSAVE; // assume generic floating-point registers
+}
+
+RegisterContext_x86_64::~RegisterContext_x86_64()
+{
+}
+
+void
+RegisterContext_x86_64::Invalidate()
+{
+}
+
+void
+RegisterContext_x86_64::InvalidateAllRegisters()
+{
+}
+
+unsigned
+RegisterContext_x86_64::GetRegisterOffset(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_offset;
+}
+
+unsigned
+RegisterContext_x86_64::GetRegisterSize(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register number.");
+ return GetRegisterInfo()[reg].byte_size;
+}
+
+size_t
+RegisterContext_x86_64::GetRegisterCount()
+{
+ size_t num_registers = k_num_gpr_registers + k_num_fpr_registers;
+ if (m_fpr_type == eXSAVE)
+ return num_registers + k_num_avx_registers;
+ return num_registers;
+}
+
+const RegisterInfo *
+RegisterContext_x86_64::GetRegisterInfo()
+{
+ // Commonly, this method is overridden and g_register_infos is copied and specialized.
+ // So, use GetRegisterInfo() rather than g_register_infos in this scope.
+ return g_register_infos;
+}
+
+const RegisterInfo *
+RegisterContext_x86_64::GetRegisterInfoAtIndex(size_t reg)
+{
+ if (reg < k_num_registers)
+ return &GetRegisterInfo()[reg];
+ else
+ return NULL;
+}
+
+size_t
+RegisterContext_x86_64::GetRegisterSetCount()
+{
+ size_t sets = 0;
+ for (size_t set = 0; set < k_num_register_sets; ++set)
+ if (IsRegisterSetAvailable(set))
+ ++sets;
+
+ return sets;
+}
+
+const RegisterSet *
+RegisterContext_x86_64::GetRegisterSet(size_t set)
+{
+ if (IsRegisterSetAvailable(set))
+ return &g_reg_sets[set];
+ else
+ return NULL;
+}
+
+unsigned
+RegisterContext_x86_64::GetRegisterIndexFromOffset(unsigned offset)
+{
+ unsigned reg;
+ for (reg = 0; reg < k_num_registers; reg++)
+ {
+ if (GetRegisterInfo()[reg].byte_offset == offset)
+ break;
+ }
+ assert(reg < k_num_registers && "Invalid register offset.");
+ return reg;
+}
+
+const char *
+RegisterContext_x86_64::GetRegisterName(unsigned reg)
+{
+ assert(reg < k_num_registers && "Invalid register offset.");
+ return GetRegisterInfo()[reg].name;
+}
+
+lldb::ByteOrder
+RegisterContext_x86_64::GetByteOrder()
+{
+ // Get the target process whose privileged thread was used for the register read.
+ lldb::ByteOrder byte_order = eByteOrderInvalid;
+ Process *process = CalculateProcess().get();
+
+ if (process)
+ byte_order = process->GetByteOrder();
+ return byte_order;
+}
+
+// Parse ymm registers and into xmm.bytes and ymmh.bytes.
+bool RegisterContext_x86_64::CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order)
+{
+ if (!IsAVX(reg))
+ return false;
+
+ if (byte_order == eByteOrderLittle) {
+ ::memcpy(m_fpr.xstate.fxsave.xmm[reg - fpu_ymm0].bytes,
+ m_ymm_set.ymm[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::XMMReg));
+ ::memcpy(m_fpr.xstate.xsave.ymmh[reg - fpu_ymm0].bytes,
+ m_ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg),
+ sizeof(RegisterContext_x86_64::YMMHReg));
+ return true;
+ }
+
+ if (byte_order == eByteOrderBig) {
+ ::memcpy(m_fpr.xstate.fxsave.xmm[reg - fpu_ymm0].bytes,
+ m_ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg),
+ sizeof(RegisterContext_x86_64::XMMReg));
+ ::memcpy(m_fpr.xstate.xsave.ymmh[reg - fpu_ymm0].bytes,
+ m_ymm_set.ymm[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::YMMHReg));
+ return true;
+ }
+ return false; // unsupported or invalid byte order
+}
+
+// Concatenate xmm.bytes with ymmh.bytes
+bool RegisterContext_x86_64::CopyXSTATEtoYMM(uint32_t reg, lldb::ByteOrder byte_order)
+{
+ if (!IsAVX(reg))
+ return false;
+
+ if (byte_order == eByteOrderLittle) {
+ ::memcpy(m_ymm_set.ymm[reg - fpu_ymm0].bytes,
+ m_fpr.xstate.fxsave.xmm[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::XMMReg));
+ ::memcpy(m_ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg),
+ m_fpr.xstate.xsave.ymmh[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::YMMHReg));
+ return true;
+ }
+ if (byte_order == eByteOrderBig) {
+ ::memcpy(m_ymm_set.ymm[reg - fpu_ymm0].bytes + sizeof(RegisterContext_x86_64::XMMReg),
+ m_fpr.xstate.fxsave.xmm[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::XMMReg));
+ ::memcpy(m_ymm_set.ymm[reg - fpu_ymm0].bytes,
+ m_fpr.xstate.xsave.ymmh[reg - fpu_ymm0].bytes,
+ sizeof(RegisterContext_x86_64::YMMHReg));
+ return true;
+ }
+ return false; // unsupported or invalid byte order
+}
+
+bool
+RegisterContext_x86_64::IsRegisterSetAvailable(size_t set_index)
+{
+ // Note: Extended register sets are assumed to be at the end of g_reg_sets...
+ size_t num_sets = k_num_register_sets - k_num_extended_register_sets;
+ if (m_fpr_type == eXSAVE) // ...and to start with AVX registers.
+ ++num_sets;
+
+ return (set_index < num_sets);
+}
+
+bool
+RegisterContext_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ if (!reg_info)
+ return false;
+
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (IsFPR(reg, m_fpr_type)) {
+ if (!ReadFPR())
+ return false;
+ }
+ else {
+ bool success = ReadRegister(reg, value);
+
+ // If an i386 register should be parsed from an x86_64 register...
+ if (success && reg >= k_first_i386 && reg <= k_last_i386)
+ if (value.GetByteSize() > reg_info->byte_size)
+ value.SetType(reg_info); // ...use the type specified by reg_info rather than the uint64_t default
+ return success;
+ }
+
+ if (reg_info->encoding == eEncodingVector) {
+ ByteOrder byte_order = GetByteOrder();
+
+ if (byte_order != ByteOrder::eByteOrderInvalid) {
+ if (reg >= fpu_stmm0 && reg <= fpu_stmm7) {
+ value.SetBytes(m_fpr.xstate.fxsave.stmm[reg - fpu_stmm0].bytes, reg_info->byte_size, byte_order);
+ }
+ if (reg >= fpu_xmm0 && reg <= fpu_xmm15) {
+ value.SetBytes(m_fpr.xstate.fxsave.xmm[reg - fpu_xmm0].bytes, reg_info->byte_size, byte_order);
+ }
+ if (reg >= fpu_ymm0 && reg <= fpu_ymm15) {
+ // Concatenate ymm using the register halves in xmm.bytes and ymmh.bytes
+ if (m_fpr_type == eXSAVE && CopyXSTATEtoYMM(reg, byte_order))
+ value.SetBytes(m_ymm_set.ymm[reg - fpu_ymm0].bytes, reg_info->byte_size, byte_order);
+ else
+ return false;
+ }
+ return value.GetType() == RegisterValue::eTypeBytes;
+ }
+ return false;
+ }
+
+ // Note that lldb uses slightly different naming conventions from sys/user.h
+ switch (reg)
+ {
+ default:
+ return false;
+ case fpu_dp:
+ value = m_fpr.xstate.fxsave.dp;
+ break;
+ case fpu_fcw:
+ value = m_fpr.xstate.fxsave.fcw;
+ break;
+ case fpu_fsw:
+ value = m_fpr.xstate.fxsave.fsw;
+ break;
+ case fpu_ip:
+ value = m_fpr.xstate.fxsave.ip;
+ break;
+ case fpu_fop:
+ value = m_fpr.xstate.fxsave.fop;
+ break;
+ case fpu_ftw:
+ value = m_fpr.xstate.fxsave.ftw;
+ break;
+ case fpu_mxcsr:
+ value = m_fpr.xstate.fxsave.mxcsr;
+ break;
+ case fpu_mxcsrmask:
+ value = m_fpr.xstate.fxsave.mxcsrmask;
+ break;
+ }
+ return true;
+}
+
+bool
+RegisterContext_x86_64::ReadAllRegisterValues(DataBufferSP &data_sp)
+{
+ bool success = false;
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp && ReadGPR () && ReadFPR ())
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ success = dst != 0;
+
+ if (success) {
+ ::memcpy (dst, &m_gpr, GetGPRSize());
+ dst += GetGPRSize();
+ }
+ if (m_fpr_type == eFXSAVE)
+ ::memcpy (dst, &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
+
+ if (m_fpr_type == eXSAVE) {
+ ByteOrder byte_order = GetByteOrder();
+
+ // Assemble the YMM register content from the register halves.
+ for (uint32_t reg = fpu_ymm0; success && reg <= fpu_ymm15; ++reg)
+ success = CopyXSTATEtoYMM(reg, byte_order);
+
+ if (success) {
+ // Copy the extended register state including the assembled ymm registers.
+ ::memcpy (dst, &m_fpr, sizeof(m_fpr));
+ }
+ }
+ }
+ return success;
+}
+
+bool
+RegisterContext_x86_64::WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ if (IsGPR(reg)) {
+ return WriteRegister(reg, value);
+ }
+
+ if (IsFPR(reg, m_fpr_type)) {
+ switch (reg)
+ {
+ default:
+ if (reg_info->encoding != eEncodingVector)
+ return false;
+
+ if (reg >= fpu_stmm0 && reg <= fpu_stmm7)
+ ::memcpy (m_fpr.xstate.fxsave.stmm[reg - fpu_stmm0].bytes, value.GetBytes(), value.GetByteSize());
+
+ if (reg >= fpu_xmm0 && reg <= fpu_xmm15)
+ ::memcpy (m_fpr.xstate.fxsave.xmm[reg - fpu_xmm0].bytes, value.GetBytes(), value.GetByteSize());
+
+ if (reg >= fpu_ymm0 && reg <= fpu_ymm15) {
+ if (m_fpr_type != eXSAVE)
+ return false; // the target processor does not support AVX
+
+ // Store ymm register content, and split into the register halves in xmm.bytes and ymmh.bytes
+ ::memcpy (m_ymm_set.ymm[reg - fpu_ymm0].bytes, value.GetBytes(), value.GetByteSize());
+ if (false == CopyYMMtoXSTATE(reg, GetByteOrder()))
+ return false;
+ }
+ break;
+ case fpu_dp:
+ m_fpr.xstate.fxsave.dp = value.GetAsUInt64();
+ break;
+ case fpu_fcw:
+ m_fpr.xstate.fxsave.fcw = value.GetAsUInt16();
+ break;
+ case fpu_fsw:
+ m_fpr.xstate.fxsave.fsw = value.GetAsUInt16();
+ break;
+ case fpu_ip:
+ m_fpr.xstate.fxsave.ip = value.GetAsUInt64();
+ break;
+ case fpu_fop:
+ m_fpr.xstate.fxsave.fop = value.GetAsUInt16();
+ break;
+ case fpu_ftw:
+ m_fpr.xstate.fxsave.ftw = value.GetAsUInt16();
+ break;
+ case fpu_mxcsr:
+ m_fpr.xstate.fxsave.mxcsr = value.GetAsUInt32();
+ break;
+ case fpu_mxcsrmask:
+ m_fpr.xstate.fxsave.mxcsrmask = value.GetAsUInt32();
+ break;
+ }
+ if (WriteFPR()) {
+ if (IsAVX(reg))
+ return CopyYMMtoXSTATE(reg, GetByteOrder());
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+RegisterContext_x86_64::WriteAllRegisterValues(const DataBufferSP &data_sp)
+{
+ bool success = false;
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ uint8_t *src = data_sp->GetBytes();
+ if (src) {
+ ::memcpy (&m_gpr, src, GetGPRSize());
+
+ if (WriteGPR()) {
+ src += GetGPRSize();
+ if (m_fpr_type == eFXSAVE)
+ ::memcpy (&m_fpr.xstate.fxsave, src, sizeof(m_fpr.xstate.fxsave));
+ if (m_fpr_type == eXSAVE)
+ ::memcpy (&m_fpr.xstate.xsave, src, sizeof(m_fpr.xstate.xsave));
+
+ success = WriteFPR();
+ if (success) {
+ success = true;
+
+ if (m_fpr_type == eXSAVE) {
+ ByteOrder byte_order = GetByteOrder();
+
+ // Parse the YMM register content from the register halves.
+ for (uint32_t reg = fpu_ymm0; success && reg <= fpu_ymm15; ++reg)
+ success = CopyYMMtoXSTATE(reg, byte_order);
+ }
+ }
+ }
+ }
+ }
+ return success;
+}
+
+bool
+RegisterContext_x86_64::UpdateAfterBreakpoint()
+{
+ // PC points one byte past the int3 responsible for the breakpoint.
+ lldb::addr_t pc;
+
+ if ((pc = GetPC()) == LLDB_INVALID_ADDRESS)
+ return false;
+
+ SetPC(pc - 1);
+ return true;
+}
+
+uint32_t
+RegisterContext_x86_64::ConvertRegisterKindToRegisterNumber(uint32_t kind,
+ uint32_t num)
+{
+ const Process *process = CalculateProcess().get();
+ if (process)
+ {
+ const ArchSpec arch = process->GetTarget().GetArchitecture();;
+ switch (arch.GetCore())
+ {
+ default:
+ assert(false && "CPU type not supported!");
+ break;
+
+ case ArchSpec::eCore_x86_32_i386:
+ case ArchSpec::eCore_x86_32_i486:
+ case ArchSpec::eCore_x86_32_i486sx:
+ {
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (num)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_eip;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_esp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_ebp;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_eflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (num)
+ {
+ case dwarf_eax: return gpr_eax;
+ case dwarf_edx: return gpr_edx;
+ case dwarf_ecx: return gpr_ecx;
+ case dwarf_ebx: return gpr_ebx;
+ case dwarf_esi: return gpr_esi;
+ case dwarf_edi: return gpr_edi;
+ case dwarf_ebp: return gpr_ebp;
+ case dwarf_esp: return gpr_esp;
+ case dwarf_eip: return gpr_eip;
+ case dwarf_xmm0: return fpu_xmm0;
+ case dwarf_xmm1: return fpu_xmm1;
+ case dwarf_xmm2: return fpu_xmm2;
+ case dwarf_xmm3: return fpu_xmm3;
+ case dwarf_xmm4: return fpu_xmm4;
+ case dwarf_xmm5: return fpu_xmm5;
+ case dwarf_xmm6: return fpu_xmm6;
+ case dwarf_xmm7: return fpu_xmm7;
+ case dwarf_stmm0: return fpu_stmm0;
+ case dwarf_stmm1: return fpu_stmm1;
+ case dwarf_stmm2: return fpu_stmm2;
+ case dwarf_stmm3: return fpu_stmm3;
+ case dwarf_stmm4: return fpu_stmm4;
+ case dwarf_stmm5: return fpu_stmm5;
+ case dwarf_stmm6: return fpu_stmm6;
+ case dwarf_stmm7: return fpu_stmm7;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGDB)
+ {
+ switch (num)
+ {
+ case gdb_eax : return gpr_eax;
+ case gdb_ebx : return gpr_ebx;
+ case gdb_ecx : return gpr_ecx;
+ case gdb_edx : return gpr_edx;
+ case gdb_esi : return gpr_esi;
+ case gdb_edi : return gpr_edi;
+ case gdb_ebp : return gpr_ebp;
+ case gdb_esp : return gpr_esp;
+ case gdb_eip : return gpr_eip;
+ case gdb_eflags : return gpr_eflags;
+ case gdb_cs : return gpr_cs;
+ case gdb_ss : return gpr_ss;
+ case gdb_ds : return gpr_ds;
+ case gdb_es : return gpr_es;
+ case gdb_fs : return gpr_fs;
+ case gdb_gs : return gpr_gs;
+ case gdb_stmm0 : return fpu_stmm0;
+ case gdb_stmm1 : return fpu_stmm1;
+ case gdb_stmm2 : return fpu_stmm2;
+ case gdb_stmm3 : return fpu_stmm3;
+ case gdb_stmm4 : return fpu_stmm4;
+ case gdb_stmm5 : return fpu_stmm5;
+ case gdb_stmm6 : return fpu_stmm6;
+ case gdb_stmm7 : return fpu_stmm7;
+ case gdb_fcw : return fpu_fcw;
+ case gdb_fsw : return fpu_fsw;
+ case gdb_ftw : return fpu_ftw;
+ case gdb_fpu_cs : return fpu_cs;
+ case gdb_ip : return fpu_ip;
+ case gdb_fpu_ds : return fpu_ds; //fpu_fos
+ case gdb_dp : return fpu_dp; //fpu_foo
+ case gdb_fop : return fpu_fop;
+ case gdb_xmm0 : return fpu_xmm0;
+ case gdb_xmm1 : return fpu_xmm1;
+ case gdb_xmm2 : return fpu_xmm2;
+ case gdb_xmm3 : return fpu_xmm3;
+ case gdb_xmm4 : return fpu_xmm4;
+ case gdb_xmm5 : return fpu_xmm5;
+ case gdb_xmm6 : return fpu_xmm6;
+ case gdb_xmm7 : return fpu_xmm7;
+ case gdb_mxcsr : return fpu_mxcsr;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return num;
+ }
+
+ break;
+ }
+
+ case ArchSpec::eCore_x86_64_x86_64:
+ {
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (num)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_rip;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_rsp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_rbp;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_rflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (num)
+ {
+ case gcc_dwarf_gpr_rax: return gpr_rax;
+ case gcc_dwarf_gpr_rdx: return gpr_rdx;
+ case gcc_dwarf_gpr_rcx: return gpr_rcx;
+ case gcc_dwarf_gpr_rbx: return gpr_rbx;
+ case gcc_dwarf_gpr_rsi: return gpr_rsi;
+ case gcc_dwarf_gpr_rdi: return gpr_rdi;
+ case gcc_dwarf_gpr_rbp: return gpr_rbp;
+ case gcc_dwarf_gpr_rsp: return gpr_rsp;
+ case gcc_dwarf_gpr_r8: return gpr_r8;
+ case gcc_dwarf_gpr_r9: return gpr_r9;
+ case gcc_dwarf_gpr_r10: return gpr_r10;
+ case gcc_dwarf_gpr_r11: return gpr_r11;
+ case gcc_dwarf_gpr_r12: return gpr_r12;
+ case gcc_dwarf_gpr_r13: return gpr_r13;
+ case gcc_dwarf_gpr_r14: return gpr_r14;
+ case gcc_dwarf_gpr_r15: return gpr_r15;
+ case gcc_dwarf_gpr_rip: return gpr_rip;
+ case gcc_dwarf_fpu_xmm0: return fpu_xmm0;
+ case gcc_dwarf_fpu_xmm1: return fpu_xmm1;
+ case gcc_dwarf_fpu_xmm2: return fpu_xmm2;
+ case gcc_dwarf_fpu_xmm3: return fpu_xmm3;
+ case gcc_dwarf_fpu_xmm4: return fpu_xmm4;
+ case gcc_dwarf_fpu_xmm5: return fpu_xmm5;
+ case gcc_dwarf_fpu_xmm6: return fpu_xmm6;
+ case gcc_dwarf_fpu_xmm7: return fpu_xmm7;
+ case gcc_dwarf_fpu_xmm8: return fpu_xmm8;
+ case gcc_dwarf_fpu_xmm9: return fpu_xmm9;
+ case gcc_dwarf_fpu_xmm10: return fpu_xmm10;
+ case gcc_dwarf_fpu_xmm11: return fpu_xmm11;
+ case gcc_dwarf_fpu_xmm12: return fpu_xmm12;
+ case gcc_dwarf_fpu_xmm13: return fpu_xmm13;
+ case gcc_dwarf_fpu_xmm14: return fpu_xmm14;
+ case gcc_dwarf_fpu_xmm15: return fpu_xmm15;
+ case gcc_dwarf_fpu_stmm0: return fpu_stmm0;
+ case gcc_dwarf_fpu_stmm1: return fpu_stmm1;
+ case gcc_dwarf_fpu_stmm2: return fpu_stmm2;
+ case gcc_dwarf_fpu_stmm3: return fpu_stmm3;
+ case gcc_dwarf_fpu_stmm4: return fpu_stmm4;
+ case gcc_dwarf_fpu_stmm5: return fpu_stmm5;
+ case gcc_dwarf_fpu_stmm6: return fpu_stmm6;
+ case gcc_dwarf_fpu_stmm7: return fpu_stmm7;
+ case gcc_dwarf_fpu_ymm0: return fpu_ymm0;
+ case gcc_dwarf_fpu_ymm1: return fpu_ymm1;
+ case gcc_dwarf_fpu_ymm2: return fpu_ymm2;
+ case gcc_dwarf_fpu_ymm3: return fpu_ymm3;
+ case gcc_dwarf_fpu_ymm4: return fpu_ymm4;
+ case gcc_dwarf_fpu_ymm5: return fpu_ymm5;
+ case gcc_dwarf_fpu_ymm6: return fpu_ymm6;
+ case gcc_dwarf_fpu_ymm7: return fpu_ymm7;
+ case gcc_dwarf_fpu_ymm8: return fpu_ymm8;
+ case gcc_dwarf_fpu_ymm9: return fpu_ymm9;
+ case gcc_dwarf_fpu_ymm10: return fpu_ymm10;
+ case gcc_dwarf_fpu_ymm11: return fpu_ymm11;
+ case gcc_dwarf_fpu_ymm12: return fpu_ymm12;
+ case gcc_dwarf_fpu_ymm13: return fpu_ymm13;
+ case gcc_dwarf_fpu_ymm14: return fpu_ymm14;
+ case gcc_dwarf_fpu_ymm15: return fpu_ymm15;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+
+ if (kind == eRegisterKindGDB)
+ {
+ switch (num)
+ {
+ case gdb_gpr_rax : return gpr_rax;
+ case gdb_gpr_rbx : return gpr_rbx;
+ case gdb_gpr_rcx : return gpr_rcx;
+ case gdb_gpr_rdx : return gpr_rdx;
+ case gdb_gpr_rsi : return gpr_rsi;
+ case gdb_gpr_rdi : return gpr_rdi;
+ case gdb_gpr_rbp : return gpr_rbp;
+ case gdb_gpr_rsp : return gpr_rsp;
+ case gdb_gpr_r8 : return gpr_r8;
+ case gdb_gpr_r9 : return gpr_r9;
+ case gdb_gpr_r10 : return gpr_r10;
+ case gdb_gpr_r11 : return gpr_r11;
+ case gdb_gpr_r12 : return gpr_r12;
+ case gdb_gpr_r13 : return gpr_r13;
+ case gdb_gpr_r14 : return gpr_r14;
+ case gdb_gpr_r15 : return gpr_r15;
+ case gdb_gpr_rip : return gpr_rip;
+ case gdb_gpr_rflags : return gpr_rflags;
+ case gdb_gpr_cs : return gpr_cs;
+ case gdb_gpr_ss : return gpr_ss;
+ case gdb_gpr_ds : return gpr_ds;
+ case gdb_gpr_es : return gpr_es;
+ case gdb_gpr_fs : return gpr_fs;
+ case gdb_gpr_gs : return gpr_gs;
+ case gdb_fpu_stmm0 : return fpu_stmm0;
+ case gdb_fpu_stmm1 : return fpu_stmm1;
+ case gdb_fpu_stmm2 : return fpu_stmm2;
+ case gdb_fpu_stmm3 : return fpu_stmm3;
+ case gdb_fpu_stmm4 : return fpu_stmm4;
+ case gdb_fpu_stmm5 : return fpu_stmm5;
+ case gdb_fpu_stmm6 : return fpu_stmm6;
+ case gdb_fpu_stmm7 : return fpu_stmm7;
+ case gdb_fpu_fcw : return fpu_fcw;
+ case gdb_fpu_fsw : return fpu_fsw;
+ case gdb_fpu_ftw : return fpu_ftw;
+ case gdb_fpu_cs_64 : return fpu_cs;
+ case gdb_fpu_ip : return fpu_ip;
+ case gdb_fpu_ds_64 : return fpu_ds;
+ case gdb_fpu_dp : return fpu_dp;
+ case gdb_fpu_fop : return fpu_fop;
+ case gdb_fpu_xmm0 : return fpu_xmm0;
+ case gdb_fpu_xmm1 : return fpu_xmm1;
+ case gdb_fpu_xmm2 : return fpu_xmm2;
+ case gdb_fpu_xmm3 : return fpu_xmm3;
+ case gdb_fpu_xmm4 : return fpu_xmm4;
+ case gdb_fpu_xmm5 : return fpu_xmm5;
+ case gdb_fpu_xmm6 : return fpu_xmm6;
+ case gdb_fpu_xmm7 : return fpu_xmm7;
+ case gdb_fpu_xmm8 : return fpu_xmm8;
+ case gdb_fpu_xmm9 : return fpu_xmm9;
+ case gdb_fpu_xmm10 : return fpu_xmm10;
+ case gdb_fpu_xmm11 : return fpu_xmm11;
+ case gdb_fpu_xmm12 : return fpu_xmm12;
+ case gdb_fpu_xmm13 : return fpu_xmm13;
+ case gdb_fpu_xmm14 : return fpu_xmm14;
+ case gdb_fpu_xmm15 : return fpu_xmm15;
+ case gdb_fpu_mxcsr : return fpu_mxcsr;
+ case gdb_fpu_ymm0 : return fpu_ymm0;
+ case gdb_fpu_ymm1 : return fpu_ymm1;
+ case gdb_fpu_ymm2 : return fpu_ymm2;
+ case gdb_fpu_ymm3 : return fpu_ymm3;
+ case gdb_fpu_ymm4 : return fpu_ymm4;
+ case gdb_fpu_ymm5 : return fpu_ymm5;
+ case gdb_fpu_ymm6 : return fpu_ymm6;
+ case gdb_fpu_ymm7 : return fpu_ymm7;
+ case gdb_fpu_ymm8 : return fpu_ymm8;
+ case gdb_fpu_ymm9 : return fpu_ymm9;
+ case gdb_fpu_ymm10 : return fpu_ymm10;
+ case gdb_fpu_ymm11 : return fpu_ymm11;
+ case gdb_fpu_ymm12 : return fpu_ymm12;
+ case gdb_fpu_ymm13 : return fpu_ymm13;
+ case gdb_fpu_ymm14 : return fpu_ymm14;
+ case gdb_fpu_ymm15 : return fpu_ymm15;
+ default:
+ return LLDB_INVALID_REGNUM;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return num;
+ }
+ }
+ }
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
+uint32_t
+RegisterContext_x86_64::NumSupportedHardwareWatchpoints()
+{
+ // Available debug address registers: dr0, dr1, dr2, dr3
+ return 4;
+}
+
+bool
+RegisterContext_x86_64::IsWatchpointVacant(uint32_t hw_index)
+{
+ bool is_vacant = false;
+ RegisterValue value;
+
+ assert(hw_index < NumSupportedHardwareWatchpoints());
+
+ if (m_watchpoints_initialized == false)
+ {
+ // Reset the debug status and debug control registers
+ RegisterValue zero_bits = RegisterValue(uint64_t(0));
+ if (!WriteRegister(dr6, zero_bits) || !WriteRegister(dr7, zero_bits))
+ assert(false && "Could not initialize watchpoint registers");
+ m_watchpoints_initialized = true;
+ }
+
+ if (ReadRegister(dr7, value))
+ {
+ uint64_t val = value.GetAsUInt64();
+ is_vacant = (val & (3 << 2*hw_index)) == 0;
+ }
+
+ return is_vacant;
+}
+
+static uint32_t
+size_and_rw_bits(size_t size, bool read, bool write)
+{
+ uint32_t rw;
+ if (read) {
+ rw = 0x3; // READ or READ/WRITE
+ } else if (write) {
+ rw = 0x1; // WRITE
+ } else {
+ assert(0 && "read and write cannot both be false");
+ }
+
+ switch (size) {
+ case 1:
+ return rw;
+ case 2:
+ return (0x1 << 2) | rw;
+ case 4:
+ return (0x3 << 2) | rw;
+ case 8:
+ return (0x2 << 2) | rw;
+ default:
+ assert(0 && "invalid size, must be one of 1, 2, 4, or 8");
+ }
+}
+
+uint32_t
+RegisterContext_x86_64::SetHardwareWatchpoint(addr_t addr, size_t size,
+ bool read, bool write)
+{
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+ uint32_t hw_index;
+
+ for (hw_index = 0; hw_index < num_hw_watchpoints; ++hw_index)
+ {
+ if (IsWatchpointVacant(hw_index))
+ return SetHardwareWatchpointWithIndex(addr, size,
+ read, write,
+ hw_index);
+ }
+
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContext_x86_64::SetHardwareWatchpointWithIndex(addr_t addr, size_t size,
+ bool read, bool write,
+ uint32_t hw_index)
+{
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+
+ if (num_hw_watchpoints == 0 || hw_index >= num_hw_watchpoints)
+ return false;
+
+ if (!(size == 1 || size == 2 || size == 4 || size == 8))
+ return false;
+
+ if (read == false && write == false)
+ return false;
+
+ if (!IsWatchpointVacant(hw_index))
+ return false;
+
+ // Set both dr7 (debug control register) and dri (debug address register).
+
+ // dr7{7-0} encodes the local/gloabl enable bits:
+ // global enable --. .-- local enable
+ // | |
+ // v v
+ // dr0 -> bits{1-0}
+ // dr1 -> bits{3-2}
+ // dr2 -> bits{5-4}
+ // dr3 -> bits{7-6}
+ //
+ // dr7{31-16} encodes the rw/len bits:
+ // b_x+3, b_x+2, b_x+1, b_x
+ // where bits{x+1, x} => rw
+ // 0b00: execute, 0b01: write, 0b11: read-or-write,
+ // 0b10: io read-or-write (unused)
+ // and bits{x+3, x+2} => len
+ // 0b00: 1-byte, 0b01: 2-byte, 0b11: 4-byte, 0b10: 8-byte
+ //
+ // dr0 -> bits{19-16}
+ // dr1 -> bits{23-20}
+ // dr2 -> bits{27-24}
+ // dr3 -> bits{31-28}
+ if (hw_index < num_hw_watchpoints)
+ {
+ RegisterValue current_dr7_bits;
+
+ if (ReadRegister(dr7, current_dr7_bits))
+ {
+ uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() |
+ (1 << (2*hw_index) |
+ size_and_rw_bits(size, read, write) <<
+ (16+4*hw_index));
+
+ if (WriteRegister(dr0 + hw_index, RegisterValue(addr)) &&
+ WriteRegister(dr7, RegisterValue(new_dr7_bits)))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+RegisterContext_x86_64::ClearHardwareWatchpoint(uint32_t hw_index)
+{
+ if (hw_index < NumSupportedHardwareWatchpoints())
+ {
+ RegisterValue current_dr7_bits;
+
+ if (ReadRegister(dr7, current_dr7_bits))
+ {
+ uint64_t new_dr7_bits = current_dr7_bits.GetAsUInt64() & ~(3 << (2*hw_index));
+
+ if (WriteRegister(dr7, RegisterValue(new_dr7_bits)))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool
+RegisterContext_x86_64::IsWatchpointHit(uint32_t hw_index)
+{
+ bool is_hit = false;
+
+ if (m_watchpoints_initialized == false)
+ {
+ // Reset the debug status and debug control registers
+ RegisterValue zero_bits = RegisterValue(uint64_t(0));
+ if (!WriteRegister(dr6, zero_bits) || !WriteRegister(dr7, zero_bits))
+ assert(false && "Could not initialize watchpoint registers");
+ m_watchpoints_initialized = true;
+ }
+
+ if (hw_index < NumSupportedHardwareWatchpoints())
+ {
+ RegisterValue value;
+
+ if (ReadRegister(dr6, value))
+ {
+ uint64_t val = value.GetAsUInt64();
+ is_hit = val & (1 << hw_index);
+ }
+ }
+
+ return is_hit;
+}
+
+addr_t
+RegisterContext_x86_64::GetWatchpointAddress(uint32_t hw_index)
+{
+ addr_t wp_monitor_addr = LLDB_INVALID_ADDRESS;
+
+ if (hw_index < NumSupportedHardwareWatchpoints())
+ {
+ if (!IsWatchpointVacant(hw_index))
+ {
+ RegisterValue value;
+
+ if (ReadRegister(dr0 + hw_index, value))
+ wp_monitor_addr = value.GetAsUInt64();
+ }
+ }
+
+ return wp_monitor_addr;
+}
+
+
+bool
+RegisterContext_x86_64::ClearWatchpointHits()
+{
+ return WriteRegister(dr6, RegisterValue((uint64_t)0));
+}
+
+bool
+RegisterContext_x86_64::HardwareSingleStep(bool enable)
+{
+ enum { TRACE_BIT = 0x100 };
+ uint64_t rflags;
+
+ if ((rflags = ReadRegisterAsUnsigned(gpr_rflags, -1UL)) == -1UL)
+ return false;
+
+ if (enable)
+ {
+ if (rflags & TRACE_BIT)
+ return true;
+
+ rflags |= TRACE_BIT;
+ }
+ else
+ {
+ if (!(rflags & TRACE_BIT))
+ return false;
+
+ rflags &= ~TRACE_BIT;
+ }
+
+ return WriteRegisterFromUnsigned(gpr_rflags, rflags);
+}
+
+#if defined(__linux__) or defined(__FreeBSD__)
+
+ProcessMonitor &
+RegisterContext_x86_64::GetMonitor()
+{
+ ProcessSP base = CalculateProcess();
+ ProcessPOSIX *process = static_cast<ProcessPOSIX*>(base.get());
+ return process->GetMonitor();
+}
+
+bool
+RegisterContext_x86_64::ReadGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadGPR(m_thread.GetID(), &m_gpr, GetGPRSize());
+}
+
+bool
+RegisterContext_x86_64::ReadFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ if (m_fpr_type == eFXSAVE)
+ return monitor.ReadFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
+
+ if (m_fpr_type == eXSAVE)
+ return monitor.ReadRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
+ return false;
+}
+
+bool
+RegisterContext_x86_64::WriteGPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteGPR(m_thread.GetID(), &m_gpr, GetGPRSize());
+}
+
+bool
+RegisterContext_x86_64::WriteFPR()
+{
+ ProcessMonitor &monitor = GetMonitor();
+ if (m_fpr_type == eFXSAVE)
+ return monitor.WriteFPR(m_thread.GetID(), &m_fpr.xstate.fxsave, sizeof(m_fpr.xstate.fxsave));
+
+ if (m_fpr_type == eXSAVE)
+ return monitor.WriteRegisterSet(m_thread.GetID(), &m_iovec, sizeof(m_fpr.xstate.xsave), NT_X86_XSTATE);
+ return false;
+}
+
+bool
+RegisterContext_x86_64::ReadRegister(const unsigned reg,
+ RegisterValue &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.ReadRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg),
+ GetRegisterName(reg),
+ GetRegisterSize(reg),
+ value);
+}
+
+bool
+RegisterContext_x86_64::WriteRegister(const unsigned reg,
+ const RegisterValue &value)
+{
+ ProcessMonitor &monitor = GetMonitor();
+ return monitor.WriteRegisterValue(m_thread.GetID(),
+ GetRegisterOffset(reg),
+ GetRegisterName(reg),
+ value);
+}
+
+#else
+
+bool
+RegisterContext_x86_64::ReadGPR()
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+bool
+RegisterContext_x86_64::ReadFPR()
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+bool
+RegisterContext_x86_64::WriteGPR()
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+bool
+RegisterContext_x86_64::WriteFPR()
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+bool
+RegisterContext_x86_64::ReadRegister(const unsigned reg,
+ RegisterValue &value)
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+bool
+RegisterContext_x86_64::WriteRegister(const unsigned reg,
+ const RegisterValue &value)
+{
+ llvm_unreachable("not implemented");
+ return false;
+}
+
+#endif
diff --git a/source/Plugins/Process/POSIX/RegisterContext_x86_64.h b/source/Plugins/Process/POSIX/RegisterContext_x86_64.h
new file mode 100644
index 000000000000..9d59bd78e547
--- /dev/null
+++ b/source/Plugins/Process/POSIX/RegisterContext_x86_64.h
@@ -0,0 +1,347 @@
+//===-- RegisterContext_x86_64.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContext_x86_64_H_
+#define liblldb_RegisterContext_x86_64_H_
+
+#include "lldb/Core/Log.h"
+#include "RegisterContextPOSIX.h"
+
+class ProcessMonitor;
+
+// Internal codes for all x86_64 registers.
+enum
+{
+ k_first_gpr,
+ gpr_rax = k_first_gpr,
+ gpr_rbx,
+ gpr_rcx,
+ gpr_rdx,
+ gpr_rdi,
+ gpr_rsi,
+ gpr_rbp,
+ gpr_rsp,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_r14,
+ gpr_r15,
+ gpr_rip,
+ gpr_rflags,
+ gpr_cs,
+ gpr_fs,
+ gpr_gs,
+ gpr_ss,
+ gpr_ds,
+ gpr_es,
+ k_first_i386,
+ gpr_eax = k_first_i386,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_eip,
+ gpr_eflags, // eRegisterKindLLDB == 33
+ k_last_i386 = gpr_eflags,
+ k_last_gpr = gpr_eflags,
+
+ k_first_fpr,
+ fpu_fcw = k_first_fpr,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ fpu_xmm8,
+ fpu_xmm9,
+ fpu_xmm10,
+ fpu_xmm11,
+ fpu_xmm12,
+ fpu_xmm13,
+ fpu_xmm14,
+ fpu_xmm15,
+ k_last_fpr = fpu_xmm15,
+ k_first_avx,
+ fpu_ymm0 = k_first_avx,
+ fpu_ymm1,
+ fpu_ymm2,
+ fpu_ymm3,
+ fpu_ymm4,
+ fpu_ymm5,
+ fpu_ymm6,
+ fpu_ymm7,
+ fpu_ymm8,
+ fpu_ymm9,
+ fpu_ymm10,
+ fpu_ymm11,
+ fpu_ymm12,
+ fpu_ymm13,
+ fpu_ymm14,
+ fpu_ymm15,
+ k_last_avx = fpu_ymm15,
+
+ dr0,
+ dr1,
+ dr2,
+ dr3,
+ dr4,
+ dr5,
+ dr6,
+ dr7,
+
+ k_num_registers,
+ k_num_gpr_registers = k_last_gpr - k_first_gpr + 1,
+ k_num_fpr_registers = k_last_fpr - k_first_fpr + 1,
+ k_num_avx_registers = k_last_avx - k_first_avx + 1
+};
+
+class RegisterContext_x86_64
+ : public RegisterContextPOSIX
+{
+public:
+ RegisterContext_x86_64 (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ ~RegisterContext_x86_64();
+
+ void
+ Invalidate();
+
+ void
+ InvalidateAllRegisters();
+
+ size_t
+ GetRegisterCount();
+
+ virtual size_t
+ GetGPRSize() = 0;
+
+ virtual unsigned
+ GetRegisterSize(unsigned reg);
+
+ virtual unsigned
+ GetRegisterOffset(unsigned reg);
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex(size_t reg);
+
+ size_t
+ GetRegisterSetCount();
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet(size_t set);
+
+ unsigned
+ GetRegisterIndexFromOffset(unsigned offset);
+
+ const char *
+ GetRegisterName(unsigned reg);
+
+ virtual bool
+ ReadRegister(const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteRegister(const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber(uint32_t kind, uint32_t num);
+
+ uint32_t
+ NumSupportedHardwareWatchpoints();
+
+ uint32_t
+ SetHardwareWatchpoint(lldb::addr_t, size_t size, bool read, bool write);
+
+ bool
+ SetHardwareWatchpointWithIndex(lldb::addr_t, size_t size, bool read,
+ bool write, uint32_t hw_index);
+
+ bool
+ ClearHardwareWatchpoint(uint32_t hw_index);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+ bool
+ UpdateAfterBreakpoint();
+
+ bool
+ IsWatchpointVacant(uint32_t hw_index);
+
+ bool
+ IsWatchpointHit (uint32_t hw_index);
+
+ lldb::addr_t
+ GetWatchpointAddress (uint32_t hw_index);
+
+ bool
+ ClearWatchpointHits();
+
+ //---------------------------------------------------------------------------
+ // Generic floating-point registers
+ //---------------------------------------------------------------------------
+
+ struct MMSReg
+ {
+ uint8_t bytes[10];
+ uint8_t pad[6];
+ };
+
+ struct XMMReg
+ {
+ uint8_t bytes[16]; // 128-bits for each XMM register
+ };
+
+ struct FXSAVE
+ {
+ uint16_t fcw;
+ uint16_t fsw;
+ uint16_t ftw;
+ uint16_t fop;
+ uint64_t ip;
+ uint64_t dp;
+ uint32_t mxcsr;
+ uint32_t mxcsrmask;
+ MMSReg stmm[8];
+ XMMReg xmm[16];
+ uint32_t padding[24];
+ };
+
+ //---------------------------------------------------------------------------
+ // Extended floating-point registers
+ //---------------------------------------------------------------------------
+ struct YMMHReg
+ {
+ uint8_t bytes[16]; // 16 * 8 bits for the high bytes of each YMM register
+ };
+
+ struct YMMReg
+ {
+ uint8_t bytes[32]; // 16 * 16 bits for each YMM register
+ };
+
+ struct YMM
+ {
+ YMMReg ymm[16]; // assembled from ymmh and xmm registers
+ };
+
+ struct XSAVE_HDR
+ {
+ uint64_t xstate_bv; // OS enabled xstate mask to determine the extended states supported by the processor
+ uint64_t reserved1[2];
+ uint64_t reserved2[5];
+ } __attribute__((packed));
+
+ // x86 extensions to FXSAVE (i.e. for AVX processors)
+ struct XSAVE
+ {
+ FXSAVE i387; // floating point registers typical in i387_fxsave_struct
+ XSAVE_HDR header; // The xsave_hdr_struct can be used to determine if the following extensions are usable
+ YMMHReg ymmh[16]; // High 16 bytes of each of 16 YMM registers (the low bytes are in FXSAVE.xmm for compatibility with SSE)
+ // Slot any extensions to the register file here
+ } __attribute__((packed, aligned (64)));
+
+ struct IOVEC
+ {
+ void *iov_base; // pointer to XSAVE
+ size_t iov_len; // sizeof(XSAVE)
+ };
+
+ //---------------------------------------------------------------------------
+ // Note: prefer kernel definitions over user-land
+ //---------------------------------------------------------------------------
+ enum FPRType
+ {
+ eNotValid = 0,
+ eFSAVE, // TODO
+ eFXSAVE,
+ eSOFT, // TODO
+ eXSAVE
+ };
+
+ // Floating-point registers
+ struct FPR
+ {
+ // Thread state for the floating-point unit of the processor read by ptrace.
+ union XSTATE {
+ FXSAVE fxsave; // Generic floating-point registers.
+ XSAVE xsave; // x86 extended processor state.
+ } xstate;
+ };
+
+protected:
+ // Determines if an extended register set is supported on the processor running the inferior process.
+ virtual bool
+ IsRegisterSetAvailable(size_t set_index);
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfo();
+
+ virtual bool
+ ReadRegister(const unsigned reg, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister(const unsigned reg, const lldb_private::RegisterValue &value);
+
+private:
+ uint64_t m_gpr[k_num_gpr_registers]; // general purpose registers.
+ FPRType m_fpr_type; // determines the type of data stored by union FPR, if any.
+ FPR m_fpr; // floating-point registers including extended register sets.
+ IOVEC m_iovec; // wrapper for xsave.
+ YMM m_ymm_set; // copy of ymmh and xmm register halves.
+
+ ProcessMonitor &GetMonitor();
+ lldb::ByteOrder GetByteOrder();
+
+ bool CopyXSTATEtoYMM(uint32_t reg, lldb::ByteOrder byte_order);
+ bool CopyYMMtoXSTATE(uint32_t reg, lldb::ByteOrder byte_order);
+ bool IsFPR(unsigned reg, FPRType fpr_type);
+
+ bool ReadGPR();
+ bool ReadFPR();
+
+ bool WriteGPR();
+ bool WriteFPR();
+};
+
+#endif // #ifndef liblldb_RegisterContext_x86_64_H_
diff --git a/source/Plugins/Process/Utility/ARMDefines.h b/source/Plugins/Process/Utility/ARMDefines.h
new file mode 100644
index 000000000000..4b1f06a2f9cd
--- /dev/null
+++ b/source/Plugins/Process/Utility/ARMDefines.h
@@ -0,0 +1,110 @@
+//===-- lldb_ARMDefines.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_ARMDefines_h_
+#define lldb_ARMDefines_h_
+
+// Common defintions for the ARM/Thumb Instruction Set Architecture.
+
+namespace lldb_private {
+
+// ARM shifter types
+typedef enum
+{
+ SRType_LSL,
+ SRType_LSR,
+ SRType_ASR,
+ SRType_ROR,
+ SRType_RRX,
+ SRType_Invalid
+} ARM_ShifterType;
+
+// ARM conditions // Meaning (integer) Meaning (floating-point) Condition flags
+#define COND_EQ 0x0 // Equal Equal Z == 1
+#define COND_NE 0x1 // Not equal Not equal, or unordered Z == 0
+#define COND_CS 0x2 // Carry set >, ==, or unordered C == 1
+#define COND_HS 0x2
+#define COND_CC 0x3 // Carry clear Less than C == 0
+#define COND_LO 0x3
+#define COND_MI 0x4 // Minus, negative Less than N == 1
+#define COND_PL 0x5 // Plus, positive or zero >, ==, or unordered N == 0
+#define COND_VS 0x6 // Overflow Unordered V == 1
+#define COND_VC 0x7 // No overflow Not unordered V == 0
+#define COND_HI 0x8 // Unsigned higher Greater than, or unordered C == 1 and Z == 0
+#define COND_LS 0x9 // Unsigned lower or same Less than or equal C == 0 or Z == 1
+#define COND_GE 0xA // Greater than or equal Greater than or equal N == V
+#define COND_LT 0xB // Less than Less than, or unordered N != V
+#define COND_GT 0xC // Greater than Greater than Z == 0 and N == V
+#define COND_LE 0xD // Less than or equal <, ==, or unordered Z == 1 or N != V
+#define COND_AL 0xE // Always (unconditional) Always (unconditional) Any
+#define COND_UNCOND 0xF
+
+static inline const char *ARMCondCodeToString(uint32_t CC)
+{
+ switch (CC) {
+ default: assert(0 && "Unknown condition code");
+ case COND_EQ: return "eq";
+ case COND_NE: return "ne";
+ case COND_HS: return "hs";
+ case COND_LO: return "lo";
+ case COND_MI: return "mi";
+ case COND_PL: return "pl";
+ case COND_VS: return "vs";
+ case COND_VC: return "vc";
+ case COND_HI: return "hi";
+ case COND_LS: return "ls";
+ case COND_GE: return "ge";
+ case COND_LT: return "lt";
+ case COND_GT: return "gt";
+ case COND_LE: return "le";
+ case COND_AL: return "al";
+ }
+}
+
+// Bit positions for CPSR
+#define CPSR_T_POS 5
+#define CPSR_F_POS 6
+#define CPSR_I_POS 7
+#define CPSR_A_POS 8
+#define CPSR_E_POS 9
+#define CPSR_J_POS 24
+#define CPSR_Q_POS 27
+#define CPSR_V_POS 28
+#define CPSR_C_POS 29
+#define CPSR_Z_POS 30
+#define CPSR_N_POS 31
+
+// CPSR mode definitions
+#define CPSR_MODE_USR 0x10u
+#define CPSR_MODE_FIQ 0x11u
+#define CPSR_MODE_IRQ 0x12u
+#define CPSR_MODE_SVC 0x13u
+#define CPSR_MODE_ABT 0x17u
+#define CPSR_MODE_UND 0x1bu
+#define CPSR_MODE_SYS 0x1fu
+
+// Masks for CPSR
+#define MASK_CPSR_MODE_MASK (0x0000001fu)
+#define MASK_CPSR_IT_MASK (0x0600fc00u)
+#define MASK_CPSR_T (1u << CPSR_T_POS)
+#define MASK_CPSR_F (1u << CPSR_F_POS)
+#define MASK_CPSR_I (1u << CPSR_I_POS)
+#define MASK_CPSR_A (1u << CPSR_A_POS)
+#define MASK_CPSR_E (1u << CPSR_E_POS)
+#define MASK_CPSR_GE_MASK (0x000f0000u)
+#define MASK_CPSR_J (1u << CPSR_J_POS)
+#define MASK_CPSR_Q (1u << CPSR_Q_POS)
+#define MASK_CPSR_V (1u << CPSR_V_POS)
+#define MASK_CPSR_C (1u << CPSR_C_POS)
+#define MASK_CPSR_Z (1u << CPSR_Z_POS)
+#define MASK_CPSR_N (1u << CPSR_N_POS)
+
+} // namespace lldb_private
+
+#endif // lldb_ARMDefines_h_
diff --git a/source/Plugins/Process/Utility/ARMUtils.h b/source/Plugins/Process/Utility/ARMUtils.h
new file mode 100644
index 000000000000..76d64e15a53e
--- /dev/null
+++ b/source/Plugins/Process/Utility/ARMUtils.h
@@ -0,0 +1,394 @@
+//===-- ARMUtils.h ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_ARMUtils_h_
+#define lldb_ARMUtils_h_
+
+#include "ARMDefines.h"
+#include "InstructionUtils.h"
+#include "llvm/Support/MathExtras.h" // for SignExtend64 template function
+
+// Common utilities for the ARM/Thumb Instruction Set Architecture.
+
+namespace lldb_private {
+
+static inline uint32_t Align(uint32_t val, uint32_t alignment)
+{
+ return alignment * (val / alignment);
+}
+
+static inline uint32_t DecodeImmShift(const uint32_t type, const uint32_t imm5, ARM_ShifterType &shift_t)
+{
+ switch (type)
+ {
+ default:
+ //assert(0 && "Invalid shift type");
+ case 0:
+ shift_t = SRType_LSL;
+ return imm5;
+ case 1:
+ shift_t = SRType_LSR;
+ return (imm5 == 0 ? 32 : imm5);
+ case 2:
+ shift_t = SRType_ASR;
+ return (imm5 == 0 ? 32 : imm5);
+ case 3:
+ if (imm5 == 0)
+ {
+ shift_t = SRType_RRX;
+ return 1;
+ }
+ else
+ {
+ shift_t = SRType_ROR;
+ return imm5;
+ }
+ }
+ shift_t = SRType_Invalid;
+ return UINT32_MAX;
+
+}
+
+// A8.6.35 CMP (register) -- Encoding T3
+// Convenience function.
+static inline uint32_t DecodeImmShiftThumb(const uint32_t opcode, ARM_ShifterType &shift_t)
+{
+ return DecodeImmShift(Bits32(opcode, 5, 4), Bits32(opcode, 14, 12)<<2 | Bits32(opcode, 7, 6), shift_t);
+}
+
+// A8.6.35 CMP (register) -- Encoding A1
+// Convenience function.
+static inline uint32_t DecodeImmShiftARM(const uint32_t opcode, ARM_ShifterType &shift_t)
+{
+ return DecodeImmShift(Bits32(opcode, 6, 5), Bits32(opcode, 11, 7), shift_t);
+}
+
+static inline uint32_t DecodeImmShift(const ARM_ShifterType shift_t, const uint32_t imm5)
+{
+ ARM_ShifterType dont_care;
+ return DecodeImmShift(shift_t, imm5, dont_care);
+}
+
+static inline ARM_ShifterType DecodeRegShift(const uint32_t type)
+{
+ switch (type) {
+ default:
+ //assert(0 && "Invalid shift type");
+ return SRType_Invalid;
+ case 0:
+ return SRType_LSL;
+ case 1:
+ return SRType_LSR;
+ case 2:
+ return SRType_ASR;
+ case 3:
+ return SRType_ROR;
+ }
+}
+
+static inline uint32_t LSL_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ carry_out = amount <= 32 ? Bit32(value, 32 - amount) : 0;
+ return value << amount;
+}
+
+static inline uint32_t LSL(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = LSL_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t LSR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ carry_out = amount <= 32 ? Bit32(value, amount - 1) : 0;
+ return value >> amount;
+}
+
+static inline uint32_t LSR(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = LSR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t ASR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0 || amount > 32) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ bool negative = BitIsSet(value, 31);
+ if (amount <= 32)
+ {
+ carry_out = Bit32(value, amount - 1);
+ int64_t extended = llvm::SignExtend64<32>(value);
+ return UnsignedBits(extended, amount + 31, amount);
+ }
+ else
+ {
+ carry_out = (negative ? 1 : 0);
+ return (negative ? 0xffffffff : 0);
+ }
+}
+
+static inline uint32_t ASR(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = ASR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t ROR_C(const uint32_t value, const uint32_t amount, uint32_t &carry_out, bool *success)
+{
+ if (amount == 0) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+ uint32_t amt = amount % 32;
+ uint32_t result = Rotr32(value, amt);
+ carry_out = Bit32(value, 31);
+ return result;
+}
+
+static inline uint32_t ROR(const uint32_t value, const uint32_t amount, bool *success)
+{
+ *success = true;
+ if (amount == 0)
+ return value;
+ uint32_t dont_care;
+ uint32_t result = ROR_C(value, amount, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t RRX_C(const uint32_t value, const uint32_t carry_in, uint32_t &carry_out, bool *success)
+{
+ *success = true;
+ carry_out = Bit32(value, 0);
+ return Bit32(carry_in, 0) << 31 | Bits32(value, 31, 1);
+}
+
+static inline uint32_t RRX(const uint32_t value, const uint32_t carry_in, bool *success)
+{
+ *success = true;
+ uint32_t dont_care;
+ uint32_t result = RRX_C(value, carry_in, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t Shift_C(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
+ const uint32_t carry_in, uint32_t &carry_out, bool *success)
+{
+ if (type == SRType_RRX && amount != 1) {
+ *success = false;
+ return 0;
+ }
+ *success = true;
+
+ if (amount == 0) {
+ carry_out = carry_in;
+ return value;
+ }
+ uint32_t result;
+ switch (type) {
+ case SRType_LSL:
+ result = LSL_C(value, amount, carry_out, success);
+ break;
+ case SRType_LSR:
+ result = LSR_C(value, amount, carry_out, success);
+ break;
+ case SRType_ASR:
+ result = ASR_C(value, amount, carry_out, success);
+ break;
+ case SRType_ROR:
+ result = ROR_C(value, amount, carry_out, success);
+ break;
+ case SRType_RRX:
+ result = RRX_C(value, carry_in, carry_out, success);
+ break;
+ default:
+ *success = false;
+ break;
+ }
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t Shift(const uint32_t value, ARM_ShifterType type, const uint32_t amount,
+ const uint32_t carry_in, bool *success)
+{
+ // Don't care about carry out in this case.
+ uint32_t dont_care;
+ uint32_t result = Shift_C(value, type, amount, carry_in, dont_care, success);
+ if (*success)
+ return result;
+ else
+ return 0;
+}
+
+static inline uint32_t bits(const uint32_t val, const uint32_t msbit, const uint32_t lsbit)
+{
+ return Bits32(val, msbit, lsbit);
+}
+
+static inline uint32_t bit(const uint32_t val, const uint32_t msbit)
+{
+ return bits(val, msbit, msbit);
+}
+
+static uint32_t ror(uint32_t val, uint32_t N, uint32_t shift)
+{
+ uint32_t m = shift % N;
+ return (val >> m) | (val << (N - m));
+}
+
+// (imm32, carry_out) = ARMExpandImm_C(imm12, carry_in)
+static inline uint32_t ARMExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out)
+{
+ uint32_t imm32; // the expanded result
+ uint32_t imm = bits(opcode, 7, 0); // immediate value
+ uint32_t amt = 2 * bits(opcode, 11, 8); // rotate amount
+ if (amt == 0)
+ {
+ imm32 = imm;
+ carry_out = carry_in;
+ }
+ else
+ {
+ imm32 = ror(imm, 32, amt);
+ carry_out = Bit32(imm32, 31);
+ }
+ return imm32;
+}
+
+static inline uint32_t ARMExpandImm(uint32_t opcode)
+{
+ // 'carry_in' argument to following function call does not affect the imm32 result.
+ uint32_t carry_in = 0;
+ uint32_t carry_out;
+ return ARMExpandImm_C(opcode, carry_in, carry_out);
+}
+
+// (imm32, carry_out) = ThumbExpandImm_C(imm12, carry_in)
+static inline uint32_t ThumbExpandImm_C(uint32_t opcode, uint32_t carry_in, uint32_t &carry_out)
+{
+ uint32_t imm32; // the expaned result
+ const uint32_t i = bit(opcode, 26);
+ const uint32_t imm3 = bits(opcode, 14, 12);
+ const uint32_t abcdefgh = bits(opcode, 7, 0);
+ const uint32_t imm12 = i << 11 | imm3 << 8 | abcdefgh;
+
+ if (bits(imm12, 11, 10) == 0)
+ {
+ switch (bits(imm12, 9, 8)) {
+ default: // Keep static analyzer happy with a default case
+ case 0:
+ imm32 = abcdefgh;
+ break;
+
+ case 1:
+ imm32 = abcdefgh << 16 | abcdefgh;
+ break;
+
+ case 2:
+ imm32 = abcdefgh << 24 | abcdefgh << 8;
+ break;
+
+ case 3:
+ imm32 = abcdefgh << 24 | abcdefgh << 16 | abcdefgh << 8 | abcdefgh;
+ break;
+ }
+ carry_out = carry_in;
+ }
+ else
+ {
+ const uint32_t unrotated_value = 0x80 | bits(imm12, 6, 0);
+ imm32 = ror(unrotated_value, 32, bits(imm12, 11, 7));
+ carry_out = Bit32(imm32, 31);
+ }
+ return imm32;
+}
+
+static inline uint32_t ThumbExpandImm(uint32_t opcode)
+{
+ // 'carry_in' argument to following function call does not affect the imm32 result.
+ uint32_t carry_in = 0;
+ uint32_t carry_out;
+ return ThumbExpandImm_C(opcode, carry_in, carry_out);
+}
+
+// imm32 = ZeroExtend(i:imm3:imm8, 32)
+static inline uint32_t ThumbImm12(uint32_t opcode)
+{
+ const uint32_t i = bit(opcode, 26);
+ const uint32_t imm3 = bits(opcode, 14, 12);
+ const uint32_t imm8 = bits(opcode, 7, 0);
+ const uint32_t imm12 = i << 11 | imm3 << 8 | imm8;
+ return imm12;
+}
+
+// imm32 = ZeroExtend(imm7:'00', 32)
+static inline uint32_t ThumbImm7Scaled(uint32_t opcode)
+{
+ const uint32_t imm7 = bits(opcode, 6, 0);
+ return imm7 * 4;
+}
+
+// imm32 = ZeroExtend(imm8:'00', 32)
+static inline uint32_t ThumbImm8Scaled(uint32_t opcode)
+{
+ const uint32_t imm8 = bits(opcode, 7, 0);
+ return imm8 * 4;
+}
+
+// This function performs the check for the register numbers 13 and 15 that are
+// not permitted for many Thumb register specifiers.
+static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; }
+
+} // namespace lldb_private
+
+#endif // lldb_ARMUtils_h_
diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
new file mode 100644
index 000000000000..0c95d66cef94
--- /dev/null
+++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.cpp
@@ -0,0 +1,279 @@
+//===-- DynamicRegisterInfo.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+#include "DynamicRegisterInfo.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Interpreter/Args.h"
+
+#ifndef LLDB_DISABLE_PYTHON
+#include "lldb/Interpreter/PythonDataObjects.h"
+#endif
+
+using namespace lldb;
+using namespace lldb_private;
+
+DynamicRegisterInfo::DynamicRegisterInfo () :
+ m_regs (),
+ m_sets (),
+ m_set_reg_nums (),
+ m_set_names (),
+ m_reg_data_byte_size (0)
+{
+}
+
+DynamicRegisterInfo::DynamicRegisterInfo (const lldb_private::PythonDictionary &dict) :
+ m_regs (),
+ m_sets (),
+ m_set_reg_nums (),
+ m_set_names (),
+ m_reg_data_byte_size (0)
+{
+ SetRegisterInfo (dict);
+}
+
+DynamicRegisterInfo::~DynamicRegisterInfo ()
+{
+}
+
+
+size_t
+DynamicRegisterInfo::SetRegisterInfo (const lldb_private::PythonDictionary &dict)
+{
+#ifndef LLDB_DISABLE_PYTHON
+ PythonList sets (dict.GetItemForKey("sets"));
+ if (sets)
+ {
+ const uint32_t num_sets = sets.GetSize();
+ for (uint32_t i=0; i<num_sets; ++i)
+ {
+ PythonString py_set_name(sets.GetItemAtIndex(i));
+ ConstString set_name;
+ if (py_set_name)
+ set_name.SetCString(py_set_name.GetString());
+ if (set_name)
+ {
+ RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL };
+ m_sets.push_back (new_set);
+ }
+ else
+ {
+ Clear();
+ return 0;
+ }
+ }
+ m_set_reg_nums.resize(m_sets.size());
+ }
+ PythonList regs (dict.GetItemForKey("registers"));
+ if (regs)
+ {
+ const uint32_t num_regs = regs.GetSize();
+ PythonString name_pystr("name");
+ PythonString altname_pystr("alt-name");
+ PythonString bitsize_pystr("bitsize");
+ PythonString offset_pystr("offset");
+ PythonString encoding_pystr("encoding");
+ PythonString format_pystr("format");
+ PythonString set_pystr("set");
+ PythonString gcc_pystr("gcc");
+ PythonString dwarf_pystr("dwarf");
+ PythonString generic_pystr("generic");
+ for (uint32_t i=0; i<num_regs; ++i)
+ {
+ PythonDictionary reg_info_dict(regs.GetItemAtIndex(i));
+ if (reg_info_dict)
+ {
+ // { 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 2, 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', },
+ RegisterInfo reg_info;
+ bzero (&reg_info, sizeof(reg_info));
+
+ reg_info.name = ConstString (reg_info_dict.GetItemForKeyAsString(name_pystr)).GetCString();
+ if (reg_info.name == NULL)
+ {
+ Clear();
+ return 0;
+ }
+
+ reg_info.alt_name = ConstString (reg_info_dict.GetItemForKeyAsString(altname_pystr)).GetCString();
+
+ reg_info.byte_offset = reg_info_dict.GetItemForKeyAsInteger(offset_pystr, UINT32_MAX);
+
+ if (reg_info.byte_offset == UINT32_MAX)
+ {
+ Clear();
+ return 0;
+ }
+ reg_info.byte_size = reg_info_dict.GetItemForKeyAsInteger(bitsize_pystr, 0) / 8;
+
+ if (reg_info.byte_size == 0)
+ {
+ Clear();
+ return 0;
+ }
+
+ const char *format_cstr = reg_info_dict.GetItemForKeyAsString(format_pystr);
+ if (format_cstr)
+ {
+ if (Args::StringToFormat(format_cstr, reg_info.format, NULL).Fail())
+ {
+ Clear();
+ return 0;
+ }
+ }
+ else
+ reg_info.format = eFormatHex;
+
+ const char *encoding_cstr = reg_info_dict.GetItemForKeyAsString(encoding_pystr);
+ if (encoding_cstr)
+ reg_info.encoding = Args::StringToEncoding (encoding_cstr, eEncodingUint);
+ else
+ reg_info.encoding = eEncodingUint;
+
+ const int64_t set = reg_info_dict.GetItemForKeyAsInteger(set_pystr, -1);
+ if (set >= m_sets.size())
+ {
+ Clear();
+ return 0;
+ }
+
+ reg_info.kinds[lldb::eRegisterKindLLDB] = i;
+ reg_info.kinds[lldb::eRegisterKindGDB] = i;
+ reg_info.kinds[lldb::eRegisterKindGCC] = reg_info_dict.GetItemForKeyAsInteger(gcc_pystr, LLDB_INVALID_REGNUM);
+ reg_info.kinds[lldb::eRegisterKindDWARF] = reg_info_dict.GetItemForKeyAsInteger(dwarf_pystr, LLDB_INVALID_REGNUM);
+ reg_info.kinds[lldb::eRegisterKindGeneric] = Args::StringToGenericRegister (reg_info_dict.GetItemForKeyAsString(generic_pystr));
+ const size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size;
+ if (m_reg_data_byte_size < end_reg_offset)
+ m_reg_data_byte_size = end_reg_offset;
+
+ m_regs.push_back (reg_info);
+ m_set_reg_nums[set].push_back(i);
+
+ }
+ else
+ {
+ Clear();
+ return 0;
+ }
+ }
+ Finalize ();
+ }
+#endif
+ return 0;
+}
+
+
+void
+DynamicRegisterInfo::AddRegister (RegisterInfo &reg_info,
+ ConstString &reg_name,
+ ConstString &reg_alt_name,
+ ConstString &set_name)
+{
+ const uint32_t reg_num = m_regs.size();
+ reg_info.name = reg_name.AsCString();
+ assert (reg_info.name);
+ reg_info.alt_name = reg_alt_name.AsCString(NULL);
+ m_regs.push_back (reg_info);
+ uint32_t set = GetRegisterSetIndexByName (set_name, true);
+ assert (set < m_sets.size());
+ assert (set < m_set_reg_nums.size());
+ assert (set < m_set_names.size());
+ m_set_reg_nums[set].push_back(reg_num);
+ size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size;
+ if (m_reg_data_byte_size < end_reg_offset)
+ m_reg_data_byte_size = end_reg_offset;
+}
+
+void
+DynamicRegisterInfo::Finalize ()
+{
+ for (uint32_t set = 0; set < m_sets.size(); ++set)
+ {
+ assert (m_sets.size() == m_set_reg_nums.size());
+ m_sets[set].num_registers = m_set_reg_nums[set].size();
+ m_sets[set].registers = &m_set_reg_nums[set][0];
+ }
+}
+
+size_t
+DynamicRegisterInfo::GetNumRegisters() const
+{
+ return m_regs.size();
+}
+
+size_t
+DynamicRegisterInfo::GetNumRegisterSets() const
+{
+ return m_sets.size();
+}
+
+size_t
+DynamicRegisterInfo::GetRegisterDataByteSize() const
+{
+ return m_reg_data_byte_size;
+}
+
+const RegisterInfo *
+DynamicRegisterInfo::GetRegisterInfoAtIndex (uint32_t i) const
+{
+ if (i < m_regs.size())
+ return &m_regs[i];
+ return NULL;
+}
+
+const RegisterSet *
+DynamicRegisterInfo::GetRegisterSet (uint32_t i) const
+{
+ if (i < m_sets.size())
+ return &m_sets[i];
+ return NULL;
+}
+
+uint32_t
+DynamicRegisterInfo::GetRegisterSetIndexByName (ConstString &set_name, bool can_create)
+{
+ name_collection::iterator pos, end = m_set_names.end();
+ for (pos = m_set_names.begin(); pos != end; ++pos)
+ {
+ if (*pos == set_name)
+ return std::distance (m_set_names.begin(), pos);
+ }
+
+ m_set_names.push_back(set_name);
+ m_set_reg_nums.resize(m_set_reg_nums.size()+1);
+ RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL };
+ m_sets.push_back (new_set);
+ return m_sets.size() - 1;
+}
+
+uint32_t
+DynamicRegisterInfo::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const
+{
+ reg_collection::const_iterator pos, end = m_regs.end();
+ for (pos = m_regs.begin(); pos != end; ++pos)
+ {
+ if (pos->kinds[kind] == num)
+ return std::distance (m_regs.begin(), pos);
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
+void
+DynamicRegisterInfo::Clear()
+{
+ m_regs.clear();
+ m_sets.clear();
+ m_set_reg_nums.clear();
+ m_set_names.clear();
+}
diff --git a/source/Plugins/Process/Utility/DynamicRegisterInfo.h b/source/Plugins/Process/Utility/DynamicRegisterInfo.h
new file mode 100644
index 000000000000..a11cd333545f
--- /dev/null
+++ b/source/Plugins/Process/Utility/DynamicRegisterInfo.h
@@ -0,0 +1,85 @@
+//===-- DynamicRegisterInfo.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_DynamicRegisterInfo_h_
+#define lldb_DynamicRegisterInfo_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ConstString.h"
+
+class DynamicRegisterInfo
+{
+public:
+ DynamicRegisterInfo ();
+
+ DynamicRegisterInfo (const lldb_private::PythonDictionary &dict);
+
+ virtual
+ ~DynamicRegisterInfo ();
+
+ size_t
+ SetRegisterInfo (const lldb_private::PythonDictionary &dict);
+
+ void
+ AddRegister (lldb_private::RegisterInfo &reg_info,
+ lldb_private::ConstString &reg_name,
+ lldb_private::ConstString &reg_alt_name,
+ lldb_private::ConstString &set_name);
+
+ void
+ Finalize ();
+
+ size_t
+ GetNumRegisters() const;
+
+ size_t
+ GetNumRegisterSets() const;
+
+ size_t
+ GetRegisterDataByteSize() const;
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t i) const;
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet (uint32_t i) const;
+
+ uint32_t
+ GetRegisterSetIndexByName (lldb_private::ConstString &set_name, bool can_create);
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const;
+
+ void
+ Clear();
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from DynamicRegisterInfo can see and modify these
+ //------------------------------------------------------------------
+ typedef std::vector <lldb_private::RegisterInfo> reg_collection;
+ typedef std::vector <lldb_private::RegisterSet> set_collection;
+ typedef std::vector <uint32_t> reg_num_collection;
+ typedef std::vector <reg_num_collection> set_reg_num_collection;
+ typedef std::vector <lldb_private::ConstString> name_collection;
+
+ reg_collection m_regs;
+ set_collection m_sets;
+ set_reg_num_collection m_set_reg_nums;
+ name_collection m_set_names;
+ size_t m_reg_data_byte_size; // The number of bytes required to store all registers
+};
+
+#endif // lldb_DynamicRegisterInfo_h_
diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
new file mode 100644
index 000000000000..499d6d766150
--- /dev/null
+++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
@@ -0,0 +1,274 @@
+//===-- InferiorCallPOSIX.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InferiorCallPOSIX.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+
+#include <sys/mman.h>
+
+using namespace lldb;
+using namespace lldb_private;
+
+bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
+ addr_t addr, addr_t length, unsigned prot,
+ unsigned flags, addr_t fd, addr_t offset) {
+ Thread *thread = process->GetThreadList().GetSelectedThread().get();
+ if (thread == NULL)
+ return false;
+
+ const bool append = true;
+ const bool include_symbols = true;
+ const bool include_inlines = false;
+ SymbolContextList sc_list;
+ const uint32_t count
+ = process->GetTarget().GetImages().FindFunctions (ConstString ("mmap"),
+ eFunctionNameTypeFull,
+ include_symbols,
+ include_inlines,
+ append,
+ sc_list);
+ if (count > 0)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(0, sc))
+ {
+ const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol;
+ const bool use_inline_block_range = false;
+ const bool stop_other_threads = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ const bool try_all_threads = true;
+ const uint32_t timeout_usec = 500000;
+
+ addr_t prot_arg, flags_arg = 0;
+ if (prot == eMmapProtNone)
+ prot_arg = PROT_NONE;
+ else {
+ prot_arg = 0;
+ if (prot & eMmapProtExec)
+ prot_arg |= PROT_EXEC;
+ if (prot & eMmapProtRead)
+ prot_arg |= PROT_READ;
+ if (prot & eMmapProtWrite)
+ prot_arg |= PROT_WRITE;
+ }
+
+ if (flags & eMmapFlagsPrivate)
+ flags_arg |= MAP_PRIVATE;
+ if (flags & eMmapFlagsAnon)
+ flags_arg |= MAP_ANON;
+
+ AddressRange mmap_range;
+ if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, mmap_range))
+ {
+ ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
+ ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ ThreadPlanCallFunction *call_function_thread_plan
+ = new ThreadPlanCallFunction (*thread,
+ mmap_range.GetBaseAddress(),
+ clang_void_ptr_type,
+ stop_other_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ &addr,
+ &length,
+ &prot_arg,
+ &flags_arg,
+ &fd,
+ &offset);
+ lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
+ if (call_plan_sp)
+ {
+ StreamFile error_strm;
+ // This plan is a utility plan, so set it to discard itself when done.
+ call_plan_sp->SetIsMasterPlan (true);
+ call_plan_sp->SetOkayToDiscard(true);
+
+ StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
+ if (frame)
+ {
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext (exe_ctx);
+ ExecutionResults result = process->RunThreadPlan (exe_ctx,
+ call_plan_sp,
+ stop_other_threads,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ error_strm);
+ if (result == eExecutionCompleted)
+ {
+
+ allocated_addr = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+ if (process->GetAddressByteSize() == 4)
+ {
+ if (allocated_addr == UINT32_MAX)
+ return false;
+ }
+ else if (process->GetAddressByteSize() == 8)
+ {
+ if (allocated_addr == UINT64_MAX)
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr,
+ addr_t length) {
+ Thread *thread = process->GetThreadList().GetSelectedThread().get();
+ if (thread == NULL)
+ return false;
+
+ const bool append = true;
+ const bool include_symbols = true;
+ const bool include_inlines = false;
+ SymbolContextList sc_list;
+ const uint32_t count
+ = process->GetTarget().GetImages().FindFunctions (ConstString ("munmap"),
+ eFunctionNameTypeFull,
+ include_symbols,
+ include_inlines,
+ append,
+ sc_list);
+ if (count > 0)
+ {
+ SymbolContext sc;
+ if (sc_list.GetContextAtIndex(0, sc))
+ {
+ const uint32_t range_scope = eSymbolContextFunction | eSymbolContextSymbol;
+ const bool use_inline_block_range = false;
+ const bool stop_other_threads = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ const bool try_all_threads = true;
+ const uint32_t timeout_usec = 500000;
+
+ AddressRange munmap_range;
+ if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, munmap_range))
+ {
+ lldb::ThreadPlanSP call_plan_sp (new ThreadPlanCallFunction (*thread,
+ munmap_range.GetBaseAddress(),
+ ClangASTType(),
+ stop_other_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ &addr,
+ &length));
+ if (call_plan_sp)
+ {
+ StreamFile error_strm;
+ // This plan is a utility plan, so set it to discard itself when done.
+ call_plan_sp->SetIsMasterPlan (true);
+ call_plan_sp->SetOkayToDiscard(true);
+
+ StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
+ if (frame)
+ {
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext (exe_ctx);
+ ExecutionResults result = process->RunThreadPlan (exe_ctx,
+ call_plan_sp,
+ stop_other_threads,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ error_strm);
+ if (result == eExecutionCompleted)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+bool lldb_private::InferiorCall(Process *process, const Address *address, addr_t &returned_func) {
+ Thread *thread = process->GetThreadList().GetSelectedThread().get();
+ if (thread == NULL || address == NULL)
+ return false;
+
+ const bool stop_other_threads = true;
+ const bool unwind_on_error = true;
+ const bool ignore_breakpoints = true;
+ const bool try_all_threads = true;
+ const uint32_t timeout_usec = 500000;
+
+ ClangASTContext *clang_ast_context = process->GetTarget().GetScratchClangASTContext();
+ ClangASTType clang_void_ptr_type = clang_ast_context->GetBasicType(eBasicTypeVoid).GetPointerType();
+ ThreadPlanCallFunction *call_function_thread_plan
+ = new ThreadPlanCallFunction (*thread,
+ *address,
+ clang_void_ptr_type,
+ stop_other_threads,
+ unwind_on_error,
+ ignore_breakpoints);
+ lldb::ThreadPlanSP call_plan_sp (call_function_thread_plan);
+ if (call_plan_sp)
+ {
+ StreamFile error_strm;
+ // This plan is a utility plan, so set it to discard itself when done.
+ call_plan_sp->SetIsMasterPlan (true);
+ call_plan_sp->SetOkayToDiscard(true);
+
+ StackFrame *frame = thread->GetStackFrameAtIndex (0).get();
+ if (frame)
+ {
+ ExecutionContext exe_ctx;
+ frame->CalculateExecutionContext (exe_ctx);
+ ExecutionResults result = process->RunThreadPlan (exe_ctx,
+ call_plan_sp,
+ stop_other_threads,
+ try_all_threads,
+ unwind_on_error,
+ ignore_breakpoints,
+ timeout_usec,
+ error_strm);
+ if (result == eExecutionCompleted)
+ {
+ returned_func = call_plan_sp->GetReturnValueObject()->GetValueAsUnsigned(LLDB_INVALID_ADDRESS);
+
+ if (process->GetAddressByteSize() == 4)
+ {
+ if (returned_func == UINT32_MAX)
+ return false;
+ }
+ else if (process->GetAddressByteSize() == 8)
+ {
+ if (returned_func == UINT64_MAX)
+ return false;
+ }
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
diff --git a/source/Plugins/Process/Utility/InferiorCallPOSIX.h b/source/Plugins/Process/Utility/InferiorCallPOSIX.h
new file mode 100644
index 000000000000..d8b6d0ed57fd
--- /dev/null
+++ b/source/Plugins/Process/Utility/InferiorCallPOSIX.h
@@ -0,0 +1,43 @@
+//===-- InferiorCallPOSIX.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_InferiorCallPOSIX_h_
+#define lldb_InferiorCallPOSIX_h_
+
+// Inferior execution of POSIX functions.
+
+#include "lldb/lldb-types.h"
+
+namespace lldb_private {
+
+class Process;
+
+enum MmapProt {
+ eMmapProtNone = 0,
+ eMmapProtExec = 1,
+ eMmapProtRead = 2,
+ eMmapProtWrite = 4
+};
+
+enum MmapFlags {
+ eMmapFlagsPrivate = 1,
+ eMmapFlagsAnon = 2
+};
+
+bool InferiorCallMmap(Process *proc, lldb::addr_t &allocated_addr,
+ lldb::addr_t addr, lldb::addr_t length, unsigned prot,
+ unsigned flags, lldb::addr_t fd, lldb::addr_t offset);
+
+bool InferiorCallMunmap(Process *proc, lldb::addr_t addr, lldb::addr_t length);
+
+bool InferiorCall(Process *proc, const Address *address, lldb::addr_t &returned_func);
+
+} // namespace lldb_private
+
+#endif // lldb_InferiorCallPOSIX_h_
diff --git a/source/Plugins/Process/Utility/InstructionUtils.h b/source/Plugins/Process/Utility/InstructionUtils.h
new file mode 100644
index 000000000000..4bb644e6efe6
--- /dev/null
+++ b/source/Plugins/Process/Utility/InstructionUtils.h
@@ -0,0 +1,136 @@
+//===-- InstructionUtils.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_InstructionUtils_h_
+#define lldb_InstructionUtils_h_
+
+// Common utilities for manipulating instruction bit fields.
+
+namespace lldb_private {
+
+// Return the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 64-bit unsigned value.
+static inline uint64_t
+Bits64 (const uint64_t bits, const uint32_t msbit, const uint32_t lsbit)
+{
+ assert(msbit < 64 && lsbit <= msbit);
+ return (bits >> lsbit) & ((1u << (msbit - lsbit + 1)) - 1);
+}
+
+// Return the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 32-bit unsigned value.
+static inline uint32_t
+Bits32 (const uint32_t bits, const uint32_t msbit, const uint32_t lsbit)
+{
+ assert(msbit < 32 && lsbit <= msbit);
+ return (bits >> lsbit) & ((1u << (msbit - lsbit + 1)) - 1);
+}
+
+// Return the bit value from the 'bit' position of a 32-bit unsigned value.
+static inline uint32_t
+Bit32 (const uint32_t bits, const uint32_t bit)
+{
+ return (bits >> bit) & 1u;
+}
+
+static inline uint64_t
+Bit64 (const uint64_t bits, const uint32_t bit)
+{
+ return (bits >> bit) & 1ull;
+}
+
+// Set the bit field(s) from the most significant bit (msbit) to the
+// least significant bit (lsbit) of a 32-bit unsigned value to 'val'.
+static inline void
+SetBits32(uint32_t &bits, const uint32_t msbit, const uint32_t lsbit, const uint32_t val)
+{
+ assert(msbit < 32 && lsbit < 32 && msbit >= lsbit);
+ uint32_t mask = ((1u << (msbit - lsbit + 1)) - 1);
+ bits &= ~(mask << lsbit);
+ bits |= (val & mask) << lsbit;
+}
+
+// Set the 'bit' position of a 32-bit unsigned value to 'val'.
+static inline void
+SetBit32(uint32_t &bits, const uint32_t bit, const uint32_t val)
+{
+ SetBits32(bits, bit, bit, val);
+}
+
+// Rotate a 32-bit unsigned value right by the specified amount.
+static inline uint32_t
+Rotr32 (uint32_t bits, uint32_t amt)
+{
+ assert(amt < 32 && "Invalid rotate amount");
+ return (bits >> amt) | (bits << ((32-amt)&31));
+}
+
+// Rotate a 32-bit unsigned value left by the specified amount.
+static inline uint32_t
+Rotl32 (uint32_t bits, uint32_t amt)
+{
+ assert(amt < 32 && "Invalid rotate amount");
+ return (bits << amt) | (bits >> ((32-amt)&31));
+}
+
+// Create a mask that starts at bit zero and includes "bit"
+static inline uint64_t
+MaskUpToBit (const uint64_t bit)
+{
+ return (1ull << (bit + 1ull)) - 1ull;
+}
+
+// Return an integer result equal to the number of bits of x that are ones.
+static inline uint32_t
+BitCount (uint64_t x)
+{
+ // c accumulates the total bits set in x
+ uint32_t c;
+ for (c = 0; x; ++c)
+ {
+ x &= x - 1; // clear the least significant bit set
+ }
+ return c;
+}
+
+static inline bool
+BitIsSet (const uint64_t value, const uint64_t bit)
+{
+ return (value & (1ull << bit)) != 0;
+}
+
+static inline bool
+BitIsClear (const uint64_t value, const uint64_t bit)
+{
+ return (value & (1ull << bit)) == 0;
+}
+
+static inline uint64_t
+UnsignedBits (const uint64_t value, const uint64_t msbit, const uint64_t lsbit)
+{
+ uint64_t result = value >> lsbit;
+ result &= MaskUpToBit (msbit - lsbit);
+ return result;
+}
+
+static inline int64_t
+SignedBits (const uint64_t value, const uint64_t msbit, const uint64_t lsbit)
+{
+ uint64_t result = UnsignedBits (value, msbit, lsbit);
+ if (BitIsSet(value, msbit))
+ {
+ // Sign extend
+ result |= ~MaskUpToBit (msbit - lsbit);
+ }
+ return result;
+}
+
+} // namespace lldb_private
+
+#endif // lldb_InstructionUtils_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
new file mode 100644
index 000000000000..4d77b6f20fdc
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.cpp
@@ -0,0 +1,1226 @@
+//===-- RegisterContextDarwin_arm.cpp ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+#include "RegisterContextDarwin_arm.h"
+
+// C Includes
+#include <mach/mach_types.h>
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+#include "Plugins/Process/Utility/InstructionUtils.h"
+
+// Support building against older versions of LLVM, this macro was added
+// recently.
+#ifndef LLVM_EXTENSION
+#define LLVM_EXTENSION
+#endif
+
+// Project includes
+#include "ARM_GCC_Registers.h"
+#include "ARM_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum
+{
+ gpr_r0 = 0,
+ gpr_r1,
+ gpr_r2,
+ gpr_r3,
+ gpr_r4,
+ gpr_r5,
+ gpr_r6,
+ gpr_r7,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13, gpr_sp = gpr_r13,
+ gpr_r14, gpr_lr = gpr_r14,
+ gpr_r15, gpr_pc = gpr_r15,
+ gpr_cpsr,
+
+ fpu_s0,
+ fpu_s1,
+ fpu_s2,
+ fpu_s3,
+ fpu_s4,
+ fpu_s5,
+ fpu_s6,
+ fpu_s7,
+ fpu_s8,
+ fpu_s9,
+ fpu_s10,
+ fpu_s11,
+ fpu_s12,
+ fpu_s13,
+ fpu_s14,
+ fpu_s15,
+ fpu_s16,
+ fpu_s17,
+ fpu_s18,
+ fpu_s19,
+ fpu_s20,
+ fpu_s21,
+ fpu_s22,
+ fpu_s23,
+ fpu_s24,
+ fpu_s25,
+ fpu_s26,
+ fpu_s27,
+ fpu_s28,
+ fpu_s29,
+ fpu_s30,
+ fpu_s31,
+ fpu_fpscr,
+
+ exc_exception,
+ exc_fsr,
+ exc_far,
+
+ dbg_bvr0,
+ dbg_bvr1,
+ dbg_bvr2,
+ dbg_bvr3,
+ dbg_bvr4,
+ dbg_bvr5,
+ dbg_bvr6,
+ dbg_bvr7,
+ dbg_bvr8,
+ dbg_bvr9,
+ dbg_bvr10,
+ dbg_bvr11,
+ dbg_bvr12,
+ dbg_bvr13,
+ dbg_bvr14,
+ dbg_bvr15,
+
+ dbg_bcr0,
+ dbg_bcr1,
+ dbg_bcr2,
+ dbg_bcr3,
+ dbg_bcr4,
+ dbg_bcr5,
+ dbg_bcr6,
+ dbg_bcr7,
+ dbg_bcr8,
+ dbg_bcr9,
+ dbg_bcr10,
+ dbg_bcr11,
+ dbg_bcr12,
+ dbg_bcr13,
+ dbg_bcr14,
+ dbg_bcr15,
+
+ dbg_wvr0,
+ dbg_wvr1,
+ dbg_wvr2,
+ dbg_wvr3,
+ dbg_wvr4,
+ dbg_wvr5,
+ dbg_wvr6,
+ dbg_wvr7,
+ dbg_wvr8,
+ dbg_wvr9,
+ dbg_wvr10,
+ dbg_wvr11,
+ dbg_wvr12,
+ dbg_wvr13,
+ dbg_wvr14,
+ dbg_wvr15,
+
+ dbg_wcr0,
+ dbg_wcr1,
+ dbg_wcr2,
+ dbg_wcr3,
+ dbg_wcr4,
+ dbg_wcr5,
+ dbg_wcr6,
+ dbg_wcr7,
+ dbg_wcr8,
+ dbg_wcr9,
+ dbg_wcr10,
+ dbg_wcr11,
+ dbg_wcr12,
+ dbg_wcr13,
+ dbg_wcr14,
+ dbg_wcr15,
+
+ k_num_registers
+};
+
+
+RegisterContextDarwin_arm::RegisterContextDarwin_arm(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContext(thread, concrete_frame_idx),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_arm::~RegisterContextDarwin_arm()
+{
+}
+
+
+#define GPR_OFFSET(idx) ((idx) * 4)
+#define FPU_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextDarwin_arm::GPR))
+#define EXC_OFFSET(idx) ((idx) * 4 + sizeof (RegisterContextDarwin_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU))
+#define DBG_OFFSET(reg) ((LLVM_EXTENSION offsetof (RegisterContextDarwin_arm::DBG, reg) + sizeof (RegisterContextDarwin_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU) + sizeof (RegisterContextDarwin_arm::EXC)))
+
+#define DEFINE_DBG(reg, i) #reg, NULL, sizeof(((RegisterContextDarwin_arm::DBG *)NULL)->reg[i]), DBG_OFFSET(reg[i]), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, dbg_##reg##i }, NULL, NULL
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_arm::GPR) + sizeof (RegisterContextDarwin_arm::FPU) + sizeof (RegisterContextDarwin_arm::EXC))
+
+static RegisterInfo g_register_infos[] = {
+// General purpose registers
+// NAME ALT SZ OFFSET ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB NATIVE VALUE REGS INVALIDATE REGS
+// ====== ======= == ============= ============= ============ =============== =============== ========================= ===================== ============= ========== ===============
+{ "r0", NULL, 4, GPR_OFFSET(0), eEncodingUint, eFormatHex, { gcc_r0, dwarf_r0, LLDB_INVALID_REGNUM, gdb_arm_r0, gpr_r0 }, NULL, NULL},
+{ "r1", NULL, 4, GPR_OFFSET(1), eEncodingUint, eFormatHex, { gcc_r1, dwarf_r1, LLDB_INVALID_REGNUM, gdb_arm_r1, gpr_r1 }, NULL, NULL},
+{ "r2", NULL, 4, GPR_OFFSET(2), eEncodingUint, eFormatHex, { gcc_r2, dwarf_r2, LLDB_INVALID_REGNUM, gdb_arm_r2, gpr_r2 }, NULL, NULL},
+{ "r3", NULL, 4, GPR_OFFSET(3), eEncodingUint, eFormatHex, { gcc_r3, dwarf_r3, LLDB_INVALID_REGNUM, gdb_arm_r3, gpr_r3 }, NULL, NULL},
+{ "r4", NULL, 4, GPR_OFFSET(4), eEncodingUint, eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, gdb_arm_r4, gpr_r4 }, NULL, NULL},
+{ "r5", NULL, 4, GPR_OFFSET(5), eEncodingUint, eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, gdb_arm_r5, gpr_r5 }, NULL, NULL},
+{ "r6", NULL, 4, GPR_OFFSET(6), eEncodingUint, eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, gdb_arm_r6, gpr_r6 }, NULL, NULL},
+{ "r7", NULL, 4, GPR_OFFSET(7), eEncodingUint, eFormatHex, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, gdb_arm_r7, gpr_r7 }, NULL, NULL},
+{ "r8", NULL, 4, GPR_OFFSET(8), eEncodingUint, eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, gdb_arm_r8, gpr_r8 }, NULL, NULL},
+{ "r9", NULL, 4, GPR_OFFSET(9), eEncodingUint, eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, gdb_arm_r9, gpr_r9 }, NULL, NULL},
+{ "r10", NULL, 4, GPR_OFFSET(10), eEncodingUint, eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, gdb_arm_r10, gpr_r10 }, NULL, NULL},
+{ "r11", NULL, 4, GPR_OFFSET(11), eEncodingUint, eFormatHex, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM, gdb_arm_r11, gpr_r11 }, NULL, NULL},
+{ "r12", NULL, 4, GPR_OFFSET(12), eEncodingUint, eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, gdb_arm_r12, gpr_r12 }, NULL, NULL},
+{ "sp", "r13", 4, GPR_OFFSET(13), eEncodingUint, eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, gdb_arm_sp, gpr_sp }, NULL, NULL},
+{ "lr", "r14", 4, GPR_OFFSET(14), eEncodingUint, eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, gdb_arm_lr, gpr_lr }, NULL, NULL},
+{ "pc", "r15", 4, GPR_OFFSET(15), eEncodingUint, eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, gdb_arm_pc, gpr_pc }, NULL, NULL},
+{ "cpsr", "psr", 4, GPR_OFFSET(16), eEncodingUint, eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_REGNUM_GENERIC_FLAGS, gdb_arm_cpsr, gpr_cpsr }, NULL, NULL},
+
+{ "s0", NULL, 4, FPU_OFFSET(0), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, gdb_arm_s0, fpu_s0 }, NULL, NULL},
+{ "s1", NULL, 4, FPU_OFFSET(1), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, gdb_arm_s1, fpu_s1 }, NULL, NULL},
+{ "s2", NULL, 4, FPU_OFFSET(2), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, gdb_arm_s2, fpu_s2 }, NULL, NULL},
+{ "s3", NULL, 4, FPU_OFFSET(3), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, gdb_arm_s3, fpu_s3 }, NULL, NULL},
+{ "s4", NULL, 4, FPU_OFFSET(4), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, gdb_arm_s4, fpu_s4 }, NULL, NULL},
+{ "s5", NULL, 4, FPU_OFFSET(5), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, gdb_arm_s5, fpu_s5 }, NULL, NULL},
+{ "s6", NULL, 4, FPU_OFFSET(6), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, gdb_arm_s6, fpu_s6 }, NULL, NULL},
+{ "s7", NULL, 4, FPU_OFFSET(7), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, gdb_arm_s7, fpu_s7 }, NULL, NULL},
+{ "s8", NULL, 4, FPU_OFFSET(8), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, gdb_arm_s8, fpu_s8 }, NULL, NULL},
+{ "s9", NULL, 4, FPU_OFFSET(9), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, gdb_arm_s9, fpu_s9 }, NULL, NULL},
+{ "s10", NULL, 4, FPU_OFFSET(10), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, gdb_arm_s10, fpu_s10 }, NULL, NULL},
+{ "s11", NULL, 4, FPU_OFFSET(11), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, gdb_arm_s11, fpu_s11 }, NULL, NULL},
+{ "s12", NULL, 4, FPU_OFFSET(12), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, gdb_arm_s12, fpu_s12 }, NULL, NULL},
+{ "s13", NULL, 4, FPU_OFFSET(13), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, gdb_arm_s13, fpu_s13 }, NULL, NULL},
+{ "s14", NULL, 4, FPU_OFFSET(14), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, gdb_arm_s14, fpu_s14 }, NULL, NULL},
+{ "s15", NULL, 4, FPU_OFFSET(15), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, gdb_arm_s15, fpu_s15 }, NULL, NULL},
+{ "s16", NULL, 4, FPU_OFFSET(16), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, gdb_arm_s16, fpu_s16 }, NULL, NULL},
+{ "s17", NULL, 4, FPU_OFFSET(17), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, gdb_arm_s17, fpu_s17 }, NULL, NULL},
+{ "s18", NULL, 4, FPU_OFFSET(18), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, gdb_arm_s18, fpu_s18 }, NULL, NULL},
+{ "s19", NULL, 4, FPU_OFFSET(19), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, gdb_arm_s19, fpu_s19 }, NULL, NULL},
+{ "s20", NULL, 4, FPU_OFFSET(20), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, gdb_arm_s20, fpu_s20 }, NULL, NULL},
+{ "s21", NULL, 4, FPU_OFFSET(21), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, gdb_arm_s21, fpu_s21 }, NULL, NULL},
+{ "s22", NULL, 4, FPU_OFFSET(22), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, gdb_arm_s22, fpu_s22 }, NULL, NULL},
+{ "s23", NULL, 4, FPU_OFFSET(23), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, gdb_arm_s23, fpu_s23 }, NULL, NULL},
+{ "s24", NULL, 4, FPU_OFFSET(24), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, gdb_arm_s24, fpu_s24 }, NULL, NULL},
+{ "s25", NULL, 4, FPU_OFFSET(25), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, gdb_arm_s25, fpu_s25 }, NULL, NULL},
+{ "s26", NULL, 4, FPU_OFFSET(26), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, gdb_arm_s26, fpu_s26 }, NULL, NULL},
+{ "s27", NULL, 4, FPU_OFFSET(27), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, gdb_arm_s27, fpu_s27 }, NULL, NULL},
+{ "s28", NULL, 4, FPU_OFFSET(28), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, gdb_arm_s28, fpu_s28 }, NULL, NULL},
+{ "s29", NULL, 4, FPU_OFFSET(29), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, gdb_arm_s29, fpu_s29 }, NULL, NULL},
+{ "s30", NULL, 4, FPU_OFFSET(30), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, gdb_arm_s30, fpu_s30 }, NULL, NULL},
+{ "s31", NULL, 4, FPU_OFFSET(31), eEncodingIEEE754,eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, gdb_arm_s31, fpu_s31 }, NULL, NULL},
+{ "fpscr", NULL, 4, FPU_OFFSET(32), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, gdb_arm_fpscr, fpu_fpscr }, NULL, NULL},
+
+{ "exception",NULL, 4, EXC_OFFSET(0), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_exception }, NULL, NULL},
+{ "fsr", NULL, 4, EXC_OFFSET(1), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_fsr }, NULL, NULL},
+{ "far", NULL, 4, EXC_OFFSET(2), eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM,LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, exc_far }, NULL, NULL},
+
+{ DEFINE_DBG (bvr, 0) },
+{ DEFINE_DBG (bvr, 1) },
+{ DEFINE_DBG (bvr, 2) },
+{ DEFINE_DBG (bvr, 3) },
+{ DEFINE_DBG (bvr, 4) },
+{ DEFINE_DBG (bvr, 5) },
+{ DEFINE_DBG (bvr, 6) },
+{ DEFINE_DBG (bvr, 7) },
+{ DEFINE_DBG (bvr, 8) },
+{ DEFINE_DBG (bvr, 9) },
+{ DEFINE_DBG (bvr, 10) },
+{ DEFINE_DBG (bvr, 11) },
+{ DEFINE_DBG (bvr, 12) },
+{ DEFINE_DBG (bvr, 13) },
+{ DEFINE_DBG (bvr, 14) },
+{ DEFINE_DBG (bvr, 15) },
+
+{ DEFINE_DBG (bcr, 0) },
+{ DEFINE_DBG (bcr, 1) },
+{ DEFINE_DBG (bcr, 2) },
+{ DEFINE_DBG (bcr, 3) },
+{ DEFINE_DBG (bcr, 4) },
+{ DEFINE_DBG (bcr, 5) },
+{ DEFINE_DBG (bcr, 6) },
+{ DEFINE_DBG (bcr, 7) },
+{ DEFINE_DBG (bcr, 8) },
+{ DEFINE_DBG (bcr, 9) },
+{ DEFINE_DBG (bcr, 10) },
+{ DEFINE_DBG (bcr, 11) },
+{ DEFINE_DBG (bcr, 12) },
+{ DEFINE_DBG (bcr, 13) },
+{ DEFINE_DBG (bcr, 14) },
+{ DEFINE_DBG (bcr, 15) },
+
+{ DEFINE_DBG (wvr, 0) },
+{ DEFINE_DBG (wvr, 1) },
+{ DEFINE_DBG (wvr, 2) },
+{ DEFINE_DBG (wvr, 3) },
+{ DEFINE_DBG (wvr, 4) },
+{ DEFINE_DBG (wvr, 5) },
+{ DEFINE_DBG (wvr, 6) },
+{ DEFINE_DBG (wvr, 7) },
+{ DEFINE_DBG (wvr, 8) },
+{ DEFINE_DBG (wvr, 9) },
+{ DEFINE_DBG (wvr, 10) },
+{ DEFINE_DBG (wvr, 11) },
+{ DEFINE_DBG (wvr, 12) },
+{ DEFINE_DBG (wvr, 13) },
+{ DEFINE_DBG (wvr, 14) },
+{ DEFINE_DBG (wvr, 15) },
+
+{ DEFINE_DBG (wcr, 0) },
+{ DEFINE_DBG (wcr, 1) },
+{ DEFINE_DBG (wcr, 2) },
+{ DEFINE_DBG (wcr, 3) },
+{ DEFINE_DBG (wcr, 4) },
+{ DEFINE_DBG (wcr, 5) },
+{ DEFINE_DBG (wcr, 6) },
+{ DEFINE_DBG (wcr, 7) },
+{ DEFINE_DBG (wcr, 8) },
+{ DEFINE_DBG (wcr, 9) },
+{ DEFINE_DBG (wcr, 10) },
+{ DEFINE_DBG (wcr, 11) },
+{ DEFINE_DBG (wcr, 12) },
+{ DEFINE_DBG (wcr, 13) },
+{ DEFINE_DBG (wcr, 14) },
+{ DEFINE_DBG (wcr, 15) }
+};
+
+// General purpose registers
+static uint32_t
+g_gpr_regnums[] =
+{
+ gpr_r0,
+ gpr_r1,
+ gpr_r2,
+ gpr_r3,
+ gpr_r4,
+ gpr_r5,
+ gpr_r6,
+ gpr_r7,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_sp,
+ gpr_lr,
+ gpr_pc,
+ gpr_cpsr
+};
+
+// Floating point registers
+static uint32_t
+g_fpu_regnums[] =
+{
+ fpu_s0,
+ fpu_s1,
+ fpu_s2,
+ fpu_s3,
+ fpu_s4,
+ fpu_s5,
+ fpu_s6,
+ fpu_s7,
+ fpu_s8,
+ fpu_s9,
+ fpu_s10,
+ fpu_s11,
+ fpu_s12,
+ fpu_s13,
+ fpu_s14,
+ fpu_s15,
+ fpu_s16,
+ fpu_s17,
+ fpu_s18,
+ fpu_s19,
+ fpu_s20,
+ fpu_s21,
+ fpu_s22,
+ fpu_s23,
+ fpu_s24,
+ fpu_s25,
+ fpu_s26,
+ fpu_s27,
+ fpu_s28,
+ fpu_s29,
+ fpu_s30,
+ fpu_s31,
+ fpu_fpscr,
+};
+
+// Exception registers
+
+static uint32_t
+g_exc_regnums[] =
+{
+ exc_exception,
+ exc_fsr,
+ exc_far,
+};
+
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+
+void
+RegisterContextDarwin_arm::InvalidateAllRegisters ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextDarwin_arm::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_arm::GetRegisterInfoAtIndex (size_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+size_t
+RegisterContextDarwin_arm::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_arm::GetRegisterInfos ()
+{
+ return g_register_infos;
+}
+
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t);
+const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t);
+const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t);
+
+//----------------------------------------------------------------------
+// Register set definitions. The first definitions at register set index
+// of zero is for all registers, followed by other registers sets. The
+// register information for the all register set need not be filled in.
+//----------------------------------------------------------------------
+static const RegisterSet g_reg_sets[] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums },
+ { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums }
+};
+
+const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet);
+
+
+size_t
+RegisterContextDarwin_arm::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_arm::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Register information defintions for 32 bit i386.
+//----------------------------------------------------------------------
+int
+RegisterContextDarwin_arm::GetSetForNativeRegNum (int reg)
+{
+ if (reg < fpu_s0)
+ return GPRRegSet;
+ else if (reg < exc_exception)
+ return FPURegSet;
+ else if (reg < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+int
+RegisterContextDarwin_arm::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::ReadDBG (bool force)
+{
+ int set = DBGRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadDBG(GetThreadID(), set, dbg));
+ }
+ return GetError(DBGRegSet, Read);
+}
+
+int
+RegisterContextDarwin_arm::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError (set, Read, -1);
+ return GetError(GPRRegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError (set, Read, -1);
+ return GetError(FPURegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError (set, Read, -1);
+ return GetError(EXCRegSet, Write);
+}
+
+int
+RegisterContextDarwin_arm::WriteDBG ()
+{
+ int set = DBGRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return KERN_INVALID_ARGUMENT;
+ }
+ SetError (set, Write, DoWriteDBG(GetThreadID(), set, dbg));
+ SetError (set, Read, -1);
+ return GetError(DBGRegSet, Write);
+}
+
+
+int
+RegisterContextDarwin_arm::ReadRegisterSet (uint32_t set, bool force)
+{
+ switch (set)
+ {
+ case GPRRegSet: return ReadGPR(force);
+ case FPURegSet: return ReadFPU(force);
+ case EXCRegSet: return ReadEXC(force);
+ case DBGRegSet: return ReadDBG(force);
+ default: break;
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+int
+RegisterContextDarwin_arm::WriteRegisterSet (uint32_t set)
+{
+ // Make sure we have a valid context to set.
+ if (RegisterSetIsCached(set))
+ {
+ switch (set)
+ {
+ case GPRRegSet: return WriteGPR();
+ case FPURegSet: return WriteFPU();
+ case EXCRegSet: return WriteEXC();
+ case DBGRegSet: return WriteDBG();
+ default: break;
+ }
+ }
+ return KERN_INVALID_ARGUMENT;
+}
+
+void
+RegisterContextDarwin_arm::LogDBGRegisters (Log *log, const DBG& dbg)
+{
+ if (log)
+ {
+ for (uint32_t i=0; i<16; i++)
+ log->Printf("BVR%-2u/BCR%-2u = { 0x%8.8x, 0x%8.8x } WVR%-2u/WCR%-2u = { 0x%8.8x, 0x%8.8x }",
+ i, i, dbg.bvr[i], dbg.bcr[i],
+ i, i, dbg.wvr[i], dbg.wcr[i]);
+ }
+}
+
+
+bool
+RegisterContextDarwin_arm::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_arm::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_r0:
+ case gpr_r1:
+ case gpr_r2:
+ case gpr_r3:
+ case gpr_r4:
+ case gpr_r5:
+ case gpr_r6:
+ case gpr_r7:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ value.SetUInt32 (gpr.r[reg - gpr_r0]);
+ break;
+
+ case fpu_s0:
+ case fpu_s1:
+ case fpu_s2:
+ case fpu_s3:
+ case fpu_s4:
+ case fpu_s5:
+ case fpu_s6:
+ case fpu_s7:
+ case fpu_s8:
+ case fpu_s9:
+ case fpu_s10:
+ case fpu_s11:
+ case fpu_s12:
+ case fpu_s13:
+ case fpu_s14:
+ case fpu_s15:
+ case fpu_s16:
+ case fpu_s17:
+ case fpu_s18:
+ case fpu_s19:
+ case fpu_s20:
+ case fpu_s21:
+ case fpu_s22:
+ case fpu_s23:
+ case fpu_s24:
+ case fpu_s25:
+ case fpu_s26:
+ case fpu_s27:
+ case fpu_s28:
+ case fpu_s29:
+ case fpu_s30:
+ case fpu_s31:
+ value.SetUInt32 (fpu.floats.s[reg], RegisterValue::eTypeFloat);
+ break;
+
+ case fpu_fpscr:
+ value.SetUInt32 (fpu.fpscr);
+ break;
+
+ case exc_exception:
+ value.SetUInt32 (exc.exception);
+ break;
+ case exc_fsr:
+ value.SetUInt32 (exc.fsr);
+ break;
+ case exc_far:
+ value.SetUInt32 (exc.far);
+ break;
+
+ default:
+ value.SetValueToInvalid();
+ return false;
+
+ }
+ return true;
+}
+
+
+bool
+RegisterContextDarwin_arm::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != KERN_SUCCESS)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_r0:
+ case gpr_r1:
+ case gpr_r2:
+ case gpr_r3:
+ case gpr_r4:
+ case gpr_r5:
+ case gpr_r6:
+ case gpr_r7:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_sp:
+ case gpr_lr:
+ case gpr_pc:
+ case gpr_cpsr:
+ gpr.r[reg - gpr_r0] = value.GetAsUInt32();
+ break;
+
+ case fpu_s0:
+ case fpu_s1:
+ case fpu_s2:
+ case fpu_s3:
+ case fpu_s4:
+ case fpu_s5:
+ case fpu_s6:
+ case fpu_s7:
+ case fpu_s8:
+ case fpu_s9:
+ case fpu_s10:
+ case fpu_s11:
+ case fpu_s12:
+ case fpu_s13:
+ case fpu_s14:
+ case fpu_s15:
+ case fpu_s16:
+ case fpu_s17:
+ case fpu_s18:
+ case fpu_s19:
+ case fpu_s20:
+ case fpu_s21:
+ case fpu_s22:
+ case fpu_s23:
+ case fpu_s24:
+ case fpu_s25:
+ case fpu_s26:
+ case fpu_s27:
+ case fpu_s28:
+ case fpu_s29:
+ case fpu_s30:
+ case fpu_s31:
+ fpu.floats.s[reg] = value.GetAsUInt32();
+ break;
+
+ case fpu_fpscr:
+ fpu.fpscr = value.GetAsUInt32();
+ break;
+
+ case exc_exception:
+ exc.exception = value.GetAsUInt32();
+ break;
+ case exc_fsr:
+ exc.fsr = value.GetAsUInt32();
+ break;
+ case exc_far:
+ exc.far = value.GetAsUInt32();
+ break;
+
+ default:
+ return false;
+
+ }
+ return WriteRegisterSet(set) == KERN_SUCCESS;
+}
+
+bool
+RegisterContextDarwin_arm::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == KERN_SUCCESS &&
+ ReadFPU (false) == KERN_SUCCESS &&
+ ReadEXC (false) == KERN_SUCCESS)
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy (dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextDarwin_arm::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy (&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy (&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy (&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteFPU() == KERN_SUCCESS)
+ ++success_count;
+ if (WriteEXC() == KERN_SUCCESS)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+uint32_t
+RegisterContextDarwin_arm::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (reg)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_pc;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_sp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_r7;
+ case LLDB_REGNUM_GENERIC_RA: return gpr_lr;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_cpsr;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindDWARF)
+ {
+ switch (reg)
+ {
+ case dwarf_r0: return gpr_r0;
+ case dwarf_r1: return gpr_r1;
+ case dwarf_r2: return gpr_r2;
+ case dwarf_r3: return gpr_r3;
+ case dwarf_r4: return gpr_r4;
+ case dwarf_r5: return gpr_r5;
+ case dwarf_r6: return gpr_r6;
+ case dwarf_r7: return gpr_r7;
+ case dwarf_r8: return gpr_r8;
+ case dwarf_r9: return gpr_r9;
+ case dwarf_r10: return gpr_r10;
+ case dwarf_r11: return gpr_r11;
+ case dwarf_r12: return gpr_r12;
+ case dwarf_sp: return gpr_sp;
+ case dwarf_lr: return gpr_lr;
+ case dwarf_pc: return gpr_pc;
+ case dwarf_spsr: return gpr_cpsr;
+
+ case dwarf_s0: return fpu_s0;
+ case dwarf_s1: return fpu_s1;
+ case dwarf_s2: return fpu_s2;
+ case dwarf_s3: return fpu_s3;
+ case dwarf_s4: return fpu_s4;
+ case dwarf_s5: return fpu_s5;
+ case dwarf_s6: return fpu_s6;
+ case dwarf_s7: return fpu_s7;
+ case dwarf_s8: return fpu_s8;
+ case dwarf_s9: return fpu_s9;
+ case dwarf_s10: return fpu_s10;
+ case dwarf_s11: return fpu_s11;
+ case dwarf_s12: return fpu_s12;
+ case dwarf_s13: return fpu_s13;
+ case dwarf_s14: return fpu_s14;
+ case dwarf_s15: return fpu_s15;
+ case dwarf_s16: return fpu_s16;
+ case dwarf_s17: return fpu_s17;
+ case dwarf_s18: return fpu_s18;
+ case dwarf_s19: return fpu_s19;
+ case dwarf_s20: return fpu_s20;
+ case dwarf_s21: return fpu_s21;
+ case dwarf_s22: return fpu_s22;
+ case dwarf_s23: return fpu_s23;
+ case dwarf_s24: return fpu_s24;
+ case dwarf_s25: return fpu_s25;
+ case dwarf_s26: return fpu_s26;
+ case dwarf_s27: return fpu_s27;
+ case dwarf_s28: return fpu_s28;
+ case dwarf_s29: return fpu_s29;
+ case dwarf_s30: return fpu_s30;
+ case dwarf_s31: return fpu_s31;
+
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGCC)
+ {
+ switch (reg)
+ {
+ case gcc_r0: return gpr_r0;
+ case gcc_r1: return gpr_r1;
+ case gcc_r2: return gpr_r2;
+ case gcc_r3: return gpr_r3;
+ case gcc_r4: return gpr_r4;
+ case gcc_r5: return gpr_r5;
+ case gcc_r6: return gpr_r6;
+ case gcc_r7: return gpr_r7;
+ case gcc_r8: return gpr_r8;
+ case gcc_r9: return gpr_r9;
+ case gcc_r10: return gpr_r10;
+ case gcc_r11: return gpr_r11;
+ case gcc_r12: return gpr_r12;
+ case gcc_sp: return gpr_sp;
+ case gcc_lr: return gpr_lr;
+ case gcc_pc: return gpr_pc;
+ case gcc_cpsr: return gpr_cpsr;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+
+uint32_t
+RegisterContextDarwin_arm::NumSupportedHardwareBreakpoints ()
+{
+#if defined (__arm__)
+ // Set the init value to something that will let us know that we need to
+ // autodetect how many breakpoints are supported dynamically...
+ static uint32_t g_num_supported_hw_breakpoints = UINT32_MAX;
+ if (g_num_supported_hw_breakpoints == UINT32_MAX)
+ {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_breakpoints = 0;
+
+ uint32_t register_DBGDIDR;
+
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR));
+ g_num_supported_hw_breakpoints = Bits32 (register_DBGDIDR, 27, 24);
+ // Zero is reserved for the BRP count, so don't increment it if it is zero
+ if (g_num_supported_hw_breakpoints > 0)
+ g_num_supported_hw_breakpoints++;
+// if (log) log->Printf ("DBGDIDR=0x%8.8x (number BRP pairs = %u)", register_DBGDIDR, g_num_supported_hw_breakpoints);
+
+ }
+ return g_num_supported_hw_breakpoints;
+#else
+ // TODO: figure out remote case here!
+ return 6;
+#endif
+}
+
+uint32_t
+RegisterContextDarwin_arm::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ // Make sure our address isn't bogus
+ if (addr & 1)
+ return LLDB_INVALID_INDEX32;
+
+ int kret = ReadDBG (false);
+
+ if (kret == KERN_SUCCESS)
+ {
+ const uint32_t num_hw_breakpoints = NumSupportedHardwareBreakpoints();
+ uint32_t i;
+ for (i=0; i<num_hw_breakpoints; ++i)
+ {
+ if ((dbg.bcr[i] & BCR_ENABLE) == 0)
+ break; // We found an available hw breakpoint slot (in i)
+ }
+
+ // See if we found an available hw breakpoint slot above
+ if (i < num_hw_breakpoints)
+ {
+ // Make sure bits 1:0 are clear in our address
+ dbg.bvr[i] = addr & ~((lldb::addr_t)3);
+
+ if (size == 2 || addr & 2)
+ {
+ uint32_t byte_addr_select = (addr & 2) ? BAS_IMVA_2_3 : BAS_IMVA_0_1;
+
+ // We have a thumb breakpoint
+ // We have an ARM breakpoint
+ dbg.bcr[i] = BCR_M_IMVA_MATCH | // Stop on address mismatch
+ byte_addr_select | // Set the correct byte address select so we only trigger on the correct opcode
+ S_USER | // Which modes should this breakpoint stop in?
+ BCR_ENABLE; // Enable this hardware breakpoint
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (Thumb)",
+// addr,
+// size,
+// i,
+// i,
+// dbg.bvr[i],
+// dbg.bcr[i]);
+ }
+ else if (size == 4)
+ {
+ // We have an ARM breakpoint
+ dbg.bcr[i] = BCR_M_IMVA_MATCH | // Stop on address mismatch
+ BAS_IMVA_ALL | // Stop on any of the four bytes following the IMVA
+ S_USER | // Which modes should this breakpoint stop in?
+ BCR_ENABLE; // Enable this hardware breakpoint
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint( addr = %8.8p, size = %u ) - BVR%u/BCR%u = 0x%8.8x / 0x%8.8x (ARM)",
+// addr,
+// size,
+// i,
+// i,
+// dbg.bvr[i],
+// dbg.bcr[i]);
+ }
+
+ kret = WriteDBG();
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint() WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+// else
+// {
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareBreakpoint(addr = %8.8p, size = %u) => all hardware breakpoint resources are being used.", addr, size);
+// }
+ }
+
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextDarwin_arm::ClearHardwareBreakpoint (uint32_t hw_index)
+{
+ int kret = ReadDBG (false);
+
+ const uint32_t num_hw_points = NumSupportedHardwareBreakpoints();
+ if (kret == KERN_SUCCESS)
+ {
+ if (hw_index < num_hw_points)
+ {
+ dbg.bcr[hw_index] = 0;
+// if (log) log->Printf ("RegisterContextDarwin_arm::SetHardwareBreakpoint( %u ) - BVR%u = 0x%8.8x BCR%u = 0x%8.8x",
+// hw_index,
+// hw_index,
+// dbg.bvr[hw_index],
+// hw_index,
+// dbg.bcr[hw_index]);
+
+ kret = WriteDBG();
+
+ if (kret == KERN_SUCCESS)
+ return true;
+ }
+ }
+ return false;
+}
+
+uint32_t
+RegisterContextDarwin_arm::NumSupportedHardwareWatchpoints ()
+{
+#if defined (__arm__)
+ // Set the init value to something that will let us know that we need to
+ // autodetect how many watchpoints are supported dynamically...
+ static uint32_t g_num_supported_hw_watchpoints = UINT32_MAX;
+ if (g_num_supported_hw_watchpoints == UINT32_MAX)
+ {
+ // Set this to zero in case we can't tell if there are any HW breakpoints
+ g_num_supported_hw_watchpoints = 0;
+
+ uint32_t register_DBGDIDR;
+ asm("mrc p14, 0, %0, c0, c0, 0" : "=r" (register_DBGDIDR));
+ g_num_supported_hw_watchpoints = Bits32 (register_DBGDIDR, 31, 28) + 1;
+// if (log) log->Printf ("DBGDIDR=0x%8.8x (number WRP pairs = %u)", register_DBGDIDR, g_num_supported_hw_watchpoints);
+ }
+ return g_num_supported_hw_watchpoints;
+#else
+ // TODO: figure out remote case here!
+ return 2;
+#endif
+}
+
+
+uint32_t
+RegisterContextDarwin_arm::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
+{
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint(addr = %8.8p, size = %u, read = %u, write = %u)", addr, size, read, write);
+
+ const uint32_t num_hw_watchpoints = NumSupportedHardwareWatchpoints();
+
+ // Can't watch zero bytes
+ if (size == 0)
+ return LLDB_INVALID_INDEX32;
+
+ // We must watch for either read or write
+ if (read == false && write == false)
+ return LLDB_INVALID_INDEX32;
+
+ // Can't watch more than 4 bytes per WVR/WCR pair
+ if (size > 4)
+ return LLDB_INVALID_INDEX32;
+
+ // We can only watch up to four bytes that follow a 4 byte aligned address
+ // per watchpoint register pair. Since we have at most so we can only watch
+ // until the next 4 byte boundary and we need to make sure we can properly
+ // encode this.
+ uint32_t addr_word_offset = addr % 4;
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() - addr_word_offset = 0x%8.8x", addr_word_offset);
+
+ uint32_t byte_mask = ((1u << size) - 1u) << addr_word_offset;
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() - byte_mask = 0x%8.8x", byte_mask);
+ if (byte_mask > 0xfu)
+ return LLDB_INVALID_INDEX32;
+
+ // Read the debug state
+ int kret = ReadDBG (false);
+
+ if (kret == KERN_SUCCESS)
+ {
+ // Check to make sure we have the needed hardware support
+ uint32_t i = 0;
+
+ for (i=0; i<num_hw_watchpoints; ++i)
+ {
+ if ((dbg.wcr[i] & WCR_ENABLE) == 0)
+ break; // We found an available hw breakpoint slot (in i)
+ }
+
+ // See if we found an available hw breakpoint slot above
+ if (i < num_hw_watchpoints)
+ {
+ // Make the byte_mask into a valid Byte Address Select mask
+ uint32_t byte_address_select = byte_mask << 5;
+ // Make sure bits 1:0 are clear in our address
+ dbg.wvr[i] = addr & ~((lldb::addr_t)3);
+ dbg.wcr[i] = byte_address_select | // Which bytes that follow the IMVA that we will watch
+ S_USER | // Stop only in user mode
+ (read ? WCR_LOAD : 0) | // Stop on read access?
+ (write ? WCR_STORE : 0) | // Stop on write access?
+ WCR_ENABLE; // Enable this watchpoint;
+
+ kret = WriteDBG();
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint() WriteDBG() => 0x%8.8x.", kret);
+
+ if (kret == KERN_SUCCESS)
+ return i;
+ }
+ else
+ {
+// if (log) log->Printf ("RegisterContextDarwin_arm::EnableHardwareWatchpoint(): All hardware resources (%u) are in use.", num_hw_watchpoints);
+ }
+ }
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+RegisterContextDarwin_arm::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ int kret = ReadDBG (false);
+
+ const uint32_t num_hw_points = NumSupportedHardwareWatchpoints();
+ if (kret == KERN_SUCCESS)
+ {
+ if (hw_index < num_hw_points)
+ {
+ dbg.wcr[hw_index] = 0;
+// if (log) log->Printf ("RegisterContextDarwin_arm::ClearHardwareWatchpoint( %u ) - WVR%u = 0x%8.8x WCR%u = 0x%8.8x",
+// hw_index,
+// hw_index,
+// dbg.wvr[hw_index],
+// hw_index,
+// dbg.wcr[hw_index]);
+
+ kret = WriteDBG();
+
+ if (kret == KERN_SUCCESS)
+ return true;
+ }
+ }
+ return false;
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h
new file mode 100644
index 000000000000..0bf204f57c80
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_arm.h
@@ -0,0 +1,333 @@
+//===-- RegisterContextDarwin_arm.h -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextDarwin_arm_h_
+#define liblldb_RegisterContextDarwin_arm_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+// BCR address match type
+#define BCR_M_IMVA_MATCH ((uint32_t)(0u << 21))
+#define BCR_M_CONTEXT_ID_MATCH ((uint32_t)(1u << 21))
+#define BCR_M_IMVA_MISMATCH ((uint32_t)(2u << 21))
+#define BCR_M_RESERVED ((uint32_t)(3u << 21))
+
+// Link a BVR/BCR or WVR/WCR pair to another
+#define E_ENABLE_LINKING ((uint32_t)(1u << 20))
+
+// Byte Address Select
+#define BAS_IMVA_PLUS_0 ((uint32_t)(1u << 5))
+#define BAS_IMVA_PLUS_1 ((uint32_t)(1u << 6))
+#define BAS_IMVA_PLUS_2 ((uint32_t)(1u << 7))
+#define BAS_IMVA_PLUS_3 ((uint32_t)(1u << 8))
+#define BAS_IMVA_0_1 ((uint32_t)(3u << 5))
+#define BAS_IMVA_2_3 ((uint32_t)(3u << 7))
+#define BAS_IMVA_ALL ((uint32_t)(0xfu << 5))
+
+// Break only in privileged or user mode
+#define S_RSVD ((uint32_t)(0u << 1))
+#define S_PRIV ((uint32_t)(1u << 1))
+#define S_USER ((uint32_t)(2u << 1))
+#define S_PRIV_USER ((S_PRIV) | (S_USER))
+
+#define BCR_ENABLE ((uint32_t)(1u))
+#define WCR_ENABLE ((uint32_t)(1u))
+
+// Watchpoint load/store
+#define WCR_LOAD ((uint32_t)(1u << 3))
+#define WCR_STORE ((uint32_t)(1u << 4))
+
+class RegisterContextDarwin_arm : public lldb_private::RegisterContext
+{
+public:
+
+ RegisterContextDarwin_arm(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextDarwin_arm();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+ virtual uint32_t
+ NumSupportedHardwareBreakpoints ();
+
+ virtual uint32_t
+ SetHardwareBreakpoint (lldb::addr_t addr, size_t size);
+
+ virtual bool
+ ClearHardwareBreakpoint (uint32_t hw_idx);
+
+ virtual uint32_t
+ NumSupportedHardwareWatchpoints ();
+
+ virtual uint32_t
+ SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write);
+
+ virtual bool
+ ClearHardwareWatchpoint (uint32_t hw_index);
+
+ struct GPR
+ {
+ uint32_t r[16]; // R0-R15
+ uint32_t cpsr; // CPSR
+ };
+
+
+ struct QReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ union {
+ uint32_t s[32];
+ uint64_t d[32];
+ QReg q[16]; // the 128-bit NEON registers
+ } floats;
+ uint32_t fpscr;
+ };
+
+// struct NeonReg
+// {
+// uint8_t bytes[16];
+// };
+//
+// struct VFPv3
+// {
+// union {
+// uint32_t s[32];
+// uint64_t d[32];
+// NeonReg q[16];
+// } v3;
+// uint32_t fpscr;
+// };
+
+ struct EXC
+ {
+ uint32_t exception;
+ uint32_t fsr; /* Fault status */
+ uint32_t far; /* Virtual Fault Address */
+ };
+
+ struct DBG
+ {
+ uint32_t bvr[16];
+ uint32_t bcr[16];
+ uint32_t wvr[16];
+ uint32_t wcr[16];
+ };
+
+ static void
+ LogDBGRegisters (lldb_private::Log *log, const DBG& dbg);
+
+protected:
+
+ enum
+ {
+ GPRRegSet = 1, // ARM_THREAD_STATE
+ FPURegSet = 2, // ARM_VFP_STATE
+ EXCRegSet = 3, // ARM_EXCEPTION_STATE
+ DBGRegSet = 4 // ARM_DEBUG_STATE
+ };
+
+ enum
+ {
+ GPRWordCount = sizeof(GPR)/sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU)/sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC)/sizeof(uint32_t),
+ DBGWordCount = sizeof(DBG)/sizeof(uint32_t)
+ };
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ DBG dbg;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+ int dbg_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ int
+ GetError (int flavor, uint32_t err_idx) const
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet: return gpr_errs[err_idx];
+ case FPURegSet: return fpu_errs[err_idx];
+ case EXCRegSet: return exc_errs[err_idx];
+ case DBGRegSet: return dbg_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+
+ bool
+ SetError (int flavor, uint32_t err_idx, int err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ case DBGRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ bool
+ RegisterSetIsCached (int set) const
+ {
+ return GetError(set, Read) == 0;
+ }
+
+ int
+ ReadGPR (bool force);
+
+ int
+ ReadFPU (bool force);
+
+ int
+ ReadEXC (bool force);
+
+ int
+ ReadDBG (bool force);
+
+ int
+ WriteGPR ();
+
+ int
+ WriteFPU ();
+
+ int
+ WriteEXC ();
+
+ int
+ WriteDBG ();
+
+
+ // Subclasses override these to do the actual reading.
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+ {
+ return -1;
+ }
+
+ virtual int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int
+ DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg) = 0;
+
+ virtual int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ virtual int
+ DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg) = 0;
+
+ int
+ ReadRegisterSet (uint32_t set, bool force);
+
+ int
+ WriteRegisterSet (uint32_t set);
+
+ static uint32_t
+ GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num);
+
+ static int
+ GetSetForNativeRegNum (int reg_num);
+
+ static size_t
+ GetRegisterInfosCount ();
+
+ static const lldb_private::RegisterInfo *
+ GetRegisterInfos ();
+};
+
+#endif // liblldb_RegisterContextDarwin_arm_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
new file mode 100644
index 000000000000..a94d1f538a28
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.cpp
@@ -0,0 +1,980 @@
+//===-- RegisterContextDarwin_i386.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+#include <stddef.h> // offsetof
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+// Support building against older versions of LLVM, this macro was added
+// recently.
+#ifndef LLVM_EXTENSION
+#define LLVM_EXTENSION
+#endif
+
+// Project includes
+#include "RegisterContextDarwin_i386.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum
+{
+ gpr_eax = 0,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_ss,
+ gpr_eflags,
+ gpr_eip,
+ gpr_cs,
+ gpr_ds,
+ gpr_es,
+ gpr_fs,
+ gpr_gs,
+
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr,
+
+ k_num_registers,
+
+ // Aliases
+ fpu_fctrl = fpu_fcw,
+ fpu_fstat = fpu_fsw,
+ fpu_ftag = fpu_ftw,
+ fpu_fiseg = fpu_cs,
+ fpu_fioff = fpu_ip,
+ fpu_foseg = fpu_ds,
+ fpu_fooff = fpu_dp
+};
+
+enum
+{
+ gcc_eax = 0,
+ gcc_ecx,
+ gcc_edx,
+ gcc_ebx,
+ gcc_ebp,
+ gcc_esp,
+ gcc_esi,
+ gcc_edi,
+ gcc_eip,
+ gcc_eflags
+};
+
+enum
+{
+ dwarf_eax = 0,
+ dwarf_ecx,
+ dwarf_edx,
+ dwarf_ebx,
+ dwarf_esp,
+ dwarf_ebp,
+ dwarf_esi,
+ dwarf_edi,
+ dwarf_eip,
+ dwarf_eflags,
+ dwarf_stmm0 = 11,
+ dwarf_stmm1,
+ dwarf_stmm2,
+ dwarf_stmm3,
+ dwarf_stmm4,
+ dwarf_stmm5,
+ dwarf_stmm6,
+ dwarf_stmm7,
+ dwarf_xmm0 = 21,
+ dwarf_xmm1,
+ dwarf_xmm2,
+ dwarf_xmm3,
+ dwarf_xmm4,
+ dwarf_xmm5,
+ dwarf_xmm6,
+ dwarf_xmm7
+};
+
+enum
+{
+ gdb_eax = 0,
+ gdb_ecx = 1,
+ gdb_edx = 2,
+ gdb_ebx = 3,
+ gdb_esp = 4,
+ gdb_ebp = 5,
+ gdb_esi = 6,
+ gdb_edi = 7,
+ gdb_eip = 8,
+ gdb_eflags = 9,
+ gdb_cs = 10,
+ gdb_ss = 11,
+ gdb_ds = 12,
+ gdb_es = 13,
+ gdb_fs = 14,
+ gdb_gs = 15,
+ gdb_stmm0 = 16,
+ gdb_stmm1 = 17,
+ gdb_stmm2 = 18,
+ gdb_stmm3 = 19,
+ gdb_stmm4 = 20,
+ gdb_stmm5 = 21,
+ gdb_stmm6 = 22,
+ gdb_stmm7 = 23,
+ gdb_fctrl = 24, gdb_fcw = gdb_fctrl,
+ gdb_fstat = 25, gdb_fsw = gdb_fstat,
+ gdb_ftag = 26, gdb_ftw = gdb_ftag,
+ gdb_fiseg = 27, gdb_fpu_cs = gdb_fiseg,
+ gdb_fioff = 28, gdb_ip = gdb_fioff,
+ gdb_foseg = 29, gdb_fpu_ds = gdb_foseg,
+ gdb_fooff = 30, gdb_dp = gdb_fooff,
+ gdb_fop = 31,
+ gdb_xmm0 = 32,
+ gdb_xmm1 = 33,
+ gdb_xmm2 = 34,
+ gdb_xmm3 = 35,
+ gdb_xmm4 = 36,
+ gdb_xmm5 = 37,
+ gdb_xmm6 = 38,
+ gdb_xmm7 = 39,
+ gdb_mxcsr = 40,
+ gdb_mm0 = 41,
+ gdb_mm1 = 42,
+ gdb_mm2 = 43,
+ gdb_mm3 = 44,
+ gdb_mm4 = 45,
+ gdb_mm5 = 46,
+ gdb_mm6 = 47,
+ gdb_mm7 = 48
+};
+
+RegisterContextDarwin_i386::RegisterContextDarwin_i386 (Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContext(thread, concrete_frame_idx),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_i386::~RegisterContextDarwin_i386()
+{
+}
+
+
+
+#define GPR_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_i386::GPR, reg))
+#define FPU_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_i386::FPU, reg) + sizeof (RegisterContextDarwin_i386::GPR))
+#define EXC_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_i386::EXC, reg) + sizeof (RegisterContextDarwin_i386::GPR) + sizeof (RegisterContextDarwin_i386::FPU))
+
+// These macros will auto define the register name, alt name, register size,
+// register offset, encoding, format and native register. This ensures that
+// the register state structures are defined correctly and have the correct
+// sizes and offsets.
+#define DEFINE_GPR(reg, alt) #reg, alt, sizeof(((RegisterContextDarwin_i386::GPR *)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_UINT(reg) #reg, NULL, sizeof(((RegisterContextDarwin_i386::FPU *)NULL)->reg), FPU_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_VECT(reg, i) #reg#i, NULL, sizeof(((RegisterContextDarwin_i386::FPU *)NULL)->reg[i].bytes), FPU_OFFSET(reg[i]), eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_##reg##i, LLDB_INVALID_REGNUM, gdb_##reg##i, fpu_##reg##i }, NULL, NULL
+
+#define DEFINE_EXC(reg) #reg, NULL, sizeof(((RegisterContextDarwin_i386::EXC *)NULL)->reg), EXC_OFFSET(reg), eEncodingUint, eFormatHex
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_i386::GPR) + sizeof (RegisterContextDarwin_i386::FPU) + sizeof (RegisterContextDarwin_i386::EXC))
+
+static RegisterInfo g_register_infos[] =
+{
+// Macro auto defines most stuff GCC DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS
+// =============================== ======================= =================== ========================= ================== ================= ========== ===============
+ { DEFINE_GPR(eax , NULL) , { gcc_eax , dwarf_eax , LLDB_INVALID_REGNUM , gdb_eax , gpr_eax }, NULL, NULL},
+ { DEFINE_GPR(ebx , NULL) , { gcc_ebx , dwarf_ebx , LLDB_INVALID_REGNUM , gdb_ebx , gpr_ebx }, NULL, NULL},
+ { DEFINE_GPR(ecx , NULL) , { gcc_ecx , dwarf_ecx , LLDB_INVALID_REGNUM , gdb_ecx , gpr_ecx }, NULL, NULL},
+ { DEFINE_GPR(edx , NULL) , { gcc_edx , dwarf_edx , LLDB_INVALID_REGNUM , gdb_edx , gpr_edx }, NULL, NULL},
+ { DEFINE_GPR(edi , NULL) , { gcc_edi , dwarf_edi , LLDB_INVALID_REGNUM , gdb_edi , gpr_edi }, NULL, NULL},
+ { DEFINE_GPR(esi , NULL) , { gcc_esi , dwarf_esi , LLDB_INVALID_REGNUM , gdb_esi , gpr_esi }, NULL, NULL},
+ { DEFINE_GPR(ebp , "fp") , { gcc_ebp , dwarf_ebp , LLDB_REGNUM_GENERIC_FP , gdb_ebp , gpr_ebp }, NULL, NULL},
+ { DEFINE_GPR(esp , "sp") , { gcc_esp , dwarf_esp , LLDB_REGNUM_GENERIC_SP , gdb_esp , gpr_esp }, NULL, NULL},
+ { DEFINE_GPR(ss , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ss , gpr_ss }, NULL, NULL},
+ { DEFINE_GPR(eflags , "flags") , { gcc_eflags , dwarf_eflags , LLDB_REGNUM_GENERIC_FLAGS , gdb_eflags , gpr_eflags }, NULL, NULL},
+ { DEFINE_GPR(eip , "pc") , { gcc_eip , dwarf_eip , LLDB_REGNUM_GENERIC_PC , gdb_eip , gpr_eip }, NULL, NULL},
+ { DEFINE_GPR(cs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_cs , gpr_cs }, NULL, NULL},
+ { DEFINE_GPR(ds , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ds , gpr_ds }, NULL, NULL},
+ { DEFINE_GPR(es , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_es , gpr_es }, NULL, NULL},
+ { DEFINE_GPR(fs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fs , gpr_fs }, NULL, NULL},
+ { DEFINE_GPR(gs , NULL) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gs , gpr_gs }, NULL, NULL},
+
+ { DEFINE_FPU_UINT(fcw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fcw , fpu_fcw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fsw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fsw , fpu_fsw }, NULL, NULL},
+ { DEFINE_FPU_UINT(ftw) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ftw , fpu_ftw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fop) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fop , fpu_fop }, NULL, NULL},
+ { DEFINE_FPU_UINT(ip) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ip , fpu_ip }, NULL, NULL},
+ { DEFINE_FPU_UINT(cs) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_cs , fpu_cs }, NULL, NULL},
+ { DEFINE_FPU_UINT(dp) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_dp , fpu_dp }, NULL, NULL},
+ { DEFINE_FPU_UINT(ds) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_ds , fpu_ds }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_mxcsr , fpu_mxcsr }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsrmask) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, fpu_mxcsrmask}, NULL, NULL},
+ { DEFINE_FPU_VECT(stmm,0) },
+ { DEFINE_FPU_VECT(stmm,1) },
+ { DEFINE_FPU_VECT(stmm,2) },
+ { DEFINE_FPU_VECT(stmm,3) },
+ { DEFINE_FPU_VECT(stmm,4) },
+ { DEFINE_FPU_VECT(stmm,5) },
+ { DEFINE_FPU_VECT(stmm,6) },
+ { DEFINE_FPU_VECT(stmm,7) },
+ { DEFINE_FPU_VECT(xmm,0) },
+ { DEFINE_FPU_VECT(xmm,1) },
+ { DEFINE_FPU_VECT(xmm,2) },
+ { DEFINE_FPU_VECT(xmm,3) },
+ { DEFINE_FPU_VECT(xmm,4) },
+ { DEFINE_FPU_VECT(xmm,5) },
+ { DEFINE_FPU_VECT(xmm,6) },
+ { DEFINE_FPU_VECT(xmm,7) },
+
+ { DEFINE_EXC(trapno) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_trapno }, NULL, NULL},
+ { DEFINE_EXC(err) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_err }, NULL, NULL},
+ { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_faultvaddr }, NULL, NULL}
+};
+
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+
+void
+RegisterContextDarwin_i386::InvalidateAllRegisters ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextDarwin_i386::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_i386::GetRegisterInfoAtIndex (size_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+size_t
+RegisterContextDarwin_i386::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const RegisterInfo *
+RegisterContextDarwin_i386::GetRegisterInfos ()
+{
+ return g_register_infos;
+}
+
+
+// General purpose registers
+static uint32_t
+g_gpr_regnums[] =
+{
+ gpr_eax,
+ gpr_ebx,
+ gpr_ecx,
+ gpr_edx,
+ gpr_edi,
+ gpr_esi,
+ gpr_ebp,
+ gpr_esp,
+ gpr_ss,
+ gpr_eflags,
+ gpr_eip,
+ gpr_cs,
+ gpr_ds,
+ gpr_es,
+ gpr_fs,
+ gpr_gs
+};
+
+// Floating point registers
+static uint32_t
+g_fpu_regnums[] =
+{
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7
+};
+
+// Exception registers
+
+static uint32_t
+g_exc_regnums[] =
+{
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr
+};
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t);
+const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t);
+const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t);
+
+//----------------------------------------------------------------------
+// Register set definitions. The first definitions at register set index
+// of zero is for all registers, followed by other registers sets. The
+// register information for the all register set need not be filled in.
+//----------------------------------------------------------------------
+static const RegisterSet g_reg_sets[] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums },
+ { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums }
+};
+
+const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet);
+
+
+size_t
+RegisterContextDarwin_i386::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_i386::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// Register information definitions for 32 bit i386.
+//----------------------------------------------------------------------
+int
+RegisterContextDarwin_i386::GetSetForNativeRegNum (int reg_num)
+{
+ if (reg_num < fpu_fcw)
+ return GPRRegSet;
+ else if (reg_num < exc_trapno)
+ return FPURegSet;
+ else if (reg_num < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+
+void
+RegisterContextDarwin_i386::LogGPR(Log *log, const char *title)
+{
+ if (log)
+ {
+ if (title)
+ log->Printf ("%s", title);
+ for (uint32_t i=0; i<k_num_gpr_registers; i++)
+ {
+ uint32_t reg = gpr_eax + i;
+ log->Printf("%12s = 0x%8.8x", g_register_infos[reg].name, (&gpr.eax)[reg]);
+ }
+ }
+}
+
+
+
+int
+RegisterContextDarwin_i386::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(set, Read);
+}
+
+int
+RegisterContextDarwin_i386::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(set, Read);
+}
+
+int
+RegisterContextDarwin_i386::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(set, Read);
+}
+
+int
+RegisterContextDarwin_i386::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+int
+RegisterContextDarwin_i386::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+int
+RegisterContextDarwin_i386::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError (set, Read, -1);
+ return GetError(set, Write);
+}
+
+int
+RegisterContextDarwin_i386::ReadRegisterSet (uint32_t set, bool force)
+{
+ switch (set)
+ {
+ case GPRRegSet: return ReadGPR(force);
+ case FPURegSet: return ReadFPU(force);
+ case EXCRegSet: return ReadEXC(force);
+ default: break;
+ }
+ return -1;
+}
+
+int
+RegisterContextDarwin_i386::WriteRegisterSet (uint32_t set)
+{
+ // Make sure we have a valid context to set.
+ if (RegisterSetIsCached(set))
+ {
+ switch (set)
+ {
+ case GPRRegSet: return WriteGPR();
+ case FPURegSet: return WriteFPU();
+ case EXCRegSet: return WriteEXC();
+ default: break;
+ }
+ }
+ return -1;
+}
+
+bool
+RegisterContextDarwin_i386::ReadRegister (const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_i386::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_eax:
+ case gpr_ebx:
+ case gpr_ecx:
+ case gpr_edx:
+ case gpr_edi:
+ case gpr_esi:
+ case gpr_ebp:
+ case gpr_esp:
+ case gpr_ss:
+ case gpr_eflags:
+ case gpr_eip:
+ case gpr_cs:
+ case gpr_ds:
+ case gpr_es:
+ case gpr_fs:
+ case gpr_gs:
+ value = (&gpr.eax)[reg - gpr_eax];
+ break;
+
+ case fpu_fcw:
+ value = fpu.fcw;
+ break;
+
+ case fpu_fsw:
+ value = fpu.fsw;
+ break;
+
+ case fpu_ftw:
+ value = fpu.ftw;
+ break;
+
+ case fpu_fop:
+ value = fpu.fop;
+ break;
+
+ case fpu_ip:
+ value = fpu.ip;
+ break;
+
+ case fpu_cs:
+ value = fpu.cs;
+ break;
+
+ case fpu_dp:
+ value = fpu.dp;
+ break;
+
+ case fpu_ds:
+ value = fpu.ds;
+ break;
+
+ case fpu_mxcsr:
+ value = fpu.mxcsr;
+ break;
+
+ case fpu_mxcsrmask:
+ value = fpu.mxcsrmask;
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ // These values don't fit into scalar types,
+ // RegisterContext::ReadRegisterBytes() must be used for these
+ // registers
+ //::memcpy (reg_value.value.vector.uint8, fpu.stmm[reg - fpu_stmm0].bytes, 10);
+ return false;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ //::memcpy (reg_value.value.vector.uint8, fpu.xmm[reg - fpu_xmm0].bytes, 16);
+ return false;
+
+ case exc_trapno:
+ value = exc.trapno;
+ break;
+
+ case exc_err:
+ value = exc.err;
+ break;
+
+ case exc_faultvaddr:
+ value = exc.faultvaddr;
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+
+bool
+RegisterContextDarwin_i386::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_eax:
+ case gpr_ebx:
+ case gpr_ecx:
+ case gpr_edx:
+ case gpr_edi:
+ case gpr_esi:
+ case gpr_ebp:
+ case gpr_esp:
+ case gpr_ss:
+ case gpr_eflags:
+ case gpr_eip:
+ case gpr_cs:
+ case gpr_ds:
+ case gpr_es:
+ case gpr_fs:
+ case gpr_gs:
+ (&gpr.eax)[reg - gpr_eax] = value.GetAsUInt32();
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = value.GetAsUInt16();
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = value.GetAsUInt16();
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = value.GetAsUInt8();
+ break;
+
+ case fpu_fop:
+ fpu.fop = value.GetAsUInt16();
+ break;
+
+ case fpu_ip:
+ fpu.ip = value.GetAsUInt32();
+ break;
+
+ case fpu_cs:
+ fpu.cs = value.GetAsUInt16();
+ break;
+
+ case fpu_dp:
+ fpu.dp = value.GetAsUInt32();
+ break;
+
+ case fpu_ds:
+ fpu.ds = value.GetAsUInt16();
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = value.GetAsUInt32();
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = value.GetAsUInt32();
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ ::memcpy (fpu.stmm[reg - fpu_stmm0].bytes, value.GetBytes(), value.GetByteSize());
+ return false;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ // These values don't fit into scalar types, RegisterContext::ReadRegisterBytes()
+ // must be used for these registers
+ ::memcpy (fpu.xmm[reg - fpu_xmm0].bytes, value.GetBytes(), value.GetByteSize());
+ return false;
+
+ case exc_trapno:
+ exc.trapno = value.GetAsUInt32();
+ break;
+
+ case exc_err:
+ exc.err = value.GetAsUInt32();
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = value.GetAsUInt32();
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == 0;
+}
+
+bool
+RegisterContextDarwin_i386::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == 0 &&
+ ReadFPU (false) == 0 &&
+ ReadEXC (false) == 0)
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy (dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextDarwin_i386::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy (&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy (&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy (&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == 0)
+ ++success_count;
+ if (WriteFPU() == 0)
+ ++success_count;
+ if (WriteEXC() == 0)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+
+uint32_t
+RegisterContextDarwin_i386::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (reg)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_eip;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_esp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_ebp;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_eflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (reg)
+ {
+ case dwarf_eax: return gpr_eax;
+ case dwarf_ecx: return gpr_ecx;
+ case dwarf_edx: return gpr_edx;
+ case dwarf_ebx: return gpr_ebx;
+ case dwarf_esp: return gpr_esp;
+ case dwarf_ebp: return gpr_ebp;
+ case dwarf_esi: return gpr_esi;
+ case dwarf_edi: return gpr_edi;
+ case dwarf_eip: return gpr_eip;
+ case dwarf_eflags: return gpr_eflags;
+ case dwarf_stmm0: return fpu_stmm0;
+ case dwarf_stmm1: return fpu_stmm1;
+ case dwarf_stmm2: return fpu_stmm2;
+ case dwarf_stmm3: return fpu_stmm3;
+ case dwarf_stmm4: return fpu_stmm4;
+ case dwarf_stmm5: return fpu_stmm5;
+ case dwarf_stmm6: return fpu_stmm6;
+ case dwarf_stmm7: return fpu_stmm7;
+ case dwarf_xmm0: return fpu_xmm0;
+ case dwarf_xmm1: return fpu_xmm1;
+ case dwarf_xmm2: return fpu_xmm2;
+ case dwarf_xmm3: return fpu_xmm3;
+ case dwarf_xmm4: return fpu_xmm4;
+ case dwarf_xmm5: return fpu_xmm5;
+ case dwarf_xmm6: return fpu_xmm6;
+ case dwarf_xmm7: return fpu_xmm7;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGDB)
+ {
+ switch (reg)
+ {
+ case gdb_eax : return gpr_eax;
+ case gdb_ebx : return gpr_ebx;
+ case gdb_ecx : return gpr_ecx;
+ case gdb_edx : return gpr_edx;
+ case gdb_esi : return gpr_esi;
+ case gdb_edi : return gpr_edi;
+ case gdb_ebp : return gpr_ebp;
+ case gdb_esp : return gpr_esp;
+ case gdb_eip : return gpr_eip;
+ case gdb_eflags : return gpr_eflags;
+ case gdb_cs : return gpr_cs;
+ case gdb_ss : return gpr_ss;
+ case gdb_ds : return gpr_ds;
+ case gdb_es : return gpr_es;
+ case gdb_fs : return gpr_fs;
+ case gdb_gs : return gpr_gs;
+ case gdb_stmm0 : return fpu_stmm0;
+ case gdb_stmm1 : return fpu_stmm1;
+ case gdb_stmm2 : return fpu_stmm2;
+ case gdb_stmm3 : return fpu_stmm3;
+ case gdb_stmm4 : return fpu_stmm4;
+ case gdb_stmm5 : return fpu_stmm5;
+ case gdb_stmm6 : return fpu_stmm6;
+ case gdb_stmm7 : return fpu_stmm7;
+ case gdb_fctrl : return fpu_fctrl;
+ case gdb_fstat : return fpu_fstat;
+ case gdb_ftag : return fpu_ftag;
+ case gdb_fiseg : return fpu_fiseg;
+ case gdb_fioff : return fpu_fioff;
+ case gdb_foseg : return fpu_foseg;
+ case gdb_fooff : return fpu_fooff;
+ case gdb_fop : return fpu_fop;
+ case gdb_xmm0 : return fpu_xmm0;
+ case gdb_xmm1 : return fpu_xmm1;
+ case gdb_xmm2 : return fpu_xmm2;
+ case gdb_xmm3 : return fpu_xmm3;
+ case gdb_xmm4 : return fpu_xmm4;
+ case gdb_xmm5 : return fpu_xmm5;
+ case gdb_xmm6 : return fpu_xmm6;
+ case gdb_xmm7 : return fpu_xmm7;
+ case gdb_mxcsr : return fpu_mxcsr;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+
+bool
+RegisterContextDarwin_i386::HardwareSingleStep (bool enable)
+{
+ if (ReadGPR(false) != 0)
+ return false;
+
+ const uint32_t trace_bit = 0x100u;
+ if (enable)
+ {
+ // If the trace bit is already set, there is nothing to do
+ if (gpr.eflags & trace_bit)
+ return true;
+ else
+ gpr.eflags |= trace_bit;
+ }
+ else
+ {
+ // If the trace bit is already cleared, there is nothing to do
+ if (gpr.eflags & trace_bit)
+ gpr.eflags &= ~trace_bit;
+ else
+ return true;
+ }
+
+ return WriteGPR() == 0;
+}
+
+
+
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h
new file mode 100644
index 000000000000..a588494f9dcf
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_i386.h
@@ -0,0 +1,269 @@
+//===-- RegisterContextDarwin_i386.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextDarwin_i386_h_
+#define liblldb_RegisterContextDarwin_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+class RegisterContextDarwin_i386 : public lldb_private::RegisterContext
+{
+public:
+
+ RegisterContextDarwin_i386(lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextDarwin_i386();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+ virtual bool
+ HardwareSingleStep (bool enable);
+
+ struct GPR
+ {
+ uint32_t eax;
+ uint32_t ebx;
+ uint32_t ecx;
+ uint32_t edx;
+ uint32_t edi;
+ uint32_t esi;
+ uint32_t ebp;
+ uint32_t esp;
+ uint32_t ss;
+ uint32_t eflags;
+ uint32_t eip;
+ uint32_t cs;
+ uint32_t ds;
+ uint32_t es;
+ uint32_t fs;
+ uint32_t gs;
+ };
+
+ struct MMSReg
+ {
+ uint8_t bytes[10];
+ uint8_t pad[6];
+ };
+
+ struct XMMReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ uint32_t pad[2];
+ uint16_t fcw;
+ uint16_t fsw;
+ uint8_t ftw;
+ uint8_t pad1;
+ uint16_t fop;
+ uint32_t ip;
+ uint16_t cs;
+ uint16_t pad2;
+ uint32_t dp;
+ uint16_t ds;
+ uint16_t pad3;
+ uint32_t mxcsr;
+ uint32_t mxcsrmask;
+ MMSReg stmm[8];
+ XMMReg xmm[8];
+ uint8_t pad4[14*16];
+ int pad5;
+ };
+
+ struct EXC
+ {
+ uint32_t trapno;
+ uint32_t err;
+ uint32_t faultvaddr;
+ };
+
+protected:
+
+ enum
+ {
+ GPRRegSet = 1,
+ FPURegSet = 2,
+ EXCRegSet = 3
+ };
+
+ enum
+ {
+ GPRWordCount = sizeof(GPR)/sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU)/sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC)/sizeof(uint32_t)
+ };
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ int
+ GetError (int flavor, uint32_t err_idx) const
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet: return gpr_errs[err_idx];
+ case FPURegSet: return fpu_errs[err_idx];
+ case EXCRegSet: return exc_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+
+ bool
+ SetError (int flavor, uint32_t err_idx, int err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ bool
+ RegisterSetIsCached (int set) const
+ {
+ return GetError(set, Read) == 0;
+ }
+
+ void
+ LogGPR (lldb_private::Log *log, const char *title);
+
+ int
+ ReadGPR (bool force);
+
+ int
+ ReadFPU (bool force);
+
+ int
+ ReadEXC (bool force);
+
+ int
+ WriteGPR ();
+
+ int
+ WriteFPU ();
+
+ int
+ WriteEXC ();
+
+ // Subclasses override these to do the actual reading.
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) = 0;
+
+ virtual int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ int
+ ReadRegisterSet (uint32_t set, bool force);
+
+ int
+ WriteRegisterSet (uint32_t set);
+
+ static uint32_t
+ GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num);
+
+ static int
+ GetSetForNativeRegNum (int reg_num);
+
+ static size_t
+ GetRegisterInfosCount ();
+
+ static const lldb_private::RegisterInfo *
+ GetRegisterInfos ();
+};
+
+#endif // liblldb_RegisterContextDarwin_i386_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
new file mode 100644
index 000000000000..433782fe20c0
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.cpp
@@ -0,0 +1,1066 @@
+//===-- RegisterContextDarwin_x86_64.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+// C Includes
+#include <stdarg.h>
+#include <stddef.h> // offsetof
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Endian.h"
+#include "llvm/Support/Compiler.h"
+
+// Support building against older versions of LLVM, this macro was added
+// recently.
+#ifndef LLVM_EXTENSION
+#define LLVM_EXTENSION
+#endif
+
+// Project includes
+#include "RegisterContextDarwin_x86_64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum
+{
+ gpr_rax = 0,
+ gpr_rbx,
+ gpr_rcx,
+ gpr_rdx,
+ gpr_rdi,
+ gpr_rsi,
+ gpr_rbp,
+ gpr_rsp,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_r14,
+ gpr_r15,
+ gpr_rip,
+ gpr_rflags,
+ gpr_cs,
+ gpr_fs,
+ gpr_gs,
+
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ fpu_xmm8,
+ fpu_xmm9,
+ fpu_xmm10,
+ fpu_xmm11,
+ fpu_xmm12,
+ fpu_xmm13,
+ fpu_xmm14,
+ fpu_xmm15,
+
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr,
+
+ k_num_registers,
+
+ // Aliases
+ fpu_fctrl = fpu_fcw,
+ fpu_fstat = fpu_fsw,
+ fpu_ftag = fpu_ftw,
+ fpu_fiseg = fpu_cs,
+ fpu_fioff = fpu_ip,
+ fpu_foseg = fpu_ds,
+ fpu_fooff = fpu_dp
+};
+
+enum gcc_dwarf_regnums
+{
+ gcc_dwarf_gpr_rax = 0,
+ gcc_dwarf_gpr_rdx,
+ gcc_dwarf_gpr_rcx,
+ gcc_dwarf_gpr_rbx,
+ gcc_dwarf_gpr_rsi,
+ gcc_dwarf_gpr_rdi,
+ gcc_dwarf_gpr_rbp,
+ gcc_dwarf_gpr_rsp,
+ gcc_dwarf_gpr_r8,
+ gcc_dwarf_gpr_r9,
+ gcc_dwarf_gpr_r10,
+ gcc_dwarf_gpr_r11,
+ gcc_dwarf_gpr_r12,
+ gcc_dwarf_gpr_r13,
+ gcc_dwarf_gpr_r14,
+ gcc_dwarf_gpr_r15,
+ gcc_dwarf_gpr_rip,
+ gcc_dwarf_fpu_xmm0,
+ gcc_dwarf_fpu_xmm1,
+ gcc_dwarf_fpu_xmm2,
+ gcc_dwarf_fpu_xmm3,
+ gcc_dwarf_fpu_xmm4,
+ gcc_dwarf_fpu_xmm5,
+ gcc_dwarf_fpu_xmm6,
+ gcc_dwarf_fpu_xmm7,
+ gcc_dwarf_fpu_xmm8,
+ gcc_dwarf_fpu_xmm9,
+ gcc_dwarf_fpu_xmm10,
+ gcc_dwarf_fpu_xmm11,
+ gcc_dwarf_fpu_xmm12,
+ gcc_dwarf_fpu_xmm13,
+ gcc_dwarf_fpu_xmm14,
+ gcc_dwarf_fpu_xmm15,
+ gcc_dwarf_fpu_stmm0,
+ gcc_dwarf_fpu_stmm1,
+ gcc_dwarf_fpu_stmm2,
+ gcc_dwarf_fpu_stmm3,
+ gcc_dwarf_fpu_stmm4,
+ gcc_dwarf_fpu_stmm5,
+ gcc_dwarf_fpu_stmm6,
+ gcc_dwarf_fpu_stmm7
+
+};
+
+enum gdb_regnums
+{
+ gdb_gpr_rax = 0,
+ gdb_gpr_rbx = 1,
+ gdb_gpr_rcx = 2,
+ gdb_gpr_rdx = 3,
+ gdb_gpr_rsi = 4,
+ gdb_gpr_rdi = 5,
+ gdb_gpr_rbp = 6,
+ gdb_gpr_rsp = 7,
+ gdb_gpr_r8 = 8,
+ gdb_gpr_r9 = 9,
+ gdb_gpr_r10 = 10,
+ gdb_gpr_r11 = 11,
+ gdb_gpr_r12 = 12,
+ gdb_gpr_r13 = 13,
+ gdb_gpr_r14 = 14,
+ gdb_gpr_r15 = 15,
+ gdb_gpr_rip = 16,
+ gdb_gpr_rflags = 17,
+ gdb_gpr_cs = 18,
+ gdb_gpr_ss = 19,
+ gdb_gpr_ds = 20,
+ gdb_gpr_es = 21,
+ gdb_gpr_fs = 22,
+ gdb_gpr_gs = 23,
+ gdb_fpu_stmm0 = 24,
+ gdb_fpu_stmm1 = 25,
+ gdb_fpu_stmm2 = 26,
+ gdb_fpu_stmm3 = 27,
+ gdb_fpu_stmm4 = 28,
+ gdb_fpu_stmm5 = 29,
+ gdb_fpu_stmm6 = 30,
+ gdb_fpu_stmm7 = 31,
+ gdb_fpu_fctrl = 32, gdb_fpu_fcw = gdb_fpu_fctrl,
+ gdb_fpu_fstat = 33, gdb_fpu_fsw = gdb_fpu_fstat,
+ gdb_fpu_ftag = 34, gdb_fpu_ftw = gdb_fpu_ftag,
+ gdb_fpu_fiseg = 35, gdb_fpu_cs = gdb_fpu_fiseg,
+ gdb_fpu_fioff = 36, gdb_fpu_ip = gdb_fpu_fioff,
+ gdb_fpu_foseg = 37, gdb_fpu_ds = gdb_fpu_foseg,
+ gdb_fpu_fooff = 38, gdb_fpu_dp = gdb_fpu_fooff,
+ gdb_fpu_fop = 39,
+ gdb_fpu_xmm0 = 40,
+ gdb_fpu_xmm1 = 41,
+ gdb_fpu_xmm2 = 42,
+ gdb_fpu_xmm3 = 43,
+ gdb_fpu_xmm4 = 44,
+ gdb_fpu_xmm5 = 45,
+ gdb_fpu_xmm6 = 46,
+ gdb_fpu_xmm7 = 47,
+ gdb_fpu_xmm8 = 48,
+ gdb_fpu_xmm9 = 49,
+ gdb_fpu_xmm10 = 50,
+ gdb_fpu_xmm11 = 51,
+ gdb_fpu_xmm12 = 52,
+ gdb_fpu_xmm13 = 53,
+ gdb_fpu_xmm14 = 54,
+ gdb_fpu_xmm15 = 55,
+ gdb_fpu_mxcsr = 56
+};
+
+RegisterContextDarwin_x86_64::RegisterContextDarwin_x86_64 (Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContext (thread, concrete_frame_idx),
+ gpr(),
+ fpu(),
+ exc()
+{
+ uint32_t i;
+ for (i=0; i<kNumErrors; i++)
+ {
+ gpr_errs[i] = -1;
+ fpu_errs[i] = -1;
+ exc_errs[i] = -1;
+ }
+}
+
+RegisterContextDarwin_x86_64::~RegisterContextDarwin_x86_64()
+{
+}
+
+#define GPR_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_x86_64::GPR, reg))
+#define FPU_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_x86_64::FPU, reg) + sizeof (RegisterContextDarwin_x86_64::GPR))
+#define EXC_OFFSET(reg) (LLVM_EXTENSION offsetof (RegisterContextDarwin_x86_64::EXC, reg) + sizeof (RegisterContextDarwin_x86_64::GPR) + sizeof (RegisterContextDarwin_x86_64::FPU))
+
+// These macros will auto define the register name, alt name, register size,
+// register offset, encoding, format and native register. This ensures that
+// the register state structures are defined correctly and have the correct
+// sizes and offsets.
+#define DEFINE_GPR(reg, alt) #reg, alt, sizeof(((RegisterContextDarwin_x86_64::GPR *)NULL)->reg), GPR_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_UINT(reg) #reg, NULL, sizeof(((RegisterContextDarwin_x86_64::FPU *)NULL)->reg), FPU_OFFSET(reg), eEncodingUint, eFormatHex
+#define DEFINE_FPU_VECT(reg, i) #reg#i, NULL, sizeof(((RegisterContextDarwin_x86_64::FPU *)NULL)->reg[i].bytes), FPU_OFFSET(reg[i]), eEncodingVector, eFormatVectorOfUInt8, { gcc_dwarf_fpu_##reg##i, gcc_dwarf_fpu_##reg##i, LLDB_INVALID_REGNUM, gdb_fpu_##reg##i, fpu_##reg##i }, NULL, NULL
+#define DEFINE_EXC(reg) #reg, NULL, sizeof(((RegisterContextDarwin_x86_64::EXC *)NULL)->reg), EXC_OFFSET(reg), eEncodingUint, eFormatHex
+
+#define REG_CONTEXT_SIZE (sizeof (RegisterContextDarwin_x86_64::GPR) + sizeof (RegisterContextDarwin_x86_64::FPU) + sizeof (RegisterContextDarwin_x86_64::EXC))
+
+// General purpose registers for 64 bit
+static RegisterInfo g_register_infos[] =
+{
+// Macro auto defines most stuff GCC DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS
+// =============================== ====================== =================== ========================== ==================== =================== ========== ===============
+ { DEFINE_GPR (rax , NULL) , { gcc_dwarf_gpr_rax , gcc_dwarf_gpr_rax , LLDB_INVALID_REGNUM , gdb_gpr_rax , gpr_rax }, NULL, NULL},
+ { DEFINE_GPR (rbx , NULL) , { gcc_dwarf_gpr_rbx , gcc_dwarf_gpr_rbx , LLDB_INVALID_REGNUM , gdb_gpr_rbx , gpr_rbx }, NULL, NULL},
+ { DEFINE_GPR (rcx , NULL) , { gcc_dwarf_gpr_rcx , gcc_dwarf_gpr_rcx , LLDB_INVALID_REGNUM , gdb_gpr_rcx , gpr_rcx }, NULL, NULL},
+ { DEFINE_GPR (rdx , NULL) , { gcc_dwarf_gpr_rdx , gcc_dwarf_gpr_rdx , LLDB_INVALID_REGNUM , gdb_gpr_rdx , gpr_rdx }, NULL, NULL},
+ { DEFINE_GPR (rdi , NULL) , { gcc_dwarf_gpr_rdi , gcc_dwarf_gpr_rdi , LLDB_INVALID_REGNUM , gdb_gpr_rdi , gpr_rdi }, NULL, NULL},
+ { DEFINE_GPR (rsi , NULL) , { gcc_dwarf_gpr_rsi , gcc_dwarf_gpr_rsi , LLDB_INVALID_REGNUM , gdb_gpr_rsi , gpr_rsi }, NULL, NULL},
+ { DEFINE_GPR (rbp , "fp") , { gcc_dwarf_gpr_rbp , gcc_dwarf_gpr_rbp , LLDB_REGNUM_GENERIC_FP , gdb_gpr_rbp , gpr_rbp }, NULL, NULL},
+ { DEFINE_GPR (rsp , "sp") , { gcc_dwarf_gpr_rsp , gcc_dwarf_gpr_rsp , LLDB_REGNUM_GENERIC_SP , gdb_gpr_rsp , gpr_rsp }, NULL, NULL},
+ { DEFINE_GPR (r8 , NULL) , { gcc_dwarf_gpr_r8 , gcc_dwarf_gpr_r8 , LLDB_INVALID_REGNUM , gdb_gpr_r8 , gpr_r8 }, NULL, NULL},
+ { DEFINE_GPR (r9 , NULL) , { gcc_dwarf_gpr_r9 , gcc_dwarf_gpr_r9 , LLDB_INVALID_REGNUM , gdb_gpr_r9 , gpr_r9 }, NULL, NULL},
+ { DEFINE_GPR (r10 , NULL) , { gcc_dwarf_gpr_r10 , gcc_dwarf_gpr_r10 , LLDB_INVALID_REGNUM , gdb_gpr_r10 , gpr_r10 }, NULL, NULL},
+ { DEFINE_GPR (r11 , NULL) , { gcc_dwarf_gpr_r11 , gcc_dwarf_gpr_r11 , LLDB_INVALID_REGNUM , gdb_gpr_r11 , gpr_r11 }, NULL, NULL},
+ { DEFINE_GPR (r12 , NULL) , { gcc_dwarf_gpr_r12 , gcc_dwarf_gpr_r12 , LLDB_INVALID_REGNUM , gdb_gpr_r12 , gpr_r12 }, NULL, NULL},
+ { DEFINE_GPR (r13 , NULL) , { gcc_dwarf_gpr_r13 , gcc_dwarf_gpr_r13 , LLDB_INVALID_REGNUM , gdb_gpr_r13 , gpr_r13 }, NULL, NULL},
+ { DEFINE_GPR (r14 , NULL) , { gcc_dwarf_gpr_r14 , gcc_dwarf_gpr_r14 , LLDB_INVALID_REGNUM , gdb_gpr_r14 , gpr_r14 }, NULL, NULL},
+ { DEFINE_GPR (r15 , NULL) , { gcc_dwarf_gpr_r15 , gcc_dwarf_gpr_r15 , LLDB_INVALID_REGNUM , gdb_gpr_r15 , gpr_r15 }, NULL, NULL},
+ { DEFINE_GPR (rip , "pc") , { gcc_dwarf_gpr_rip , gcc_dwarf_gpr_rip , LLDB_REGNUM_GENERIC_PC , gdb_gpr_rip , gpr_rip }, NULL, NULL},
+ { DEFINE_GPR (rflags, "flags") , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_REGNUM_GENERIC_FLAGS, gdb_gpr_rflags , gpr_rflags }, NULL, NULL},
+ { DEFINE_GPR (cs , NULL) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gpr_cs , gpr_cs }, NULL, NULL},
+ { DEFINE_GPR (fs , NULL) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gpr_fs , gpr_fs }, NULL, NULL},
+ { DEFINE_GPR (gs , NULL) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_gpr_gs , gpr_gs }, NULL, NULL},
+
+ { DEFINE_FPU_UINT(fcw) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_fcw , fpu_fcw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fsw) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_fsw , fpu_fsw }, NULL, NULL},
+ { DEFINE_FPU_UINT(ftw) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_ftw , fpu_ftw }, NULL, NULL},
+ { DEFINE_FPU_UINT(fop) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_fop , fpu_fop }, NULL, NULL},
+ { DEFINE_FPU_UINT(ip) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_ip , fpu_ip }, NULL, NULL},
+ { DEFINE_FPU_UINT(cs) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_cs , fpu_cs }, NULL, NULL},
+ { DEFINE_FPU_UINT(dp) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_dp , fpu_dp }, NULL, NULL},
+ { DEFINE_FPU_UINT(ds) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_ds , fpu_ds }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsr) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , gdb_fpu_mxcsr , fpu_mxcsr }, NULL, NULL},
+ { DEFINE_FPU_UINT(mxcsrmask) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, fpu_mxcsrmask }, NULL, NULL},
+ { DEFINE_FPU_VECT(stmm,0) },
+ { DEFINE_FPU_VECT(stmm,1) },
+ { DEFINE_FPU_VECT(stmm,2) },
+ { DEFINE_FPU_VECT(stmm,3) },
+ { DEFINE_FPU_VECT(stmm,4) },
+ { DEFINE_FPU_VECT(stmm,5) },
+ { DEFINE_FPU_VECT(stmm,6) },
+ { DEFINE_FPU_VECT(stmm,7) },
+ { DEFINE_FPU_VECT(xmm,0) },
+ { DEFINE_FPU_VECT(xmm,1) },
+ { DEFINE_FPU_VECT(xmm,2) },
+ { DEFINE_FPU_VECT(xmm,3) },
+ { DEFINE_FPU_VECT(xmm,4) },
+ { DEFINE_FPU_VECT(xmm,5) },
+ { DEFINE_FPU_VECT(xmm,6) },
+ { DEFINE_FPU_VECT(xmm,7) },
+ { DEFINE_FPU_VECT(xmm,8) },
+ { DEFINE_FPU_VECT(xmm,9) },
+ { DEFINE_FPU_VECT(xmm,10) },
+ { DEFINE_FPU_VECT(xmm,11) },
+ { DEFINE_FPU_VECT(xmm,12) },
+ { DEFINE_FPU_VECT(xmm,13) },
+ { DEFINE_FPU_VECT(xmm,14) },
+ { DEFINE_FPU_VECT(xmm,15) },
+
+ { DEFINE_EXC(trapno) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_trapno }, NULL, NULL},
+ { DEFINE_EXC(err) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_err }, NULL, NULL},
+ { DEFINE_EXC(faultvaddr) , { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, exc_faultvaddr }, NULL, NULL}
+};
+
+static size_t k_num_register_infos = (sizeof(g_register_infos)/sizeof(RegisterInfo));
+
+
+void
+RegisterContextDarwin_x86_64::InvalidateAllRegisters ()
+{
+ InvalidateAllRegisterStates();
+}
+
+
+size_t
+RegisterContextDarwin_x86_64::GetRegisterCount ()
+{
+ assert(k_num_register_infos == k_num_registers);
+ return k_num_registers;
+}
+
+
+const RegisterInfo *
+RegisterContextDarwin_x86_64::GetRegisterInfoAtIndex (size_t reg)
+{
+ assert(k_num_register_infos == k_num_registers);
+ if (reg < k_num_registers)
+ return &g_register_infos[reg];
+ return NULL;
+}
+
+
+size_t
+RegisterContextDarwin_x86_64::GetRegisterInfosCount ()
+{
+ return k_num_register_infos;
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextDarwin_x86_64::GetRegisterInfos ()
+{
+ return g_register_infos;
+}
+
+
+
+static uint32_t g_gpr_regnums[] =
+{
+ gpr_rax,
+ gpr_rbx,
+ gpr_rcx,
+ gpr_rdx,
+ gpr_rdi,
+ gpr_rsi,
+ gpr_rbp,
+ gpr_rsp,
+ gpr_r8,
+ gpr_r9,
+ gpr_r10,
+ gpr_r11,
+ gpr_r12,
+ gpr_r13,
+ gpr_r14,
+ gpr_r15,
+ gpr_rip,
+ gpr_rflags,
+ gpr_cs,
+ gpr_fs,
+ gpr_gs
+};
+
+static uint32_t g_fpu_regnums[] =
+{
+ fpu_fcw,
+ fpu_fsw,
+ fpu_ftw,
+ fpu_fop,
+ fpu_ip,
+ fpu_cs,
+ fpu_dp,
+ fpu_ds,
+ fpu_mxcsr,
+ fpu_mxcsrmask,
+ fpu_stmm0,
+ fpu_stmm1,
+ fpu_stmm2,
+ fpu_stmm3,
+ fpu_stmm4,
+ fpu_stmm5,
+ fpu_stmm6,
+ fpu_stmm7,
+ fpu_xmm0,
+ fpu_xmm1,
+ fpu_xmm2,
+ fpu_xmm3,
+ fpu_xmm4,
+ fpu_xmm5,
+ fpu_xmm6,
+ fpu_xmm7,
+ fpu_xmm8,
+ fpu_xmm9,
+ fpu_xmm10,
+ fpu_xmm11,
+ fpu_xmm12,
+ fpu_xmm13,
+ fpu_xmm14,
+ fpu_xmm15
+};
+
+static uint32_t
+g_exc_regnums[] =
+{
+ exc_trapno,
+ exc_err,
+ exc_faultvaddr
+};
+
+// Number of registers in each register set
+const size_t k_num_gpr_registers = sizeof(g_gpr_regnums) / sizeof(uint32_t);
+const size_t k_num_fpu_registers = sizeof(g_fpu_regnums) / sizeof(uint32_t);
+const size_t k_num_exc_registers = sizeof(g_exc_regnums) / sizeof(uint32_t);
+
+//----------------------------------------------------------------------
+// Register set definitions. The first definitions at register set index
+// of zero is for all registers, followed by other registers sets. The
+// register information for the all register set need not be filled in.
+//----------------------------------------------------------------------
+static const RegisterSet g_reg_sets[] =
+{
+ { "General Purpose Registers", "gpr", k_num_gpr_registers, g_gpr_regnums, },
+ { "Floating Point Registers", "fpu", k_num_fpu_registers, g_fpu_regnums },
+ { "Exception State Registers", "exc", k_num_exc_registers, g_exc_regnums }
+};
+
+const size_t k_num_regsets = sizeof(g_reg_sets) / sizeof(RegisterSet);
+
+
+size_t
+RegisterContextDarwin_x86_64::GetRegisterSetCount ()
+{
+ return k_num_regsets;
+}
+
+const RegisterSet *
+RegisterContextDarwin_x86_64::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set < k_num_regsets)
+ return &g_reg_sets[reg_set];
+ return NULL;
+}
+
+int
+RegisterContextDarwin_x86_64::GetSetForNativeRegNum (int reg_num)
+{
+ if (reg_num < fpu_fcw)
+ return GPRRegSet;
+ else if (reg_num < exc_trapno)
+ return FPURegSet;
+ else if (reg_num < k_num_registers)
+ return EXCRegSet;
+ return -1;
+}
+
+void
+RegisterContextDarwin_x86_64::LogGPR(Log *log, const char *format, ...)
+{
+ if (log)
+ {
+ if (format)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+ for (uint32_t i=0; i<k_num_gpr_registers; i++)
+ {
+ uint32_t reg = gpr_rax + i;
+ log->Printf("%12s = 0x%16.16" PRIx64, g_register_infos[reg].name, (&gpr.rax)[reg]);
+ }
+ }
+}
+
+int
+RegisterContextDarwin_x86_64::ReadGPR (bool force)
+{
+ int set = GPRRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadGPR(GetThreadID(), set, gpr));
+ }
+ return GetError(GPRRegSet, Read);
+}
+
+int
+RegisterContextDarwin_x86_64::ReadFPU (bool force)
+{
+ int set = FPURegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadFPU(GetThreadID(), set, fpu));
+ }
+ return GetError(FPURegSet, Read);
+}
+
+int
+RegisterContextDarwin_x86_64::ReadEXC (bool force)
+{
+ int set = EXCRegSet;
+ if (force || !RegisterSetIsCached(set))
+ {
+ SetError(set, Read, DoReadEXC(GetThreadID(), set, exc));
+ }
+ return GetError(EXCRegSet, Read);
+}
+
+int
+RegisterContextDarwin_x86_64::WriteGPR ()
+{
+ int set = GPRRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteGPR(GetThreadID(), set, gpr));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+int
+RegisterContextDarwin_x86_64::WriteFPU ()
+{
+ int set = FPURegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteFPU(GetThreadID(), set, fpu));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+int
+RegisterContextDarwin_x86_64::WriteEXC ()
+{
+ int set = EXCRegSet;
+ if (!RegisterSetIsCached(set))
+ {
+ SetError (set, Write, -1);
+ return -1;
+ }
+ SetError (set, Write, DoWriteEXC(GetThreadID(), set, exc));
+ SetError (set, Read, -1);
+ return GetError (set, Write);
+}
+
+int
+RegisterContextDarwin_x86_64::ReadRegisterSet(uint32_t set, bool force)
+{
+ switch (set)
+ {
+ case GPRRegSet: return ReadGPR (force);
+ case FPURegSet: return ReadFPU (force);
+ case EXCRegSet: return ReadEXC (force);
+ default: break;
+ }
+ return -1;
+}
+
+int
+RegisterContextDarwin_x86_64::WriteRegisterSet(uint32_t set)
+{
+ // Make sure we have a valid context to set.
+ switch (set)
+ {
+ case GPRRegSet: return WriteGPR ();
+ case FPURegSet: return WriteFPU ();
+ case EXCRegSet: return WriteEXC ();
+ default: break;
+ }
+ return -1;
+}
+
+
+bool
+RegisterContextDarwin_x86_64::ReadRegister (const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_x86_64::GetSetForNativeRegNum (reg);
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_rax:
+ case gpr_rbx:
+ case gpr_rcx:
+ case gpr_rdx:
+ case gpr_rdi:
+ case gpr_rsi:
+ case gpr_rbp:
+ case gpr_rsp:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_r13:
+ case gpr_r14:
+ case gpr_r15:
+ case gpr_rip:
+ case gpr_rflags:
+ case gpr_cs:
+ case gpr_fs:
+ case gpr_gs:
+ value = (&gpr.rax)[reg - gpr_rax];
+ break;
+
+ case fpu_fcw:
+ value = fpu.fcw;
+ break;
+
+ case fpu_fsw:
+ value = fpu.fsw;
+ break;
+
+ case fpu_ftw:
+ value = fpu.ftw;
+ break;
+
+ case fpu_fop:
+ value = fpu.fop;
+ break;
+
+ case fpu_ip:
+ value = fpu.ip;
+ break;
+
+ case fpu_cs:
+ value = fpu.cs;
+ break;
+
+ case fpu_dp:
+ value = fpu.dp;
+ break;
+
+ case fpu_ds:
+ value = fpu.ds;
+ break;
+
+ case fpu_mxcsr:
+ value = fpu.mxcsr;
+ break;
+
+ case fpu_mxcsrmask:
+ value = fpu.mxcsrmask;
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ value.SetBytes(fpu.stmm[reg - fpu_stmm0].bytes, reg_info->byte_size, lldb::endian::InlHostByteOrder());
+ break;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ case fpu_xmm8:
+ case fpu_xmm9:
+ case fpu_xmm10:
+ case fpu_xmm11:
+ case fpu_xmm12:
+ case fpu_xmm13:
+ case fpu_xmm14:
+ case fpu_xmm15:
+ value.SetBytes(fpu.xmm[reg - fpu_xmm0].bytes, reg_info->byte_size, lldb::endian::InlHostByteOrder());
+ break;
+
+ case exc_trapno:
+ value = exc.trapno;
+ break;
+
+ case exc_err:
+ value = exc.err;
+ break;
+
+ case exc_faultvaddr:
+ value = exc.faultvaddr;
+ break;
+
+ default:
+ return false;
+ }
+ return true;
+}
+
+
+bool
+RegisterContextDarwin_x86_64::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ int set = RegisterContextDarwin_x86_64::GetSetForNativeRegNum (reg);
+
+ if (set == -1)
+ return false;
+
+ if (ReadRegisterSet(set, false) != 0)
+ return false;
+
+ switch (reg)
+ {
+ case gpr_rax:
+ case gpr_rbx:
+ case gpr_rcx:
+ case gpr_rdx:
+ case gpr_rdi:
+ case gpr_rsi:
+ case gpr_rbp:
+ case gpr_rsp:
+ case gpr_r8:
+ case gpr_r9:
+ case gpr_r10:
+ case gpr_r11:
+ case gpr_r12:
+ case gpr_r13:
+ case gpr_r14:
+ case gpr_r15:
+ case gpr_rip:
+ case gpr_rflags:
+ case gpr_cs:
+ case gpr_fs:
+ case gpr_gs:
+ (&gpr.rax)[reg - gpr_rax] = value.GetAsUInt64();
+ break;
+
+ case fpu_fcw:
+ fpu.fcw = value.GetAsUInt16();
+ break;
+
+ case fpu_fsw:
+ fpu.fsw = value.GetAsUInt16();
+ break;
+
+ case fpu_ftw:
+ fpu.ftw = value.GetAsUInt8();
+ break;
+
+ case fpu_fop:
+ fpu.fop = value.GetAsUInt16();
+ break;
+
+ case fpu_ip:
+ fpu.ip = value.GetAsUInt32();
+ break;
+
+ case fpu_cs:
+ fpu.cs = value.GetAsUInt16();
+ break;
+
+ case fpu_dp:
+ fpu.dp = value.GetAsUInt32();
+ break;
+
+ case fpu_ds:
+ fpu.ds = value.GetAsUInt16();
+ break;
+
+ case fpu_mxcsr:
+ fpu.mxcsr = value.GetAsUInt32();
+ break;
+
+ case fpu_mxcsrmask:
+ fpu.mxcsrmask = value.GetAsUInt32();
+ break;
+
+ case fpu_stmm0:
+ case fpu_stmm1:
+ case fpu_stmm2:
+ case fpu_stmm3:
+ case fpu_stmm4:
+ case fpu_stmm5:
+ case fpu_stmm6:
+ case fpu_stmm7:
+ ::memcpy (fpu.stmm[reg - fpu_stmm0].bytes, value.GetBytes(), value.GetByteSize());
+ break;
+
+ case fpu_xmm0:
+ case fpu_xmm1:
+ case fpu_xmm2:
+ case fpu_xmm3:
+ case fpu_xmm4:
+ case fpu_xmm5:
+ case fpu_xmm6:
+ case fpu_xmm7:
+ case fpu_xmm8:
+ case fpu_xmm9:
+ case fpu_xmm10:
+ case fpu_xmm11:
+ case fpu_xmm12:
+ case fpu_xmm13:
+ case fpu_xmm14:
+ case fpu_xmm15:
+ ::memcpy (fpu.xmm[reg - fpu_xmm0].bytes, value.GetBytes(), value.GetByteSize());
+ return false;
+
+ case exc_trapno:
+ exc.trapno = value.GetAsUInt32();
+ break;
+
+ case exc_err:
+ exc.err = value.GetAsUInt32();
+ break;
+
+ case exc_faultvaddr:
+ exc.faultvaddr = value.GetAsUInt64();
+ break;
+
+ default:
+ return false;
+ }
+ return WriteRegisterSet(set) == 0;
+}
+
+bool
+RegisterContextDarwin_x86_64::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ data_sp.reset (new DataBufferHeap (REG_CONTEXT_SIZE, 0));
+ if (data_sp &&
+ ReadGPR (false) == 0 &&
+ ReadFPU (false) == 0 &&
+ ReadEXC (false) == 0)
+ {
+ uint8_t *dst = data_sp->GetBytes();
+ ::memcpy (dst, &gpr, sizeof(gpr));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &fpu, sizeof(fpu));
+ dst += sizeof(gpr);
+
+ ::memcpy (dst, &exc, sizeof(exc));
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextDarwin_x86_64::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ if (data_sp && data_sp->GetByteSize() == REG_CONTEXT_SIZE)
+ {
+ const uint8_t *src = data_sp->GetBytes();
+ ::memcpy (&gpr, src, sizeof(gpr));
+ src += sizeof(gpr);
+
+ ::memcpy (&fpu, src, sizeof(fpu));
+ src += sizeof(gpr);
+
+ ::memcpy (&exc, src, sizeof(exc));
+ uint32_t success_count = 0;
+ if (WriteGPR() == 0)
+ ++success_count;
+ if (WriteFPU() == 0)
+ ++success_count;
+ if (WriteEXC() == 0)
+ ++success_count;
+ return success_count == 3;
+ }
+ return false;
+}
+
+
+uint32_t
+RegisterContextDarwin_x86_64::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t reg)
+{
+ if (kind == eRegisterKindGeneric)
+ {
+ switch (reg)
+ {
+ case LLDB_REGNUM_GENERIC_PC: return gpr_rip;
+ case LLDB_REGNUM_GENERIC_SP: return gpr_rsp;
+ case LLDB_REGNUM_GENERIC_FP: return gpr_rbp;
+ case LLDB_REGNUM_GENERIC_FLAGS: return gpr_rflags;
+ case LLDB_REGNUM_GENERIC_RA:
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGCC || kind == eRegisterKindDWARF)
+ {
+ switch (reg)
+ {
+ case gcc_dwarf_gpr_rax: return gpr_rax;
+ case gcc_dwarf_gpr_rdx: return gpr_rdx;
+ case gcc_dwarf_gpr_rcx: return gpr_rcx;
+ case gcc_dwarf_gpr_rbx: return gpr_rbx;
+ case gcc_dwarf_gpr_rsi: return gpr_rsi;
+ case gcc_dwarf_gpr_rdi: return gpr_rdi;
+ case gcc_dwarf_gpr_rbp: return gpr_rbp;
+ case gcc_dwarf_gpr_rsp: return gpr_rsp;
+ case gcc_dwarf_gpr_r8: return gpr_r8;
+ case gcc_dwarf_gpr_r9: return gpr_r9;
+ case gcc_dwarf_gpr_r10: return gpr_r10;
+ case gcc_dwarf_gpr_r11: return gpr_r11;
+ case gcc_dwarf_gpr_r12: return gpr_r12;
+ case gcc_dwarf_gpr_r13: return gpr_r13;
+ case gcc_dwarf_gpr_r14: return gpr_r14;
+ case gcc_dwarf_gpr_r15: return gpr_r15;
+ case gcc_dwarf_gpr_rip: return gpr_rip;
+ case gcc_dwarf_fpu_xmm0: return fpu_xmm0;
+ case gcc_dwarf_fpu_xmm1: return fpu_xmm1;
+ case gcc_dwarf_fpu_xmm2: return fpu_xmm2;
+ case gcc_dwarf_fpu_xmm3: return fpu_xmm3;
+ case gcc_dwarf_fpu_xmm4: return fpu_xmm4;
+ case gcc_dwarf_fpu_xmm5: return fpu_xmm5;
+ case gcc_dwarf_fpu_xmm6: return fpu_xmm6;
+ case gcc_dwarf_fpu_xmm7: return fpu_xmm7;
+ case gcc_dwarf_fpu_xmm8: return fpu_xmm8;
+ case gcc_dwarf_fpu_xmm9: return fpu_xmm9;
+ case gcc_dwarf_fpu_xmm10: return fpu_xmm10;
+ case gcc_dwarf_fpu_xmm11: return fpu_xmm11;
+ case gcc_dwarf_fpu_xmm12: return fpu_xmm12;
+ case gcc_dwarf_fpu_xmm13: return fpu_xmm13;
+ case gcc_dwarf_fpu_xmm14: return fpu_xmm14;
+ case gcc_dwarf_fpu_xmm15: return fpu_xmm15;
+ case gcc_dwarf_fpu_stmm0: return fpu_stmm0;
+ case gcc_dwarf_fpu_stmm1: return fpu_stmm1;
+ case gcc_dwarf_fpu_stmm2: return fpu_stmm2;
+ case gcc_dwarf_fpu_stmm3: return fpu_stmm3;
+ case gcc_dwarf_fpu_stmm4: return fpu_stmm4;
+ case gcc_dwarf_fpu_stmm5: return fpu_stmm5;
+ case gcc_dwarf_fpu_stmm6: return fpu_stmm6;
+ case gcc_dwarf_fpu_stmm7: return fpu_stmm7;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindGDB)
+ {
+ switch (reg)
+ {
+ case gdb_gpr_rax : return gpr_rax;
+ case gdb_gpr_rbx : return gpr_rbx;
+ case gdb_gpr_rcx : return gpr_rcx;
+ case gdb_gpr_rdx : return gpr_rdx;
+ case gdb_gpr_rsi : return gpr_rsi;
+ case gdb_gpr_rdi : return gpr_rdi;
+ case gdb_gpr_rbp : return gpr_rbp;
+ case gdb_gpr_rsp : return gpr_rsp;
+ case gdb_gpr_r8 : return gpr_r8;
+ case gdb_gpr_r9 : return gpr_r9;
+ case gdb_gpr_r10 : return gpr_r10;
+ case gdb_gpr_r11 : return gpr_r11;
+ case gdb_gpr_r12 : return gpr_r12;
+ case gdb_gpr_r13 : return gpr_r13;
+ case gdb_gpr_r14 : return gpr_r14;
+ case gdb_gpr_r15 : return gpr_r15;
+ case gdb_gpr_rip : return gpr_rip;
+ case gdb_gpr_rflags : return gpr_rflags;
+ case gdb_gpr_cs : return gpr_cs;
+ case gdb_gpr_ss : return gpr_gs; // HACK: For now for "ss", just copy what is in "gs"
+ case gdb_gpr_ds : return gpr_gs; // HACK: For now for "ds", just copy what is in "gs"
+ case gdb_gpr_es : return gpr_gs; // HACK: For now for "es", just copy what is in "gs"
+ case gdb_gpr_fs : return gpr_fs;
+ case gdb_gpr_gs : return gpr_gs;
+ case gdb_fpu_stmm0 : return fpu_stmm0;
+ case gdb_fpu_stmm1 : return fpu_stmm1;
+ case gdb_fpu_stmm2 : return fpu_stmm2;
+ case gdb_fpu_stmm3 : return fpu_stmm3;
+ case gdb_fpu_stmm4 : return fpu_stmm4;
+ case gdb_fpu_stmm5 : return fpu_stmm5;
+ case gdb_fpu_stmm6 : return fpu_stmm6;
+ case gdb_fpu_stmm7 : return fpu_stmm7;
+ case gdb_fpu_fctrl : return fpu_fctrl;
+ case gdb_fpu_fstat : return fpu_fstat;
+ case gdb_fpu_ftag : return fpu_ftag;
+ case gdb_fpu_fiseg : return fpu_fiseg;
+ case gdb_fpu_fioff : return fpu_fioff;
+ case gdb_fpu_foseg : return fpu_foseg;
+ case gdb_fpu_fooff : return fpu_fooff;
+ case gdb_fpu_fop : return fpu_fop;
+ case gdb_fpu_xmm0 : return fpu_xmm0;
+ case gdb_fpu_xmm1 : return fpu_xmm1;
+ case gdb_fpu_xmm2 : return fpu_xmm2;
+ case gdb_fpu_xmm3 : return fpu_xmm3;
+ case gdb_fpu_xmm4 : return fpu_xmm4;
+ case gdb_fpu_xmm5 : return fpu_xmm5;
+ case gdb_fpu_xmm6 : return fpu_xmm6;
+ case gdb_fpu_xmm7 : return fpu_xmm7;
+ case gdb_fpu_xmm8 : return fpu_xmm8;
+ case gdb_fpu_xmm9 : return fpu_xmm9;
+ case gdb_fpu_xmm10 : return fpu_xmm10;
+ case gdb_fpu_xmm11 : return fpu_xmm11;
+ case gdb_fpu_xmm12 : return fpu_xmm12;
+ case gdb_fpu_xmm13 : return fpu_xmm13;
+ case gdb_fpu_xmm14 : return fpu_xmm14;
+ case gdb_fpu_xmm15 : return fpu_xmm15;
+ case gdb_fpu_mxcsr : return fpu_mxcsr;
+ default:
+ break;
+ }
+ }
+ else if (kind == eRegisterKindLLDB)
+ {
+ return reg;
+ }
+ return LLDB_INVALID_REGNUM;
+}
+
+bool
+RegisterContextDarwin_x86_64::HardwareSingleStep (bool enable)
+{
+ if (ReadGPR(true) != 0)
+ return false;
+
+ const uint64_t trace_bit = 0x100ull;
+ if (enable)
+ {
+
+ if (gpr.rflags & trace_bit)
+ return true; // trace bit is already set, there is nothing to do
+ else
+ gpr.rflags |= trace_bit;
+ }
+ else
+ {
+ if (gpr.rflags & trace_bit)
+ gpr.rflags &= ~trace_bit;
+ else
+ return true; // trace bit is clear, there is nothing to do
+ }
+
+ return WriteGPR() == 0;
+}
+
diff --git a/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h
new file mode 100644
index 000000000000..4b8127af997c
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDarwin_x86_64.h
@@ -0,0 +1,274 @@
+//===-- RegisterContextDarwin_x86_64.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextDarwin_x86_64_h_
+#define liblldb_RegisterContextDarwin_x86_64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+class RegisterContextDarwin_x86_64 : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextDarwin_x86_64 (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextDarwin_x86_64();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+ virtual bool
+ HardwareSingleStep (bool enable);
+
+ struct GPR
+ {
+ uint64_t rax;
+ uint64_t rbx;
+ uint64_t rcx;
+ uint64_t rdx;
+ uint64_t rdi;
+ uint64_t rsi;
+ uint64_t rbp;
+ uint64_t rsp;
+ uint64_t r8;
+ uint64_t r9;
+ uint64_t r10;
+ uint64_t r11;
+ uint64_t r12;
+ uint64_t r13;
+ uint64_t r14;
+ uint64_t r15;
+ uint64_t rip;
+ uint64_t rflags;
+ uint64_t cs;
+ uint64_t fs;
+ uint64_t gs;
+ };
+
+ struct MMSReg
+ {
+ uint8_t bytes[10];
+ uint8_t pad[6];
+ };
+
+ struct XMMReg
+ {
+ uint8_t bytes[16];
+ };
+
+ struct FPU
+ {
+ uint32_t pad[2];
+ uint16_t fcw; // "fctrl"
+ uint16_t fsw; // "fstat"
+ uint8_t ftw; // "ftag"
+ uint8_t pad1;
+ uint16_t fop; // "fop"
+ uint32_t ip; // "fioff"
+ uint16_t cs; // "fiseg"
+ uint16_t pad2;
+ uint32_t dp; // "fooff"
+ uint16_t ds; // "foseg"
+ uint16_t pad3;
+ uint32_t mxcsr;
+ uint32_t mxcsrmask;
+ MMSReg stmm[8];
+ XMMReg xmm[16];
+ uint8_t pad4[6*16];
+ int pad5;
+ };
+
+ struct EXC
+ {
+ uint32_t trapno;
+ uint32_t err;
+ uint64_t faultvaddr;
+ };
+
+protected:
+
+ enum
+ {
+ GPRRegSet = 4,
+ FPURegSet = 5,
+ EXCRegSet = 6
+ };
+
+ enum
+ {
+ GPRWordCount = sizeof(GPR)/sizeof(uint32_t),
+ FPUWordCount = sizeof(FPU)/sizeof(uint32_t),
+ EXCWordCount = sizeof(EXC)/sizeof(uint32_t)
+ };
+
+ enum
+ {
+ Read = 0,
+ Write = 1,
+ kNumErrors = 2
+ };
+
+ GPR gpr;
+ FPU fpu;
+ EXC exc;
+ int gpr_errs[2]; // Read/Write errors
+ int fpu_errs[2]; // Read/Write errors
+ int exc_errs[2]; // Read/Write errors
+
+ void
+ InvalidateAllRegisterStates()
+ {
+ SetError (GPRRegSet, Read, -1);
+ SetError (FPURegSet, Read, -1);
+ SetError (EXCRegSet, Read, -1);
+ }
+
+ int
+ GetError (int flavor, uint32_t err_idx) const
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ // When getting all errors, just OR all values together to see if
+ // we got any kind of error.
+ case GPRRegSet: return gpr_errs[err_idx];
+ case FPURegSet: return fpu_errs[err_idx];
+ case EXCRegSet: return exc_errs[err_idx];
+ default: break;
+ }
+ }
+ return -1;
+ }
+
+ bool
+ SetError (int flavor, uint32_t err_idx, int err)
+ {
+ if (err_idx < kNumErrors)
+ {
+ switch (flavor)
+ {
+ case GPRRegSet:
+ gpr_errs[err_idx] = err;
+ return true;
+
+ case FPURegSet:
+ fpu_errs[err_idx] = err;
+ return true;
+
+ case EXCRegSet:
+ exc_errs[err_idx] = err;
+ return true;
+
+ default: break;
+ }
+ }
+ return false;
+ }
+
+ bool
+ RegisterSetIsCached (int set) const
+ {
+ return GetError(set, Read) == 0;
+ }
+
+ void
+ LogGPR (lldb_private::Log *log, const char *format, ...);
+
+ int
+ ReadGPR (bool force);
+
+ int
+ ReadFPU (bool force);
+
+ int
+ ReadEXC (bool force);
+
+ int
+ WriteGPR ();
+
+ int
+ WriteFPU ();
+
+ int
+ WriteEXC ();
+
+ // Subclasses override these to do the actual reading.
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr) = 0;
+
+ virtual int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu) = 0;
+
+ virtual int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc) = 0;
+
+ virtual int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr) = 0;
+
+ virtual int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu) = 0;
+
+ virtual int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc) = 0;
+
+ int
+ ReadRegisterSet (uint32_t set, bool force);
+
+ int
+ WriteRegisterSet (uint32_t set);
+
+ static uint32_t
+ GetRegisterNumber (uint32_t reg_kind, uint32_t reg_num);
+
+ static int
+ GetSetForNativeRegNum (int reg_num);
+
+ static size_t
+ GetRegisterInfosCount ();
+
+ static const lldb_private::RegisterInfo *
+ GetRegisterInfos ();
+
+};
+
+#endif // liblldb_RegisterContextDarwin_x86_64_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextDummy.cpp b/source/Plugins/Process/Utility/RegisterContextDummy.cpp
new file mode 100644
index 000000000000..1e282ce74f2e
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDummy.cpp
@@ -0,0 +1,137 @@
+//===-- RegisterContextDummy.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "RegisterContextDummy.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextDummy::RegisterContextDummy (Thread &thread, uint32_t concrete_frame_idx, uint32_t address_byte_size) :
+RegisterContext (thread, concrete_frame_idx)
+{
+ m_reg_set0.name = "General Purpose Registers";
+ m_reg_set0.short_name = "GPR";
+ m_reg_set0.num_registers = 1;
+ m_reg_set0.registers = new uint32_t(0);
+
+ m_pc_reg_info.name = "pc";
+ m_pc_reg_info.alt_name = "pc";
+ m_pc_reg_info.byte_offset = 0;
+ m_pc_reg_info.byte_size = address_byte_size;
+ m_pc_reg_info.encoding = eEncodingUint;
+ m_pc_reg_info.format = eFormatPointer;
+ m_pc_reg_info.invalidate_regs = NULL;
+ m_pc_reg_info.value_regs = NULL;
+ m_pc_reg_info.kinds[eRegisterKindGCC] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindDWARF] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC;
+ m_pc_reg_info.kinds[eRegisterKindGDB] = LLDB_INVALID_REGNUM;
+ m_pc_reg_info.kinds[eRegisterKindLLDB] = LLDB_INVALID_REGNUM;
+}
+
+RegisterContextDummy::~RegisterContextDummy ()
+{
+ delete m_reg_set0.registers;
+ delete m_pc_reg_info.invalidate_regs;
+ delete m_pc_reg_info.value_regs;
+}
+
+void
+RegisterContextDummy::InvalidateAllRegisters () {}
+
+size_t
+RegisterContextDummy::GetRegisterCount ()
+{
+ return 1;
+}
+
+const lldb_private::RegisterInfo *
+RegisterContextDummy::GetRegisterInfoAtIndex (size_t reg)
+{
+ if (reg)
+ return NULL;
+ return &m_pc_reg_info;
+}
+
+size_t
+RegisterContextDummy::GetRegisterSetCount ()
+{
+ return 1;
+}
+
+const lldb_private::RegisterSet *
+RegisterContextDummy::GetRegisterSet (size_t reg_set)
+{
+ if (reg_set)
+ return NULL;
+ return &m_reg_set0;
+}
+
+bool
+RegisterContextDummy::ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value)
+{
+ if (!reg_info)
+ return false;
+ uint32_t reg_number = reg_info->kinds[eRegisterKindGeneric];
+ if (reg_number == LLDB_REGNUM_GENERIC_PC)
+ {
+ value.SetUInt(LLDB_INVALID_ADDRESS, reg_info->byte_size);
+ return true;
+ }
+ return false;
+}
+
+bool
+RegisterContextDummy::WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextDummy::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextDummy::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+uint32_t
+RegisterContextDummy::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ if (kind == eRegisterKindGeneric && num == LLDB_REGNUM_GENERIC_PC)
+ return 0;
+ return LLDB_INVALID_REGNUM;
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextDummy.h b/source/Plugins/Process/Utility/RegisterContextDummy.h
new file mode 100644
index 000000000000..ee8d5a134bbc
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextDummy.h
@@ -0,0 +1,77 @@
+//===-- RegisterContextDummy.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterContextDummy_h_
+#define lldb_RegisterContextDummy_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+namespace lldb_private {
+
+class RegisterContextDummy : public lldb_private::RegisterContext
+{
+public:
+ typedef std::shared_ptr<RegisterContextDummy> SharedPtr;
+
+ RegisterContextDummy (Thread &thread, uint32_t concrete_frame_idx, uint32_t address_byte_size);
+
+ ///
+ // pure virtual functions from the base class that we must implement
+ ///
+
+ virtual
+ ~RegisterContextDummy ();
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+private:
+ //------------------------------------------------------------------
+ // For RegisterContextLLDB only
+ //------------------------------------------------------------------
+
+ lldb_private::RegisterSet m_reg_set0; // register set 0 (PC only)
+ lldb_private::RegisterInfo m_pc_reg_info;
+
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextDummy);
+};
+} // namespace lldb_private
+
+#endif // lldb_RegisterContextDummy_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.cpp b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
new file mode 100644
index 000000000000..1ffc30da5762
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextLLDB.cpp
@@ -0,0 +1,1541 @@
+//===-- RegisterContextLLDB.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/AddressRange.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/DWARFCallFrameInfo.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/ABI.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StackFrame.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/DynamicLoader.h"
+
+#include "RegisterContextLLDB.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextLLDB::RegisterContextLLDB
+(
+ Thread& thread,
+ const SharedPtr &next_frame,
+ SymbolContext& sym_ctx,
+ uint32_t frame_number,
+ UnwindLLDB& unwind_lldb
+) :
+ RegisterContext (thread, frame_number),
+ m_thread(thread),
+ m_fast_unwind_plan_sp (),
+ m_full_unwind_plan_sp (),
+ m_all_registers_available(false),
+ m_frame_type (-1),
+ m_cfa (LLDB_INVALID_ADDRESS),
+ m_start_pc (),
+ m_current_pc (),
+ m_current_offset (0),
+ m_current_offset_backed_up_one (0),
+ m_sym_ctx(sym_ctx),
+ m_sym_ctx_valid (false),
+ m_frame_number (frame_number),
+ m_registers(),
+ m_parent_unwind (unwind_lldb)
+{
+ m_sym_ctx.Clear(false);
+ m_sym_ctx_valid = false;
+
+ if (IsFrameZero ())
+ {
+ InitializeZerothFrame ();
+ }
+ else
+ {
+ InitializeNonZerothFrame ();
+ }
+
+ // This same code exists over in the GetFullUnwindPlanForFrame() but it may not have been executed yet
+ if (IsFrameZero()
+ || next_frame->m_frame_type == eSigtrampFrame
+ || next_frame->m_frame_type == eDebuggerFrame)
+ {
+ m_all_registers_available = true;
+ }
+}
+
+// Initialize a RegisterContextLLDB which is the first frame of a stack -- the zeroth frame or currently
+// executing frame.
+
+void
+RegisterContextLLDB::InitializeZerothFrame()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ RegisterContextSP reg_ctx_sp = m_thread.GetRegisterContext();
+
+ if (reg_ctx_sp.get() == NULL)
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ addr_t current_pc = reg_ctx_sp->GetPC();
+
+ if (current_pc == LLDB_INVALID_ADDRESS)
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ Process *process = exe_ctx.GetProcessPtr();
+
+ // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
+ // this will strip bit zero in case we read a PC from memory or from the LR.
+ // (which would be a no-op in frame 0 where we get it from the register set,
+ // but still a good idea to make the call here for other ABIs that may exist.)
+ ABI *abi = process->GetABI().get();
+ if (abi)
+ current_pc = abi->FixCodeAddress(current_pc);
+
+ // Initialize m_current_pc, an Address object, based on current_pc, an addr_t.
+ process->GetTarget().GetSectionLoadList().ResolveLoadAddress (current_pc, m_current_pc);
+
+ // If we don't have a Module for some reason, we're not going to find symbol/function information - just
+ // stick in some reasonable defaults and hope we can unwind past this frame.
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp)
+ {
+ UnwindLogMsg ("using architectural default unwind method");
+ }
+
+ // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us.
+ if (pc_module_sp.get()
+ && (pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
+ {
+ m_sym_ctx_valid = true;
+ }
+
+ AddressRange addr_range;
+ m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range);
+
+ static ConstString g_sigtramp_name ("_sigtramp");
+ if ((m_sym_ctx.function && m_sym_ctx.function->GetName() == g_sigtramp_name) ||
+ (m_sym_ctx.symbol && m_sym_ctx.symbol->GetName() == g_sigtramp_name))
+ {
+ m_frame_type = eSigtrampFrame;
+ }
+ else
+ {
+ // FIXME: Detect eDebuggerFrame here.
+ m_frame_type = eNormalFrame;
+ }
+
+ // If we were able to find a symbol/function, set addr_range to the bounds of that symbol/function.
+ // else treat the current pc value as the start_pc and record no offset.
+ if (addr_range.GetBaseAddress().IsValid())
+ {
+ m_start_pc = addr_range.GetBaseAddress();
+ if (m_current_pc.GetSection() == m_start_pc.GetSection())
+ {
+ m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset();
+ }
+ else if (m_current_pc.GetModule() == m_start_pc.GetModule())
+ {
+ // This means that whatever symbol we kicked up isn't really correct
+ // --- we should not cross section boundaries ... We really should NULL out
+ // the function/symbol in this case unless there is a bad assumption
+ // here due to inlined functions?
+ m_current_offset = m_current_pc.GetFileAddress() - m_start_pc.GetFileAddress();
+ }
+ m_current_offset_backed_up_one = m_current_offset;
+ }
+ else
+ {
+ m_start_pc = m_current_pc;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ }
+
+ // We've set m_frame_type and m_sym_ctx before these calls.
+
+ m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame ();
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
+
+ UnwindPlan::RowSP active_row;
+ int cfa_offset = 0;
+ int row_register_kind = -1;
+ if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+ if (active_row.get() && log)
+ {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg ("%s", active_row_strm.GetString().c_str());
+ }
+ }
+
+ if (!active_row.get())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+
+ addr_t cfa_regval = LLDB_INVALID_ADDRESS;
+ if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ cfa_offset = active_row->GetCFAOffset ();
+ m_cfa = cfa_regval + cfa_offset;
+
+ UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset);
+ UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64 " using %s UnwindPlan",
+ (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()),
+ (uint64_t) m_cfa,
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+}
+
+// Initialize a RegisterContextLLDB for the non-zeroth frame -- rely on the RegisterContextLLDB "below" it
+// to provide things like its current pc value.
+
+void
+RegisterContextLLDB::InitializeNonZerothFrame()
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (IsFrameZero ())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ if (!GetNextFrame().get() || !GetNextFrame()->IsValid())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ if (!m_thread.GetRegisterContext())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ addr_t pc;
+ if (!ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc))
+ {
+ UnwindLogMsg ("could not get pc value");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ if (log)
+ {
+ UnwindLogMsg ("pc = 0x%16.16" PRIx64, pc);
+ addr_t reg_val;
+ if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP, reg_val))
+ UnwindLogMsg ("fp = 0x%16.16" PRIx64, reg_val);
+ if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, reg_val))
+ UnwindLogMsg ("sp = 0x%16.16" PRIx64, reg_val);
+ }
+
+ // A pc of 0x0 means it's the end of the stack crawl
+ if (pc == 0)
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ // Let ABIs fixup code addresses to make sure they are valid. In ARM ABIs
+ // this will strip bit zero in case we read a PC from memory or from the LR.
+ ABI *abi = process->GetABI().get();
+ if (abi)
+ pc = abi->FixCodeAddress(pc);
+
+ process->GetTarget().GetSectionLoadList().ResolveLoadAddress (pc, m_current_pc);
+
+ // If we don't have a Module for some reason, we're not going to find symbol/function information - just
+ // stick in some reasonable defaults and hope we can unwind past this frame.
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp)
+ {
+ UnwindLogMsg ("using architectural default unwind method");
+
+ // Test the pc value to see if we know it's in an unmapped/non-executable region of memory.
+ uint32_t permissions;
+ if (process->GetLoadAddressPermissions(pc, permissions)
+ && (permissions & ePermissionsExecutable) == 0)
+ {
+ // If this is the second frame off the stack, we may have unwound the first frame
+ // incorrectly. But using the architecture default unwind plan may get us back on
+ // track -- albeit possibly skipping a real frame. Give this frame a clearly-invalid
+ // pc and see if we can get any further.
+ if (GetNextFrame().get() && GetNextFrame()->IsValid() && GetNextFrame()->IsFrameZero())
+ {
+ UnwindLogMsg ("had a pc of 0x%" PRIx64 " which is not in executable memory but on frame 1 -- allowing it once.",
+ (uint64_t) pc);
+ m_frame_type = eSkipFrame;
+ }
+ else
+ {
+ // anywhere other than the second frame, a non-executable pc means we're off in the weeds -- stop now.
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ }
+
+ if (abi)
+ {
+ m_fast_unwind_plan_sp.reset ();
+ m_full_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateDefaultUnwindPlan(*m_full_unwind_plan_sp);
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNormalFrame;
+ }
+ m_all_registers_available = false;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ addr_t cfa_regval = LLDB_INVALID_ADDRESS;
+ int row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+ UnwindPlan::RowSP row = m_full_unwind_plan_sp->GetRowForFunctionOffset(0);
+ if (row.get())
+ {
+ uint32_t cfa_regnum = row->GetCFARegister();
+ int cfa_offset = row->GetCFAOffset();
+ if (!ReadGPRValue (row_register_kind, cfa_regnum, cfa_regval))
+ {
+ UnwindLogMsg ("failed to get cfa value");
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNormalFrame;
+ }
+ return;
+ }
+ m_cfa = cfa_regval + cfa_offset;
+
+ // A couple of sanity checks..
+ if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1)
+ {
+ UnwindLogMsg ("could not find a valid cfa address");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ // cfa_regval should point into the stack memory; if we can query memory region permissions,
+ // see if the memory is allocated & readable.
+ if (process->GetLoadAddressPermissions(cfa_regval, permissions)
+ && (permissions & ePermissionsReadable) == 0)
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ }
+ else
+ {
+ UnwindLogMsg ("could not find a row for function offset zero");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ UnwindLogMsg ("initialized frame cfa is 0x%" PRIx64, (uint64_t) m_cfa);
+ return;
+ }
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ // We require that eSymbolContextSymbol be successfully filled in or this context is of no use to us.
+ if ((pc_module_sp->ResolveSymbolContextForAddress (m_current_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
+ {
+ m_sym_ctx_valid = true;
+ }
+
+ AddressRange addr_range;
+ if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range))
+ {
+ m_sym_ctx_valid = false;
+ }
+
+ bool decr_pc_and_recompute_addr_range = false;
+
+ // If the symbol lookup failed...
+ if (m_sym_ctx_valid == false)
+ decr_pc_and_recompute_addr_range = true;
+
+ // Or if we're in the middle of the stack (and not "above" an asynchronous event like sigtramp),
+ // and our "current" pc is the start of a function...
+ if (m_sym_ctx_valid
+ && GetNextFrame()->m_frame_type != eSigtrampFrame
+ && GetNextFrame()->m_frame_type != eDebuggerFrame
+ && addr_range.GetBaseAddress().IsValid()
+ && addr_range.GetBaseAddress().GetSection() == m_current_pc.GetSection()
+ && addr_range.GetBaseAddress().GetOffset() == m_current_pc.GetOffset())
+ {
+ decr_pc_and_recompute_addr_range = true;
+ }
+
+ // We need to back up the pc by 1 byte and re-search for the Symbol to handle the case where the "saved pc"
+ // value is pointing to the next function, e.g. if a function ends with a CALL instruction.
+ // FIXME this may need to be an architectural-dependent behavior; if so we'll need to add a member function
+ // to the ABI plugin and consult that.
+ if (decr_pc_and_recompute_addr_range)
+ {
+ Address temporary_pc(m_current_pc);
+ temporary_pc.SetOffset(m_current_pc.GetOffset() - 1);
+ m_sym_ctx.Clear(false);
+ m_sym_ctx_valid = false;
+ if ((pc_module_sp->ResolveSymbolContextForAddress (temporary_pc, eSymbolContextFunction| eSymbolContextSymbol, m_sym_ctx) & eSymbolContextSymbol) == eSymbolContextSymbol)
+ {
+ m_sym_ctx_valid = true;
+ }
+ if (!m_sym_ctx.GetAddressRange (eSymbolContextFunction | eSymbolContextSymbol, 0, false, addr_range))
+ {
+ m_sym_ctx_valid = false;
+ }
+ }
+
+ // If we were able to find a symbol/function, set addr_range_ptr to the bounds of that symbol/function.
+ // else treat the current pc value as the start_pc and record no offset.
+ if (addr_range.GetBaseAddress().IsValid())
+ {
+ m_start_pc = addr_range.GetBaseAddress();
+ m_current_offset = m_current_pc.GetOffset() - m_start_pc.GetOffset();
+ m_current_offset_backed_up_one = m_current_offset;
+ if (decr_pc_and_recompute_addr_range && m_current_offset_backed_up_one > 0)
+ {
+ m_current_offset_backed_up_one--;
+ if (m_sym_ctx_valid)
+ m_current_pc.SetOffset(m_current_pc.GetOffset() - 1);
+ }
+ }
+ else
+ {
+ m_start_pc = m_current_pc;
+ m_current_offset = -1;
+ m_current_offset_backed_up_one = -1;
+ }
+
+ static ConstString sigtramp_name ("_sigtramp");
+ if ((m_sym_ctx.function && m_sym_ctx.function->GetMangled().GetMangledName() == sigtramp_name)
+ || (m_sym_ctx.symbol && m_sym_ctx.symbol->GetMangled().GetMangledName() == sigtramp_name))
+ {
+ m_frame_type = eSigtrampFrame;
+ }
+ else
+ {
+ // FIXME: Detect eDebuggerFrame here.
+ if (m_frame_type != eSkipFrame) // don't override eSkipFrame
+ {
+ m_frame_type = eNormalFrame;
+ }
+ }
+
+ // We've set m_frame_type and m_sym_ctx before this call.
+ m_fast_unwind_plan_sp = GetFastUnwindPlanForFrame ();
+
+ UnwindPlan::RowSP active_row;
+ int cfa_offset = 0;
+ int row_register_kind = -1;
+
+ // Try to get by with just the fast UnwindPlan if possible - the full UnwindPlan may be expensive to get
+ // (e.g. if we have to parse the entire eh_frame section of an ObjectFile for the first time.)
+
+ if (m_fast_unwind_plan_sp && m_fast_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ row_register_kind = m_fast_unwind_plan_sp->GetRegisterKind ();
+ if (active_row.get() && log)
+ {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_fast_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg ("active row: %s", active_row_strm.GetString().c_str());
+ }
+ }
+ else
+ {
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
+ if (m_full_unwind_plan_sp && m_full_unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ row_register_kind = m_full_unwind_plan_sp->GetRegisterKind ();
+ if (active_row.get() && log)
+ {
+ StreamString active_row_strm;
+ active_row->Dump(active_row_strm, m_full_unwind_plan_sp.get(), &m_thread, m_start_pc.GetLoadAddress(exe_ctx.GetTargetPtr()));
+ UnwindLogMsg ("active row: %s", active_row_strm.GetString().c_str());
+ }
+ }
+ }
+
+ if (!active_row.get())
+ {
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ addr_t cfa_regval = LLDB_INVALID_ADDRESS;
+ if (!ReadGPRValue (row_register_kind, active_row->GetCFARegister(), cfa_regval))
+ {
+ UnwindLogMsg ("failed to get cfa reg %d/%d", row_register_kind, active_row->GetCFARegister());
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ cfa_offset = active_row->GetCFAOffset ();
+ m_cfa = cfa_regval + cfa_offset;
+
+ UnwindLogMsg ("cfa_regval = 0x%16.16" PRIx64 " (cfa_regval = 0x%16.16" PRIx64 ", cfa_offset = %i)", m_cfa, cfa_regval, cfa_offset);
+
+ // A couple of sanity checks..
+ if (cfa_regval == LLDB_INVALID_ADDRESS || cfa_regval == 0 || cfa_regval == 1)
+ {
+ UnwindLogMsg ("could not find a valid cfa address");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+
+ // If we have a bad stack setup, we can get the same CFA value multiple times -- or even
+ // more devious, we can actually oscillate between two CFA values. Detect that here and
+ // break out to avoid a possible infinite loop in lldb trying to unwind the stack.
+ addr_t next_frame_cfa;
+ addr_t next_next_frame_cfa = LLDB_INVALID_ADDRESS;
+ if (GetNextFrame().get() && GetNextFrame()->GetCFA(next_frame_cfa))
+ {
+ bool repeating_frames = false;
+ if (next_frame_cfa == m_cfa)
+ {
+ repeating_frames = true;
+ }
+ else
+ {
+ if (GetNextFrame()->GetNextFrame() && GetNextFrame()->GetNextFrame()->GetCFA(next_next_frame_cfa)
+ && next_next_frame_cfa == m_cfa)
+ {
+ repeating_frames = true;
+ }
+ }
+ if (repeating_frames && abi->FunctionCallsChangeCFA())
+ {
+ UnwindLogMsg ("same CFA address as next frame, assuming the unwind is looping - stopping");
+ m_frame_type = eNotAValidFrame;
+ return;
+ }
+ }
+
+ UnwindLogMsg ("initialized frame current pc is 0x%" PRIx64 " cfa is 0x%" PRIx64,
+ (uint64_t) m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr()), (uint64_t) m_cfa);
+}
+
+
+bool
+RegisterContextLLDB::IsFrameZero () const
+{
+ return m_frame_number == 0;
+}
+
+
+// Find a fast unwind plan for this frame, if possible.
+//
+// On entry to this method,
+//
+// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct,
+// 2. m_sym_ctx should already be filled in, and
+// 3. m_current_pc should have the current pc value for this frame
+// 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown
+
+UnwindPlanSP
+RegisterContextLLDB::GetFastUnwindPlanForFrame ()
+{
+ UnwindPlanSP unwind_plan_sp;
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+
+ if (!m_current_pc.IsValid() || !pc_module_sp || pc_module_sp->GetObjectFile() == NULL)
+ return unwind_plan_sp;
+
+ if (IsFrameZero ())
+ return unwind_plan_sp;
+
+ FuncUnwindersSP func_unwinders_sp (pc_module_sp->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx));
+ if (!func_unwinders_sp)
+ return unwind_plan_sp;
+
+ // If we're in _sigtramp(), unwinding past this frame requires special knowledge.
+ if (m_frame_type == eSigtrampFrame || m_frame_type == eDebuggerFrame)
+ return unwind_plan_sp;
+
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanFastUnwind (m_thread);
+ if (unwind_plan_sp)
+ {
+ if (unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log && log->GetVerbose())
+ {
+ if (m_fast_unwind_plan_sp)
+ UnwindLogMsgVerbose ("frame, and has a fast UnwindPlan");
+ else
+ UnwindLogMsgVerbose ("frame");
+ }
+ m_frame_type = eNormalFrame;
+ return unwind_plan_sp;
+ }
+ else
+ {
+ unwind_plan_sp.reset();
+ }
+ }
+ return unwind_plan_sp;
+}
+
+// On entry to this method,
+//
+// 1. m_frame_type should already be set to eSigtrampFrame/eDebuggerFrame if either of those are correct,
+// 2. m_sym_ctx should already be filled in, and
+// 3. m_current_pc should have the current pc value for this frame
+// 4. m_current_offset_backed_up_one should have the current byte offset into the function, maybe backed up by 1, -1 if unknown
+
+UnwindPlanSP
+RegisterContextLLDB::GetFullUnwindPlanForFrame ()
+{
+ UnwindPlanSP unwind_plan_sp;
+ UnwindPlanSP arch_default_unwind_plan_sp;
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ ABI *abi = process ? process->GetABI().get() : NULL;
+ if (abi)
+ {
+ arch_default_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp);
+ }
+
+ bool behaves_like_zeroth_frame = false;
+ if (IsFrameZero ()
+ || GetNextFrame()->m_frame_type == eSigtrampFrame
+ || GetNextFrame()->m_frame_type == eDebuggerFrame)
+ {
+ behaves_like_zeroth_frame = true;
+ // If this frame behaves like a 0th frame (currently executing or
+ // interrupted asynchronously), all registers can be retrieved.
+ m_all_registers_available = true;
+ }
+
+ // If we've done a jmp 0x0 / bl 0x0 (called through a null function pointer) so the pc is 0x0
+ // in the zeroth frame, we need to use the "unwind at first instruction" arch default UnwindPlan
+ // Also, if this Process can report on memory region attributes, any non-executable region means
+ // we jumped through a bad function pointer - handle the same way as 0x0.
+ // Note, if the symbol context has a function for the symbol, then we don't need to do this check.
+
+ if ((!m_sym_ctx_valid || m_sym_ctx.function == NULL) && behaves_like_zeroth_frame && m_current_pc.IsValid())
+ {
+ uint32_t permissions;
+ addr_t current_pc_addr = m_current_pc.GetLoadAddress (exe_ctx.GetTargetPtr());
+ if (current_pc_addr == 0
+ || (process->GetLoadAddressPermissions(current_pc_addr, permissions)
+ && (permissions & ePermissionsExecutable) == 0))
+ {
+ unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateFunctionEntryUnwindPlan(*unwind_plan_sp);
+ m_frame_type = eNormalFrame;
+ return unwind_plan_sp;
+ }
+ }
+
+ // No Module for the current pc, try using the architecture default unwind.
+ ModuleSP pc_module_sp (m_current_pc.GetModule());
+ if (!m_current_pc.IsValid() || !pc_module_sp || pc_module_sp->GetObjectFile() == NULL)
+ {
+ m_frame_type = eNormalFrame;
+ return arch_default_unwind_plan_sp;
+ }
+
+ FuncUnwindersSP func_unwinders_sp;
+ if (m_sym_ctx_valid)
+ {
+ func_unwinders_sp = pc_module_sp->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx);
+ }
+
+ // No FuncUnwinders available for this pc (i.e. a stripped function symbol and -fomit-frame-pointer).
+ // Try using the eh_frame information relative to the current PC,
+ // and finally fall back on the architectural default unwind.
+ if (!func_unwinders_sp)
+ {
+ DWARFCallFrameInfo *eh_frame = pc_module_sp && pc_module_sp->GetObjectFile() ?
+ pc_module_sp->GetObjectFile()->GetUnwindTable().GetEHFrameInfo() : nullptr;
+
+ m_frame_type = eNormalFrame;
+ if (eh_frame && m_current_pc.IsValid())
+ {
+ unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ // Even with -fomit-frame-pointer, we can try eh_frame to get back on track.
+ if (eh_frame->GetUnwindPlan (m_current_pc, *unwind_plan_sp))
+ return unwind_plan_sp;
+ else
+ unwind_plan_sp.reset();
+ }
+ return arch_default_unwind_plan_sp;
+ }
+
+ // If we're in _sigtramp(), unwinding past this frame requires special knowledge. On Mac OS X this knowledge
+ // is properly encoded in the eh_frame section, so prefer that if available.
+ // On other platforms we may need to provide a platform-specific UnwindPlan which encodes the details of
+ // how to unwind out of sigtramp.
+ if (m_frame_type == eSigtrampFrame)
+ {
+ m_fast_unwind_plan_sp.reset();
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ return unwind_plan_sp;
+ }
+
+ // Ask the DynamicLoader if the eh_frame CFI should be trusted in this frame even when it's frame zero
+ // This comes up if we have hand-written functions in a Module and hand-written eh_frame. The assembly
+ // instruction inspection may fail and the eh_frame CFI were probably written with some care to do the
+ // right thing. It'd be nice if there was a way to ask the eh_frame directly if it is asynchronous
+ // (can be trusted at every instruction point) or synchronous (the normal case - only at call sites).
+ // But there is not.
+ if (process && process->GetDynamicLoader() && process->GetDynamicLoader()->AlwaysRelyOnEHUnwindInfo (m_sym_ctx))
+ {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan because the DynamicLoader suggested we prefer it",
+ unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+ }
+
+ // Typically the NonCallSite UnwindPlan is the unwind created by inspecting the assembly language instructions
+ if (behaves_like_zeroth_frame)
+ {
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+ }
+
+ // Typically this is unwind info from an eh_frame section intended for exception handling; only valid at call sites
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtCallSite (m_current_offset_backed_up_one);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+
+ // We'd prefer to use an UnwindPlan intended for call sites when we're at a call site but if we've
+ // struck out on that, fall back to using the non-call-site assembly inspection UnwindPlan if possible.
+ unwind_plan_sp = func_unwinders_sp->GetUnwindPlanAtNonCallSite (m_thread);
+ if (unwind_plan_sp && unwind_plan_sp->PlanValidAtAddress (m_current_pc))
+ {
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", unwind_plan_sp->GetSourceName().GetCString());
+ return unwind_plan_sp;
+ }
+
+ // If nothing else, use the architectural default UnwindPlan and hope that does the job.
+ UnwindLogMsgVerbose ("frame uses %s for full UnwindPlan", arch_default_unwind_plan_sp->GetSourceName().GetCString());
+ return arch_default_unwind_plan_sp;
+}
+
+
+void
+RegisterContextLLDB::InvalidateAllRegisters ()
+{
+ m_frame_type = eNotAValidFrame;
+}
+
+size_t
+RegisterContextLLDB::GetRegisterCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterCount();
+}
+
+const RegisterInfo *
+RegisterContextLLDB::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex (reg);
+}
+
+size_t
+RegisterContextLLDB::GetRegisterSetCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterSetCount ();
+}
+
+const RegisterSet *
+RegisterContextLLDB::GetRegisterSet (size_t reg_set)
+{
+ return m_thread.GetRegisterContext()->GetRegisterSet (reg_set);
+}
+
+uint32_t
+RegisterContextLLDB::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
+bool
+RegisterContextLLDB::ReadRegisterValueFromRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+ bool success = false;
+
+ switch (regloc.type)
+ {
+ case UnwindLLDB::RegisterLocation::eRegisterInRegister:
+ {
+ const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
+
+ if (!other_reg_info)
+ return false;
+
+ if (IsFrameZero ())
+ {
+ success = m_thread.GetRegisterContext()->ReadRegister (other_reg_info, value);
+ }
+ else
+ {
+ success = GetNextFrame()->ReadRegister (other_reg_info, value);
+ }
+ }
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterValueInferred:
+ success = value.SetUInt (regloc.location.inferred_value, reg_info->byte_size);
+ break;
+
+ case UnwindLLDB::RegisterLocation::eRegisterNotSaved:
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
+ assert ("FIXME debugger inferior function call unwind");
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation:
+ {
+ Error error (ReadRegisterValueFromMemory(reg_info,
+ regloc.location.target_memory_location,
+ reg_info->byte_size,
+ value));
+ success = error.Success();
+ }
+ break;
+ default:
+ assert ("Unknown RegisterLocation type.");
+ break;
+ }
+ return success;
+}
+
+bool
+RegisterContextLLDB::WriteRegisterValueToRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+
+ bool success = false;
+
+ switch (regloc.type)
+ {
+ case UnwindLLDB::RegisterLocation::eRegisterInRegister:
+ {
+ const RegisterInfo *other_reg_info = GetRegisterInfoAtIndex(regloc.location.register_number);
+ if (IsFrameZero ())
+ {
+ success = m_thread.GetRegisterContext()->WriteRegister (other_reg_info, value);
+ }
+ else
+ {
+ success = GetNextFrame()->WriteRegister (other_reg_info, value);
+ }
+ }
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterValueInferred:
+ case UnwindLLDB::RegisterLocation::eRegisterNotSaved:
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtHostMemoryLocation:
+ assert ("FIXME debugger inferior function call unwind");
+ break;
+ case UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation:
+ {
+ Error error (WriteRegisterValueToMemory (reg_info,
+ regloc.location.target_memory_location,
+ reg_info->byte_size,
+ value));
+ success = error.Success();
+ }
+ break;
+ default:
+ assert ("Unknown RegisterLocation type.");
+ break;
+ }
+ return success;
+}
+
+
+bool
+RegisterContextLLDB::IsValid () const
+{
+ return m_frame_type != eNotAValidFrame;
+}
+
+// A skip frame is a bogus frame on the stack -- but one where we're likely to find a real frame farther
+// up the stack if we keep looking. It's always the second frame in an unwind (i.e. the first frame after
+// frame zero) where unwinding can be the trickiest. Ideally we'll mark up this frame in some way so the
+// user knows we're displaying bad data and we may have skipped one frame of their real program in the
+// process of getting back on track.
+
+bool
+RegisterContextLLDB::IsSkipFrame () const
+{
+ return m_frame_type == eSkipFrame;
+}
+
+// Answer the question: Where did THIS frame save the CALLER frame ("previous" frame)'s register value?
+
+enum UnwindLLDB::RegisterSearchResult
+RegisterContextLLDB::SavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc)
+{
+ // Have we already found this register location?
+ if (!m_registers.empty())
+ {
+ std::map<uint32_t, lldb_private::UnwindLLDB::RegisterLocation>::const_iterator iterator;
+ iterator = m_registers.find (lldb_regnum);
+ if (iterator != m_registers.end())
+ {
+ regloc = iterator->second;
+ UnwindLogMsg ("supplying caller's saved reg %d's location, cached", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+
+ uint32_t sp_regnum = LLDB_INVALID_REGNUM;
+ uint32_t pc_regnum = LLDB_INVALID_REGNUM;
+ m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, eRegisterKindLLDB, sp_regnum);
+ m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, eRegisterKindLLDB, pc_regnum);
+
+ // Are we looking for the CALLER's stack pointer? The stack pointer is defined to be the same as THIS frame's
+ // CFA so just return the CFA value. This is true on x86-32/x86-64 at least.
+ if (sp_regnum != LLDB_INVALID_REGNUM && sp_regnum == lldb_regnum)
+ {
+ // make sure we won't lose precision copying an addr_t (m_cfa) into a uint64_t (.inferred_value)
+ assert (sizeof (addr_t) <= sizeof (uint64_t));
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = m_cfa;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's stack pointer (%d) value, computed from CFA", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ // Look through the available UnwindPlans for the register location.
+
+ UnwindPlan::Row::RegisterLocation unwindplan_regloc;
+ bool have_unwindplan_regloc = false;
+ RegisterKind unwindplan_registerkind = (RegisterKind)-1;
+
+ if (m_fast_unwind_plan_sp)
+ {
+ UnwindPlan::RowSP active_row = m_fast_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ unwindplan_registerkind = m_fast_unwind_plan_sp->GetRegisterKind ();
+ uint32_t row_regnum;
+ if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum))
+ {
+ UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
+ lldb_regnum, (int) unwindplan_registerkind);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc))
+ {
+ UnwindLogMsg ("supplying caller's saved reg %d's location using FastUnwindPlan", lldb_regnum);
+ have_unwindplan_regloc = true;
+ }
+ }
+
+ if (!have_unwindplan_regloc)
+ {
+ // m_full_unwind_plan_sp being NULL means that we haven't tried to find a full UnwindPlan yet
+ if (!m_full_unwind_plan_sp)
+ m_full_unwind_plan_sp = GetFullUnwindPlanForFrame ();
+
+ if (m_full_unwind_plan_sp)
+ {
+ UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ unwindplan_registerkind = m_full_unwind_plan_sp->GetRegisterKind ();
+ uint32_t row_regnum;
+ bool row_register_rewritten_to_return_address_reg = false;
+
+ // If we're fetching the saved pc and this UnwindPlan defines a ReturnAddress register (e.g. lr on arm),
+ // look for the return address register number in the UnwindPlan's row.
+ if (lldb_regnum == pc_regnum && m_full_unwind_plan_sp->GetReturnAddressRegister() != LLDB_INVALID_REGNUM)
+ {
+ row_regnum = m_full_unwind_plan_sp->GetReturnAddressRegister();
+ row_register_rewritten_to_return_address_reg = true;
+ UnwindLogMsg ("requested caller's saved PC but this UnwindPlan uses a RA reg; getting reg %d instead",
+ row_regnum);
+ }
+ else
+ {
+ if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindLLDB, lldb_regnum, unwindplan_registerkind, row_regnum))
+ {
+ if (unwindplan_registerkind == eRegisterKindGeneric)
+ UnwindLogMsg ("could not convert lldb regnum %d into eRegisterKindGeneric reg numbering scheme", lldb_regnum);
+ else
+ UnwindLogMsg ("could not convert lldb regnum %d into %d RegisterKind reg numbering scheme",
+ lldb_regnum, (int) unwindplan_registerkind);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ }
+
+ if (active_row->GetRegisterInfo (row_regnum, unwindplan_regloc))
+ {
+ have_unwindplan_regloc = true;
+ UnwindLogMsg ("supplying caller's saved reg %d's location using %s UnwindPlan", lldb_regnum,
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+ }
+
+ // This is frame 0 and we're retrieving the PC and it's saved in a Return Address register and
+ // it hasn't been saved anywhere yet -- that is, it's still live in the actual register.
+ // Handle this specially.
+
+ if (have_unwindplan_regloc == false
+ && row_register_rewritten_to_return_address_reg == true
+ && IsFrameZero()
+ && row_regnum != LLDB_INVALID_REGNUM)
+ {
+ uint32_t ra_regnum_in_lldb_reg_numbering;
+ if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (unwindplan_registerkind, row_regnum, eRegisterKindLLDB, ra_regnum_in_lldb_reg_numbering))
+ {
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
+ new_regloc.location.register_number = ra_regnum_in_lldb_reg_numbering;
+ m_registers[lldb_regnum] = new_regloc;
+ regloc = new_regloc;
+ UnwindLogMsg ("supplying caller's register %d from the live RegisterContext at frame 0, saved in %d", lldb_regnum, ra_regnum_in_lldb_reg_numbering);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+
+ // If this architecture stores the return address in a register (it defines a Return Address register)
+ // and we're on a non-zero stack frame and the Full UnwindPlan says that the pc is stored in the
+ // RA registers (e.g. lr on arm), then we know that the full unwindplan is not trustworthy -- this
+ // is an impossible situation and the instruction emulation code has likely been misled.
+ // If this stack frame meets those criteria, we need to throw away the Full UnwindPlan that the
+ // instruction emulation came up with and fall back to the architecture's Default UnwindPlan so
+ // the stack walk can get past this point.
+
+ // Special note: If the Full UnwindPlan was generated from the compiler, don't second-guess it
+ // when we're at a call site location.
+
+ // arch_default_ra_regnum is the return address register # in the Full UnwindPlan register numbering
+ uint32_t arch_default_ra_regnum = LLDB_INVALID_REGNUM;
+ if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, unwindplan_registerkind, arch_default_ra_regnum)
+ && arch_default_ra_regnum != LLDB_INVALID_REGNUM
+ && pc_regnum != LLDB_INVALID_REGNUM
+ && pc_regnum == lldb_regnum
+ && unwindplan_regloc.IsInOtherRegister()
+ && unwindplan_regloc.GetRegisterNumber() == arch_default_ra_regnum
+ && m_full_unwind_plan_sp->GetSourcedFromCompiler() != eLazyBoolYes
+ && !m_all_registers_available)
+ {
+ UnwindLogMsg ("%s UnwindPlan tried to restore the pc from the link register but this is a non-zero frame",
+ m_full_unwind_plan_sp->GetSourceName().GetCString());
+
+ // Throw away the full unwindplan; install the arch default unwindplan
+ InvalidateFullUnwindPlan();
+
+ // Now re-fetch the pc value we're searching for
+ uint32_t arch_default_pc_reg = LLDB_INVALID_REGNUM;
+ UnwindPlan::RowSP active_row = m_full_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+ if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, m_full_unwind_plan_sp->GetRegisterKind(), arch_default_pc_reg)
+ && arch_default_pc_reg != LLDB_INVALID_REGNUM
+ && active_row
+ && active_row->GetRegisterInfo (arch_default_pc_reg, unwindplan_regloc))
+ {
+ have_unwindplan_regloc = true;
+ }
+ else
+ {
+ have_unwindplan_regloc = false;
+ }
+ }
+ }
+ }
+
+
+ ExecutionContext exe_ctx(m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ if (have_unwindplan_regloc == false)
+ {
+ // If a volatile register is being requested, we don't want to forward the next frame's register contents
+ // up the stack -- the register is not retrievable at this frame.
+ ABI *abi = process ? process->GetABI().get() : NULL;
+ if (abi)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum);
+ if (reg_info && abi->RegisterIsVolatile (reg_info))
+ {
+ UnwindLogMsg ("did not supply reg location for %d because it is volatile", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile;
+ }
+ }
+
+ if (IsFrameZero ())
+ {
+ // This is frame 0 - we should return the actual live register context value
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
+ new_regloc.location.register_number = lldb_regnum;
+ m_registers[lldb_regnum] = new_regloc;
+ regloc = new_regloc;
+ UnwindLogMsg ("supplying caller's register %d from the live RegisterContext at frame 0", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ else
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ // unwindplan_regloc has valid contents about where to retrieve the register
+ if (unwindplan_regloc.IsUnspecified())
+ {
+ lldb_private::UnwindLLDB::RegisterLocation new_regloc;
+ new_regloc.type = UnwindLLDB::RegisterLocation::eRegisterNotSaved;
+ m_registers[lldb_regnum] = new_regloc;
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ if (unwindplan_regloc.IsSame())
+ {
+ if (IsFrameZero ())
+ {
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ else
+ {
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ }
+
+ if (unwindplan_regloc.IsCFAPlusOffset())
+ {
+ int offset = unwindplan_regloc.GetOffset();
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = m_cfa + offset;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's register %d, value is CFA plus offset", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsAtCFAPlusOffset())
+ {
+ int offset = unwindplan_regloc.GetOffset();
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
+ regloc.location.target_memory_location = m_cfa + offset;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's register %d from the stack, saved at CFA plus offset", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsInOtherRegister())
+ {
+ uint32_t unwindplan_regnum = unwindplan_regloc.GetRegisterNumber();
+ uint32_t row_regnum_in_lldb;
+ if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (unwindplan_registerkind, unwindplan_regnum, eRegisterKindLLDB, row_regnum_in_lldb))
+ {
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterInRegister;
+ regloc.location.register_number = row_regnum_in_lldb;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's register %d, saved in register %d", lldb_regnum, row_regnum_in_lldb);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+
+ if (unwindplan_regloc.IsDWARFExpression() || unwindplan_regloc.IsAtDWARFExpression())
+ {
+ DataExtractor dwarfdata (unwindplan_regloc.GetDWARFExpressionBytes(),
+ unwindplan_regloc.GetDWARFExpressionLength(),
+ process->GetByteOrder(), process->GetAddressByteSize());
+ DWARFExpression dwarfexpr (dwarfdata, 0, unwindplan_regloc.GetDWARFExpressionLength());
+ dwarfexpr.SetRegisterKind (unwindplan_registerkind);
+ Value result;
+ Error error;
+ if (dwarfexpr.Evaluate (&exe_ctx, NULL, NULL, this, 0, NULL, result, &error))
+ {
+ addr_t val;
+ val = result.GetScalar().ULongLong();
+ if (unwindplan_regloc.IsDWARFExpression())
+ {
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterValueInferred;
+ regloc.location.inferred_value = val;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's register %d via DWARF expression (IsDWARFExpression)", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ else
+ {
+ regloc.type = UnwindLLDB::RegisterLocation::eRegisterSavedAtMemoryLocation;
+ regloc.location.target_memory_location = val;
+ m_registers[lldb_regnum] = regloc;
+ UnwindLogMsg ("supplying caller's register %d via DWARF expression (IsAtDWARFExpression)", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterFound;
+ }
+ }
+ UnwindLogMsg ("tried to use IsDWARFExpression or IsAtDWARFExpression for reg %d but failed", lldb_regnum);
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ }
+
+ UnwindLogMsg ("could not supply caller's reg %d location", lldb_regnum);
+
+ // FIXME UnwindPlan::Row types atDWARFExpression and isDWARFExpression are unsupported.
+
+ return UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+}
+
+// If the Full unwindplan has been determined to be incorrect, this method will
+// replace it with the architecture's default unwindplna, if one is defined.
+// It will also find the FuncUnwinders object for this function and replace the
+// Full unwind method for the function there so we don't use the errant Full unwindplan
+// again in the future of this debug session.
+// We're most likely doing this because the Full unwindplan was generated by assembly
+// instruction profiling and the profiler got something wrong.
+
+void
+RegisterContextLLDB::InvalidateFullUnwindPlan ()
+{
+ UnwindPlan::Row::RegisterLocation unwindplan_regloc;
+ ExecutionContext exe_ctx (m_thread.shared_from_this());
+ Process *process = exe_ctx.GetProcessPtr();
+ ABI *abi = process ? process->GetABI().get() : NULL;
+ if (abi)
+ {
+ UnwindPlanSP original_full_unwind_plan_sp = m_full_unwind_plan_sp;
+ UnwindPlanSP arch_default_unwind_plan_sp;
+ arch_default_unwind_plan_sp.reset (new UnwindPlan (lldb::eRegisterKindGeneric));
+ abi->CreateDefaultUnwindPlan(*arch_default_unwind_plan_sp);
+ if (arch_default_unwind_plan_sp)
+ {
+ UnwindPlan::RowSP active_row = arch_default_unwind_plan_sp->GetRowForFunctionOffset (m_current_offset);
+
+ if (active_row && active_row->GetCFARegister() != LLDB_INVALID_REGNUM)
+ {
+ FuncUnwindersSP func_unwinders_sp;
+ if (m_sym_ctx_valid && m_current_pc.IsValid() && m_current_pc.GetModule())
+ {
+ func_unwinders_sp = m_current_pc.GetModule()->GetObjectFile()->GetUnwindTable().GetFuncUnwindersContainingAddress (m_current_pc, m_sym_ctx);
+ if (func_unwinders_sp)
+ {
+ func_unwinders_sp->InvalidateNonCallSiteUnwindPlan (m_thread);
+ }
+ }
+ m_registers.clear();
+ m_full_unwind_plan_sp = arch_default_unwind_plan_sp;
+ addr_t cfa_regval = LLDB_INVALID_ADDRESS;
+ if (ReadGPRValue (arch_default_unwind_plan_sp->GetRegisterKind(), active_row->GetCFARegister(), cfa_regval))
+ {
+ m_cfa = cfa_regval + active_row->GetCFAOffset ();
+ }
+
+ UnwindLogMsg ("full unwind plan '%s' has been replaced by architecture default unwind plan '%s' for this function from now on.",
+ original_full_unwind_plan_sp->GetSourceName().GetCString(), arch_default_unwind_plan_sp->GetSourceName().GetCString());
+ }
+ }
+ }
+}
+
+// Retrieve a general purpose register value for THIS frame, as saved by the NEXT frame, i.e. the frame that
+// this frame called. e.g.
+//
+// foo () { }
+// bar () { foo (); }
+// main () { bar (); }
+//
+// stopped in foo() so
+// frame 0 - foo
+// frame 1 - bar
+// frame 2 - main
+// and this RegisterContext is for frame 1 (bar) - if we want to get the pc value for frame 1, we need to ask
+// where frame 0 (the "next" frame) saved that and retrieve the value.
+
+bool
+RegisterContextLLDB::ReadGPRValue (int register_kind, uint32_t regnum, addr_t &value)
+{
+ if (!IsValid())
+ return false;
+
+ uint32_t lldb_regnum;
+ if (register_kind == eRegisterKindLLDB)
+ {
+ lldb_regnum = regnum;
+ }
+ else if (!m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (register_kind, regnum, eRegisterKindLLDB, lldb_regnum))
+ {
+ return false;
+ }
+
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(lldb_regnum);
+ RegisterValue reg_value;
+ // if this is frame 0 (currently executing frame), get the requested reg contents from the actual thread registers
+ if (IsFrameZero ())
+ {
+ if (m_thread.GetRegisterContext()->ReadRegister (reg_info, reg_value))
+ {
+ value = reg_value.GetAsUInt64();
+ return true;
+ }
+ return false;
+ }
+
+ bool pc_register = false;
+ uint32_t generic_regnum;
+ if (register_kind == eRegisterKindGeneric && regnum == LLDB_REGNUM_GENERIC_PC)
+ {
+ pc_register = true;
+ }
+ else if (m_thread.GetRegisterContext()->ConvertBetweenRegisterKinds (register_kind, regnum, eRegisterKindGeneric, generic_regnum)
+ && generic_regnum == LLDB_REGNUM_GENERIC_PC)
+ {
+ pc_register = true;
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, pc_register))
+ {
+ return false;
+ }
+ if (ReadRegisterValueFromRegisterLocation (regloc, reg_info, reg_value))
+ {
+ value = reg_value.GetAsUInt64();
+ return true;
+ }
+ return false;
+}
+
+// Find the value of a register in THIS frame
+
+bool
+RegisterContextLLDB::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+
+ const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
+ UnwindLogMsgVerbose ("looking for register saved location for reg %d", lldb_regnum);
+
+ // If this is the 0th frame, hand this over to the live register context
+ if (IsFrameZero ())
+ {
+ UnwindLogMsgVerbose ("passing along to the live register context for reg %d", lldb_regnum);
+ return m_thread.GetRegisterContext()->ReadRegister (reg_info, value);
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ // Find out where the NEXT frame saved THIS frame's register contents
+ if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, false))
+ return false;
+
+ return ReadRegisterValueFromRegisterLocation (regloc, reg_info, value);
+}
+
+bool
+RegisterContextLLDB::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ if (!IsValid())
+ return false;
+
+ const uint32_t lldb_regnum = reg_info->kinds[eRegisterKindLLDB];
+ UnwindLogMsgVerbose ("looking for register saved location for reg %d", lldb_regnum);
+
+ // If this is the 0th frame, hand this over to the live register context
+ if (IsFrameZero ())
+ {
+ UnwindLogMsgVerbose ("passing along to the live register context for reg %d", lldb_regnum);
+ return m_thread.GetRegisterContext()->WriteRegister (reg_info, value);
+ }
+
+ lldb_private::UnwindLLDB::RegisterLocation regloc;
+ // Find out where the NEXT frame saved THIS frame's register contents
+ if (!m_parent_unwind.SearchForSavedLocationForRegister (lldb_regnum, regloc, m_frame_number - 1, false))
+ return false;
+
+ return WriteRegisterValueToRegisterLocation (regloc, reg_info, value);
+}
+
+// Don't need to implement this one
+bool
+RegisterContextLLDB::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+// Don't need to implement this one
+bool
+RegisterContextLLDB::WriteAllRegisterValues (const lldb::DataBufferSP& data_sp)
+{
+ return false;
+}
+
+// Retrieve the pc value for THIS from
+
+bool
+RegisterContextLLDB::GetCFA (addr_t& cfa)
+{
+ if (!IsValid())
+ {
+ return false;
+ }
+ if (m_cfa == LLDB_INVALID_ADDRESS)
+ {
+ return false;
+ }
+ cfa = m_cfa;
+ return true;
+}
+
+
+RegisterContextLLDB::SharedPtr
+RegisterContextLLDB::GetNextFrame () const
+{
+ RegisterContextLLDB::SharedPtr regctx;
+ if (m_frame_number == 0)
+ return regctx;
+ return m_parent_unwind.GetRegisterContextForFrameNum (m_frame_number - 1);
+}
+
+RegisterContextLLDB::SharedPtr
+RegisterContextLLDB::GetPrevFrame () const
+{
+ RegisterContextLLDB::SharedPtr regctx;
+ return m_parent_unwind.GetRegisterContextForFrameNum (m_frame_number + 1);
+}
+
+// Retrieve the address of the start of the function of THIS frame
+
+bool
+RegisterContextLLDB::GetStartPC (addr_t& start_pc)
+{
+ if (!IsValid())
+ return false;
+
+ if (!m_start_pc.IsValid())
+ {
+ return ReadPC (start_pc);
+ }
+ start_pc = m_start_pc.GetLoadAddress (CalculateTarget().get());
+ return true;
+}
+
+// Retrieve the current pc value for THIS frame, as saved by the NEXT frame.
+
+bool
+RegisterContextLLDB::ReadPC (addr_t& pc)
+{
+ if (!IsValid())
+ return false;
+
+ if (ReadGPRValue (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc))
+ {
+ // A pc value of 0 or 1 is impossible in the middle of the stack -- it indicates the end of a stack walk.
+ // On the currently executing frame (or such a frame interrupted asynchronously by sigtramp et al) this may
+ // occur if code has jumped through a NULL pointer -- we want to be able to unwind past that frame to help
+ // find the bug.
+
+ if (m_all_registers_available == false
+ && (pc == 0 || pc == 1))
+ {
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+void
+RegisterContextLLDB::UnwindLogMsg (const char *fmt, ...)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log)
+ {
+ va_list args;
+ va_start (args, fmt);
+
+ char *logmsg;
+ if (vasprintf (&logmsg, fmt, args) == -1 || logmsg == NULL)
+ {
+ if (logmsg)
+ free (logmsg);
+ va_end (args);
+ return;
+ }
+ va_end (args);
+
+ log->Printf ("%*sth%d/fr%u %s",
+ m_frame_number < 100 ? m_frame_number : 100, "", m_thread.GetIndexID(), m_frame_number,
+ logmsg);
+ free (logmsg);
+ }
+}
+
+void
+RegisterContextLLDB::UnwindLogMsgVerbose (const char *fmt, ...)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ if (log && log->GetVerbose())
+ {
+ va_list args;
+ va_start (args, fmt);
+
+ char *logmsg;
+ if (vasprintf (&logmsg, fmt, args) == -1 || logmsg == NULL)
+ {
+ if (logmsg)
+ free (logmsg);
+ va_end (args);
+ return;
+ }
+ va_end (args);
+
+ log->Printf ("%*sth%d/fr%u %s",
+ m_frame_number < 100 ? m_frame_number : 100, "", m_thread.GetIndexID(), m_frame_number,
+ logmsg);
+ free (logmsg);
+ }
+}
+
diff --git a/source/Plugins/Process/Utility/RegisterContextLLDB.h b/source/Plugins/Process/Utility/RegisterContextLLDB.h
new file mode 100644
index 000000000000..dc6d8c61fa4a
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextLLDB.h
@@ -0,0 +1,212 @@
+//===-- RegisterContextLLDB.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterContextLLDB_h_
+#define lldb_RegisterContextLLDB_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "UnwindLLDB.h"
+
+namespace lldb_private {
+
+class UnwindLLDB;
+
+class RegisterContextLLDB : public lldb_private::RegisterContext
+{
+public:
+ typedef std::shared_ptr<RegisterContextLLDB> SharedPtr;
+
+ RegisterContextLLDB (lldb_private::Thread &thread,
+ const SharedPtr& next_frame,
+ lldb_private::SymbolContext& sym_ctx,
+ uint32_t frame_number, lldb_private::UnwindLLDB& unwind_lldb);
+
+ ///
+ // pure virtual functions from the base class that we must implement
+ ///
+
+ virtual
+ ~RegisterContextLLDB () { }
+
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+ bool
+ IsValid () const;
+
+ bool
+ GetCFA (lldb::addr_t& cfa);
+
+ bool
+ GetStartPC (lldb::addr_t& start_pc);
+
+ bool
+ ReadPC (lldb::addr_t& start_pc);
+
+private:
+
+ enum FrameType
+ {
+ eNormalFrame,
+ eSigtrampFrame,
+ eDebuggerFrame, // a debugger inferior function call frame; we get caller's registers from debugger
+ eSkipFrame, // The unwind resulted in a bogus frame but may get back on track so we don't want to give up yet
+ eNotAValidFrame // this frame is invalid for some reason - most likely it is past the top (end) of the stack
+ };
+
+ // UnwindLLDB needs to pass around references to RegisterLocations
+ friend class UnwindLLDB;
+
+ // Indicates whether this frame is frame zero -- the currently
+ // executing frame -- or not.
+ bool
+ IsFrameZero () const;
+
+ void
+ InitializeZerothFrame ();
+
+ void
+ InitializeNonZerothFrame();
+
+ SharedPtr
+ GetNextFrame () const;
+
+ SharedPtr
+ GetPrevFrame () const;
+
+ // A SkipFrame occurs when the unwind out of frame 0 didn't go right -- we've got one bogus frame at frame #1.
+ // There is a good chance we'll get back on track if we follow the frame pointer chain (or whatever is appropriate
+ // on this ABI) so we allow one invalid frame to be in the stack. Ideally we'll mark this frame specially at some
+ // point and indicate to the user that the unwinder had a hiccup. Often when this happens we will miss a frame of
+ // the program's actual stack in the unwind and we want to flag that for the user somehow.
+ bool
+ IsSkipFrame () const;
+
+ // Provide a location for where THIS function saved the CALLER's register value
+ // Or a frame "below" this one saved it, i.e. a function called by this one, preserved a register that this
+ // function didn't modify/use.
+ //
+ // The RegisterLocation type may be set to eRegisterNotAvailable -- this will happen for a volatile register
+ // being queried mid-stack. Instead of floating frame 0's contents of that register up the stack (which may
+ // or may not be the value of that reg when the function was executing), we won't return any value.
+ //
+ // If a non-volatile register (a "preserved" register) is requested mid-stack and no frames "below" the requested
+ // stack have saved the register anywhere, it is safe to assume that frame 0's register values are still the same
+ // as the requesting frame's.
+ lldb_private::UnwindLLDB::RegisterSearchResult
+ SavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc);
+
+ bool
+ ReadRegisterValueFromRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &value);
+
+ bool
+ WriteRegisterValueToRegisterLocation (lldb_private::UnwindLLDB::RegisterLocation regloc,
+ const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &value);
+
+ void
+ InvalidateFullUnwindPlan ();
+
+ // Get the contents of a general purpose (address-size) register for this frame
+ // (usually retrieved from the next frame)
+ bool
+ ReadGPRValue (int register_kind, uint32_t regnum, lldb::addr_t &value);
+
+ lldb::UnwindPlanSP
+ GetFastUnwindPlanForFrame ();
+
+ lldb::UnwindPlanSP
+ GetFullUnwindPlanForFrame ();
+
+ void
+ UnwindLogMsg (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ void
+ UnwindLogMsgVerbose (const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+
+ lldb_private::Thread& m_thread;
+
+ ///
+ // The following tell us how to retrieve the CALLER's register values (ie the "previous" frame, aka the frame above)
+ // i.e. where THIS frame saved them
+ ///
+
+ lldb::UnwindPlanSP m_fast_unwind_plan_sp; // may be NULL
+ lldb::UnwindPlanSP m_full_unwind_plan_sp;
+ bool m_all_registers_available; // Can we retrieve all regs or just nonvolatile regs?
+ int m_frame_type; // enum FrameType
+
+ lldb::addr_t m_cfa;
+ lldb_private::Address m_start_pc;
+ lldb_private::Address m_current_pc;
+
+ int m_current_offset; // how far into the function we've executed; -1 if unknown
+ // 0 if no instructions have been executed yet.
+
+ int m_current_offset_backed_up_one; // how far into the function we've executed; -1 if unknown
+ // 0 if no instructions have been executed yet.
+ // On architectures where the return address on the stack points
+ // to the instruction after the CALL, this value will have 1
+ // subtracted from it. Else a function that ends in a CALL will
+ // have an offset pointing into the next function's address range.
+ // m_current_pc has the actual address of the "current" pc.
+
+ lldb_private::SymbolContext& m_sym_ctx;
+ bool m_sym_ctx_valid; // if ResolveSymbolContextForAddress fails, don't try to use m_sym_ctx
+
+ uint32_t m_frame_number; // What stack frame this RegisterContext is
+
+ std::map<uint32_t, lldb_private::UnwindLLDB::RegisterLocation> m_registers; // where to find reg values for this frame
+
+ lldb_private::UnwindLLDB& m_parent_unwind; // The UnwindLLDB that is creating this RegisterContextLLDB
+
+ //------------------------------------------------------------------
+ // For RegisterContextLLDB only
+ //------------------------------------------------------------------
+
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextLLDB);
+};
+
+} // namespace lldb_private
+
+#endif // lldb_RegisterContextLLDB_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
new file mode 100644
index 000000000000..2c3eee452488
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.cpp
@@ -0,0 +1,206 @@
+//===-- RegisterContextMacOSXFrameBackchain.cpp -----------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMacOSXFrameBackchain.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/Thread.h"
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// RegisterContextMacOSXFrameBackchain constructor
+//----------------------------------------------------------------------
+RegisterContextMacOSXFrameBackchain::RegisterContextMacOSXFrameBackchain
+(
+ Thread &thread,
+ uint32_t concrete_frame_idx,
+ const UnwindMacOSXFrameBackchain::Cursor &cursor
+) :
+ RegisterContext (thread, concrete_frame_idx),
+ m_cursor (cursor),
+ m_cursor_is_valid (true)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RegisterContextMacOSXFrameBackchain::~RegisterContextMacOSXFrameBackchain()
+{
+}
+
+void
+RegisterContextMacOSXFrameBackchain::InvalidateAllRegisters ()
+{
+ m_cursor_is_valid = false;
+}
+
+size_t
+RegisterContextMacOSXFrameBackchain::GetRegisterCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterCount();
+}
+
+const RegisterInfo *
+RegisterContextMacOSXFrameBackchain::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_thread.GetRegisterContext()->GetRegisterInfoAtIndex(reg);
+}
+
+size_t
+RegisterContextMacOSXFrameBackchain::GetRegisterSetCount ()
+{
+ return m_thread.GetRegisterContext()->GetRegisterSetCount();
+}
+
+
+
+const RegisterSet *
+RegisterContextMacOSXFrameBackchain::GetRegisterSet (size_t reg_set)
+{
+ return m_thread.GetRegisterContext()->GetRegisterSet (reg_set);
+}
+
+
+
+bool
+RegisterContextMacOSXFrameBackchain::ReadRegister (const RegisterInfo *reg_info,
+ RegisterValue &value)
+{
+ if (!m_cursor_is_valid)
+ return false;
+
+ uint64_t reg_value = LLDB_INVALID_ADDRESS;
+
+ switch (reg_info->kinds[eRegisterKindGeneric])
+ {
+ case LLDB_REGNUM_GENERIC_PC:
+ if (m_cursor.pc == LLDB_INVALID_ADDRESS)
+ return false;
+ reg_value = m_cursor.pc;
+ break;
+
+ case LLDB_REGNUM_GENERIC_FP:
+ if (m_cursor.fp == LLDB_INVALID_ADDRESS)
+ return false;
+ reg_value = m_cursor.fp;
+ break;
+
+ default:
+ return false;
+ }
+
+ switch (reg_info->encoding)
+ {
+ case eEncodingInvalid:
+ case eEncodingVector:
+ break;
+
+ case eEncodingUint:
+ case eEncodingSint:
+ value.SetUInt(reg_value, reg_info->byte_size);
+ return true;
+
+ case eEncodingIEEE754:
+ switch (reg_info->byte_size)
+ {
+ case sizeof (float):
+ if (sizeof (float) == sizeof(uint32_t))
+ {
+ value.SetUInt32(reg_value, RegisterValue::eTypeFloat);
+ return true;
+ }
+ else if (sizeof (float) == sizeof(uint64_t))
+ {
+ value.SetUInt64(reg_value, RegisterValue::eTypeFloat);
+ return true;
+ }
+ break;
+
+ case sizeof (double):
+ if (sizeof (double) == sizeof(uint32_t))
+ {
+ value.SetUInt32(reg_value, RegisterValue::eTypeDouble);
+ return true;
+ }
+ else if (sizeof (double) == sizeof(uint64_t))
+ {
+ value.SetUInt64(reg_value, RegisterValue::eTypeDouble);
+ return true;
+ }
+ break;
+
+ // TOOD: need a better way to detect when "long double" types are
+ // the same bytes size as "double"
+#if !defined(__arm__)
+ case sizeof (long double):
+ if (sizeof (long double) == sizeof(uint32_t))
+ {
+ value.SetUInt32(reg_value, RegisterValue::eTypeLongDouble);
+ return true;
+ }
+ else if (sizeof (long double) == sizeof(uint64_t))
+ {
+ value.SetUInt64(reg_value, RegisterValue::eTypeLongDouble);
+ return true;
+ }
+ break;
+#endif
+ }
+ break;
+ }
+ return false;
+}
+
+bool
+RegisterContextMacOSXFrameBackchain::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ // Not supported yet. We could easily add support for this by remembering
+ // the address of each entry (it would need to be part of the cursor)
+ return false;
+}
+
+bool
+RegisterContextMacOSXFrameBackchain::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ // libunwind frames can't handle this it doesn't always have all register
+ // values. This call should only be called on frame zero anyway so there
+ // shouldn't be any problem
+ return false;
+}
+
+bool
+RegisterContextMacOSXFrameBackchain::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ // Since this class doesn't respond to "ReadAllRegisterValues()", it must
+ // not have been the one that saved all the register values. So we just let
+ // the thread's register context (the register context for frame zero) do
+ // the writing.
+ return m_thread.GetRegisterContext()->WriteAllRegisterValues(data_sp);
+}
+
+
+uint32_t
+RegisterContextMacOSXFrameBackchain::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_thread.GetRegisterContext()->ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
diff --git a/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h
new file mode 100644
index 000000000000..449e053e5ef1
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMacOSXFrameBackchain.h
@@ -0,0 +1,77 @@
+//===-- RegisterContextMacOSXFrameBackchain.h -------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterContextMacOSXFrameBackchain_h_
+#define lldb_RegisterContextMacOSXFrameBackchain_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "UnwindMacOSXFrameBackchain.h"
+
+class RegisterContextMacOSXFrameBackchain : public lldb_private::RegisterContext
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContextMacOSXFrameBackchain (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ const UnwindMacOSXFrameBackchain::Cursor &cursor);
+
+ virtual
+ ~RegisterContextMacOSXFrameBackchain ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+private:
+ UnwindMacOSXFrameBackchain::Cursor m_cursor;
+ bool m_cursor_is_valid;
+ //------------------------------------------------------------------
+ // For RegisterContextMacOSXFrameBackchain only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextMacOSXFrameBackchain);
+};
+
+#endif // lldb_RegisterContextMacOSXFrameBackchain_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp b/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp
new file mode 100644
index 000000000000..7ceb536272f4
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_arm.cpp
@@ -0,0 +1,87 @@
+//===-- RegisterContextMach_arm.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+#include "RegisterContextMach_arm.h"
+
+// C Includes
+#include <mach/mach_types.h>
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextMach_arm::RegisterContextMach_arm(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_arm (thread, concrete_frame_idx)
+{
+}
+
+RegisterContextMach_arm::~RegisterContextMach_arm()
+{
+}
+
+int
+RegisterContextMach_arm::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int
+RegisterContextMach_arm::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int
+RegisterContextMach_arm::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int
+RegisterContextMach_arm::DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg)
+{
+ mach_msg_type_number_t count = DBGWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&dbg, &count);
+}
+
+int
+RegisterContextMach_arm::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
+}
+
+int
+RegisterContextMach_arm::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
+}
+
+int
+RegisterContextMach_arm::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
+}
+
+int
+RegisterContextMach_arm::DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&dbg, DBGWordCount);
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_arm.h b/source/Plugins/Process/Utility/RegisterContextMach_arm.h
new file mode 100644
index 000000000000..e97a4bfff2b6
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_arm.h
@@ -0,0 +1,56 @@
+//===-- RegisterContextMach_arm.h -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextMach_arm_h_
+#define liblldb_RegisterContextMach_arm_h_
+
+// C Includes
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextDarwin_arm.h"
+
+class RegisterContextMach_arm : public RegisterContextDarwin_arm
+{
+public:
+
+ RegisterContextMach_arm(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextMach_arm();
+
+protected:
+
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+
+ int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+
+ int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+
+ int
+ DoReadDBG (lldb::tid_t tid, int flavor, DBG &dbg);
+
+ int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+
+ int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+
+ int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+
+ int
+ DoWriteDBG (lldb::tid_t tid, int flavor, const DBG &dbg);
+};
+
+#endif // liblldb_RegisterContextMach_arm_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp b/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp
new file mode 100644
index 000000000000..3d6c9a6baca6
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_i386.cpp
@@ -0,0 +1,72 @@
+//===-- RegisterContextMach_i386.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+// C Includes
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextMach_i386.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextMach_i386::RegisterContextMach_i386(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_i386 (thread, concrete_frame_idx)
+{
+}
+
+RegisterContextMach_i386::~RegisterContextMach_i386()
+{
+}
+
+int
+RegisterContextMach_i386::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int
+RegisterContextMach_i386::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int
+RegisterContextMach_i386::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int
+RegisterContextMach_i386::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
+}
+
+int
+RegisterContextMach_i386::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
+}
+
+int
+RegisterContextMach_i386::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_i386.h b/source/Plugins/Process/Utility/RegisterContextMach_i386.h
new file mode 100644
index 000000000000..ad0f69d1c052
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_i386.h
@@ -0,0 +1,49 @@
+//===-- RegisterContextMach_i386.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextMach_i386_h_
+#define liblldb_RegisterContextMach_i386_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextDarwin_i386.h"
+
+class RegisterContextMach_i386 : public RegisterContextDarwin_i386
+{
+public:
+
+ RegisterContextMach_i386(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextMach_i386();
+
+protected:
+
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+
+ int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+
+ int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+
+ int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+
+ int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+
+ int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+};
+
+#endif // liblldb_RegisterContextMach_i386_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp
new file mode 100644
index 000000000000..f03685e1313f
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.cpp
@@ -0,0 +1,72 @@
+//===-- RegisterContextMach_x86_64.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#if defined(__APPLE__)
+
+// C Includes
+#include <mach/thread_act.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextMach_x86_64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+RegisterContextMach_x86_64::RegisterContextMach_x86_64(Thread &thread, uint32_t concrete_frame_idx) :
+ RegisterContextDarwin_x86_64 (thread, concrete_frame_idx)
+{
+}
+
+RegisterContextMach_x86_64::~RegisterContextMach_x86_64()
+{
+}
+
+int
+RegisterContextMach_x86_64::DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr)
+{
+ mach_msg_type_number_t count = GPRWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&gpr, &count);
+}
+
+int
+RegisterContextMach_x86_64::DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu)
+{
+ mach_msg_type_number_t count = FPUWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&fpu, &count);
+}
+
+int
+RegisterContextMach_x86_64::DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc)
+{
+ mach_msg_type_number_t count = EXCWordCount;
+ return ::thread_get_state(tid, flavor, (thread_state_t)&exc, &count);
+}
+
+int
+RegisterContextMach_x86_64::DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&gpr, GPRWordCount);
+}
+
+int
+RegisterContextMach_x86_64::DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&fpu, FPUWordCount);
+}
+
+int
+RegisterContextMach_x86_64::DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc)
+{
+ return ::thread_set_state(tid, flavor, (thread_state_t)&exc, EXCWordCount);
+}
+
+#endif
diff --git a/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h
new file mode 100644
index 000000000000..9e6dfa395500
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMach_x86_64.h
@@ -0,0 +1,49 @@
+//===-- RegisterContextMach_x86_64.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextMach_x86_64_h_
+#define liblldb_RegisterContextMach_x86_64_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "RegisterContextDarwin_x86_64.h"
+
+class RegisterContextMach_x86_64 : public RegisterContextDarwin_x86_64
+{
+public:
+
+ RegisterContextMach_x86_64(lldb_private::Thread &thread, uint32_t concrete_frame_idx);
+
+ virtual
+ ~RegisterContextMach_x86_64();
+
+protected:
+
+ virtual int
+ DoReadGPR (lldb::tid_t tid, int flavor, GPR &gpr);
+
+ int
+ DoReadFPU (lldb::tid_t tid, int flavor, FPU &fpu);
+
+ int
+ DoReadEXC (lldb::tid_t tid, int flavor, EXC &exc);
+
+ int
+ DoWriteGPR (lldb::tid_t tid, int flavor, const GPR &gpr);
+
+ int
+ DoWriteFPU (lldb::tid_t tid, int flavor, const FPU &fpu);
+
+ int
+ DoWriteEXC (lldb::tid_t tid, int flavor, const EXC &exc);
+};
+
+#endif // liblldb_RegisterContextMach_x86_64_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextMemory.cpp b/source/Plugins/Process/Utility/RegisterContextMemory.cpp
new file mode 100644
index 000000000000..8c33a6814acc
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMemory.cpp
@@ -0,0 +1,174 @@
+//===-- RegisterContextMemory.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "RegisterContextMemory.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "DynamicRegisterInfo.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// RegisterContextMemory constructor
+//----------------------------------------------------------------------
+RegisterContextMemory::RegisterContextMemory
+(
+ Thread &thread,
+ uint32_t concrete_frame_idx,
+ DynamicRegisterInfo &reg_infos,
+ addr_t reg_data_addr
+) :
+ RegisterContext (thread, concrete_frame_idx),
+ m_reg_infos (reg_infos),
+ m_reg_valid (),
+ m_reg_data (),
+ m_reg_data_addr (reg_data_addr)
+{
+ // Resize our vector of bools to contain one bool for every register.
+ // We will use these boolean values to know when a register value
+ // is valid in m_reg_data.
+ const size_t num_regs = reg_infos.GetNumRegisters();
+ assert (num_regs > 0);
+ m_reg_valid.resize (num_regs);
+
+ // Make a heap based buffer that is big enough to store all registers
+ DataBufferSP reg_data_sp(new DataBufferHeap (reg_infos.GetRegisterDataByteSize(), 0));
+ m_reg_data.SetData (reg_data_sp);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+RegisterContextMemory::~RegisterContextMemory()
+{
+}
+
+void
+RegisterContextMemory::InvalidateAllRegisters ()
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ SetAllRegisterValid (false);
+}
+
+void
+RegisterContextMemory::SetAllRegisterValid (bool b)
+{
+ std::vector<bool>::iterator pos, end = m_reg_valid.end();
+ for (pos = m_reg_valid.begin(); pos != end; ++pos)
+ *pos = b;
+}
+
+size_t
+RegisterContextMemory::GetRegisterCount ()
+{
+ return m_reg_infos.GetNumRegisters ();
+}
+
+const RegisterInfo *
+RegisterContextMemory::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_reg_infos.GetRegisterInfoAtIndex (reg);
+}
+
+size_t
+RegisterContextMemory::GetRegisterSetCount ()
+{
+ return m_reg_infos.GetNumRegisterSets ();
+}
+
+const RegisterSet *
+RegisterContextMemory::GetRegisterSet (size_t reg_set)
+{
+ return m_reg_infos.GetRegisterSet (reg_set);
+}
+
+uint32_t
+RegisterContextMemory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_reg_infos.ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
+bool
+RegisterContextMemory::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ const uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB];
+ if (!m_reg_valid[reg_num])
+ {
+ if (!ReadAllRegisterValues(m_reg_data.GetSharedDataBuffer ()))
+ return false;
+ }
+ const bool partial_data_ok = false;
+ return reg_value.SetValueFromData(reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok).Success();
+}
+
+bool
+RegisterContextMemory::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ {
+ const uint32_t reg_num = reg_info->kinds[eRegisterKindLLDB];
+ addr_t reg_addr = m_reg_data_addr + reg_info->byte_offset;
+ Error error (WriteRegisterValueToMemory(reg_info, reg_addr, reg_info->byte_size, reg_value));
+ m_reg_valid[reg_num] = false;
+ return error.Success();
+ }
+ return false;
+}
+
+bool
+RegisterContextMemory::ReadAllRegisterValues (DataBufferSP &data_sp)
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ {
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ if (process_sp->ReadMemory(m_reg_data_addr, data_sp->GetBytes(), data_sp->GetByteSize(), error) == data_sp->GetByteSize())
+ {
+ SetAllRegisterValid (true);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+RegisterContextMemory::WriteAllRegisterValues (const DataBufferSP &data_sp)
+{
+ if (m_reg_data_addr != LLDB_INVALID_ADDRESS)
+ {
+ ProcessSP process_sp (CalculateProcess());
+ if (process_sp)
+ {
+ Error error;
+ SetAllRegisterValid (false);
+ if (process_sp->WriteMemory(m_reg_data_addr, data_sp->GetBytes(), data_sp->GetByteSize(), error) == data_sp->GetByteSize())
+ return true;
+ }
+ }
+ return false;
+}
+
+void
+RegisterContextMemory::SetAllRegisterData (const lldb::DataBufferSP &data_sp)
+{
+ m_reg_data.SetData(data_sp);
+ SetAllRegisterValid (true);
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextMemory.h b/source/Plugins/Process/Utility/RegisterContextMemory.h
new file mode 100644
index 000000000000..8bba52c627f3
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextMemory.h
@@ -0,0 +1,102 @@
+//===-- RegisterContextMemory.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterContextMemory_h_
+#define lldb_RegisterContextMemory_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/RegisterContext.h"
+
+class DynamicRegisterInfo;
+
+class RegisterContextMemory : public lldb_private::RegisterContext
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ RegisterContextMemory (lldb_private::Thread &thread,
+ uint32_t concrete_frame_idx,
+ DynamicRegisterInfo &reg_info,
+ lldb::addr_t reg_data_addr);
+
+ virtual
+ ~RegisterContextMemory ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+
+ //------------------------------------------------------------------
+ // If all of the thread register are in a contiguous buffer in
+ // memory, then the default ReadRegister/WriteRegister and
+ // ReadAllRegisterValues/WriteAllRegisterValues will work. If thread
+ // registers are not contiguous, clients will want to subclass this
+ // class and modify the read/write functions as needed.
+ //------------------------------------------------------------------
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ void
+ SetAllRegisterData (const lldb::DataBufferSP &data_sp);
+protected:
+
+ void
+ SetAllRegisterValid (bool b);
+
+ DynamicRegisterInfo &m_reg_infos;
+ std::vector<bool> m_reg_valid;
+ lldb_private::DataExtractor m_reg_data;
+ lldb::addr_t m_reg_data_addr; // If this is valid, then we have a register context that is stored in memmory
+
+private:
+ //------------------------------------------------------------------
+ // For RegisterContextMemory only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextMemory);
+};
+
+#endif // lldb_RegisterContextMemory_h_
diff --git a/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp b/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
new file mode 100644
index 000000000000..d35a5d095705
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextThreadMemory.cpp
@@ -0,0 +1,261 @@
+//===-- RegisterContextThreadMemory.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+#include "RegisterContextThreadMemory.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+RegisterContextThreadMemory::RegisterContextThreadMemory (Thread &thread,
+ lldb::addr_t register_data_addr) :
+ RegisterContext (thread, 0),
+ m_thread_wp (thread.shared_from_this()),
+ m_reg_ctx_sp (),
+ m_register_data_addr (register_data_addr),
+ m_stop_id(0)
+{
+}
+
+RegisterContextThreadMemory::~RegisterContextThreadMemory()
+{
+}
+
+void
+RegisterContextThreadMemory::UpdateRegisterContext ()
+{
+ ThreadSP thread_sp (m_thread_wp.lock());
+ if (thread_sp)
+ {
+ ProcessSP process_sp (thread_sp->GetProcess());
+
+ if (process_sp)
+ {
+ const uint32_t stop_id = process_sp->GetModID().GetStopID();
+ if (m_stop_id != stop_id)
+ {
+ m_stop_id = stop_id;
+ m_reg_ctx_sp.reset();
+ }
+ if (!m_reg_ctx_sp)
+ {
+ ThreadSP backing_thread_sp (thread_sp->GetBackingThread());
+ if (backing_thread_sp)
+ {
+ m_reg_ctx_sp = backing_thread_sp->GetRegisterContext();
+ }
+ else
+ {
+ OperatingSystem *os = process_sp->GetOperatingSystem ();
+ if (os->IsOperatingSystemPluginThread (thread_sp))
+ m_reg_ctx_sp = os->CreateRegisterContextForThread (thread_sp.get(), LLDB_INVALID_ADDRESS);
+ }
+ }
+ }
+ else
+ {
+ m_reg_ctx_sp.reset();
+ }
+ }
+ else
+ {
+ m_reg_ctx_sp.reset();
+ }
+}
+
+//------------------------------------------------------------------
+// Subclasses must override these functions
+//------------------------------------------------------------------
+void
+RegisterContextThreadMemory::InvalidateAllRegisters ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ m_reg_ctx_sp->InvalidateAllRegisters();
+}
+
+size_t
+RegisterContextThreadMemory::GetRegisterCount ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterCount();
+ return 0;
+}
+
+const RegisterInfo *
+RegisterContextThreadMemory::GetRegisterInfoAtIndex (size_t reg)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterInfoAtIndex(reg);
+ return NULL;
+}
+
+size_t
+RegisterContextThreadMemory::GetRegisterSetCount ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterSetCount();
+ return 0;
+}
+
+const RegisterSet *
+RegisterContextThreadMemory::GetRegisterSet (size_t reg_set)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->GetRegisterSet(reg_set);
+ return NULL;
+}
+
+bool
+RegisterContextThreadMemory::ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadRegister(reg_info, reg_value);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteRegister (reg_info, reg_value);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadAllRegisterValues(data_sp);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteAllRegisterValues (data_sp);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::CopyFromRegisterContext (lldb::RegisterContextSP reg_ctx_sp)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->CopyFromRegisterContext(reg_ctx_sp);
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ConvertRegisterKindToRegisterNumber(kind, num);
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::NumSupportedHardwareBreakpoints ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->NumSupportedHardwareBreakpoints();
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->SetHardwareBreakpoint(addr, size);
+ return 0;
+}
+
+bool
+RegisterContextThreadMemory::ClearHardwareBreakpoint (uint32_t hw_idx)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ClearHardwareBreakpoint (hw_idx);
+ return false;
+}
+
+uint32_t
+RegisterContextThreadMemory::NumSupportedHardwareWatchpoints ()
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->NumSupportedHardwareWatchpoints();
+ return 0;
+}
+
+uint32_t
+RegisterContextThreadMemory::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->SetHardwareWatchpoint(addr, size, read, write);
+ return 0;
+}
+
+bool
+RegisterContextThreadMemory::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ClearHardwareWatchpoint(hw_index);
+ return false;
+}
+
+bool
+RegisterContextThreadMemory::HardwareSingleStep (bool enable)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->HardwareSingleStep(enable);
+ return false;
+}
+
+Error
+RegisterContextThreadMemory::ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->ReadRegisterValueFromMemory (reg_info, src_addr, src_len, reg_value);
+ Error error;
+ error.SetErrorString("invalid register context");
+ return error;
+}
+
+Error
+RegisterContextThreadMemory::WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue &reg_value)
+{
+ UpdateRegisterContext ();
+ if (m_reg_ctx_sp)
+ return m_reg_ctx_sp->WriteRegisterValueToMemory (reg_info, dst_addr, dst_len, reg_value);
+ Error error;
+ error.SetErrorString("invalid register context");
+ return error;
+}
diff --git a/source/Plugins/Process/Utility/RegisterContextThreadMemory.h b/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
new file mode 100644
index 000000000000..8d7a4b622fe8
--- /dev/null
+++ b/source/Plugins/Process/Utility/RegisterContextThreadMemory.h
@@ -0,0 +1,114 @@
+//===-- RegisterContextThreadMemory.h ---------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_RegisterContextThreadMemory_h_
+#define lldb_RegisterContextThreadMemory_h_
+
+#include <vector>
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+namespace lldb_private {
+
+class RegisterContextThreadMemory : public lldb_private::RegisterContext
+{
+public:
+ RegisterContextThreadMemory (Thread &thread,
+ lldb::addr_t register_data_addr);
+
+ virtual ~RegisterContextThreadMemory();
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual bool
+ ReadRegister (const RegisterInfo *reg_info, RegisterValue &reg_value);
+
+ virtual bool
+ WriteRegister (const RegisterInfo *reg_info, const RegisterValue &reg_value);
+
+ // These two functions are used to implement "push" and "pop" of register states. They are used primarily
+ // for expression evaluation, where we need to push a new state (storing the old one in data_sp) and then
+ // restoring the original state by passing the data_sp we got from ReadAllRegisters to WriteAllRegisterValues.
+ // ReadAllRegisters will do what is necessary to return a coherent set of register values for this thread, which
+ // may mean e.g. interrupting a thread that is sitting in a kernel trap. That is a somewhat disruptive operation,
+ // so these API's should only be used when this behavior is needed.
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ bool
+ CopyFromRegisterContext (lldb::RegisterContextSP context);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+ //------------------------------------------------------------------
+ // Subclasses can override these functions if desired
+ //------------------------------------------------------------------
+ virtual uint32_t
+ NumSupportedHardwareBreakpoints ();
+
+ virtual uint32_t
+ SetHardwareBreakpoint (lldb::addr_t addr, size_t size);
+
+ virtual bool
+ ClearHardwareBreakpoint (uint32_t hw_idx);
+
+ virtual uint32_t
+ NumSupportedHardwareWatchpoints ();
+
+ virtual uint32_t
+ SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write);
+
+ virtual bool
+ ClearHardwareWatchpoint (uint32_t hw_index);
+
+ virtual bool
+ HardwareSingleStep (bool enable);
+
+ virtual Error
+ ReadRegisterValueFromMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t src_addr, uint32_t src_len, RegisterValue &reg_value);
+
+ virtual Error
+ WriteRegisterValueToMemory (const lldb_private::RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, const RegisterValue &reg_value);
+
+protected:
+ void
+ UpdateRegisterContext ();
+
+ lldb::ThreadWP m_thread_wp;
+ lldb::RegisterContextSP m_reg_ctx_sp;
+ lldb::addr_t m_register_data_addr;
+ uint32_t m_stop_id;
+private:
+ DISALLOW_COPY_AND_ASSIGN (RegisterContextThreadMemory);
+};
+} // namespace lldb_private
+
+#endif // lldb_RegisterContextThreadMemory_h_
diff --git a/source/Plugins/Process/Utility/StopInfoMachException.cpp b/source/Plugins/Process/Utility/StopInfoMachException.cpp
new file mode 100644
index 000000000000..51d2052e1931
--- /dev/null
+++ b/source/Plugins/Process/Utility/StopInfoMachException.cpp
@@ -0,0 +1,482 @@
+//===-- StopInfoMachException.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "StopInfoMachException.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/UnixSignals.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+const char *
+StopInfoMachException::GetDescription ()
+{
+ if (m_description.empty() && m_value != 0)
+ {
+ ExecutionContext exe_ctx (m_thread_wp.lock());
+ Target *target = exe_ctx.GetTargetPtr();
+ const llvm::Triple::ArchType cpu = target ? target->GetArchitecture().GetMachine() : llvm::Triple::UnknownArch;
+
+ const char *exc_desc = NULL;
+ const char *code_label = "code";
+ const char *code_desc = NULL;
+ const char *subcode_label = "subcode";
+ const char *subcode_desc = NULL;
+ switch (m_value)
+ {
+ case 1: // EXC_BAD_ACCESS
+ exc_desc = "EXC_BAD_ACCESS";
+ subcode_label = "address";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code)
+ {
+ case 0xd: code_desc = "EXC_I386_GPFLT"; m_exc_data_count = 1; break;
+ }
+ break;
+ case llvm::Triple::arm:
+ switch (m_exc_code)
+ {
+ case 0x101: code_desc = "EXC_ARM_DA_ALIGN"; break;
+ case 0x102: code_desc = "EXC_ARM_DA_DEBUG"; break;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 0x101: code_desc = "EXC_PPC_VM_PROT_READ"; break;
+ case 0x102: code_desc = "EXC_PPC_BADSPACE"; break;
+ case 0x103: code_desc = "EXC_PPC_UNALIGNED"; break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 2: // EXC_BAD_INSTRUCTION
+ exc_desc = "EXC_BAD_INSTRUCTION";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (m_exc_code == 1)
+ code_desc = "EXC_I386_INVOP";
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_PPC_INVALID_SYSCALL"; break;
+ case 2: code_desc = "EXC_PPC_UNIPL_INST"; break;
+ case 3: code_desc = "EXC_PPC_PRIVINST"; break;
+ case 4: code_desc = "EXC_PPC_PRIVREG"; break;
+ case 5: code_desc = "EXC_PPC_TRACE"; break;
+ case 6: code_desc = "EXC_PPC_PERFMON"; break;
+ }
+ break;
+
+ case llvm::Triple::arm:
+ if (m_exc_code == 1)
+ code_desc = "EXC_ARM_UNDEFINED";
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 3: // EXC_ARITHMETIC
+ exc_desc = "EXC_ARITHMETIC";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_I386_DIV"; break;
+ case 2: code_desc = "EXC_I386_INTO"; break;
+ case 3: code_desc = "EXC_I386_NOEXT"; break;
+ case 4: code_desc = "EXC_I386_EXTOVR"; break;
+ case 5: code_desc = "EXC_I386_EXTERR"; break;
+ case 6: code_desc = "EXC_I386_EMERR"; break;
+ case 7: code_desc = "EXC_I386_BOUND"; break;
+ case 8: code_desc = "EXC_I386_SSEEXTERR"; break;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_PPC_OVERFLOW"; break;
+ case 2: code_desc = "EXC_PPC_ZERO_DIVIDE"; break;
+ case 3: code_desc = "EXC_PPC_FLT_INEXACT"; break;
+ case 4: code_desc = "EXC_PPC_FLT_ZERO_DIVIDE"; break;
+ case 5: code_desc = "EXC_PPC_FLT_UNDERFLOW"; break;
+ case 6: code_desc = "EXC_PPC_FLT_OVERFLOW"; break;
+ case 7: code_desc = "EXC_PPC_FLT_NOT_A_NUMBER"; break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 4: // EXC_EMULATION
+ exc_desc = "EXC_EMULATION";
+ break;
+
+
+ case 5: // EXC_SOFTWARE
+ exc_desc = "EXC_SOFTWARE";
+ if (m_exc_code == 0x10003)
+ {
+ subcode_desc = "EXC_SOFT_SIGNAL";
+ subcode_label = "signo";
+ }
+ break;
+
+ case 6: // EXC_BREAKPOINT
+ {
+ exc_desc = "EXC_BREAKPOINT";
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_I386_SGL"; break;
+ case 2: code_desc = "EXC_I386_BPT"; break;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (m_exc_code)
+ {
+ case 1: code_desc = "EXC_PPC_BREAKPOINT"; break;
+ }
+ break;
+
+ case llvm::Triple::arm:
+ switch (m_exc_code)
+ {
+ case 0x101: code_desc = "EXC_ARM_DA_ALIGN"; break;
+ case 0x102: code_desc = "EXC_ARM_DA_DEBUG"; break;
+ case 1: code_desc = "EXC_ARM_BREAKPOINT"; break;
+ // FIXME temporary workaround, exc_code 0 does not really mean EXC_ARM_BREAKPOINT
+ case 0: code_desc = "EXC_ARM_BREAKPOINT"; break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ break;
+
+ case 7:
+ exc_desc = "EXC_SYSCALL";
+ break;
+
+ case 8:
+ exc_desc = "EXC_MACH_SYSCALL";
+ break;
+
+ case 9:
+ exc_desc = "EXC_RPC_ALERT";
+ break;
+
+ case 10:
+ exc_desc = "EXC_CRASH";
+ break;
+ case 11:
+ exc_desc = "EXC_RESOURCE";
+ break;
+ case 12:
+ exc_desc = "EXC_GUARD";
+ break;
+ }
+
+ StreamString strm;
+
+ if (exc_desc)
+ strm.PutCString(exc_desc);
+ else
+ strm.Printf("EXC_??? (%" PRIu64 ")", m_value);
+
+ if (m_exc_data_count >= 1)
+ {
+ if (code_desc)
+ strm.Printf(" (%s=%s", code_label, code_desc);
+ else
+ strm.Printf(" (%s=%" PRIu64, code_label, m_exc_code);
+ }
+
+ if (m_exc_data_count >= 2)
+ {
+ if (subcode_desc)
+ strm.Printf(", %s=%s", subcode_label, subcode_desc);
+ else
+ strm.Printf(", %s=0x%" PRIx64, subcode_label, m_exc_subcode);
+ }
+
+ if (m_exc_data_count > 0)
+ strm.PutChar(')');
+
+ m_description.swap (strm.GetString());
+ }
+ return m_description.c_str();
+}
+
+
+
+
+
+StopInfoSP
+StopInfoMachException::CreateStopReasonWithMachException
+(
+ Thread &thread,
+ uint32_t exc_type,
+ uint32_t exc_data_count,
+ uint64_t exc_code,
+ uint64_t exc_sub_code,
+ uint64_t exc_sub_sub_code,
+ bool pc_already_adjusted,
+ bool adjust_pc_if_needed
+)
+{
+ if (exc_type != 0)
+ {
+ uint32_t pc_decrement = 0;
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ const llvm::Triple::ArchType cpu = target ? target->GetArchitecture().GetMachine() : llvm::Triple::UnknownArch;
+
+ switch (exc_type)
+ {
+ case 1: // EXC_BAD_ACCESS
+ break;
+
+ case 2: // EXC_BAD_INSTRUCTION
+ switch (cpu)
+ {
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ switch (exc_code)
+ {
+ case 1: // EXC_PPC_INVALID_SYSCALL
+ case 2: // EXC_PPC_UNIPL_INST
+ case 3: // EXC_PPC_PRIVINST
+ case 4: // EXC_PPC_PRIVREG
+ break;
+ case 5: // EXC_PPC_TRACE
+ return StopInfo::CreateStopReasonToTrace (thread);
+ case 6: // EXC_PPC_PERFMON
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case 3: // EXC_ARITHMETIC
+ case 4: // EXC_EMULATION
+ break;
+
+ case 5: // EXC_SOFTWARE
+ if (exc_code == 0x10003) // EXC_SOFT_SIGNAL
+ {
+ if (exc_sub_code == 5)
+ {
+ // On MacOSX, a SIGTRAP can signify that a process has called
+ // exec, so we should check with our dynamic loader to verify.
+ ProcessSP process_sp (thread.GetProcess());
+ if (process_sp)
+ {
+ DynamicLoader *dynamic_loader = process_sp->GetDynamicLoader();
+ if (dynamic_loader && dynamic_loader->ProcessDidExec())
+ {
+ // The program was re-exec'ed
+ return StopInfo::CreateStopReasonWithExec (thread);
+ }
+// if (!process_did_exec)
+// {
+// // We have a SIGTRAP, make sure we didn't exec by checking
+// // for the PC being at "_dyld_start"...
+// lldb::StackFrameSP frame_sp (thread.GetStackFrameAtIndex(0));
+// if (frame_sp)
+// {
+// const Symbol *symbol = frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol;
+// if (symbol)
+// {
+// if (symbol->GetName() == ConstString("_dyld_start"))
+// process_did_exec = true;
+// }
+// }
+// }
+ }
+ }
+ return StopInfo::CreateStopReasonWithSignal (thread, exc_sub_code);
+ }
+ break;
+
+ case 6: // EXC_BREAKPOINT
+ {
+ bool is_actual_breakpoint = false;
+ bool is_trace_if_actual_breakpoint_missing = false;
+ switch (cpu)
+ {
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ if (exc_code == 1) // EXC_I386_SGL
+ {
+ if (!exc_sub_code)
+ return StopInfo::CreateStopReasonToTrace(thread);
+
+ // It's a watchpoint, then.
+ // The exc_sub_code indicates the data break address.
+ lldb::WatchpointSP wp_sp;
+ if (target)
+ wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
+ if (wp_sp && wp_sp->IsEnabled())
+ {
+ // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data.
+ // Set the hardware index if that's the case.
+ if (exc_data_count >=3)
+ wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
+ return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
+ }
+ }
+ else if (exc_code == 2 || // EXC_I386_BPT
+ exc_code == 3) // EXC_I386_BPTFLT
+ {
+ // KDP returns EXC_I386_BPTFLT for trace breakpoints
+ if (exc_code == 3)
+ is_trace_if_actual_breakpoint_missing = true;
+
+ is_actual_breakpoint = true;
+ if (!pc_already_adjusted)
+ pc_decrement = 1;
+ }
+ break;
+
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
+ is_actual_breakpoint = exc_code == 1; // EXC_PPC_BREAKPOINT
+ break;
+
+ case llvm::Triple::arm:
+ if (exc_code == 0x102) // EXC_ARM_DA_DEBUG
+ {
+ // It's a watchpoint, then, if the exc_sub_code indicates a known/enabled
+ // data break address from our watchpoint list.
+ lldb::WatchpointSP wp_sp;
+ if (target)
+ wp_sp = target->GetWatchpointList().FindByAddress((lldb::addr_t)exc_sub_code);
+ if (wp_sp && wp_sp->IsEnabled())
+ {
+ // Debugserver may piggyback the hardware index of the fired watchpoint in the exception data.
+ // Set the hardware index if that's the case.
+ if (exc_data_count >=3)
+ wp_sp->SetHardwareIndex((uint32_t)exc_sub_sub_code);
+ return StopInfo::CreateStopReasonWithWatchpointID(thread, wp_sp->GetID());
+ }
+ // EXC_ARM_DA_DEBUG seems to be reused for EXC_BREAKPOINT as well as EXC_BAD_ACCESS
+ if (thread.GetTemporaryResumeState() == eStateStepping)
+ return StopInfo::CreateStopReasonToTrace(thread);
+ }
+ else if (exc_code == 1) // EXC_ARM_BREAKPOINT
+ {
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ }
+ else if (exc_code == 0) // FIXME not EXC_ARM_BREAKPOINT but a kernel is currently returning this so accept it as indicating a breakpoint until the kernel is fixed
+ {
+ is_actual_breakpoint = true;
+ is_trace_if_actual_breakpoint_missing = true;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (is_actual_breakpoint)
+ {
+ RegisterContextSP reg_ctx_sp (thread.GetRegisterContext());
+ addr_t pc = reg_ctx_sp->GetPC() - pc_decrement;
+
+ ProcessSP process_sp (thread.CalculateProcess());
+
+ lldb::BreakpointSiteSP bp_site_sp;
+ if (process_sp)
+ bp_site_sp = process_sp->GetBreakpointSiteList().FindByAddress(pc);
+ if (bp_site_sp && bp_site_sp->IsEnabled())
+ {
+ // Update the PC if we were asked to do so, but only do
+ // so if we find a breakpoint that we know about cause
+ // this could be a trap instruction in the code
+ if (pc_decrement > 0 && adjust_pc_if_needed)
+ reg_ctx_sp->SetPC (pc);
+
+ // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ if (bp_site_sp->ValidForThisThread (&thread))
+ return StopInfo::CreateStopReasonWithBreakpointSiteID (thread, bp_site_sp->GetID());
+ else
+ return StopInfoSP();
+ }
+
+ // Don't call this a trace if we weren't single stepping this thread.
+ if (is_trace_if_actual_breakpoint_missing && thread.GetTemporaryResumeState() == eStateStepping)
+ {
+ return StopInfo::CreateStopReasonToTrace (thread);
+ }
+ }
+ }
+ break;
+
+ case 7: // EXC_SYSCALL
+ case 8: // EXC_MACH_SYSCALL
+ case 9: // EXC_RPC_ALERT
+ case 10: // EXC_CRASH
+ break;
+ }
+
+ return StopInfoSP(new StopInfoMachException (thread, exc_type, exc_data_count, exc_code, exc_sub_code));
+ }
+ return StopInfoSP();
+}
diff --git a/source/Plugins/Process/Utility/StopInfoMachException.h b/source/Plugins/Process/Utility/StopInfoMachException.h
new file mode 100644
index 000000000000..130ee0b709b0
--- /dev/null
+++ b/source/Plugins/Process/Utility/StopInfoMachException.h
@@ -0,0 +1,77 @@
+//===-- StopInfoMachException.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_StopInfoMachException_h_
+#define liblldb_StopInfoMachException_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/StopInfo.h"
+
+namespace lldb_private {
+
+class StopInfoMachException : public StopInfo
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ StopInfoMachException (Thread &thread,
+ uint32_t exc_type,
+ uint32_t exc_data_count,
+ uint64_t exc_code,
+ uint64_t exc_subcode) :
+ StopInfo (thread, exc_type),
+ m_exc_data_count (exc_data_count),
+ m_exc_code (exc_code),
+ m_exc_subcode (exc_subcode)
+ {
+ }
+
+ virtual ~StopInfoMachException()
+ {
+ }
+
+
+ virtual lldb::StopReason
+ GetStopReason () const
+ {
+ return lldb::eStopReasonException;
+ }
+
+ virtual const char *
+ GetDescription ();
+
+ // Since some mach exceptions will be reported as breakpoints, signals,
+ // or trace, we use this static accessor which will translate the mach
+ // exception into the correct StopInfo.
+ static lldb::StopInfoSP
+ CreateStopReasonWithMachException (Thread &thread,
+ uint32_t exc_type,
+ uint32_t exc_data_count,
+ uint64_t exc_code,
+ uint64_t exc_sub_code,
+ uint64_t exc_sub_sub_code,
+ bool pc_already_adjusted = true,
+ bool adjust_pc_if_needed = false);
+
+protected:
+ uint32_t m_exc_data_count;
+ uint64_t m_exc_code;
+ uint64_t m_exc_subcode;
+};
+
+
+} // namespace lldb_private
+
+#endif // liblldb_StopInfoMachException_h_
diff --git a/source/Plugins/Process/Utility/ThreadMemory.cpp b/source/Plugins/Process/Utility/ThreadMemory.cpp
new file mode 100644
index 000000000000..56e5a9a59fab
--- /dev/null
+++ b/source/Plugins/Process/Utility/ThreadMemory.cpp
@@ -0,0 +1,140 @@
+//===-- ThreadMemory.cpp ----------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Plugins/Process/Utility/ThreadMemory.h"
+#include "lldb/Target/OperatingSystem.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Unwind.h"
+#include "Plugins/Process/Utility/RegisterContextThreadMemory.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ThreadMemory::ThreadMemory (Process &process,
+ tid_t tid,
+ const ValueObjectSP &thread_info_valobj_sp) :
+ Thread (process, tid),
+ m_backing_thread_sp (),
+ m_thread_info_valobj_sp (thread_info_valobj_sp),
+ m_name(),
+ m_queue()
+{
+}
+
+
+ThreadMemory::ThreadMemory (Process &process,
+ lldb::tid_t tid,
+ const char *name,
+ const char *queue,
+ lldb::addr_t register_data_addr) :
+ Thread (process, tid),
+ m_backing_thread_sp (),
+ m_thread_info_valobj_sp (),
+ m_name(),
+ m_queue(),
+ m_register_data_addr (register_data_addr)
+{
+ if (name)
+ m_name = name;
+ if (queue)
+ m_queue = queue;
+}
+
+
+ThreadMemory::~ThreadMemory()
+{
+ DestroyThread();
+}
+
+void
+ThreadMemory::WillResume (StateType resume_state)
+{
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->WillResume(resume_state);
+}
+
+void
+ThreadMemory::ClearStackFrames ()
+{
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->ClearStackFrames();
+ Thread::ClearStackFrames();
+}
+
+RegisterContextSP
+ThreadMemory::GetRegisterContext ()
+{
+ if (!m_reg_context_sp)
+ m_reg_context_sp.reset (new RegisterContextThreadMemory (*this, m_register_data_addr));
+ return m_reg_context_sp;
+}
+
+RegisterContextSP
+ThreadMemory::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex ();
+
+ if (concrete_frame_idx == 0)
+ {
+ reg_ctx_sp = GetRegisterContext ();
+ }
+ else
+ {
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ reg_ctx_sp = unwinder->CreateRegisterContextForFrame (frame);
+ }
+ return reg_ctx_sp;
+}
+
+bool
+ThreadMemory::CalculateStopInfo ()
+{
+ if (m_backing_thread_sp)
+ {
+ lldb::StopInfoSP backing_stop_info_sp (m_backing_thread_sp->GetPrivateStopInfo());
+ if (backing_stop_info_sp)
+ {
+ backing_stop_info_sp->SetThread (shared_from_this());
+ SetStopInfo (backing_stop_info_sp);
+ return true;
+ }
+ }
+ else
+ {
+ ProcessSP process_sp (GetProcess());
+
+ if (process_sp)
+ {
+ OperatingSystem *os = process_sp->GetOperatingSystem ();
+ if (os)
+ {
+ SetStopInfo (os->CreateThreadStopReason (this));
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void
+ThreadMemory::RefreshStateAfterStop()
+{
+ if (m_backing_thread_sp)
+ return m_backing_thread_sp->RefreshStateAfterStop();
+
+ if (m_reg_context_sp)
+ m_reg_context_sp->InvalidateAllRegisters();
+}
diff --git a/source/Plugins/Process/Utility/ThreadMemory.h b/source/Plugins/Process/Utility/ThreadMemory.h
new file mode 100644
index 000000000000..07eb45dcb431
--- /dev/null
+++ b/source/Plugins/Process/Utility/ThreadMemory.h
@@ -0,0 +1,152 @@
+//===-- ThreadMemory.h -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ThreadMemory_h_
+#define liblldb_ThreadMemory_h_
+
+#include "lldb/Target/Thread.h"
+
+class ThreadMemory :
+ public lldb_private::Thread
+{
+public:
+
+ ThreadMemory (lldb_private::Process &process,
+ lldb::tid_t tid,
+ const lldb::ValueObjectSP &thread_info_valobj_sp);
+
+ ThreadMemory (lldb_private::Process &process,
+ lldb::tid_t tid,
+ const char *name,
+ const char *queue,
+ lldb::addr_t register_data_addr);
+
+ virtual
+ ~ThreadMemory();
+
+ //------------------------------------------------------------------
+ // lldb_private::Thread methods
+ //------------------------------------------------------------------
+ virtual lldb::RegisterContextSP
+ GetRegisterContext ();
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ virtual bool
+ CalculateStopInfo ();
+
+ virtual const char *
+ GetInfo ()
+ {
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->GetInfo();
+ return NULL;
+ }
+
+ virtual const char *
+ GetName ()
+ {
+ if (!m_name.empty())
+ return m_name.c_str();
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->GetName();
+ return NULL;
+ }
+
+ virtual const char *
+ GetQueueName ()
+ {
+ if (!m_queue.empty())
+ return m_queue.c_str();
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->GetQueueName();
+ return NULL;
+ }
+
+ virtual void
+ WillResume (lldb::StateType resume_state);
+
+ virtual void
+ DidResume ()
+ {
+ if (m_backing_thread_sp)
+ m_backing_thread_sp->DidResume();
+ }
+
+ virtual lldb::user_id_t
+ GetProtocolID () const
+ {
+ if (m_backing_thread_sp)
+ return m_backing_thread_sp->GetProtocolID();
+ return Thread::GetProtocolID();
+ }
+
+ virtual void
+ RefreshStateAfterStop();
+
+ lldb::ValueObjectSP &
+ GetValueObject ()
+ {
+ return m_thread_info_valobj_sp;
+ }
+
+ virtual void
+ ClearStackFrames ();
+
+ virtual void
+ ClearBackingThread ()
+ {
+ m_backing_thread_sp.reset();
+ }
+
+ virtual bool
+ SetBackingThread (const lldb::ThreadSP &thread_sp)
+ {
+ //printf ("Thread 0x%llx is being backed by thread 0x%llx\n", GetID(), thread_sp->GetID());
+ m_backing_thread_sp = thread_sp;
+ return (bool)thread_sp;
+ }
+
+ virtual lldb::ThreadSP
+ GetBackingThread () const
+ {
+ return m_backing_thread_sp;
+ }
+
+protected:
+
+ virtual bool
+ IsOperatingSystemPluginThread () const
+ {
+ return true;
+ }
+
+
+ //------------------------------------------------------------------
+ // For ThreadMemory and subclasses
+ //------------------------------------------------------------------
+ // If this memory thread is actually represented by a thread from the
+ // lldb_private::Process subclass, then fill in the thread here and
+ // all APIs will be routed through this thread object. If m_backing_thread_sp
+ // is empty, then this thread is simply in memory with no representation
+ // through the process plug-in.
+ lldb::ThreadSP m_backing_thread_sp;
+ lldb::ValueObjectSP m_thread_info_valobj_sp;
+ std::string m_name;
+ std::string m_queue;
+ lldb::addr_t m_register_data_addr;
+private:
+ //------------------------------------------------------------------
+ // For ThreadMemory only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ThreadMemory);
+};
+
+#endif // liblldb_ThreadMemory_h_
diff --git a/source/Plugins/Process/Utility/UnwindLLDB.cpp b/source/Plugins/Process/Utility/UnwindLLDB.cpp
new file mode 100644
index 000000000000..0eea00363498
--- /dev/null
+++ b/source/Plugins/Process/Utility/UnwindLLDB.cpp
@@ -0,0 +1,322 @@
+//===-- UnwindLLDB.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+
+#include "UnwindLLDB.h"
+#include "RegisterContextLLDB.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+UnwindLLDB::UnwindLLDB (Thread &thread) :
+ Unwind (thread),
+ m_frames(),
+ m_unwind_complete(false)
+{
+}
+
+uint32_t
+UnwindLLDB::DoGetFrameCount()
+{
+ if (!m_unwind_complete)
+ {
+//#define DEBUG_FRAME_SPEED 1
+#if DEBUG_FRAME_SPEED
+#define FRAME_COUNT 10000
+ TimeValue time_value (TimeValue::Now());
+#endif
+ if (!AddFirstFrame ())
+ return 0;
+
+ ProcessSP process_sp (m_thread.GetProcess());
+ ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
+
+ while (AddOneMoreFrame (abi))
+ {
+#if DEBUG_FRAME_SPEED
+ if ((m_frames.size() % FRAME_COUNT) == 0)
+ {
+ TimeValue now(TimeValue::Now());
+ uint64_t delta_t = now - time_value;
+ printf ("%u frames in %" PRIu64 ".%09llu ms (%g frames/sec)\n",
+ FRAME_COUNT,
+ delta_t / TimeValue::NanoSecPerSec,
+ delta_t % TimeValue::NanoSecPerSec,
+ (float)FRAME_COUNT / ((float)delta_t / (float)TimeValue::NanoSecPerSec));
+ time_value = now;
+ }
+#endif
+ }
+ }
+ return m_frames.size ();
+}
+
+bool
+UnwindLLDB::AddFirstFrame ()
+{
+ if (m_frames.size() > 0)
+ return true;
+
+ // First, set up the 0th (initial) frame
+ CursorSP first_cursor_sp(new Cursor ());
+ RegisterContextLLDBSP reg_ctx_sp (new RegisterContextLLDB (m_thread,
+ RegisterContextLLDBSP(),
+ first_cursor_sp->sctx,
+ 0, *this));
+ if (reg_ctx_sp.get() == NULL)
+ goto unwind_done;
+
+ if (!reg_ctx_sp->IsValid())
+ goto unwind_done;
+
+ if (!reg_ctx_sp->GetCFA (first_cursor_sp->cfa))
+ goto unwind_done;
+
+ if (!reg_ctx_sp->ReadPC (first_cursor_sp->start_pc))
+ goto unwind_done;
+
+ // Everything checks out, so release the auto pointer value and let the
+ // cursor own it in its shared pointer
+ first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp;
+ m_frames.push_back (first_cursor_sp);
+ return true;
+unwind_done:
+ m_unwind_complete = true;
+ return false;
+}
+
+// For adding a non-zero stack frame to m_frames.
+bool
+UnwindLLDB::AddOneMoreFrame (ABI *abi)
+{
+ // If we've already gotten to the end of the stack, don't bother to try again...
+ if (m_unwind_complete)
+ return false;
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+ CursorSP cursor_sp(new Cursor ());
+
+ // Frame zero is a little different
+ if (m_frames.size() == 0)
+ return false;
+
+ uint32_t cur_idx = m_frames.size ();
+ RegisterContextLLDBSP reg_ctx_sp(new RegisterContextLLDB (m_thread,
+ m_frames[cur_idx - 1]->reg_ctx_lldb_sp,
+ cursor_sp->sctx,
+ cur_idx,
+ *this));
+
+ // We want to detect an unwind that cycles erronously and stop backtracing.
+ // Don't want this maximum unwind limit to be too low -- if you have a backtrace
+ // with an "infinitely recursing" bug, it will crash when the stack blows out
+ // and the first 35,000 frames are uninteresting - it's the top most 5 frames that
+ // you actually care about. So you can't just cap the unwind at 10,000 or something.
+ // Realistically anything over around 200,000 is going to blow out the stack space.
+ // If we're still unwinding at that point, we're probably never going to finish.
+ if (cur_idx > 300000)
+ {
+ if (log)
+ log->Printf ("%*sFrame %d unwound too many frames, assuming unwind has gone astray, stopping.",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ goto unwind_done;
+ }
+
+ if (reg_ctx_sp.get() == NULL)
+ goto unwind_done;
+
+ if (!reg_ctx_sp->IsValid())
+ {
+ if (log)
+ {
+ log->Printf("%*sFrame %d invalid RegisterContext for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ goto unwind_done;
+ }
+ if (!reg_ctx_sp->GetCFA (cursor_sp->cfa))
+ {
+ if (log)
+ {
+ log->Printf("%*sFrame %d did not get CFA for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ goto unwind_done;
+ }
+ if (abi && !abi->CallFrameAddressIsValid(cursor_sp->cfa))
+ {
+ if (log)
+ {
+ log->Printf("%*sFrame %d did not get a valid CFA for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ goto unwind_done;
+ }
+ if (!reg_ctx_sp->ReadPC (cursor_sp->start_pc))
+ {
+ if (log)
+ {
+ log->Printf("%*sFrame %d did not get PC for this frame, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ goto unwind_done;
+ }
+ if (abi && !abi->CodeAddressIsValid (cursor_sp->start_pc))
+ {
+ if (log)
+ {
+ log->Printf("%*sFrame %d did not get a valid PC, stopping stack walk",
+ cur_idx < 100 ? cur_idx : 100, "", cur_idx);
+ }
+ goto unwind_done;
+ }
+ if (!m_frames.empty())
+ {
+ if (m_frames.back()->start_pc == cursor_sp->start_pc)
+ {
+ if (m_frames.back()->cfa == cursor_sp->cfa)
+ goto unwind_done; // Infinite loop where the current cursor is the same as the previous one...
+ else if (abi && abi->StackUsesFrames())
+ {
+ // We might have a CFA that is not using the frame pointer and
+ // we want to validate that the frame pointer is valid.
+ if (reg_ctx_sp->GetFP() == 0)
+ goto unwind_done;
+ }
+ }
+ }
+ cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp;
+ m_frames.push_back (cursor_sp);
+ return true;
+
+unwind_done:
+ m_unwind_complete = true;
+ return false;
+}
+
+bool
+UnwindLLDB::DoGetFrameInfoAtIndex (uint32_t idx, addr_t& cfa, addr_t& pc)
+{
+ if (m_frames.size() == 0)
+ {
+ if (!AddFirstFrame())
+ return false;
+ }
+
+ ProcessSP process_sp (m_thread.GetProcess());
+ ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
+
+ while (idx >= m_frames.size() && AddOneMoreFrame (abi))
+ ;
+
+ if (idx < m_frames.size ())
+ {
+ cfa = m_frames[idx]->cfa;
+ pc = m_frames[idx]->start_pc;
+ return true;
+ }
+ return false;
+}
+
+lldb::RegisterContextSP
+UnwindLLDB::DoCreateRegisterContextForFrame (StackFrame *frame)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+ uint32_t idx = frame->GetConcreteFrameIndex ();
+
+ if (idx == 0)
+ {
+ return m_thread.GetRegisterContext();
+ }
+
+ if (m_frames.size() == 0)
+ {
+ if (!AddFirstFrame())
+ return reg_ctx_sp;
+ }
+
+ ProcessSP process_sp (m_thread.GetProcess());
+ ABI *abi = process_sp ? process_sp->GetABI().get() : NULL;
+
+ while (idx >= m_frames.size())
+ {
+ if (!AddOneMoreFrame (abi))
+ break;
+ }
+
+ const uint32_t num_frames = m_frames.size();
+ if (idx < num_frames)
+ {
+ Cursor *frame_cursor = m_frames[idx].get();
+ reg_ctx_sp = frame_cursor->reg_ctx_lldb_sp;
+ }
+ return reg_ctx_sp;
+}
+
+UnwindLLDB::RegisterContextLLDBSP
+UnwindLLDB::GetRegisterContextForFrameNum (uint32_t frame_num)
+{
+ RegisterContextLLDBSP reg_ctx_sp;
+ if (frame_num < m_frames.size())
+ reg_ctx_sp = m_frames[frame_num]->reg_ctx_lldb_sp;
+ return reg_ctx_sp;
+}
+
+bool
+UnwindLLDB::SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc, uint32_t starting_frame_num, bool pc_reg)
+{
+ int64_t frame_num = starting_frame_num;
+ if (frame_num >= m_frames.size())
+ return false;
+
+ // Never interrogate more than one level while looking for the saved pc value. If the value
+ // isn't saved by frame_num, none of the frames lower on the stack will have a useful value.
+ if (pc_reg)
+ {
+ UnwindLLDB::RegisterSearchResult result;
+ result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister (lldb_regnum, regloc);
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound)
+ return true;
+ else
+ return false;
+ }
+ while (frame_num >= 0)
+ {
+ UnwindLLDB::RegisterSearchResult result;
+ result = m_frames[frame_num]->reg_ctx_lldb_sp->SavedLocationForRegister (lldb_regnum, regloc);
+
+ // If we have unwind instructions saying that register N is saved in register M in the middle of
+ // the stack (and N can equal M here, meaning the register was not used in this function), then
+ // change the register number we're looking for to M and keep looking for a concrete location
+ // down the stack, or an actual value from a live RegisterContext at frame 0.
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound
+ && regloc.type == UnwindLLDB::RegisterLocation::eRegisterInRegister
+ && frame_num > 0)
+ {
+ result = UnwindLLDB::RegisterSearchResult::eRegisterNotFound;
+ lldb_regnum = regloc.location.register_number;
+ }
+
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterFound)
+ return true;
+ if (result == UnwindLLDB::RegisterSearchResult::eRegisterIsVolatile)
+ return false;
+ frame_num--;
+ }
+ return false;
+}
diff --git a/source/Plugins/Process/Utility/UnwindLLDB.h b/source/Plugins/Process/Utility/UnwindLLDB.h
new file mode 100644
index 000000000000..5725654a6869
--- /dev/null
+++ b/source/Plugins/Process/Utility/UnwindLLDB.h
@@ -0,0 +1,125 @@
+//===-- UnwindLLDB.h --------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_UnwindLLDB_h_
+#define lldb_UnwindLLDB_h_
+
+#include <vector>
+
+#include "lldb/lldb-public.h"
+#include "lldb/Symbol/FuncUnwinders.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Unwind.h"
+
+namespace lldb_private {
+
+class RegisterContextLLDB;
+
+class UnwindLLDB : public lldb_private::Unwind
+{
+public:
+ UnwindLLDB (lldb_private::Thread &thread);
+
+ virtual
+ ~UnwindLLDB() { }
+
+ enum RegisterSearchResult
+ {
+ eRegisterFound = 0,
+ eRegisterNotFound,
+ eRegisterIsVolatile
+ };
+
+protected:
+ friend class lldb_private::RegisterContextLLDB;
+
+ struct RegisterLocation {
+ enum RegisterLocationTypes
+ {
+ eRegisterNotSaved = 0, // register was not preserved by callee. If volatile reg, is unavailable
+ eRegisterSavedAtMemoryLocation, // register is saved at a specific word of target mem (target_memory_location)
+ eRegisterInRegister, // register is available in a (possible other) register (register_number)
+ eRegisterSavedAtHostMemoryLocation, // register is saved at a word in lldb's address space
+ eRegisterValueInferred // register val was computed (and is in inferred_value)
+ };
+ int type;
+ union
+ {
+ lldb::addr_t target_memory_location;
+ uint32_t register_number; // in eRegisterKindLLDB register numbering system
+ void* host_memory_location;
+ uint64_t inferred_value; // eRegisterValueInferred - e.g. stack pointer == cfa + offset
+ } location;
+ };
+
+ void
+ DoClear()
+ {
+ m_frames.clear();
+ m_unwind_complete = false;
+ }
+
+ virtual uint32_t
+ DoGetFrameCount();
+
+ bool
+ DoGetFrameInfoAtIndex (uint32_t frame_idx,
+ lldb::addr_t& cfa,
+ lldb::addr_t& start_pc);
+
+ lldb::RegisterContextSP
+ DoCreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ typedef std::shared_ptr<RegisterContextLLDB> RegisterContextLLDBSP;
+
+ // Needed to retrieve the "next" frame (e.g. frame 2 needs to retrieve frame 1's RegisterContextLLDB)
+ // The RegisterContext for frame_num must already exist or this returns an empty shared pointer.
+ RegisterContextLLDBSP
+ GetRegisterContextForFrameNum (uint32_t frame_num);
+
+ // Iterate over the RegisterContextLLDB's in our m_frames vector, look for the first one that
+ // has a saved location for this reg.
+ bool
+ SearchForSavedLocationForRegister (uint32_t lldb_regnum, lldb_private::UnwindLLDB::RegisterLocation &regloc, uint32_t starting_frame_num, bool pc_register);
+
+
+private:
+
+ struct Cursor
+ {
+ lldb::addr_t start_pc; // The start address of the function/symbol for this frame - current pc if unknown
+ lldb::addr_t cfa; // The canonical frame address for this stack frame
+ lldb_private::SymbolContext sctx; // A symbol context we'll contribute to & provide to the StackFrame creation
+ RegisterContextLLDBSP reg_ctx_lldb_sp; // These are all RegisterContextLLDB's
+
+ Cursor () : start_pc (LLDB_INVALID_ADDRESS), cfa (LLDB_INVALID_ADDRESS), sctx(), reg_ctx_lldb_sp() { }
+ private:
+ DISALLOW_COPY_AND_ASSIGN (Cursor);
+ };
+
+ typedef std::shared_ptr<Cursor> CursorSP;
+ std::vector<CursorSP> m_frames;
+ bool m_unwind_complete; // If this is true, we've enumerated all the frames in the stack, and m_frames.size() is the
+ // number of frames, etc. Otherwise we've only gone as far as directly asked, and m_frames.size()
+ // is how far we've currently gone.
+
+
+ bool AddOneMoreFrame (ABI *abi);
+ bool AddFirstFrame ();
+
+ //------------------------------------------------------------------
+ // For UnwindLLDB only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (UnwindLLDB);
+};
+
+} // namespace lldb_private
+
+#endif // lldb_UnwindLLDB_h_
diff --git a/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp
new file mode 100644
index 000000000000..d011314b0963
--- /dev/null
+++ b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.cpp
@@ -0,0 +1,275 @@
+//===-- UnwindMacOSXFrameBackchain.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+#include "RegisterContextMacOSXFrameBackchain.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+UnwindMacOSXFrameBackchain::UnwindMacOSXFrameBackchain (Thread &thread) :
+ Unwind (thread),
+ m_cursors()
+{
+}
+
+uint32_t
+UnwindMacOSXFrameBackchain::DoGetFrameCount()
+{
+ if (m_cursors.empty())
+ {
+ ExecutionContext exe_ctx (m_thread.shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ {
+ const ArchSpec& target_arch = target->GetArchitecture ();
+ // Frame zero should always be supplied by the thread...
+ exe_ctx.SetFrameSP (m_thread.GetStackFrameAtIndex (0));
+
+ if (target_arch.GetAddressByteSize() == 8)
+ GetStackFrameData_x86_64 (exe_ctx);
+ else
+ GetStackFrameData_i386 (exe_ctx);
+ }
+ }
+ return m_cursors.size();
+}
+
+bool
+UnwindMacOSXFrameBackchain::DoGetFrameInfoAtIndex (uint32_t idx, addr_t& cfa, addr_t& pc)
+{
+ const uint32_t frame_count = GetFrameCount();
+ if (idx < frame_count)
+ {
+ if (m_cursors[idx].pc == LLDB_INVALID_ADDRESS)
+ return false;
+ if (m_cursors[idx].fp == LLDB_INVALID_ADDRESS)
+ return false;
+
+ pc = m_cursors[idx].pc;
+ cfa = m_cursors[idx].fp;
+
+ return true;
+ }
+ return false;
+}
+
+lldb::RegisterContextSP
+UnwindMacOSXFrameBackchain::DoCreateRegisterContextForFrame (StackFrame *frame)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_idx = frame->GetConcreteFrameIndex ();
+ const uint32_t frame_count = GetFrameCount();
+ if (concrete_idx < frame_count)
+ reg_ctx_sp.reset (new RegisterContextMacOSXFrameBackchain (m_thread, concrete_idx, m_cursors[concrete_idx]));
+ return reg_ctx_sp;
+}
+
+size_t
+UnwindMacOSXFrameBackchain::GetStackFrameData_i386 (const ExecutionContext &exe_ctx)
+{
+ m_cursors.clear();
+
+ StackFrame *first_frame = exe_ctx.GetFramePtr();
+
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ return 0;
+
+ std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
+
+ struct Frame_i386
+ {
+ uint32_t fp;
+ uint32_t pc;
+ };
+
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
+ assert (reg_ctx);
+
+ Cursor cursor;
+ cursor.pc = reg_ctx->GetPC (LLDB_INVALID_ADDRESS);
+ cursor.fp = reg_ctx->GetFP (0);
+
+ Frame_i386 frame = { static_cast<uint32_t>(cursor.fp), static_cast<uint32_t>(cursor.pc) };
+
+ m_cursors.push_back(cursor);
+
+ const size_t k_frame_size = sizeof(frame);
+ Error error;
+ while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
+ {
+ // Read both the FP and PC (8 bytes)
+ if (process->ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
+ break;
+ if (frame.pc >= 0x1000)
+ {
+ cursor.pc = frame.pc;
+ cursor.fp = frame.fp;
+ m_cursors.push_back (cursor);
+ }
+ }
+ if (!m_cursors.empty())
+ {
+ lldb::addr_t first_frame_pc = m_cursors.front().pc;
+ if (first_frame_pc != LLDB_INVALID_ADDRESS)
+ {
+ const uint32_t resolve_scope = eSymbolContextModule |
+ eSymbolContextCompUnit |
+ eSymbolContextFunction |
+ eSymbolContextSymbol;
+
+ SymbolContext first_frame_sc (first_frame->GetSymbolContext(resolve_scope));
+ const AddressRange *addr_range_ptr = NULL;
+ AddressRange range;
+ if (first_frame_sc.function)
+ addr_range_ptr = &first_frame_sc.function->GetAddressRange();
+ else if (first_frame_sc.symbol)
+ {
+ range.GetBaseAddress() = first_frame_sc.symbol->GetAddress();
+ range.SetByteSize (first_frame_sc.symbol->GetByteSize());
+ addr_range_ptr = &range;
+ }
+
+ if (addr_range_ptr)
+ {
+ if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress())
+ {
+ // We are at the first instruction, so we can recover the
+ // previous PC by dereferencing the SP
+ lldb::addr_t first_frame_sp = reg_ctx->GetSP (0);
+ // Read the real second frame return address into frame.pc
+ if (first_frame_sp && process->ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
+ {
+ cursor.fp = m_cursors.front().fp;
+ cursor.pc = frame.pc; // Set the new second frame PC
+
+ // Insert the second frame
+ m_cursors.insert(m_cursors.begin()+1, cursor);
+
+ m_cursors.front().fp = first_frame_sp;
+ }
+ }
+ }
+ }
+ }
+// uint32_t i=0;
+// printf(" PC FP\n");
+// printf(" ------------------ ------------------ \n");
+// for (i=0; i<m_cursors.size(); ++i)
+// {
+// printf("[%3u] 0x%16.16" PRIx64 " 0x%16.16" PRIx64 "\n", i, m_cursors[i].pc, m_cursors[i].fp);
+// }
+ return m_cursors.size();
+}
+
+
+size_t
+UnwindMacOSXFrameBackchain::GetStackFrameData_x86_64 (const ExecutionContext &exe_ctx)
+{
+ m_cursors.clear();
+
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process == NULL)
+ return 0;
+
+ StackFrame *first_frame = exe_ctx.GetFramePtr();
+
+ std::pair<lldb::addr_t, lldb::addr_t> fp_pc_pair;
+
+ struct Frame_x86_64
+ {
+ uint64_t fp;
+ uint64_t pc;
+ };
+
+ RegisterContext *reg_ctx = m_thread.GetRegisterContext().get();
+ assert (reg_ctx);
+
+ Cursor cursor;
+ cursor.pc = reg_ctx->GetPC (LLDB_INVALID_ADDRESS);
+ cursor.fp = reg_ctx->GetFP (0);
+
+ Frame_x86_64 frame = { cursor.fp, cursor.pc };
+
+ m_cursors.push_back(cursor);
+ Error error;
+ const size_t k_frame_size = sizeof(frame);
+ while (frame.fp != 0 && frame.pc != 0 && ((frame.fp & 7) == 0))
+ {
+ // Read both the FP and PC (16 bytes)
+ if (process->ReadMemory (frame.fp, &frame.fp, k_frame_size, error) != k_frame_size)
+ break;
+
+ if (frame.pc >= 0x1000)
+ {
+ cursor.pc = frame.pc;
+ cursor.fp = frame.fp;
+ m_cursors.push_back (cursor);
+ }
+ }
+ if (!m_cursors.empty())
+ {
+ lldb::addr_t first_frame_pc = m_cursors.front().pc;
+ if (first_frame_pc != LLDB_INVALID_ADDRESS)
+ {
+ const uint32_t resolve_scope = eSymbolContextModule |
+ eSymbolContextCompUnit |
+ eSymbolContextFunction |
+ eSymbolContextSymbol;
+
+ SymbolContext first_frame_sc(first_frame->GetSymbolContext(resolve_scope));
+ const AddressRange *addr_range_ptr = NULL;
+ AddressRange range;
+ if (first_frame_sc.function)
+ addr_range_ptr = &first_frame_sc.function->GetAddressRange();
+ else if (first_frame_sc.symbol)
+ {
+ range.GetBaseAddress() = first_frame_sc.symbol->GetAddress();
+ range.SetByteSize (first_frame_sc.symbol->GetByteSize());
+ addr_range_ptr = &range;
+ }
+
+ if (addr_range_ptr)
+ {
+ if (first_frame->GetFrameCodeAddress() == addr_range_ptr->GetBaseAddress())
+ {
+ // We are at the first instruction, so we can recover the
+ // previous PC by dereferencing the SP
+ lldb::addr_t first_frame_sp = reg_ctx->GetSP (0);
+ // Read the real second frame return address into frame.pc
+ if (process->ReadMemory (first_frame_sp, &frame.pc, sizeof(frame.pc), error) == sizeof(frame.pc))
+ {
+ cursor.fp = m_cursors.front().fp;
+ cursor.pc = frame.pc; // Set the new second frame PC
+
+ // Insert the second frame
+ m_cursors.insert(m_cursors.begin()+1, cursor);
+
+ m_cursors.front().fp = first_frame_sp;
+ }
+ }
+ }
+ }
+ }
+ return m_cursors.size();
+}
+
diff --git a/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h
new file mode 100644
index 000000000000..2695376fd6e0
--- /dev/null
+++ b/source/Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h
@@ -0,0 +1,74 @@
+//===-- UnwindMacOSXFrameBackchain.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_UnwindMacOSXFrameBackchain_h_
+#define lldb_UnwindMacOSXFrameBackchain_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/Target/Unwind.h"
+
+class UnwindMacOSXFrameBackchain : public lldb_private::Unwind
+{
+public:
+ UnwindMacOSXFrameBackchain (lldb_private::Thread &thread);
+
+ virtual
+ ~UnwindMacOSXFrameBackchain()
+ {
+ }
+
+protected:
+ virtual void
+ DoClear()
+ {
+ m_cursors.clear();
+ }
+
+ virtual uint32_t
+ DoGetFrameCount();
+
+ bool
+ DoGetFrameInfoAtIndex (uint32_t frame_idx,
+ lldb::addr_t& cfa,
+ lldb::addr_t& pc);
+
+ lldb::RegisterContextSP
+ DoCreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ friend class RegisterContextMacOSXFrameBackchain;
+
+ struct Cursor
+ {
+ lldb::addr_t pc; // Program counter
+ lldb::addr_t fp; // Frame pointer for us with backchain
+ };
+
+private:
+ std::vector<Cursor> m_cursors;
+
+ size_t
+ GetStackFrameData_i386 (const lldb_private::ExecutionContext &exe_ctx);
+
+ size_t
+ GetStackFrameData_x86_64 (const lldb_private::ExecutionContext &exe_ctx);
+
+ //------------------------------------------------------------------
+ // For UnwindMacOSXFrameBackchain only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (UnwindMacOSXFrameBackchain);
+};
+
+#endif // lldb_UnwindMacOSXFrameBackchain_h_
diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.cpp b/source/Plugins/Process/elf-core/ProcessElfCore.cpp
new file mode 100644
index 000000000000..dd553ce36c89
--- /dev/null
+++ b/source/Plugins/Process/elf-core/ProcessElfCore.cpp
@@ -0,0 +1,619 @@
+//===-- ProcessElfCore.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// C Includes
+#include <stdlib.h>
+
+// Other libraries and framework includes
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "ProcessPOSIXLog.h"
+
+#include "Plugins/ObjectFile/ELF/ObjectFileELF.h"
+#include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h"
+
+// Project includes
+#include "ProcessElfCore.h"
+#include "ThreadElfCore.h"
+
+using namespace lldb_private;
+
+ConstString
+ProcessElfCore::GetPluginNameStatic()
+{
+ static ConstString g_name("elf-core");
+ return g_name;
+}
+
+const char *
+ProcessElfCore::GetPluginDescriptionStatic()
+{
+ return "ELF core dump plug-in.";
+}
+
+void
+ProcessElfCore::Terminate()
+{
+ PluginManager::UnregisterPlugin (ProcessElfCore::CreateInstance);
+}
+
+
+lldb::ProcessSP
+ProcessElfCore::CreateInstance (Target &target, Listener &listener, const FileSpec *crash_file)
+{
+ lldb::ProcessSP process_sp;
+ if (crash_file)
+ process_sp.reset(new ProcessElfCore (target, listener, *crash_file));
+ return process_sp;
+}
+
+bool
+ProcessElfCore::CanDebug(Target &target, bool plugin_specified_by_name)
+{
+ // For now we are just making sure the file exists for a given module
+ if (!m_core_module_sp && m_core_file.Exists())
+ {
+ ModuleSpec core_module_spec(m_core_file, target.GetArchitecture());
+ Error error (ModuleList::GetSharedModule (core_module_spec, m_core_module_sp,
+ NULL, NULL, NULL));
+ if (m_core_module_sp)
+ {
+ ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+ if (core_objfile && core_objfile->GetType() == ObjectFile::eTypeCoreFile)
+ return true;
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// ProcessElfCore constructor
+//----------------------------------------------------------------------
+ProcessElfCore::ProcessElfCore(Target& target, Listener &listener,
+ const FileSpec &core_file) :
+ Process (target, listener),
+ m_core_module_sp (),
+ m_core_file (core_file),
+ m_dyld_plugin_name (),
+ m_thread_data_valid(false),
+ m_thread_data(),
+ m_core_aranges ()
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ProcessElfCore::~ProcessElfCore()
+{
+ Clear();
+ // We need to call finalize on the process before destroying ourselves
+ // to make sure all of the broadcaster cleanup goes as planned. If we
+ // destruct this class, then Process::~Process() might have problems
+ // trying to fully destroy the broadcaster.
+ Finalize();
+}
+
+//----------------------------------------------------------------------
+// PluginInterface
+//----------------------------------------------------------------------
+ConstString
+ProcessElfCore::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessElfCore::GetPluginVersion()
+{
+ return 1;
+}
+
+lldb::addr_t
+ProcessElfCore::AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader *header)
+{
+ lldb::addr_t addr = header->p_vaddr;
+ FileRange file_range (header->p_offset, header->p_filesz);
+ VMRangeToFileOffset::Entry range_entry(addr, header->p_memsz, file_range);
+
+ VMRangeToFileOffset::Entry *last_entry = m_core_aranges.Back();
+ if (last_entry &&
+ last_entry->GetRangeEnd() == range_entry.GetRangeBase() &&
+ last_entry->data.GetRangeEnd() == range_entry.data.GetRangeBase())
+ {
+ last_entry->SetRangeEnd (range_entry.GetRangeEnd());
+ last_entry->data.SetRangeEnd (range_entry.data.GetRangeEnd());
+ }
+ else
+ {
+ m_core_aranges.Append(range_entry);
+ }
+
+ return addr;
+}
+
+//----------------------------------------------------------------------
+// Process Control
+//----------------------------------------------------------------------
+Error
+ProcessElfCore::DoLoadCore ()
+{
+ Error error;
+ if (!m_core_module_sp)
+ {
+ error.SetErrorString ("invalid core module");
+ return error;
+ }
+
+ ObjectFileELF *core = (ObjectFileELF *)(m_core_module_sp->GetObjectFile());
+ if (core == NULL)
+ {
+ error.SetErrorString ("invalid core object file");
+ return error;
+ }
+
+ const uint32_t num_segments = core->GetProgramHeaderCount();
+ if (num_segments == 0)
+ {
+ error.SetErrorString ("core file has no sections");
+ return error;
+ }
+
+ SetCanJIT(false);
+
+ m_thread_data_valid = true;
+
+ bool ranges_are_sorted = true;
+ lldb::addr_t vm_addr = 0;
+ /// Walk through segments and Thread and Address Map information.
+ /// PT_NOTE - Contains Thread and Register information
+ /// PT_LOAD - Contains a contiguous range of Process Address Space
+ for(uint32_t i = 1; i <= num_segments; i++)
+ {
+ const elf::ELFProgramHeader *header = core->GetProgramHeaderByIndex(i);
+ assert(header != NULL);
+
+ DataExtractor data = core->GetSegmentDataByIndex(i);
+
+ // Parse thread contexts and auxv structure
+ if (header->p_type == llvm::ELF::PT_NOTE)
+ ParseThreadContextsFromNoteSegment(header, data);
+
+ // PT_LOAD segments contains address map
+ if (header->p_type == llvm::ELF::PT_LOAD)
+ {
+ lldb::addr_t last_addr = AddAddressRangeFromLoadSegment(header);
+ if (vm_addr > last_addr)
+ ranges_are_sorted = false;
+ vm_addr = last_addr;
+ }
+ }
+
+ if (!ranges_are_sorted)
+ m_core_aranges.Sort();
+
+ // Even if the architecture is set in the target, we need to override
+ // it to match the core file which is always single arch.
+ ArchSpec arch (m_core_module_sp->GetArchitecture());
+ if (arch.IsValid())
+ m_target.SetArchitecture(arch);
+
+ return error;
+}
+
+lldb_private::DynamicLoader *
+ProcessElfCore::GetDynamicLoader ()
+{
+ if (m_dyld_ap.get() == NULL)
+ m_dyld_ap.reset (DynamicLoader::FindPlugin(this, DynamicLoaderPOSIXDYLD::GetPluginNameStatic().GetCString()));
+ return m_dyld_ap.get();
+}
+
+bool
+ProcessElfCore::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ const uint32_t num_threads = GetNumThreadContexts ();
+ if (!m_thread_data_valid)
+ return false;
+
+ for (lldb::tid_t tid = 0; tid < num_threads; ++tid)
+ {
+ const ThreadData &td = m_thread_data[tid];
+ lldb::ThreadSP thread_sp(new ThreadElfCore (*this, tid, td));
+ new_thread_list.AddThread (thread_sp);
+ }
+ return new_thread_list.GetSize(false) > 0;
+}
+
+void
+ProcessElfCore::RefreshStateAfterStop ()
+{
+}
+
+Error
+ProcessElfCore::DoDestroy ()
+{
+ return Error();
+}
+
+//------------------------------------------------------------------
+// Process Queries
+//------------------------------------------------------------------
+
+bool
+ProcessElfCore::IsAlive ()
+{
+ return true;
+}
+
+//------------------------------------------------------------------
+// Process Memory
+//------------------------------------------------------------------
+size_t
+ProcessElfCore::ReadMemory (lldb::addr_t addr, void *buf, size_t size, Error &error)
+{
+ // Don't allow the caching that lldb_private::Process::ReadMemory does
+ // since in core files we have it all cached our our core file anyway.
+ return DoReadMemory (addr, buf, size, error);
+}
+
+size_t
+ProcessElfCore::DoReadMemory (lldb::addr_t addr, void *buf, size_t size, Error &error)
+{
+ ObjectFile *core_objfile = m_core_module_sp->GetObjectFile();
+
+ if (core_objfile == NULL)
+ return 0;
+
+ // Get the address range
+ const VMRangeToFileOffset::Entry *address_range = m_core_aranges.FindEntryThatContains (addr);
+ if (address_range == NULL || address_range->GetRangeEnd() < addr)
+ {
+ error.SetErrorStringWithFormat ("core file does not contain 0x%" PRIx64, addr);
+ return 0;
+ }
+
+ // Convert the address into core file offset
+ const lldb::addr_t offset = addr - address_range->GetRangeBase();
+ const lldb::addr_t file_start = address_range->data.GetRangeBase();
+ const lldb::addr_t file_end = address_range->data.GetRangeEnd();
+ size_t bytes_to_read = size; // Number of bytes to read from the core file
+ size_t bytes_copied = 0; // Number of bytes actually read from the core file
+ size_t zero_fill_size = 0; // Padding
+ lldb::addr_t bytes_left = 0; // Number of bytes available in the core file from the given address
+
+ if (file_end > offset)
+ bytes_left = file_end - offset;
+
+ if (bytes_to_read > bytes_left)
+ {
+ zero_fill_size = bytes_to_read - bytes_left;
+ bytes_to_read = bytes_left;
+ }
+
+ // If there is data available on the core file read it
+ if (bytes_to_read)
+ bytes_copied = core_objfile->CopyData(offset + file_start, bytes_to_read, buf);
+
+ assert(zero_fill_size <= size);
+ // Pad remaining bytes
+ if (zero_fill_size)
+ memset(((char *)buf) + bytes_copied, 0, zero_fill_size);
+
+ return bytes_copied + zero_fill_size;
+}
+
+void
+ProcessElfCore::Clear()
+{
+ m_thread_list.Clear();
+}
+
+void
+ProcessElfCore::Initialize()
+{
+ static bool g_initialized = false;
+
+ if (g_initialized == false)
+ {
+ g_initialized = true;
+ PluginManager::RegisterPlugin (GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance);
+ }
+}
+
+lldb::addr_t
+ProcessElfCore::GetImageInfoAddress()
+{
+ Target *target = &GetTarget();
+ ObjectFile *obj_file = target->GetExecutableModule()->GetObjectFile();
+ Address addr = obj_file->GetImageInfoAddress();
+
+ if (addr.IsValid())
+ return addr.GetLoadAddress(target);
+ return LLDB_INVALID_ADDRESS;
+}
+
+/// Core files PT_NOTE segment descriptor types
+enum {
+ NT_PRSTATUS = 1,
+ NT_FPREGSET,
+ NT_PRPSINFO,
+ NT_TASKSTRUCT,
+ NT_PLATFORM,
+ NT_AUXV
+};
+
+enum {
+ NT_FREEBSD_PRSTATUS = 1,
+ NT_FREEBSD_FPREGSET,
+ NT_FREEBSD_PRPSINFO,
+ NT_FREEBSD_THRMISC = 7,
+ NT_FREEBSD_PROCSTAT_AUXV = 16
+};
+
+/// Align the given value to next boundary specified by the alignment bytes
+static uint32_t
+AlignToNext(uint32_t value, int alignment_bytes)
+{
+ return (value + alignment_bytes - 1) & ~(alignment_bytes - 1);
+}
+
+/// Note Structure found in ELF core dumps.
+/// This is PT_NOTE type program/segments in the core file.
+struct ELFNote
+{
+ elf::elf_word n_namesz;
+ elf::elf_word n_descsz;
+ elf::elf_word n_type;
+
+ std::string n_name;
+
+ ELFNote() : n_namesz(0), n_descsz(0), n_type(0)
+ {
+ }
+
+ /// Parse an ELFNote entry from the given DataExtractor starting at position
+ /// \p offset.
+ ///
+ /// @param[in] data
+ /// The DataExtractor to read from.
+ ///
+ /// @param[in,out] offset
+ /// Pointer to an offset in the data. On return the offset will be
+ /// advanced by the number of bytes read.
+ ///
+ /// @return
+ /// True if the ELFRel entry was successfully read and false otherwise.
+ bool
+ Parse(const DataExtractor &data, lldb::offset_t *offset)
+ {
+ // Read all fields.
+ if (data.GetU32(offset, &n_namesz, 3) == NULL)
+ return false;
+
+ // The name field is required to be nul-terminated, and n_namesz
+ // includes the terminating nul in observed implementations (contrary
+ // to the ELF-64 spec). A special case is needed for cores generated
+ // by some older Linux versions, which write a note named "CORE"
+ // without a nul terminator and n_namesz = 4.
+ if (n_namesz == 4)
+ {
+ char buf[4];
+ if (data.ExtractBytes (*offset, 4, data.GetByteOrder(), buf) != 4)
+ return false;
+ if (strncmp (buf, "CORE", 4) == 0)
+ {
+ n_name = "CORE";
+ *offset += 4;
+ return true;
+ }
+ }
+
+ const char *cstr = data.GetCStr(offset, AlignToNext(n_namesz, 4));
+ if (cstr == NULL)
+ {
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+ if (log)
+ log->Printf("Failed to parse note name lacking nul terminator");
+
+ return false;
+ }
+ n_name = cstr;
+ return true;
+ }
+};
+
+// Parse a FreeBSD NT_PRSTATUS note - see FreeBSD sys/procfs.h for details.
+static void
+ParseFreeBSDPrStatus(ThreadData *thread_data, DataExtractor &data,
+ ArchSpec &arch)
+{
+ lldb::offset_t offset = 0;
+ bool have_padding = (arch.GetMachine() == llvm::Triple::x86_64);
+ int pr_version = data.GetU32(&offset);
+
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
+ if (log)
+ {
+ if (pr_version > 1)
+ log->Printf("FreeBSD PRSTATUS unexpected version %d", pr_version);
+ }
+
+ if (have_padding)
+ offset += 4;
+ offset += 28; // pr_statussz, pr_gregsetsz, pr_fpregsetsz, pr_osreldate
+ thread_data->signo = data.GetU32(&offset); // pr_cursig
+ offset += 4; // pr_pid
+ if (have_padding)
+ offset += 4;
+
+ size_t len = data.GetByteSize() - offset;
+ thread_data->gpregset = DataExtractor(data, offset, len);
+}
+
+static void
+ParseFreeBSDThrMisc(ThreadData *thread_data, DataExtractor &data)
+{
+ lldb::offset_t offset = 0;
+ thread_data->name = data.GetCStr(&offset, 20);
+}
+
+/// Parse Thread context from PT_NOTE segment and store it in the thread list
+/// Notes:
+/// 1) A PT_NOTE segment is composed of one or more NOTE entries.
+/// 2) NOTE Entry contains a standard header followed by variable size data.
+/// (see ELFNote structure)
+/// 3) A Thread Context in a core file usually described by 3 NOTE entries.
+/// a) NT_PRSTATUS - Register context
+/// b) NT_PRPSINFO - Process info(pid..)
+/// c) NT_FPREGSET - Floating point registers
+/// 4) The NOTE entries can be in any order
+/// 5) If a core file contains multiple thread contexts then there is two data forms
+/// a) Each thread context(2 or more NOTE entries) contained in its own segment (PT_NOTE)
+/// b) All thread context is stored in a single segment(PT_NOTE).
+/// This case is little tricker since while parsing we have to find where the
+/// new thread starts. The current implementation marks beginning of
+/// new thread when it finds NT_PRSTATUS or NT_PRPSINFO NOTE entry.
+/// For case (b) there may be either one NT_PRPSINFO per thread, or a single
+/// one that applies to all threads (depending on the platform type).
+void
+ProcessElfCore::ParseThreadContextsFromNoteSegment(const elf::ELFProgramHeader *segment_header,
+ DataExtractor segment_data)
+{
+ assert(segment_header && segment_header->p_type == llvm::ELF::PT_NOTE);
+
+ lldb::offset_t offset = 0;
+ ThreadData *thread_data = new ThreadData();
+ bool have_prstatus = false;
+ bool have_prpsinfo = false;
+
+ ArchSpec arch = GetArchitecture();
+ ELFLinuxPrPsInfo prpsinfo;
+ ELFLinuxPrStatus prstatus;
+ size_t header_size;
+ size_t len;
+
+ // Loop through the NOTE entires in the segment
+ while (offset < segment_header->p_filesz)
+ {
+ ELFNote note = ELFNote();
+ note.Parse(segment_data, &offset);
+
+ // Beginning of new thread
+ if ((note.n_type == NT_PRSTATUS && have_prstatus) ||
+ (note.n_type == NT_PRPSINFO && have_prpsinfo))
+ {
+ assert(thread_data->gpregset.GetByteSize() > 0);
+ // Add the new thread to thread list
+ m_thread_data.push_back(*thread_data);
+ thread_data = new ThreadData();
+ have_prstatus = false;
+ have_prpsinfo = false;
+ }
+
+ size_t note_start, note_size;
+ note_start = offset;
+ note_size = AlignToNext(note.n_descsz, 4);
+
+ // Store the NOTE information in the current thread
+ DataExtractor note_data (segment_data, note_start, note_size);
+ if (note.n_name == "FreeBSD")
+ {
+ switch (note.n_type)
+ {
+ case NT_FREEBSD_PRSTATUS:
+ have_prstatus = true;
+ ParseFreeBSDPrStatus(thread_data, note_data, arch);
+ break;
+ case NT_FREEBSD_FPREGSET:
+ thread_data->fpregset = note_data;
+ break;
+ case NT_FREEBSD_PRPSINFO:
+ have_prpsinfo = true;
+ break;
+ case NT_FREEBSD_THRMISC:
+ ParseFreeBSDThrMisc(thread_data, note_data);
+ break;
+ case NT_FREEBSD_PROCSTAT_AUXV:
+ // FIXME: FreeBSD sticks an int at the beginning of the note
+ m_auxv = DataExtractor(segment_data, note_start + 4, note_size - 4);
+ break;
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch (note.n_type)
+ {
+ case NT_PRSTATUS:
+ have_prstatus = true;
+ prstatus.Parse(note_data, arch);
+ thread_data->signo = prstatus.pr_cursig;
+ header_size = ELFLinuxPrStatus::GetSize(arch);
+ len = note_data.GetByteSize() - header_size;
+ thread_data->gpregset = DataExtractor(note_data, header_size, len);
+ break;
+ case NT_FPREGSET:
+ thread_data->fpregset = note_data;
+ break;
+ case NT_PRPSINFO:
+ have_prpsinfo = true;
+ prpsinfo.Parse(note_data, arch);
+ thread_data->name = prpsinfo.pr_fname;
+ break;
+ case NT_AUXV:
+ m_auxv = DataExtractor(note_data);
+ break;
+ default:
+ break;
+ }
+ }
+
+ offset += note_size;
+ }
+ // Add last entry in the note section
+ if (thread_data && thread_data->gpregset.GetByteSize() > 0)
+ {
+ m_thread_data.push_back(*thread_data);
+ }
+}
+
+uint32_t
+ProcessElfCore::GetNumThreadContexts ()
+{
+ if (!m_thread_data_valid)
+ DoLoadCore();
+ return m_thread_data.size();
+}
+
+ArchSpec
+ProcessElfCore::GetArchitecture()
+{
+ ObjectFileELF *core_file = (ObjectFileELF *)(m_core_module_sp->GetObjectFile());
+ ArchSpec arch;
+ core_file->GetArchitecture(arch);
+ return arch;
+}
+
+const lldb::DataBufferSP
+ProcessElfCore::GetAuxvData()
+{
+ const uint8_t *start = m_auxv.GetDataStart();
+ size_t len = m_auxv.GetByteSize();
+ lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(start, len));
+ return buffer;
+}
+
diff --git a/source/Plugins/Process/elf-core/ProcessElfCore.h b/source/Plugins/Process/elf-core/ProcessElfCore.h
new file mode 100644
index 000000000000..1c1ed98ce17a
--- /dev/null
+++ b/source/Plugins/Process/elf-core/ProcessElfCore.h
@@ -0,0 +1,171 @@
+//===-- ProcessElfCore.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+// Notes about Linux Process core dumps:
+// 1) Linux core dump is stored as ELF file.
+// 2) The ELF file's PT_NOTE and PT_LOAD segments describes the program's
+// address space and thread contexts.
+// 3) PT_NOTE segment contains note entries which describes a thread context.
+// 4) PT_LOAD segment describes a valid contigous range of process address
+// space.
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessElfCore_h_
+#define liblldb_ProcessElfCore_h_
+
+// C++ Includes
+#include <list>
+#include <vector>
+
+// Other libraries and framework includes
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Target/Process.h"
+
+#include "Plugins/ObjectFile/ELF/ELFHeader.h"
+
+struct ThreadData;
+
+class ProcessElfCore : public lldb_private::Process
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ static lldb::ProcessSP
+ CreateInstance (lldb_private::Target& target,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec *crash_file_path);
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ProcessElfCore(lldb_private::Target& target,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec &core_file);
+
+ virtual
+ ~ProcessElfCore();
+
+ //------------------------------------------------------------------
+ // Check if a given Process
+ //------------------------------------------------------------------
+ virtual bool
+ CanDebug (lldb_private::Target &target,
+ bool plugin_specified_by_name);
+
+ //------------------------------------------------------------------
+ // Creating a new process, or attaching to an existing one
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ DoLoadCore ();
+
+ virtual lldb_private::DynamicLoader *
+ GetDynamicLoader ();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ //------------------------------------------------------------------
+ // Process Control
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ DoDestroy ();
+
+ virtual void
+ RefreshStateAfterStop();
+
+ //------------------------------------------------------------------
+ // Process Queries
+ //------------------------------------------------------------------
+ virtual bool
+ IsAlive ();
+
+ //------------------------------------------------------------------
+ // Process Memory
+ //------------------------------------------------------------------
+ virtual size_t
+ ReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error);
+
+ virtual size_t
+ DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error);
+
+ virtual lldb::addr_t
+ GetImageInfoAddress ();
+
+ lldb_private::ArchSpec
+ GetArchitecture();
+
+ // Returns AUXV structure found in the core file
+ const lldb::DataBufferSP
+ GetAuxvData();
+
+protected:
+ void
+ Clear ( );
+
+ virtual bool
+ UpdateThreadList (lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list);
+
+private:
+ //------------------------------------------------------------------
+ // For ProcessElfCore only
+ //------------------------------------------------------------------
+ typedef lldb_private::Range<lldb::addr_t, lldb::addr_t> FileRange;
+ typedef lldb_private::RangeDataArray<lldb::addr_t, lldb::addr_t, FileRange, 1> VMRangeToFileOffset;
+
+ lldb::ModuleSP m_core_module_sp;
+ lldb_private::FileSpec m_core_file;
+ std::string m_dyld_plugin_name;
+ DISALLOW_COPY_AND_ASSIGN (ProcessElfCore);
+
+ // True if m_thread_contexts contains valid entries
+ bool m_thread_data_valid;
+
+ // Contain thread data read from NOTE segments
+ std::vector<ThreadData> m_thread_data;
+
+ // AUXV structure found from the NOTE segment
+ lldb_private::DataExtractor m_auxv;
+
+ // Address ranges found in the core
+ VMRangeToFileOffset m_core_aranges;
+
+ // Parse thread(s) data structures(prstatus, prpsinfo) from given NOTE segment
+ void
+ ParseThreadContextsFromNoteSegment (const elf::ELFProgramHeader *segment_header,
+ lldb_private::DataExtractor segment_data);
+
+ // Returns number of thread contexts stored in the core file
+ uint32_t
+ GetNumThreadContexts();
+
+ // Parse a contiguous address range of the process from LOAD segment
+ lldb::addr_t
+ AddAddressRangeFromLoadSegment(const elf::ELFProgramHeader *header);
+};
+
+#endif // liblldb_ProcessElffCore_h_
diff --git a/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.cpp b/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.cpp
new file mode 100644
index 000000000000..6210175f9a7f
--- /dev/null
+++ b/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.cpp
@@ -0,0 +1,68 @@
+//===-- RegisterContextCoreFreeBSD_x86_64.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
+#include "RegisterContextCoreFreeBSD_x86_64.h"
+
+RegisterContextCoreFreeBSD_x86_64::RegisterContextCoreFreeBSD_x86_64(Thread &thread,
+ const DataExtractor &gpregset, const DataExtractor &fpregset)
+ : RegisterContextFreeBSD_x86_64(thread, 0)
+{
+ size_t size, len;
+
+ size = GetGPRSize();
+ m_gpregset = new uint8_t[size];
+ len = gpregset.ExtractBytes(0, size, lldb::eByteOrderLittle, m_gpregset);
+ assert(len == size);
+}
+
+RegisterContextCoreFreeBSD_x86_64::~RegisterContextCoreFreeBSD_x86_64()
+{
+ delete [] m_gpregset;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ value = *(uint64_t *)(m_gpregset + reg_info->byte_offset);
+ return true;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::UpdateAfterBreakpoint()
+{
+ return false;
+}
+
+bool
+RegisterContextCoreFreeBSD_x86_64::HardwareSingleStep(bool enable)
+{
+ return false;
+}
+
diff --git a/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.h b/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.h
new file mode 100644
index 000000000000..acd594a6e666
--- /dev/null
+++ b/source/Plugins/Process/elf-core/RegisterContextCoreFreeBSD_x86_64.h
@@ -0,0 +1,47 @@
+//===-- RegisterContextCoreFreeBSD_x86_64.h ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextCoreFreeBSD_x86_64_H_
+#define liblldb_RegisterContextCoreFreeBSD_x86_64_H_
+
+#include "Plugins/Process/POSIX/RegisterContextFreeBSD_x86_64.h"
+
+using namespace lldb_private;
+
+class RegisterContextCoreFreeBSD_x86_64: public RegisterContextFreeBSD_x86_64
+{
+public:
+ RegisterContextCoreFreeBSD_x86_64 (Thread &thread, const DataExtractor &gpregset,
+ const DataExtractor &fpregset);
+
+ ~RegisterContextCoreFreeBSD_x86_64();
+
+ virtual bool
+ ReadRegister(const RegisterInfo *reg_info, RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+ bool
+ UpdateAfterBreakpoint();
+
+private:
+ uint8_t *m_gpregset;
+};
+
+#endif // #ifndef liblldb_RegisterContextCoreFreeBSD_x86_64_H_
diff --git a/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.cpp b/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.cpp
new file mode 100644
index 000000000000..d9e3f6d5f90b
--- /dev/null
+++ b/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.cpp
@@ -0,0 +1,68 @@
+//===-- RegisterContextCoreLinux_x86_64.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Target/Thread.h"
+#include "RegisterContextCoreLinux_x86_64.h"
+
+RegisterContextCoreLinux_x86_64::RegisterContextCoreLinux_x86_64(Thread &thread,
+ const DataExtractor &gpregset,
+ const DataExtractor &fpregset)
+ : RegisterContextLinux_x86_64(thread, 0)
+{
+ size_t size, len;
+
+ size = GetGPRSize();
+ m_gpregset = new uint8_t[size];
+ len = gpregset.ExtractBytes(0, size, lldb::eByteOrderLittle, m_gpregset);
+ assert(len == size);
+}
+
+RegisterContextCoreLinux_x86_64::~RegisterContextCoreLinux_x86_64()
+{
+ delete [] m_gpregset;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::ReadRegister(const RegisterInfo *reg_info, RegisterValue &value)
+{
+ value = *(uint64_t *)(m_gpregset + reg_info->byte_offset);
+ return true;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::ReadAllRegisterValues(lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value)
+{
+ return false;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::WriteAllRegisterValues(const lldb::DataBufferSP &data_sp)
+{
+ return false;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::UpdateAfterBreakpoint()
+{
+ return false;
+}
+
+bool
+RegisterContextCoreLinux_x86_64::HardwareSingleStep(bool enable)
+{
+ return false;
+}
diff --git a/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.h b/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.h
new file mode 100644
index 000000000000..9cf545afd56a
--- /dev/null
+++ b/source/Plugins/Process/elf-core/RegisterContextCoreLinux_x86_64.h
@@ -0,0 +1,54 @@
+//===-- RegisterContextCoreLinux_x86_64.h ----------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef liblldb_RegisterContextCoreLinux_x86_64_H_
+#define liblldb_RegisterContextCoreLinux_x86_64_H_
+
+#include "Plugins/Process/POSIX/RegisterContextLinux_x86_64.h"
+
+using namespace lldb_private;
+
+class RegisterContextCoreLinux_x86_64: public RegisterContextLinux_x86_64
+{
+public:
+ RegisterContextCoreLinux_x86_64 (Thread &thread, const DataExtractor &gpregset,
+ const DataExtractor &fpregset);
+
+ ~RegisterContextCoreLinux_x86_64();
+
+ virtual bool
+ ReadRegister(const RegisterInfo *reg_info, RegisterValue &value);
+
+ bool
+ ReadAllRegisterValues(lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteRegister(const RegisterInfo *reg_info, const RegisterValue &value);
+
+ bool
+ WriteAllRegisterValues(const lldb::DataBufferSP &data_sp);
+
+ bool
+ HardwareSingleStep(bool enable);
+
+ bool
+ UpdateAfterBreakpoint();
+
+protected:
+ bool
+ ReadFPR()
+ {
+ assert(0);
+ }
+
+private:
+ uint8_t *m_gpregset;
+};
+
+#endif // #ifndef liblldb_RegisterContextCoreLinux_x86_64_H_
diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.cpp b/source/Plugins/Process/elf-core/ThreadElfCore.cpp
new file mode 100644
index 000000000000..a7229663dc89
--- /dev/null
+++ b/source/Plugins/Process/elf-core/ThreadElfCore.cpp
@@ -0,0 +1,176 @@
+//===-- ThreadElfCore.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Unwind.h"
+#include "ProcessPOSIXLog.h"
+
+#include "ThreadElfCore.h"
+#include "ProcessElfCore.h"
+#include "RegisterContextCoreFreeBSD_x86_64.h"
+#include "RegisterContextCoreLinux_x86_64.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Construct a Thread object with given data
+//----------------------------------------------------------------------
+ThreadElfCore::ThreadElfCore (Process &process, tid_t tid,
+ const ThreadData &td) :
+ Thread(process, tid),
+ m_thread_name(td.name),
+ m_thread_reg_ctx_sp (),
+ m_signo(td.signo),
+ m_gpregset_data(td.gpregset),
+ m_fpregset_data(td.fpregset)
+{
+}
+
+ThreadElfCore::~ThreadElfCore ()
+{
+ DestroyThread();
+}
+
+void
+ThreadElfCore::RefreshStateAfterStop()
+{
+ GetRegisterContext()->InvalidateIfNeeded (false);
+}
+
+void
+ThreadElfCore::ClearStackFrames ()
+{
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ unwinder->Clear();
+ Thread::ClearStackFrames();
+}
+
+RegisterContextSP
+ThreadElfCore::GetRegisterContext ()
+{
+ if (m_reg_context_sp.get() == NULL) {
+ m_reg_context_sp = CreateRegisterContextForFrame (NULL);
+ }
+ return m_reg_context_sp;
+}
+
+RegisterContextSP
+ThreadElfCore::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ RegisterContextSP reg_ctx_sp;
+ uint32_t concrete_frame_idx = 0;
+ Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex ();
+
+ if (concrete_frame_idx == 0)
+ {
+ if (m_thread_reg_ctx_sp)
+ return m_thread_reg_ctx_sp;
+
+ ProcessElfCore *process = static_cast<ProcessElfCore *>(GetProcess().get());
+ ArchSpec arch = process->GetArchitecture();
+ switch (arch.GetMachine())
+ {
+ case llvm::Triple::x86_64:
+ switch (arch.GetTriple().getOS())
+ {
+ case llvm::Triple::FreeBSD:
+ m_thread_reg_ctx_sp.reset(new RegisterContextCoreFreeBSD_x86_64 (*this, m_gpregset_data, m_fpregset_data));
+ break;
+ case llvm::Triple::Linux:
+ m_thread_reg_ctx_sp.reset(new RegisterContextCoreLinux_x86_64 (*this, m_gpregset_data, m_fpregset_data));
+ break;
+ default:
+ if (log)
+ log->Printf ("elf-core::%s:: OS(%d) not supported",
+ __FUNCTION__, arch.GetTriple().getOS());
+ assert (false && "OS not supported");
+ break;
+ }
+ break;
+ default:
+ if (log)
+ log->Printf ("elf-core::%s:: Architecture(%d) not supported",
+ __FUNCTION__, arch.GetMachine());
+ assert (false && "Architecture not supported");
+ }
+ reg_ctx_sp = m_thread_reg_ctx_sp;
+ }
+ else if (m_unwinder_ap.get())
+ {
+ reg_ctx_sp = m_unwinder_ap->CreateRegisterContextForFrame (frame);
+ }
+ return reg_ctx_sp;
+}
+
+bool
+ThreadElfCore::CalculateStopInfo ()
+{
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ SetStopInfo(StopInfo::CreateStopReasonWithSignal (*this, m_signo));
+ return true;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------
+// Parse PRSTATUS from NOTE entry
+//----------------------------------------------------------------
+ELFLinuxPrStatus::ELFLinuxPrStatus()
+{
+ memset(this, 0, sizeof(ELFLinuxPrStatus));
+}
+
+bool
+ELFLinuxPrStatus::Parse(DataExtractor &data, ArchSpec &arch)
+{
+ ByteOrder byteorder = data.GetByteOrder();
+ size_t len;
+ switch(arch.GetCore())
+ {
+ case ArchSpec::eCore_x86_64_x86_64:
+ len = data.ExtractBytes(0, ELFLINUXPRSTATUS64_SIZE, byteorder, this);
+ return len == ELFLINUXPRSTATUS64_SIZE;
+ default:
+ return false;
+ }
+}
+
+//----------------------------------------------------------------
+// Parse PRPSINFO from NOTE entry
+//----------------------------------------------------------------
+ELFLinuxPrPsInfo::ELFLinuxPrPsInfo()
+{
+ memset(this, 0, sizeof(ELFLinuxPrPsInfo));
+}
+
+bool
+ELFLinuxPrPsInfo::Parse(DataExtractor &data, ArchSpec &arch)
+{
+ ByteOrder byteorder = data.GetByteOrder();
+ size_t len;
+ switch(arch.GetCore())
+ {
+ case ArchSpec::eCore_x86_64_x86_64:
+ len = data.ExtractBytes(0, ELFLINUXPRPSINFO64_SIZE, byteorder, this);
+ return len == ELFLINUXPRPSINFO64_SIZE;
+ default:
+ return false;
+ }
+}
+
diff --git a/source/Plugins/Process/elf-core/ThreadElfCore.h b/source/Plugins/Process/elf-core/ThreadElfCore.h
new file mode 100644
index 000000000000..ca6339d7ec9d
--- /dev/null
+++ b/source/Plugins/Process/elf-core/ThreadElfCore.h
@@ -0,0 +1,174 @@
+//===-- ThreadElfCore.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ThreadElfCore_h_
+#define liblldb_ThreadElfCore_h_
+
+#include <string>
+
+#include "lldb/Target/Thread.h"
+#include "lldb/Core/DataExtractor.h"
+
+struct compat_timeval
+{
+ int64_t tv_sec;
+ int32_t tv_usec;
+};
+
+// PRSTATUS structure's size differs based on architecture.
+// Currently parsing done only for x86-64 architecture by
+// simply reading data from the buffer.
+// The following macros are used to specify the size.
+// Calculating size using sizeof() wont work because of padding.
+#define ELFLINUXPRSTATUS64_SIZE (112)
+#define ELFLINUXPRPSINFO64_SIZE (132)
+
+struct ELFLinuxPrStatus
+{
+ int32_t si_signo;
+ int32_t si_code;
+ int32_t si_errno;
+
+ int16_t pr_cursig;
+
+ uint64_t pr_sigpend;
+ uint64_t pr_sighold;
+
+ uint32_t pr_pid;
+ uint32_t pr_ppid;
+ uint32_t pr_pgrp;
+ uint32_t pr_sid;
+
+ compat_timeval pr_utime;
+ compat_timeval pr_stime;
+ compat_timeval pr_cutime;
+ compat_timeval pr_cstime;
+
+ ELFLinuxPrStatus();
+
+ bool
+ Parse(lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch);
+
+ static size_t
+ GetSize(lldb_private::ArchSpec &arch)
+ {
+ switch(arch.GetCore())
+ {
+ case lldb_private::ArchSpec::eCore_x86_64_x86_64:
+ return ELFLINUXPRSTATUS64_SIZE;
+ default:
+ return 0;
+ }
+ }
+};
+
+struct ELFLinuxPrPsInfo
+{
+ char pr_state;
+ char pr_sname;
+ char pr_zomb;
+ char pr_nice;
+ uint64_t pr_flag;
+ uint32_t pr_uid;
+ uint32_t pr_gid;
+ int32_t pr_pid;
+ int32_t pr_ppid;
+ int32_t pr_pgrp;
+ int32_t pr_sid;
+ char pr_fname[16];
+ char pr_psargs[80];
+
+ ELFLinuxPrPsInfo();
+
+ bool
+ Parse(lldb_private::DataExtractor &data, lldb_private::ArchSpec &arch);
+
+ static size_t
+ GetSize(lldb_private::ArchSpec &arch)
+ {
+ switch(arch.GetCore())
+ {
+ case lldb_private::ArchSpec::eCore_x86_64_x86_64:
+ return ELFLINUXPRPSINFO64_SIZE;
+ default:
+ return 0;
+ }
+ }
+
+};
+
+struct ThreadData
+{
+ lldb_private::DataExtractor gpregset;
+ lldb_private::DataExtractor fpregset;
+ int signo;
+ std::string name;
+};
+
+class ThreadElfCore : public lldb_private::Thread
+{
+public:
+ ThreadElfCore (lldb_private::Process &process, lldb::tid_t tid,
+ const ThreadData &td);
+
+ virtual
+ ~ThreadElfCore ();
+
+ virtual void
+ RefreshStateAfterStop();
+
+ virtual lldb::RegisterContextSP
+ GetRegisterContext ();
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ virtual void
+ ClearStackFrames ();
+
+ static bool
+ ThreadIDIsValid (lldb::tid_t thread)
+ {
+ return thread != 0;
+ }
+
+ virtual const char *
+ GetName ()
+ {
+ if (m_thread_name.empty())
+ return NULL;
+ return m_thread_name.c_str();
+ }
+
+ void
+ SetName (const char *name)
+ {
+ if (name && name[0])
+ m_thread_name.assign (name);
+ else
+ m_thread_name.clear();
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ std::string m_thread_name;
+ lldb::RegisterContextSP m_thread_reg_ctx_sp;
+
+ int m_signo;
+
+ lldb_private::DataExtractor m_gpregset_data;
+ lldb_private::DataExtractor m_fpregset_data;
+
+ virtual bool CalculateStopInfo();
+
+};
+
+#endif // liblldb_ThreadElfCore_h_
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
new file mode 100644
index 000000000000..d7efdf2302d8
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.cpp
@@ -0,0 +1,643 @@
+//===-- GDBRemoteCommunication.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "GDBRemoteCommunication.h"
+
+// C Includes
+#include <limits.h>
+#include <string.h>
+
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/Log.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Target/Process.h"
+
+// Project includes
+#include "ProcessGDBRemoteLog.h"
+
+#define DEBUGSERVER_BASENAME "debugserver"
+
+using namespace lldb;
+using namespace lldb_private;
+
+GDBRemoteCommunication::History::History (uint32_t size) :
+ m_packets(),
+ m_curr_idx (0),
+ m_total_packet_count (0),
+ m_dumped_to_log (false)
+{
+ m_packets.resize(size);
+}
+
+GDBRemoteCommunication::History::~History ()
+{
+}
+
+void
+GDBRemoteCommunication::History::AddPacket (char packet_char,
+ PacketType type,
+ uint32_t bytes_transmitted)
+{
+ const size_t size = m_packets.size();
+ if (size > 0)
+ {
+ const uint32_t idx = GetNextIndex();
+ m_packets[idx].packet.assign (1, packet_char);
+ m_packets[idx].type = type;
+ m_packets[idx].bytes_transmitted = bytes_transmitted;
+ m_packets[idx].packet_idx = m_total_packet_count;
+ m_packets[idx].tid = Host::GetCurrentThreadID();
+ }
+}
+
+void
+GDBRemoteCommunication::History::AddPacket (const std::string &src,
+ uint32_t src_len,
+ PacketType type,
+ uint32_t bytes_transmitted)
+{
+ const size_t size = m_packets.size();
+ if (size > 0)
+ {
+ const uint32_t idx = GetNextIndex();
+ m_packets[idx].packet.assign (src, 0, src_len);
+ m_packets[idx].type = type;
+ m_packets[idx].bytes_transmitted = bytes_transmitted;
+ m_packets[idx].packet_idx = m_total_packet_count;
+ m_packets[idx].tid = Host::GetCurrentThreadID();
+ }
+}
+
+void
+GDBRemoteCommunication::History::Dump (lldb_private::Stream &strm) const
+{
+ const uint32_t size = GetNumPacketsInHistory ();
+ const uint32_t first_idx = GetFirstSavedPacketIndex ();
+ const uint32_t stop_idx = m_curr_idx + size;
+ for (uint32_t i = first_idx; i < stop_idx; ++i)
+ {
+ const uint32_t idx = NormalizeIndex (i);
+ const Entry &entry = m_packets[idx];
+ if (entry.type == ePacketTypeInvalid || entry.packet.empty())
+ break;
+ strm.Printf ("history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s\n",
+ entry.packet_idx,
+ entry.tid,
+ entry.bytes_transmitted,
+ (entry.type == ePacketTypeSend) ? "send" : "read",
+ entry.packet.c_str());
+ }
+}
+
+void
+GDBRemoteCommunication::History::Dump (lldb_private::Log *log) const
+{
+ if (log && !m_dumped_to_log)
+ {
+ m_dumped_to_log = true;
+ const uint32_t size = GetNumPacketsInHistory ();
+ const uint32_t first_idx = GetFirstSavedPacketIndex ();
+ const uint32_t stop_idx = m_curr_idx + size;
+ for (uint32_t i = first_idx; i < stop_idx; ++i)
+ {
+ const uint32_t idx = NormalizeIndex (i);
+ const Entry &entry = m_packets[idx];
+ if (entry.type == ePacketTypeInvalid || entry.packet.empty())
+ break;
+ log->Printf ("history[%u] tid=0x%4.4" PRIx64 " <%4u> %s packet: %s",
+ entry.packet_idx,
+ entry.tid,
+ entry.bytes_transmitted,
+ (entry.type == ePacketTypeSend) ? "send" : "read",
+ entry.packet.c_str());
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// GDBRemoteCommunication constructor
+//----------------------------------------------------------------------
+GDBRemoteCommunication::GDBRemoteCommunication(const char *comm_name,
+ const char *listener_name,
+ bool is_platform) :
+ Communication(comm_name),
+ m_packet_timeout (1),
+ m_sequence_mutex (Mutex::eMutexTypeRecursive),
+ m_public_is_running (false),
+ m_private_is_running (false),
+ m_history (512),
+ m_send_acks (true),
+ m_is_platform (is_platform)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteCommunication::~GDBRemoteCommunication()
+{
+ if (IsConnected())
+ {
+ Disconnect();
+ }
+}
+
+char
+GDBRemoteCommunication::CalculcateChecksum (const char *payload, size_t payload_length)
+{
+ int checksum = 0;
+
+ for (size_t i = 0; i < payload_length; ++i)
+ checksum += payload[i];
+
+ return checksum & 255;
+}
+
+size_t
+GDBRemoteCommunication::SendAck ()
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
+ ConnectionStatus status = eConnectionStatusSuccess;
+ char ch = '+';
+ const size_t bytes_written = Write (&ch, 1, status, NULL);
+ if (log)
+ log->Printf ("<%4zu> send packet: %c", bytes_written, ch);
+ m_history.AddPacket (ch, History::ePacketTypeSend, bytes_written);
+ return bytes_written;
+}
+
+size_t
+GDBRemoteCommunication::SendNack ()
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
+ ConnectionStatus status = eConnectionStatusSuccess;
+ char ch = '-';
+ const size_t bytes_written = Write (&ch, 1, status, NULL);
+ if (log)
+ log->Printf ("<%4zu> send packet: %c", bytes_written, ch);
+ m_history.AddPacket (ch, History::ePacketTypeSend, bytes_written);
+ return bytes_written;
+}
+
+size_t
+GDBRemoteCommunication::SendPacket (const char *payload, size_t payload_length)
+{
+ Mutex::Locker locker(m_sequence_mutex);
+ return SendPacketNoLock (payload, payload_length);
+}
+
+size_t
+GDBRemoteCommunication::SendPacketNoLock (const char *payload, size_t payload_length)
+{
+ if (IsConnected())
+ {
+ StreamString packet(0, 4, eByteOrderBig);
+
+ packet.PutChar('$');
+ packet.Write (payload, payload_length);
+ packet.PutChar('#');
+ packet.PutHex8(CalculcateChecksum (payload, payload_length));
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
+ ConnectionStatus status = eConnectionStatusSuccess;
+ size_t bytes_written = Write (packet.GetData(), packet.GetSize(), status, NULL);
+ if (log)
+ {
+ // If logging was just enabled and we have history, then dump out what
+ // we have to the log so we get the historical context. The Dump() call that
+ // logs all of the packet will set a boolean so that we don't dump this more
+ // than once
+ if (!m_history.DidDumpToLog ())
+ m_history.Dump (log);
+
+ log->Printf ("<%4zu> send packet: %.*s", bytes_written, (int)packet.GetSize(), packet.GetData());
+ }
+
+ m_history.AddPacket (packet.GetString(), packet.GetSize(), History::ePacketTypeSend, bytes_written);
+
+
+ if (bytes_written == packet.GetSize())
+ {
+ if (GetSendAcks ())
+ {
+ if (GetAck () != '+')
+ {
+ if (log)
+ log->Printf("get ack failed...");
+ return 0;
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("error: failed to send packet: %.*s", (int)packet.GetSize(), packet.GetData());
+ }
+ return bytes_written;
+ }
+ return 0;
+}
+
+char
+GDBRemoteCommunication::GetAck ()
+{
+ StringExtractorGDBRemote packet;
+ if (WaitForPacketWithTimeoutMicroSecondsNoLock (packet, GetPacketTimeoutInMicroSeconds ()) == 1)
+ return packet.GetChar();
+ return 0;
+}
+
+bool
+GDBRemoteCommunication::GetSequenceMutex (Mutex::Locker& locker, const char *failure_message)
+{
+ if (IsRunning())
+ return locker.TryLock (m_sequence_mutex, failure_message);
+
+ locker.Lock (m_sequence_mutex);
+ return true;
+}
+
+
+bool
+GDBRemoteCommunication::WaitForNotRunningPrivate (const TimeValue *timeout_ptr)
+{
+ return m_private_is_running.WaitForValueEqualTo (false, timeout_ptr, NULL);
+}
+
+size_t
+GDBRemoteCommunication::WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &packet, uint32_t timeout_usec)
+{
+ uint8_t buffer[8192];
+ Error error;
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS | GDBR_LOG_VERBOSE));
+
+ // Check for a packet from our cache first without trying any reading...
+ if (CheckForPacket (NULL, 0, packet))
+ return packet.GetStringRef().size();
+
+ bool timed_out = false;
+ while (IsConnected() && !timed_out)
+ {
+ lldb::ConnectionStatus status = eConnectionStatusNoConnection;
+ size_t bytes_read = Read (buffer, sizeof(buffer), timeout_usec, status, &error);
+
+ if (log)
+ log->Printf ("%s: Read (buffer, (sizeof(buffer), timeout_usec = 0x%x, status = %s, error = %s) => bytes_read = %" PRIu64,
+ __PRETTY_FUNCTION__,
+ timeout_usec,
+ Communication::ConnectionStatusAsCString (status),
+ error.AsCString(),
+ (uint64_t)bytes_read);
+
+ if (bytes_read > 0)
+ {
+ if (CheckForPacket (buffer, bytes_read, packet))
+ return packet.GetStringRef().size();
+ }
+ else
+ {
+ switch (status)
+ {
+ case eConnectionStatusTimedOut:
+ timed_out = true;
+ break;
+ case eConnectionStatusSuccess:
+ //printf ("status = success but error = %s\n", error.AsCString("<invalid>"));
+ break;
+
+ case eConnectionStatusEndOfFile:
+ case eConnectionStatusNoConnection:
+ case eConnectionStatusLostConnection:
+ case eConnectionStatusError:
+ Disconnect();
+ break;
+ }
+ }
+ }
+ packet.Clear ();
+ return 0;
+}
+
+bool
+GDBRemoteCommunication::CheckForPacket (const uint8_t *src, size_t src_len, StringExtractorGDBRemote &packet)
+{
+ // Put the packet data into the buffer in a thread safe fashion
+ Mutex::Locker locker(m_bytes_mutex);
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
+
+ if (src && src_len > 0)
+ {
+ if (log && log->GetVerbose())
+ {
+ StreamString s;
+ log->Printf ("GDBRemoteCommunication::%s adding %u bytes: %.*s",
+ __FUNCTION__,
+ (uint32_t)src_len,
+ (uint32_t)src_len,
+ src);
+ }
+ m_bytes.append ((const char *)src, src_len);
+ }
+
+ // Parse up the packets into gdb remote packets
+ if (!m_bytes.empty())
+ {
+ // end_idx must be one past the last valid packet byte. Start
+ // it off with an invalid value that is the same as the current
+ // index.
+ size_t content_start = 0;
+ size_t content_length = 0;
+ size_t total_length = 0;
+ size_t checksum_idx = std::string::npos;
+
+ switch (m_bytes[0])
+ {
+ case '+': // Look for ack
+ case '-': // Look for cancel
+ case '\x03': // ^C to halt target
+ content_length = total_length = 1; // The command is one byte long...
+ break;
+
+ case '$':
+ // Look for a standard gdb packet?
+ {
+ size_t hash_pos = m_bytes.find('#');
+ if (hash_pos != std::string::npos)
+ {
+ if (hash_pos + 2 < m_bytes.size())
+ {
+ checksum_idx = hash_pos + 1;
+ // Skip the dollar sign
+ content_start = 1;
+ // Don't include the # in the content or the $ in the content length
+ content_length = hash_pos - 1;
+
+ total_length = hash_pos + 3; // Skip the # and the two hex checksum bytes
+ }
+ else
+ {
+ // Checksum bytes aren't all here yet
+ content_length = std::string::npos;
+ }
+ }
+ }
+ break;
+
+ default:
+ {
+ // We have an unexpected byte and we need to flush all bad
+ // data that is in m_bytes, so we need to find the first
+ // byte that is a '+' (ACK), '-' (NACK), \x03 (CTRL+C interrupt),
+ // or '$' character (start of packet header) or of course,
+ // the end of the data in m_bytes...
+ const size_t bytes_len = m_bytes.size();
+ bool done = false;
+ uint32_t idx;
+ for (idx = 1; !done && idx < bytes_len; ++idx)
+ {
+ switch (m_bytes[idx])
+ {
+ case '+':
+ case '-':
+ case '\x03':
+ case '$':
+ done = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (log)
+ log->Printf ("GDBRemoteCommunication::%s tossing %u junk bytes: '%.*s'",
+ __FUNCTION__, idx, idx, m_bytes.c_str());
+ m_bytes.erase(0, idx);
+ }
+ break;
+ }
+
+ if (content_length == std::string::npos)
+ {
+ packet.Clear();
+ return false;
+ }
+ else if (total_length > 0)
+ {
+
+ // We have a valid packet...
+ assert (content_length <= m_bytes.size());
+ assert (total_length <= m_bytes.size());
+ assert (content_length <= total_length);
+
+ bool success = true;
+ std::string &packet_str = packet.GetStringRef();
+
+
+ if (log)
+ {
+ // If logging was just enabled and we have history, then dump out what
+ // we have to the log so we get the historical context. The Dump() call that
+ // logs all of the packet will set a boolean so that we don't dump this more
+ // than once
+ if (!m_history.DidDumpToLog ())
+ m_history.Dump (log);
+
+ log->Printf ("<%4zu> read packet: %.*s", total_length, (int)(total_length), m_bytes.c_str());
+ }
+
+ m_history.AddPacket (m_bytes.c_str(), total_length, History::ePacketTypeRecv, total_length);
+
+ packet_str.assign (m_bytes, content_start, content_length);
+
+ if (m_bytes[0] == '$')
+ {
+ assert (checksum_idx < m_bytes.size());
+ if (::isxdigit (m_bytes[checksum_idx+0]) ||
+ ::isxdigit (m_bytes[checksum_idx+1]))
+ {
+ if (GetSendAcks ())
+ {
+ const char *packet_checksum_cstr = &m_bytes[checksum_idx];
+ char packet_checksum = strtol (packet_checksum_cstr, NULL, 16);
+ char actual_checksum = CalculcateChecksum (packet_str.c_str(), packet_str.size());
+ success = packet_checksum == actual_checksum;
+ if (!success)
+ {
+ if (log)
+ log->Printf ("error: checksum mismatch: %.*s expected 0x%2.2x, got 0x%2.2x",
+ (int)(total_length),
+ m_bytes.c_str(),
+ (uint8_t)packet_checksum,
+ (uint8_t)actual_checksum);
+ }
+ // Send the ack or nack if needed
+ if (!success)
+ SendNack();
+ else
+ SendAck();
+ }
+ }
+ else
+ {
+ success = false;
+ if (log)
+ log->Printf ("error: invalid checksum in packet: '%s'\n", m_bytes.c_str());
+ }
+ }
+
+ m_bytes.erase(0, total_length);
+ packet.SetFilePos(0);
+ return success;
+ }
+ }
+ packet.Clear();
+ return false;
+}
+
+Error
+GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url,
+ const char *unix_socket_name, // For handshaking
+ lldb_private::ProcessLaunchInfo &launch_info)
+{
+ Error error;
+ // If we locate debugserver, keep that located version around
+ static FileSpec g_debugserver_file_spec;
+
+ // This function will fill in the launch information for the debugserver
+ // instance that gets launched.
+ launch_info.Clear();
+
+ char debugserver_path[PATH_MAX];
+ FileSpec &debugserver_file_spec = launch_info.GetExecutableFile();
+
+ // Always check to see if we have an environment override for the path
+ // to the debugserver to use and use it if we do.
+ const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH");
+ if (env_debugserver_path)
+ debugserver_file_spec.SetFile (env_debugserver_path, false);
+ else
+ debugserver_file_spec = g_debugserver_file_spec;
+ bool debugserver_exists = debugserver_file_spec.Exists();
+ if (!debugserver_exists)
+ {
+ // The debugserver binary is in the LLDB.framework/Resources
+ // directory.
+ if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec))
+ {
+ debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME);
+ debugserver_exists = debugserver_file_spec.Exists();
+ if (debugserver_exists)
+ {
+ g_debugserver_file_spec = debugserver_file_spec;
+ }
+ else
+ {
+ g_debugserver_file_spec.Clear();
+ debugserver_file_spec.Clear();
+ }
+ }
+ }
+
+ if (debugserver_exists)
+ {
+ debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path));
+
+ Args &debugserver_args = launch_info.GetArguments();
+ debugserver_args.Clear();
+ char arg_cstr[PATH_MAX];
+
+ // Start args with "debugserver /file/path -r --"
+ debugserver_args.AppendArgument(debugserver_path);
+ debugserver_args.AppendArgument(debugserver_url);
+ // use native registers, not the GDB registers
+ debugserver_args.AppendArgument("--native-regs");
+ // make debugserver run in its own session so signals generated by
+ // special terminal key sequences (^C) don't affect debugserver
+ debugserver_args.AppendArgument("--setsid");
+
+ if (unix_socket_name && unix_socket_name[0])
+ {
+ debugserver_args.AppendArgument("--unix-socket");
+ debugserver_args.AppendArgument(unix_socket_name);
+ }
+
+ const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE");
+ if (env_debugserver_log_file)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file);
+ debugserver_args.AppendArgument(arg_cstr);
+ }
+
+ const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS");
+ if (env_debugserver_log_flags)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags);
+ debugserver_args.AppendArgument(arg_cstr);
+ }
+ // debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt");
+ // debugserver_args.AppendArgument("--log-flags=0x802e0e");
+
+ // We currently send down all arguments, attach pids, or attach
+ // process names in dedicated GDB server packets, so we don't need
+ // to pass them as arguments. This is currently because of all the
+ // things we need to setup prior to launching: the environment,
+ // current working dir, file actions, etc.
+#if 0
+ // Now append the program arguments
+ if (inferior_argv)
+ {
+ // Terminate the debugserver args so we can now append the inferior args
+ debugserver_args.AppendArgument("--");
+
+ for (int i = 0; inferior_argv[i] != NULL; ++i)
+ debugserver_args.AppendArgument (inferior_argv[i]);
+ }
+ else if (attach_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid);
+ debugserver_args.AppendArgument (arg_cstr);
+ }
+ else if (attach_name && attach_name[0])
+ {
+ if (wait_for_launch)
+ debugserver_args.AppendArgument ("--waitfor");
+ else
+ debugserver_args.AppendArgument ("--attach");
+ debugserver_args.AppendArgument (attach_name);
+ }
+#endif
+
+ // Close STDIN, STDOUT and STDERR. We might need to redirect them
+ // to "/dev/null" if we run into any problems.
+// launch_info.AppendCloseFileAction (STDIN_FILENO);
+// launch_info.AppendCloseFileAction (STDOUT_FILENO);
+// launch_info.AppendCloseFileAction (STDERR_FILENO);
+
+ error = Host::LaunchProcess(launch_info);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME );
+ }
+ return error;
+}
+
+void
+GDBRemoteCommunication::DumpHistory(Stream &strm)
+{
+ m_history.Dump (strm);
+}
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
new file mode 100644
index 000000000000..a1077957c6a6
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunication.h
@@ -0,0 +1,268 @@
+//===-- GDBRemoteCommunication.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_GDBRemoteCommunication_h_
+#define liblldb_GDBRemoteCommunication_h_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <string>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-public.h"
+#include "lldb/Core/Communication.h"
+#include "lldb/Core/Listener.h"
+#include "lldb/Host/Mutex.h"
+#include "lldb/Host/Predicate.h"
+#include "lldb/Host/TimeValue.h"
+
+#include "Utility/StringExtractorGDBRemote.h"
+
+class ProcessGDBRemote;
+
+class GDBRemoteCommunication : public lldb_private::Communication
+{
+public:
+ enum
+ {
+ eBroadcastBitRunPacketSent = kLoUserBroadcastBit
+ };
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ GDBRemoteCommunication(const char *comm_name,
+ const char *listener_name,
+ bool is_platform);
+
+ virtual
+ ~GDBRemoteCommunication();
+
+ char
+ GetAck ();
+
+ size_t
+ SendAck ();
+
+ size_t
+ SendNack ();
+
+ char
+ CalculcateChecksum (const char *payload,
+ size_t payload_length);
+
+ bool
+ GetSequenceMutex (lldb_private::Mutex::Locker& locker, const char *failure_message = NULL);
+
+ bool
+ CheckForPacket (const uint8_t *src,
+ size_t src_len,
+ StringExtractorGDBRemote &packet);
+ bool
+ IsRunning() const
+ {
+ return m_public_is_running.GetValue();
+ }
+
+ bool
+ GetSendAcks ()
+ {
+ return m_send_acks;
+ }
+
+ //------------------------------------------------------------------
+ // Client and server must implement these pure virtual functions
+ //------------------------------------------------------------------
+ virtual bool
+ GetThreadSuffixSupported () = 0;
+
+ //------------------------------------------------------------------
+ // Set the global packet timeout.
+ //
+ // For clients, this is the timeout that gets used when sending
+ // packets and waiting for responses. For servers, this might not
+ // get used, and if it doesn't this should be moved to the
+ // GDBRemoteCommunicationClient.
+ //------------------------------------------------------------------
+ uint32_t
+ SetPacketTimeout (uint32_t packet_timeout)
+ {
+ const uint32_t old_packet_timeout = m_packet_timeout;
+ m_packet_timeout = packet_timeout;
+ return old_packet_timeout;
+ }
+
+ uint32_t
+ GetPacketTimeoutInMicroSeconds () const
+ {
+ return m_packet_timeout * lldb_private::TimeValue::MicroSecPerSec;
+ }
+ //------------------------------------------------------------------
+ // Start a debugserver instance on the current host using the
+ // supplied connection URL.
+ //------------------------------------------------------------------
+ lldb_private::Error
+ StartDebugserverProcess (const char *connect_url,
+ const char *unix_socket_name,
+ lldb_private::ProcessLaunchInfo &launch_info);
+
+ void
+ DumpHistory(lldb_private::Stream &strm);
+
+protected:
+
+ class History
+ {
+ public:
+ enum PacketType
+ {
+ ePacketTypeInvalid = 0,
+ ePacketTypeSend,
+ ePacketTypeRecv
+ };
+
+ struct Entry
+ {
+ Entry() :
+ packet(),
+ type (ePacketTypeInvalid),
+ bytes_transmitted (0),
+ packet_idx (0),
+ tid (LLDB_INVALID_THREAD_ID)
+ {
+ }
+
+ void
+ Clear ()
+ {
+ packet.clear();
+ type = ePacketTypeInvalid;
+ bytes_transmitted = 0;
+ packet_idx = 0;
+ tid = LLDB_INVALID_THREAD_ID;
+ }
+ std::string packet;
+ PacketType type;
+ uint32_t bytes_transmitted;
+ uint32_t packet_idx;
+ lldb::tid_t tid;
+ };
+
+ History (uint32_t size);
+
+ ~History ();
+
+ // For single char packets for ack, nack and /x03
+ void
+ AddPacket (char packet_char,
+ PacketType type,
+ uint32_t bytes_transmitted);
+ void
+ AddPacket (const std::string &src,
+ uint32_t src_len,
+ PacketType type,
+ uint32_t bytes_transmitted);
+
+ void
+ Dump (lldb_private::Stream &strm) const;
+
+ void
+ Dump (lldb_private::Log *log) const;
+
+ bool
+ DidDumpToLog () const
+ {
+ return m_dumped_to_log;
+ }
+
+protected:
+ uint32_t
+ GetFirstSavedPacketIndex () const
+ {
+ if (m_total_packet_count < m_packets.size())
+ return 0;
+ else
+ return m_curr_idx + 1;
+ }
+
+ uint32_t
+ GetNumPacketsInHistory () const
+ {
+ if (m_total_packet_count < m_packets.size())
+ return m_total_packet_count;
+ else
+ return (uint32_t)m_packets.size();
+ }
+
+ uint32_t
+ GetNextIndex()
+ {
+ ++m_total_packet_count;
+ const uint32_t idx = m_curr_idx;
+ m_curr_idx = NormalizeIndex(idx + 1);
+ return idx;
+ }
+
+ uint32_t
+ NormalizeIndex (uint32_t i) const
+ {
+ return i % m_packets.size();
+ }
+
+
+ std::vector<Entry> m_packets;
+ uint32_t m_curr_idx;
+ uint32_t m_total_packet_count;
+ mutable bool m_dumped_to_log;
+ };
+
+ size_t
+ SendPacket (const char *payload,
+ size_t payload_length);
+
+ size_t
+ SendPacketNoLock (const char *payload,
+ size_t payload_length);
+
+ size_t
+ WaitForPacketWithTimeoutMicroSecondsNoLock (StringExtractorGDBRemote &response,
+ uint32_t timeout_usec);
+
+ bool
+ WaitForNotRunningPrivate (const lldb_private::TimeValue *timeout_ptr);
+
+ //------------------------------------------------------------------
+ // Classes that inherit from GDBRemoteCommunication can see and modify these
+ //------------------------------------------------------------------
+ uint32_t m_packet_timeout;
+#ifdef LLDB_CONFIGURATION_DEBUG
+ lldb_private::TrackingMutex m_sequence_mutex;
+#else
+ lldb_private::Mutex m_sequence_mutex; // Restrict access to sending/receiving packets to a single thread at a time
+#endif
+ lldb_private::Predicate<bool> m_public_is_running;
+ lldb_private::Predicate<bool> m_private_is_running;
+ History m_history;
+ bool m_send_acks;
+ bool m_is_platform; // Set to true if this class represents a platform,
+ // false if this class represents a debug session for
+ // a single process
+
+
+
+
+private:
+ //------------------------------------------------------------------
+ // For GDBRemoteCommunication only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunication);
+};
+
+#endif // liblldb_GDBRemoteCommunication_h_
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
new file mode 100644
index 000000000000..ca594a8f3fd5
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -0,0 +1,2348 @@
+//===-- GDBRemoteCommunicationClient.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "GDBRemoteCommunicationClient.h"
+
+// C Includes
+// C++ Includes
+#include <sstream>
+
+// Other libraries and framework includes
+#include "llvm/ADT/Triple.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/TimeValue.h"
+
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// GDBRemoteCommunicationClient constructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationClient::GDBRemoteCommunicationClient(bool is_platform) :
+ GDBRemoteCommunication("gdb-remote.client", "gdb-remote.client.rx_packet", is_platform),
+ m_supports_not_sending_acks (eLazyBoolCalculate),
+ m_supports_thread_suffix (eLazyBoolCalculate),
+ m_supports_threads_in_stop_reply (eLazyBoolCalculate),
+ m_supports_vCont_all (eLazyBoolCalculate),
+ m_supports_vCont_any (eLazyBoolCalculate),
+ m_supports_vCont_c (eLazyBoolCalculate),
+ m_supports_vCont_C (eLazyBoolCalculate),
+ m_supports_vCont_s (eLazyBoolCalculate),
+ m_supports_vCont_S (eLazyBoolCalculate),
+ m_qHostInfo_is_valid (eLazyBoolCalculate),
+ m_qProcessInfo_is_valid (eLazyBoolCalculate),
+ m_supports_alloc_dealloc_memory (eLazyBoolCalculate),
+ m_supports_memory_region_info (eLazyBoolCalculate),
+ m_supports_watchpoint_support_info (eLazyBoolCalculate),
+ m_supports_detach_stay_stopped (eLazyBoolCalculate),
+ m_watchpoints_trigger_after_instruction(eLazyBoolCalculate),
+ m_attach_or_wait_reply(eLazyBoolCalculate),
+ m_prepare_for_reg_writing_reply (eLazyBoolCalculate),
+ m_supports_qProcessInfoPID (true),
+ m_supports_qfProcessInfo (true),
+ m_supports_qUserName (true),
+ m_supports_qGroupName (true),
+ m_supports_qThreadStopInfo (true),
+ m_supports_z0 (true),
+ m_supports_z1 (true),
+ m_supports_z2 (true),
+ m_supports_z3 (true),
+ m_supports_z4 (true),
+ m_curr_tid (LLDB_INVALID_THREAD_ID),
+ m_curr_tid_run (LLDB_INVALID_THREAD_ID),
+ m_num_supported_hardware_watchpoints (0),
+ m_async_mutex (Mutex::eMutexTypeRecursive),
+ m_async_packet_predicate (false),
+ m_async_packet (),
+ m_async_response (),
+ m_async_signal (-1),
+ m_thread_id_to_used_usec_map (),
+ m_host_arch(),
+ m_process_arch(),
+ m_os_version_major (UINT32_MAX),
+ m_os_version_minor (UINT32_MAX),
+ m_os_version_update (UINT32_MAX)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationClient::~GDBRemoteCommunicationClient()
+{
+ if (IsConnected())
+ Disconnect();
+}
+
+bool
+GDBRemoteCommunicationClient::HandshakeWithServer (Error *error_ptr)
+{
+ // Start the read thread after we send the handshake ack since if we
+ // fail to send the handshake ack, there is no reason to continue...
+ if (SendAck())
+ return true;
+
+ if (error_ptr)
+ error_ptr->SetErrorString("failed to send the handshake ack");
+ return false;
+}
+
+void
+GDBRemoteCommunicationClient::QueryNoAckModeSupported ()
+{
+ if (m_supports_not_sending_acks == eLazyBoolCalculate)
+ {
+ m_send_acks = true;
+ m_supports_not_sending_acks = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("QStartNoAckMode", response, false))
+ {
+ if (response.IsOKResponse())
+ {
+ m_send_acks = false;
+ m_supports_not_sending_acks = eLazyBoolYes;
+ }
+ }
+ }
+}
+
+void
+GDBRemoteCommunicationClient::GetListThreadsInStopReplySupported ()
+{
+ if (m_supports_threads_in_stop_reply == eLazyBoolCalculate)
+ {
+ m_supports_threads_in_stop_reply = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("QListThreadsInStopReply", response, false))
+ {
+ if (response.IsOKResponse())
+ m_supports_threads_in_stop_reply = eLazyBoolYes;
+ }
+ }
+}
+
+bool
+GDBRemoteCommunicationClient::GetVAttachOrWaitSupported ()
+{
+ if (m_attach_or_wait_reply == eLazyBoolCalculate)
+ {
+ m_attach_or_wait_reply = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qVAttachOrWaitSupported", response, false))
+ {
+ if (response.IsOKResponse())
+ m_attach_or_wait_reply = eLazyBoolYes;
+ }
+ }
+ if (m_attach_or_wait_reply == eLazyBoolYes)
+ return true;
+ else
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetSyncThreadStateSupported ()
+{
+ if (m_prepare_for_reg_writing_reply == eLazyBoolCalculate)
+ {
+ m_prepare_for_reg_writing_reply = eLazyBoolNo;
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qSyncThreadStateSupported", response, false))
+ {
+ if (response.IsOKResponse())
+ m_prepare_for_reg_writing_reply = eLazyBoolYes;
+ }
+ }
+ if (m_prepare_for_reg_writing_reply == eLazyBoolYes)
+ return true;
+ else
+ return false;
+}
+
+
+void
+GDBRemoteCommunicationClient::ResetDiscoverableSettings()
+{
+ m_supports_not_sending_acks = eLazyBoolCalculate;
+ m_supports_thread_suffix = eLazyBoolCalculate;
+ m_supports_threads_in_stop_reply = eLazyBoolCalculate;
+ m_supports_vCont_c = eLazyBoolCalculate;
+ m_supports_vCont_C = eLazyBoolCalculate;
+ m_supports_vCont_s = eLazyBoolCalculate;
+ m_supports_vCont_S = eLazyBoolCalculate;
+ m_qHostInfo_is_valid = eLazyBoolCalculate;
+ m_qProcessInfo_is_valid = eLazyBoolCalculate;
+ m_supports_alloc_dealloc_memory = eLazyBoolCalculate;
+ m_supports_memory_region_info = eLazyBoolCalculate;
+ m_prepare_for_reg_writing_reply = eLazyBoolCalculate;
+ m_attach_or_wait_reply = eLazyBoolCalculate;
+
+ m_supports_qProcessInfoPID = true;
+ m_supports_qfProcessInfo = true;
+ m_supports_qUserName = true;
+ m_supports_qGroupName = true;
+ m_supports_qThreadStopInfo = true;
+ m_supports_z0 = true;
+ m_supports_z1 = true;
+ m_supports_z2 = true;
+ m_supports_z3 = true;
+ m_supports_z4 = true;
+ m_host_arch.Clear();
+ m_process_arch.Clear();
+}
+
+
+bool
+GDBRemoteCommunicationClient::GetThreadSuffixSupported ()
+{
+ if (m_supports_thread_suffix == eLazyBoolCalculate)
+ {
+ StringExtractorGDBRemote response;
+ m_supports_thread_suffix = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("QThreadSuffixSupported", response, false))
+ {
+ if (response.IsOKResponse())
+ m_supports_thread_suffix = eLazyBoolYes;
+ }
+ }
+ return m_supports_thread_suffix;
+}
+bool
+GDBRemoteCommunicationClient::GetVContSupported (char flavor)
+{
+ if (m_supports_vCont_c == eLazyBoolCalculate)
+ {
+ StringExtractorGDBRemote response;
+ m_supports_vCont_any = eLazyBoolNo;
+ m_supports_vCont_all = eLazyBoolNo;
+ m_supports_vCont_c = eLazyBoolNo;
+ m_supports_vCont_C = eLazyBoolNo;
+ m_supports_vCont_s = eLazyBoolNo;
+ m_supports_vCont_S = eLazyBoolNo;
+ if (SendPacketAndWaitForResponse("vCont?", response, false))
+ {
+ const char *response_cstr = response.GetStringRef().c_str();
+ if (::strstr (response_cstr, ";c"))
+ m_supports_vCont_c = eLazyBoolYes;
+
+ if (::strstr (response_cstr, ";C"))
+ m_supports_vCont_C = eLazyBoolYes;
+
+ if (::strstr (response_cstr, ";s"))
+ m_supports_vCont_s = eLazyBoolYes;
+
+ if (::strstr (response_cstr, ";S"))
+ m_supports_vCont_S = eLazyBoolYes;
+
+ if (m_supports_vCont_c == eLazyBoolYes &&
+ m_supports_vCont_C == eLazyBoolYes &&
+ m_supports_vCont_s == eLazyBoolYes &&
+ m_supports_vCont_S == eLazyBoolYes)
+ {
+ m_supports_vCont_all = eLazyBoolYes;
+ }
+
+ if (m_supports_vCont_c == eLazyBoolYes ||
+ m_supports_vCont_C == eLazyBoolYes ||
+ m_supports_vCont_s == eLazyBoolYes ||
+ m_supports_vCont_S == eLazyBoolYes)
+ {
+ m_supports_vCont_any = eLazyBoolYes;
+ }
+ }
+ }
+
+ switch (flavor)
+ {
+ case 'a': return m_supports_vCont_any;
+ case 'A': return m_supports_vCont_all;
+ case 'c': return m_supports_vCont_c;
+ case 'C': return m_supports_vCont_C;
+ case 's': return m_supports_vCont_s;
+ case 'S': return m_supports_vCont_S;
+ default: break;
+ }
+ return false;
+}
+
+
+size_t
+GDBRemoteCommunicationClient::SendPacketAndWaitForResponse
+(
+ const char *payload,
+ StringExtractorGDBRemote &response,
+ bool send_async
+)
+{
+ return SendPacketAndWaitForResponse (payload,
+ ::strlen (payload),
+ response,
+ send_async);
+}
+
+size_t
+GDBRemoteCommunicationClient::SendPacketAndWaitForResponse
+(
+ const char *payload,
+ size_t payload_length,
+ StringExtractorGDBRemote &response,
+ bool send_async
+)
+{
+ Mutex::Locker locker;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ size_t response_len = 0;
+ if (GetSequenceMutex (locker))
+ {
+ if (SendPacketNoLock (payload, payload_length))
+ response_len = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ());
+ else
+ {
+ if (log)
+ log->Printf("error: failed to send '%*s'", (int) payload_length, payload);
+ }
+ }
+ else
+ {
+ if (send_async)
+ {
+ if (IsRunning())
+ {
+ Mutex::Locker async_locker (m_async_mutex);
+ m_async_packet.assign(payload, payload_length);
+ m_async_packet_predicate.SetValue (true, eBroadcastNever);
+
+ if (log)
+ log->Printf ("async: async packet = %s", m_async_packet.c_str());
+
+ bool timed_out = false;
+ if (SendInterrupt(locker, 2, timed_out))
+ {
+ if (m_interrupt_sent)
+ {
+ m_interrupt_sent = false;
+ TimeValue timeout_time;
+ timeout_time = TimeValue::Now();
+ timeout_time.OffsetWithSeconds (m_packet_timeout);
+
+ if (log)
+ log->Printf ("async: sent interrupt");
+
+ if (m_async_packet_predicate.WaitForValueEqualTo (false, &timeout_time, &timed_out))
+ {
+ if (log)
+ log->Printf ("async: got response");
+
+ // Swap the response buffer to avoid malloc and string copy
+ response.GetStringRef().swap (m_async_response.GetStringRef());
+ response_len = response.GetStringRef().size();
+ }
+ else
+ {
+ if (log)
+ log->Printf ("async: timed out waiting for response");
+ }
+
+ // Make sure we wait until the continue packet has been sent again...
+ if (m_private_is_running.WaitForValueEqualTo (true, &timeout_time, &timed_out))
+ {
+ if (log)
+ {
+ if (timed_out)
+ log->Printf ("async: timed out waiting for process to resume, but process was resumed");
+ else
+ log->Printf ("async: async packet sent");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("async: timed out waiting for process to resume");
+ }
+ }
+ else
+ {
+ // We had a racy condition where we went to send the interrupt
+ // yet we were able to get the lock, so the process must have
+ // just stopped?
+ if (log)
+ log->Printf ("async: got lock without sending interrupt");
+ // Send the packet normally since we got the lock
+ if (SendPacketNoLock (payload, payload_length))
+ response_len = WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ());
+ else
+ {
+ if (log)
+ log->Printf("error: failed to send '%*s'", (int) payload_length, payload);
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("async: failed to interrupt");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("async: not running, async is ignored");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("error: failed to get packet sequence mutex, not sending packet '%*s'", (int) payload_length, payload);
+ }
+ }
+ if (response_len == 0)
+ {
+ if (log)
+ log->Printf("error: failed to get response for '%*s'", (int) payload_length, payload);
+ }
+ return response_len;
+}
+
+static const char *end_delimiter = "--end--;";
+static const int end_delimiter_len = 8;
+
+std::string
+GDBRemoteCommunicationClient::HarmonizeThreadIdsForProfileData
+( ProcessGDBRemote *process,
+ StringExtractorGDBRemote& profileDataExtractor
+)
+{
+ std::map<uint64_t, uint32_t> new_thread_id_to_used_usec_map;
+ std::stringstream final_output;
+ std::string name, value;
+
+ // Going to assuming thread_used_usec comes first, else bail out.
+ while (profileDataExtractor.GetNameColonValue(name, value))
+ {
+ if (name.compare("thread_used_id") == 0)
+ {
+ StringExtractor threadIDHexExtractor(value.c_str());
+ uint64_t thread_id = threadIDHexExtractor.GetHexMaxU64(false, 0);
+
+ bool has_used_usec = false;
+ uint32_t curr_used_usec = 0;
+ std::string usec_name, usec_value;
+ uint32_t input_file_pos = profileDataExtractor.GetFilePos();
+ if (profileDataExtractor.GetNameColonValue(usec_name, usec_value))
+ {
+ if (usec_name.compare("thread_used_usec") == 0)
+ {
+ has_used_usec = true;
+ curr_used_usec = strtoull(usec_value.c_str(), NULL, 0);
+ }
+ else
+ {
+ // We didn't find what we want, it is probably
+ // an older version. Bail out.
+ profileDataExtractor.SetFilePos(input_file_pos);
+ }
+ }
+
+ if (has_used_usec)
+ {
+ uint32_t prev_used_usec = 0;
+ std::map<uint64_t, uint32_t>::iterator iterator = m_thread_id_to_used_usec_map.find(thread_id);
+ if (iterator != m_thread_id_to_used_usec_map.end())
+ {
+ prev_used_usec = m_thread_id_to_used_usec_map[thread_id];
+ }
+
+ uint32_t real_used_usec = curr_used_usec - prev_used_usec;
+ // A good first time record is one that runs for at least 0.25 sec
+ bool good_first_time = (prev_used_usec == 0) && (real_used_usec > 250000);
+ bool good_subsequent_time = (prev_used_usec > 0) &&
+ ((real_used_usec > 0) || (process->HasAssignedIndexIDToThread(thread_id)));
+
+ if (good_first_time || good_subsequent_time)
+ {
+ // We try to avoid doing too many index id reservation,
+ // resulting in fast increase of index ids.
+
+ final_output << name << ":";
+ int32_t index_id = process->AssignIndexIDToThread(thread_id);
+ final_output << index_id << ";";
+
+ final_output << usec_name << ":" << usec_value << ";";
+ }
+ else
+ {
+ // Skip past 'thread_used_name'.
+ std::string local_name, local_value;
+ profileDataExtractor.GetNameColonValue(local_name, local_value);
+ }
+
+ // Store current time as previous time so that they can be compared later.
+ new_thread_id_to_used_usec_map[thread_id] = curr_used_usec;
+ }
+ else
+ {
+ // Bail out and use old string.
+ final_output << name << ":" << value << ";";
+ }
+ }
+ else
+ {
+ final_output << name << ":" << value << ";";
+ }
+ }
+ final_output << end_delimiter;
+ m_thread_id_to_used_usec_map = new_thread_id_to_used_usec_map;
+
+ return final_output.str();
+}
+
+StateType
+GDBRemoteCommunicationClient::SendContinuePacketAndWaitForResponse
+(
+ ProcessGDBRemote *process,
+ const char *payload,
+ size_t packet_length,
+ StringExtractorGDBRemote &response
+)
+{
+ m_curr_tid = LLDB_INVALID_THREAD_ID;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s ()", __FUNCTION__);
+
+ Mutex::Locker locker(m_sequence_mutex);
+ StateType state = eStateRunning;
+
+ BroadcastEvent(eBroadcastBitRunPacketSent, NULL);
+ m_public_is_running.SetValue (true, eBroadcastNever);
+ // Set the starting continue packet into "continue_packet". This packet
+ // may change if we are interrupted and we continue after an async packet...
+ std::string continue_packet(payload, packet_length);
+
+ bool got_async_packet = false;
+
+ while (state == eStateRunning)
+ {
+ if (!got_async_packet)
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () sending continue packet: %s", __FUNCTION__, continue_packet.c_str());
+ if (SendPacketNoLock(continue_packet.c_str(), continue_packet.size()) == 0)
+ state = eStateInvalid;
+
+ m_private_is_running.SetValue (true, eBroadcastAlways);
+ }
+
+ got_async_packet = false;
+
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(%s)", __FUNCTION__, continue_packet.c_str());
+
+ if (WaitForPacketWithTimeoutMicroSecondsNoLock(response, UINT32_MAX))
+ {
+ if (response.Empty())
+ state = eStateInvalid;
+ else
+ {
+ const char stop_type = response.GetChar();
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () got packet: %s", __FUNCTION__, response.GetStringRef().c_str());
+ switch (stop_type)
+ {
+ case 'T':
+ case 'S':
+ {
+ if (process->GetStopID() == 0)
+ {
+ if (process->GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ lldb::pid_t pid = GetCurrentProcessID ();
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ process->SetID (pid);
+ }
+ process->BuildDynamicRegisterInfo (true);
+ }
+
+ // Privately notify any internal threads that we have stopped
+ // in case we wanted to interrupt our process, yet we might
+ // send a packet and continue without returning control to the
+ // user.
+ m_private_is_running.SetValue (false, eBroadcastAlways);
+
+ const uint8_t signo = response.GetHexU8 (UINT8_MAX);
+
+ bool continue_after_async = m_async_signal != -1 || m_async_packet_predicate.GetValue();
+ if (continue_after_async || m_interrupt_sent)
+ {
+ // We sent an interrupt packet to stop the inferior process
+ // for an async signal or to send an async packet while running
+ // but we might have been single stepping and received the
+ // stop packet for the step instead of for the interrupt packet.
+ // Typically when an interrupt is sent a SIGINT or SIGSTOP
+ // is used, so if we get anything else, we need to try and
+ // get another stop reply packet that may have been sent
+ // due to sending the interrupt when the target is stopped
+ // which will just re-send a copy of the last stop reply
+ // packet. If we don't do this, then the reply for our
+ // async packet will be the repeat stop reply packet and cause
+ // a lot of trouble for us!
+ if (signo != SIGINT && signo != SIGSTOP)
+ {
+ continue_after_async = false;
+
+ // We didn't get a a SIGINT or SIGSTOP, so try for a
+ // very brief time (1 ms) to get another stop reply
+ // packet to make sure it doesn't get in the way
+ StringExtractorGDBRemote extra_stop_reply_packet;
+ uint32_t timeout_usec = 1000;
+ if (WaitForPacketWithTimeoutMicroSecondsNoLock (extra_stop_reply_packet, timeout_usec))
+ {
+ switch (extra_stop_reply_packet.GetChar())
+ {
+ case 'T':
+ case 'S':
+ // We did get an extra stop reply, which means
+ // our interrupt didn't stop the target so we
+ // shouldn't continue after the async signal
+ // or packet is sent...
+ continue_after_async = false;
+ break;
+ }
+ }
+ }
+ }
+
+ if (m_async_signal != -1)
+ {
+ if (log)
+ log->Printf ("async: send signo = %s", Host::GetSignalAsCString (m_async_signal));
+
+ // Save off the async signal we are supposed to send
+ const int async_signal = m_async_signal;
+ // Clear the async signal member so we don't end up
+ // sending the signal multiple times...
+ m_async_signal = -1;
+ // Check which signal we stopped with
+ if (signo == async_signal)
+ {
+ if (log)
+ log->Printf ("async: stopped with signal %s, we are done running", Host::GetSignalAsCString (signo));
+
+ // We already stopped with a signal that we wanted
+ // to stop with, so we are done
+ }
+ else
+ {
+ // We stopped with a different signal that the one
+ // we wanted to stop with, so now we must resume
+ // with the signal we want
+ char signal_packet[32];
+ int signal_packet_len = 0;
+ signal_packet_len = ::snprintf (signal_packet,
+ sizeof (signal_packet),
+ "C%2.2x",
+ async_signal);
+
+ if (log)
+ log->Printf ("async: stopped with signal %s, resume with %s",
+ Host::GetSignalAsCString (signo),
+ Host::GetSignalAsCString (async_signal));
+
+ // Set the continue packet to resume even if the
+ // interrupt didn't cause our stop (ignore continue_after_async)
+ continue_packet.assign(signal_packet, signal_packet_len);
+ continue;
+ }
+ }
+ else if (m_async_packet_predicate.GetValue())
+ {
+ Log * packet_log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PACKETS));
+
+ // We are supposed to send an asynchronous packet while
+ // we are running.
+ m_async_response.Clear();
+ if (m_async_packet.empty())
+ {
+ if (packet_log)
+ packet_log->Printf ("async: error: empty async packet");
+
+ }
+ else
+ {
+ if (packet_log)
+ packet_log->Printf ("async: sending packet");
+
+ SendPacketAndWaitForResponse (&m_async_packet[0],
+ m_async_packet.size(),
+ m_async_response,
+ false);
+ }
+ // Let the other thread that was trying to send the async
+ // packet know that the packet has been sent and response is
+ // ready...
+ m_async_packet_predicate.SetValue(false, eBroadcastAlways);
+
+ if (packet_log)
+ packet_log->Printf ("async: sent packet, continue_after_async = %i", continue_after_async);
+
+ // Set the continue packet to resume if our interrupt
+ // for the async packet did cause the stop
+ if (continue_after_async)
+ {
+ // Reverting this for now as it is causing deadlocks
+ // in programs (<rdar://problem/11529853>). In the future
+ // we should check our thread list and "do the right thing"
+ // for new threads that show up while we stop and run async
+ // packets. Setting the packet to 'c' to continue all threads
+ // is the right thing to do 99.99% of the time because if a
+ // thread was single stepping, and we sent an interrupt, we
+ // will notice above that we didn't stop due to an interrupt
+ // but stopped due to stepping and we would _not_ continue.
+ continue_packet.assign (1, 'c');
+ continue;
+ }
+ }
+ // Stop with signal and thread info
+ state = eStateStopped;
+ }
+ break;
+
+ case 'W':
+ case 'X':
+ // process exited
+ state = eStateExited;
+ break;
+
+ case 'O':
+ // STDOUT
+ {
+ got_async_packet = true;
+ std::string inferior_stdout;
+ inferior_stdout.reserve(response.GetBytesLeft () / 2);
+ char ch;
+ while ((ch = response.GetHexU8()) != '\0')
+ inferior_stdout.append(1, ch);
+ process->AppendSTDOUT (inferior_stdout.c_str(), inferior_stdout.size());
+ }
+ break;
+
+ case 'A':
+ // Async miscellaneous reply. Right now, only profile data is coming through this channel.
+ {
+ got_async_packet = true;
+ std::string input = response.GetStringRef().substr(1); // '1' to move beyond 'A'
+ if (m_partial_profile_data.length() > 0)
+ {
+ m_partial_profile_data.append(input);
+ input = m_partial_profile_data;
+ m_partial_profile_data.clear();
+ }
+
+ size_t found, pos = 0, len = input.length();
+ while ((found = input.find(end_delimiter, pos)) != std::string::npos)
+ {
+ StringExtractorGDBRemote profileDataExtractor(input.substr(pos, found).c_str());
+ std::string profile_data = HarmonizeThreadIdsForProfileData(process, profileDataExtractor);
+ process->BroadcastAsyncProfileData (profile_data);
+
+ pos = found + end_delimiter_len;
+ }
+
+ if (pos < len)
+ {
+ // Last incomplete chunk.
+ m_partial_profile_data = input.substr(pos);
+ }
+ }
+ break;
+
+ case 'E':
+ // ERROR
+ state = eStateInvalid;
+ break;
+
+ default:
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () unrecognized async packet", __FUNCTION__);
+ state = eStateInvalid;
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () WaitForPacket(...) => false", __FUNCTION__);
+ state = eStateInvalid;
+ }
+ }
+ if (log)
+ log->Printf ("GDBRemoteCommunicationClient::%s () => %s", __FUNCTION__, StateAsCString(state));
+ response.SetFilePos(0);
+ m_private_is_running.SetValue (false, eBroadcastAlways);
+ m_public_is_running.SetValue (false, eBroadcastAlways);
+ return state;
+}
+
+bool
+GDBRemoteCommunicationClient::SendAsyncSignal (int signo)
+{
+ Mutex::Locker async_locker (m_async_mutex);
+ m_async_signal = signo;
+ bool timed_out = false;
+ Mutex::Locker locker;
+ if (SendInterrupt (locker, 1, timed_out))
+ return true;
+ m_async_signal = -1;
+ return false;
+}
+
+// This function takes a mutex locker as a parameter in case the GetSequenceMutex
+// actually succeeds. If it doesn't succeed in acquiring the sequence mutex
+// (the expected result), then it will send the halt packet. If it does succeed
+// then the caller that requested the interrupt will want to keep the sequence
+// locked down so that no one else can send packets while the caller has control.
+// This function usually gets called when we are running and need to stop the
+// target. It can also be used when we are running and and we need to do something
+// else (like read/write memory), so we need to interrupt the running process
+// (gdb remote protocol requires this), and do what we need to do, then resume.
+
+bool
+GDBRemoteCommunicationClient::SendInterrupt
+(
+ Mutex::Locker& locker,
+ uint32_t seconds_to_wait_for_stop,
+ bool &timed_out
+)
+{
+ timed_out = false;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS));
+
+ if (IsRunning())
+ {
+ // Only send an interrupt if our debugserver is running...
+ if (GetSequenceMutex (locker))
+ {
+ if (log)
+ log->Printf ("SendInterrupt () - got sequence mutex without having to interrupt");
+ }
+ else
+ {
+ // Someone has the mutex locked waiting for a response or for the
+ // inferior to stop, so send the interrupt on the down low...
+ char ctrl_c = '\x03';
+ ConnectionStatus status = eConnectionStatusSuccess;
+ size_t bytes_written = Write (&ctrl_c, 1, status, NULL);
+ if (log)
+ log->PutCString("send packet: \\x03");
+ if (bytes_written > 0)
+ {
+ m_interrupt_sent = true;
+ if (seconds_to_wait_for_stop)
+ {
+ TimeValue timeout;
+ if (seconds_to_wait_for_stop)
+ {
+ timeout = TimeValue::Now();
+ timeout.OffsetWithSeconds (seconds_to_wait_for_stop);
+ }
+ if (m_private_is_running.WaitForValueEqualTo (false, &timeout, &timed_out))
+ {
+ if (log)
+ log->PutCString ("SendInterrupt () - sent interrupt, private state stopped");
+ return true;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SendInterrupt () - sent interrupt, timed out wating for async thread resume");
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SendInterrupt () - sent interrupt, not waiting for stop...");
+ return true;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SendInterrupt () - failed to write interrupt");
+ }
+ return false;
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("SendInterrupt () - not running");
+ }
+ return true;
+}
+
+lldb::pid_t
+GDBRemoteCommunicationClient::GetCurrentProcessID ()
+{
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qC", strlen("qC"), response, false))
+ {
+ if (response.GetChar() == 'Q')
+ if (response.GetChar() == 'C')
+ return response.GetHexMaxU32 (false, LLDB_INVALID_PROCESS_ID);
+ }
+ return LLDB_INVALID_PROCESS_ID;
+}
+
+bool
+GDBRemoteCommunicationClient::GetLaunchSuccess (std::string &error_str)
+{
+ error_str.clear();
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qLaunchSuccess", strlen("qLaunchSuccess"), response, false))
+ {
+ if (response.IsOKResponse())
+ return true;
+ if (response.GetChar() == 'E')
+ {
+ // A string the describes what failed when launching...
+ error_str = response.GetStringRef().substr(1);
+ }
+ else
+ {
+ error_str.assign ("unknown error occurred launching process");
+ }
+ }
+ else
+ {
+ error_str.assign ("timed out waiting for app to launch");
+ }
+ return false;
+}
+
+int
+GDBRemoteCommunicationClient::SendArgumentsPacket (char const *argv[])
+{
+ if (argv && argv[0])
+ {
+ StreamString packet;
+ packet.PutChar('A');
+ const char *arg;
+ for (uint32_t i = 0; (arg = argv[i]) != NULL; ++i)
+ {
+ const int arg_len = strlen(arg);
+ if (i > 0)
+ packet.PutChar(',');
+ packet.Printf("%i,%i,", arg_len * 2, i);
+ packet.PutBytesAsRawHex8 (arg, arg_len);
+ }
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SendEnvironmentPacket (char const *name_equal_value)
+{
+ if (name_equal_value && name_equal_value[0])
+ {
+ StreamString packet;
+ packet.Printf("QEnvironment:%s", name_equal_value);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SendLaunchArchPacket (char const *arch)
+{
+ if (arch && arch[0])
+ {
+ StreamString packet;
+ packet.Printf("QLaunchArch:%s", arch);
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+bool
+GDBRemoteCommunicationClient::GetOSVersion (uint32_t &major,
+ uint32_t &minor,
+ uint32_t &update)
+{
+ if (GetHostInfo ())
+ {
+ if (m_os_version_major != UINT32_MAX)
+ {
+ major = m_os_version_major;
+ minor = m_os_version_minor;
+ update = m_os_version_update;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetOSBuildString (std::string &s)
+{
+ if (GetHostInfo ())
+ {
+ if (!m_os_build.empty())
+ {
+ s = m_os_build;
+ return true;
+ }
+ }
+ s.clear();
+ return false;
+}
+
+
+bool
+GDBRemoteCommunicationClient::GetOSKernelDescription (std::string &s)
+{
+ if (GetHostInfo ())
+ {
+ if (!m_os_kernel.empty())
+ {
+ s = m_os_kernel;
+ return true;
+ }
+ }
+ s.clear();
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetHostname (std::string &s)
+{
+ if (GetHostInfo ())
+ {
+ if (!m_hostname.empty())
+ {
+ s = m_hostname;
+ return true;
+ }
+ }
+ s.clear();
+ return false;
+}
+
+ArchSpec
+GDBRemoteCommunicationClient::GetSystemArchitecture ()
+{
+ if (GetHostInfo ())
+ return m_host_arch;
+ return ArchSpec();
+}
+
+const lldb_private::ArchSpec &
+GDBRemoteCommunicationClient::GetProcessArchitecture ()
+{
+ if (m_qProcessInfo_is_valid == eLazyBoolCalculate)
+ GetCurrentProcessInfo ();
+ return m_process_arch;
+}
+
+
+bool
+GDBRemoteCommunicationClient::GetHostInfo (bool force)
+{
+ if (force || m_qHostInfo_is_valid == eLazyBoolCalculate)
+ {
+ m_qHostInfo_is_valid = eLazyBoolNo;
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse ("qHostInfo", response, false))
+ {
+ if (response.IsNormalResponse())
+ {
+ std::string name;
+ std::string value;
+ uint32_t cpu = LLDB_INVALID_CPUTYPE;
+ uint32_t sub = 0;
+ std::string arch_name;
+ std::string os_name;
+ std::string vendor_name;
+ std::string triple;
+ uint32_t pointer_byte_size = 0;
+ StringExtractor extractor;
+ ByteOrder byte_order = eByteOrderInvalid;
+ uint32_t num_keys_decoded = 0;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("cputype") == 0)
+ {
+ // exception type in big endian hex
+ cpu = Args::StringToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 0);
+ if (cpu != LLDB_INVALID_CPUTYPE)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("cpusubtype") == 0)
+ {
+ // exception count in big endian hex
+ sub = Args::StringToUInt32 (value.c_str(), 0, 0);
+ if (sub != 0)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("arch") == 0)
+ {
+ arch_name.swap (value);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("triple") == 0)
+ {
+ // The triple comes as ASCII hex bytes since it contains '-' chars
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (triple);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("os_build") == 0)
+ {
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (m_os_build);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("hostname") == 0)
+ {
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (m_hostname);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("os_kernel") == 0)
+ {
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (m_os_kernel);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("ostype") == 0)
+ {
+ os_name.swap (value);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("vendor") == 0)
+ {
+ vendor_name.swap(value);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("endian") == 0)
+ {
+ ++num_keys_decoded;
+ if (value.compare("little") == 0)
+ byte_order = eByteOrderLittle;
+ else if (value.compare("big") == 0)
+ byte_order = eByteOrderBig;
+ else if (value.compare("pdp") == 0)
+ byte_order = eByteOrderPDP;
+ else
+ --num_keys_decoded;
+ }
+ else if (name.compare("ptrsize") == 0)
+ {
+ pointer_byte_size = Args::StringToUInt32 (value.c_str(), 0, 0);
+ if (pointer_byte_size != 0)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("os_version") == 0)
+ {
+ Args::StringToVersion (value.c_str(),
+ m_os_version_major,
+ m_os_version_minor,
+ m_os_version_update);
+ if (m_os_version_major != UINT32_MAX)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("watchpoint_exceptions_received") == 0)
+ {
+ ++num_keys_decoded;
+ if (strcmp(value.c_str(),"before") == 0)
+ m_watchpoints_trigger_after_instruction = eLazyBoolNo;
+ else if (strcmp(value.c_str(),"after") == 0)
+ m_watchpoints_trigger_after_instruction = eLazyBoolYes;
+ else
+ --num_keys_decoded;
+ }
+
+ }
+
+ if (num_keys_decoded > 0)
+ m_qHostInfo_is_valid = eLazyBoolYes;
+
+ if (triple.empty())
+ {
+ if (arch_name.empty())
+ {
+ if (cpu != LLDB_INVALID_CPUTYPE)
+ {
+ m_host_arch.SetArchitecture (eArchTypeMachO, cpu, sub);
+ if (pointer_byte_size)
+ {
+ assert (pointer_byte_size == m_host_arch.GetAddressByteSize());
+ }
+ if (byte_order != eByteOrderInvalid)
+ {
+ assert (byte_order == m_host_arch.GetByteOrder());
+ }
+
+ if (!os_name.empty() && vendor_name.compare("apple") == 0 && os_name.find("darwin") == 0)
+ {
+ switch (m_host_arch.GetMachine())
+ {
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ os_name = "ios";
+ break;
+ default:
+ os_name = "macosx";
+ break;
+ }
+ }
+ if (!vendor_name.empty())
+ m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name));
+ if (!os_name.empty())
+ m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name));
+
+ }
+ }
+ else
+ {
+ std::string triple;
+ triple += arch_name;
+ if (!vendor_name.empty() || !os_name.empty())
+ {
+ triple += '-';
+ if (vendor_name.empty())
+ triple += "unknown";
+ else
+ triple += vendor_name;
+ triple += '-';
+ if (os_name.empty())
+ triple += "unknown";
+ else
+ triple += os_name;
+ }
+ m_host_arch.SetTriple (triple.c_str());
+
+ llvm::Triple &host_triple = m_host_arch.GetTriple();
+ if (host_triple.getVendor() == llvm::Triple::Apple && host_triple.getOS() == llvm::Triple::Darwin)
+ {
+ switch (m_host_arch.GetMachine())
+ {
+ case llvm::Triple::arm:
+ case llvm::Triple::thumb:
+ host_triple.setOS(llvm::Triple::IOS);
+ break;
+ default:
+ host_triple.setOS(llvm::Triple::MacOSX);
+ break;
+ }
+ }
+ if (pointer_byte_size)
+ {
+ assert (pointer_byte_size == m_host_arch.GetAddressByteSize());
+ }
+ if (byte_order != eByteOrderInvalid)
+ {
+ assert (byte_order == m_host_arch.GetByteOrder());
+ }
+
+ }
+ }
+ else
+ {
+ m_host_arch.SetTriple (triple.c_str());
+ if (pointer_byte_size)
+ {
+ assert (pointer_byte_size == m_host_arch.GetAddressByteSize());
+ }
+ if (byte_order != eByteOrderInvalid)
+ {
+ assert (byte_order == m_host_arch.GetByteOrder());
+ }
+ }
+ }
+ }
+ }
+ return m_qHostInfo_is_valid == eLazyBoolYes;
+}
+
+int
+GDBRemoteCommunicationClient::SendAttach
+(
+ lldb::pid_t pid,
+ StringExtractorGDBRemote& response
+)
+{
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ char packet[64];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, pid);
+ assert (packet_len < (int)sizeof(packet));
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ if (response.IsErrorResponse())
+ return response.GetError();
+ return 0;
+ }
+ }
+ return -1;
+}
+
+const lldb_private::ArchSpec &
+GDBRemoteCommunicationClient::GetHostArchitecture ()
+{
+ if (m_qHostInfo_is_valid == eLazyBoolCalculate)
+ GetHostInfo ();
+ return m_host_arch;
+}
+
+addr_t
+GDBRemoteCommunicationClient::AllocateMemory (size_t size, uint32_t permissions)
+{
+ if (m_supports_alloc_dealloc_memory != eLazyBoolNo)
+ {
+ m_supports_alloc_dealloc_memory = eLazyBoolYes;
+ char packet[64];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "_M%" PRIx64 ",%s%s%s",
+ (uint64_t)size,
+ permissions & lldb::ePermissionsReadable ? "r" : "",
+ permissions & lldb::ePermissionsWritable ? "w" : "",
+ permissions & lldb::ePermissionsExecutable ? "x" : "");
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ if (!response.IsErrorResponse())
+ return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ }
+ else
+ {
+ m_supports_alloc_dealloc_memory = eLazyBoolNo;
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+GDBRemoteCommunicationClient::DeallocateMemory (addr_t addr)
+{
+ if (m_supports_alloc_dealloc_memory != eLazyBoolNo)
+ {
+ m_supports_alloc_dealloc_memory = eLazyBoolYes;
+ char packet[64];
+ const int packet_len = ::snprintf(packet, sizeof(packet), "_m%" PRIx64, (uint64_t)addr);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ if (response.IsOKResponse())
+ return true;
+ }
+ else
+ {
+ m_supports_alloc_dealloc_memory = eLazyBoolNo;
+ }
+ }
+ return false;
+}
+
+Error
+GDBRemoteCommunicationClient::Detach (bool keep_stopped)
+{
+ Error error;
+
+ if (keep_stopped)
+ {
+ if (m_supports_detach_stay_stopped == eLazyBoolCalculate)
+ {
+ char packet[64];
+ const int packet_len = ::snprintf(packet, sizeof(packet), "qSupportsDetachAndStayStopped:");
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ m_supports_detach_stay_stopped = eLazyBoolYes;
+ }
+ else
+ {
+ m_supports_detach_stay_stopped = eLazyBoolNo;
+ }
+ }
+
+ if (m_supports_detach_stay_stopped == eLazyBoolNo)
+ {
+ error.SetErrorString("Stays stopped not supported by this target.");
+ return error;
+ }
+ else
+ {
+ size_t num_sent = SendPacket ("D1", 2);
+ if (num_sent == 0)
+ error.SetErrorString ("Sending extended disconnect packet failed.");
+ }
+ }
+ else
+ {
+ size_t num_sent = SendPacket ("D", 1);
+ if (num_sent == 0)
+ error.SetErrorString ("Sending disconnect packet failed.");
+ }
+ return error;
+}
+
+Error
+GDBRemoteCommunicationClient::GetMemoryRegionInfo (lldb::addr_t addr,
+ lldb_private::MemoryRegionInfo &region_info)
+{
+ Error error;
+ region_info.Clear();
+
+ if (m_supports_memory_region_info != eLazyBoolNo)
+ {
+ m_supports_memory_region_info = eLazyBoolYes;
+ char packet[64];
+ const int packet_len = ::snprintf(packet, sizeof(packet), "qMemoryRegionInfo:%" PRIx64, (uint64_t)addr);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ std::string name;
+ std::string value;
+ addr_t addr_value;
+ bool success = true;
+ bool saw_permissions = false;
+ while (success && response.GetNameColonValue(name, value))
+ {
+ if (name.compare ("start") == 0)
+ {
+ addr_value = Args::StringToUInt64(value.c_str(), LLDB_INVALID_ADDRESS, 16, &success);
+ if (success)
+ region_info.GetRange().SetRangeBase(addr_value);
+ }
+ else if (name.compare ("size") == 0)
+ {
+ addr_value = Args::StringToUInt64(value.c_str(), 0, 16, &success);
+ if (success)
+ region_info.GetRange().SetByteSize (addr_value);
+ }
+ else if (name.compare ("permissions") == 0 && region_info.GetRange().IsValid())
+ {
+ saw_permissions = true;
+ if (region_info.GetRange().Contains (addr))
+ {
+ if (value.find('r') != std::string::npos)
+ region_info.SetReadable (MemoryRegionInfo::eYes);
+ else
+ region_info.SetReadable (MemoryRegionInfo::eNo);
+
+ if (value.find('w') != std::string::npos)
+ region_info.SetWritable (MemoryRegionInfo::eYes);
+ else
+ region_info.SetWritable (MemoryRegionInfo::eNo);
+
+ if (value.find('x') != std::string::npos)
+ region_info.SetExecutable (MemoryRegionInfo::eYes);
+ else
+ region_info.SetExecutable (MemoryRegionInfo::eNo);
+ }
+ else
+ {
+ // The reported region does not contain this address -- we're looking at an unmapped page
+ region_info.SetReadable (MemoryRegionInfo::eNo);
+ region_info.SetWritable (MemoryRegionInfo::eNo);
+ region_info.SetExecutable (MemoryRegionInfo::eNo);
+ }
+ }
+ else if (name.compare ("error") == 0)
+ {
+ StringExtractorGDBRemote name_extractor;
+ // Swap "value" over into "name_extractor"
+ name_extractor.GetStringRef().swap(value);
+ // Now convert the HEX bytes into a string value
+ name_extractor.GetHexByteString (value);
+ error.SetErrorString(value.c_str());
+ }
+ }
+
+ // We got a valid address range back but no permissions -- which means this is an unmapped page
+ if (region_info.GetRange().IsValid() && saw_permissions == false)
+ {
+ region_info.SetReadable (MemoryRegionInfo::eNo);
+ region_info.SetWritable (MemoryRegionInfo::eNo);
+ region_info.SetExecutable (MemoryRegionInfo::eNo);
+ }
+ }
+ else
+ {
+ m_supports_memory_region_info = eLazyBoolNo;
+ }
+ }
+
+ if (m_supports_memory_region_info == eLazyBoolNo)
+ {
+ error.SetErrorString("qMemoryRegionInfo is not supported");
+ }
+ if (error.Fail())
+ region_info.Clear();
+ return error;
+
+}
+
+Error
+GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num)
+{
+ Error error;
+
+ if (m_supports_watchpoint_support_info == eLazyBoolYes)
+ {
+ num = m_num_supported_hardware_watchpoints;
+ return error;
+ }
+
+ // Set num to 0 first.
+ num = 0;
+ if (m_supports_watchpoint_support_info != eLazyBoolNo)
+ {
+ char packet[64];
+ const int packet_len = ::snprintf(packet, sizeof(packet), "qWatchpointSupportInfo:");
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ m_supports_watchpoint_support_info = eLazyBoolYes;
+ std::string name;
+ std::string value;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare ("num") == 0)
+ {
+ num = Args::StringToUInt32(value.c_str(), 0, 0);
+ m_num_supported_hardware_watchpoints = num;
+ }
+ }
+ }
+ else
+ {
+ m_supports_watchpoint_support_info = eLazyBoolNo;
+ }
+ }
+
+ if (m_supports_watchpoint_support_info == eLazyBoolNo)
+ {
+ error.SetErrorString("qWatchpointSupportInfo is not supported");
+ }
+ return error;
+
+}
+
+lldb_private::Error
+GDBRemoteCommunicationClient::GetWatchpointSupportInfo (uint32_t &num, bool& after)
+{
+ Error error(GetWatchpointSupportInfo(num));
+ if (error.Success())
+ error = GetWatchpointsTriggerAfterInstruction(after);
+ return error;
+}
+
+lldb_private::Error
+GDBRemoteCommunicationClient::GetWatchpointsTriggerAfterInstruction (bool &after)
+{
+ Error error;
+
+ // we assume watchpoints will happen after running the relevant opcode
+ // and we only want to override this behavior if we have explicitly
+ // received a qHostInfo telling us otherwise
+ if (m_qHostInfo_is_valid != eLazyBoolYes)
+ after = true;
+ else
+ after = (m_watchpoints_trigger_after_instruction != eLazyBoolNo);
+ return error;
+}
+
+int
+GDBRemoteCommunicationClient::SetSTDIN (char const *path)
+{
+ if (path && path[0])
+ {
+ StreamString packet;
+ packet.PutCString("QSetSTDIN:");
+ packet.PutBytesAsRawHex8(path, strlen(path));
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SetSTDOUT (char const *path)
+{
+ if (path && path[0])
+ {
+ StreamString packet;
+ packet.PutCString("QSetSTDOUT:");
+ packet.PutBytesAsRawHex8(path, strlen(path));
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SetSTDERR (char const *path)
+{
+ if (path && path[0])
+ {
+ StreamString packet;
+ packet.PutCString("QSetSTDERR:");
+ packet.PutBytesAsRawHex8(path, strlen(path));
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SetWorkingDir (char const *path)
+{
+ if (path && path[0])
+ {
+ StreamString packet;
+ packet.PutCString("QSetWorkingDir:");
+ packet.PutBytesAsRawHex8(path, strlen(path));
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ }
+ return -1;
+}
+
+int
+GDBRemoteCommunicationClient::SetDisableASLR (bool enable)
+{
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof (packet), "QSetDisableASLR:%i", enable ? 1 : 0);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ uint8_t error = response.GetError();
+ if (error)
+ return error;
+ }
+ return -1;
+}
+
+bool
+GDBRemoteCommunicationClient::DecodeProcessInfoResponse (StringExtractorGDBRemote &response, ProcessInstanceInfo &process_info)
+{
+ if (response.IsNormalResponse())
+ {
+ std::string name;
+ std::string value;
+ StringExtractor extractor;
+
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("pid") == 0)
+ {
+ process_info.SetProcessID (Args::StringToUInt32 (value.c_str(), LLDB_INVALID_PROCESS_ID, 0));
+ }
+ else if (name.compare("ppid") == 0)
+ {
+ process_info.SetParentProcessID (Args::StringToUInt32 (value.c_str(), LLDB_INVALID_PROCESS_ID, 0));
+ }
+ else if (name.compare("uid") == 0)
+ {
+ process_info.SetUserID (Args::StringToUInt32 (value.c_str(), UINT32_MAX, 0));
+ }
+ else if (name.compare("euid") == 0)
+ {
+ process_info.SetEffectiveUserID (Args::StringToUInt32 (value.c_str(), UINT32_MAX, 0));
+ }
+ else if (name.compare("gid") == 0)
+ {
+ process_info.SetGroupID (Args::StringToUInt32 (value.c_str(), UINT32_MAX, 0));
+ }
+ else if (name.compare("egid") == 0)
+ {
+ process_info.SetEffectiveGroupID (Args::StringToUInt32 (value.c_str(), UINT32_MAX, 0));
+ }
+ else if (name.compare("triple") == 0)
+ {
+ // The triple comes as ASCII hex bytes since it contains '-' chars
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (value);
+ process_info.GetArchitecture ().SetTriple (value.c_str());
+ }
+ else if (name.compare("name") == 0)
+ {
+ StringExtractor extractor;
+ // The process name from ASCII hex bytes since we can't
+ // control the characters in a process name
+ extractor.GetStringRef().swap(value);
+ extractor.SetFilePos(0);
+ extractor.GetHexByteString (value);
+ process_info.GetExecutableFile().SetFile (value.c_str(), false);
+ }
+ }
+
+ if (process_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+ return true;
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info)
+{
+ process_info.Clear();
+
+ if (m_supports_qProcessInfoPID)
+ {
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof (packet), "qProcessInfoPID:%" PRIu64, pid);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ return DecodeProcessInfoResponse (response, process_info);
+ }
+ else
+ {
+ m_supports_qProcessInfoPID = false;
+ return false;
+ }
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetCurrentProcessInfo ()
+{
+ if (m_qProcessInfo_is_valid == eLazyBoolYes)
+ return true;
+ if (m_qProcessInfo_is_valid == eLazyBoolNo)
+ return false;
+
+ GetHostInfo ();
+
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse ("qProcessInfo", response, false))
+ {
+ if (response.IsNormalResponse())
+ {
+ std::string name;
+ std::string value;
+ uint32_t cpu = LLDB_INVALID_CPUTYPE;
+ uint32_t sub = 0;
+ std::string arch_name;
+ std::string os_name;
+ std::string vendor_name;
+ std::string triple;
+ uint32_t pointer_byte_size = 0;
+ StringExtractor extractor;
+ ByteOrder byte_order = eByteOrderInvalid;
+ uint32_t num_keys_decoded = 0;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("cputype") == 0)
+ {
+ cpu = Args::StringToUInt32 (value.c_str(), LLDB_INVALID_CPUTYPE, 16);
+ if (cpu != LLDB_INVALID_CPUTYPE)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("cpusubtype") == 0)
+ {
+ sub = Args::StringToUInt32 (value.c_str(), 0, 16);
+ if (sub != 0)
+ ++num_keys_decoded;
+ }
+ else if (name.compare("ostype") == 0)
+ {
+ os_name.swap (value);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("vendor") == 0)
+ {
+ vendor_name.swap(value);
+ ++num_keys_decoded;
+ }
+ else if (name.compare("endian") == 0)
+ {
+ ++num_keys_decoded;
+ if (value.compare("little") == 0)
+ byte_order = eByteOrderLittle;
+ else if (value.compare("big") == 0)
+ byte_order = eByteOrderBig;
+ else if (value.compare("pdp") == 0)
+ byte_order = eByteOrderPDP;
+ else
+ --num_keys_decoded;
+ }
+ else if (name.compare("ptrsize") == 0)
+ {
+ pointer_byte_size = Args::StringToUInt32 (value.c_str(), 0, 16);
+ if (pointer_byte_size != 0)
+ ++num_keys_decoded;
+ }
+ }
+ if (num_keys_decoded > 0)
+ m_qProcessInfo_is_valid = eLazyBoolYes;
+ if (cpu != LLDB_INVALID_CPUTYPE && !os_name.empty() && !vendor_name.empty())
+ {
+ m_process_arch.SetArchitecture (eArchTypeMachO, cpu, sub);
+ if (pointer_byte_size)
+ {
+ assert (pointer_byte_size == m_process_arch.GetAddressByteSize());
+ }
+ m_host_arch.GetTriple().setVendorName (llvm::StringRef (vendor_name));
+ m_host_arch.GetTriple().setOSName (llvm::StringRef (os_name));
+ return true;
+ }
+ }
+ }
+ else
+ {
+ m_qProcessInfo_is_valid = eLazyBoolNo;
+ }
+
+ return false;
+}
+
+
+uint32_t
+GDBRemoteCommunicationClient::FindProcesses (const ProcessInstanceInfoMatch &match_info,
+ ProcessInstanceInfoList &process_infos)
+{
+ process_infos.Clear();
+
+ if (m_supports_qfProcessInfo)
+ {
+ StreamString packet;
+ packet.PutCString ("qfProcessInfo");
+ if (!match_info.MatchAllProcesses())
+ {
+ packet.PutChar (':');
+ const char *name = match_info.GetProcessInfo().GetName();
+ bool has_name_match = false;
+ if (name && name[0])
+ {
+ has_name_match = true;
+ NameMatchType name_match_type = match_info.GetNameMatchType();
+ switch (name_match_type)
+ {
+ case eNameMatchIgnore:
+ has_name_match = false;
+ break;
+
+ case eNameMatchEquals:
+ packet.PutCString ("name_match:equals;");
+ break;
+
+ case eNameMatchContains:
+ packet.PutCString ("name_match:contains;");
+ break;
+
+ case eNameMatchStartsWith:
+ packet.PutCString ("name_match:starts_with;");
+ break;
+
+ case eNameMatchEndsWith:
+ packet.PutCString ("name_match:ends_with;");
+ break;
+
+ case eNameMatchRegularExpression:
+ packet.PutCString ("name_match:regex;");
+ break;
+ }
+ if (has_name_match)
+ {
+ packet.PutCString ("name:");
+ packet.PutBytesAsRawHex8(name, ::strlen(name));
+ packet.PutChar (';');
+ }
+ }
+
+ if (match_info.GetProcessInfo().ProcessIDIsValid())
+ packet.Printf("pid:%" PRIu64 ";",match_info.GetProcessInfo().GetProcessID());
+ if (match_info.GetProcessInfo().ParentProcessIDIsValid())
+ packet.Printf("parent_pid:%" PRIu64 ";",match_info.GetProcessInfo().GetParentProcessID());
+ if (match_info.GetProcessInfo().UserIDIsValid())
+ packet.Printf("uid:%u;",match_info.GetProcessInfo().GetUserID());
+ if (match_info.GetProcessInfo().GroupIDIsValid())
+ packet.Printf("gid:%u;",match_info.GetProcessInfo().GetGroupID());
+ if (match_info.GetProcessInfo().EffectiveUserIDIsValid())
+ packet.Printf("euid:%u;",match_info.GetProcessInfo().GetEffectiveUserID());
+ if (match_info.GetProcessInfo().EffectiveGroupIDIsValid())
+ packet.Printf("egid:%u;",match_info.GetProcessInfo().GetEffectiveGroupID());
+ if (match_info.GetProcessInfo().EffectiveGroupIDIsValid())
+ packet.Printf("all_users:%u;",match_info.GetMatchAllUsers() ? 1 : 0);
+ if (match_info.GetProcessInfo().GetArchitecture().IsValid())
+ {
+ const ArchSpec &match_arch = match_info.GetProcessInfo().GetArchitecture();
+ const llvm::Triple &triple = match_arch.GetTriple();
+ packet.PutCString("triple:");
+ packet.PutCStringAsRawHex8(triple.getTriple().c_str());
+ packet.PutChar (';');
+ }
+ }
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false))
+ {
+ do
+ {
+ ProcessInstanceInfo process_info;
+ if (!DecodeProcessInfoResponse (response, process_info))
+ break;
+ process_infos.Append(process_info);
+ response.GetStringRef().clear();
+ response.SetFilePos(0);
+ } while (SendPacketAndWaitForResponse ("qsProcessInfo", strlen ("qsProcessInfo"), response, false));
+ }
+ else
+ {
+ m_supports_qfProcessInfo = false;
+ return 0;
+ }
+ }
+ return process_infos.GetSize();
+
+}
+
+bool
+GDBRemoteCommunicationClient::GetUserName (uint32_t uid, std::string &name)
+{
+ if (m_supports_qUserName)
+ {
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof (packet), "qUserName:%i", uid);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ if (response.IsNormalResponse())
+ {
+ // Make sure we parsed the right number of characters. The response is
+ // the hex encoded user name and should make up the entire packet.
+ // If there are any non-hex ASCII bytes, the length won't match below..
+ if (response.GetHexByteString (name) * 2 == response.GetStringRef().size())
+ return true;
+ }
+ }
+ else
+ {
+ m_supports_qUserName = false;
+ return false;
+ }
+ }
+ return false;
+
+}
+
+bool
+GDBRemoteCommunicationClient::GetGroupName (uint32_t gid, std::string &name)
+{
+ if (m_supports_qGroupName)
+ {
+ char packet[32];
+ const int packet_len = ::snprintf (packet, sizeof (packet), "qGroupName:%i", gid);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse (packet, packet_len, response, false))
+ {
+ if (response.IsNormalResponse())
+ {
+ // Make sure we parsed the right number of characters. The response is
+ // the hex encoded group name and should make up the entire packet.
+ // If there are any non-hex ASCII bytes, the length won't match below..
+ if (response.GetHexByteString (name) * 2 == response.GetStringRef().size())
+ return true;
+ }
+ }
+ else
+ {
+ m_supports_qGroupName = false;
+ return false;
+ }
+ }
+ return false;
+}
+
+void
+GDBRemoteCommunicationClient::TestPacketSpeed (const uint32_t num_packets)
+{
+ uint32_t i;
+ TimeValue start_time, end_time;
+ uint64_t total_time_nsec;
+ float packets_per_second;
+ if (SendSpeedTestPacket (0, 0))
+ {
+ for (uint32_t send_size = 0; send_size <= 1024; send_size *= 2)
+ {
+ for (uint32_t recv_size = 0; recv_size <= 1024; recv_size *= 2)
+ {
+ start_time = TimeValue::Now();
+ for (i=0; i<num_packets; ++i)
+ {
+ SendSpeedTestPacket (send_size, recv_size);
+ }
+ end_time = TimeValue::Now();
+ total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970();
+ packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec;
+ printf ("%u qSpeedTest(send=%-5u, recv=%-5u) in %" PRIu64 ".%9.9" PRIu64 " sec for %f packets/sec.\n",
+ num_packets,
+ send_size,
+ recv_size,
+ total_time_nsec / TimeValue::NanoSecPerSec,
+ total_time_nsec % TimeValue::NanoSecPerSec,
+ packets_per_second);
+ if (recv_size == 0)
+ recv_size = 32;
+ }
+ if (send_size == 0)
+ send_size = 32;
+ }
+ }
+ else
+ {
+ start_time = TimeValue::Now();
+ for (i=0; i<num_packets; ++i)
+ {
+ GetCurrentProcessID ();
+ }
+ end_time = TimeValue::Now();
+ total_time_nsec = end_time.GetAsNanoSecondsSinceJan1_1970() - start_time.GetAsNanoSecondsSinceJan1_1970();
+ packets_per_second = (((float)num_packets)/(float)total_time_nsec) * (float)TimeValue::NanoSecPerSec;
+ printf ("%u 'qC' packets packets in 0x%" PRIu64 "%9.9" PRIu64 " sec for %f packets/sec.\n",
+ num_packets,
+ total_time_nsec / TimeValue::NanoSecPerSec,
+ total_time_nsec % TimeValue::NanoSecPerSec,
+ packets_per_second);
+ }
+}
+
+bool
+GDBRemoteCommunicationClient::SendSpeedTestPacket (uint32_t send_size, uint32_t recv_size)
+{
+ StreamString packet;
+ packet.Printf ("qSpeedTest:response_size:%i;data:", recv_size);
+ uint32_t bytes_left = send_size;
+ while (bytes_left > 0)
+ {
+ if (bytes_left >= 26)
+ {
+ packet.PutCString("abcdefghijklmnopqrstuvwxyz");
+ bytes_left -= 26;
+ }
+ else
+ {
+ packet.Printf ("%*.*s;", bytes_left, bytes_left, "abcdefghijklmnopqrstuvwxyz");
+ bytes_left = 0;
+ }
+ }
+
+ StringExtractorGDBRemote response;
+ return SendPacketAndWaitForResponse (packet.GetData(), packet.GetSize(), response, false) > 0;
+ return false;
+}
+
+uint16_t
+GDBRemoteCommunicationClient::LaunchGDBserverAndGetPort ()
+{
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qLaunchGDBServer", strlen("qLaunchGDBServer"), response, false))
+ {
+ std::string name;
+ std::string value;
+ uint16_t port = 0;
+ //lldb::pid_t pid = LLDB_INVALID_PROCESS_ID;
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.size() == 4 && name.compare("port") == 0)
+ port = Args::StringToUInt32(value.c_str(), 0, 0);
+// if (name.size() == 3 && name.compare("pid") == 0)
+// pid = Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0);
+ }
+ return port;
+ }
+ return 0;
+}
+
+bool
+GDBRemoteCommunicationClient::SetCurrentThread (uint64_t tid)
+{
+ if (m_curr_tid == tid)
+ return true;
+
+ char packet[32];
+ int packet_len;
+ if (tid == UINT64_MAX)
+ packet_len = ::snprintf (packet, sizeof(packet), "Hg-1");
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "Hg%" PRIx64, tid);
+ assert (packet_len + 1 < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.IsOKResponse())
+ {
+ m_curr_tid = tid;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::SetCurrentThreadForRun (uint64_t tid)
+{
+ if (m_curr_tid_run == tid)
+ return true;
+
+ char packet[32];
+ int packet_len;
+ if (tid == UINT64_MAX)
+ packet_len = ::snprintf (packet, sizeof(packet), "Hc-1");
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "Hc%" PRIx64, tid);
+
+ assert (packet_len + 1 < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.IsOKResponse())
+ {
+ m_curr_tid_run = tid;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetStopReply (StringExtractorGDBRemote &response)
+{
+ if (SendPacketAndWaitForResponse("?", 1, response, false))
+ return response.IsNormalResponse();
+ return false;
+}
+
+bool
+GDBRemoteCommunicationClient::GetThreadStopInfo (lldb::tid_t tid, StringExtractorGDBRemote &response)
+{
+ if (m_supports_qThreadStopInfo)
+ {
+ char packet[256];
+ int packet_len = ::snprintf(packet, sizeof(packet), "qThreadStopInfo%" PRIx64, tid);
+ assert (packet_len < (int)sizeof(packet));
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.IsNormalResponse())
+ return true;
+ else
+ return false;
+ }
+ else
+ {
+ m_supports_qThreadStopInfo = false;
+ }
+ }
+// if (SetCurrentThread (tid))
+// return GetStopReply (response);
+ return false;
+}
+
+
+uint8_t
+GDBRemoteCommunicationClient::SendGDBStoppointTypePacket (GDBStoppointType type, bool insert, addr_t addr, uint32_t length)
+{
+ switch (type)
+ {
+ case eBreakpointSoftware: if (!m_supports_z0) return UINT8_MAX; break;
+ case eBreakpointHardware: if (!m_supports_z1) return UINT8_MAX; break;
+ case eWatchpointWrite: if (!m_supports_z2) return UINT8_MAX; break;
+ case eWatchpointRead: if (!m_supports_z3) return UINT8_MAX; break;
+ case eWatchpointReadWrite: if (!m_supports_z4) return UINT8_MAX; break;
+ }
+
+ char packet[64];
+ const int packet_len = ::snprintf (packet,
+ sizeof(packet),
+ "%c%i,%" PRIx64 ",%x",
+ insert ? 'Z' : 'z',
+ type,
+ addr,
+ length);
+
+ assert (packet_len + 1 < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse(packet, packet_len, response, true))
+ {
+ if (response.IsOKResponse())
+ return 0;
+ else if (response.IsErrorResponse())
+ return response.GetError();
+ }
+ else
+ {
+ switch (type)
+ {
+ case eBreakpointSoftware: m_supports_z0 = false; break;
+ case eBreakpointHardware: m_supports_z1 = false; break;
+ case eWatchpointWrite: m_supports_z2 = false; break;
+ case eWatchpointRead: m_supports_z3 = false; break;
+ case eWatchpointReadWrite: m_supports_z4 = false; break;
+ }
+ }
+
+ return UINT8_MAX;
+}
+
+size_t
+GDBRemoteCommunicationClient::GetCurrentThreadIDs (std::vector<lldb::tid_t> &thread_ids,
+ bool &sequence_mutex_unavailable)
+{
+ Mutex::Locker locker;
+ thread_ids.clear();
+
+ if (GetSequenceMutex (locker, "ProcessGDBRemote::UpdateThreadList() failed due to not getting the sequence mutex"))
+ {
+ sequence_mutex_unavailable = false;
+ StringExtractorGDBRemote response;
+
+ for (SendPacketNoLock ("qfThreadInfo", strlen("qfThreadInfo")) && WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ());
+ response.IsNormalResponse();
+ SendPacketNoLock ("qsThreadInfo", strlen("qsThreadInfo")) && WaitForPacketWithTimeoutMicroSecondsNoLock (response, GetPacketTimeoutInMicroSeconds ()))
+ {
+ char ch = response.GetChar();
+ if (ch == 'l')
+ break;
+ if (ch == 'm')
+ {
+ do
+ {
+ tid_t tid = response.GetHexMaxU64(false, LLDB_INVALID_THREAD_ID);
+
+ if (tid != LLDB_INVALID_THREAD_ID)
+ {
+ thread_ids.push_back (tid);
+ }
+ ch = response.GetChar(); // Skip the command separator
+ } while (ch == ','); // Make sure we got a comma separator
+ }
+ }
+ }
+ else
+ {
+#if defined (LLDB_CONFIGURATION_DEBUG)
+ // assert(!"ProcessGDBRemote::UpdateThreadList() failed due to not getting the sequence mutex");
+#else
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_PROCESS | GDBR_LOG_PACKETS));
+ if (log)
+ log->Printf("error: failed to get packet sequence mutex, not sending packet 'qfThreadInfo'");
+#endif
+ sequence_mutex_unavailable = true;
+ }
+ return thread_ids.size();
+}
+
+lldb::addr_t
+GDBRemoteCommunicationClient::GetShlibInfoAddr()
+{
+ if (!IsRunning())
+ {
+ StringExtractorGDBRemote response;
+ if (SendPacketAndWaitForResponse("qShlibInfoAddr", ::strlen ("qShlibInfoAddr"), response, false))
+ {
+ if (response.IsNormalResponse())
+ return response.GetHexMaxU64(false, LLDB_INVALID_ADDRESS);
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
new file mode 100644
index 000000000000..5bb8387b9094
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.h
@@ -0,0 +1,430 @@
+//===-- GDBRemoteCommunicationClient.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_GDBRemoteCommunicationClient_h_
+#define liblldb_GDBRemoteCommunicationClient_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Target/Process.h"
+
+#include "GDBRemoteCommunication.h"
+
+typedef enum
+{
+ eBreakpointSoftware = 0,
+ eBreakpointHardware,
+ eWatchpointWrite,
+ eWatchpointRead,
+ eWatchpointReadWrite
+} GDBStoppointType;
+
+class GDBRemoteCommunicationClient : public GDBRemoteCommunication
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ GDBRemoteCommunicationClient(bool is_platform);
+
+ virtual
+ ~GDBRemoteCommunicationClient();
+
+ //------------------------------------------------------------------
+ // After connecting, send the handshake to the server to make sure
+ // we are communicating with it.
+ //------------------------------------------------------------------
+ bool
+ HandshakeWithServer (lldb_private::Error *error_ptr);
+
+ size_t
+ SendPacketAndWaitForResponse (const char *send_payload,
+ StringExtractorGDBRemote &response,
+ bool send_async);
+
+ size_t
+ SendPacketAndWaitForResponse (const char *send_payload,
+ size_t send_length,
+ StringExtractorGDBRemote &response,
+ bool send_async);
+
+ lldb::StateType
+ SendContinuePacketAndWaitForResponse (ProcessGDBRemote *process,
+ const char *packet_payload,
+ size_t packet_length,
+ StringExtractorGDBRemote &response);
+
+ virtual bool
+ GetThreadSuffixSupported ();
+
+ void
+ QueryNoAckModeSupported ();
+
+ void
+ GetListThreadsInStopReplySupported ();
+
+ bool
+ SendAsyncSignal (int signo);
+
+ bool
+ SendInterrupt (lldb_private::Mutex::Locker &locker,
+ uint32_t seconds_to_wait_for_stop,
+ bool &timed_out);
+
+ lldb::pid_t
+ GetCurrentProcessID ();
+
+ bool
+ GetLaunchSuccess (std::string &error_str);
+
+ uint16_t
+ LaunchGDBserverAndGetPort ();
+
+ //------------------------------------------------------------------
+ /// Sends a GDB remote protocol 'A' packet that delivers program
+ /// arguments to the remote server.
+ ///
+ /// @param[in] argv
+ /// A NULL terminated array of const C strings to use as the
+ /// arguments.
+ ///
+ /// @return
+ /// Zero if the response was "OK", a positive value if the
+ /// the response was "Exx" where xx are two hex digits, or
+ /// -1 if the call is unsupported or any other unexpected
+ /// response was received.
+ //------------------------------------------------------------------
+ int
+ SendArgumentsPacket (char const *argv[]);
+
+ //------------------------------------------------------------------
+ /// Sends a "QEnvironment:NAME=VALUE" packet that will build up the
+ /// environment that will get used when launching an application
+ /// in conjunction with the 'A' packet. This function can be called
+ /// multiple times in a row in order to pass on the desired
+ /// environment that the inferior should be launched with.
+ ///
+ /// @param[in] name_equal_value
+ /// A NULL terminated C string that contains a single environment
+ /// in the format "NAME=VALUE".
+ ///
+ /// @return
+ /// Zero if the response was "OK", a positive value if the
+ /// the response was "Exx" where xx are two hex digits, or
+ /// -1 if the call is unsupported or any other unexpected
+ /// response was received.
+ //------------------------------------------------------------------
+ int
+ SendEnvironmentPacket (char const *name_equal_value);
+
+ int
+ SendLaunchArchPacket (const char *arch);
+ //------------------------------------------------------------------
+ /// Sends a "vAttach:PID" where PID is in hex.
+ ///
+ /// @param[in] pid
+ /// A process ID for the remote gdb server to attach to.
+ ///
+ /// @param[out] response
+ /// The response received from the gdb server. If the return
+ /// value is zero, \a response will contain a stop reply
+ /// packet.
+ ///
+ /// @return
+ /// Zero if the attach was successful, or an error indicating
+ /// an error code.
+ //------------------------------------------------------------------
+ int
+ SendAttach (lldb::pid_t pid,
+ StringExtractorGDBRemote& response);
+
+
+ //------------------------------------------------------------------
+ /// Sets the path to use for stdin/out/err for a process
+ /// that will be launched with the 'A' packet.
+ ///
+ /// @param[in] path
+ /// The path to use for stdin/out/err
+ ///
+ /// @return
+ /// Zero if the for success, or an error code for failure.
+ //------------------------------------------------------------------
+ int
+ SetSTDIN (char const *path);
+ int
+ SetSTDOUT (char const *path);
+ int
+ SetSTDERR (char const *path);
+
+ //------------------------------------------------------------------
+ /// Sets the disable ASLR flag to \a enable for a process that will
+ /// be launched with the 'A' packet.
+ ///
+ /// @param[in] enable
+ /// A boolean value indicating wether to disable ASLR or not.
+ ///
+ /// @return
+ /// Zero if the for success, or an error code for failure.
+ //------------------------------------------------------------------
+ int
+ SetDisableASLR (bool enable);
+
+ //------------------------------------------------------------------
+ /// Sets the working directory to \a path for a process that will
+ /// be launched with the 'A' packet.
+ ///
+ /// @param[in] path
+ /// The path to a directory to use when launching our processs
+ ///
+ /// @return
+ /// Zero if the for success, or an error code for failure.
+ //------------------------------------------------------------------
+ int
+ SetWorkingDir (char const *path);
+
+ lldb::addr_t
+ AllocateMemory (size_t size, uint32_t permissions);
+
+ bool
+ DeallocateMemory (lldb::addr_t addr);
+
+ lldb_private::Error
+ Detach (bool keep_stopped);
+
+ lldb_private::Error
+ GetMemoryRegionInfo (lldb::addr_t addr,
+ lldb_private::MemoryRegionInfo &range_info);
+
+ lldb_private::Error
+ GetWatchpointSupportInfo (uint32_t &num);
+
+ lldb_private::Error
+ GetWatchpointSupportInfo (uint32_t &num, bool& after);
+
+ lldb_private::Error
+ GetWatchpointsTriggerAfterInstruction (bool &after);
+
+ const lldb_private::ArchSpec &
+ GetHostArchitecture ();
+
+ const lldb_private::ArchSpec &
+ GetProcessArchitecture ();
+
+ bool
+ GetVContSupported (char flavor);
+
+ bool
+ GetVAttachOrWaitSupported ();
+
+ bool
+ GetSyncThreadStateSupported();
+
+ void
+ ResetDiscoverableSettings();
+
+ bool
+ GetHostInfo (bool force = false);
+
+ bool
+ GetOSVersion (uint32_t &major,
+ uint32_t &minor,
+ uint32_t &update);
+
+ bool
+ GetOSBuildString (std::string &s);
+
+ bool
+ GetOSKernelDescription (std::string &s);
+
+ lldb_private::ArchSpec
+ GetSystemArchitecture ();
+
+ bool
+ GetHostname (std::string &s);
+
+ lldb::addr_t
+ GetShlibInfoAddr();
+
+ bool
+ GetSupportsThreadSuffix ();
+
+ bool
+ GetProcessInfo (lldb::pid_t pid,
+ lldb_private::ProcessInstanceInfo &process_info);
+
+ uint32_t
+ FindProcesses (const lldb_private::ProcessInstanceInfoMatch &process_match_info,
+ lldb_private::ProcessInstanceInfoList &process_infos);
+
+ bool
+ GetUserName (uint32_t uid, std::string &name);
+
+ bool
+ GetGroupName (uint32_t gid, std::string &name);
+
+ bool
+ HasFullVContSupport ()
+ {
+ return GetVContSupported ('A');
+ }
+
+ bool
+ HasAnyVContSupport ()
+ {
+ return GetVContSupported ('a');
+ }
+
+ bool
+ GetStopReply (StringExtractorGDBRemote &response);
+
+ bool
+ GetThreadStopInfo (lldb::tid_t tid,
+ StringExtractorGDBRemote &response);
+
+ bool
+ SupportsGDBStoppointPacket (GDBStoppointType type)
+ {
+ switch (type)
+ {
+ case eBreakpointSoftware: return m_supports_z0;
+ case eBreakpointHardware: return m_supports_z1;
+ case eWatchpointWrite: return m_supports_z2;
+ case eWatchpointRead: return m_supports_z3;
+ case eWatchpointReadWrite: return m_supports_z4;
+ }
+ return false;
+ }
+ uint8_t
+ SendGDBStoppointTypePacket (GDBStoppointType type, // Type of breakpoint or watchpoint
+ bool insert, // Insert or remove?
+ lldb::addr_t addr, // Address of breakpoint or watchpoint
+ uint32_t length); // Byte Size of breakpoint or watchpoint
+
+ void
+ TestPacketSpeed (const uint32_t num_packets);
+
+ // This packet is for testing the speed of the interface only. Both
+ // the client and server need to support it, but this allows us to
+ // measure the packet speed without any other work being done on the
+ // other end and avoids any of that work affecting the packet send
+ // and response times.
+ bool
+ SendSpeedTestPacket (uint32_t send_size,
+ uint32_t recv_size);
+
+ bool
+ SetCurrentThread (uint64_t tid);
+
+ bool
+ SetCurrentThreadForRun (uint64_t tid);
+
+ lldb_private::LazyBool
+ SupportsAllocDeallocMemory () // const
+ {
+ // Uncomment this to have lldb pretend the debug server doesn't respond to alloc/dealloc memory packets.
+ // m_supports_alloc_dealloc_memory = lldb_private::eLazyBoolNo;
+ return m_supports_alloc_dealloc_memory;
+ }
+
+ size_t
+ GetCurrentThreadIDs (std::vector<lldb::tid_t> &thread_ids,
+ bool &sequence_mutex_unavailable);
+
+ bool
+ GetInterruptWasSent () const
+ {
+ return m_interrupt_sent;
+ }
+
+ std::string
+ HarmonizeThreadIdsForProfileData (ProcessGDBRemote *process,
+ StringExtractorGDBRemote &inputStringExtractor);
+
+protected:
+
+ bool
+ GetCurrentProcessInfo ();
+
+ //------------------------------------------------------------------
+ // Classes that inherit from GDBRemoteCommunicationClient can see and modify these
+ //------------------------------------------------------------------
+ lldb_private::LazyBool m_supports_not_sending_acks;
+ lldb_private::LazyBool m_supports_thread_suffix;
+ lldb_private::LazyBool m_supports_threads_in_stop_reply;
+ lldb_private::LazyBool m_supports_vCont_all;
+ lldb_private::LazyBool m_supports_vCont_any;
+ lldb_private::LazyBool m_supports_vCont_c;
+ lldb_private::LazyBool m_supports_vCont_C;
+ lldb_private::LazyBool m_supports_vCont_s;
+ lldb_private::LazyBool m_supports_vCont_S;
+ lldb_private::LazyBool m_qHostInfo_is_valid;
+ lldb_private::LazyBool m_qProcessInfo_is_valid;
+ lldb_private::LazyBool m_supports_alloc_dealloc_memory;
+ lldb_private::LazyBool m_supports_memory_region_info;
+ lldb_private::LazyBool m_supports_watchpoint_support_info;
+ lldb_private::LazyBool m_supports_detach_stay_stopped;
+ lldb_private::LazyBool m_watchpoints_trigger_after_instruction;
+ lldb_private::LazyBool m_attach_or_wait_reply;
+ lldb_private::LazyBool m_prepare_for_reg_writing_reply;
+
+ bool
+ m_supports_qProcessInfoPID:1,
+ m_supports_qfProcessInfo:1,
+ m_supports_qUserName:1,
+ m_supports_qGroupName:1,
+ m_supports_qThreadStopInfo:1,
+ m_supports_z0:1,
+ m_supports_z1:1,
+ m_supports_z2:1,
+ m_supports_z3:1,
+ m_supports_z4:1;
+
+
+ lldb::tid_t m_curr_tid; // Current gdb remote protocol thread index for all other operations
+ lldb::tid_t m_curr_tid_run; // Current gdb remote protocol thread index for continue, step, etc
+
+
+ uint32_t m_num_supported_hardware_watchpoints;
+
+ // If we need to send a packet while the target is running, the m_async_XXX
+ // member variables take care of making this happen.
+ lldb_private::Mutex m_async_mutex;
+ lldb_private::Predicate<bool> m_async_packet_predicate;
+ std::string m_async_packet;
+ StringExtractorGDBRemote m_async_response;
+ int m_async_signal; // We were asked to deliver a signal to the inferior process.
+ bool m_interrupt_sent;
+ std::string m_partial_profile_data;
+ std::map<uint64_t, uint32_t> m_thread_id_to_used_usec_map;
+
+ lldb_private::ArchSpec m_host_arch;
+ lldb_private::ArchSpec m_process_arch;
+ uint32_t m_os_version_major;
+ uint32_t m_os_version_minor;
+ uint32_t m_os_version_update;
+ std::string m_os_build;
+ std::string m_os_kernel;
+ std::string m_hostname;
+
+ bool
+ DecodeProcessInfoResponse (StringExtractorGDBRemote &response,
+ lldb_private::ProcessInstanceInfo &process_info);
+private:
+ //------------------------------------------------------------------
+ // For GDBRemoteCommunicationClient only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationClient);
+};
+
+#endif // liblldb_GDBRemoteCommunicationClient_h_
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
new file mode 100644
index 000000000000..3a14e9fe759a
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.cpp
@@ -0,0 +1,839 @@
+//===-- GDBRemoteCommunicationServer.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "GDBRemoteCommunicationServer.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "llvm/ADT/Triple.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Host/Endian.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Target/Process.h"
+
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// GDBRemoteCommunicationServer constructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationServer::GDBRemoteCommunicationServer(bool is_platform) :
+ GDBRemoteCommunication ("gdb-remote.server", "gdb-remote.server.rx_packet", is_platform),
+ m_async_thread (LLDB_INVALID_HOST_THREAD),
+ m_process_launch_info (),
+ m_process_launch_error (),
+ m_proc_infos (),
+ m_proc_infos_index (0),
+ m_lo_port_num (0),
+ m_hi_port_num (0)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteCommunicationServer::~GDBRemoteCommunicationServer()
+{
+}
+
+
+//void *
+//GDBRemoteCommunicationServer::AsyncThread (void *arg)
+//{
+// GDBRemoteCommunicationServer *server = (GDBRemoteCommunicationServer*) arg;
+//
+// Log *log;// (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+// if (log)
+// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread starting...", __FUNCTION__, arg, process->GetID());
+//
+// StringExtractorGDBRemote packet;
+//
+// while ()
+// {
+// if (packet.
+// }
+//
+// if (log)
+// log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %i) thread exiting...", __FUNCTION__, arg, process->GetID());
+//
+// process->m_async_thread = LLDB_INVALID_HOST_THREAD;
+// return NULL;
+//}
+//
+bool
+GDBRemoteCommunicationServer::GetPacketAndSendResponse (uint32_t timeout_usec,
+ Error &error,
+ bool &interrupt,
+ bool &quit)
+{
+ StringExtractorGDBRemote packet;
+ if (WaitForPacketWithTimeoutMicroSecondsNoLock (packet, timeout_usec))
+ {
+ const StringExtractorGDBRemote::ServerPacketType packet_type = packet.GetServerPacketType ();
+ switch (packet_type)
+ {
+ case StringExtractorGDBRemote::eServerPacketType_nack:
+ case StringExtractorGDBRemote::eServerPacketType_ack:
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_invalid:
+ error.SetErrorString("invalid packet");
+ quit = true;
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_interrupt:
+ error.SetErrorString("interrupt received");
+ interrupt = true;
+ break;
+
+ case StringExtractorGDBRemote::eServerPacketType_unimplemented:
+ return SendUnimplementedResponse (packet.GetStringRef().c_str()) > 0;
+
+ case StringExtractorGDBRemote::eServerPacketType_A:
+ return Handle_A (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qfProcessInfo:
+ return Handle_qfProcessInfo (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qsProcessInfo:
+ return Handle_qsProcessInfo (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qC:
+ return Handle_qC (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qHostInfo:
+ return Handle_qHostInfo (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qLaunchGDBServer:
+ return Handle_qLaunchGDBServer (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qLaunchSuccess:
+ return Handle_qLaunchSuccess (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qGroupName:
+ return Handle_qGroupName (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qProcessInfoPID:
+ return Handle_qProcessInfoPID (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qSpeedTest:
+ return Handle_qSpeedTest (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_qUserName:
+ return Handle_qUserName (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QEnvironment:
+ return Handle_QEnvironment (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QSetDisableASLR:
+ return Handle_QSetDisableASLR (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QSetSTDIN:
+ return Handle_QSetSTDIN (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QSetSTDOUT:
+ return Handle_QSetSTDOUT (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QSetSTDERR:
+ return Handle_QSetSTDERR (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QSetWorkingDir:
+ return Handle_QSetWorkingDir (packet);
+
+ case StringExtractorGDBRemote::eServerPacketType_QStartNoAckMode:
+ return Handle_QStartNoAckMode (packet);
+ }
+ return true;
+ }
+ else
+ {
+ if (!IsConnected())
+ error.SetErrorString("lost connection");
+ else
+ error.SetErrorString("timeout");
+ }
+
+ return false;
+}
+
+size_t
+GDBRemoteCommunicationServer::SendUnimplementedResponse (const char *)
+{
+ // TODO: Log the packet we aren't handling...
+ return SendPacketNoLock ("", 0);
+}
+
+size_t
+GDBRemoteCommunicationServer::SendErrorResponse (uint8_t err)
+{
+ char packet[16];
+ int packet_len = ::snprintf (packet, sizeof(packet), "E%2.2x", err);
+ assert (packet_len < (int)sizeof(packet));
+ return SendPacketNoLock (packet, packet_len);
+}
+
+
+size_t
+GDBRemoteCommunicationServer::SendOKResponse ()
+{
+ return SendPacketNoLock ("OK", 2);
+}
+
+bool
+GDBRemoteCommunicationServer::HandshakeWithClient(Error *error_ptr)
+{
+ return GetAck();
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qHostInfo (StringExtractorGDBRemote &packet)
+{
+ StreamString response;
+
+ // $cputype:16777223;cpusubtype:3;ostype:Darwin;vendor:apple;endian:little;ptrsize:8;#00
+
+ ArchSpec host_arch (Host::GetArchitecture ());
+ const llvm::Triple &host_triple = host_arch.GetTriple();
+ response.PutCString("triple:");
+ response.PutCStringAsRawHex8(host_triple.getTriple().c_str());
+ response.Printf (";ptrsize:%u;",host_arch.GetAddressByteSize());
+
+ uint32_t cpu = host_arch.GetMachOCPUType();
+ uint32_t sub = host_arch.GetMachOCPUSubType();
+ if (cpu != LLDB_INVALID_CPUTYPE)
+ response.Printf ("cputype:%u;", cpu);
+ if (sub != LLDB_INVALID_CPUTYPE)
+ response.Printf ("cpusubtype:%u;", sub);
+
+ if (cpu == ArchSpec::kCore_arm_any)
+ response.Printf("watchpoint_exceptions_received:before;"); // On armv7 we use "synchronous" watchpoints which means the exception is delivered before the instruction executes.
+ else
+ response.Printf("watchpoint_exceptions_received:after;");
+
+ switch (lldb::endian::InlHostByteOrder())
+ {
+ case eByteOrderBig: response.PutCString ("endian:big;"); break;
+ case eByteOrderLittle: response.PutCString ("endian:little;"); break;
+ case eByteOrderPDP: response.PutCString ("endian:pdp;"); break;
+ default: response.PutCString ("endian:unknown;"); break;
+ }
+
+ uint32_t major = UINT32_MAX;
+ uint32_t minor = UINT32_MAX;
+ uint32_t update = UINT32_MAX;
+ if (Host::GetOSVersion (major, minor, update))
+ {
+ if (major != UINT32_MAX)
+ {
+ response.Printf("os_version:%u", major);
+ if (minor != UINT32_MAX)
+ {
+ response.Printf(".%u", minor);
+ if (update != UINT32_MAX)
+ response.Printf(".%u", update);
+ }
+ response.PutChar(';');
+ }
+ }
+
+ std::string s;
+ if (Host::GetOSBuildString (s))
+ {
+ response.PutCString ("os_build:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+ if (Host::GetOSKernelDescription (s))
+ {
+ response.PutCString ("os_kernel:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+ if (Host::GetHostname (s))
+ {
+ response.PutCString ("hostname:");
+ response.PutCStringAsRawHex8(s.c_str());
+ response.PutChar(';');
+ }
+
+ return SendPacketNoLock (response.GetData(), response.GetSize()) > 0;
+}
+
+static void
+CreateProcessInfoResponse (const ProcessInstanceInfo &proc_info, StreamString &response)
+{
+ response.Printf ("pid:%" PRIu64 ";ppid:%" PRIu64 ";uid:%i;gid:%i;euid:%i;egid:%i;",
+ proc_info.GetProcessID(),
+ proc_info.GetParentProcessID(),
+ proc_info.GetUserID(),
+ proc_info.GetGroupID(),
+ proc_info.GetEffectiveUserID(),
+ proc_info.GetEffectiveGroupID());
+ response.PutCString ("name:");
+ response.PutCStringAsRawHex8(proc_info.GetName());
+ response.PutChar(';');
+ const ArchSpec &proc_arch = proc_info.GetArchitecture();
+ if (proc_arch.IsValid())
+ {
+ const llvm::Triple &proc_triple = proc_arch.GetTriple();
+ response.PutCString("triple:");
+ response.PutCStringAsRawHex8(proc_triple.getTriple().c_str());
+ response.PutChar(';');
+ }
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qProcessInfoPID (StringExtractorGDBRemote &packet)
+{
+ // Packet format: "qProcessInfoPID:%i" where %i is the pid
+ packet.SetFilePos(::strlen ("qProcessInfoPID:"));
+ lldb::pid_t pid = packet.GetU32 (LLDB_INVALID_PROCESS_ID);
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ ProcessInstanceInfo proc_info;
+ if (Host::GetProcessInfo(pid, proc_info))
+ {
+ StreamString response;
+ CreateProcessInfoResponse (proc_info, response);
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse (1);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qfProcessInfo (StringExtractorGDBRemote &packet)
+{
+ m_proc_infos_index = 0;
+ m_proc_infos.Clear();
+
+ ProcessInstanceInfoMatch match_info;
+ packet.SetFilePos(::strlen ("qfProcessInfo"));
+ if (packet.GetChar() == ':')
+ {
+
+ std::string key;
+ std::string value;
+ while (packet.GetNameColonValue(key, value))
+ {
+ bool success = true;
+ if (key.compare("name") == 0)
+ {
+ StringExtractor extractor;
+ extractor.GetStringRef().swap(value);
+ extractor.GetHexByteString (value);
+ match_info.GetProcessInfo().GetExecutableFile().SetFile(value.c_str(), false);
+ }
+ else if (key.compare("name_match") == 0)
+ {
+ if (value.compare("equals") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchEquals);
+ }
+ else if (value.compare("starts_with") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchStartsWith);
+ }
+ else if (value.compare("ends_with") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchEndsWith);
+ }
+ else if (value.compare("contains") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchContains);
+ }
+ else if (value.compare("regex") == 0)
+ {
+ match_info.SetNameMatchType (eNameMatchRegularExpression);
+ }
+ else
+ {
+ success = false;
+ }
+ }
+ else if (key.compare("pid") == 0)
+ {
+ match_info.GetProcessInfo().SetProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
+ }
+ else if (key.compare("parent_pid") == 0)
+ {
+ match_info.GetProcessInfo().SetParentProcessID (Args::StringToUInt32(value.c_str(), LLDB_INVALID_PROCESS_ID, 0, &success));
+ }
+ else if (key.compare("uid") == 0)
+ {
+ match_info.GetProcessInfo().SetUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("gid") == 0)
+ {
+ match_info.GetProcessInfo().SetGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("euid") == 0)
+ {
+ match_info.GetProcessInfo().SetEffectiveUserID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("egid") == 0)
+ {
+ match_info.GetProcessInfo().SetEffectiveGroupID (Args::StringToUInt32(value.c_str(), UINT32_MAX, 0, &success));
+ }
+ else if (key.compare("all_users") == 0)
+ {
+ match_info.SetMatchAllUsers(Args::StringToBoolean(value.c_str(), false, &success));
+ }
+ else if (key.compare("triple") == 0)
+ {
+ match_info.GetProcessInfo().GetArchitecture().SetTriple (value.c_str(), NULL);
+ }
+ else
+ {
+ success = false;
+ }
+
+ if (!success)
+ return SendErrorResponse (2);
+ }
+ }
+
+ if (Host::FindProcesses (match_info, m_proc_infos))
+ {
+ // We found something, return the first item by calling the get
+ // subsequent process info packet handler...
+ return Handle_qsProcessInfo (packet);
+ }
+ return SendErrorResponse (3);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qsProcessInfo (StringExtractorGDBRemote &packet)
+{
+ if (m_proc_infos_index < m_proc_infos.GetSize())
+ {
+ StreamString response;
+ CreateProcessInfoResponse (m_proc_infos.GetProcessInfoAtIndex(m_proc_infos_index), response);
+ ++m_proc_infos_index;
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ return SendErrorResponse (4);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qUserName (StringExtractorGDBRemote &packet)
+{
+ // Packet format: "qUserName:%i" where %i is the uid
+ packet.SetFilePos(::strlen ("qUserName:"));
+ uint32_t uid = packet.GetU32 (UINT32_MAX);
+ if (uid != UINT32_MAX)
+ {
+ std::string name;
+ if (Host::GetUserName (uid, name))
+ {
+ StreamString response;
+ response.PutCStringAsRawHex8 (name.c_str());
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse (5);
+
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qGroupName (StringExtractorGDBRemote &packet)
+{
+ // Packet format: "qGroupName:%i" where %i is the gid
+ packet.SetFilePos(::strlen ("qGroupName:"));
+ uint32_t gid = packet.GetU32 (UINT32_MAX);
+ if (gid != UINT32_MAX)
+ {
+ std::string name;
+ if (Host::GetGroupName (gid, name))
+ {
+ StreamString response;
+ response.PutCStringAsRawHex8 (name.c_str());
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse (6);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qSpeedTest (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("qSpeedTest:"));
+
+ std::string key;
+ std::string value;
+ bool success = packet.GetNameColonValue(key, value);
+ if (success && key.compare("response_size") == 0)
+ {
+ uint32_t response_size = Args::StringToUInt32(value.c_str(), 0, 0, &success);
+ if (success)
+ {
+ if (response_size == 0)
+ return SendOKResponse();
+ StreamString response;
+ uint32_t bytes_left = response_size;
+ response.PutCString("data:");
+ while (bytes_left > 0)
+ {
+ if (bytes_left >= 26)
+ {
+ response.PutCString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ bytes_left -= 26;
+ }
+ else
+ {
+ response.Printf ("%*.*s;", bytes_left, bytes_left, "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ bytes_left = 0;
+ }
+ }
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+ }
+ }
+ return SendErrorResponse (7);
+}
+
+
+static void *
+AcceptPortFromInferior (void *arg)
+{
+ const char *connect_url = (const char *)arg;
+ ConnectionFileDescriptor file_conn;
+ Error error;
+ if (file_conn.Connect (connect_url, &error) == eConnectionStatusSuccess)
+ {
+ char pid_str[256];
+ ::memset (pid_str, 0, sizeof(pid_str));
+ ConnectionStatus status;
+ const size_t pid_str_len = file_conn.Read (pid_str, sizeof(pid_str), 0, status, NULL);
+ if (pid_str_len > 0)
+ {
+ int pid = atoi (pid_str);
+ return (void *)(intptr_t)pid;
+ }
+ }
+ return NULL;
+}
+//
+//static bool
+//WaitForProcessToSIGSTOP (const lldb::pid_t pid, const int timeout_in_seconds)
+//{
+// const int time_delta_usecs = 100000;
+// const int num_retries = timeout_in_seconds/time_delta_usecs;
+// for (int i=0; i<num_retries; i++)
+// {
+// struct proc_bsdinfo bsd_info;
+// int error = ::proc_pidinfo (pid, PROC_PIDTBSDINFO,
+// (uint64_t) 0,
+// &bsd_info,
+// PROC_PIDTBSDINFO_SIZE);
+//
+// switch (error)
+// {
+// case EINVAL:
+// case ENOTSUP:
+// case ESRCH:
+// case EPERM:
+// return false;
+//
+// default:
+// break;
+//
+// case 0:
+// if (bsd_info.pbi_status == SSTOP)
+// return true;
+// }
+// ::usleep (time_delta_usecs);
+// }
+// return false;
+//}
+
+bool
+GDBRemoteCommunicationServer::Handle_A (StringExtractorGDBRemote &packet)
+{
+ // The 'A' packet is the most over designed packet ever here with
+ // redundant argument indexes, redundant argument lengths and needed hex
+ // encoded argument string values. Really all that is needed is a comma
+ // separated hex encoded argument value list, but we will stay true to the
+ // documented version of the 'A' packet here...
+
+ packet.SetFilePos(1); // Skip the 'A'
+ bool success = true;
+ while (success && packet.GetBytesLeft() > 0)
+ {
+ // Decode the decimal argument string length. This length is the
+ // number of hex nibbles in the argument string value.
+ const uint32_t arg_len = packet.GetU32(UINT32_MAX);
+ if (arg_len == UINT32_MAX)
+ success = false;
+ else
+ {
+ // Make sure the argument hex string length is followed by a comma
+ if (packet.GetChar() != ',')
+ success = false;
+ else
+ {
+ // Decode the argument index. We ignore this really becuase
+ // who would really send down the arguments in a random order???
+ const uint32_t arg_idx = packet.GetU32(UINT32_MAX);
+ if (arg_idx == UINT32_MAX)
+ success = false;
+ else
+ {
+ // Make sure the argument index is followed by a comma
+ if (packet.GetChar() != ',')
+ success = false;
+ else
+ {
+ // Decode the argument string value from hex bytes
+ // back into a UTF8 string and make sure the length
+ // matches the one supplied in the packet
+ std::string arg;
+ if (packet.GetHexByteString(arg) != (arg_len / 2))
+ success = false;
+ else
+ {
+ // If there are any bytes lft
+ if (packet.GetBytesLeft())
+ {
+ if (packet.GetChar() != ',')
+ success = false;
+ }
+
+ if (success)
+ {
+ if (arg_idx == 0)
+ m_process_launch_info.GetExecutableFile().SetFile(arg.c_str(), false);
+ m_process_launch_info.GetArguments().AppendArgument(arg.c_str());
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (success)
+ {
+ m_process_launch_info.GetFlags().Set (eLaunchFlagDebug);
+ m_process_launch_error = Host::LaunchProcess (m_process_launch_info);
+ if (m_process_launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
+ {
+ return SendOKResponse ();
+ }
+ }
+ return SendErrorResponse (8);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qC (StringExtractorGDBRemote &packet)
+{
+ lldb::pid_t pid = m_process_launch_info.GetProcessID();
+ StreamString response;
+ response.Printf("QC%" PRIx64, pid);
+ if (m_is_platform)
+ {
+ // If we launch a process and this GDB server is acting as a platform,
+ // then we need to clear the process launch state so we can start
+ // launching another process. In order to launch a process a bunch or
+ // packets need to be sent: environment packets, working directory,
+ // disable ASLR, and many more settings. When we launch a process we
+ // then need to know when to clear this information. Currently we are
+ // selecting the 'qC' packet as that packet which seems to make the most
+ // sense.
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ {
+ m_process_launch_info.Clear();
+ }
+ }
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet)
+{
+ // Spawn a local debugserver as a platform so we can then attach or launch
+ // a process...
+
+ if (m_is_platform)
+ {
+ // Sleep and wait a bit for debugserver to start to listen...
+ ConnectionFileDescriptor file_conn;
+ char connect_url[PATH_MAX];
+ Error error;
+ char unix_socket_name[PATH_MAX] = "/tmp/XXXXXX";
+ if (::mktemp (unix_socket_name) == NULL)
+ {
+ error.SetErrorString ("failed to make temporary path for a unix socket");
+ }
+ else
+ {
+ ::snprintf (connect_url, sizeof(connect_url), "unix-accept://%s", unix_socket_name);
+ // Spawn a new thread to accept the port that gets bound after
+ // binding to port 0 (zero).
+ lldb::thread_t accept_thread = Host::ThreadCreate (unix_socket_name,
+ AcceptPortFromInferior,
+ connect_url,
+ &error);
+
+ if (IS_VALID_LLDB_HOST_THREAD(accept_thread))
+ {
+ // Spawn a debugserver and try to get
+ ProcessLaunchInfo debugserver_launch_info;
+ error = StartDebugserverProcess ("localhost:0",
+ unix_socket_name,
+ debugserver_launch_info);
+
+ lldb::pid_t debugserver_pid = debugserver_launch_info.GetProcessID();
+ if (error.Success())
+ {
+ bool success = false;
+
+ thread_result_t accept_thread_result = NULL;
+ if (Host::ThreadJoin (accept_thread, &accept_thread_result, &error))
+ {
+ if (accept_thread_result)
+ {
+ uint16_t port = (intptr_t)accept_thread_result;
+ char response[256];
+ const int response_len = ::snprintf (response, sizeof(response), "pid:%" PRIu64 ";port:%u;", debugserver_pid, port);
+ assert (response_len < (int)sizeof(response));
+ //m_port_to_pid_map[port] = debugserver_launch_info.GetProcessID();
+ success = SendPacketNoLock (response, response_len) > 0;
+ }
+ }
+ ::unlink (unix_socket_name);
+
+ if (!success)
+ {
+ if (debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ ::kill (debugserver_pid, SIGINT);
+ }
+ return success;
+ }
+ }
+ }
+ }
+ return SendErrorResponse (13);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_qLaunchSuccess (StringExtractorGDBRemote &packet)
+{
+ if (m_process_launch_error.Success())
+ return SendOKResponse();
+ StreamString response;
+ response.PutChar('E');
+ response.PutCString(m_process_launch_error.AsCString("<unknown error>"));
+ return SendPacketNoLock (response.GetData(), response.GetSize());
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QEnvironment (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QEnvironment:"));
+ const uint32_t bytes_left = packet.GetBytesLeft();
+ if (bytes_left > 0)
+ {
+ m_process_launch_info.GetEnvironmentEntries ().AppendArgument (packet.Peek());
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (9);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QSetDisableASLR (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetDisableASLR:"));
+ if (packet.GetU32(0))
+ m_process_launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
+ else
+ m_process_launch_info.GetFlags().Clear (eLaunchFlagDisableASLR);
+ return SendOKResponse ();
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QSetWorkingDir (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetWorkingDir:"));
+ std::string path;
+ packet.GetHexByteString(path);
+ m_process_launch_info.SwapWorkingDirectory (path);
+ return SendOKResponse ();
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QSetSTDIN (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDIN:"));
+ ProcessLaunchInfo::FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = false;
+ const bool write = true;
+ if (file_action.Open(STDIN_FILENO, path.c_str(), read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (10);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QSetSTDOUT (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDOUT:"));
+ ProcessLaunchInfo::FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = true;
+ const bool write = false;
+ if (file_action.Open(STDOUT_FILENO, path.c_str(), read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (11);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QSetSTDERR (StringExtractorGDBRemote &packet)
+{
+ packet.SetFilePos(::strlen ("QSetSTDERR:"));
+ ProcessLaunchInfo::FileAction file_action;
+ std::string path;
+ packet.GetHexByteString(path);
+ const bool read = true;
+ const bool write = false;
+ if (file_action.Open(STDERR_FILENO, path.c_str(), read, write))
+ {
+ m_process_launch_info.AppendFileAction(file_action);
+ return SendOKResponse ();
+ }
+ return SendErrorResponse (12);
+}
+
+bool
+GDBRemoteCommunicationServer::Handle_QStartNoAckMode (StringExtractorGDBRemote &packet)
+{
+ // Send response first before changing m_send_acks to we ack this packet
+ SendOKResponse ();
+ m_send_acks = false;
+ return true;
+}
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
new file mode 100644
index 000000000000..cce0e4e64c1e
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServer.h
@@ -0,0 +1,147 @@
+//===-- GDBRemoteCommunicationServer.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_GDBRemoteCommunicationServer_h_
+#define liblldb_GDBRemoteCommunicationServer_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Target/Process.h"
+
+#include "GDBRemoteCommunication.h"
+
+class ProcessGDBRemote;
+class StringExtractorGDBRemote;
+
+class GDBRemoteCommunicationServer : public GDBRemoteCommunication
+{
+public:
+ enum
+ {
+ eBroadcastBitRunPacketSent = kLoUserBroadcastBit
+ };
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ GDBRemoteCommunicationServer(bool is_platform);
+
+ virtual
+ ~GDBRemoteCommunicationServer();
+
+ bool
+ GetPacketAndSendResponse (uint32_t timeout_usec,
+ lldb_private::Error &error,
+ bool &interrupt,
+ bool &quit);
+
+ virtual bool
+ GetThreadSuffixSupported ()
+ {
+ return true;
+ }
+
+ // After connecting, do a little handshake with the client to make sure
+ // we are at least communicating
+ bool
+ HandshakeWithClient (lldb_private::Error *error_ptr);
+
+ // Set both ports to zero to let the platform automatically bind to
+ // a port chosen by the OS.
+ void
+ SetPortRange (uint16_t lo_port_num, uint16_t hi_port_num)
+ {
+ m_lo_port_num = lo_port_num;
+ m_hi_port_num = hi_port_num;
+ }
+
+protected:
+ //typedef std::map<uint16_t, lldb::pid_t> PortToPIDMap;
+
+ lldb::thread_t m_async_thread;
+ lldb_private::ProcessLaunchInfo m_process_launch_info;
+ lldb_private::Error m_process_launch_error;
+ lldb_private::ProcessInstanceInfoList m_proc_infos;
+ uint32_t m_proc_infos_index;
+ uint16_t m_lo_port_num;
+ uint16_t m_hi_port_num;
+ //PortToPIDMap m_port_to_pid_map;
+
+ size_t
+ SendUnimplementedResponse (const char *packet);
+
+ size_t
+ SendErrorResponse (uint8_t error);
+
+ size_t
+ SendOKResponse ();
+
+ bool
+ Handle_A (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qLaunchSuccess (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qHostInfo (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qLaunchGDBServer (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qProcessInfoPID (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qfProcessInfo (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qsProcessInfo (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qC (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qUserName (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qGroupName (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_qSpeedTest (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_QEnvironment (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_QSetDisableASLR (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_QSetWorkingDir (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_QStartNoAckMode (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_QSetSTDIN (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_QSetSTDOUT (StringExtractorGDBRemote &packet);
+
+ bool
+ Handle_QSetSTDERR (StringExtractorGDBRemote &packet);
+
+private:
+ //------------------------------------------------------------------
+ // For GDBRemoteCommunicationServer only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteCommunicationServer);
+};
+
+#endif // liblldb_GDBRemoteCommunicationServer_h_
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
new file mode 100644
index 000000000000..b1612a5f3c2f
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.cpp
@@ -0,0 +1,971 @@
+//===-- GDBRemoteRegisterContext.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "GDBRemoteRegisterContext.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Utility/Utils.h"
+// Project includes
+#include "Utility/StringExtractorGDBRemote.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "ThreadGDBRemote.h"
+#include "Utility/ARM_GCC_Registers.h"
+#include "Utility/ARM_DWARF_Registers.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// GDBRemoteRegisterContext constructor
+//----------------------------------------------------------------------
+GDBRemoteRegisterContext::GDBRemoteRegisterContext
+(
+ ThreadGDBRemote &thread,
+ uint32_t concrete_frame_idx,
+ GDBRemoteDynamicRegisterInfo &reg_info,
+ bool read_all_at_once
+) :
+ RegisterContext (thread, concrete_frame_idx),
+ m_reg_info (reg_info),
+ m_reg_valid (),
+ m_reg_data (),
+ m_read_all_at_once (read_all_at_once)
+{
+ // Resize our vector of bools to contain one bool for every register.
+ // We will use these boolean values to know when a register value
+ // is valid in m_reg_data.
+ m_reg_valid.resize (reg_info.GetNumRegisters());
+
+ // Make a heap based buffer that is big enough to store all registers
+ DataBufferSP reg_data_sp(new DataBufferHeap (reg_info.GetRegisterDataByteSize(), 0));
+ m_reg_data.SetData (reg_data_sp);
+
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+GDBRemoteRegisterContext::~GDBRemoteRegisterContext()
+{
+}
+
+void
+GDBRemoteRegisterContext::InvalidateAllRegisters ()
+{
+ SetAllRegisterValid (false);
+}
+
+void
+GDBRemoteRegisterContext::SetAllRegisterValid (bool b)
+{
+ std::vector<bool>::iterator pos, end = m_reg_valid.end();
+ for (pos = m_reg_valid.begin(); pos != end; ++pos)
+ *pos = b;
+}
+
+size_t
+GDBRemoteRegisterContext::GetRegisterCount ()
+{
+ return m_reg_info.GetNumRegisters ();
+}
+
+const RegisterInfo *
+GDBRemoteRegisterContext::GetRegisterInfoAtIndex (size_t reg)
+{
+ return m_reg_info.GetRegisterInfoAtIndex (reg);
+}
+
+size_t
+GDBRemoteRegisterContext::GetRegisterSetCount ()
+{
+ return m_reg_info.GetNumRegisterSets ();
+}
+
+
+
+const RegisterSet *
+GDBRemoteRegisterContext::GetRegisterSet (size_t reg_set)
+{
+ return m_reg_info.GetRegisterSet (reg_set);
+}
+
+
+
+bool
+GDBRemoteRegisterContext::ReadRegister (const RegisterInfo *reg_info, RegisterValue &value)
+{
+ // Read the register
+ if (ReadRegisterBytes (reg_info, m_reg_data))
+ {
+ const bool partial_data_ok = false;
+ Error error (value.SetValueFromData(reg_info, m_reg_data, reg_info->byte_offset, partial_data_ok));
+ return error.Success();
+ }
+ return false;
+}
+
+bool
+GDBRemoteRegisterContext::PrivateSetRegisterValue (uint32_t reg, StringExtractor &response)
+{
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg);
+ if (reg_info == NULL)
+ return false;
+
+ // Invalidate if needed
+ InvalidateIfNeeded(false);
+
+ const uint32_t reg_byte_size = reg_info->byte_size;
+ const size_t bytes_copied = response.GetHexBytes (const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_byte_size)), reg_byte_size, '\xcc');
+ bool success = bytes_copied == reg_byte_size;
+ if (success)
+ {
+ SetRegisterIsValid(reg, true);
+ }
+ else if (bytes_copied > 0)
+ {
+ // Only set register is valid to false if we copied some bytes, else
+ // leave it as it was.
+ SetRegisterIsValid(reg, false);
+ }
+ return success;
+}
+
+// Helper function for GDBRemoteRegisterContext::ReadRegisterBytes().
+bool
+GDBRemoteRegisterContext::GetPrimordialRegister(const lldb_private::RegisterInfo *reg_info,
+ GDBRemoteCommunicationClient &gdb_comm)
+{
+ char packet[64];
+ StringExtractorGDBRemote response;
+ int packet_len = 0;
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ if (gdb_comm.GetThreadSuffixSupported())
+ packet_len = ::snprintf (packet, sizeof(packet), "p%x;thread:%4.4" PRIx64 ";", reg, m_thread.GetProtocolID());
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "p%x", reg);
+ assert (packet_len < ((int)sizeof(packet) - 1));
+ if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false))
+ return PrivateSetRegisterValue (reg, response);
+
+ return false;
+}
+bool
+GDBRemoteRegisterContext::ReadRegisterBytes (const RegisterInfo *reg_info, DataExtractor &data)
+{
+ ExecutionContext exe_ctx (CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == NULL || thread == NULL)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ InvalidateIfNeeded(false);
+
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ if (!GetRegisterIsValid(reg))
+ {
+ Mutex::Locker locker;
+ if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read register."))
+ {
+ const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID()))
+ {
+ char packet[64];
+ StringExtractorGDBRemote response;
+ int packet_len = 0;
+ if (m_read_all_at_once)
+ {
+ // Get all registers in one packet
+ if (thread_suffix_supported)
+ packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "g");
+ assert (packet_len < ((int)sizeof(packet) - 1));
+ if (gdb_comm.SendPacketAndWaitForResponse(packet, response, false))
+ {
+ if (response.IsNormalResponse())
+ if (response.GetHexBytes ((void *)m_reg_data.GetDataStart(), m_reg_data.GetByteSize(), '\xcc') == m_reg_data.GetByteSize())
+ SetAllRegisterValid (true);
+ }
+ }
+ else if (reg_info->value_regs)
+ {
+ // Process this composite register request by delegating to the constituent
+ // primordial registers.
+
+ // Index of the primordial register.
+ bool success = true;
+ for (uint32_t idx = 0; success; ++idx)
+ {
+ const uint32_t prim_reg = reg_info->value_regs[idx];
+ if (prim_reg == LLDB_INVALID_REGNUM)
+ break;
+ // We have a valid primordial regsiter as our constituent.
+ // Grab the corresponding register info.
+ const RegisterInfo *prim_reg_info = GetRegisterInfoAtIndex(prim_reg);
+ if (prim_reg_info == NULL)
+ success = false;
+ else
+ {
+ // Read the containing register if it hasn't already been read
+ if (!GetRegisterIsValid(prim_reg))
+ success = GetPrimordialRegister(prim_reg_info, gdb_comm);
+ }
+ }
+
+ if (success)
+ {
+ // If we reach this point, all primordial register requests have succeeded.
+ // Validate this composite register.
+ SetRegisterIsValid (reg_info, true);
+ }
+ }
+ else
+ {
+ // Get each register individually
+ GetPrimordialRegister(reg_info, gdb_comm);
+ }
+ }
+ }
+ else
+ {
+#if LLDB_CONFIGURATION_DEBUG
+ StreamString strm;
+ gdb_comm.DumpHistory(strm);
+ Host::SetCrashDescription (strm.GetData());
+ assert (!"Didn't get sequence mutex for read register.");
+#else
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
+ if (log)
+ {
+ if (log->GetVerbose())
+ {
+ StreamString strm;
+ gdb_comm.DumpHistory(strm);
+ log->Printf("error: failed to get packet sequence mutex, not sending read register for \"%s\":\n%s", reg_info->name, strm.GetData());
+ }
+ else
+ {
+ log->Printf("error: failed to get packet sequence mutex, not sending read register for \"%s\"", reg_info->name);
+ }
+ }
+#endif
+ }
+
+ // Make sure we got a valid register value after reading it
+ if (!GetRegisterIsValid(reg))
+ return false;
+ }
+
+ if (&data != &m_reg_data)
+ {
+ // If we aren't extracting into our own buffer (which
+ // only happens when this function is called from
+ // ReadRegisterValue(uint32_t, Scalar&)) then
+ // we transfer bytes from our buffer into the data
+ // buffer that was passed in
+ data.SetByteOrder (m_reg_data.GetByteOrder());
+ data.SetData (m_reg_data, reg_info->byte_offset, reg_info->byte_size);
+ }
+ return true;
+}
+
+bool
+GDBRemoteRegisterContext::WriteRegister (const RegisterInfo *reg_info,
+ const RegisterValue &value)
+{
+ DataExtractor data;
+ if (value.GetData (data))
+ return WriteRegisterBytes (reg_info, data, 0);
+ return false;
+}
+
+// Helper function for GDBRemoteRegisterContext::WriteRegisterBytes().
+bool
+GDBRemoteRegisterContext::SetPrimordialRegister(const lldb_private::RegisterInfo *reg_info,
+ GDBRemoteCommunicationClient &gdb_comm)
+{
+ StreamString packet;
+ StringExtractorGDBRemote response;
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+ packet.Printf ("P%x=", reg);
+ packet.PutBytesAsRawHex8 (m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size),
+ reg_info->byte_size,
+ lldb::endian::InlHostByteOrder(),
+ lldb::endian::InlHostByteOrder());
+
+ if (gdb_comm.GetThreadSuffixSupported())
+ packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+
+ // Invalidate just this register
+ SetRegisterIsValid(reg, false);
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ false))
+ {
+ if (response.IsOKResponse())
+ return true;
+ }
+ return false;
+}
+
+void
+GDBRemoteRegisterContext::SyncThreadState(Process *process)
+{
+ // NB. We assume our caller has locked the sequence mutex.
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *) process)->GetGDBRemote());
+ if (!gdb_comm.GetSyncThreadStateSupported())
+ return;
+
+ StreamString packet;
+ StringExtractorGDBRemote response;
+ packet.Printf ("QSyncThreadState:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ false))
+ {
+ if (response.IsOKResponse())
+ InvalidateAllRegisters();
+ }
+}
+
+bool
+GDBRemoteRegisterContext::WriteRegisterBytes (const lldb_private::RegisterInfo *reg_info, DataExtractor &data, uint32_t data_offset)
+{
+ ExecutionContext exe_ctx (CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == NULL || thread == NULL)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+// FIXME: This check isn't right because IsRunning checks the Public state, but this
+// is work you need to do - for instance in ShouldStop & friends - before the public
+// state has been changed.
+// if (gdb_comm.IsRunning())
+// return false;
+
+ // Grab a pointer to where we are going to put this register
+ uint8_t *dst = const_cast<uint8_t*>(m_reg_data.PeekData(reg_info->byte_offset, reg_info->byte_size));
+
+ if (dst == NULL)
+ return false;
+
+
+ if (data.CopyByteOrderedData (data_offset, // src offset
+ reg_info->byte_size, // src length
+ dst, // dst
+ reg_info->byte_size, // dst length
+ m_reg_data.GetByteOrder())) // dst byte order
+ {
+ Mutex::Locker locker;
+ if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write register."))
+ {
+ const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID()))
+ {
+ StreamString packet;
+ StringExtractorGDBRemote response;
+
+ if (m_read_all_at_once)
+ {
+ // Set all registers in one packet
+ packet.PutChar ('G');
+ packet.PutBytesAsRawHex8 (m_reg_data.GetDataStart(),
+ m_reg_data.GetByteSize(),
+ lldb::endian::InlHostByteOrder(),
+ lldb::endian::InlHostByteOrder());
+
+ if (thread_suffix_supported)
+ packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+
+ // Invalidate all register values
+ InvalidateIfNeeded (true);
+
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ false))
+ {
+ SetAllRegisterValid (false);
+ if (response.IsOKResponse())
+ {
+ return true;
+ }
+ }
+ }
+ else
+ {
+ bool success = true;
+
+ if (reg_info->value_regs)
+ {
+ // This register is part of another register. In this case we read the actual
+ // register data for any "value_regs", and once all that data is read, we will
+ // have enough data in our register context bytes for the value of this register
+
+ // Invalidate this composite register first.
+
+ for (uint32_t idx = 0; success; ++idx)
+ {
+ const uint32_t reg = reg_info->value_regs[idx];
+ if (reg == LLDB_INVALID_REGNUM)
+ break;
+ // We have a valid primordial regsiter as our constituent.
+ // Grab the corresponding register info.
+ const RegisterInfo *value_reg_info = GetRegisterInfoAtIndex(reg);
+ if (value_reg_info == NULL)
+ success = false;
+ else
+ success = SetPrimordialRegister(value_reg_info, gdb_comm);
+ }
+ }
+ else
+ {
+ // This is an actual register, write it
+ success = SetPrimordialRegister(reg_info, gdb_comm);
+ }
+
+ // Check if writing this register will invalidate any other register values?
+ // If so, invalidate them
+ if (reg_info->invalidate_regs)
+ {
+ for (uint32_t idx = 0, reg = reg_info->invalidate_regs[0];
+ reg != LLDB_INVALID_REGNUM;
+ reg = reg_info->invalidate_regs[++idx])
+ {
+ SetRegisterIsValid(reg, false);
+ }
+ }
+
+ return success;
+ }
+ }
+ }
+ else
+ {
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
+ if (log)
+ {
+ if (log->GetVerbose())
+ {
+ StreamString strm;
+ gdb_comm.DumpHistory(strm);
+ log->Printf("error: failed to get packet sequence mutex, not sending write register for \"%s\":\n%s", reg_info->name, strm.GetData());
+ }
+ else
+ log->Printf("error: failed to get packet sequence mutex, not sending write register for \"%s\"", reg_info->name);
+ }
+ }
+ }
+ return false;
+}
+
+
+bool
+GDBRemoteRegisterContext::ReadAllRegisterValues (lldb::DataBufferSP &data_sp)
+{
+ ExecutionContext exe_ctx (CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == NULL || thread == NULL)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ StringExtractorGDBRemote response;
+
+ Mutex::Locker locker;
+ if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for read all registers."))
+ {
+ SyncThreadState(process);
+
+ char packet[32];
+ const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID()))
+ {
+ int packet_len = 0;
+ if (thread_suffix_supported)
+ packet_len = ::snprintf (packet, sizeof(packet), "g;thread:%4.4" PRIx64, m_thread.GetProtocolID());
+ else
+ packet_len = ::snprintf (packet, sizeof(packet), "g");
+ assert (packet_len < ((int)sizeof(packet) - 1));
+
+ if (gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ if (response.IsErrorResponse())
+ return false;
+
+ std::string &response_str = response.GetStringRef();
+ if (isxdigit(response_str[0]))
+ {
+ response_str.insert(0, 1, 'G');
+ if (thread_suffix_supported)
+ {
+ char thread_id_cstr[64];
+ ::snprintf (thread_id_cstr, sizeof(thread_id_cstr), ";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+ response_str.append (thread_id_cstr);
+ }
+ data_sp.reset (new DataBufferHeap (response_str.c_str(), response_str.size()));
+ return true;
+ }
+ }
+ }
+ }
+ else
+ {
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
+ if (log)
+ {
+ if (log->GetVerbose())
+ {
+ StreamString strm;
+ gdb_comm.DumpHistory(strm);
+ log->Printf("error: failed to get packet sequence mutex, not sending read all registers:\n%s", strm.GetData());
+ }
+ else
+ log->Printf("error: failed to get packet sequence mutex, not sending read all registers");
+ }
+ }
+
+ data_sp.reset();
+ return false;
+}
+
+bool
+GDBRemoteRegisterContext::WriteAllRegisterValues (const lldb::DataBufferSP &data_sp)
+{
+ if (!data_sp || data_sp->GetBytes() == NULL || data_sp->GetByteSize() == 0)
+ return false;
+
+ ExecutionContext exe_ctx (CalculateThread());
+
+ Process *process = exe_ctx.GetProcessPtr();
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (process == NULL || thread == NULL)
+ return false;
+
+ GDBRemoteCommunicationClient &gdb_comm (((ProcessGDBRemote *)process)->GetGDBRemote());
+
+ StringExtractorGDBRemote response;
+ Mutex::Locker locker;
+ if (gdb_comm.GetSequenceMutex (locker, "Didn't get sequence mutex for write all registers."))
+ {
+ const bool thread_suffix_supported = gdb_comm.GetThreadSuffixSupported();
+ ProcessSP process_sp (m_thread.GetProcess());
+ if (thread_suffix_supported || static_cast<ProcessGDBRemote *>(process_sp.get())->GetGDBRemote().SetCurrentThread(m_thread.GetProtocolID()))
+ {
+ // The data_sp contains the entire G response packet including the
+ // G, and if the thread suffix is supported, it has the thread suffix
+ // as well.
+ const char *G_packet = (const char *)data_sp->GetBytes();
+ size_t G_packet_len = data_sp->GetByteSize();
+ if (gdb_comm.SendPacketAndWaitForResponse (G_packet,
+ G_packet_len,
+ response,
+ false))
+ {
+ if (response.IsOKResponse())
+ return true;
+ else if (response.IsErrorResponse())
+ {
+ uint32_t num_restored = 0;
+ // We need to manually go through all of the registers and
+ // restore them manually
+
+ response.GetStringRef().assign (G_packet, G_packet_len);
+ response.SetFilePos(1); // Skip the leading 'G'
+ DataBufferHeap buffer (m_reg_data.GetByteSize(), 0);
+ DataExtractor restore_data (buffer.GetBytes(),
+ buffer.GetByteSize(),
+ m_reg_data.GetByteOrder(),
+ m_reg_data.GetAddressByteSize());
+
+ const uint32_t bytes_extracted = response.GetHexBytes ((void *)restore_data.GetDataStart(),
+ restore_data.GetByteSize(),
+ '\xcc');
+
+ if (bytes_extracted < restore_data.GetByteSize())
+ restore_data.SetData(restore_data.GetDataStart(), bytes_extracted, m_reg_data.GetByteOrder());
+
+ //ReadRegisterBytes (const RegisterInfo *reg_info, RegisterValue &value, DataExtractor &data)
+ const RegisterInfo *reg_info;
+ // We have to march the offset of each register along in the
+ // buffer to make sure we get the right offset.
+ uint32_t reg_byte_offset = 0;
+ for (uint32_t reg_idx=0; (reg_info = GetRegisterInfoAtIndex (reg_idx)) != NULL; ++reg_idx, reg_byte_offset += reg_info->byte_size)
+ {
+ const uint32_t reg = reg_info->kinds[eRegisterKindLLDB];
+
+ // Skip composite registers.
+ if (reg_info->value_regs)
+ continue;
+
+ // Only write down the registers that need to be written
+ // if we are going to be doing registers individually.
+ bool write_reg = true;
+ const uint32_t reg_byte_size = reg_info->byte_size;
+
+ const char *restore_src = (const char *)restore_data.PeekData(reg_byte_offset, reg_byte_size);
+ if (restore_src)
+ {
+ if (GetRegisterIsValid(reg))
+ {
+ const char *current_src = (const char *)m_reg_data.PeekData(reg_byte_offset, reg_byte_size);
+ if (current_src)
+ write_reg = memcmp (current_src, restore_src, reg_byte_size) != 0;
+ }
+
+ if (write_reg)
+ {
+ StreamString packet;
+ packet.Printf ("P%x=", reg);
+ packet.PutBytesAsRawHex8 (restore_src,
+ reg_byte_size,
+ lldb::endian::InlHostByteOrder(),
+ lldb::endian::InlHostByteOrder());
+
+ if (thread_suffix_supported)
+ packet.Printf (";thread:%4.4" PRIx64 ";", m_thread.GetProtocolID());
+
+ SetRegisterIsValid(reg, false);
+ if (gdb_comm.SendPacketAndWaitForResponse(packet.GetString().c_str(),
+ packet.GetString().size(),
+ response,
+ false))
+ {
+ if (response.IsOKResponse())
+ ++num_restored;
+ }
+ }
+ }
+ }
+ return num_restored > 0;
+ }
+ }
+ }
+ }
+ else
+ {
+ Log *log (ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (GDBR_LOG_THREAD | GDBR_LOG_PACKETS));
+ if (log)
+ {
+ if (log->GetVerbose())
+ {
+ StreamString strm;
+ gdb_comm.DumpHistory(strm);
+ log->Printf("error: failed to get packet sequence mutex, not sending write all registers:\n%s", strm.GetData());
+ }
+ else
+ log->Printf("error: failed to get packet sequence mutex, not sending write all registers");
+ }
+ }
+ return false;
+}
+
+
+uint32_t
+GDBRemoteRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num)
+{
+ return m_reg_info.ConvertRegisterKindToRegisterNumber (kind, num);
+}
+
+void
+GDBRemoteDynamicRegisterInfo::HardcodeARMRegisters(bool from_scratch)
+{
+ // For Advanced SIMD and VFP register mapping.
+ static uint32_t g_d0_regs[] = { 26, 27, LLDB_INVALID_REGNUM }; // (s0, s1)
+ static uint32_t g_d1_regs[] = { 28, 29, LLDB_INVALID_REGNUM }; // (s2, s3)
+ static uint32_t g_d2_regs[] = { 30, 31, LLDB_INVALID_REGNUM }; // (s4, s5)
+ static uint32_t g_d3_regs[] = { 32, 33, LLDB_INVALID_REGNUM }; // (s6, s7)
+ static uint32_t g_d4_regs[] = { 34, 35, LLDB_INVALID_REGNUM }; // (s8, s9)
+ static uint32_t g_d5_regs[] = { 36, 37, LLDB_INVALID_REGNUM }; // (s10, s11)
+ static uint32_t g_d6_regs[] = { 38, 39, LLDB_INVALID_REGNUM }; // (s12, s13)
+ static uint32_t g_d7_regs[] = { 40, 41, LLDB_INVALID_REGNUM }; // (s14, s15)
+ static uint32_t g_d8_regs[] = { 42, 43, LLDB_INVALID_REGNUM }; // (s16, s17)
+ static uint32_t g_d9_regs[] = { 44, 45, LLDB_INVALID_REGNUM }; // (s18, s19)
+ static uint32_t g_d10_regs[] = { 46, 47, LLDB_INVALID_REGNUM }; // (s20, s21)
+ static uint32_t g_d11_regs[] = { 48, 49, LLDB_INVALID_REGNUM }; // (s22, s23)
+ static uint32_t g_d12_regs[] = { 50, 51, LLDB_INVALID_REGNUM }; // (s24, s25)
+ static uint32_t g_d13_regs[] = { 52, 53, LLDB_INVALID_REGNUM }; // (s26, s27)
+ static uint32_t g_d14_regs[] = { 54, 55, LLDB_INVALID_REGNUM }; // (s28, s29)
+ static uint32_t g_d15_regs[] = { 56, 57, LLDB_INVALID_REGNUM }; // (s30, s31)
+ static uint32_t g_q0_regs[] = { 26, 27, 28, 29, LLDB_INVALID_REGNUM }; // (d0, d1) -> (s0, s1, s2, s3)
+ static uint32_t g_q1_regs[] = { 30, 31, 32, 33, LLDB_INVALID_REGNUM }; // (d2, d3) -> (s4, s5, s6, s7)
+ static uint32_t g_q2_regs[] = { 34, 35, 36, 37, LLDB_INVALID_REGNUM }; // (d4, d5) -> (s8, s9, s10, s11)
+ static uint32_t g_q3_regs[] = { 38, 39, 40, 41, LLDB_INVALID_REGNUM }; // (d6, d7) -> (s12, s13, s14, s15)
+ static uint32_t g_q4_regs[] = { 42, 43, 44, 45, LLDB_INVALID_REGNUM }; // (d8, d9) -> (s16, s17, s18, s19)
+ static uint32_t g_q5_regs[] = { 46, 47, 48, 49, LLDB_INVALID_REGNUM }; // (d10, d11) -> (s20, s21, s22, s23)
+ static uint32_t g_q6_regs[] = { 50, 51, 52, 53, LLDB_INVALID_REGNUM }; // (d12, d13) -> (s24, s25, s26, s27)
+ static uint32_t g_q7_regs[] = { 54, 55, 56, 57, LLDB_INVALID_REGNUM }; // (d14, d15) -> (s28, s29, s30, s31)
+ static uint32_t g_q8_regs[] = { 59, 60, LLDB_INVALID_REGNUM }; // (d16, d17)
+ static uint32_t g_q9_regs[] = { 61, 62, LLDB_INVALID_REGNUM }; // (d18, d19)
+ static uint32_t g_q10_regs[] = { 63, 64, LLDB_INVALID_REGNUM }; // (d20, d21)
+ static uint32_t g_q11_regs[] = { 65, 66, LLDB_INVALID_REGNUM }; // (d22, d23)
+ static uint32_t g_q12_regs[] = { 67, 68, LLDB_INVALID_REGNUM }; // (d24, d25)
+ static uint32_t g_q13_regs[] = { 69, 70, LLDB_INVALID_REGNUM }; // (d26, d27)
+ static uint32_t g_q14_regs[] = { 71, 72, LLDB_INVALID_REGNUM }; // (d28, d29)
+ static uint32_t g_q15_regs[] = { 73, 74, LLDB_INVALID_REGNUM }; // (d30, d31)
+
+ // This is our array of composite registers, with each element coming from the above register mappings.
+ static uint32_t *g_composites[] = {
+ g_d0_regs, g_d1_regs, g_d2_regs, g_d3_regs, g_d4_regs, g_d5_regs, g_d6_regs, g_d7_regs,
+ g_d8_regs, g_d9_regs, g_d10_regs, g_d11_regs, g_d12_regs, g_d13_regs, g_d14_regs, g_d15_regs,
+ g_q0_regs, g_q1_regs, g_q2_regs, g_q3_regs, g_q4_regs, g_q5_regs, g_q6_regs, g_q7_regs,
+ g_q8_regs, g_q9_regs, g_q10_regs, g_q11_regs, g_q12_regs, g_q13_regs, g_q14_regs, g_q15_regs
+ };
+
+ static RegisterInfo g_register_infos[] = {
+// NAME ALT SZ OFF ENCODING FORMAT COMPILER DWARF GENERIC GDB LLDB VALUE REGS INVALIDATE REGS
+// ====== ====== === === ============= ============ =================== =================== ====================== === ==== ========== ===============
+ { "r0", "arg1", 4, 0, eEncodingUint, eFormatHex, { gcc_r0, dwarf_r0, LLDB_REGNUM_GENERIC_ARG1,0, 0 }, NULL, NULL},
+ { "r1", "arg2", 4, 0, eEncodingUint, eFormatHex, { gcc_r1, dwarf_r1, LLDB_REGNUM_GENERIC_ARG2,1, 1 }, NULL, NULL},
+ { "r2", "arg3", 4, 0, eEncodingUint, eFormatHex, { gcc_r2, dwarf_r2, LLDB_REGNUM_GENERIC_ARG3,2, 2 }, NULL, NULL},
+ { "r3", "arg4", 4, 0, eEncodingUint, eFormatHex, { gcc_r3, dwarf_r3, LLDB_REGNUM_GENERIC_ARG4,3, 3 }, NULL, NULL},
+ { "r4", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r4, dwarf_r4, LLDB_INVALID_REGNUM, 4, 4 }, NULL, NULL},
+ { "r5", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r5, dwarf_r5, LLDB_INVALID_REGNUM, 5, 5 }, NULL, NULL},
+ { "r6", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r6, dwarf_r6, LLDB_INVALID_REGNUM, 6, 6 }, NULL, NULL},
+ { "r7", "fp", 4, 0, eEncodingUint, eFormatHex, { gcc_r7, dwarf_r7, LLDB_REGNUM_GENERIC_FP, 7, 7 }, NULL, NULL},
+ { "r8", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r8, dwarf_r8, LLDB_INVALID_REGNUM, 8, 8 }, NULL, NULL},
+ { "r9", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r9, dwarf_r9, LLDB_INVALID_REGNUM, 9, 9 }, NULL, NULL},
+ { "r10", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r10, dwarf_r10, LLDB_INVALID_REGNUM, 10, 10 }, NULL, NULL},
+ { "r11", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r11, dwarf_r11, LLDB_INVALID_REGNUM, 11, 11 }, NULL, NULL},
+ { "r12", NULL, 4, 0, eEncodingUint, eFormatHex, { gcc_r12, dwarf_r12, LLDB_INVALID_REGNUM, 12, 12 }, NULL, NULL},
+ { "sp", "r13", 4, 0, eEncodingUint, eFormatHex, { gcc_sp, dwarf_sp, LLDB_REGNUM_GENERIC_SP, 13, 13 }, NULL, NULL},
+ { "lr", "r14", 4, 0, eEncodingUint, eFormatHex, { gcc_lr, dwarf_lr, LLDB_REGNUM_GENERIC_RA, 14, 14 }, NULL, NULL},
+ { "pc", "r15", 4, 0, eEncodingUint, eFormatHex, { gcc_pc, dwarf_pc, LLDB_REGNUM_GENERIC_PC, 15, 15 }, NULL, NULL},
+ { "f0", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 16, 16 }, NULL, NULL},
+ { "f1", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 17, 17 }, NULL, NULL},
+ { "f2", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 18, 18 }, NULL, NULL},
+ { "f3", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 19, 19 }, NULL, NULL},
+ { "f4", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 20, 20 }, NULL, NULL},
+ { "f5", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 21, 21 }, NULL, NULL},
+ { "f6", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 22, 22 }, NULL, NULL},
+ { "f7", NULL, 12, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 23, 23 }, NULL, NULL},
+ { "fps", NULL, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 24, 24 }, NULL, NULL},
+ { "cpsr","flags", 4, 0, eEncodingUint, eFormatHex, { gcc_cpsr, dwarf_cpsr, LLDB_INVALID_REGNUM, 25, 25 }, NULL, NULL},
+ { "s0", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s0, LLDB_INVALID_REGNUM, 26, 26 }, NULL, NULL},
+ { "s1", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s1, LLDB_INVALID_REGNUM, 27, 27 }, NULL, NULL},
+ { "s2", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s2, LLDB_INVALID_REGNUM, 28, 28 }, NULL, NULL},
+ { "s3", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s3, LLDB_INVALID_REGNUM, 29, 29 }, NULL, NULL},
+ { "s4", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s4, LLDB_INVALID_REGNUM, 30, 30 }, NULL, NULL},
+ { "s5", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s5, LLDB_INVALID_REGNUM, 31, 31 }, NULL, NULL},
+ { "s6", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s6, LLDB_INVALID_REGNUM, 32, 32 }, NULL, NULL},
+ { "s7", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s7, LLDB_INVALID_REGNUM, 33, 33 }, NULL, NULL},
+ { "s8", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s8, LLDB_INVALID_REGNUM, 34, 34 }, NULL, NULL},
+ { "s9", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s9, LLDB_INVALID_REGNUM, 35, 35 }, NULL, NULL},
+ { "s10", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s10, LLDB_INVALID_REGNUM, 36, 36 }, NULL, NULL},
+ { "s11", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s11, LLDB_INVALID_REGNUM, 37, 37 }, NULL, NULL},
+ { "s12", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s12, LLDB_INVALID_REGNUM, 38, 38 }, NULL, NULL},
+ { "s13", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s13, LLDB_INVALID_REGNUM, 39, 39 }, NULL, NULL},
+ { "s14", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s14, LLDB_INVALID_REGNUM, 40, 40 }, NULL, NULL},
+ { "s15", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s15, LLDB_INVALID_REGNUM, 41, 41 }, NULL, NULL},
+ { "s16", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s16, LLDB_INVALID_REGNUM, 42, 42 }, NULL, NULL},
+ { "s17", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s17, LLDB_INVALID_REGNUM, 43, 43 }, NULL, NULL},
+ { "s18", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s18, LLDB_INVALID_REGNUM, 44, 44 }, NULL, NULL},
+ { "s19", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s19, LLDB_INVALID_REGNUM, 45, 45 }, NULL, NULL},
+ { "s20", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s20, LLDB_INVALID_REGNUM, 46, 46 }, NULL, NULL},
+ { "s21", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s21, LLDB_INVALID_REGNUM, 47, 47 }, NULL, NULL},
+ { "s22", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s22, LLDB_INVALID_REGNUM, 48, 48 }, NULL, NULL},
+ { "s23", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s23, LLDB_INVALID_REGNUM, 49, 49 }, NULL, NULL},
+ { "s24", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s24, LLDB_INVALID_REGNUM, 50, 50 }, NULL, NULL},
+ { "s25", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s25, LLDB_INVALID_REGNUM, 51, 51 }, NULL, NULL},
+ { "s26", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s26, LLDB_INVALID_REGNUM, 52, 52 }, NULL, NULL},
+ { "s27", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s27, LLDB_INVALID_REGNUM, 53, 53 }, NULL, NULL},
+ { "s28", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s28, LLDB_INVALID_REGNUM, 54, 54 }, NULL, NULL},
+ { "s29", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s29, LLDB_INVALID_REGNUM, 55, 55 }, NULL, NULL},
+ { "s30", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s30, LLDB_INVALID_REGNUM, 56, 56 }, NULL, NULL},
+ { "s31", NULL, 4, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_s31, LLDB_INVALID_REGNUM, 57, 57 }, NULL, NULL},
+ { "fpscr",NULL, 4, 0, eEncodingUint, eFormatHex, { LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM, 58, 58 }, NULL, NULL},
+ { "d16", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d16, LLDB_INVALID_REGNUM, 59, 59 }, NULL, NULL},
+ { "d17", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d17, LLDB_INVALID_REGNUM, 60, 60 }, NULL, NULL},
+ { "d18", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d18, LLDB_INVALID_REGNUM, 61, 61 }, NULL, NULL},
+ { "d19", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d19, LLDB_INVALID_REGNUM, 62, 62 }, NULL, NULL},
+ { "d20", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d20, LLDB_INVALID_REGNUM, 63, 63 }, NULL, NULL},
+ { "d21", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d21, LLDB_INVALID_REGNUM, 64, 64 }, NULL, NULL},
+ { "d22", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d22, LLDB_INVALID_REGNUM, 65, 65 }, NULL, NULL},
+ { "d23", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d23, LLDB_INVALID_REGNUM, 66, 66 }, NULL, NULL},
+ { "d24", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d24, LLDB_INVALID_REGNUM, 67, 67 }, NULL, NULL},
+ { "d25", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d25, LLDB_INVALID_REGNUM, 68, 68 }, NULL, NULL},
+ { "d26", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d26, LLDB_INVALID_REGNUM, 69, 69 }, NULL, NULL},
+ { "d27", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d27, LLDB_INVALID_REGNUM, 70, 70 }, NULL, NULL},
+ { "d28", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d28, LLDB_INVALID_REGNUM, 71, 71 }, NULL, NULL},
+ { "d29", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d29, LLDB_INVALID_REGNUM, 72, 72 }, NULL, NULL},
+ { "d30", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d30, LLDB_INVALID_REGNUM, 73, 73 }, NULL, NULL},
+ { "d31", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d31, LLDB_INVALID_REGNUM, 74, 74 }, NULL, NULL},
+ { "d0", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d0, LLDB_INVALID_REGNUM, 75, 75 }, g_d0_regs, NULL},
+ { "d1", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d1, LLDB_INVALID_REGNUM, 76, 76 }, g_d1_regs, NULL},
+ { "d2", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d2, LLDB_INVALID_REGNUM, 77, 77 }, g_d2_regs, NULL},
+ { "d3", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d3, LLDB_INVALID_REGNUM, 78, 78 }, g_d3_regs, NULL},
+ { "d4", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d4, LLDB_INVALID_REGNUM, 79, 79 }, g_d4_regs, NULL},
+ { "d5", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d5, LLDB_INVALID_REGNUM, 80, 80 }, g_d5_regs, NULL},
+ { "d6", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d6, LLDB_INVALID_REGNUM, 81, 81 }, g_d6_regs, NULL},
+ { "d7", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d7, LLDB_INVALID_REGNUM, 82, 82 }, g_d7_regs, NULL},
+ { "d8", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d8, LLDB_INVALID_REGNUM, 83, 83 }, g_d8_regs, NULL},
+ { "d9", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d9, LLDB_INVALID_REGNUM, 84, 84 }, g_d9_regs, NULL},
+ { "d10", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d10, LLDB_INVALID_REGNUM, 85, 85 }, g_d10_regs, NULL},
+ { "d11", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d11, LLDB_INVALID_REGNUM, 86, 86 }, g_d11_regs, NULL},
+ { "d12", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d12, LLDB_INVALID_REGNUM, 87, 87 }, g_d12_regs, NULL},
+ { "d13", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d13, LLDB_INVALID_REGNUM, 88, 88 }, g_d13_regs, NULL},
+ { "d14", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d14, LLDB_INVALID_REGNUM, 89, 89 }, g_d14_regs, NULL},
+ { "d15", NULL, 8, 0, eEncodingIEEE754, eFormatFloat, { LLDB_INVALID_REGNUM, dwarf_d15, LLDB_INVALID_REGNUM, 90, 90 }, g_d15_regs, NULL},
+ { "q0", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q0, LLDB_INVALID_REGNUM, 91, 91 }, g_q0_regs, NULL},
+ { "q1", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q1, LLDB_INVALID_REGNUM, 92, 92 }, g_q1_regs, NULL},
+ { "q2", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q2, LLDB_INVALID_REGNUM, 93, 93 }, g_q2_regs, NULL},
+ { "q3", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q3, LLDB_INVALID_REGNUM, 94, 94 }, g_q3_regs, NULL},
+ { "q4", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q4, LLDB_INVALID_REGNUM, 95, 95 }, g_q4_regs, NULL},
+ { "q5", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q5, LLDB_INVALID_REGNUM, 96, 96 }, g_q5_regs, NULL},
+ { "q6", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q6, LLDB_INVALID_REGNUM, 97, 97 }, g_q6_regs, NULL},
+ { "q7", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q7, LLDB_INVALID_REGNUM, 98, 98 }, g_q7_regs, NULL},
+ { "q8", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q8, LLDB_INVALID_REGNUM, 99, 99 }, g_q8_regs, NULL},
+ { "q9", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q9, LLDB_INVALID_REGNUM, 100, 100 }, g_q9_regs, NULL},
+ { "q10", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q10, LLDB_INVALID_REGNUM, 101, 101 }, g_q10_regs, NULL},
+ { "q11", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q11, LLDB_INVALID_REGNUM, 102, 102 }, g_q11_regs, NULL},
+ { "q12", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q12, LLDB_INVALID_REGNUM, 103, 103 }, g_q12_regs, NULL},
+ { "q13", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q13, LLDB_INVALID_REGNUM, 104, 104 }, g_q13_regs, NULL},
+ { "q14", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q14, LLDB_INVALID_REGNUM, 105, 105 }, g_q14_regs, NULL},
+ { "q15", NULL, 16, 0, eEncodingVector, eFormatVectorOfUInt8, { LLDB_INVALID_REGNUM, dwarf_q15, LLDB_INVALID_REGNUM, 106, 106 }, g_q15_regs, NULL}
+ };
+
+ static const uint32_t num_registers = llvm::array_lengthof(g_register_infos);
+ static ConstString gpr_reg_set ("General Purpose Registers");
+ static ConstString sfp_reg_set ("Software Floating Point Registers");
+ static ConstString vfp_reg_set ("Floating Point Registers");
+ size_t i;
+ if (from_scratch)
+ {
+ // Calculate the offsets of the registers
+ // Note that the layout of the "composite" registers (d0-d15 and q0-q15) which comes after the
+ // "primordial" registers is important. This enables us to calculate the offset of the composite
+ // register by using the offset of its first primordial register. For example, to calculate the
+ // offset of q0, use s0's offset.
+ if (g_register_infos[2].byte_offset == 0)
+ {
+ uint32_t byte_offset = 0;
+ for (i=0; i<num_registers; ++i)
+ {
+ // For primordial registers, increment the byte_offset by the byte_size to arrive at the
+ // byte_offset for the next register. Otherwise, we have a composite register whose
+ // offset can be calculated by consulting the offset of its first primordial register.
+ if (!g_register_infos[i].value_regs)
+ {
+ g_register_infos[i].byte_offset = byte_offset;
+ byte_offset += g_register_infos[i].byte_size;
+ }
+ else
+ {
+ const uint32_t first_primordial_reg = g_register_infos[i].value_regs[0];
+ g_register_infos[i].byte_offset = g_register_infos[first_primordial_reg].byte_offset;
+ }
+ }
+ }
+ for (i=0; i<num_registers; ++i)
+ {
+ ConstString name;
+ ConstString alt_name;
+ if (g_register_infos[i].name && g_register_infos[i].name[0])
+ name.SetCString(g_register_infos[i].name);
+ if (g_register_infos[i].alt_name && g_register_infos[i].alt_name[0])
+ alt_name.SetCString(g_register_infos[i].alt_name);
+
+ if (i <= 15 || i == 25)
+ AddRegister (g_register_infos[i], name, alt_name, gpr_reg_set);
+ else if (i <= 24)
+ AddRegister (g_register_infos[i], name, alt_name, sfp_reg_set);
+ else
+ AddRegister (g_register_infos[i], name, alt_name, vfp_reg_set);
+ }
+ }
+ else
+ {
+ // Add composite registers to our primordial registers, then.
+ const size_t num_composites = llvm::array_lengthof(g_composites);
+ const size_t num_dynamic_regs = GetNumRegisters();
+ const size_t num_common_regs = num_registers - num_composites;
+ RegisterInfo *g_comp_register_infos = g_register_infos + num_common_regs;
+
+ // First we need to validate that all registers that we already have match the non composite regs.
+ // If so, then we can add the registers, else we need to bail
+ bool match = true;
+ if (num_dynamic_regs == num_common_regs)
+ {
+ for (i=0; match && i<num_dynamic_regs; ++i)
+ {
+ // Make sure all register names match
+ if (m_regs[i].name && g_register_infos[i].name)
+ {
+ if (strcmp(m_regs[i].name, g_register_infos[i].name))
+ {
+ match = false;
+ break;
+ }
+ }
+
+ // Make sure all register byte sizes match
+ if (m_regs[i].byte_size != g_register_infos[i].byte_size)
+ {
+ match = false;
+ break;
+ }
+ }
+ }
+ else
+ {
+ // Wrong number of registers.
+ match = false;
+ }
+ // If "match" is true, then we can add extra registers.
+ if (match)
+ {
+ for (i=0; i<num_composites; ++i)
+ {
+ ConstString name;
+ ConstString alt_name;
+ const uint32_t first_primordial_reg = g_comp_register_infos[i].value_regs[0];
+ const char *reg_name = g_register_infos[first_primordial_reg].name;
+ if (reg_name && reg_name[0])
+ {
+ for (uint32_t j = 0; j < num_dynamic_regs; ++j)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(j);
+ // Find a matching primordial register info entry.
+ if (reg_info && reg_info->name && ::strcasecmp(reg_info->name, reg_name) == 0)
+ {
+ // The name matches the existing primordial entry.
+ // Find and assign the offset, and then add this composite register entry.
+ g_comp_register_infos[i].byte_offset = reg_info->byte_offset;
+ name.SetCString(g_comp_register_infos[i].name);
+ AddRegister(g_comp_register_infos[i], name, alt_name, vfp_reg_set);
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
new file mode 100644
index 000000000000..3110ddf8edf9
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/GDBRemoteRegisterContext.h
@@ -0,0 +1,311 @@
+//===-- GDBRemoteRegisterContext.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_GDBRemoteRegisterContext_h_
+#define lldb_GDBRemoteRegisterContext_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+// Project includes
+#include "lldb/lldb-private.h"
+#include "lldb/lldb-enumerations.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Target/RegisterContext.h"
+#include "GDBRemoteCommunicationClient.h"
+
+class ThreadGDBRemote;
+class ProcessGDBRemote;
+class StringExtractor;
+
+class GDBRemoteDynamicRegisterInfo
+{
+public:
+ GDBRemoteDynamicRegisterInfo () :
+ m_regs (),
+ m_sets (),
+ m_set_reg_nums (),
+ m_reg_names (),
+ m_reg_alt_names (),
+ m_set_names (),
+ m_reg_data_byte_size (0)
+ {
+ }
+
+ ~GDBRemoteDynamicRegisterInfo ()
+ {
+ }
+
+ void
+ AddRegister (lldb_private::RegisterInfo reg_info,
+ lldb_private::ConstString &reg_name,
+ lldb_private::ConstString &reg_alt_name,
+ lldb_private::ConstString &set_name)
+ {
+ const uint32_t reg_num = (uint32_t)m_regs.size();
+ m_reg_names.push_back (reg_name);
+ m_reg_alt_names.push_back (reg_alt_name);
+ reg_info.name = reg_name.AsCString();
+ assert (reg_info.name);
+ reg_info.alt_name = reg_alt_name.AsCString(NULL);
+ uint32_t i;
+ if (reg_info.value_regs)
+ {
+ for (i=0; reg_info.value_regs[i] != LLDB_INVALID_REGNUM; ++i)
+ m_value_regs_map[reg_num].push_back(reg_info.value_regs[i]);
+ m_value_regs_map[reg_num].push_back(LLDB_INVALID_REGNUM);
+ reg_info.value_regs = m_value_regs_map[reg_num].data();
+ }
+ if (reg_info.invalidate_regs)
+ {
+ for (i=0; reg_info.invalidate_regs[i] != LLDB_INVALID_REGNUM; ++i)
+ m_invalidate_regs_map[reg_num].push_back(reg_info.invalidate_regs[i]);
+ m_invalidate_regs_map[reg_num].push_back(LLDB_INVALID_REGNUM);
+ reg_info.invalidate_regs = m_invalidate_regs_map[reg_num].data();
+ }
+ m_regs.push_back (reg_info);
+ uint32_t set = GetRegisterSetIndexByName (set_name);
+ assert (set < m_sets.size());
+ assert (set < m_set_reg_nums.size());
+ assert (set < m_set_names.size());
+ m_set_reg_nums[set].push_back(reg_num);
+ size_t end_reg_offset = reg_info.byte_offset + reg_info.byte_size;
+ if (m_reg_data_byte_size < end_reg_offset)
+ m_reg_data_byte_size = end_reg_offset;
+ }
+
+ void
+ Finalize ()
+ {
+ for (uint32_t set = 0; set < m_sets.size(); ++set)
+ {
+ assert (m_sets.size() == m_set_reg_nums.size());
+ m_sets[set].num_registers = m_set_reg_nums[set].size();
+ m_sets[set].registers = &m_set_reg_nums[set][0];
+ }
+ }
+
+ size_t
+ GetNumRegisters() const
+ {
+ return m_regs.size();
+ }
+
+ size_t
+ GetNumRegisterSets() const
+ {
+ return m_sets.size();
+ }
+
+ size_t
+ GetRegisterDataByteSize() const
+ {
+ return m_reg_data_byte_size;
+ }
+
+ const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (uint32_t i) const
+ {
+ if (i < m_regs.size())
+ return &m_regs[i];
+ return NULL;
+ }
+
+ const lldb_private::RegisterSet *
+ GetRegisterSet (uint32_t i) const
+ {
+ if (i < m_sets.size())
+ return &m_sets[i];
+ return NULL;
+ }
+
+ uint32_t
+ GetRegisterSetIndexByName (lldb_private::ConstString &set_name)
+ {
+ name_collection::iterator pos, end = m_set_names.end();
+ for (pos = m_set_names.begin(); pos != end; ++pos)
+ {
+ if (*pos == set_name)
+ return static_cast<uint32_t>(std::distance (m_set_names.begin(), pos));
+ }
+
+ m_set_names.push_back(set_name);
+ m_set_reg_nums.resize(m_set_reg_nums.size()+1);
+ lldb_private::RegisterSet new_set = { set_name.AsCString(), NULL, 0, NULL };
+ m_sets.push_back (new_set);
+ return static_cast<uint32_t>(m_sets.size() - 1);
+ }
+
+ uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const
+ {
+ reg_collection::const_iterator pos, end = m_regs.end();
+ for (pos = m_regs.begin(); pos != end; ++pos)
+ {
+ if (pos->kinds[kind] == num)
+ return static_cast<uint32_t>(std::distance (m_regs.begin(), pos));
+ }
+
+ return LLDB_INVALID_REGNUM;
+ }
+ void
+ Clear()
+ {
+ m_regs.clear();
+ m_sets.clear();
+ m_set_reg_nums.clear();
+ m_reg_names.clear();
+ m_reg_alt_names.clear();
+ m_set_names.clear();
+ }
+
+ void
+ HardcodeARMRegisters(bool from_scratch);
+
+protected:
+ //------------------------------------------------------------------
+ // Classes that inherit from GDBRemoteRegisterContext can see and modify these
+ //------------------------------------------------------------------
+ typedef std::vector <lldb_private::RegisterInfo> reg_collection;
+ typedef std::vector <lldb_private::RegisterSet> set_collection;
+ typedef std::vector <uint32_t> reg_num_collection;
+ typedef std::vector <reg_num_collection> set_reg_num_collection;
+ typedef std::vector <lldb_private::ConstString> name_collection;
+ typedef std::map<uint32_t, reg_num_collection> reg_to_regs_map;
+
+ reg_collection m_regs;
+ set_collection m_sets;
+ set_reg_num_collection m_set_reg_nums;
+ name_collection m_reg_names;
+ name_collection m_reg_alt_names;
+ name_collection m_set_names;
+ reg_to_regs_map m_value_regs_map;
+ reg_to_regs_map m_invalidate_regs_map;
+ size_t m_reg_data_byte_size; // The number of bytes required to store all registers
+};
+
+class GDBRemoteRegisterContext : public lldb_private::RegisterContext
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ GDBRemoteRegisterContext (ThreadGDBRemote &thread,
+ uint32_t concrete_frame_idx,
+ GDBRemoteDynamicRegisterInfo &reg_info,
+ bool read_all_at_once);
+
+ virtual
+ ~GDBRemoteRegisterContext ();
+
+ //------------------------------------------------------------------
+ // Subclasses must override these functions
+ //------------------------------------------------------------------
+ virtual void
+ InvalidateAllRegisters ();
+
+ virtual size_t
+ GetRegisterCount ();
+
+ virtual const lldb_private::RegisterInfo *
+ GetRegisterInfoAtIndex (size_t reg);
+
+ virtual size_t
+ GetRegisterSetCount ();
+
+ virtual const lldb_private::RegisterSet *
+ GetRegisterSet (size_t reg_set);
+
+ virtual bool
+ ReadRegister (const lldb_private::RegisterInfo *reg_info, lldb_private::RegisterValue &value);
+
+ virtual bool
+ WriteRegister (const lldb_private::RegisterInfo *reg_info, const lldb_private::RegisterValue &value);
+
+ virtual bool
+ ReadAllRegisterValues (lldb::DataBufferSP &data_sp);
+
+ virtual bool
+ WriteAllRegisterValues (const lldb::DataBufferSP &data_sp);
+
+ virtual uint32_t
+ ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num);
+
+protected:
+ friend class ThreadGDBRemote;
+
+ bool
+ ReadRegisterBytes (const lldb_private::RegisterInfo *reg_info,
+ lldb_private::DataExtractor &data);
+
+ bool
+ WriteRegisterBytes (const lldb_private::RegisterInfo *reg_info,
+ lldb_private::DataExtractor &data,
+ uint32_t data_offset);
+
+ bool
+ PrivateSetRegisterValue (uint32_t reg, StringExtractor &response);
+
+ void
+ SetAllRegisterValid (bool b);
+
+ bool
+ GetRegisterIsValid (uint32_t reg) const
+ {
+#if defined (LLDB_CONFIGURATION_DEBUG)
+ assert (reg < m_reg_valid.size());
+#endif
+ if (reg < m_reg_valid.size())
+ return m_reg_valid[reg];
+ return false;
+ }
+
+ void
+ SetRegisterIsValid (const lldb_private::RegisterInfo *reg_info, bool valid)
+ {
+ if (reg_info)
+ return SetRegisterIsValid (reg_info->kinds[lldb::eRegisterKindLLDB], valid);
+ }
+
+ void
+ SetRegisterIsValid (uint32_t reg, bool valid)
+ {
+#if defined (LLDB_CONFIGURATION_DEBUG)
+ assert (reg < m_reg_valid.size());
+#endif
+ if (reg < m_reg_valid.size())
+ m_reg_valid[reg] = valid;
+ }
+
+ void
+ SyncThreadState(lldb_private::Process *process); // Assumes the sequence mutex has already been acquired.
+
+ GDBRemoteDynamicRegisterInfo &m_reg_info;
+ std::vector<bool> m_reg_valid;
+ lldb_private::DataExtractor m_reg_data;
+ bool m_read_all_at_once;
+
+private:
+ // Helper function for ReadRegisterBytes().
+ bool GetPrimordialRegister(const lldb_private::RegisterInfo *reg_info,
+ GDBRemoteCommunicationClient &gdb_comm);
+ // Helper function for WriteRegisterBytes().
+ bool SetPrimordialRegister(const lldb_private::RegisterInfo *reg_info,
+ GDBRemoteCommunicationClient &gdb_comm);
+
+ //------------------------------------------------------------------
+ // For GDBRemoteRegisterContext only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (GDBRemoteRegisterContext);
+};
+
+#endif // lldb_GDBRemoteRegisterContext_h_
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
new file mode 100644
index 000000000000..d27207f121d3
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -0,0 +1,3291 @@
+//===-- ProcessGDBRemote.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+// C Includes
+#include <errno.h>
+#include <spawn.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <sys/mman.h> // for mmap
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+
+// C++ Includes
+#include <algorithm>
+#include <map>
+
+// Other libraries and framework includes
+
+#include "lldb/Breakpoint/Watchpoint.h"
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/ConnectionFileDescriptor.h"
+#include "lldb/Host/FileSpec.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/State.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Host/TimeValue.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/CommandObject.h"
+#include "lldb/Interpreter/CommandObjectMultiword.h"
+#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/TargetList.h"
+#include "lldb/Target/ThreadPlanCallFunction.h"
+#include "lldb/Utility/PseudoTerminal.h"
+
+// Project includes
+#include "lldb/Host/Host.h"
+#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
+#include "Plugins/Process/Utility/StopInfoMachException.h"
+#include "Plugins/Platform/MacOSX/PlatformRemoteiOS.h"
+#include "Utility/StringExtractorGDBRemote.h"
+#include "GDBRemoteRegisterContext.h"
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "ThreadGDBRemote.h"
+
+
+namespace lldb
+{
+ // Provide a function that can easily dump the packet history if we know a
+ // ProcessGDBRemote * value (which we can get from logs or from debugging).
+ // We need the function in the lldb namespace so it makes it into the final
+ // executable since the LLDB shared library only exports stuff in the lldb
+ // namespace. This allows you to attach with a debugger and call this
+ // function and get the packet history dumped to a file.
+ void
+ DumpProcessGDBRemotePacketHistory (void *p, const char *path)
+ {
+ lldb_private::StreamFile strm;
+ lldb_private::Error error (strm.GetFile().Open(path, lldb_private::File::eOpenOptionWrite | lldb_private::File::eOpenOptionCanCreate));
+ if (error.Success())
+ ((ProcessGDBRemote *)p)->GetGDBRemote().DumpHistory (strm);
+ }
+}
+
+#define DEBUGSERVER_BASENAME "debugserver"
+using namespace lldb;
+using namespace lldb_private;
+
+
+namespace {
+
+ static PropertyDefinition
+ g_properties[] =
+ {
+ { "packet-timeout" , OptionValue::eTypeUInt64 , true , 1, NULL, NULL, "Specify the default packet timeout in seconds." },
+ { NULL , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL }
+ };
+
+ enum
+ {
+ ePropertyPacketTimeout
+ };
+
+ class PluginProperties : public Properties
+ {
+ public:
+
+ static ConstString
+ GetSettingName ()
+ {
+ return ProcessGDBRemote::GetPluginNameStatic();
+ }
+
+ PluginProperties() :
+ Properties ()
+ {
+ m_collection_sp.reset (new OptionValueProperties(GetSettingName()));
+ m_collection_sp->Initialize(g_properties);
+ }
+
+ virtual
+ ~PluginProperties()
+ {
+ }
+
+ uint64_t
+ GetPacketTimeout()
+ {
+ const uint32_t idx = ePropertyPacketTimeout;
+ return m_collection_sp->GetPropertyAtIndexAsUInt64(NULL, idx, g_properties[idx].default_uint_value);
+ }
+ };
+
+ typedef std::shared_ptr<PluginProperties> ProcessKDPPropertiesSP;
+
+ static const ProcessKDPPropertiesSP &
+ GetGlobalPluginProperties()
+ {
+ static ProcessKDPPropertiesSP g_settings_sp;
+ if (!g_settings_sp)
+ g_settings_sp.reset (new PluginProperties ());
+ return g_settings_sp;
+ }
+
+} // anonymous namespace end
+
+static bool rand_initialized = false;
+
+// TODO Randomly assigning a port is unsafe. We should get an unused
+// ephemeral port from the kernel and make sure we reserve it before passing
+// it to debugserver.
+
+#if defined (__APPLE__)
+#define LOW_PORT (IPPORT_RESERVED)
+#define HIGH_PORT (IPPORT_HIFIRSTAUTO)
+#else
+#define LOW_PORT (1024u)
+#define HIGH_PORT (49151u)
+#endif
+
+static inline uint16_t
+get_random_port ()
+{
+ if (!rand_initialized)
+ {
+ time_t seed = time(NULL);
+
+ rand_initialized = true;
+ srand(seed);
+ }
+ return (rand() % (HIGH_PORT - LOW_PORT)) + LOW_PORT;
+}
+
+
+lldb_private::ConstString
+ProcessGDBRemote::GetPluginNameStatic()
+{
+ static ConstString g_name("gdb-remote");
+ return g_name;
+}
+
+const char *
+ProcessGDBRemote::GetPluginDescriptionStatic()
+{
+ return "GDB Remote protocol based debugging plug-in.";
+}
+
+void
+ProcessGDBRemote::Terminate()
+{
+ PluginManager::UnregisterPlugin (ProcessGDBRemote::CreateInstance);
+}
+
+
+lldb::ProcessSP
+ProcessGDBRemote::CreateInstance (Target &target, Listener &listener, const FileSpec *crash_file_path)
+{
+ lldb::ProcessSP process_sp;
+ if (crash_file_path == NULL)
+ process_sp.reset (new ProcessGDBRemote (target, listener));
+ return process_sp;
+}
+
+bool
+ProcessGDBRemote::CanDebug (Target &target, bool plugin_specified_by_name)
+{
+ if (plugin_specified_by_name)
+ return true;
+
+ // For now we are just making sure the file exists for a given module
+ Module *exe_module = target.GetExecutableModulePointer();
+ if (exe_module)
+ {
+ ObjectFile *exe_objfile = exe_module->GetObjectFile();
+ // We can't debug core files...
+ switch (exe_objfile->GetType())
+ {
+ case ObjectFile::eTypeInvalid:
+ case ObjectFile::eTypeCoreFile:
+ case ObjectFile::eTypeDebugInfo:
+ case ObjectFile::eTypeObjectFile:
+ case ObjectFile::eTypeSharedLibrary:
+ case ObjectFile::eTypeStubLibrary:
+ return false;
+ case ObjectFile::eTypeExecutable:
+ case ObjectFile::eTypeDynamicLinker:
+ case ObjectFile::eTypeUnknown:
+ break;
+ }
+ return exe_module->GetFileSpec().Exists();
+ }
+ // However, if there is no executable module, we return true since we might be preparing to attach.
+ return true;
+}
+
+//----------------------------------------------------------------------
+// ProcessGDBRemote constructor
+//----------------------------------------------------------------------
+ProcessGDBRemote::ProcessGDBRemote(Target& target, Listener &listener) :
+ Process (target, listener),
+ m_flags (0),
+ m_gdb_comm(false),
+ m_debugserver_pid (LLDB_INVALID_PROCESS_ID),
+ m_last_stop_packet (),
+ m_last_stop_packet_mutex (Mutex::eMutexTypeNormal),
+ m_register_info (),
+ m_async_broadcaster (NULL, "lldb.process.gdb-remote.async-broadcaster"),
+ m_async_thread (LLDB_INVALID_HOST_THREAD),
+ m_async_thread_state(eAsyncThreadNotStarted),
+ m_async_thread_state_mutex(Mutex::eMutexTypeRecursive),
+ m_thread_ids (),
+ m_continue_c_tids (),
+ m_continue_C_tids (),
+ m_continue_s_tids (),
+ m_continue_S_tids (),
+ m_dispatch_queue_offsets_addr (LLDB_INVALID_ADDRESS),
+ m_max_memory_size (512),
+ m_addr_to_mmap_size (),
+ m_thread_create_bp_sp (),
+ m_waiting_for_attach (false),
+ m_destroy_tried_resuming (false),
+ m_command_sp ()
+{
+ m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadShouldExit, "async thread should exit");
+ m_async_broadcaster.SetEventName (eBroadcastBitAsyncContinue, "async thread continue");
+ m_async_broadcaster.SetEventName (eBroadcastBitAsyncThreadDidExit, "async thread did exit");
+ const uint64_t timeout_seconds = GetGlobalPluginProperties()->GetPacketTimeout();
+ if (timeout_seconds > 0)
+ m_gdb_comm.SetPacketTimeout(timeout_seconds);
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+ProcessGDBRemote::~ProcessGDBRemote()
+{
+ // m_mach_process.UnregisterNotificationCallbacks (this);
+ Clear();
+ // We need to call finalize on the process before destroying ourselves
+ // to make sure all of the broadcaster cleanup goes as planned. If we
+ // destruct this class, then Process::~Process() might have problems
+ // trying to fully destroy the broadcaster.
+ Finalize();
+
+ // The general Finalize is going to try to destroy the process and that SHOULD
+ // shut down the async thread. However, if we don't kill it it will get stranded and
+ // its connection will go away so when it wakes up it will crash. So kill it for sure here.
+ StopAsyncThread();
+ KillDebugserverProcess();
+}
+
+//----------------------------------------------------------------------
+// PluginInterface
+//----------------------------------------------------------------------
+ConstString
+ProcessGDBRemote::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+ProcessGDBRemote::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+ProcessGDBRemote::BuildDynamicRegisterInfo (bool force)
+{
+ if (!force && m_register_info.GetNumRegisters() > 0)
+ return;
+
+ char packet[128];
+ m_register_info.Clear();
+ uint32_t reg_offset = 0;
+ uint32_t reg_num = 0;
+ for (StringExtractorGDBRemote::ResponseType response_type = StringExtractorGDBRemote::eResponse;
+ response_type == StringExtractorGDBRemote::eResponse;
+ ++reg_num)
+ {
+ const int packet_len = ::snprintf (packet, sizeof(packet), "qRegisterInfo%x", reg_num);
+ assert (packet_len < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, false))
+ {
+ response_type = response.GetResponseType();
+ if (response_type == StringExtractorGDBRemote::eResponse)
+ {
+ std::string name;
+ std::string value;
+ ConstString reg_name;
+ ConstString alt_name;
+ ConstString set_name;
+ std::vector<uint32_t> value_regs;
+ std::vector<uint32_t> invalidate_regs;
+ RegisterInfo reg_info = { NULL, // Name
+ NULL, // Alt name
+ 0, // byte size
+ reg_offset, // offset
+ eEncodingUint, // encoding
+ eFormatHex, // formate
+ {
+ LLDB_INVALID_REGNUM, // GCC reg num
+ LLDB_INVALID_REGNUM, // DWARF reg num
+ LLDB_INVALID_REGNUM, // generic reg num
+ reg_num, // GDB reg num
+ reg_num // native register number
+ },
+ NULL,
+ NULL
+ };
+
+ while (response.GetNameColonValue(name, value))
+ {
+ if (name.compare("name") == 0)
+ {
+ reg_name.SetCString(value.c_str());
+ }
+ else if (name.compare("alt-name") == 0)
+ {
+ alt_name.SetCString(value.c_str());
+ }
+ else if (name.compare("bitsize") == 0)
+ {
+ reg_info.byte_size = Args::StringToUInt32(value.c_str(), 0, 0) / CHAR_BIT;
+ }
+ else if (name.compare("offset") == 0)
+ {
+ uint32_t offset = Args::StringToUInt32(value.c_str(), UINT32_MAX, 0);
+ if (reg_offset != offset)
+ {
+ reg_offset = offset;
+ }
+ }
+ else if (name.compare("encoding") == 0)
+ {
+ const Encoding encoding = Args::StringToEncoding (value.c_str());
+ if (encoding != eEncodingInvalid)
+ reg_info.encoding = encoding;
+ }
+ else if (name.compare("format") == 0)
+ {
+ Format format = eFormatInvalid;
+ if (Args::StringToFormat (value.c_str(), format, NULL).Success())
+ reg_info.format = format;
+ else if (value.compare("binary") == 0)
+ reg_info.format = eFormatBinary;
+ else if (value.compare("decimal") == 0)
+ reg_info.format = eFormatDecimal;
+ else if (value.compare("hex") == 0)
+ reg_info.format = eFormatHex;
+ else if (value.compare("float") == 0)
+ reg_info.format = eFormatFloat;
+ else if (value.compare("vector-sint8") == 0)
+ reg_info.format = eFormatVectorOfSInt8;
+ else if (value.compare("vector-uint8") == 0)
+ reg_info.format = eFormatVectorOfUInt8;
+ else if (value.compare("vector-sint16") == 0)
+ reg_info.format = eFormatVectorOfSInt16;
+ else if (value.compare("vector-uint16") == 0)
+ reg_info.format = eFormatVectorOfUInt16;
+ else if (value.compare("vector-sint32") == 0)
+ reg_info.format = eFormatVectorOfSInt32;
+ else if (value.compare("vector-uint32") == 0)
+ reg_info.format = eFormatVectorOfUInt32;
+ else if (value.compare("vector-float32") == 0)
+ reg_info.format = eFormatVectorOfFloat32;
+ else if (value.compare("vector-uint128") == 0)
+ reg_info.format = eFormatVectorOfUInt128;
+ }
+ else if (name.compare("set") == 0)
+ {
+ set_name.SetCString(value.c_str());
+ }
+ else if (name.compare("gcc") == 0)
+ {
+ reg_info.kinds[eRegisterKindGCC] = Args::StringToUInt32(value.c_str(), LLDB_INVALID_REGNUM, 0);
+ }
+ else if (name.compare("dwarf") == 0)
+ {
+ reg_info.kinds[eRegisterKindDWARF] = Args::StringToUInt32(value.c_str(), LLDB_INVALID_REGNUM, 0);
+ }
+ else if (name.compare("generic") == 0)
+ {
+ reg_info.kinds[eRegisterKindGeneric] = Args::StringToGenericRegister (value.c_str());
+ }
+ else if (name.compare("container-regs") == 0)
+ {
+ std::pair<llvm::StringRef, llvm::StringRef> value_pair;
+ value_pair.second = value;
+ do
+ {
+ value_pair = value_pair.second.split(',');
+ if (!value_pair.first.empty())
+ {
+ uint32_t reg = Args::StringToUInt32 (value_pair.first.str().c_str(), LLDB_INVALID_REGNUM, 16);
+ if (reg != LLDB_INVALID_REGNUM)
+ value_regs.push_back (reg);
+ }
+ } while (!value_pair.second.empty());
+ }
+ else if (name.compare("invalidate-regs") == 0)
+ {
+ std::pair<llvm::StringRef, llvm::StringRef> value_pair;
+ value_pair.second = value;
+ do
+ {
+ value_pair = value_pair.second.split(',');
+ if (!value_pair.first.empty())
+ {
+ uint32_t reg = Args::StringToUInt32 (value_pair.first.str().c_str(), LLDB_INVALID_REGNUM, 16);
+ if (reg != LLDB_INVALID_REGNUM)
+ invalidate_regs.push_back (reg);
+ }
+ } while (!value_pair.second.empty());
+ }
+ }
+
+ reg_info.byte_offset = reg_offset;
+ assert (reg_info.byte_size != 0);
+ reg_offset += reg_info.byte_size;
+ if (!value_regs.empty())
+ {
+ value_regs.push_back(LLDB_INVALID_REGNUM);
+ reg_info.value_regs = value_regs.data();
+ }
+ if (!invalidate_regs.empty())
+ {
+ invalidate_regs.push_back(LLDB_INVALID_REGNUM);
+ reg_info.invalidate_regs = invalidate_regs.data();
+ }
+
+ m_register_info.AddRegister(reg_info, reg_name, alt_name, set_name);
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ // We didn't get anything if the accumulated reg_num is zero. See if we are
+ // debugging ARM and fill with a hard coded register set until we can get an
+ // updated debugserver down on the devices.
+ // On the other hand, if the accumulated reg_num is positive, see if we can
+ // add composite registers to the existing primordial ones.
+ bool from_scratch = (reg_num == 0);
+
+ const ArchSpec &target_arch = GetTarget().GetArchitecture();
+ const ArchSpec &remote_host_arch = m_gdb_comm.GetHostArchitecture();
+ const ArchSpec &remote_process_arch = m_gdb_comm.GetProcessArchitecture();
+
+ // Use the process' architecture instead of the host arch, if available
+ ArchSpec remote_arch;
+ if (remote_process_arch.IsValid ())
+ remote_arch = remote_process_arch;
+ else
+ remote_arch = remote_host_arch;
+
+ if (!target_arch.IsValid())
+ {
+ if (remote_arch.IsValid()
+ && remote_arch.GetMachine() == llvm::Triple::arm
+ && remote_arch.GetTriple().getVendor() == llvm::Triple::Apple)
+ m_register_info.HardcodeARMRegisters(from_scratch);
+ }
+ else if (target_arch.GetMachine() == llvm::Triple::arm)
+ {
+ m_register_info.HardcodeARMRegisters(from_scratch);
+ }
+
+ // At this point, we can finalize our register info.
+ m_register_info.Finalize ();
+}
+
+Error
+ProcessGDBRemote::WillLaunch (Module* module)
+{
+ return WillLaunchOrAttach ();
+}
+
+Error
+ProcessGDBRemote::WillAttachToProcessWithID (lldb::pid_t pid)
+{
+ return WillLaunchOrAttach ();
+}
+
+Error
+ProcessGDBRemote::WillAttachToProcessWithName (const char *process_name, bool wait_for_launch)
+{
+ return WillLaunchOrAttach ();
+}
+
+Error
+ProcessGDBRemote::DoConnectRemote (Stream *strm, const char *remote_url)
+{
+ Error error (WillLaunchOrAttach ());
+
+ if (error.Fail())
+ return error;
+
+ error = ConnectToDebugserver (remote_url);
+
+ if (error.Fail())
+ return error;
+ StartAsyncThread ();
+
+ lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID ();
+ if (pid == LLDB_INVALID_PROCESS_ID)
+ {
+ // We don't have a valid process ID, so note that we are connected
+ // and could now request to launch or attach, or get remote process
+ // listings...
+ SetPrivateState (eStateConnected);
+ }
+ else
+ {
+ // We have a valid process
+ SetID (pid);
+ GetThreadList();
+ if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false))
+ {
+ const StateType state = SetThreadStopInfo (m_last_stop_packet);
+ if (state == eStateStopped)
+ {
+ SetPrivateState (state);
+ }
+ else
+ error.SetErrorStringWithFormat ("Process %" PRIu64 " was reported after connecting to '%s', but state was not stopped: %s", pid, remote_url, StateAsCString (state));
+ }
+ else
+ error.SetErrorStringWithFormat ("Process %" PRIu64 " was reported after connecting to '%s', but no stop reply packet was received", pid, remote_url);
+ }
+
+ if (error.Success()
+ && !GetTarget().GetArchitecture().IsValid()
+ && m_gdb_comm.GetHostArchitecture().IsValid())
+ {
+ // Prefer the *process'* architecture over that of the *host*, if available.
+ if (m_gdb_comm.GetProcessArchitecture().IsValid())
+ GetTarget().SetArchitecture(m_gdb_comm.GetProcessArchitecture());
+ else
+ GetTarget().SetArchitecture(m_gdb_comm.GetHostArchitecture());
+ }
+
+ return error;
+}
+
+Error
+ProcessGDBRemote::WillLaunchOrAttach ()
+{
+ Error error;
+ m_stdio_communication.Clear ();
+ return error;
+}
+
+//----------------------------------------------------------------------
+// Process Control
+//----------------------------------------------------------------------
+Error
+ProcessGDBRemote::DoLaunch (Module *exe_module, const ProcessLaunchInfo &launch_info)
+{
+ Error error;
+
+ uint32_t launch_flags = launch_info.GetFlags().Get();
+ const char *stdin_path = NULL;
+ const char *stdout_path = NULL;
+ const char *stderr_path = NULL;
+ const char *working_dir = launch_info.GetWorkingDirectory();
+
+ const ProcessLaunchInfo::FileAction *file_action;
+ file_action = launch_info.GetFileActionForFD (STDIN_FILENO);
+ if (file_action)
+ {
+ if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
+ stdin_path = file_action->GetPath();
+ }
+ file_action = launch_info.GetFileActionForFD (STDOUT_FILENO);
+ if (file_action)
+ {
+ if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
+ stdout_path = file_action->GetPath();
+ }
+ file_action = launch_info.GetFileActionForFD (STDERR_FILENO);
+ if (file_action)
+ {
+ if (file_action->GetAction () == ProcessLaunchInfo::FileAction::eFileActionOpen)
+ stderr_path = file_action->GetPath();
+ }
+
+ // ::LogSetBitMask (GDBR_LOG_DEFAULT);
+ // ::LogSetOptions (LLDB_LOG_OPTION_THREADSAFE | LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_PROC_AND_THREAD);
+ // ::LogSetLogFile ("/dev/stdout");
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+
+ ObjectFile * object_file = exe_module->GetObjectFile();
+ if (object_file)
+ {
+ char host_port[128];
+ snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ());
+ char connect_url[128];
+ snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port);
+
+ // Make sure we aren't already connected?
+ if (!m_gdb_comm.IsConnected())
+ {
+ error = StartDebugserverProcess (host_port, launch_info);
+ if (error.Fail())
+ {
+ if (log)
+ log->Printf("failed to start debugserver process: %s", error.AsCString());
+ return error;
+ }
+
+ error = ConnectToDebugserver (connect_url);
+ }
+
+ if (error.Success())
+ {
+ lldb_utility::PseudoTerminal pty;
+ const bool disable_stdio = (launch_flags & eLaunchFlagDisableSTDIO) != 0;
+
+ // If the debugserver is local and we aren't disabling STDIO, lets use
+ // a pseudo terminal to instead of relying on the 'O' packets for stdio
+ // since 'O' packets can really slow down debugging if the inferior
+ // does a lot of output.
+ PlatformSP platform_sp (m_target.GetPlatform());
+ if (platform_sp && platform_sp->IsHost() && !disable_stdio)
+ {
+ const char *slave_name = NULL;
+ if (stdin_path == NULL || stdout_path == NULL || stderr_path == NULL)
+ {
+ if (pty.OpenFirstAvailableMaster(O_RDWR|O_NOCTTY, NULL, 0))
+ slave_name = pty.GetSlaveName (NULL, 0);
+ }
+ if (stdin_path == NULL)
+ stdin_path = slave_name;
+
+ if (stdout_path == NULL)
+ stdout_path = slave_name;
+
+ if (stderr_path == NULL)
+ stderr_path = slave_name;
+ }
+
+ // Set STDIN to /dev/null if we want STDIO disabled or if either
+ // STDOUT or STDERR have been set to something and STDIN hasn't
+ if (disable_stdio || (stdin_path == NULL && (stdout_path || stderr_path)))
+ stdin_path = "/dev/null";
+
+ // Set STDOUT to /dev/null if we want STDIO disabled or if either
+ // STDIN or STDERR have been set to something and STDOUT hasn't
+ if (disable_stdio || (stdout_path == NULL && (stdin_path || stderr_path)))
+ stdout_path = "/dev/null";
+
+ // Set STDERR to /dev/null if we want STDIO disabled or if either
+ // STDIN or STDOUT have been set to something and STDERR hasn't
+ if (disable_stdio || (stderr_path == NULL && (stdin_path || stdout_path)))
+ stderr_path = "/dev/null";
+
+ if (stdin_path)
+ m_gdb_comm.SetSTDIN (stdin_path);
+ if (stdout_path)
+ m_gdb_comm.SetSTDOUT (stdout_path);
+ if (stderr_path)
+ m_gdb_comm.SetSTDERR (stderr_path);
+
+ m_gdb_comm.SetDisableASLR (launch_flags & eLaunchFlagDisableASLR);
+
+ m_gdb_comm.SendLaunchArchPacket (m_target.GetArchitecture().GetArchitectureName());
+
+ if (working_dir && working_dir[0])
+ {
+ m_gdb_comm.SetWorkingDir (working_dir);
+ }
+
+ // Send the environment and the program + arguments after we connect
+ const Args &environment = launch_info.GetEnvironmentEntries();
+ if (environment.GetArgumentCount())
+ {
+ size_t num_environment_entries = environment.GetArgumentCount();
+ for (size_t i=0; i<num_environment_entries; ++i)
+ {
+ const char *env_entry = environment.GetArgumentAtIndex(i);
+ if (env_entry == NULL || m_gdb_comm.SendEnvironmentPacket(env_entry) != 0)
+ break;
+ }
+ }
+
+ const uint32_t old_packet_timeout = m_gdb_comm.SetPacketTimeout (10);
+ int arg_packet_err = m_gdb_comm.SendArgumentsPacket (launch_info.GetArguments().GetConstArgumentVector());
+ if (arg_packet_err == 0)
+ {
+ std::string error_str;
+ if (m_gdb_comm.GetLaunchSuccess (error_str))
+ {
+ SetID (m_gdb_comm.GetCurrentProcessID ());
+ }
+ else
+ {
+ error.SetErrorString (error_str.c_str());
+ }
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("'A' packet returned an error: %i", arg_packet_err);
+ }
+
+ m_gdb_comm.SetPacketTimeout (old_packet_timeout);
+
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ if (log)
+ log->Printf("failed to connect to debugserver: %s", error.AsCString());
+ KillDebugserverProcess ();
+ return error;
+ }
+
+ if (m_gdb_comm.SendPacketAndWaitForResponse("?", 1, m_last_stop_packet, false))
+ {
+ SetPrivateState (SetThreadStopInfo (m_last_stop_packet));
+
+ if (!disable_stdio)
+ {
+ if (pty.GetMasterFileDescriptor() != lldb_utility::PseudoTerminal::invalid_fd)
+ SetSTDIOFileDescriptor (pty.ReleaseMasterFileDescriptor());
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf("failed to connect to debugserver: %s", error.AsCString());
+ }
+ }
+ else
+ {
+ // Set our user ID to an invalid process ID.
+ SetID(LLDB_INVALID_PROCESS_ID);
+ error.SetErrorStringWithFormat ("failed to get object file from '%s' for arch %s",
+ exe_module->GetFileSpec().GetFilename().AsCString(),
+ exe_module->GetArchitecture().GetArchitectureName());
+ }
+ return error;
+
+}
+
+
+Error
+ProcessGDBRemote::ConnectToDebugserver (const char *connect_url)
+{
+ Error error;
+ // Sleep and wait a bit for debugserver to start to listen...
+ std::unique_ptr<ConnectionFileDescriptor> conn_ap(new ConnectionFileDescriptor());
+ if (conn_ap.get())
+ {
+ const uint32_t max_retry_count = 50;
+ uint32_t retry_count = 0;
+ while (!m_gdb_comm.IsConnected())
+ {
+ if (conn_ap->Connect(connect_url, &error) == eConnectionStatusSuccess)
+ {
+ m_gdb_comm.SetConnection (conn_ap.release());
+ break;
+ }
+ else if (error.WasInterrupted())
+ {
+ // If we were interrupted, don't keep retrying.
+ break;
+ }
+
+ retry_count++;
+
+ if (retry_count >= max_retry_count)
+ break;
+
+ usleep (100000);
+ }
+ }
+
+ if (!m_gdb_comm.IsConnected())
+ {
+ if (error.Success())
+ error.SetErrorString("not connected to remote gdb server");
+ return error;
+ }
+
+ // We always seem to be able to open a connection to a local port
+ // so we need to make sure we can then send data to it. If we can't
+ // then we aren't actually connected to anything, so try and do the
+ // handshake with the remote GDB server and make sure that goes
+ // alright.
+ if (!m_gdb_comm.HandshakeWithServer (NULL))
+ {
+ m_gdb_comm.Disconnect();
+ if (error.Success())
+ error.SetErrorString("not connected to remote gdb server");
+ return error;
+ }
+ m_gdb_comm.ResetDiscoverableSettings();
+ m_gdb_comm.QueryNoAckModeSupported ();
+ m_gdb_comm.GetThreadSuffixSupported ();
+ m_gdb_comm.GetListThreadsInStopReplySupported ();
+ m_gdb_comm.GetHostInfo ();
+ m_gdb_comm.GetVContSupported ('c');
+ m_gdb_comm.GetVAttachOrWaitSupported();
+
+ size_t num_cmds = GetExtraStartupCommands().GetArgumentCount();
+ for (size_t idx = 0; idx < num_cmds; idx++)
+ {
+ StringExtractorGDBRemote response;
+ m_gdb_comm.SendPacketAndWaitForResponse (GetExtraStartupCommands().GetArgumentAtIndex(idx), response, false);
+ }
+ return error;
+}
+
+void
+ProcessGDBRemote::DidLaunchOrAttach ()
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::DidLaunch()");
+ if (GetID() != LLDB_INVALID_PROCESS_ID)
+ {
+ m_dispatch_queue_offsets_addr = LLDB_INVALID_ADDRESS;
+
+ BuildDynamicRegisterInfo (false);
+
+ // See if the GDB server supports the qHostInfo information
+
+ ArchSpec gdb_remote_arch = m_gdb_comm.GetHostArchitecture();
+
+ // See if the GDB server supports the qProcessInfo packet, if so
+ // prefer that over the Host information as it will be more specific
+ // to our process.
+
+ if (m_gdb_comm.GetProcessArchitecture().IsValid())
+ gdb_remote_arch = m_gdb_comm.GetProcessArchitecture();
+
+ if (gdb_remote_arch.IsValid())
+ {
+ ArchSpec &target_arch = GetTarget().GetArchitecture();
+
+ if (target_arch.IsValid())
+ {
+ // If the remote host is ARM and we have apple as the vendor, then
+ // ARM executables and shared libraries can have mixed ARM architectures.
+ // You can have an armv6 executable, and if the host is armv7, then the
+ // system will load the best possible architecture for all shared libraries
+ // it has, so we really need to take the remote host architecture as our
+ // defacto architecture in this case.
+
+ if (gdb_remote_arch.GetMachine() == llvm::Triple::arm &&
+ gdb_remote_arch.GetTriple().getVendor() == llvm::Triple::Apple)
+ {
+ target_arch = gdb_remote_arch;
+ }
+ else
+ {
+ // Fill in what is missing in the triple
+ const llvm::Triple &remote_triple = gdb_remote_arch.GetTriple();
+ llvm::Triple &target_triple = target_arch.GetTriple();
+ if (target_triple.getVendorName().size() == 0)
+ {
+ target_triple.setVendor (remote_triple.getVendor());
+
+ if (target_triple.getOSName().size() == 0)
+ {
+ target_triple.setOS (remote_triple.getOS());
+
+ if (target_triple.getEnvironmentName().size() == 0)
+ target_triple.setEnvironment (remote_triple.getEnvironment());
+ }
+ }
+ }
+ }
+ else
+ {
+ // The target doesn't have a valid architecture yet, set it from
+ // the architecture we got from the remote GDB server
+ target_arch = gdb_remote_arch;
+ }
+ }
+ }
+}
+
+void
+ProcessGDBRemote::DidLaunch ()
+{
+ DidLaunchOrAttach ();
+}
+
+Error
+ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid)
+{
+ ProcessAttachInfo attach_info;
+ return DoAttachToProcessWithID(attach_pid, attach_info);
+}
+
+Error
+ProcessGDBRemote::DoAttachToProcessWithID (lldb::pid_t attach_pid, const ProcessAttachInfo &attach_info)
+{
+ Error error;
+ // Clear out and clean up from any current state
+ Clear();
+ if (attach_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ // Make sure we aren't already connected?
+ if (!m_gdb_comm.IsConnected())
+ {
+ char host_port[128];
+ snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ());
+ char connect_url[128];
+ snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port);
+
+ error = StartDebugserverProcess (host_port, attach_info);
+
+ if (error.Fail())
+ {
+ const char *error_string = error.AsCString();
+ if (error_string == NULL)
+ error_string = "unable to launch " DEBUGSERVER_BASENAME;
+
+ SetExitStatus (-1, error_string);
+ }
+ else
+ {
+ error = ConnectToDebugserver (connect_url);
+ }
+ }
+
+ if (error.Success())
+ {
+ char packet[64];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "vAttach;%" PRIx64, attach_pid);
+ SetID (attach_pid);
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (packet, packet_len));
+ }
+ }
+ return error;
+}
+
+size_t
+ProcessGDBRemote::AttachInputReaderCallback
+(
+ void *baton,
+ InputReader *reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len
+)
+{
+ if (notification == eInputReaderGotToken)
+ {
+ ProcessGDBRemote *gdb_process = (ProcessGDBRemote *)baton;
+ if (gdb_process->m_waiting_for_attach)
+ gdb_process->m_waiting_for_attach = false;
+ reader->SetIsDone(true);
+ return 1;
+ }
+ return 0;
+}
+
+Error
+ProcessGDBRemote::DoAttachToProcessWithName (const char *process_name, bool wait_for_launch, const ProcessAttachInfo &attach_info)
+{
+ Error error;
+ // Clear out and clean up from any current state
+ Clear();
+
+ if (process_name && process_name[0])
+ {
+ // Make sure we aren't already connected?
+ if (!m_gdb_comm.IsConnected())
+ {
+ char host_port[128];
+ snprintf (host_port, sizeof(host_port), "localhost:%u", get_random_port ());
+ char connect_url[128];
+ snprintf (connect_url, sizeof(connect_url), "connect://%s", host_port);
+
+ error = StartDebugserverProcess (host_port, attach_info);
+ if (error.Fail())
+ {
+ const char *error_string = error.AsCString();
+ if (error_string == NULL)
+ error_string = "unable to launch " DEBUGSERVER_BASENAME;
+
+ SetExitStatus (-1, error_string);
+ }
+ else
+ {
+ error = ConnectToDebugserver (connect_url);
+ }
+ }
+
+ if (error.Success())
+ {
+ StreamString packet;
+
+ if (wait_for_launch)
+ {
+ if (!m_gdb_comm.GetVAttachOrWaitSupported())
+ {
+ packet.PutCString ("vAttachWait");
+ }
+ else
+ {
+ if (attach_info.GetIgnoreExisting())
+ packet.PutCString("vAttachWait");
+ else
+ packet.PutCString ("vAttachOrWait");
+ }
+ }
+ else
+ packet.PutCString("vAttachName");
+ packet.PutChar(';');
+ packet.PutBytesAsRawHex8(process_name, strlen(process_name), lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder());
+
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (packet.GetData(), packet.GetSize()));
+
+ }
+ }
+ return error;
+}
+
+
+void
+ProcessGDBRemote::DidAttach ()
+{
+ DidLaunchOrAttach ();
+}
+
+
+Error
+ProcessGDBRemote::WillResume ()
+{
+ m_continue_c_tids.clear();
+ m_continue_C_tids.clear();
+ m_continue_s_tids.clear();
+ m_continue_S_tids.clear();
+ return Error();
+}
+
+Error
+ProcessGDBRemote::DoResume ()
+{
+ Error error;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::Resume()");
+
+ Listener listener ("gdb-remote.resume-packet-sent");
+ if (listener.StartListeningForEvents (&m_gdb_comm, GDBRemoteCommunication::eBroadcastBitRunPacketSent))
+ {
+ listener.StartListeningForEvents (&m_async_broadcaster, ProcessGDBRemote::eBroadcastBitAsyncThreadDidExit);
+
+ const size_t num_threads = GetThreadList().GetSize();
+
+ StreamString continue_packet;
+ bool continue_packet_error = false;
+ if (m_gdb_comm.HasAnyVContSupport ())
+ {
+ if (m_continue_c_tids.size() == num_threads)
+ {
+ // All threads are continuing, just send a "c" packet
+ continue_packet.PutCString ("c");
+ }
+ else
+ {
+ continue_packet.PutCString ("vCont");
+
+ if (!m_continue_c_tids.empty())
+ {
+ if (m_gdb_comm.GetVContSupported ('c'))
+ {
+ for (tid_collection::const_iterator t_pos = m_continue_c_tids.begin(), t_end = m_continue_c_tids.end(); t_pos != t_end; ++t_pos)
+ continue_packet.Printf(";c:%4.4" PRIx64, *t_pos);
+ }
+ else
+ continue_packet_error = true;
+ }
+
+ if (!continue_packet_error && !m_continue_C_tids.empty())
+ {
+ if (m_gdb_comm.GetVContSupported ('C'))
+ {
+ for (tid_sig_collection::const_iterator s_pos = m_continue_C_tids.begin(), s_end = m_continue_C_tids.end(); s_pos != s_end; ++s_pos)
+ continue_packet.Printf(";C%2.2x:%4.4" PRIx64, s_pos->second, s_pos->first);
+ }
+ else
+ continue_packet_error = true;
+ }
+
+ if (!continue_packet_error && !m_continue_s_tids.empty())
+ {
+ if (m_gdb_comm.GetVContSupported ('s'))
+ {
+ for (tid_collection::const_iterator t_pos = m_continue_s_tids.begin(), t_end = m_continue_s_tids.end(); t_pos != t_end; ++t_pos)
+ continue_packet.Printf(";s:%4.4" PRIx64, *t_pos);
+ }
+ else
+ continue_packet_error = true;
+ }
+
+ if (!continue_packet_error && !m_continue_S_tids.empty())
+ {
+ if (m_gdb_comm.GetVContSupported ('S'))
+ {
+ for (tid_sig_collection::const_iterator s_pos = m_continue_S_tids.begin(), s_end = m_continue_S_tids.end(); s_pos != s_end; ++s_pos)
+ continue_packet.Printf(";S%2.2x:%4.4" PRIx64, s_pos->second, s_pos->first);
+ }
+ else
+ continue_packet_error = true;
+ }
+
+ if (continue_packet_error)
+ continue_packet.GetString().clear();
+ }
+ }
+ else
+ continue_packet_error = true;
+
+ if (continue_packet_error)
+ {
+ // Either no vCont support, or we tried to use part of the vCont
+ // packet that wasn't supported by the remote GDB server.
+ // We need to try and make a simple packet that can do our continue
+ const size_t num_continue_c_tids = m_continue_c_tids.size();
+ const size_t num_continue_C_tids = m_continue_C_tids.size();
+ const size_t num_continue_s_tids = m_continue_s_tids.size();
+ const size_t num_continue_S_tids = m_continue_S_tids.size();
+ if (num_continue_c_tids > 0)
+ {
+ if (num_continue_c_tids == num_threads)
+ {
+ // All threads are resuming...
+ m_gdb_comm.SetCurrentThreadForRun (-1);
+ continue_packet.PutChar ('c');
+ continue_packet_error = false;
+ }
+ else if (num_continue_c_tids == 1 &&
+ num_continue_C_tids == 0 &&
+ num_continue_s_tids == 0 &&
+ num_continue_S_tids == 0 )
+ {
+ // Only one thread is continuing
+ m_gdb_comm.SetCurrentThreadForRun (m_continue_c_tids.front());
+ continue_packet.PutChar ('c');
+ continue_packet_error = false;
+ }
+ }
+
+ if (continue_packet_error && num_continue_C_tids > 0)
+ {
+ if ((num_continue_C_tids + num_continue_c_tids) == num_threads &&
+ num_continue_C_tids > 0 &&
+ num_continue_s_tids == 0 &&
+ num_continue_S_tids == 0 )
+ {
+ const int continue_signo = m_continue_C_tids.front().second;
+ // Only one thread is continuing
+ if (num_continue_C_tids > 1)
+ {
+ // More that one thread with a signal, yet we don't have
+ // vCont support and we are being asked to resume each
+ // thread with a signal, we need to make sure they are
+ // all the same signal, or we can't issue the continue
+ // accurately with the current support...
+ if (num_continue_C_tids > 1)
+ {
+ continue_packet_error = false;
+ for (size_t i=1; i<m_continue_C_tids.size(); ++i)
+ {
+ if (m_continue_C_tids[i].second != continue_signo)
+ continue_packet_error = true;
+ }
+ }
+ if (!continue_packet_error)
+ m_gdb_comm.SetCurrentThreadForRun (-1);
+ }
+ else
+ {
+ // Set the continue thread ID
+ continue_packet_error = false;
+ m_gdb_comm.SetCurrentThreadForRun (m_continue_C_tids.front().first);
+ }
+ if (!continue_packet_error)
+ {
+ // Add threads continuing with the same signo...
+ continue_packet.Printf("C%2.2x", continue_signo);
+ }
+ }
+ }
+
+ if (continue_packet_error && num_continue_s_tids > 0)
+ {
+ if (num_continue_s_tids == num_threads)
+ {
+ // All threads are resuming...
+ m_gdb_comm.SetCurrentThreadForRun (-1);
+ continue_packet.PutChar ('s');
+ continue_packet_error = false;
+ }
+ else if (num_continue_c_tids == 0 &&
+ num_continue_C_tids == 0 &&
+ num_continue_s_tids == 1 &&
+ num_continue_S_tids == 0 )
+ {
+ // Only one thread is stepping
+ m_gdb_comm.SetCurrentThreadForRun (m_continue_s_tids.front());
+ continue_packet.PutChar ('s');
+ continue_packet_error = false;
+ }
+ }
+
+ if (!continue_packet_error && num_continue_S_tids > 0)
+ {
+ if (num_continue_S_tids == num_threads)
+ {
+ const int step_signo = m_continue_S_tids.front().second;
+ // Are all threads trying to step with the same signal?
+ continue_packet_error = false;
+ if (num_continue_S_tids > 1)
+ {
+ for (size_t i=1; i<num_threads; ++i)
+ {
+ if (m_continue_S_tids[i].second != step_signo)
+ continue_packet_error = true;
+ }
+ }
+ if (!continue_packet_error)
+ {
+ // Add threads stepping with the same signo...
+ m_gdb_comm.SetCurrentThreadForRun (-1);
+ continue_packet.Printf("S%2.2x", step_signo);
+ }
+ }
+ else if (num_continue_c_tids == 0 &&
+ num_continue_C_tids == 0 &&
+ num_continue_s_tids == 0 &&
+ num_continue_S_tids == 1 )
+ {
+ // Only one thread is stepping with signal
+ m_gdb_comm.SetCurrentThreadForRun (m_continue_S_tids.front().first);
+ continue_packet.Printf("S%2.2x", m_continue_S_tids.front().second);
+ continue_packet_error = false;
+ }
+ }
+ }
+
+ if (continue_packet_error)
+ {
+ error.SetErrorString ("can't make continue packet for this resume");
+ }
+ else
+ {
+ EventSP event_sp;
+ TimeValue timeout;
+ timeout = TimeValue::Now();
+ timeout.OffsetWithSeconds (5);
+ if (!IS_VALID_LLDB_HOST_THREAD(m_async_thread))
+ {
+ error.SetErrorString ("Trying to resume but the async thread is dead.");
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoResume: Trying to resume but the async thread is dead.");
+ return error;
+ }
+
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncContinue, new EventDataBytes (continue_packet.GetData(), continue_packet.GetSize()));
+
+ if (listener.WaitForEvent (&timeout, event_sp) == false)
+ {
+ error.SetErrorString("Resume timed out.");
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoResume: Resume timed out.");
+ }
+ else if (event_sp->BroadcasterIs (&m_async_broadcaster))
+ {
+ error.SetErrorString ("Broadcast continue, but the async thread was killed before we got an ack back.");
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoResume: Broadcast continue, but the async thread was killed before we got an ack back.");
+ return error;
+ }
+ }
+ }
+
+ return error;
+}
+
+void
+ProcessGDBRemote::ClearThreadIDList ()
+{
+ Mutex::Locker locker(m_thread_list_real.GetMutex());
+ m_thread_ids.clear();
+}
+
+bool
+ProcessGDBRemote::UpdateThreadIDList ()
+{
+ Mutex::Locker locker(m_thread_list_real.GetMutex());
+ bool sequence_mutex_unavailable = false;
+ m_gdb_comm.GetCurrentThreadIDs (m_thread_ids, sequence_mutex_unavailable);
+ if (sequence_mutex_unavailable)
+ {
+ return false; // We just didn't get the list
+ }
+ return true;
+}
+
+bool
+ProcessGDBRemote::UpdateThreadList (ThreadList &old_thread_list, ThreadList &new_thread_list)
+{
+ // locker will keep a mutex locked until it goes out of scope
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_THREAD));
+ if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
+ log->Printf ("ProcessGDBRemote::%s (pid = %" PRIu64 ")", __FUNCTION__, GetID());
+
+ size_t num_thread_ids = m_thread_ids.size();
+ // The "m_thread_ids" thread ID list should always be updated after each stop
+ // reply packet, but in case it isn't, update it here.
+ if (num_thread_ids == 0)
+ {
+ if (!UpdateThreadIDList ())
+ return false;
+ num_thread_ids = m_thread_ids.size();
+ }
+
+ ThreadList old_thread_list_copy(old_thread_list);
+ if (num_thread_ids > 0)
+ {
+ for (size_t i=0; i<num_thread_ids; ++i)
+ {
+ tid_t tid = m_thread_ids[i];
+ ThreadSP thread_sp (old_thread_list_copy.RemoveThreadByProtocolID(tid, false));
+ if (!thread_sp)
+ {
+ thread_sp.reset (new ThreadGDBRemote (*this, tid));
+ if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
+ log->Printf(
+ "ProcessGDBRemote::%s Making new thread: %p for thread ID: 0x%" PRIx64 ".\n",
+ __FUNCTION__,
+ thread_sp.get(),
+ thread_sp->GetID());
+ }
+ else
+ {
+ if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
+ log->Printf(
+ "ProcessGDBRemote::%s Found old thread: %p for thread ID: 0x%" PRIx64 ".\n",
+ __FUNCTION__,
+ thread_sp.get(),
+ thread_sp->GetID());
+ }
+ new_thread_list.AddThread(thread_sp);
+ }
+ }
+
+ // Whatever that is left in old_thread_list_copy are not
+ // present in new_thread_list. Remove non-existent threads from internal id table.
+ size_t old_num_thread_ids = old_thread_list_copy.GetSize(false);
+ for (size_t i=0; i<old_num_thread_ids; i++)
+ {
+ ThreadSP old_thread_sp(old_thread_list_copy.GetThreadAtIndex (i, false));
+ if (old_thread_sp)
+ {
+ lldb::tid_t old_thread_id = old_thread_sp->GetProtocolID();
+ m_thread_id_to_index_id_map.erase(old_thread_id);
+ }
+ }
+
+ return true;
+}
+
+
+StateType
+ProcessGDBRemote::SetThreadStopInfo (StringExtractor& stop_packet)
+{
+ stop_packet.SetFilePos (0);
+ const char stop_type = stop_packet.GetChar();
+ switch (stop_type)
+ {
+ case 'T':
+ case 'S':
+ {
+ // This is a bit of a hack, but is is required. If we did exec, we
+ // need to clear our thread lists and also know to rebuild our dynamic
+ // register info before we lookup and threads and populate the expedited
+ // register values so we need to know this right away so we can cleanup
+ // and update our registers.
+ const uint32_t stop_id = GetStopID();
+ if (stop_id == 0)
+ {
+ // Our first stop, make sure we have a process ID, and also make
+ // sure we know about our registers
+ if (GetID() == LLDB_INVALID_PROCESS_ID)
+ {
+ lldb::pid_t pid = m_gdb_comm.GetCurrentProcessID ();
+ if (pid != LLDB_INVALID_PROCESS_ID)
+ SetID (pid);
+ }
+ BuildDynamicRegisterInfo (true);
+ }
+ // Stop with signal and thread info
+ const uint8_t signo = stop_packet.GetHexU8();
+ std::string name;
+ std::string value;
+ std::string thread_name;
+ std::string reason;
+ std::string description;
+ uint32_t exc_type = 0;
+ std::vector<addr_t> exc_data;
+ addr_t thread_dispatch_qaddr = LLDB_INVALID_ADDRESS;
+ ThreadSP thread_sp;
+ ThreadGDBRemote *gdb_thread = NULL;
+
+ while (stop_packet.GetNameColonValue(name, value))
+ {
+ if (name.compare("metype") == 0)
+ {
+ // exception type in big endian hex
+ exc_type = Args::StringToUInt32 (value.c_str(), 0, 16);
+ }
+ else if (name.compare("medata") == 0)
+ {
+ // exception data in big endian hex
+ exc_data.push_back(Args::StringToUInt64 (value.c_str(), 0, 16));
+ }
+ else if (name.compare("thread") == 0)
+ {
+ // thread in big endian hex
+ lldb::tid_t tid = Args::StringToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16);
+ // m_thread_list_real does have its own mutex, but we need to
+ // hold onto the mutex between the call to m_thread_list_real.FindThreadByID(...)
+ // and the m_thread_list_real.AddThread(...) so it doesn't change on us
+ Mutex::Locker locker (m_thread_list_real.GetMutex ());
+ thread_sp = m_thread_list_real.FindThreadByProtocolID(tid, false);
+
+ if (!thread_sp)
+ {
+ // Create the thread if we need to
+ thread_sp.reset (new ThreadGDBRemote (*this, tid));
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_THREAD));
+ if (log && log->GetMask().Test(GDBR_LOG_VERBOSE))
+ log->Printf ("ProcessGDBRemote::%s Adding new thread: %p for thread ID: 0x%" PRIx64 ".\n",
+ __FUNCTION__,
+ thread_sp.get(),
+ thread_sp->GetID());
+
+ m_thread_list_real.AddThread(thread_sp);
+ }
+ gdb_thread = static_cast<ThreadGDBRemote *> (thread_sp.get());
+
+ }
+ else if (name.compare("threads") == 0)
+ {
+ Mutex::Locker locker(m_thread_list_real.GetMutex());
+ m_thread_ids.clear();
+ // A comma separated list of all threads in the current
+ // process that includes the thread for this stop reply
+ // packet
+ size_t comma_pos;
+ lldb::tid_t tid;
+ while ((comma_pos = value.find(',')) != std::string::npos)
+ {
+ value[comma_pos] = '\0';
+ // thread in big endian hex
+ tid = Args::StringToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16);
+ if (tid != LLDB_INVALID_THREAD_ID)
+ m_thread_ids.push_back (tid);
+ value.erase(0, comma_pos + 1);
+
+ }
+ tid = Args::StringToUInt64 (value.c_str(), LLDB_INVALID_THREAD_ID, 16);
+ if (tid != LLDB_INVALID_THREAD_ID)
+ m_thread_ids.push_back (tid);
+ }
+ else if (name.compare("hexname") == 0)
+ {
+ StringExtractor name_extractor;
+ // Swap "value" over into "name_extractor"
+ name_extractor.GetStringRef().swap(value);
+ // Now convert the HEX bytes into a string value
+ name_extractor.GetHexByteString (value);
+ thread_name.swap (value);
+ }
+ else if (name.compare("name") == 0)
+ {
+ thread_name.swap (value);
+ }
+ else if (name.compare("qaddr") == 0)
+ {
+ thread_dispatch_qaddr = Args::StringToUInt64 (value.c_str(), 0, 16);
+ }
+ else if (name.compare("reason") == 0)
+ {
+ reason.swap(value);
+ }
+ else if (name.compare("description") == 0)
+ {
+ StringExtractor desc_extractor;
+ // Swap "value" over into "name_extractor"
+ desc_extractor.GetStringRef().swap(value);
+ // Now convert the HEX bytes into a string value
+ desc_extractor.GetHexByteString (thread_name);
+ }
+ else if (name.size() == 2 && ::isxdigit(name[0]) && ::isxdigit(name[1]))
+ {
+ // We have a register number that contains an expedited
+ // register value. Lets supply this register to our thread
+ // so it won't have to go and read it.
+ if (gdb_thread)
+ {
+ uint32_t reg = Args::StringToUInt32 (name.c_str(), UINT32_MAX, 16);
+
+ if (reg != UINT32_MAX)
+ {
+ StringExtractor reg_value_extractor;
+ // Swap "value" over into "reg_value_extractor"
+ reg_value_extractor.GetStringRef().swap(value);
+ if (!gdb_thread->PrivateSetRegisterValue (reg, reg_value_extractor))
+ {
+ Host::SetCrashDescriptionWithFormat("Setting thread register '%s' (decoded to %u (0x%x)) with value '%s' for stop packet: '%s'",
+ name.c_str(),
+ reg,
+ reg,
+ reg_value_extractor.GetStringRef().c_str(),
+ stop_packet.GetStringRef().c_str());
+ }
+ }
+ }
+ }
+ }
+
+ if (thread_sp)
+ {
+ // Clear the stop info just in case we don't set it to anything
+ thread_sp->SetStopInfo (StopInfoSP());
+
+ gdb_thread->SetThreadDispatchQAddr (thread_dispatch_qaddr);
+ gdb_thread->SetName (thread_name.empty() ? NULL : thread_name.c_str());
+ if (exc_type != 0)
+ {
+ const size_t exc_data_size = exc_data.size();
+
+ thread_sp->SetStopInfo (StopInfoMachException::CreateStopReasonWithMachException (*thread_sp,
+ exc_type,
+ exc_data_size,
+ exc_data_size >= 1 ? exc_data[0] : 0,
+ exc_data_size >= 2 ? exc_data[1] : 0,
+ exc_data_size >= 3 ? exc_data[2] : 0));
+ }
+ else
+ {
+ bool handled = false;
+ bool did_exec = false;
+ if (!reason.empty())
+ {
+ if (reason.compare("trace") == 0)
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp));
+ handled = true;
+ }
+ else if (reason.compare("breakpoint") == 0)
+ {
+ addr_t pc = thread_sp->GetRegisterContext()->GetPC();
+ lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc);
+ if (bp_site_sp)
+ {
+ // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ handled = true;
+ if (bp_site_sp->ValidForThisThread (thread_sp.get()))
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID()));
+ }
+ else
+ {
+ StopInfoSP invalid_stop_info_sp;
+ thread_sp->SetStopInfo (invalid_stop_info_sp);
+ }
+ }
+
+ }
+ else if (reason.compare("trap") == 0)
+ {
+ // Let the trap just use the standard signal stop reason below...
+ }
+ else if (reason.compare("watchpoint") == 0)
+ {
+ break_id_t watch_id = LLDB_INVALID_WATCH_ID;
+ // TODO: locate the watchpoint somehow...
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithWatchpointID (*thread_sp, watch_id));
+ handled = true;
+ }
+ else if (reason.compare("exception") == 0)
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException(*thread_sp, description.c_str()));
+ handled = true;
+ }
+ else if (reason.compare("exec") == 0)
+ {
+ did_exec = true;
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithExec(*thread_sp));
+ handled = true;
+ }
+ }
+
+ if (signo && did_exec == false)
+ {
+ if (signo == SIGTRAP)
+ {
+ // Currently we are going to assume SIGTRAP means we are either
+ // hitting a breakpoint or hardware single stepping.
+ handled = true;
+ addr_t pc = thread_sp->GetRegisterContext()->GetPC();
+ lldb::BreakpointSiteSP bp_site_sp = thread_sp->GetProcess()->GetBreakpointSiteList().FindByAddress(pc);
+
+ if (bp_site_sp)
+ {
+ // If the breakpoint is for this thread, then we'll report the hit, but if it is for another thread,
+ // we can just report no reason. We don't need to worry about stepping over the breakpoint here, that
+ // will be taken care of when the thread resumes and notices that there's a breakpoint under the pc.
+ if (bp_site_sp->ValidForThisThread (thread_sp.get()))
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithBreakpointSiteID (*thread_sp, bp_site_sp->GetID()));
+ }
+ else
+ {
+ StopInfoSP invalid_stop_info_sp;
+ thread_sp->SetStopInfo (invalid_stop_info_sp);
+ }
+ }
+ else
+ {
+ // If we were stepping then assume the stop was the result of the trace. If we were
+ // not stepping then report the SIGTRAP.
+ // FIXME: We are still missing the case where we single step over a trap instruction.
+ if (thread_sp->GetTemporaryResumeState() == eStateStepping)
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonToTrace (*thread_sp));
+ else
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal(*thread_sp, signo));
+ }
+ }
+ if (!handled)
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithSignal (*thread_sp, signo));
+ }
+
+ if (!description.empty())
+ {
+ lldb::StopInfoSP stop_info_sp (thread_sp->GetStopInfo ());
+ if (stop_info_sp)
+ {
+ stop_info_sp->SetDescription (description.c_str());
+ }
+ else
+ {
+ thread_sp->SetStopInfo (StopInfo::CreateStopReasonWithException (*thread_sp, description.c_str()));
+ }
+ }
+ }
+ }
+ return eStateStopped;
+ }
+ break;
+
+ case 'W':
+ // process exited
+ return eStateExited;
+
+ default:
+ break;
+ }
+ return eStateInvalid;
+}
+
+void
+ProcessGDBRemote::RefreshStateAfterStop ()
+{
+ Mutex::Locker locker(m_thread_list_real.GetMutex());
+ m_thread_ids.clear();
+ // Set the thread stop info. It might have a "threads" key whose value is
+ // a list of all thread IDs in the current process, so m_thread_ids might
+ // get set.
+ SetThreadStopInfo (m_last_stop_packet);
+ // Check to see if SetThreadStopInfo() filled in m_thread_ids?
+ if (m_thread_ids.empty())
+ {
+ // No, we need to fetch the thread list manually
+ UpdateThreadIDList();
+ }
+
+ // Let all threads recover from stopping and do any clean up based
+ // on the previous thread state (if any).
+ m_thread_list_real.RefreshStateAfterStop();
+
+}
+
+Error
+ProcessGDBRemote::DoHalt (bool &caused_stop)
+{
+ Error error;
+
+ bool timed_out = false;
+ Mutex::Locker locker;
+
+ if (m_public_state.GetValue() == eStateAttaching)
+ {
+ // We are being asked to halt during an attach. We need to just close
+ // our file handle and debugserver will go away, and we can be done...
+ m_gdb_comm.Disconnect();
+ }
+ else
+ {
+ if (!m_gdb_comm.SendInterrupt (locker, 2, timed_out))
+ {
+ if (timed_out)
+ error.SetErrorString("timed out sending interrupt packet");
+ else
+ error.SetErrorString("unknown error sending interrupt packet");
+ }
+
+ caused_stop = m_gdb_comm.GetInterruptWasSent ();
+ }
+ return error;
+}
+
+Error
+ProcessGDBRemote::DoDetach(bool keep_stopped)
+{
+ Error error;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDetach(keep_stopped: %i)", keep_stopped);
+
+ DisableAllBreakpointSites ();
+
+ m_thread_list.DiscardThreadPlans();
+
+ error = m_gdb_comm.Detach (keep_stopped);
+ if (log)
+ {
+ if (error.Success())
+ log->PutCString ("ProcessGDBRemote::DoDetach() detach packet sent successfully");
+ else
+ log->Printf ("ProcessGDBRemote::DoDetach() detach packet send failed: %s", error.AsCString() ? error.AsCString() : "<unknown error>");
+ }
+
+ if (!error.Success())
+ return error;
+
+ // Sleep for one second to let the process get all detached...
+ StopAsyncThread ();
+
+ SetPrivateState (eStateDetached);
+ ResumePrivateStateThread();
+
+ //KillDebugserverProcess ();
+ return error;
+}
+
+
+Error
+ProcessGDBRemote::DoDestroy ()
+{
+ Error error;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy()");
+
+ // There is a bug in older iOS debugservers where they don't shut down the process
+ // they are debugging properly. If the process is sitting at a breakpoint or an exception,
+ // this can cause problems with restarting. So we check to see if any of our threads are stopped
+ // at a breakpoint, and if so we remove all the breakpoints, resume the process, and THEN
+ // destroy it again.
+ //
+ // Note, we don't have a good way to test the version of debugserver, but I happen to know that
+ // the set of all the iOS debugservers which don't support GetThreadSuffixSupported() and that of
+ // the debugservers with this bug are equal. There really should be a better way to test this!
+ //
+ // We also use m_destroy_tried_resuming to make sure we only do this once, if we resume and then halt and
+ // get called here to destroy again and we're still at a breakpoint or exception, then we should
+ // just do the straight-forward kill.
+ //
+ // And of course, if we weren't able to stop the process by the time we get here, it isn't
+ // necessary (or helpful) to do any of this.
+
+ if (!m_gdb_comm.GetThreadSuffixSupported() && m_public_state.GetValue() != eStateRunning)
+ {
+ PlatformSP platform_sp = GetTarget().GetPlatform();
+
+ // FIXME: These should be ConstStrings so we aren't doing strcmp'ing.
+ if (platform_sp
+ && platform_sp->GetName()
+ && platform_sp->GetName() == PlatformRemoteiOS::GetPluginNameStatic())
+ {
+ if (m_destroy_tried_resuming)
+ {
+ if (log)
+ log->PutCString ("ProcessGDBRemote::DoDestroy()Tried resuming to destroy once already, not doing it again.");
+ }
+ else
+ {
+ // At present, the plans are discarded and the breakpoints disabled Process::Destroy,
+ // but we really need it to happen here and it doesn't matter if we do it twice.
+ m_thread_list.DiscardThreadPlans();
+ DisableAllBreakpointSites();
+
+ bool stop_looks_like_crash = false;
+ ThreadList &threads = GetThreadList();
+
+ {
+ Mutex::Locker locker(threads.GetMutex());
+
+ size_t num_threads = threads.GetSize();
+ for (size_t i = 0; i < num_threads; i++)
+ {
+ ThreadSP thread_sp = threads.GetThreadAtIndex(i);
+ StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo();
+ StopReason reason = eStopReasonInvalid;
+ if (stop_info_sp)
+ reason = stop_info_sp->GetStopReason();
+ if (reason == eStopReasonBreakpoint
+ || reason == eStopReasonException)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy() - thread: 0x%4.4" PRIx64 " stopped with reason: %s.",
+ thread_sp->GetProtocolID(),
+ stop_info_sp->GetDescription());
+ stop_looks_like_crash = true;
+ break;
+ }
+ }
+ }
+
+ if (stop_looks_like_crash)
+ {
+ if (log)
+ log->PutCString ("ProcessGDBRemote::DoDestroy() - Stopped at a breakpoint, continue and then kill.");
+ m_destroy_tried_resuming = true;
+
+ // If we are going to run again before killing, it would be good to suspend all the threads
+ // before resuming so they won't get into more trouble. Sadly, for the threads stopped with
+ // the breakpoint or exception, the exception doesn't get cleared if it is suspended, so we do
+ // have to run the risk of letting those threads proceed a bit.
+
+ {
+ Mutex::Locker locker(threads.GetMutex());
+
+ size_t num_threads = threads.GetSize();
+ for (size_t i = 0; i < num_threads; i++)
+ {
+ ThreadSP thread_sp = threads.GetThreadAtIndex(i);
+ StopInfoSP stop_info_sp = thread_sp->GetPrivateStopInfo();
+ StopReason reason = eStopReasonInvalid;
+ if (stop_info_sp)
+ reason = stop_info_sp->GetStopReason();
+ if (reason != eStopReasonBreakpoint
+ && reason != eStopReasonException)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy() - Suspending thread: 0x%4.4" PRIx64 " before running.",
+ thread_sp->GetProtocolID());
+ thread_sp->SetResumeState(eStateSuspended);
+ }
+ }
+ }
+ Resume ();
+ return Destroy();
+ }
+ }
+ }
+ }
+
+ // Interrupt if our inferior is running...
+ int exit_status = SIGABRT;
+ std::string exit_string;
+
+ if (m_gdb_comm.IsConnected())
+ {
+ if (m_public_state.GetValue() != eStateAttaching)
+ {
+
+ StringExtractorGDBRemote response;
+ bool send_async = true;
+ const uint32_t old_packet_timeout = m_gdb_comm.SetPacketTimeout (3);
+
+ if (m_gdb_comm.SendPacketAndWaitForResponse("k", 1, response, send_async))
+ {
+ char packet_cmd = response.GetChar(0);
+
+ if (packet_cmd == 'W' || packet_cmd == 'X')
+ {
+ SetLastStopPacket (response);
+ ClearThreadIDList ();
+ exit_status = response.GetHexU8();
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy - got unexpected response to k packet: %s", response.GetStringRef().c_str());
+ exit_string.assign("got unexpected response to k packet: ");
+ exit_string.append(response.GetStringRef());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy - failed to send k packet");
+ exit_string.assign("failed to send the k packet");
+ }
+
+ m_gdb_comm.SetPacketTimeout(old_packet_timeout);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoDestroy - failed to send k packet");
+ exit_string.assign ("killed or interrupted while attaching.");
+ }
+ }
+ else
+ {
+ // If we missed setting the exit status on the way out, do it here.
+ // NB set exit status can be called multiple times, the first one sets the status.
+ exit_string.assign("destroying when not connected to debugserver");
+ }
+
+ SetExitStatus(exit_status, exit_string.c_str());
+
+ StopAsyncThread ();
+ KillDebugserverProcess ();
+ return error;
+}
+
+void
+ProcessGDBRemote::SetLastStopPacket (const StringExtractorGDBRemote &response)
+{
+ lldb_private::Mutex::Locker locker (m_last_stop_packet_mutex);
+ const bool did_exec = response.GetStringRef().find(";reason:exec;") != std::string::npos;
+ if (did_exec)
+ {
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::SetLastStopPacket () - detected exec");
+
+ m_thread_list_real.Clear();
+ m_thread_list.Clear();
+ BuildDynamicRegisterInfo (true);
+ m_gdb_comm.ResetDiscoverableSettings();
+ }
+ m_last_stop_packet = response;
+}
+
+
+//------------------------------------------------------------------
+// Process Queries
+//------------------------------------------------------------------
+
+bool
+ProcessGDBRemote::IsAlive ()
+{
+ return m_gdb_comm.IsConnected() && m_private_state.GetValue() != eStateExited;
+}
+
+addr_t
+ProcessGDBRemote::GetImageInfoAddress()
+{
+ return m_gdb_comm.GetShlibInfoAddr();
+}
+
+//------------------------------------------------------------------
+// Process Memory
+//------------------------------------------------------------------
+size_t
+ProcessGDBRemote::DoReadMemory (addr_t addr, void *buf, size_t size, Error &error)
+{
+ if (size > m_max_memory_size)
+ {
+ // Keep memory read sizes down to a sane limit. This function will be
+ // called multiple times in order to complete the task by
+ // lldb_private::Process so it is ok to do this.
+ size = m_max_memory_size;
+ }
+
+ char packet[64];
+ const int packet_len = ::snprintf (packet, sizeof(packet), "m%" PRIx64 ",%" PRIx64, (uint64_t)addr, (uint64_t)size);
+ assert (packet_len + 1 < (int)sizeof(packet));
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet, packet_len, response, true))
+ {
+ if (response.IsNormalResponse())
+ {
+ error.Clear();
+ return response.GetHexBytes(buf, size, '\xdd');
+ }
+ else if (response.IsErrorResponse())
+ error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, addr);
+ else if (response.IsUnsupportedResponse())
+ error.SetErrorStringWithFormat("GDB server does not support reading memory");
+ else
+ error.SetErrorStringWithFormat("unexpected response to GDB server memory read packet '%s': '%s'", packet, response.GetStringRef().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("failed to send packet: '%s'", packet);
+ }
+ return 0;
+}
+
+size_t
+ProcessGDBRemote::DoWriteMemory (addr_t addr, const void *buf, size_t size, Error &error)
+{
+ if (size > m_max_memory_size)
+ {
+ // Keep memory read sizes down to a sane limit. This function will be
+ // called multiple times in order to complete the task by
+ // lldb_private::Process so it is ok to do this.
+ size = m_max_memory_size;
+ }
+
+ StreamString packet;
+ packet.Printf("M%" PRIx64 ",%" PRIx64 ":", addr, (uint64_t)size);
+ packet.PutBytesAsRawHex8(buf, size, lldb::endian::InlHostByteOrder(), lldb::endian::InlHostByteOrder());
+ StringExtractorGDBRemote response;
+ if (m_gdb_comm.SendPacketAndWaitForResponse(packet.GetData(), packet.GetSize(), response, true))
+ {
+ if (response.IsOKResponse())
+ {
+ error.Clear();
+ return size;
+ }
+ else if (response.IsErrorResponse())
+ error.SetErrorStringWithFormat("memory write failed for 0x%" PRIx64, addr);
+ else if (response.IsUnsupportedResponse())
+ error.SetErrorStringWithFormat("GDB server does not support writing memory");
+ else
+ error.SetErrorStringWithFormat("unexpected response to GDB server memory write packet '%s': '%s'", packet.GetString().c_str(), response.GetStringRef().c_str());
+ }
+ else
+ {
+ error.SetErrorStringWithFormat("failed to send packet: '%s'", packet.GetString().c_str());
+ }
+ return 0;
+}
+
+lldb::addr_t
+ProcessGDBRemote::DoAllocateMemory (size_t size, uint32_t permissions, Error &error)
+{
+ addr_t allocated_addr = LLDB_INVALID_ADDRESS;
+
+ LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory();
+ switch (supported)
+ {
+ case eLazyBoolCalculate:
+ case eLazyBoolYes:
+ allocated_addr = m_gdb_comm.AllocateMemory (size, permissions);
+ if (allocated_addr != LLDB_INVALID_ADDRESS || supported == eLazyBoolYes)
+ return allocated_addr;
+
+ case eLazyBoolNo:
+ // Call mmap() to create memory in the inferior..
+ unsigned prot = 0;
+ if (permissions & lldb::ePermissionsReadable)
+ prot |= eMmapProtRead;
+ if (permissions & lldb::ePermissionsWritable)
+ prot |= eMmapProtWrite;
+ if (permissions & lldb::ePermissionsExecutable)
+ prot |= eMmapProtExec;
+
+ if (InferiorCallMmap(this, allocated_addr, 0, size, prot,
+ eMmapFlagsAnon | eMmapFlagsPrivate, -1, 0))
+ m_addr_to_mmap_size[allocated_addr] = size;
+ else
+ allocated_addr = LLDB_INVALID_ADDRESS;
+ break;
+ }
+
+ if (allocated_addr == LLDB_INVALID_ADDRESS)
+ error.SetErrorStringWithFormat("unable to allocate %" PRIu64 " bytes of memory with permissions %s", (uint64_t)size, GetPermissionsAsCString (permissions));
+ else
+ error.Clear();
+ return allocated_addr;
+}
+
+Error
+ProcessGDBRemote::GetMemoryRegionInfo (addr_t load_addr,
+ MemoryRegionInfo &region_info)
+{
+
+ Error error (m_gdb_comm.GetMemoryRegionInfo (load_addr, region_info));
+ return error;
+}
+
+Error
+ProcessGDBRemote::GetWatchpointSupportInfo (uint32_t &num)
+{
+
+ Error error (m_gdb_comm.GetWatchpointSupportInfo (num));
+ return error;
+}
+
+Error
+ProcessGDBRemote::GetWatchpointSupportInfo (uint32_t &num, bool& after)
+{
+ Error error (m_gdb_comm.GetWatchpointSupportInfo (num, after));
+ return error;
+}
+
+Error
+ProcessGDBRemote::DoDeallocateMemory (lldb::addr_t addr)
+{
+ Error error;
+ LazyBool supported = m_gdb_comm.SupportsAllocDeallocMemory();
+
+ switch (supported)
+ {
+ case eLazyBoolCalculate:
+ // We should never be deallocating memory without allocating memory
+ // first so we should never get eLazyBoolCalculate
+ error.SetErrorString ("tried to deallocate memory without ever allocating memory");
+ break;
+
+ case eLazyBoolYes:
+ if (!m_gdb_comm.DeallocateMemory (addr))
+ error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr);
+ break;
+
+ case eLazyBoolNo:
+ // Call munmap() to deallocate memory in the inferior..
+ {
+ MMapMap::iterator pos = m_addr_to_mmap_size.find(addr);
+ if (pos != m_addr_to_mmap_size.end() &&
+ InferiorCallMunmap(this, addr, pos->second))
+ m_addr_to_mmap_size.erase (pos);
+ else
+ error.SetErrorStringWithFormat("unable to deallocate memory at 0x%" PRIx64, addr);
+ }
+ break;
+ }
+
+ return error;
+}
+
+
+//------------------------------------------------------------------
+// Process STDIO
+//------------------------------------------------------------------
+size_t
+ProcessGDBRemote::PutSTDIN (const char *src, size_t src_len, Error &error)
+{
+ if (m_stdio_communication.IsConnected())
+ {
+ ConnectionStatus status;
+ m_stdio_communication.Write(src, src_len, status, NULL);
+ }
+ return 0;
+}
+
+Error
+ProcessGDBRemote::EnableBreakpointSite (BreakpointSite *bp_site)
+{
+ Error error;
+ assert (bp_site != NULL);
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS));
+ user_id_t site_id = bp_site->GetID();
+ const addr_t addr = bp_site->GetLoadAddress();
+ if (log)
+ log->Printf ("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64, site_id, (uint64_t)addr);
+
+ if (bp_site->IsEnabled())
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::EnableBreakpointSite (size_id = %" PRIu64 ") address = 0x%" PRIx64 " -- SUCCESS (already enabled)", site_id, (uint64_t)addr);
+ return error;
+ }
+ else
+ {
+ const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode (bp_site);
+
+ if (bp_site->HardwarePreferred())
+ {
+ // Try and set hardware breakpoint, and if that fails, fall through
+ // and set a software breakpoint?
+ if (m_gdb_comm.SupportsGDBStoppointPacket (eBreakpointHardware))
+ {
+ if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointHardware, true, addr, bp_op_size) == 0)
+ {
+ bp_site->SetEnabled(true);
+ bp_site->SetType (BreakpointSite::eHardware);
+ return error;
+ }
+ }
+ }
+
+ if (m_gdb_comm.SupportsGDBStoppointPacket (eBreakpointSoftware))
+ {
+ if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, true, addr, bp_op_size) == 0)
+ {
+ bp_site->SetEnabled(true);
+ bp_site->SetType (BreakpointSite::eExternal);
+ return error;
+ }
+ }
+
+ return EnableSoftwareBreakpoint (bp_site);
+ }
+
+ if (log)
+ {
+ const char *err_string = error.AsCString();
+ log->Printf ("ProcessGDBRemote::EnableBreakpointSite () error for breakpoint at 0x%8.8" PRIx64 ": %s",
+ bp_site->GetLoadAddress(),
+ err_string ? err_string : "NULL");
+ }
+ // We shouldn't reach here on a successful breakpoint enable...
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+Error
+ProcessGDBRemote::DisableBreakpointSite (BreakpointSite *bp_site)
+{
+ Error error;
+ assert (bp_site != NULL);
+ addr_t addr = bp_site->GetLoadAddress();
+ user_id_t site_id = bp_site->GetID();
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_BREAKPOINTS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64 ") addr = 0x%8.8" PRIx64, site_id, (uint64_t)addr);
+
+ if (bp_site->IsEnabled())
+ {
+ const size_t bp_op_size = GetSoftwareBreakpointTrapOpcode (bp_site);
+
+ BreakpointSite::Type bp_type = bp_site->GetType();
+ switch (bp_type)
+ {
+ case BreakpointSite::eSoftware:
+ error = DisableSoftwareBreakpoint (bp_site);
+ break;
+
+ case BreakpointSite::eHardware:
+ if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, false, addr, bp_op_size))
+ error.SetErrorToGenericError();
+ break;
+
+ case BreakpointSite::eExternal:
+ if (m_gdb_comm.SendGDBStoppointTypePacket(eBreakpointSoftware, false, addr, bp_op_size))
+ error.SetErrorToGenericError();
+ break;
+ }
+ if (error.Success())
+ bp_site->SetEnabled(false);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableBreakpointSite (site_id = %" PRIu64 ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", site_id, (uint64_t)addr);
+ return error;
+ }
+
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+// Pre-requisite: wp != NULL.
+static GDBStoppointType
+GetGDBStoppointType (Watchpoint *wp)
+{
+ assert(wp);
+ bool watch_read = wp->WatchpointRead();
+ bool watch_write = wp->WatchpointWrite();
+
+ // watch_read and watch_write cannot both be false.
+ assert(watch_read || watch_write);
+ if (watch_read && watch_write)
+ return eWatchpointReadWrite;
+ else if (watch_read)
+ return eWatchpointRead;
+ else // Must be watch_write, then.
+ return eWatchpointWrite;
+}
+
+Error
+ProcessGDBRemote::EnableWatchpoint (Watchpoint *wp, bool notify)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+ addr_t addr = wp->GetLoadAddress();
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ")", watchID);
+ if (wp->IsEnabled())
+ {
+ if (log)
+ log->Printf("ProcessGDBRemote::EnableWatchpoint(watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64 ": watchpoint already enabled.", watchID, (uint64_t)addr);
+ return error;
+ }
+
+ GDBStoppointType type = GetGDBStoppointType(wp);
+ // Pass down an appropriate z/Z packet...
+ if (m_gdb_comm.SupportsGDBStoppointPacket (type))
+ {
+ if (m_gdb_comm.SendGDBStoppointTypePacket(type, true, addr, wp->GetByteSize()) == 0)
+ {
+ wp->SetEnabled(true, notify);
+ return error;
+ }
+ else
+ error.SetErrorString("sending gdb watchpoint packet failed");
+ }
+ else
+ error.SetErrorString("watchpoints not supported");
+ }
+ else
+ {
+ error.SetErrorString("Watchpoint argument was NULL.");
+ }
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+Error
+ProcessGDBRemote::DisableWatchpoint (Watchpoint *wp, bool notify)
+{
+ Error error;
+ if (wp)
+ {
+ user_id_t watchID = wp->GetID();
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_WATCHPOINTS));
+
+ addr_t addr = wp->GetLoadAddress();
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64, watchID, (uint64_t)addr);
+
+ if (!wp->IsEnabled())
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::DisableWatchpoint (watchID = %" PRIu64 ") addr = 0x%8.8" PRIx64 " -- SUCCESS (already disabled)", watchID, (uint64_t)addr);
+ // See also 'class WatchpointSentry' within StopInfo.cpp.
+ // This disabling attempt might come from the user-supplied actions, we'll route it in order for
+ // the watchpoint object to intelligently process this action.
+ wp->SetEnabled(false, notify);
+ return error;
+ }
+
+ if (wp->IsHardware())
+ {
+ GDBStoppointType type = GetGDBStoppointType(wp);
+ // Pass down an appropriate z/Z packet...
+ if (m_gdb_comm.SendGDBStoppointTypePacket(type, false, addr, wp->GetByteSize()) == 0)
+ {
+ wp->SetEnabled(false, notify);
+ return error;
+ }
+ else
+ error.SetErrorString("sending gdb watchpoint packet failed");
+ }
+ // TODO: clear software watchpoints if we implement them
+ }
+ else
+ {
+ error.SetErrorString("Watchpoint argument was NULL.");
+ }
+ if (error.Success())
+ error.SetErrorToGenericError();
+ return error;
+}
+
+void
+ProcessGDBRemote::Clear()
+{
+ m_flags = 0;
+ m_thread_list_real.Clear();
+ m_thread_list.Clear();
+}
+
+Error
+ProcessGDBRemote::DoSignal (int signo)
+{
+ Error error;
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::DoSignal (signal = %d)", signo);
+
+ if (!m_gdb_comm.SendAsyncSignal (signo))
+ error.SetErrorStringWithFormat("failed to send signal %i", signo);
+ return error;
+}
+
+Error
+ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url)
+{
+ ProcessLaunchInfo launch_info;
+ return StartDebugserverProcess(debugserver_url, launch_info);
+}
+
+Error
+ProcessGDBRemote::StartDebugserverProcess (const char *debugserver_url, const ProcessInfo &process_info) // The connection string to use in the spawned debugserver ("localhost:1234" or "/dev/tty...")
+{
+ Error error;
+ if (m_debugserver_pid == LLDB_INVALID_PROCESS_ID)
+ {
+ // If we locate debugserver, keep that located version around
+ static FileSpec g_debugserver_file_spec;
+
+ ProcessLaunchInfo debugserver_launch_info;
+ char debugserver_path[PATH_MAX];
+ FileSpec &debugserver_file_spec = debugserver_launch_info.GetExecutableFile();
+
+ // Always check to see if we have an environment override for the path
+ // to the debugserver to use and use it if we do.
+ const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH");
+ if (env_debugserver_path)
+ debugserver_file_spec.SetFile (env_debugserver_path, false);
+ else
+ debugserver_file_spec = g_debugserver_file_spec;
+ bool debugserver_exists = debugserver_file_spec.Exists();
+ if (!debugserver_exists)
+ {
+ // The debugserver binary is in the LLDB.framework/Resources
+ // directory.
+ if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec))
+ {
+ debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME);
+ debugserver_exists = debugserver_file_spec.Exists();
+ if (debugserver_exists)
+ {
+ g_debugserver_file_spec = debugserver_file_spec;
+ }
+ else
+ {
+ g_debugserver_file_spec.Clear();
+ debugserver_file_spec.Clear();
+ }
+ }
+ }
+
+ if (debugserver_exists)
+ {
+ debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path));
+
+ m_stdio_communication.Clear();
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+
+ Args &debugserver_args = debugserver_launch_info.GetArguments();
+ char arg_cstr[PATH_MAX];
+
+ // Start args with "debugserver /file/path -r --"
+ debugserver_args.AppendArgument(debugserver_path);
+ debugserver_args.AppendArgument(debugserver_url);
+ // use native registers, not the GDB registers
+ debugserver_args.AppendArgument("--native-regs");
+ // make debugserver run in its own session so signals generated by
+ // special terminal key sequences (^C) don't affect debugserver
+ debugserver_args.AppendArgument("--setsid");
+
+ const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE");
+ if (env_debugserver_log_file)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file);
+ debugserver_args.AppendArgument(arg_cstr);
+ }
+
+ const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS");
+ if (env_debugserver_log_flags)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags);
+ debugserver_args.AppendArgument(arg_cstr);
+ }
+// debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt");
+// debugserver_args.AppendArgument("--log-flags=0x802e0e");
+
+ // We currently send down all arguments, attach pids, or attach
+ // process names in dedicated GDB server packets, so we don't need
+ // to pass them as arguments. This is currently because of all the
+ // things we need to setup prior to launching: the environment,
+ // current working dir, file actions, etc.
+#if 0
+ // Now append the program arguments
+ if (inferior_argv)
+ {
+ // Terminate the debugserver args so we can now append the inferior args
+ debugserver_args.AppendArgument("--");
+
+ for (int i = 0; inferior_argv[i] != NULL; ++i)
+ debugserver_args.AppendArgument (inferior_argv[i]);
+ }
+ else if (attach_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid);
+ debugserver_args.AppendArgument (arg_cstr);
+ }
+ else if (attach_name && attach_name[0])
+ {
+ if (wait_for_launch)
+ debugserver_args.AppendArgument ("--waitfor");
+ else
+ debugserver_args.AppendArgument ("--attach");
+ debugserver_args.AppendArgument (attach_name);
+ }
+#endif
+
+ ProcessLaunchInfo::FileAction file_action;
+
+ // Close STDIN, STDOUT and STDERR. We might need to redirect them
+ // to "/dev/null" if we run into any problems.
+ file_action.Close (STDIN_FILENO);
+ debugserver_launch_info.AppendFileAction (file_action);
+ file_action.Close (STDOUT_FILENO);
+ debugserver_launch_info.AppendFileAction (file_action);
+ file_action.Close (STDERR_FILENO);
+ debugserver_launch_info.AppendFileAction (file_action);
+
+ if (log)
+ {
+ StreamString strm;
+ debugserver_args.Dump (&strm);
+ log->Printf("%s arguments:\n%s", debugserver_args.GetArgumentAtIndex(0), strm.GetData());
+ }
+
+ debugserver_launch_info.SetMonitorProcessCallback (MonitorDebugserverProcess, this, false);
+ debugserver_launch_info.SetUserID(process_info.GetUserID());
+
+ error = Host::LaunchProcess(debugserver_launch_info);
+
+ if (error.Success ())
+ m_debugserver_pid = debugserver_launch_info.GetProcessID();
+ else
+ m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+
+ if (error.Fail() || log)
+ error.PutToLog(log, "Host::LaunchProcess (launch_info) => pid=%" PRIu64 ", path='%s'", m_debugserver_pid, debugserver_path);
+ }
+ else
+ {
+ error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME);
+ }
+
+ if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ StartAsyncThread ();
+ }
+ return error;
+}
+
+bool
+ProcessGDBRemote::MonitorDebugserverProcess
+(
+ void *callback_baton,
+ lldb::pid_t debugserver_pid,
+ bool exited, // True if the process did exit
+ int signo, // Zero for no signal
+ int exit_status // Exit value of process if signal is zero
+)
+{
+ // The baton is a "ProcessGDBRemote *". Now this class might be gone
+ // and might not exist anymore, so we need to carefully try to get the
+ // target for this process first since we have a race condition when
+ // we are done running between getting the notice that the inferior
+ // process has died and the debugserver that was debugging this process.
+ // In our test suite, we are also continually running process after
+ // process, so we must be very careful to make sure:
+ // 1 - process object hasn't been deleted already
+ // 2 - that a new process object hasn't been recreated in its place
+
+ // "debugserver_pid" argument passed in is the process ID for
+ // debugserver that we are tracking...
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+
+ ProcessGDBRemote *process = (ProcessGDBRemote *)callback_baton;
+
+ // Get a shared pointer to the target that has a matching process pointer.
+ // This target could be gone, or the target could already have a new process
+ // object inside of it
+ TargetSP target_sp (Debugger::FindTargetWithProcess(process));
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::MonitorDebugserverProcess (baton=%p, pid=%" PRIu64 ", signo=%i (0x%x), exit_status=%i)", callback_baton, debugserver_pid, signo, signo, exit_status);
+
+ if (target_sp)
+ {
+ // We found a process in a target that matches, but another thread
+ // might be in the process of launching a new process that will
+ // soon replace it, so get a shared pointer to the process so we
+ // can keep it alive.
+ ProcessSP process_sp (target_sp->GetProcessSP());
+ // Now we have a shared pointer to the process that can't go away on us
+ // so we now make sure it was the same as the one passed in, and also make
+ // sure that our previous "process *" didn't get deleted and have a new
+ // "process *" created in its place with the same pointer. To verify this
+ // we make sure the process has our debugserver process ID. If we pass all
+ // of these tests, then we are sure that this process is the one we were
+ // looking for.
+ if (process_sp && process == process_sp.get() && process->m_debugserver_pid == debugserver_pid)
+ {
+ // Sleep for a half a second to make sure our inferior process has
+ // time to set its exit status before we set it incorrectly when
+ // both the debugserver and the inferior process shut down.
+ usleep (500000);
+ // If our process hasn't yet exited, debugserver might have died.
+ // If the process did exit, the we are reaping it.
+ const StateType state = process->GetState();
+
+ if (process->m_debugserver_pid != LLDB_INVALID_PROCESS_ID &&
+ state != eStateInvalid &&
+ state != eStateUnloaded &&
+ state != eStateExited &&
+ state != eStateDetached)
+ {
+ char error_str[1024];
+ if (signo)
+ {
+ const char *signal_cstr = process->GetUnixSignals().GetSignalAsCString (signo);
+ if (signal_cstr)
+ ::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with signal %s", signal_cstr);
+ else
+ ::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with signal %i", signo);
+ }
+ else
+ {
+ ::snprintf (error_str, sizeof (error_str), DEBUGSERVER_BASENAME " died with an exit status of 0x%8.8x", exit_status);
+ }
+
+ process->SetExitStatus (-1, error_str);
+ }
+ // Debugserver has exited we need to let our ProcessGDBRemote
+ // know that it no longer has a debugserver instance
+ process->m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+ }
+ }
+ return true;
+}
+
+void
+ProcessGDBRemote::KillDebugserverProcess ()
+{
+ if (m_debugserver_pid != LLDB_INVALID_PROCESS_ID)
+ {
+ ::kill (m_debugserver_pid, SIGINT);
+ m_debugserver_pid = LLDB_INVALID_PROCESS_ID;
+ }
+}
+
+void
+ProcessGDBRemote::Initialize()
+{
+ static bool g_initialized = false;
+
+ if (g_initialized == false)
+ {
+ g_initialized = true;
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance,
+ DebuggerInitialize);
+
+ Log::Callbacks log_callbacks = {
+ ProcessGDBRemoteLog::DisableLog,
+ ProcessGDBRemoteLog::EnableLog,
+ ProcessGDBRemoteLog::ListLogCategories
+ };
+
+ Log::RegisterLogChannel (ProcessGDBRemote::GetPluginNameStatic(), log_callbacks);
+ }
+}
+
+void
+ProcessGDBRemote::DebuggerInitialize (lldb_private::Debugger &debugger)
+{
+ if (!PluginManager::GetSettingForProcessPlugin(debugger, PluginProperties::GetSettingName()))
+ {
+ const bool is_global_setting = true;
+ PluginManager::CreateSettingForProcessPlugin (debugger,
+ GetGlobalPluginProperties()->GetValueProperties(),
+ ConstString ("Properties for the gdb-remote process plug-in."),
+ is_global_setting);
+ }
+}
+
+bool
+ProcessGDBRemote::StartAsyncThread ()
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__);
+
+ Mutex::Locker start_locker(m_async_thread_state_mutex);
+ if (m_async_thread_state == eAsyncThreadNotStarted)
+ {
+ // Create a thread that watches our internal state and controls which
+ // events make it to clients (into the DCProcess event queue).
+ m_async_thread = Host::ThreadCreate ("<lldb.process.gdb-remote.async>", ProcessGDBRemote::AsyncThread, this, NULL);
+ if (IS_VALID_LLDB_HOST_THREAD(m_async_thread))
+ {
+ m_async_thread_state = eAsyncThreadRunning;
+ return true;
+ }
+ else
+ return false;
+ }
+ else
+ {
+ // Somebody tried to start the async thread while it was either being started or stopped. If the former, and
+ // it started up successfully, then say all's well. Otherwise it is an error, since we aren't going to restart it.
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s () - Called when Async thread was in state: %d.", __FUNCTION__, m_async_thread_state);
+ if (m_async_thread_state == eAsyncThreadRunning)
+ return true;
+ else
+ return false;
+ }
+}
+
+void
+ProcessGDBRemote::StopAsyncThread ()
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet(GDBR_LOG_PROCESS));
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s ()", __FUNCTION__);
+
+ Mutex::Locker start_locker(m_async_thread_state_mutex);
+ if (m_async_thread_state == eAsyncThreadRunning)
+ {
+ m_async_broadcaster.BroadcastEvent (eBroadcastBitAsyncThreadShouldExit);
+
+ // This will shut down the async thread.
+ m_gdb_comm.Disconnect(); // Disconnect from the debug server.
+
+ // Stop the stdio thread
+ if (IS_VALID_LLDB_HOST_THREAD(m_async_thread))
+ {
+ Host::ThreadJoin (m_async_thread, NULL, NULL);
+ }
+ m_async_thread_state = eAsyncThreadDone;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s () - Called when Async thread was in state: %d.", __FUNCTION__, m_async_thread_state);
+ }
+}
+
+
+void *
+ProcessGDBRemote::AsyncThread (void *arg)
+{
+ ProcessGDBRemote *process = (ProcessGDBRemote*) arg;
+
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (GDBR_LOG_PROCESS));
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") thread starting...", __FUNCTION__, arg, process->GetID());
+
+ Listener listener ("ProcessGDBRemote::AsyncThread");
+ EventSP event_sp;
+ const uint32_t desired_event_mask = eBroadcastBitAsyncContinue |
+ eBroadcastBitAsyncThreadShouldExit;
+
+ if (listener.StartListeningForEvents (&process->m_async_broadcaster, desired_event_mask) == desired_event_mask)
+ {
+ listener.StartListeningForEvents (&process->m_gdb_comm, Communication::eBroadcastBitReadThreadDidExit);
+
+ bool done = false;
+ while (!done)
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp)...", __FUNCTION__, arg, process->GetID());
+ if (listener.WaitForEvent (NULL, event_sp))
+ {
+ const uint32_t event_type = event_sp->GetType();
+ if (event_sp->BroadcasterIs (&process->m_async_broadcaster))
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") Got an event of type: %d...", __FUNCTION__, arg, process->GetID(), event_type);
+
+ switch (event_type)
+ {
+ case eBroadcastBitAsyncContinue:
+ {
+ const EventDataBytes *continue_packet = EventDataBytes::GetEventDataFromEvent(event_sp.get());
+
+ if (continue_packet)
+ {
+ const char *continue_cstr = (const char *)continue_packet->GetBytes ();
+ const size_t continue_cstr_len = continue_packet->GetByteSize ();
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got eBroadcastBitAsyncContinue: %s", __FUNCTION__, arg, process->GetID(), continue_cstr);
+
+ if (::strstr (continue_cstr, "vAttach") == NULL)
+ process->SetPrivateState(eStateRunning);
+ StringExtractorGDBRemote response;
+ StateType stop_state = process->GetGDBRemote().SendContinuePacketAndWaitForResponse (process, continue_cstr, continue_cstr_len, response);
+
+ // We need to immediately clear the thread ID list so we are sure to get a valid list of threads.
+ // The thread ID list might be contained within the "response", or the stop reply packet that
+ // caused the stop. So clear it now before we give the stop reply packet to the process
+ // using the process->SetLastStopPacket()...
+ process->ClearThreadIDList ();
+
+ switch (stop_state)
+ {
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ process->SetLastStopPacket (response);
+ process->SetPrivateState (stop_state);
+ break;
+
+ case eStateExited:
+ process->SetLastStopPacket (response);
+ process->ClearThreadIDList();
+ response.SetFilePos(1);
+ process->SetExitStatus(response.GetHexU8(), NULL);
+ done = true;
+ break;
+
+ case eStateInvalid:
+ process->SetExitStatus(-1, "lost connection");
+ break;
+
+ default:
+ process->SetPrivateState (stop_state);
+ break;
+ }
+ }
+ }
+ break;
+
+ case eBroadcastBitAsyncThreadShouldExit:
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got eBroadcastBitAsyncThreadShouldExit...", __FUNCTION__, arg, process->GetID());
+ done = true;
+ break;
+
+ default:
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") got unknown event 0x%8.8x", __FUNCTION__, arg, process->GetID(), event_type);
+ done = true;
+ break;
+ }
+ }
+ else if (event_sp->BroadcasterIs (&process->m_gdb_comm))
+ {
+ if (event_type & Communication::eBroadcastBitReadThreadDidExit)
+ {
+ process->SetExitStatus (-1, "lost connection");
+ done = true;
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") listener.WaitForEvent (NULL, event_sp) => false", __FUNCTION__, arg, process->GetID());
+ done = true;
+ }
+ }
+ }
+
+ if (log)
+ log->Printf ("ProcessGDBRemote::%s (arg = %p, pid = %" PRIu64 ") thread exiting...", __FUNCTION__, arg, process->GetID());
+
+ process->m_async_thread = LLDB_INVALID_HOST_THREAD;
+ return NULL;
+}
+
+const char *
+ProcessGDBRemote::GetDispatchQueueNameForThread
+(
+ addr_t thread_dispatch_qaddr,
+ std::string &dispatch_queue_name
+)
+{
+ dispatch_queue_name.clear();
+ if (thread_dispatch_qaddr != 0 && thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
+ {
+ // Cache the dispatch_queue_offsets_addr value so we don't always have
+ // to look it up
+ if (m_dispatch_queue_offsets_addr == LLDB_INVALID_ADDRESS)
+ {
+ static ConstString g_dispatch_queue_offsets_symbol_name ("dispatch_queue_offsets");
+ const Symbol *dispatch_queue_offsets_symbol = NULL;
+ ModuleSpec libSystem_module_spec (FileSpec("libSystem.B.dylib", false));
+ ModuleSP module_sp(GetTarget().GetImages().FindFirstModule (libSystem_module_spec));
+ if (module_sp)
+ dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
+
+ if (dispatch_queue_offsets_symbol == NULL)
+ {
+ ModuleSpec libdispatch_module_spec (FileSpec("libdispatch.dylib", false));
+ module_sp = GetTarget().GetImages().FindFirstModule (libdispatch_module_spec);
+ if (module_sp)
+ dispatch_queue_offsets_symbol = module_sp->FindFirstSymbolWithNameAndType (g_dispatch_queue_offsets_symbol_name, eSymbolTypeData);
+ }
+ if (dispatch_queue_offsets_symbol)
+ m_dispatch_queue_offsets_addr = dispatch_queue_offsets_symbol->GetAddress().GetLoadAddress(&m_target);
+
+ if (m_dispatch_queue_offsets_addr == LLDB_INVALID_ADDRESS)
+ return NULL;
+ }
+
+ uint8_t memory_buffer[8];
+ DataExtractor data (memory_buffer,
+ sizeof(memory_buffer),
+ m_target.GetArchitecture().GetByteOrder(),
+ m_target.GetArchitecture().GetAddressByteSize());
+
+ // Excerpt from src/queue_private.h
+ struct dispatch_queue_offsets_s
+ {
+ uint16_t dqo_version;
+ uint16_t dqo_label; // in version 1-3, offset to string; in version 4+, offset to a pointer to a string
+ uint16_t dqo_label_size; // in version 1-3, length of string; in version 4+, size of a (void*) in this process
+ } dispatch_queue_offsets;
+
+
+ Error error;
+ if (ReadMemory (m_dispatch_queue_offsets_addr, memory_buffer, sizeof(dispatch_queue_offsets), error) == sizeof(dispatch_queue_offsets))
+ {
+ lldb::offset_t data_offset = 0;
+ if (data.GetU16(&data_offset, &dispatch_queue_offsets.dqo_version, sizeof(dispatch_queue_offsets)/sizeof(uint16_t)))
+ {
+ if (ReadMemory (thread_dispatch_qaddr, &memory_buffer, data.GetAddressByteSize(), error) == data.GetAddressByteSize())
+ {
+ data_offset = 0;
+ lldb::addr_t queue_addr = data.GetAddress(&data_offset);
+ if (dispatch_queue_offsets.dqo_version >= 4)
+ {
+ // libdispatch versions 4+, pointer to dispatch name is in the
+ // queue structure.
+ lldb::addr_t pointer_to_label_address = queue_addr + dispatch_queue_offsets.dqo_label;
+ if (ReadMemory (pointer_to_label_address, &memory_buffer, data.GetAddressByteSize(), error) == data.GetAddressByteSize())
+ {
+ data_offset = 0;
+ lldb::addr_t label_addr = data.GetAddress(&data_offset);
+ ReadCStringFromMemory (label_addr, dispatch_queue_name, error);
+ }
+ }
+ else
+ {
+ // libdispatch versions 1-3, dispatch name is a fixed width char array
+ // in the queue structure.
+ lldb::addr_t label_addr = queue_addr + dispatch_queue_offsets.dqo_label;
+ dispatch_queue_name.resize(dispatch_queue_offsets.dqo_label_size, '\0');
+ size_t bytes_read = ReadMemory (label_addr, &dispatch_queue_name[0], dispatch_queue_offsets.dqo_label_size, error);
+ if (bytes_read < dispatch_queue_offsets.dqo_label_size)
+ dispatch_queue_name.erase (bytes_read);
+ }
+ }
+ }
+ }
+ }
+ if (dispatch_queue_name.empty())
+ return NULL;
+ return dispatch_queue_name.c_str();
+}
+
+//uint32_t
+//ProcessGDBRemote::ListProcessesMatchingName (const char *name, StringList &matches, std::vector<lldb::pid_t> &pids)
+//{
+// // If we are planning to launch the debugserver remotely, then we need to fire up a debugserver
+// // process and ask it for the list of processes. But if we are local, we can let the Host do it.
+// if (m_local_debugserver)
+// {
+// return Host::ListProcessesMatchingName (name, matches, pids);
+// }
+// else
+// {
+// // FIXME: Implement talking to the remote debugserver.
+// return 0;
+// }
+//
+//}
+//
+bool
+ProcessGDBRemote::NewThreadNotifyBreakpointHit (void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id)
+{
+ // I don't think I have to do anything here, just make sure I notice the new thread when it starts to
+ // run so I can stop it if that's what I want to do.
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log)
+ log->Printf("Hit New Thread Notification breakpoint.");
+ return false;
+}
+
+
+bool
+ProcessGDBRemote::StartNoticingNewThreads()
+{
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (m_thread_create_bp_sp)
+ {
+ if (log && log->GetVerbose())
+ log->Printf("Enabled noticing new thread breakpoint.");
+ m_thread_create_bp_sp->SetEnabled(true);
+ }
+ else
+ {
+ PlatformSP platform_sp (m_target.GetPlatform());
+ if (platform_sp)
+ {
+ m_thread_create_bp_sp = platform_sp->SetThreadCreationBreakpoint(m_target);
+ if (m_thread_create_bp_sp)
+ {
+ if (log && log->GetVerbose())
+ log->Printf("Successfully created new thread notification breakpoint %i", m_thread_create_bp_sp->GetID());
+ m_thread_create_bp_sp->SetCallback (ProcessGDBRemote::NewThreadNotifyBreakpointHit, this, true);
+ }
+ else
+ {
+ if (log)
+ log->Printf("Failed to create new thread notification breakpoint.");
+ }
+ }
+ }
+ return m_thread_create_bp_sp.get() != NULL;
+}
+
+bool
+ProcessGDBRemote::StopNoticingNewThreads()
+{
+ Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
+ if (log && log->GetVerbose())
+ log->Printf ("Disabling new thread notification breakpoint.");
+
+ if (m_thread_create_bp_sp)
+ m_thread_create_bp_sp->SetEnabled(false);
+
+ return true;
+}
+
+lldb_private::DynamicLoader *
+ProcessGDBRemote::GetDynamicLoader ()
+{
+ if (m_dyld_ap.get() == NULL)
+ m_dyld_ap.reset (DynamicLoader::FindPlugin(this, NULL));
+ return m_dyld_ap.get();
+}
+
+
+class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed
+{
+private:
+
+public:
+ CommandObjectProcessGDBRemotePacketHistory(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process plugin packet history",
+ "Dumps the packet history buffer. ",
+ NULL)
+ {
+ }
+
+ ~CommandObjectProcessGDBRemotePacketHistory ()
+ {
+ }
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0)
+ {
+ ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process)
+ {
+ process->GetGDBRemote().DumpHistory(result.GetOutputStream());
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ return true;
+ }
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("'%s' takes no arguments", m_cmd_name.c_str());
+ }
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+};
+
+class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed
+{
+private:
+
+public:
+ CommandObjectProcessGDBRemotePacketSend(CommandInterpreter &interpreter) :
+ CommandObjectParsed (interpreter,
+ "process plugin packet send",
+ "Send a custom packet through the GDB remote protocol and print the answer. "
+ "The packet header and footer will automatically be added to the packet prior to sending and stripped from the result.",
+ NULL)
+ {
+ }
+
+ ~CommandObjectProcessGDBRemotePacketSend ()
+ {
+ }
+
+ bool
+ DoExecute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+ if (argc == 0)
+ {
+ result.AppendErrorWithFormat ("'%s' takes a one or more packet content arguments", m_cmd_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process)
+ {
+ for (size_t i=0; i<argc; ++ i)
+ {
+ const char *packet_cstr = command.GetArgumentAtIndex(0);
+ bool send_async = true;
+ StringExtractorGDBRemote response;
+ process->GetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response, send_async);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ Stream &output_strm = result.GetOutputStream();
+ output_strm.Printf (" packet: %s\n", packet_cstr);
+ std::string &response_str = response.GetStringRef();
+
+ if (strstr(packet_cstr, "qGetProfileData") != NULL)
+ {
+ response_str = process->GetGDBRemote().HarmonizeThreadIdsForProfileData(process, response);
+ }
+
+ if (response_str.empty())
+ output_strm.PutCString ("response: \nerror: UNIMPLEMENTED\n");
+ else
+ output_strm.Printf ("response: %s\n", response.GetStringRef().c_str());
+ }
+ }
+ return true;
+ }
+};
+
+class CommandObjectProcessGDBRemotePacketMonitor : public CommandObjectRaw
+{
+private:
+
+public:
+ CommandObjectProcessGDBRemotePacketMonitor(CommandInterpreter &interpreter) :
+ CommandObjectRaw (interpreter,
+ "process plugin packet monitor",
+ "Send a qRcmd packet through the GDB remote protocol and print the response."
+ "The argument passed to this command will be hex encoded into a valid 'qRcmd' packet, sent and the response will be printed.",
+ NULL)
+ {
+ }
+
+ ~CommandObjectProcessGDBRemotePacketMonitor ()
+ {
+ }
+
+ bool
+ DoExecute (const char *command, CommandReturnObject &result)
+ {
+ if (command == NULL || command[0] == '\0')
+ {
+ result.AppendErrorWithFormat ("'%s' takes a command string argument", m_cmd_name.c_str());
+ result.SetStatus (eReturnStatusFailed);
+ return false;
+ }
+
+ ProcessGDBRemote *process = (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
+ if (process)
+ {
+ StreamString packet;
+ packet.PutCString("qRcmd,");
+ packet.PutBytesAsRawHex8(command, strlen(command));
+ const char *packet_cstr = packet.GetString().c_str();
+
+ bool send_async = true;
+ StringExtractorGDBRemote response;
+ process->GetGDBRemote().SendPacketAndWaitForResponse(packet_cstr, response, send_async);
+ result.SetStatus (eReturnStatusSuccessFinishResult);
+ Stream &output_strm = result.GetOutputStream();
+ output_strm.Printf (" packet: %s\n", packet_cstr);
+ const std::string &response_str = response.GetStringRef();
+
+ if (response_str.empty())
+ output_strm.PutCString ("response: \nerror: UNIMPLEMENTED\n");
+ else
+ output_strm.Printf ("response: %s\n", response.GetStringRef().c_str());
+ }
+ return true;
+ }
+};
+
+class CommandObjectProcessGDBRemotePacket : public CommandObjectMultiword
+{
+private:
+
+public:
+ CommandObjectProcessGDBRemotePacket(CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "process plugin packet",
+ "Commands that deal with GDB remote packets.",
+ NULL)
+ {
+ LoadSubCommand ("history", CommandObjectSP (new CommandObjectProcessGDBRemotePacketHistory (interpreter)));
+ LoadSubCommand ("send", CommandObjectSP (new CommandObjectProcessGDBRemotePacketSend (interpreter)));
+ LoadSubCommand ("monitor", CommandObjectSP (new CommandObjectProcessGDBRemotePacketMonitor (interpreter)));
+ }
+
+ ~CommandObjectProcessGDBRemotePacket ()
+ {
+ }
+};
+
+class CommandObjectMultiwordProcessGDBRemote : public CommandObjectMultiword
+{
+public:
+ CommandObjectMultiwordProcessGDBRemote (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "process plugin",
+ "A set of commands for operating on a ProcessGDBRemote process.",
+ "process plugin <subcommand> [<subcommand-options>]")
+ {
+ LoadSubCommand ("packet", CommandObjectSP (new CommandObjectProcessGDBRemotePacket (interpreter)));
+ }
+
+ ~CommandObjectMultiwordProcessGDBRemote ()
+ {
+ }
+};
+
+CommandObject *
+ProcessGDBRemote::GetPluginCommandObject()
+{
+ if (!m_command_sp)
+ m_command_sp.reset (new CommandObjectMultiwordProcessGDBRemote (GetTarget().GetDebugger().GetCommandInterpreter()));
+ return m_command_sp.get();
+}
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
new file mode 100644
index 000000000000..e104b7191eab
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
@@ -0,0 +1,396 @@
+//===-- ProcessGDBRemote.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessGDBRemote_h_
+#define liblldb_ProcessGDBRemote_h_
+
+// C Includes
+
+// C++ Includes
+#include <list>
+#include <vector>
+
+// Other libraries and framework includes
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/Broadcaster.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/InputReader.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/StringList.h"
+#include "lldb/Core/ThreadSafeValue.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+#include "GDBRemoteCommunicationClient.h"
+#include "Utility/StringExtractor.h"
+#include "GDBRemoteRegisterContext.h"
+
+class ThreadGDBRemote;
+
+class ProcessGDBRemote : public lldb_private::Process
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ static lldb::ProcessSP
+ CreateInstance (lldb_private::Target& target,
+ lldb_private::Listener &listener,
+ const lldb_private::FileSpec *crash_file_path);
+
+ static void
+ Initialize();
+
+ static void
+ DebuggerInitialize (lldb_private::Debugger &debugger);
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ ProcessGDBRemote(lldb_private::Target& target, lldb_private::Listener &listener);
+
+ virtual
+ ~ProcessGDBRemote();
+
+ //------------------------------------------------------------------
+ // Check if a given Process
+ //------------------------------------------------------------------
+ virtual bool
+ CanDebug (lldb_private::Target &target,
+ bool plugin_specified_by_name);
+
+ virtual lldb_private::CommandObject *
+ GetPluginCommandObject();
+
+ //------------------------------------------------------------------
+ // Creating a new process, or attaching to an existing one
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ WillLaunch (lldb_private::Module* module);
+
+ virtual lldb_private::Error
+ DoLaunch (lldb_private::Module *exe_module,
+ const lldb_private::ProcessLaunchInfo &launch_info);
+
+ virtual void
+ DidLaunch ();
+
+ virtual lldb_private::Error
+ WillAttachToProcessWithID (lldb::pid_t pid);
+
+ virtual lldb_private::Error
+ WillAttachToProcessWithName (const char *process_name, bool wait_for_launch);
+
+ virtual lldb_private::Error
+ DoConnectRemote (lldb_private::Stream *strm, const char *remote_url);
+
+ lldb_private::Error
+ WillLaunchOrAttach ();
+
+ virtual lldb_private::Error
+ DoAttachToProcessWithID (lldb::pid_t pid);
+
+ virtual lldb_private::Error
+ DoAttachToProcessWithID (lldb::pid_t pid, const lldb_private::ProcessAttachInfo &attach_info);
+
+ virtual lldb_private::Error
+ DoAttachToProcessWithName (const char *process_name,
+ bool wait_for_launch,
+ const lldb_private::ProcessAttachInfo &attach_info);
+
+ virtual void
+ DidAttach ();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ //------------------------------------------------------------------
+ // Process Control
+ //------------------------------------------------------------------
+ virtual lldb_private::Error
+ WillResume ();
+
+ virtual lldb_private::Error
+ DoResume ();
+
+ virtual lldb_private::Error
+ DoHalt (bool &caused_stop);
+
+ virtual lldb_private::Error
+ DoDetach (bool keep_stopped);
+
+ virtual bool
+ DetachRequiresHalt() { return true; }
+
+ virtual lldb_private::Error
+ DoSignal (int signal);
+
+ virtual lldb_private::Error
+ DoDestroy ();
+
+ virtual void
+ RefreshStateAfterStop();
+
+ //------------------------------------------------------------------
+ // Process Queries
+ //------------------------------------------------------------------
+ virtual bool
+ IsAlive ();
+
+ virtual lldb::addr_t
+ GetImageInfoAddress();
+
+ //------------------------------------------------------------------
+ // Process Memory
+ //------------------------------------------------------------------
+ virtual size_t
+ DoReadMemory (lldb::addr_t addr, void *buf, size_t size, lldb_private::Error &error);
+
+ virtual size_t
+ DoWriteMemory (lldb::addr_t addr, const void *buf, size_t size, lldb_private::Error &error);
+
+ virtual lldb::addr_t
+ DoAllocateMemory (size_t size, uint32_t permissions, lldb_private::Error &error);
+
+ virtual lldb_private::Error
+ GetMemoryRegionInfo (lldb::addr_t load_addr,
+ lldb_private::MemoryRegionInfo &region_info);
+
+ virtual lldb_private::Error
+ DoDeallocateMemory (lldb::addr_t ptr);
+
+ //------------------------------------------------------------------
+ // Process STDIO
+ //------------------------------------------------------------------
+ virtual size_t
+ PutSTDIN (const char *buf, size_t buf_size, lldb_private::Error &error);
+
+ //----------------------------------------------------------------------
+ // Process Breakpoints
+ //----------------------------------------------------------------------
+ virtual lldb_private::Error
+ EnableBreakpointSite (lldb_private::BreakpointSite *bp_site);
+
+ virtual lldb_private::Error
+ DisableBreakpointSite (lldb_private::BreakpointSite *bp_site);
+
+ //----------------------------------------------------------------------
+ // Process Watchpoints
+ //----------------------------------------------------------------------
+ virtual lldb_private::Error
+ EnableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true);
+
+ virtual lldb_private::Error
+ DisableWatchpoint (lldb_private::Watchpoint *wp, bool notify = true);
+
+ virtual lldb_private::Error
+ GetWatchpointSupportInfo (uint32_t &num);
+
+ virtual lldb_private::Error
+ GetWatchpointSupportInfo (uint32_t &num, bool& after);
+
+ virtual bool
+ StartNoticingNewThreads();
+
+ virtual bool
+ StopNoticingNewThreads();
+
+ GDBRemoteCommunicationClient &
+ GetGDBRemote()
+ {
+ return m_gdb_comm;
+ }
+
+protected:
+ friend class ThreadGDBRemote;
+ friend class GDBRemoteCommunicationClient;
+ friend class GDBRemoteRegisterContext;
+
+ //----------------------------------------------------------------------
+ // Accessors
+ //----------------------------------------------------------------------
+ bool
+ IsRunning ( lldb::StateType state )
+ {
+ return state == lldb::eStateRunning || IsStepping(state);
+ }
+
+ bool
+ IsStepping ( lldb::StateType state)
+ {
+ return state == lldb::eStateStepping;
+ }
+ bool
+ CanResume ( lldb::StateType state)
+ {
+ return state == lldb::eStateStopped;
+ }
+
+ bool
+ HasExited (lldb::StateType state)
+ {
+ return state == lldb::eStateExited;
+ }
+
+ bool
+ ProcessIDIsValid ( ) const;
+
+ void
+ Clear ( );
+
+ lldb_private::Flags &
+ GetFlags ()
+ {
+ return m_flags;
+ }
+
+ const lldb_private::Flags &
+ GetFlags () const
+ {
+ return m_flags;
+ }
+
+ virtual bool
+ UpdateThreadList (lldb_private::ThreadList &old_thread_list,
+ lldb_private::ThreadList &new_thread_list);
+
+ lldb_private::Error
+ StartDebugserverProcess (const char *debugserver_url);
+
+ lldb_private::Error
+ StartDebugserverProcess (const char *debugserver_url, const lldb_private::ProcessInfo &process_info);
+
+ void
+ KillDebugserverProcess ();
+
+ void
+ BuildDynamicRegisterInfo (bool force);
+
+ void
+ SetLastStopPacket (const StringExtractorGDBRemote &response);
+
+ //------------------------------------------------------------------
+ /// Broadcaster event bits definitions.
+ //------------------------------------------------------------------
+ enum
+ {
+ eBroadcastBitAsyncContinue = (1 << 0),
+ eBroadcastBitAsyncThreadShouldExit = (1 << 1),
+ eBroadcastBitAsyncThreadDidExit = (1 << 2)
+ };
+
+ typedef enum AsyncThreadState
+ {
+ eAsyncThreadNotStarted,
+ eAsyncThreadRunning,
+ eAsyncThreadDone
+ } AsyncThreadState;
+
+ lldb_private::Flags m_flags; // Process specific flags (see eFlags enums)
+ GDBRemoteCommunicationClient m_gdb_comm;
+ lldb::pid_t m_debugserver_pid;
+ StringExtractorGDBRemote m_last_stop_packet;
+ lldb_private::Mutex m_last_stop_packet_mutex;
+ GDBRemoteDynamicRegisterInfo m_register_info;
+ lldb_private::Broadcaster m_async_broadcaster;
+ lldb::thread_t m_async_thread;
+ AsyncThreadState m_async_thread_state;
+ lldb_private::Mutex m_async_thread_state_mutex;
+ typedef std::vector<lldb::tid_t> tid_collection;
+ typedef std::vector< std::pair<lldb::tid_t,int> > tid_sig_collection;
+ typedef std::map<lldb::addr_t, lldb::addr_t> MMapMap;
+ tid_collection m_thread_ids; // Thread IDs for all threads. This list gets updated after stopping
+ tid_collection m_continue_c_tids; // 'c' for continue
+ tid_sig_collection m_continue_C_tids; // 'C' for continue with signal
+ tid_collection m_continue_s_tids; // 's' for step
+ tid_sig_collection m_continue_S_tids; // 'S' for step with signal
+ lldb::addr_t m_dispatch_queue_offsets_addr;
+ size_t m_max_memory_size; // The maximum number of bytes to read/write when reading and writing memory
+ MMapMap m_addr_to_mmap_size;
+ lldb::BreakpointSP m_thread_create_bp_sp;
+ bool m_waiting_for_attach;
+ bool m_destroy_tried_resuming;
+ lldb::CommandObjectSP m_command_sp;
+
+ bool
+ StartAsyncThread ();
+
+ void
+ StopAsyncThread ();
+
+ static void *
+ AsyncThread (void *arg);
+
+ static bool
+ MonitorDebugserverProcess (void *callback_baton,
+ lldb::pid_t pid,
+ bool exited,
+ int signo,
+ int exit_status);
+
+ lldb::StateType
+ SetThreadStopInfo (StringExtractor& stop_packet);
+
+ void
+ ClearThreadIDList ();
+
+ bool
+ UpdateThreadIDList ();
+
+ void
+ DidLaunchOrAttach ();
+
+ lldb_private::Error
+ ConnectToDebugserver (const char *host_port);
+
+ const char *
+ GetDispatchQueueNameForThread (lldb::addr_t thread_dispatch_qaddr,
+ std::string &dispatch_queue_name);
+
+ static size_t
+ AttachInputReaderCallback (void *baton,
+ lldb_private::InputReader *reader,
+ lldb::InputReaderAction notification,
+ const char *bytes,
+ size_t bytes_len);
+
+ lldb_private::DynamicLoader *
+ GetDynamicLoader ();
+
+private:
+ //------------------------------------------------------------------
+ // For ProcessGDBRemote only
+ //------------------------------------------------------------------
+ static bool
+ NewThreadNotifyBreakpointHit (void *baton,
+ lldb_private::StoppointCallbackContext *context,
+ lldb::user_id_t break_id,
+ lldb::user_id_t break_loc_id);
+
+ DISALLOW_COPY_AND_ASSIGN (ProcessGDBRemote);
+
+};
+
+#endif // liblldb_ProcessGDBRemote_h_
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
new file mode 100644
index 000000000000..15b861feaa82
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.cpp
@@ -0,0 +1,196 @@
+//===-- ProcessGDBRemoteLog.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessGDBRemoteLog.h"
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/StreamFile.h"
+
+#include "ProcessGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+// We want to avoid global constructors where code needs to be run so here we
+// control access to our static g_log_sp by hiding it in a singleton function
+// that will construct the static g_lob_sp the first time this function is
+// called.
+static bool g_log_enabled = false;
+static Log * g_log = NULL;
+static Log *
+GetLog ()
+{
+ if (!g_log_enabled)
+ return NULL;
+ return g_log;
+}
+
+
+Log *
+ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (uint32_t mask)
+{
+ Log *log(GetLog ());
+ if (log && mask)
+ {
+ uint32_t log_mask = log->GetMask().Get();
+ if ((log_mask & mask) != mask)
+ return NULL;
+ }
+ return log;
+}
+
+Log *
+ProcessGDBRemoteLog::GetLogIfAnyCategoryIsSet (uint32_t mask)
+{
+ Log *log(GetLog ());
+ if (log && log->GetMask().Get() & mask)
+ return log;
+ return NULL;
+}
+
+void
+ProcessGDBRemoteLog::DisableLog (const char **categories, Stream *feedback_strm)
+{
+ Log *log (GetLog ());
+ if (log)
+ {
+ uint32_t flag_bits = 0;
+
+ if (categories[0] != NULL)
+ {
+ flag_bits = log->GetMask().Get();
+ for (size_t i = 0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+
+ if (::strcasecmp (arg, "all") == 0 ) flag_bits &= ~GDBR_LOG_ALL;
+ else if (::strcasecmp (arg, "async") == 0 ) flag_bits &= ~GDBR_LOG_ASYNC;
+ else if (::strncasecmp (arg, "break", 5) == 0 ) flag_bits &= ~GDBR_LOG_BREAKPOINTS;
+ else if (::strncasecmp (arg, "comm", 4) == 0 ) flag_bits &= ~GDBR_LOG_COMM;
+ else if (::strcasecmp (arg, "default") == 0 ) flag_bits &= ~GDBR_LOG_DEFAULT;
+ else if (::strcasecmp (arg, "packets") == 0 ) flag_bits &= ~GDBR_LOG_PACKETS;
+ else if (::strcasecmp (arg, "memory") == 0 ) flag_bits &= ~GDBR_LOG_MEMORY;
+ else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits &= ~GDBR_LOG_MEMORY_DATA_SHORT;
+ else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits &= ~GDBR_LOG_MEMORY_DATA_LONG;
+ else if (::strcasecmp (arg, "process") == 0 ) flag_bits &= ~GDBR_LOG_PROCESS;
+ else if (::strcasecmp (arg, "step") == 0 ) flag_bits &= ~GDBR_LOG_STEP;
+ else if (::strcasecmp (arg, "thread") == 0 ) flag_bits &= ~GDBR_LOG_THREAD;
+ else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits &= ~GDBR_LOG_VERBOSE;
+ else if (::strncasecmp (arg, "watch", 5) == 0 ) flag_bits &= ~GDBR_LOG_WATCHPOINTS;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ ListLogCategories (feedback_strm);
+ }
+
+ }
+ }
+
+ if (flag_bits == 0)
+ g_log_enabled = false;
+ else
+ log->GetMask().Reset (flag_bits);
+ }
+
+ return;
+}
+
+Log *
+ProcessGDBRemoteLog::EnableLog (StreamSP &log_stream_sp, uint32_t log_options, const char **categories, Stream *feedback_strm)
+{
+ // Try see if there already is a log - that way we can reuse its settings.
+ // We could reuse the log in toto, but we don't know that the stream is the same.
+ uint32_t flag_bits = 0;
+ if (g_log)
+ flag_bits = g_log->GetMask().Get();
+
+ // Now make a new log with this stream if one was provided
+ if (log_stream_sp)
+ {
+ if (g_log)
+ g_log->SetStream(log_stream_sp);
+ else
+ g_log = new Log(log_stream_sp);
+ }
+
+ if (g_log)
+ {
+ bool got_unknown_category = false;
+ for (size_t i=0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+ if (::strcasecmp (arg, "all") == 0 ) flag_bits |= GDBR_LOG_ALL;
+ else if (::strcasecmp (arg, "async") == 0 ) flag_bits |= GDBR_LOG_ASYNC;
+ else if (::strncasecmp (arg, "break", 5) == 0 ) flag_bits |= GDBR_LOG_BREAKPOINTS;
+ else if (::strncasecmp (arg, "comm", 4) == 0 ) flag_bits |= GDBR_LOG_COMM;
+ else if (::strcasecmp (arg, "default") == 0 ) flag_bits |= GDBR_LOG_DEFAULT;
+ else if (::strcasecmp (arg, "packets") == 0 ) flag_bits |= GDBR_LOG_PACKETS;
+ else if (::strcasecmp (arg, "memory") == 0 ) flag_bits |= GDBR_LOG_MEMORY;
+ else if (::strcasecmp (arg, "data-short") == 0 ) flag_bits |= GDBR_LOG_MEMORY_DATA_SHORT;
+ else if (::strcasecmp (arg, "data-long") == 0 ) flag_bits |= GDBR_LOG_MEMORY_DATA_LONG;
+ else if (::strcasecmp (arg, "process") == 0 ) flag_bits |= GDBR_LOG_PROCESS;
+ else if (::strcasecmp (arg, "step") == 0 ) flag_bits |= GDBR_LOG_STEP;
+ else if (::strcasecmp (arg, "thread") == 0 ) flag_bits |= GDBR_LOG_THREAD;
+ else if (::strcasecmp (arg, "verbose") == 0 ) flag_bits |= GDBR_LOG_VERBOSE;
+ else if (::strncasecmp (arg, "watch", 5) == 0 ) flag_bits |= GDBR_LOG_WATCHPOINTS;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ if (got_unknown_category == false)
+ {
+ got_unknown_category = true;
+ ListLogCategories (feedback_strm);
+ }
+ }
+ }
+ if (flag_bits == 0)
+ flag_bits = GDBR_LOG_DEFAULT;
+ g_log->GetMask().Reset(flag_bits);
+ g_log->GetOptions().Reset(log_options);
+ }
+ g_log_enabled = true;
+ return g_log;
+}
+
+void
+ProcessGDBRemoteLog::ListLogCategories (Stream *strm)
+{
+ strm->Printf ("Logging categories for '%s':\n"
+ " all - turn on all available logging categories\n"
+ " async - log asynchronous activity\n"
+ " break - log breakpoints\n"
+ " communication - log communication activity\n"
+ " default - enable the default set of logging categories for liblldb\n"
+ " packets - log gdb remote packets\n"
+ " memory - log memory reads and writes\n"
+ " data-short - log memory bytes for memory reads and writes for short transactions only\n"
+ " data-long - log memory bytes for memory reads and writes for all transactions\n"
+ " process - log process events and activities\n"
+ " thread - log thread events and activities\n"
+ " step - log step related activities\n"
+ " verbose - enable verbose logging\n"
+ " watch - log watchpoint related activities\n", ProcessGDBRemote::GetPluginNameStatic().GetCString());
+}
+
+
+void
+ProcessGDBRemoteLog::LogIf (uint32_t mask, const char *format, ...)
+{
+ Log *log (ProcessGDBRemoteLog::GetLogIfAllCategoriesSet (mask));
+ if (log)
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+}
diff --git a/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
new file mode 100644
index 000000000000..93734067f133
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ProcessGDBRemoteLog.h
@@ -0,0 +1,57 @@
+//===-- ProcessGDBRemoteLog.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessGDBRemoteLog_h_
+#define liblldb_ProcessGDBRemoteLog_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/Core/Log.h"
+
+#define GDBR_LOG_VERBOSE (1u << 0)
+#define GDBR_LOG_PROCESS (1u << 1)
+#define GDBR_LOG_THREAD (1u << 2)
+#define GDBR_LOG_PACKETS (1u << 3)
+#define GDBR_LOG_MEMORY (1u << 4) // Log memory reads/writes calls
+#define GDBR_LOG_MEMORY_DATA_SHORT (1u << 5) // Log short memory reads/writes bytes
+#define GDBR_LOG_MEMORY_DATA_LONG (1u << 6) // Log all memory reads/writes bytes
+#define GDBR_LOG_BREAKPOINTS (1u << 7)
+#define GDBR_LOG_WATCHPOINTS (1u << 8)
+#define GDBR_LOG_STEP (1u << 9)
+#define GDBR_LOG_COMM (1u << 10)
+#define GDBR_LOG_ASYNC (1u << 11)
+#define GDBR_LOG_ALL (UINT32_MAX)
+#define GDBR_LOG_DEFAULT GDBR_LOG_PACKETS
+
+class ProcessGDBRemoteLog
+{
+public:
+ static lldb_private::Log *
+ GetLogIfAllCategoriesSet(uint32_t mask = 0);
+
+ static lldb_private::Log *
+ GetLogIfAnyCategoryIsSet (uint32_t mask);
+
+ static void
+ DisableLog (const char **categories, lldb_private::Stream *feedback_strm);
+
+ static lldb_private::Log *
+ EnableLog (lldb::StreamSP &log_stream_sp, uint32_t log_options, const char **categories, lldb_private::Stream *feedback_strm);
+
+ static void
+ ListLogCategories (lldb_private::Stream *strm);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+};
+
+#endif // liblldb_ProcessGDBRemoteLog_h_
diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
new file mode 100644
index 000000000000..38fb84d66ef3
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.cpp
@@ -0,0 +1,214 @@
+//===-- ThreadGDBRemote.cpp -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+
+#include "ThreadGDBRemote.h"
+
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/State.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/StopInfo.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Unwind.h"
+#include "lldb/Breakpoint/Watchpoint.h"
+
+#include "ProcessGDBRemote.h"
+#include "ProcessGDBRemoteLog.h"
+#include "Utility/StringExtractorGDBRemote.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Thread Registers
+//----------------------------------------------------------------------
+
+ThreadGDBRemote::ThreadGDBRemote (Process &process, lldb::tid_t tid) :
+ Thread(process, tid),
+ m_thread_name (),
+ m_dispatch_queue_name (),
+ m_thread_dispatch_qaddr (LLDB_INVALID_ADDRESS)
+{
+ ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::ThreadGDBRemote (pid = %i, tid = 0x%4.4x)",
+ this,
+ process.GetID(),
+ GetID());
+}
+
+ThreadGDBRemote::~ThreadGDBRemote ()
+{
+ ProcessSP process_sp(GetProcess());
+ ProcessGDBRemoteLog::LogIf(GDBR_LOG_THREAD, "%p: ThreadGDBRemote::~ThreadGDBRemote (pid = %i, tid = 0x%4.4x)",
+ this,
+ process_sp ? process_sp->GetID() : LLDB_INVALID_PROCESS_ID,
+ GetID());
+ DestroyThread();
+}
+
+const char *
+ThreadGDBRemote::GetName ()
+{
+ if (m_thread_name.empty())
+ return NULL;
+ return m_thread_name.c_str();
+}
+
+
+const char *
+ThreadGDBRemote::GetQueueName ()
+{
+ // Always re-fetch the dispatch queue name since it can change
+
+ if (m_thread_dispatch_qaddr != 0 || m_thread_dispatch_qaddr != LLDB_INVALID_ADDRESS)
+ {
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get());
+ return gdb_process->GetDispatchQueueNameForThread (m_thread_dispatch_qaddr, m_dispatch_queue_name);
+ }
+ }
+ return NULL;
+}
+
+void
+ThreadGDBRemote::WillResume (StateType resume_state)
+{
+ int signo = GetResumeSignal();
+ const lldb::user_id_t tid = GetProtocolID();
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (GDBR_LOG_THREAD));
+ if (log)
+ log->Printf ("Resuming thread: %4.4" PRIx64 " with state: %s.", tid, StateAsCString(resume_state));
+
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get());
+ switch (resume_state)
+ {
+ case eStateSuspended:
+ case eStateStopped:
+ // Don't append anything for threads that should stay stopped.
+ break;
+
+ case eStateRunning:
+ if (gdb_process->GetUnixSignals().SignalIsValid (signo))
+ gdb_process->m_continue_C_tids.push_back(std::make_pair(tid, signo));
+ else
+ gdb_process->m_continue_c_tids.push_back(tid);
+ break;
+
+ case eStateStepping:
+ if (gdb_process->GetUnixSignals().SignalIsValid (signo))
+ gdb_process->m_continue_S_tids.push_back(std::make_pair(tid, signo));
+ else
+ gdb_process->m_continue_s_tids.push_back(tid);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+void
+ThreadGDBRemote::RefreshStateAfterStop()
+{
+ // Invalidate all registers in our register context. We don't set "force" to
+ // true because the stop reply packet might have had some register values
+ // that were expedited and these will already be copied into the register
+ // context by the time this function gets called. The GDBRemoteRegisterContext
+ // class has been made smart enough to detect when it needs to invalidate
+ // which registers are valid by putting hooks in the register read and
+ // register supply functions where they check the process stop ID and do
+ // the right thing.
+ const bool force = false;
+ GetRegisterContext()->InvalidateIfNeeded (force);
+}
+
+bool
+ThreadGDBRemote::ThreadIDIsValid (lldb::tid_t thread)
+{
+ return thread != 0;
+}
+
+void
+ThreadGDBRemote::Dump(Log *log, uint32_t index)
+{
+}
+
+
+bool
+ThreadGDBRemote::ShouldStop (bool &step_more)
+{
+ return true;
+}
+lldb::RegisterContextSP
+ThreadGDBRemote::GetRegisterContext ()
+{
+ if (m_reg_context_sp.get() == NULL)
+ m_reg_context_sp = CreateRegisterContextForFrame (NULL);
+ return m_reg_context_sp;
+}
+
+lldb::RegisterContextSP
+ThreadGDBRemote::CreateRegisterContextForFrame (StackFrame *frame)
+{
+ lldb::RegisterContextSP reg_ctx_sp;
+ const bool read_all_registers_at_once = false;
+ uint32_t concrete_frame_idx = 0;
+
+ if (frame)
+ concrete_frame_idx = frame->GetConcreteFrameIndex ();
+
+
+ if (concrete_frame_idx == 0)
+ {
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get());
+ reg_ctx_sp.reset (new GDBRemoteRegisterContext (*this, concrete_frame_idx, gdb_process->m_register_info, read_all_registers_at_once));
+ }
+ }
+ else
+ {
+ Unwind *unwinder = GetUnwinder ();
+ if (unwinder)
+ reg_ctx_sp = unwinder->CreateRegisterContextForFrame (frame);
+ }
+ return reg_ctx_sp;
+}
+
+bool
+ThreadGDBRemote::PrivateSetRegisterValue (uint32_t reg, StringExtractor &response)
+{
+ GDBRemoteRegisterContext *gdb_reg_ctx = static_cast<GDBRemoteRegisterContext *>(GetRegisterContext ().get());
+ assert (gdb_reg_ctx);
+ return gdb_reg_ctx->PrivateSetRegisterValue (reg, response);
+}
+
+bool
+ThreadGDBRemote::CalculateStopInfo ()
+{
+ ProcessSP process_sp (GetProcess());
+ if (process_sp)
+ {
+ StringExtractorGDBRemote stop_packet;
+ ProcessGDBRemote *gdb_process = static_cast<ProcessGDBRemote *>(process_sp.get());
+ if (gdb_process->GetGDBRemote().GetThreadStopInfo(GetProtocolID(), stop_packet))
+ return gdb_process->SetThreadStopInfo (stop_packet) == eStateStopped;
+ }
+ return false;
+}
+
+
diff --git a/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
new file mode 100644
index 000000000000..50a3f19c6505
--- /dev/null
+++ b/source/Plugins/Process/gdb-remote/ThreadGDBRemote.h
@@ -0,0 +1,107 @@
+//===-- ThreadGDBRemote.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ThreadGDBRemote_h_
+#define liblldb_ThreadGDBRemote_h_
+
+#include <string>
+
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+
+class StringExtractor;
+class ProcessGDBRemote;
+
+class ThreadGDBRemote : public lldb_private::Thread
+{
+public:
+ ThreadGDBRemote (lldb_private::Process &process, lldb::tid_t tid);
+
+ virtual
+ ~ThreadGDBRemote ();
+
+ virtual void
+ WillResume (lldb::StateType resume_state);
+
+ virtual void
+ RefreshStateAfterStop();
+
+ virtual const char *
+ GetName ();
+
+ virtual const char *
+ GetQueueName ();
+
+ virtual lldb::RegisterContextSP
+ GetRegisterContext ();
+
+ virtual lldb::RegisterContextSP
+ CreateRegisterContextForFrame (lldb_private::StackFrame *frame);
+
+ void
+ Dump (lldb_private::Log *log, uint32_t index);
+
+ static bool
+ ThreadIDIsValid (lldb::tid_t thread);
+
+ bool
+ ShouldStop (bool &step_more);
+
+ const char *
+ GetBasicInfoAsString ();
+
+ void
+ SetName (const char *name)
+ {
+ if (name && name[0])
+ m_thread_name.assign (name);
+ else
+ m_thread_name.clear();
+ }
+
+ lldb::addr_t
+ GetThreadDispatchQAddr ()
+ {
+ return m_thread_dispatch_qaddr;
+ }
+
+ void
+ SetThreadDispatchQAddr (lldb::addr_t thread_dispatch_qaddr)
+ {
+ m_thread_dispatch_qaddr = thread_dispatch_qaddr;
+ }
+
+protected:
+
+ friend class ProcessGDBRemote;
+
+ bool
+ PrivateSetRegisterValue (uint32_t reg,
+ StringExtractor &response);
+
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+ std::string m_thread_name;
+ std::string m_dispatch_queue_name;
+ lldb::addr_t m_thread_dispatch_qaddr;
+ //------------------------------------------------------------------
+ // Member variables.
+ //------------------------------------------------------------------
+
+ void
+ SetStopInfoFromPacket (StringExtractor &stop_packet, uint32_t stop_id);
+
+ virtual bool
+ CalculateStopInfo ();
+
+
+};
+
+#endif // liblldb_ThreadGDBRemote_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp
new file mode 100644
index 000000000000..06e87eab33ce
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.cpp
@@ -0,0 +1,211 @@
+//===-- DWARFAbbreviationDeclaration.cpp ------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFAbbreviationDeclaration.h"
+
+#include "lldb/Core/dwarf.h"
+
+#include "DWARFFormValue.h"
+
+using namespace lldb_private;
+
+DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() :
+ m_code (InvalidCode),
+ m_tag (0),
+ m_has_children (0),
+ m_attributes()
+{
+}
+
+DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration(dw_tag_t tag, uint8_t has_children) :
+ m_code (InvalidCode),
+ m_tag (tag),
+ m_has_children (has_children),
+ m_attributes()
+{
+}
+
+bool
+DWARFAbbreviationDeclaration::Extract(const DataExtractor& data, lldb::offset_t* offset_ptr)
+{
+ return Extract(data, offset_ptr, data.GetULEB128(offset_ptr));
+}
+
+bool
+DWARFAbbreviationDeclaration::Extract(const DataExtractor& data, lldb::offset_t *offset_ptr, dw_uleb128_t code)
+{
+ m_code = code;
+ m_attributes.clear();
+ if (m_code)
+ {
+ m_tag = data.GetULEB128(offset_ptr);
+ m_has_children = data.GetU8(offset_ptr);
+
+ while (data.ValidOffset(*offset_ptr))
+ {
+ dw_attr_t attr = data.GetULEB128(offset_ptr);
+ dw_form_t form = data.GetULEB128(offset_ptr);
+
+ if (attr && form)
+ m_attributes.push_back(DWARFAttribute(attr, form));
+ else
+ break;
+ }
+
+ return m_tag != 0;
+ }
+ else
+ {
+ m_tag = 0;
+ m_has_children = 0;
+ }
+
+ return false;
+}
+
+
+void
+DWARFAbbreviationDeclaration::Dump(Stream *s) const
+{
+// *ostrm_ptr << std::setfill(' ') << std::dec << '[' << std::setw(3) << std::right << m_code << ']' << ' ' << std::setw(30) << std::left << DW_TAG_value_to_name(m_tag) << DW_CHILDREN_value_to_name(m_has_children) << std::endl;
+//
+// DWARFAttribute::const_iterator pos;
+//
+// for (pos = m_attributes.begin(); pos != m_attributes.end(); ++pos)
+// *ostrm_ptr << " " << std::setw(29) << std::left << DW_AT_value_to_name(pos->attr()) << ' ' << DW_FORM_value_to_name(pos->form()) << std::endl;
+//
+// *ostrm_ptr << std::endl;
+}
+
+
+
+bool
+DWARFAbbreviationDeclaration::IsValid()
+{
+ return m_code != 0 && m_tag != 0;
+}
+
+
+void
+DWARFAbbreviationDeclaration::CopyExcludingAddressAttributes(const DWARFAbbreviationDeclaration& abbr_decl, const uint32_t idx)
+{
+ m_code = abbr_decl.Code(); // Invalidate the code since that can't be copied safely.
+ m_tag = abbr_decl.Tag();
+ m_has_children = abbr_decl.HasChildren();
+
+ const DWARFAttribute::collection& attributes = abbr_decl.Attributes();
+ const uint32_t num_abbr_decl_attributes = attributes.size();
+
+ dw_attr_t attr;
+ dw_form_t form;
+ uint32_t i;
+
+ for (i = 0; i < num_abbr_decl_attributes; ++i)
+ {
+ attributes[i].get(attr, form);
+ switch (attr)
+ {
+ case DW_AT_location:
+ case DW_AT_frame_base:
+ // Only add these if they are location expressions (have a single
+ // value) and not location lists (have a lists of location
+ // expressions which are only valid over specific address ranges)
+ if (DWARFFormValue::IsBlockForm(form))
+ m_attributes.push_back(DWARFAttribute(attr, form));
+ break;
+
+ case DW_AT_low_pc:
+ case DW_AT_high_pc:
+ case DW_AT_ranges:
+ case DW_AT_entry_pc:
+ // Don't add these attributes
+ if (i >= idx)
+ break;
+ // Fall through and add attribute
+ default:
+ // Add anything that isn't address related
+ m_attributes.push_back(DWARFAttribute(attr, form));
+ break;
+ }
+ }
+}
+
+void
+DWARFAbbreviationDeclaration::CopyChangingStringToStrp(
+ const DWARFAbbreviationDeclaration& abbr_decl,
+ const DataExtractor& debug_info_data,
+ dw_offset_t debug_info_offset,
+ const DWARFCompileUnit* cu,
+ const uint32_t strp_min_len
+)
+{
+ m_code = InvalidCode;
+ m_tag = abbr_decl.Tag();
+ m_has_children = abbr_decl.HasChildren();
+
+ const DWARFAttribute::collection& attributes = abbr_decl.Attributes();
+ const uint32_t num_abbr_decl_attributes = attributes.size();
+
+ dw_attr_t attr;
+ dw_form_t form;
+ uint32_t i;
+ lldb::offset_t offset = debug_info_offset;
+
+ for (i = 0; i < num_abbr_decl_attributes; ++i)
+ {
+ attributes[i].get(attr, form);
+ dw_offset_t attr_offset = offset;
+ DWARFFormValue::SkipValue(form, debug_info_data, &offset, cu);
+
+ if (form == DW_FORM_string && ((offset - attr_offset) >= strp_min_len))
+ m_attributes.push_back(DWARFAttribute(attr, DW_FORM_strp));
+ else
+ m_attributes.push_back(DWARFAttribute(attr, form));
+ }
+}
+
+
+uint32_t
+DWARFAbbreviationDeclaration::FindAttributeIndex(dw_attr_t attr) const
+{
+ uint32_t i;
+ const uint32_t kNumAttributes = m_attributes.size();
+ for (i = 0; i < kNumAttributes; ++i)
+ {
+ if (m_attributes[i].get_attr() == attr)
+ return i;
+ }
+ return DW_INVALID_INDEX;
+}
+
+
+bool
+DWARFAbbreviationDeclaration::operator == (const DWARFAbbreviationDeclaration& rhs) const
+{
+ return Tag() == rhs.Tag()
+ && HasChildren() == rhs.HasChildren()
+ && Attributes() == rhs.Attributes();
+}
+
+#if 0
+DWARFAbbreviationDeclaration::Append(BinaryStreamBuf& out_buff) const
+{
+ out_buff.Append32_as_ULEB128(Code());
+ out_buff.Append32_as_ULEB128(Tag());
+ out_buff.Append8(HasChildren());
+ const uint32_t kNumAttributes = m_attributes.size();
+ for (uint32_t i = 0; i < kNumAttributes; ++i)
+ {
+ out_buff.Append32_as_ULEB128(m_attributes[i].attr());
+ out_buff.Append32_as_ULEB128(m_attributes[i].form());
+ }
+ out_buff.Append8(0); // Output a zero for attr (faster than using Append32_as_ULEB128)
+ out_buff.Append8(0); // Output a zero for attr (faster than using Append32_as_ULEB128)
+}
+#endif // 0
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h
new file mode 100644
index 000000000000..f462b7fc108d
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFAbbreviationDeclaration.h
@@ -0,0 +1,81 @@
+//===-- DWARFAbbreviationDeclaration.h --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_DWARFAbbreviationDeclaration_h_
+#define liblldb_DWARFAbbreviationDeclaration_h_
+
+#include "SymbolFileDWARF.h"
+#include "DWARFAttribute.h"
+
+class DWARFCompileUnit;
+
+class DWARFAbbreviationDeclaration
+{
+public:
+ enum { InvalidCode = 0 };
+ DWARFAbbreviationDeclaration();
+
+ // For hand crafting an abbreviation declaration
+ DWARFAbbreviationDeclaration(dw_tag_t tag, uint8_t has_children);
+ void AddAttribute(const DWARFAttribute& attr)
+ {
+ m_attributes.push_back(attr);
+ }
+
+ dw_uleb128_t Code() const { return m_code; }
+ void SetCode(dw_uleb128_t code) { m_code = code; }
+ dw_tag_t Tag() const { return m_tag; }
+ bool HasChildren() const { return m_has_children; }
+ size_t NumAttributes() const { return m_attributes.size(); }
+ dw_attr_t GetAttrByIndex(uint32_t idx) const { return m_attributes.size() > idx ? m_attributes[idx].get_attr() : 0; }
+ dw_form_t GetFormByIndex(uint32_t idx) const { return m_attributes.size() > idx ? m_attributes[idx].get_form() : 0; }
+ bool GetAttrAndFormByIndex(uint32_t idx, dw_attr_t& attr, dw_form_t& form) const
+ {
+ if (m_attributes.size() > idx)
+ {
+ m_attributes[idx].get(attr, form);
+ return true;
+ }
+ attr = form = 0;
+ return false;
+ }
+
+ // idx is assumed to be valid when calling GetAttrAndFormByIndexUnchecked()
+ void GetAttrAndFormByIndexUnchecked(uint32_t idx, dw_attr_t& attr, dw_form_t& form) const
+ {
+ m_attributes[idx].get(attr, form);
+ }
+ dw_form_t GetFormByIndexUnchecked (uint32_t idx) const
+ {
+ return m_attributes[idx].get_form();
+ }
+ void CopyExcludingAddressAttributes(const DWARFAbbreviationDeclaration& abbr_decl, const uint32_t idx);
+ void CopyChangingStringToStrp(
+ const DWARFAbbreviationDeclaration& abbr_decl,
+ const lldb_private::DataExtractor& debug_info_data,
+ dw_offset_t debug_info_offset,
+ const DWARFCompileUnit* cu,
+ const uint32_t strp_min_len);
+ uint32_t FindAttributeIndex(dw_attr_t attr) const;
+ bool Extract(const lldb_private::DataExtractor& data, lldb::offset_t *offset_ptr);
+ bool Extract(const lldb_private::DataExtractor& data, lldb::offset_t *offset_ptr, dw_uleb128_t code);
+// void Append(BinaryStreamBuf& out_buff) const;
+ bool IsValid();
+ void Dump(lldb_private::Stream *s) const;
+ bool operator == (const DWARFAbbreviationDeclaration& rhs) const;
+// DWARFAttribute::collection& Attributes() { return m_attributes; }
+ const DWARFAttribute::collection& Attributes() const { return m_attributes; }
+protected:
+ dw_uleb128_t m_code;
+ dw_tag_t m_tag;
+ uint8_t m_has_children;
+ DWARFAttribute::collection m_attributes;
+};
+
+#endif // liblldb_DWARFAbbreviationDeclaration_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h
new file mode 100644
index 000000000000..8310b1dda5f1
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFAttribute.h
@@ -0,0 +1,45 @@
+//===-- DWARFAttribute.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFAttribute_h_
+#define SymbolFileDWARF_DWARFAttribute_h_
+
+#include "DWARFDefines.h"
+#include <vector>
+
+class DWARFAttribute
+{
+public:
+ DWARFAttribute(dw_attr_t attr, dw_form_t form) :
+ m_attr_form ( attr << 16 | form )
+ {
+ }
+
+ void set(dw_attr_t attr, dw_form_t form) { m_attr_form = (attr << 16) | form; }
+ void set_attr(dw_attr_t attr) { m_attr_form = (m_attr_form & 0x0000ffffu) | (attr << 16); }
+ void set_form(dw_form_t form) { m_attr_form = (m_attr_form & 0xffff0000u) | form; }
+ dw_attr_t get_attr() const { return m_attr_form >> 16; }
+ dw_form_t get_form() const { return (dw_form_t)m_attr_form; }
+ void get(dw_attr_t& attr, dw_form_t& form) const
+ {
+ register uint32_t attr_form = m_attr_form;
+ attr = attr_form >> 16;
+ form = (dw_form_t)attr_form;
+ }
+ bool operator == (const DWARFAttribute& rhs) const { return m_attr_form == rhs.m_attr_form; }
+ typedef std::vector<DWARFAttribute> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+protected:
+ uint32_t m_attr_form; // Upper 16 bits is attribute, lower 16 bits is form
+};
+
+
+#endif // SymbolFileDWARF_DWARFAttribute_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
new file mode 100644
index 000000000000..493b3af6ecd1
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.cpp
@@ -0,0 +1,1027 @@
+//===-- DWARFCompileUnit.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFCompileUnit.h"
+
+#include "lldb/Core/Mangled.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Target/ObjCLanguageRuntime.h"
+
+#include "DWARFDebugAbbrev.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFDIECollection.h"
+#include "DWARFFormValue.h"
+#include "LogChannelDWARF.h"
+#include "NameToDIE.h"
+#include "SymbolFileDWARF.h"
+#include "SymbolFileDWARFDebugMap.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace std;
+
+
+extern int g_verbose;
+
+DWARFCompileUnit::DWARFCompileUnit(SymbolFileDWARF* dwarf2Data) :
+ m_dwarf2Data (dwarf2Data),
+ m_abbrevs (NULL),
+ m_user_data (NULL),
+ m_die_array (),
+ m_func_aranges_ap (),
+ m_base_addr (0),
+ m_offset (DW_INVALID_OFFSET),
+ m_length (0),
+ m_version (0),
+ m_addr_size (DWARFCompileUnit::GetDefaultAddressSize()),
+ m_producer (eProducerInvalid),
+ m_producer_version_major (0),
+ m_producer_version_minor (0),
+ m_producer_version_update (0)
+{
+}
+
+void
+DWARFCompileUnit::Clear()
+{
+ m_offset = DW_INVALID_OFFSET;
+ m_length = 0;
+ m_version = 0;
+ m_abbrevs = NULL;
+ m_addr_size = DWARFCompileUnit::GetDefaultAddressSize();
+ m_base_addr = 0;
+ m_die_array.clear();
+ m_func_aranges_ap.reset();
+ m_user_data = NULL;
+ m_producer = eProducerInvalid;
+}
+
+bool
+DWARFCompileUnit::Extract(const DataExtractor &debug_info, lldb::offset_t *offset_ptr)
+{
+ Clear();
+
+ m_offset = *offset_ptr;
+
+ if (debug_info.ValidOffset(*offset_ptr))
+ {
+ dw_offset_t abbr_offset;
+ const DWARFDebugAbbrev *abbr = m_dwarf2Data->DebugAbbrev();
+ m_length = debug_info.GetU32(offset_ptr);
+ m_version = debug_info.GetU16(offset_ptr);
+ abbr_offset = debug_info.GetU32(offset_ptr);
+ m_addr_size = debug_info.GetU8 (offset_ptr);
+
+ bool length_OK = debug_info.ValidOffset(GetNextCompileUnitOffset()-1);
+ bool version_OK = SymbolFileDWARF::SupportedVersion(m_version);
+ bool abbr_offset_OK = m_dwarf2Data->get_debug_abbrev_data().ValidOffset(abbr_offset);
+ bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8));
+
+ if (length_OK && version_OK && addr_size_OK && abbr_offset_OK && abbr != NULL)
+ {
+ m_abbrevs = abbr->GetAbbreviationDeclarationSet(abbr_offset);
+ return true;
+ }
+
+ // reset the offset to where we tried to parse from if anything went wrong
+ *offset_ptr = m_offset;
+ }
+
+ return false;
+}
+
+
+dw_offset_t
+DWARFCompileUnit::Extract(lldb::offset_t offset, const DataExtractor& debug_info_data, const DWARFAbbreviationDeclarationSet* abbrevs)
+{
+ Clear();
+
+ m_offset = offset;
+
+ if (debug_info_data.ValidOffset(offset))
+ {
+ m_length = debug_info_data.GetU32(&offset);
+ m_version = debug_info_data.GetU16(&offset);
+ bool abbrevs_OK = debug_info_data.GetU32(&offset) == abbrevs->GetOffset();
+ m_abbrevs = abbrevs;
+ m_addr_size = debug_info_data.GetU8 (&offset);
+
+ bool version_OK = SymbolFileDWARF::SupportedVersion(m_version);
+ bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8));
+
+ if (version_OK && addr_size_OK && abbrevs_OK && debug_info_data.ValidOffset(offset))
+ return offset;
+ }
+ return DW_INVALID_OFFSET;
+}
+
+void
+DWARFCompileUnit::ClearDIEs(bool keep_compile_unit_die)
+{
+ if (m_die_array.size() > 1)
+ {
+ // std::vectors never get any smaller when resized to a smaller size,
+ // or when clear() or erase() are called, the size will report that it
+ // is smaller, but the memory allocated remains intact (call capacity()
+ // to see this). So we need to create a temporary vector and swap the
+ // contents which will cause just the internal pointers to be swapped
+ // so that when "tmp_array" goes out of scope, it will destroy the
+ // contents.
+
+ // Save at least the compile unit DIE
+ DWARFDebugInfoEntry::collection tmp_array;
+ m_die_array.swap(tmp_array);
+ if (keep_compile_unit_die)
+ m_die_array.push_back(tmp_array.front());
+ }
+}
+
+//----------------------------------------------------------------------
+// ParseCompileUnitDIEsIfNeeded
+//
+// Parses a compile unit and indexes its DIEs if it hasn't already been
+// done.
+//----------------------------------------------------------------------
+size_t
+DWARFCompileUnit::ExtractDIEsIfNeeded (bool cu_die_only)
+{
+ const size_t initial_die_array_size = m_die_array.size();
+ if ((cu_die_only && initial_die_array_size > 0) || initial_die_array_size > 1)
+ return 0; // Already parsed
+
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "%8.8x: DWARFCompileUnit::ExtractDIEsIfNeeded( cu_die_only = %i )",
+ m_offset,
+ cu_die_only);
+
+ // Set the offset to that of the first DIE and calculate the start of the
+ // next compilation unit header.
+ lldb::offset_t offset = GetFirstDIEOffset();
+ lldb::offset_t next_cu_offset = GetNextCompileUnitOffset();
+
+ DWARFDebugInfoEntry die;
+ // Keep a flat array of the DIE for binary lookup by DIE offset
+ if (!cu_die_only)
+ {
+ Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO | DWARF_LOG_LOOKUPS));
+ if (log)
+ {
+ m_dwarf2Data->GetObjectFile()->GetModule()->LogMessageVerboseBacktrace (log,
+ "DWARFCompileUnit::ExtractDIEsIfNeeded () for compile unit at .debug_info[0x%8.8x]",
+ GetOffset());
+ }
+ }
+
+ uint32_t depth = 0;
+ // We are in our compile unit, parse starting at the offset
+ // we were told to parse
+ const DataExtractor& debug_info_data = m_dwarf2Data->get_debug_info_data();
+ std::vector<uint32_t> die_index_stack;
+ die_index_stack.reserve(32);
+ die_index_stack.push_back(0);
+ bool prev_die_had_children = false;
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (GetAddressByteSize());
+ while (offset < next_cu_offset &&
+ die.FastExtract (debug_info_data, this, fixed_form_sizes, &offset))
+ {
+// if (log)
+// log->Printf("0x%8.8x: %*.*s%s%s",
+// die.GetOffset(),
+// depth * 2, depth * 2, "",
+// DW_TAG_value_to_name (die.Tag()),
+// die.HasChildren() ? " *" : "");
+
+ const bool null_die = die.IsNULL();
+ if (depth == 0)
+ {
+ uint64_t base_addr = die.GetAttributeValueAsUnsigned(m_dwarf2Data, this, DW_AT_low_pc, LLDB_INVALID_ADDRESS);
+ if (base_addr == LLDB_INVALID_ADDRESS)
+ base_addr = die.GetAttributeValueAsUnsigned(m_dwarf2Data, this, DW_AT_entry_pc, 0);
+ SetBaseAddress (base_addr);
+ if (initial_die_array_size == 0)
+ AddDIE (die);
+ if (cu_die_only)
+ return 1;
+ }
+ else
+ {
+ if (null_die)
+ {
+ if (prev_die_had_children)
+ {
+ // This will only happen if a DIE says is has children
+ // but all it contains is a NULL tag. Since we are removing
+ // the NULL DIEs from the list (saves up to 25% in C++ code),
+ // we need a way to let the DIE know that it actually doesn't
+ // have children.
+ if (!m_die_array.empty())
+ m_die_array.back().SetEmptyChildren(true);
+ }
+ }
+ else
+ {
+ die.SetParentIndex(m_die_array.size() - die_index_stack[depth-1]);
+
+ if (die_index_stack.back())
+ m_die_array[die_index_stack.back()].SetSiblingIndex(m_die_array.size()-die_index_stack.back());
+
+ // Only push the DIE if it isn't a NULL DIE
+ m_die_array.push_back(die);
+ }
+ }
+
+ if (null_die)
+ {
+ // NULL DIE.
+ if (!die_index_stack.empty())
+ die_index_stack.pop_back();
+
+ if (depth > 0)
+ --depth;
+ if (depth == 0)
+ break; // We are done with this compile unit!
+
+ prev_die_had_children = false;
+ }
+ else
+ {
+ die_index_stack.back() = m_die_array.size() - 1;
+ // Normal DIE
+ const bool die_has_children = die.HasChildren();
+ if (die_has_children)
+ {
+ die_index_stack.push_back(0);
+ ++depth;
+ }
+ prev_die_had_children = die_has_children;
+ }
+ }
+
+ // Give a little bit of info if we encounter corrupt DWARF (our offset
+ // should always terminate at or before the start of the next compilation
+ // unit header).
+ if (offset > next_cu_offset)
+ {
+ m_dwarf2Data->GetObjectFile()->GetModule()->ReportWarning ("DWARF compile unit extends beyond its bounds cu 0x%8.8x at 0x%8.8" PRIx64 "\n",
+ GetOffset(),
+ offset);
+ }
+
+ // Since std::vector objects will double their size, we really need to
+ // make a new array with the perfect size so we don't end up wasting
+ // space. So here we copy and swap to make sure we don't have any extra
+ // memory taken up.
+
+ if (m_die_array.size () < m_die_array.capacity())
+ {
+ DWARFDebugInfoEntry::collection exact_size_die_array (m_die_array.begin(), m_die_array.end());
+ exact_size_die_array.swap (m_die_array);
+ }
+ Log *log (LogChannelDWARF::GetLogIfAll (DWARF_LOG_DEBUG_INFO | DWARF_LOG_VERBOSE));
+ if (log)
+ {
+ StreamString strm;
+ DWARFDebugInfoEntry::DumpDIECollection (strm, m_die_array);
+ log->PutCString (strm.GetString().c_str());
+ }
+
+ return m_die_array.size();
+}
+
+
+dw_offset_t
+DWARFCompileUnit::GetAbbrevOffset() const
+{
+ return m_abbrevs ? m_abbrevs->GetOffset() : DW_INVALID_OFFSET;
+}
+
+
+
+bool
+DWARFCompileUnit::Verify(Stream *s) const
+{
+ const DataExtractor& debug_info = m_dwarf2Data->get_debug_info_data();
+ bool valid_offset = debug_info.ValidOffset(m_offset);
+ bool length_OK = debug_info.ValidOffset(GetNextCompileUnitOffset()-1);
+ bool version_OK = SymbolFileDWARF::SupportedVersion(m_version);
+ bool abbr_offset_OK = m_dwarf2Data->get_debug_abbrev_data().ValidOffset(GetAbbrevOffset());
+ bool addr_size_OK = ((m_addr_size == 4) || (m_addr_size == 8));
+ bool verbose = s->GetVerbose();
+ if (valid_offset && length_OK && version_OK && addr_size_OK && abbr_offset_OK)
+ {
+ if (verbose)
+ s->Printf(" 0x%8.8x: OK\n", m_offset);
+ return true;
+ }
+ else
+ {
+ s->Printf(" 0x%8.8x: ", m_offset);
+
+ m_dwarf2Data->get_debug_info_data().Dump (s, m_offset, lldb::eFormatHex, 1, Size(), 32, LLDB_INVALID_ADDRESS, 0, 0);
+ s->EOL();
+ if (valid_offset)
+ {
+ if (!length_OK)
+ s->Printf(" The length (0x%8.8x) for this compile unit is too large for the .debug_info provided.\n", m_length);
+ if (!version_OK)
+ s->Printf(" The 16 bit compile unit header version is not supported.\n");
+ if (!abbr_offset_OK)
+ s->Printf(" The offset into the .debug_abbrev section (0x%8.8x) is not valid.\n", GetAbbrevOffset());
+ if (!addr_size_OK)
+ s->Printf(" The address size is unsupported: 0x%2.2x\n", m_addr_size);
+ }
+ else
+ s->Printf(" The start offset of the compile unit header in the .debug_info is invalid.\n");
+ }
+ return false;
+}
+
+
+void
+DWARFCompileUnit::Dump(Stream *s) const
+{
+ s->Printf("0x%8.8x: Compile Unit: length = 0x%8.8x, version = 0x%4.4x, abbr_offset = 0x%8.8x, addr_size = 0x%2.2x (next CU at {0x%8.8x})\n",
+ m_offset, m_length, m_version, GetAbbrevOffset(), m_addr_size, GetNextCompileUnitOffset());
+}
+
+
+static uint8_t g_default_addr_size = 4;
+
+uint8_t
+DWARFCompileUnit::GetAddressByteSize(const DWARFCompileUnit* cu)
+{
+ if (cu)
+ return cu->GetAddressByteSize();
+ return DWARFCompileUnit::GetDefaultAddressSize();
+}
+
+uint8_t
+DWARFCompileUnit::GetDefaultAddressSize()
+{
+ return g_default_addr_size;
+}
+
+void
+DWARFCompileUnit::SetDefaultAddressSize(uint8_t addr_size)
+{
+ g_default_addr_size = addr_size;
+}
+
+void
+DWARFCompileUnit::BuildAddressRangeTable (SymbolFileDWARF* dwarf2Data,
+ DWARFDebugAranges* debug_aranges,
+ bool clear_dies_if_already_not_parsed)
+{
+ // This function is usually called if there in no .debug_aranges section
+ // in order to produce a compile unit level set of address ranges that
+ // is accurate. If the DIEs weren't parsed, then we don't want all dies for
+ // all compile units to stay loaded when they weren't needed. So we can end
+ // up parsing the DWARF and then throwing them all away to keep memory usage
+ // down.
+ const bool clear_dies = ExtractDIEsIfNeeded (false) > 1;
+
+ const DWARFDebugInfoEntry* die = DIE();
+ if (die)
+ die->BuildAddressRangeTable(dwarf2Data, this, debug_aranges);
+
+ if (debug_aranges->IsEmpty())
+ {
+ // We got nothing from the functions, maybe we have a line tables only
+ // situation. Check the line tables and build the arange table from this.
+ SymbolContext sc;
+ sc.comp_unit = dwarf2Data->GetCompUnitForDWARFCompUnit(this);
+ if (sc.comp_unit)
+ {
+ SymbolFileDWARFDebugMap *debug_map_sym_file = m_dwarf2Data->GetDebugMapSymfile();
+ if (debug_map_sym_file == NULL)
+ {
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+
+ if (line_table)
+ {
+ LineTable::FileAddressRanges file_ranges;
+ const bool append = true;
+ const size_t num_ranges = line_table->GetContiguousFileAddressRanges (file_ranges, append);
+ for (uint32_t idx=0; idx<num_ranges; ++idx)
+ {
+ const LineTable::FileAddressRanges::Entry &range = file_ranges.GetEntryRef(idx);
+ debug_aranges->AppendRange(GetOffset(), range.GetRangeBase(), range.GetRangeEnd());
+ printf ("0x%8.8x: [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")\n", GetOffset(), range.GetRangeBase(), range.GetRangeEnd());
+ }
+ }
+ }
+ else
+ debug_map_sym_file->AddOSOARanges(dwarf2Data,debug_aranges);
+ }
+ }
+
+ // Keep memory down by clearing DIEs if this generate function
+ // caused them to be parsed
+ if (clear_dies)
+ ClearDIEs (true);
+
+}
+
+
+const DWARFDebugAranges &
+DWARFCompileUnit::GetFunctionAranges ()
+{
+ if (m_func_aranges_ap.get() == NULL)
+ {
+ m_func_aranges_ap.reset (new DWARFDebugAranges());
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES));
+
+ if (log)
+ {
+ m_dwarf2Data->GetObjectFile()->GetModule()->LogMessage (log,
+ "DWARFCompileUnit::GetFunctionAranges() for compile unit at .debug_info[0x%8.8x]",
+ GetOffset());
+ }
+ const DWARFDebugInfoEntry* die = DIE();
+ if (die)
+ die->BuildFunctionAddressRangeTable (m_dwarf2Data, this, m_func_aranges_ap.get());
+ const bool minimize = false;
+ m_func_aranges_ap->Sort(minimize);
+ }
+ return *m_func_aranges_ap.get();
+}
+
+bool
+DWARFCompileUnit::LookupAddress
+(
+ const dw_addr_t address,
+ DWARFDebugInfoEntry** function_die_handle,
+ DWARFDebugInfoEntry** block_die_handle
+)
+{
+ bool success = false;
+
+ if (function_die_handle != NULL && DIE())
+ {
+
+ const DWARFDebugAranges &func_aranges = GetFunctionAranges ();
+
+ // Re-check the aranges auto pointer contents in case it was created above
+ if (!func_aranges.IsEmpty())
+ {
+ *function_die_handle = GetDIEPtr(func_aranges.FindAddress(address));
+ if (*function_die_handle != NULL)
+ {
+ success = true;
+ if (block_die_handle != NULL)
+ {
+ DWARFDebugInfoEntry* child = (*function_die_handle)->GetFirstChild();
+ while (child)
+ {
+ if (child->LookupAddress(address, m_dwarf2Data, this, NULL, block_die_handle))
+ break;
+ child = child->GetSibling();
+ }
+ }
+ }
+ }
+ }
+ return success;
+}
+
+//----------------------------------------------------------------------
+// Compare function DWARFDebugAranges::Range structures
+//----------------------------------------------------------------------
+static bool CompareDIEOffset (const DWARFDebugInfoEntry& die1, const DWARFDebugInfoEntry& die2)
+{
+ return die1.GetOffset() < die2.GetOffset();
+}
+
+//----------------------------------------------------------------------
+// GetDIEPtr()
+//
+// Get the DIE (Debug Information Entry) with the specified offset.
+//----------------------------------------------------------------------
+DWARFDebugInfoEntry*
+DWARFCompileUnit::GetDIEPtr(dw_offset_t die_offset)
+{
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ ExtractDIEsIfNeeded (false);
+ DWARFDebugInfoEntry compare_die;
+ compare_die.SetOffset(die_offset);
+ DWARFDebugInfoEntry::iterator end = m_die_array.end();
+ DWARFDebugInfoEntry::iterator pos = lower_bound(m_die_array.begin(), end, compare_die, CompareDIEOffset);
+ if (pos != end)
+ {
+ if (die_offset == (*pos).GetOffset())
+ return &(*pos);
+ }
+ }
+ return NULL; // Not found in any compile units
+}
+
+//----------------------------------------------------------------------
+// GetDIEPtrContainingOffset()
+//
+// Get the DIE (Debug Information Entry) that contains the specified
+// .debug_info offset.
+//----------------------------------------------------------------------
+const DWARFDebugInfoEntry*
+DWARFCompileUnit::GetDIEPtrContainingOffset(dw_offset_t die_offset)
+{
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ ExtractDIEsIfNeeded (false);
+ DWARFDebugInfoEntry compare_die;
+ compare_die.SetOffset(die_offset);
+ DWARFDebugInfoEntry::iterator end = m_die_array.end();
+ DWARFDebugInfoEntry::iterator pos = lower_bound(m_die_array.begin(), end, compare_die, CompareDIEOffset);
+ if (pos != end)
+ {
+ if (die_offset >= (*pos).GetOffset())
+ {
+ DWARFDebugInfoEntry::iterator next = pos + 1;
+ if (next != end)
+ {
+ if (die_offset < (*next).GetOffset())
+ return &(*pos);
+ }
+ }
+ }
+ }
+ return NULL; // Not found in any compile units
+}
+
+
+
+size_t
+DWARFCompileUnit::AppendDIEsWithTag (const dw_tag_t tag, DWARFDIECollection& dies, uint32_t depth) const
+{
+ size_t old_size = dies.Size();
+ DWARFDebugInfoEntry::const_iterator pos;
+ DWARFDebugInfoEntry::const_iterator end = m_die_array.end();
+ for (pos = m_die_array.begin(); pos != end; ++pos)
+ {
+ if (pos->Tag() == tag)
+ dies.Append (&(*pos));
+ }
+
+ // Return the number of DIEs added to the collection
+ return dies.Size() - old_size;
+}
+
+//void
+//DWARFCompileUnit::AddGlobalDIEByIndex (uint32_t die_idx)
+//{
+// m_global_die_indexes.push_back (die_idx);
+//}
+//
+//
+//void
+//DWARFCompileUnit::AddGlobal (const DWARFDebugInfoEntry* die)
+//{
+// // Indexes to all file level global and static variables
+// m_global_die_indexes;
+//
+// if (m_die_array.empty())
+// return;
+//
+// const DWARFDebugInfoEntry* first_die = &m_die_array[0];
+// const DWARFDebugInfoEntry* end = first_die + m_die_array.size();
+// if (first_die <= die && die < end)
+// m_global_die_indexes.push_back (die - first_die);
+//}
+
+
+void
+DWARFCompileUnit::Index (const uint32_t cu_idx,
+ NameToDIE& func_basenames,
+ NameToDIE& func_fullnames,
+ NameToDIE& func_methods,
+ NameToDIE& func_selectors,
+ NameToDIE& objc_class_selectors,
+ NameToDIE& globals,
+ NameToDIE& types,
+ NameToDIE& namespaces)
+{
+ const DataExtractor* debug_str = &m_dwarf2Data->get_debug_str_data();
+
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (GetAddressByteSize());
+
+ Log *log (LogChannelDWARF::GetLogIfAll (DWARF_LOG_LOOKUPS));
+
+ if (log)
+ {
+ m_dwarf2Data->GetObjectFile()->GetModule()->LogMessage (log,
+ "DWARFCompileUnit::Index() for compile unit at .debug_info[0x%8.8x]",
+ GetOffset());
+ }
+
+ DWARFDebugInfoEntry::const_iterator pos;
+ DWARFDebugInfoEntry::const_iterator begin = m_die_array.begin();
+ DWARFDebugInfoEntry::const_iterator end = m_die_array.end();
+ for (pos = begin; pos != end; ++pos)
+ {
+ const DWARFDebugInfoEntry &die = *pos;
+
+ const dw_tag_t tag = die.Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_base_type:
+ case DW_TAG_class_type:
+ case DW_TAG_constant:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_string_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_typedef:
+ case DW_TAG_namespace:
+ case DW_TAG_variable:
+ case DW_TAG_unspecified_type:
+ break;
+
+ default:
+ continue;
+ }
+
+ DWARFDebugInfoEntry::Attributes attributes;
+ const char *name = NULL;
+ const char *mangled_cstr = NULL;
+ bool is_declaration = false;
+ //bool is_artificial = false;
+ bool has_address = false;
+ bool has_location = false;
+ bool is_global_or_static_variable = false;
+
+ dw_offset_t specification_die_offset = DW_INVALID_OFFSET;
+ const size_t num_attributes = die.GetAttributes(m_dwarf2Data, this, fixed_form_sizes, attributes);
+ if (num_attributes > 0)
+ {
+ for (uint32_t i=0; i<num_attributes; ++i)
+ {
+ dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ switch (attr)
+ {
+ case DW_AT_name:
+ if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value))
+ name = form_value.AsCString(debug_str);
+ break;
+
+ case DW_AT_declaration:
+ if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value))
+ is_declaration = form_value.Unsigned() != 0;
+ break;
+
+// case DW_AT_artificial:
+// if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value))
+// is_artificial = form_value.Unsigned() != 0;
+// break;
+
+ case DW_AT_MIPS_linkage_name:
+ case DW_AT_linkage_name:
+ if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value))
+ mangled_cstr = form_value.AsCString(debug_str);
+ break;
+
+ case DW_AT_low_pc:
+ case DW_AT_high_pc:
+ case DW_AT_ranges:
+ has_address = true;
+ break;
+
+ case DW_AT_entry_pc:
+ has_address = true;
+ break;
+
+ case DW_AT_location:
+ has_location = true;
+ if (tag == DW_TAG_variable)
+ {
+ const DWARFDebugInfoEntry* parent_die = die.GetParent();
+ while ( parent_die != NULL )
+ {
+ switch (parent_die->Tag())
+ {
+ case DW_TAG_subprogram:
+ case DW_TAG_lexical_block:
+ case DW_TAG_inlined_subroutine:
+ // Even if this is a function level static, we don't add it. We could theoretically
+ // add these if we wanted to by introspecting into the DW_AT_location and seeing
+ // if the location describes a hard coded address, but we dont want the performance
+ // penalty of that right now.
+ is_global_or_static_variable = false;
+// if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value))
+// {
+// // If we have valid block data, then we have location expression bytes
+// // that are fixed (not a location list).
+// const uint8_t *block_data = form_value.BlockData();
+// if (block_data)
+// {
+// uint32_t block_length = form_value.Unsigned();
+// if (block_length == 1 + attributes.CompileUnitAtIndex(i)->GetAddressByteSize())
+// {
+// if (block_data[0] == DW_OP_addr)
+// add_die = true;
+// }
+// }
+// }
+ parent_die = NULL; // Terminate the while loop.
+ break;
+
+ case DW_TAG_compile_unit:
+ is_global_or_static_variable = true;
+ parent_die = NULL; // Terminate the while loop.
+ break;
+
+ default:
+ parent_die = parent_die->GetParent(); // Keep going in the while loop.
+ break;
+ }
+ }
+ }
+ break;
+
+ case DW_AT_specification:
+ if (attributes.ExtractFormValueAtIndex(m_dwarf2Data, i, form_value))
+ specification_die_offset = form_value.Reference(this);
+ break;
+ }
+ }
+ }
+
+ switch (tag)
+ {
+ case DW_TAG_subprogram:
+ if (has_address)
+ {
+ if (name)
+ {
+ // Note, this check is also done in ParseMethodName, but since this is a hot loop, we do the
+ // simple inlined check outside the call.
+ ObjCLanguageRuntime::MethodName objc_method(name, true);
+ if (objc_method.IsValid(true))
+ {
+ ConstString objc_class_name_with_category (objc_method.GetClassNameWithCategory());
+ ConstString objc_selector_name (objc_method.GetSelector());
+ ConstString objc_fullname_no_category_name (objc_method.GetFullNameWithoutCategory(true));
+ ConstString objc_class_name_no_category (objc_method.GetClassName());
+ func_fullnames.Insert (ConstString(name), die.GetOffset());
+ if (objc_class_name_with_category)
+ objc_class_selectors.Insert(objc_class_name_with_category, die.GetOffset());
+ if (objc_class_name_no_category && objc_class_name_no_category != objc_class_name_with_category)
+ objc_class_selectors.Insert(objc_class_name_no_category, die.GetOffset());
+ if (objc_selector_name)
+ func_selectors.Insert (objc_selector_name, die.GetOffset());
+ if (objc_fullname_no_category_name)
+ func_fullnames.Insert (objc_fullname_no_category_name, die.GetOffset());
+ }
+ // If we have a mangled name, then the DW_AT_name attribute
+ // is usually the method name without the class or any parameters
+ const DWARFDebugInfoEntry *parent = die.GetParent();
+ bool is_method = false;
+ if (parent)
+ {
+ dw_tag_t parent_tag = parent->Tag();
+ if (parent_tag == DW_TAG_class_type || parent_tag == DW_TAG_structure_type)
+ {
+ is_method = true;
+ }
+ else
+ {
+ if (specification_die_offset != DW_INVALID_OFFSET)
+ {
+ const DWARFDebugInfoEntry *specification_die = m_dwarf2Data->DebugInfo()->GetDIEPtr (specification_die_offset, NULL);
+ if (specification_die)
+ {
+ parent = specification_die->GetParent();
+ if (parent)
+ {
+ parent_tag = parent->Tag();
+
+ if (parent_tag == DW_TAG_class_type || parent_tag == DW_TAG_structure_type)
+ is_method = true;
+ }
+ }
+ }
+ }
+ }
+
+
+ if (is_method)
+ func_methods.Insert (ConstString(name), die.GetOffset());
+ else
+ func_basenames.Insert (ConstString(name), die.GetOffset());
+
+ if (!is_method && !mangled_cstr && !objc_method.IsValid(true))
+ func_fullnames.Insert (ConstString(name), die.GetOffset());
+ }
+ if (mangled_cstr)
+ {
+ // Make sure our mangled name isn't the same string table entry
+ // as our name. If it starts with '_', then it is ok, else compare
+ // the string to make sure it isn't the same and we don't end up
+ // with duplicate entries
+ if (name != mangled_cstr && ((mangled_cstr[0] == '_') || (name && ::strcmp(name, mangled_cstr) != 0)))
+ {
+ Mangled mangled (ConstString(mangled_cstr), true);
+ func_fullnames.Insert (mangled.GetMangledName(), die.GetOffset());
+ if (mangled.GetDemangledName())
+ func_fullnames.Insert (mangled.GetDemangledName(), die.GetOffset());
+ }
+ }
+ }
+ break;
+
+ case DW_TAG_inlined_subroutine:
+ if (has_address)
+ {
+ if (name)
+ func_basenames.Insert (ConstString(name), die.GetOffset());
+ if (mangled_cstr)
+ {
+ // Make sure our mangled name isn't the same string table entry
+ // as our name. If it starts with '_', then it is ok, else compare
+ // the string to make sure it isn't the same and we don't end up
+ // with duplicate entries
+ if (name != mangled_cstr && ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0)))
+ {
+ Mangled mangled (ConstString(mangled_cstr), true);
+ func_fullnames.Insert (mangled.GetMangledName(), die.GetOffset());
+ if (mangled.GetDemangledName())
+ func_fullnames.Insert (mangled.GetDemangledName(), die.GetOffset());
+ }
+ }
+ else
+ func_fullnames.Insert (ConstString(name), die.GetOffset());
+ }
+ break;
+
+ case DW_TAG_base_type:
+ case DW_TAG_class_type:
+ case DW_TAG_constant:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_string_type:
+ case DW_TAG_subroutine_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_typedef:
+ case DW_TAG_unspecified_type:
+ if (name && is_declaration == false)
+ {
+ types.Insert (ConstString(name), die.GetOffset());
+ }
+ break;
+
+ case DW_TAG_namespace:
+ if (name)
+ namespaces.Insert (ConstString(name), die.GetOffset());
+ break;
+
+ case DW_TAG_variable:
+ if (name && has_location && is_global_or_static_variable)
+ {
+ globals.Insert (ConstString(name), die.GetOffset());
+ // Be sure to include variables by their mangled and demangled
+ // names if they have any since a variable can have a basename
+ // "i", a mangled named "_ZN12_GLOBAL__N_11iE" and a demangled
+ // mangled name "(anonymous namespace)::i"...
+
+ // Make sure our mangled name isn't the same string table entry
+ // as our name. If it starts with '_', then it is ok, else compare
+ // the string to make sure it isn't the same and we don't end up
+ // with duplicate entries
+ if (mangled_cstr && name != mangled_cstr && ((mangled_cstr[0] == '_') || (::strcmp(name, mangled_cstr) != 0)))
+ {
+ Mangled mangled (ConstString(mangled_cstr), true);
+ globals.Insert (mangled.GetMangledName(), die.GetOffset());
+ if (mangled.GetDemangledName())
+ globals.Insert (mangled.GetDemangledName(), die.GetOffset());
+ }
+ }
+ break;
+
+ default:
+ continue;
+ }
+ }
+}
+
+bool
+DWARFCompileUnit::Supports_unnamed_objc_bitfields ()
+{
+ if (GetProducer() == eProducerClang)
+ {
+ const uint32_t major_version = GetProducerVersionMajor();
+ if (major_version > 425 || (major_version == 425 && GetProducerVersionUpdate() >= 13))
+ return true;
+ else
+ return false;
+ }
+ return true; // Assume all other compilers didn't have incorrect ObjC bitfield info
+}
+
+bool
+DWARFCompileUnit::Supports_DW_AT_APPLE_objc_complete_type ()
+{
+ if (GetProducer() == eProducerLLVMGCC)
+ return false;
+ return true;
+}
+
+bool
+DWARFCompileUnit::DW_AT_decl_file_attributes_are_invalid()
+{
+ // llvm-gcc makes completely invalid decl file attributes and won't ever
+ // be fixed, so we need to know to ignore these.
+ return GetProducer() == eProducerLLVMGCC;
+}
+
+void
+DWARFCompileUnit::ParseProducerInfo ()
+{
+ m_producer_version_major = UINT32_MAX;
+ m_producer_version_minor = UINT32_MAX;
+ m_producer_version_update = UINT32_MAX;
+
+ const DWARFDebugInfoEntry *die = GetCompileUnitDIEOnly();
+ if (die)
+ {
+
+ const char *producer_cstr = die->GetAttributeValueAsString(m_dwarf2Data, this, DW_AT_producer, NULL);
+ if (producer_cstr)
+ {
+ RegularExpression llvm_gcc_regex("^4\\.[012]\\.[01] \\(Based on Apple Inc\\. build [0-9]+\\) \\(LLVM build [\\.0-9]+\\)$");
+ if (llvm_gcc_regex.Execute (producer_cstr))
+ {
+ m_producer = eProducerLLVMGCC;
+ }
+ else if (strstr(producer_cstr, "clang"))
+ {
+ static RegularExpression g_clang_version_regex("clang-([0-9]+)\\.([0-9]+)\\.([0-9]+)");
+ RegularExpression::Match regex_match(3);
+ if (g_clang_version_regex.Execute (producer_cstr, &regex_match))
+ {
+ std::string str;
+ if (regex_match.GetMatchAtIndex (producer_cstr, 1, str))
+ m_producer_version_major = Args::StringToUInt32(str.c_str(), UINT32_MAX, 10);
+ if (regex_match.GetMatchAtIndex (producer_cstr, 2, str))
+ m_producer_version_minor = Args::StringToUInt32(str.c_str(), UINT32_MAX, 10);
+ if (regex_match.GetMatchAtIndex (producer_cstr, 3, str))
+ m_producer_version_update = Args::StringToUInt32(str.c_str(), UINT32_MAX, 10);
+ }
+ m_producer = eProducerClang;
+ }
+ else if (strstr(producer_cstr, "GNU"))
+ m_producer = eProducerGCC;
+ }
+ }
+ if (m_producer == eProducerInvalid)
+ m_producer = eProcucerOther;
+}
+
+DWARFCompileUnit::Producer
+DWARFCompileUnit::GetProducer ()
+{
+ if (m_producer == eProducerInvalid)
+ ParseProducerInfo ();
+ return m_producer;
+}
+
+
+uint32_t
+DWARFCompileUnit::GetProducerVersionMajor()
+{
+ if (m_producer_version_major == 0)
+ ParseProducerInfo ();
+ return m_producer_version_major;
+}
+
+uint32_t
+DWARFCompileUnit::GetProducerVersionMinor()
+{
+ if (m_producer_version_minor == 0)
+ ParseProducerInfo ();
+ return m_producer_version_minor;
+}
+
+uint32_t
+DWARFCompileUnit::GetProducerVersionUpdate()
+{
+ if (m_producer_version_update == 0)
+ ParseProducerInfo ();
+ return m_producer_version_update;
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
new file mode 100644
index 000000000000..9fee0a2d2236
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFCompileUnit.h
@@ -0,0 +1,210 @@
+//===-- DWARFCompileUnit.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFCompileUnit_h_
+#define SymbolFileDWARF_DWARFCompileUnit_h_
+
+#include "DWARFDebugInfoEntry.h"
+#include "SymbolFileDWARF.h"
+
+class NameToDIE;
+
+class DWARFCompileUnit
+{
+public:
+ enum Producer
+ {
+ eProducerInvalid = 0,
+ eProducerClang,
+ eProducerGCC,
+ eProducerLLVMGCC,
+ eProcucerOther
+ };
+
+ DWARFCompileUnit(SymbolFileDWARF* dwarf2Data);
+
+ bool Extract(const lldb_private::DataExtractor &debug_info, lldb::offset_t *offset_ptr);
+ dw_offset_t Extract(lldb::offset_t offset, const lldb_private::DataExtractor& debug_info_data, const DWARFAbbreviationDeclarationSet* abbrevs);
+ size_t ExtractDIEsIfNeeded (bool cu_die_only);
+ bool LookupAddress(
+ const dw_addr_t address,
+ DWARFDebugInfoEntry** function_die,
+ DWARFDebugInfoEntry** block_die);
+
+ size_t AppendDIEsWithTag (const dw_tag_t tag, DWARFDIECollection& matching_dies, uint32_t depth = UINT32_MAX) const;
+ void Clear();
+ bool Verify(lldb_private::Stream *s) const;
+ void Dump(lldb_private::Stream *s) const;
+ dw_offset_t GetOffset() const { return m_offset; }
+ uint32_t Size() const { return 11; /* Size in bytes of the compile unit header */ }
+ bool ContainsDIEOffset(dw_offset_t die_offset) const { return die_offset >= GetFirstDIEOffset() && die_offset < GetNextCompileUnitOffset(); }
+ dw_offset_t GetFirstDIEOffset() const { return m_offset + Size(); }
+ dw_offset_t GetNextCompileUnitOffset() const { return m_offset + m_length + 4; }
+ size_t GetDebugInfoSize() const { return m_length + 4 - Size(); /* Size in bytes of the .debug_info data associated with this compile unit. */ }
+ uint32_t GetLength() const { return m_length; }
+ uint16_t GetVersion() const { return m_version; }
+ const DWARFAbbreviationDeclarationSet* GetAbbreviations() const { return m_abbrevs; }
+ dw_offset_t GetAbbrevOffset() const;
+ uint8_t GetAddressByteSize() const { return m_addr_size; }
+ dw_addr_t GetBaseAddress() const { return m_base_addr; }
+ void ClearDIEs(bool keep_compile_unit_die);
+ void BuildAddressRangeTable (SymbolFileDWARF* dwarf2Data,
+ DWARFDebugAranges* debug_aranges,
+ bool clear_dies_if_already_not_parsed);
+
+ void
+ SetBaseAddress(dw_addr_t base_addr)
+ {
+ m_base_addr = base_addr;
+ }
+
+ const DWARFDebugInfoEntry*
+ GetCompileUnitDIEOnly()
+ {
+ ExtractDIEsIfNeeded (true);
+ if (m_die_array.empty())
+ return NULL;
+ return &m_die_array[0];
+ }
+
+ const DWARFDebugInfoEntry*
+ DIE()
+ {
+ ExtractDIEsIfNeeded (false);
+ if (m_die_array.empty())
+ return NULL;
+ return &m_die_array[0];
+ }
+
+ void
+ AddDIE (DWARFDebugInfoEntry& die)
+ {
+ // The average bytes per DIE entry has been seen to be
+ // around 14-20 so lets pre-reserve half of that since
+ // we are now stripping the NULL tags.
+
+ // Only reserve the memory if we are adding children of
+ // the main compile unit DIE. The compile unit DIE is always
+ // the first entry, so if our size is 1, then we are adding
+ // the first compile unit child DIE and should reserve
+ // the memory.
+ if (m_die_array.empty())
+ m_die_array.reserve(GetDebugInfoSize() / 24);
+ m_die_array.push_back(die);
+ }
+
+ bool
+ HasDIEsParsed () const
+ {
+ return m_die_array.size() > 1;
+ }
+
+ DWARFDebugInfoEntry*
+ GetDIEAtIndexUnchecked (uint32_t idx)
+ {
+ return &m_die_array[idx];
+ }
+
+ DWARFDebugInfoEntry*
+ GetDIEPtr (dw_offset_t die_offset);
+
+ const DWARFDebugInfoEntry*
+ GetDIEPtrContainingOffset (dw_offset_t die_offset);
+
+ static uint8_t
+ GetAddressByteSize(const DWARFCompileUnit* cu);
+
+ static uint8_t
+ GetDefaultAddressSize();
+
+ static void
+ SetDefaultAddressSize(uint8_t addr_size);
+
+ void *
+ GetUserData() const
+ {
+ return m_user_data;
+ }
+
+ void
+ SetUserData(void *d)
+ {
+ m_user_data = d;
+ }
+
+ bool
+ Supports_DW_AT_APPLE_objc_complete_type ();
+
+ bool
+ DW_AT_decl_file_attributes_are_invalid();
+
+ bool
+ Supports_unnamed_objc_bitfields ();
+
+// void
+// AddGlobalDIEByIndex (uint32_t die_idx);
+//
+// void
+// AddGlobal (const DWARFDebugInfoEntry* die);
+//
+ void
+ Index (const uint32_t cu_idx,
+ NameToDIE& func_basenames,
+ NameToDIE& func_fullnames,
+ NameToDIE& func_methods,
+ NameToDIE& func_selectors,
+ NameToDIE& objc_class_selectors,
+ NameToDIE& globals,
+ NameToDIE& types,
+ NameToDIE& namespaces);
+
+ const DWARFDebugAranges &
+ GetFunctionAranges ();
+
+ SymbolFileDWARF*
+ GetSymbolFileDWARF () const
+ {
+ return m_dwarf2Data;
+ }
+
+ Producer
+ GetProducer ();
+
+ uint32_t
+ GetProducerVersionMajor();
+
+ uint32_t
+ GetProducerVersionMinor();
+
+ uint32_t
+ GetProducerVersionUpdate();
+
+protected:
+ SymbolFileDWARF* m_dwarf2Data;
+ const DWARFAbbreviationDeclarationSet *m_abbrevs;
+ void * m_user_data;
+ DWARFDebugInfoEntry::collection m_die_array; // The compile unit debug information entry item
+ std::unique_ptr<DWARFDebugAranges> m_func_aranges_ap; // A table similar to the .debug_aranges table, but this one points to the exact DW_TAG_subprogram DIEs
+ dw_addr_t m_base_addr;
+ dw_offset_t m_offset;
+ uint32_t m_length;
+ uint16_t m_version;
+ uint8_t m_addr_size;
+ Producer m_producer;
+ uint32_t m_producer_version_major;
+ uint32_t m_producer_version_minor;
+ uint32_t m_producer_version_update;
+
+ void
+ ParseProducerInfo ();
+private:
+ DISALLOW_COPY_AND_ASSIGN (DWARFCompileUnit);
+};
+
+#endif // SymbolFileDWARF_DWARFCompileUnit_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp
new file mode 100644
index 000000000000..1beb75d33642
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.cpp
@@ -0,0 +1,62 @@
+//===-- DWARFDIECollection.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDIECollection.h"
+
+#include <algorithm>
+
+#include "lldb/Core/Stream.h"
+
+#include "DWARFDebugInfoEntry.h"
+
+using namespace lldb_private;
+using namespace std;
+
+bool
+DWARFDIECollection::Insert(const DWARFDebugInfoEntry *die)
+{
+ iterator end_pos = m_dies.end();
+ iterator insert_pos = upper_bound(m_dies.begin(), end_pos, die);
+ if (insert_pos != end_pos && (*insert_pos == die))
+ return false;
+ m_dies.insert(insert_pos, die);
+ return true;
+}
+
+void
+DWARFDIECollection::Append (const DWARFDebugInfoEntry *die)
+{
+ m_dies.push_back (die);
+}
+
+const DWARFDebugInfoEntry *
+DWARFDIECollection::GetDIEPtrAtIndex(uint32_t idx) const
+{
+ if (idx < m_dies.size())
+ return m_dies[idx];
+ return NULL;
+}
+
+
+size_t
+DWARFDIECollection::Size() const
+{
+ return m_dies.size();
+}
+
+void
+DWARFDIECollection::Dump(Stream *s, const char* title) const
+{
+ if (title && title[0] != '\0')
+ s->Printf( "%s\n", title);
+ const_iterator end_pos = m_dies.end();
+ const_iterator pos;
+ for (pos = m_dies.begin(); pos != end_pos; ++pos)
+ s->Printf( "0x%8.8x\n", (*pos)->GetOffset());
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h
new file mode 100644
index 000000000000..173d0a5604d0
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDIECollection.h
@@ -0,0 +1,51 @@
+//===-- DWARFDIECollection.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDIECollection_h_
+#define SymbolFileDWARF_DWARFDIECollection_h_
+
+#include "SymbolFileDWARF.h"
+#include <vector>
+
+class DWARFDIECollection
+{
+public:
+ DWARFDIECollection() :
+ m_dies()
+ {
+ }
+ ~DWARFDIECollection()
+ {
+ }
+
+ void
+ Append (const DWARFDebugInfoEntry *die);
+
+ void
+ Dump(lldb_private::Stream *s, const char* title) const;
+
+ const DWARFDebugInfoEntry*
+ GetDIEPtrAtIndex(uint32_t idx) const;
+
+ bool
+ Insert(const DWARFDebugInfoEntry *die);
+
+ size_t
+ Size() const;
+
+protected:
+ typedef std::vector<const DWARFDebugInfoEntry *> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ collection m_dies; // Ordered list of die offsets
+};
+
+
+#endif // SymbolFileDWARF_DWARFDIECollection_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp
new file mode 100644
index 000000000000..47657d5089b2
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.cpp
@@ -0,0 +1,202 @@
+//===-- DWARFDebugAbbrev.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugAbbrev.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Stream.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace std;
+
+//----------------------------------------------------------------------
+// DWARFAbbreviationDeclarationSet::Clear()
+//----------------------------------------------------------------------
+void
+DWARFAbbreviationDeclarationSet::Clear()
+{
+ m_idx_offset = 0;
+ m_decls.clear();
+}
+
+
+//----------------------------------------------------------------------
+// DWARFAbbreviationDeclarationSet::Extract()
+//----------------------------------------------------------------------
+bool
+DWARFAbbreviationDeclarationSet::Extract(const DataExtractor& data, lldb::offset_t *offset_ptr)
+{
+ const lldb::offset_t begin_offset = *offset_ptr;
+ m_offset = begin_offset;
+ Clear();
+ DWARFAbbreviationDeclaration abbrevDeclaration;
+ dw_uleb128_t prev_abbr_code = 0;
+ while (abbrevDeclaration.Extract(data, offset_ptr))
+ {
+ m_decls.push_back(abbrevDeclaration);
+ if (m_idx_offset == 0)
+ m_idx_offset = abbrevDeclaration.Code();
+ else
+ {
+ if (prev_abbr_code + 1 != abbrevDeclaration.Code())
+ m_idx_offset = UINT32_MAX; // Out of order indexes, we can't do O(1) lookups...
+ }
+ prev_abbr_code = abbrevDeclaration.Code();
+ }
+ return begin_offset != *offset_ptr;
+}
+
+
+//----------------------------------------------------------------------
+// DWARFAbbreviationDeclarationSet::Dump()
+//----------------------------------------------------------------------
+void
+DWARFAbbreviationDeclarationSet::Dump(Stream *s) const
+{
+ std::for_each (m_decls.begin(), m_decls.end(), bind2nd(std::mem_fun_ref(&DWARFAbbreviationDeclaration::Dump),s));
+}
+
+
+//----------------------------------------------------------------------
+// DWARFAbbreviationDeclarationSet::GetAbbreviationDeclaration()
+//----------------------------------------------------------------------
+const DWARFAbbreviationDeclaration*
+DWARFAbbreviationDeclarationSet::GetAbbreviationDeclaration(dw_uleb128_t abbrCode) const
+{
+ if (m_idx_offset == UINT32_MAX)
+ {
+ DWARFAbbreviationDeclarationCollConstIter pos;
+ DWARFAbbreviationDeclarationCollConstIter end = m_decls.end();
+ for (pos = m_decls.begin(); pos != end; ++pos)
+ {
+ if (pos->Code() == abbrCode)
+ return &(*pos);
+ }
+ }
+ else
+ {
+ uint32_t idx = abbrCode - m_idx_offset;
+ if (idx < m_decls.size())
+ return &m_decls[idx];
+ }
+ return NULL;
+}
+
+//----------------------------------------------------------------------
+// DWARFAbbreviationDeclarationSet::AppendAbbrevDeclSequential()
+//
+// Append an abbreviation declaration with a sequential code for O(n)
+// lookups. Handy when creating an DWARFAbbreviationDeclarationSet.
+//----------------------------------------------------------------------
+dw_uleb128_t
+DWARFAbbreviationDeclarationSet::AppendAbbrevDeclSequential(const DWARFAbbreviationDeclaration& abbrevDecl)
+{
+ // Get the next abbreviation code based on our current array size
+ dw_uleb128_t code = m_decls.size()+1;
+
+ // Push the new declaration on the back
+ m_decls.push_back(abbrevDecl);
+
+ // Update the code for this new declaration
+ m_decls.back().SetCode(code);
+
+ return code; // return the new abbreviation code!
+}
+
+
+//----------------------------------------------------------------------
+// Encode
+//
+// Encode the abbreviation table onto the end of the buffer provided
+// into a byte representation as would be found in a ".debug_abbrev"
+// debug information section.
+//----------------------------------------------------------------------
+//void
+//DWARFAbbreviationDeclarationSet::Encode(BinaryStreamBuf& debug_abbrev_buf) const
+//{
+// DWARFAbbreviationDeclarationCollConstIter pos;
+// DWARFAbbreviationDeclarationCollConstIter end = m_decls.end();
+// for (pos = m_decls.begin(); pos != end; ++pos)
+// pos->Append(debug_abbrev_buf);
+// debug_abbrev_buf.Append8(0);
+//}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugAbbrev constructor
+//----------------------------------------------------------------------
+DWARFDebugAbbrev::DWARFDebugAbbrev() :
+ m_abbrevCollMap(),
+ m_prev_abbr_offset_pos(m_abbrevCollMap.end())
+{
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugAbbrev::Parse()
+//----------------------------------------------------------------------
+void
+DWARFDebugAbbrev::Parse(const DataExtractor& data)
+{
+ lldb::offset_t offset = 0;
+
+ while (data.ValidOffset(offset))
+ {
+ uint32_t initial_cu_offset = offset;
+ DWARFAbbreviationDeclarationSet abbrevDeclSet;
+
+ if (abbrevDeclSet.Extract(data, &offset))
+ m_abbrevCollMap[initial_cu_offset] = abbrevDeclSet;
+ else
+ break;
+ }
+ m_prev_abbr_offset_pos = m_abbrevCollMap.end();
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugAbbrev::Dump()
+//----------------------------------------------------------------------
+void
+DWARFDebugAbbrev::Dump(Stream *s) const
+{
+ if (m_abbrevCollMap.empty())
+ {
+ s->PutCString("< EMPTY >\n");
+ return;
+ }
+
+ DWARFAbbreviationDeclarationCollMapConstIter pos;
+ for (pos = m_abbrevCollMap.begin(); pos != m_abbrevCollMap.end(); ++pos)
+ {
+ s->Printf("Abbrev table for offset: 0x%8.8x\n", pos->first);
+ pos->second.Dump(s);
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugAbbrev::GetAbbreviationDeclarationSet()
+//----------------------------------------------------------------------
+const DWARFAbbreviationDeclarationSet*
+DWARFDebugAbbrev::GetAbbreviationDeclarationSet(dw_offset_t cu_abbr_offset) const
+{
+ DWARFAbbreviationDeclarationCollMapConstIter end = m_abbrevCollMap.end();
+ DWARFAbbreviationDeclarationCollMapConstIter pos;
+ if (m_prev_abbr_offset_pos != end && m_prev_abbr_offset_pos->first == cu_abbr_offset)
+ return &(m_prev_abbr_offset_pos->second);
+ else
+ {
+ pos = m_abbrevCollMap.find(cu_abbr_offset);
+ m_prev_abbr_offset_pos = pos;
+ }
+
+ if (pos != m_abbrevCollMap.end())
+ return &(pos->second);
+ return NULL;
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h
new file mode 100644
index 000000000000..eba439928a2c
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAbbrev.h
@@ -0,0 +1,74 @@
+//===-- DWARFDebugAbbrev.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugAbbrev_h_
+#define SymbolFileDWARF_DWARFDebugAbbrev_h_
+
+#include <list>
+#include <map>
+
+#include "lldb/lldb-private.h"
+
+#include "DWARFDefines.h"
+#include "DWARFAbbreviationDeclaration.h"
+
+typedef std::vector<DWARFAbbreviationDeclaration> DWARFAbbreviationDeclarationColl;
+typedef DWARFAbbreviationDeclarationColl::iterator DWARFAbbreviationDeclarationCollIter;
+typedef DWARFAbbreviationDeclarationColl::const_iterator DWARFAbbreviationDeclarationCollConstIter;
+
+
+class DWARFAbbreviationDeclarationSet
+{
+public:
+ DWARFAbbreviationDeclarationSet() :
+ m_offset(DW_INVALID_OFFSET),
+ m_idx_offset(0),
+ m_decls()
+ {
+ }
+
+ DWARFAbbreviationDeclarationSet(dw_offset_t offset, uint32_t idx_offset) :
+ m_offset(offset),
+ m_idx_offset(idx_offset),
+ m_decls()
+ {
+ }
+
+ void Clear();
+ dw_offset_t GetOffset() const { return m_offset; }
+ void Dump(lldb_private::Stream *s) const;
+ bool Extract(const lldb_private::DataExtractor& data, lldb::offset_t *offset_ptr);
+ //void Encode(BinaryStreamBuf& debug_abbrev_buf) const;
+ dw_uleb128_t AppendAbbrevDeclSequential(const DWARFAbbreviationDeclaration& abbrevDecl);
+
+ const DWARFAbbreviationDeclaration* GetAbbreviationDeclaration(dw_uleb128_t abbrCode) const;
+private:
+ dw_offset_t m_offset;
+ uint32_t m_idx_offset;
+ std::vector<DWARFAbbreviationDeclaration> m_decls;
+};
+
+typedef std::map<dw_offset_t, DWARFAbbreviationDeclarationSet> DWARFAbbreviationDeclarationCollMap;
+typedef DWARFAbbreviationDeclarationCollMap::iterator DWARFAbbreviationDeclarationCollMapIter;
+typedef DWARFAbbreviationDeclarationCollMap::const_iterator DWARFAbbreviationDeclarationCollMapConstIter;
+
+
+class DWARFDebugAbbrev
+{
+public:
+ DWARFDebugAbbrev();
+ const DWARFAbbreviationDeclarationSet* GetAbbreviationDeclarationSet(dw_offset_t cu_abbr_offset) const;
+ void Dump(lldb_private::Stream *s) const;
+ void Parse(const lldb_private::DataExtractor& data);
+protected:
+ DWARFAbbreviationDeclarationCollMap m_abbrevCollMap;
+ mutable DWARFAbbreviationDeclarationCollMapConstIter m_prev_abbr_offset_pos;
+};
+
+#endif // SymbolFileDWARF_DWARFDebugAbbrev_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp
new file mode 100644
index 000000000000..b1eb27299efb
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.cpp
@@ -0,0 +1,274 @@
+//===-- DWARFDebugArangeSet.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugArangeSet.h"
+
+#include <assert.h>
+#include "lldb/Core/Stream.h"
+#include "SymbolFileDWARF.h"
+
+using namespace lldb_private;
+
+DWARFDebugArangeSet::DWARFDebugArangeSet() :
+ m_offset(DW_INVALID_OFFSET),
+ m_header(),
+ m_arange_descriptors()
+{
+ m_header.length = 0;
+ m_header.version = 0;
+ m_header.cu_offset = 0;
+ m_header.addr_size = 0;
+ m_header.seg_size = 0;
+}
+
+void
+DWARFDebugArangeSet::Clear()
+{
+ m_offset = DW_INVALID_OFFSET;
+ m_header.length = 0;
+ m_header.version = 0;
+ m_header.cu_offset = 0;
+ m_header.addr_size = 0;
+ m_header.seg_size = 0;
+ m_arange_descriptors.clear();
+}
+
+void
+DWARFDebugArangeSet::SetHeader
+(
+ uint16_t version,
+ uint32_t cu_offset,
+ uint8_t addr_size,
+ uint8_t seg_size
+)
+{
+ m_header.version = version;
+ m_header.cu_offset = cu_offset;
+ m_header.addr_size = addr_size;
+ m_header.seg_size = seg_size;
+}
+
+void
+DWARFDebugArangeSet::Compact()
+{
+ if (m_arange_descriptors.empty())
+ return;
+
+ // Iterate through all arange descriptors and combine any ranges that
+ // overlap or have matching boundaries. The m_arange_descriptors are assumed
+ // to be in ascending order after being built by adding descriptors
+ // using the AddDescriptor method.
+ uint32_t i = 0;
+ while (i + 1 < m_arange_descriptors.size())
+ {
+ if (m_arange_descriptors[i].end_address() >= m_arange_descriptors[i+1].address)
+ {
+ // The current range ends at or exceeds the start of the next address range.
+ // Compute the max end address between the two and use that to make the new
+ // length.
+ const dw_addr_t max_end_addr = std::max(m_arange_descriptors[i].end_address(), m_arange_descriptors[i+1].end_address());
+ m_arange_descriptors[i].length = max_end_addr - m_arange_descriptors[i].address;
+ // Now remove the next entry as it was just combined with the previous one.
+ m_arange_descriptors.erase(m_arange_descriptors.begin()+i+1);
+ }
+ else
+ {
+ // Discontiguous address range, just proceed to the next one.
+ ++i;
+ }
+ }
+}
+//----------------------------------------------------------------------
+// Compare function DWARFDebugArangeSet::Descriptor structures
+//----------------------------------------------------------------------
+static bool DescriptorLessThan (const DWARFDebugArangeSet::Descriptor& range1, const DWARFDebugArangeSet::Descriptor& range2)
+{
+ return range1.address < range2.address;
+}
+
+//----------------------------------------------------------------------
+// Add a range descriptor and keep things sorted so we can easily
+// compact the ranges before being saved or used.
+//----------------------------------------------------------------------
+void
+DWARFDebugArangeSet::AddDescriptor(const DWARFDebugArangeSet::Descriptor& range)
+{
+ if (m_arange_descriptors.empty())
+ {
+ m_arange_descriptors.push_back(range);
+ return;
+ }
+
+ DescriptorIter end = m_arange_descriptors.end();
+ DescriptorIter pos = lower_bound(m_arange_descriptors.begin(), end, range, DescriptorLessThan);
+ const dw_addr_t range_end_addr = range.end_address();
+ if (pos != end)
+ {
+ const dw_addr_t found_end_addr = pos->end_address();
+ if (range.address < pos->address)
+ {
+ if (range_end_addr < pos->address)
+ {
+ // Non-contiguous entries, add this one before the found entry
+ m_arange_descriptors.insert(pos, range);
+ }
+ else if (range_end_addr == pos->address)
+ {
+ // The top end of 'range' is the lower end of the entry
+ // pointed to by 'pos'. We can combine range with the
+ // entry we found by setting the starting address and
+ // increasing the length since they don't overlap.
+ pos->address = range.address;
+ pos->length += range.length;
+ }
+ else
+ {
+ // We can combine these two and make sure the largest end
+ // address is used to make end address.
+ pos->address = range.address;
+ pos->length = std::max(found_end_addr, range_end_addr) - pos->address;
+ }
+ }
+ else if (range.address == pos->address)
+ {
+ pos->length = std::max(pos->length, range.length);
+ }
+ }
+ else
+ {
+ // NOTE: 'pos' points to entry past the end which is ok for insert,
+ // don't use otherwise!!!
+ const dw_addr_t max_addr = m_arange_descriptors.back().end_address();
+ if (max_addr < range.address)
+ {
+ // Non-contiguous entries, add this one before the found entry
+ m_arange_descriptors.insert(pos, range);
+ }
+ else if (max_addr == range.address)
+ {
+ m_arange_descriptors.back().length += range.length;
+ }
+ else
+ {
+ m_arange_descriptors.back().length = std::max(max_addr, range_end_addr) - m_arange_descriptors.back().address;
+ }
+ }
+}
+
+bool
+DWARFDebugArangeSet::Extract(const DataExtractor &data, lldb::offset_t *offset_ptr)
+{
+ if (data.ValidOffset(*offset_ptr))
+ {
+ m_arange_descriptors.clear();
+ m_offset = *offset_ptr;
+
+ // 7.20 Address Range Table
+ //
+ // Each set of entries in the table of address ranges contained in
+ // the .debug_aranges section begins with a header consisting of: a
+ // 4-byte length containing the length of the set of entries for this
+ // compilation unit, not including the length field itself; a 2-byte
+ // version identifier containing the value 2 for DWARF Version 2; a
+ // 4-byte offset into the.debug_infosection; a 1-byte unsigned integer
+ // containing the size in bytes of an address (or the offset portion of
+ // an address for segmented addressing) on the target system; and a
+ // 1-byte unsigned integer containing the size in bytes of a segment
+ // descriptor on the target system. This header is followed by a series
+ // of tuples. Each tuple consists of an address and a length, each in
+ // the size appropriate for an address on the target architecture.
+ m_header.length = data.GetU32(offset_ptr);
+ m_header.version = data.GetU16(offset_ptr);
+ m_header.cu_offset = data.GetU32(offset_ptr);
+ m_header.addr_size = data.GetU8(offset_ptr);
+ m_header.seg_size = data.GetU8(offset_ptr);
+
+
+ // The first tuple following the header in each set begins at an offset
+ // that is a multiple of the size of a single tuple (that is, twice the
+ // size of an address). The header is padded, if necessary, to the
+ // appropriate boundary.
+ const uint32_t header_size = *offset_ptr - m_offset;
+ const uint32_t tuple_size = m_header.addr_size << 1;
+ uint32_t first_tuple_offset = 0;
+ while (first_tuple_offset < header_size)
+ first_tuple_offset += tuple_size;
+
+ *offset_ptr = m_offset + first_tuple_offset;
+
+ Descriptor arangeDescriptor;
+
+ assert(sizeof(arangeDescriptor.address) == sizeof(arangeDescriptor.length));
+ assert(sizeof(arangeDescriptor.address) >= m_header.addr_size);
+
+ while (data.ValidOffset(*offset_ptr))
+ {
+ arangeDescriptor.address = data.GetMaxU64(offset_ptr, m_header.addr_size);
+ arangeDescriptor.length = data.GetMaxU64(offset_ptr, m_header.addr_size);
+
+ // Each set of tuples is terminated by a 0 for the address and 0
+ // for the length.
+ if (arangeDescriptor.address || arangeDescriptor.length)
+ m_arange_descriptors.push_back(arangeDescriptor);
+ else
+ break; // We are done if we get a zero address and length
+ }
+
+ return !m_arange_descriptors.empty();
+ }
+ return false;
+}
+
+
+dw_offset_t
+DWARFDebugArangeSet::GetOffsetOfNextEntry() const
+{
+ return m_offset + m_header.length + 4;
+}
+
+
+void
+DWARFDebugArangeSet::Dump(Stream *s) const
+{
+ s->Printf("Address Range Header: length = 0x%8.8x, version = 0x%4.4x, cu_offset = 0x%8.8x, addr_size = 0x%2.2x, seg_size = 0x%2.2x\n",
+ m_header.length ,m_header.version, m_header.cu_offset, m_header.addr_size, m_header.seg_size);
+
+ const uint32_t hex_width = m_header.addr_size * 2;
+ DescriptorConstIter pos;
+ DescriptorConstIter end = m_arange_descriptors.end();
+ for (pos = m_arange_descriptors.begin(); pos != end; ++pos)
+ s->Printf("[0x%*.*" PRIx64 " - 0x%*.*" PRIx64 ")\n",
+ hex_width, hex_width, pos->address,
+ hex_width, hex_width, pos->end_address());
+}
+
+
+class DescriptorContainsAddress
+{
+public:
+ DescriptorContainsAddress (dw_addr_t address) : m_address(address) {}
+ bool operator() (const DWARFDebugArangeSet::Descriptor& desc) const
+ {
+ return (m_address >= desc.address) && (m_address < (desc.address + desc.length));
+ }
+ private:
+ const dw_addr_t m_address;
+};
+
+dw_offset_t
+DWARFDebugArangeSet::FindAddress(dw_addr_t address) const
+{
+ DescriptorConstIter end = m_arange_descriptors.end();
+ DescriptorConstIter pos = std::find_if( m_arange_descriptors.begin(), end, // Range
+ DescriptorContainsAddress(address));// Predicate
+ if (pos != end)
+ return m_header.cu_offset;
+
+ return DW_INVALID_OFFSET;
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h
new file mode 100644
index 000000000000..19ec8d042e72
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugArangeSet.h
@@ -0,0 +1,76 @@
+//===-- DWARFDebugArangeSet.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugArangeSet_h_
+#define SymbolFileDWARF_DWARFDebugArangeSet_h_
+
+#include "SymbolFileDWARF.h"
+#include <vector>
+
+class SymbolFileDWARF;
+
+class DWARFDebugArangeSet
+{
+public:
+ struct Header
+ {
+ uint32_t length; // The total length of the entries for that set, not including the length field itself.
+ uint16_t version; // The DWARF version number
+ uint32_t cu_offset; // The offset from the beginning of the .debug_info section of the compilation unit entry referenced by the table.
+ uint8_t addr_size; // The size in bytes of an address on the target architecture. For segmented addressing, this is the size of the offset portion of the address
+ uint8_t seg_size; // The size in bytes of a segment descriptor on the target architecture. If the target system uses a flat address space, this value is 0.
+ };
+
+ struct Descriptor
+ {
+ dw_addr_t address;
+ dw_addr_t length;
+ dw_addr_t end_address() const { return address + length; }
+ };
+
+
+ DWARFDebugArangeSet();
+ void Clear();
+ void SetOffset(uint32_t offset) { m_offset = offset; }
+ void SetHeader(uint16_t version, uint32_t cu_offset, uint8_t addr_size, uint8_t seg_size);
+ void AddDescriptor(const DWARFDebugArangeSet::Descriptor& range);
+ void Compact();
+ bool Extract(const lldb_private::DataExtractor &data, lldb::offset_t *offset_ptr);
+ void Dump(lldb_private::Stream *s) const;
+ dw_offset_t GetCompileUnitDIEOffset() const { return m_header.cu_offset; }
+ dw_offset_t GetOffsetOfNextEntry() const;
+ dw_offset_t FindAddress(dw_addr_t address) const;
+ size_t NumDescriptors() const { return m_arange_descriptors.size(); }
+ const Header& GetHeader() const { return m_header; }
+ const Descriptor* GetDescriptor(uint32_t i) const
+ {
+ if (i < m_arange_descriptors.size())
+ return &m_arange_descriptors[i];
+ return NULL;
+ }
+
+ const Descriptor &
+ GetDescriptorRef (uint32_t i) const
+ {
+ return m_arange_descriptors[i];
+ }
+
+
+protected:
+ typedef std::vector<Descriptor> DescriptorColl;
+ typedef DescriptorColl::iterator DescriptorIter;
+ typedef DescriptorColl::const_iterator DescriptorConstIter;
+
+
+ uint32_t m_offset;
+ Header m_header;
+ DescriptorColl m_arange_descriptors;
+};
+
+#endif // SymbolFileDWARF_DWARFDebugArangeSet_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
new file mode 100644
index 000000000000..3b004c4b3890
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.cpp
@@ -0,0 +1,177 @@
+//===-- DWARFDebugAranges.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugAranges.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#include <algorithm>
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+
+#include "LogChannelDWARF.h"
+#include "SymbolFileDWARF.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFCompileUnit.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+DWARFDebugAranges::DWARFDebugAranges() :
+ m_aranges()
+{
+}
+
+//----------------------------------------------------------------------
+// CountArangeDescriptors
+//----------------------------------------------------------------------
+class CountArangeDescriptors
+{
+public:
+ CountArangeDescriptors (uint32_t& count_ref) : count(count_ref)
+ {
+// printf("constructor CountArangeDescriptors()\n");
+ }
+ void operator() (const DWARFDebugArangeSet& set)
+ {
+ count += set.NumDescriptors();
+ }
+ uint32_t& count;
+};
+
+
+//----------------------------------------------------------------------
+// Extract
+//----------------------------------------------------------------------
+bool
+DWARFDebugAranges::Extract(const DataExtractor &debug_aranges_data)
+{
+ if (debug_aranges_data.ValidOffset(0))
+ {
+ lldb::offset_t offset = 0;
+
+ DWARFDebugArangeSet set;
+ Range range;
+ while (set.Extract(debug_aranges_data, &offset))
+ {
+ const uint32_t num_descriptors = set.NumDescriptors();
+ if (num_descriptors > 0)
+ {
+ const dw_offset_t cu_offset = set.GetCompileUnitDIEOffset();
+
+ for (uint32_t i=0; i<num_descriptors; ++i)
+ {
+ const DWARFDebugArangeSet::Descriptor &descriptor = set.GetDescriptorRef(i);
+ m_aranges.Append(RangeToDIE::Entry (descriptor.address, descriptor.length, cu_offset));
+ }
+ }
+ set.Clear();
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Generate
+//----------------------------------------------------------------------
+bool
+DWARFDebugAranges::Generate(SymbolFileDWARF* dwarf2Data)
+{
+ Clear();
+ DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
+ if (debug_info)
+ {
+ const bool clear_dies_if_already_not_parsed = true;
+ uint32_t cu_idx = 0;
+ const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
+ for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
+ {
+ DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
+ if (cu)
+ cu->BuildAddressRangeTable(dwarf2Data, this, clear_dies_if_already_not_parsed);
+ }
+ }
+ return !IsEmpty();
+}
+
+
+void
+DWARFDebugAranges::Dump (Log *log) const
+{
+ if (log == NULL)
+ return;
+
+ const size_t num_entries = m_aranges.GetSize();
+ for (size_t i=0; i<num_entries; ++i)
+ {
+ const RangeToDIE::Entry *entry = m_aranges.GetEntryAtIndex(i);
+ if (entry)
+ log->Printf ("0x%8.8x: [0x%" PRIx64 " - 0x%" PRIx64 ")",
+ entry->data,
+ entry->GetRangeBase(),
+ entry->GetRangeEnd());
+ }
+}
+
+void
+DWARFDebugAranges::AppendRange (dw_offset_t offset, dw_addr_t low_pc, dw_addr_t high_pc)
+{
+ if (high_pc > low_pc)
+ m_aranges.Append(RangeToDIE::Entry (low_pc, high_pc - low_pc, offset));
+}
+
+void
+DWARFDebugAranges::Sort (bool minimize)
+{
+ Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p",
+ __PRETTY_FUNCTION__, this);
+
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES));
+ size_t orig_arange_size = 0;
+ if (log)
+ {
+ orig_arange_size = m_aranges.GetSize();
+ log->Printf ("DWARFDebugAranges::Sort(minimize = %u) with %" PRIu64 " entries", minimize, (uint64_t)orig_arange_size);
+ }
+
+ m_aranges.Sort();
+ m_aranges.CombineConsecutiveEntriesWithEqualData();
+
+ if (log)
+ {
+ if (minimize)
+ {
+ const size_t new_arange_size = m_aranges.GetSize();
+ const size_t delta = orig_arange_size - new_arange_size;
+ log->Printf ("DWARFDebugAranges::Sort() %" PRIu64 " entries after minimizing (%" PRIu64 " entries combined for %" PRIu64 " bytes saved)",
+ (uint64_t)new_arange_size,
+ (uint64_t)delta,
+ (uint64_t)delta * sizeof(Range));
+ }
+ Dump (log);
+ }
+}
+
+//----------------------------------------------------------------------
+// FindAddress
+//----------------------------------------------------------------------
+dw_offset_t
+DWARFDebugAranges::FindAddress(dw_addr_t address) const
+{
+ const RangeToDIE::Entry *entry = m_aranges.FindEntryThatContains(address);
+ if (entry)
+ return entry->data;
+ return DW_INVALID_OFFSET;
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h
new file mode 100644
index 000000000000..88db929226ab
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugAranges.h
@@ -0,0 +1,94 @@
+//===-- DWARFDebugAranges.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugAranges_h_
+#define SymbolFileDWARF_DWARFDebugAranges_h_
+
+#include "DWARFDebugArangeSet.h"
+#include <list>
+
+#include "lldb/Core/RangeMap.h"
+
+class SymbolFileDWARF;
+
+class DWARFDebugAranges
+{
+protected:
+ typedef lldb_private::RangeDataArray<dw_addr_t, uint32_t, dw_offset_t, 1> RangeToDIE;
+
+public:
+ typedef RangeToDIE::Entry Range;
+ typedef std::vector<RangeToDIE::Entry> RangeColl;
+
+ DWARFDebugAranges();
+
+ void
+ Clear()
+ {
+ m_aranges.Clear();
+ }
+
+ bool
+ Extract(const lldb_private::DataExtractor &debug_aranges_data);
+
+ bool
+ Generate(SymbolFileDWARF* dwarf2Data);
+
+ // Use append range multiple times and then call sort
+ void
+ AppendRange (dw_offset_t cu_offset,
+ dw_addr_t low_pc,
+ dw_addr_t high_pc);
+
+ void
+ Sort (bool minimize);
+
+ const Range*
+ RangeAtIndex(uint32_t idx) const
+ {
+ return m_aranges.GetEntryAtIndex (idx);
+ }
+
+ void
+ Dump (lldb_private::Log *log) const;
+
+ dw_offset_t
+ FindAddress(dw_addr_t address) const;
+
+ bool
+ IsEmpty() const
+ {
+ return m_aranges.IsEmpty();
+ }
+ size_t
+ GetNumRanges() const
+ {
+ return m_aranges.GetSize();
+ }
+
+ dw_offset_t
+ OffsetAtIndex(uint32_t idx) const
+ {
+ const Range *range = m_aranges.GetEntryAtIndex (idx);
+ if (range)
+ return range->data;
+ return DW_INVALID_OFFSET;
+ }
+
+ static void
+ Dump(SymbolFileDWARF* dwarf2Data, lldb_private::Stream *s);
+
+protected:
+
+
+ RangeToDIE m_aranges;
+};
+
+
+#endif // SymbolFileDWARF_DWARFDebugAranges_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
new file mode 100644
index 000000000000..4c76eed8166f
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.cpp
@@ -0,0 +1,797 @@
+//===-- DWARFDebugInfo.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileDWARF.h"
+
+#include <algorithm>
+#include <set>
+
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfoEntry.h"
+#include "DWARFFormValue.h"
+#include "LogChannelDWARF.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace std;
+
+//----------------------------------------------------------------------
+// Constructor
+//----------------------------------------------------------------------
+DWARFDebugInfo::DWARFDebugInfo() :
+ m_dwarf2Data(NULL),
+ m_compile_units(),
+ m_cu_aranges_ap ()
+{
+}
+
+//----------------------------------------------------------------------
+// SetDwarfData
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::SetDwarfData(SymbolFileDWARF* dwarf2Data)
+{
+ m_dwarf2Data = dwarf2Data;
+ m_compile_units.clear();
+}
+
+
+DWARFDebugAranges &
+DWARFDebugInfo::GetCompileUnitAranges ()
+{
+ if (m_cu_aranges_ap.get() == NULL && m_dwarf2Data)
+ {
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_ARANGES));
+
+ m_cu_aranges_ap.reset (new DWARFDebugAranges());
+ const DataExtractor &debug_aranges_data = m_dwarf2Data->get_debug_aranges_data();
+ if (debug_aranges_data.GetByteSize() > 0)
+ {
+ if (log)
+ log->Printf ("DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" from .debug_aranges",
+ m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str());
+ m_cu_aranges_ap->Extract (debug_aranges_data);
+
+ }
+ else
+ {
+ if (log)
+ log->Printf ("DWARFDebugInfo::GetCompileUnitAranges() for \"%s\" by parsing",
+ m_dwarf2Data->GetObjectFile()->GetFileSpec().GetPath().c_str());
+ const size_t num_compile_units = GetNumCompileUnits();
+ const bool clear_dies_if_already_not_parsed = true;
+ for (size_t idx = 0; idx < num_compile_units; ++idx)
+ {
+ DWARFCompileUnit* cu = GetCompileUnitAtIndex(idx);
+ if (cu)
+ cu->BuildAddressRangeTable (m_dwarf2Data, m_cu_aranges_ap.get(), clear_dies_if_already_not_parsed);
+ }
+ }
+
+ const bool minimize = true;
+ m_cu_aranges_ap->Sort (minimize);
+ }
+ return *m_cu_aranges_ap.get();
+}
+
+
+//----------------------------------------------------------------------
+// LookupAddress
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfo::LookupAddress
+(
+ const dw_addr_t address,
+ const dw_offset_t hint_die_offset,
+ DWARFCompileUnitSP& cu_sp,
+ DWARFDebugInfoEntry** function_die,
+ DWARFDebugInfoEntry** block_die
+)
+{
+
+ if (hint_die_offset != DW_INVALID_OFFSET)
+ cu_sp = GetCompileUnit(hint_die_offset);
+ else
+ {
+ DWARFDebugAranges &cu_aranges = GetCompileUnitAranges ();
+ const dw_offset_t cu_offset = cu_aranges.FindAddress (address);
+ cu_sp = GetCompileUnit(cu_offset);
+ }
+
+ if (cu_sp.get())
+ {
+ if (cu_sp->LookupAddress(address, function_die, block_die))
+ return true;
+ cu_sp.reset();
+ }
+ else
+ {
+ // The hint_die_offset may have been a pointer to the actual item that
+ // we are looking for
+ DWARFDebugInfoEntry* die_ptr = GetDIEPtr(hint_die_offset, &cu_sp);
+ if (die_ptr)
+ {
+ if (cu_sp.get())
+ {
+ if (function_die || block_die)
+ return die_ptr->LookupAddress(address, m_dwarf2Data, cu_sp.get(), function_die, block_die);
+
+ // We only wanted the compile unit that contained this address
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+
+void
+DWARFDebugInfo::ParseCompileUnitHeadersIfNeeded()
+{
+ if (m_compile_units.empty())
+ {
+ if (m_dwarf2Data != NULL)
+ {
+ lldb::offset_t offset = 0;
+ const DataExtractor &debug_info_data = m_dwarf2Data->get_debug_info_data();
+ while (debug_info_data.ValidOffset(offset))
+ {
+ DWARFCompileUnitSP cu_sp(new DWARFCompileUnit(m_dwarf2Data));
+ // Out of memory?
+ if (cu_sp.get() == NULL)
+ break;
+
+ if (cu_sp->Extract(debug_info_data, &offset) == false)
+ break;
+
+ m_compile_units.push_back(cu_sp);
+
+ offset = cu_sp->GetNextCompileUnitOffset();
+ }
+ }
+ }
+}
+
+size_t
+DWARFDebugInfo::GetNumCompileUnits()
+{
+ ParseCompileUnitHeadersIfNeeded();
+ return m_compile_units.size();
+}
+
+DWARFCompileUnit*
+DWARFDebugInfo::GetCompileUnitAtIndex(uint32_t idx)
+{
+ DWARFCompileUnit* cu = NULL;
+ if (idx < GetNumCompileUnits())
+ cu = m_compile_units[idx].get();
+ return cu;
+}
+
+bool
+DWARFDebugInfo::ContainsCompileUnit (const DWARFCompileUnit *cu) const
+{
+ // Not a verify efficient function, but it is handy for use in assertions
+ // to make sure that a compile unit comes from a debug information file.
+ CompileUnitColl::const_iterator end_pos = m_compile_units.end();
+ CompileUnitColl::const_iterator pos;
+
+ for (pos = m_compile_units.begin(); pos != end_pos; ++pos)
+ {
+ if (pos->get() == cu)
+ return true;
+ }
+ return false;
+}
+
+
+static bool CompileUnitOffsetLessThan (const DWARFCompileUnitSP& a, const DWARFCompileUnitSP& b)
+{
+ return a->GetOffset() < b->GetOffset();
+}
+
+
+static int
+CompareDWARFCompileUnitSPOffset (const void *key, const void *arrmem)
+{
+ const dw_offset_t key_cu_offset = *(dw_offset_t*) key;
+ const dw_offset_t cu_offset = ((DWARFCompileUnitSP *)arrmem)->get()->GetOffset();
+ if (key_cu_offset < cu_offset)
+ return -1;
+ if (key_cu_offset > cu_offset)
+ return 1;
+ return 0;
+}
+
+DWARFCompileUnitSP
+DWARFDebugInfo::GetCompileUnit(dw_offset_t cu_offset, uint32_t* idx_ptr)
+{
+ DWARFCompileUnitSP cu_sp;
+ uint32_t cu_idx = DW_INVALID_INDEX;
+ if (cu_offset != DW_INVALID_OFFSET)
+ {
+ ParseCompileUnitHeadersIfNeeded();
+
+ DWARFCompileUnitSP* match = (DWARFCompileUnitSP*)bsearch(&cu_offset, &m_compile_units[0], m_compile_units.size(), sizeof(DWARFCompileUnitSP), CompareDWARFCompileUnitSPOffset);
+ if (match)
+ {
+ cu_sp = *match;
+ cu_idx = match - &m_compile_units[0];
+ }
+ }
+ if (idx_ptr)
+ *idx_ptr = cu_idx;
+ return cu_sp;
+}
+
+DWARFCompileUnitSP
+DWARFDebugInfo::GetCompileUnitContainingDIE(dw_offset_t die_offset)
+{
+ DWARFCompileUnitSP cu_sp;
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ ParseCompileUnitHeadersIfNeeded();
+
+ CompileUnitColl::const_iterator end_pos = m_compile_units.end();
+ CompileUnitColl::const_iterator pos;
+
+ for (pos = m_compile_units.begin(); pos != end_pos; ++pos)
+ {
+ dw_offset_t cu_start_offset = (*pos)->GetOffset();
+ dw_offset_t cu_end_offset = (*pos)->GetNextCompileUnitOffset();
+ if (cu_start_offset <= die_offset && die_offset < cu_end_offset)
+ {
+ cu_sp = *pos;
+ break;
+ }
+ }
+ }
+ return cu_sp;
+}
+
+//----------------------------------------------------------------------
+// Compare function DWARFDebugAranges::Range structures
+//----------------------------------------------------------------------
+static bool CompareDIEOffset (const DWARFDebugInfoEntry& die1, const DWARFDebugInfoEntry& die2)
+{
+ return die1.GetOffset() < die2.GetOffset();
+}
+
+
+//----------------------------------------------------------------------
+// GetDIE()
+//
+// Get the DIE (Debug Information Entry) with the specified offset.
+//----------------------------------------------------------------------
+DWARFDebugInfoEntry*
+DWARFDebugInfo::GetDIEPtr(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr)
+{
+ DWARFCompileUnitSP cu_sp(GetCompileUnitContainingDIE(die_offset));
+ if (cu_sp_ptr)
+ *cu_sp_ptr = cu_sp;
+ if (cu_sp.get())
+ return cu_sp->GetDIEPtr(die_offset);
+ return NULL; // Not found in any compile units
+}
+
+DWARFDebugInfoEntry*
+DWARFDebugInfo::GetDIEPtrWithCompileUnitHint (dw_offset_t die_offset, DWARFCompileUnit**cu_handle)
+{
+ assert (cu_handle);
+ DWARFDebugInfoEntry* die = NULL;
+ if (*cu_handle)
+ die = (*cu_handle)->GetDIEPtr(die_offset);
+
+ if (die == NULL)
+ {
+ DWARFCompileUnitSP cu_sp (GetCompileUnitContainingDIE(die_offset));
+ if (cu_sp.get())
+ {
+ *cu_handle = cu_sp.get();
+ die = cu_sp->GetDIEPtr(die_offset);
+ }
+ }
+ if (die == NULL)
+ *cu_handle = NULL;
+ return die;
+}
+
+
+const DWARFDebugInfoEntry*
+DWARFDebugInfo::GetDIEPtrContainingOffset(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr)
+{
+ DWARFCompileUnitSP cu_sp(GetCompileUnitContainingDIE(die_offset));
+ if (cu_sp_ptr)
+ *cu_sp_ptr = cu_sp;
+ if (cu_sp.get())
+ return cu_sp->GetDIEPtrContainingOffset(die_offset);
+
+ return NULL; // Not found in any compile units
+
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugInfo_ParseCallback
+//
+// A callback function for the static DWARFDebugInfo::Parse() function
+// that gets parses all compile units and DIE's into an internate
+// representation for further modification.
+//----------------------------------------------------------------------
+
+static dw_offset_t
+DWARFDebugInfo_ParseCallback
+(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnitSP& cu_sp,
+ DWARFDebugInfoEntry* die,
+ const dw_offset_t next_offset,
+ const uint32_t curr_depth,
+ void* userData
+)
+{
+ DWARFDebugInfo* debug_info = (DWARFDebugInfo*)userData;
+ DWARFCompileUnit* cu = cu_sp.get();
+ if (die)
+ {
+ cu->AddDIE(*die);
+ }
+ else if (cu)
+ {
+ debug_info->AddCompileUnit(cu_sp);
+ }
+
+ // Just return the current offset to parse the next CU or DIE entry
+ return next_offset;
+}
+
+//----------------------------------------------------------------------
+// AddCompileUnit
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::AddCompileUnit(DWARFCompileUnitSP& cu)
+{
+ m_compile_units.push_back(cu);
+}
+
+/*
+void
+DWARFDebugInfo::AddDIE(DWARFDebugInfoEntry& die)
+{
+ m_die_array.push_back(die);
+}
+*/
+
+
+
+
+//----------------------------------------------------------------------
+// Parse
+//
+// Parses the .debug_info section and uses the .debug_abbrev section
+// and various other sections in the SymbolFileDWARF class and calls the
+// supplied callback function each time a compile unit header, or debug
+// information entry is successfully parsed. This function can be used
+// for different tasks such as parsing the file contents into a
+// structured data, dumping, verifying and much more.
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::Parse(SymbolFileDWARF* dwarf2Data, Callback callback, void* userData)
+{
+ if (dwarf2Data)
+ {
+ lldb::offset_t offset = 0;
+ uint32_t depth = 0;
+ DWARFCompileUnitSP cu(new DWARFCompileUnit(dwarf2Data));
+ if (cu.get() == NULL)
+ return;
+ DWARFDebugInfoEntry die;
+
+ while (cu->Extract(dwarf2Data->get_debug_info_data(), &offset))
+ {
+ const dw_offset_t next_cu_offset = cu->GetNextCompileUnitOffset();
+
+ depth = 0;
+ // Call the callback function with no DIE pointer for the compile unit
+ // and get the offset that we are to continue to parse from
+ offset = callback(dwarf2Data, cu, NULL, offset, depth, userData);
+
+ // Make sure we are within our compile unit
+ if (offset < next_cu_offset)
+ {
+ // We are in our compile unit, parse starting at the offset
+ // we were told to parse
+ bool done = false;
+ while (!done && die.Extract(dwarf2Data, cu.get(), &offset))
+ {
+ // Call the callback function with DIE pointer that falls within the compile unit
+ offset = callback(dwarf2Data, cu, &die, offset, depth, userData);
+
+ if (die.IsNULL())
+ {
+ if (depth)
+ --depth;
+ else
+ done = true; // We are done with this compile unit!
+ }
+ else if (die.HasChildren())
+ ++depth;
+ }
+ }
+
+ // Make sure the offset returned is valid, and if not stop parsing.
+ // Returning DW_INVALID_OFFSET from this callback is a good way to end
+ // all parsing
+ if (!dwarf2Data->get_debug_info_data().ValidOffset(offset))
+ break;
+
+ // See if during the callback anyone retained a copy of the compile
+ // unit other than ourselves and if so, let whomever did own the object
+ // and create a new one for our own use!
+ if (!cu.unique())
+ cu.reset(new DWARFCompileUnit(dwarf2Data));
+
+
+ // Make sure we start on a proper
+ offset = next_cu_offset;
+ }
+ }
+}
+
+typedef struct DumpInfo
+{
+ DumpInfo(Stream* init_strm, uint32_t off, uint32_t depth) :
+ strm(init_strm),
+ die_offset(off),
+ recurse_depth(depth),
+ found_depth(UINT32_MAX),
+ found_die(false),
+ ancestors()
+ {
+ }
+ Stream* strm;
+ const uint32_t die_offset;
+ const uint32_t recurse_depth;
+ uint32_t found_depth;
+ bool found_die;
+ std::vector<DWARFDebugInfoEntry> ancestors;
+
+ DISALLOW_COPY_AND_ASSIGN(DumpInfo);
+} DumpInfo;
+
+//----------------------------------------------------------------------
+// DumpCallback
+//
+// A callback function for the static DWARFDebugInfo::Parse() function
+// that gets called each time a compile unit header or debug information
+// entry is successfully parsed.
+//
+// This function dump DWARF information and obey recurse depth and
+// whether a single DIE is to be dumped (or all of the data).
+//----------------------------------------------------------------------
+static dw_offset_t DumpCallback
+(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnitSP& cu_sp,
+ DWARFDebugInfoEntry* die,
+ const dw_offset_t next_offset,
+ const uint32_t curr_depth,
+ void* userData
+)
+{
+ DumpInfo* dumpInfo = (DumpInfo*)userData;
+
+ const DWARFCompileUnit* cu = cu_sp.get();
+
+ Stream *s = dumpInfo->strm;
+ bool show_parents = s->GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowAncestors);
+
+ if (die)
+ {
+ // Are we dumping everything?
+ if (dumpInfo->die_offset == DW_INVALID_OFFSET)
+ {
+ // Yes we are dumping everything. Obey our recurse level though
+ if (curr_depth < dumpInfo->recurse_depth)
+ die->Dump(dwarf2Data, cu, *s, 0);
+ }
+ else
+ {
+ // We are dumping a specific DIE entry by offset
+ if (dumpInfo->die_offset == die->GetOffset())
+ {
+ // We found the DIE we were looking for, dump it!
+ if (show_parents)
+ {
+ s->SetIndentLevel(0);
+ const uint32_t num_ancestors = dumpInfo->ancestors.size();
+ if (num_ancestors > 0)
+ {
+ for (uint32_t i=0; i<num_ancestors-1; ++i)
+ {
+ dumpInfo->ancestors[i].Dump(dwarf2Data, cu, *s, 0);
+ s->IndentMore();
+ }
+ }
+ }
+
+ dumpInfo->found_depth = curr_depth;
+
+ die->Dump(dwarf2Data, cu, *s, 0);
+
+ // Note that we found the DIE we were looking for
+ dumpInfo->found_die = true;
+
+ // Since we are dumping a single DIE, if there are no children we are done!
+ if (!die->HasChildren() || dumpInfo->recurse_depth == 0)
+ return DW_INVALID_OFFSET; // Return an invalid address to end parsing
+ }
+ else if (dumpInfo->found_die)
+ {
+ // Are we done with all the children?
+ if (curr_depth <= dumpInfo->found_depth)
+ return DW_INVALID_OFFSET;
+
+ // We have already found our DIE and are printing it's children. Obey
+ // our recurse depth and return an invalid offset if we get done
+ // dumping all the the children
+ if (dumpInfo->recurse_depth == UINT32_MAX || curr_depth <= dumpInfo->found_depth + dumpInfo->recurse_depth)
+ die->Dump(dwarf2Data, cu, *s, 0);
+ }
+ else if (dumpInfo->die_offset > die->GetOffset())
+ {
+ if (show_parents)
+ dumpInfo->ancestors.back() = *die;
+ }
+ }
+
+ // Keep up with our indent level
+ if (die->IsNULL())
+ {
+ if (show_parents)
+ dumpInfo->ancestors.pop_back();
+
+ if (curr_depth <= 1)
+ return cu->GetNextCompileUnitOffset();
+ else
+ s->IndentLess();
+ }
+ else if (die->HasChildren())
+ {
+ if (show_parents)
+ {
+ DWARFDebugInfoEntry null_die;
+ dumpInfo->ancestors.push_back(null_die);
+ }
+ s->IndentMore();
+ }
+ }
+ else
+ {
+ if (cu == NULL)
+ s->PutCString("NULL - cu");
+ // We have a compile unit, reset our indent level to zero just in case
+ s->SetIndentLevel(0);
+
+ // See if we are dumping everything?
+ if (dumpInfo->die_offset == DW_INVALID_OFFSET)
+ {
+ // We are dumping everything
+ cu->Dump(s);
+ return cu->GetFirstDIEOffset(); // Return true to parse all DIEs in this Compile Unit
+ }
+ else
+ {
+ if (show_parents)
+ {
+ dumpInfo->ancestors.clear();
+ dumpInfo->ancestors.resize(1);
+ }
+
+ // We are dumping only a single DIE possibly with it's children and
+ // we must find it's compile unit before we can dump it properly
+ if (dumpInfo->die_offset < cu->GetFirstDIEOffset())
+ {
+ // Not found, maybe the DIE offset provided wasn't correct?
+ // *ostrm_ptr << "DIE at offset " << HEX32 << dumpInfo->die_offset << " was not found." << endl;
+ return DW_INVALID_OFFSET;
+ }
+ else
+ {
+ // See if the DIE is in this compile unit?
+ if (dumpInfo->die_offset < cu->GetNextCompileUnitOffset())
+ {
+ // This DIE is in this compile unit!
+ if (s->GetVerbose())
+ cu->Dump(s); // Dump the compile unit for the DIE in verbose mode
+
+ return next_offset;
+ // // We found our compile unit that contains our DIE, just skip to dumping the requested DIE...
+ // return dumpInfo->die_offset;
+ }
+ else
+ {
+ // Skip to the next compile unit as the DIE isn't in the current one!
+ return cu->GetNextCompileUnitOffset();
+ }
+ }
+ }
+ }
+
+ // Just return the current offset to parse the next CU or DIE entry
+ return next_offset;
+}
+
+//----------------------------------------------------------------------
+// Dump
+//
+// Dump the information in the .debug_info section to the specified
+// ostream. If die_offset is valid, a single DIE will be dumped. If the
+// die_offset is invalid, all the DWARF information will be dumped. Both
+// cases will obey a "recurse_depth" or how deep to traverse into the
+// children of each DIE entry. A recurse_depth of zero will dump all
+// compile unit headers. A recurse_depth of 1 will dump all compile unit
+// headers and the DW_TAG_compile unit tags. A depth of 2 will also
+// dump all types and functions.
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::Dump
+(
+ Stream *s,
+ SymbolFileDWARF* dwarf2Data,
+ const uint32_t die_offset,
+ const uint32_t recurse_depth
+)
+{
+ DumpInfo dumpInfo(s, die_offset, recurse_depth);
+ s->PutCString(".debug_info contents");
+ if (dwarf2Data->get_debug_info_data().GetByteSize() > 0)
+ {
+ if (die_offset == DW_INVALID_OFFSET)
+ s->PutCString(":\n");
+ else
+ {
+ s->Printf(" for DIE entry at .debug_info[0x%8.8x]", die_offset);
+ if (recurse_depth != UINT32_MAX)
+ s->Printf(" recursing %u levels deep.", recurse_depth);
+ s->EOL();
+ }
+ }
+ else
+ {
+ s->PutCString(": < EMPTY >\n");
+ return;
+ }
+ DWARFDebugInfo::Parse(dwarf2Data, DumpCallback, &dumpInfo);
+}
+
+
+//----------------------------------------------------------------------
+// Dump
+//
+// Dump the contents of this DWARFDebugInfo object as has been parsed
+// and/or modified after it has been parsed.
+//----------------------------------------------------------------------
+void
+DWARFDebugInfo::Dump (Stream *s, const uint32_t die_offset, const uint32_t recurse_depth)
+{
+ DumpInfo dumpInfo(s, die_offset, recurse_depth);
+
+ s->PutCString("Dumping .debug_info section from internal representation\n");
+
+ CompileUnitColl::const_iterator pos;
+ uint32_t curr_depth = 0;
+ ParseCompileUnitHeadersIfNeeded();
+ for (pos = m_compile_units.begin(); pos != m_compile_units.end(); ++pos)
+ {
+ const DWARFCompileUnitSP& cu_sp = *pos;
+ DumpCallback(m_dwarf2Data, (DWARFCompileUnitSP&)cu_sp, NULL, 0, curr_depth, &dumpInfo);
+
+ const DWARFDebugInfoEntry* die = cu_sp->DIE();
+ if (die)
+ die->Dump(m_dwarf2Data, cu_sp.get(), *s, recurse_depth);
+ }
+}
+
+
+//----------------------------------------------------------------------
+// FindCallbackString
+//
+// A callback function for the static DWARFDebugInfo::Parse() function
+// that gets called each time a compile unit header or debug information
+// entry is successfully parsed.
+//
+// This function will find the die_offset of any items whose DW_AT_name
+// matches the given string
+//----------------------------------------------------------------------
+typedef struct FindCallbackStringInfoTag
+{
+ const char* name;
+ bool ignore_case;
+ RegularExpression* regex;
+ vector<dw_offset_t>& die_offsets;
+} FindCallbackStringInfo;
+
+static dw_offset_t FindCallbackString
+(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnitSP& cu_sp,
+ DWARFDebugInfoEntry* die,
+ const dw_offset_t next_offset,
+ const uint32_t curr_depth,
+ void* userData
+)
+{
+ FindCallbackStringInfo* info = (FindCallbackStringInfo*)userData;
+ const DWARFCompileUnit* cu = cu_sp.get();
+
+ if (die)
+ {
+ const char* die_name = die->GetName(dwarf2Data, cu);
+ if (die_name)
+ {
+ if (info->regex)
+ {
+ if (info->regex->Execute(die_name))
+ info->die_offsets.push_back(die->GetOffset());
+ }
+ else
+ {
+ if ((info->ignore_case ? strcasecmp(die_name, info->name) : strcmp(die_name, info->name)) == 0)
+ info->die_offsets.push_back(die->GetOffset());
+ }
+ }
+ }
+
+ // Just return the current offset to parse the next CU or DIE entry
+ return next_offset;
+}
+
+//----------------------------------------------------------------------
+// Find
+//
+// Finds all DIE that have a specific DW_AT_name attribute by manually
+// searching through the debug information (not using the
+// .debug_pubnames section). The string must match the entire name
+// and case sensitive searches are an option.
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfo::Find(const char* name, bool ignore_case, vector<dw_offset_t>& die_offsets) const
+{
+ die_offsets.clear();
+ if (name && name[0])
+ {
+ FindCallbackStringInfo info = { name, ignore_case, NULL, die_offsets };
+ DWARFDebugInfo::Parse(m_dwarf2Data, FindCallbackString, &info);
+ }
+ return !die_offsets.empty();
+}
+
+//----------------------------------------------------------------------
+// Find
+//
+// Finds all DIE that have a specific DW_AT_name attribute by manually
+// searching through the debug information (not using the
+// .debug_pubnames section). The string must match the supplied regular
+// expression.
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfo::Find(RegularExpression& re, vector<dw_offset_t>& die_offsets) const
+{
+ die_offsets.clear();
+ FindCallbackStringInfo info = { NULL, false, &re, die_offsets };
+ DWARFDebugInfo::Parse(m_dwarf2Data, FindCallbackString, &info);
+ return !die_offsets.empty();
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
new file mode 100644
index 000000000000..50a7ae76921f
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfo.h
@@ -0,0 +1,89 @@
+//===-- DWARFDebugInfo.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugInfo_h_
+#define SymbolFileDWARF_DWARFDebugInfo_h_
+
+#include <vector>
+#include <map>
+
+#include "lldb/lldb-private.h"
+#include "lldb/lldb-private.h"
+#include "SymbolFileDWARF.h"
+
+typedef std::multimap<const char*, dw_offset_t, CStringCompareFunctionObject> CStringToDIEMap;
+typedef CStringToDIEMap::iterator CStringToDIEMapIter;
+typedef CStringToDIEMap::const_iterator CStringToDIEMapConstIter;
+
+typedef std::shared_ptr<DWARFCompileUnit> DWARFCompileUnitSP;
+
+class DWARFDebugInfo
+{
+public:
+ typedef dw_offset_t (*Callback)(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnitSP& cu_shared_ptr,
+ DWARFDebugInfoEntry* die,
+ const dw_offset_t next_offset,
+ const uint32_t depth,
+ void* userData);
+
+ DWARFDebugInfo();
+ void SetDwarfData(SymbolFileDWARF* dwarf2Data);
+
+ bool LookupAddress(
+ const dw_addr_t address,
+ const dw_offset_t cu_offset, // Can be valid (find in .debug_aranges), or DW_INVALID_OFFSET if we need to search manually
+ DWARFCompileUnitSP& cu_shared_ptr,
+ DWARFDebugInfoEntry** function_die,
+ DWARFDebugInfoEntry** block_die);
+
+ void AddCompileUnit(DWARFCompileUnitSP& cu);
+ size_t GetNumCompileUnits();
+ bool ContainsCompileUnit (const DWARFCompileUnit *cu) const;
+ DWARFCompileUnit* GetCompileUnitAtIndex(uint32_t idx);
+ DWARFCompileUnitSP GetCompileUnit(dw_offset_t cu_offset, uint32_t* idx_ptr = NULL);
+ DWARFCompileUnitSP GetCompileUnitContainingDIE(dw_offset_t die_offset);
+
+ DWARFDebugInfoEntry* GetDIEPtr(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr);
+ DWARFDebugInfoEntry* GetDIEPtrWithCompileUnitHint (dw_offset_t die_offset, DWARFCompileUnit**cu_handle);
+
+ const DWARFDebugInfoEntry* GetDIEPtrContainingOffset(dw_offset_t die_offset, DWARFCompileUnitSP* cu_sp_ptr);
+
+ void Dump(lldb_private::Stream *s, const uint32_t die_offset, const uint32_t recurse_depth);
+ static void Parse(SymbolFileDWARF* parser, Callback callback, void* userData);
+ static void Verify(lldb_private::Stream *s, SymbolFileDWARF* dwarf2Data);
+ static void Dump(lldb_private::Stream *s, SymbolFileDWARF* dwarf2Data, const uint32_t die_offset, const uint32_t recurse_depth);
+ bool Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offsets) const;
+ bool Find(lldb_private::RegularExpression& re, std::vector<dw_offset_t>& die_offsets) const;
+
+ enum
+ {
+ eDumpFlag_Verbose = (1<<0), // Verbose dumping
+ eDumpFlag_ShowForm = (1<<1), // Show the DW_form type
+ eDumpFlag_ShowAncestors = (1<<2) // Show all parent DIEs when dumping single DIEs
+ };
+
+ DWARFDebugAranges &
+ GetCompileUnitAranges ();
+
+protected:
+ SymbolFileDWARF* m_dwarf2Data;
+ typedef std::vector<DWARFCompileUnitSP> CompileUnitColl;
+ CompileUnitColl m_compile_units;
+ std::unique_ptr<DWARFDebugAranges> m_cu_aranges_ap; // A quick address to compile unit table
+
+private:
+ // All parsing needs to be done partially any managed by this class as accessors are called.
+ void ParseCompileUnitHeadersIfNeeded();
+
+ DISALLOW_COPY_AND_ASSIGN (DWARFDebugInfo);
+};
+
+#endif // SymbolFileDWARF_DWARFDebugInfo_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
new file mode 100644
index 000000000000..03c12e366f92
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.cpp
@@ -0,0 +1,2317 @@
+//===-- DWARFDebugInfoEntry.cpp ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugInfoEntry.h"
+
+#include <assert.h>
+
+#include <algorithm>
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Expression/DWARFExpression.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+#include "DWARFCompileUnit.h"
+#include "SymbolFileDWARF.h"
+#include "DWARFDebugAbbrev.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFDeclContext.h"
+#include "DWARFDIECollection.h"
+#include "DWARFFormValue.h"
+#include "DWARFLocationDescription.h"
+#include "DWARFLocationList.h"
+#include "DWARFDebugRanges.h"
+
+using namespace lldb_private;
+using namespace std;
+extern int g_verbose;
+
+
+
+DWARFDebugInfoEntry::Attributes::Attributes() :
+ m_infos()
+{
+}
+
+DWARFDebugInfoEntry::Attributes::~Attributes()
+{
+}
+
+
+uint32_t
+DWARFDebugInfoEntry::Attributes::FindAttributeIndex(dw_attr_t attr) const
+{
+ collection::const_iterator end = m_infos.end();
+ collection::const_iterator beg = m_infos.begin();
+ collection::const_iterator pos;
+ for (pos = beg; pos != end; ++pos)
+ {
+ if (pos->attr == attr)
+ return std::distance(beg, pos);
+ }
+ return UINT32_MAX;
+}
+
+void
+DWARFDebugInfoEntry::Attributes::Append(const DWARFCompileUnit *cu, dw_offset_t attr_die_offset, dw_attr_t attr, dw_form_t form)
+{
+ Info info = { cu, attr_die_offset, attr, form };
+ m_infos.push_back(info);
+}
+
+bool
+DWARFDebugInfoEntry::Attributes::ContainsAttribute(dw_attr_t attr) const
+{
+ return FindAttributeIndex(attr) != UINT32_MAX;
+}
+
+bool
+DWARFDebugInfoEntry::Attributes::RemoveAttribute(dw_attr_t attr)
+{
+ uint32_t attr_index = FindAttributeIndex(attr);
+ if (attr_index != UINT32_MAX)
+ {
+ m_infos.erase(m_infos.begin() + attr_index);
+ return true;
+ }
+ return false;
+}
+
+bool
+DWARFDebugInfoEntry::Attributes::ExtractFormValueAtIndex (SymbolFileDWARF* dwarf2Data, uint32_t i, DWARFFormValue &form_value) const
+{
+ form_value.SetForm(FormAtIndex(i));
+ lldb::offset_t offset = DIEOffsetAtIndex(i);
+ return form_value.ExtractValue(dwarf2Data->get_debug_info_data(), &offset, CompileUnitAtIndex(i));
+}
+
+uint64_t
+DWARFDebugInfoEntry::Attributes::FormValueAsUnsigned (SymbolFileDWARF* dwarf2Data, dw_attr_t attr, uint64_t fail_value) const
+{
+ const uint32_t attr_idx = FindAttributeIndex (attr);
+ if (attr_idx != UINT32_MAX)
+ return FormValueAsUnsignedAtIndex (dwarf2Data, attr_idx, fail_value);
+ return fail_value;
+}
+
+uint64_t
+DWARFDebugInfoEntry::Attributes::FormValueAsUnsignedAtIndex(SymbolFileDWARF* dwarf2Data, uint32_t i, uint64_t fail_value) const
+{
+ DWARFFormValue form_value;
+ if (ExtractFormValueAtIndex(dwarf2Data, i, form_value))
+ return form_value.Reference(CompileUnitAtIndex(i));
+ return fail_value;
+}
+
+
+
+bool
+DWARFDebugInfoEntry::FastExtract
+(
+ const DataExtractor& debug_info_data,
+ const DWARFCompileUnit* cu,
+ const uint8_t *fixed_form_sizes,
+ lldb::offset_t *offset_ptr
+)
+{
+ m_offset = *offset_ptr;
+ m_parent_idx = 0;
+ m_sibling_idx = 0;
+ m_empty_children = false;
+ const uint64_t abbr_idx = debug_info_data.GetULEB128 (offset_ptr);
+ assert (abbr_idx < (1 << DIE_ABBR_IDX_BITSIZE));
+ m_abbr_idx = abbr_idx;
+
+ //assert (fixed_form_sizes); // For best performance this should be specified!
+
+ if (m_abbr_idx)
+ {
+ lldb::offset_t offset = *offset_ptr;
+
+ const DWARFAbbreviationDeclaration *abbrevDecl = cu->GetAbbreviations()->GetAbbreviationDeclaration(m_abbr_idx);
+
+ if (abbrevDecl == NULL)
+ {
+ cu->GetSymbolFileDWARF()->GetObjectFile()->GetModule()->ReportError ("{0x%8.8x}: invalid abbreviation code %u, please file a bug and attach the file at the start of this error message",
+ m_offset,
+ (unsigned)abbr_idx);
+ // WE can't parse anymore if the DWARF is borked...
+ *offset_ptr = UINT32_MAX;
+ return false;
+ }
+ m_tag = abbrevDecl->Tag();
+ m_has_children = abbrevDecl->HasChildren();
+ // Skip all data in the .debug_info for the attributes
+ const uint32_t numAttributes = abbrevDecl->NumAttributes();
+ register uint32_t i;
+ register dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ form = abbrevDecl->GetFormByIndexUnchecked(i);
+
+ const uint8_t fixed_skip_size = fixed_form_sizes [form];
+ if (fixed_skip_size)
+ offset += fixed_skip_size;
+ else
+ {
+ bool form_is_indirect = false;
+ do
+ {
+ form_is_indirect = false;
+ register uint32_t form_size = 0;
+ switch (form)
+ {
+ // Blocks if inlined data that have a length field and the data bytes
+ // inlined in the .debug_info
+ case DW_FORM_exprloc :
+ case DW_FORM_block : form_size = debug_info_data.GetULEB128 (&offset); break;
+ case DW_FORM_block1 : form_size = debug_info_data.GetU8_unchecked (&offset); break;
+ case DW_FORM_block2 : form_size = debug_info_data.GetU16_unchecked (&offset);break;
+ case DW_FORM_block4 : form_size = debug_info_data.GetU32_unchecked (&offset);break;
+
+ // Inlined NULL terminated C-strings
+ case DW_FORM_string :
+ debug_info_data.GetCStr (&offset);
+ break;
+
+ // Compile unit address sized values
+ case DW_FORM_addr :
+ form_size = cu->GetAddressByteSize();
+ break;
+ case DW_FORM_ref_addr :
+ if (cu->GetVersion() <= 2)
+ form_size = cu->GetAddressByteSize();
+ else
+ form_size = 4; // 4 bytes for DWARF 32, 8 bytes for DWARF 64, but we don't support DWARF64 yet
+ break;
+
+ // 0 sized form
+ case DW_FORM_flag_present:
+ form_size = 0;
+ break;
+
+ // 1 byte values
+ case DW_FORM_data1 :
+ case DW_FORM_flag :
+ case DW_FORM_ref1 :
+ form_size = 1;
+ break;
+
+ // 2 byte values
+ case DW_FORM_data2 :
+ case DW_FORM_ref2 :
+ form_size = 2;
+ break;
+
+ // 4 byte values
+ case DW_FORM_strp :
+ case DW_FORM_data4 :
+ case DW_FORM_ref4 :
+ form_size = 4;
+ break;
+
+ // 8 byte values
+ case DW_FORM_data8 :
+ case DW_FORM_ref8 :
+ case DW_FORM_ref_sig8 :
+ form_size = 8;
+ break;
+
+ // signed or unsigned LEB 128 values
+ case DW_FORM_sdata :
+ case DW_FORM_udata :
+ case DW_FORM_ref_udata :
+ debug_info_data.Skip_LEB128 (&offset);
+ break;
+
+ case DW_FORM_indirect :
+ form_is_indirect = true;
+ form = debug_info_data.GetULEB128 (&offset);
+ break;
+
+ case DW_FORM_sec_offset :
+ if (cu->GetAddressByteSize () == 4)
+ debug_info_data.GetU32 (offset_ptr);
+ else
+ debug_info_data.GetU64 (offset_ptr);
+ break;
+
+ default:
+ *offset_ptr = m_offset;
+ return false;
+ }
+ offset += form_size;
+
+ } while (form_is_indirect);
+ }
+ }
+ *offset_ptr = offset;
+ return true;
+ }
+ else
+ {
+ m_tag = 0;
+ m_has_children = false;
+ return true; // NULL debug tag entry
+ }
+
+ return false;
+}
+
+//----------------------------------------------------------------------
+// Extract
+//
+// Extract a debug info entry for a given compile unit from the
+// .debug_info and .debug_abbrev data within the SymbolFileDWARF class
+// starting at the given offset
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::Extract
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ lldb::offset_t *offset_ptr
+)
+{
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+// const DataExtractor& debug_str_data = dwarf2Data->get_debug_str_data();
+ const uint32_t cu_end_offset = cu->GetNextCompileUnitOffset();
+ const uint8_t cu_addr_size = cu->GetAddressByteSize();
+ lldb::offset_t offset = *offset_ptr;
+// if (offset >= cu_end_offset)
+// Log::Error("DIE at offset 0x%8.8x is beyond the end of the current compile unit (0x%8.8x)", m_offset, cu_end_offset);
+ if ((offset < cu_end_offset) && debug_info_data.ValidOffset(offset))
+ {
+ m_offset = offset;
+
+ const uint64_t abbr_idx = debug_info_data.GetULEB128(&offset);
+ assert (abbr_idx < (1 << DIE_ABBR_IDX_BITSIZE));
+ m_abbr_idx = abbr_idx;
+ if (abbr_idx)
+ {
+ const DWARFAbbreviationDeclaration *abbrevDecl = cu->GetAbbreviations()->GetAbbreviationDeclaration(abbr_idx);
+
+ if (abbrevDecl)
+ {
+ m_tag = abbrevDecl->Tag();
+ m_has_children = abbrevDecl->HasChildren();
+
+ bool isCompileUnitTag = m_tag == DW_TAG_compile_unit;
+ if (cu && isCompileUnitTag)
+ ((DWARFCompileUnit*)cu)->SetBaseAddress(0);
+
+ // Skip all data in the .debug_info for the attributes
+ const uint32_t numAttributes = abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form);
+
+ if (isCompileUnitTag && ((attr == DW_AT_entry_pc) || (attr == DW_AT_low_pc)))
+ {
+ DWARFFormValue form_value(form);
+ if (form_value.ExtractValue(debug_info_data, &offset, cu))
+ {
+ if (attr == DW_AT_low_pc || attr == DW_AT_entry_pc)
+ ((DWARFCompileUnit*)cu)->SetBaseAddress(form_value.Unsigned());
+ }
+ }
+ else
+ {
+ bool form_is_indirect = false;
+ do
+ {
+ form_is_indirect = false;
+ register uint32_t form_size = 0;
+ switch (form)
+ {
+ // Blocks if inlined data that have a length field and the data bytes
+ // inlined in the .debug_info
+ case DW_FORM_exprloc :
+ case DW_FORM_block : form_size = debug_info_data.GetULEB128(&offset); break;
+ case DW_FORM_block1 : form_size = debug_info_data.GetU8(&offset); break;
+ case DW_FORM_block2 : form_size = debug_info_data.GetU16(&offset); break;
+ case DW_FORM_block4 : form_size = debug_info_data.GetU32(&offset); break;
+
+ // Inlined NULL terminated C-strings
+ case DW_FORM_string : debug_info_data.GetCStr(&offset); break;
+
+ // Compile unit address sized values
+ case DW_FORM_addr :
+ form_size = cu_addr_size;
+ break;
+ case DW_FORM_ref_addr :
+ if (cu->GetVersion() <= 2)
+ form_size = cu_addr_size;
+ else
+ form_size = 4; // 4 bytes for DWARF 32, 8 bytes for DWARF 64, but we don't support DWARF64 yet
+ break;
+
+ // 0 sized form
+ case DW_FORM_flag_present:
+ form_size = 0;
+ break;
+
+ // 1 byte values
+ case DW_FORM_data1 :
+ case DW_FORM_flag :
+ case DW_FORM_ref1 :
+ form_size = 1;
+ break;
+
+ // 2 byte values
+ case DW_FORM_data2 :
+ case DW_FORM_ref2 :
+ form_size = 2;
+ break;
+
+ // 4 byte values
+ case DW_FORM_strp :
+ form_size = 4;
+ break;
+
+ case DW_FORM_data4 :
+ case DW_FORM_ref4 :
+ form_size = 4;
+ break;
+
+ // 8 byte values
+ case DW_FORM_data8 :
+ case DW_FORM_ref8 :
+ case DW_FORM_ref_sig8 :
+ form_size = 8;
+ break;
+
+ // signed or unsigned LEB 128 values
+ case DW_FORM_sdata :
+ case DW_FORM_udata :
+ case DW_FORM_ref_udata :
+ debug_info_data.Skip_LEB128(&offset);
+ break;
+
+ case DW_FORM_indirect :
+ form = debug_info_data.GetULEB128(&offset);
+ form_is_indirect = true;
+ break;
+
+ case DW_FORM_sec_offset :
+ if (cu->GetAddressByteSize () == 4)
+ debug_info_data.GetU32 (offset_ptr);
+ else
+ debug_info_data.GetU64 (offset_ptr);
+ break;
+
+ default:
+ *offset_ptr = offset;
+ return false;
+ }
+
+ offset += form_size;
+ } while (form_is_indirect);
+ }
+ }
+ *offset_ptr = offset;
+ return true;
+ }
+ }
+ else
+ {
+ m_tag = 0;
+ m_has_children = false;
+ *offset_ptr = offset;
+ return true; // NULL debug tag entry
+ }
+ }
+
+ return false;
+}
+
+//----------------------------------------------------------------------
+// DumpAncestry
+//
+// Dumps all of a debug information entries parents up until oldest and
+// all of it's attributes to the specified stream.
+//----------------------------------------------------------------------
+void
+DWARFDebugInfoEntry::DumpAncestry
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry* oldest,
+ Stream &s,
+ uint32_t recurse_depth
+) const
+{
+ const DWARFDebugInfoEntry* parent = GetParent();
+ if (parent && parent != oldest)
+ parent->DumpAncestry(dwarf2Data, cu, oldest, s, 0);
+ Dump(dwarf2Data, cu, s, recurse_depth);
+}
+
+//----------------------------------------------------------------------
+// Compare two DIE by comparing all their attributes values, and
+// following all DW_FORM_ref attributes and comparing their contents as
+// well (except for DW_AT_sibling attributes.
+//
+// DWARFDebugInfoEntry::CompareState compare_state;
+// int result = DWARFDebugInfoEntry::Compare(this, 0x00017ccb, 0x0001eb2b, compare_state, false, true);
+//----------------------------------------------------------------------
+//int
+//DWARFDebugInfoEntry::Compare
+//(
+// SymbolFileDWARF* dwarf2Data,
+// dw_offset_t a_die_offset,
+// dw_offset_t b_die_offset,
+// CompareState &compare_state,
+// bool compare_siblings,
+// bool compare_children
+//)
+//{
+// if (a_die_offset == b_die_offset)
+// return 0;
+//
+// DWARFCompileUnitSP a_cu_sp;
+// DWARFCompileUnitSP b_cu_sp;
+// const DWARFDebugInfoEntry* a_die = dwarf2Data->DebugInfo()->GetDIEPtr(a_die_offset, &a_cu_sp);
+// const DWARFDebugInfoEntry* b_die = dwarf2Data->DebugInfo()->GetDIEPtr(b_die_offset, &b_cu_sp);
+//
+// return Compare(dwarf2Data, a_cu_sp.get(), a_die, b_cu_sp.get(), b_die, compare_state, compare_siblings, compare_children);
+//}
+//
+//int
+//DWARFDebugInfoEntry::Compare
+//(
+// SymbolFileDWARF* dwarf2Data,
+// DWARFCompileUnit* a_cu, const DWARFDebugInfoEntry* a_die,
+// DWARFCompileUnit* b_cu, const DWARFDebugInfoEntry* b_die,
+// CompareState &compare_state,
+// bool compare_siblings,
+// bool compare_children
+//)
+//{
+// if (a_die == b_die)
+// return 0;
+//
+// if (!compare_state.AddTypePair(a_die->GetOffset(), b_die->GetOffset()))
+// {
+// // We are already comparing both of these types, so let
+// // compares complete for the real result
+// return 0;
+// }
+//
+// //printf("DWARFDebugInfoEntry::Compare(0x%8.8x, 0x%8.8x)\n", a_die->GetOffset(), b_die->GetOffset());
+//
+// // Do we have two valid DIEs?
+// if (a_die && b_die)
+// {
+// // Both DIE are valid
+// int result = 0;
+//
+// const dw_tag_t a_tag = a_die->Tag();
+// const dw_tag_t b_tag = b_die->Tag();
+// if (a_tag == 0 && b_tag == 0)
+// return 0;
+//
+// //printf(" comparing tags: %s and %s\n", DW_TAG_value_to_name(a_tag), DW_TAG_value_to_name(b_tag));
+//
+// if (a_tag < b_tag)
+// return -1;
+// else if (a_tag > b_tag)
+// return 1;
+//
+// DWARFDebugInfoEntry::Attributes a_attrs;
+// DWARFDebugInfoEntry::Attributes b_attrs;
+// size_t a_attr_count = a_die->GetAttributes(dwarf2Data, a_cu, a_attrs);
+// size_t b_attr_count = b_die->GetAttributes(dwarf2Data, b_cu, b_attrs);
+// if (a_attr_count != b_attr_count)
+// {
+// a_attrs.RemoveAttribute(DW_AT_sibling);
+// b_attrs.RemoveAttribute(DW_AT_sibling);
+// }
+//
+// a_attr_count = a_attrs.Size();
+// b_attr_count = b_attrs.Size();
+//
+// DWARFFormValue a_form_value;
+// DWARFFormValue b_form_value;
+//
+// if (a_attr_count != b_attr_count)
+// {
+// uint32_t is_decl_index = a_attrs.FindAttributeIndex(DW_AT_declaration);
+// uint32_t a_name_index = UINT32_MAX;
+// uint32_t b_name_index = UINT32_MAX;
+// if (is_decl_index != UINT32_MAX)
+// {
+// if (a_attr_count == 2)
+// {
+// a_name_index = a_attrs.FindAttributeIndex(DW_AT_name);
+// b_name_index = b_attrs.FindAttributeIndex(DW_AT_name);
+// }
+// }
+// else
+// {
+// is_decl_index = b_attrs.FindAttributeIndex(DW_AT_declaration);
+// if (is_decl_index != UINT32_MAX && a_attr_count == 2)
+// {
+// a_name_index = a_attrs.FindAttributeIndex(DW_AT_name);
+// b_name_index = b_attrs.FindAttributeIndex(DW_AT_name);
+// }
+// }
+// if (a_name_index != UINT32_MAX && b_name_index != UINT32_MAX)
+// {
+// if (a_attrs.ExtractFormValueAtIndex(dwarf2Data, a_name_index, a_form_value) &&
+// b_attrs.ExtractFormValueAtIndex(dwarf2Data, b_name_index, b_form_value))
+// {
+// result = DWARFFormValue::Compare (a_form_value, b_form_value, a_cu, b_cu, &dwarf2Data->get_debug_str_data());
+// if (result == 0)
+// {
+// a_attr_count = b_attr_count = 0;
+// compare_children = false;
+// }
+// }
+// }
+// }
+//
+// if (a_attr_count < b_attr_count)
+// return -1;
+// if (a_attr_count > b_attr_count)
+// return 1;
+//
+//
+// // The number of attributes are the same...
+// if (a_attr_count > 0)
+// {
+// const DataExtractor* debug_str_data_ptr = &dwarf2Data->get_debug_str_data();
+//
+// uint32_t i;
+// for (i=0; i<a_attr_count; ++i)
+// {
+// const dw_attr_t a_attr = a_attrs.AttributeAtIndex(i);
+// const dw_attr_t b_attr = b_attrs.AttributeAtIndex(i);
+// //printf(" comparing attributes\n\t\t0x%8.8x: %s %s\t\t0x%8.8x: %s %s\n",
+// // a_attrs.DIEOffsetAtIndex(i), DW_FORM_value_to_name(a_attrs.FormAtIndex(i)), DW_AT_value_to_name(a_attr),
+// // b_attrs.DIEOffsetAtIndex(i), DW_FORM_value_to_name(b_attrs.FormAtIndex(i)), DW_AT_value_to_name(b_attr));
+//
+// if (a_attr < b_attr)
+// return -1;
+// else if (a_attr > b_attr)
+// return 1;
+//
+// switch (a_attr)
+// {
+// // Since we call a form of GetAttributes which inlines the
+// // attributes from DW_AT_abstract_origin and DW_AT_specification
+// // we don't care if their values mismatch...
+// case DW_AT_abstract_origin:
+// case DW_AT_specification:
+// case DW_AT_sibling:
+// case DW_AT_containing_type:
+// //printf(" action = IGNORE\n");
+// result = 0;
+// break; // ignore
+//
+// default:
+// if (a_attrs.ExtractFormValueAtIndex(dwarf2Data, i, a_form_value) &&
+// b_attrs.ExtractFormValueAtIndex(dwarf2Data, i, b_form_value))
+// result = DWARFFormValue::Compare (a_form_value, b_form_value, a_cu, b_cu, debug_str_data_ptr);
+// break;
+// }
+//
+// //printf("\t result = %i\n", result);
+//
+// if (result != 0)
+// {
+// // Attributes weren't equal, lets see if we care?
+// switch (a_attr)
+// {
+// case DW_AT_decl_file:
+// // TODO: add the ability to compare files in two different compile units
+// if (a_cu == b_cu)
+// {
+// //printf(" action = RETURN RESULT\n");
+// return result; // Only return the compare results when the compile units are the same and the decl_file attributes can be compared
+// }
+// else
+// {
+// result = 0;
+// //printf(" action = IGNORE\n");
+// }
+// break;
+//
+// default:
+// switch (a_attrs.FormAtIndex(i))
+// {
+// case DW_FORM_ref1:
+// case DW_FORM_ref2:
+// case DW_FORM_ref4:
+// case DW_FORM_ref8:
+// case DW_FORM_ref_udata:
+// case DW_FORM_ref_addr:
+// //printf(" action = COMPARE DIEs 0x%8.8x 0x%8.8x\n", (dw_offset_t)a_form_value.Reference(a_cu), (dw_offset_t)b_form_value.Reference(b_cu));
+// // These attribute values refer to other DIEs, so lets compare those instead of their DIE offsets...
+// result = Compare(dwarf2Data, a_form_value.Reference(a_cu), b_form_value.Reference(b_cu), compare_state, false, true);
+// if (result != 0)
+// return result;
+// break;
+//
+// default:
+// // We do care that they were different, return this result...
+// //printf(" action = RETURN RESULT\n");
+// return result;
+// }
+// }
+// }
+// }
+// }
+// //printf(" SUCCESS\n\t\t0x%8.8x: %s\n\t\t0x%8.8x: %s\n", a_die->GetOffset(), DW_TAG_value_to_name(a_tag), b_die->GetOffset(), DW_TAG_value_to_name(b_tag));
+//
+// if (compare_children)
+// {
+// bool a_has_children = a_die->HasChildren();
+// bool b_has_children = b_die->HasChildren();
+// if (a_has_children == b_has_children)
+// {
+// // Both either have kids or don't
+// if (a_has_children)
+// result = Compare( dwarf2Data,
+// a_cu, a_die->GetFirstChild(),
+// b_cu, b_die->GetFirstChild(),
+// compare_state, true, compare_children);
+// else
+// result = 0;
+// }
+// else if (!a_has_children)
+// result = -1; // A doesn't have kids, but B does
+// else
+// result = 1; // A has kids, but B doesn't
+// }
+//
+// if (compare_siblings)
+// {
+// result = Compare( dwarf2Data,
+// a_cu, a_die->GetSibling(),
+// b_cu, b_die->GetSibling(),
+// compare_state, true, compare_children);
+// }
+//
+// return result;
+// }
+//
+// if (a_die == NULL)
+// return -1; // a_die is NULL, yet b_die is non-NULL
+// else
+// return 1; // a_die is non-NULL, yet b_die is NULL
+//
+//}
+//
+//
+//int
+//DWARFDebugInfoEntry::Compare
+//(
+// SymbolFileDWARF* dwarf2Data,
+// const DWARFCompileUnit* cu_a,
+// const DWARFDebugInfoEntry* die_a,
+// const DWARFCompileUnit* cu_a,
+// const DWARFDebugInfoEntry* die_b,
+// CompareState &compare_state
+//)
+//{
+//}
+
+//----------------------------------------------------------------------
+// GetDIENamesAndRanges
+//
+// Gets the valid address ranges for a given DIE by looking for a
+// DW_AT_low_pc/DW_AT_high_pc pair, DW_AT_entry_pc, or DW_AT_ranges
+// attributes.
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::GetDIENamesAndRanges
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const char * &name,
+ const char * &mangled,
+ DWARFDebugRanges::RangeList& ranges,
+ int& decl_file,
+ int& decl_line,
+ int& decl_column,
+ int& call_file,
+ int& call_line,
+ int& call_column,
+ DWARFExpression *frame_base
+) const
+{
+ if (dwarf2Data == NULL)
+ return false;
+
+ dw_addr_t lo_pc = LLDB_INVALID_ADDRESS;
+ dw_addr_t hi_pc = LLDB_INVALID_ADDRESS;
+ std::vector<dw_offset_t> die_offsets;
+ bool set_frame_base_loclist_addr = false;
+
+ lldb::offset_t offset;
+ const DWARFAbbreviationDeclaration* abbrevDecl = GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset);
+
+ if (abbrevDecl)
+ {
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+
+ if (!debug_info_data.ValidOffset(offset))
+ return false;
+
+ const uint32_t numAttributes = abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ bool do_offset = false;
+
+ for (i=0; i<numAttributes; ++i)
+ {
+ abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form);
+ DWARFFormValue form_value(form);
+ if (form_value.ExtractValue(debug_info_data, &offset, cu))
+ {
+ switch (attr)
+ {
+ case DW_AT_low_pc:
+ lo_pc = form_value.Unsigned();
+
+ if (do_offset)
+ hi_pc += lo_pc;
+ do_offset = false;
+ break;
+
+ case DW_AT_entry_pc:
+ lo_pc = form_value.Unsigned();
+ break;
+
+ case DW_AT_high_pc:
+ hi_pc = form_value.Unsigned();
+ if (form_value.Form() != DW_FORM_addr)
+ {
+ if (lo_pc == LLDB_INVALID_ADDRESS)
+ do_offset = hi_pc != LLDB_INVALID_ADDRESS;
+ else
+ hi_pc += lo_pc; // DWARF 4 introduces <offset-from-lo-pc> to save on relocations
+ }
+ break;
+
+ case DW_AT_ranges:
+ {
+ const DWARFDebugRanges* debug_ranges = dwarf2Data->DebugRanges();
+ debug_ranges->FindRanges(form_value.Unsigned(), ranges);
+ // All DW_AT_ranges are relative to the base address of the
+ // compile unit. We add the compile unit base address to make
+ // sure all the addresses are properly fixed up.
+ ranges.Slide(cu->GetBaseAddress());
+ }
+ break;
+
+ case DW_AT_name:
+ if (name == NULL)
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ break;
+
+ case DW_AT_MIPS_linkage_name:
+ case DW_AT_linkage_name:
+ if (mangled == NULL)
+ mangled = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ break;
+
+ case DW_AT_abstract_origin:
+ die_offsets.push_back(form_value.Reference(cu));
+ break;
+
+ case DW_AT_specification:
+ die_offsets.push_back(form_value.Reference(cu));
+ break;
+
+ case DW_AT_decl_file:
+ if (decl_file == 0)
+ decl_file = form_value.Unsigned();
+ break;
+
+ case DW_AT_decl_line:
+ if (decl_line == 0)
+ decl_line = form_value.Unsigned();
+ break;
+
+ case DW_AT_decl_column:
+ if (decl_column == 0)
+ decl_column = form_value.Unsigned();
+ break;
+
+ case DW_AT_call_file:
+ if (call_file == 0)
+ call_file = form_value.Unsigned();
+ break;
+
+ case DW_AT_call_line:
+ if (call_line == 0)
+ call_line = form_value.Unsigned();
+ break;
+
+ case DW_AT_call_column:
+ if (call_column == 0)
+ call_column = form_value.Unsigned();
+ break;
+
+ case DW_AT_frame_base:
+ if (frame_base)
+ {
+ if (form_value.BlockData())
+ {
+ uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart();
+ uint32_t block_length = form_value.Unsigned();
+ frame_base->SetOpcodeData(debug_info_data, block_offset, block_length);
+ }
+ else
+ {
+ const DataExtractor &debug_loc_data = dwarf2Data->get_debug_loc_data();
+ const dw_offset_t debug_loc_offset = form_value.Unsigned();
+
+ size_t loc_list_length = DWARFLocationList::Size(debug_loc_data, debug_loc_offset);
+ if (loc_list_length > 0)
+ {
+ frame_base->SetOpcodeData(debug_loc_data, debug_loc_offset, loc_list_length);
+ if (lo_pc != LLDB_INVALID_ADDRESS)
+ {
+ assert (lo_pc >= cu->GetBaseAddress());
+ frame_base->SetLocationListSlide(lo_pc - cu->GetBaseAddress());
+ }
+ else
+ {
+ set_frame_base_loclist_addr = true;
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if (ranges.IsEmpty())
+ {
+ if (lo_pc != LLDB_INVALID_ADDRESS)
+ {
+ if (hi_pc != LLDB_INVALID_ADDRESS && hi_pc > lo_pc)
+ ranges.Append(DWARFDebugRanges::Range (lo_pc, hi_pc - lo_pc));
+ else
+ ranges.Append(DWARFDebugRanges::Range (lo_pc, 0));
+ }
+ }
+
+ if (set_frame_base_loclist_addr)
+ {
+ dw_addr_t lowest_range_pc = ranges.GetMinRangeBase(0);
+ assert (lowest_range_pc >= cu->GetBaseAddress());
+ frame_base->SetLocationListSlide (lowest_range_pc - cu->GetBaseAddress());
+ }
+
+ if (ranges.IsEmpty() || name == NULL || mangled == NULL)
+ {
+ std::vector<dw_offset_t>::const_iterator pos;
+ std::vector<dw_offset_t>::const_iterator end = die_offsets.end();
+ for (pos = die_offsets.begin(); pos != end; ++pos)
+ {
+ DWARFCompileUnitSP cu_sp_ptr;
+ const DWARFDebugInfoEntry* die = NULL;
+ dw_offset_t die_offset = *pos;
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ die = dwarf2Data->DebugInfo()->GetDIEPtr(die_offset, &cu_sp_ptr);
+ if (die)
+ die->GetDIENamesAndRanges(dwarf2Data, cu_sp_ptr.get(), name, mangled, ranges, decl_file, decl_line, decl_column, call_file, call_line, call_column);
+ }
+ }
+ }
+ return !ranges.IsEmpty();
+}
+
+//----------------------------------------------------------------------
+// Dump
+//
+// Dumps a debug information entry and all of it's attributes to the
+// specified stream.
+//----------------------------------------------------------------------
+void
+DWARFDebugInfoEntry::Dump
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ Stream &s,
+ uint32_t recurse_depth
+) const
+{
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+ lldb::offset_t offset = m_offset;
+
+ if (debug_info_data.ValidOffset(offset))
+ {
+ dw_uleb128_t abbrCode = debug_info_data.GetULEB128(&offset);
+
+ s.Printf("\n0x%8.8x: ", m_offset);
+ s.Indent();
+ if (abbrCode != m_abbr_idx)
+ {
+ s.Printf( "error: DWARF has been modified\n");
+ }
+ else if (abbrCode)
+ {
+ const DWARFAbbreviationDeclaration* abbrevDecl = cu->GetAbbreviations()->GetAbbreviationDeclaration (abbrCode);
+
+ if (abbrevDecl)
+ {
+ s.PutCString(DW_TAG_value_to_name(abbrevDecl->Tag()));
+ s.Printf( " [%u] %c\n", abbrCode, abbrevDecl->HasChildren() ? '*':' ');
+
+ // Dump all data in the .debug_info for the attributes
+ const uint32_t numAttributes = abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ for (i=0; i<numAttributes; ++i)
+ {
+ abbrevDecl->GetAttrAndFormByIndexUnchecked(i, attr, form);
+
+ DumpAttribute(dwarf2Data, cu, debug_info_data, &offset, s, attr, form);
+ }
+
+ const DWARFDebugInfoEntry* child = GetFirstChild();
+ if (recurse_depth > 0 && child)
+ {
+ s.IndentMore();
+
+ while (child)
+ {
+ child->Dump(dwarf2Data, cu, s, recurse_depth-1);
+ child = child->GetSibling();
+ }
+ s.IndentLess();
+ }
+ }
+ else
+ s.Printf( "Abbreviation code note found in 'debug_abbrev' class for code: %u\n", abbrCode);
+ }
+ else
+ {
+ s.Printf( "NULL\n");
+ }
+ }
+}
+
+void
+DWARFDebugInfoEntry::DumpLocation
+(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ Stream &s
+) const
+{
+ const DWARFDebugInfoEntry *cu_die = cu->GetCompileUnitDIEOnly();
+ const char *cu_name = NULL;
+ if (cu_die != NULL)
+ cu_name = cu_die->GetName (dwarf2Data, cu);
+ const char *obj_file_name = NULL;
+ ObjectFile *obj_file = dwarf2Data->GetObjectFile();
+ if (obj_file)
+ obj_file_name = obj_file->GetFileSpec().GetFilename().AsCString();
+ const char *die_name = GetName (dwarf2Data, cu);
+ s.Printf ("0x%8.8x/0x%8.8x: %-30s (from %s in %s)",
+ cu->GetOffset(),
+ GetOffset(),
+ die_name ? die_name : "",
+ cu_name ? cu_name : "<NULL>",
+ obj_file_name ? obj_file_name : "<NULL>");
+}
+
+//----------------------------------------------------------------------
+// DumpAttribute
+//
+// Dumps a debug information entry attribute along with it's form. Any
+// special display of attributes is done (disassemble location lists,
+// show enumeration values for attributes, etc).
+//----------------------------------------------------------------------
+void
+DWARFDebugInfoEntry::DumpAttribute
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const DataExtractor& debug_info_data,
+ lldb::offset_t *offset_ptr,
+ Stream &s,
+ dw_attr_t attr,
+ dw_form_t form
+)
+{
+ bool verbose = s.GetVerbose();
+ bool show_form = s.GetFlags().Test(DWARFDebugInfo::eDumpFlag_ShowForm);
+
+ const DataExtractor* debug_str_data = dwarf2Data ? &dwarf2Data->get_debug_str_data() : NULL;
+ if (verbose)
+ s.Offset (*offset_ptr);
+ else
+ s.Printf (" ");
+ s.Indent(DW_AT_value_to_name(attr));
+
+ if (show_form)
+ {
+ s.Printf( "[%s", DW_FORM_value_to_name(form));
+ }
+
+ DWARFFormValue form_value(form);
+
+ if (!form_value.ExtractValue(debug_info_data, offset_ptr, cu))
+ return;
+
+ if (show_form)
+ {
+ if (form == DW_FORM_indirect)
+ {
+ s.Printf( " [%s]", DW_FORM_value_to_name(form_value.Form()));
+ }
+
+ s.PutCString("] ");
+ }
+
+ s.PutCString("( ");
+
+ // Always dump form value if verbose is enabled
+ if (verbose)
+ {
+ form_value.Dump(s, debug_str_data, cu);
+ }
+
+
+ // Check to see if we have any special attribute formatters
+ switch (attr)
+ {
+ case DW_AT_stmt_list:
+ if ( verbose ) s.PutCString(" ( ");
+ s.Printf( "0x%8.8" PRIx64, form_value.Unsigned());
+ if ( verbose ) s.PutCString(" )");
+ break;
+
+ case DW_AT_language:
+ if ( verbose ) s.PutCString(" ( ");
+ s.PutCString(DW_LANG_value_to_name(form_value.Unsigned()));
+ if ( verbose ) s.PutCString(" )");
+ break;
+
+ case DW_AT_encoding:
+ if ( verbose ) s.PutCString(" ( ");
+ s.PutCString(DW_ATE_value_to_name(form_value.Unsigned()));
+ if ( verbose ) s.PutCString(" )");
+ break;
+
+ case DW_AT_frame_base:
+ case DW_AT_location:
+ case DW_AT_data_member_location:
+ {
+ const uint8_t* blockData = form_value.BlockData();
+ if (blockData)
+ {
+ if (!verbose)
+ form_value.Dump(s, debug_str_data, cu);
+
+ // Location description is inlined in data in the form value
+ DataExtractor locationData(debug_info_data, (*offset_ptr) - form_value.Unsigned(), form_value.Unsigned());
+ if ( verbose ) s.PutCString(" ( ");
+ print_dwarf_expression (s, locationData, DWARFCompileUnit::GetAddressByteSize(cu), 4, false);
+ if ( verbose ) s.PutCString(" )");
+ }
+ else
+ {
+ // We have a location list offset as the value that is
+ // the offset into the .debug_loc section that describes
+ // the value over it's lifetime
+ uint64_t debug_loc_offset = form_value.Unsigned();
+ if (dwarf2Data)
+ {
+ if ( !verbose )
+ form_value.Dump(s, debug_str_data, cu);
+ DWARFLocationList::Dump(s, cu, dwarf2Data->get_debug_loc_data(), debug_loc_offset);
+ }
+ else
+ {
+ if ( !verbose )
+ form_value.Dump(s, NULL, cu);
+ }
+ }
+ }
+ break;
+
+ case DW_AT_abstract_origin:
+ case DW_AT_specification:
+ {
+ uint64_t abstract_die_offset = form_value.Reference(cu);
+ form_value.Dump(s, debug_str_data, cu);
+ // *ostrm_ptr << HEX32 << abstract_die_offset << " ( ";
+ if ( verbose ) s.PutCString(" ( ");
+ GetName(dwarf2Data, cu, abstract_die_offset, s);
+ if ( verbose ) s.PutCString(" )");
+ }
+ break;
+
+ case DW_AT_type:
+ {
+ uint64_t type_die_offset = form_value.Reference(cu);
+ if (!verbose)
+ form_value.Dump(s, debug_str_data, cu);
+ s.PutCString(" ( ");
+ AppendTypeName(dwarf2Data, cu, type_die_offset, s);
+ s.PutCString(" )");
+ }
+ break;
+
+ case DW_AT_ranges:
+ {
+ if ( !verbose )
+ form_value.Dump(s, debug_str_data, cu);
+ lldb::offset_t ranges_offset = form_value.Unsigned();
+ dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0;
+ if (dwarf2Data)
+ DWARFDebugRanges::Dump(s, dwarf2Data->get_debug_ranges_data(), &ranges_offset, base_addr);
+ }
+ break;
+
+ default:
+ if ( !verbose )
+ form_value.Dump(s, debug_str_data, cu);
+ break;
+ }
+
+ s.PutCString(" )\n");
+}
+
+//----------------------------------------------------------------------
+// Get all attribute values for a given DIE, including following any
+// specification or abstract origin attributes and including those in
+// the results. Any duplicate attributes will have the first instance
+// take precedence (this can happen for declaration attributes).
+//----------------------------------------------------------------------
+size_t
+DWARFDebugInfoEntry::GetAttributes
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const uint8_t *fixed_form_sizes,
+ DWARFDebugInfoEntry::Attributes& attributes,
+ uint32_t curr_depth
+) const
+{
+ lldb::offset_t offset;
+ const DWARFAbbreviationDeclaration* abbrevDecl = GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset);
+
+ if (abbrevDecl)
+ {
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+
+ if (fixed_form_sizes == NULL)
+ fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize(cu->GetAddressByteSize());
+
+ const uint32_t num_attributes = abbrevDecl->NumAttributes();
+ uint32_t i;
+ dw_attr_t attr;
+ dw_form_t form;
+ DWARFFormValue form_value;
+ for (i=0; i<num_attributes; ++i)
+ {
+ abbrevDecl->GetAttrAndFormByIndexUnchecked (i, attr, form);
+
+ // If we are tracking down DW_AT_specification or DW_AT_abstract_origin
+ // attributes, the depth will be non-zero. We need to omit certain
+ // attributes that don't make sense.
+ switch (attr)
+ {
+ case DW_AT_sibling:
+ case DW_AT_declaration:
+ if (curr_depth > 0)
+ {
+ // This attribute doesn't make sense when combined with
+ // the DIE that references this DIE. We know a DIE is
+ // referencing this DIE because curr_depth is not zero
+ break;
+ }
+ // Fall through...
+ default:
+ attributes.Append(cu, offset, attr, form);
+ break;
+ }
+
+ if ((attr == DW_AT_specification) || (attr == DW_AT_abstract_origin))
+ {
+ form_value.SetForm(form);
+ if (form_value.ExtractValue(debug_info_data, &offset, cu))
+ {
+ const DWARFDebugInfoEntry* die = NULL;
+ dw_offset_t die_offset = form_value.Reference(cu);
+ if (cu->ContainsDIEOffset(die_offset))
+ {
+ die = const_cast<DWARFCompileUnit*>(cu)->GetDIEPtr(die_offset);
+ if (die)
+ die->GetAttributes(dwarf2Data, cu, fixed_form_sizes, attributes, curr_depth + 1);
+ }
+ else
+ {
+ DWARFCompileUnitSP cu_sp_ptr;
+ die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(die_offset, &cu_sp_ptr);
+ if (die)
+ die->GetAttributes(dwarf2Data, cu_sp_ptr.get(), fixed_form_sizes, attributes, curr_depth + 1);
+ }
+ }
+ }
+ else
+ {
+ const uint8_t fixed_skip_size = fixed_form_sizes [form];
+ if (fixed_skip_size)
+ offset += fixed_skip_size;
+ else
+ DWARFFormValue::SkipValue(form, debug_info_data, &offset, cu);
+ }
+ }
+ }
+ else
+ {
+ attributes.Clear();
+ }
+ return attributes.Size();
+
+}
+
+//----------------------------------------------------------------------
+// GetAttributeValue
+//
+// Get the value of an attribute and return the .debug_info offset of the
+// attribute if it was properly extracted into form_value, or zero
+// if we fail since an offset of zero is invalid for an attribute (it
+// would be a compile unit header).
+//----------------------------------------------------------------------
+dw_offset_t
+DWARFDebugInfoEntry::GetAttributeValue
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ DWARFFormValue& form_value,
+ dw_offset_t* end_attr_offset_ptr
+) const
+{
+ lldb::offset_t offset;
+ const DWARFAbbreviationDeclaration* abbrevDecl = GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset);
+
+ if (abbrevDecl)
+ {
+ uint32_t attr_idx = abbrevDecl->FindAttributeIndex(attr);
+
+ if (attr_idx != DW_INVALID_INDEX)
+ {
+ const DataExtractor& debug_info_data = dwarf2Data->get_debug_info_data();
+
+ uint32_t idx=0;
+ while (idx<attr_idx)
+ DWARFFormValue::SkipValue(abbrevDecl->GetFormByIndex(idx++), debug_info_data, &offset, cu);
+
+ const dw_offset_t attr_offset = offset;
+ form_value.SetForm(abbrevDecl->GetFormByIndex(idx));
+ if (form_value.ExtractValue(debug_info_data, &offset, cu))
+ {
+ if (end_attr_offset_ptr)
+ *end_attr_offset_ptr = offset;
+ return attr_offset;
+ }
+ }
+ }
+
+ return 0;
+}
+
+//----------------------------------------------------------------------
+// GetAttributeValueAsString
+//
+// Get the value of an attribute as a string return it. The resulting
+// pointer to the string data exists within the supplied SymbolFileDWARF
+// and will only be available as long as the SymbolFileDWARF is still around
+// and it's content doesn't change.
+//----------------------------------------------------------------------
+const char*
+DWARFDebugInfoEntry::GetAttributeValueAsString
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ const char* fail_value) const
+{
+ DWARFFormValue form_value;
+ if (GetAttributeValue(dwarf2Data, cu, attr, form_value))
+ return form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ return fail_value;
+}
+
+//----------------------------------------------------------------------
+// GetAttributeValueAsUnsigned
+//
+// Get the value of an attribute as unsigned and return it.
+//----------------------------------------------------------------------
+uint64_t
+DWARFDebugInfoEntry::GetAttributeValueAsUnsigned
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ uint64_t fail_value
+) const
+{
+ DWARFFormValue form_value;
+ if (GetAttributeValue(dwarf2Data, cu, attr, form_value))
+ return form_value.Unsigned();
+ return fail_value;
+}
+
+//----------------------------------------------------------------------
+// GetAttributeValueAsSigned
+//
+// Get the value of an attribute a signed value and return it.
+//----------------------------------------------------------------------
+int64_t
+DWARFDebugInfoEntry::GetAttributeValueAsSigned
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ int64_t fail_value
+) const
+{
+ DWARFFormValue form_value;
+ if (GetAttributeValue(dwarf2Data, cu, attr, form_value))
+ return form_value.Signed();
+ return fail_value;
+}
+
+//----------------------------------------------------------------------
+// GetAttributeValueAsReference
+//
+// Get the value of an attribute as reference and fix up and compile
+// unit relative offsets as needed.
+//----------------------------------------------------------------------
+uint64_t
+DWARFDebugInfoEntry::GetAttributeValueAsReference
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ uint64_t fail_value
+) const
+{
+ DWARFFormValue form_value;
+ if (GetAttributeValue(dwarf2Data, cu, attr, form_value))
+ return form_value.Reference(cu);
+ return fail_value;
+}
+
+//----------------------------------------------------------------------
+// GetAttributeHighPC
+//
+// Get the hi_pc, adding hi_pc to lo_pc when specified
+// as an <offset-from-low-pc>.
+//
+// Returns the hi_pc or fail_value.
+//----------------------------------------------------------------------
+dw_addr_t
+DWARFDebugInfoEntry::GetAttributeHighPC
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ dw_addr_t lo_pc,
+ uint64_t fail_value
+) const
+{
+ DWARFFormValue form_value;
+
+ if (GetAttributeValue(dwarf2Data, cu, DW_AT_high_pc, form_value))
+ {
+ dw_addr_t hi_pc = form_value.Unsigned();
+ if (form_value.Form() != DW_FORM_addr)
+ hi_pc += lo_pc; // DWARF4 can specify the hi_pc as an <offset-from-lowpc>
+ return hi_pc;
+ }
+ return fail_value;
+}
+
+//----------------------------------------------------------------------
+// GetAttributeAddressRange
+//
+// Get the lo_pc and hi_pc, adding hi_pc to lo_pc when specified
+// as an <offset-from-low-pc>.
+//
+// Returns true or sets lo_pc and hi_pc to fail_value.
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::GetAttributeAddressRange
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ dw_addr_t& lo_pc,
+ dw_addr_t& hi_pc,
+ uint64_t fail_value
+) const
+{
+ lo_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, fail_value);
+ if (lo_pc != fail_value)
+ {
+ hi_pc = GetAttributeHighPC(dwarf2Data, cu, lo_pc, fail_value);
+ if (hi_pc != fail_value)
+ return true;
+ }
+ lo_pc = fail_value;
+ hi_pc = fail_value;
+ return false;
+}
+//----------------------------------------------------------------------
+// GetAttributeValueAsLocation
+//
+// Get the value of an attribute as reference and fix up and compile
+// unit relative offsets as needed.
+//----------------------------------------------------------------------
+dw_offset_t
+DWARFDebugInfoEntry::GetAttributeValueAsLocation
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ DataExtractor& location_data,
+ uint32_t &block_size
+) const
+{
+ block_size = 0;
+ DWARFFormValue form_value;
+
+ // Empty out data in case we don't find anything
+ location_data.Clear();
+ dw_offset_t end_addr_offset = DW_INVALID_OFFSET;
+ const dw_offset_t attr_offset = GetAttributeValue(dwarf2Data, cu, attr, form_value, &end_addr_offset);
+ if (attr_offset)
+ {
+ const uint8_t* blockData = form_value.BlockData();
+ if (blockData)
+ {
+ // We have an inlined location list in the .debug_info section
+ const DataExtractor& debug_info = dwarf2Data->get_debug_info_data();
+ dw_offset_t block_offset = blockData - debug_info.GetDataStart();
+ block_size = (end_addr_offset - attr_offset) - form_value.Unsigned();
+ location_data.SetData(debug_info, block_offset, block_size);
+ }
+ else
+ {
+ // We have a location list offset as the value that is
+ // the offset into the .debug_loc section that describes
+ // the value over it's lifetime
+ lldb::offset_t debug_loc_offset = form_value.Unsigned();
+ if (dwarf2Data)
+ {
+ assert(dwarf2Data->get_debug_loc_data().GetAddressByteSize() == cu->GetAddressByteSize());
+ return DWARFLocationList::Extract(dwarf2Data->get_debug_loc_data(), &debug_loc_offset, location_data);
+ }
+ }
+ }
+ return attr_offset;
+}
+
+//----------------------------------------------------------------------
+// GetName
+//
+// Get value of the DW_AT_name attribute and return it if one exists,
+// else return NULL.
+//----------------------------------------------------------------------
+const char*
+DWARFDebugInfoEntry::GetName
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu
+) const
+{
+ DWARFFormValue form_value;
+ if (GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value))
+ return form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ else
+ {
+ if (GetAttributeValue(dwarf2Data, cu, DW_AT_specification, form_value))
+ {
+ DWARFCompileUnitSP cu_sp_ptr;
+ const DWARFDebugInfoEntry* die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(cu), &cu_sp_ptr);
+ if (die)
+ return die->GetName(dwarf2Data, cu_sp_ptr.get());
+ }
+ }
+ return NULL;
+}
+
+
+//----------------------------------------------------------------------
+// GetMangledName
+//
+// Get value of the DW_AT_MIPS_linkage_name attribute and return it if
+// one exists, else return the value of the DW_AT_name attribute
+//----------------------------------------------------------------------
+const char*
+DWARFDebugInfoEntry::GetMangledName
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ bool substitute_name_allowed
+) const
+{
+ const char* name = NULL;
+ DWARFFormValue form_value;
+
+ if (GetAttributeValue(dwarf2Data, cu, DW_AT_MIPS_linkage_name, form_value))
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+
+ if (GetAttributeValue(dwarf2Data, cu, DW_AT_linkage_name, form_value))
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+
+ if (substitute_name_allowed && name == NULL)
+ {
+ if (GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value))
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ }
+ return name;
+}
+
+
+//----------------------------------------------------------------------
+// GetPubname
+//
+// Get value the name for a DIE as it should appear for a
+// .debug_pubnames or .debug_pubtypes section.
+//----------------------------------------------------------------------
+const char*
+DWARFDebugInfoEntry::GetPubname
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu
+) const
+{
+ const char* name = NULL;
+ if (!dwarf2Data)
+ return name;
+
+ DWARFFormValue form_value;
+
+ if (GetAttributeValue(dwarf2Data, cu, DW_AT_MIPS_linkage_name, form_value))
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ else if (GetAttributeValue(dwarf2Data, cu, DW_AT_linkage_name, form_value))
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ else if (GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value))
+ name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ else if (GetAttributeValue(dwarf2Data, cu, DW_AT_specification, form_value))
+ {
+ // The specification DIE may be in another compile unit so we need
+ // to get a die and its compile unit.
+ DWARFCompileUnitSP cu_sp_ptr;
+ const DWARFDebugInfoEntry* die = const_cast<SymbolFileDWARF*>(dwarf2Data)->DebugInfo()->GetDIEPtr(form_value.Reference(cu), &cu_sp_ptr);
+ if (die)
+ return die->GetPubname(dwarf2Data, cu_sp_ptr.get());
+ }
+ return name;
+}
+
+
+//----------------------------------------------------------------------
+// GetName
+//
+// Get value of the DW_AT_name attribute for a debug information entry
+// that exists at offset "die_offset" and place that value into the
+// supplied stream object. If the DIE is a NULL object "NULL" is placed
+// into the stream, and if no DW_AT_name attribute exists for the DIE
+// then nothing is printed.
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::GetName
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_offset_t die_offset,
+ Stream &s
+)
+{
+ if (dwarf2Data == NULL)
+ {
+ s.PutCString("NULL");
+ return false;
+ }
+
+ DWARFDebugInfoEntry die;
+ lldb::offset_t offset = die_offset;
+ if (die.Extract(dwarf2Data, cu, &offset))
+ {
+ if (die.IsNULL())
+ {
+ s.PutCString("NULL");
+ return true;
+ }
+ else
+ {
+ DWARFFormValue form_value;
+ if (die.GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value))
+ {
+ const char* name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ if (name)
+ {
+ s.PutCString(name);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// AppendTypeName
+//
+// Follows the type name definition down through all needed tags to
+// end up with a fully qualified type name and dump the results to
+// the supplied stream. This is used to show the name of types given
+// a type identifier.
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::AppendTypeName
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_offset_t die_offset,
+ Stream &s
+)
+{
+ if (dwarf2Data == NULL)
+ {
+ s.PutCString("NULL");
+ return false;
+ }
+
+ DWARFDebugInfoEntry die;
+ lldb::offset_t offset = die_offset;
+ if (die.Extract(dwarf2Data, cu, &offset))
+ {
+ if (die.IsNULL())
+ {
+ s.PutCString("NULL");
+ return true;
+ }
+ else
+ {
+ const char* name = die.GetPubname(dwarf2Data, cu);
+ // if (die.GetAttributeValue(dwarf2Data, cu, DW_AT_name, form_value))
+ // name = form_value.AsCString(&dwarf2Data->get_debug_str_data());
+ if (name)
+ s.PutCString(name);
+ else
+ {
+ bool result = true;
+ const DWARFAbbreviationDeclaration* abbrevDecl = die.GetAbbreviationDeclarationPtr(dwarf2Data, cu, offset);
+
+ if (abbrevDecl == NULL)
+ return false;
+
+ switch (abbrevDecl->Tag())
+ {
+ case DW_TAG_array_type: break; // print out a "[]" after printing the full type of the element below
+ case DW_TAG_base_type: s.PutCString("base "); break;
+ case DW_TAG_class_type: s.PutCString("class "); break;
+ case DW_TAG_const_type: s.PutCString("const "); break;
+ case DW_TAG_enumeration_type: s.PutCString("enum "); break;
+ case DW_TAG_file_type: s.PutCString("file "); break;
+ case DW_TAG_interface_type: s.PutCString("interface "); break;
+ case DW_TAG_packed_type: s.PutCString("packed "); break;
+ case DW_TAG_pointer_type: break; // print out a '*' after printing the full type below
+ case DW_TAG_ptr_to_member_type: break; // print out a '*' after printing the full type below
+ case DW_TAG_reference_type: break; // print out a '&' after printing the full type below
+ case DW_TAG_restrict_type: s.PutCString("restrict "); break;
+ case DW_TAG_set_type: s.PutCString("set "); break;
+ case DW_TAG_shared_type: s.PutCString("shared "); break;
+ case DW_TAG_string_type: s.PutCString("string "); break;
+ case DW_TAG_structure_type: s.PutCString("struct "); break;
+ case DW_TAG_subrange_type: s.PutCString("subrange "); break;
+ case DW_TAG_subroutine_type: s.PutCString("function "); break;
+ case DW_TAG_thrown_type: s.PutCString("thrown "); break;
+ case DW_TAG_union_type: s.PutCString("union "); break;
+ case DW_TAG_unspecified_type: s.PutCString("unspecified "); break;
+ case DW_TAG_volatile_type: s.PutCString("volatile "); break;
+ default:
+ return false;
+ }
+
+ // Follow the DW_AT_type if possible
+ DWARFFormValue form_value;
+ if (die.GetAttributeValue(dwarf2Data, cu, DW_AT_type, form_value))
+ {
+ uint64_t next_die_offset = form_value.Reference(cu);
+ result = AppendTypeName(dwarf2Data, cu, next_die_offset, s);
+ }
+
+ switch (abbrevDecl->Tag())
+ {
+ case DW_TAG_array_type: s.PutCString("[]"); break;
+ case DW_TAG_pointer_type: s.PutChar('*'); break;
+ case DW_TAG_ptr_to_member_type: s.PutChar('*'); break;
+ case DW_TAG_reference_type: s.PutChar('&'); break;
+ default:
+ break;
+ }
+ return result;
+ }
+ }
+ }
+ return false;
+}
+
+bool
+DWARFDebugInfoEntry::Contains (const DWARFDebugInfoEntry *die) const
+{
+ if (die)
+ {
+ const dw_offset_t die_offset = die->GetOffset();
+ if (die_offset > GetOffset())
+ {
+ const DWARFDebugInfoEntry *sibling = GetSibling();
+ assert (sibling); // TODO: take this out
+ if (sibling)
+ return die_offset < sibling->GetOffset();
+ }
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// BuildAddressRangeTable
+//----------------------------------------------------------------------
+void
+DWARFDebugInfoEntry::BuildAddressRangeTable
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugAranges* debug_aranges
+) const
+{
+ if (m_tag)
+ {
+ if (m_tag == DW_TAG_subprogram)
+ {
+ dw_addr_t lo_pc = LLDB_INVALID_ADDRESS;
+ dw_addr_t hi_pc = LLDB_INVALID_ADDRESS;
+ if (GetAttributeAddressRange(dwarf2Data, cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS))
+ {
+ /// printf("BuildAddressRangeTable() 0x%8.8x: %30s: [0x%8.8x - 0x%8.8x)\n", m_offset, DW_TAG_value_to_name(tag), lo_pc, hi_pc);
+ debug_aranges->AppendRange (cu->GetOffset(), lo_pc, hi_pc);
+ }
+ }
+
+
+ const DWARFDebugInfoEntry* child = GetFirstChild();
+ while (child)
+ {
+ child->BuildAddressRangeTable(dwarf2Data, cu, debug_aranges);
+ child = child->GetSibling();
+ }
+ }
+}
+
+//----------------------------------------------------------------------
+// BuildFunctionAddressRangeTable
+//
+// This function is very similar to the BuildAddressRangeTable function
+// except that the actual DIE offset for the function is placed in the
+// table instead of the compile unit offset (which is the way the
+// standard .debug_aranges section does it).
+//----------------------------------------------------------------------
+void
+DWARFDebugInfoEntry::BuildFunctionAddressRangeTable
+(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugAranges* debug_aranges
+) const
+{
+ if (m_tag)
+ {
+ if (m_tag == DW_TAG_subprogram)
+ {
+ dw_addr_t lo_pc = LLDB_INVALID_ADDRESS;
+ dw_addr_t hi_pc = LLDB_INVALID_ADDRESS;
+ if (GetAttributeAddressRange(dwarf2Data, cu, lo_pc, hi_pc, LLDB_INVALID_ADDRESS))
+ {
+ // printf("BuildAddressRangeTable() 0x%8.8x: [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")\n", m_offset, lo_pc, hi_pc); // DEBUG ONLY
+ debug_aranges->AppendRange (GetOffset(), lo_pc, hi_pc);
+ }
+ }
+
+ const DWARFDebugInfoEntry* child = GetFirstChild();
+ while (child)
+ {
+ child->BuildFunctionAddressRangeTable(dwarf2Data, cu, debug_aranges);
+ child = child->GetSibling();
+ }
+ }
+}
+
+void
+DWARFDebugInfoEntry::GetDeclContextDIEs (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ DWARFDIECollection &decl_context_dies) const
+{
+ const DWARFDebugInfoEntry *parent_decl_ctx_die = GetParentDeclContextDIE (dwarf2Data, cu);
+ if (parent_decl_ctx_die && parent_decl_ctx_die != this)
+ {
+ decl_context_dies.Append(parent_decl_ctx_die);
+ parent_decl_ctx_die->GetDeclContextDIEs (dwarf2Data, cu, decl_context_dies);
+ }
+}
+
+void
+DWARFDebugInfoEntry::GetDWARFDeclContext (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ DWARFDeclContext &dwarf_decl_ctx) const
+{
+ const dw_tag_t tag = Tag();
+ if (tag != DW_TAG_compile_unit)
+ {
+ dwarf_decl_ctx.AppendDeclContext(tag, GetName(dwarf2Data, cu));
+ const DWARFDebugInfoEntry *parent_decl_ctx_die = GetParentDeclContextDIE (dwarf2Data, cu);
+ if (parent_decl_ctx_die && parent_decl_ctx_die != this)
+ {
+ if (parent_decl_ctx_die->Tag() != DW_TAG_compile_unit)
+ parent_decl_ctx_die->GetDWARFDeclContext (dwarf2Data, cu, dwarf_decl_ctx);
+ }
+ }
+}
+
+
+bool
+DWARFDebugInfoEntry::MatchesDWARFDeclContext (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ const DWARFDeclContext &dwarf_decl_ctx) const
+{
+
+ DWARFDeclContext this_dwarf_decl_ctx;
+ GetDWARFDeclContext (dwarf2Data, cu, this_dwarf_decl_ctx);
+ return this_dwarf_decl_ctx == dwarf_decl_ctx;
+}
+
+const DWARFDebugInfoEntry *
+DWARFDebugInfoEntry::GetParentDeclContextDIE (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu) const
+{
+ DWARFDebugInfoEntry::Attributes attributes;
+ GetAttributes(dwarf2Data, cu, NULL, attributes);
+ return GetParentDeclContextDIE (dwarf2Data, cu, attributes);
+}
+
+const DWARFDebugInfoEntry *
+DWARFDebugInfoEntry::GetParentDeclContextDIE (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry::Attributes& attributes) const
+{
+ const DWARFDebugInfoEntry * die = this;
+
+ while (die != NULL)
+ {
+ // If this is the original DIE that we are searching for a declaration
+ // for, then don't look in the cache as we don't want our own decl
+ // context to be our decl context...
+ if (die != this)
+ {
+ switch (die->Tag())
+ {
+ case DW_TAG_compile_unit:
+ case DW_TAG_namespace:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ return die;
+
+ default:
+ break;
+ }
+ }
+
+ dw_offset_t die_offset;
+
+ die_offset = attributes.FormValueAsUnsigned(dwarf2Data, DW_AT_specification, DW_INVALID_OFFSET);
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ const DWARFDebugInfoEntry *spec_die = cu->GetDIEPtr (die_offset);
+ if (spec_die)
+ {
+ const DWARFDebugInfoEntry *spec_die_decl_ctx_die = spec_die->GetParentDeclContextDIE (dwarf2Data, cu);
+ if (spec_die_decl_ctx_die)
+ return spec_die_decl_ctx_die;
+ }
+ }
+
+ die_offset = attributes.FormValueAsUnsigned(dwarf2Data, DW_AT_abstract_origin, DW_INVALID_OFFSET);
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ const DWARFDebugInfoEntry *abs_die = cu->GetDIEPtr (die_offset);
+ if (abs_die)
+ {
+ const DWARFDebugInfoEntry *abs_die_decl_ctx_die = abs_die->GetParentDeclContextDIE (dwarf2Data, cu);
+ if (abs_die_decl_ctx_die)
+ return abs_die_decl_ctx_die;
+ }
+ }
+
+ die = die->GetParent();
+ }
+ return NULL;
+}
+
+
+const char *
+DWARFDebugInfoEntry::GetQualifiedName (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ std::string &storage) const
+{
+ DWARFDebugInfoEntry::Attributes attributes;
+ GetAttributes(dwarf2Data, cu, NULL, attributes);
+ return GetQualifiedName (dwarf2Data, cu, attributes, storage);
+}
+
+const char*
+DWARFDebugInfoEntry::GetQualifiedName (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry::Attributes& attributes,
+ std::string &storage) const
+{
+
+ const char *name = GetName (dwarf2Data, cu);
+
+ if (name)
+ {
+ const DWARFDebugInfoEntry *parent_decl_ctx_die = GetParentDeclContextDIE (dwarf2Data, cu);
+ storage.clear();
+ // TODO: change this to get the correct decl context parent....
+ while (parent_decl_ctx_die)
+ {
+ const dw_tag_t parent_tag = parent_decl_ctx_die->Tag();
+ switch (parent_tag)
+ {
+ case DW_TAG_namespace:
+ {
+ const char *namespace_name = parent_decl_ctx_die->GetName (dwarf2Data, cu);
+ if (namespace_name)
+ {
+ storage.insert (0, "::");
+ storage.insert (0, namespace_name);
+ }
+ else
+ {
+ storage.insert (0, "(anonymous namespace)::");
+ }
+ parent_decl_ctx_die = parent_decl_ctx_die->GetParentDeclContextDIE(dwarf2Data, cu);
+ }
+ break;
+
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ {
+ const char *class_union_struct_name = parent_decl_ctx_die->GetName (dwarf2Data, cu);
+
+ if (class_union_struct_name)
+ {
+ storage.insert (0, "::");
+ storage.insert (0, class_union_struct_name);
+ }
+ parent_decl_ctx_die = parent_decl_ctx_die->GetParentDeclContextDIE(dwarf2Data, cu);
+ }
+ break;
+
+ default:
+ parent_decl_ctx_die = NULL;
+ break;
+ }
+ }
+
+ if (storage.empty())
+ storage.append ("::");
+
+ storage.append (name);
+ }
+ if (storage.empty())
+ return NULL;
+ return storage.c_str();
+}
+
+
+//----------------------------------------------------------------------
+// LookupAddress
+//----------------------------------------------------------------------
+bool
+DWARFDebugInfoEntry::LookupAddress
+(
+ const dw_addr_t address,
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugInfoEntry** function_die,
+ DWARFDebugInfoEntry** block_die
+)
+{
+ bool found_address = false;
+ if (m_tag)
+ {
+ bool check_children = false;
+ bool match_addr_range = false;
+ // printf("0x%8.8x: %30s: address = 0x%8.8x - ", m_offset, DW_TAG_value_to_name(tag), address);
+ switch (m_tag)
+ {
+ case DW_TAG_array_type : break;
+ case DW_TAG_class_type : check_children = true; break;
+ case DW_TAG_entry_point : break;
+ case DW_TAG_enumeration_type : break;
+ case DW_TAG_formal_parameter : break;
+ case DW_TAG_imported_declaration : break;
+ case DW_TAG_label : break;
+ case DW_TAG_lexical_block : check_children = true; match_addr_range = true; break;
+ case DW_TAG_member : break;
+ case DW_TAG_pointer_type : break;
+ case DW_TAG_reference_type : break;
+ case DW_TAG_compile_unit : match_addr_range = true; break;
+ case DW_TAG_string_type : break;
+ case DW_TAG_structure_type : check_children = true; break;
+ case DW_TAG_subroutine_type : break;
+ case DW_TAG_typedef : break;
+ case DW_TAG_union_type : break;
+ case DW_TAG_unspecified_parameters : break;
+ case DW_TAG_variant : break;
+ case DW_TAG_common_block : check_children = true; break;
+ case DW_TAG_common_inclusion : break;
+ case DW_TAG_inheritance : break;
+ case DW_TAG_inlined_subroutine : check_children = true; match_addr_range = true; break;
+ case DW_TAG_module : match_addr_range = true; break;
+ case DW_TAG_ptr_to_member_type : break;
+ case DW_TAG_set_type : break;
+ case DW_TAG_subrange_type : break;
+ case DW_TAG_with_stmt : break;
+ case DW_TAG_access_declaration : break;
+ case DW_TAG_base_type : break;
+ case DW_TAG_catch_block : match_addr_range = true; break;
+ case DW_TAG_const_type : break;
+ case DW_TAG_constant : break;
+ case DW_TAG_enumerator : break;
+ case DW_TAG_file_type : break;
+ case DW_TAG_friend : break;
+ case DW_TAG_namelist : break;
+ case DW_TAG_namelist_item : break;
+ case DW_TAG_packed_type : break;
+ case DW_TAG_subprogram : match_addr_range = true; break;
+ case DW_TAG_template_type_parameter : break;
+ case DW_TAG_template_value_parameter : break;
+ case DW_TAG_thrown_type : break;
+ case DW_TAG_try_block : match_addr_range = true; break;
+ case DW_TAG_variant_part : break;
+ case DW_TAG_variable : break;
+ case DW_TAG_volatile_type : break;
+ case DW_TAG_dwarf_procedure : break;
+ case DW_TAG_restrict_type : break;
+ case DW_TAG_interface_type : break;
+ case DW_TAG_namespace : check_children = true; break;
+ case DW_TAG_imported_module : break;
+ case DW_TAG_unspecified_type : break;
+ case DW_TAG_partial_unit : break;
+ case DW_TAG_imported_unit : break;
+ case DW_TAG_shared_type : break;
+ default: break;
+ }
+
+ if (match_addr_range)
+ {
+ dw_addr_t lo_pc = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_low_pc, LLDB_INVALID_ADDRESS);
+ if (lo_pc != LLDB_INVALID_ADDRESS)
+ {
+ dw_addr_t hi_pc = GetAttributeHighPC(dwarf2Data, cu, lo_pc, LLDB_INVALID_ADDRESS);
+ if (hi_pc != LLDB_INVALID_ADDRESS)
+ {
+ // printf("\n0x%8.8x: %30s: address = 0x%8.8x [0x%8.8x - 0x%8.8x) ", m_offset, DW_TAG_value_to_name(tag), address, lo_pc, hi_pc);
+ if ((lo_pc <= address) && (address < hi_pc))
+ {
+ found_address = true;
+ // puts("***MATCH***");
+ switch (m_tag)
+ {
+ case DW_TAG_compile_unit: // File
+ check_children = ((function_die != NULL) || (block_die != NULL));
+ break;
+
+ case DW_TAG_subprogram: // Function
+ if (function_die)
+ *function_die = this;
+ check_children = (block_die != NULL);
+ break;
+
+ case DW_TAG_inlined_subroutine: // Inlined Function
+ case DW_TAG_lexical_block: // Block { } in code
+ if (block_die)
+ {
+ *block_die = this;
+ check_children = true;
+ }
+ break;
+
+ default:
+ check_children = true;
+ break;
+ }
+ }
+ }
+ else
+ { // compile units may not have a valid high/low pc when there
+ // are address gaps in subroutines so we must always search
+ // if there is no valid high and low PC
+ check_children = (m_tag == DW_TAG_compile_unit) && ((function_die != NULL) || (block_die != NULL));
+ }
+ }
+ else
+ {
+ dw_offset_t debug_ranges_offset = GetAttributeValueAsUnsigned(dwarf2Data, cu, DW_AT_ranges, DW_INVALID_OFFSET);
+ if (debug_ranges_offset != DW_INVALID_OFFSET)
+ {
+ DWARFDebugRanges::RangeList ranges;
+ DWARFDebugRanges* debug_ranges = dwarf2Data->DebugRanges();
+ debug_ranges->FindRanges(debug_ranges_offset, ranges);
+ // All DW_AT_ranges are relative to the base address of the
+ // compile unit. We add the compile unit base address to make
+ // sure all the addresses are properly fixed up.
+ ranges.Slide (cu->GetBaseAddress());
+ if (ranges.FindEntryThatContains(address))
+ {
+ found_address = true;
+ // puts("***MATCH***");
+ switch (m_tag)
+ {
+ case DW_TAG_compile_unit: // File
+ check_children = ((function_die != NULL) || (block_die != NULL));
+ break;
+
+ case DW_TAG_subprogram: // Function
+ if (function_die)
+ *function_die = this;
+ check_children = (block_die != NULL);
+ break;
+
+ case DW_TAG_inlined_subroutine: // Inlined Function
+ case DW_TAG_lexical_block: // Block { } in code
+ if (block_die)
+ {
+ *block_die = this;
+ check_children = true;
+ }
+ break;
+
+ default:
+ check_children = true;
+ break;
+ }
+ }
+ else
+ {
+ check_children = false;
+ }
+ }
+ }
+ }
+
+
+ if (check_children)
+ {
+ // printf("checking children\n");
+ DWARFDebugInfoEntry* child = GetFirstChild();
+ while (child)
+ {
+ if (child->LookupAddress(address, dwarf2Data, cu, function_die, block_die))
+ return true;
+ child = child->GetSibling();
+ }
+ }
+ }
+ return found_address;
+}
+
+const DWARFAbbreviationDeclaration*
+DWARFDebugInfoEntry::GetAbbreviationDeclarationPtr (SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit *cu,
+ lldb::offset_t &offset) const
+{
+ if (dwarf2Data)
+ {
+ offset = GetOffset();
+
+ const DWARFAbbreviationDeclaration* abbrev_decl = cu->GetAbbreviations()->GetAbbreviationDeclaration (m_abbr_idx);
+ if (abbrev_decl)
+ {
+ // Make sure the abbreviation code still matches. If it doesn't and
+ // the DWARF data was mmap'ed, the backing file might have been modified
+ // which is bad news.
+ const uint64_t abbrev_code = dwarf2Data->get_debug_info_data().GetULEB128 (&offset);
+
+ if (abbrev_decl->Code() == abbrev_code)
+ return abbrev_decl;
+
+ dwarf2Data->GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("0x%8.8x: the DWARF debug information has been modified (abbrev code was %u, and is now %u)",
+ GetOffset(),
+ (uint32_t)abbrev_decl->Code(),
+ (uint32_t)abbrev_code);
+ }
+ }
+ offset = DW_INVALID_OFFSET;
+ return NULL;
+}
+
+
+bool
+DWARFDebugInfoEntry::OffsetLessThan (const DWARFDebugInfoEntry& a, const DWARFDebugInfoEntry& b)
+{
+ return a.GetOffset() < b.GetOffset();
+}
+
+void
+DWARFDebugInfoEntry::DumpDIECollection (Stream &strm, DWARFDebugInfoEntry::collection &die_collection)
+{
+ DWARFDebugInfoEntry::const_iterator pos;
+ DWARFDebugInfoEntry::const_iterator end = die_collection.end();
+ strm.PutCString("\noffset parent sibling child\n");
+ strm.PutCString("-------- -------- -------- --------\n");
+ for (pos = die_collection.begin(); pos != end; ++pos)
+ {
+ const DWARFDebugInfoEntry& die_ref = *pos;
+ const DWARFDebugInfoEntry* p = die_ref.GetParent();
+ const DWARFDebugInfoEntry* s = die_ref.GetSibling();
+ const DWARFDebugInfoEntry* c = die_ref.GetFirstChild();
+ strm.Printf("%.8x: %.8x %.8x %.8x 0x%4.4x %s%s\n",
+ die_ref.GetOffset(),
+ p ? p->GetOffset() : 0,
+ s ? s->GetOffset() : 0,
+ c ? c->GetOffset() : 0,
+ die_ref.Tag(),
+ DW_TAG_value_to_name(die_ref.Tag()),
+ die_ref.HasChildren() ? " *" : "");
+ }
+}
+
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
new file mode 100644
index 000000000000..85f4109ae01a
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugInfoEntry.h
@@ -0,0 +1,457 @@
+//===-- DWARFDebugInfoEntry.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugInfoEntry_h_
+#define SymbolFileDWARF_DWARFDebugInfoEntry_h_
+
+#include "SymbolFileDWARF.h"
+#include "llvm/ADT/SmallVector.h"
+
+#include "DWARFDebugAbbrev.h"
+#include "DWARFAbbreviationDeclaration.h"
+#include "DWARFDebugRanges.h"
+#include <vector>
+#include <map>
+#include <set>
+
+typedef std::map<const DWARFDebugInfoEntry*, dw_addr_t> DIEToAddressMap;
+typedef DIEToAddressMap::iterator DIEToAddressMapIter;
+typedef DIEToAddressMap::const_iterator DIEToAddressMapConstIter;
+
+typedef std::map<dw_addr_t, const DWARFDebugInfoEntry*> AddressToDIEMap;
+typedef AddressToDIEMap::iterator AddressToDIEMapIter;
+typedef AddressToDIEMap::const_iterator AddressToDIEMapConstIter;
+
+
+typedef std::map<dw_offset_t, dw_offset_t> DIEToDIEMap;
+typedef DIEToDIEMap::iterator DIEToDIEMapIter;
+typedef DIEToDIEMap::const_iterator DIEToDIEMapConstIter;
+
+typedef std::map<uint32_t, const DWARFDebugInfoEntry*> UInt32ToDIEMap;
+typedef UInt32ToDIEMap::iterator UInt32ToDIEMapIter;
+typedef UInt32ToDIEMap::const_iterator UInt32ToDIEMapConstIter;
+
+typedef std::multimap<uint32_t, const DWARFDebugInfoEntry*> UInt32ToDIEMMap;
+typedef UInt32ToDIEMMap::iterator UInt32ToDIEMMapIter;
+typedef UInt32ToDIEMMap::const_iterator UInt32ToDIEMMapConstIter;
+
+class DWARFDeclContext;
+
+#define DIE_SIBLING_IDX_BITSIZE 31
+#define DIE_ABBR_IDX_BITSIZE 15
+
+class DWARFDebugInfoEntry
+{
+public:
+ typedef std::vector<DWARFDebugInfoEntry> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ typedef std::vector<dw_offset_t> offset_collection;
+ typedef offset_collection::iterator offset_collection_iterator;
+ typedef offset_collection::const_iterator offset_collection_const_iterator;
+
+ class Attributes
+ {
+ public:
+ Attributes();
+ ~Attributes();
+
+ void Append(const DWARFCompileUnit *cu, dw_offset_t attr_die_offset, dw_attr_t attr, dw_form_t form);
+ const DWARFCompileUnit * CompileUnitAtIndex(uint32_t i) const { return m_infos[i].cu; }
+ dw_offset_t DIEOffsetAtIndex(uint32_t i) const { return m_infos[i].die_offset; }
+ dw_attr_t AttributeAtIndex(uint32_t i) const { return m_infos[i].attr; }
+ dw_attr_t FormAtIndex(uint32_t i) const { return m_infos[i].form; }
+ bool ExtractFormValueAtIndex (SymbolFileDWARF* dwarf2Data, uint32_t i, DWARFFormValue &form_value) const;
+ uint64_t FormValueAsUnsignedAtIndex (SymbolFileDWARF* dwarf2Data, uint32_t i, uint64_t fail_value) const;
+ uint64_t FormValueAsUnsigned (SymbolFileDWARF* dwarf2Data, dw_attr_t attr, uint64_t fail_value) const;
+ uint32_t FindAttributeIndex(dw_attr_t attr) const;
+ bool ContainsAttribute(dw_attr_t attr) const;
+ bool RemoveAttribute(dw_attr_t attr);
+ void Clear() { m_infos.clear(); }
+ size_t Size() const { return m_infos.size(); }
+
+ protected:
+ struct Info
+ {
+ const DWARFCompileUnit *cu; // Keep the compile unit with each attribute in case we have DW_FORM_ref_addr values
+ dw_offset_t die_offset;
+ dw_attr_t attr;
+ dw_form_t form;
+ };
+
+ typedef llvm::SmallVector<Info, 32> collection;
+ collection m_infos;
+ };
+
+ struct CompareState
+ {
+ CompareState() :
+ die_offset_pairs()
+ {
+ assert(sizeof(dw_offset_t)*2 == sizeof(uint64_t));
+ }
+
+ bool AddTypePair(dw_offset_t a, dw_offset_t b)
+ {
+ uint64_t a_b_offsets = (uint64_t)a << 32 | (uint64_t)b;
+ // Return true if this type was inserted, false otherwise
+ return die_offset_pairs.insert(a_b_offsets).second;
+ }
+ std::set< uint64_t > die_offset_pairs;
+ };
+
+ DWARFDebugInfoEntry():
+ m_offset (DW_INVALID_OFFSET),
+ m_parent_idx (0),
+ m_sibling_idx (0),
+ m_empty_children(false),
+ m_abbr_idx (0),
+ m_has_children (false),
+ m_tag (0)
+ {
+ }
+
+ void Clear ()
+ {
+ m_offset = DW_INVALID_OFFSET;
+ m_parent_idx = 0;
+ m_sibling_idx = 0;
+ m_empty_children = false;
+ m_abbr_idx = 0;
+ m_has_children = false;
+ m_tag = 0;
+ }
+
+ bool Contains (const DWARFDebugInfoEntry *die) const;
+
+ void BuildAddressRangeTable(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugAranges* debug_aranges) const;
+
+ void BuildFunctionAddressRangeTable(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugAranges* debug_aranges) const;
+
+ bool FastExtract(
+ const lldb_private::DataExtractor& debug_info_data,
+ const DWARFCompileUnit* cu,
+ const uint8_t *fixed_form_sizes,
+ lldb::offset_t* offset_ptr);
+
+ bool Extract(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ lldb::offset_t* offset_ptr);
+
+ bool LookupAddress(
+ const dw_addr_t address,
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ DWARFDebugInfoEntry** function_die,
+ DWARFDebugInfoEntry** block_die);
+
+ size_t GetAttributes(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const uint8_t *fixed_form_sizes,
+ DWARFDebugInfoEntry::Attributes& attrs,
+ uint32_t curr_depth = 0) const; // "curr_depth" for internal use only, don't set this yourself!!!
+
+ dw_offset_t GetAttributeValue(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ DWARFFormValue& formValue,
+ dw_offset_t* end_attr_offset_ptr = NULL) const;
+
+ const char* GetAttributeValueAsString(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ const char* fail_value) const;
+
+ uint64_t GetAttributeValueAsUnsigned(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ uint64_t fail_value) const;
+
+ uint64_t GetAttributeValueAsReference(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ uint64_t fail_value) const;
+
+ int64_t GetAttributeValueAsSigned(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ int64_t fail_value) const;
+
+ dw_addr_t GetAttributeHighPC(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ dw_addr_t lo_pc,
+ uint64_t fail_value) const;
+
+ bool GetAttributeAddressRange(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ dw_addr_t& lo_pc,
+ dw_addr_t& hi_pc,
+ uint64_t fail_value) const;
+
+ dw_offset_t GetAttributeValueAsLocation(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_attr_t attr,
+ lldb_private::DataExtractor& data,
+ uint32_t &block_size) const;
+
+ const char* GetName(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu) const;
+
+ const char* GetMangledName(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ bool substitute_name_allowed = true) const;
+
+ const char* GetPubname(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu) const;
+
+ static bool GetName(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_offset_t die_offset,
+ lldb_private::Stream &s);
+
+ static bool AppendTypeName(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const dw_offset_t die_offset,
+ lldb_private::Stream &s);
+
+ const char * GetQualifiedName (
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ std::string &storage) const;
+
+ const char * GetQualifiedName (
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry::Attributes& attributes,
+ std::string &storage) const;
+
+// static int Compare(
+// SymbolFileDWARF* dwarf2Data,
+// dw_offset_t a_die_offset,
+// dw_offset_t b_die_offset,
+// CompareState &compare_state,
+// bool compare_siblings,
+// bool compare_children);
+//
+// static int Compare(
+// SymbolFileDWARF* dwarf2Data,
+// DWARFCompileUnit* a_cu, const DWARFDebugInfoEntry* a_die,
+// DWARFCompileUnit* b_cu, const DWARFDebugInfoEntry* b_die,
+// CompareState &compare_state,
+// bool compare_siblings,
+// bool compare_children);
+
+ static bool OffsetLessThan (
+ const DWARFDebugInfoEntry& a,
+ const DWARFDebugInfoEntry& b);
+
+ void Dump(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ lldb_private::Stream &s,
+ uint32_t recurse_depth) const;
+
+ void DumpAncestry(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry* oldest,
+ lldb_private::Stream &s,
+ uint32_t recurse_depth) const;
+
+ static void DumpAttribute(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const lldb_private::DataExtractor& debug_info_data,
+ lldb::offset_t *offset_ptr,
+ lldb_private::Stream &s,
+ dw_attr_t attr,
+ dw_form_t form);
+ // This one dumps the comp unit name, objfile name and die offset for this die so the stream S.
+ void DumpLocation(
+ SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ lldb_private::Stream &s) const;
+
+ bool GetDIENamesAndRanges(
+ SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const char * &name,
+ const char * &mangled,
+ DWARFDebugRanges::RangeList& rangeList,
+ int& decl_file,
+ int& decl_line,
+ int& decl_column,
+ int& call_file,
+ int& call_line,
+ int& call_column,
+ lldb_private::DWARFExpression *frame_base = NULL) const;
+
+ const DWARFAbbreviationDeclaration*
+ GetAbbreviationDeclarationPtr (SymbolFileDWARF* dwarf2Data,
+ const DWARFCompileUnit *cu,
+ lldb::offset_t &offset) const;
+
+ dw_tag_t
+ Tag () const
+ {
+ return m_tag;
+ }
+
+ bool
+ IsNULL() const
+ {
+ return m_abbr_idx == 0;
+ }
+
+ dw_offset_t
+ GetOffset () const
+ {
+ return m_offset;
+ }
+
+ void
+ SetOffset (dw_offset_t offset)
+ {
+ m_offset = offset;
+ }
+
+ bool
+ HasChildren () const
+ {
+ return m_has_children;
+ }
+
+ void
+ SetHasChildren (bool b)
+ {
+ m_has_children = b;
+ }
+
+ // We know we are kept in a vector of contiguous entries, so we know
+ // our parent will be some index behind "this".
+ DWARFDebugInfoEntry* GetParent() { return m_parent_idx > 0 ? this - m_parent_idx : NULL; }
+ const DWARFDebugInfoEntry* GetParent() const { return m_parent_idx > 0 ? this - m_parent_idx : NULL; }
+ // We know we are kept in a vector of contiguous entries, so we know
+ // our sibling will be some index after "this".
+ DWARFDebugInfoEntry* GetSibling() { return m_sibling_idx > 0 ? this + m_sibling_idx : NULL; }
+ const DWARFDebugInfoEntry* GetSibling() const { return m_sibling_idx > 0 ? this + m_sibling_idx : NULL; }
+ // We know we are kept in a vector of contiguous entries, so we know
+ // we don't need to store our child pointer, if we have a child it will
+ // be the next entry in the list...
+ DWARFDebugInfoEntry* GetFirstChild() { return (HasChildren() && !m_empty_children) ? this + 1 : NULL; }
+ const DWARFDebugInfoEntry* GetFirstChild() const { return (HasChildren() && !m_empty_children) ? this + 1 : NULL; }
+
+
+ void GetDeclContextDIEs (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ DWARFDIECollection &decl_context_dies) const;
+
+ void GetDWARFDeclContext (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ DWARFDeclContext &dwarf_decl_ctx) const;
+
+
+ bool MatchesDWARFDeclContext(SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ const DWARFDeclContext &dwarf_decl_ctx) const;
+
+ const DWARFDebugInfoEntry* GetParentDeclContextDIE (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu) const;
+ const DWARFDebugInfoEntry* GetParentDeclContextDIE (SymbolFileDWARF* dwarf2Data,
+ DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry::Attributes& attributes) const;
+
+ void
+ SetParent (DWARFDebugInfoEntry* parent)
+ {
+ if (parent)
+ {
+ // We know we are kept in a vector of contiguous entries, so we know
+ // our parent will be some index behind "this".
+ m_parent_idx = this - parent;
+ }
+ else
+ m_parent_idx = 0;
+ }
+ void
+ SetSibling (DWARFDebugInfoEntry* sibling)
+ {
+ if (sibling)
+ {
+ // We know we are kept in a vector of contiguous entries, so we know
+ // our sibling will be some index after "this".
+ m_sibling_idx = sibling - this;
+ sibling->SetParent(GetParent());
+ }
+ else
+ m_sibling_idx = 0;
+ }
+
+ void
+ SetSiblingIndex (uint32_t idx)
+ {
+ m_sibling_idx = idx;
+ }
+
+ void
+ SetParentIndex (uint32_t idx)
+ {
+ m_parent_idx = idx;
+ }
+
+ bool
+ GetEmptyChildren () const
+ {
+ return m_empty_children;
+ }
+
+ void
+ SetEmptyChildren (bool b)
+ {
+ m_empty_children = b;
+ }
+
+ static void
+ DumpDIECollection (lldb_private::Stream &strm,
+ DWARFDebugInfoEntry::collection &die_collection);
+
+protected:
+ dw_offset_t m_offset; // Offset within the .debug_info of the start of this entry
+ uint32_t m_parent_idx; // How many to subtract from "this" to get the parent. If zero this die has no parent
+ uint32_t m_sibling_idx:31, // How many to add to "this" to get the sibling.
+ m_empty_children:1; // If a DIE says it had children, yet it just contained a NULL tag, this will be set.
+ uint32_t m_abbr_idx:DIE_ABBR_IDX_BITSIZE,
+ m_has_children:1, // Set to 1 if this DIE has children
+ m_tag:16; // A copy of the DW_TAG value so we don't have to go through the compile unit abbrev table
+
+};
+
+#endif // SymbolFileDWARF_DWARFDebugInfoEntry_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
new file mode 100644
index 000000000000..6c9336a08426
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.cpp
@@ -0,0 +1,1436 @@
+//===-- DWARFDebugLine.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugLine.h"
+
+//#define ENABLE_DEBUG_PRINTF // DO NOT LEAVE THIS DEFINED: DEBUG ONLY!!!
+#include <assert.h>
+
+#include "lldb/Core/FileSpecList.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+
+#include "SymbolFileDWARF.h"
+#include "LogChannelDWARF.h"
+
+using namespace lldb;
+using namespace lldb_private;
+using namespace std;
+
+//----------------------------------------------------------------------
+// Parse
+//
+// Parse all information in the debug_line_data into an internal
+// representation.
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Parse(const DataExtractor& debug_line_data)
+{
+ m_lineTableMap.clear();
+ lldb::offset_t offset = 0;
+ LineTable::shared_ptr line_table_sp(new LineTable);
+ while (debug_line_data.ValidOffset(offset))
+ {
+ const lldb::offset_t debug_line_offset = offset;
+
+ if (line_table_sp.get() == NULL)
+ break;
+
+ if (ParseStatementTable(debug_line_data, &offset, line_table_sp.get()))
+ {
+ // Make sure we don't don't loop infinitely
+ if (offset <= debug_line_offset)
+ break;
+ //DEBUG_PRINTF("m_lineTableMap[0x%8.8x] = line_table_sp\n", debug_line_offset);
+ m_lineTableMap[debug_line_offset] = line_table_sp;
+ line_table_sp.reset(new LineTable);
+ }
+ else
+ ++offset; // Try next byte in line table
+ }
+}
+
+void
+DWARFDebugLine::ParseIfNeeded(const DataExtractor& debug_line_data)
+{
+ if (m_lineTableMap.empty())
+ Parse(debug_line_data);
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::GetLineTable
+//----------------------------------------------------------------------
+DWARFDebugLine::LineTable::shared_ptr
+DWARFDebugLine::GetLineTable(const dw_offset_t offset) const
+{
+ DWARFDebugLine::LineTable::shared_ptr line_table_shared_ptr;
+ LineTableConstIter pos = m_lineTableMap.find(offset);
+ if (pos != m_lineTableMap.end())
+ line_table_shared_ptr = pos->second;
+ return line_table_shared_ptr;
+}
+
+
+//----------------------------------------------------------------------
+// DumpStateToFile
+//----------------------------------------------------------------------
+static void
+DumpStateToFile (dw_offset_t offset, const DWARFDebugLine::State& state, void* userData)
+{
+ Log *log = (Log *)userData;
+ if (state.row == DWARFDebugLine::State::StartParsingLineTable)
+ {
+ // If the row is zero we are being called with the prologue only
+ state.prologue->Dump (log);
+ log->PutCString ("Address Line Column File");
+ log->PutCString ("------------------ ------ ------ ------");
+ }
+ else if (state.row == DWARFDebugLine::State::DoneParsingLineTable)
+ {
+ // Done parsing line table
+ }
+ else
+ {
+ log->Printf( "0x%16.16" PRIx64 " %6u %6u %6u%s\n", state.address, state.line, state.column, state.file, state.end_sequence ? " END" : "");
+ }
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::DumpLineTableRows
+//----------------------------------------------------------------------
+bool
+DWARFDebugLine::DumpLineTableRows(Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t debug_line_offset)
+{
+ const DataExtractor& debug_line_data = dwarf2Data->get_debug_line_data();
+
+ if (debug_line_offset == DW_INVALID_OFFSET)
+ {
+ // Dump line table to a single file only
+ debug_line_offset = 0;
+ while (debug_line_data.ValidOffset(debug_line_offset))
+ debug_line_offset = DumpStatementTable (log, debug_line_data, debug_line_offset);
+ }
+ else
+ {
+ // Dump line table to a single file only
+ DumpStatementTable (log, debug_line_data, debug_line_offset);
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::DumpStatementTable
+//----------------------------------------------------------------------
+dw_offset_t
+DWARFDebugLine::DumpStatementTable(Log *log, const DataExtractor& debug_line_data, const dw_offset_t debug_line_offset)
+{
+ if (debug_line_data.ValidOffset(debug_line_offset))
+ {
+ lldb::offset_t offset = debug_line_offset;
+ log->Printf( "----------------------------------------------------------------------\n"
+ "debug_line[0x%8.8x]\n"
+ "----------------------------------------------------------------------\n", debug_line_offset);
+
+ if (ParseStatementTable(debug_line_data, &offset, DumpStateToFile, log))
+ return offset;
+ else
+ return debug_line_offset + 1; // Skip to next byte in .debug_line section
+ }
+
+ return DW_INVALID_OFFSET;
+}
+
+
+//----------------------------------------------------------------------
+// DumpOpcodes
+//----------------------------------------------------------------------
+bool
+DWARFDebugLine::DumpOpcodes(Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t debug_line_offset, uint32_t dump_flags)
+{
+ const DataExtractor& debug_line_data = dwarf2Data->get_debug_line_data();
+
+ if (debug_line_data.GetByteSize() == 0)
+ {
+ log->Printf( "< EMPTY >\n");
+ return false;
+ }
+
+ if (debug_line_offset == DW_INVALID_OFFSET)
+ {
+ // Dump line table to a single file only
+ debug_line_offset = 0;
+ while (debug_line_data.ValidOffset(debug_line_offset))
+ debug_line_offset = DumpStatementOpcodes (log, debug_line_data, debug_line_offset, dump_flags);
+ }
+ else
+ {
+ // Dump line table to a single file only
+ DumpStatementOpcodes (log, debug_line_data, debug_line_offset, dump_flags);
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// DumpStatementOpcodes
+//----------------------------------------------------------------------
+dw_offset_t
+DWARFDebugLine::DumpStatementOpcodes(Log *log, const DataExtractor& debug_line_data, const dw_offset_t debug_line_offset, uint32_t flags)
+{
+ lldb::offset_t offset = debug_line_offset;
+ if (debug_line_data.ValidOffset(offset))
+ {
+ Prologue prologue;
+
+ if (ParsePrologue(debug_line_data, &offset, &prologue))
+ {
+ log->PutCString ("----------------------------------------------------------------------");
+ log->Printf ("debug_line[0x%8.8x]", debug_line_offset);
+ log->PutCString ("----------------------------------------------------------------------\n");
+ prologue.Dump (log);
+ }
+ else
+ {
+ offset = debug_line_offset;
+ log->Printf( "0x%8.8" PRIx64 ": skipping pad byte %2.2x", offset, debug_line_data.GetU8(&offset));
+ return offset;
+ }
+
+ Row row(prologue.default_is_stmt);
+ const dw_offset_t end_offset = debug_line_offset + prologue.total_length + sizeof(prologue.total_length);
+
+ assert(debug_line_data.ValidOffset(end_offset-1));
+
+ while (offset < end_offset)
+ {
+ const uint32_t op_offset = offset;
+ uint8_t opcode = debug_line_data.GetU8(&offset);
+ switch (opcode)
+ {
+ case 0: // Extended Opcodes always start with a zero opcode followed by
+ { // a uleb128 length so you can skip ones you don't know about
+
+ dw_offset_t ext_offset = offset;
+ dw_uleb128_t len = debug_line_data.GetULEB128(&offset);
+ dw_offset_t arg_size = len - (offset - ext_offset);
+ uint8_t sub_opcode = debug_line_data.GetU8(&offset);
+// if (verbose)
+// log->Printf( "Extended: <%u> %2.2x ", len, sub_opcode);
+
+ switch (sub_opcode)
+ {
+ case DW_LNE_end_sequence :
+ log->Printf( "0x%8.8x: DW_LNE_end_sequence", op_offset);
+ row.Dump(log);
+ row.Reset(prologue.default_is_stmt);
+ break;
+
+ case DW_LNE_set_address :
+ {
+ row.address = debug_line_data.GetMaxU64(&offset, arg_size);
+ log->Printf( "0x%8.8x: DW_LNE_set_address (0x%" PRIx64 ")", op_offset, row.address);
+ }
+ break;
+
+ case DW_LNE_define_file:
+ {
+ FileNameEntry fileEntry;
+ fileEntry.name = debug_line_data.GetCStr(&offset);
+ fileEntry.dir_idx = debug_line_data.GetULEB128(&offset);
+ fileEntry.mod_time = debug_line_data.GetULEB128(&offset);
+ fileEntry.length = debug_line_data.GetULEB128(&offset);
+ log->Printf( "0x%8.8x: DW_LNE_define_file('%s', dir=%i, mod_time=0x%8.8x, length=%i )",
+ op_offset,
+ fileEntry.name.c_str(),
+ fileEntry.dir_idx,
+ fileEntry.mod_time,
+ fileEntry.length);
+ prologue.file_names.push_back(fileEntry);
+ }
+ break;
+
+ default:
+ log->Printf( "0x%8.8x: DW_LNE_??? (%2.2x) - Skipping unknown upcode", op_offset, opcode);
+ // Length doesn't include the zero opcode byte or the length itself, but
+ // it does include the sub_opcode, so we have to adjust for that below
+ offset += arg_size;
+ break;
+ }
+ }
+ break;
+
+ // Standard Opcodes
+ case DW_LNS_copy:
+ log->Printf( "0x%8.8x: DW_LNS_copy", op_offset);
+ row.Dump (log);
+ break;
+
+ case DW_LNS_advance_pc:
+ {
+ dw_uleb128_t addr_offset_n = debug_line_data.GetULEB128(&offset);
+ dw_uleb128_t addr_offset = addr_offset_n * prologue.min_inst_length;
+ log->Printf( "0x%8.8x: DW_LNS_advance_pc (0x%x)", op_offset, addr_offset);
+ row.address += addr_offset;
+ }
+ break;
+
+ case DW_LNS_advance_line:
+ {
+ dw_sleb128_t line_offset = debug_line_data.GetSLEB128(&offset);
+ log->Printf( "0x%8.8x: DW_LNS_advance_line (%i)", op_offset, line_offset);
+ row.line += line_offset;
+ }
+ break;
+
+ case DW_LNS_set_file:
+ row.file = debug_line_data.GetULEB128(&offset);
+ log->Printf( "0x%8.8x: DW_LNS_set_file (%u)", op_offset, row.file);
+ break;
+
+ case DW_LNS_set_column:
+ row.column = debug_line_data.GetULEB128(&offset);
+ log->Printf( "0x%8.8x: DW_LNS_set_column (%u)", op_offset, row.column);
+ break;
+
+ case DW_LNS_negate_stmt:
+ row.is_stmt = !row.is_stmt;
+ log->Printf( "0x%8.8x: DW_LNS_negate_stmt", op_offset);
+ break;
+
+ case DW_LNS_set_basic_block:
+ row.basic_block = true;
+ log->Printf( "0x%8.8x: DW_LNS_set_basic_block", op_offset);
+ break;
+
+ case DW_LNS_const_add_pc:
+ {
+ uint8_t adjust_opcode = 255 - prologue.opcode_base;
+ dw_addr_t addr_offset = (adjust_opcode / prologue.line_range) * prologue.min_inst_length;
+ log->Printf( "0x%8.8x: DW_LNS_const_add_pc (0x%8.8" PRIx64 ")", op_offset, addr_offset);
+ row.address += addr_offset;
+ }
+ break;
+
+ case DW_LNS_fixed_advance_pc:
+ {
+ uint16_t pc_offset = debug_line_data.GetU16(&offset);
+ log->Printf( "0x%8.8x: DW_LNS_fixed_advance_pc (0x%4.4x)", op_offset, pc_offset);
+ row.address += pc_offset;
+ }
+ break;
+
+ case DW_LNS_set_prologue_end:
+ row.prologue_end = true;
+ log->Printf( "0x%8.8x: DW_LNS_set_prologue_end", op_offset);
+ break;
+
+ case DW_LNS_set_epilogue_begin:
+ row.epilogue_begin = true;
+ log->Printf( "0x%8.8x: DW_LNS_set_epilogue_begin", op_offset);
+ break;
+
+ case DW_LNS_set_isa:
+ row.isa = debug_line_data.GetULEB128(&offset);
+ log->Printf( "0x%8.8x: DW_LNS_set_isa (%u)", op_offset, row.isa);
+ break;
+
+ // Special Opcodes
+ default:
+ if (opcode < prologue.opcode_base)
+ {
+ // We have an opcode that this parser doesn't know about, skip
+ // the number of ULEB128 numbers that is says to skip in the
+ // prologue's standard_opcode_lengths array
+ uint8_t n = prologue.standard_opcode_lengths[opcode-1];
+ log->Printf( "0x%8.8x: Special : Unknown skipping %u ULEB128 values.", op_offset, n);
+ while (n > 0)
+ {
+ debug_line_data.GetULEB128(&offset);
+ --n;
+ }
+ }
+ else
+ {
+ uint8_t adjust_opcode = opcode - prologue.opcode_base;
+ dw_addr_t addr_offset = (adjust_opcode / prologue.line_range) * prologue.min_inst_length;
+ int32_t line_offset = prologue.line_base + (adjust_opcode % prologue.line_range);
+ log->Printf("0x%8.8x: address += 0x%" PRIx64 ", line += %i\n", op_offset, (uint64_t)addr_offset, line_offset);
+ row.address += addr_offset;
+ row.line += line_offset;
+ row.Dump (log);
+ }
+ break;
+ }
+ }
+ return end_offset;
+ }
+ return DW_INVALID_OFFSET;
+}
+
+
+
+
+//----------------------------------------------------------------------
+// Parse
+//
+// Parse the entire line table contents calling callback each time a
+// new prologue is parsed and every time a new row is to be added to
+// the line table.
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Parse(const DataExtractor& debug_line_data, DWARFDebugLine::State::Callback callback, void* userData)
+{
+ lldb::offset_t offset = 0;
+ if (debug_line_data.ValidOffset(offset))
+ {
+ if (!ParseStatementTable(debug_line_data, &offset, callback, userData))
+ ++offset; // Skip to next byte in .debug_line section
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::ParsePrologue
+//----------------------------------------------------------------------
+bool
+DWARFDebugLine::ParsePrologue(const DataExtractor& debug_line_data, lldb::offset_t* offset_ptr, Prologue* prologue)
+{
+ const lldb::offset_t prologue_offset = *offset_ptr;
+
+ //DEBUG_PRINTF("0x%8.8x: ParsePrologue()\n", *offset_ptr);
+
+ prologue->Clear();
+ uint32_t i;
+ const char * s;
+ prologue->total_length = debug_line_data.GetU32(offset_ptr);
+ prologue->version = debug_line_data.GetU16(offset_ptr);
+ if (prologue->version != 2)
+ return false;
+
+ prologue->prologue_length = debug_line_data.GetU32(offset_ptr);
+ const lldb::offset_t end_prologue_offset = prologue->prologue_length + *offset_ptr;
+ prologue->min_inst_length = debug_line_data.GetU8(offset_ptr);
+ prologue->default_is_stmt = debug_line_data.GetU8(offset_ptr);
+ prologue->line_base = debug_line_data.GetU8(offset_ptr);
+ prologue->line_range = debug_line_data.GetU8(offset_ptr);
+ prologue->opcode_base = debug_line_data.GetU8(offset_ptr);
+
+ prologue->standard_opcode_lengths.reserve(prologue->opcode_base-1);
+
+ for (i=1; i<prologue->opcode_base; ++i)
+ {
+ uint8_t op_len = debug_line_data.GetU8(offset_ptr);
+ prologue->standard_opcode_lengths.push_back(op_len);
+ }
+
+ while (*offset_ptr < end_prologue_offset)
+ {
+ s = debug_line_data.GetCStr(offset_ptr);
+ if (s && s[0])
+ prologue->include_directories.push_back(s);
+ else
+ break;
+ }
+
+ while (*offset_ptr < end_prologue_offset)
+ {
+ const char* name = debug_line_data.GetCStr( offset_ptr );
+ if (name && name[0])
+ {
+ FileNameEntry fileEntry;
+ fileEntry.name = name;
+ fileEntry.dir_idx = debug_line_data.GetULEB128( offset_ptr );
+ fileEntry.mod_time = debug_line_data.GetULEB128( offset_ptr );
+ fileEntry.length = debug_line_data.GetULEB128( offset_ptr );
+ prologue->file_names.push_back(fileEntry);
+ }
+ else
+ break;
+ }
+
+ if (*offset_ptr != end_prologue_offset)
+ {
+ Host::SystemLog (Host::eSystemLogWarning,
+ "warning: parsing line table prologue at 0x%8.8" PRIx64 " should have ended at 0x%8.8" PRIx64 " but it ended ad 0x%8.8" PRIx64 "\n",
+ prologue_offset,
+ end_prologue_offset,
+ *offset_ptr);
+ }
+ return end_prologue_offset;
+}
+
+bool
+DWARFDebugLine::ParseSupportFiles (const lldb::ModuleSP &module_sp,
+ const DataExtractor& debug_line_data,
+ const char *cu_comp_dir,
+ dw_offset_t stmt_list,
+ FileSpecList &support_files)
+{
+ lldb::offset_t offset = stmt_list + 4; // Skip the total length
+ const char * s;
+ uint32_t version = debug_line_data.GetU16(&offset);
+ if (version != 2)
+ return false;
+
+ const dw_offset_t end_prologue_offset = debug_line_data.GetU32(&offset) + offset;
+ // Skip instruction length, default is stmt, line base, line range and
+ // opcode base, and all opcode lengths
+ offset += 4;
+ const uint8_t opcode_base = debug_line_data.GetU8(&offset);
+ offset += opcode_base - 1;
+ std::vector<std::string> include_directories;
+ include_directories.push_back(""); // Directory at index zero doesn't exist
+ while (offset < end_prologue_offset)
+ {
+ s = debug_line_data.GetCStr(&offset);
+ if (s && s[0])
+ include_directories.push_back(s);
+ else
+ break;
+ }
+ std::string fullpath;
+ std::string remapped_fullpath;
+ while (offset < end_prologue_offset)
+ {
+ const char* path = debug_line_data.GetCStr( &offset );
+ if (path && path[0])
+ {
+ uint32_t dir_idx = debug_line_data.GetULEB128( &offset );
+ debug_line_data.Skip_LEB128(&offset); // Skip mod_time
+ debug_line_data.Skip_LEB128(&offset); // Skip length
+
+ if (path[0] == '/')
+ {
+ // The path starts with a directory delimiter, so we are done.
+ if (module_sp->RemapSourceFile (path, fullpath))
+ support_files.Append(FileSpec (fullpath.c_str(), false));
+ else
+ support_files.Append(FileSpec (path, false));
+ }
+ else
+ {
+ if (dir_idx > 0 && dir_idx < include_directories.size())
+ {
+ if (cu_comp_dir && include_directories[dir_idx][0] != '/')
+ {
+ fullpath = cu_comp_dir;
+
+ if (*fullpath.rbegin() != '/')
+ fullpath += '/';
+ fullpath += include_directories[dir_idx];
+
+ }
+ else
+ fullpath = include_directories[dir_idx];
+ }
+ else if (cu_comp_dir && cu_comp_dir[0])
+ {
+ fullpath = cu_comp_dir;
+ }
+
+ if (!fullpath.empty())
+ {
+ if (*fullpath.rbegin() != '/')
+ fullpath += '/';
+ }
+ fullpath += path;
+ if (module_sp->RemapSourceFile (fullpath.c_str(), remapped_fullpath))
+ support_files.Append(FileSpec (remapped_fullpath.c_str(), false));
+ else
+ support_files.Append(FileSpec (fullpath.c_str(), false));
+ }
+
+ }
+ }
+
+ if (offset != end_prologue_offset)
+ {
+ Host::SystemLog (Host::eSystemLogError,
+ "warning: parsing line table prologue at 0x%8.8x should have ended at 0x%8.8x but it ended ad 0x%8.8" PRIx64 "\n",
+ stmt_list,
+ end_prologue_offset,
+ offset);
+ }
+ return end_prologue_offset;
+}
+
+//----------------------------------------------------------------------
+// ParseStatementTable
+//
+// Parse a single line table (prologue and all rows) and call the
+// callback function once for the prologue (row in state will be zero)
+// and each time a row is to be added to the line table.
+//----------------------------------------------------------------------
+bool
+DWARFDebugLine::ParseStatementTable
+(
+ const DataExtractor& debug_line_data,
+ lldb::offset_t* offset_ptr,
+ DWARFDebugLine::State::Callback callback,
+ void* userData
+)
+{
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_LINE));
+ Prologue::shared_ptr prologue(new Prologue());
+
+
+ const dw_offset_t debug_line_offset = *offset_ptr;
+
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "DWARFDebugLine::ParseStatementTable (.debug_line[0x%8.8x])",
+ debug_line_offset);
+
+ if (!ParsePrologue(debug_line_data, offset_ptr, prologue.get()))
+ {
+ if (log)
+ log->Error ("failed to parse DWARF line table prologue");
+ // Restore our offset and return false to indicate failure!
+ *offset_ptr = debug_line_offset;
+ return false;
+ }
+
+ if (log)
+ prologue->Dump (log);
+
+ const dw_offset_t end_offset = debug_line_offset + prologue->total_length + sizeof(prologue->total_length);
+
+ State state(prologue, log, callback, userData);
+
+ while (*offset_ptr < end_offset)
+ {
+ //DEBUG_PRINTF("0x%8.8x: ", *offset_ptr);
+ uint8_t opcode = debug_line_data.GetU8(offset_ptr);
+
+ if (opcode == 0)
+ {
+ // Extended Opcodes always start with a zero opcode followed by
+ // a uleb128 length so you can skip ones you don't know about
+ lldb::offset_t ext_offset = *offset_ptr;
+ dw_uleb128_t len = debug_line_data.GetULEB128(offset_ptr);
+ dw_offset_t arg_size = len - (*offset_ptr - ext_offset);
+
+ //DEBUG_PRINTF("Extended: <%2u> ", len);
+ uint8_t sub_opcode = debug_line_data.GetU8(offset_ptr);
+ switch (sub_opcode)
+ {
+ case DW_LNE_end_sequence:
+ // Set the end_sequence register of the state machine to true and
+ // append a row to the matrix using the current values of the
+ // state-machine registers. Then reset the registers to the initial
+ // values specified above. Every statement program sequence must end
+ // with a DW_LNE_end_sequence instruction which creates a row whose
+ // address is that of the byte after the last target machine instruction
+ // of the sequence.
+ state.end_sequence = true;
+ state.AppendRowToMatrix(*offset_ptr);
+ state.Reset();
+ break;
+
+ case DW_LNE_set_address:
+ // Takes a single relocatable address as an operand. The size of the
+ // operand is the size appropriate to hold an address on the target
+ // machine. Set the address register to the value given by the
+ // relocatable address. All of the other statement program opcodes
+ // that affect the address register add a delta to it. This instruction
+ // stores a relocatable value into it instead.
+ state.address = debug_line_data.GetAddress(offset_ptr);
+ break;
+
+ case DW_LNE_define_file:
+ // Takes 4 arguments. The first is a null terminated string containing
+ // a source file name. The second is an unsigned LEB128 number representing
+ // the directory index of the directory in which the file was found. The
+ // third is an unsigned LEB128 number representing the time of last
+ // modification of the file. The fourth is an unsigned LEB128 number
+ // representing the length in bytes of the file. The time and length
+ // fields may contain LEB128(0) if the information is not available.
+ //
+ // The directory index represents an entry in the include_directories
+ // section of the statement program prologue. The index is LEB128(0)
+ // if the file was found in the current directory of the compilation,
+ // LEB128(1) if it was found in the first directory in the
+ // include_directories section, and so on. The directory index is
+ // ignored for file names that represent full path names.
+ //
+ // The files are numbered, starting at 1, in the order in which they
+ // appear; the names in the prologue come before names defined by
+ // the DW_LNE_define_file instruction. These numbers are used in the
+ // the file register of the state machine.
+ {
+ FileNameEntry fileEntry;
+ fileEntry.name = debug_line_data.GetCStr(offset_ptr);
+ fileEntry.dir_idx = debug_line_data.GetULEB128(offset_ptr);
+ fileEntry.mod_time = debug_line_data.GetULEB128(offset_ptr);
+ fileEntry.length = debug_line_data.GetULEB128(offset_ptr);
+ state.prologue->file_names.push_back(fileEntry);
+ }
+ break;
+
+ default:
+ // Length doesn't include the zero opcode byte or the length itself, but
+ // it does include the sub_opcode, so we have to adjust for that below
+ (*offset_ptr) += arg_size;
+ break;
+ }
+ }
+ else if (opcode < prologue->opcode_base)
+ {
+ switch (opcode)
+ {
+ // Standard Opcodes
+ case DW_LNS_copy:
+ // Takes no arguments. Append a row to the matrix using the
+ // current values of the state-machine registers. Then set
+ // the basic_block register to false.
+ state.AppendRowToMatrix(*offset_ptr);
+ break;
+
+ case DW_LNS_advance_pc:
+ // Takes a single unsigned LEB128 operand, multiplies it by the
+ // min_inst_length field of the prologue, and adds the
+ // result to the address register of the state machine.
+ state.address += debug_line_data.GetULEB128(offset_ptr) * prologue->min_inst_length;
+ break;
+
+ case DW_LNS_advance_line:
+ // Takes a single signed LEB128 operand and adds that value to
+ // the line register of the state machine.
+ state.line += debug_line_data.GetSLEB128(offset_ptr);
+ break;
+
+ case DW_LNS_set_file:
+ // Takes a single unsigned LEB128 operand and stores it in the file
+ // register of the state machine.
+ state.file = debug_line_data.GetULEB128(offset_ptr);
+ break;
+
+ case DW_LNS_set_column:
+ // Takes a single unsigned LEB128 operand and stores it in the
+ // column register of the state machine.
+ state.column = debug_line_data.GetULEB128(offset_ptr);
+ break;
+
+ case DW_LNS_negate_stmt:
+ // Takes no arguments. Set the is_stmt register of the state
+ // machine to the logical negation of its current value.
+ state.is_stmt = !state.is_stmt;
+ break;
+
+ case DW_LNS_set_basic_block:
+ // Takes no arguments. Set the basic_block register of the
+ // state machine to true
+ state.basic_block = true;
+ break;
+
+ case DW_LNS_const_add_pc:
+ // Takes no arguments. Add to the address register of the state
+ // machine the address increment value corresponding to special
+ // opcode 255. The motivation for DW_LNS_const_add_pc is this:
+ // when the statement program needs to advance the address by a
+ // small amount, it can use a single special opcode, which occupies
+ // a single byte. When it needs to advance the address by up to
+ // twice the range of the last special opcode, it can use
+ // DW_LNS_const_add_pc followed by a special opcode, for a total
+ // of two bytes. Only if it needs to advance the address by more
+ // than twice that range will it need to use both DW_LNS_advance_pc
+ // and a special opcode, requiring three or more bytes.
+ {
+ uint8_t adjust_opcode = 255 - prologue->opcode_base;
+ dw_addr_t addr_offset = (adjust_opcode / prologue->line_range) * prologue->min_inst_length;
+ state.address += addr_offset;
+ }
+ break;
+
+ case DW_LNS_fixed_advance_pc:
+ // Takes a single uhalf operand. Add to the address register of
+ // the state machine the value of the (unencoded) operand. This
+ // is the only extended opcode that takes an argument that is not
+ // a variable length number. The motivation for DW_LNS_fixed_advance_pc
+ // is this: existing assemblers cannot emit DW_LNS_advance_pc or
+ // special opcodes because they cannot encode LEB128 numbers or
+ // judge when the computation of a special opcode overflows and
+ // requires the use of DW_LNS_advance_pc. Such assemblers, however,
+ // can use DW_LNS_fixed_advance_pc instead, sacrificing compression.
+ state.address += debug_line_data.GetU16(offset_ptr);
+ break;
+
+ case DW_LNS_set_prologue_end:
+ // Takes no arguments. Set the prologue_end register of the
+ // state machine to true
+ state.prologue_end = true;
+ break;
+
+ case DW_LNS_set_epilogue_begin:
+ // Takes no arguments. Set the basic_block register of the
+ // state machine to true
+ state.epilogue_begin = true;
+ break;
+
+ case DW_LNS_set_isa:
+ // Takes a single unsigned LEB128 operand and stores it in the
+ // column register of the state machine.
+ state.isa = debug_line_data.GetULEB128(offset_ptr);
+ break;
+
+ default:
+ // Handle any unknown standard opcodes here. We know the lengths
+ // of such opcodes because they are specified in the prologue
+ // as a multiple of LEB128 operands for each opcode.
+ {
+ uint8_t i;
+ assert (opcode - 1 < prologue->standard_opcode_lengths.size());
+ const uint8_t opcode_length = prologue->standard_opcode_lengths[opcode - 1];
+ for (i=0; i<opcode_length; ++i)
+ debug_line_data.Skip_LEB128(offset_ptr);
+ }
+ break;
+ }
+ }
+ else
+ {
+ // Special Opcodes
+
+ // A special opcode value is chosen based on the amount that needs
+ // to be added to the line and address registers. The maximum line
+ // increment for a special opcode is the value of the line_base
+ // field in the header, plus the value of the line_range field,
+ // minus 1 (line base + line range - 1). If the desired line
+ // increment is greater than the maximum line increment, a standard
+ // opcode must be used instead of a special opcode. The "address
+ // advance" is calculated by dividing the desired address increment
+ // by the minimum_instruction_length field from the header. The
+ // special opcode is then calculated using the following formula:
+ //
+ // opcode = (desired line increment - line_base) + (line_range * address advance) + opcode_base
+ //
+ // If the resulting opcode is greater than 255, a standard opcode
+ // must be used instead.
+ //
+ // To decode a special opcode, subtract the opcode_base from the
+ // opcode itself to give the adjusted opcode. The amount to
+ // increment the address register is the result of the adjusted
+ // opcode divided by the line_range multiplied by the
+ // minimum_instruction_length field from the header. That is:
+ //
+ // address increment = (adjusted opcode / line_range) * minimum_instruction_length
+ //
+ // The amount to increment the line register is the line_base plus
+ // the result of the adjusted opcode modulo the line_range. That is:
+ //
+ // line increment = line_base + (adjusted opcode % line_range)
+
+ uint8_t adjust_opcode = opcode - prologue->opcode_base;
+ dw_addr_t addr_offset = (adjust_opcode / prologue->line_range) * prologue->min_inst_length;
+ int32_t line_offset = prologue->line_base + (adjust_opcode % prologue->line_range);
+ state.line += line_offset;
+ state.address += addr_offset;
+ state.AppendRowToMatrix(*offset_ptr);
+ }
+ }
+
+ state.Finalize( *offset_ptr );
+
+ return end_offset;
+}
+
+
+//----------------------------------------------------------------------
+// ParseStatementTableCallback
+//----------------------------------------------------------------------
+static void
+ParseStatementTableCallback(dw_offset_t offset, const DWARFDebugLine::State& state, void* userData)
+{
+ DWARFDebugLine::LineTable* line_table = (DWARFDebugLine::LineTable*)userData;
+ if (state.row == DWARFDebugLine::State::StartParsingLineTable)
+ {
+ // Just started parsing the line table, so lets keep a reference to
+ // the prologue using the supplied shared pointer
+ line_table->prologue = state.prologue;
+ }
+ else if (state.row == DWARFDebugLine::State::DoneParsingLineTable)
+ {
+ // Done parsing line table, nothing to do for the cleanup
+ }
+ else
+ {
+ // We have a new row, lets append it
+ line_table->AppendRow(state);
+ }
+}
+
+//----------------------------------------------------------------------
+// ParseStatementTable
+//
+// Parse a line table at offset and populate the LineTable class with
+// the prologue and all rows.
+//----------------------------------------------------------------------
+bool
+DWARFDebugLine::ParseStatementTable(const DataExtractor& debug_line_data, lldb::offset_t *offset_ptr, LineTable* line_table)
+{
+ return ParseStatementTable(debug_line_data, offset_ptr, ParseStatementTableCallback, line_table);
+}
+
+
+inline bool
+DWARFDebugLine::Prologue::IsValid() const
+{
+ return SymbolFileDWARF::SupportedVersion(version);
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::Prologue::Dump
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Prologue::Dump(Log *log)
+{
+ uint32_t i;
+
+ log->Printf( "Line table prologue:");
+ log->Printf( " total_length: 0x%8.8x", total_length);
+ log->Printf( " version: %u", version);
+ log->Printf( "prologue_length: 0x%8.8x", prologue_length);
+ log->Printf( "min_inst_length: %u", min_inst_length);
+ log->Printf( "default_is_stmt: %u", default_is_stmt);
+ log->Printf( " line_base: %i", line_base);
+ log->Printf( " line_range: %u", line_range);
+ log->Printf( " opcode_base: %u", opcode_base);
+
+ for (i=0; i<standard_opcode_lengths.size(); ++i)
+ {
+ log->Printf( "standard_opcode_lengths[%s] = %u", DW_LNS_value_to_name(i+1), standard_opcode_lengths[i]);
+ }
+
+ if (!include_directories.empty())
+ {
+ for (i=0; i<include_directories.size(); ++i)
+ {
+ log->Printf( "include_directories[%3u] = '%s'", i+1, include_directories[i].c_str());
+ }
+ }
+
+ if (!file_names.empty())
+ {
+ log->PutCString (" Dir Mod Time File Len File Name");
+ log->PutCString (" ---- ---------- ---------- ---------------------------");
+ for (i=0; i<file_names.size(); ++i)
+ {
+ const FileNameEntry& fileEntry = file_names[i];
+ log->Printf ("file_names[%3u] %4u 0x%8.8x 0x%8.8x %s",
+ i+1,
+ fileEntry.dir_idx,
+ fileEntry.mod_time,
+ fileEntry.length,
+ fileEntry.name.c_str());
+ }
+ }
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::ParsePrologue::Append
+//
+// Append the contents of the prologue to the binary stream buffer
+//----------------------------------------------------------------------
+//void
+//DWARFDebugLine::Prologue::Append(BinaryStreamBuf& buff) const
+//{
+// uint32_t i;
+//
+// buff.Append32(total_length);
+// buff.Append16(version);
+// buff.Append32(prologue_length);
+// buff.Append8(min_inst_length);
+// buff.Append8(default_is_stmt);
+// buff.Append8(line_base);
+// buff.Append8(line_range);
+// buff.Append8(opcode_base);
+//
+// for (i=0; i<standard_opcode_lengths.size(); ++i)
+// buff.Append8(standard_opcode_lengths[i]);
+//
+// for (i=0; i<include_directories.size(); ++i)
+// buff.AppendCStr(include_directories[i].c_str());
+// buff.Append8(0); // Terminate the include directory section with empty string
+//
+// for (i=0; i<file_names.size(); ++i)
+// {
+// buff.AppendCStr(file_names[i].name.c_str());
+// buff.Append32_as_ULEB128(file_names[i].dir_idx);
+// buff.Append32_as_ULEB128(file_names[i].mod_time);
+// buff.Append32_as_ULEB128(file_names[i].length);
+// }
+// buff.Append8(0); // Terminate the file names section with empty string
+//}
+
+
+bool DWARFDebugLine::Prologue::GetFile(uint32_t file_idx, std::string& path, std::string& directory) const
+{
+ uint32_t idx = file_idx - 1; // File indexes are 1 based...
+ if (idx < file_names.size())
+ {
+ path = file_names[idx].name;
+ uint32_t dir_idx = file_names[idx].dir_idx - 1;
+ if (dir_idx < include_directories.size())
+ directory = include_directories[dir_idx];
+ else
+ directory.clear();
+ return true;
+ }
+ return false;
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::LineTable::Dump
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::LineTable::Dump(Log *log) const
+{
+ if (prologue.get())
+ prologue->Dump (log);
+
+ if (!rows.empty())
+ {
+ log->PutCString ("Address Line Column File ISA Flags");
+ log->PutCString ("------------------ ------ ------ ------ --- -------------");
+ Row::const_iterator pos = rows.begin();
+ Row::const_iterator end = rows.end();
+ while (pos != end)
+ {
+ (*pos).Dump (log);
+ ++pos;
+ }
+ }
+}
+
+
+void
+DWARFDebugLine::LineTable::AppendRow(const DWARFDebugLine::Row& state)
+{
+ rows.push_back(state);
+}
+
+
+
+//----------------------------------------------------------------------
+// Compare function for the binary search in DWARFDebugLine::LineTable::LookupAddress()
+//----------------------------------------------------------------------
+static bool FindMatchingAddress (const DWARFDebugLine::Row& row1, const DWARFDebugLine::Row& row2)
+{
+ return row1.address < row2.address;
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::LineTable::LookupAddress
+//----------------------------------------------------------------------
+uint32_t
+DWARFDebugLine::LineTable::LookupAddress(dw_addr_t address, dw_addr_t cu_high_pc) const
+{
+ uint32_t index = UINT32_MAX;
+ if (!rows.empty())
+ {
+ // Use the lower_bound algorithm to perform a binary search since we know
+ // that our line table data is ordered by address.
+ DWARFDebugLine::Row row;
+ row.address = address;
+ Row::const_iterator begin_pos = rows.begin();
+ Row::const_iterator end_pos = rows.end();
+ Row::const_iterator pos = lower_bound(begin_pos, end_pos, row, FindMatchingAddress);
+ if (pos == end_pos)
+ {
+ if (address < cu_high_pc)
+ return rows.size()-1;
+ }
+ else
+ {
+ // Rely on fact that we are using a std::vector and we can do
+ // pointer arithmetic to find the row index (which will be one less
+ // that what we found since it will find the first position after
+ // the current address) since std::vector iterators are just
+ // pointers to the container type.
+ index = pos - begin_pos;
+ if (pos->address > address)
+ {
+ if (index > 0)
+ --index;
+ else
+ index = UINT32_MAX;
+ }
+ }
+ }
+ return index; // Failed to find address
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::Row::Row
+//----------------------------------------------------------------------
+DWARFDebugLine::Row::Row(bool default_is_stmt) :
+ address(0),
+ line(1),
+ column(0),
+ file(1),
+ is_stmt(default_is_stmt),
+ basic_block(false),
+ end_sequence(false),
+ prologue_end(false),
+ epilogue_begin(false),
+ isa(0)
+{
+}
+
+//----------------------------------------------------------------------
+// Called after a row is appended to the matrix
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Row::PostAppend()
+{
+ basic_block = false;
+ prologue_end = false;
+ epilogue_begin = false;
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::Row::Reset
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Row::Reset(bool default_is_stmt)
+{
+ address = 0;
+ line = 1;
+ column = 0;
+ file = 1;
+ is_stmt = default_is_stmt;
+ basic_block = false;
+ end_sequence = false;
+ prologue_end = false;
+ epilogue_begin = false;
+ isa = 0;
+}
+//----------------------------------------------------------------------
+// DWARFDebugLine::Row::Dump
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::Row::Dump(Log *log) const
+{
+ log->Printf( "0x%16.16" PRIx64 " %6u %6u %6u %3u %s%s%s%s%s",
+ address,
+ line,
+ column,
+ file,
+ isa,
+ is_stmt ? " is_stmt" : "",
+ basic_block ? " basic_block" : "",
+ prologue_end ? " prologue_end" : "",
+ epilogue_begin ? " epilogue_begin" : "",
+ end_sequence ? " end_sequence" : "");
+}
+
+//----------------------------------------------------------------------
+// Compare function LineTable structures
+//----------------------------------------------------------------------
+static bool AddressLessThan (const DWARFDebugLine::Row& a, const DWARFDebugLine::Row& b)
+{
+ return a.address < b.address;
+}
+
+
+
+// Insert a row at the correct address if the addresses can be out of
+// order which can only happen when we are linking a line table that
+// may have had it's contents rearranged.
+void
+DWARFDebugLine::Row::Insert(Row::collection& state_coll, const Row& state)
+{
+ // If we don't have anything yet, or if the address of the last state in our
+ // line table is less than the current one, just append the current state
+ if (state_coll.empty() || AddressLessThan(state_coll.back(), state))
+ {
+ state_coll.push_back(state);
+ }
+ else
+ {
+ // Do a binary search for the correct entry
+ pair<Row::iterator, Row::iterator> range(equal_range(state_coll.begin(), state_coll.end(), state, AddressLessThan));
+
+ // If the addresses are equal, we can safely replace the previous entry
+ // with the current one if the one it is replacing is an end_sequence entry.
+ // We currently always place an extra end sequence when ever we exit a valid
+ // address range for a function in case the functions get rearranged by
+ // optimizations or by order specifications. These extra end sequences will
+ // disappear by getting replaced with valid consecutive entries within a
+ // compile unit if there are no gaps.
+ if (range.first == range.second)
+ {
+ state_coll.insert(range.first, state);
+ }
+ else
+ {
+ if ((distance(range.first, range.second) == 1) && range.first->end_sequence == true)
+ {
+ *range.first = state;
+ }
+ else
+ {
+ state_coll.insert(range.second, state);
+ }
+ }
+ }
+}
+
+void
+DWARFDebugLine::Row::Dump(Log *log, const Row::collection& state_coll)
+{
+ std::for_each (state_coll.begin(), state_coll.end(), bind2nd(std::mem_fun_ref(&Row::Dump),log));
+}
+
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::State::State
+//----------------------------------------------------------------------
+DWARFDebugLine::State::State(Prologue::shared_ptr& p, Log *l, DWARFDebugLine::State::Callback cb, void* userData) :
+ Row (p->default_is_stmt),
+ prologue (p),
+ log (l),
+ callback (cb),
+ callbackUserData (userData),
+ row (StartParsingLineTable)
+{
+ // Call the callback with the initial row state of zero for the prologue
+ if (callback)
+ callback(0, *this, callbackUserData);
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::State::Reset
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::State::Reset()
+{
+ Row::Reset(prologue->default_is_stmt);
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::State::AppendRowToMatrix
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::State::AppendRowToMatrix(dw_offset_t offset)
+{
+ // Each time we are to add an entry into the line table matrix
+ // call the callback function so that someone can do something with
+ // the current state of the state machine (like build a line table
+ // or dump the line table!)
+ if (log)
+ {
+ if (row == 0)
+ {
+ log->PutCString ("Address Line Column File ISA Flags");
+ log->PutCString ("------------------ ------ ------ ------ --- -------------");
+ }
+ Dump (log);
+ }
+
+ ++row; // Increase the row number before we call our callback for a real row
+ if (callback)
+ callback(offset, *this, callbackUserData);
+ PostAppend();
+}
+
+//----------------------------------------------------------------------
+// DWARFDebugLine::State::Finalize
+//----------------------------------------------------------------------
+void
+DWARFDebugLine::State::Finalize(dw_offset_t offset)
+{
+ // Call the callback with a special row state when we are done parsing a
+ // line table
+ row = DoneParsingLineTable;
+ if (callback)
+ callback(offset, *this, callbackUserData);
+}
+
+//void
+//DWARFDebugLine::AppendLineTableData
+//(
+// const DWARFDebugLine::Prologue* prologue,
+// const DWARFDebugLine::Row::collection& state_coll,
+// const uint32_t addr_size,
+// BinaryStreamBuf &debug_line_data
+//)
+//{
+// if (state_coll.empty())
+// {
+// // We have no entries, just make an empty line table
+// debug_line_data.Append8(0);
+// debug_line_data.Append8(1);
+// debug_line_data.Append8(DW_LNE_end_sequence);
+// }
+// else
+// {
+// DWARFDebugLine::Row::const_iterator pos;
+// Row::const_iterator end = state_coll.end();
+// bool default_is_stmt = prologue->default_is_stmt;
+// const DWARFDebugLine::Row reset_state(default_is_stmt);
+// const DWARFDebugLine::Row* prev_state = &reset_state;
+// const int32_t max_line_increment_for_special_opcode = prologue->MaxLineIncrementForSpecialOpcode();
+// for (pos = state_coll.begin(); pos != end; ++pos)
+// {
+// const DWARFDebugLine::Row& curr_state = *pos;
+// int32_t line_increment = 0;
+// dw_addr_t addr_offset = curr_state.address - prev_state->address;
+// dw_addr_t addr_advance = (addr_offset) / prologue->min_inst_length;
+// line_increment = (int32_t)(curr_state.line - prev_state->line);
+//
+// // If our previous state was the reset state, then let's emit the
+// // address to keep GDB's DWARF parser happy. If we don't start each
+// // sequence with a DW_LNE_set_address opcode, the line table won't
+// // get slid properly in GDB.
+//
+// if (prev_state == &reset_state)
+// {
+// debug_line_data.Append8(0); // Extended opcode
+// debug_line_data.Append32_as_ULEB128(addr_size + 1); // Length of opcode bytes
+// debug_line_data.Append8(DW_LNE_set_address);
+// debug_line_data.AppendMax64(curr_state.address, addr_size);
+// addr_advance = 0;
+// }
+//
+// if (prev_state->file != curr_state.file)
+// {
+// debug_line_data.Append8(DW_LNS_set_file);
+// debug_line_data.Append32_as_ULEB128(curr_state.file);
+// }
+//
+// if (prev_state->column != curr_state.column)
+// {
+// debug_line_data.Append8(DW_LNS_set_column);
+// debug_line_data.Append32_as_ULEB128(curr_state.column);
+// }
+//
+// // Don't do anything fancy if we are at the end of a sequence
+// // as we don't want to push any extra rows since the DW_LNE_end_sequence
+// // will push a row itself!
+// if (curr_state.end_sequence)
+// {
+// if (line_increment != 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_line);
+// debug_line_data.Append32_as_SLEB128(line_increment);
+// }
+//
+// if (addr_advance > 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_pc);
+// debug_line_data.Append32_as_ULEB128(addr_advance);
+// }
+//
+// // Now push the end sequence on!
+// debug_line_data.Append8(0);
+// debug_line_data.Append8(1);
+// debug_line_data.Append8(DW_LNE_end_sequence);
+//
+// prev_state = &reset_state;
+// }
+// else
+// {
+// if (line_increment || addr_advance)
+// {
+// if (line_increment > max_line_increment_for_special_opcode)
+// {
+// debug_line_data.Append8(DW_LNS_advance_line);
+// debug_line_data.Append32_as_SLEB128(line_increment);
+// line_increment = 0;
+// }
+//
+// uint32_t special_opcode = (line_increment >= prologue->line_base) ? ((line_increment - prologue->line_base) + (prologue->line_range * addr_advance) + prologue->opcode_base) : 256;
+// if (special_opcode > 255)
+// {
+// // Both the address and line won't fit in one special opcode
+// // check to see if just the line advance will?
+// uint32_t special_opcode_line = ((line_increment >= prologue->line_base) && (line_increment != 0)) ?
+// ((line_increment - prologue->line_base) + prologue->opcode_base) : 256;
+//
+//
+// if (special_opcode_line > 255)
+// {
+// // Nope, the line advance won't fit by itself, check the address increment by itself
+// uint32_t special_opcode_addr = addr_advance ?
+// ((0 - prologue->line_base) + (prologue->line_range * addr_advance) + prologue->opcode_base) : 256;
+//
+// if (special_opcode_addr > 255)
+// {
+// // Neither the address nor the line will fit in a
+// // special opcode, we must manually enter both then
+// // do a DW_LNS_copy to push a row (special opcode
+// // automatically imply a new row is pushed)
+// if (line_increment != 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_line);
+// debug_line_data.Append32_as_SLEB128(line_increment);
+// }
+//
+// if (addr_advance > 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_pc);
+// debug_line_data.Append32_as_ULEB128(addr_advance);
+// }
+//
+// // Now push a row onto the line table manually
+// debug_line_data.Append8(DW_LNS_copy);
+//
+// }
+// else
+// {
+// // The address increment alone will fit into a special opcode
+// // so modify our line change, then issue a special opcode
+// // for the address increment and it will push a row into the
+// // line table
+// if (line_increment != 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_line);
+// debug_line_data.Append32_as_SLEB128(line_increment);
+// }
+//
+// // Advance of line and address will fit into a single byte special opcode
+// // and this will also push a row onto the line table
+// debug_line_data.Append8(special_opcode_addr);
+// }
+// }
+// else
+// {
+// // The line change alone will fit into a special opcode
+// // so modify our address increment first, then issue a
+// // special opcode for the line change and it will push
+// // a row into the line table
+// if (addr_advance > 0)
+// {
+// debug_line_data.Append8(DW_LNS_advance_pc);
+// debug_line_data.Append32_as_ULEB128(addr_advance);
+// }
+//
+// // Advance of line and address will fit into a single byte special opcode
+// // and this will also push a row onto the line table
+// debug_line_data.Append8(special_opcode_line);
+// }
+// }
+// else
+// {
+// // Advance of line and address will fit into a single byte special opcode
+// // and this will also push a row onto the line table
+// debug_line_data.Append8(special_opcode);
+// }
+// }
+// prev_state = &curr_state;
+// }
+// }
+// }
+//}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h
new file mode 100644
index 000000000000..cfa8654ed9ba
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugLine.h
@@ -0,0 +1,225 @@
+//===-- DWARFDebugLine.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugLine_h_
+#define SymbolFileDWARF_DWARFDebugLine_h_
+
+#include <map>
+#include <vector>
+#include <string>
+
+#include "lldb/lldb-private.h"
+
+#include "DWARFDefines.h"
+
+class SymbolFileDWARF;
+class DWARFDebugInfoEntry;
+
+//----------------------------------------------------------------------
+// DWARFDebugLine
+//----------------------------------------------------------------------
+class DWARFDebugLine
+{
+public:
+ //------------------------------------------------------------------
+ // FileNameEntry
+ //------------------------------------------------------------------
+ struct FileNameEntry
+ {
+ FileNameEntry() :
+ name(),
+ dir_idx(0),
+ mod_time(0),
+ length(0)
+ {
+ }
+
+ std::string name;
+ dw_sleb128_t dir_idx;
+ dw_sleb128_t mod_time;
+ dw_sleb128_t length;
+
+ };
+
+ //------------------------------------------------------------------
+ // Prologue
+ //------------------------------------------------------------------
+ struct Prologue
+ {
+
+ Prologue() :
+ total_length(0),
+ version(0),
+ prologue_length(0),
+ min_inst_length(0),
+ default_is_stmt(0),
+ line_base(0),
+ line_range(0),
+ opcode_base(0),
+ standard_opcode_lengths(),
+ include_directories(),
+ file_names()
+ {
+ }
+
+ typedef std::shared_ptr<Prologue> shared_ptr;
+
+ uint32_t total_length; // The size in bytes of the statement information for this compilation unit (not including the total_length field itself).
+ uint16_t version; // Version identifier for the statement information format.
+ uint32_t prologue_length;// The number of bytes following the prologue_length field to the beginning of the first byte of the statement program itself.
+ uint8_t min_inst_length;// The size in bytes of the smallest target machine instruction. Statement program opcodes that alter the address register first multiply their operands by this value.
+ uint8_t default_is_stmt;// The initial value of theis_stmtregister.
+ int8_t line_base; // This parameter affects the meaning of the special opcodes. See below.
+ uint8_t line_range; // This parameter affects the meaning of the special opcodes. See below.
+ uint8_t opcode_base; // The number assigned to the first special opcode.
+ std::vector<uint8_t> standard_opcode_lengths;
+ std::vector<std::string> include_directories;
+ std::vector<FileNameEntry> file_names;
+
+ // Length of the prologue in bytes
+ uint32_t Length() const { return prologue_length + sizeof(total_length) + sizeof(version) + sizeof(prologue_length); }
+ // Length of the line table data in bytes (not including the prologue)
+ uint32_t StatementTableLength() const { return total_length + sizeof(total_length) - Length(); }
+ int32_t MaxLineIncrementForSpecialOpcode() const { return line_base + (int8_t)line_range - 1; }
+ bool IsValid() const;
+// void Append(BinaryStreamBuf& buff) const;
+ void Dump (lldb_private::Log *log);
+ void Clear()
+ {
+ total_length = version = prologue_length = min_inst_length = line_base = line_range = opcode_base = 0;
+ line_base = 0;
+ standard_opcode_lengths.clear();
+ include_directories.clear();
+ file_names.clear();
+ }
+ bool GetFile(uint32_t file_idx, std::string& file, std::string& dir) const;
+
+ };
+
+ // Standard .debug_line state machine structure
+ struct Row
+ {
+ typedef std::vector<Row> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ Row(bool default_is_stmt = false);
+ virtual ~Row() {}
+ void PostAppend ();
+ void Reset(bool default_is_stmt);
+ void Dump(lldb_private::Log *log) const;
+ static void Insert(Row::collection& state_coll, const Row& state);
+ static void Dump(lldb_private::Log *log, const Row::collection& state_coll);
+
+ dw_addr_t address; // The program-counter value corresponding to a machine instruction generated by the compiler.
+ uint32_t line; // An unsigned integer indicating a source line number. Lines are numbered beginning at 1. The compiler may emit the value 0 in cases where an instruction cannot be attributed to any source line.
+ uint16_t column; // An unsigned integer indicating a column number within a source line. Columns are numbered beginning at 1. The value 0 is reserved to indicate that a statement begins at the 'left edge' of the line.
+ uint16_t file; // An unsigned integer indicating the identity of the source file corresponding to a machine instruction.
+ uint8_t is_stmt:1, // A boolean indicating that the current instruction is the beginning of a statement.
+ basic_block:1, // A boolean indicating that the current instruction is the beginning of a basic block.
+ end_sequence:1, // A boolean indicating that the current address is that of the first byte after the end of a sequence of target machine instructions.
+ prologue_end:1, // A boolean indicating that the current address is one (of possibly many) where execution should be suspended for an entry breakpoint of a function.
+ epilogue_begin:1;// A boolean indicating that the current address is one (of possibly many) where execution should be suspended for an exit breakpoint of a function.
+ uint32_t isa; // An unsigned integer whose value encodes the applicable instruction set architecture for the current instruction.
+ };
+
+
+ //------------------------------------------------------------------
+ // LineTable
+ //------------------------------------------------------------------
+ struct LineTable
+ {
+ typedef std::shared_ptr<LineTable> shared_ptr;
+
+ LineTable() :
+ prologue(),
+ rows()
+ {
+ }
+
+ void AppendRow(const DWARFDebugLine::Row& state);
+ void Clear()
+ {
+ prologue.reset();
+ rows.clear();
+ }
+
+ uint32_t LookupAddress(dw_addr_t address, dw_addr_t cu_high_pc) const;
+ void Dump(lldb_private::Log *log) const;
+
+ Prologue::shared_ptr prologue;
+ Row::collection rows;
+ };
+
+ //------------------------------------------------------------------
+ // State
+ //------------------------------------------------------------------
+ struct State : public Row
+ {
+ typedef void (*Callback)(dw_offset_t offset, const State& state, void* userData);
+
+ // Special row codes used when calling the callback
+ enum
+ {
+ StartParsingLineTable = 0,
+ DoneParsingLineTable = -1
+ };
+
+ State (Prologue::shared_ptr& prologue_sp,
+ lldb_private::Log *log,
+ Callback callback,
+ void* userData);
+
+ void
+ AppendRowToMatrix (dw_offset_t offset);
+
+ void
+ Finalize (dw_offset_t offset);
+
+ void
+ Reset ();
+
+ Prologue::shared_ptr prologue;
+ lldb_private::Log *log;
+ Callback callback; // Callback function that gets called each time an entry is to be added to the matrix
+ void* callbackUserData;
+ int row; // The row number that starts at zero for the prologue, and increases for each row added to the matrix
+ private:
+ DISALLOW_COPY_AND_ASSIGN (State);
+ };
+
+ static bool DumpOpcodes(lldb_private::Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t line_offset = DW_INVALID_OFFSET, uint32_t dump_flags = 0); // If line_offset is invalid, dump everything
+ static bool DumpLineTableRows(lldb_private::Log *log, SymbolFileDWARF* dwarf2Data, dw_offset_t line_offset = DW_INVALID_OFFSET); // If line_offset is invalid, dump everything
+ static bool ParseSupportFiles(const lldb::ModuleSP &module_sp, const lldb_private::DataExtractor& debug_line_data, const char *cu_comp_dir, dw_offset_t stmt_list, lldb_private::FileSpecList &support_files);
+ static bool ParsePrologue(const lldb_private::DataExtractor& debug_line_data, lldb::offset_t* offset_ptr, Prologue* prologue);
+ static bool ParseStatementTable(const lldb_private::DataExtractor& debug_line_data, lldb::offset_t* offset_ptr, State::Callback callback, void* userData);
+ static dw_offset_t DumpStatementTable(lldb_private::Log *log, const lldb_private::DataExtractor& debug_line_data, const dw_offset_t line_offset);
+ static dw_offset_t DumpStatementOpcodes(lldb_private::Log *log, const lldb_private::DataExtractor& debug_line_data, const dw_offset_t line_offset, uint32_t flags);
+ static bool ParseStatementTable(const lldb_private::DataExtractor& debug_line_data, lldb::offset_t *offset_ptr, LineTable* line_table);
+ static void Parse(const lldb_private::DataExtractor& debug_line_data, DWARFDebugLine::State::Callback callback, void* userData);
+// static void AppendLineTableData(const DWARFDebugLine::Prologue* prologue, const DWARFDebugLine::Row::collection& state_coll, const uint32_t addr_size, BinaryStreamBuf &debug_line_data);
+
+ DWARFDebugLine() :
+ m_lineTableMap()
+ {
+ }
+
+ void Parse(const lldb_private::DataExtractor& debug_line_data);
+ void ParseIfNeeded(const lldb_private::DataExtractor& debug_line_data);
+ LineTable::shared_ptr GetLineTable(const dw_offset_t offset) const;
+
+protected:
+ typedef std::map<dw_offset_t, LineTable::shared_ptr> LineTableMap;
+ typedef LineTableMap::iterator LineTableIter;
+ typedef LineTableMap::const_iterator LineTableConstIter;
+
+ LineTableMap m_lineTableMap;
+};
+
+#endif // SymbolFileDWARF_DWARFDebugLine_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp
new file mode 100644
index 000000000000..60ace9e82290
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.cpp
@@ -0,0 +1,48 @@
+//===-- DWARFDebugMacinfo.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugMacinfo.h"
+
+#include "DWARFDebugMacinfoEntry.h"
+#include "SymbolFileDWARF.h"
+
+#include "lldb/Core/Stream.h"
+
+using namespace lldb_private;
+using namespace std;
+
+DWARFDebugMacinfo::DWARFDebugMacinfo()
+{
+}
+
+DWARFDebugMacinfo::~DWARFDebugMacinfo()
+{
+}
+
+void
+DWARFDebugMacinfo::Dump(Stream *s, const DataExtractor& macinfo_data, lldb::offset_t offset)
+{
+ DWARFDebugMacinfoEntry maninfo_entry;
+ if (macinfo_data.GetByteSize() == 0)
+ {
+ s->PutCString("< EMPTY >\n");
+ return;
+ }
+ if (offset == LLDB_INVALID_OFFSET)
+ {
+ offset = 0;
+ while (maninfo_entry.Extract(macinfo_data, &offset))
+ maninfo_entry.Dump(s);
+ }
+ else
+ {
+ if (maninfo_entry.Extract(macinfo_data, &offset))
+ maninfo_entry.Dump(s);
+ }
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h
new file mode 100644
index 000000000000..5f3b437d964f
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfo.h
@@ -0,0 +1,29 @@
+//===-- DWARFDebugMacinfo.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugMacinfo_h_
+#define SymbolFileDWARF_DWARFDebugMacinfo_h_
+
+#include "SymbolFileDWARF.h"
+
+class DWARFDebugMacinfo
+{
+public:
+ DWARFDebugMacinfo();
+
+ ~DWARFDebugMacinfo();
+
+ static void
+ Dump (lldb_private::Stream *s,
+ const lldb_private::DataExtractor& macinfo_data,
+ lldb::offset_t offset = LLDB_INVALID_OFFSET);
+};
+
+
+#endif // SymbolFileDWARF_DWARFDebugMacinfo_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp
new file mode 100644
index 000000000000..5cd9cb6be474
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.cpp
@@ -0,0 +1,132 @@
+//===-- DWARFDebugMacinfoEntry.cpp ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugMacinfoEntry.h"
+
+#include "lldb/Core/Stream.h"
+
+using namespace lldb_private;
+using namespace std;
+
+DWARFDebugMacinfoEntry::DWARFDebugMacinfoEntry() :
+ m_type_code(0),
+ m_line(0),
+ m_op2()
+{
+ m_op2.cstr = NULL;
+}
+
+DWARFDebugMacinfoEntry::~DWARFDebugMacinfoEntry()
+{
+}
+
+const char*
+DWARFDebugMacinfoEntry::GetCString() const
+{
+ switch (m_type_code)
+ {
+ case 0:
+ case DW_MACINFO_start_file:
+ case DW_MACINFO_end_file:
+ return NULL;
+ default:
+ break;
+ }
+ return m_op2.cstr;
+}
+
+
+
+void
+DWARFDebugMacinfoEntry::Dump(Stream *s) const
+{
+ if (m_type_code)
+ {
+ s->PutCString(DW_MACINFO_value_to_name(m_type_code));
+
+ switch (m_type_code)
+ {
+ case DW_MACINFO_define:
+ s->Printf(" line:%u #define %s\n", (uint32_t)m_line, m_op2.cstr);
+ break;
+
+ case DW_MACINFO_undef:
+ s->Printf(" line:%u #undef %s\n", (uint32_t)m_line, m_op2.cstr);
+ break;
+
+ default:
+ s->Printf(" line:%u str: '%s'\n", (uint32_t)m_line, m_op2.cstr);
+ break;
+
+ case DW_MACINFO_start_file:
+ s->Printf(" line:%u file index: '%u'\n", (uint32_t)m_line, (uint32_t)m_op2.file_idx);
+ break;
+
+ case DW_MACINFO_end_file:
+ break;
+ }
+ }
+ else
+ {
+ s->PutCString(" END\n");
+ }
+}
+
+
+bool
+DWARFDebugMacinfoEntry::Extract(const DataExtractor& mac_info_data, lldb::offset_t* offset_ptr)
+{
+ if (mac_info_data.ValidOffset(*offset_ptr))
+ {
+ m_type_code = mac_info_data.GetU8(offset_ptr);
+
+ switch (m_type_code)
+ {
+
+ case DW_MACINFO_define:
+ case DW_MACINFO_undef:
+ // 2 operands:
+ // Arg 1: operand encodes the line number of the source line on which
+ // the relevant defining or undefining pre-processor directives
+ // appeared.
+ m_line = mac_info_data.GetULEB128(offset_ptr);
+ // Arg 2: define string
+ m_op2.cstr = mac_info_data.GetCStr(offset_ptr);
+ break;
+
+ case DW_MACINFO_start_file:
+ // 2 operands:
+ // Op 1: line number of the source line on which the inclusion
+ // pre-processor directive occurred.
+ m_line = mac_info_data.GetULEB128(offset_ptr);
+ // Op 2: a source file name index to a file number in the statement
+ // information table for the relevant compilation unit.
+ m_op2.file_idx = mac_info_data.GetULEB128(offset_ptr);
+ break;
+
+ case 0: // End of list
+ case DW_MACINFO_end_file:
+ // No operands
+ m_line = DW_INVALID_OFFSET;
+ m_op2.cstr = NULL;
+ break;
+ default:
+ // Vendor specific entries always have a ULEB128 and a string
+ m_line = mac_info_data.GetULEB128(offset_ptr);
+ m_op2.cstr = mac_info_data.GetCStr(offset_ptr);
+ break;
+ }
+ return true;
+ }
+ else
+ m_type_code = 0;
+
+ return false;
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h
new file mode 100644
index 000000000000..46fd44a22a63
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugMacinfoEntry.h
@@ -0,0 +1,57 @@
+//===-- DWARFDebugMacinfoEntry.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugMacinfoEntry_h_
+#define SymbolFileDWARF_DWARFDebugMacinfoEntry_h_
+
+#include "SymbolFileDWARF.h"
+
+class DWARFDebugMacinfoEntry
+{
+public:
+ DWARFDebugMacinfoEntry();
+
+ ~DWARFDebugMacinfoEntry();
+
+ uint8_t
+ TypeCode() const
+ {
+ return m_type_code;
+ }
+
+ uint8_t
+ GetLineNumber() const
+ {
+ return m_line;
+ }
+
+ void
+ Dump(lldb_private::Stream *s) const;
+
+ const char*
+ GetCString() const;
+
+ bool
+ Extract(const lldb_private::DataExtractor& mac_info_data,
+ lldb::offset_t* offset_ptr);
+
+protected:
+
+private:
+ uint8_t m_type_code;
+ dw_uleb128_t m_line;
+ union
+ {
+ dw_uleb128_t file_idx;
+ const char* cstr;
+ } m_op2;
+};
+
+
+#endif // SymbolFileDWARF_DWARFDebugMacinfoEntry_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp
new file mode 100644
index 000000000000..3e511007a1ec
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.cpp
@@ -0,0 +1,296 @@
+//===-- DWARFDebugPubnames.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugPubnames.h"
+
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/Timer.h"
+
+#include "DWARFDebugInfo.h"
+#include "DWARFDIECollection.h"
+#include "DWARFFormValue.h"
+#include "DWARFCompileUnit.h"
+#include "LogChannelDWARF.h"
+#include "SymbolFileDWARF.h"
+
+
+using namespace lldb;
+using namespace lldb_private;
+
+DWARFDebugPubnames::DWARFDebugPubnames() :
+ m_sets()
+{
+}
+
+bool
+DWARFDebugPubnames::Extract(const DataExtractor& data)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "DWARFDebugPubnames::Extract (byte_size = %" PRIu64 ")",
+ (uint64_t)data.GetByteSize());
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES));
+ if (log)
+ log->Printf("DWARFDebugPubnames::Extract (byte_size = %" PRIu64 ")", (uint64_t)data.GetByteSize());
+
+ if (data.ValidOffset(0))
+ {
+ lldb::offset_t offset = 0;
+
+ DWARFDebugPubnamesSet set;
+ while (data.ValidOffset(offset))
+ {
+ if (set.Extract(data, &offset))
+ {
+ m_sets.push_back(set);
+ offset = set.GetOffsetOfNextEntry();
+ }
+ else
+ break;
+ }
+ if (log)
+ Dump (log);
+ return true;
+ }
+ return false;
+}
+
+
+bool
+DWARFDebugPubnames::GeneratePubnames(SymbolFileDWARF* dwarf2Data)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "DWARFDebugPubnames::GeneratePubnames (data = %p)",
+ dwarf2Data);
+
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_PUBNAMES));
+ if (log)
+ log->Printf("DWARFDebugPubnames::GeneratePubnames (data = %p)", dwarf2Data);
+
+ m_sets.clear();
+ DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
+ if (debug_info)
+ {
+
+ const DataExtractor* debug_str = &dwarf2Data->get_debug_str_data();
+
+ uint32_t cu_idx = 0;
+ const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
+ for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
+ {
+
+ DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
+
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (cu->GetAddressByteSize());
+
+ bool clear_dies = cu->ExtractDIEsIfNeeded (false) > 1;
+
+ DWARFDIECollection dies;
+ const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_subprogram, dies) +
+ cu->AppendDIEsWithTag (DW_TAG_variable, dies);
+
+ dw_offset_t cu_offset = cu->GetOffset();
+ DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset);
+
+ size_t die_idx;
+ for (die_idx = 0; die_idx < die_count; ++die_idx)
+ {
+ const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx);
+ DWARFDebugInfoEntry::Attributes attributes;
+ const char *name = NULL;
+ const char *mangled = NULL;
+ bool add_die = false;
+ const size_t num_attributes = die->GetAttributes(dwarf2Data, cu, fixed_form_sizes, attributes);
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+
+ dw_tag_t tag = die->Tag();
+
+ for (i=0; i<num_attributes; ++i)
+ {
+ dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ switch (attr)
+ {
+ case DW_AT_name:
+ if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value))
+ name = form_value.AsCString(debug_str);
+ break;
+
+ case DW_AT_MIPS_linkage_name:
+ case DW_AT_linkage_name:
+ if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value))
+ mangled = form_value.AsCString(debug_str);
+ break;
+
+ case DW_AT_low_pc:
+ case DW_AT_ranges:
+ case DW_AT_entry_pc:
+ if (tag == DW_TAG_subprogram)
+ add_die = true;
+ break;
+
+ case DW_AT_location:
+ if (tag == DW_TAG_variable)
+ {
+ const DWARFDebugInfoEntry* parent_die = die->GetParent();
+ while ( parent_die != NULL )
+ {
+ switch (parent_die->Tag())
+ {
+ case DW_TAG_subprogram:
+ case DW_TAG_lexical_block:
+ case DW_TAG_inlined_subroutine:
+ // Even if this is a function level static, we don't add it. We could theoretically
+ // add these if we wanted to by introspecting into the DW_AT_location and seeing
+ // if the location describes a hard coded address, but we don't want the performance
+ // penalty of that right now.
+ add_die = false;
+// if (attributes.ExtractFormValueAtIndex(dwarf2Data, i, form_value))
+// {
+// // If we have valid block data, then we have location expression bytes
+// // that are fixed (not a location list).
+// const uint8_t *block_data = form_value.BlockData();
+// if (block_data)
+// {
+// uint32_t block_length = form_value.Unsigned();
+// if (block_length == 1 + attributes.CompileUnitAtIndex(i)->GetAddressByteSize())
+// {
+// if (block_data[0] == DW_OP_addr)
+// add_die = true;
+// }
+// }
+// }
+ parent_die = NULL; // Terminate the while loop.
+ break;
+
+ case DW_TAG_compile_unit:
+ add_die = true;
+ parent_die = NULL; // Terminate the while loop.
+ break;
+
+ default:
+ parent_die = parent_die->GetParent(); // Keep going in the while loop.
+ break;
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ if (add_die && (name || mangled))
+ {
+ pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, mangled ? mangled : name);
+ }
+ }
+
+ if (pubnames_set.NumDescriptors() > 0)
+ {
+ m_sets.push_back(pubnames_set);
+ }
+
+ // Keep memory down by clearing DIEs if this generate function
+ // caused them to be parsed
+ if (clear_dies)
+ cu->ClearDIEs (true);
+ }
+ }
+ if (m_sets.empty())
+ return false;
+ if (log)
+ Dump (log);
+ return true;
+}
+
+bool
+DWARFDebugPubnames::GeneratePubBaseTypes(SymbolFileDWARF* dwarf2Data)
+{
+ m_sets.clear();
+ DWARFDebugInfo* debug_info = dwarf2Data->DebugInfo();
+ if (debug_info)
+ {
+ uint32_t cu_idx = 0;
+ const uint32_t num_compile_units = dwarf2Data->GetNumCompileUnits();
+ for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
+ {
+ DWARFCompileUnit* cu = debug_info->GetCompileUnitAtIndex(cu_idx);
+ DWARFDIECollection dies;
+ const size_t die_count = cu->AppendDIEsWithTag (DW_TAG_base_type, dies);
+ dw_offset_t cu_offset = cu->GetOffset();
+ DWARFDebugPubnamesSet pubnames_set(DW_INVALID_OFFSET, cu_offset, cu->GetNextCompileUnitOffset() - cu_offset);
+
+ size_t die_idx;
+ for (die_idx = 0; die_idx < die_count; ++die_idx)
+ {
+ const DWARFDebugInfoEntry *die = dies.GetDIEPtrAtIndex(die_idx);
+ const char *name = die->GetAttributeValueAsString(dwarf2Data, cu, DW_AT_name, NULL);
+
+ if (name)
+ {
+ pubnames_set.AddDescriptor(die->GetOffset() - cu_offset, name);
+ }
+ }
+
+ if (pubnames_set.NumDescriptors() > 0)
+ {
+ m_sets.push_back(pubnames_set);
+ }
+ }
+ }
+ return !m_sets.empty();
+}
+
+void
+DWARFDebugPubnames::Dump(Log *s) const
+{
+ if (m_sets.empty())
+ s->PutCString("< EMPTY >\n");
+ else
+ {
+ const_iterator pos;
+ const_iterator end = m_sets.end();
+
+ for (pos = m_sets.begin(); pos != end; ++pos)
+ (*pos).Dump(s);
+ }
+}
+
+bool
+DWARFDebugPubnames::Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offsets) const
+{
+ const_iterator pos;
+ const_iterator end = m_sets.end();
+
+ die_offsets.clear();
+
+ for (pos = m_sets.begin(); pos != end; ++pos)
+ {
+ (*pos).Find(name, ignore_case, die_offsets);
+ }
+
+ return !die_offsets.empty();
+}
+
+bool
+DWARFDebugPubnames::Find(const RegularExpression& regex, std::vector<dw_offset_t>& die_offsets) const
+{
+ const_iterator pos;
+ const_iterator end = m_sets.end();
+
+ die_offsets.clear();
+
+ for (pos = m_sets.begin(); pos != end; ++pos)
+ {
+ (*pos).Find(regex, die_offsets);
+ }
+
+ return !die_offsets.empty();
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h
new file mode 100644
index 000000000000..09eb80ab3006
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnames.h
@@ -0,0 +1,38 @@
+//===-- DWARFDebugPubnames.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugPubnames_h_
+#define SymbolFileDWARF_DWARFDebugPubnames_h_
+
+#include "SymbolFileDWARF.h"
+
+#include <list>
+
+#include "DWARFDebugPubnamesSet.h"
+
+class DWARFDebugPubnames
+{
+public:
+ DWARFDebugPubnames();
+ bool Extract(const lldb_private::DataExtractor& data);
+ bool GeneratePubnames(SymbolFileDWARF* dwarf2Data);
+ bool GeneratePubBaseTypes(SymbolFileDWARF* dwarf2Data);
+
+ void Dump(lldb_private::Log *s) const;
+ bool Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offset_coll) const;
+ bool Find(const lldb_private::RegularExpression& regex, std::vector<dw_offset_t>& die_offsets) const;
+protected:
+ typedef std::list<DWARFDebugPubnamesSet> collection;
+ typedef collection::iterator iterator;
+ typedef collection::const_iterator const_iterator;
+
+ collection m_sets;
+};
+
+#endif // SymbolFileDWARF_DWARFDebugPubnames_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp
new file mode 100644
index 000000000000..2df8d525f03f
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.cpp
@@ -0,0 +1,166 @@
+//===-- DWARFDebugPubnamesSet.cpp -------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugPubnamesSet.h"
+
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Log.h"
+
+#include "SymbolFileDWARF.h"
+
+using namespace lldb_private;
+
+DWARFDebugPubnamesSet::DWARFDebugPubnamesSet() :
+ m_offset(DW_INVALID_OFFSET),
+ m_header(),
+ m_descriptors(),
+ m_name_to_descriptor_index()
+{
+}
+
+DWARFDebugPubnamesSet::DWARFDebugPubnamesSet(dw_offset_t debug_aranges_offset, dw_offset_t cu_die_offset, dw_offset_t cu_die_length) :
+ m_offset(debug_aranges_offset),
+ m_header(),
+ m_descriptors(),
+ m_name_to_descriptor_index()
+{
+ m_header.length = 10; // set the length to only include the header right for now
+ m_header.version = 2; // The DWARF version number
+ m_header.die_offset = cu_die_offset;// compile unit .debug_info offset
+ m_header.die_length = cu_die_length;// compile unit .debug_info length
+}
+
+void
+DWARFDebugPubnamesSet::AddDescriptor(dw_offset_t cu_rel_offset, const char* name)
+{
+ if (name && name[0])
+ {
+ // Adjust our header length
+ m_header.length += strlen(name) + 1 + sizeof(dw_offset_t);
+ Descriptor pubnameDesc(cu_rel_offset, name);
+ m_descriptors.push_back(pubnameDesc);
+ }
+}
+
+void
+DWARFDebugPubnamesSet::Clear()
+{
+ m_offset = DW_INVALID_OFFSET;
+ m_header.length = 10;
+ m_header.version = 2;
+ m_header.die_offset = DW_INVALID_OFFSET;
+ m_header.die_length = 0;
+ m_descriptors.clear();
+}
+
+
+//----------------------------------------------------------------------
+// InitNameIndexes
+//----------------------------------------------------------------------
+void
+DWARFDebugPubnamesSet::InitNameIndexes() const
+{
+ // Create the name index vector to be able to quickly search by name
+ const size_t count = m_descriptors.size();
+ for (uint32_t idx = 0; idx < count; ++idx)
+ {
+ const char* name = m_descriptors[idx].name.c_str();
+ if (name && name[0])
+ m_name_to_descriptor_index.insert(cstr_to_index_mmap::value_type(name, idx));
+ }
+}
+
+
+bool
+DWARFDebugPubnamesSet::Extract(const DataExtractor& data, lldb::offset_t *offset_ptr)
+{
+ if (data.ValidOffset(*offset_ptr))
+ {
+ m_descriptors.clear();
+ m_offset = *offset_ptr;
+ m_header.length = data.GetU32(offset_ptr);
+ m_header.version = data.GetU16(offset_ptr);
+ m_header.die_offset = data.GetU32(offset_ptr);
+ m_header.die_length = data.GetU32(offset_ptr);
+
+ Descriptor pubnameDesc;
+ while (data.ValidOffset(*offset_ptr))
+ {
+ pubnameDesc.offset = data.GetU32(offset_ptr);
+
+ if (pubnameDesc.offset)
+ {
+ const char* name = data.GetCStr(offset_ptr);
+ if (name && name[0])
+ {
+ pubnameDesc.name = name;
+ m_descriptors.push_back(pubnameDesc);
+ }
+ }
+ else
+ break; // We are done if we get a zero 4 byte offset
+ }
+
+ return !m_descriptors.empty();
+ }
+ return false;
+}
+
+dw_offset_t
+DWARFDebugPubnamesSet::GetOffsetOfNextEntry() const
+{
+ return m_offset + m_header.length + 4;
+}
+
+void
+DWARFDebugPubnamesSet::Dump(Log *log) const
+{
+ log->Printf("Pubnames Header: length = 0x%8.8x, version = 0x%4.4x, die_offset = 0x%8.8x, die_length = 0x%8.8x",
+ m_header.length,
+ m_header.version,
+ m_header.die_offset,
+ m_header.die_length);
+
+ bool verbose = log->GetVerbose();
+
+ DescriptorConstIter pos;
+ DescriptorConstIter end = m_descriptors.end();
+ for (pos = m_descriptors.begin(); pos != end; ++pos)
+ {
+ if (verbose)
+ log->Printf("0x%8.8x + 0x%8.8x = 0x%8.8x: %s", pos->offset, m_header.die_offset, pos->offset + m_header.die_offset, pos->name.c_str());
+ else
+ log->Printf("0x%8.8x: %s", pos->offset + m_header.die_offset, pos->name.c_str());
+ }
+}
+
+
+void
+DWARFDebugPubnamesSet::Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offset_coll) const
+{
+ if (!m_descriptors.empty() && m_name_to_descriptor_index.empty())
+ InitNameIndexes();
+
+ std::pair<cstr_to_index_mmap::const_iterator, cstr_to_index_mmap::const_iterator> range(m_name_to_descriptor_index.equal_range(name));
+ for (cstr_to_index_mmap::const_iterator pos = range.first; pos != range.second; ++pos)
+ die_offset_coll.push_back(m_header.die_offset + m_descriptors[(*pos).second].offset);
+}
+
+void
+DWARFDebugPubnamesSet::Find(const RegularExpression& regex, std::vector<dw_offset_t>& die_offset_coll) const
+{
+ DescriptorConstIter pos;
+ DescriptorConstIter end = m_descriptors.end();
+ for (pos = m_descriptors.begin(); pos != end; ++pos)
+ {
+ if ( regex.Execute(pos->name.c_str()) )
+ die_offset_coll.push_back(m_header.die_offset + pos->offset);
+ }
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h
new file mode 100644
index 000000000000..941c83e58a44
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugPubnamesSet.h
@@ -0,0 +1,99 @@
+//===-- DWARFDebugPubnamesSet.h ---------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugPubnamesSet_h_
+#define SymbolFileDWARF_DWARFDebugPubnamesSet_h_
+
+#include "SymbolFileDWARF.h"
+#include <string>
+#include <vector>
+#if __cplusplus >= 201103L
+#include <unordered_map>
+#else
+#include <ext/hash_map>
+#endif
+
+class DWARFDebugPubnamesSet
+{
+public:
+ struct Header
+ {
+ uint32_t length; // length of the set of entries for this compilation unit, not including the length field itself
+ uint16_t version; // The DWARF version number
+ uint32_t die_offset; // compile unit .debug_info offset
+ uint32_t die_length; // compile unit .debug_info length
+ Header() :
+ length(10),
+ version(2),
+ die_offset(DW_INVALID_OFFSET),
+ die_length(0)
+ {
+ }
+ };
+
+ struct Descriptor
+ {
+ Descriptor() :
+ offset(),
+ name()
+ {
+ }
+
+ Descriptor(dw_offset_t the_offset, const char *the_name) :
+ offset(the_offset),
+ name(the_name ? the_name : "")
+ {
+ }
+
+ dw_offset_t offset;
+ std::string name;
+ };
+
+ DWARFDebugPubnamesSet();
+ DWARFDebugPubnamesSet(dw_offset_t debug_aranges_offset, dw_offset_t cu_die_offset, dw_offset_t die_length);
+ dw_offset_t GetOffset() const { return m_offset; }
+ void SetOffset(dw_offset_t offset) { m_offset = offset; }
+ DWARFDebugPubnamesSet::Header& GetHeader() { return m_header; }
+ const DWARFDebugPubnamesSet::Header& GetHeader() const { return m_header; }
+ const DWARFDebugPubnamesSet::Descriptor* GetDescriptor(uint32_t i) const
+ {
+ if (i < m_descriptors.size())
+ return &m_descriptors[i];
+ return NULL;
+ }
+ uint32_t NumDescriptors() const { return m_descriptors.size(); }
+ void AddDescriptor(dw_offset_t cu_rel_offset, const char* name);
+ void Clear();
+ bool Extract(const lldb_private::DataExtractor& debug_pubnames_data, lldb::offset_t *offset_ptr);
+ void Dump(lldb_private::Log *s) const;
+ void InitNameIndexes() const;
+ void Find(const char* name, bool ignore_case, std::vector<dw_offset_t>& die_offset_coll) const;
+ void Find(const lldb_private::RegularExpression& regex, std::vector<dw_offset_t>& die_offsets) const;
+ dw_offset_t GetOffsetOfNextEntry() const;
+
+
+
+protected:
+ typedef std::vector<Descriptor> DescriptorColl;
+ typedef DescriptorColl::iterator DescriptorIter;
+ typedef DescriptorColl::const_iterator DescriptorConstIter;
+
+
+ dw_offset_t m_offset;
+ Header m_header;
+#if __cplusplus >= 201103L
+ typedef std::unordered_multimap<const char*, uint32_t, std::hash<const char*>, CStringEqualBinaryPredicate> cstr_to_index_mmap;
+#else
+ typedef __gnu_cxx::hash_multimap<const char*, uint32_t, __gnu_cxx::hash<const char*>, CStringEqualBinaryPredicate> cstr_to_index_mmap;
+#endif
+ DescriptorColl m_descriptors;
+ mutable cstr_to_index_mmap m_name_to_descriptor_index;
+};
+
+#endif // SymbolFileDWARF_DWARFDebugPubnamesSet_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp
new file mode 100644
index 000000000000..461b17fc3aba
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.cpp
@@ -0,0 +1,192 @@
+//===-- DWARFDebugRanges.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDebugRanges.h"
+#include "SymbolFileDWARF.h"
+#include "lldb/Core/Stream.h"
+#include <assert.h>
+
+using namespace lldb_private;
+using namespace std;
+
+DWARFDebugRanges::DWARFDebugRanges() :
+ m_range_map()
+{
+}
+
+DWARFDebugRanges::~DWARFDebugRanges()
+{
+}
+
+void
+DWARFDebugRanges::Extract(SymbolFileDWARF* dwarf2Data)
+{
+ RangeList range_list;
+ lldb::offset_t offset = 0;
+ dw_offset_t debug_ranges_offset = offset;
+ while (Extract(dwarf2Data, &offset, range_list))
+ {
+ m_range_map[debug_ranges_offset] = range_list;
+ debug_ranges_offset = offset;
+ }
+}
+
+//void
+//DWARFDebugRanges::RangeList::AddOffset(dw_addr_t offset)
+//{
+// if (!ranges.empty())
+// {
+// Range::iterator pos = ranges.begin();
+// Range::iterator end_pos = ranges.end();
+// for (pos = ranges.begin(); pos != end_pos; ++pos)
+// {
+// // assert for unsigned overflows
+// assert (~pos->begin_offset >= offset);
+// assert (~pos->end_offset >= offset);
+// pos->begin_offset += offset;
+// pos->end_offset += offset;
+// }
+// }
+//}
+//
+//void
+//DWARFDebugRanges::RangeList::SubtractOffset(dw_addr_t offset)
+//{
+// if (!ranges.empty())
+// {
+// Range::iterator pos = ranges.begin();
+// Range::iterator end_pos = ranges.end();
+// for (pos = ranges.begin(); pos != end_pos; ++pos)
+// {
+// assert (pos->begin_offset >= offset);
+// assert (pos->end_offset >= offset);
+// pos->begin_offset -= offset;
+// pos->end_offset -= offset;
+// }
+// }
+//}
+//
+//
+//const DWARFDebugRanges::Range*
+//DWARFDebugRanges::RangeList::RangeAtIndex(size_t i) const
+//{
+// if (i < ranges.size())
+// return &ranges[i];
+// return NULL;
+//}
+
+bool
+DWARFDebugRanges::Extract(SymbolFileDWARF* dwarf2Data, lldb::offset_t *offset_ptr, RangeList &range_list)
+{
+ range_list.Clear();
+
+ lldb::offset_t range_offset = *offset_ptr;
+ const DataExtractor& debug_ranges_data = dwarf2Data->get_debug_ranges_data();
+ uint32_t addr_size = debug_ranges_data.GetAddressByteSize();
+
+ while (debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size))
+ {
+ dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
+ dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
+ if (!begin && !end)
+ {
+ // End of range list
+ break;
+ }
+ // Extend 4 byte addresses that consists of 32 bits of 1's to be 64 bits
+ // of ones
+ switch (addr_size)
+ {
+ case 2:
+ if (begin == 0xFFFFull)
+ begin = LLDB_INVALID_ADDRESS;
+ break;
+
+ case 4:
+ if (begin == 0xFFFFFFFFull)
+ begin = LLDB_INVALID_ADDRESS;
+ break;
+
+ case 8:
+ break;
+
+ default:
+ assert(!"DWARFDebugRanges::RangeList::Extract() unsupported address size.");
+ break;
+ }
+
+ // Filter out empty ranges
+ if (begin < end)
+ range_list.Append(Range(begin, end - begin));
+ }
+
+ // Make sure we consumed at least something
+ return range_offset != *offset_ptr;
+}
+
+
+void
+DWARFDebugRanges::Dump(Stream &s, const DataExtractor& debug_ranges_data, lldb::offset_t *offset_ptr, dw_addr_t cu_base_addr)
+{
+ uint32_t addr_size = s.GetAddressByteSize();
+ bool verbose = s.GetVerbose();
+
+ dw_addr_t base_addr = cu_base_addr;
+ while (debug_ranges_data.ValidOffsetForDataOfSize(*offset_ptr, 2 * addr_size))
+ {
+ dw_addr_t begin = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
+ dw_addr_t end = debug_ranges_data.GetMaxU64(offset_ptr, addr_size);
+ // Extend 4 byte addresses that consits of 32 bits of 1's to be 64 bits
+ // of ones
+ if (begin == 0xFFFFFFFFull && addr_size == 4)
+ begin = LLDB_INVALID_ADDRESS;
+
+ s.Indent();
+ if (verbose)
+ {
+ s.AddressRange(begin, end, sizeof (dw_addr_t), " offsets = ");
+ }
+
+
+ if (begin == 0 && end == 0)
+ {
+ s.PutCString(" End");
+ break;
+ }
+ else if (begin == LLDB_INVALID_ADDRESS)
+ {
+ // A base address selection entry
+ base_addr = end;
+ s.Address(base_addr, sizeof (dw_addr_t), " Base address = ");
+ }
+ else
+ {
+ // Convert from offset to an address
+ dw_addr_t begin_addr = begin + base_addr;
+ dw_addr_t end_addr = end + base_addr;
+
+ s.AddressRange(begin_addr, end_addr, sizeof (dw_addr_t), verbose ? " ==> addrs = " : NULL);
+ }
+ }
+}
+
+bool
+DWARFDebugRanges::FindRanges(dw_offset_t debug_ranges_offset, RangeList& range_list) const
+{
+ range_map_const_iterator pos = m_range_map.find(debug_ranges_offset);
+ if (pos != m_range_map.end())
+ {
+ range_list = pos->second;
+ return true;
+ }
+ return false;
+}
+
+
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h
new file mode 100644
index 000000000000..40899abe9c25
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDebugRanges.h
@@ -0,0 +1,46 @@
+//===-- DWARFDebugRanges.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDebugRanges_h_
+#define SymbolFileDWARF_DWARFDebugRanges_h_
+
+#include "SymbolFileDWARF.h"
+
+#include <map>
+#include <vector>
+
+#include "lldb/Core/RangeMap.h"
+
+class DWARFDebugRanges
+{
+public:
+ typedef lldb_private::RangeArray<dw_addr_t, dw_addr_t, 2> RangeList;
+ typedef RangeList::Entry Range;
+
+ DWARFDebugRanges();
+ ~DWARFDebugRanges();
+ void Extract(SymbolFileDWARF* dwarf2Data);
+ static void Dump(lldb_private::Stream &s, const lldb_private::DataExtractor& debug_ranges_data, lldb::offset_t *offset_ptr, dw_addr_t cu_base_addr);
+ bool FindRanges(dw_offset_t debug_ranges_offset, DWARFDebugRanges::RangeList& range_list) const;
+
+protected:
+
+ bool
+ Extract (SymbolFileDWARF* dwarf2Data,
+ lldb::offset_t *offset_ptr,
+ RangeList &range_list);
+
+ typedef std::map<dw_offset_t, RangeList> range_map;
+ typedef range_map::iterator range_map_iterator;
+ typedef range_map::const_iterator range_map_const_iterator;
+ range_map m_range_map;
+};
+
+
+#endif // SymbolFileDWARF_DWARFDebugRanges_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
new file mode 100644
index 000000000000..abf69190c93c
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.cpp
@@ -0,0 +1,104 @@
+//===-- DWARFDeclContext.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDeclContext.h"
+
+const char *
+DWARFDeclContext::GetQualifiedName () const
+{
+ if (m_qualified_name.empty())
+ {
+ // The declaration context array for a class named "foo" in namespace
+ // "a::b::c" will be something like:
+ // [0] DW_TAG_class_type "foo"
+ // [1] DW_TAG_namespace "c"
+ // [2] DW_TAG_namespace "b"
+ // [3] DW_TAG_namespace "a"
+ if (!m_entries.empty())
+ {
+ if (m_entries.size() == 1)
+ {
+ if (m_entries[0].name)
+ {
+ m_qualified_name.append("::");
+ m_qualified_name.append(m_entries[0].name);
+ }
+ }
+ else
+ {
+ collection::const_reverse_iterator pos;
+ collection::const_reverse_iterator begin = m_entries.rbegin();
+ collection::const_reverse_iterator end = m_entries.rend();
+ for (pos = begin; pos != end; ++pos)
+ {
+ if (pos != begin)
+ m_qualified_name.append("::");
+ if (pos->name == NULL)
+ {
+ if (pos->tag == DW_TAG_namespace)
+ m_qualified_name.append ("(anonymous namespace)");
+ else if (pos->tag == DW_TAG_class_type)
+ m_qualified_name.append ("(anonymous class)");
+ else if (pos->tag == DW_TAG_structure_type)
+ m_qualified_name.append ("(anonymous struct)");
+ else if (pos->tag == DW_TAG_union_type)
+ m_qualified_name.append ("(anonymous union)");
+ else
+ m_qualified_name.append ("(anonymous)");
+ }
+ else
+ m_qualified_name.append(pos->name);
+ }
+ }
+ }
+ }
+ if (m_qualified_name.empty())
+ return NULL;
+ return m_qualified_name.c_str();
+}
+
+
+bool
+DWARFDeclContext::operator==(const DWARFDeclContext& rhs) const
+{
+ if (m_entries.size() != rhs.m_entries.size())
+ return false;
+
+ collection::const_iterator pos;
+ collection::const_iterator begin = m_entries.begin();
+ collection::const_iterator end = m_entries.end();
+
+ collection::const_iterator rhs_pos;
+ collection::const_iterator rhs_begin = rhs.m_entries.begin();
+ // The two entry arrays have the same size
+
+ // First compare the tags before we do expensize name compares
+ for (pos = begin, rhs_pos = rhs_begin; pos != end; ++pos, ++rhs_pos)
+ {
+ if (pos->tag != rhs_pos->tag)
+ {
+ // Check for DW_TAG_structure_type and DW_TAG_class_type as they are often
+ // used interchangeably in GCC
+ if (pos->tag == DW_TAG_structure_type && rhs_pos->tag == DW_TAG_class_type)
+ continue;
+ if (pos->tag == DW_TAG_class_type && rhs_pos->tag == DW_TAG_structure_type)
+ continue;
+ return false;
+ }
+ }
+ // The tags all match, now compare the names
+ for (pos = begin, rhs_pos = rhs_begin; pos != end; ++pos, ++rhs_pos)
+ {
+ if (!pos->NameMatches (*rhs_pos))
+ return false;
+ }
+ // All tags and names match
+ return true;
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
new file mode 100644
index 000000000000..accd3446317a
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDeclContext.h
@@ -0,0 +1,109 @@
+//===-- DWARFDeclContext.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDeclContext_h_
+#define SymbolFileDWARF_DWARFDeclContext_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <vector>
+// Other libraries and framework includes
+#include "lldb/Core/ConstString.h"
+// Project includes
+#include "DWARFDefines.h"
+
+//----------------------------------------------------------------------
+// DWARFDeclContext
+//
+// A class that represents a declaration context all the way down to a
+// DIE. This is useful when trying to find a DIE in one DWARF to a DIE
+// in another DWARF file.
+//----------------------------------------------------------------------
+
+class DWARFDeclContext
+{
+public:
+ struct Entry
+ {
+ Entry () :
+ tag(0),
+ name(NULL)
+ {
+ }
+ Entry (dw_tag_t t, const char *n) :
+ tag(t),
+ name(n)
+ {
+ }
+
+ bool
+ NameMatches (const Entry& rhs) const
+ {
+ if (name == rhs.name)
+ return true;
+ else if (name && rhs.name)
+ return strcmp(name, rhs.name) == 0;
+ return false;
+ }
+
+ // Test operator
+ operator bool() const
+ {
+ return tag != 0;
+ }
+
+ dw_tag_t tag;
+ const char *name;
+ };
+
+ DWARFDeclContext () :
+ m_entries()
+ {
+ }
+
+ void
+ AppendDeclContext (dw_tag_t tag, const char *name)
+ {
+ m_entries.push_back(Entry(tag, name));
+ }
+
+ bool
+ operator ==(const DWARFDeclContext& rhs) const;
+
+ uint32_t
+ GetSize() const
+ {
+ return m_entries.size();
+ }
+
+ Entry &
+ operator[] (uint32_t idx)
+ {
+ // "idx" must be valid
+ return m_entries[idx];
+ }
+
+ const Entry &
+ operator[] (uint32_t idx) const
+ {
+ // "idx" must be valid
+ return m_entries[idx];
+ }
+
+ const char *
+ GetQualifiedName () const;
+
+protected:
+ typedef std::vector<Entry> collection;
+ collection m_entries;
+ mutable std::string m_qualified_name;
+};
+
+#endif // SymbolFileDWARF_DWARFDeclContext_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp b/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp
new file mode 100644
index 000000000000..fe4093bc130e
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDefines.cpp
@@ -0,0 +1,497 @@
+//===-- DWARFDefines.c ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFDefines.h"
+#include <cstdio>
+#include <cstring>
+#include <string>
+#include "lldb/Core/ConstString.h"
+
+namespace lldb_private {
+
+const char *
+DW_TAG_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+
+ if (val == 0)
+ return "NULL";
+
+ const char *llvmstr = llvm::dwarf::TagString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_TAG constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_CHILDREN_value_to_name (uint8_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::ChildrenString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_CHILDREN constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_AT_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::AttributeString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_AT constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_FORM_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::FormEncodingString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_FORM constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_OP_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::OperationEncodingString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_OP constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+DRC_class
+DW_OP_value_to_class (uint32_t val)
+{
+ switch (val) {
+ case 0x03: return DRC_ONEOPERAND;
+ case 0x06: return DRC_ZEROOPERANDS;
+ case 0x08: return DRC_ONEOPERAND;
+ case 0x09: return DRC_ONEOPERAND;
+ case 0x0a: return DRC_ONEOPERAND;
+ case 0x0b: return DRC_ONEOPERAND;
+ case 0x0c: return DRC_ONEOPERAND;
+ case 0x0d: return DRC_ONEOPERAND;
+ case 0x0e: return DRC_ONEOPERAND;
+ case 0x0f: return DRC_ONEOPERAND;
+ case 0x10: return DRC_ONEOPERAND;
+ case 0x11: return DRC_ONEOPERAND;
+ case 0x12: return DRC_ZEROOPERANDS;
+ case 0x13: return DRC_ZEROOPERANDS;
+ case 0x14: return DRC_ZEROOPERANDS;
+ case 0x15: return DRC_ONEOPERAND;
+ case 0x16: return DRC_ZEROOPERANDS;
+ case 0x17: return DRC_ZEROOPERANDS;
+ case 0x18: return DRC_ZEROOPERANDS;
+ case 0x19: return DRC_ZEROOPERANDS;
+ case 0x1a: return DRC_ZEROOPERANDS;
+ case 0x1b: return DRC_ZEROOPERANDS;
+ case 0x1c: return DRC_ZEROOPERANDS;
+ case 0x1d: return DRC_ZEROOPERANDS;
+ case 0x1e: return DRC_ZEROOPERANDS;
+ case 0x1f: return DRC_ZEROOPERANDS;
+ case 0x20: return DRC_ZEROOPERANDS;
+ case 0x21: return DRC_ZEROOPERANDS;
+ case 0x22: return DRC_ZEROOPERANDS;
+ case 0x23: return DRC_ONEOPERAND;
+ case 0x24: return DRC_ZEROOPERANDS;
+ case 0x25: return DRC_ZEROOPERANDS;
+ case 0x26: return DRC_ZEROOPERANDS;
+ case 0x27: return DRC_ZEROOPERANDS;
+ case 0x2f: return DRC_ONEOPERAND;
+ case 0x28: return DRC_ONEOPERAND;
+ case 0x29: return DRC_ZEROOPERANDS;
+ case 0x2a: return DRC_ZEROOPERANDS;
+ case 0x2b: return DRC_ZEROOPERANDS;
+ case 0x2c: return DRC_ZEROOPERANDS;
+ case 0x2d: return DRC_ZEROOPERANDS;
+ case 0x2e: return DRC_ZEROOPERANDS;
+ case 0x30: return DRC_ZEROOPERANDS;
+ case 0x31: return DRC_ZEROOPERANDS;
+ case 0x32: return DRC_ZEROOPERANDS;
+ case 0x33: return DRC_ZEROOPERANDS;
+ case 0x34: return DRC_ZEROOPERANDS;
+ case 0x35: return DRC_ZEROOPERANDS;
+ case 0x36: return DRC_ZEROOPERANDS;
+ case 0x37: return DRC_ZEROOPERANDS;
+ case 0x38: return DRC_ZEROOPERANDS;
+ case 0x39: return DRC_ZEROOPERANDS;
+ case 0x3a: return DRC_ZEROOPERANDS;
+ case 0x3b: return DRC_ZEROOPERANDS;
+ case 0x3c: return DRC_ZEROOPERANDS;
+ case 0x3d: return DRC_ZEROOPERANDS;
+ case 0x3e: return DRC_ZEROOPERANDS;
+ case 0x3f: return DRC_ZEROOPERANDS;
+ case 0x40: return DRC_ZEROOPERANDS;
+ case 0x41: return DRC_ZEROOPERANDS;
+ case 0x42: return DRC_ZEROOPERANDS;
+ case 0x43: return DRC_ZEROOPERANDS;
+ case 0x44: return DRC_ZEROOPERANDS;
+ case 0x45: return DRC_ZEROOPERANDS;
+ case 0x46: return DRC_ZEROOPERANDS;
+ case 0x47: return DRC_ZEROOPERANDS;
+ case 0x48: return DRC_ZEROOPERANDS;
+ case 0x49: return DRC_ZEROOPERANDS;
+ case 0x4a: return DRC_ZEROOPERANDS;
+ case 0x4b: return DRC_ZEROOPERANDS;
+ case 0x4c: return DRC_ZEROOPERANDS;
+ case 0x4d: return DRC_ZEROOPERANDS;
+ case 0x4e: return DRC_ZEROOPERANDS;
+ case 0x4f: return DRC_ZEROOPERANDS;
+ case 0x50: return DRC_ZEROOPERANDS;
+ case 0x51: return DRC_ZEROOPERANDS;
+ case 0x52: return DRC_ZEROOPERANDS;
+ case 0x53: return DRC_ZEROOPERANDS;
+ case 0x54: return DRC_ZEROOPERANDS;
+ case 0x55: return DRC_ZEROOPERANDS;
+ case 0x56: return DRC_ZEROOPERANDS;
+ case 0x57: return DRC_ZEROOPERANDS;
+ case 0x58: return DRC_ZEROOPERANDS;
+ case 0x59: return DRC_ZEROOPERANDS;
+ case 0x5a: return DRC_ZEROOPERANDS;
+ case 0x5b: return DRC_ZEROOPERANDS;
+ case 0x5c: return DRC_ZEROOPERANDS;
+ case 0x5d: return DRC_ZEROOPERANDS;
+ case 0x5e: return DRC_ZEROOPERANDS;
+ case 0x5f: return DRC_ZEROOPERANDS;
+ case 0x60: return DRC_ZEROOPERANDS;
+ case 0x61: return DRC_ZEROOPERANDS;
+ case 0x62: return DRC_ZEROOPERANDS;
+ case 0x63: return DRC_ZEROOPERANDS;
+ case 0x64: return DRC_ZEROOPERANDS;
+ case 0x65: return DRC_ZEROOPERANDS;
+ case 0x66: return DRC_ZEROOPERANDS;
+ case 0x67: return DRC_ZEROOPERANDS;
+ case 0x68: return DRC_ZEROOPERANDS;
+ case 0x69: return DRC_ZEROOPERANDS;
+ case 0x6a: return DRC_ZEROOPERANDS;
+ case 0x6b: return DRC_ZEROOPERANDS;
+ case 0x6c: return DRC_ZEROOPERANDS;
+ case 0x6d: return DRC_ZEROOPERANDS;
+ case 0x6e: return DRC_ZEROOPERANDS;
+ case 0x6f: return DRC_ZEROOPERANDS;
+ case 0x70: return DRC_ONEOPERAND;
+ case 0x71: return DRC_ONEOPERAND;
+ case 0x72: return DRC_ONEOPERAND;
+ case 0x73: return DRC_ONEOPERAND;
+ case 0x74: return DRC_ONEOPERAND;
+ case 0x75: return DRC_ONEOPERAND;
+ case 0x76: return DRC_ONEOPERAND;
+ case 0x77: return DRC_ONEOPERAND;
+ case 0x78: return DRC_ONEOPERAND;
+ case 0x79: return DRC_ONEOPERAND;
+ case 0x7a: return DRC_ONEOPERAND;
+ case 0x7b: return DRC_ONEOPERAND;
+ case 0x7c: return DRC_ONEOPERAND;
+ case 0x7d: return DRC_ONEOPERAND;
+ case 0x7e: return DRC_ONEOPERAND;
+ case 0x7f: return DRC_ONEOPERAND;
+ case 0x80: return DRC_ONEOPERAND;
+ case 0x81: return DRC_ONEOPERAND;
+ case 0x82: return DRC_ONEOPERAND;
+ case 0x83: return DRC_ONEOPERAND;
+ case 0x84: return DRC_ONEOPERAND;
+ case 0x85: return DRC_ONEOPERAND;
+ case 0x86: return DRC_ONEOPERAND;
+ case 0x87: return DRC_ONEOPERAND;
+ case 0x88: return DRC_ONEOPERAND;
+ case 0x89: return DRC_ONEOPERAND;
+ case 0x8a: return DRC_ONEOPERAND;
+ case 0x8b: return DRC_ONEOPERAND;
+ case 0x8c: return DRC_ONEOPERAND;
+ case 0x8d: return DRC_ONEOPERAND;
+ case 0x8e: return DRC_ONEOPERAND;
+ case 0x8f: return DRC_ONEOPERAND;
+ case 0x90: return DRC_ONEOPERAND;
+ case 0x91: return DRC_ONEOPERAND;
+ case 0x92: return DRC_TWOOPERANDS;
+ case 0x93: return DRC_ONEOPERAND;
+ case 0x94: return DRC_ONEOPERAND;
+ case 0x95: return DRC_ONEOPERAND;
+ case 0x96: return DRC_ZEROOPERANDS;
+ case 0x97: return DRC_DWARFv3 | DRC_ZEROOPERANDS;
+ case 0x98: return DRC_DWARFv3 | DRC_ONEOPERAND;
+ case 0x99: return DRC_DWARFv3 | DRC_ONEOPERAND;
+ case 0x9a: return DRC_DWARFv3 | DRC_ONEOPERAND;
+ case 0xf0: return DRC_ZEROOPERANDS; /* DW_OP_APPLE_uninit */
+ case 0xe0: return 0;
+ case 0xff: return 0;
+ default: return 0;
+ }
+}
+
+const char *
+DW_ATE_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::AttributeEncodingString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_ATE constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_ACCESS_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+
+ const char *llvmstr = llvm::dwarf::AccessibilityString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_ACCESS constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_VIS_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::VisibilityString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_VIS constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_VIRTUALITY_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::VirtualityString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_VIRTUALITY constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_LANG_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::LanguageString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_LANG constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_ID_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::CaseString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_ID constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_CC_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::ConventionString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_CC constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_INL_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::InlineCodeString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_INL constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_ORD_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::ArrayOrderString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_ORD constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_DSC_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::DiscriminantString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_DSC constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_LNS_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::LNStandardString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_LNS constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_LNE_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::LNExtendedString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_LNE constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_MACINFO_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::MacinfoString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_MACINFO constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+const char *
+DW_CFA_value_to_name (uint32_t val)
+{
+ static char invalid[100];
+ const char *llvmstr = llvm::dwarf::CallFrameString (val);
+ if (llvmstr == NULL)
+ {
+ snprintf (invalid, sizeof (invalid), "Unknown DW_CFA constant: 0x%x", val);
+ return invalid;
+ }
+ return llvmstr;
+}
+
+DW_TAG_CategoryEnum
+get_tag_category (uint16_t tag)
+{
+ switch (tag)
+ {
+ case DW_TAG_array_type : return TagCategoryType;
+ case DW_TAG_class_type : return TagCategoryType;
+ case DW_TAG_entry_point : return TagCategoryProgram;
+ case DW_TAG_enumeration_type : return TagCategoryType;
+ case DW_TAG_formal_parameter : return TagCategoryVariable;
+ case DW_TAG_imported_declaration : return TagCategoryProgram;
+ case DW_TAG_label : return TagCategoryProgram;
+ case DW_TAG_lexical_block : return TagCategoryProgram;
+ case DW_TAG_member : return TagCategoryType;
+ case DW_TAG_pointer_type : return TagCategoryType;
+ case DW_TAG_reference_type : return TagCategoryType;
+ case DW_TAG_compile_unit : return TagCategoryProgram;
+ case DW_TAG_string_type : return TagCategoryType;
+ case DW_TAG_structure_type : return TagCategoryType;
+ case DW_TAG_subroutine_type : return TagCategoryType;
+ case DW_TAG_typedef : return TagCategoryType;
+ case DW_TAG_union_type : return TagCategoryType;
+ case DW_TAG_unspecified_parameters : return TagCategoryVariable;
+ case DW_TAG_variant : return TagCategoryType;
+ case DW_TAG_common_block : return TagCategoryProgram;
+ case DW_TAG_common_inclusion : return TagCategoryProgram;
+ case DW_TAG_inheritance : return TagCategoryType;
+ case DW_TAG_inlined_subroutine : return TagCategoryProgram;
+ case DW_TAG_module : return TagCategoryProgram;
+ case DW_TAG_ptr_to_member_type : return TagCategoryType;
+ case DW_TAG_set_type : return TagCategoryType;
+ case DW_TAG_subrange_type : return TagCategoryType;
+ case DW_TAG_with_stmt : return TagCategoryProgram;
+ case DW_TAG_access_declaration : return TagCategoryProgram;
+ case DW_TAG_base_type : return TagCategoryType;
+ case DW_TAG_catch_block : return TagCategoryProgram;
+ case DW_TAG_const_type : return TagCategoryType;
+ case DW_TAG_constant : return TagCategoryVariable;
+ case DW_TAG_enumerator : return TagCategoryType;
+ case DW_TAG_file_type : return TagCategoryType;
+ case DW_TAG_friend : return TagCategoryType;
+ case DW_TAG_namelist : return TagCategoryVariable;
+ case DW_TAG_namelist_item : return TagCategoryVariable;
+ case DW_TAG_packed_type : return TagCategoryType;
+ case DW_TAG_subprogram : return TagCategoryProgram;
+ case DW_TAG_template_type_parameter : return TagCategoryType;
+ case DW_TAG_template_value_parameter : return TagCategoryType;
+ case DW_TAG_thrown_type : return TagCategoryType;
+ case DW_TAG_try_block : return TagCategoryProgram;
+ case DW_TAG_variant_part : return TagCategoryType;
+ case DW_TAG_variable : return TagCategoryVariable;
+ case DW_TAG_volatile_type : return TagCategoryType;
+ case DW_TAG_dwarf_procedure : return TagCategoryProgram;
+ case DW_TAG_restrict_type : return TagCategoryType;
+ case DW_TAG_interface_type : return TagCategoryType;
+ case DW_TAG_namespace : return TagCategoryProgram;
+ case DW_TAG_imported_module : return TagCategoryProgram;
+ case DW_TAG_unspecified_type : return TagCategoryType;
+ case DW_TAG_partial_unit : return TagCategoryProgram;
+ case DW_TAG_imported_unit : return TagCategoryProgram;
+ case DW_TAG_shared_type : return TagCategoryType;
+ default: break;
+ }
+ return TagCategoryProgram;
+}
+
+} // namespace lldb_private
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFDefines.h b/source/Plugins/SymbolFile/DWARF/DWARFDefines.h
new file mode 100644
index 000000000000..e37aefb27a72
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFDefines.h
@@ -0,0 +1,116 @@
+//===-- DWARFDefines.h ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFDefines_h_
+#define SymbolFileDWARF_DWARFDefines_h_
+
+#include <stdint.h>
+#include <stdbool.h>
+#include "lldb/Core/dwarf.h"
+
+namespace lldb_private {
+
+typedef uint32_t DRC_class; // Holds DRC_* class bitfields
+
+enum DW_TAG_Category
+{
+ TagCategoryVariable,
+ TagCategoryType,
+ TagCategoryProgram,
+ kNumTagCategories
+};
+
+typedef enum DW_TAG_Category DW_TAG_CategoryEnum;
+
+const char *DW_TAG_value_to_name (uint32_t val);
+
+DW_TAG_CategoryEnum get_tag_category (uint16_t tag);
+
+const char *DW_CHILDREN_value_to_name (uint8_t val);
+
+const char *DW_AT_value_to_name (uint32_t val);
+
+const char *DW_FORM_value_to_name (uint32_t val);
+
+const char *DW_OP_value_to_name (uint32_t val);
+
+DRC_class DW_OP_value_to_class (uint32_t val);
+
+const char *DW_ATE_value_to_name (uint32_t val);
+
+const char *DW_ACCESS_value_to_name (uint32_t val);
+
+const char *DW_VIS_value_to_name (uint32_t val);
+
+const char *DW_VIRTUALITY_value_to_name (uint32_t val);
+
+const char *DW_LANG_value_to_name (uint32_t val);
+
+const char *DW_ID_value_to_name (uint32_t val);
+
+const char *DW_CC_value_to_name (uint32_t val);
+
+const char *DW_INL_value_to_name (uint32_t val);
+
+const char *DW_ORD_value_to_name (uint32_t val);
+
+const char *DW_DSC_value_to_name (uint32_t val);
+
+const char *DW_LNS_value_to_name (uint32_t val);
+
+const char *DW_LNE_value_to_name (uint32_t val);
+
+const char *DW_MACINFO_value_to_name (uint32_t val);
+
+const char *DW_CFA_value_to_name (uint32_t val);
+
+const char *DW_GNU_EH_PE_value_to_name (uint32_t val);
+
+/* These DRC are entirely our own construction,
+ although they are derived from various comments in the DWARF standard.
+ Most of these are not useful to the parser, but the DW_AT and DW_FORM
+ classes should prove to be usable in some fashion. */
+
+#define DRC_0x65 0x1
+#define DRC_ADDRESS 0x2
+#define DRC_BLOCK 0x4
+#define DRC_CONSTANT 0x8
+#define DRC_DWARFv3 0x10
+#define DRC_FLAG 0x20
+#define DRC_INDIRECT_SPECIAL 0x40
+#define DRC_LINEPTR 0x80
+#define DRC_LOCEXPR 0x100
+#define DRC_LOCLISTPTR 0x200
+#define DRC_MACPTR 0x400
+#define DRC_ONEOPERAND 0x800
+#define DRC_OPERANDONE_1BYTE_DELTA 0x1000
+#define DRC_OPERANDONE_2BYTE_DELTA 0x2000
+#define DRC_OPERANDONE_4BYTE_DELTA 0x4000
+#define DRC_OPERANDONE_ADDRESS 0x8000
+#define DRC_OPERANDONE_BLOCK 0x10000
+#define DRC_OPERANDONE_SLEB128_OFFSET 0x20000
+#define DRC_OPERANDONE_ULEB128_OFFSET 0x40000
+#define DRC_OPERANDONE_ULEB128_REGISTER 0x80000
+#define DRC_OPERANDTWO_BLOCK 0x100000
+#define DRC_OPERANDTWO_SLEB128_OFFSET 0x200000
+#define DRC_OPERANDTWO_ULEB128_OFFSET 0x400000
+#define DRC_OPERANDTWO_ULEB128_REGISTER 0x800000
+#define DRC_OPERNADONE_ULEB128_REGISTER 0x1000000
+#define DRC_RANGELISTPTR 0x2000000
+#define DRC_REFERENCE 0x4000000
+#define DRC_STRING 0x8000000
+#define DRC_TWOOPERANDS 0x10000000
+#define DRC_VENDOR_GNU 0x20000000
+#define DRC_VENDOR_MIPS 0x40000000
+#define DRC_ZEROOPERANDS 0x80000000
+
+} // namespace lldb_private
+
+
+#endif // SymbolFileDWARF_DWARFDefines_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
new file mode 100644
index 000000000000..6113a146c93d
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
@@ -0,0 +1,599 @@
+//===-- DWARFFormValue.cpp --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <assert.h>
+
+#include "lldb/Core/dwarf.h"
+#include "lldb/Core/Stream.h"
+
+#include "DWARFFormValue.h"
+#include "DWARFCompileUnit.h"
+
+class DWARFCompileUnit;
+
+using namespace lldb_private;
+
+
+static uint8_t g_form_sizes_addr4[] =
+{
+ 0, // 0x00 unused
+ 4, // 0x01 DW_FORM_addr
+ 0, // 0x02 unused
+ 0, // 0x03 DW_FORM_block2
+ 0, // 0x04 DW_FORM_block4
+ 2, // 0x05 DW_FORM_data2
+ 4, // 0x06 DW_FORM_data4
+ 8, // 0x07 DW_FORM_data8
+ 0, // 0x08 DW_FORM_string
+ 0, // 0x09 DW_FORM_block
+ 0, // 0x0a DW_FORM_block1
+ 1, // 0x0b DW_FORM_data1
+ 1, // 0x0c DW_FORM_flag
+ 0, // 0x0d DW_FORM_sdata
+ 4, // 0x0e DW_FORM_strp
+ 0, // 0x0f DW_FORM_udata
+ 0, // 0x10 DW_FORM_ref_addr (addr size for DWARF2 and earlier, 4 bytes for DWARF32, 8 bytes for DWARF32 in DWARF 3 and later
+ 1, // 0x11 DW_FORM_ref1
+ 2, // 0x12 DW_FORM_ref2
+ 4, // 0x13 DW_FORM_ref4
+ 8, // 0x14 DW_FORM_ref8
+ 0, // 0x15 DW_FORM_ref_udata
+ 0, // 0x16 DW_FORM_indirect
+ 4, // 0x17 DW_FORM_sec_offset
+ 0, // 0x18 DW_FORM_exprloc
+ 0, // 0x19 DW_FORM_flag_present
+ 0, // 0x1a
+ 0, // 0x1b
+ 0, // 0x1c
+ 0, // 0x1d
+ 0, // 0x1e
+ 0, // 0x1f
+ 8, // 0x20 DW_FORM_ref_sig8
+
+};
+
+static uint8_t
+g_form_sizes_addr8[] =
+{
+ 0, // 0x00 unused
+ 8, // 0x01 DW_FORM_addr
+ 0, // 0x02 unused
+ 0, // 0x03 DW_FORM_block2
+ 0, // 0x04 DW_FORM_block4
+ 2, // 0x05 DW_FORM_data2
+ 4, // 0x06 DW_FORM_data4
+ 8, // 0x07 DW_FORM_data8
+ 0, // 0x08 DW_FORM_string
+ 0, // 0x09 DW_FORM_block
+ 0, // 0x0a DW_FORM_block1
+ 1, // 0x0b DW_FORM_data1
+ 1, // 0x0c DW_FORM_flag
+ 0, // 0x0d DW_FORM_sdata
+ 4, // 0x0e DW_FORM_strp
+ 0, // 0x0f DW_FORM_udata
+ 0, // 0x10 DW_FORM_ref_addr (addr size for DWARF2 and earlier, 4 bytes for DWARF32, 8 bytes for DWARF32 in DWARF 3 and later
+ 1, // 0x11 DW_FORM_ref1
+ 2, // 0x12 DW_FORM_ref2
+ 4, // 0x13 DW_FORM_ref4
+ 8, // 0x14 DW_FORM_ref8
+ 0, // 0x15 DW_FORM_ref_udata
+ 0, // 0x16 DW_FORM_indirect
+ 4, // 0x17 DW_FORM_sec_offset
+ 0, // 0x18 DW_FORM_exprloc
+ 0, // 0x19 DW_FORM_flag_present
+ 0, // 0x1a
+ 0, // 0x1b
+ 0, // 0x1c
+ 0, // 0x1d
+ 0, // 0x1e
+ 0, // 0x1f
+ 8, // 0x20 DW_FORM_ref_sig8
+};
+
+const uint8_t *
+DWARFFormValue::GetFixedFormSizesForAddressSize (uint8_t addr_size)
+{
+ switch (addr_size)
+ {
+ case 4: return g_form_sizes_addr4;
+ case 8: return g_form_sizes_addr8;
+ }
+ return NULL;
+}
+
+DWARFFormValue::DWARFFormValue(dw_form_t form) :
+ m_form(form),
+ m_value()
+{
+}
+
+bool
+DWARFFormValue::ExtractValue(const DataExtractor& data, lldb::offset_t* offset_ptr, const DWARFCompileUnit* cu)
+{
+ bool indirect = false;
+ bool is_block = false;
+ m_value.data = NULL;
+ // Read the value for the form into value and follow and DW_FORM_indirect instances we run into
+ do
+ {
+ indirect = false;
+ switch (m_form)
+ {
+ case DW_FORM_addr: m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::GetAddressByteSize(cu)); break;
+ case DW_FORM_block2: m_value.value.uval = data.GetU16(offset_ptr); is_block = true; break;
+ case DW_FORM_block4: m_value.value.uval = data.GetU32(offset_ptr); is_block = true; break;
+ case DW_FORM_data2: m_value.value.uval = data.GetU16(offset_ptr); break;
+ case DW_FORM_data4: m_value.value.uval = data.GetU32(offset_ptr); break;
+ case DW_FORM_data8: m_value.value.uval = data.GetU64(offset_ptr); break;
+ case DW_FORM_string: m_value.value.cstr = data.GetCStr(offset_ptr);
+ // Set the string value to also be the data for inlined cstr form values only
+ // so we can tell the differnence between DW_FORM_string and DW_FORM_strp form
+ // values;
+ m_value.data = (uint8_t*)m_value.value.cstr; break;
+ case DW_FORM_exprloc:
+ case DW_FORM_block: m_value.value.uval = data.GetULEB128(offset_ptr); is_block = true; break;
+ case DW_FORM_block1: m_value.value.uval = data.GetU8(offset_ptr); is_block = true; break;
+ case DW_FORM_data1: m_value.value.uval = data.GetU8(offset_ptr); break;
+ case DW_FORM_flag: m_value.value.uval = data.GetU8(offset_ptr); break;
+ case DW_FORM_sdata: m_value.value.sval = data.GetSLEB128(offset_ptr); break;
+ case DW_FORM_strp: m_value.value.uval = data.GetU32(offset_ptr); break;
+ // case DW_FORM_APPLE_db_str:
+ case DW_FORM_udata: m_value.value.uval = data.GetULEB128(offset_ptr); break;
+ case DW_FORM_ref_addr:
+ if (cu->GetVersion() <= 2)
+ m_value.value.uval = data.GetMaxU64(offset_ptr, DWARFCompileUnit::GetAddressByteSize(cu));
+ else
+ m_value.value.uval = data.GetU32(offset_ptr); // 4 for DWARF32, 8 for DWARF64, but we don't support DWARF64 yet
+ break;
+ case DW_FORM_ref1: m_value.value.uval = data.GetU8(offset_ptr); break;
+ case DW_FORM_ref2: m_value.value.uval = data.GetU16(offset_ptr); break;
+ case DW_FORM_ref4: m_value.value.uval = data.GetU32(offset_ptr); break;
+ case DW_FORM_ref8: m_value.value.uval = data.GetU64(offset_ptr); break;
+ case DW_FORM_ref_udata: m_value.value.uval = data.GetULEB128(offset_ptr); break;
+ case DW_FORM_indirect:
+ m_form = data.GetULEB128(offset_ptr);
+ indirect = true;
+ break;
+
+ case DW_FORM_sec_offset: m_value.value.uval = data.GetU32(offset_ptr); break;
+ case DW_FORM_flag_present: m_value.value.uval = 1; break;
+ case DW_FORM_ref_sig8: m_value.value.uval = data.GetU64(offset_ptr); break;
+ default:
+ return false;
+ break;
+ }
+ } while (indirect);
+
+ if (is_block)
+ {
+ m_value.data = data.PeekData(*offset_ptr, m_value.value.uval);
+ if (m_value.data != NULL)
+ {
+ *offset_ptr += m_value.value.uval;
+ }
+ }
+
+ return true;
+}
+
+bool
+DWARFFormValue::SkipValue(const DataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu) const
+{
+ return DWARFFormValue::SkipValue(m_form, debug_info_data, offset_ptr, cu);
+}
+
+bool
+DWARFFormValue::SkipValue(dw_form_t form, const DataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu)
+{
+ switch (form)
+ {
+ // Blocks if inlined data that have a length field and the data bytes
+ // inlined in the .debug_info
+ case DW_FORM_exprloc:
+ case DW_FORM_block: { dw_uleb128_t size = debug_info_data.GetULEB128(offset_ptr); *offset_ptr += size; } return true;
+ case DW_FORM_block1: { dw_uleb128_t size = debug_info_data.GetU8(offset_ptr); *offset_ptr += size; } return true;
+ case DW_FORM_block2: { dw_uleb128_t size = debug_info_data.GetU16(offset_ptr); *offset_ptr += size; } return true;
+ case DW_FORM_block4: { dw_uleb128_t size = debug_info_data.GetU32(offset_ptr); *offset_ptr += size; } return true;
+
+ // Inlined NULL terminated C-strings
+ case DW_FORM_string:
+ debug_info_data.GetCStr(offset_ptr);
+ return true;
+
+ // Compile unit address sized values
+ case DW_FORM_addr:
+ *offset_ptr += DWARFCompileUnit::GetAddressByteSize(cu);
+ return true;
+
+ case DW_FORM_ref_addr:
+ if (cu->GetVersion() <= 2)
+ *offset_ptr += DWARFCompileUnit::GetAddressByteSize(cu);
+ else
+ *offset_ptr += 4;// 4 for DWARF32, 8 for DWARF64, but we don't support DWARF64 yet
+ return true;
+
+ // 0 bytes values (implied from DW_FORM)
+ case DW_FORM_flag_present:
+ return true;
+
+ // 1 byte values
+ case DW_FORM_data1:
+ case DW_FORM_flag:
+ case DW_FORM_ref1:
+ *offset_ptr += 1;
+ return true;
+
+ // 2 byte values
+ case DW_FORM_data2:
+ case DW_FORM_ref2:
+ *offset_ptr += 2;
+ return true;
+
+ // 32 bit for DWARF 32, 64 for DWARF 64
+ case DW_FORM_sec_offset:
+ *offset_ptr += 4;
+ return true;
+
+ // 4 byte values
+ case DW_FORM_strp:
+ case DW_FORM_data4:
+ case DW_FORM_ref4:
+ *offset_ptr += 4;
+ return true;
+
+ // 8 byte values
+ case DW_FORM_data8:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_sig8:
+ *offset_ptr += 8;
+ return true;
+
+ // signed or unsigned LEB 128 values
+ case DW_FORM_sdata:
+ case DW_FORM_udata:
+ case DW_FORM_ref_udata:
+ debug_info_data.Skip_LEB128(offset_ptr);
+ return true;
+
+ case DW_FORM_indirect:
+ {
+ dw_form_t indirect_form = debug_info_data.GetULEB128(offset_ptr);
+ return DWARFFormValue::SkipValue (indirect_form,
+ debug_info_data,
+ offset_ptr,
+ cu);
+ }
+
+ default:
+ break;
+ }
+ return false;
+}
+
+
+void
+DWARFFormValue::Dump(Stream &s, const DataExtractor* debug_str_data, const DWARFCompileUnit* cu) const
+{
+ uint64_t uvalue = Unsigned();
+ bool cu_relative_offset = false;
+
+ bool verbose = s.GetVerbose();
+
+ switch (m_form)
+ {
+ case DW_FORM_addr: s.Address(uvalue, sizeof (uint64_t)); break;
+ case DW_FORM_flag:
+ case DW_FORM_data1: s.PutHex8(uvalue); break;
+ case DW_FORM_data2: s.PutHex16(uvalue); break;
+ case DW_FORM_sec_offset:
+ case DW_FORM_data4: s.PutHex32(uvalue); break;
+ case DW_FORM_ref_sig8:
+ case DW_FORM_data8: s.PutHex64(uvalue); break;
+ case DW_FORM_string: s.QuotedCString(AsCString(NULL)); break;
+ case DW_FORM_exprloc:
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ if (uvalue > 0)
+ {
+ switch (m_form)
+ {
+ case DW_FORM_exprloc:
+ case DW_FORM_block: s.Printf("<0x%" PRIx64 "> ", uvalue); break;
+ case DW_FORM_block1: s.Printf("<0x%2.2x> ", (uint8_t)uvalue); break;
+ case DW_FORM_block2: s.Printf("<0x%4.4x> ", (uint16_t)uvalue); break;
+ case DW_FORM_block4: s.Printf("<0x%8.8x> ", (uint32_t)uvalue); break;
+ default: break;
+ }
+
+ const uint8_t* data_ptr = m_value.data;
+ if (data_ptr)
+ {
+ const uint8_t* end_data_ptr = data_ptr + uvalue; // uvalue contains size of block
+ while (data_ptr < end_data_ptr)
+ {
+ s.Printf("%2.2x ", *data_ptr);
+ ++data_ptr;
+ }
+ }
+ else
+ s.PutCString("NULL");
+ }
+ break;
+
+ case DW_FORM_sdata: s.PutSLEB128(uvalue); break;
+ case DW_FORM_udata: s.PutULEB128(uvalue); break;
+ case DW_FORM_strp:
+ if (debug_str_data)
+ {
+ if (verbose)
+ s.Printf(" .debug_str[0x%8.8x] = ", (uint32_t)uvalue);
+
+ const char* dbg_str = AsCString(debug_str_data);
+ if (dbg_str)
+ s.QuotedCString(dbg_str);
+ }
+ else
+ {
+ s.PutHex32(uvalue);
+ }
+ break;
+
+ case DW_FORM_ref_addr:
+ {
+ if (cu->GetVersion() <= 2)
+ s.Address(uvalue, sizeof (uint64_t) * 2);
+ else
+ s.Address(uvalue, 4 * 2);// 4 for DWARF32, 8 for DWARF64, but we don't support DWARF64 yet
+ break;
+ }
+ case DW_FORM_ref1: cu_relative_offset = true; if (verbose) s.Printf("cu + 0x%2.2x", (uint8_t)uvalue); break;
+ case DW_FORM_ref2: cu_relative_offset = true; if (verbose) s.Printf("cu + 0x%4.4x", (uint16_t)uvalue); break;
+ case DW_FORM_ref4: cu_relative_offset = true; if (verbose) s.Printf("cu + 0x%4.4x", (uint32_t)uvalue); break;
+ case DW_FORM_ref8: cu_relative_offset = true; if (verbose) s.Printf("cu + 0x%8.8" PRIx64, uvalue); break;
+ case DW_FORM_ref_udata: cu_relative_offset = true; if (verbose) s.Printf("cu + 0x%" PRIx64, uvalue); break;
+
+ // All DW_FORM_indirect attributes should be resolved prior to calling this function
+ case DW_FORM_indirect: s.PutCString("DW_FORM_indirect"); break;
+ case DW_FORM_flag_present: break;
+ default:
+ s.Printf("DW_FORM(0x%4.4x)", m_form);
+ break;
+ }
+
+ if (cu_relative_offset)
+ {
+ if (verbose)
+ s.PutCString(" => ");
+
+ s.Printf("{0x%8.8" PRIx64 "}", (uvalue + (cu ? cu->GetOffset() : 0)));
+ }
+}
+
+const char*
+DWARFFormValue::AsCString(const DataExtractor* debug_str_data_ptr) const
+{
+ if (IsInlinedCStr())
+ return m_value.value.cstr;
+ else if (debug_str_data_ptr)
+ return debug_str_data_ptr->PeekCStr(m_value.value.uval);
+ return NULL;
+}
+
+uint64_t
+DWARFFormValue::Reference(const DWARFCompileUnit* cu) const
+{
+ uint64_t die_offset = m_value.value.uval;
+ switch (m_form)
+ {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ die_offset += (cu ? cu->GetOffset() : 0);
+ break;
+
+ default:
+ break;
+ }
+
+ return die_offset;
+}
+
+uint64_t
+DWARFFormValue::Reference (dw_offset_t base_offset) const
+{
+ uint64_t die_offset = m_value.value.uval;
+ switch (m_form)
+ {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ die_offset += base_offset;
+ break;
+
+ default:
+ break;
+ }
+
+ return die_offset;
+}
+
+//----------------------------------------------------------------------
+// Resolve any compile unit specific references so that we don't need
+// the compile unit at a later time in order to work with the form
+// value.
+//----------------------------------------------------------------------
+bool
+DWARFFormValue::ResolveCompileUnitReferences(const DWARFCompileUnit* cu)
+{
+ switch (m_form)
+ {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ m_value.value.uval += cu->GetOffset();
+ m_form = DW_FORM_ref_addr;
+ return true;
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
+const uint8_t*
+DWARFFormValue::BlockData() const
+{
+ if (!IsInlinedCStr())
+ return m_value.data;
+ return NULL;
+}
+
+
+bool
+DWARFFormValue::IsBlockForm(const dw_form_t form)
+{
+ switch (form)
+ {
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ return true;
+ }
+ return false;
+}
+
+bool
+DWARFFormValue::IsDataForm(const dw_form_t form)
+{
+ switch (form)
+ {
+ case DW_FORM_sdata:
+ case DW_FORM_udata:
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ return true;
+ }
+ return false;
+}
+
+int
+DWARFFormValue::Compare (const DWARFFormValue& a_value, const DWARFFormValue& b_value, const DWARFCompileUnit* a_cu, const DWARFCompileUnit* b_cu, const DataExtractor* debug_str_data_ptr)
+{
+ dw_form_t a_form = a_value.Form();
+ dw_form_t b_form = b_value.Form();
+ if (a_form < b_form)
+ return -1;
+ if (a_form > b_form)
+ return 1;
+ switch (a_form)
+ {
+ case DW_FORM_addr:
+ case DW_FORM_flag:
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_udata:
+ case DW_FORM_ref_addr:
+ case DW_FORM_sec_offset:
+ case DW_FORM_flag_present:
+ case DW_FORM_ref_sig8:
+ {
+ uint64_t a = a_value.Unsigned();
+ uint64_t b = b_value.Unsigned();
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ return 0;
+ }
+
+ case DW_FORM_sdata:
+ {
+ int64_t a = a_value.Signed();
+ int64_t b = b_value.Signed();
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ return 0;
+ }
+
+ case DW_FORM_string:
+ case DW_FORM_strp:
+ {
+ const char *a_string = a_value.AsCString(debug_str_data_ptr);
+ const char *b_string = b_value.AsCString(debug_str_data_ptr);
+ if (a_string == b_string)
+ return 0;
+ else if (a_string && b_string)
+ return strcmp(a_string, b_string);
+ else if (a_string == NULL)
+ return -1; // A string is NULL, and B is valid
+ else
+ return 1; // A string valid, and B is NULL
+ }
+
+
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ case DW_FORM_exprloc:
+ {
+ uint64_t a_len = a_value.Unsigned();
+ uint64_t b_len = b_value.Unsigned();
+ if (a_len < b_len)
+ return -1;
+ if (a_len > b_len)
+ return 1;
+ // The block lengths are the same
+ return memcmp(a_value.BlockData(), b_value.BlockData(), a_value.Unsigned());
+ }
+ break;
+
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ {
+ uint64_t a = a_value.Reference(a_cu);
+ uint64_t b = b_value.Reference(b_cu);
+ if (a < b)
+ return -1;
+ if (a > b)
+ return 1;
+ return 0;
+ }
+
+ case DW_FORM_indirect:
+ assert(!"This shouldn't happen after the form has been extracted...");
+ break;
+
+ default:
+ assert(!"Unhandled DW_FORM");
+ break;
+ }
+ return -1;
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
new file mode 100644
index 000000000000..4c400b2df58e
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFFormValue.h
@@ -0,0 +1,81 @@
+//===-- DWARFFormValue.h ----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFFormValue_h_
+#define SymbolFileDWARF_DWARFFormValue_h_
+
+#include <stddef.h> // for NULL
+
+class DWARFCompileUnit;
+
+class DWARFFormValue
+{
+public:
+ typedef struct ValueTypeTag
+ {
+ ValueTypeTag() :
+ value(),
+ data(NULL)
+ {
+ value.uval = 0;
+ }
+
+ union
+ {
+ uint64_t uval;
+ int64_t sval;
+ const char* cstr;
+ } value;
+ const uint8_t* data;
+ } ValueType;
+
+ enum
+ {
+ eValueTypeInvalid = 0,
+ eValueTypeUnsigned,
+ eValueTypeSigned,
+ eValueTypeCStr,
+ eValueTypeBlock
+ };
+
+ DWARFFormValue(dw_form_t form = 0);
+ dw_form_t Form() const { return m_form; }
+ void SetForm(dw_form_t form) { m_form = form; }
+ const ValueType& Value() const { return m_value; }
+ void Dump(lldb_private::Stream &s, const lldb_private::DataExtractor* debug_str_data, const DWARFCompileUnit* cu) const;
+ bool ExtractValue(const lldb_private::DataExtractor& data,
+ lldb::offset_t* offset_ptr,
+ const DWARFCompileUnit* cu);
+ bool IsInlinedCStr() const { return (m_value.data != NULL) && m_value.data == (uint8_t*)m_value.value.cstr; }
+ const uint8_t* BlockData() const;
+ uint64_t Reference(const DWARFCompileUnit* cu) const;
+ uint64_t Reference (dw_offset_t offset) const;
+ bool ResolveCompileUnitReferences(const DWARFCompileUnit* cu);
+ bool Boolean() const { return m_value.value.uval != 0; }
+ uint64_t Unsigned() const { return m_value.value.uval; }
+ void SetUnsigned(uint64_t uval) { m_value.value.uval = uval; }
+ int64_t Signed() const { return m_value.value.sval; }
+ void SetSigned(int64_t sval) { m_value.value.sval = sval; }
+ const char* AsCString(const lldb_private::DataExtractor* debug_str_data_ptr) const;
+ bool SkipValue(const lldb_private::DataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu) const;
+ static bool SkipValue(const dw_form_t form, const lldb_private::DataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu);
+// static bool TransferValue(dw_form_t form, const lldb_private::DataExtractor& debug_info_data, lldb::offset_t *offset_ptr, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff);
+// static bool TransferValue(const DWARFFormValue& formValue, const DWARFCompileUnit* cu, BinaryStreamBuf& out_buff);
+// static bool PutUnsigned(dw_form_t form, dw_offset_t offset, uint64_t value, BinaryStreamBuf& out_buff, const DWARFCompileUnit* cu, bool fixup_cu_relative_refs);
+ static bool IsBlockForm(const dw_form_t form);
+ static bool IsDataForm(const dw_form_t form);
+ static const uint8_t * GetFixedFormSizesForAddressSize (uint8_t addr_size);
+ static int Compare (const DWARFFormValue& a, const DWARFFormValue& b, const DWARFCompileUnit* a_cu, const DWARFCompileUnit* b_cu, const lldb_private::DataExtractor* debug_str_data_ptr);
+protected:
+ dw_form_t m_form; // Form for this value
+ ValueType m_value; // Contains all data for the form
+};
+
+
+#endif // SymbolFileDWARF_DWARFFormValue_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp b/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp
new file mode 100644
index 000000000000..fdc07836b88d
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.cpp
@@ -0,0 +1,172 @@
+//===-- DWARFLocationDescription.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFLocationDescription.h"
+#include "DWARFDefines.h"
+#include "lldb/lldb-private.h"
+#include "lldb/Core/Stream.h"
+
+
+using namespace lldb_private;
+
+static int print_dwarf_exp_op (Stream &s, const DataExtractor& data, lldb::offset_t *offset_ptr, int address_size, int dwarf_ref_size);
+
+int
+print_dwarf_expression (Stream &s,
+ const DataExtractor& data,
+ int address_size,
+ int dwarf_ref_size,
+ bool location_expression)
+{
+ int op_count = 0;
+ lldb::offset_t offset = 0;
+ while (data.ValidOffset(offset))
+ {
+ if (location_expression && op_count > 0)
+ {
+ // err (baton, "Dwarf location expressions may only have one operand!");
+ return 1;
+ }
+ if (op_count > 0)
+ {
+ s.PutCString(", ");
+ }
+ if (print_dwarf_exp_op (s, data, &offset, address_size, dwarf_ref_size) == 1)
+ return 1;
+ op_count++;
+ }
+
+ return 0;
+}
+
+static int
+print_dwarf_exp_op (Stream &s,
+ const DataExtractor& data,
+ lldb::offset_t *offset_ptr,
+ int address_size,
+ int dwarf_ref_size)
+{
+ uint8_t opcode = data.GetU8(offset_ptr);
+ DRC_class opcode_class;
+ uint64_t uint;
+ int64_t sint;
+
+ int size;
+
+ opcode_class = DW_OP_value_to_class (opcode) & (~DRC_DWARFv3);
+
+ s.Printf("%s ", DW_OP_value_to_name (opcode));
+
+ /* Does this take zero parameters? If so we can shortcut this function. */
+ if (opcode_class == DRC_ZEROOPERANDS)
+ return 0;
+
+ if (opcode_class == DRC_TWOOPERANDS && opcode == DW_OP_bregx)
+ {
+ uint = data.GetULEB128(offset_ptr);
+ sint = data.GetSLEB128(offset_ptr);
+ s.Printf("%" PRIu64 " %" PRIi64, uint, sint);
+ return 0;
+ }
+ if (opcode_class != DRC_ONEOPERAND)
+ {
+ s.Printf("UNKNOWN OP %u", opcode);
+ return 1;
+ }
+
+ switch (opcode)
+ {
+ case DW_OP_addr: size = address_size; break;
+ case DW_OP_const1u: size = 1; break;
+ case DW_OP_const1s: size = -1; break;
+ case DW_OP_const2u: size = 2; break;
+ case DW_OP_const2s: size = -2; break;
+ case DW_OP_const4u: size = 4; break;
+ case DW_OP_const4s: size = -4; break;
+ case DW_OP_const8u: size = 8; break;
+ case DW_OP_const8s: size = -8; break;
+ case DW_OP_constu: size = 128; break;
+ case DW_OP_consts: size = -128; break;
+ case DW_OP_fbreg: size = -128; break;
+ case DW_OP_breg0:
+ case DW_OP_breg1:
+ case DW_OP_breg2:
+ case DW_OP_breg3:
+ case DW_OP_breg4:
+ case DW_OP_breg5:
+ case DW_OP_breg6:
+ case DW_OP_breg7:
+ case DW_OP_breg8:
+ case DW_OP_breg9:
+ case DW_OP_breg10:
+ case DW_OP_breg11:
+ case DW_OP_breg12:
+ case DW_OP_breg13:
+ case DW_OP_breg14:
+ case DW_OP_breg15:
+ case DW_OP_breg16:
+ case DW_OP_breg17:
+ case DW_OP_breg18:
+ case DW_OP_breg19:
+ case DW_OP_breg20:
+ case DW_OP_breg21:
+ case DW_OP_breg22:
+ case DW_OP_breg23:
+ case DW_OP_breg24:
+ case DW_OP_breg25:
+ case DW_OP_breg26:
+ case DW_OP_breg27:
+ case DW_OP_breg28:
+ case DW_OP_breg29:
+ case DW_OP_breg30:
+ case DW_OP_breg31:
+ size = -128; break;
+ case DW_OP_pick:
+ size = 1; break;
+ case DW_OP_deref_size:
+ size = 1; break;
+ case DW_OP_xderef_size:
+ size = 1; break;
+ case DW_OP_plus_uconst:
+ size = 128; break;
+ case DW_OP_skip:
+ size = -2; break;
+ case DW_OP_bra:
+ size = -2; break;
+ case DW_OP_call2:
+ size = 2; break;
+ case DW_OP_call4:
+ size = 4; break;
+ case DW_OP_call_ref:
+ size = dwarf_ref_size; break;
+ case DW_OP_piece:
+ size = 128; break;
+ case DW_OP_regx:
+ size = 128; break;
+ default:
+ s.Printf("UNKNOWN ONE-OPERAND OPCODE, #%u", opcode);
+ return 1;
+ }
+
+ switch (size)
+ {
+ case -1: sint = (int8_t) data.GetU8(offset_ptr); s.Printf("%+" PRIi64, sint); break;
+ case -2: sint = (int16_t) data.GetU16(offset_ptr); s.Printf("%+" PRIi64, sint); break;
+ case -4: sint = (int32_t) data.GetU32(offset_ptr); s.Printf("%+" PRIi64, sint); break;
+ case -8: sint = (int64_t) data.GetU64(offset_ptr); s.Printf("%+" PRIi64, sint); break;
+ case -128: sint = data.GetSLEB128(offset_ptr); s.Printf("%+" PRIi64, sint); break;
+ case 1: uint = data.GetU8(offset_ptr); s.Printf("0x%2.2" PRIx64, uint); break;
+ case 2: uint = data.GetU16(offset_ptr); s.Printf("0x%4.4" PRIx64, uint); break;
+ case 4: uint = data.GetU32(offset_ptr); s.Printf("0x%8.8" PRIx64, uint); break;
+ case 8: uint = data.GetU64(offset_ptr); s.Printf("0x%16.16" PRIx64, uint); break;
+ case 128: uint = data.GetULEB128(offset_ptr); s.Printf("0x%" PRIx64, uint); break;
+ }
+
+ return 0;
+}
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h b/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h
new file mode 100644
index 000000000000..ff7c907e921c
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFLocationDescription.h
@@ -0,0 +1,24 @@
+//===-- DWARFLocationDescription.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFLocationDescription_h_
+#define SymbolFileDWARF_DWARFLocationDescription_h_
+
+#include "SymbolFileDWARF.h"
+
+int
+print_dwarf_expression (lldb_private::Stream &s,
+ const lldb_private::DataExtractor& data,
+ int address_size,
+ int dwarf_ref_size,
+ bool location_expression);
+
+
+
+#endif // SymbolFileDWARF_DWARFLocationDescription_h_
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp b/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp
new file mode 100644
index 000000000000..dad5691267df
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFLocationList.cpp
@@ -0,0 +1,94 @@
+//===-- DWARFLocationList.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DWARFLocationList.h"
+
+#include "lldb/Core/Stream.h"
+
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFLocationDescription.h"
+
+using namespace lldb_private;
+
+dw_offset_t
+DWARFLocationList::Dump(Stream &s, const DWARFCompileUnit* cu, const DataExtractor& debug_loc_data, lldb::offset_t offset)
+{
+ uint64_t start_addr, end_addr;
+ uint32_t addr_size = DWARFCompileUnit::GetAddressByteSize(cu);
+ s.SetAddressByteSize(DWARFCompileUnit::GetAddressByteSize(cu));
+ dw_addr_t base_addr = cu ? cu->GetBaseAddress() : 0;
+ while (debug_loc_data.ValidOffset(offset))
+ {
+ start_addr = debug_loc_data.GetMaxU64(&offset,addr_size);
+ end_addr = debug_loc_data.GetMaxU64(&offset,addr_size);
+
+ if (start_addr == 0 && end_addr == 0)
+ break;
+
+ s.PutCString("\n ");
+ s.Indent();
+ if (cu)
+ s.AddressRange (start_addr + base_addr,
+ end_addr + base_addr,
+ cu->GetAddressByteSize(),
+ NULL,
+ ": ");
+ uint32_t loc_length = debug_loc_data.GetU16(&offset);
+
+ DataExtractor locationData(debug_loc_data, offset, loc_length);
+ // if ( dump_flags & DWARFDebugInfo::eDumpFlag_Verbose ) *ostrm_ptr << " ( ";
+ print_dwarf_expression (s, locationData, addr_size, 4, false);
+ offset += loc_length;
+ }
+
+ return offset;
+}
+
+bool
+DWARFLocationList::Extract(const DataExtractor& debug_loc_data, lldb::offset_t* offset_ptr, DataExtractor& location_list_data)
+{
+ // Initialize with no data just in case we don't find anything
+ location_list_data.Clear();
+
+ size_t loc_list_length = Size(debug_loc_data, *offset_ptr);
+ if (loc_list_length > 0)
+ {
+ location_list_data.SetData(debug_loc_data, *offset_ptr, loc_list_length);
+ *offset_ptr += loc_list_length;
+ return true;
+ }
+
+ return false;
+}
+
+size_t
+DWARFLocationList::Size(const DataExtractor& debug_loc_data, lldb::offset_t offset)
+{
+ const dw_offset_t debug_loc_offset = offset;
+
+ while (debug_loc_data.ValidOffset(offset))
+ {
+ dw_addr_t start_addr = debug_loc_data.GetAddress(&offset);
+ dw_addr_t end_addr = debug_loc_data.GetAddress(&offset);
+
+ if (start_addr == 0 && end_addr == 0)
+ break;
+
+ uint16_t loc_length = debug_loc_data.GetU16(&offset);
+ offset += loc_length;
+ }
+
+ if (offset > debug_loc_offset)
+ return offset - debug_loc_offset;
+ return 0;
+}
+
+
+
diff --git a/source/Plugins/SymbolFile/DWARF/DWARFLocationList.h b/source/Plugins/SymbolFile/DWARF/DWARFLocationList.h
new file mode 100644
index 000000000000..85e11d90b36b
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/DWARFLocationList.h
@@ -0,0 +1,34 @@
+//===-- DWARFLocationList.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_DWARFLocationList_h_
+#define SymbolFileDWARF_DWARFLocationList_h_
+
+#include "SymbolFileDWARF.h"
+
+class DWARFLocationList
+{
+public:
+ static dw_offset_t
+ Dump (lldb_private::Stream &s,
+ const DWARFCompileUnit* cu,
+ const lldb_private::DataExtractor& debug_loc_data,
+ lldb::offset_t offset);
+
+ static bool
+ Extract (const lldb_private::DataExtractor& debug_loc_data,
+ lldb::offset_t* offset_ptr,
+ lldb_private::DataExtractor& location_list_data);
+
+ static size_t
+ Size (const lldb_private::DataExtractor& debug_loc_data,
+ lldb::offset_t offset);
+
+};
+#endif // SymbolFileDWARF_DWARFLocationList_h_
diff --git a/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h
new file mode 100644
index 000000000000..c31cbaf3ca20
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/HashedNameToDIE.h
@@ -0,0 +1,933 @@
+//===-- HashedNameToDIE.h ---------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_HashedNameToDIE_h_
+#define SymbolFileDWARF_HashedNameToDIE_h_
+
+#include <vector>
+
+#include "DWARFDefines.h"
+#include "DWARFFormValue.h"
+
+#include "lldb/lldb-defines.h"
+#include "lldb/Core/dwarf.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/MappedHash.h"
+
+
+class SymbolFileDWARF;
+class DWARFCompileUnit;
+class DWARFDebugInfoEntry;
+
+struct DWARFMappedHash
+{
+ struct DIEInfo
+ {
+ dw_offset_t offset; // The DIE offset
+ dw_tag_t tag;
+ uint32_t type_flags; // Any flags for this DIEInfo
+ uint32_t qualified_name_hash; // A 32 bit hash of the fully qualified name
+
+ DIEInfo () :
+ offset (DW_INVALID_OFFSET),
+ tag (0),
+ type_flags (0),
+ qualified_name_hash (0)
+ {
+ }
+
+ DIEInfo (dw_offset_t o, dw_tag_t t, uint32_t f, uint32_t h) :
+ offset(o),
+ tag (t),
+ type_flags (f),
+ qualified_name_hash (h)
+ {
+ }
+
+ void
+ Clear()
+ {
+ offset = DW_INVALID_OFFSET;
+ tag = 0;
+ type_flags = 0;
+ qualified_name_hash = 0;
+ }
+ };
+
+ typedef std::vector<DIEInfo> DIEInfoArray;
+ typedef std::vector<uint32_t> DIEArray;
+
+ static void
+ ExtractDIEArray (const DIEInfoArray &die_info_array,
+ DIEArray &die_offsets)
+ {
+ const size_t count = die_info_array.size();
+ for (size_t i=0; i<count; ++i)
+ {
+ die_offsets.push_back (die_info_array[i].offset);
+ }
+ }
+
+ static void
+ ExtractDIEArray (const DIEInfoArray &die_info_array,
+ const dw_tag_t tag,
+ DIEArray &die_offsets)
+ {
+ if (tag == 0)
+ {
+ ExtractDIEArray (die_info_array, die_offsets);
+ }
+ else
+ {
+ const size_t count = die_info_array.size();
+ for (size_t i=0; i<count; ++i)
+ {
+ const dw_tag_t die_tag = die_info_array[i].tag;
+ bool tag_matches = die_tag == 0 || tag == die_tag;
+ if (!tag_matches)
+ {
+ if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
+ tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
+ }
+ if (tag_matches)
+ die_offsets.push_back (die_info_array[i].offset);
+ }
+ }
+ }
+
+ static void
+ ExtractDIEArray (const DIEInfoArray &die_info_array,
+ const dw_tag_t tag,
+ const uint32_t qualified_name_hash,
+ DIEArray &die_offsets)
+ {
+ if (tag == 0)
+ {
+ ExtractDIEArray (die_info_array, die_offsets);
+ }
+ else
+ {
+ const size_t count = die_info_array.size();
+ for (size_t i=0; i<count; ++i)
+ {
+ if (qualified_name_hash != die_info_array[i].qualified_name_hash)
+ continue;
+ const dw_tag_t die_tag = die_info_array[i].tag;
+ bool tag_matches = die_tag == 0 || tag == die_tag;
+ if (!tag_matches)
+ {
+ if (die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
+ tag_matches = tag == DW_TAG_structure_type || tag == DW_TAG_class_type;
+ }
+ if (tag_matches)
+ die_offsets.push_back (die_info_array[i].offset);
+ }
+ }
+ }
+
+ enum AtomType
+ {
+ eAtomTypeNULL = 0u,
+ eAtomTypeDIEOffset = 1u, // DIE offset, check form for encoding
+ eAtomTypeCUOffset = 2u, // DIE offset of the compiler unit header that contains the item in question
+ eAtomTypeTag = 3u, // DW_TAG_xxx value, should be encoded as DW_FORM_data1 (if no tags exceed 255) or DW_FORM_data2
+ eAtomTypeNameFlags = 4u, // Flags from enum NameFlags
+ eAtomTypeTypeFlags = 5u, // Flags from enum TypeFlags,
+ eAtomTypeQualNameHash = 6u // A 32 bit hash of the full qualified name (since all hash entries are basename only)
+ // For example a type like "std::vector<int>::iterator" would have a name of "iterator"
+ // and a 32 bit hash for "std::vector<int>::iterator" to allow us to not have to pull
+ // in debug info for a type when we know the fully qualified name.
+ };
+
+ // Bit definitions for the eAtomTypeTypeFlags flags
+ enum TypeFlags
+ {
+ // Always set for C++, only set for ObjC if this is the
+ // @implementation for class
+ eTypeFlagClassIsImplementation = ( 1u << 1 )
+ };
+
+
+ static void
+ ExtractClassOrStructDIEArray (const DIEInfoArray &die_info_array,
+ bool return_implementation_only_if_available,
+ DIEArray &die_offsets)
+ {
+ const size_t count = die_info_array.size();
+ for (size_t i=0; i<count; ++i)
+ {
+ const dw_tag_t die_tag = die_info_array[i].tag;
+ if (die_tag == 0 || die_tag == DW_TAG_class_type || die_tag == DW_TAG_structure_type)
+ {
+ if (die_info_array[i].type_flags & eTypeFlagClassIsImplementation)
+ {
+ if (return_implementation_only_if_available)
+ {
+ // We found the one true definiton for this class, so
+ // only return that
+ die_offsets.clear();
+ die_offsets.push_back (die_info_array[i].offset);
+ return;
+ }
+ else
+ {
+ // Put the one true definition as the first entry so it
+ // matches first
+ die_offsets.insert (die_offsets.begin(), die_info_array[i].offset);
+ }
+ }
+ else
+ {
+ die_offsets.push_back (die_info_array[i].offset);
+ }
+ }
+ }
+ }
+
+ static void
+ ExtractTypesFromDIEArray (const DIEInfoArray &die_info_array,
+ uint32_t type_flag_mask,
+ uint32_t type_flag_value,
+ DIEArray &die_offsets)
+ {
+ const size_t count = die_info_array.size();
+ for (size_t i=0; i<count; ++i)
+ {
+ if ((die_info_array[i].type_flags & type_flag_mask) == type_flag_value)
+ die_offsets.push_back (die_info_array[i].offset);
+ }
+ }
+
+ struct Atom
+ {
+ uint16_t type;
+ dw_form_t form;
+
+ Atom (uint16_t t = eAtomTypeNULL, dw_form_t f = 0) :
+ type (t),
+ form (f)
+ {
+ }
+ };
+
+ typedef std::vector<Atom> AtomArray;
+
+ static uint32_t
+ GetTypeFlags (SymbolFileDWARF *dwarf2Data,
+ const DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry* die);
+
+
+ static const char *
+ GetAtomTypeName (uint16_t atom)
+ {
+ switch (atom)
+ {
+ case eAtomTypeNULL: return "NULL";
+ case eAtomTypeDIEOffset: return "die-offset";
+ case eAtomTypeCUOffset: return "cu-offset";
+ case eAtomTypeTag: return "die-tag";
+ case eAtomTypeNameFlags: return "name-flags";
+ case eAtomTypeTypeFlags: return "type-flags";
+ case eAtomTypeQualNameHash: return "qualified-name-hash";
+ }
+ return "<invalid>";
+ }
+ struct Prologue
+ {
+ // DIE offset base so die offsets in hash_data can be CU relative
+ dw_offset_t die_base_offset;
+ AtomArray atoms;
+ uint32_t atom_mask;
+ size_t min_hash_data_byte_size;
+ bool hash_data_has_fixed_byte_size;
+
+ Prologue (dw_offset_t _die_base_offset = 0) :
+ die_base_offset (_die_base_offset),
+ atoms(),
+ atom_mask (0),
+ min_hash_data_byte_size(0),
+ hash_data_has_fixed_byte_size(true)
+ {
+ // Define an array of DIE offsets by first defining an array,
+ // and then define the atom type for the array, in this case
+ // we have an array of DIE offsets
+ AppendAtom (eAtomTypeDIEOffset, DW_FORM_data4);
+ }
+
+ virtual ~Prologue()
+ {
+ }
+
+ void
+ ClearAtoms ()
+ {
+ hash_data_has_fixed_byte_size = true;
+ min_hash_data_byte_size = 0;
+ atom_mask = 0;
+ atoms.clear();
+ }
+
+ bool
+ ContainsAtom (AtomType atom_type) const
+ {
+ return (atom_mask & (1u << atom_type)) != 0;
+ }
+
+ virtual void
+ Clear ()
+ {
+ die_base_offset = 0;
+ ClearAtoms ();
+ }
+
+ void
+ AppendAtom (AtomType type, dw_form_t form)
+ {
+ atoms.push_back (Atom(type, form));
+ atom_mask |= 1u << type;
+ switch (form)
+ {
+ case DW_FORM_indirect:
+ case DW_FORM_exprloc:
+ case DW_FORM_flag_present:
+ case DW_FORM_ref_sig8:
+ assert (!"Unhandled atom form");
+ break;
+
+ case DW_FORM_string:
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_sdata:
+ case DW_FORM_udata:
+ case DW_FORM_ref_udata:
+ hash_data_has_fixed_byte_size = false;
+ // Fall through to the cases below...
+ case DW_FORM_flag:
+ case DW_FORM_data1:
+ case DW_FORM_ref1:
+ case DW_FORM_sec_offset:
+ min_hash_data_byte_size += 1;
+ break;
+
+ case DW_FORM_block2:
+ hash_data_has_fixed_byte_size = false;
+ // Fall through to the cases below...
+ case DW_FORM_data2:
+ case DW_FORM_ref2:
+ min_hash_data_byte_size += 2;
+ break;
+
+ case DW_FORM_block4:
+ hash_data_has_fixed_byte_size = false;
+ // Fall through to the cases below...
+ case DW_FORM_data4:
+ case DW_FORM_ref4:
+ case DW_FORM_addr:
+ case DW_FORM_ref_addr:
+ case DW_FORM_strp:
+ min_hash_data_byte_size += 4;
+ break;
+
+ case DW_FORM_data8:
+ case DW_FORM_ref8:
+ min_hash_data_byte_size += 8;
+ break;
+
+ }
+ }
+
+// void
+// Dump (std::ostream* ostrm_ptr);
+
+ lldb::offset_t
+ Read (const lldb_private::DataExtractor &data,
+ lldb::offset_t offset)
+ {
+ ClearAtoms ();
+
+ die_base_offset = data.GetU32 (&offset);
+
+ const uint32_t atom_count = data.GetU32 (&offset);
+ if (atom_count == 0x00060003u)
+ {
+ // Old format, deal with contents of old pre-release format
+ while (data.GetU32(&offset))
+ /* do nothing */;
+
+ // Hardcode to the only known value for now.
+ AppendAtom (eAtomTypeDIEOffset, DW_FORM_data4);
+ }
+ else
+ {
+ for (uint32_t i=0; i<atom_count; ++i)
+ {
+ AtomType type = (AtomType)data.GetU16 (&offset);
+ dw_form_t form = (dw_form_t)data.GetU16 (&offset);
+ AppendAtom (type, form);
+ }
+ }
+ return offset;
+ }
+
+// virtual void
+// Write (BinaryStreamBuf &s);
+
+ size_t
+ GetByteSize () const
+ {
+ // Add an extra count to the atoms size for the zero termination Atom that gets
+ // written to disk
+ return sizeof(die_base_offset) + sizeof(uint32_t) + atoms.size() * sizeof(Atom);
+ }
+
+ size_t
+ GetMinumumHashDataByteSize () const
+ {
+ return min_hash_data_byte_size;
+ }
+
+ bool
+ HashDataHasFixedByteSize() const
+ {
+ return hash_data_has_fixed_byte_size;
+ }
+ };
+
+ struct Header : public MappedHash::Header<Prologue>
+ {
+ Header (dw_offset_t _die_base_offset = 0)
+ {
+ }
+
+ virtual
+ ~Header()
+ {
+ }
+
+ virtual size_t
+ GetByteSize (const HeaderData &header_data)
+ {
+ return header_data.GetByteSize();
+ }
+
+ // virtual void
+ // Dump (std::ostream* ostrm_ptr);
+ //
+ virtual lldb::offset_t
+ Read (lldb_private::DataExtractor &data, lldb::offset_t offset)
+ {
+ offset = MappedHash::Header<Prologue>::Read (data, offset);
+ if (offset != UINT32_MAX)
+ {
+ offset = header_data.Read (data, offset);
+ }
+ return offset;
+ }
+
+ bool
+ Read (const lldb_private::DataExtractor &data,
+ lldb::offset_t *offset_ptr,
+ DIEInfo &hash_data) const
+ {
+ const size_t num_atoms = header_data.atoms.size();
+ if (num_atoms == 0)
+ return false;
+
+ for (size_t i=0; i<num_atoms; ++i)
+ {
+ DWARFFormValue form_value (header_data.atoms[i].form);
+
+ if (!form_value.ExtractValue(data, offset_ptr, NULL))
+ return false;
+
+ switch (header_data.atoms[i].type)
+ {
+ case eAtomTypeDIEOffset: // DIE offset, check form for encoding
+ hash_data.offset = (dw_offset_t)form_value.Reference (header_data.die_base_offset);
+ break;
+
+ case eAtomTypeTag: // DW_TAG value for the DIE
+ hash_data.tag = (dw_tag_t)form_value.Unsigned ();
+
+ case eAtomTypeTypeFlags: // Flags from enum TypeFlags
+ hash_data.type_flags = (uint32_t)form_value.Unsigned ();
+ break;
+
+ case eAtomTypeQualNameHash: // Flags from enum TypeFlags
+ hash_data.qualified_name_hash = form_value.Unsigned ();
+ break;
+
+ default:
+ // We can always skip atomes we don't know about
+ break;
+ }
+ }
+ return true;
+ }
+
+ void
+ Dump (lldb_private::Stream& strm, const DIEInfo &hash_data) const
+ {
+ const size_t num_atoms = header_data.atoms.size();
+ for (size_t i=0; i<num_atoms; ++i)
+ {
+ if (i > 0)
+ strm.PutCString (", ");
+
+ DWARFFormValue form_value (header_data.atoms[i].form);
+ switch (header_data.atoms[i].type)
+ {
+ case eAtomTypeDIEOffset: // DIE offset, check form for encoding
+ strm.Printf ("{0x%8.8x}", hash_data.offset);
+ break;
+
+ case eAtomTypeTag: // DW_TAG value for the DIE
+ {
+ const char *tag_cstr = lldb_private::DW_TAG_value_to_name (hash_data.tag);
+ if (tag_cstr)
+ strm.PutCString (tag_cstr);
+ else
+ strm.Printf ("DW_TAG_(0x%4.4x)", hash_data.tag);
+ }
+ break;
+
+ case eAtomTypeTypeFlags: // Flags from enum TypeFlags
+ strm.Printf ("0x%2.2x", hash_data.type_flags);
+ if (hash_data.type_flags)
+ {
+ strm.PutCString (" (");
+ if (hash_data.type_flags & eTypeFlagClassIsImplementation)
+ strm.PutCString (" implementation");
+ strm.PutCString (" )");
+ }
+ break;
+
+ case eAtomTypeQualNameHash: // Flags from enum TypeFlags
+ strm.Printf ("0x%8.8x", hash_data.qualified_name_hash);
+ break;
+
+ default:
+ strm.Printf ("AtomType(0x%x)", header_data.atoms[i].type);
+ break;
+ }
+ }
+ }
+ };
+
+// class ExportTable
+// {
+// public:
+// ExportTable ();
+//
+// void
+// AppendNames (DWARFDebugPubnamesSet &pubnames_set,
+// StringTable &string_table);
+//
+// void
+// AppendNamesEntry (SymbolFileDWARF *dwarf2Data,
+// const DWARFCompileUnit* cu,
+// const DWARFDebugInfoEntry* die,
+// StringTable &string_table);
+//
+// void
+// AppendTypesEntry (DWARFData *dwarf2Data,
+// const DWARFCompileUnit* cu,
+// const DWARFDebugInfoEntry* die,
+// StringTable &string_table);
+//
+// size_t
+// Save (BinaryStreamBuf &names_data, const StringTable &string_table);
+//
+// void
+// AppendName (const char *name,
+// uint32_t die_offset,
+// StringTable &string_table,
+// dw_offset_t name_debug_str_offset = DW_INVALID_OFFSET); // If "name" has already been looked up, then it can be supplied
+// void
+// AppendType (const char *name,
+// uint32_t die_offset,
+// StringTable &string_table);
+//
+//
+// protected:
+// struct Entry
+// {
+// uint32_t hash;
+// uint32_t str_offset;
+// uint32_t die_offset;
+// };
+//
+// // Map uniqued .debug_str offset to the corresponding DIE offsets
+// typedef std::map<uint32_t, DIEInfoArray> NameInfo;
+// // Map a name hash to one or more name infos
+// typedef std::map<uint32_t, NameInfo> BucketEntry;
+//
+// static uint32_t
+// GetByteSize (const NameInfo &name_info);
+//
+// typedef std::vector<BucketEntry> BucketEntryColl;
+// typedef std::vector<Entry> EntryColl;
+// EntryColl m_entries;
+//
+// };
+
+
+ // A class for reading and using a saved hash table from a block of data
+ // in memory
+ class MemoryTable : public MappedHash::MemoryTable<uint32_t, DWARFMappedHash::Header, DIEInfoArray>
+ {
+ public:
+
+ MemoryTable (lldb_private::DataExtractor &table_data,
+ const lldb_private::DataExtractor &string_table,
+ const char *name) :
+ MappedHash::MemoryTable<uint32_t, Header, DIEInfoArray> (table_data),
+ m_data (table_data),
+ m_string_table (string_table),
+ m_name (name)
+ {
+ }
+
+ virtual
+ ~MemoryTable ()
+ {
+ }
+
+ virtual const char *
+ GetStringForKeyType (KeyType key) const
+ {
+ // The key in the DWARF table is the .debug_str offset for the string
+ return m_string_table.PeekCStr (key);
+ }
+
+ virtual bool
+ ReadHashData (uint32_t hash_data_offset,
+ HashData &hash_data) const
+ {
+ lldb::offset_t offset = hash_data_offset;
+ offset += 4; // Skip string table offset that contains offset of hash name in .debug_str
+ const uint32_t count = m_data.GetU32 (&offset);
+ if (count > 0)
+ {
+ hash_data.resize(count);
+ for (uint32_t i=0; i<count; ++i)
+ {
+ if (!m_header.Read(m_data, &offset, hash_data[i]))
+ return false;
+ }
+ }
+ else
+ hash_data.clear();
+ return true;
+ }
+
+ virtual Result
+ GetHashDataForName (const char *name,
+ lldb::offset_t* hash_data_offset_ptr,
+ Pair &pair) const
+ {
+ pair.key = m_data.GetU32 (hash_data_offset_ptr);
+ pair.value.clear();
+
+ // If the key is zero, this terminates our chain of HashData objects
+ // for this hash value.
+ if (pair.key == 0)
+ return eResultEndOfHashData;
+
+ // There definitely should be a string for this string offset, if
+ // there isn't, there is something wrong, return and error
+ const char *strp_cstr = m_string_table.PeekCStr (pair.key);
+ if (strp_cstr == NULL)
+ {
+ *hash_data_offset_ptr = UINT32_MAX;
+ return eResultError;
+ }
+
+ const uint32_t count = m_data.GetU32 (hash_data_offset_ptr);
+ const size_t min_total_hash_data_size = count * m_header.header_data.GetMinumumHashDataByteSize();
+ if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size))
+ {
+ // We have at least one HashData entry, and we have enough
+ // data to parse at leats "count" HashData enties.
+
+ // First make sure the entire C string matches...
+ const bool match = strcmp (name, strp_cstr) == 0;
+
+ if (!match && m_header.header_data.HashDataHasFixedByteSize())
+ {
+ // If the string doesn't match and we have fixed size data,
+ // we can just add the total byte size of all HashData objects
+ // to the hash data offset and be done...
+ *hash_data_offset_ptr += min_total_hash_data_size;
+ }
+ else
+ {
+ // If the string does match, or we don't have fixed size data
+ // then we need to read the hash data as a stream. If the
+ // string matches we also append all HashData objects to the
+ // value array.
+ for (uint32_t i=0; i<count; ++i)
+ {
+ DIEInfo die_info;
+ if (m_header.Read(m_data, hash_data_offset_ptr, die_info))
+ {
+ // Only happend the HashData if the string matched...
+ if (match)
+ pair.value.push_back (die_info);
+ }
+ else
+ {
+ // Something went wrong while reading the data
+ *hash_data_offset_ptr = UINT32_MAX;
+ return eResultError;
+ }
+ }
+ }
+ // Return the correct response depending on if the string matched
+ // or not...
+ if (match)
+ return eResultKeyMatch; // The key (cstring) matches and we have lookup results!
+ else
+ return eResultKeyMismatch; // The key doesn't match, this function will get called
+ // again for the next key/value or the key terminator
+ // which in our case is a zero .debug_str offset.
+ }
+ else
+ {
+ *hash_data_offset_ptr = UINT32_MAX;
+ return eResultError;
+ }
+ }
+
+ virtual Result
+ AppendHashDataForRegularExpression (const lldb_private::RegularExpression& regex,
+ lldb::offset_t* hash_data_offset_ptr,
+ Pair &pair) const
+ {
+ pair.key = m_data.GetU32 (hash_data_offset_ptr);
+ // If the key is zero, this terminates our chain of HashData objects
+ // for this hash value.
+ if (pair.key == 0)
+ return eResultEndOfHashData;
+
+ // There definitely should be a string for this string offset, if
+ // there isn't, there is something wrong, return and error
+ const char *strp_cstr = m_string_table.PeekCStr (pair.key);
+ if (strp_cstr == NULL)
+ return eResultError;
+
+ const uint32_t count = m_data.GetU32 (hash_data_offset_ptr);
+ const size_t min_total_hash_data_size = count * m_header.header_data.GetMinumumHashDataByteSize();
+ if (count > 0 && m_data.ValidOffsetForDataOfSize (*hash_data_offset_ptr, min_total_hash_data_size))
+ {
+ const bool match = regex.Execute(strp_cstr);
+
+ if (!match && m_header.header_data.HashDataHasFixedByteSize())
+ {
+ // If the regex doesn't match and we have fixed size data,
+ // we can just add the total byte size of all HashData objects
+ // to the hash data offset and be done...
+ *hash_data_offset_ptr += min_total_hash_data_size;
+ }
+ else
+ {
+ // If the string does match, or we don't have fixed size data
+ // then we need to read the hash data as a stream. If the
+ // string matches we also append all HashData objects to the
+ // value array.
+ for (uint32_t i=0; i<count; ++i)
+ {
+ DIEInfo die_info;
+ if (m_header.Read(m_data, hash_data_offset_ptr, die_info))
+ {
+ // Only happend the HashData if the string matched...
+ if (match)
+ pair.value.push_back (die_info);
+ }
+ else
+ {
+ // Something went wrong while reading the data
+ *hash_data_offset_ptr = UINT32_MAX;
+ return eResultError;
+ }
+ }
+ }
+ // Return the correct response depending on if the string matched
+ // or not...
+ if (match)
+ return eResultKeyMatch; // The key (cstring) matches and we have lookup results!
+ else
+ return eResultKeyMismatch; // The key doesn't match, this function will get called
+ // again for the next key/value or the key terminator
+ // which in our case is a zero .debug_str offset.
+ }
+ else
+ {
+ *hash_data_offset_ptr = UINT32_MAX;
+ return eResultError;
+ }
+ }
+
+ size_t
+ AppendAllDIEsThatMatchingRegex (const lldb_private::RegularExpression& regex,
+ DIEInfoArray &die_info_array) const
+ {
+ const uint32_t hash_count = m_header.hashes_count;
+ Pair pair;
+ for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx)
+ {
+ lldb::offset_t hash_data_offset = GetHashDataOffset (offset_idx);
+ while (hash_data_offset != UINT32_MAX)
+ {
+ const lldb::offset_t prev_hash_data_offset = hash_data_offset;
+ Result hash_result = AppendHashDataForRegularExpression (regex, &hash_data_offset, pair);
+ if (prev_hash_data_offset == hash_data_offset)
+ break;
+
+ // Check the result of getting our hash data
+ switch (hash_result)
+ {
+ case eResultKeyMatch:
+ case eResultKeyMismatch:
+ // Whether we matches or not, it doesn't matter, we
+ // keep looking.
+ break;
+
+ case eResultEndOfHashData:
+ case eResultError:
+ hash_data_offset = UINT32_MAX;
+ break;
+ }
+ }
+ }
+ die_info_array.swap (pair.value);
+ return die_info_array.size();
+ }
+
+ size_t
+ AppendAllDIEsInRange (const uint32_t die_offset_start,
+ const uint32_t die_offset_end,
+ DIEInfoArray &die_info_array) const
+ {
+ const uint32_t hash_count = m_header.hashes_count;
+ for (uint32_t offset_idx=0; offset_idx<hash_count; ++offset_idx)
+ {
+ bool done = false;
+ lldb::offset_t hash_data_offset = GetHashDataOffset (offset_idx);
+ while (!done && hash_data_offset != UINT32_MAX)
+ {
+ KeyType key = m_data.GetU32 (&hash_data_offset);
+ // If the key is zero, this terminates our chain of HashData objects
+ // for this hash value.
+ if (key == 0)
+ break;
+
+ const uint32_t count = m_data.GetU32 (&hash_data_offset);
+ for (uint32_t i=0; i<count; ++i)
+ {
+ DIEInfo die_info;
+ if (m_header.Read(m_data, &hash_data_offset, die_info))
+ {
+ if (die_info.offset == 0)
+ done = true;
+ if (die_offset_start <= die_info.offset && die_info.offset < die_offset_end)
+ die_info_array.push_back(die_info);
+ }
+ }
+ }
+ }
+ return die_info_array.size();
+ }
+
+ size_t
+ FindByName (const char *name, DIEArray &die_offsets)
+ {
+ DIEInfoArray die_info_array;
+ if (FindByName(name, die_info_array))
+ DWARFMappedHash::ExtractDIEArray (die_info_array, die_offsets);
+ return die_info_array.size();
+ }
+
+ size_t
+ FindByNameAndTag (const char *name,
+ const dw_tag_t tag,
+ DIEArray &die_offsets)
+ {
+ DIEInfoArray die_info_array;
+ if (FindByName(name, die_info_array))
+ DWARFMappedHash::ExtractDIEArray (die_info_array, tag, die_offsets);
+ return die_info_array.size();
+ }
+
+ size_t
+ FindByNameAndTagAndQualifiedNameHash (const char *name,
+ const dw_tag_t tag,
+ const uint32_t qualified_name_hash,
+ DIEArray &die_offsets)
+ {
+ DIEInfoArray die_info_array;
+ if (FindByName(name, die_info_array))
+ DWARFMappedHash::ExtractDIEArray (die_info_array, tag, qualified_name_hash, die_offsets);
+ return die_info_array.size();
+ }
+
+ size_t
+ FindCompleteObjCClassByName (const char *name, DIEArray &die_offsets, bool must_be_implementation)
+ {
+ DIEInfoArray die_info_array;
+ if (FindByName(name, die_info_array))
+ {
+ if (must_be_implementation && GetHeader().header_data.ContainsAtom (eAtomTypeTypeFlags))
+ {
+ // If we have two atoms, then we have the DIE offset and
+ // the type flags so we can find the objective C class
+ // efficiently.
+ DWARFMappedHash::ExtractTypesFromDIEArray (die_info_array,
+ UINT32_MAX,
+ eTypeFlagClassIsImplementation,
+ die_offsets);
+ }
+ else
+ {
+ // We don't only want the one true definition, so try and see
+ // what we can find, and only return class or struct DIEs.
+ // If we do have the full implementation, then return it alone,
+ // else return all possible matches.
+ const bool return_implementation_only_if_available = true;
+ DWARFMappedHash::ExtractClassOrStructDIEArray (die_info_array,
+ return_implementation_only_if_available,
+ die_offsets);
+ }
+ }
+ return die_offsets.size();
+ }
+
+ size_t
+ FindByName (const char *name, DIEInfoArray &die_info_array)
+ {
+ Pair kv_pair;
+ size_t old_size = die_info_array.size();
+ if (Find (name, kv_pair))
+ {
+ die_info_array.swap(kv_pair.value);
+ return die_info_array.size() - old_size;
+ }
+ return 0;
+ }
+
+ protected:
+ const lldb_private::DataExtractor &m_data;
+ const lldb_private::DataExtractor &m_string_table;
+ std::string m_name;
+ };
+};
+
+
+#endif // SymbolFileDWARF_HashedNameToDIE_h_
diff --git a/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp
new file mode 100644
index 000000000000..27fa261813bb
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.cpp
@@ -0,0 +1,232 @@
+//===-- LogChannelDWARF.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LogChannelDWARF.h"
+
+#include "lldb/Interpreter/Args.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamFile.h"
+#include "SymbolFileDWARF.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+// when the one and only logging channel is abled, then this will be non NULL.
+static LogChannelDWARF* g_log_channel = NULL;
+
+LogChannelDWARF::LogChannelDWARF () :
+ LogChannel ()
+{
+}
+
+LogChannelDWARF::~LogChannelDWARF ()
+{
+}
+
+
+void
+LogChannelDWARF::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ LogChannelDWARF::CreateInstance);
+}
+
+void
+LogChannelDWARF::Terminate()
+{
+ PluginManager::UnregisterPlugin (LogChannelDWARF::CreateInstance);
+}
+
+LogChannel*
+LogChannelDWARF::CreateInstance ()
+{
+ return new LogChannelDWARF ();
+}
+
+lldb_private::ConstString
+LogChannelDWARF::GetPluginNameStatic()
+{
+ return SymbolFileDWARF::GetPluginNameStatic();
+}
+
+const char *
+LogChannelDWARF::GetPluginDescriptionStatic()
+{
+ return "DWARF log channel for debugging plug-in issues.";
+}
+
+lldb_private::ConstString
+LogChannelDWARF::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+LogChannelDWARF::GetPluginVersion()
+{
+ return 1;
+}
+
+
+void
+LogChannelDWARF::Delete ()
+{
+ g_log_channel = NULL;
+}
+
+
+void
+LogChannelDWARF::Disable (const char **categories, Stream *feedback_strm)
+{
+ if (m_log_ap.get() == NULL)
+ return;
+
+ uint32_t flag_bits = m_log_ap->GetMask().Get();
+ for (size_t i = 0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+ if (::strcasecmp (arg, "all") == 0) flag_bits &= ~DWARF_LOG_ALL;
+ else if (::strcasecmp (arg, "info") == 0) flag_bits &= ~DWARF_LOG_DEBUG_INFO;
+ else if (::strcasecmp (arg, "line") == 0) flag_bits &= ~DWARF_LOG_DEBUG_LINE;
+ else if (::strcasecmp (arg, "pubnames") == 0) flag_bits &= ~DWARF_LOG_DEBUG_PUBNAMES;
+ else if (::strcasecmp (arg, "pubtypes") == 0) flag_bits &= ~DWARF_LOG_DEBUG_PUBTYPES;
+ else if (::strcasecmp (arg, "aranges") == 0) flag_bits &= ~DWARF_LOG_DEBUG_ARANGES;
+ else if (::strcasecmp (arg, "lookups") == 0) flag_bits &= ~DWARF_LOG_LOOKUPS;
+ else if (::strcasecmp (arg, "map") == 0) flag_bits &= ~DWARF_LOG_DEBUG_MAP;
+ else if (::strcasecmp (arg, "default") == 0) flag_bits &= ~DWARF_LOG_DEFAULT;
+ else if (::strncasecmp(arg, "comp", 4) == 0) flag_bits &= ~DWARF_LOG_TYPE_COMPLETION;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ ListCategories (feedback_strm);
+ }
+ }
+
+ if (flag_bits == 0)
+ Delete ();
+ else
+ m_log_ap->GetMask().Reset (flag_bits);
+
+ return;
+}
+
+bool
+LogChannelDWARF::Enable
+(
+ StreamSP &log_stream_sp,
+ uint32_t log_options,
+ Stream *feedback_strm, // Feedback stream for argument errors etc
+ const char **categories // The categories to enable within this logging stream, if empty, enable default set
+)
+{
+ Delete ();
+
+ if (m_log_ap)
+ m_log_ap->SetStream(log_stream_sp);
+ else
+ m_log_ap.reset(new Log (log_stream_sp));
+
+ g_log_channel = this;
+ uint32_t flag_bits = 0;
+ bool got_unknown_category = false;
+ for (size_t i = 0; categories[i] != NULL; ++i)
+ {
+ const char *arg = categories[i];
+
+ if (::strcasecmp (arg, "all") == 0) flag_bits |= DWARF_LOG_ALL;
+ else if (::strcasecmp (arg, "info") == 0) flag_bits |= DWARF_LOG_DEBUG_INFO;
+ else if (::strcasecmp (arg, "line") == 0) flag_bits |= DWARF_LOG_DEBUG_LINE;
+ else if (::strcasecmp (arg, "pubnames") == 0) flag_bits |= DWARF_LOG_DEBUG_PUBNAMES;
+ else if (::strcasecmp (arg, "pubtypes") == 0) flag_bits |= DWARF_LOG_DEBUG_PUBTYPES;
+ else if (::strcasecmp (arg, "aranges") == 0) flag_bits |= DWARF_LOG_DEBUG_ARANGES;
+ else if (::strcasecmp (arg, "lookups") == 0) flag_bits |= DWARF_LOG_LOOKUPS;
+ else if (::strcasecmp (arg, "map") == 0) flag_bits |= DWARF_LOG_DEBUG_MAP;
+ else if (::strcasecmp (arg, "default") == 0) flag_bits |= DWARF_LOG_DEFAULT;
+ else if (::strncasecmp(arg, "comp", 4) == 0) flag_bits |= DWARF_LOG_TYPE_COMPLETION;
+ else
+ {
+ feedback_strm->Printf("error: unrecognized log category '%s'\n", arg);
+ if (got_unknown_category == false)
+ {
+ got_unknown_category = true;
+ ListCategories (feedback_strm);
+ }
+ }
+ }
+ if (flag_bits == 0)
+ flag_bits = DWARF_LOG_DEFAULT;
+ m_log_ap->GetMask().Reset(flag_bits);
+ m_log_ap->GetOptions().Reset(log_options);
+ return m_log_ap.get() != NULL;
+}
+
+void
+LogChannelDWARF::ListCategories (Stream *strm)
+{
+ strm->Printf ("Logging categories for '%s':\n"
+ " all - turn on all available logging categories\n"
+ " info - log the parsing if .debug_info\n"
+ " line - log the parsing if .debug_line\n"
+ " pubnames - log the parsing if .debug_pubnames\n"
+ " pubtypes - log the parsing if .debug_pubtypes\n"
+ " lookups - log any lookups that happen by name, regex, or address\n"
+ " completion - log struct/unions/class type completions\n"
+ " map - log insertions of object files into DWARF debug maps\n",
+ SymbolFileDWARF::GetPluginNameStatic().GetCString());
+}
+
+Log *
+LogChannelDWARF::GetLog ()
+{
+ if (g_log_channel)
+ return g_log_channel->m_log_ap.get();
+
+ return NULL;
+}
+
+Log *
+LogChannelDWARF::GetLogIfAll (uint32_t mask)
+{
+ if (g_log_channel && g_log_channel->m_log_ap.get())
+ {
+ if (g_log_channel->m_log_ap->GetMask().AllSet(mask))
+ return g_log_channel->m_log_ap.get();
+ }
+ return NULL;
+}
+
+Log *
+LogChannelDWARF::GetLogIfAny (uint32_t mask)
+{
+ if (g_log_channel && g_log_channel->m_log_ap.get())
+ {
+ if (g_log_channel->m_log_ap->GetMask().AnySet(mask))
+ return g_log_channel->m_log_ap.get();
+ }
+ return NULL;
+}
+
+void
+LogChannelDWARF::LogIf (uint32_t mask, const char *format, ...)
+{
+ if (g_log_channel)
+ {
+ Log *log = g_log_channel->m_log_ap.get();
+ if (log && log->GetMask().AnySet(mask))
+ {
+ va_list args;
+ va_start (args, format);
+ log->VAPrintf (format, args);
+ va_end (args);
+ }
+ }
+}
diff --git a/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h
new file mode 100644
index 000000000000..2091a8414f58
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/LogChannelDWARF.h
@@ -0,0 +1,89 @@
+//===-- LogChannelDWARF.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_LogChannelDWARF_h_
+#define SymbolFileDWARF_LogChannelDWARF_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+
+// Project includes
+#include "lldb/Core/Log.h"
+
+#define DWARF_LOG_VERBOSE (1u << 0)
+#define DWARF_LOG_DEBUG_INFO (1u << 1)
+#define DWARF_LOG_DEBUG_LINE (1u << 2)
+#define DWARF_LOG_DEBUG_PUBNAMES (1u << 3)
+#define DWARF_LOG_DEBUG_PUBTYPES (1u << 4)
+#define DWARF_LOG_DEBUG_ARANGES (1u << 5)
+#define DWARF_LOG_LOOKUPS (1u << 6)
+#define DWARF_LOG_TYPE_COMPLETION (1u << 7)
+#define DWARF_LOG_DEBUG_MAP (1u << 8)
+#define DWARF_LOG_ALL (UINT32_MAX)
+#define DWARF_LOG_DEFAULT (DWARF_LOG_DEBUG_INFO)
+
+class LogChannelDWARF : public lldb_private::LogChannel
+{
+public:
+ LogChannelDWARF ();
+
+ virtual
+ ~LogChannelDWARF ();
+
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::LogChannel *
+ CreateInstance ();
+
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ virtual void
+ Disable (const char** categories, lldb_private::Stream *feedback_strm);
+
+ void
+ Delete ();
+
+ virtual bool
+ Enable (lldb::StreamSP &log_stream_sp,
+ uint32_t log_options,
+ lldb_private::Stream *feedback_strm, // Feedback stream for argument errors etc
+ const char **categories); // The categories to enable within this logging stream, if empty, enable default set
+
+ virtual void
+ ListCategories (lldb_private::Stream *strm);
+
+ static lldb_private::Log *
+ GetLog ();
+
+ static lldb_private::Log *
+ GetLogIfAll (uint32_t mask);
+
+ static lldb_private::Log *
+ GetLogIfAny (uint32_t mask);
+
+ static void
+ LogIf (uint32_t mask, const char *format, ...);
+};
+
+#endif // SymbolFileDWARF_LogChannelDWARF_h_
diff --git a/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp b/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
new file mode 100644
index 000000000000..5514469d0758
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/NameToDIE.cpp
@@ -0,0 +1,87 @@
+//===-- NameToDIE.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "NameToDIE.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Stream.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFDebugInfoEntry.h"
+#include "SymbolFileDWARF.h"
+using namespace lldb;
+using namespace lldb_private;
+
+void
+NameToDIE::Finalize()
+{
+ m_map.Sort ();
+ m_map.SizeToFit ();
+}
+
+void
+NameToDIE::Insert (const ConstString& name, uint32_t die_offset)
+{
+ m_map.Append(name.GetCString(), die_offset);
+}
+
+size_t
+NameToDIE::Find (const ConstString &name, DIEArray &info_array) const
+{
+ return m_map.GetValues (name.GetCString(), info_array);
+}
+
+size_t
+NameToDIE::Find (const RegularExpression& regex, DIEArray &info_array) const
+{
+ return m_map.GetValues (regex, info_array);
+}
+
+size_t
+NameToDIE::FindAllEntriesForCompileUnit (uint32_t cu_offset,
+ uint32_t cu_end_offset,
+ DIEArray &info_array) const
+{
+ const size_t initial_size = info_array.size();
+ const uint32_t size = m_map.GetSize();
+ for (uint32_t i=0; i<size; ++i)
+ {
+ const uint32_t die_offset = m_map.GetValueAtIndexUnchecked(i);
+ if (cu_offset < die_offset && die_offset < cu_end_offset)
+ info_array.push_back (die_offset);
+ }
+ return info_array.size() - initial_size;
+}
+
+void
+NameToDIE::Dump (Stream *s)
+{
+ const uint32_t size = m_map.GetSize();
+ for (uint32_t i=0; i<size; ++i)
+ {
+ const char *cstr = m_map.GetCStringAtIndex(i);
+ s->Printf("%p: {0x%8.8x} \"%s\"\n", cstr, m_map.GetValueAtIndexUnchecked(i), cstr);
+ }
+}
+
+void
+NameToDIE::ForEach (std::function <bool(const char *name, uint32_t die_offset)> const &callback) const
+{
+ const uint32_t size = m_map.GetSize();
+ for (uint32_t i=0; i<size; ++i)
+ {
+ if (!callback(m_map.GetCStringAtIndexUnchecked(i),
+ m_map.GetValueAtIndexUnchecked (i)))
+ break;
+ }
+}
diff --git a/source/Plugins/SymbolFile/DWARF/NameToDIE.h b/source/Plugins/SymbolFile/DWARF/NameToDIE.h
new file mode 100644
index 000000000000..f9a12736bf9e
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/NameToDIE.h
@@ -0,0 +1,65 @@
+//===-- NameToDIE.h ---------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_NameToDIE_h_
+#define SymbolFileDWARF_NameToDIE_h_
+
+#include "lldb/Core/UniqueCStringMap.h"
+
+#include <functional>
+
+#include "lldb/lldb-defines.h"
+
+class SymbolFileDWARF;
+
+typedef std::vector<uint32_t> DIEArray;
+
+class NameToDIE
+{
+public:
+ NameToDIE () :
+ m_map()
+ {
+ }
+
+ ~NameToDIE ()
+ {
+ }
+
+ void
+ Dump (lldb_private::Stream *s);
+
+ void
+ Insert (const lldb_private::ConstString& name, uint32_t die_offset);
+
+ void
+ Finalize();
+
+ size_t
+ Find (const lldb_private::ConstString &name,
+ DIEArray &info_array) const;
+
+ size_t
+ Find (const lldb_private::RegularExpression& regex,
+ DIEArray &info_array) const;
+
+ size_t
+ FindAllEntriesForCompileUnit (uint32_t cu_offset,
+ uint32_t cu_end_offset,
+ DIEArray &info_array) const;
+
+ void
+ ForEach (std::function <bool(const char *name, uint32_t die_offset)> const &callback) const;
+
+protected:
+ lldb_private::UniqueCStringMap<uint32_t> m_map;
+
+};
+
+#endif // SymbolFileDWARF_NameToDIE_h_
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
new file mode 100644
index 000000000000..f265af837eef
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -0,0 +1,7973 @@
+//===-- SymbolFileDWARF.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileDWARF.h"
+
+// Other libraries and framework includes
+#include "clang/AST/ASTConsumer.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/AST/DeclObjC.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/Specifiers.h"
+#include "clang/Sema/DeclSpec.h"
+
+#include "llvm/Support/Casting.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamFile.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Core/Value.h"
+
+#include "lldb/Host/Host.h"
+
+#include "lldb/Symbol/Block.h"
+#include "lldb/Symbol/ClangExternalASTSourceCallbacks.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/VariableList.h"
+
+#include "lldb/Target/ObjCLanguageRuntime.h"
+#include "lldb/Target/CPPLanguageRuntime.h"
+
+#include "DWARFCompileUnit.h"
+#include "DWARFDebugAbbrev.h"
+#include "DWARFDebugAranges.h"
+#include "DWARFDebugInfo.h"
+#include "DWARFDebugInfoEntry.h"
+#include "DWARFDebugLine.h"
+#include "DWARFDebugPubnames.h"
+#include "DWARFDebugRanges.h"
+#include "DWARFDeclContext.h"
+#include "DWARFDIECollection.h"
+#include "DWARFFormValue.h"
+#include "DWARFLocationList.h"
+#include "LogChannelDWARF.h"
+#include "SymbolFileDWARFDebugMap.h"
+
+#include <map>
+
+//#define ENABLE_DEBUG_PRINTF // COMMENT OUT THIS LINE PRIOR TO CHECKIN
+
+#ifdef ENABLE_DEBUG_PRINTF
+#include <stdio.h>
+#define DEBUG_PRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DEBUG_PRINTF(fmt, ...)
+#endif
+
+#define DIE_IS_BEING_PARSED ((lldb_private::Type*)1)
+
+using namespace lldb;
+using namespace lldb_private;
+
+//static inline bool
+//child_requires_parent_class_union_or_struct_to_be_completed (dw_tag_t tag)
+//{
+// switch (tag)
+// {
+// default:
+// break;
+// case DW_TAG_subprogram:
+// case DW_TAG_inlined_subroutine:
+// case DW_TAG_class_type:
+// case DW_TAG_structure_type:
+// case DW_TAG_union_type:
+// return true;
+// }
+// return false;
+//}
+//
+static AccessType
+DW_ACCESS_to_AccessType (uint32_t dwarf_accessibility)
+{
+ switch (dwarf_accessibility)
+ {
+ case DW_ACCESS_public: return eAccessPublic;
+ case DW_ACCESS_private: return eAccessPrivate;
+ case DW_ACCESS_protected: return eAccessProtected;
+ default: break;
+ }
+ return eAccessNone;
+}
+
+#if defined(LLDB_CONFIGURATION_DEBUG) or defined(LLDB_CONFIGURATION_RELEASE)
+
+class DIEStack
+{
+public:
+
+ void Push (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die)
+ {
+ m_dies.push_back (DIEInfo(cu, die));
+ }
+
+
+ void LogDIEs (Log *log, SymbolFileDWARF *dwarf)
+ {
+ StreamString log_strm;
+ const size_t n = m_dies.size();
+ log_strm.Printf("DIEStack[%" PRIu64 "]:\n", (uint64_t)n);
+ for (size_t i=0; i<n; i++)
+ {
+ DWARFCompileUnit *cu = m_dies[i].cu;
+ const DWARFDebugInfoEntry *die = m_dies[i].die;
+ std::string qualified_name;
+ die->GetQualifiedName(dwarf, cu, qualified_name);
+ log_strm.Printf ("[%" PRIu64 "] 0x%8.8x: %s name='%s'\n",
+ (uint64_t)i,
+ die->GetOffset(),
+ DW_TAG_value_to_name(die->Tag()),
+ qualified_name.c_str());
+ }
+ log->PutCString(log_strm.GetData());
+ }
+ void Pop ()
+ {
+ m_dies.pop_back();
+ }
+
+ class ScopedPopper
+ {
+ public:
+ ScopedPopper (DIEStack &die_stack) :
+ m_die_stack (die_stack),
+ m_valid (false)
+ {
+ }
+
+ void
+ Push (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die)
+ {
+ m_valid = true;
+ m_die_stack.Push (cu, die);
+ }
+
+ ~ScopedPopper ()
+ {
+ if (m_valid)
+ m_die_stack.Pop();
+ }
+
+
+
+ protected:
+ DIEStack &m_die_stack;
+ bool m_valid;
+ };
+
+protected:
+ struct DIEInfo {
+ DIEInfo (DWARFCompileUnit *c, const DWARFDebugInfoEntry *d) :
+ cu(c),
+ die(d)
+ {
+ }
+ DWARFCompileUnit *cu;
+ const DWARFDebugInfoEntry *die;
+ };
+ typedef std::vector<DIEInfo> Stack;
+ Stack m_dies;
+};
+#endif
+
+void
+SymbolFileDWARF::Initialize()
+{
+ LogChannelDWARF::Initialize();
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SymbolFileDWARF::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+ LogChannelDWARF::Initialize();
+}
+
+
+lldb_private::ConstString
+SymbolFileDWARF::GetPluginNameStatic()
+{
+ static ConstString g_name("dwarf");
+ return g_name;
+}
+
+const char *
+SymbolFileDWARF::GetPluginDescriptionStatic()
+{
+ return "DWARF and DWARF3 debug symbol file reader.";
+}
+
+
+SymbolFile*
+SymbolFileDWARF::CreateInstance (ObjectFile* obj_file)
+{
+ return new SymbolFileDWARF(obj_file);
+}
+
+TypeList *
+SymbolFileDWARF::GetTypeList ()
+{
+ if (GetDebugMapSymfile ())
+ return m_debug_map_symfile->GetTypeList();
+ return m_obj_file->GetModule()->GetTypeList();
+
+}
+void
+SymbolFileDWARF::GetTypes (DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry *die,
+ dw_offset_t min_die_offset,
+ dw_offset_t max_die_offset,
+ uint32_t type_mask,
+ TypeSet &type_set)
+{
+ if (cu)
+ {
+ if (die)
+ {
+ const dw_offset_t die_offset = die->GetOffset();
+
+ if (die_offset >= max_die_offset)
+ return;
+
+ if (die_offset >= min_die_offset)
+ {
+ const dw_tag_t tag = die->Tag();
+
+ bool add_type = false;
+
+ switch (tag)
+ {
+ case DW_TAG_array_type: add_type = (type_mask & eTypeClassArray ) != 0; break;
+ case DW_TAG_unspecified_type:
+ case DW_TAG_base_type: add_type = (type_mask & eTypeClassBuiltin ) != 0; break;
+ case DW_TAG_class_type: add_type = (type_mask & eTypeClassClass ) != 0; break;
+ case DW_TAG_structure_type: add_type = (type_mask & eTypeClassStruct ) != 0; break;
+ case DW_TAG_union_type: add_type = (type_mask & eTypeClassUnion ) != 0; break;
+ case DW_TAG_enumeration_type: add_type = (type_mask & eTypeClassEnumeration ) != 0; break;
+ case DW_TAG_subroutine_type:
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine: add_type = (type_mask & eTypeClassFunction ) != 0; break;
+ case DW_TAG_pointer_type: add_type = (type_mask & eTypeClassPointer ) != 0; break;
+ case DW_TAG_rvalue_reference_type:
+ case DW_TAG_reference_type: add_type = (type_mask & eTypeClassReference ) != 0; break;
+ case DW_TAG_typedef: add_type = (type_mask & eTypeClassTypedef ) != 0; break;
+ case DW_TAG_ptr_to_member_type: add_type = (type_mask & eTypeClassMemberPointer ) != 0; break;
+ }
+
+ if (add_type)
+ {
+ const bool assert_not_being_parsed = true;
+ Type *type = ResolveTypeUID (cu, die, assert_not_being_parsed);
+ if (type)
+ {
+ if (type_set.find(type) == type_set.end())
+ type_set.insert(type);
+ }
+ }
+ }
+
+ for (const DWARFDebugInfoEntry *child_die = die->GetFirstChild();
+ child_die != NULL;
+ child_die = child_die->GetSibling())
+ {
+ GetTypes (cu, child_die, min_die_offset, max_die_offset, type_mask, type_set);
+ }
+ }
+ }
+}
+
+size_t
+SymbolFileDWARF::GetTypes (SymbolContextScope *sc_scope,
+ uint32_t type_mask,
+ TypeList &type_list)
+
+{
+ TypeSet type_set;
+
+ CompileUnit *comp_unit = NULL;
+ DWARFCompileUnit* dwarf_cu = NULL;
+ if (sc_scope)
+ comp_unit = sc_scope->CalculateSymbolContextCompileUnit();
+
+ if (comp_unit)
+ {
+ dwarf_cu = GetDWARFCompileUnit(comp_unit);
+ if (dwarf_cu == 0)
+ return 0;
+ GetTypes (dwarf_cu,
+ dwarf_cu->DIE(),
+ dwarf_cu->GetOffset(),
+ dwarf_cu->GetNextCompileUnitOffset(),
+ type_mask,
+ type_set);
+ }
+ else
+ {
+ DWARFDebugInfo* info = DebugInfo();
+ if (info)
+ {
+ const size_t num_cus = info->GetNumCompileUnits();
+ for (size_t cu_idx=0; cu_idx<num_cus; ++cu_idx)
+ {
+ dwarf_cu = info->GetCompileUnitAtIndex(cu_idx);
+ if (dwarf_cu)
+ {
+ GetTypes (dwarf_cu,
+ dwarf_cu->DIE(),
+ 0,
+ UINT32_MAX,
+ type_mask,
+ type_set);
+ }
+ }
+ }
+ }
+// if (m_using_apple_tables)
+// {
+// DWARFMappedHash::MemoryTable *apple_types = m_apple_types_ap.get();
+// if (apple_types)
+// {
+// apple_types->ForEach([this, &type_set, apple_types, type_mask](const DWARFMappedHash::DIEInfoArray &die_info_array) -> bool {
+//
+// for (auto die_info: die_info_array)
+// {
+// bool add_type = TagMatchesTypeMask (type_mask, 0);
+// if (!add_type)
+// {
+// dw_tag_t tag = die_info.tag;
+// if (tag == 0)
+// {
+// const DWARFDebugInfoEntry *die = DebugInfo()->GetDIEPtr(die_info.offset, NULL);
+// tag = die->Tag();
+// }
+// add_type = TagMatchesTypeMask (type_mask, tag);
+// }
+// if (add_type)
+// {
+// Type *type = ResolveTypeUID(die_info.offset);
+//
+// if (type_set.find(type) == type_set.end())
+// type_set.insert(type);
+// }
+// }
+// return true; // Keep iterating
+// });
+// }
+// }
+// else
+// {
+// if (!m_indexed)
+// Index ();
+//
+// m_type_index.ForEach([this, &type_set, type_mask](const char *name, uint32_t die_offset) -> bool {
+//
+// bool add_type = TagMatchesTypeMask (type_mask, 0);
+//
+// if (!add_type)
+// {
+// const DWARFDebugInfoEntry *die = DebugInfo()->GetDIEPtr(die_offset, NULL);
+// if (die)
+// {
+// const dw_tag_t tag = die->Tag();
+// add_type = TagMatchesTypeMask (type_mask, tag);
+// }
+// }
+//
+// if (add_type)
+// {
+// Type *type = ResolveTypeUID(die_offset);
+//
+// if (type_set.find(type) == type_set.end())
+// type_set.insert(type);
+// }
+// return true; // Keep iterating
+// });
+// }
+
+ std::set<ClangASTType> clang_type_set;
+ size_t num_types_added = 0;
+ for (Type *type : type_set)
+ {
+ ClangASTType clang_type = type->GetClangForwardType();
+ if (clang_type_set.find(clang_type) == clang_type_set.end())
+ {
+ clang_type_set.insert(clang_type);
+ type_list.Insert (type->shared_from_this());
+ ++num_types_added;
+ }
+ }
+ return num_types_added;
+}
+
+
+//----------------------------------------------------------------------
+// Gets the first parent that is a lexical block, function or inlined
+// subroutine, or compile unit.
+//----------------------------------------------------------------------
+static const DWARFDebugInfoEntry *
+GetParentSymbolContextDIE(const DWARFDebugInfoEntry *child_die)
+{
+ const DWARFDebugInfoEntry *die;
+ for (die = child_die->GetParent(); die != NULL; die = die->GetParent())
+ {
+ dw_tag_t tag = die->Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_compile_unit:
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_lexical_block:
+ return die;
+ }
+ }
+ return NULL;
+}
+
+
+SymbolFileDWARF::SymbolFileDWARF(ObjectFile* objfile) :
+ SymbolFile (objfile),
+ UserID (0), // Used by SymbolFileDWARFDebugMap to when this class parses .o files to contain the .o file index/ID
+ m_debug_map_module_wp (),
+ m_debug_map_symfile (NULL),
+ m_clang_tu_decl (NULL),
+ m_flags(),
+ m_data_debug_abbrev (),
+ m_data_debug_aranges (),
+ m_data_debug_frame (),
+ m_data_debug_info (),
+ m_data_debug_line (),
+ m_data_debug_loc (),
+ m_data_debug_ranges (),
+ m_data_debug_str (),
+ m_data_apple_names (),
+ m_data_apple_types (),
+ m_data_apple_namespaces (),
+ m_abbr(),
+ m_info(),
+ m_line(),
+ m_apple_names_ap (),
+ m_apple_types_ap (),
+ m_apple_namespaces_ap (),
+ m_apple_objc_ap (),
+ m_function_basename_index(),
+ m_function_fullname_index(),
+ m_function_method_index(),
+ m_function_selector_index(),
+ m_objc_class_selectors_index(),
+ m_global_index(),
+ m_type_index(),
+ m_namespace_index(),
+ m_indexed (false),
+ m_is_external_ast_source (false),
+ m_using_apple_tables (false),
+ m_supports_DW_AT_APPLE_objc_complete_type (eLazyBoolCalculate),
+ m_ranges(),
+ m_unique_ast_type_map ()
+{
+}
+
+SymbolFileDWARF::~SymbolFileDWARF()
+{
+ if (m_is_external_ast_source)
+ {
+ ModuleSP module_sp (m_obj_file->GetModule());
+ if (module_sp)
+ module_sp->GetClangASTContext().RemoveExternalSource ();
+ }
+}
+
+static const ConstString &
+GetDWARFMachOSegmentName ()
+{
+ static ConstString g_dwarf_section_name ("__DWARF");
+ return g_dwarf_section_name;
+}
+
+UniqueDWARFASTTypeMap &
+SymbolFileDWARF::GetUniqueDWARFASTTypeMap ()
+{
+ if (GetDebugMapSymfile ())
+ return m_debug_map_symfile->GetUniqueDWARFASTTypeMap ();
+ return m_unique_ast_type_map;
+}
+
+ClangASTContext &
+SymbolFileDWARF::GetClangASTContext ()
+{
+ if (GetDebugMapSymfile ())
+ return m_debug_map_symfile->GetClangASTContext ();
+
+ ClangASTContext &ast = m_obj_file->GetModule()->GetClangASTContext();
+ if (!m_is_external_ast_source)
+ {
+ m_is_external_ast_source = true;
+ llvm::OwningPtr<clang::ExternalASTSource> ast_source_ap (
+ new ClangExternalASTSourceCallbacks (SymbolFileDWARF::CompleteTagDecl,
+ SymbolFileDWARF::CompleteObjCInterfaceDecl,
+ SymbolFileDWARF::FindExternalVisibleDeclsByName,
+ SymbolFileDWARF::LayoutRecordType,
+ this));
+ ast.SetExternalSource (ast_source_ap);
+ }
+ return ast;
+}
+
+void
+SymbolFileDWARF::InitializeObject()
+{
+ // Install our external AST source callbacks so we can complete Clang types.
+ ModuleSP module_sp (m_obj_file->GetModule());
+ if (module_sp)
+ {
+ const SectionList *section_list = module_sp->GetSectionList();
+
+ const Section* section = section_list->FindSectionByName(GetDWARFMachOSegmentName ()).get();
+
+ // Memory map the DWARF mach-o segment so we have everything mmap'ed
+ // to keep our heap memory usage down.
+ if (section)
+ m_obj_file->MemoryMapSectionData(section, m_dwarf_data);
+ }
+ get_apple_names_data();
+ if (m_data_apple_names.GetByteSize() > 0)
+ {
+ m_apple_names_ap.reset (new DWARFMappedHash::MemoryTable (m_data_apple_names, get_debug_str_data(), ".apple_names"));
+ if (m_apple_names_ap->IsValid())
+ m_using_apple_tables = true;
+ else
+ m_apple_names_ap.reset();
+ }
+ get_apple_types_data();
+ if (m_data_apple_types.GetByteSize() > 0)
+ {
+ m_apple_types_ap.reset (new DWARFMappedHash::MemoryTable (m_data_apple_types, get_debug_str_data(), ".apple_types"));
+ if (m_apple_types_ap->IsValid())
+ m_using_apple_tables = true;
+ else
+ m_apple_types_ap.reset();
+ }
+
+ get_apple_namespaces_data();
+ if (m_data_apple_namespaces.GetByteSize() > 0)
+ {
+ m_apple_namespaces_ap.reset (new DWARFMappedHash::MemoryTable (m_data_apple_namespaces, get_debug_str_data(), ".apple_namespaces"));
+ if (m_apple_namespaces_ap->IsValid())
+ m_using_apple_tables = true;
+ else
+ m_apple_namespaces_ap.reset();
+ }
+
+ get_apple_objc_data();
+ if (m_data_apple_objc.GetByteSize() > 0)
+ {
+ m_apple_objc_ap.reset (new DWARFMappedHash::MemoryTable (m_data_apple_objc, get_debug_str_data(), ".apple_objc"));
+ if (m_apple_objc_ap->IsValid())
+ m_using_apple_tables = true;
+ else
+ m_apple_objc_ap.reset();
+ }
+}
+
+bool
+SymbolFileDWARF::SupportedVersion(uint16_t version)
+{
+ return version == 2 || version == 3 || version == 4;
+}
+
+uint32_t
+SymbolFileDWARF::CalculateAbilities ()
+{
+ uint32_t abilities = 0;
+ if (m_obj_file != NULL)
+ {
+ const Section* section = NULL;
+ const SectionList *section_list = m_obj_file->GetSectionList();
+ if (section_list == NULL)
+ return 0;
+
+ uint64_t debug_abbrev_file_size = 0;
+ uint64_t debug_info_file_size = 0;
+ uint64_t debug_line_file_size = 0;
+
+ section = section_list->FindSectionByName(GetDWARFMachOSegmentName ()).get();
+
+ if (section)
+ section_list = &section->GetChildren ();
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugInfo, true).get();
+ if (section != NULL)
+ {
+ debug_info_file_size = section->GetFileSize();
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugAbbrev, true).get();
+ if (section)
+ debug_abbrev_file_size = section->GetFileSize();
+ else
+ m_flags.Set (flagsGotDebugAbbrevData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugAranges, true).get();
+ if (!section)
+ m_flags.Set (flagsGotDebugArangesData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugFrame, true).get();
+ if (!section)
+ m_flags.Set (flagsGotDebugFrameData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugLine, true).get();
+ if (section)
+ debug_line_file_size = section->GetFileSize();
+ else
+ m_flags.Set (flagsGotDebugLineData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugLoc, true).get();
+ if (!section)
+ m_flags.Set (flagsGotDebugLocData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugMacInfo, true).get();
+ if (!section)
+ m_flags.Set (flagsGotDebugMacInfoData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugPubNames, true).get();
+ if (!section)
+ m_flags.Set (flagsGotDebugPubNamesData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugPubTypes, true).get();
+ if (!section)
+ m_flags.Set (flagsGotDebugPubTypesData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugRanges, true).get();
+ if (!section)
+ m_flags.Set (flagsGotDebugRangesData);
+
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugStr, true).get();
+ if (!section)
+ m_flags.Set (flagsGotDebugStrData);
+ }
+ else
+ {
+ const char *symfile_dir_cstr = m_obj_file->GetFileSpec().GetDirectory().GetCString();
+ if (symfile_dir_cstr)
+ {
+ if (strcasestr(symfile_dir_cstr, ".dsym"))
+ {
+ if (m_obj_file->GetType() == ObjectFile::eTypeDebugInfo)
+ {
+ // We have a dSYM file that didn't have a any debug info.
+ // If the string table has a size of 1, then it was made from
+ // an executable with no debug info, or from an executable that
+ // was stripped.
+ section = section_list->FindSectionByType (eSectionTypeDWARFDebugStr, true).get();
+ if (section && section->GetFileSize() == 1)
+ {
+ m_obj_file->GetModule()->ReportWarning ("empty dSYM file detected, dSYM was created with an executable with no debug info.");
+ }
+ }
+ }
+ }
+ }
+
+ if (debug_abbrev_file_size > 0 && debug_info_file_size > 0)
+ abilities |= CompileUnits | Functions | Blocks | GlobalVariables | LocalVariables | VariableTypes;
+
+ if (debug_line_file_size > 0)
+ abilities |= LineTables;
+ }
+ return abilities;
+}
+
+const DataExtractor&
+SymbolFileDWARF::GetCachedSectionData (uint32_t got_flag, SectionType sect_type, DataExtractor &data)
+{
+ if (m_flags.IsClear (got_flag))
+ {
+ ModuleSP module_sp (m_obj_file->GetModule());
+ m_flags.Set (got_flag);
+ const SectionList *section_list = module_sp->GetSectionList();
+ if (section_list)
+ {
+ SectionSP section_sp (section_list->FindSectionByType(sect_type, true));
+ if (section_sp)
+ {
+ // See if we memory mapped the DWARF segment?
+ if (m_dwarf_data.GetByteSize())
+ {
+ data.SetData(m_dwarf_data, section_sp->GetOffset (), section_sp->GetFileSize());
+ }
+ else
+ {
+ if (m_obj_file->ReadSectionData (section_sp.get(), data) == 0)
+ data.Clear();
+ }
+ }
+ }
+ }
+ return data;
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_abbrev_data()
+{
+ return GetCachedSectionData (flagsGotDebugAbbrevData, eSectionTypeDWARFDebugAbbrev, m_data_debug_abbrev);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_aranges_data()
+{
+ return GetCachedSectionData (flagsGotDebugArangesData, eSectionTypeDWARFDebugAranges, m_data_debug_aranges);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_frame_data()
+{
+ return GetCachedSectionData (flagsGotDebugFrameData, eSectionTypeDWARFDebugFrame, m_data_debug_frame);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_info_data()
+{
+ return GetCachedSectionData (flagsGotDebugInfoData, eSectionTypeDWARFDebugInfo, m_data_debug_info);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_line_data()
+{
+ return GetCachedSectionData (flagsGotDebugLineData, eSectionTypeDWARFDebugLine, m_data_debug_line);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_loc_data()
+{
+ return GetCachedSectionData (flagsGotDebugLocData, eSectionTypeDWARFDebugLoc, m_data_debug_loc);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_ranges_data()
+{
+ return GetCachedSectionData (flagsGotDebugRangesData, eSectionTypeDWARFDebugRanges, m_data_debug_ranges);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_debug_str_data()
+{
+ return GetCachedSectionData (flagsGotDebugStrData, eSectionTypeDWARFDebugStr, m_data_debug_str);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_apple_names_data()
+{
+ return GetCachedSectionData (flagsGotAppleNamesData, eSectionTypeDWARFAppleNames, m_data_apple_names);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_apple_types_data()
+{
+ return GetCachedSectionData (flagsGotAppleTypesData, eSectionTypeDWARFAppleTypes, m_data_apple_types);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_apple_namespaces_data()
+{
+ return GetCachedSectionData (flagsGotAppleNamespacesData, eSectionTypeDWARFAppleNamespaces, m_data_apple_namespaces);
+}
+
+const DataExtractor&
+SymbolFileDWARF::get_apple_objc_data()
+{
+ return GetCachedSectionData (flagsGotAppleObjCData, eSectionTypeDWARFAppleObjC, m_data_apple_objc);
+}
+
+
+DWARFDebugAbbrev*
+SymbolFileDWARF::DebugAbbrev()
+{
+ if (m_abbr.get() == NULL)
+ {
+ const DataExtractor &debug_abbrev_data = get_debug_abbrev_data();
+ if (debug_abbrev_data.GetByteSize() > 0)
+ {
+ m_abbr.reset(new DWARFDebugAbbrev());
+ if (m_abbr.get())
+ m_abbr->Parse(debug_abbrev_data);
+ }
+ }
+ return m_abbr.get();
+}
+
+const DWARFDebugAbbrev*
+SymbolFileDWARF::DebugAbbrev() const
+{
+ return m_abbr.get();
+}
+
+
+DWARFDebugInfo*
+SymbolFileDWARF::DebugInfo()
+{
+ if (m_info.get() == NULL)
+ {
+ Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this);
+ if (get_debug_info_data().GetByteSize() > 0)
+ {
+ m_info.reset(new DWARFDebugInfo());
+ if (m_info.get())
+ {
+ m_info->SetDwarfData(this);
+ }
+ }
+ }
+ return m_info.get();
+}
+
+const DWARFDebugInfo*
+SymbolFileDWARF::DebugInfo() const
+{
+ return m_info.get();
+}
+
+DWARFCompileUnit*
+SymbolFileDWARF::GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit)
+{
+ DWARFDebugInfo* info = DebugInfo();
+ if (info)
+ {
+ if (GetDebugMapSymfile ())
+ {
+ // The debug map symbol file made the compile units for this DWARF
+ // file which is .o file with DWARF in it, and we should have
+ // only 1 compile unit which is at offset zero in the DWARF.
+ // TODO: modify to support LTO .o files where each .o file might
+ // have multiple DW_TAG_compile_unit tags.
+ return info->GetCompileUnit(0).get();
+ }
+ else
+ {
+ // Just a normal DWARF file whose user ID for the compile unit is
+ // the DWARF offset itself
+ return info->GetCompileUnit((dw_offset_t)comp_unit->GetID()).get();
+ }
+ }
+ return NULL;
+}
+
+
+DWARFDebugRanges*
+SymbolFileDWARF::DebugRanges()
+{
+ if (m_ranges.get() == NULL)
+ {
+ Timer scoped_timer(__PRETTY_FUNCTION__, "%s this = %p", __PRETTY_FUNCTION__, this);
+ if (get_debug_ranges_data().GetByteSize() > 0)
+ {
+ m_ranges.reset(new DWARFDebugRanges());
+ if (m_ranges.get())
+ m_ranges->Extract(this);
+ }
+ }
+ return m_ranges.get();
+}
+
+const DWARFDebugRanges*
+SymbolFileDWARF::DebugRanges() const
+{
+ return m_ranges.get();
+}
+
+lldb::CompUnitSP
+SymbolFileDWARF::ParseCompileUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx)
+{
+ CompUnitSP cu_sp;
+ if (dwarf_cu)
+ {
+ CompileUnit *comp_unit = (CompileUnit*)dwarf_cu->GetUserData();
+ if (comp_unit)
+ {
+ // We already parsed this compile unit, had out a shared pointer to it
+ cu_sp = comp_unit->shared_from_this();
+ }
+ else
+ {
+ if (GetDebugMapSymfile ())
+ {
+ // Let the debug map create the compile unit
+ cu_sp = m_debug_map_symfile->GetCompileUnit(this);
+ dwarf_cu->SetUserData(cu_sp.get());
+ }
+ else
+ {
+ ModuleSP module_sp (m_obj_file->GetModule());
+ if (module_sp)
+ {
+ const DWARFDebugInfoEntry * cu_die = dwarf_cu->GetCompileUnitDIEOnly ();
+ if (cu_die)
+ {
+ const char * cu_die_name = cu_die->GetName(this, dwarf_cu);
+ const char * cu_comp_dir = cu_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_comp_dir, NULL);
+ LanguageType cu_language = (LanguageType)cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_language, 0);
+ if (cu_die_name)
+ {
+ std::string ramapped_file;
+ FileSpec cu_file_spec;
+
+ if (cu_die_name[0] == '/' || cu_comp_dir == NULL || cu_comp_dir[0] == '\0')
+ {
+ // If we have a full path to the compile unit, we don't need to resolve
+ // the file. This can be expensive e.g. when the source files are NFS mounted.
+ if (module_sp->RemapSourceFile(cu_die_name, ramapped_file))
+ cu_file_spec.SetFile (ramapped_file.c_str(), false);
+ else
+ cu_file_spec.SetFile (cu_die_name, false);
+ }
+ else
+ {
+ std::string fullpath(cu_comp_dir);
+ if (*fullpath.rbegin() != '/')
+ fullpath += '/';
+ fullpath += cu_die_name;
+ if (module_sp->RemapSourceFile (fullpath.c_str(), ramapped_file))
+ cu_file_spec.SetFile (ramapped_file.c_str(), false);
+ else
+ cu_file_spec.SetFile (fullpath.c_str(), false);
+ }
+
+ cu_sp.reset(new CompileUnit (module_sp,
+ dwarf_cu,
+ cu_file_spec,
+ MakeUserID(dwarf_cu->GetOffset()),
+ cu_language));
+ if (cu_sp)
+ {
+ dwarf_cu->SetUserData(cu_sp.get());
+
+ // Figure out the compile unit index if we weren't given one
+ if (cu_idx == UINT32_MAX)
+ DebugInfo()->GetCompileUnit(dwarf_cu->GetOffset(), &cu_idx);
+
+ m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(cu_idx, cu_sp);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return cu_sp;
+}
+
+uint32_t
+SymbolFileDWARF::GetNumCompileUnits()
+{
+ DWARFDebugInfo* info = DebugInfo();
+ if (info)
+ return info->GetNumCompileUnits();
+ return 0;
+}
+
+CompUnitSP
+SymbolFileDWARF::ParseCompileUnitAtIndex(uint32_t cu_idx)
+{
+ CompUnitSP cu_sp;
+ DWARFDebugInfo* info = DebugInfo();
+ if (info)
+ {
+ DWARFCompileUnit* dwarf_cu = info->GetCompileUnitAtIndex(cu_idx);
+ if (dwarf_cu)
+ cu_sp = ParseCompileUnit(dwarf_cu, cu_idx);
+ }
+ return cu_sp;
+}
+
+static void
+AddRangesToBlock (Block& block,
+ DWARFDebugRanges::RangeList& ranges,
+ addr_t block_base_addr)
+{
+ const size_t num_ranges = ranges.GetSize();
+ for (size_t i = 0; i<num_ranges; ++i)
+ {
+ const DWARFDebugRanges::Range &range = ranges.GetEntryRef (i);
+ const addr_t range_base = range.GetRangeBase();
+ assert (range_base >= block_base_addr);
+ block.AddRange(Block::Range (range_base - block_base_addr, range.GetByteSize()));;
+ }
+ block.FinalizeRanges ();
+}
+
+
+Function *
+SymbolFileDWARF::ParseCompileUnitFunction (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die)
+{
+ DWARFDebugRanges::RangeList func_ranges;
+ const char *name = NULL;
+ const char *mangled = NULL;
+ int decl_file = 0;
+ int decl_line = 0;
+ int decl_column = 0;
+ int call_file = 0;
+ int call_line = 0;
+ int call_column = 0;
+ DWARFExpression frame_base;
+
+ assert (die->Tag() == DW_TAG_subprogram);
+
+ if (die->Tag() != DW_TAG_subprogram)
+ return NULL;
+
+ if (die->GetDIENamesAndRanges (this,
+ dwarf_cu,
+ name,
+ mangled,
+ func_ranges,
+ decl_file,
+ decl_line,
+ decl_column,
+ call_file,
+ call_line,
+ call_column,
+ &frame_base))
+ {
+ // Union of all ranges in the function DIE (if the function is discontiguous)
+ AddressRange func_range;
+ lldb::addr_t lowest_func_addr = func_ranges.GetMinRangeBase (0);
+ lldb::addr_t highest_func_addr = func_ranges.GetMaxRangeEnd (0);
+ if (lowest_func_addr != LLDB_INVALID_ADDRESS && lowest_func_addr <= highest_func_addr)
+ {
+ ModuleSP module_sp (m_obj_file->GetModule());
+ func_range.GetBaseAddress().ResolveAddressUsingFileSections (lowest_func_addr, module_sp->GetSectionList());
+ if (func_range.GetBaseAddress().IsValid())
+ func_range.SetByteSize(highest_func_addr - lowest_func_addr);
+ }
+
+ if (func_range.GetBaseAddress().IsValid())
+ {
+ Mangled func_name;
+ if (mangled)
+ func_name.SetValue(ConstString(mangled), true);
+ else if (name)
+ func_name.SetValue(ConstString(name), false);
+
+ FunctionSP func_sp;
+ std::unique_ptr<Declaration> decl_ap;
+ if (decl_file != 0 || decl_line != 0 || decl_column != 0)
+ decl_ap.reset(new Declaration (sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file),
+ decl_line,
+ decl_column));
+
+ // Supply the type _only_ if it has already been parsed
+ Type *func_type = m_die_to_type.lookup (die);
+
+ assert(func_type == NULL || func_type != DIE_IS_BEING_PARSED);
+
+ if (FixupAddress (func_range.GetBaseAddress()))
+ {
+ const user_id_t func_user_id = MakeUserID(die->GetOffset());
+ func_sp.reset(new Function (sc.comp_unit,
+ MakeUserID(func_user_id), // UserID is the DIE offset
+ MakeUserID(func_user_id),
+ func_name,
+ func_type,
+ func_range)); // first address range
+
+ if (func_sp.get() != NULL)
+ {
+ if (frame_base.IsValid())
+ func_sp->GetFrameBaseExpression() = frame_base;
+ sc.comp_unit->AddFunction(func_sp);
+ return func_sp.get();
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+bool
+SymbolFileDWARF::FixupAddress (Address &addr)
+{
+ SymbolFileDWARFDebugMap * debug_map_symfile = GetDebugMapSymfile ();
+ if (debug_map_symfile)
+ {
+ return debug_map_symfile->LinkOSOAddress(addr);
+ }
+ // This is a normal DWARF file, no address fixups need to happen
+ return true;
+}
+lldb::LanguageType
+SymbolFileDWARF::ParseCompileUnitLanguage (const SymbolContext& sc)
+{
+ assert (sc.comp_unit);
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
+ if (dwarf_cu)
+ {
+ const DWARFDebugInfoEntry *die = dwarf_cu->GetCompileUnitDIEOnly();
+ if (die)
+ {
+ const uint32_t language = die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_language, 0);
+ if (language)
+ return (lldb::LanguageType)language;
+ }
+ }
+ return eLanguageTypeUnknown;
+}
+
+size_t
+SymbolFileDWARF::ParseCompileUnitFunctions(const SymbolContext &sc)
+{
+ assert (sc.comp_unit);
+ size_t functions_added = 0;
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
+ if (dwarf_cu)
+ {
+ DWARFDIECollection function_dies;
+ const size_t num_functions = dwarf_cu->AppendDIEsWithTag (DW_TAG_subprogram, function_dies);
+ size_t func_idx;
+ for (func_idx = 0; func_idx < num_functions; ++func_idx)
+ {
+ const DWARFDebugInfoEntry *die = function_dies.GetDIEPtrAtIndex(func_idx);
+ if (sc.comp_unit->FindFunctionByUID (MakeUserID(die->GetOffset())).get() == NULL)
+ {
+ if (ParseCompileUnitFunction(sc, dwarf_cu, die))
+ ++functions_added;
+ }
+ }
+ //FixupTypes();
+ }
+ return functions_added;
+}
+
+bool
+SymbolFileDWARF::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList& support_files)
+{
+ assert (sc.comp_unit);
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
+ if (dwarf_cu)
+ {
+ const DWARFDebugInfoEntry * cu_die = dwarf_cu->GetCompileUnitDIEOnly();
+
+ if (cu_die)
+ {
+ const char * cu_comp_dir = cu_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_comp_dir, NULL);
+ dw_offset_t stmt_list = cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_stmt_list, DW_INVALID_OFFSET);
+
+ // All file indexes in DWARF are one based and a file of index zero is
+ // supposed to be the compile unit itself.
+ support_files.Append (*sc.comp_unit);
+
+ return DWARFDebugLine::ParseSupportFiles(sc.comp_unit->GetModule(), get_debug_line_data(), cu_comp_dir, stmt_list, support_files);
+ }
+ }
+ return false;
+}
+
+struct ParseDWARFLineTableCallbackInfo
+{
+ LineTable* line_table;
+ std::unique_ptr<LineSequence> sequence_ap;
+};
+
+//----------------------------------------------------------------------
+// ParseStatementTableCallback
+//----------------------------------------------------------------------
+static void
+ParseDWARFLineTableCallback(dw_offset_t offset, const DWARFDebugLine::State& state, void* userData)
+{
+ if (state.row == DWARFDebugLine::State::StartParsingLineTable)
+ {
+ // Just started parsing the line table
+ }
+ else if (state.row == DWARFDebugLine::State::DoneParsingLineTable)
+ {
+ // Done parsing line table, nothing to do for the cleanup
+ }
+ else
+ {
+ ParseDWARFLineTableCallbackInfo* info = (ParseDWARFLineTableCallbackInfo*)userData;
+ LineTable* line_table = info->line_table;
+
+ // If this is our first time here, we need to create a
+ // sequence container.
+ if (!info->sequence_ap.get())
+ {
+ info->sequence_ap.reset(line_table->CreateLineSequenceContainer());
+ assert(info->sequence_ap.get());
+ }
+ line_table->AppendLineEntryToSequence (info->sequence_ap.get(),
+ state.address,
+ state.line,
+ state.column,
+ state.file,
+ state.is_stmt,
+ state.basic_block,
+ state.prologue_end,
+ state.epilogue_begin,
+ state.end_sequence);
+ if (state.end_sequence)
+ {
+ // First, put the current sequence into the line table.
+ line_table->InsertSequence(info->sequence_ap.get());
+ // Then, empty it to prepare for the next sequence.
+ info->sequence_ap->Clear();
+ }
+ }
+}
+
+bool
+SymbolFileDWARF::ParseCompileUnitLineTable (const SymbolContext &sc)
+{
+ assert (sc.comp_unit);
+ if (sc.comp_unit->GetLineTable() != NULL)
+ return true;
+
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
+ if (dwarf_cu)
+ {
+ const DWARFDebugInfoEntry *dwarf_cu_die = dwarf_cu->GetCompileUnitDIEOnly();
+ if (dwarf_cu_die)
+ {
+ const dw_offset_t cu_line_offset = dwarf_cu_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_stmt_list, DW_INVALID_OFFSET);
+ if (cu_line_offset != DW_INVALID_OFFSET)
+ {
+ std::unique_ptr<LineTable> line_table_ap(new LineTable(sc.comp_unit));
+ if (line_table_ap.get())
+ {
+ ParseDWARFLineTableCallbackInfo info;
+ info.line_table = line_table_ap.get();
+ lldb::offset_t offset = cu_line_offset;
+ DWARFDebugLine::ParseStatementTable(get_debug_line_data(), &offset, ParseDWARFLineTableCallback, &info);
+ if (m_debug_map_symfile)
+ {
+ // We have an object file that has a line table with addresses
+ // that are not linked. We need to link the line table and convert
+ // the addresses that are relative to the .o file into addresses
+ // for the main executable.
+ sc.comp_unit->SetLineTable (m_debug_map_symfile->LinkOSOLineTable (this, line_table_ap.get()));
+ }
+ else
+ {
+ sc.comp_unit->SetLineTable(line_table_ap.release());
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
+
+size_t
+SymbolFileDWARF::ParseFunctionBlocks
+(
+ const SymbolContext& sc,
+ Block *parent_block,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ addr_t subprogram_low_pc,
+ uint32_t depth
+)
+{
+ size_t blocks_added = 0;
+ while (die != NULL)
+ {
+ dw_tag_t tag = die->Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_subprogram:
+ case DW_TAG_lexical_block:
+ {
+ Block *block = NULL;
+ if (tag == DW_TAG_subprogram)
+ {
+ // Skip any DW_TAG_subprogram DIEs that are inside
+ // of a normal or inlined functions. These will be
+ // parsed on their own as separate entities.
+
+ if (depth > 0)
+ break;
+
+ block = parent_block;
+ }
+ else
+ {
+ BlockSP block_sp(new Block (MakeUserID(die->GetOffset())));
+ parent_block->AddChild(block_sp);
+ block = block_sp.get();
+ }
+ DWARFDebugRanges::RangeList ranges;
+ const char *name = NULL;
+ const char *mangled_name = NULL;
+
+ int decl_file = 0;
+ int decl_line = 0;
+ int decl_column = 0;
+ int call_file = 0;
+ int call_line = 0;
+ int call_column = 0;
+ if (die->GetDIENamesAndRanges (this,
+ dwarf_cu,
+ name,
+ mangled_name,
+ ranges,
+ decl_file, decl_line, decl_column,
+ call_file, call_line, call_column))
+ {
+ if (tag == DW_TAG_subprogram)
+ {
+ assert (subprogram_low_pc == LLDB_INVALID_ADDRESS);
+ subprogram_low_pc = ranges.GetMinRangeBase(0);
+ }
+ else if (tag == DW_TAG_inlined_subroutine)
+ {
+ // We get called here for inlined subroutines in two ways.
+ // The first time is when we are making the Function object
+ // for this inlined concrete instance. Since we're creating a top level block at
+ // here, the subprogram_low_pc will be LLDB_INVALID_ADDRESS. So we need to
+ // adjust the containing address.
+ // The second time is when we are parsing the blocks inside the function that contains
+ // the inlined concrete instance. Since these will be blocks inside the containing "real"
+ // function the offset will be for that function.
+ if (subprogram_low_pc == LLDB_INVALID_ADDRESS)
+ {
+ subprogram_low_pc = ranges.GetMinRangeBase(0);
+ }
+ }
+
+ AddRangesToBlock (*block, ranges, subprogram_low_pc);
+
+ if (tag != DW_TAG_subprogram && (name != NULL || mangled_name != NULL))
+ {
+ std::unique_ptr<Declaration> decl_ap;
+ if (decl_file != 0 || decl_line != 0 || decl_column != 0)
+ decl_ap.reset(new Declaration(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(decl_file),
+ decl_line, decl_column));
+
+ std::unique_ptr<Declaration> call_ap;
+ if (call_file != 0 || call_line != 0 || call_column != 0)
+ call_ap.reset(new Declaration(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(call_file),
+ call_line, call_column));
+
+ block->SetInlinedFunctionInfo (name, mangled_name, decl_ap.get(), call_ap.get());
+ }
+
+ ++blocks_added;
+
+ if (die->HasChildren())
+ {
+ blocks_added += ParseFunctionBlocks (sc,
+ block,
+ dwarf_cu,
+ die->GetFirstChild(),
+ subprogram_low_pc,
+ depth + 1);
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Only parse siblings of the block if we are not at depth zero. A depth
+ // of zero indicates we are currently parsing the top level
+ // DW_TAG_subprogram DIE
+
+ if (depth == 0)
+ die = NULL;
+ else
+ die = die->GetSibling();
+ }
+ return blocks_added;
+}
+
+bool
+SymbolFileDWARF::ParseTemplateDIE (DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ ClangASTContext::TemplateParameterInfos &template_param_infos)
+{
+ const dw_tag_t tag = die->Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_template_type_parameter:
+ case DW_TAG_template_value_parameter:
+ {
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_attributes = die->GetAttributes (this,
+ dwarf_cu,
+ fixed_form_sizes,
+ attributes);
+ const char *name = NULL;
+ Type *lldb_type = NULL;
+ ClangASTType clang_type;
+ uint64_t uval64 = 0;
+ bool uval64_valid = false;
+ if (num_attributes > 0)
+ {
+ DWARFFormValue form_value;
+ for (size_t i=0; i<num_attributes; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+
+ switch (attr)
+ {
+ case DW_AT_name:
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ name = form_value.AsCString(&get_debug_str_data());
+ break;
+
+ case DW_AT_type:
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ const dw_offset_t type_die_offset = form_value.Reference(dwarf_cu);
+ lldb_type = ResolveTypeUID(type_die_offset);
+ if (lldb_type)
+ clang_type = lldb_type->GetClangForwardType();
+ }
+ break;
+
+ case DW_AT_const_value:
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ uval64_valid = true;
+ uval64 = form_value.Unsigned();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ clang::ASTContext *ast = GetClangASTContext().getASTContext();
+ if (!clang_type)
+ clang_type = GetClangASTContext().GetBasicType(eBasicTypeVoid);
+
+ if (clang_type)
+ {
+ bool is_signed = false;
+ if (name && name[0])
+ template_param_infos.names.push_back(name);
+ else
+ template_param_infos.names.push_back(NULL);
+
+ if (tag == DW_TAG_template_value_parameter &&
+ lldb_type != NULL &&
+ clang_type.IsIntegerType (is_signed) &&
+ uval64_valid)
+ {
+ llvm::APInt apint (lldb_type->GetByteSize() * 8, uval64, is_signed);
+ template_param_infos.args.push_back (clang::TemplateArgument (*ast,
+ llvm::APSInt(apint),
+ clang_type.GetQualType()));
+ }
+ else
+ {
+ template_param_infos.args.push_back (clang::TemplateArgument (clang_type.GetQualType()));
+ }
+ }
+ else
+ {
+ return false;
+ }
+
+ }
+ }
+ return true;
+
+ default:
+ break;
+ }
+ return false;
+}
+
+bool
+SymbolFileDWARF::ParseTemplateParameterInfos (DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ ClangASTContext::TemplateParameterInfos &template_param_infos)
+{
+
+ if (parent_die == NULL)
+ return false;
+
+ Args template_parameter_names;
+ for (const DWARFDebugInfoEntry *die = parent_die->GetFirstChild();
+ die != NULL;
+ die = die->GetSibling())
+ {
+ const dw_tag_t tag = die->Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_template_type_parameter:
+ case DW_TAG_template_value_parameter:
+ ParseTemplateDIE (dwarf_cu, die, template_param_infos);
+ break;
+
+ default:
+ break;
+ }
+ }
+ if (template_param_infos.args.empty())
+ return false;
+ return template_param_infos.args.size() == template_param_infos.names.size();
+}
+
+clang::ClassTemplateDecl *
+SymbolFileDWARF::ParseClassTemplateDecl (clang::DeclContext *decl_ctx,
+ lldb::AccessType access_type,
+ const char *parent_name,
+ int tag_decl_kind,
+ const ClangASTContext::TemplateParameterInfos &template_param_infos)
+{
+ if (template_param_infos.IsValid())
+ {
+ std::string template_basename(parent_name);
+ template_basename.erase (template_basename.find('<'));
+ ClangASTContext &ast = GetClangASTContext();
+
+ return ast.CreateClassTemplateDecl (decl_ctx,
+ access_type,
+ template_basename.c_str(),
+ tag_decl_kind,
+ template_param_infos);
+ }
+ return NULL;
+}
+
+class SymbolFileDWARF::DelayedAddObjCClassProperty
+{
+public:
+ DelayedAddObjCClassProperty
+ (
+ const ClangASTType &class_opaque_type,
+ const char *property_name,
+ const ClangASTType &property_opaque_type, // The property type is only required if you don't have an ivar decl
+ clang::ObjCIvarDecl *ivar_decl,
+ const char *property_setter_name,
+ const char *property_getter_name,
+ uint32_t property_attributes,
+ const ClangASTMetadata *metadata
+ ) :
+ m_class_opaque_type (class_opaque_type),
+ m_property_name (property_name),
+ m_property_opaque_type (property_opaque_type),
+ m_ivar_decl (ivar_decl),
+ m_property_setter_name (property_setter_name),
+ m_property_getter_name (property_getter_name),
+ m_property_attributes (property_attributes)
+ {
+ if (metadata != NULL)
+ {
+ m_metadata_ap.reset(new ClangASTMetadata());
+ *m_metadata_ap = *metadata;
+ }
+ }
+
+ DelayedAddObjCClassProperty (const DelayedAddObjCClassProperty &rhs)
+ {
+ *this = rhs;
+ }
+
+ DelayedAddObjCClassProperty& operator= (const DelayedAddObjCClassProperty &rhs)
+ {
+ m_class_opaque_type = rhs.m_class_opaque_type;
+ m_property_name = rhs.m_property_name;
+ m_property_opaque_type = rhs.m_property_opaque_type;
+ m_ivar_decl = rhs.m_ivar_decl;
+ m_property_setter_name = rhs.m_property_setter_name;
+ m_property_getter_name = rhs.m_property_getter_name;
+ m_property_attributes = rhs.m_property_attributes;
+
+ if (rhs.m_metadata_ap.get())
+ {
+ m_metadata_ap.reset (new ClangASTMetadata());
+ *m_metadata_ap = *rhs.m_metadata_ap;
+ }
+ return *this;
+ }
+
+ bool
+ Finalize()
+ {
+ return m_class_opaque_type.AddObjCClassProperty (m_property_name,
+ m_property_opaque_type,
+ m_ivar_decl,
+ m_property_setter_name,
+ m_property_getter_name,
+ m_property_attributes,
+ m_metadata_ap.get());
+ }
+private:
+ ClangASTType m_class_opaque_type;
+ const char *m_property_name;
+ ClangASTType m_property_opaque_type;
+ clang::ObjCIvarDecl *m_ivar_decl;
+ const char *m_property_setter_name;
+ const char *m_property_getter_name;
+ uint32_t m_property_attributes;
+ std::unique_ptr<ClangASTMetadata> m_metadata_ap;
+};
+
+struct BitfieldInfo
+{
+ uint64_t bit_size;
+ uint64_t bit_offset;
+
+ BitfieldInfo () :
+ bit_size (LLDB_INVALID_ADDRESS),
+ bit_offset (LLDB_INVALID_ADDRESS)
+ {
+ }
+
+ bool IsValid ()
+ {
+ return (bit_size != LLDB_INVALID_ADDRESS) &&
+ (bit_offset != LLDB_INVALID_ADDRESS);
+ }
+};
+
+
+bool
+SymbolFileDWARF::ClassOrStructIsVirtual (DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die)
+{
+ if (parent_die)
+ {
+ for (const DWARFDebugInfoEntry *die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling())
+ {
+ dw_tag_t tag = die->Tag();
+ bool check_virtuality = false;
+ switch (tag)
+ {
+ case DW_TAG_inheritance:
+ case DW_TAG_subprogram:
+ check_virtuality = true;
+ break;
+ default:
+ break;
+ }
+ if (check_virtuality)
+ {
+ if (die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_virtuality, 0) != 0)
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+size_t
+SymbolFileDWARF::ParseChildMembers
+(
+ const SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ ClangASTType &class_clang_type,
+ const LanguageType class_language,
+ std::vector<clang::CXXBaseSpecifier *>& base_classes,
+ std::vector<int>& member_accessibilities,
+ DWARFDIECollection& member_function_dies,
+ DelayedPropertyList& delayed_properties,
+ AccessType& default_accessibility,
+ bool &is_a_class,
+ LayoutInfo &layout_info
+)
+{
+ if (parent_die == NULL)
+ return 0;
+
+ size_t count = 0;
+ const DWARFDebugInfoEntry *die;
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+ uint32_t member_idx = 0;
+ BitfieldInfo last_field_info;
+
+ for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling())
+ {
+ dw_tag_t tag = die->Tag();
+
+ switch (tag)
+ {
+ case DW_TAG_member:
+ case DW_TAG_APPLE_property:
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_attributes = die->GetAttributes (this,
+ dwarf_cu,
+ fixed_form_sizes,
+ attributes);
+ if (num_attributes > 0)
+ {
+ Declaration decl;
+ //DWARFExpression location;
+ const char *name = NULL;
+ const char *prop_name = NULL;
+ const char *prop_getter_name = NULL;
+ const char *prop_setter_name = NULL;
+ uint32_t prop_attributes = 0;
+
+
+ bool is_artificial = false;
+ lldb::user_id_t encoding_uid = LLDB_INVALID_UID;
+ AccessType accessibility = eAccessNone;
+ uint32_t member_byte_offset = UINT32_MAX;
+ size_t byte_size = 0;
+ size_t bit_offset = 0;
+ size_t bit_size = 0;
+ bool is_external = false; // On DW_TAG_members, this means the member is static
+ uint32_t i;
+ for (i=0; i<num_attributes && !is_artificial; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_name: name = form_value.AsCString(&get_debug_str_data()); break;
+ case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break;
+ case DW_AT_bit_offset: bit_offset = form_value.Unsigned(); break;
+ case DW_AT_bit_size: bit_size = form_value.Unsigned(); break;
+ case DW_AT_byte_size: byte_size = form_value.Unsigned(); break;
+ case DW_AT_data_member_location:
+ if (form_value.BlockData())
+ {
+ Value initialValue(0);
+ Value memberOffset(0);
+ const DataExtractor& debug_info_data = get_debug_info_data();
+ uint32_t block_length = form_value.Unsigned();
+ uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart();
+ if (DWARFExpression::Evaluate(NULL, // ExecutionContext *
+ NULL, // ClangExpressionVariableList *
+ NULL, // ClangExpressionDeclMap *
+ NULL, // RegisterContext *
+ debug_info_data,
+ block_offset,
+ block_length,
+ eRegisterKindDWARF,
+ &initialValue,
+ memberOffset,
+ NULL))
+ {
+ member_byte_offset = memberOffset.ResolveValue(NULL).UInt();
+ }
+ }
+ else
+ {
+ // With DWARF 3 and later, if the value is an integer constant,
+ // this form value is the offset in bytes from the beginning
+ // of the containing entity.
+ member_byte_offset = form_value.Unsigned();
+ }
+ break;
+
+ case DW_AT_accessibility: accessibility = DW_ACCESS_to_AccessType (form_value.Unsigned()); break;
+ case DW_AT_artificial: is_artificial = form_value.Boolean(); break;
+ case DW_AT_APPLE_property_name: prop_name = form_value.AsCString(&get_debug_str_data()); break;
+ case DW_AT_APPLE_property_getter: prop_getter_name = form_value.AsCString(&get_debug_str_data()); break;
+ case DW_AT_APPLE_property_setter: prop_setter_name = form_value.AsCString(&get_debug_str_data()); break;
+ case DW_AT_APPLE_property_attribute: prop_attributes = form_value.Unsigned(); break;
+ case DW_AT_external: is_external = form_value.Boolean(); break;
+
+ default:
+ case DW_AT_declaration:
+ case DW_AT_description:
+ case DW_AT_mutable:
+ case DW_AT_visibility:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ if (prop_name)
+ {
+ ConstString fixed_getter;
+ ConstString fixed_setter;
+
+ // Check if the property getter/setter were provided as full
+ // names. We want basenames, so we extract them.
+
+ if (prop_getter_name && prop_getter_name[0] == '-')
+ {
+ ObjCLanguageRuntime::MethodName prop_getter_method(prop_getter_name, true);
+ prop_getter_name = prop_getter_method.GetSelector().GetCString();
+ }
+
+ if (prop_setter_name && prop_setter_name[0] == '-')
+ {
+ ObjCLanguageRuntime::MethodName prop_setter_method(prop_setter_name, true);
+ prop_setter_name = prop_setter_method.GetSelector().GetCString();
+ }
+
+ // If the names haven't been provided, they need to be
+ // filled in.
+
+ if (!prop_getter_name)
+ {
+ prop_getter_name = prop_name;
+ }
+ if (!prop_setter_name && prop_name[0] && !(prop_attributes & DW_APPLE_PROPERTY_readonly))
+ {
+ StreamString ss;
+
+ ss.Printf("set%c%s:",
+ toupper(prop_name[0]),
+ &prop_name[1]);
+
+ fixed_setter.SetCString(ss.GetData());
+ prop_setter_name = fixed_setter.GetCString();
+ }
+ }
+
+ // Clang has a DWARF generation bug where sometimes it
+ // represents fields that are references with bad byte size
+ // and bit size/offset information such as:
+ //
+ // DW_AT_byte_size( 0x00 )
+ // DW_AT_bit_size( 0x40 )
+ // DW_AT_bit_offset( 0xffffffffffffffc0 )
+ //
+ // So check the bit offset to make sure it is sane, and if
+ // the values are not sane, remove them. If we don't do this
+ // then we will end up with a crash if we try to use this
+ // type in an expression when clang becomes unhappy with its
+ // recycled debug info.
+
+ if (bit_offset > 128)
+ {
+ bit_size = 0;
+ bit_offset = 0;
+ }
+
+ // FIXME: Make Clang ignore Objective-C accessibility for expressions
+ if (class_language == eLanguageTypeObjC ||
+ class_language == eLanguageTypeObjC_plus_plus)
+ accessibility = eAccessNone;
+
+ if (member_idx == 0 && !is_artificial && name && (strstr (name, "_vptr$") == name))
+ {
+ // Not all compilers will mark the vtable pointer
+ // member as artificial (llvm-gcc). We can't have
+ // the virtual members in our classes otherwise it
+ // throws off all child offsets since we end up
+ // having and extra pointer sized member in our
+ // class layouts.
+ is_artificial = true;
+ }
+
+ // Handle static members
+ if (is_external && member_byte_offset == UINT32_MAX)
+ {
+ Type *var_type = ResolveTypeUID(encoding_uid);
+
+ if (var_type)
+ {
+ if (accessibility == eAccessNone)
+ accessibility = eAccessPublic;
+ class_clang_type.AddVariableToRecordType (name,
+ var_type->GetClangLayoutType(),
+ accessibility);
+ }
+ break;
+ }
+
+ if (is_artificial == false)
+ {
+ Type *member_type = ResolveTypeUID(encoding_uid);
+
+ clang::FieldDecl *field_decl = NULL;
+ if (tag == DW_TAG_member)
+ {
+ if (member_type)
+ {
+ if (accessibility == eAccessNone)
+ accessibility = default_accessibility;
+ member_accessibilities.push_back(accessibility);
+
+ BitfieldInfo this_field_info;
+
+ this_field_info.bit_size = bit_size;
+
+ if (member_byte_offset != UINT32_MAX || bit_size != 0)
+ {
+ /////////////////////////////////////////////////////////////
+ // How to locate a field given the DWARF debug information
+ //
+ // AT_byte_size indicates the size of the word in which the
+ // bit offset must be interpreted.
+ //
+ // AT_data_member_location indicates the byte offset of the
+ // word from the base address of the structure.
+ //
+ // AT_bit_offset indicates how many bits into the word
+ // (according to the host endianness) the low-order bit of
+ // the field starts. AT_bit_offset can be negative.
+ //
+ // AT_bit_size indicates the size of the field in bits.
+ /////////////////////////////////////////////////////////////
+
+ this_field_info.bit_offset = 0;
+
+ this_field_info.bit_offset += (member_byte_offset == UINT32_MAX ? 0 : (member_byte_offset * 8));
+
+ if (GetObjectFile()->GetByteOrder() == eByteOrderLittle)
+ {
+ this_field_info.bit_offset += byte_size * 8;
+ this_field_info.bit_offset -= (bit_offset + bit_size);
+ }
+ else
+ {
+ this_field_info.bit_offset += bit_offset;
+ }
+ }
+
+ // If the member to be emitted did not start on a character boundary and there is
+ // empty space between the last field and this one, then we need to emit an
+ // anonymous member filling up the space up to its start. There are three cases
+ // here:
+ //
+ // 1 If the previous member ended on a character boundary, then we can emit an
+ // anonymous member starting at the most recent character boundary.
+ //
+ // 2 If the previous member did not end on a character boundary and the distance
+ // from the end of the previous member to the current member is less than a
+ // word width, then we can emit an anonymous member starting right after the
+ // previous member and right before this member.
+ //
+ // 3 If the previous member did not end on a character boundary and the distance
+ // from the end of the previous member to the current member is greater than
+ // or equal a word width, then we act as in Case 1.
+
+ const uint64_t character_width = 8;
+ const uint64_t word_width = 32;
+
+ if (this_field_info.IsValid())
+ {
+ // Objective-C has invalid DW_AT_bit_offset values in older versions
+ // of clang, so we have to be careful and only insert unnammed bitfields
+ // if we have a new enough clang.
+ bool detect_unnamed_bitfields = true;
+
+ if (class_language == eLanguageTypeObjC || class_language == eLanguageTypeObjC_plus_plus)
+ detect_unnamed_bitfields = dwarf_cu->Supports_unnamed_objc_bitfields ();
+
+ if (detect_unnamed_bitfields)
+ {
+ BitfieldInfo anon_field_info;
+
+ if ((this_field_info.bit_offset % character_width) != 0) // not char aligned
+ {
+ uint64_t last_field_end = 0;
+
+ if (last_field_info.IsValid())
+ last_field_end = last_field_info.bit_offset + last_field_info.bit_size;
+
+ if (this_field_info.bit_offset != last_field_end)
+ {
+ if (((last_field_end % character_width) == 0) || // case 1
+ (this_field_info.bit_offset - last_field_end >= word_width)) // case 3
+ {
+ anon_field_info.bit_size = this_field_info.bit_offset % character_width;
+ anon_field_info.bit_offset = this_field_info.bit_offset - anon_field_info.bit_size;
+ }
+ else // case 2
+ {
+ anon_field_info.bit_size = this_field_info.bit_offset - last_field_end;
+ anon_field_info.bit_offset = last_field_end;
+ }
+ }
+ }
+
+ if (anon_field_info.IsValid())
+ {
+ clang::FieldDecl *unnamed_bitfield_decl = class_clang_type.AddFieldToRecordType (NULL,
+ GetClangASTContext().GetBuiltinTypeForEncodingAndBitSize(eEncodingSint, word_width),
+ accessibility,
+ anon_field_info.bit_size);
+
+ layout_info.field_offsets.insert(std::make_pair(unnamed_bitfield_decl, anon_field_info.bit_offset));
+ }
+ }
+ }
+
+ ClangASTType member_clang_type = member_type->GetClangLayoutType();
+
+ {
+ // Older versions of clang emit array[0] and array[1] in the same way (<rdar://problem/12566646>).
+ // If the current field is at the end of the structure, then there is definitely no room for extra
+ // elements and we override the type to array[0].
+
+ ClangASTType member_array_element_type;
+ uint64_t member_array_size;
+ bool member_array_is_incomplete;
+
+ if (member_clang_type.IsArrayType(&member_array_element_type,
+ &member_array_size,
+ &member_array_is_incomplete) &&
+ !member_array_is_incomplete)
+ {
+ uint64_t parent_byte_size = parent_die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_byte_size, UINT64_MAX);
+
+ if (member_byte_offset >= parent_byte_size)
+ {
+ if (member_array_size != 1)
+ {
+ GetObjectFile()->GetModule()->ReportError ("0x%8.8" PRIx64 ": DW_TAG_member '%s' refers to type 0x%8.8" PRIx64 " which extends beyond the bounds of 0x%8.8" PRIx64,
+ MakeUserID(die->GetOffset()),
+ name,
+ encoding_uid,
+ MakeUserID(parent_die->GetOffset()));
+ }
+
+ member_clang_type = GetClangASTContext().CreateArrayType(member_array_element_type, 0, false);
+ }
+ }
+ }
+
+ field_decl = class_clang_type.AddFieldToRecordType (name,
+ member_clang_type,
+ accessibility,
+ bit_size);
+
+ GetClangASTContext().SetMetadataAsUserID (field_decl, MakeUserID(die->GetOffset()));
+
+ if (this_field_info.IsValid())
+ {
+ layout_info.field_offsets.insert(std::make_pair(field_decl, this_field_info.bit_offset));
+ last_field_info = this_field_info;
+ }
+ }
+ else
+ {
+ if (name)
+ GetObjectFile()->GetModule()->ReportError ("0x%8.8" PRIx64 ": DW_TAG_member '%s' refers to type 0x%8.8" PRIx64 " which was unable to be parsed",
+ MakeUserID(die->GetOffset()),
+ name,
+ encoding_uid);
+ else
+ GetObjectFile()->GetModule()->ReportError ("0x%8.8" PRIx64 ": DW_TAG_member refers to type 0x%8.8" PRIx64 " which was unable to be parsed",
+ MakeUserID(die->GetOffset()),
+ encoding_uid);
+ }
+ }
+
+ if (prop_name != NULL)
+ {
+ clang::ObjCIvarDecl *ivar_decl = NULL;
+
+ if (field_decl)
+ {
+ ivar_decl = clang::dyn_cast<clang::ObjCIvarDecl>(field_decl);
+ assert (ivar_decl != NULL);
+ }
+
+ ClangASTMetadata metadata;
+ metadata.SetUserID (MakeUserID(die->GetOffset()));
+ delayed_properties.push_back(DelayedAddObjCClassProperty(class_clang_type,
+ prop_name,
+ member_type->GetClangLayoutType(),
+ ivar_decl,
+ prop_setter_name,
+ prop_getter_name,
+ prop_attributes,
+ &metadata));
+
+ if (ivar_decl)
+ GetClangASTContext().SetMetadataAsUserID (ivar_decl, MakeUserID(die->GetOffset()));
+ }
+ }
+ }
+ ++member_idx;
+ }
+ break;
+
+ case DW_TAG_subprogram:
+ // Let the type parsing code handle this one for us.
+ member_function_dies.Append (die);
+ break;
+
+ case DW_TAG_inheritance:
+ {
+ is_a_class = true;
+ if (default_accessibility == eAccessNone)
+ default_accessibility = eAccessPrivate;
+ // TODO: implement DW_TAG_inheritance type parsing
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_attributes = die->GetAttributes (this,
+ dwarf_cu,
+ fixed_form_sizes,
+ attributes);
+ if (num_attributes > 0)
+ {
+ Declaration decl;
+ DWARFExpression location;
+ lldb::user_id_t encoding_uid = LLDB_INVALID_UID;
+ AccessType accessibility = default_accessibility;
+ bool is_virtual = false;
+ bool is_base_of_class = true;
+ off_t member_byte_offset = 0;
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break;
+ case DW_AT_data_member_location:
+ if (form_value.BlockData())
+ {
+ Value initialValue(0);
+ Value memberOffset(0);
+ const DataExtractor& debug_info_data = get_debug_info_data();
+ uint32_t block_length = form_value.Unsigned();
+ uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart();
+ if (DWARFExpression::Evaluate (NULL,
+ NULL,
+ NULL,
+ NULL,
+ debug_info_data,
+ block_offset,
+ block_length,
+ eRegisterKindDWARF,
+ &initialValue,
+ memberOffset,
+ NULL))
+ {
+ member_byte_offset = memberOffset.ResolveValue(NULL).UInt();
+ }
+ }
+ else
+ {
+ // With DWARF 3 and later, if the value is an integer constant,
+ // this form value is the offset in bytes from the beginning
+ // of the containing entity.
+ member_byte_offset = form_value.Unsigned();
+ }
+ break;
+
+ case DW_AT_accessibility:
+ accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned());
+ break;
+
+ case DW_AT_virtuality:
+ is_virtual = form_value.Boolean();
+ break;
+
+ case DW_AT_sibling:
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ Type *base_class_type = ResolveTypeUID(encoding_uid);
+ assert(base_class_type);
+
+ ClangASTType base_class_clang_type = base_class_type->GetClangFullType();
+ assert (base_class_clang_type);
+ if (class_language == eLanguageTypeObjC)
+ {
+ class_clang_type.SetObjCSuperClass(base_class_clang_type);
+ }
+ else
+ {
+ base_classes.push_back (base_class_clang_type.CreateBaseClassSpecifier (accessibility,
+ is_virtual,
+ is_base_of_class));
+
+ if (is_virtual)
+ {
+ layout_info.vbase_offsets.insert(std::make_pair(class_clang_type.GetAsCXXRecordDecl(),
+ clang::CharUnits::fromQuantity(member_byte_offset)));
+ }
+ else
+ {
+ layout_info.base_offsets.insert(std::make_pair(class_clang_type.GetAsCXXRecordDecl(),
+ clang::CharUnits::fromQuantity(member_byte_offset)));
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return count;
+}
+
+
+clang::DeclContext*
+SymbolFileDWARF::GetClangDeclContextContainingTypeUID (lldb::user_id_t type_uid)
+{
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info && UserIDMatches(type_uid))
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = debug_info->GetDIEPtr(type_uid, &cu_sp);
+ if (die)
+ return GetClangDeclContextContainingDIE (cu_sp.get(), die, NULL);
+ }
+ return NULL;
+}
+
+clang::DeclContext*
+SymbolFileDWARF::GetClangDeclContextForTypeUID (const lldb_private::SymbolContext &sc, lldb::user_id_t type_uid)
+{
+ if (UserIDMatches(type_uid))
+ return GetClangDeclContextForDIEOffset (sc, type_uid);
+ return NULL;
+}
+
+Type*
+SymbolFileDWARF::ResolveTypeUID (lldb::user_id_t type_uid)
+{
+ if (UserIDMatches(type_uid))
+ {
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info)
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* type_die = debug_info->GetDIEPtr(type_uid, &cu_sp);
+ const bool assert_not_being_parsed = true;
+ return ResolveTypeUID (cu_sp.get(), type_die, assert_not_being_parsed);
+ }
+ }
+ return NULL;
+}
+
+Type*
+SymbolFileDWARF::ResolveTypeUID (DWARFCompileUnit* cu, const DWARFDebugInfoEntry* die, bool assert_not_being_parsed)
+{
+ if (die != NULL)
+ {
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO));
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::ResolveTypeUID (die = 0x%8.8x) %s '%s'",
+ die->GetOffset(),
+ DW_TAG_value_to_name(die->Tag()),
+ die->GetName(this, cu));
+
+ // We might be coming in in the middle of a type tree (a class
+ // withing a class, an enum within a class), so parse any needed
+ // parent DIEs before we get to this one...
+ const DWARFDebugInfoEntry *decl_ctx_die = GetDeclContextDIEContainingDIE (cu, die);
+ switch (decl_ctx_die->Tag())
+ {
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ {
+ // Get the type, which could be a forward declaration
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::ResolveTypeUID (die = 0x%8.8x) %s '%s' resolve parent forward type for 0x%8.8x",
+ die->GetOffset(),
+ DW_TAG_value_to_name(die->Tag()),
+ die->GetName(this, cu),
+ decl_ctx_die->GetOffset());
+//
+// Type *parent_type = ResolveTypeUID (cu, decl_ctx_die, assert_not_being_parsed);
+// if (child_requires_parent_class_union_or_struct_to_be_completed(die->Tag()))
+// {
+// if (log)
+// GetObjectFile()->GetModule()->LogMessage (log,
+// "SymbolFileDWARF::ResolveTypeUID (die = 0x%8.8x) %s '%s' resolve parent full type for 0x%8.8x since die is a function",
+// die->GetOffset(),
+// DW_TAG_value_to_name(die->Tag()),
+// die->GetName(this, cu),
+// decl_ctx_die->GetOffset());
+// // Ask the type to complete itself if it already hasn't since if we
+// // want a function (method or static) from a class, the class must
+// // create itself and add it's own methods and class functions.
+// if (parent_type)
+// parent_type->GetClangFullType();
+// }
+ }
+ break;
+
+ default:
+ break;
+ }
+ return ResolveType (cu, die);
+ }
+ return NULL;
+}
+
+// This function is used when SymbolFileDWARFDebugMap owns a bunch of
+// SymbolFileDWARF objects to detect if this DWARF file is the one that
+// can resolve a clang_type.
+bool
+SymbolFileDWARF::HasForwardDeclForClangType (const ClangASTType &clang_type)
+{
+ ClangASTType clang_type_no_qualifiers = clang_type.RemoveFastQualifiers();
+ const DWARFDebugInfoEntry* die = m_forward_decl_clang_type_to_die.lookup (clang_type_no_qualifiers.GetOpaqueQualType());
+ return die != NULL;
+}
+
+
+bool
+SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (ClangASTType &clang_type)
+{
+ // We have a struct/union/class/enum that needs to be fully resolved.
+ ClangASTType clang_type_no_qualifiers = clang_type.RemoveFastQualifiers();
+ const DWARFDebugInfoEntry* die = m_forward_decl_clang_type_to_die.lookup (clang_type_no_qualifiers.GetOpaqueQualType());
+ if (die == NULL)
+ {
+ // We have already resolved this type...
+ return true;
+ }
+ // Once we start resolving this type, remove it from the forward declaration
+ // map in case anyone child members or other types require this type to get resolved.
+ // The type will get resolved when all of the calls to SymbolFileDWARF::ResolveClangOpaqueTypeDefinition
+ // are done.
+ m_forward_decl_clang_type_to_die.erase (clang_type_no_qualifiers.GetOpaqueQualType());
+
+
+ // Disable external storage for this type so we don't get anymore
+ // clang::ExternalASTSource queries for this type.
+ clang_type.SetHasExternalStorage (false);
+
+ DWARFDebugInfo* debug_info = DebugInfo();
+
+ DWARFCompileUnit *dwarf_cu = debug_info->GetCompileUnitContainingDIE (die->GetOffset()).get();
+ Type *type = m_die_to_type.lookup (die);
+
+ const dw_tag_t tag = die->Tag();
+
+ Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO|DWARF_LOG_TYPE_COMPLETION));
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessageVerboseBacktrace (log,
+ "0x%8.8" PRIx64 ": %s '%s' resolving forward declaration...",
+ MakeUserID(die->GetOffset()),
+ DW_TAG_value_to_name(tag),
+ type->GetName().AsCString());
+
+ }
+ assert (clang_type);
+ DWARFDebugInfoEntry::Attributes attributes;
+
+ switch (tag)
+ {
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ {
+ LayoutInfo layout_info;
+
+ {
+ if (die->HasChildren())
+ {
+
+ LanguageType class_language = eLanguageTypeUnknown;
+ if (clang_type.IsObjCObjectOrInterfaceType())
+ {
+ class_language = eLanguageTypeObjC;
+ // For objective C we don't start the definition when
+ // the class is created.
+ clang_type.StartTagDeclarationDefinition ();
+ }
+
+ int tag_decl_kind = -1;
+ AccessType default_accessibility = eAccessNone;
+ if (tag == DW_TAG_structure_type)
+ {
+ tag_decl_kind = clang::TTK_Struct;
+ default_accessibility = eAccessPublic;
+ }
+ else if (tag == DW_TAG_union_type)
+ {
+ tag_decl_kind = clang::TTK_Union;
+ default_accessibility = eAccessPublic;
+ }
+ else if (tag == DW_TAG_class_type)
+ {
+ tag_decl_kind = clang::TTK_Class;
+ default_accessibility = eAccessPrivate;
+ }
+
+ SymbolContext sc(GetCompUnitForDWARFCompUnit(dwarf_cu));
+ std::vector<clang::CXXBaseSpecifier *> base_classes;
+ std::vector<int> member_accessibilities;
+ bool is_a_class = false;
+ // Parse members and base classes first
+ DWARFDIECollection member_function_dies;
+
+ DelayedPropertyList delayed_properties;
+ ParseChildMembers (sc,
+ dwarf_cu,
+ die,
+ clang_type,
+ class_language,
+ base_classes,
+ member_accessibilities,
+ member_function_dies,
+ delayed_properties,
+ default_accessibility,
+ is_a_class,
+ layout_info);
+
+ // Now parse any methods if there were any...
+ size_t num_functions = member_function_dies.Size();
+ if (num_functions > 0)
+ {
+ for (size_t i=0; i<num_functions; ++i)
+ {
+ ResolveType(dwarf_cu, member_function_dies.GetDIEPtrAtIndex(i));
+ }
+ }
+
+ if (class_language == eLanguageTypeObjC)
+ {
+ std::string class_str (clang_type.GetTypeName());
+ if (!class_str.empty())
+ {
+
+ DIEArray method_die_offsets;
+ if (m_using_apple_tables)
+ {
+ if (m_apple_objc_ap.get())
+ m_apple_objc_ap->FindByName(class_str.c_str(), method_die_offsets);
+ }
+ else
+ {
+ if (!m_indexed)
+ Index ();
+
+ ConstString class_name (class_str.c_str());
+ m_objc_class_selectors_index.Find (class_name, method_die_offsets);
+ }
+
+ if (!method_die_offsets.empty())
+ {
+ DWARFDebugInfo* debug_info = DebugInfo();
+
+ DWARFCompileUnit* method_cu = NULL;
+ const size_t num_matches = method_die_offsets.size();
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ const dw_offset_t die_offset = method_die_offsets[i];
+ DWARFDebugInfoEntry *method_die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &method_cu);
+
+ if (method_die)
+ ResolveType (method_cu, method_die);
+ else
+ {
+ if (m_using_apple_tables)
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_objc accelerator table had bad die 0x%8.8x for '%s')\n",
+ die_offset, class_str.c_str());
+ }
+ }
+ }
+ }
+
+ for (DelayedPropertyList::iterator pi = delayed_properties.begin(), pe = delayed_properties.end();
+ pi != pe;
+ ++pi)
+ pi->Finalize();
+ }
+ }
+
+ // If we have a DW_TAG_structure_type instead of a DW_TAG_class_type we
+ // need to tell the clang type it is actually a class.
+ if (class_language != eLanguageTypeObjC)
+ {
+ if (is_a_class && tag_decl_kind != clang::TTK_Class)
+ clang_type.SetTagTypeKind (clang::TTK_Class);
+ }
+
+ // Since DW_TAG_structure_type gets used for both classes
+ // and structures, we may need to set any DW_TAG_member
+ // fields to have a "private" access if none was specified.
+ // When we parsed the child members we tracked that actual
+ // accessibility value for each DW_TAG_member in the
+ // "member_accessibilities" array. If the value for the
+ // member is zero, then it was set to the "default_accessibility"
+ // which for structs was "public". Below we correct this
+ // by setting any fields to "private" that weren't correctly
+ // set.
+ if (is_a_class && !member_accessibilities.empty())
+ {
+ // This is a class and all members that didn't have
+ // their access specified are private.
+ clang_type.SetDefaultAccessForRecordFields (eAccessPrivate,
+ &member_accessibilities.front(),
+ member_accessibilities.size());
+ }
+
+ if (!base_classes.empty())
+ {
+ clang_type.SetBaseClassesForClassType (&base_classes.front(),
+ base_classes.size());
+
+ // Clang will copy each CXXBaseSpecifier in "base_classes"
+ // so we have to free them all.
+ ClangASTType::DeleteBaseClassSpecifiers (&base_classes.front(),
+ base_classes.size());
+ }
+ }
+ }
+
+ clang_type.BuildIndirectFields ();
+ clang_type.CompleteTagDeclarationDefinition ();
+
+ if (!layout_info.field_offsets.empty() ||
+ !layout_info.base_offsets.empty() ||
+ !layout_info.vbase_offsets.empty() )
+ {
+ if (type)
+ layout_info.bit_size = type->GetByteSize() * 8;
+ if (layout_info.bit_size == 0)
+ layout_info.bit_size = die->GetAttributeValueAsUnsigned(this, dwarf_cu, DW_AT_byte_size, 0) * 8;
+
+ clang::CXXRecordDecl *record_decl = clang_type.GetAsCXXRecordDecl();
+ if (record_decl)
+ {
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) caching layout info for record_decl = %p, bit_size = %" PRIu64 ", alignment = %" PRIu64 ", field_offsets[%u], base_offsets[%u], vbase_offsets[%u])",
+ clang_type.GetOpaqueQualType(),
+ record_decl,
+ layout_info.bit_size,
+ layout_info.alignment,
+ (uint32_t)layout_info.field_offsets.size(),
+ (uint32_t)layout_info.base_offsets.size(),
+ (uint32_t)layout_info.vbase_offsets.size());
+
+ uint32_t idx;
+ {
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t>::const_iterator pos, end = layout_info.field_offsets.end();
+ for (idx = 0, pos = layout_info.field_offsets.begin(); pos != end; ++pos, ++idx)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) field[%u] = { bit_offset=%u, name='%s' }",
+ clang_type.GetOpaqueQualType(),
+ idx,
+ (uint32_t)pos->second,
+ pos->first->getNameAsString().c_str());
+ }
+ }
+
+ {
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits>::const_iterator base_pos, base_end = layout_info.base_offsets.end();
+ for (idx = 0, base_pos = layout_info.base_offsets.begin(); base_pos != base_end; ++base_pos, ++idx)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) base[%u] = { byte_offset=%u, name='%s' }",
+ clang_type.GetOpaqueQualType(),
+ idx,
+ (uint32_t)base_pos->second.getQuantity(),
+ base_pos->first->getNameAsString().c_str());
+ }
+ }
+ {
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits>::const_iterator vbase_pos, vbase_end = layout_info.vbase_offsets.end();
+ for (idx = 0, vbase_pos = layout_info.vbase_offsets.begin(); vbase_pos != vbase_end; ++vbase_pos, ++idx)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition (clang_type = %p) vbase[%u] = { byte_offset=%u, name='%s' }",
+ clang_type.GetOpaqueQualType(),
+ idx,
+ (uint32_t)vbase_pos->second.getQuantity(),
+ vbase_pos->first->getNameAsString().c_str());
+ }
+ }
+ }
+ m_record_decl_to_layout_map.insert(std::make_pair(record_decl, layout_info));
+ }
+ }
+ }
+
+ return clang_type;
+
+ case DW_TAG_enumeration_type:
+ clang_type.StartTagDeclarationDefinition ();
+ if (die->HasChildren())
+ {
+ SymbolContext sc(GetCompUnitForDWARFCompUnit(dwarf_cu));
+ bool is_signed = false;
+ clang_type.IsIntegerType(is_signed);
+ ParseChildEnumerators(sc, clang_type, is_signed, type->GetByteSize(), dwarf_cu, die);
+ }
+ clang_type.CompleteTagDeclarationDefinition ();
+ return clang_type;
+
+ default:
+ assert(false && "not a forward clang type decl!");
+ break;
+ }
+ return false;
+}
+
+Type*
+SymbolFileDWARF::ResolveType (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry* type_die, bool assert_not_being_parsed)
+{
+ if (type_die != NULL)
+ {
+ Type *type = m_die_to_type.lookup (type_die);
+
+ if (type == NULL)
+ type = GetTypeForDIE (dwarf_cu, type_die).get();
+
+ if (assert_not_being_parsed)
+ {
+ if (type != DIE_IS_BEING_PARSED)
+ return type;
+
+ GetObjectFile()->GetModule()->ReportError ("Parsing a die that is being parsed die: 0x%8.8x: %s %s",
+ type_die->GetOffset(),
+ DW_TAG_value_to_name(type_die->Tag()),
+ type_die->GetName(this, dwarf_cu));
+
+ }
+ else
+ return type;
+ }
+ return NULL;
+}
+
+CompileUnit*
+SymbolFileDWARF::GetCompUnitForDWARFCompUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx)
+{
+ // Check if the symbol vendor already knows about this compile unit?
+ if (dwarf_cu->GetUserData() == NULL)
+ {
+ // The symbol vendor doesn't know about this compile unit, we
+ // need to parse and add it to the symbol vendor object.
+ return ParseCompileUnit(dwarf_cu, cu_idx).get();
+ }
+ return (CompileUnit*)dwarf_cu->GetUserData();
+}
+
+bool
+SymbolFileDWARF::GetFunction (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry* func_die, SymbolContext& sc)
+{
+ sc.Clear(false);
+ // Check if the symbol vendor already knows about this compile unit?
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX);
+
+ sc.function = sc.comp_unit->FindFunctionByUID (MakeUserID(func_die->GetOffset())).get();
+ if (sc.function == NULL)
+ sc.function = ParseCompileUnitFunction(sc, dwarf_cu, func_die);
+
+ if (sc.function)
+ {
+ sc.module_sp = sc.function->CalculateSymbolContextModule();
+ return true;
+ }
+
+ return false;
+}
+
+uint32_t
+SymbolFileDWARF::ResolveSymbolContext (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc)
+{
+ Timer scoped_timer(__PRETTY_FUNCTION__,
+ "SymbolFileDWARF::ResolveSymbolContext (so_addr = { section = %p, offset = 0x%" PRIx64 " }, resolve_scope = 0x%8.8x)",
+ so_addr.GetSection().get(),
+ so_addr.GetOffset(),
+ resolve_scope);
+ uint32_t resolved = 0;
+ if (resolve_scope & ( eSymbolContextCompUnit |
+ eSymbolContextFunction |
+ eSymbolContextBlock |
+ eSymbolContextLineEntry))
+ {
+ lldb::addr_t file_vm_addr = so_addr.GetFileAddress();
+
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info)
+ {
+ const dw_offset_t cu_offset = debug_info->GetCompileUnitAranges().FindAddress(file_vm_addr);
+ if (cu_offset != DW_INVALID_OFFSET)
+ {
+ uint32_t cu_idx = DW_INVALID_INDEX;
+ DWARFCompileUnit* dwarf_cu = debug_info->GetCompileUnit(cu_offset, &cu_idx).get();
+ if (dwarf_cu)
+ {
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, cu_idx);
+ if (sc.comp_unit)
+ {
+ resolved |= eSymbolContextCompUnit;
+
+ bool force_check_line_table = false;
+ if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock))
+ {
+ DWARFDebugInfoEntry *function_die = NULL;
+ DWARFDebugInfoEntry *block_die = NULL;
+ if (resolve_scope & eSymbolContextBlock)
+ {
+ dwarf_cu->LookupAddress(file_vm_addr, &function_die, &block_die);
+ }
+ else
+ {
+ dwarf_cu->LookupAddress(file_vm_addr, &function_die, NULL);
+ }
+
+ if (function_die != NULL)
+ {
+ sc.function = sc.comp_unit->FindFunctionByUID (MakeUserID(function_die->GetOffset())).get();
+ if (sc.function == NULL)
+ sc.function = ParseCompileUnitFunction(sc, dwarf_cu, function_die);
+ }
+ else
+ {
+ // We might have had a compile unit that had discontiguous
+ // address ranges where the gaps are symbols that don't have
+ // any debug info. Discontiguous compile unit address ranges
+ // should only happen when there aren't other functions from
+ // other compile units in these gaps. This helps keep the size
+ // of the aranges down.
+ force_check_line_table = true;
+ }
+
+ if (sc.function != NULL)
+ {
+ resolved |= eSymbolContextFunction;
+
+ if (resolve_scope & eSymbolContextBlock)
+ {
+ Block& block = sc.function->GetBlock (true);
+
+ if (block_die != NULL)
+ sc.block = block.FindBlockByID (MakeUserID(block_die->GetOffset()));
+ else
+ sc.block = block.FindBlockByID (MakeUserID(function_die->GetOffset()));
+ if (sc.block)
+ resolved |= eSymbolContextBlock;
+ }
+ }
+ }
+
+ if ((resolve_scope & eSymbolContextLineEntry) || force_check_line_table)
+ {
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+ if (line_table != NULL)
+ {
+ // And address that makes it into this function should be in terms
+ // of this debug file if there is no debug map, or it will be an
+ // address in the .o file which needs to be fixed up to be in terms
+ // of the debug map executable. Either way, calling FixupAddress()
+ // will work for us.
+ Address exe_so_addr (so_addr);
+ if (FixupAddress(exe_so_addr))
+ {
+ if (line_table->FindLineEntryByAddress (exe_so_addr, sc.line_entry))
+ {
+ resolved |= eSymbolContextLineEntry;
+ }
+ }
+ }
+ }
+
+ if (force_check_line_table && !(resolved & eSymbolContextLineEntry))
+ {
+ // We might have had a compile unit that had discontiguous
+ // address ranges where the gaps are symbols that don't have
+ // any debug info. Discontiguous compile unit address ranges
+ // should only happen when there aren't other functions from
+ // other compile units in these gaps. This helps keep the size
+ // of the aranges down.
+ sc.comp_unit = NULL;
+ resolved &= ~eSymbolContextCompUnit;
+ }
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->ReportWarning ("0x%8.8x: compile unit %u failed to create a valid lldb_private::CompileUnit class.",
+ cu_offset,
+ cu_idx);
+ }
+ }
+ }
+ }
+ }
+ return resolved;
+}
+
+
+
+uint32_t
+SymbolFileDWARF::ResolveSymbolContext(const FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list)
+{
+ const uint32_t prev_size = sc_list.GetSize();
+ if (resolve_scope & eSymbolContextCompUnit)
+ {
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info)
+ {
+ uint32_t cu_idx;
+ DWARFCompileUnit* dwarf_cu = NULL;
+
+ for (cu_idx = 0; (dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx)) != NULL; ++cu_idx)
+ {
+ CompileUnit *dc_cu = GetCompUnitForDWARFCompUnit(dwarf_cu, cu_idx);
+ const bool full_match = file_spec.GetDirectory();
+ bool file_spec_matches_cu_file_spec = dc_cu != NULL && FileSpec::Equal(file_spec, *dc_cu, full_match);
+ if (check_inlines || file_spec_matches_cu_file_spec)
+ {
+ SymbolContext sc (m_obj_file->GetModule());
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, cu_idx);
+ if (sc.comp_unit)
+ {
+ uint32_t file_idx = UINT32_MAX;
+
+ // If we are looking for inline functions only and we don't
+ // find it in the support files, we are done.
+ if (check_inlines)
+ {
+ file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex (1, file_spec, true);
+ if (file_idx == UINT32_MAX)
+ continue;
+ }
+
+ if (line != 0)
+ {
+ LineTable *line_table = sc.comp_unit->GetLineTable();
+
+ if (line_table != NULL && line != 0)
+ {
+ // We will have already looked up the file index if
+ // we are searching for inline entries.
+ if (!check_inlines)
+ file_idx = sc.comp_unit->GetSupportFiles().FindFileIndex (1, file_spec, true);
+
+ if (file_idx != UINT32_MAX)
+ {
+ uint32_t found_line;
+ uint32_t line_idx = line_table->FindLineEntryIndexByFileIndex (0, file_idx, line, false, &sc.line_entry);
+ found_line = sc.line_entry.line;
+
+ while (line_idx != UINT32_MAX)
+ {
+ sc.function = NULL;
+ sc.block = NULL;
+ if (resolve_scope & (eSymbolContextFunction | eSymbolContextBlock))
+ {
+ const lldb::addr_t file_vm_addr = sc.line_entry.range.GetBaseAddress().GetFileAddress();
+ if (file_vm_addr != LLDB_INVALID_ADDRESS)
+ {
+ DWARFDebugInfoEntry *function_die = NULL;
+ DWARFDebugInfoEntry *block_die = NULL;
+ dwarf_cu->LookupAddress(file_vm_addr, &function_die, resolve_scope & eSymbolContextBlock ? &block_die : NULL);
+
+ if (function_die != NULL)
+ {
+ sc.function = sc.comp_unit->FindFunctionByUID (MakeUserID(function_die->GetOffset())).get();
+ if (sc.function == NULL)
+ sc.function = ParseCompileUnitFunction(sc, dwarf_cu, function_die);
+ }
+
+ if (sc.function != NULL)
+ {
+ Block& block = sc.function->GetBlock (true);
+
+ if (block_die != NULL)
+ sc.block = block.FindBlockByID (MakeUserID(block_die->GetOffset()));
+ else
+ sc.block = block.FindBlockByID (MakeUserID(function_die->GetOffset()));
+ }
+ }
+ }
+
+ sc_list.Append(sc);
+ line_idx = line_table->FindLineEntryIndexByFileIndex (line_idx + 1, file_idx, found_line, true, &sc.line_entry);
+ }
+ }
+ }
+ else if (file_spec_matches_cu_file_spec && !check_inlines)
+ {
+ // only append the context if we aren't looking for inline call sites
+ // by file and line and if the file spec matches that of the compile unit
+ sc_list.Append(sc);
+ }
+ }
+ else if (file_spec_matches_cu_file_spec && !check_inlines)
+ {
+ // only append the context if we aren't looking for inline call sites
+ // by file and line and if the file spec matches that of the compile unit
+ sc_list.Append(sc);
+ }
+
+ if (!check_inlines)
+ break;
+ }
+ }
+ }
+ }
+ }
+ return sc_list.GetSize() - prev_size;
+}
+
+void
+SymbolFileDWARF::Index ()
+{
+ if (m_indexed)
+ return;
+ m_indexed = true;
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARF::Index (%s)",
+ GetObjectFile()->GetFileSpec().GetFilename().AsCString());
+
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info)
+ {
+ uint32_t cu_idx = 0;
+ const uint32_t num_compile_units = GetNumCompileUnits();
+ for (cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
+ {
+ DWARFCompileUnit* dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx);
+
+ bool clear_dies = dwarf_cu->ExtractDIEsIfNeeded (false) > 1;
+
+ dwarf_cu->Index (cu_idx,
+ m_function_basename_index,
+ m_function_fullname_index,
+ m_function_method_index,
+ m_function_selector_index,
+ m_objc_class_selectors_index,
+ m_global_index,
+ m_type_index,
+ m_namespace_index);
+
+ // Keep memory down by clearing DIEs if this generate function
+ // caused them to be parsed
+ if (clear_dies)
+ dwarf_cu->ClearDIEs (true);
+ }
+
+ m_function_basename_index.Finalize();
+ m_function_fullname_index.Finalize();
+ m_function_method_index.Finalize();
+ m_function_selector_index.Finalize();
+ m_objc_class_selectors_index.Finalize();
+ m_global_index.Finalize();
+ m_type_index.Finalize();
+ m_namespace_index.Finalize();
+
+#if defined (ENABLE_DEBUG_PRINTF)
+ StreamFile s(stdout, false);
+ s.Printf ("DWARF index for '%s':",
+ GetObjectFile()->GetFileSpec().GetPath().c_str());
+ s.Printf("\nFunction basenames:\n"); m_function_basename_index.Dump (&s);
+ s.Printf("\nFunction fullnames:\n"); m_function_fullname_index.Dump (&s);
+ s.Printf("\nFunction methods:\n"); m_function_method_index.Dump (&s);
+ s.Printf("\nFunction selectors:\n"); m_function_selector_index.Dump (&s);
+ s.Printf("\nObjective C class selectors:\n"); m_objc_class_selectors_index.Dump (&s);
+ s.Printf("\nGlobals and statics:\n"); m_global_index.Dump (&s);
+ s.Printf("\nTypes:\n"); m_type_index.Dump (&s);
+ s.Printf("\nNamepaces:\n"); m_namespace_index.Dump (&s);
+#endif
+ }
+}
+
+bool
+SymbolFileDWARF::NamespaceDeclMatchesThisSymbolFile (const ClangNamespaceDecl *namespace_decl)
+{
+ if (namespace_decl == NULL)
+ {
+ // Invalid namespace decl which means we aren't matching only things
+ // in this symbol file, so return true to indicate it matches this
+ // symbol file.
+ return true;
+ }
+
+ clang::ASTContext *namespace_ast = namespace_decl->GetASTContext();
+
+ if (namespace_ast == NULL)
+ return true; // No AST in the "namespace_decl", return true since it
+ // could then match any symbol file, including this one
+
+ if (namespace_ast == GetClangASTContext().getASTContext())
+ return true; // The ASTs match, return true
+
+ // The namespace AST was valid, and it does not match...
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
+
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage(log, "Valid namespace does not match symbol file");
+
+ return false;
+}
+
+bool
+SymbolFileDWARF::DIEIsInNamespace (const ClangNamespaceDecl *namespace_decl,
+ DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry* die)
+{
+ // No namespace specified, so the answesr i
+ if (namespace_decl == NULL)
+ return true;
+
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
+
+ const DWARFDebugInfoEntry *decl_ctx_die = NULL;
+ clang::DeclContext *die_clang_decl_ctx = GetClangDeclContextContainingDIE (cu, die, &decl_ctx_die);
+ if (decl_ctx_die)
+ {
+ clang::NamespaceDecl *clang_namespace_decl = namespace_decl->GetNamespaceDecl();
+
+ if (clang_namespace_decl)
+ {
+ if (decl_ctx_die->Tag() != DW_TAG_namespace)
+ {
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage(log, "Found a match, but its parent is not a namespace");
+ return false;
+ }
+
+ if (clang_namespace_decl == die_clang_decl_ctx)
+ return true;
+ else
+ return false;
+ }
+ else
+ {
+ // We have a namespace_decl that was not NULL but it contained
+ // a NULL "clang::NamespaceDecl", so this means the global namespace
+ // So as long the the contained decl context DIE isn't a namespace
+ // we should be ok.
+ if (decl_ctx_die->Tag() != DW_TAG_namespace)
+ return true;
+ }
+ }
+
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage(log, "Found a match, but its parent doesn't exist");
+
+ return false;
+}
+uint32_t
+SymbolFileDWARF::FindGlobalVariables (const ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, VariableList& variables)
+{
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
+
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", namespace_decl=%p, append=%u, max_matches=%u, variables)",
+ name.GetCString(),
+ namespace_decl,
+ append,
+ max_matches);
+ }
+
+ if (!NamespaceDeclMatchesThisSymbolFile(namespace_decl))
+ return 0;
+
+ DWARFDebugInfo* info = DebugInfo();
+ if (info == NULL)
+ return 0;
+
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ variables.Clear();
+
+ // Remember how many variables are in the list before we search in case
+ // we are appending the results to a variable list.
+ const uint32_t original_size = variables.GetSize();
+
+ DIEArray die_offsets;
+
+ if (m_using_apple_tables)
+ {
+ if (m_apple_names_ap.get())
+ {
+ const char *name_cstr = name.GetCString();
+ const char *base_name_start;
+ const char *base_name_end = NULL;
+
+ if (!CPPLanguageRuntime::StripNamespacesFromVariableName(name_cstr, base_name_start, base_name_end))
+ base_name_start = name_cstr;
+
+ m_apple_names_ap->FindByName (base_name_start, die_offsets);
+ }
+ }
+ else
+ {
+ // Index the DWARF if we haven't already
+ if (!m_indexed)
+ Index ();
+
+ m_global_index.Find (name, die_offsets);
+ }
+
+ const size_t num_die_matches = die_offsets.size();
+ if (num_die_matches)
+ {
+ SymbolContext sc;
+ sc.module_sp = m_obj_file->GetModule();
+ assert (sc.module_sp);
+
+ DWARFDebugInfo* debug_info = DebugInfo();
+ DWARFCompileUnit* dwarf_cu = NULL;
+ const DWARFDebugInfoEntry* die = NULL;
+ bool done = false;
+ for (size_t i=0; i<num_die_matches && !done; ++i)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+
+ if (die)
+ {
+ switch (die->Tag())
+ {
+ default:
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_try_block:
+ case DW_TAG_catch_block:
+ break;
+
+ case DW_TAG_variable:
+ {
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX);
+
+ if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
+ continue;
+
+ ParseVariables(sc, dwarf_cu, LLDB_INVALID_ADDRESS, die, false, false, &variables);
+
+ if (variables.GetSize() - original_size >= max_matches)
+ done = true;
+ }
+ break;
+ }
+ }
+ else
+ {
+ if (m_using_apple_tables)
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')\n",
+ die_offset, name.GetCString());
+ }
+ }
+ }
+ }
+
+ // Return the number of variable that were appended to the list
+ const uint32_t num_matches = variables.GetSize() - original_size;
+ if (log && num_matches > 0)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindGlobalVariables (name=\"%s\", namespace_decl=%p, append=%u, max_matches=%u, variables) => %u",
+ name.GetCString(),
+ namespace_decl,
+ append,
+ max_matches,
+ num_matches);
+ }
+ return num_matches;
+}
+
+uint32_t
+SymbolFileDWARF::FindGlobalVariables(const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables)
+{
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
+
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindGlobalVariables (regex=\"%s\", append=%u, max_matches=%u, variables)",
+ regex.GetText(),
+ append,
+ max_matches);
+ }
+
+ DWARFDebugInfo* info = DebugInfo();
+ if (info == NULL)
+ return 0;
+
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ variables.Clear();
+
+ // Remember how many variables are in the list before we search in case
+ // we are appending the results to a variable list.
+ const uint32_t original_size = variables.GetSize();
+
+ DIEArray die_offsets;
+
+ if (m_using_apple_tables)
+ {
+ if (m_apple_names_ap.get())
+ {
+ DWARFMappedHash::DIEInfoArray hash_data_array;
+ if (m_apple_names_ap->AppendAllDIEsThatMatchingRegex (regex, hash_data_array))
+ DWARFMappedHash::ExtractDIEArray (hash_data_array, die_offsets);
+ }
+ }
+ else
+ {
+ // Index the DWARF if we haven't already
+ if (!m_indexed)
+ Index ();
+
+ m_global_index.Find (regex, die_offsets);
+ }
+
+ SymbolContext sc;
+ sc.module_sp = m_obj_file->GetModule();
+ assert (sc.module_sp);
+
+ DWARFCompileUnit* dwarf_cu = NULL;
+ const DWARFDebugInfoEntry* die = NULL;
+ const size_t num_matches = die_offsets.size();
+ if (num_matches)
+ {
+ DWARFDebugInfo* debug_info = DebugInfo();
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+
+ if (die)
+ {
+ sc.comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX);
+
+ ParseVariables(sc, dwarf_cu, LLDB_INVALID_ADDRESS, die, false, false, &variables);
+
+ if (variables.GetSize() - original_size >= max_matches)
+ break;
+ }
+ else
+ {
+ if (m_using_apple_tables)
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for regex '%s')\n",
+ die_offset, regex.GetText());
+ }
+ }
+ }
+ }
+
+ // Return the number of variable that were appended to the list
+ return variables.GetSize() - original_size;
+}
+
+
+bool
+SymbolFileDWARF::ResolveFunction (dw_offset_t die_offset,
+ DWARFCompileUnit *&dwarf_cu,
+ SymbolContextList& sc_list)
+{
+ const DWARFDebugInfoEntry *die = DebugInfo()->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+ return ResolveFunction (dwarf_cu, die, sc_list);
+}
+
+
+bool
+SymbolFileDWARF::ResolveFunction (DWARFCompileUnit *cu,
+ const DWARFDebugInfoEntry *die,
+ SymbolContextList& sc_list)
+{
+ SymbolContext sc;
+
+ if (die == NULL)
+ return false;
+
+ // If we were passed a die that is not a function, just return false...
+ if (die->Tag() != DW_TAG_subprogram && die->Tag() != DW_TAG_inlined_subroutine)
+ return false;
+
+ const DWARFDebugInfoEntry* inlined_die = NULL;
+ if (die->Tag() == DW_TAG_inlined_subroutine)
+ {
+ inlined_die = die;
+
+ while ((die = die->GetParent()) != NULL)
+ {
+ if (die->Tag() == DW_TAG_subprogram)
+ break;
+ }
+ }
+ assert (die->Tag() == DW_TAG_subprogram);
+ if (GetFunction (cu, die, sc))
+ {
+ Address addr;
+ // Parse all blocks if needed
+ if (inlined_die)
+ {
+ sc.block = sc.function->GetBlock (true).FindBlockByID (MakeUserID(inlined_die->GetOffset()));
+ assert (sc.block != NULL);
+ if (sc.block->GetStartAddress (addr) == false)
+ addr.Clear();
+ }
+ else
+ {
+ sc.block = NULL;
+ addr = sc.function->GetAddressRange().GetBaseAddress();
+ }
+
+ if (addr.IsValid())
+ {
+ sc_list.Append(sc);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void
+SymbolFileDWARF::FindFunctions (const ConstString &name,
+ const NameToDIE &name_to_die,
+ SymbolContextList& sc_list)
+{
+ DIEArray die_offsets;
+ if (name_to_die.Find (name, die_offsets))
+ {
+ ParseFunctions (die_offsets, sc_list);
+ }
+}
+
+
+void
+SymbolFileDWARF::FindFunctions (const RegularExpression &regex,
+ const NameToDIE &name_to_die,
+ SymbolContextList& sc_list)
+{
+ DIEArray die_offsets;
+ if (name_to_die.Find (regex, die_offsets))
+ {
+ ParseFunctions (die_offsets, sc_list);
+ }
+}
+
+
+void
+SymbolFileDWARF::FindFunctions (const RegularExpression &regex,
+ const DWARFMappedHash::MemoryTable &memory_table,
+ SymbolContextList& sc_list)
+{
+ DIEArray die_offsets;
+ DWARFMappedHash::DIEInfoArray hash_data_array;
+ if (memory_table.AppendAllDIEsThatMatchingRegex (regex, hash_data_array))
+ {
+ DWARFMappedHash::ExtractDIEArray (hash_data_array, die_offsets);
+ ParseFunctions (die_offsets, sc_list);
+ }
+}
+
+void
+SymbolFileDWARF::ParseFunctions (const DIEArray &die_offsets,
+ SymbolContextList& sc_list)
+{
+ const size_t num_matches = die_offsets.size();
+ if (num_matches)
+ {
+ SymbolContext sc;
+
+ DWARFCompileUnit* dwarf_cu = NULL;
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ ResolveFunction (die_offset, dwarf_cu, sc_list);
+ }
+ }
+}
+
+bool
+SymbolFileDWARF::FunctionDieMatchesPartialName (const DWARFDebugInfoEntry* die,
+ const DWARFCompileUnit *dwarf_cu,
+ uint32_t name_type_mask,
+ const char *partial_name,
+ const char *base_name_start,
+ const char *base_name_end)
+{
+ // If we are looking only for methods, throw away all the ones that are or aren't in C++ classes:
+ if (name_type_mask == eFunctionNameTypeMethod || name_type_mask == eFunctionNameTypeBase)
+ {
+ clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIEOffset(die->GetOffset());
+ if (!containing_decl_ctx)
+ return false;
+
+ bool is_cxx_method = DeclKindIsCXXClass(containing_decl_ctx->getDeclKind());
+
+ if (name_type_mask == eFunctionNameTypeMethod)
+ {
+ if (is_cxx_method == false)
+ return false;
+ }
+
+ if (name_type_mask == eFunctionNameTypeBase)
+ {
+ if (is_cxx_method == true)
+ return false;
+ }
+ }
+
+ // Now we need to check whether the name we got back for this type matches the extra specifications
+ // that were in the name we're looking up:
+ if (base_name_start != partial_name || *base_name_end != '\0')
+ {
+ // First see if the stuff to the left matches the full name. To do that let's see if
+ // we can pull out the mips linkage name attribute:
+
+ Mangled best_name;
+ DWARFDebugInfoEntry::Attributes attributes;
+ DWARFFormValue form_value;
+ die->GetAttributes(this, dwarf_cu, NULL, attributes);
+ uint32_t idx = attributes.FindAttributeIndex(DW_AT_MIPS_linkage_name);
+ if (idx == UINT32_MAX)
+ idx = attributes.FindAttributeIndex(DW_AT_linkage_name);
+ if (idx != UINT32_MAX)
+ {
+ if (attributes.ExtractFormValueAtIndex(this, idx, form_value))
+ {
+ const char *mangled_name = form_value.AsCString(&get_debug_str_data());
+ if (mangled_name)
+ best_name.SetValue (ConstString(mangled_name), true);
+ }
+ }
+
+ if (!best_name)
+ {
+ idx = attributes.FindAttributeIndex(DW_AT_name);
+ if (idx != UINT32_MAX && attributes.ExtractFormValueAtIndex(this, idx, form_value))
+ {
+ const char *name = form_value.AsCString(&get_debug_str_data());
+ best_name.SetValue (ConstString(name), false);
+ }
+ }
+
+ if (best_name.GetDemangledName())
+ {
+ const char *demangled = best_name.GetDemangledName().GetCString();
+ if (demangled)
+ {
+ std::string name_no_parens(partial_name, base_name_end - partial_name);
+ const char *partial_in_demangled = strstr (demangled, name_no_parens.c_str());
+ if (partial_in_demangled == NULL)
+ return false;
+ else
+ {
+ // Sort out the case where our name is something like "Process::Destroy" and the match is
+ // "SBProcess::Destroy" - that shouldn't be a match. We should really always match on
+ // namespace boundaries...
+
+ if (partial_name[0] == ':' && partial_name[1] == ':')
+ {
+ // The partial name was already on a namespace boundary so all matches are good.
+ return true;
+ }
+ else if (partial_in_demangled == demangled)
+ {
+ // They both start the same, so this is an good match.
+ return true;
+ }
+ else
+ {
+ if (partial_in_demangled - demangled == 1)
+ {
+ // Only one character difference, can't be a namespace boundary...
+ return false;
+ }
+ else if (*(partial_in_demangled - 1) == ':' && *(partial_in_demangled - 2) == ':')
+ {
+ // We are on a namespace boundary, so this is also good.
+ return true;
+ }
+ else
+ return false;
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+uint32_t
+SymbolFileDWARF::FindFunctions (const ConstString &name,
+ const lldb_private::ClangNamespaceDecl *namespace_decl,
+ uint32_t name_type_mask,
+ bool include_inlines,
+ bool append,
+ SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARF::FindFunctions (name = '%s')",
+ name.AsCString());
+
+ // eFunctionNameTypeAuto should be pre-resolved by a call to Module::PrepareForFunctionNameLookup()
+ assert ((name_type_mask & eFunctionNameTypeAuto) == 0);
+
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
+
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindFunctions (name=\"%s\", name_type_mask=0x%x, append=%u, sc_list)",
+ name.GetCString(),
+ name_type_mask,
+ append);
+ }
+
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ sc_list.Clear();
+
+ if (!NamespaceDeclMatchesThisSymbolFile(namespace_decl))
+ return 0;
+
+ // If name is empty then we won't find anything.
+ if (name.IsEmpty())
+ return 0;
+
+ // Remember how many sc_list are in the list before we search in case
+ // we are appending the results to a variable list.
+
+ const char *name_cstr = name.GetCString();
+
+ const uint32_t original_size = sc_list.GetSize();
+
+ DWARFDebugInfo* info = DebugInfo();
+ if (info == NULL)
+ return 0;
+
+ DWARFCompileUnit *dwarf_cu = NULL;
+ std::set<const DWARFDebugInfoEntry *> resolved_dies;
+ if (m_using_apple_tables)
+ {
+ if (m_apple_names_ap.get())
+ {
+
+ DIEArray die_offsets;
+
+ uint32_t num_matches = 0;
+
+ if (name_type_mask & eFunctionNameTypeFull)
+ {
+ // If they asked for the full name, match what they typed. At some point we may
+ // want to canonicalize this (strip double spaces, etc. For now, we just add all the
+ // dies that we find by exact match.
+ num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets);
+ for (uint32_t i = 0; i < num_matches; i++)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ const DWARFDebugInfoEntry *die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+ if (die)
+ {
+ if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
+ continue;
+
+ if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
+ continue;
+
+ if (resolved_dies.find(die) == resolved_dies.end())
+ {
+ if (ResolveFunction (dwarf_cu, die, sc_list))
+ resolved_dies.insert(die);
+ }
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')",
+ die_offset, name_cstr);
+ }
+ }
+ }
+
+ if (name_type_mask & eFunctionNameTypeSelector)
+ {
+ if (namespace_decl && *namespace_decl)
+ return 0; // no selectors in namespaces
+
+ num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets);
+ // Now make sure these are actually ObjC methods. In this case we can simply look up the name,
+ // and if it is an ObjC method name, we're good.
+
+ for (uint32_t i = 0; i < num_matches; i++)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+ if (die)
+ {
+ const char *die_name = die->GetName(this, dwarf_cu);
+ if (ObjCLanguageRuntime::IsPossibleObjCMethodName(die_name))
+ {
+ if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
+ continue;
+
+ if (resolved_dies.find(die) == resolved_dies.end())
+ {
+ if (ResolveFunction (dwarf_cu, die, sc_list))
+ resolved_dies.insert(die);
+ }
+ }
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->ReportError ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')",
+ die_offset, name_cstr);
+ }
+ }
+ die_offsets.clear();
+ }
+
+ if (((name_type_mask & eFunctionNameTypeMethod) && !namespace_decl) || name_type_mask & eFunctionNameTypeBase)
+ {
+ // The apple_names table stores just the "base name" of C++ methods in the table. So we have to
+ // extract the base name, look that up, and if there is any other information in the name we were
+ // passed in we have to post-filter based on that.
+
+ // FIXME: Arrange the logic above so that we don't calculate the base name twice:
+ num_matches = m_apple_names_ap->FindByName (name_cstr, die_offsets);
+
+ for (uint32_t i = 0; i < num_matches; i++)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+ if (die)
+ {
+ if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
+ continue;
+
+ if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
+ continue;
+
+ // If we get to here, the die is good, and we should add it:
+ if (resolved_dies.find(die) == resolved_dies.end())
+ if (ResolveFunction (dwarf_cu, die, sc_list))
+ {
+ bool keep_die = true;
+ if ((name_type_mask & (eFunctionNameTypeBase|eFunctionNameTypeMethod)) != (eFunctionNameTypeBase|eFunctionNameTypeMethod))
+ {
+ // We are looking for either basenames or methods, so we need to
+ // trim out the ones we won't want by looking at the type
+ SymbolContext sc;
+ if (sc_list.GetLastContext(sc))
+ {
+ if (sc.block)
+ {
+ // We have an inlined function
+ }
+ else if (sc.function)
+ {
+ Type *type = sc.function->GetType();
+
+ clang::DeclContext* decl_ctx = GetClangDeclContextContainingTypeUID (type->GetID());
+ if (decl_ctx->isRecord())
+ {
+ if (name_type_mask & eFunctionNameTypeBase)
+ {
+ sc_list.RemoveContextAtIndex(sc_list.GetSize()-1);
+ keep_die = false;
+ }
+ }
+ else
+ {
+ if (name_type_mask & eFunctionNameTypeMethod)
+ {
+ sc_list.RemoveContextAtIndex(sc_list.GetSize()-1);
+ keep_die = false;
+ }
+ }
+ }
+ }
+ }
+ if (keep_die)
+ resolved_dies.insert(die);
+ }
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x for '%s')",
+ die_offset, name_cstr);
+ }
+ }
+ die_offsets.clear();
+ }
+ }
+ }
+ else
+ {
+
+ // Index the DWARF if we haven't already
+ if (!m_indexed)
+ Index ();
+
+ if (name_type_mask & eFunctionNameTypeFull)
+ {
+ FindFunctions (name, m_function_fullname_index, sc_list);
+
+ // Temporary workaround for global/anonymous namespace functions on linux
+#if defined (__linux__)
+ // If we didn't find any functions in the global namespace try
+ // looking in the basename index but ignore any returned
+ // functions that have a namespace (ie. mangled names starting with
+ // '_ZN') but keep functions which have an anonymous namespace
+ if (sc_list.GetSize() == 0)
+ {
+ SymbolContextList temp_sc_list;
+ FindFunctions (name, m_function_basename_index, temp_sc_list);
+ if (!namespace_decl)
+ {
+ SymbolContext sc;
+ for (uint32_t i = 0; i < temp_sc_list.GetSize(); i++)
+ {
+ if (temp_sc_list.GetContextAtIndex(i, sc))
+ {
+ ConstString mangled_name = sc.GetFunctionName(Mangled::ePreferMangled);
+ ConstString demangled_name = sc.GetFunctionName(Mangled::ePreferDemangled);
+ if (strncmp(mangled_name.GetCString(), "_ZN", 3) ||
+ !strncmp(demangled_name.GetCString(), "(anonymous namespace)", 21))
+ {
+ sc_list.Append(sc);
+ }
+ }
+ }
+ }
+ }
+#endif
+ }
+ DIEArray die_offsets;
+ DWARFCompileUnit *dwarf_cu = NULL;
+
+ if (name_type_mask & eFunctionNameTypeBase)
+ {
+ uint32_t num_base = m_function_basename_index.Find(name, die_offsets);
+ for (uint32_t i = 0; i < num_base; i++)
+ {
+ const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offsets[i], &dwarf_cu);
+ if (die)
+ {
+ if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
+ continue;
+
+ if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
+ continue;
+
+ // If we get to here, the die is good, and we should add it:
+ if (resolved_dies.find(die) == resolved_dies.end())
+ {
+ if (ResolveFunction (dwarf_cu, die, sc_list))
+ resolved_dies.insert(die);
+ }
+ }
+ }
+ die_offsets.clear();
+ }
+
+ if (name_type_mask & eFunctionNameTypeMethod)
+ {
+ if (namespace_decl && *namespace_decl)
+ return 0; // no methods in namespaces
+
+ uint32_t num_base = m_function_method_index.Find(name, die_offsets);
+ {
+ for (uint32_t i = 0; i < num_base; i++)
+ {
+ const DWARFDebugInfoEntry* die = info->GetDIEPtrWithCompileUnitHint (die_offsets[i], &dwarf_cu);
+ if (die)
+ {
+ if (!include_inlines && die->Tag() == DW_TAG_inlined_subroutine)
+ continue;
+
+ // If we get to here, the die is good, and we should add it:
+ if (resolved_dies.find(die) == resolved_dies.end())
+ {
+ if (ResolveFunction (dwarf_cu, die, sc_list))
+ resolved_dies.insert(die);
+ }
+ }
+ }
+ }
+ die_offsets.clear();
+ }
+
+ if ((name_type_mask & eFunctionNameTypeSelector) && (!namespace_decl || !*namespace_decl))
+ {
+ FindFunctions (name, m_function_selector_index, sc_list);
+ }
+
+ }
+
+ // Return the number of variable that were appended to the list
+ const uint32_t num_matches = sc_list.GetSize() - original_size;
+
+ if (log && num_matches > 0)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindFunctions (name=\"%s\", name_type_mask=0x%x, append=%u, sc_list) => %u",
+ name.GetCString(),
+ name_type_mask,
+ append,
+ num_matches);
+ }
+ return num_matches;
+}
+
+uint32_t
+SymbolFileDWARF::FindFunctions(const RegularExpression& regex, bool include_inlines, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARF::FindFunctions (regex = '%s')",
+ regex.GetText());
+
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
+
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindFunctions (regex=\"%s\", append=%u, sc_list)",
+ regex.GetText(),
+ append);
+ }
+
+
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ sc_list.Clear();
+
+ // Remember how many sc_list are in the list before we search in case
+ // we are appending the results to a variable list.
+ uint32_t original_size = sc_list.GetSize();
+
+ if (m_using_apple_tables)
+ {
+ if (m_apple_names_ap.get())
+ FindFunctions (regex, *m_apple_names_ap, sc_list);
+ }
+ else
+ {
+ // Index the DWARF if we haven't already
+ if (!m_indexed)
+ Index ();
+
+ FindFunctions (regex, m_function_basename_index, sc_list);
+
+ FindFunctions (regex, m_function_fullname_index, sc_list);
+ }
+
+ // Return the number of variable that were appended to the list
+ return sc_list.GetSize() - original_size;
+}
+
+uint32_t
+SymbolFileDWARF::FindTypes (const SymbolContext& sc,
+ const ConstString &name,
+ const lldb_private::ClangNamespaceDecl *namespace_decl,
+ bool append,
+ uint32_t max_matches,
+ TypeList& types)
+{
+ DWARFDebugInfo* info = DebugInfo();
+ if (info == NULL)
+ return 0;
+
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
+
+ if (log)
+ {
+ if (namespace_decl)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(%p) \"%s\", append=%u, max_matches=%u, type_list)",
+ name.GetCString(),
+ namespace_decl->GetNamespaceDecl(),
+ namespace_decl->GetQualifiedName().c_str(),
+ append,
+ max_matches);
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(NULL), append=%u, max_matches=%u, type_list)",
+ name.GetCString(),
+ append,
+ max_matches);
+ }
+ }
+
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ types.Clear();
+
+ if (!NamespaceDeclMatchesThisSymbolFile(namespace_decl))
+ return 0;
+
+ DIEArray die_offsets;
+
+ if (m_using_apple_tables)
+ {
+ if (m_apple_types_ap.get())
+ {
+ const char *name_cstr = name.GetCString();
+ m_apple_types_ap->FindByName (name_cstr, die_offsets);
+ }
+ }
+ else
+ {
+ if (!m_indexed)
+ Index ();
+
+ m_type_index.Find (name, die_offsets);
+ }
+
+ const size_t num_die_matches = die_offsets.size();
+
+ if (num_die_matches)
+ {
+ const uint32_t initial_types_size = types.GetSize();
+ DWARFCompileUnit* dwarf_cu = NULL;
+ const DWARFDebugInfoEntry* die = NULL;
+ DWARFDebugInfo* debug_info = DebugInfo();
+ for (size_t i=0; i<num_die_matches; ++i)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+
+ if (die)
+ {
+ if (namespace_decl && !DIEIsInNamespace (namespace_decl, dwarf_cu, die))
+ continue;
+
+ Type *matching_type = ResolveType (dwarf_cu, die);
+ if (matching_type)
+ {
+ // We found a type pointer, now find the shared pointer form our type list
+ types.InsertUnique (matching_type->shared_from_this());
+ if (types.GetSize() >= max_matches)
+ break;
+ }
+ }
+ else
+ {
+ if (m_using_apple_tables)
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_types accelerator table had bad die 0x%8.8x for '%s')\n",
+ die_offset, name.GetCString());
+ }
+ }
+
+ }
+ const uint32_t num_matches = types.GetSize() - initial_types_size;
+ if (log && num_matches)
+ {
+ if (namespace_decl)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(%p) \"%s\", append=%u, max_matches=%u, type_list) => %u",
+ name.GetCString(),
+ namespace_decl->GetNamespaceDecl(),
+ namespace_decl->GetQualifiedName().c_str(),
+ append,
+ max_matches,
+ num_matches);
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindTypes (sc, name=\"%s\", clang::NamespaceDecl(NULL), append=%u, max_matches=%u, type_list) => %u",
+ name.GetCString(),
+ append,
+ max_matches,
+ num_matches);
+ }
+ }
+ return num_matches;
+ }
+ return 0;
+}
+
+
+ClangNamespaceDecl
+SymbolFileDWARF::FindNamespace (const SymbolContext& sc,
+ const ConstString &name,
+ const lldb_private::ClangNamespaceDecl *parent_namespace_decl)
+{
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_LOOKUPS));
+
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindNamespace (sc, name=\"%s\")",
+ name.GetCString());
+ }
+
+ if (!NamespaceDeclMatchesThisSymbolFile(parent_namespace_decl))
+ return ClangNamespaceDecl();
+
+ ClangNamespaceDecl namespace_decl;
+ DWARFDebugInfo* info = DebugInfo();
+ if (info)
+ {
+ DIEArray die_offsets;
+
+ // Index if we already haven't to make sure the compile units
+ // get indexed and make their global DIE index list
+ if (m_using_apple_tables)
+ {
+ if (m_apple_namespaces_ap.get())
+ {
+ const char *name_cstr = name.GetCString();
+ m_apple_namespaces_ap->FindByName (name_cstr, die_offsets);
+ }
+ }
+ else
+ {
+ if (!m_indexed)
+ Index ();
+
+ m_namespace_index.Find (name, die_offsets);
+ }
+
+ DWARFCompileUnit* dwarf_cu = NULL;
+ const DWARFDebugInfoEntry* die = NULL;
+ const size_t num_matches = die_offsets.size();
+ if (num_matches)
+ {
+ DWARFDebugInfo* debug_info = DebugInfo();
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+
+ if (die)
+ {
+ if (parent_namespace_decl && !DIEIsInNamespace (parent_namespace_decl, dwarf_cu, die))
+ continue;
+
+ clang::NamespaceDecl *clang_namespace_decl = ResolveNamespaceDIE (dwarf_cu, die);
+ if (clang_namespace_decl)
+ {
+ namespace_decl.SetASTContext (GetClangASTContext().getASTContext());
+ namespace_decl.SetNamespaceDecl (clang_namespace_decl);
+ break;
+ }
+ }
+ else
+ {
+ if (m_using_apple_tables)
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_namespaces accelerator table had bad die 0x%8.8x for '%s')\n",
+ die_offset, name.GetCString());
+ }
+ }
+
+ }
+ }
+ }
+ if (log && namespace_decl.GetNamespaceDecl())
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindNamespace (sc, name=\"%s\") => clang::NamespaceDecl(%p) \"%s\"",
+ name.GetCString(),
+ namespace_decl.GetNamespaceDecl(),
+ namespace_decl.GetQualifiedName().c_str());
+ }
+
+ return namespace_decl;
+}
+
+uint32_t
+SymbolFileDWARF::FindTypes(std::vector<dw_offset_t> die_offsets, uint32_t max_matches, TypeList& types)
+{
+ // Remember how many sc_list are in the list before we search in case
+ // we are appending the results to a variable list.
+ uint32_t original_size = types.GetSize();
+
+ const uint32_t num_die_offsets = die_offsets.size();
+ // Parse all of the types we found from the pubtypes matches
+ uint32_t i;
+ uint32_t num_matches = 0;
+ for (i = 0; i < num_die_offsets; ++i)
+ {
+ Type *matching_type = ResolveTypeUID (die_offsets[i]);
+ if (matching_type)
+ {
+ // We found a type pointer, now find the shared pointer form our type list
+ types.InsertUnique (matching_type->shared_from_this());
+ ++num_matches;
+ if (num_matches >= max_matches)
+ break;
+ }
+ }
+
+ // Return the number of variable that were appended to the list
+ return types.GetSize() - original_size;
+}
+
+
+size_t
+SymbolFileDWARF::ParseChildParameters (const SymbolContext& sc,
+ clang::DeclContext *containing_decl_ctx,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ bool skip_artificial,
+ bool &is_static,
+ TypeList* type_list,
+ std::vector<ClangASTType>& function_param_types,
+ std::vector<clang::ParmVarDecl*>& function_param_decls,
+ unsigned &type_quals,
+ ClangASTContext::TemplateParameterInfos &template_param_infos)
+{
+ if (parent_die == NULL)
+ return 0;
+
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+
+ size_t arg_idx = 0;
+ const DWARFDebugInfoEntry *die;
+ for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling())
+ {
+ dw_tag_t tag = die->Tag();
+ switch (tag)
+ {
+ case DW_TAG_formal_parameter:
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, fixed_form_sizes, attributes);
+ if (num_attributes > 0)
+ {
+ const char *name = NULL;
+ Declaration decl;
+ dw_offset_t param_type_die_offset = DW_INVALID_OFFSET;
+ bool is_artificial = false;
+ // one of None, Auto, Register, Extern, Static, PrivateExtern
+
+ clang::StorageClass storage = clang::SC_None;
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_name: name = form_value.AsCString(&get_debug_str_data()); break;
+ case DW_AT_type: param_type_die_offset = form_value.Reference(dwarf_cu); break;
+ case DW_AT_artificial: is_artificial = form_value.Boolean(); break;
+ case DW_AT_location:
+ // if (form_value.BlockData())
+ // {
+ // const DataExtractor& debug_info_data = debug_info();
+ // uint32_t block_length = form_value.Unsigned();
+ // DataExtractor location(debug_info_data, form_value.BlockData() - debug_info_data.GetDataStart(), block_length);
+ // }
+ // else
+ // {
+ // }
+ // break;
+ case DW_AT_const_value:
+ case DW_AT_default_value:
+ case DW_AT_description:
+ case DW_AT_endianity:
+ case DW_AT_is_optional:
+ case DW_AT_segment:
+ case DW_AT_variable_parameter:
+ default:
+ case DW_AT_abstract_origin:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ bool skip = false;
+ if (skip_artificial)
+ {
+ if (is_artificial)
+ {
+ // In order to determine if a C++ member function is
+ // "const" we have to look at the const-ness of "this"...
+ // Ugly, but that
+ if (arg_idx == 0)
+ {
+ if (DeclKindIsCXXClass(containing_decl_ctx->getDeclKind()))
+ {
+ // Often times compilers omit the "this" name for the
+ // specification DIEs, so we can't rely upon the name
+ // being in the formal parameter DIE...
+ if (name == NULL || ::strcmp(name, "this")==0)
+ {
+ Type *this_type = ResolveTypeUID (param_type_die_offset);
+ if (this_type)
+ {
+ uint32_t encoding_mask = this_type->GetEncodingMask();
+ if (encoding_mask & Type::eEncodingIsPointerUID)
+ {
+ is_static = false;
+
+ if (encoding_mask & (1u << Type::eEncodingIsConstUID))
+ type_quals |= clang::Qualifiers::Const;
+ if (encoding_mask & (1u << Type::eEncodingIsVolatileUID))
+ type_quals |= clang::Qualifiers::Volatile;
+ }
+ }
+ }
+ }
+ }
+ skip = true;
+ }
+ else
+ {
+
+ // HACK: Objective C formal parameters "self" and "_cmd"
+ // are not marked as artificial in the DWARF...
+ CompileUnit *comp_unit = GetCompUnitForDWARFCompUnit(dwarf_cu, UINT32_MAX);
+ if (comp_unit)
+ {
+ switch (comp_unit->GetLanguage())
+ {
+ case eLanguageTypeObjC:
+ case eLanguageTypeObjC_plus_plus:
+ if (name && name[0] && (strcmp (name, "self") == 0 || strcmp (name, "_cmd") == 0))
+ skip = true;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if (!skip)
+ {
+ Type *type = ResolveTypeUID(param_type_die_offset);
+ if (type)
+ {
+ function_param_types.push_back (type->GetClangForwardType());
+
+ clang::ParmVarDecl *param_var_decl = GetClangASTContext().CreateParameterDeclaration (name,
+ type->GetClangForwardType(),
+ storage);
+ assert(param_var_decl);
+ function_param_decls.push_back(param_var_decl);
+
+ GetClangASTContext().SetMetadataAsUserID (param_var_decl, MakeUserID(die->GetOffset()));
+ }
+ }
+ }
+ arg_idx++;
+ }
+ break;
+
+ case DW_TAG_template_type_parameter:
+ case DW_TAG_template_value_parameter:
+ ParseTemplateDIE (dwarf_cu, die,template_param_infos);
+ break;
+
+ default:
+ break;
+ }
+ }
+ return arg_idx;
+}
+
+size_t
+SymbolFileDWARF::ParseChildEnumerators
+(
+ const SymbolContext& sc,
+ lldb_private::ClangASTType &clang_type,
+ bool is_signed,
+ uint32_t enumerator_byte_size,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die
+)
+{
+ if (parent_die == NULL)
+ return 0;
+
+ size_t enumerators_added = 0;
+ const DWARFDebugInfoEntry *die;
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+
+ for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling())
+ {
+ const dw_tag_t tag = die->Tag();
+ if (tag == DW_TAG_enumerator)
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_child_attributes = die->GetAttributes(this, dwarf_cu, fixed_form_sizes, attributes);
+ if (num_child_attributes > 0)
+ {
+ const char *name = NULL;
+ bool got_value = false;
+ int64_t enum_value = 0;
+ Declaration decl;
+
+ uint32_t i;
+ for (i=0; i<num_child_attributes; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_const_value:
+ got_value = true;
+ if (is_signed)
+ enum_value = form_value.Signed();
+ else
+ enum_value = form_value.Unsigned();
+ break;
+
+ case DW_AT_name:
+ name = form_value.AsCString(&get_debug_str_data());
+ break;
+
+ case DW_AT_description:
+ default:
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ if (name && name[0] && got_value)
+ {
+ clang_type.AddEnumerationValueToEnumerationType (clang_type.GetEnumerationIntegerType(),
+ decl,
+ name,
+ enum_value,
+ enumerator_byte_size * 8);
+ ++enumerators_added;
+ }
+ }
+ }
+ }
+ return enumerators_added;
+}
+
+void
+SymbolFileDWARF::ParseChildArrayInfo
+(
+ const SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ int64_t& first_index,
+ std::vector<uint64_t>& element_orders,
+ uint32_t& byte_stride,
+ uint32_t& bit_stride
+)
+{
+ if (parent_die == NULL)
+ return;
+
+ const DWARFDebugInfoEntry *die;
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+ for (die = parent_die->GetFirstChild(); die != NULL; die = die->GetSibling())
+ {
+ const dw_tag_t tag = die->Tag();
+ switch (tag)
+ {
+ case DW_TAG_subrange_type:
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_child_attributes = die->GetAttributes(this, dwarf_cu, fixed_form_sizes, attributes);
+ if (num_child_attributes > 0)
+ {
+ uint64_t num_elements = 0;
+ uint64_t lower_bound = 0;
+ uint64_t upper_bound = 0;
+ bool upper_bound_valid = false;
+ uint32_t i;
+ for (i=0; i<num_child_attributes; ++i)
+ {
+ const dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_name:
+ break;
+
+ case DW_AT_count:
+ num_elements = form_value.Unsigned();
+ break;
+
+ case DW_AT_bit_stride:
+ bit_stride = form_value.Unsigned();
+ break;
+
+ case DW_AT_byte_stride:
+ byte_stride = form_value.Unsigned();
+ break;
+
+ case DW_AT_lower_bound:
+ lower_bound = form_value.Unsigned();
+ break;
+
+ case DW_AT_upper_bound:
+ upper_bound_valid = true;
+ upper_bound = form_value.Unsigned();
+ break;
+
+ default:
+ case DW_AT_abstract_origin:
+ case DW_AT_accessibility:
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_data_location:
+ case DW_AT_declaration:
+ case DW_AT_description:
+ case DW_AT_sibling:
+ case DW_AT_threads_scaled:
+ case DW_AT_type:
+ case DW_AT_visibility:
+ break;
+ }
+ }
+ }
+
+ if (num_elements == 0)
+ {
+ if (upper_bound_valid && upper_bound >= lower_bound)
+ num_elements = upper_bound - lower_bound + 1;
+ }
+
+ element_orders.push_back (num_elements);
+ }
+ }
+ break;
+ }
+ }
+}
+
+TypeSP
+SymbolFileDWARF::GetTypeForDIE (DWARFCompileUnit *dwarf_cu, const DWARFDebugInfoEntry* die)
+{
+ TypeSP type_sp;
+ if (die != NULL)
+ {
+ assert(dwarf_cu != NULL);
+ Type *type_ptr = m_die_to_type.lookup (die);
+ if (type_ptr == NULL)
+ {
+ CompileUnit* lldb_cu = GetCompUnitForDWARFCompUnit(dwarf_cu);
+ assert (lldb_cu);
+ SymbolContext sc(lldb_cu);
+ type_sp = ParseType(sc, dwarf_cu, die, NULL);
+ }
+ else if (type_ptr != DIE_IS_BEING_PARSED)
+ {
+ // Grab the existing type from the master types lists
+ type_sp = type_ptr->shared_from_this();
+ }
+
+ }
+ return type_sp;
+}
+
+clang::DeclContext *
+SymbolFileDWARF::GetClangDeclContextContainingDIEOffset (dw_offset_t die_offset)
+{
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = DebugInfo()->GetDIEPtr(die_offset, &cu_sp);
+ return GetClangDeclContextContainingDIE (cu_sp.get(), die, NULL);
+ }
+ return NULL;
+}
+
+clang::DeclContext *
+SymbolFileDWARF::GetClangDeclContextForDIEOffset (const SymbolContext &sc, dw_offset_t die_offset)
+{
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ DWARFDebugInfo* debug_info = DebugInfo();
+ if (debug_info)
+ {
+ DWARFCompileUnitSP cu_sp;
+ const DWARFDebugInfoEntry* die = debug_info->GetDIEPtr(die_offset, &cu_sp);
+ if (die)
+ return GetClangDeclContextForDIE (sc, cu_sp.get(), die);
+ }
+ }
+ return NULL;
+}
+
+clang::NamespaceDecl *
+SymbolFileDWARF::ResolveNamespaceDIE (DWARFCompileUnit *dwarf_cu, const DWARFDebugInfoEntry *die)
+{
+ if (die && die->Tag() == DW_TAG_namespace)
+ {
+ // See if we already parsed this namespace DIE and associated it with a
+ // uniqued namespace declaration
+ clang::NamespaceDecl *namespace_decl = static_cast<clang::NamespaceDecl *>(m_die_to_decl_ctx[die]);
+ if (namespace_decl)
+ return namespace_decl;
+ else
+ {
+ const char *namespace_name = die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_name, NULL);
+ clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, NULL);
+ namespace_decl = GetClangASTContext().GetUniqueNamespaceDeclaration (namespace_name, containing_decl_ctx);
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO));
+ if (log)
+ {
+ if (namespace_name)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "ASTContext => %p: 0x%8.8" PRIx64 ": DW_TAG_namespace with DW_AT_name(\"%s\") => clang::NamespaceDecl *%p (original = %p)",
+ GetClangASTContext().getASTContext(),
+ MakeUserID(die->GetOffset()),
+ namespace_name,
+ namespace_decl,
+ namespace_decl->getOriginalNamespace());
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "ASTContext => %p: 0x%8.8" PRIx64 ": DW_TAG_namespace (anonymous) => clang::NamespaceDecl *%p (original = %p)",
+ GetClangASTContext().getASTContext(),
+ MakeUserID(die->GetOffset()),
+ namespace_decl,
+ namespace_decl->getOriginalNamespace());
+ }
+ }
+
+ if (namespace_decl)
+ LinkDeclContextToDIE((clang::DeclContext*)namespace_decl, die);
+ return namespace_decl;
+ }
+ }
+ return NULL;
+}
+
+clang::DeclContext *
+SymbolFileDWARF::GetClangDeclContextForDIE (const SymbolContext &sc, DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die)
+{
+ clang::DeclContext *clang_decl_ctx = GetCachedClangDeclContextForDIE (die);
+ if (clang_decl_ctx)
+ return clang_decl_ctx;
+ // If this DIE has a specification, or an abstract origin, then trace to those.
+
+ dw_offset_t die_offset = die->GetAttributeValueAsReference(this, cu, DW_AT_specification, DW_INVALID_OFFSET);
+ if (die_offset != DW_INVALID_OFFSET)
+ return GetClangDeclContextForDIEOffset (sc, die_offset);
+
+ die_offset = die->GetAttributeValueAsReference(this, cu, DW_AT_abstract_origin, DW_INVALID_OFFSET);
+ if (die_offset != DW_INVALID_OFFSET)
+ return GetClangDeclContextForDIEOffset (sc, die_offset);
+
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO));
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage(log, "SymbolFileDWARF::GetClangDeclContextForDIE (die = 0x%8.8x) %s '%s'", die->GetOffset(), DW_TAG_value_to_name(die->Tag()), die->GetName(this, cu));
+ // This is the DIE we want. Parse it, then query our map.
+ bool assert_not_being_parsed = true;
+ ResolveTypeUID (cu, die, assert_not_being_parsed);
+
+ clang_decl_ctx = GetCachedClangDeclContextForDIE (die);
+
+ return clang_decl_ctx;
+}
+
+clang::DeclContext *
+SymbolFileDWARF::GetClangDeclContextContainingDIE (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die, const DWARFDebugInfoEntry **decl_ctx_die_copy)
+{
+ if (m_clang_tu_decl == NULL)
+ m_clang_tu_decl = GetClangASTContext().getASTContext()->getTranslationUnitDecl();
+
+ const DWARFDebugInfoEntry *decl_ctx_die = GetDeclContextDIEContainingDIE (cu, die);
+
+ if (decl_ctx_die_copy)
+ *decl_ctx_die_copy = decl_ctx_die;
+
+ if (decl_ctx_die)
+ {
+
+ DIEToDeclContextMap::iterator pos = m_die_to_decl_ctx.find (decl_ctx_die);
+ if (pos != m_die_to_decl_ctx.end())
+ return pos->second;
+
+ switch (decl_ctx_die->Tag())
+ {
+ case DW_TAG_compile_unit:
+ return m_clang_tu_decl;
+
+ case DW_TAG_namespace:
+ return ResolveNamespaceDIE (cu, decl_ctx_die);
+ break;
+
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ {
+ Type* type = ResolveType (cu, decl_ctx_die);
+ if (type)
+ {
+ clang::DeclContext *decl_ctx = type->GetClangForwardType().GetDeclContextForType ();
+ if (decl_ctx)
+ {
+ LinkDeclContextToDIE (decl_ctx, decl_ctx_die);
+ if (decl_ctx)
+ return decl_ctx;
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ return m_clang_tu_decl;
+}
+
+
+const DWARFDebugInfoEntry *
+SymbolFileDWARF::GetDeclContextDIEContainingDIE (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die)
+{
+ if (cu && die)
+ {
+ const DWARFDebugInfoEntry * const decl_die = die;
+
+ while (die != NULL)
+ {
+ // If this is the original DIE that we are searching for a declaration
+ // for, then don't look in the cache as we don't want our own decl
+ // context to be our decl context...
+ if (decl_die != die)
+ {
+ switch (die->Tag())
+ {
+ case DW_TAG_compile_unit:
+ case DW_TAG_namespace:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ return die;
+
+ default:
+ break;
+ }
+ }
+
+ dw_offset_t die_offset = die->GetAttributeValueAsReference(this, cu, DW_AT_specification, DW_INVALID_OFFSET);
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ DWARFCompileUnit *spec_cu = cu;
+ const DWARFDebugInfoEntry *spec_die = DebugInfo()->GetDIEPtrWithCompileUnitHint (die_offset, &spec_cu);
+ const DWARFDebugInfoEntry *spec_die_decl_ctx_die = GetDeclContextDIEContainingDIE (spec_cu, spec_die);
+ if (spec_die_decl_ctx_die)
+ return spec_die_decl_ctx_die;
+ }
+
+ die_offset = die->GetAttributeValueAsReference(this, cu, DW_AT_abstract_origin, DW_INVALID_OFFSET);
+ if (die_offset != DW_INVALID_OFFSET)
+ {
+ DWARFCompileUnit *abs_cu = cu;
+ const DWARFDebugInfoEntry *abs_die = DebugInfo()->GetDIEPtrWithCompileUnitHint (die_offset, &abs_cu);
+ const DWARFDebugInfoEntry *abs_die_decl_ctx_die = GetDeclContextDIEContainingDIE (abs_cu, abs_die);
+ if (abs_die_decl_ctx_die)
+ return abs_die_decl_ctx_die;
+ }
+
+ die = die->GetParent();
+ }
+ }
+ return NULL;
+}
+
+
+Symbol *
+SymbolFileDWARF::GetObjCClassSymbol (const ConstString &objc_class_name)
+{
+ Symbol *objc_class_symbol = NULL;
+ if (m_obj_file)
+ {
+ Symtab *symtab = m_obj_file->GetSymtab ();
+ if (symtab)
+ {
+ objc_class_symbol = symtab->FindFirstSymbolWithNameAndType (objc_class_name,
+ eSymbolTypeObjCClass,
+ Symtab::eDebugNo,
+ Symtab::eVisibilityAny);
+ }
+ }
+ return objc_class_symbol;
+}
+
+// Some compilers don't emit the DW_AT_APPLE_objc_complete_type attribute. If they don't
+// then we can end up looking through all class types for a complete type and never find
+// the full definition. We need to know if this attribute is supported, so we determine
+// this here and cache th result. We also need to worry about the debug map DWARF file
+// if we are doing darwin DWARF in .o file debugging.
+bool
+SymbolFileDWARF::Supports_DW_AT_APPLE_objc_complete_type (DWARFCompileUnit *cu)
+{
+ if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolCalculate)
+ {
+ m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolNo;
+ if (cu && cu->Supports_DW_AT_APPLE_objc_complete_type())
+ m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes;
+ else
+ {
+ DWARFDebugInfo* debug_info = DebugInfo();
+ const uint32_t num_compile_units = GetNumCompileUnits();
+ for (uint32_t cu_idx = 0; cu_idx < num_compile_units; ++cu_idx)
+ {
+ DWARFCompileUnit* dwarf_cu = debug_info->GetCompileUnitAtIndex(cu_idx);
+ if (dwarf_cu != cu && dwarf_cu->Supports_DW_AT_APPLE_objc_complete_type())
+ {
+ m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes;
+ break;
+ }
+ }
+ }
+ if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolNo && GetDebugMapSymfile ())
+ return m_debug_map_symfile->Supports_DW_AT_APPLE_objc_complete_type (this);
+ }
+ return m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolYes;
+}
+
+// This function can be used when a DIE is found that is a forward declaration
+// DIE and we want to try and find a type that has the complete definition.
+TypeSP
+SymbolFileDWARF::FindCompleteObjCDefinitionTypeForDIE (const DWARFDebugInfoEntry *die,
+ const ConstString &type_name,
+ bool must_be_implementation)
+{
+
+ TypeSP type_sp;
+
+ if (!type_name || (must_be_implementation && !GetObjCClassSymbol (type_name)))
+ return type_sp;
+
+ DIEArray die_offsets;
+
+ if (m_using_apple_tables)
+ {
+ if (m_apple_types_ap.get())
+ {
+ const char *name_cstr = type_name.GetCString();
+ m_apple_types_ap->FindCompleteObjCClassByName (name_cstr, die_offsets, must_be_implementation);
+ }
+ }
+ else
+ {
+ if (!m_indexed)
+ Index ();
+
+ m_type_index.Find (type_name, die_offsets);
+ }
+
+ const size_t num_matches = die_offsets.size();
+
+ DWARFCompileUnit* type_cu = NULL;
+ const DWARFDebugInfoEntry* type_die = NULL;
+ if (num_matches)
+ {
+ DWARFDebugInfo* debug_info = DebugInfo();
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ type_die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &type_cu);
+
+ if (type_die)
+ {
+ bool try_resolving_type = false;
+
+ // Don't try and resolve the DIE we are looking for with the DIE itself!
+ if (type_die != die)
+ {
+ switch (type_die->Tag())
+ {
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ try_resolving_type = true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (try_resolving_type)
+ {
+ if (must_be_implementation && type_cu->Supports_DW_AT_APPLE_objc_complete_type())
+ try_resolving_type = type_die->GetAttributeValueAsUnsigned (this, type_cu, DW_AT_APPLE_objc_complete_type, 0);
+
+ if (try_resolving_type)
+ {
+ Type *resolved_type = ResolveType (type_cu, type_die, false);
+ if (resolved_type && resolved_type != DIE_IS_BEING_PARSED)
+ {
+ DEBUG_PRINTF ("resolved 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ") from %s to 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ")\n",
+ MakeUserID(die->GetOffset()),
+ MakeUserID(dwarf_cu->GetOffset()),
+ m_obj_file->GetFileSpec().GetFilename().AsCString(),
+ MakeUserID(type_die->GetOffset()),
+ MakeUserID(type_cu->GetOffset()));
+
+ if (die)
+ m_die_to_type[die] = resolved_type;
+ type_sp = resolved_type->shared_from_this();
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ if (m_using_apple_tables)
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_types accelerator table had bad die 0x%8.8x for '%s')\n",
+ die_offset, type_name.GetCString());
+ }
+ }
+
+ }
+ }
+ return type_sp;
+}
+
+
+//----------------------------------------------------------------------
+// This function helps to ensure that the declaration contexts match for
+// two different DIEs. Often times debug information will refer to a
+// forward declaration of a type (the equivalent of "struct my_struct;".
+// There will often be a declaration of that type elsewhere that has the
+// full definition. When we go looking for the full type "my_struct", we
+// will find one or more matches in the accelerator tables and we will
+// then need to make sure the type was in the same declaration context
+// as the original DIE. This function can efficiently compare two DIEs
+// and will return true when the declaration context matches, and false
+// when they don't.
+//----------------------------------------------------------------------
+bool
+SymbolFileDWARF::DIEDeclContextsMatch (DWARFCompileUnit* cu1, const DWARFDebugInfoEntry *die1,
+ DWARFCompileUnit* cu2, const DWARFDebugInfoEntry *die2)
+{
+ if (die1 == die2)
+ return true;
+
+#if defined (LLDB_CONFIGURATION_DEBUG)
+ // You can't and shouldn't call this function with a compile unit from
+ // two different SymbolFileDWARF instances.
+ assert (DebugInfo()->ContainsCompileUnit (cu1));
+ assert (DebugInfo()->ContainsCompileUnit (cu2));
+#endif
+
+ DWARFDIECollection decl_ctx_1;
+ DWARFDIECollection decl_ctx_2;
+ //The declaration DIE stack is a stack of the declaration context
+ // DIEs all the way back to the compile unit. If a type "T" is
+ // declared inside a class "B", and class "B" is declared inside
+ // a class "A" and class "A" is in a namespace "lldb", and the
+ // namespace is in a compile unit, there will be a stack of DIEs:
+ //
+ // [0] DW_TAG_class_type for "B"
+ // [1] DW_TAG_class_type for "A"
+ // [2] DW_TAG_namespace for "lldb"
+ // [3] DW_TAG_compile_unit for the source file.
+ //
+ // We grab both contexts and make sure that everything matches
+ // all the way back to the compiler unit.
+
+ // First lets grab the decl contexts for both DIEs
+ die1->GetDeclContextDIEs (this, cu1, decl_ctx_1);
+ die2->GetDeclContextDIEs (this, cu2, decl_ctx_2);
+ // Make sure the context arrays have the same size, otherwise
+ // we are done
+ const size_t count1 = decl_ctx_1.Size();
+ const size_t count2 = decl_ctx_2.Size();
+ if (count1 != count2)
+ return false;
+
+ // Make sure the DW_TAG values match all the way back up the the
+ // compile unit. If they don't, then we are done.
+ const DWARFDebugInfoEntry *decl_ctx_die1;
+ const DWARFDebugInfoEntry *decl_ctx_die2;
+ size_t i;
+ for (i=0; i<count1; i++)
+ {
+ decl_ctx_die1 = decl_ctx_1.GetDIEPtrAtIndex (i);
+ decl_ctx_die2 = decl_ctx_2.GetDIEPtrAtIndex (i);
+ if (decl_ctx_die1->Tag() != decl_ctx_die2->Tag())
+ return false;
+ }
+#if defined LLDB_CONFIGURATION_DEBUG
+
+ // Make sure the top item in the decl context die array is always
+ // DW_TAG_compile_unit. If it isn't then something went wrong in
+ // the DWARFDebugInfoEntry::GetDeclContextDIEs() function...
+ assert (decl_ctx_1.GetDIEPtrAtIndex (count1 - 1)->Tag() == DW_TAG_compile_unit);
+
+#endif
+ // Always skip the compile unit when comparing by only iterating up to
+ // "count - 1". Here we compare the names as we go.
+ for (i=0; i<count1 - 1; i++)
+ {
+ decl_ctx_die1 = decl_ctx_1.GetDIEPtrAtIndex (i);
+ decl_ctx_die2 = decl_ctx_2.GetDIEPtrAtIndex (i);
+ const char *name1 = decl_ctx_die1->GetName(this, cu1);
+ const char *name2 = decl_ctx_die2->GetName(this, cu2);
+ // If the string was from a DW_FORM_strp, then the pointer will often
+ // be the same!
+ if (name1 == name2)
+ continue;
+
+ // Name pointers are not equal, so only compare the strings
+ // if both are not NULL.
+ if (name1 && name2)
+ {
+ // If the strings don't compare, we are done...
+ if (strcmp(name1, name2) != 0)
+ return false;
+ }
+ else
+ {
+ // One name was NULL while the other wasn't
+ return false;
+ }
+ }
+ // We made it through all of the checks and the declaration contexts
+ // are equal.
+ return true;
+}
+
+// This function can be used when a DIE is found that is a forward declaration
+// DIE and we want to try and find a type that has the complete definition.
+// "cu" and "die" must be from this SymbolFileDWARF
+TypeSP
+SymbolFileDWARF::FindDefinitionTypeForDIE (DWARFCompileUnit* cu,
+ const DWARFDebugInfoEntry *die,
+ const ConstString &type_name)
+{
+ TypeSP type_sp;
+
+#if defined (LLDB_CONFIGURATION_DEBUG)
+ // You can't and shouldn't call this function with a compile unit from
+ // another SymbolFileDWARF instance.
+ assert (DebugInfo()->ContainsCompileUnit (cu));
+#endif
+
+ if (cu == NULL || die == NULL || !type_name)
+ return type_sp;
+
+ std::string qualified_name;
+
+ Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION|DWARF_LOG_LOOKUPS));
+ if (log)
+ {
+ die->GetQualifiedName(this, cu, qualified_name);
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindDefinitionTypeForDIE(die=0x%8.8x (%s), name='%s')",
+ die->GetOffset(),
+ qualified_name.c_str(),
+ type_name.GetCString());
+ }
+
+ DIEArray die_offsets;
+
+ if (m_using_apple_tables)
+ {
+ if (m_apple_types_ap.get())
+ {
+ const bool has_tag = m_apple_types_ap->GetHeader().header_data.ContainsAtom (DWARFMappedHash::eAtomTypeTag);
+ const bool has_qualified_name_hash = m_apple_types_ap->GetHeader().header_data.ContainsAtom (DWARFMappedHash::eAtomTypeQualNameHash);
+ if (has_tag && has_qualified_name_hash)
+ {
+ if (qualified_name.empty())
+ die->GetQualifiedName(this, cu, qualified_name);
+
+ const uint32_t qualified_name_hash = MappedHash::HashStringUsingDJB (qualified_name.c_str());
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTagAndQualifiedNameHash()");
+ m_apple_types_ap->FindByNameAndTagAndQualifiedNameHash (type_name.GetCString(), die->Tag(), qualified_name_hash, die_offsets);
+ }
+ else if (has_tag > 1)
+ {
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTag()");
+ m_apple_types_ap->FindByNameAndTag (type_name.GetCString(), die->Tag(), die_offsets);
+ }
+ else
+ {
+ m_apple_types_ap->FindByName (type_name.GetCString(), die_offsets);
+ }
+ }
+ }
+ else
+ {
+ if (!m_indexed)
+ Index ();
+
+ m_type_index.Find (type_name, die_offsets);
+ }
+
+ const size_t num_matches = die_offsets.size();
+
+ const dw_tag_t die_tag = die->Tag();
+
+ DWARFCompileUnit* type_cu = NULL;
+ const DWARFDebugInfoEntry* type_die = NULL;
+ if (num_matches)
+ {
+ DWARFDebugInfo* debug_info = DebugInfo();
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ type_die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &type_cu);
+
+ if (type_die)
+ {
+ bool try_resolving_type = false;
+
+ // Don't try and resolve the DIE we are looking for with the DIE itself!
+ if (type_die != die)
+ {
+ const dw_tag_t type_die_tag = type_die->Tag();
+ // Make sure the tags match
+ if (type_die_tag == die_tag)
+ {
+ // The tags match, lets try resolving this type
+ try_resolving_type = true;
+ }
+ else
+ {
+ // The tags don't match, but we need to watch our for a
+ // forward declaration for a struct and ("struct foo")
+ // ends up being a class ("class foo { ... };") or
+ // vice versa.
+ switch (type_die_tag)
+ {
+ case DW_TAG_class_type:
+ // We had a "class foo", see if we ended up with a "struct foo { ... };"
+ try_resolving_type = (die_tag == DW_TAG_structure_type);
+ break;
+ case DW_TAG_structure_type:
+ // We had a "struct foo", see if we ended up with a "class foo { ... };"
+ try_resolving_type = (die_tag == DW_TAG_class_type);
+ break;
+ default:
+ // Tags don't match, don't event try to resolve
+ // using this type whose name matches....
+ break;
+ }
+ }
+ }
+
+ if (try_resolving_type)
+ {
+ if (log)
+ {
+ std::string qualified_name;
+ type_die->GetQualifiedName(this, cu, qualified_name);
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindDefinitionTypeForDIE(die=0x%8.8x, name='%s') trying die=0x%8.8x (%s)",
+ die->GetOffset(),
+ type_name.GetCString(),
+ type_die->GetOffset(),
+ qualified_name.c_str());
+ }
+
+ // Make sure the decl contexts match all the way up
+ if (DIEDeclContextsMatch(cu, die, type_cu, type_die))
+ {
+ Type *resolved_type = ResolveType (type_cu, type_die, false);
+ if (resolved_type && resolved_type != DIE_IS_BEING_PARSED)
+ {
+ DEBUG_PRINTF ("resolved 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ") from %s to 0x%8.8" PRIx64 " (cu 0x%8.8" PRIx64 ")\n",
+ MakeUserID(die->GetOffset()),
+ MakeUserID(dwarf_cu->GetOffset()),
+ m_obj_file->GetFileSpec().GetFilename().AsCString(),
+ MakeUserID(type_die->GetOffset()),
+ MakeUserID(type_cu->GetOffset()));
+
+ m_die_to_type[die] = resolved_type;
+ type_sp = resolved_type->shared_from_this();
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ {
+ std::string qualified_name;
+ type_die->GetQualifiedName(this, cu, qualified_name);
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindDefinitionTypeForDIE(die=0x%8.8x, name='%s') ignoring die=0x%8.8x (%s)",
+ die->GetOffset(),
+ type_name.GetCString(),
+ type_die->GetOffset(),
+ qualified_name.c_str());
+ }
+ }
+ }
+ else
+ {
+ if (m_using_apple_tables)
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_types accelerator table had bad die 0x%8.8x for '%s')\n",
+ die_offset, type_name.GetCString());
+ }
+ }
+
+ }
+ }
+ return type_sp;
+}
+
+TypeSP
+SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext (const DWARFDeclContext &dwarf_decl_ctx)
+{
+ TypeSP type_sp;
+
+ const uint32_t dwarf_decl_ctx_count = dwarf_decl_ctx.GetSize();
+ if (dwarf_decl_ctx_count > 0)
+ {
+ const ConstString type_name(dwarf_decl_ctx[0].name);
+ const dw_tag_t tag = dwarf_decl_ctx[0].tag;
+
+ if (type_name)
+ {
+ Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_TYPE_COMPLETION|DWARF_LOG_LOOKUPS));
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(tag=%s, qualified-name='%s')",
+ DW_TAG_value_to_name(dwarf_decl_ctx[0].tag),
+ dwarf_decl_ctx.GetQualifiedName());
+ }
+
+ DIEArray die_offsets;
+
+ if (m_using_apple_tables)
+ {
+ if (m_apple_types_ap.get())
+ {
+ const bool has_tag = m_apple_types_ap->GetHeader().header_data.ContainsAtom (DWARFMappedHash::eAtomTypeTag);
+ const bool has_qualified_name_hash = m_apple_types_ap->GetHeader().header_data.ContainsAtom (DWARFMappedHash::eAtomTypeQualNameHash);
+ if (has_tag && has_qualified_name_hash)
+ {
+ const char *qualified_name = dwarf_decl_ctx.GetQualifiedName();
+ const uint32_t qualified_name_hash = MappedHash::HashStringUsingDJB (qualified_name);
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTagAndQualifiedNameHash()");
+ m_apple_types_ap->FindByNameAndTagAndQualifiedNameHash (type_name.GetCString(), tag, qualified_name_hash, die_offsets);
+ }
+ else if (has_tag)
+ {
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log,"FindByNameAndTag()");
+ m_apple_types_ap->FindByNameAndTag (type_name.GetCString(), tag, die_offsets);
+ }
+ else
+ {
+ m_apple_types_ap->FindByName (type_name.GetCString(), die_offsets);
+ }
+ }
+ }
+ else
+ {
+ if (!m_indexed)
+ Index ();
+
+ m_type_index.Find (type_name, die_offsets);
+ }
+
+ const size_t num_matches = die_offsets.size();
+
+
+ DWARFCompileUnit* type_cu = NULL;
+ const DWARFDebugInfoEntry* type_die = NULL;
+ if (num_matches)
+ {
+ DWARFDebugInfo* debug_info = DebugInfo();
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ type_die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &type_cu);
+
+ if (type_die)
+ {
+ bool try_resolving_type = false;
+
+ // Don't try and resolve the DIE we are looking for with the DIE itself!
+ const dw_tag_t type_tag = type_die->Tag();
+ // Make sure the tags match
+ if (type_tag == tag)
+ {
+ // The tags match, lets try resolving this type
+ try_resolving_type = true;
+ }
+ else
+ {
+ // The tags don't match, but we need to watch our for a
+ // forward declaration for a struct and ("struct foo")
+ // ends up being a class ("class foo { ... };") or
+ // vice versa.
+ switch (type_tag)
+ {
+ case DW_TAG_class_type:
+ // We had a "class foo", see if we ended up with a "struct foo { ... };"
+ try_resolving_type = (tag == DW_TAG_structure_type);
+ break;
+ case DW_TAG_structure_type:
+ // We had a "struct foo", see if we ended up with a "class foo { ... };"
+ try_resolving_type = (tag == DW_TAG_class_type);
+ break;
+ default:
+ // Tags don't match, don't event try to resolve
+ // using this type whose name matches....
+ break;
+ }
+ }
+
+ if (try_resolving_type)
+ {
+ DWARFDeclContext type_dwarf_decl_ctx;
+ type_die->GetDWARFDeclContext (this, type_cu, type_dwarf_decl_ctx);
+
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(tag=%s, qualified-name='%s') trying die=0x%8.8x (%s)",
+ DW_TAG_value_to_name(dwarf_decl_ctx[0].tag),
+ dwarf_decl_ctx.GetQualifiedName(),
+ type_die->GetOffset(),
+ type_dwarf_decl_ctx.GetQualifiedName());
+ }
+
+ // Make sure the decl contexts match all the way up
+ if (dwarf_decl_ctx == type_dwarf_decl_ctx)
+ {
+ Type *resolved_type = ResolveType (type_cu, type_die, false);
+ if (resolved_type && resolved_type != DIE_IS_BEING_PARSED)
+ {
+ type_sp = resolved_type->shared_from_this();
+ break;
+ }
+ }
+ }
+ else
+ {
+ if (log)
+ {
+ std::string qualified_name;
+ type_die->GetQualifiedName(this, type_cu, qualified_name);
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::FindDefinitionTypeForDWARFDeclContext(tag=%s, qualified-name='%s') ignoring die=0x%8.8x (%s)",
+ DW_TAG_value_to_name(dwarf_decl_ctx[0].tag),
+ dwarf_decl_ctx.GetQualifiedName(),
+ type_die->GetOffset(),
+ qualified_name.c_str());
+ }
+ }
+ }
+ else
+ {
+ if (m_using_apple_tables)
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_types accelerator table had bad die 0x%8.8x for '%s')\n",
+ die_offset, type_name.GetCString());
+ }
+ }
+
+ }
+ }
+ }
+ }
+ return type_sp;
+}
+
+bool
+SymbolFileDWARF::CopyUniqueClassMethodTypes (SymbolFileDWARF *src_symfile,
+ Type *class_type,
+ DWARFCompileUnit* src_cu,
+ const DWARFDebugInfoEntry *src_class_die,
+ DWARFCompileUnit* dst_cu,
+ const DWARFDebugInfoEntry *dst_class_die,
+ llvm::SmallVectorImpl <const DWARFDebugInfoEntry *> &failures)
+{
+ if (!class_type || !src_cu || !src_class_die || !dst_cu || !dst_class_die)
+ return false;
+ if (src_class_die->Tag() != dst_class_die->Tag())
+ return false;
+
+ // We need to complete the class type so we can get all of the method types
+ // parsed so we can then unique those types to their equivalent counterparts
+ // in "dst_cu" and "dst_class_die"
+ class_type->GetClangFullType();
+
+ const DWARFDebugInfoEntry *src_die;
+ const DWARFDebugInfoEntry *dst_die;
+ UniqueCStringMap<const DWARFDebugInfoEntry *> src_name_to_die;
+ UniqueCStringMap<const DWARFDebugInfoEntry *> dst_name_to_die;
+ UniqueCStringMap<const DWARFDebugInfoEntry *> src_name_to_die_artificial;
+ UniqueCStringMap<const DWARFDebugInfoEntry *> dst_name_to_die_artificial;
+ for (src_die = src_class_die->GetFirstChild(); src_die != NULL; src_die = src_die->GetSibling())
+ {
+ if (src_die->Tag() == DW_TAG_subprogram)
+ {
+ // Make sure this is a declaration and not a concrete instance by looking
+ // for DW_AT_declaration set to 1. Sometimes concrete function instances
+ // are placed inside the class definitions and shouldn't be included in
+ // the list of things are are tracking here.
+ if (src_die->GetAttributeValueAsUnsigned(src_symfile, src_cu, DW_AT_declaration, 0) == 1)
+ {
+ const char *src_name = src_die->GetMangledName (src_symfile, src_cu);
+ if (src_name)
+ {
+ ConstString src_const_name(src_name);
+ if (src_die->GetAttributeValueAsUnsigned(src_symfile, src_cu, DW_AT_artificial, 0))
+ src_name_to_die_artificial.Append(src_const_name.GetCString(), src_die);
+ else
+ src_name_to_die.Append(src_const_name.GetCString(), src_die);
+ }
+ }
+ }
+ }
+ for (dst_die = dst_class_die->GetFirstChild(); dst_die != NULL; dst_die = dst_die->GetSibling())
+ {
+ if (dst_die->Tag() == DW_TAG_subprogram)
+ {
+ // Make sure this is a declaration and not a concrete instance by looking
+ // for DW_AT_declaration set to 1. Sometimes concrete function instances
+ // are placed inside the class definitions and shouldn't be included in
+ // the list of things are are tracking here.
+ if (dst_die->GetAttributeValueAsUnsigned(this, dst_cu, DW_AT_declaration, 0) == 1)
+ {
+ const char *dst_name = dst_die->GetMangledName (this, dst_cu);
+ if (dst_name)
+ {
+ ConstString dst_const_name(dst_name);
+ if (dst_die->GetAttributeValueAsUnsigned(this, dst_cu, DW_AT_artificial, 0))
+ dst_name_to_die_artificial.Append(dst_const_name.GetCString(), dst_die);
+ else
+ dst_name_to_die.Append(dst_const_name.GetCString(), dst_die);
+ }
+ }
+ }
+ }
+ const uint32_t src_size = src_name_to_die.GetSize ();
+ const uint32_t dst_size = dst_name_to_die.GetSize ();
+ Log *log (LogChannelDWARF::GetLogIfAny(DWARF_LOG_DEBUG_INFO | DWARF_LOG_TYPE_COMPLETION));
+
+ // Is everything kosher so we can go through the members at top speed?
+ bool fast_path = true;
+
+ if (src_size != dst_size)
+ {
+ if (src_size != 0 && dst_size != 0)
+ {
+ if (log)
+ log->Printf("warning: trying to unique class DIE 0x%8.8x to 0x%8.8x, but they didn't have the same size (src=%d, dst=%d)",
+ src_class_die->GetOffset(),
+ dst_class_die->GetOffset(),
+ src_size,
+ dst_size);
+ }
+
+ fast_path = false;
+ }
+
+ uint32_t idx;
+
+ if (fast_path)
+ {
+ for (idx = 0; idx < src_size; ++idx)
+ {
+ src_die = src_name_to_die.GetValueAtIndexUnchecked (idx);
+ dst_die = dst_name_to_die.GetValueAtIndexUnchecked (idx);
+
+ if (src_die->Tag() != dst_die->Tag())
+ {
+ if (log)
+ log->Printf("warning: tried to unique class DIE 0x%8.8x to 0x%8.8x, but 0x%8.8x (%s) tags didn't match 0x%8.8x (%s)",
+ src_class_die->GetOffset(),
+ dst_class_die->GetOffset(),
+ src_die->GetOffset(),
+ DW_TAG_value_to_name(src_die->Tag()),
+ dst_die->GetOffset(),
+ DW_TAG_value_to_name(src_die->Tag()));
+ fast_path = false;
+ }
+
+ const char *src_name = src_die->GetMangledName (src_symfile, src_cu);
+ const char *dst_name = dst_die->GetMangledName (this, dst_cu);
+
+ // Make sure the names match
+ if (src_name == dst_name || (strcmp (src_name, dst_name) == 0))
+ continue;
+
+ if (log)
+ log->Printf("warning: tried to unique class DIE 0x%8.8x to 0x%8.8x, but 0x%8.8x (%s) names didn't match 0x%8.8x (%s)",
+ src_class_die->GetOffset(),
+ dst_class_die->GetOffset(),
+ src_die->GetOffset(),
+ src_name,
+ dst_die->GetOffset(),
+ dst_name);
+
+ fast_path = false;
+ }
+ }
+
+ // Now do the work of linking the DeclContexts and Types.
+ if (fast_path)
+ {
+ // We can do this quickly. Just run across the tables index-for-index since
+ // we know each node has matching names and tags.
+ for (idx = 0; idx < src_size; ++idx)
+ {
+ src_die = src_name_to_die.GetValueAtIndexUnchecked (idx);
+ dst_die = dst_name_to_die.GetValueAtIndexUnchecked (idx);
+
+ clang::DeclContext *src_decl_ctx = src_symfile->m_die_to_decl_ctx[src_die];
+ if (src_decl_ctx)
+ {
+ if (log)
+ log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", src_decl_ctx, src_die->GetOffset(), dst_die->GetOffset());
+ LinkDeclContextToDIE (src_decl_ctx, dst_die);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset());
+ }
+
+ Type *src_child_type = m_die_to_type[src_die];
+ if (src_child_type)
+ {
+ if (log)
+ log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", src_child_type, src_child_type->GetID(), src_die->GetOffset(), dst_die->GetOffset());
+ m_die_to_type[dst_die] = src_child_type;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("warning: tried to unique lldb_private::Type from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset());
+ }
+ }
+ }
+ else
+ {
+ // We must do this slowly. For each member of the destination, look
+ // up a member in the source with the same name, check its tag, and
+ // unique them if everything matches up. Report failures.
+
+ if (!src_name_to_die.IsEmpty() && !dst_name_to_die.IsEmpty())
+ {
+ src_name_to_die.Sort();
+
+ for (idx = 0; idx < dst_size; ++idx)
+ {
+ const char *dst_name = dst_name_to_die.GetCStringAtIndex(idx);
+ dst_die = dst_name_to_die.GetValueAtIndexUnchecked(idx);
+ src_die = src_name_to_die.Find(dst_name, NULL);
+
+ if (src_die && (src_die->Tag() == dst_die->Tag()))
+ {
+ clang::DeclContext *src_decl_ctx = src_symfile->m_die_to_decl_ctx[src_die];
+ if (src_decl_ctx)
+ {
+ if (log)
+ log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", src_decl_ctx, src_die->GetOffset(), dst_die->GetOffset());
+ LinkDeclContextToDIE (src_decl_ctx, dst_die);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset());
+ }
+
+ Type *src_child_type = m_die_to_type[src_die];
+ if (src_child_type)
+ {
+ if (log)
+ log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", src_child_type, src_child_type->GetID(), src_die->GetOffset(), dst_die->GetOffset());
+ m_die_to_type[dst_die] = src_child_type;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("warning: tried to unique lldb_private::Type from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("warning: couldn't find a match for 0x%8.8x", dst_die->GetOffset());
+
+ failures.push_back(dst_die);
+ }
+ }
+ }
+ }
+
+ const uint32_t src_size_artificial = src_name_to_die_artificial.GetSize ();
+ const uint32_t dst_size_artificial = dst_name_to_die_artificial.GetSize ();
+
+ UniqueCStringMap<const DWARFDebugInfoEntry *> name_to_die_artificial_not_in_src;
+
+ if (src_size_artificial && dst_size_artificial)
+ {
+ dst_name_to_die_artificial.Sort();
+
+ for (idx = 0; idx < src_size_artificial; ++idx)
+ {
+ const char *src_name_artificial = src_name_to_die_artificial.GetCStringAtIndex(idx);
+ src_die = src_name_to_die_artificial.GetValueAtIndexUnchecked (idx);
+ dst_die = dst_name_to_die_artificial.Find(src_name_artificial, NULL);
+
+ if (dst_die)
+ {
+ // Both classes have the artificial types, link them
+ clang::DeclContext *src_decl_ctx = m_die_to_decl_ctx[src_die];
+ if (src_decl_ctx)
+ {
+ if (log)
+ log->Printf ("uniquing decl context %p from 0x%8.8x for 0x%8.8x", src_decl_ctx, src_die->GetOffset(), dst_die->GetOffset());
+ LinkDeclContextToDIE (src_decl_ctx, dst_die);
+ }
+ else
+ {
+ if (log)
+ log->Printf ("warning: tried to unique decl context from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset());
+ }
+
+ Type *src_child_type = m_die_to_type[src_die];
+ if (src_child_type)
+ {
+ if (log)
+ log->Printf ("uniquing type %p (uid=0x%" PRIx64 ") from 0x%8.8x for 0x%8.8x", src_child_type, src_child_type->GetID(), src_die->GetOffset(), dst_die->GetOffset());
+ m_die_to_type[dst_die] = src_child_type;
+ }
+ else
+ {
+ if (log)
+ log->Printf ("warning: tried to unique lldb_private::Type from 0x%8.8x for 0x%8.8x, but none was found", src_die->GetOffset(), dst_die->GetOffset());
+ }
+ }
+ }
+ }
+
+ if (dst_size_artificial)
+ {
+ for (idx = 0; idx < dst_size_artificial; ++idx)
+ {
+ const char *dst_name_artificial = dst_name_to_die_artificial.GetCStringAtIndex(idx);
+ dst_die = dst_name_to_die_artificial.GetValueAtIndexUnchecked (idx);
+ if (log)
+ log->Printf ("warning: need to create artificial method for 0x%8.8x for method '%s'", dst_die->GetOffset(), dst_name_artificial);
+
+ failures.push_back(dst_die);
+ }
+ }
+
+ return (failures.size() != 0);
+}
+
+TypeSP
+SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool *type_is_new_ptr)
+{
+ TypeSP type_sp;
+
+ if (type_is_new_ptr)
+ *type_is_new_ptr = false;
+
+#if defined(LLDB_CONFIGURATION_DEBUG) or defined(LLDB_CONFIGURATION_RELEASE)
+ static DIEStack g_die_stack;
+ DIEStack::ScopedPopper scoped_die_logger(g_die_stack);
+#endif
+
+ AccessType accessibility = eAccessNone;
+ if (die != NULL)
+ {
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO));
+ if (log)
+ {
+ const DWARFDebugInfoEntry *context_die;
+ clang::DeclContext *context = GetClangDeclContextContainingDIE (dwarf_cu, die, &context_die);
+
+ GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x, decl_ctx = %p (die 0x%8.8x)) %s name = '%s')",
+ die->GetOffset(),
+ context,
+ context_die->GetOffset(),
+ DW_TAG_value_to_name(die->Tag()),
+ die->GetName(this, dwarf_cu));
+
+#if defined(LLDB_CONFIGURATION_DEBUG) or defined(LLDB_CONFIGURATION_RELEASE)
+ scoped_die_logger.Push (dwarf_cu, die);
+ g_die_stack.LogDIEs(log, this);
+#endif
+ }
+//
+// Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO));
+// if (log && dwarf_cu)
+// {
+// StreamString s;
+// die->DumpLocation (this, dwarf_cu, s);
+// GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDwarf::%s %s", __FUNCTION__, s.GetData());
+//
+// }
+
+ Type *type_ptr = m_die_to_type.lookup (die);
+ TypeList* type_list = GetTypeList();
+ if (type_ptr == NULL)
+ {
+ ClangASTContext &ast = GetClangASTContext();
+ if (type_is_new_ptr)
+ *type_is_new_ptr = true;
+
+ const dw_tag_t tag = die->Tag();
+
+ bool is_forward_declaration = false;
+ DWARFDebugInfoEntry::Attributes attributes;
+ const char *type_name_cstr = NULL;
+ ConstString type_name_const_str;
+ Type::ResolveState resolve_state = Type::eResolveStateUnresolved;
+ uint64_t byte_size = 0;
+ Declaration decl;
+
+ Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID;
+ ClangASTType clang_type;
+
+ dw_attr_t attr;
+
+ switch (tag)
+ {
+ case DW_TAG_base_type:
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_rvalue_reference_type:
+ case DW_TAG_typedef:
+ case DW_TAG_const_type:
+ case DW_TAG_restrict_type:
+ case DW_TAG_volatile_type:
+ case DW_TAG_unspecified_type:
+ {
+ // Set a bit that lets us know that we are currently parsing this
+ m_die_to_type[die] = DIE_IS_BEING_PARSED;
+
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes);
+ uint32_t encoding = 0;
+ lldb::user_id_t encoding_uid = LLDB_INVALID_UID;
+
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_name:
+
+ type_name_cstr = form_value.AsCString(&get_debug_str_data());
+ // Work around a bug in llvm-gcc where they give a name to a reference type which doesn't
+ // include the "&"...
+ if (tag == DW_TAG_reference_type)
+ {
+ if (strchr (type_name_cstr, '&') == NULL)
+ type_name_cstr = NULL;
+ }
+ if (type_name_cstr)
+ type_name_const_str.SetCString(type_name_cstr);
+ break;
+ case DW_AT_byte_size: byte_size = form_value.Unsigned(); break;
+ case DW_AT_encoding: encoding = form_value.Unsigned(); break;
+ case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break;
+ default:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+ }
+
+ DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\") type => 0x%8.8x\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr, encoding_uid);
+
+ switch (tag)
+ {
+ default:
+ break;
+
+ case DW_TAG_unspecified_type:
+ if (strcmp(type_name_cstr, "nullptr_t") == 0 ||
+ strcmp(type_name_cstr, "decltype(nullptr)") == 0 )
+ {
+ resolve_state = Type::eResolveStateFull;
+ clang_type = ast.GetBasicType(eBasicTypeNullPtr);
+ break;
+ }
+ // Fall through to base type below in case we can handle the type there...
+
+ case DW_TAG_base_type:
+ resolve_state = Type::eResolveStateFull;
+ clang_type = ast.GetBuiltinTypeForDWARFEncodingAndBitSize (type_name_cstr,
+ encoding,
+ byte_size * 8);
+ break;
+
+ case DW_TAG_pointer_type: encoding_data_type = Type::eEncodingIsPointerUID; break;
+ case DW_TAG_reference_type: encoding_data_type = Type::eEncodingIsLValueReferenceUID; break;
+ case DW_TAG_rvalue_reference_type: encoding_data_type = Type::eEncodingIsRValueReferenceUID; break;
+ case DW_TAG_typedef: encoding_data_type = Type::eEncodingIsTypedefUID; break;
+ case DW_TAG_const_type: encoding_data_type = Type::eEncodingIsConstUID; break;
+ case DW_TAG_restrict_type: encoding_data_type = Type::eEncodingIsRestrictUID; break;
+ case DW_TAG_volatile_type: encoding_data_type = Type::eEncodingIsVolatileUID; break;
+ }
+
+ if (!clang_type && (encoding_data_type == Type::eEncodingIsPointerUID || encoding_data_type == Type::eEncodingIsTypedefUID) && sc.comp_unit != NULL)
+ {
+ bool translation_unit_is_objc = (sc.comp_unit->GetLanguage() == eLanguageTypeObjC || sc.comp_unit->GetLanguage() == eLanguageTypeObjC_plus_plus);
+
+ if (translation_unit_is_objc)
+ {
+ if (type_name_cstr != NULL)
+ {
+ static ConstString g_objc_type_name_id("id");
+ static ConstString g_objc_type_name_Class("Class");
+ static ConstString g_objc_type_name_selector("SEL");
+
+ if (type_name_const_str == g_objc_type_name_id)
+ {
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' is Objective C 'id' built-in type.",
+ die->GetOffset(),
+ DW_TAG_value_to_name(die->Tag()),
+ die->GetName(this, dwarf_cu));
+ clang_type = ast.GetBasicType(eBasicTypeObjCID);
+ encoding_data_type = Type::eEncodingIsUID;
+ encoding_uid = LLDB_INVALID_UID;
+ resolve_state = Type::eResolveStateFull;
+
+ }
+ else if (type_name_const_str == g_objc_type_name_Class)
+ {
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' is Objective C 'Class' built-in type.",
+ die->GetOffset(),
+ DW_TAG_value_to_name(die->Tag()),
+ die->GetName(this, dwarf_cu));
+ clang_type = ast.GetBasicType(eBasicTypeObjCClass);
+ encoding_data_type = Type::eEncodingIsUID;
+ encoding_uid = LLDB_INVALID_UID;
+ resolve_state = Type::eResolveStateFull;
+ }
+ else if (type_name_const_str == g_objc_type_name_selector)
+ {
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' is Objective C 'selector' built-in type.",
+ die->GetOffset(),
+ DW_TAG_value_to_name(die->Tag()),
+ die->GetName(this, dwarf_cu));
+ clang_type = ast.GetBasicType(eBasicTypeObjCSel);
+ encoding_data_type = Type::eEncodingIsUID;
+ encoding_uid = LLDB_INVALID_UID;
+ resolve_state = Type::eResolveStateFull;
+ }
+ }
+ else if (encoding_data_type == Type::eEncodingIsPointerUID && encoding_uid != LLDB_INVALID_UID)
+ {
+ // Clang sometimes erroneously emits id as objc_object*. In that case we fix up the type to "id".
+
+ DWARFDebugInfoEntry* encoding_die = dwarf_cu->GetDIEPtr(encoding_uid);
+
+ if (encoding_die && encoding_die->Tag() == DW_TAG_structure_type)
+ {
+ if (const char *struct_name = encoding_die->GetAttributeValueAsString(this, dwarf_cu, DW_AT_name, NULL))
+ {
+ if (!strcmp(struct_name, "objc_object"))
+ {
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log, "SymbolFileDWARF::ParseType (die = 0x%8.8x) %s '%s' is 'objc_object*', which we overrode to 'id'.",
+ die->GetOffset(),
+ DW_TAG_value_to_name(die->Tag()),
+ die->GetName(this, dwarf_cu));
+ clang_type = ast.GetBasicType(eBasicTypeObjCID);
+ encoding_data_type = Type::eEncodingIsUID;
+ encoding_uid = LLDB_INVALID_UID;
+ resolve_state = Type::eResolveStateFull;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ type_sp.reset( new Type (MakeUserID(die->GetOffset()),
+ this,
+ type_name_const_str,
+ byte_size,
+ NULL,
+ encoding_uid,
+ encoding_data_type,
+ &decl,
+ clang_type,
+ resolve_state));
+
+ m_die_to_type[die] = type_sp.get();
+
+// Type* encoding_type = GetUniquedTypeForDIEOffset(encoding_uid, type_sp, NULL, 0, 0, false);
+// if (encoding_type != NULL)
+// {
+// if (encoding_type != DIE_IS_BEING_PARSED)
+// type_sp->SetEncodingType(encoding_type);
+// else
+// m_indirect_fixups.push_back(type_sp.get());
+// }
+ }
+ break;
+
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ {
+ // Set a bit that lets us know that we are currently parsing this
+ m_die_to_type[die] = DIE_IS_BEING_PARSED;
+ bool byte_size_valid = false;
+
+ LanguageType class_language = eLanguageTypeUnknown;
+ bool is_complete_objc_class = false;
+ //bool struct_is_class = false;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes);
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file:
+ if (dwarf_cu->DW_AT_decl_file_attributes_are_invalid())
+ {
+ // llvm-gcc outputs invalid DW_AT_decl_file attributes that always
+ // point to the compile unit file, so we clear this invalid value
+ // so that we can still unique types efficiently.
+ decl.SetFile(FileSpec ("<invalid>", false));
+ }
+ else
+ decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned()));
+ break;
+
+ case DW_AT_decl_line:
+ decl.SetLine(form_value.Unsigned());
+ break;
+
+ case DW_AT_decl_column:
+ decl.SetColumn(form_value.Unsigned());
+ break;
+
+ case DW_AT_name:
+ type_name_cstr = form_value.AsCString(&get_debug_str_data());
+ type_name_const_str.SetCString(type_name_cstr);
+ break;
+
+ case DW_AT_byte_size:
+ byte_size = form_value.Unsigned();
+ byte_size_valid = true;
+ break;
+
+ case DW_AT_accessibility:
+ accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned());
+ break;
+
+ case DW_AT_declaration:
+ is_forward_declaration = form_value.Boolean();
+ break;
+
+ case DW_AT_APPLE_runtime_class:
+ class_language = (LanguageType)form_value.Signed();
+ break;
+
+ case DW_AT_APPLE_objc_complete_type:
+ is_complete_objc_class = form_value.Signed();
+ break;
+
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_data_location:
+ case DW_AT_description:
+ case DW_AT_start_scope:
+ case DW_AT_visibility:
+ default:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+ }
+
+ UniqueDWARFASTType unique_ast_entry;
+
+ // Only try and unique the type if it has a name.
+ if (type_name_const_str &&
+ GetUniqueDWARFASTTypeMap().Find (type_name_const_str,
+ this,
+ dwarf_cu,
+ die,
+ decl,
+ byte_size_valid ? byte_size : -1,
+ unique_ast_entry))
+ {
+ // We have already parsed this type or from another
+ // compile unit. GCC loves to use the "one definition
+ // rule" which can result in multiple definitions
+ // of the same class over and over in each compile
+ // unit.
+ type_sp = unique_ast_entry.m_type_sp;
+ if (type_sp)
+ {
+ m_die_to_type[die] = type_sp.get();
+ return type_sp;
+ }
+ }
+
+ DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr);
+
+ int tag_decl_kind = -1;
+ AccessType default_accessibility = eAccessNone;
+ if (tag == DW_TAG_structure_type)
+ {
+ tag_decl_kind = clang::TTK_Struct;
+ default_accessibility = eAccessPublic;
+ }
+ else if (tag == DW_TAG_union_type)
+ {
+ tag_decl_kind = clang::TTK_Union;
+ default_accessibility = eAccessPublic;
+ }
+ else if (tag == DW_TAG_class_type)
+ {
+ tag_decl_kind = clang::TTK_Class;
+ default_accessibility = eAccessPrivate;
+ }
+
+ if (byte_size_valid && byte_size == 0 && type_name_cstr &&
+ die->HasChildren() == false &&
+ sc.comp_unit->GetLanguage() == eLanguageTypeObjC)
+ {
+ // Work around an issue with clang at the moment where
+ // forward declarations for objective C classes are emitted
+ // as:
+ // DW_TAG_structure_type [2]
+ // DW_AT_name( "ForwardObjcClass" )
+ // DW_AT_byte_size( 0x00 )
+ // DW_AT_decl_file( "..." )
+ // DW_AT_decl_line( 1 )
+ //
+ // Note that there is no DW_AT_declaration and there are
+ // no children, and the byte size is zero.
+ is_forward_declaration = true;
+ }
+
+ if (class_language == eLanguageTypeObjC ||
+ class_language == eLanguageTypeObjC_plus_plus)
+ {
+ if (!is_complete_objc_class && Supports_DW_AT_APPLE_objc_complete_type(dwarf_cu))
+ {
+ // We have a valid eSymbolTypeObjCClass class symbol whose
+ // name matches the current objective C class that we
+ // are trying to find and this DIE isn't the complete
+ // definition (we checked is_complete_objc_class above and
+ // know it is false), so the real definition is in here somewhere
+ type_sp = FindCompleteObjCDefinitionTypeForDIE (die, type_name_const_str, true);
+
+ if (!type_sp && GetDebugMapSymfile ())
+ {
+ // We weren't able to find a full declaration in
+ // this DWARF, see if we have a declaration anywhere
+ // else...
+ type_sp = m_debug_map_symfile->FindCompleteObjCDefinitionTypeForDIE (die, type_name_const_str, true);
+ }
+
+ if (type_sp)
+ {
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is an incomplete objc type, complete type is 0x%8.8" PRIx64,
+ this,
+ die->GetOffset(),
+ DW_TAG_value_to_name(tag),
+ type_name_cstr,
+ type_sp->GetID());
+ }
+
+ // We found a real definition for this type elsewhere
+ // so lets use it and cache the fact that we found
+ // a complete type for this die
+ m_die_to_type[die] = type_sp.get();
+ return type_sp;
+ }
+ }
+ }
+
+
+ if (is_forward_declaration)
+ {
+ // We have a forward declaration to a type and we need
+ // to try and find a full declaration. We look in the
+ // current type index just in case we have a forward
+ // declaration followed by an actual declarations in the
+ // DWARF. If this fails, we need to look elsewhere...
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a forward declaration, trying to find complete type",
+ this,
+ die->GetOffset(),
+ DW_TAG_value_to_name(tag),
+ type_name_cstr);
+ }
+
+ DWARFDeclContext die_decl_ctx;
+ die->GetDWARFDeclContext(this, dwarf_cu, die_decl_ctx);
+
+ //type_sp = FindDefinitionTypeForDIE (dwarf_cu, die, type_name_const_str);
+ type_sp = FindDefinitionTypeForDWARFDeclContext (die_decl_ctx);
+
+ if (!type_sp && GetDebugMapSymfile ())
+ {
+ // We weren't able to find a full declaration in
+ // this DWARF, see if we have a declaration anywhere
+ // else...
+ type_sp = m_debug_map_symfile->FindDefinitionTypeForDWARFDeclContext (die_decl_ctx);
+ }
+
+ if (type_sp)
+ {
+ if (log)
+ {
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF(%p) - 0x%8.8x: %s type \"%s\" is a forward declaration, complete type is 0x%8.8" PRIx64,
+ this,
+ die->GetOffset(),
+ DW_TAG_value_to_name(tag),
+ type_name_cstr,
+ type_sp->GetID());
+ }
+
+ // We found a real definition for this type elsewhere
+ // so lets use it and cache the fact that we found
+ // a complete type for this die
+ m_die_to_type[die] = type_sp.get();
+ return type_sp;
+ }
+ }
+ assert (tag_decl_kind != -1);
+ bool clang_type_was_created = false;
+ clang_type.SetClangType(ast.getASTContext(), m_forward_decl_die_to_clang_type.lookup (die));
+ if (!clang_type)
+ {
+ const DWARFDebugInfoEntry *decl_ctx_die;
+
+ clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, &decl_ctx_die);
+ if (accessibility == eAccessNone && decl_ctx)
+ {
+ // Check the decl context that contains this class/struct/union.
+ // If it is a class we must give it an accessability.
+ const clang::Decl::Kind containing_decl_kind = decl_ctx->getDeclKind();
+ if (DeclKindIsCXXClass (containing_decl_kind))
+ accessibility = default_accessibility;
+ }
+
+ ClangASTMetadata metadata;
+ metadata.SetUserID(MakeUserID(die->GetOffset()));
+ metadata.SetIsDynamicCXXType(ClassOrStructIsVirtual (dwarf_cu, die));
+
+ if (type_name_cstr && strchr (type_name_cstr, '<'))
+ {
+ ClangASTContext::TemplateParameterInfos template_param_infos;
+ if (ParseTemplateParameterInfos (dwarf_cu, die, template_param_infos))
+ {
+ clang::ClassTemplateDecl *class_template_decl = ParseClassTemplateDecl (decl_ctx,
+ accessibility,
+ type_name_cstr,
+ tag_decl_kind,
+ template_param_infos);
+
+ clang::ClassTemplateSpecializationDecl *class_specialization_decl = ast.CreateClassTemplateSpecializationDecl (decl_ctx,
+ class_template_decl,
+ tag_decl_kind,
+ template_param_infos);
+ clang_type = ast.CreateClassTemplateSpecializationType (class_specialization_decl);
+ clang_type_was_created = true;
+
+ GetClangASTContext().SetMetadata (class_template_decl, metadata);
+ GetClangASTContext().SetMetadata (class_specialization_decl, metadata);
+ }
+ }
+
+ if (!clang_type_was_created)
+ {
+ clang_type_was_created = true;
+ clang_type = ast.CreateRecordType (decl_ctx,
+ accessibility,
+ type_name_cstr,
+ tag_decl_kind,
+ class_language,
+ &metadata);
+ }
+ }
+
+ // Store a forward declaration to this class type in case any
+ // parameters in any class methods need it for the clang
+ // types for function prototypes.
+ LinkDeclContextToDIE(clang_type.GetDeclContextForType(), die);
+ type_sp.reset (new Type (MakeUserID(die->GetOffset()),
+ this,
+ type_name_const_str,
+ byte_size,
+ NULL,
+ LLDB_INVALID_UID,
+ Type::eEncodingIsUID,
+ &decl,
+ clang_type,
+ Type::eResolveStateForward));
+
+ type_sp->SetIsCompleteObjCClass(is_complete_objc_class);
+
+
+ // Add our type to the unique type map so we don't
+ // end up creating many copies of the same type over
+ // and over in the ASTContext for our module
+ unique_ast_entry.m_type_sp = type_sp;
+ unique_ast_entry.m_symfile = this;
+ unique_ast_entry.m_cu = dwarf_cu;
+ unique_ast_entry.m_die = die;
+ unique_ast_entry.m_declaration = decl;
+ unique_ast_entry.m_byte_size = byte_size;
+ GetUniqueDWARFASTTypeMap().Insert (type_name_const_str,
+ unique_ast_entry);
+
+ if (is_forward_declaration && die->HasChildren())
+ {
+ // Check to see if the DIE actually has a definition, some version of GCC will
+ // emit DIEs with DW_AT_declaration set to true, but yet still have subprogram,
+ // members, or inheritance, so we can't trust it
+ const DWARFDebugInfoEntry *child_die = die->GetFirstChild();
+ while (child_die)
+ {
+ switch (child_die->Tag())
+ {
+ case DW_TAG_inheritance:
+ case DW_TAG_subprogram:
+ case DW_TAG_member:
+ case DW_TAG_APPLE_property:
+ child_die = NULL;
+ is_forward_declaration = false;
+ break;
+ default:
+ child_die = child_die->GetSibling();
+ break;
+ }
+ }
+ }
+
+ if (!is_forward_declaration)
+ {
+ // Always start the definition for a class type so that
+ // if the class has child classes or types that require
+ // the class to be created for use as their decl contexts
+ // the class will be ready to accept these child definitions.
+ if (die->HasChildren() == false)
+ {
+ // No children for this struct/union/class, lets finish it
+ clang_type.StartTagDeclarationDefinition ();
+ clang_type.CompleteTagDeclarationDefinition ();
+
+ if (tag == DW_TAG_structure_type) // this only applies in C
+ {
+ clang::RecordDecl *record_decl = clang_type.GetAsRecordDecl();
+
+ if (record_decl)
+ {
+ LayoutInfo layout_info;
+
+ layout_info.alignment = 0;
+ layout_info.bit_size = 0;
+
+ m_record_decl_to_layout_map.insert(std::make_pair(record_decl, layout_info));
+ }
+ }
+ }
+ else if (clang_type_was_created)
+ {
+ // Start the definition if the class is not objective C since
+ // the underlying decls respond to isCompleteDefinition(). Objective
+ // C decls dont' respond to isCompleteDefinition() so we can't
+ // start the declaration definition right away. For C++ classs/union/structs
+ // we want to start the definition in case the class is needed as the
+ // declaration context for a contained class or type without the need
+ // to complete that type..
+
+ if (class_language != eLanguageTypeObjC &&
+ class_language != eLanguageTypeObjC_plus_plus)
+ clang_type.StartTagDeclarationDefinition ();
+
+ // Leave this as a forward declaration until we need
+ // to know the details of the type. lldb_private::Type
+ // will automatically call the SymbolFile virtual function
+ // "SymbolFileDWARF::ResolveClangOpaqueTypeDefinition(Type *)"
+ // When the definition needs to be defined.
+ m_forward_decl_die_to_clang_type[die] = clang_type.GetOpaqueQualType();
+ m_forward_decl_clang_type_to_die[clang_type.RemoveFastQualifiers().GetOpaqueQualType()] = die;
+ clang_type.SetHasExternalStorage (true);
+ }
+ }
+
+ }
+ break;
+
+ case DW_TAG_enumeration_type:
+ {
+ // Set a bit that lets us know that we are currently parsing this
+ m_die_to_type[die] = DIE_IS_BEING_PARSED;
+
+ lldb::user_id_t encoding_uid = DW_INVALID_OFFSET;
+
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes);
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+
+ for (i=0; i<num_attributes; ++i)
+ {
+ attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_name:
+ type_name_cstr = form_value.AsCString(&get_debug_str_data());
+ type_name_const_str.SetCString(type_name_cstr);
+ break;
+ case DW_AT_type: encoding_uid = form_value.Reference(dwarf_cu); break;
+ case DW_AT_byte_size: byte_size = form_value.Unsigned(); break;
+ case DW_AT_accessibility: break; //accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break;
+ case DW_AT_declaration: break; //is_forward_declaration = form_value.Boolean(); break;
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_bit_stride:
+ case DW_AT_byte_stride:
+ case DW_AT_data_location:
+ case DW_AT_description:
+ case DW_AT_start_scope:
+ case DW_AT_visibility:
+ case DW_AT_specification:
+ case DW_AT_abstract_origin:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr);
+
+ ClangASTType enumerator_clang_type;
+ clang_type.SetClangType (ast.getASTContext(), m_forward_decl_die_to_clang_type.lookup (die));
+ if (!clang_type)
+ {
+ if (encoding_uid != DW_INVALID_OFFSET)
+ {
+ Type *enumerator_type = ResolveTypeUID(encoding_uid);
+ if (enumerator_type)
+ enumerator_clang_type = enumerator_type->GetClangFullType();
+ }
+
+ if (!enumerator_clang_type)
+ enumerator_clang_type = ast.GetBuiltinTypeForDWARFEncodingAndBitSize (NULL,
+ DW_ATE_signed,
+ byte_size * 8);
+
+ clang_type = ast.CreateEnumerationType (type_name_cstr,
+ GetClangDeclContextContainingDIE (dwarf_cu, die, NULL),
+ decl,
+ enumerator_clang_type);
+ }
+ else
+ {
+ enumerator_clang_type = clang_type.GetEnumerationIntegerType ();
+ }
+
+ LinkDeclContextToDIE(clang_type.GetDeclContextForType(), die);
+
+ type_sp.reset( new Type (MakeUserID(die->GetOffset()),
+ this,
+ type_name_const_str,
+ byte_size,
+ NULL,
+ encoding_uid,
+ Type::eEncodingIsUID,
+ &decl,
+ clang_type,
+ Type::eResolveStateForward));
+
+ clang_type.StartTagDeclarationDefinition ();
+ if (die->HasChildren())
+ {
+ SymbolContext cu_sc(GetCompUnitForDWARFCompUnit(dwarf_cu));
+ bool is_signed = false;
+ enumerator_clang_type.IsIntegerType(is_signed);
+ ParseChildEnumerators(cu_sc, clang_type, is_signed, type_sp->GetByteSize(), dwarf_cu, die);
+ }
+ clang_type.CompleteTagDeclarationDefinition ();
+ }
+ }
+ break;
+
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_subprogram:
+ case DW_TAG_subroutine_type:
+ {
+ // Set a bit that lets us know that we are currently parsing this
+ m_die_to_type[die] = DIE_IS_BEING_PARSED;
+
+ //const char *mangled = NULL;
+ dw_offset_t type_die_offset = DW_INVALID_OFFSET;
+ bool is_variadic = false;
+ bool is_inline = false;
+ bool is_static = false;
+ bool is_virtual = false;
+ bool is_explicit = false;
+ bool is_artificial = false;
+ dw_offset_t specification_die_offset = DW_INVALID_OFFSET;
+ dw_offset_t abstract_origin_die_offset = DW_INVALID_OFFSET;
+ dw_offset_t object_pointer_die_offset = DW_INVALID_OFFSET;
+
+ unsigned type_quals = 0;
+ clang::StorageClass storage = clang::SC_None;//, Extern, Static, PrivateExtern
+
+
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes);
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_name:
+ type_name_cstr = form_value.AsCString(&get_debug_str_data());
+ type_name_const_str.SetCString(type_name_cstr);
+ break;
+
+ case DW_AT_linkage_name:
+ case DW_AT_MIPS_linkage_name: break; // mangled = form_value.AsCString(&get_debug_str_data()); break;
+ case DW_AT_type: type_die_offset = form_value.Reference(dwarf_cu); break;
+ case DW_AT_accessibility: accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break;
+ case DW_AT_declaration: break; // is_forward_declaration = form_value.Boolean(); break;
+ case DW_AT_inline: is_inline = form_value.Boolean(); break;
+ case DW_AT_virtuality: is_virtual = form_value.Boolean(); break;
+ case DW_AT_explicit: is_explicit = form_value.Boolean(); break;
+ case DW_AT_artificial: is_artificial = form_value.Boolean(); break;
+
+
+ case DW_AT_external:
+ if (form_value.Unsigned())
+ {
+ if (storage == clang::SC_None)
+ storage = clang::SC_Extern;
+ else
+ storage = clang::SC_PrivateExtern;
+ }
+ break;
+
+ case DW_AT_specification:
+ specification_die_offset = form_value.Reference(dwarf_cu);
+ break;
+
+ case DW_AT_abstract_origin:
+ abstract_origin_die_offset = form_value.Reference(dwarf_cu);
+ break;
+
+ case DW_AT_object_pointer:
+ object_pointer_die_offset = form_value.Reference(dwarf_cu);
+ break;
+
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_address_class:
+ case DW_AT_calling_convention:
+ case DW_AT_data_location:
+ case DW_AT_elemental:
+ case DW_AT_entry_pc:
+ case DW_AT_frame_base:
+ case DW_AT_high_pc:
+ case DW_AT_low_pc:
+ case DW_AT_prototyped:
+ case DW_AT_pure:
+ case DW_AT_ranges:
+ case DW_AT_recursive:
+ case DW_AT_return_addr:
+ case DW_AT_segment:
+ case DW_AT_start_scope:
+ case DW_AT_static_link:
+ case DW_AT_trampoline:
+ case DW_AT_visibility:
+ case DW_AT_vtable_elem_location:
+ case DW_AT_description:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+ }
+
+ std::string object_pointer_name;
+ if (object_pointer_die_offset != DW_INVALID_OFFSET)
+ {
+ // Get the name from the object pointer die
+ StreamString s;
+ if (DWARFDebugInfoEntry::GetName (this, dwarf_cu, object_pointer_die_offset, s))
+ {
+ object_pointer_name.assign(s.GetData());
+ }
+ }
+
+ DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr);
+
+ ClangASTType return_clang_type;
+ Type *func_type = NULL;
+
+ if (type_die_offset != DW_INVALID_OFFSET)
+ func_type = ResolveTypeUID(type_die_offset);
+
+ if (func_type)
+ return_clang_type = func_type->GetClangForwardType();
+ else
+ return_clang_type = ast.GetBasicType(eBasicTypeVoid);
+
+
+ std::vector<ClangASTType> function_param_types;
+ std::vector<clang::ParmVarDecl*> function_param_decls;
+
+ // Parse the function children for the parameters
+
+ const DWARFDebugInfoEntry *decl_ctx_die = NULL;
+ clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, &decl_ctx_die);
+ const clang::Decl::Kind containing_decl_kind = containing_decl_ctx->getDeclKind();
+
+ const bool is_cxx_method = DeclKindIsCXXClass (containing_decl_kind);
+ // Start off static. This will be set to false in ParseChildParameters(...)
+ // if we find a "this" paramters as the first parameter
+ if (is_cxx_method)
+ is_static = true;
+ ClangASTContext::TemplateParameterInfos template_param_infos;
+
+ if (die->HasChildren())
+ {
+ bool skip_artificial = true;
+ ParseChildParameters (sc,
+ containing_decl_ctx,
+ dwarf_cu,
+ die,
+ skip_artificial,
+ is_static,
+ type_list,
+ function_param_types,
+ function_param_decls,
+ type_quals,
+ template_param_infos);
+ }
+
+ // clang_type will get the function prototype clang type after this call
+ clang_type = ast.CreateFunctionType (return_clang_type,
+ function_param_types.data(),
+ function_param_types.size(),
+ is_variadic,
+ type_quals);
+
+ bool ignore_containing_context = false;
+
+ if (type_name_cstr)
+ {
+ bool type_handled = false;
+ if (tag == DW_TAG_subprogram)
+ {
+ ObjCLanguageRuntime::MethodName objc_method (type_name_cstr, true);
+ if (objc_method.IsValid(true))
+ {
+ SymbolContext empty_sc;
+ ClangASTType class_opaque_type;
+ ConstString class_name(objc_method.GetClassName());
+ if (class_name)
+ {
+ TypeList types;
+ TypeSP complete_objc_class_type_sp (FindCompleteObjCDefinitionTypeForDIE (NULL, class_name, false));
+
+ if (complete_objc_class_type_sp)
+ {
+ ClangASTType type_clang_forward_type = complete_objc_class_type_sp->GetClangForwardType();
+ if (type_clang_forward_type.IsObjCObjectOrInterfaceType ())
+ class_opaque_type = type_clang_forward_type;
+ }
+ }
+
+ if (class_opaque_type)
+ {
+ // If accessibility isn't set to anything valid, assume public for
+ // now...
+ if (accessibility == eAccessNone)
+ accessibility = eAccessPublic;
+
+ clang::ObjCMethodDecl *objc_method_decl = class_opaque_type.AddMethodToObjCObjectType (type_name_cstr,
+ clang_type,
+ accessibility,
+ is_artificial);
+ type_handled = objc_method_decl != NULL;
+ if (type_handled)
+ {
+ LinkDeclContextToDIE(ClangASTContext::GetAsDeclContext(objc_method_decl), die);
+ GetClangASTContext().SetMetadataAsUserID (objc_method_decl, MakeUserID(die->GetOffset()));
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->ReportError ("{0x%8.8x}: invalid Objective-C method 0x%4.4x (%s), please file a bug and attach the file at the start of this error message",
+ die->GetOffset(),
+ tag,
+ DW_TAG_value_to_name(tag));
+ }
+ }
+ }
+ else if (is_cxx_method)
+ {
+ // Look at the parent of this DIE and see if is is
+ // a class or struct and see if this is actually a
+ // C++ method
+ Type *class_type = ResolveType (dwarf_cu, decl_ctx_die);
+ if (class_type)
+ {
+ if (class_type->GetID() != MakeUserID(decl_ctx_die->GetOffset()))
+ {
+ // We uniqued the parent class of this function to another class
+ // so we now need to associate all dies under "decl_ctx_die" to
+ // DIEs in the DIE for "class_type"...
+ SymbolFileDWARF *class_symfile = NULL;
+ DWARFCompileUnitSP class_type_cu_sp;
+ const DWARFDebugInfoEntry *class_type_die = NULL;
+
+ SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile();
+ if (debug_map_symfile)
+ {
+ class_symfile = debug_map_symfile->GetSymbolFileByOSOIndex(SymbolFileDWARFDebugMap::GetOSOIndexFromUserID(class_type->GetID()));
+ class_type_die = class_symfile->DebugInfo()->GetDIEPtr(class_type->GetID(), &class_type_cu_sp);
+ }
+ else
+ {
+ class_symfile = this;
+ class_type_die = DebugInfo()->GetDIEPtr(class_type->GetID(), &class_type_cu_sp);
+ }
+ if (class_type_die)
+ {
+ llvm::SmallVector<const DWARFDebugInfoEntry *, 0> failures;
+
+ CopyUniqueClassMethodTypes (class_symfile,
+ class_type,
+ class_type_cu_sp.get(),
+ class_type_die,
+ dwarf_cu,
+ decl_ctx_die,
+ failures);
+
+ // FIXME do something with these failures that's smarter than
+ // just dropping them on the ground. Unfortunately classes don't
+ // like having stuff added to them after their definitions are
+ // complete...
+
+ type_ptr = m_die_to_type[die];
+ if (type_ptr && type_ptr != DIE_IS_BEING_PARSED)
+ {
+ type_sp = type_ptr->shared_from_this();
+ break;
+ }
+ }
+ }
+
+ if (specification_die_offset != DW_INVALID_OFFSET)
+ {
+ // We have a specification which we are going to base our function
+ // prototype off of, so we need this type to be completed so that the
+ // m_die_to_decl_ctx for the method in the specification has a valid
+ // clang decl context.
+ class_type->GetClangForwardType();
+ // If we have a specification, then the function type should have been
+ // made with the specification and not with this die.
+ DWARFCompileUnitSP spec_cu_sp;
+ const DWARFDebugInfoEntry* spec_die = DebugInfo()->GetDIEPtr(specification_die_offset, &spec_cu_sp);
+ clang::DeclContext *spec_clang_decl_ctx = GetClangDeclContextForDIE (sc, dwarf_cu, spec_die);
+ if (spec_clang_decl_ctx)
+ {
+ LinkDeclContextToDIE(spec_clang_decl_ctx, die);
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->ReportWarning ("0x%8.8" PRIx64 ": DW_AT_specification(0x%8.8x) has no decl\n",
+ MakeUserID(die->GetOffset()),
+ specification_die_offset);
+ }
+ type_handled = true;
+ }
+ else if (abstract_origin_die_offset != DW_INVALID_OFFSET)
+ {
+ // We have a specification which we are going to base our function
+ // prototype off of, so we need this type to be completed so that the
+ // m_die_to_decl_ctx for the method in the abstract origin has a valid
+ // clang decl context.
+ class_type->GetClangForwardType();
+
+ DWARFCompileUnitSP abs_cu_sp;
+ const DWARFDebugInfoEntry* abs_die = DebugInfo()->GetDIEPtr(abstract_origin_die_offset, &abs_cu_sp);
+ clang::DeclContext *abs_clang_decl_ctx = GetClangDeclContextForDIE (sc, dwarf_cu, abs_die);
+ if (abs_clang_decl_ctx)
+ {
+ LinkDeclContextToDIE (abs_clang_decl_ctx, die);
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->ReportWarning ("0x%8.8" PRIx64 ": DW_AT_abstract_origin(0x%8.8x) has no decl\n",
+ MakeUserID(die->GetOffset()),
+ abstract_origin_die_offset);
+ }
+ type_handled = true;
+ }
+ else
+ {
+ ClangASTType class_opaque_type = class_type->GetClangForwardType();
+ if (class_opaque_type.IsCXXClassType ())
+ {
+ if (class_opaque_type.IsBeingDefined ())
+ {
+ // Neither GCC 4.2 nor clang++ currently set a valid accessibility
+ // in the DWARF for C++ methods... Default to public for now...
+ if (accessibility == eAccessNone)
+ accessibility = eAccessPublic;
+
+ if (!is_static && !die->HasChildren())
+ {
+ // We have a C++ member function with no children (this pointer!)
+ // and clang will get mad if we try and make a function that isn't
+ // well formed in the DWARF, so we will just skip it...
+ type_handled = true;
+ }
+ else
+ {
+ clang::CXXMethodDecl *cxx_method_decl;
+ // REMOVE THE CRASH DESCRIPTION BELOW
+ Host::SetCrashDescriptionWithFormat ("SymbolFileDWARF::ParseType() is adding a method %s to class %s in DIE 0x%8.8" PRIx64 " from %s",
+ type_name_cstr,
+ class_type->GetName().GetCString(),
+ MakeUserID(die->GetOffset()),
+ m_obj_file->GetFileSpec().GetPath().c_str());
+
+ const bool is_attr_used = false;
+
+ cxx_method_decl = class_opaque_type.AddMethodToCXXRecordType (type_name_cstr,
+ clang_type,
+ accessibility,
+ is_virtual,
+ is_static,
+ is_inline,
+ is_explicit,
+ is_attr_used,
+ is_artificial);
+
+ type_handled = cxx_method_decl != NULL;
+
+ if (type_handled)
+ {
+ LinkDeclContextToDIE(ClangASTContext::GetAsDeclContext(cxx_method_decl), die);
+
+ Host::SetCrashDescription (NULL);
+
+
+ ClangASTMetadata metadata;
+ metadata.SetUserID(MakeUserID(die->GetOffset()));
+
+ if (!object_pointer_name.empty())
+ {
+ metadata.SetObjectPtrName(object_pointer_name.c_str());
+ if (log)
+ log->Printf ("Setting object pointer name: %s on method object %p.\n",
+ object_pointer_name.c_str(),
+ cxx_method_decl);
+ }
+ GetClangASTContext().SetMetadata (cxx_method_decl, metadata);
+ }
+ else
+ {
+ ignore_containing_context = true;
+ }
+ }
+ }
+ else
+ {
+ // We were asked to parse the type for a method in a class, yet the
+ // class hasn't been asked to complete itself through the
+ // clang::ExternalASTSource protocol, so we need to just have the
+ // class complete itself and do things the right way, then our
+ // DIE should then have an entry in the m_die_to_type map. First
+ // we need to modify the m_die_to_type so it doesn't think we are
+ // trying to parse this DIE anymore...
+ m_die_to_type[die] = NULL;
+
+ // Now we get the full type to force our class type to complete itself
+ // using the clang::ExternalASTSource protocol which will parse all
+ // base classes and all methods (including the method for this DIE).
+ class_type->GetClangFullType();
+
+ // The type for this DIE should have been filled in the function call above
+ type_ptr = m_die_to_type[die];
+ if (type_ptr && type_ptr != DIE_IS_BEING_PARSED)
+ {
+ type_sp = type_ptr->shared_from_this();
+ break;
+ }
+
+ // FIXME This is fixing some even uglier behavior but we really need to
+ // uniq the methods of each class as well as the class itself.
+ // <rdar://problem/11240464>
+ type_handled = true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!type_handled)
+ {
+ // We just have a function that isn't part of a class
+ clang::FunctionDecl *function_decl = ast.CreateFunctionDeclaration (ignore_containing_context ? GetClangASTContext().GetTranslationUnitDecl() : containing_decl_ctx,
+ type_name_cstr,
+ clang_type,
+ storage,
+ is_inline);
+
+// if (template_param_infos.GetSize() > 0)
+// {
+// clang::FunctionTemplateDecl *func_template_decl = ast.CreateFunctionTemplateDecl (containing_decl_ctx,
+// function_decl,
+// type_name_cstr,
+// template_param_infos);
+//
+// ast.CreateFunctionTemplateSpecializationInfo (function_decl,
+// func_template_decl,
+// template_param_infos);
+// }
+ // Add the decl to our DIE to decl context map
+ assert (function_decl);
+ LinkDeclContextToDIE(function_decl, die);
+ if (!function_param_decls.empty())
+ ast.SetFunctionParameters (function_decl,
+ &function_param_decls.front(),
+ function_param_decls.size());
+
+ ClangASTMetadata metadata;
+ metadata.SetUserID(MakeUserID(die->GetOffset()));
+
+ if (!object_pointer_name.empty())
+ {
+ metadata.SetObjectPtrName(object_pointer_name.c_str());
+ if (log)
+ log->Printf ("Setting object pointer name: %s on function object %p.",
+ object_pointer_name.c_str(),
+ function_decl);
+ }
+ GetClangASTContext().SetMetadata (function_decl, metadata);
+ }
+ }
+ type_sp.reset( new Type (MakeUserID(die->GetOffset()),
+ this,
+ type_name_const_str,
+ 0,
+ NULL,
+ LLDB_INVALID_UID,
+ Type::eEncodingIsUID,
+ &decl,
+ clang_type,
+ Type::eResolveStateFull));
+ assert(type_sp.get());
+ }
+ break;
+
+ case DW_TAG_array_type:
+ {
+ // Set a bit that lets us know that we are currently parsing this
+ m_die_to_type[die] = DIE_IS_BEING_PARSED;
+
+ lldb::user_id_t type_die_offset = DW_INVALID_OFFSET;
+ int64_t first_index = 0;
+ uint32_t byte_stride = 0;
+ uint32_t bit_stride = 0;
+ bool is_vector = false;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes);
+
+ if (num_attributes > 0)
+ {
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_name:
+ type_name_cstr = form_value.AsCString(&get_debug_str_data());
+ type_name_const_str.SetCString(type_name_cstr);
+ break;
+
+ case DW_AT_type: type_die_offset = form_value.Reference(dwarf_cu); break;
+ case DW_AT_byte_size: break; // byte_size = form_value.Unsigned(); break;
+ case DW_AT_byte_stride: byte_stride = form_value.Unsigned(); break;
+ case DW_AT_bit_stride: bit_stride = form_value.Unsigned(); break;
+ case DW_AT_GNU_vector: is_vector = form_value.Boolean(); break;
+ case DW_AT_accessibility: break; // accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break;
+ case DW_AT_declaration: break; // is_forward_declaration = form_value.Boolean(); break;
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_data_location:
+ case DW_AT_description:
+ case DW_AT_ordering:
+ case DW_AT_start_scope:
+ case DW_AT_visibility:
+ case DW_AT_specification:
+ case DW_AT_abstract_origin:
+ case DW_AT_sibling:
+ break;
+ }
+ }
+ }
+
+ DEBUG_PRINTF ("0x%8.8" PRIx64 ": %s (\"%s\")\n", MakeUserID(die->GetOffset()), DW_TAG_value_to_name(tag), type_name_cstr);
+
+ Type *element_type = ResolveTypeUID(type_die_offset);
+
+ if (element_type)
+ {
+ std::vector<uint64_t> element_orders;
+ ParseChildArrayInfo(sc, dwarf_cu, die, first_index, element_orders, byte_stride, bit_stride);
+ if (byte_stride == 0 && bit_stride == 0)
+ byte_stride = element_type->GetByteSize();
+ ClangASTType array_element_type = element_type->GetClangForwardType();
+ uint64_t array_element_bit_stride = byte_stride * 8 + bit_stride;
+ uint64_t num_elements = 0;
+ std::vector<uint64_t>::const_reverse_iterator pos;
+ std::vector<uint64_t>::const_reverse_iterator end = element_orders.rend();
+ for (pos = element_orders.rbegin(); pos != end; ++pos)
+ {
+ num_elements = *pos;
+ clang_type = ast.CreateArrayType (array_element_type,
+ num_elements,
+ is_vector);
+ array_element_type = clang_type;
+ array_element_bit_stride = num_elements ? array_element_bit_stride * num_elements : array_element_bit_stride;
+ }
+ ConstString empty_name;
+ type_sp.reset( new Type (MakeUserID(die->GetOffset()),
+ this,
+ empty_name,
+ array_element_bit_stride / 8,
+ NULL,
+ type_die_offset,
+ Type::eEncodingIsUID,
+ &decl,
+ clang_type,
+ Type::eResolveStateFull));
+ type_sp->SetEncodingType (element_type);
+ }
+ }
+ }
+ break;
+
+ case DW_TAG_ptr_to_member_type:
+ {
+ dw_offset_t type_die_offset = DW_INVALID_OFFSET;
+ dw_offset_t containing_type_die_offset = DW_INVALID_OFFSET;
+
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes);
+
+ if (num_attributes > 0) {
+ uint32_t i;
+ for (i=0; i<num_attributes; ++i)
+ {
+ attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_type:
+ type_die_offset = form_value.Reference(dwarf_cu); break;
+ case DW_AT_containing_type:
+ containing_type_die_offset = form_value.Reference(dwarf_cu); break;
+ }
+ }
+ }
+
+ Type *pointee_type = ResolveTypeUID(type_die_offset);
+ Type *class_type = ResolveTypeUID(containing_type_die_offset);
+
+ ClangASTType pointee_clang_type = pointee_type->GetClangForwardType();
+ ClangASTType class_clang_type = class_type->GetClangLayoutType();
+
+ clang_type = pointee_clang_type.CreateMemberPointerType(class_clang_type);
+
+ byte_size = clang_type.GetByteSize();
+
+ type_sp.reset( new Type (MakeUserID(die->GetOffset()),
+ this,
+ type_name_const_str,
+ byte_size,
+ NULL,
+ LLDB_INVALID_UID,
+ Type::eEncodingIsUID,
+ NULL,
+ clang_type,
+ Type::eResolveStateForward));
+ }
+
+ break;
+ }
+ default:
+ GetObjectFile()->GetModule()->ReportError ("{0x%8.8x}: unhandled type tag 0x%4.4x (%s), please file a bug and attach the file at the start of this error message",
+ die->GetOffset(),
+ tag,
+ DW_TAG_value_to_name(tag));
+ break;
+ }
+
+ if (type_sp.get())
+ {
+ const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(die);
+ dw_tag_t sc_parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0;
+
+ SymbolContextScope * symbol_context_scope = NULL;
+ if (sc_parent_tag == DW_TAG_compile_unit)
+ {
+ symbol_context_scope = sc.comp_unit;
+ }
+ else if (sc.function != NULL)
+ {
+ symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(MakeUserID(sc_parent_die->GetOffset()));
+ if (symbol_context_scope == NULL)
+ symbol_context_scope = sc.function;
+ }
+
+ if (symbol_context_scope != NULL)
+ {
+ type_sp->SetSymbolContextScope(symbol_context_scope);
+ }
+
+ // We are ready to put this type into the uniqued list up at the module level
+ type_list->Insert (type_sp);
+
+ m_die_to_type[die] = type_sp.get();
+ }
+ }
+ else if (type_ptr != DIE_IS_BEING_PARSED)
+ {
+ type_sp = type_ptr->shared_from_this();
+ }
+ }
+ return type_sp;
+}
+
+size_t
+SymbolFileDWARF::ParseTypes
+(
+ const SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ bool parse_siblings,
+ bool parse_children
+)
+{
+ size_t types_added = 0;
+ while (die != NULL)
+ {
+ bool type_is_new = false;
+ if (ParseType(sc, dwarf_cu, die, &type_is_new).get())
+ {
+ if (type_is_new)
+ ++types_added;
+ }
+
+ if (parse_children && die->HasChildren())
+ {
+ if (die->Tag() == DW_TAG_subprogram)
+ {
+ SymbolContext child_sc(sc);
+ child_sc.function = sc.comp_unit->FindFunctionByUID(MakeUserID(die->GetOffset())).get();
+ types_added += ParseTypes(child_sc, dwarf_cu, die->GetFirstChild(), true, true);
+ }
+ else
+ types_added += ParseTypes(sc, dwarf_cu, die->GetFirstChild(), true, true);
+ }
+
+ if (parse_siblings)
+ die = die->GetSibling();
+ else
+ die = NULL;
+ }
+ return types_added;
+}
+
+
+size_t
+SymbolFileDWARF::ParseFunctionBlocks (const SymbolContext &sc)
+{
+ assert(sc.comp_unit && sc.function);
+ size_t functions_added = 0;
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
+ if (dwarf_cu)
+ {
+ dw_offset_t function_die_offset = sc.function->GetID();
+ const DWARFDebugInfoEntry *function_die = dwarf_cu->GetDIEPtr(function_die_offset);
+ if (function_die)
+ {
+ ParseFunctionBlocks(sc, &sc.function->GetBlock (false), dwarf_cu, function_die, LLDB_INVALID_ADDRESS, 0);
+ }
+ }
+
+ return functions_added;
+}
+
+
+size_t
+SymbolFileDWARF::ParseTypes (const SymbolContext &sc)
+{
+ // At least a compile unit must be valid
+ assert(sc.comp_unit);
+ size_t types_added = 0;
+ DWARFCompileUnit* dwarf_cu = GetDWARFCompileUnit(sc.comp_unit);
+ if (dwarf_cu)
+ {
+ if (sc.function)
+ {
+ dw_offset_t function_die_offset = sc.function->GetID();
+ const DWARFDebugInfoEntry *func_die = dwarf_cu->GetDIEPtr(function_die_offset);
+ if (func_die && func_die->HasChildren())
+ {
+ types_added = ParseTypes(sc, dwarf_cu, func_die->GetFirstChild(), true, true);
+ }
+ }
+ else
+ {
+ const DWARFDebugInfoEntry *dwarf_cu_die = dwarf_cu->DIE();
+ if (dwarf_cu_die && dwarf_cu_die->HasChildren())
+ {
+ types_added = ParseTypes(sc, dwarf_cu, dwarf_cu_die->GetFirstChild(), true, true);
+ }
+ }
+ }
+
+ return types_added;
+}
+
+size_t
+SymbolFileDWARF::ParseVariablesForContext (const SymbolContext& sc)
+{
+ if (sc.comp_unit != NULL)
+ {
+ DWARFDebugInfo* info = DebugInfo();
+ if (info == NULL)
+ return 0;
+
+ if (sc.function)
+ {
+ DWARFCompileUnit* dwarf_cu = info->GetCompileUnitContainingDIE(sc.function->GetID()).get();
+
+ if (dwarf_cu == NULL)
+ return 0;
+
+ const DWARFDebugInfoEntry *function_die = dwarf_cu->GetDIEPtr(sc.function->GetID());
+
+ dw_addr_t func_lo_pc = function_die->GetAttributeValueAsUnsigned (this, dwarf_cu, DW_AT_low_pc, LLDB_INVALID_ADDRESS);
+ if (func_lo_pc != LLDB_INVALID_ADDRESS)
+ {
+ const size_t num_variables = ParseVariables(sc, dwarf_cu, func_lo_pc, function_die->GetFirstChild(), true, true);
+
+ // Let all blocks know they have parse all their variables
+ sc.function->GetBlock (false).SetDidParseVariables (true, true);
+ return num_variables;
+ }
+ }
+ else if (sc.comp_unit)
+ {
+ DWARFCompileUnit* dwarf_cu = info->GetCompileUnit(sc.comp_unit->GetID()).get();
+
+ if (dwarf_cu == NULL)
+ return 0;
+
+ uint32_t vars_added = 0;
+ VariableListSP variables (sc.comp_unit->GetVariableList(false));
+
+ if (variables.get() == NULL)
+ {
+ variables.reset(new VariableList());
+ sc.comp_unit->SetVariableList(variables);
+
+ DWARFCompileUnit* match_dwarf_cu = NULL;
+ const DWARFDebugInfoEntry* die = NULL;
+ DIEArray die_offsets;
+ if (m_using_apple_tables)
+ {
+ if (m_apple_names_ap.get())
+ {
+ DWARFMappedHash::DIEInfoArray hash_data_array;
+ if (m_apple_names_ap->AppendAllDIEsInRange (dwarf_cu->GetOffset(),
+ dwarf_cu->GetNextCompileUnitOffset(),
+ hash_data_array))
+ {
+ DWARFMappedHash::ExtractDIEArray (hash_data_array, die_offsets);
+ }
+ }
+ }
+ else
+ {
+ // Index if we already haven't to make sure the compile units
+ // get indexed and make their global DIE index list
+ if (!m_indexed)
+ Index ();
+
+ m_global_index.FindAllEntriesForCompileUnit (dwarf_cu->GetOffset(),
+ dwarf_cu->GetNextCompileUnitOffset(),
+ die_offsets);
+ }
+
+ const size_t num_matches = die_offsets.size();
+ if (num_matches)
+ {
+ DWARFDebugInfo* debug_info = DebugInfo();
+ for (size_t i=0; i<num_matches; ++i)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ die = debug_info->GetDIEPtrWithCompileUnitHint (die_offset, &match_dwarf_cu);
+ if (die)
+ {
+ VariableSP var_sp (ParseVariableDIE(sc, dwarf_cu, die, LLDB_INVALID_ADDRESS));
+ if (var_sp)
+ {
+ variables->AddVariableIfUnique (var_sp);
+ ++vars_added;
+ }
+ }
+ else
+ {
+ if (m_using_apple_tables)
+ {
+ GetObjectFile()->GetModule()->ReportErrorIfModifyDetected ("the DWARF debug information has been modified (.apple_names accelerator table had bad die 0x%8.8x)\n", die_offset);
+ }
+ }
+
+ }
+ }
+ }
+ return vars_added;
+ }
+ }
+ return 0;
+}
+
+
+VariableSP
+SymbolFileDWARF::ParseVariableDIE
+(
+ const SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ const lldb::addr_t func_low_pc
+)
+{
+
+ VariableSP var_sp (m_die_to_variable_sp[die]);
+ if (var_sp)
+ return var_sp; // Already been parsed!
+
+ const dw_tag_t tag = die->Tag();
+
+ if ((tag == DW_TAG_variable) ||
+ (tag == DW_TAG_constant) ||
+ (tag == DW_TAG_formal_parameter && sc.function))
+ {
+ DWARFDebugInfoEntry::Attributes attributes;
+ const size_t num_attributes = die->GetAttributes(this, dwarf_cu, NULL, attributes);
+ if (num_attributes > 0)
+ {
+ const char *name = NULL;
+ const char *mangled = NULL;
+ Declaration decl;
+ uint32_t i;
+ lldb::user_id_t type_uid = LLDB_INVALID_UID;
+ DWARFExpression location;
+ bool is_external = false;
+ bool is_artificial = false;
+ bool location_is_const_value_data = false;
+ bool has_explicit_location = false;
+ //AccessType accessibility = eAccessNone;
+
+ for (i=0; i<num_attributes; ++i)
+ {
+ dw_attr_t attr = attributes.AttributeAtIndex(i);
+ DWARFFormValue form_value;
+ if (attributes.ExtractFormValueAtIndex(this, i, form_value))
+ {
+ switch (attr)
+ {
+ case DW_AT_decl_file: decl.SetFile(sc.comp_unit->GetSupportFiles().GetFileSpecAtIndex(form_value.Unsigned())); break;
+ case DW_AT_decl_line: decl.SetLine(form_value.Unsigned()); break;
+ case DW_AT_decl_column: decl.SetColumn(form_value.Unsigned()); break;
+ case DW_AT_name: name = form_value.AsCString(&get_debug_str_data()); break;
+ case DW_AT_linkage_name:
+ case DW_AT_MIPS_linkage_name: mangled = form_value.AsCString(&get_debug_str_data()); break;
+ case DW_AT_type: type_uid = form_value.Reference(dwarf_cu); break;
+ case DW_AT_external: is_external = form_value.Boolean(); break;
+ case DW_AT_const_value:
+ // If we have already found a DW_AT_location attribute, ignore this attribute.
+ if (!has_explicit_location)
+ {
+ location_is_const_value_data = true;
+ // The constant value will be either a block, a data value or a string.
+ const DataExtractor& debug_info_data = get_debug_info_data();
+ if (DWARFFormValue::IsBlockForm(form_value.Form()))
+ {
+ // Retrieve the value as a block expression.
+ uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart();
+ uint32_t block_length = form_value.Unsigned();
+ location.CopyOpcodeData(debug_info_data, block_offset, block_length);
+ }
+ else if (DWARFFormValue::IsDataForm(form_value.Form()))
+ {
+ // Retrieve the value as a data expression.
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+ uint32_t data_offset = attributes.DIEOffsetAtIndex(i);
+ uint32_t data_length = fixed_form_sizes[form_value.Form()];
+ location.CopyOpcodeData(debug_info_data, data_offset, data_length);
+ }
+ else
+ {
+ // Retrieve the value as a string expression.
+ if (form_value.Form() == DW_FORM_strp)
+ {
+ const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize());
+ uint32_t data_offset = attributes.DIEOffsetAtIndex(i);
+ uint32_t data_length = fixed_form_sizes[form_value.Form()];
+ location.CopyOpcodeData(debug_info_data, data_offset, data_length);
+ }
+ else
+ {
+ const char *str = form_value.AsCString(&debug_info_data);
+ uint32_t string_offset = str - (const char *)debug_info_data.GetDataStart();
+ uint32_t string_length = strlen(str) + 1;
+ location.CopyOpcodeData(debug_info_data, string_offset, string_length);
+ }
+ }
+ }
+ break;
+ case DW_AT_location:
+ {
+ location_is_const_value_data = false;
+ has_explicit_location = true;
+ if (form_value.BlockData())
+ {
+ const DataExtractor& debug_info_data = get_debug_info_data();
+
+ uint32_t block_offset = form_value.BlockData() - debug_info_data.GetDataStart();
+ uint32_t block_length = form_value.Unsigned();
+ location.CopyOpcodeData(get_debug_info_data(), block_offset, block_length);
+ }
+ else
+ {
+ const DataExtractor& debug_loc_data = get_debug_loc_data();
+ const dw_offset_t debug_loc_offset = form_value.Unsigned();
+
+ size_t loc_list_length = DWARFLocationList::Size(debug_loc_data, debug_loc_offset);
+ if (loc_list_length > 0)
+ {
+ location.CopyOpcodeData(debug_loc_data, debug_loc_offset, loc_list_length);
+ assert (func_low_pc != LLDB_INVALID_ADDRESS);
+ location.SetLocationListSlide (func_low_pc - dwarf_cu->GetBaseAddress());
+ }
+ }
+ }
+ break;
+
+ case DW_AT_artificial: is_artificial = form_value.Boolean(); break;
+ case DW_AT_accessibility: break; //accessibility = DW_ACCESS_to_AccessType(form_value.Unsigned()); break;
+ case DW_AT_declaration:
+ case DW_AT_description:
+ case DW_AT_endianity:
+ case DW_AT_segment:
+ case DW_AT_start_scope:
+ case DW_AT_visibility:
+ default:
+ case DW_AT_abstract_origin:
+ case DW_AT_sibling:
+ case DW_AT_specification:
+ break;
+ }
+ }
+ }
+
+ ValueType scope = eValueTypeInvalid;
+
+ const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(die);
+ dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0;
+ SymbolContextScope * symbol_context_scope = NULL;
+
+ // DWARF doesn't specify if a DW_TAG_variable is a local, global
+ // or static variable, so we have to do a little digging by
+ // looking at the location of a varaible to see if it contains
+ // a DW_OP_addr opcode _somewhere_ in the definition. I say
+ // somewhere because clang likes to combine small global variables
+ // into the same symbol and have locations like:
+ // DW_OP_addr(0x1000), DW_OP_constu(2), DW_OP_plus
+ // So if we don't have a DW_TAG_formal_parameter, we can look at
+ // the location to see if it contains a DW_OP_addr opcode, and
+ // then we can correctly classify our variables.
+ if (tag == DW_TAG_formal_parameter)
+ scope = eValueTypeVariableArgument;
+ else
+ {
+ bool op_error = false;
+ // Check if the location has a DW_OP_addr with any address value...
+ lldb::addr_t location_DW_OP_addr = LLDB_INVALID_ADDRESS;
+ if (!location_is_const_value_data)
+ {
+ location_DW_OP_addr = location.GetLocation_DW_OP_addr (0, op_error);
+ if (op_error)
+ {
+ StreamString strm;
+ location.DumpLocationForAddress (&strm, eDescriptionLevelFull, 0, 0, NULL);
+ GetObjectFile()->GetModule()->ReportError ("0x%8.8x: %s has an invalid location: %s", die->GetOffset(), DW_TAG_value_to_name(die->Tag()), strm.GetString().c_str());
+ }
+ }
+
+ if (location_DW_OP_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (is_external)
+ scope = eValueTypeVariableGlobal;
+ else
+ scope = eValueTypeVariableStatic;
+
+
+ SymbolFileDWARFDebugMap *debug_map_symfile = GetDebugMapSymfile ();
+
+ if (debug_map_symfile)
+ {
+ // When leaving the DWARF in the .o files on darwin,
+ // when we have a global variable that wasn't initialized,
+ // the .o file might not have allocated a virtual
+ // address for the global variable. In this case it will
+ // have created a symbol for the global variable
+ // that is undefined/data and external and the value will
+ // be the byte size of the variable. When we do the
+ // address map in SymbolFileDWARFDebugMap we rely on
+ // having an address, we need to do some magic here
+ // so we can get the correct address for our global
+ // variable. The address for all of these entries
+ // will be zero, and there will be an undefined symbol
+ // in this object file, and the executable will have
+ // a matching symbol with a good address. So here we
+ // dig up the correct address and replace it in the
+ // location for the variable, and set the variable's
+ // symbol context scope to be that of the main executable
+ // so the file address will resolve correctly.
+ bool linked_oso_file_addr = false;
+ if (is_external && location_DW_OP_addr == 0)
+ {
+ // we have a possible uninitialized extern global
+ ConstString const_name(mangled ? mangled : name);
+ ObjectFile *debug_map_objfile = debug_map_symfile->GetObjectFile();
+ if (debug_map_objfile)
+ {
+ Symtab *debug_map_symtab = debug_map_objfile->GetSymtab();
+ if (debug_map_symtab)
+ {
+ Symbol *exe_symbol = debug_map_symtab->FindFirstSymbolWithNameAndType (const_name,
+ eSymbolTypeData,
+ Symtab::eDebugYes,
+ Symtab::eVisibilityExtern);
+ if (exe_symbol)
+ {
+ if (exe_symbol->ValueIsAddress())
+ {
+ const addr_t exe_file_addr = exe_symbol->GetAddress().GetFileAddress();
+ if (exe_file_addr != LLDB_INVALID_ADDRESS)
+ {
+ if (location.Update_DW_OP_addr (exe_file_addr))
+ {
+ linked_oso_file_addr = true;
+ symbol_context_scope = exe_symbol;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (!linked_oso_file_addr)
+ {
+ // The DW_OP_addr is not zero, but it contains a .o file address which
+ // needs to be linked up correctly.
+ const lldb::addr_t exe_file_addr = debug_map_symfile->LinkOSOFileAddress(this, location_DW_OP_addr);
+ if (exe_file_addr != LLDB_INVALID_ADDRESS)
+ {
+ // Update the file address for this variable
+ location.Update_DW_OP_addr (exe_file_addr);
+ }
+ else
+ {
+ // Variable didn't make it into the final executable
+ return var_sp;
+ }
+ }
+ }
+ }
+ else
+ {
+ scope = eValueTypeVariableLocal;
+ }
+ }
+
+ if (symbol_context_scope == NULL)
+ {
+ switch (parent_tag)
+ {
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_lexical_block:
+ if (sc.function)
+ {
+ symbol_context_scope = sc.function->GetBlock(true).FindBlockByID(MakeUserID(sc_parent_die->GetOffset()));
+ if (symbol_context_scope == NULL)
+ symbol_context_scope = sc.function;
+ }
+ break;
+
+ default:
+ symbol_context_scope = sc.comp_unit;
+ break;
+ }
+ }
+
+ if (symbol_context_scope)
+ {
+ var_sp.reset (new Variable (MakeUserID(die->GetOffset()),
+ name,
+ mangled,
+ SymbolFileTypeSP (new SymbolFileType(*this, type_uid)),
+ scope,
+ symbol_context_scope,
+ &decl,
+ location,
+ is_external,
+ is_artificial));
+
+ var_sp->SetLocationIsConstantValueData (location_is_const_value_data);
+ }
+ else
+ {
+ // Not ready to parse this variable yet. It might be a global
+ // or static variable that is in a function scope and the function
+ // in the symbol context wasn't filled in yet
+ return var_sp;
+ }
+ }
+ // Cache var_sp even if NULL (the variable was just a specification or
+ // was missing vital information to be able to be displayed in the debugger
+ // (missing location due to optimization, etc)) so we don't re-parse
+ // this DIE over and over later...
+ m_die_to_variable_sp[die] = var_sp;
+ }
+ return var_sp;
+}
+
+
+const DWARFDebugInfoEntry *
+SymbolFileDWARF::FindBlockContainingSpecification (dw_offset_t func_die_offset,
+ dw_offset_t spec_block_die_offset,
+ DWARFCompileUnit **result_die_cu_handle)
+{
+ // Give the concrete function die specified by "func_die_offset", find the
+ // concrete block whose DW_AT_specification or DW_AT_abstract_origin points
+ // to "spec_block_die_offset"
+ DWARFDebugInfo* info = DebugInfo();
+
+ const DWARFDebugInfoEntry *die = info->GetDIEPtrWithCompileUnitHint(func_die_offset, result_die_cu_handle);
+ if (die)
+ {
+ assert (*result_die_cu_handle);
+ return FindBlockContainingSpecification (*result_die_cu_handle, die, spec_block_die_offset, result_die_cu_handle);
+ }
+ return NULL;
+}
+
+
+const DWARFDebugInfoEntry *
+SymbolFileDWARF::FindBlockContainingSpecification(DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ dw_offset_t spec_block_die_offset,
+ DWARFCompileUnit **result_die_cu_handle)
+{
+ if (die)
+ {
+ switch (die->Tag())
+ {
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_lexical_block:
+ {
+ if (die->GetAttributeValueAsReference (this, dwarf_cu, DW_AT_specification, DW_INVALID_OFFSET) == spec_block_die_offset)
+ {
+ *result_die_cu_handle = dwarf_cu;
+ return die;
+ }
+
+ if (die->GetAttributeValueAsReference (this, dwarf_cu, DW_AT_abstract_origin, DW_INVALID_OFFSET) == spec_block_die_offset)
+ {
+ *result_die_cu_handle = dwarf_cu;
+ return die;
+ }
+ }
+ break;
+ }
+
+ // Give the concrete function die specified by "func_die_offset", find the
+ // concrete block whose DW_AT_specification or DW_AT_abstract_origin points
+ // to "spec_block_die_offset"
+ for (const DWARFDebugInfoEntry *child_die = die->GetFirstChild(); child_die != NULL; child_die = child_die->GetSibling())
+ {
+ const DWARFDebugInfoEntry *result_die = FindBlockContainingSpecification (dwarf_cu,
+ child_die,
+ spec_block_die_offset,
+ result_die_cu_handle);
+ if (result_die)
+ return result_die;
+ }
+ }
+
+ *result_die_cu_handle = NULL;
+ return NULL;
+}
+
+size_t
+SymbolFileDWARF::ParseVariables
+(
+ const SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const lldb::addr_t func_low_pc,
+ const DWARFDebugInfoEntry *orig_die,
+ bool parse_siblings,
+ bool parse_children,
+ VariableList* cc_variable_list
+)
+{
+ if (orig_die == NULL)
+ return 0;
+
+ VariableListSP variable_list_sp;
+
+ size_t vars_added = 0;
+ const DWARFDebugInfoEntry *die = orig_die;
+ while (die != NULL)
+ {
+ dw_tag_t tag = die->Tag();
+
+ // Check to see if we have already parsed this variable or constant?
+ if (m_die_to_variable_sp[die])
+ {
+ if (cc_variable_list)
+ cc_variable_list->AddVariableIfUnique (m_die_to_variable_sp[die]);
+ }
+ else
+ {
+ // We haven't already parsed it, lets do that now.
+ if ((tag == DW_TAG_variable) ||
+ (tag == DW_TAG_constant) ||
+ (tag == DW_TAG_formal_parameter && sc.function))
+ {
+ if (variable_list_sp.get() == NULL)
+ {
+ const DWARFDebugInfoEntry *sc_parent_die = GetParentSymbolContextDIE(orig_die);
+ dw_tag_t parent_tag = sc_parent_die ? sc_parent_die->Tag() : 0;
+ switch (parent_tag)
+ {
+ case DW_TAG_compile_unit:
+ if (sc.comp_unit != NULL)
+ {
+ variable_list_sp = sc.comp_unit->GetVariableList(false);
+ if (variable_list_sp.get() == NULL)
+ {
+ variable_list_sp.reset(new VariableList());
+ sc.comp_unit->SetVariableList(variable_list_sp);
+ }
+ }
+ else
+ {
+ GetObjectFile()->GetModule()->ReportError ("parent 0x%8.8" PRIx64 " %s with no valid compile unit in symbol context for 0x%8.8" PRIx64 " %s.\n",
+ MakeUserID(sc_parent_die->GetOffset()),
+ DW_TAG_value_to_name (parent_tag),
+ MakeUserID(orig_die->GetOffset()),
+ DW_TAG_value_to_name (orig_die->Tag()));
+ }
+ break;
+
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_lexical_block:
+ if (sc.function != NULL)
+ {
+ // Check to see if we already have parsed the variables for the given scope
+
+ Block *block = sc.function->GetBlock(true).FindBlockByID(MakeUserID(sc_parent_die->GetOffset()));
+ if (block == NULL)
+ {
+ // This must be a specification or abstract origin with
+ // a concrete block couterpart in the current function. We need
+ // to find the concrete block so we can correctly add the
+ // variable to it
+ DWARFCompileUnit *concrete_block_die_cu = dwarf_cu;
+ const DWARFDebugInfoEntry *concrete_block_die = FindBlockContainingSpecification (sc.function->GetID(),
+ sc_parent_die->GetOffset(),
+ &concrete_block_die_cu);
+ if (concrete_block_die)
+ block = sc.function->GetBlock(true).FindBlockByID(MakeUserID(concrete_block_die->GetOffset()));
+ }
+
+ if (block != NULL)
+ {
+ const bool can_create = false;
+ variable_list_sp = block->GetBlockVariableList (can_create);
+ if (variable_list_sp.get() == NULL)
+ {
+ variable_list_sp.reset(new VariableList());
+ block->SetVariableList(variable_list_sp);
+ }
+ }
+ }
+ break;
+
+ default:
+ GetObjectFile()->GetModule()->ReportError ("didn't find appropriate parent DIE for variable list for 0x%8.8" PRIx64 " %s.\n",
+ MakeUserID(orig_die->GetOffset()),
+ DW_TAG_value_to_name (orig_die->Tag()));
+ break;
+ }
+ }
+
+ if (variable_list_sp)
+ {
+ VariableSP var_sp (ParseVariableDIE(sc, dwarf_cu, die, func_low_pc));
+ if (var_sp)
+ {
+ variable_list_sp->AddVariableIfUnique (var_sp);
+ if (cc_variable_list)
+ cc_variable_list->AddVariableIfUnique (var_sp);
+ ++vars_added;
+ }
+ }
+ }
+ }
+
+ bool skip_children = (sc.function == NULL && tag == DW_TAG_subprogram);
+
+ if (!skip_children && parse_children && die->HasChildren())
+ {
+ vars_added += ParseVariables(sc, dwarf_cu, func_low_pc, die->GetFirstChild(), true, true, cc_variable_list);
+ }
+
+ if (parse_siblings)
+ die = die->GetSibling();
+ else
+ die = NULL;
+ }
+ return vars_added;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+ConstString
+SymbolFileDWARF::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SymbolFileDWARF::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+SymbolFileDWARF::CompleteTagDecl (void *baton, clang::TagDecl *decl)
+{
+ SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton;
+ ClangASTType clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl);
+ if (clang_type)
+ symbol_file_dwarf->ResolveClangOpaqueTypeDefinition (clang_type);
+}
+
+void
+SymbolFileDWARF::CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *decl)
+{
+ SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton;
+ ClangASTType clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl);
+ if (clang_type)
+ symbol_file_dwarf->ResolveClangOpaqueTypeDefinition (clang_type);
+}
+
+void
+SymbolFileDWARF::DumpIndexes ()
+{
+ StreamFile s(stdout, false);
+
+ s.Printf ("DWARF index for (%s) '%s':",
+ GetObjectFile()->GetModule()->GetArchitecture().GetArchitectureName(),
+ GetObjectFile()->GetFileSpec().GetPath().c_str());
+ s.Printf("\nFunction basenames:\n"); m_function_basename_index.Dump (&s);
+ s.Printf("\nFunction fullnames:\n"); m_function_fullname_index.Dump (&s);
+ s.Printf("\nFunction methods:\n"); m_function_method_index.Dump (&s);
+ s.Printf("\nFunction selectors:\n"); m_function_selector_index.Dump (&s);
+ s.Printf("\nObjective C class selectors:\n"); m_objc_class_selectors_index.Dump (&s);
+ s.Printf("\nGlobals and statics:\n"); m_global_index.Dump (&s);
+ s.Printf("\nTypes:\n"); m_type_index.Dump (&s);
+ s.Printf("\nNamepaces:\n"); m_namespace_index.Dump (&s);
+}
+
+void
+SymbolFileDWARF::SearchDeclContext (const clang::DeclContext *decl_context,
+ const char *name,
+ llvm::SmallVectorImpl <clang::NamedDecl *> *results)
+{
+ DeclContextToDIEMap::iterator iter = m_decl_ctx_to_die.find(decl_context);
+
+ if (iter == m_decl_ctx_to_die.end())
+ return;
+
+ for (DIEPointerSet::iterator pos = iter->second.begin(), end = iter->second.end(); pos != end; ++pos)
+ {
+ const DWARFDebugInfoEntry *context_die = *pos;
+
+ if (!results)
+ return;
+
+ DWARFDebugInfo* info = DebugInfo();
+
+ DIEArray die_offsets;
+
+ DWARFCompileUnit* dwarf_cu = NULL;
+ const DWARFDebugInfoEntry* die = NULL;
+
+ if (m_using_apple_tables)
+ {
+ if (m_apple_types_ap.get())
+ m_apple_types_ap->FindByName (name, die_offsets);
+ }
+ else
+ {
+ if (!m_indexed)
+ Index ();
+
+ m_type_index.Find (ConstString(name), die_offsets);
+ }
+
+ const size_t num_matches = die_offsets.size();
+
+ if (num_matches)
+ {
+ for (size_t i = 0; i < num_matches; ++i)
+ {
+ const dw_offset_t die_offset = die_offsets[i];
+ die = info->GetDIEPtrWithCompileUnitHint (die_offset, &dwarf_cu);
+
+ if (die->GetParent() != context_die)
+ continue;
+
+ Type *matching_type = ResolveType (dwarf_cu, die);
+
+ clang::QualType qual_type = matching_type->GetClangForwardType().GetQualType();
+
+ if (const clang::TagType *tag_type = llvm::dyn_cast<clang::TagType>(qual_type.getTypePtr()))
+ {
+ clang::TagDecl *tag_decl = tag_type->getDecl();
+ results->push_back(tag_decl);
+ }
+ else if (const clang::TypedefType *typedef_type = llvm::dyn_cast<clang::TypedefType>(qual_type.getTypePtr()))
+ {
+ clang::TypedefNameDecl *typedef_decl = typedef_type->getDecl();
+ results->push_back(typedef_decl);
+ }
+ }
+ }
+ }
+}
+
+void
+SymbolFileDWARF::FindExternalVisibleDeclsByName (void *baton,
+ const clang::DeclContext *decl_context,
+ clang::DeclarationName decl_name,
+ llvm::SmallVectorImpl <clang::NamedDecl *> *results)
+{
+
+ switch (decl_context->getDeclKind())
+ {
+ case clang::Decl::Namespace:
+ case clang::Decl::TranslationUnit:
+ {
+ SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton;
+ symbol_file_dwarf->SearchDeclContext (decl_context, decl_name.getAsString().c_str(), results);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+bool
+SymbolFileDWARF::LayoutRecordType (void *baton,
+ const clang::RecordDecl *record_decl,
+ uint64_t &size,
+ uint64_t &alignment,
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets)
+{
+ SymbolFileDWARF *symbol_file_dwarf = (SymbolFileDWARF *)baton;
+ return symbol_file_dwarf->LayoutRecordType (record_decl, size, alignment, field_offsets, base_offsets, vbase_offsets);
+}
+
+
+bool
+SymbolFileDWARF::LayoutRecordType (const clang::RecordDecl *record_decl,
+ uint64_t &bit_size,
+ uint64_t &alignment,
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets)
+{
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_INFO));
+ RecordDeclToLayoutMap::iterator pos = m_record_decl_to_layout_map.find (record_decl);
+ bool success = false;
+ base_offsets.clear();
+ vbase_offsets.clear();
+ if (pos != m_record_decl_to_layout_map.end())
+ {
+ bit_size = pos->second.bit_size;
+ alignment = pos->second.alignment;
+ field_offsets.swap(pos->second.field_offsets);
+ base_offsets.swap (pos->second.base_offsets);
+ vbase_offsets.swap (pos->second.vbase_offsets);
+ m_record_decl_to_layout_map.erase(pos);
+ success = true;
+ }
+ else
+ {
+ bit_size = 0;
+ alignment = 0;
+ field_offsets.clear();
+ }
+
+ if (log)
+ GetObjectFile()->GetModule()->LogMessage (log,
+ "SymbolFileDWARF::LayoutRecordType (record_decl = %p, bit_size = %" PRIu64 ", alignment = %" PRIu64 ", field_offsets[%u],base_offsets[%u], vbase_offsets[%u]) success = %i",
+ record_decl,
+ bit_size,
+ alignment,
+ (uint32_t)field_offsets.size(),
+ (uint32_t)base_offsets.size(),
+ (uint32_t)vbase_offsets.size(),
+ success);
+ return success;
+}
+
+
+SymbolFileDWARFDebugMap *
+SymbolFileDWARF::GetDebugMapSymfile ()
+{
+ if (m_debug_map_symfile == NULL && !m_debug_map_module_wp.expired())
+ {
+ lldb::ModuleSP module_sp (m_debug_map_module_wp.lock());
+ if (module_sp)
+ {
+ SymbolVendor *sym_vendor = module_sp->GetSymbolVendor();
+ if (sym_vendor)
+ m_debug_map_symfile = (SymbolFileDWARFDebugMap *)sym_vendor->GetSymbolFile();
+ }
+ }
+ return m_debug_map_symfile;
+}
+
+
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
new file mode 100644
index 000000000000..b6c6d94782db
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h
@@ -0,0 +1,622 @@
+//===-- SymbolFileDWARF.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_SymbolFileDWARF_h_
+#define SymbolFileDWARF_SymbolFileDWARF_h_
+
+// C Includes
+// C++ Includes
+#include <list>
+#include <map>
+#include <set>
+#include <vector>
+
+// Other libraries and framework includes
+#include "clang/AST/CharUnits.h"
+#include "clang/AST/ExternalASTSource.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/ClangForward.h"
+#include "lldb/Core/ConstString.h"
+#include "lldb/Core/dwarf.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Flags.h"
+#include "lldb/Core/UniqueCStringMap.h"
+#include "lldb/Symbol/ClangASTContext.h"
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+
+// Project includes
+#include "DWARFDefines.h"
+#include "HashedNameToDIE.h"
+#include "NameToDIE.h"
+#include "UniqueDWARFASTType.h"
+
+//----------------------------------------------------------------------
+// Forward Declarations for this DWARF plugin
+//----------------------------------------------------------------------
+class DebugMapModule;
+class DWARFAbbreviationDeclaration;
+class DWARFAbbreviationDeclarationSet;
+class DWARFileUnit;
+class DWARFDebugAbbrev;
+class DWARFDebugAranges;
+class DWARFDebugInfo;
+class DWARFDebugInfoEntry;
+class DWARFDebugLine;
+class DWARFDebugPubnames;
+class DWARFDebugRanges;
+class DWARFDeclContext;
+class DWARFDIECollection;
+class DWARFFormValue;
+class SymbolFileDWARFDebugMap;
+
+class SymbolFileDWARF : public lldb_private::SymbolFile, public lldb_private::UserID
+{
+public:
+ friend class SymbolFileDWARFDebugMap;
+ friend class DebugMapModule;
+ friend class DWARFCompileUnit;
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolFile*
+ CreateInstance (lldb_private::ObjectFile* obj_file);
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolFileDWARF(lldb_private::ObjectFile* ofile);
+ virtual ~SymbolFileDWARF();
+
+ virtual uint32_t CalculateAbilities ();
+ virtual void InitializeObject();
+
+ //------------------------------------------------------------------
+ // Compile Unit function calls
+ //------------------------------------------------------------------
+ virtual uint32_t GetNumCompileUnits();
+ virtual lldb::CompUnitSP ParseCompileUnitAtIndex(uint32_t index);
+
+ virtual lldb::LanguageType ParseCompileUnitLanguage (const lldb_private::SymbolContext& sc);
+ virtual size_t ParseCompileUnitFunctions (const lldb_private::SymbolContext& sc);
+ virtual bool ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc);
+ virtual bool ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList& support_files);
+ virtual size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc);
+ virtual size_t ParseTypes (const lldb_private::SymbolContext& sc);
+ virtual size_t ParseVariablesForContext (const lldb_private::SymbolContext& sc);
+
+ virtual lldb_private::Type* ResolveTypeUID(lldb::user_id_t type_uid);
+ virtual bool ResolveClangOpaqueTypeDefinition (lldb_private::ClangASTType& clang_type);
+
+ virtual lldb_private::Type* ResolveType (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry* type_die, bool assert_not_being_parsed = true);
+ virtual clang::DeclContext* GetClangDeclContextContainingTypeUID (lldb::user_id_t type_uid);
+ virtual clang::DeclContext* GetClangDeclContextForTypeUID (const lldb_private::SymbolContext &sc, lldb::user_id_t type_uid);
+
+ virtual uint32_t ResolveSymbolContext (const lldb_private::Address& so_addr, uint32_t resolve_scope, lldb_private::SymbolContext& sc);
+ virtual uint32_t ResolveSymbolContext (const lldb_private::FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindGlobalVariables(const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+ virtual uint32_t FindGlobalVariables(const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+ virtual uint32_t FindFunctions(const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindFunctions(const lldb_private::RegularExpression& regex, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindTypes (const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::TypeList& types);
+ virtual lldb_private::TypeList *
+ GetTypeList ();
+ virtual size_t GetTypes (lldb_private::SymbolContextScope *sc_scope,
+ uint32_t type_mask,
+ lldb_private::TypeList &type_list);
+
+ virtual lldb_private::ClangASTContext &
+ GetClangASTContext ();
+
+ virtual lldb_private::ClangNamespaceDecl
+ FindNamespace (const lldb_private::SymbolContext& sc,
+ const lldb_private::ConstString &name,
+ const lldb_private::ClangNamespaceDecl *parent_namespace_decl);
+
+
+ //------------------------------------------------------------------
+ // ClangASTContext callbacks for external source lookups.
+ //------------------------------------------------------------------
+ static void
+ CompleteTagDecl (void *baton, clang::TagDecl *);
+
+ static void
+ CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *);
+
+ static void
+ FindExternalVisibleDeclsByName (void *baton,
+ const clang::DeclContext *DC,
+ clang::DeclarationName Name,
+ llvm::SmallVectorImpl <clang::NamedDecl *> *results);
+
+ static bool
+ LayoutRecordType (void *baton,
+ const clang::RecordDecl *record_decl,
+ uint64_t &size,
+ uint64_t &alignment,
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets);
+
+ bool
+ LayoutRecordType (const clang::RecordDecl *record_decl,
+ uint64_t &size,
+ uint64_t &alignment,
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets);
+
+ struct LayoutInfo
+ {
+ LayoutInfo () :
+ bit_size(0),
+ alignment(0),
+ field_offsets(),
+ base_offsets(),
+ vbase_offsets()
+ {
+ }
+ uint64_t bit_size;
+ uint64_t alignment;
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> field_offsets;
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> base_offsets;
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> vbase_offsets;
+ };
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+ // Approach 2 - count + accessor
+ // Index compile units would scan the initial compile units and register
+ // them with the module. This would only be done on demand if and only if
+ // the compile units were needed.
+ //virtual size_t GetCompUnitCount() = 0;
+ //virtual CompUnitSP GetCompUnitAtIndex(size_t cu_idx) = 0;
+
+ const lldb_private::DataExtractor& get_debug_abbrev_data ();
+ const lldb_private::DataExtractor& get_debug_aranges_data ();
+ const lldb_private::DataExtractor& get_debug_frame_data ();
+ const lldb_private::DataExtractor& get_debug_info_data ();
+ const lldb_private::DataExtractor& get_debug_line_data ();
+ const lldb_private::DataExtractor& get_debug_loc_data ();
+ const lldb_private::DataExtractor& get_debug_ranges_data ();
+ const lldb_private::DataExtractor& get_debug_str_data ();
+ const lldb_private::DataExtractor& get_apple_names_data ();
+ const lldb_private::DataExtractor& get_apple_types_data ();
+ const lldb_private::DataExtractor& get_apple_namespaces_data ();
+ const lldb_private::DataExtractor& get_apple_objc_data ();
+
+
+ DWARFDebugAbbrev* DebugAbbrev();
+ const DWARFDebugAbbrev* DebugAbbrev() const;
+
+ DWARFDebugInfo* DebugInfo();
+ const DWARFDebugInfo* DebugInfo() const;
+
+ DWARFDebugRanges* DebugRanges();
+ const DWARFDebugRanges* DebugRanges() const;
+
+ const lldb_private::DataExtractor&
+ GetCachedSectionData (uint32_t got_flag,
+ lldb::SectionType sect_type,
+ lldb_private::DataExtractor &data);
+
+ static bool
+ SupportedVersion(uint16_t version);
+
+ clang::DeclContext *
+ GetCachedClangDeclContextForDIE (const DWARFDebugInfoEntry *die)
+ {
+ DIEToDeclContextMap::iterator pos = m_die_to_decl_ctx.find(die);
+ if (pos != m_die_to_decl_ctx.end())
+ return pos->second;
+ else
+ return NULL;
+ }
+
+ clang::DeclContext *
+ GetClangDeclContextForDIE (const lldb_private::SymbolContext &sc, DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die);
+
+ clang::DeclContext *
+ GetClangDeclContextForDIEOffset (const lldb_private::SymbolContext &sc, dw_offset_t die_offset);
+
+ clang::DeclContext *
+ GetClangDeclContextContainingDIE (DWARFCompileUnit *cu,
+ const DWARFDebugInfoEntry *die,
+ const DWARFDebugInfoEntry **decl_ctx_die);
+
+ clang::DeclContext *
+ GetClangDeclContextContainingDIEOffset (dw_offset_t die_offset);
+
+ const DWARFDebugInfoEntry *
+ GetDeclContextDIEContainingDIE (DWARFCompileUnit *cu, const DWARFDebugInfoEntry *die);
+
+ void
+ SearchDeclContext (const clang::DeclContext *decl_context,
+ const char *name,
+ llvm::SmallVectorImpl <clang::NamedDecl *> *results);
+
+ lldb_private::Flags&
+ GetFlags ()
+ {
+ return m_flags;
+ }
+
+ const lldb_private::Flags&
+ GetFlags () const
+ {
+ return m_flags;
+ }
+
+ bool
+ HasForwardDeclForClangType (const lldb_private::ClangASTType &clang_type);
+
+protected:
+
+ enum
+ {
+ flagsGotDebugAbbrevData = (1 << 0),
+ flagsGotDebugArangesData = (1 << 1),
+ flagsGotDebugFrameData = (1 << 2),
+ flagsGotDebugInfoData = (1 << 3),
+ flagsGotDebugLineData = (1 << 4),
+ flagsGotDebugLocData = (1 << 5),
+ flagsGotDebugMacInfoData = (1 << 6),
+ flagsGotDebugPubNamesData = (1 << 7),
+ flagsGotDebugPubTypesData = (1 << 8),
+ flagsGotDebugRangesData = (1 << 9),
+ flagsGotDebugStrData = (1 << 10),
+ flagsGotAppleNamesData = (1 << 11),
+ flagsGotAppleTypesData = (1 << 12),
+ flagsGotAppleNamespacesData = (1 << 13),
+ flagsGotAppleObjCData = (1 << 14)
+ };
+
+ bool NamespaceDeclMatchesThisSymbolFile (const lldb_private::ClangNamespaceDecl *namespace_decl);
+
+ bool DIEIsInNamespace (const lldb_private::ClangNamespaceDecl *namespace_decl,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry* die);
+
+ DISALLOW_COPY_AND_ASSIGN (SymbolFileDWARF);
+ lldb::CompUnitSP ParseCompileUnit (DWARFCompileUnit* dwarf_cu, uint32_t cu_idx);
+ DWARFCompileUnit* GetDWARFCompileUnit(lldb_private::CompileUnit *comp_unit);
+ DWARFCompileUnit* GetNextUnparsedDWARFCompileUnit(DWARFCompileUnit* prev_cu);
+ lldb_private::CompileUnit* GetCompUnitForDWARFCompUnit(DWARFCompileUnit* dwarf_cu, uint32_t cu_idx = UINT32_MAX);
+ bool GetFunction (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry* func_die, lldb_private::SymbolContext& sc);
+ lldb_private::Function * ParseCompileUnitFunction (const lldb_private::SymbolContext& sc, DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die);
+ size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc,
+ lldb_private::Block *parent_block,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ lldb::addr_t subprogram_low_pc,
+ uint32_t depth);
+ size_t ParseTypes (const lldb_private::SymbolContext& sc, DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool parse_siblings, bool parse_children);
+ lldb::TypeSP ParseType (const lldb_private::SymbolContext& sc, DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry *die, bool *type_is_new);
+ lldb_private::Type* ResolveTypeUID (DWARFCompileUnit* dwarf_cu, const DWARFDebugInfoEntry* die, bool assert_not_being_parsed);
+
+ lldb::VariableSP ParseVariableDIE(
+ const lldb_private::SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ const lldb::addr_t func_low_pc);
+
+ size_t ParseVariables(
+ const lldb_private::SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const lldb::addr_t func_low_pc,
+ const DWARFDebugInfoEntry *die,
+ bool parse_siblings,
+ bool parse_children,
+ lldb_private::VariableList* cc_variable_list = NULL);
+
+ class DelayedAddObjCClassProperty;
+ typedef std::vector <DelayedAddObjCClassProperty> DelayedPropertyList;
+
+ bool ClassOrStructIsVirtual (
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die);
+
+ size_t ParseChildMembers(
+ const lldb_private::SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ lldb_private::ClangASTType &class_clang_type,
+ const lldb::LanguageType class_language,
+ std::vector<clang::CXXBaseSpecifier *>& base_classes,
+ std::vector<int>& member_accessibilities,
+ DWARFDIECollection& member_function_dies,
+ DelayedPropertyList& delayed_properties,
+ lldb::AccessType &default_accessibility,
+ bool &is_a_class,
+ LayoutInfo &layout_info);
+
+ size_t ParseChildParameters(
+ const lldb_private::SymbolContext& sc,
+ clang::DeclContext *containing_decl_ctx,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ bool skip_artificial,
+ bool &is_static,
+ lldb_private::TypeList* type_list,
+ std::vector<lldb_private::ClangASTType>& function_args,
+ std::vector<clang::ParmVarDecl*>& function_param_decls,
+ unsigned &type_quals,
+ lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos);
+
+ size_t ParseChildEnumerators(
+ const lldb_private::SymbolContext& sc,
+ lldb_private::ClangASTType &clang_type,
+ bool is_signed,
+ uint32_t enumerator_byte_size,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *enum_die);
+
+ void ParseChildArrayInfo(
+ const lldb_private::SymbolContext& sc,
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ int64_t& first_index,
+ std::vector<uint64_t>& element_orders,
+ uint32_t& byte_stride,
+ uint32_t& bit_stride);
+
+ // Given a die_offset, figure out the symbol context representing that die.
+ bool ResolveFunction (dw_offset_t offset,
+ DWARFCompileUnit *&dwarf_cu,
+ lldb_private::SymbolContextList& sc_list);
+
+ bool ResolveFunction (DWARFCompileUnit *cu,
+ const DWARFDebugInfoEntry *die,
+ lldb_private::SymbolContextList& sc_list);
+
+ bool FunctionDieMatchesPartialName (
+ const DWARFDebugInfoEntry* die,
+ const DWARFCompileUnit *dwarf_cu,
+ uint32_t name_type_mask,
+ const char *partial_name,
+ const char *base_name_start,
+ const char *base_name_end);
+
+ void FindFunctions(
+ const lldb_private::ConstString &name,
+ const NameToDIE &name_to_die,
+ lldb_private::SymbolContextList& sc_list);
+
+ void FindFunctions (
+ const lldb_private::RegularExpression &regex,
+ const NameToDIE &name_to_die,
+ lldb_private::SymbolContextList& sc_list);
+
+ void FindFunctions (
+ const lldb_private::RegularExpression &regex,
+ const DWARFMappedHash::MemoryTable &memory_table,
+ lldb_private::SymbolContextList& sc_list);
+
+ lldb::TypeSP FindDefinitionTypeForDIE (
+ DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ const lldb_private::ConstString &type_name);
+
+ lldb::TypeSP FindDefinitionTypeForDWARFDeclContext (
+ const DWARFDeclContext &die_decl_ctx);
+
+ lldb::TypeSP FindCompleteObjCDefinitionTypeForDIE (
+ const DWARFDebugInfoEntry *die,
+ const lldb_private::ConstString &type_name,
+ bool must_be_implementation);
+
+ bool Supports_DW_AT_APPLE_objc_complete_type (DWARFCompileUnit *cu);
+
+ lldb::TypeSP FindCompleteObjCDefinitionType (const lldb_private::ConstString &type_name,
+ bool header_definition_ok);
+
+ lldb_private::Symbol * GetObjCClassSymbol (const lldb_private::ConstString &objc_class_name);
+
+ void ParseFunctions (const DIEArray &die_offsets,
+ lldb_private::SymbolContextList& sc_list);
+ lldb::TypeSP GetTypeForDIE (DWARFCompileUnit *cu,
+ const DWARFDebugInfoEntry* die);
+
+ uint32_t FindTypes(std::vector<dw_offset_t> die_offsets, uint32_t max_matches, lldb_private::TypeList& types);
+
+ void Index();
+
+ void DumpIndexes();
+
+ void SetDebugMapModule (const lldb::ModuleSP &module_sp)
+ {
+ m_debug_map_module_wp = module_sp;
+ }
+
+ SymbolFileDWARFDebugMap *
+ GetDebugMapSymfile ();
+
+ const DWARFDebugInfoEntry *
+ FindBlockContainingSpecification (dw_offset_t func_die_offset,
+ dw_offset_t spec_block_die_offset,
+ DWARFCompileUnit **dwarf_cu_handle);
+
+ const DWARFDebugInfoEntry *
+ FindBlockContainingSpecification (DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ dw_offset_t spec_block_die_offset,
+ DWARFCompileUnit **dwarf_cu_handle);
+
+ clang::NamespaceDecl *
+ ResolveNamespaceDIE (DWARFCompileUnit *curr_cu, const DWARFDebugInfoEntry *die);
+
+ UniqueDWARFASTTypeMap &
+ GetUniqueDWARFASTTypeMap ();
+
+ void LinkDeclContextToDIE (clang::DeclContext *decl_ctx,
+ const DWARFDebugInfoEntry *die)
+ {
+ m_die_to_decl_ctx[die] = decl_ctx;
+ // There can be many DIEs for a single decl context
+ m_decl_ctx_to_die[decl_ctx].insert(die);
+ }
+
+ bool
+ UserIDMatches (lldb::user_id_t uid) const
+ {
+ const lldb::user_id_t high_uid = uid & 0xffffffff00000000ull;
+ if (high_uid)
+ return high_uid == GetID();
+ return true;
+ }
+
+ lldb::user_id_t
+ MakeUserID (dw_offset_t die_offset) const
+ {
+ return GetID() | die_offset;
+ }
+
+ static bool
+ DeclKindIsCXXClass (clang::Decl::Kind decl_kind)
+ {
+ switch (decl_kind)
+ {
+ case clang::Decl::CXXRecord:
+ case clang::Decl::ClassTemplateSpecialization:
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+
+ bool
+ ParseTemplateParameterInfos (DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *parent_die,
+ lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos);
+
+ bool
+ ParseTemplateDIE (DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos);
+
+ clang::ClassTemplateDecl *
+ ParseClassTemplateDecl (clang::DeclContext *decl_ctx,
+ lldb::AccessType access_type,
+ const char *parent_name,
+ int tag_decl_kind,
+ const lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos);
+
+ bool
+ DIEDeclContextsMatch (DWARFCompileUnit* cu1, const DWARFDebugInfoEntry *die1,
+ DWARFCompileUnit* cu2, const DWARFDebugInfoEntry *die2);
+
+ bool
+ ClassContainsSelector (DWARFCompileUnit *dwarf_cu,
+ const DWARFDebugInfoEntry *class_die,
+ const lldb_private::ConstString &selector);
+
+ bool
+ CopyUniqueClassMethodTypes (SymbolFileDWARF *class_symfile,
+ lldb_private::Type *class_type,
+ DWARFCompileUnit* src_cu,
+ const DWARFDebugInfoEntry *src_class_die,
+ DWARFCompileUnit* dst_cu,
+ const DWARFDebugInfoEntry *dst_class_die,
+ llvm::SmallVectorImpl <const DWARFDebugInfoEntry *> &failures);
+
+ bool
+ FixupAddress (lldb_private::Address &addr);
+
+ typedef std::set<lldb_private::Type *> TypeSet;
+
+ void
+ GetTypes (DWARFCompileUnit* dwarf_cu,
+ const DWARFDebugInfoEntry *die,
+ dw_offset_t min_die_offset,
+ dw_offset_t max_die_offset,
+ uint32_t type_mask,
+ TypeSet &type_set);
+
+ lldb::ModuleWP m_debug_map_module_wp;
+ SymbolFileDWARFDebugMap * m_debug_map_symfile;
+ clang::TranslationUnitDecl * m_clang_tu_decl;
+ lldb_private::Flags m_flags;
+ lldb_private::DataExtractor m_dwarf_data;
+ lldb_private::DataExtractor m_data_debug_abbrev;
+ lldb_private::DataExtractor m_data_debug_aranges;
+ lldb_private::DataExtractor m_data_debug_frame;
+ lldb_private::DataExtractor m_data_debug_info;
+ lldb_private::DataExtractor m_data_debug_line;
+ lldb_private::DataExtractor m_data_debug_loc;
+ lldb_private::DataExtractor m_data_debug_ranges;
+ lldb_private::DataExtractor m_data_debug_str;
+ lldb_private::DataExtractor m_data_apple_names;
+ lldb_private::DataExtractor m_data_apple_types;
+ lldb_private::DataExtractor m_data_apple_namespaces;
+ lldb_private::DataExtractor m_data_apple_objc;
+
+ // The unique pointer items below are generated on demand if and when someone accesses
+ // them through a non const version of this class.
+ std::unique_ptr<DWARFDebugAbbrev> m_abbr;
+ std::unique_ptr<DWARFDebugInfo> m_info;
+ std::unique_ptr<DWARFDebugLine> m_line;
+ std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_names_ap;
+ std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_types_ap;
+ std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_namespaces_ap;
+ std::unique_ptr<DWARFMappedHash::MemoryTable> m_apple_objc_ap;
+ NameToDIE m_function_basename_index; // All concrete functions
+ NameToDIE m_function_fullname_index; // All concrete functions
+ NameToDIE m_function_method_index; // All inlined functions
+ NameToDIE m_function_selector_index; // All method names for functions of classes
+ NameToDIE m_objc_class_selectors_index; // Given a class name, find all selectors for the class
+ NameToDIE m_global_index; // Global and static variables
+ NameToDIE m_type_index; // All type DIE offsets
+ NameToDIE m_namespace_index; // All type DIE offsets
+ bool m_indexed:1,
+ m_is_external_ast_source:1,
+ m_using_apple_tables:1;
+ lldb_private::LazyBool m_supports_DW_AT_APPLE_objc_complete_type;
+
+ std::unique_ptr<DWARFDebugRanges> m_ranges;
+ UniqueDWARFASTTypeMap m_unique_ast_type_map;
+ typedef llvm::SmallPtrSet<const DWARFDebugInfoEntry *, 4> DIEPointerSet;
+ typedef llvm::DenseMap<const DWARFDebugInfoEntry *, clang::DeclContext *> DIEToDeclContextMap;
+ typedef llvm::DenseMap<const clang::DeclContext *, DIEPointerSet> DeclContextToDIEMap;
+ typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb_private::Type *> DIEToTypePtr;
+ typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::VariableSP> DIEToVariableSP;
+ typedef llvm::DenseMap<const DWARFDebugInfoEntry *, lldb::clang_type_t> DIEToClangType;
+ typedef llvm::DenseMap<lldb::clang_type_t, const DWARFDebugInfoEntry *> ClangTypeToDIE;
+ typedef llvm::DenseMap<const clang::RecordDecl *, LayoutInfo> RecordDeclToLayoutMap;
+ DIEToDeclContextMap m_die_to_decl_ctx;
+ DeclContextToDIEMap m_decl_ctx_to_die;
+ DIEToTypePtr m_die_to_type;
+ DIEToVariableSP m_die_to_variable_sp;
+ DIEToClangType m_forward_decl_die_to_clang_type;
+ ClangTypeToDIE m_forward_decl_clang_type_to_die;
+ RecordDeclToLayoutMap m_record_decl_to_layout_map;
+};
+
+#endif // SymbolFileDWARF_SymbolFileDWARF_h_
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
new file mode 100644
index 000000000000..a0430e3d52b6
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.cpp
@@ -0,0 +1,1586 @@
+//===-- SymbolFileDWARFDebugMap.cpp ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileDWARFDebugMap.h"
+
+#include "DWARFDebugAranges.h"
+
+#include "lldb/Core/RangeMap.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleList.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Section.h"
+
+//#define DEBUG_OSO_DMAP // DO NOT CHECKIN WITH THIS NOT COMMENTED OUT
+#if defined(DEBUG_OSO_DMAP)
+#include "lldb/Core/StreamFile.h"
+#endif
+#include "lldb/Core/Timer.h"
+
+#include "lldb/Symbol/ClangExternalASTSourceCallbacks.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/LineTable.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolVendor.h"
+#include "lldb/Symbol/VariableList.h"
+
+#include "LogChannelDWARF.h"
+#include "SymbolFileDWARF.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+// Subclass lldb_private::Module so we can intercept the "Module::GetObjectFile()"
+// (so we can fixup the object file sections) and also for "Module::GetSymbolVendor()"
+// (so we can fixup the symbol file id.
+
+
+
+
+const SymbolFileDWARFDebugMap::FileRangeMap &
+SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap(SymbolFileDWARFDebugMap *exe_symfile)
+{
+ if (file_range_map_valid)
+ return file_range_map;
+
+ file_range_map_valid = true;
+
+ Module *oso_module = exe_symfile->GetModuleByCompUnitInfo (this);
+ if (!oso_module)
+ return file_range_map;
+
+ ObjectFile *oso_objfile = oso_module->GetObjectFile();
+ if (!oso_objfile)
+ return file_range_map;
+
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_MAP));
+ if (log)
+ {
+ ConstString object_name (oso_module->GetObjectName());
+ log->Printf("%p: SymbolFileDWARFDebugMap::CompileUnitInfo::GetFileRangeMap ('%s')",
+ this,
+ oso_module->GetSpecificationDescription().c_str());
+ }
+
+
+ std::vector<SymbolFileDWARFDebugMap::CompileUnitInfo *> cu_infos;
+ if (exe_symfile->GetCompUnitInfosForModule(oso_module, cu_infos))
+ {
+ for (auto comp_unit_info : cu_infos)
+ {
+ Symtab *exe_symtab = exe_symfile->GetObjectFile()->GetSymtab();
+ ModuleSP oso_module_sp (oso_objfile->GetModule());
+ Symtab *oso_symtab = oso_objfile->GetSymtab();
+
+ ///const uint32_t fun_resolve_flags = SymbolContext::Module | eSymbolContextCompUnit | eSymbolContextFunction;
+ //SectionList *oso_sections = oso_objfile->Sections();
+ // Now we need to make sections that map from zero based object
+ // file addresses to where things eneded up in the main executable.
+
+ assert (comp_unit_info->first_symbol_index != UINT32_MAX);
+ // End index is one past the last valid symbol index
+ const uint32_t oso_end_idx = comp_unit_info->last_symbol_index + 1;
+ for (uint32_t idx = comp_unit_info->first_symbol_index + 2; // Skip the N_SO and N_OSO
+ idx < oso_end_idx;
+ ++idx)
+ {
+ Symbol *exe_symbol = exe_symtab->SymbolAtIndex(idx);
+ if (exe_symbol)
+ {
+ if (exe_symbol->IsDebug() == false)
+ continue;
+
+ switch (exe_symbol->GetType())
+ {
+ default:
+ break;
+
+ case eSymbolTypeCode:
+ {
+ // For each N_FUN, or function that we run into in the debug map
+ // we make a new section that we add to the sections found in the
+ // .o file. This new section has the file address set to what the
+ // addresses are in the .o file, and the load address is adjusted
+ // to match where it ended up in the final executable! We do this
+ // before we parse any dwarf info so that when it goes get parsed
+ // all section/offset addresses that get registered will resolve
+ // correctly to the new addresses in the main executable.
+
+ // First we find the original symbol in the .o file's symbol table
+ Symbol *oso_fun_symbol = oso_symtab->FindFirstSymbolWithNameAndType (exe_symbol->GetMangled().GetName(Mangled::ePreferMangled),
+ eSymbolTypeCode,
+ Symtab::eDebugNo,
+ Symtab::eVisibilityAny);
+ if (oso_fun_symbol)
+ {
+ // Add the inverse OSO file address to debug map entry mapping
+ exe_symfile->AddOSOFileRange (this,
+ exe_symbol->GetAddress().GetFileAddress(),
+ oso_fun_symbol->GetAddress().GetFileAddress(),
+ std::min<addr_t>(exe_symbol->GetByteSize(), oso_fun_symbol->GetByteSize()));
+
+ }
+ }
+ break;
+
+ case eSymbolTypeData:
+ {
+ // For each N_GSYM we remap the address for the global by making
+ // a new section that we add to the sections found in the .o file.
+ // This new section has the file address set to what the
+ // addresses are in the .o file, and the load address is adjusted
+ // to match where it ended up in the final executable! We do this
+ // before we parse any dwarf info so that when it goes get parsed
+ // all section/offset addresses that get registered will resolve
+ // correctly to the new addresses in the main executable. We
+ // initially set the section size to be 1 byte, but will need to
+ // fix up these addresses further after all globals have been
+ // parsed to span the gaps, or we can find the global variable
+ // sizes from the DWARF info as we are parsing.
+
+ // Next we find the non-stab entry that corresponds to the N_GSYM in the .o file
+ Symbol *oso_gsym_symbol = oso_symtab->FindFirstSymbolWithNameAndType (exe_symbol->GetMangled().GetName(Mangled::ePreferMangled),
+ eSymbolTypeData,
+ Symtab::eDebugNo,
+ Symtab::eVisibilityAny);
+
+ if (exe_symbol && oso_gsym_symbol &&
+ exe_symbol->ValueIsAddress() &&
+ oso_gsym_symbol->ValueIsAddress())
+ {
+ // Add the inverse OSO file address to debug map entry mapping
+ exe_symfile->AddOSOFileRange (this,
+ exe_symbol->GetAddress().GetFileAddress(),
+ oso_gsym_symbol->GetAddress().GetFileAddress(),
+ std::min<addr_t>(exe_symbol->GetByteSize(), oso_gsym_symbol->GetByteSize()));
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ exe_symfile->FinalizeOSOFileRanges (this);
+ // We don't need the symbols anymore for the .o files
+ oso_objfile->ClearSymtab();
+ }
+ }
+ return file_range_map;
+}
+
+
+class DebugMapModule : public Module
+{
+public:
+ DebugMapModule (const ModuleSP &exe_module_sp,
+ uint32_t cu_idx,
+ const FileSpec& file_spec,
+ const ArchSpec& arch,
+ const ConstString *object_name,
+ off_t object_offset,
+ const TimeValue *object_mod_time_ptr) :
+ Module (file_spec, arch, object_name, object_offset, object_mod_time_ptr),
+ m_exe_module_wp (exe_module_sp),
+ m_cu_idx (cu_idx)
+ {
+ }
+
+ virtual
+ ~DebugMapModule ()
+ {
+ }
+
+
+ virtual SymbolVendor*
+ GetSymbolVendor(bool can_create = true, lldb_private::Stream *feedback_strm = NULL)
+ {
+ // Scope for locker
+ if (m_symfile_ap.get() || can_create == false)
+ return m_symfile_ap.get();
+
+ ModuleSP exe_module_sp (m_exe_module_wp.lock());
+ if (exe_module_sp)
+ {
+ // Now get the object file outside of a locking scope
+ ObjectFile *oso_objfile = GetObjectFile ();
+ if (oso_objfile)
+ {
+ Mutex::Locker locker (m_mutex);
+ SymbolVendor* symbol_vendor = Module::GetSymbolVendor(can_create, feedback_strm);
+ if (symbol_vendor)
+ {
+ // Set a a pointer to this class to set our OSO DWARF file know
+ // that the DWARF is being used along with a debug map and that
+ // it will have the remapped sections that we do below.
+ SymbolFileDWARF *oso_symfile = SymbolFileDWARFDebugMap::GetSymbolFileAsSymbolFileDWARF(symbol_vendor->GetSymbolFile());
+
+ if (!oso_symfile)
+ return NULL;
+
+ ObjectFile *exe_objfile = exe_module_sp->GetObjectFile();
+ SymbolVendor *exe_sym_vendor = exe_module_sp->GetSymbolVendor();
+
+ if (exe_objfile && exe_sym_vendor)
+ {
+ if (oso_symfile->GetNumCompileUnits() == 1)
+ {
+ oso_symfile->SetDebugMapModule(exe_module_sp);
+ // Set the ID of the symbol file DWARF to the index of the OSO
+ // shifted left by 32 bits to provide a unique prefix for any
+ // UserID's that get created in the symbol file.
+ oso_symfile->SetID (((uint64_t)m_cu_idx + 1ull) << 32ull);
+ }
+ else
+ {
+ oso_symfile->SetID (UINT64_MAX);
+ }
+ }
+ return symbol_vendor;
+ }
+ }
+ }
+ return NULL;
+ }
+
+protected:
+ ModuleWP m_exe_module_wp;
+ const uint32_t m_cu_idx;
+};
+
+void
+SymbolFileDWARFDebugMap::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SymbolFileDWARFDebugMap::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+SymbolFileDWARFDebugMap::GetPluginNameStatic()
+{
+ static ConstString g_name("dwarf-debugmap");
+ return g_name;
+}
+
+const char *
+SymbolFileDWARFDebugMap::GetPluginDescriptionStatic()
+{
+ return "DWARF and DWARF3 debug symbol file reader (debug map).";
+}
+
+SymbolFile*
+SymbolFileDWARFDebugMap::CreateInstance (ObjectFile* obj_file)
+{
+ return new SymbolFileDWARFDebugMap (obj_file);
+}
+
+
+SymbolFileDWARFDebugMap::SymbolFileDWARFDebugMap (ObjectFile* ofile) :
+ SymbolFile(ofile),
+ m_flags(),
+ m_compile_unit_infos(),
+ m_func_indexes(),
+ m_glob_indexes(),
+ m_supports_DW_AT_APPLE_objc_complete_type (eLazyBoolCalculate)
+{
+}
+
+
+SymbolFileDWARFDebugMap::~SymbolFileDWARFDebugMap()
+{
+}
+
+void
+SymbolFileDWARFDebugMap::InitializeObject()
+{
+ // Install our external AST source callbacks so we can complete Clang types.
+ llvm::OwningPtr<clang::ExternalASTSource> ast_source_ap (
+ new ClangExternalASTSourceCallbacks (SymbolFileDWARFDebugMap::CompleteTagDecl,
+ SymbolFileDWARFDebugMap::CompleteObjCInterfaceDecl,
+ NULL,
+ SymbolFileDWARFDebugMap::LayoutRecordType,
+ this));
+
+ GetClangASTContext().SetExternalSource (ast_source_ap);
+}
+
+void
+SymbolFileDWARFDebugMap::InitOSO()
+{
+ if (m_flags.test(kHaveInitializedOSOs))
+ return;
+
+ m_flags.set(kHaveInitializedOSOs);
+
+ // If the object file has been stripped, there is no sense in looking further
+ // as all of the debug symbols for the debug map will not be available
+ if (m_obj_file->IsStripped())
+ return;
+
+ // Also make sure the file type is some sort of executable. Core files, debug
+ // info files (dSYM), object files (.o files), and stub libraries all can
+ switch (m_obj_file->GetType())
+ {
+ case ObjectFile::eTypeInvalid:
+ case ObjectFile::eTypeCoreFile:
+ case ObjectFile::eTypeDebugInfo:
+ case ObjectFile::eTypeObjectFile:
+ case ObjectFile::eTypeStubLibrary:
+ case ObjectFile::eTypeUnknown:
+ return;
+
+ case ObjectFile::eTypeExecutable:
+ case ObjectFile::eTypeDynamicLinker:
+ case ObjectFile::eTypeSharedLibrary:
+ break;
+ }
+
+ // In order to get the abilities of this plug-in, we look at the list of
+ // N_OSO entries (object files) from the symbol table and make sure that
+ // these files exist and also contain valid DWARF. If we get any of that
+ // then we return the abilities of the first N_OSO's DWARF.
+
+ Symtab* symtab = m_obj_file->GetSymtab();
+ if (symtab)
+ {
+ Log *log (LogChannelDWARF::GetLogIfAll(DWARF_LOG_DEBUG_MAP));
+
+ std::vector<uint32_t> oso_indexes;
+ // When a mach-o symbol is encoded, the n_type field is encoded in bits
+ // 23:16, and the n_desc field is encoded in bits 15:0.
+ //
+ // To find all N_OSO entries that are part of the DWARF + debug map
+ // we find only object file symbols with the flags value as follows:
+ // bits 23:16 == 0x66 (N_OSO)
+ // bits 15: 0 == 0x0001 (specifies this is a debug map object file)
+ const uint32_t k_oso_symbol_flags_value = 0x660001u;
+
+ const uint32_t oso_index_count = symtab->AppendSymbolIndexesWithTypeAndFlagsValue(eSymbolTypeObjectFile, k_oso_symbol_flags_value, oso_indexes);
+
+ if (oso_index_count > 0)
+ {
+ symtab->AppendSymbolIndexesWithType (eSymbolTypeCode, Symtab::eDebugYes, Symtab::eVisibilityAny, m_func_indexes);
+ symtab->AppendSymbolIndexesWithType (eSymbolTypeData, Symtab::eDebugYes, Symtab::eVisibilityAny, m_glob_indexes);
+
+ symtab->SortSymbolIndexesByValue(m_func_indexes, true);
+ symtab->SortSymbolIndexesByValue(m_glob_indexes, true);
+
+ for (uint32_t sym_idx : m_func_indexes)
+ {
+ const Symbol *symbol = symtab->SymbolAtIndex(sym_idx);
+ lldb::addr_t file_addr = symbol->GetAddress().GetFileAddress();
+ lldb::addr_t byte_size = symbol->GetByteSize();
+ DebugMap::Entry debug_map_entry(file_addr, byte_size, OSOEntry(sym_idx, LLDB_INVALID_ADDRESS));
+ m_debug_map.Append(debug_map_entry);
+ }
+ for (uint32_t sym_idx : m_glob_indexes)
+ {
+ const Symbol *symbol = symtab->SymbolAtIndex(sym_idx);
+ lldb::addr_t file_addr = symbol->GetAddress().GetFileAddress();
+ lldb::addr_t byte_size = symbol->GetByteSize();
+ DebugMap::Entry debug_map_entry(file_addr, byte_size, OSOEntry(sym_idx, LLDB_INVALID_ADDRESS));
+ m_debug_map.Append(debug_map_entry);
+ }
+ m_debug_map.Sort();
+
+ m_compile_unit_infos.resize(oso_index_count);
+
+ for (uint32_t i=0; i<oso_index_count; ++i)
+ {
+ const uint32_t so_idx = oso_indexes[i] - 1;
+ const uint32_t oso_idx = oso_indexes[i];
+ const Symbol *so_symbol = symtab->SymbolAtIndex(so_idx);
+ const Symbol *oso_symbol = symtab->SymbolAtIndex(oso_idx);
+ if (so_symbol &&
+ oso_symbol &&
+ so_symbol->GetType() == eSymbolTypeSourceFile &&
+ oso_symbol->GetType() == eSymbolTypeObjectFile)
+ {
+ m_compile_unit_infos[i].so_file.SetFile(so_symbol->GetName().AsCString(), false);
+ m_compile_unit_infos[i].oso_path = oso_symbol->GetName();
+ TimeValue oso_mod_time;
+ oso_mod_time.OffsetWithSeconds(oso_symbol->GetAddress().GetOffset());
+ m_compile_unit_infos[i].oso_mod_time = oso_mod_time;
+ uint32_t sibling_idx = so_symbol->GetSiblingIndex();
+ // The sibling index can't be less that or equal to the current index "i"
+ if (sibling_idx <= i)
+ {
+ m_obj_file->GetModule()->ReportError ("N_SO in symbol with UID %u has invalid sibling in debug map, please file a bug and attach the binary listed in this error", so_symbol->GetID());
+ }
+ else
+ {
+ const Symbol* last_symbol = symtab->SymbolAtIndex (sibling_idx - 1);
+ m_compile_unit_infos[i].first_symbol_index = so_idx;
+ m_compile_unit_infos[i].last_symbol_index = sibling_idx - 1;
+ m_compile_unit_infos[i].first_symbol_id = so_symbol->GetID();
+ m_compile_unit_infos[i].last_symbol_id = last_symbol->GetID();
+
+ if (log)
+ log->Printf("Initialized OSO 0x%8.8x: file=%s", i, oso_symbol->GetName().GetCString());
+ }
+ }
+ else
+ {
+ if (oso_symbol == NULL)
+ m_obj_file->GetModule()->ReportError ("N_OSO symbol[%u] can't be found, please file a bug and attach the binary listed in this error", oso_idx);
+ else if (so_symbol == NULL)
+ m_obj_file->GetModule()->ReportError ("N_SO not found for N_OSO symbol[%u], please file a bug and attach the binary listed in this error", oso_idx);
+ else if (so_symbol->GetType() != eSymbolTypeSourceFile)
+ m_obj_file->GetModule()->ReportError ("N_SO has incorrect symbol type (%u) for N_OSO symbol[%u], please file a bug and attach the binary listed in this error", so_symbol->GetType(), oso_idx);
+ else if (oso_symbol->GetType() != eSymbolTypeSourceFile)
+ m_obj_file->GetModule()->ReportError ("N_OSO has incorrect symbol type (%u) for N_OSO symbol[%u], please file a bug and attach the binary listed in this error", oso_symbol->GetType(), oso_idx);
+ }
+ }
+ }
+ }
+}
+
+Module *
+SymbolFileDWARFDebugMap::GetModuleByOSOIndex (uint32_t oso_idx)
+{
+ const uint32_t cu_count = GetNumCompileUnits();
+ if (oso_idx < cu_count)
+ return GetModuleByCompUnitInfo (&m_compile_unit_infos[oso_idx]);
+ return NULL;
+}
+
+Module *
+SymbolFileDWARFDebugMap::GetModuleByCompUnitInfo (CompileUnitInfo *comp_unit_info)
+{
+ if (!comp_unit_info->oso_sp)
+ {
+ auto pos = m_oso_map.find (comp_unit_info->oso_path);
+ if (pos != m_oso_map.end())
+ {
+ comp_unit_info->oso_sp = pos->second;
+ }
+ else
+ {
+ ObjectFile *obj_file = GetObjectFile();
+ comp_unit_info->oso_sp.reset (new OSOInfo());
+ m_oso_map[comp_unit_info->oso_path] = comp_unit_info->oso_sp;
+ const char *oso_path = comp_unit_info->oso_path.GetCString();
+ FileSpec oso_file (oso_path, false);
+ ConstString oso_object;
+ if (oso_file.Exists())
+ {
+ TimeValue oso_mod_time (oso_file.GetModificationTime());
+ if (oso_mod_time != comp_unit_info->oso_mod_time)
+ {
+ obj_file->GetModule()->ReportError ("debug map object file '%s' has changed (actual time is 0x%" PRIx64 ", debug map time is 0x%" PRIx64 ") since this executable was linked, file will be ignored",
+ oso_file.GetPath().c_str(),
+ oso_mod_time.GetAsSecondsSinceJan1_1970(),
+ comp_unit_info->oso_mod_time.GetAsSecondsSinceJan1_1970());
+ return NULL;
+ }
+
+ }
+ else
+ {
+ const bool must_exist = true;
+
+ if (!ObjectFile::SplitArchivePathWithObject (oso_path,
+ oso_file,
+ oso_object,
+ must_exist))
+ {
+ return NULL;
+ }
+ }
+ // Always create a new module for .o files. Why? Because we
+ // use the debug map, to add new sections to each .o file and
+ // even though a .o file might not have changed, the sections
+ // that get added to the .o file can change.
+ comp_unit_info->oso_sp->module_sp.reset (new DebugMapModule (obj_file->GetModule(),
+ GetCompUnitInfoIndex(comp_unit_info),
+ oso_file,
+ m_obj_file->GetModule()->GetArchitecture(),
+ oso_object ? &oso_object : NULL,
+ 0,
+ oso_object ? &comp_unit_info->oso_mod_time : NULL));
+ }
+ }
+ if (comp_unit_info->oso_sp)
+ return comp_unit_info->oso_sp->module_sp.get();
+ return NULL;
+}
+
+
+bool
+SymbolFileDWARFDebugMap::GetFileSpecForSO (uint32_t oso_idx, FileSpec &file_spec)
+{
+ if (oso_idx < m_compile_unit_infos.size())
+ {
+ if (m_compile_unit_infos[oso_idx].so_file)
+ {
+ file_spec = m_compile_unit_infos[oso_idx].so_file;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+
+ObjectFile *
+SymbolFileDWARFDebugMap::GetObjectFileByOSOIndex (uint32_t oso_idx)
+{
+ Module *oso_module = GetModuleByOSOIndex (oso_idx);
+ if (oso_module)
+ return oso_module->GetObjectFile();
+ return NULL;
+}
+
+SymbolFileDWARF *
+SymbolFileDWARFDebugMap::GetSymbolFile (const SymbolContext& sc)
+{
+ CompileUnitInfo *comp_unit_info = GetCompUnitInfo (sc);
+ if (comp_unit_info)
+ return GetSymbolFileByCompUnitInfo (comp_unit_info);
+ return NULL;
+}
+
+ObjectFile *
+SymbolFileDWARFDebugMap::GetObjectFileByCompUnitInfo (CompileUnitInfo *comp_unit_info)
+{
+ Module *oso_module = GetModuleByCompUnitInfo (comp_unit_info);
+ if (oso_module)
+ return oso_module->GetObjectFile();
+ return NULL;
+}
+
+
+uint32_t
+SymbolFileDWARFDebugMap::GetCompUnitInfoIndex (const CompileUnitInfo *comp_unit_info)
+{
+ if (!m_compile_unit_infos.empty())
+ {
+ const CompileUnitInfo *first_comp_unit_info = &m_compile_unit_infos.front();
+ const CompileUnitInfo *last_comp_unit_info = &m_compile_unit_infos.back();
+ if (first_comp_unit_info <= comp_unit_info && comp_unit_info <= last_comp_unit_info)
+ return comp_unit_info - first_comp_unit_info;
+ }
+ return UINT32_MAX;
+}
+
+SymbolFileDWARF *
+SymbolFileDWARFDebugMap::GetSymbolFileByOSOIndex (uint32_t oso_idx)
+{
+ if (oso_idx < m_compile_unit_infos.size())
+ return GetSymbolFileByCompUnitInfo (&m_compile_unit_infos[oso_idx]);
+ return NULL;
+}
+
+SymbolFileDWARF *
+SymbolFileDWARFDebugMap::GetSymbolFileAsSymbolFileDWARF (SymbolFile *sym_file)
+{
+ if (sym_file && sym_file->GetPluginName() == SymbolFileDWARF::GetPluginNameStatic())
+ return (SymbolFileDWARF *)sym_file;
+ return NULL;
+}
+
+SymbolFileDWARF *
+SymbolFileDWARFDebugMap::GetSymbolFileByCompUnitInfo (CompileUnitInfo *comp_unit_info)
+{
+ Module *oso_module = GetModuleByCompUnitInfo (comp_unit_info);
+ if (oso_module)
+ {
+ SymbolVendor *sym_vendor = oso_module->GetSymbolVendor();
+ if (sym_vendor)
+ return GetSymbolFileAsSymbolFileDWARF (sym_vendor->GetSymbolFile());
+ }
+ return NULL;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::CalculateAbilities ()
+{
+ // In order to get the abilities of this plug-in, we look at the list of
+ // N_OSO entries (object files) from the symbol table and make sure that
+ // these files exist and also contain valid DWARF. If we get any of that
+ // then we return the abilities of the first N_OSO's DWARF.
+
+ const uint32_t oso_index_count = GetNumCompileUnits();
+ if (oso_index_count > 0)
+ {
+ InitOSO();
+ if (!m_compile_unit_infos.empty())
+ {
+ return SymbolFile::CompileUnits |
+ SymbolFile::Functions |
+ SymbolFile::Blocks |
+ SymbolFile::GlobalVariables |
+ SymbolFile::LocalVariables |
+ SymbolFile::VariableTypes |
+ SymbolFile::LineTables ;
+ }
+ }
+ return 0;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::GetNumCompileUnits()
+{
+ InitOSO ();
+ return m_compile_unit_infos.size();
+}
+
+
+CompUnitSP
+SymbolFileDWARFDebugMap::ParseCompileUnitAtIndex(uint32_t cu_idx)
+{
+ CompUnitSP comp_unit_sp;
+ const uint32_t cu_count = GetNumCompileUnits();
+
+ if (cu_idx < cu_count)
+ {
+ Module *oso_module = GetModuleByCompUnitInfo (&m_compile_unit_infos[cu_idx]);
+ if (oso_module)
+ {
+ FileSpec so_file_spec;
+ if (GetFileSpecForSO (cu_idx, so_file_spec))
+ {
+ // User zero as the ID to match the compile unit at offset
+ // zero in each .o file since each .o file can only have
+ // one compile unit for now.
+ lldb::user_id_t cu_id = 0;
+ m_compile_unit_infos[cu_idx].compile_unit_sp.reset(new CompileUnit (m_obj_file->GetModule(),
+ NULL,
+ so_file_spec,
+ cu_id,
+ eLanguageTypeUnknown));
+
+ if (m_compile_unit_infos[cu_idx].compile_unit_sp)
+ {
+ // Let our symbol vendor know about this compile unit
+ m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex (cu_idx, m_compile_unit_infos[cu_idx].compile_unit_sp);
+ }
+ }
+ }
+ comp_unit_sp = m_compile_unit_infos[cu_idx].compile_unit_sp;
+ }
+
+ return comp_unit_sp;
+}
+
+SymbolFileDWARFDebugMap::CompileUnitInfo *
+SymbolFileDWARFDebugMap::GetCompUnitInfo (const SymbolContext& sc)
+{
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t i=0; i<cu_count; ++i)
+ {
+ if (sc.comp_unit == m_compile_unit_infos[i].compile_unit_sp.get())
+ return &m_compile_unit_infos[i];
+ }
+ return NULL;
+}
+
+
+size_t
+SymbolFileDWARFDebugMap::GetCompUnitInfosForModule (const lldb_private::Module *module, std::vector<CompileUnitInfo *>& cu_infos)
+{
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t i=0; i<cu_count; ++i)
+ {
+ if (module == GetModuleByCompUnitInfo (&m_compile_unit_infos[i]))
+ cu_infos.push_back (&m_compile_unit_infos[i]);
+ }
+ return cu_infos.size();
+}
+
+lldb::LanguageType
+SymbolFileDWARFDebugMap::ParseCompileUnitLanguage (const SymbolContext& sc)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseCompileUnitLanguage (sc);
+ return eLanguageTypeUnknown;
+}
+
+size_t
+SymbolFileDWARFDebugMap::ParseCompileUnitFunctions (const SymbolContext& sc)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseCompileUnitFunctions (sc);
+ return 0;
+}
+
+bool
+SymbolFileDWARFDebugMap::ParseCompileUnitLineTable (const SymbolContext& sc)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseCompileUnitLineTable (sc);
+ return false;
+}
+
+bool
+SymbolFileDWARFDebugMap::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList &support_files)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseCompileUnitSupportFiles (sc, support_files);
+ return false;
+}
+
+
+size_t
+SymbolFileDWARFDebugMap::ParseFunctionBlocks (const SymbolContext& sc)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseFunctionBlocks (sc);
+ return 0;
+}
+
+
+size_t
+SymbolFileDWARFDebugMap::ParseTypes (const SymbolContext& sc)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseTypes (sc);
+ return 0;
+}
+
+
+size_t
+SymbolFileDWARFDebugMap::ParseVariablesForContext (const SymbolContext& sc)
+{
+ SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->ParseVariablesForContext (sc);
+ return 0;
+}
+
+
+
+Type*
+SymbolFileDWARFDebugMap::ResolveTypeUID(lldb::user_id_t type_uid)
+{
+ const uint64_t oso_idx = GetOSOIndexFromUserID (type_uid);
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx);
+ if (oso_dwarf)
+ return oso_dwarf->ResolveTypeUID (type_uid);
+ return NULL;
+}
+
+bool
+SymbolFileDWARFDebugMap::ResolveClangOpaqueTypeDefinition (ClangASTType& clang_type)
+{
+ // We have a struct/union/class/enum that needs to be fully resolved.
+ return false;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::ResolveSymbolContext (const Address& exe_so_addr, uint32_t resolve_scope, SymbolContext& sc)
+{
+ uint32_t resolved_flags = 0;
+ Symtab* symtab = m_obj_file->GetSymtab();
+ if (symtab)
+ {
+ const addr_t exe_file_addr = exe_so_addr.GetFileAddress();
+
+ const DebugMap::Entry *debug_map_entry = m_debug_map.FindEntryThatContains (exe_file_addr);
+ if (debug_map_entry)
+ {
+
+ sc.symbol = symtab->SymbolAtIndex(debug_map_entry->data.GetExeSymbolIndex());
+
+ if (sc.symbol != NULL)
+ {
+ resolved_flags |= eSymbolContextSymbol;
+
+ uint32_t oso_idx = 0;
+ CompileUnitInfo* comp_unit_info = GetCompileUnitInfoForSymbolWithID (sc.symbol->GetID(), &oso_idx);
+ if (comp_unit_info)
+ {
+ comp_unit_info->GetFileRangeMap(this);
+ Module *oso_module = GetModuleByCompUnitInfo (comp_unit_info);
+ if (oso_module)
+ {
+ lldb::addr_t oso_file_addr = exe_file_addr - debug_map_entry->GetRangeBase() + debug_map_entry->data.GetOSOFileAddress();
+ Address oso_so_addr;
+ if (oso_module->ResolveFileAddress(oso_file_addr, oso_so_addr))
+ {
+ resolved_flags |= oso_module->GetSymbolVendor()->ResolveSymbolContext (oso_so_addr, resolve_scope, sc);
+ }
+ }
+ }
+ }
+ }
+ }
+ return resolved_flags;
+}
+
+
+uint32_t
+SymbolFileDWARFDebugMap::ResolveSymbolContext (const FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list)
+{
+ const uint32_t initial = sc_list.GetSize();
+ const uint32_t cu_count = GetNumCompileUnits();
+
+ for (uint32_t i=0; i<cu_count; ++i)
+ {
+ // If we are checking for inlines, then we need to look through all
+ // compile units no matter if "file_spec" matches.
+ bool resolve = check_inlines;
+
+ if (!resolve)
+ {
+ FileSpec so_file_spec;
+ if (GetFileSpecForSO (i, so_file_spec))
+ {
+ // Match the full path if the incoming file_spec has a directory (not just a basename)
+ const bool full_match = file_spec.GetDirectory();
+ resolve = FileSpec::Equal (file_spec, so_file_spec, full_match);
+ }
+ }
+ if (resolve)
+ {
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (i);
+ if (oso_dwarf)
+ oso_dwarf->ResolveSymbolContext(file_spec, line, check_inlines, resolve_scope, sc_list);
+ }
+ }
+ return sc_list.GetSize() - initial;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::PrivateFindGlobalVariables
+(
+ const ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ const std::vector<uint32_t> &indexes, // Indexes into the symbol table that match "name"
+ uint32_t max_matches,
+ VariableList& variables
+)
+{
+ const uint32_t original_size = variables.GetSize();
+ const size_t match_count = indexes.size();
+ for (size_t i=0; i<match_count; ++i)
+ {
+ uint32_t oso_idx;
+ CompileUnitInfo* comp_unit_info = GetCompileUnitInfoForSymbolWithIndex (indexes[i], &oso_idx);
+ if (comp_unit_info)
+ {
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx);
+ if (oso_dwarf)
+ {
+ if (oso_dwarf->FindGlobalVariables(name, namespace_decl, true, max_matches, variables))
+ if (variables.GetSize() > max_matches)
+ break;
+ }
+ }
+ }
+ return variables.GetSize() - original_size;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::FindGlobalVariables (const ConstString &name, const ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, VariableList& variables)
+{
+
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ variables.Clear();
+
+ // Remember how many variables are in the list before we search in case
+ // we are appending the results to a variable list.
+ const uint32_t original_size = variables.GetSize();
+
+ uint32_t total_matches = 0;
+ SymbolFileDWARF *oso_dwarf;
+ for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
+ {
+ const uint32_t oso_matches = oso_dwarf->FindGlobalVariables (name,
+ namespace_decl,
+ true,
+ max_matches,
+ variables);
+ if (oso_matches > 0)
+ {
+ total_matches += oso_matches;
+
+ // Are we getting all matches?
+ if (max_matches == UINT32_MAX)
+ continue; // Yep, continue getting everything
+
+ // If we have found enough matches, lets get out
+ if (max_matches >= total_matches)
+ break;
+
+ // Update the max matches for any subsequent calls to find globals
+ // in any other object files with DWARF
+ max_matches -= oso_matches;
+ }
+ }
+ // Return the number of variable that were appended to the list
+ return variables.GetSize() - original_size;
+}
+
+
+uint32_t
+SymbolFileDWARFDebugMap::FindGlobalVariables (const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables)
+{
+ // If we aren't appending the results to this list, then clear the list
+ if (!append)
+ variables.Clear();
+
+ // Remember how many variables are in the list before we search in case
+ // we are appending the results to a variable list.
+ const uint32_t original_size = variables.GetSize();
+
+ uint32_t total_matches = 0;
+ SymbolFileDWARF *oso_dwarf;
+ for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
+ {
+ const uint32_t oso_matches = oso_dwarf->FindGlobalVariables (regex,
+ true,
+ max_matches,
+ variables);
+ if (oso_matches > 0)
+ {
+ total_matches += oso_matches;
+
+ // Are we getting all matches?
+ if (max_matches == UINT32_MAX)
+ continue; // Yep, continue getting everything
+
+ // If we have found enough matches, lets get out
+ if (max_matches >= total_matches)
+ break;
+
+ // Update the max matches for any subsequent calls to find globals
+ // in any other object files with DWARF
+ max_matches -= oso_matches;
+ }
+ }
+ // Return the number of variable that were appended to the list
+ return variables.GetSize() - original_size;
+}
+
+
+int
+SymbolFileDWARFDebugMap::SymbolContainsSymbolWithIndex (uint32_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info)
+{
+ const uint32_t symbol_idx = *symbol_idx_ptr;
+
+ if (symbol_idx < comp_unit_info->first_symbol_index)
+ return -1;
+
+ if (symbol_idx <= comp_unit_info->last_symbol_index)
+ return 0;
+
+ return 1;
+}
+
+
+int
+SymbolFileDWARFDebugMap::SymbolContainsSymbolWithID (user_id_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info)
+{
+ const user_id_t symbol_id = *symbol_idx_ptr;
+
+ if (symbol_id < comp_unit_info->first_symbol_id)
+ return -1;
+
+ if (symbol_id <= comp_unit_info->last_symbol_id)
+ return 0;
+
+ return 1;
+}
+
+
+SymbolFileDWARFDebugMap::CompileUnitInfo*
+SymbolFileDWARFDebugMap::GetCompileUnitInfoForSymbolWithIndex (uint32_t symbol_idx, uint32_t *oso_idx_ptr)
+{
+ const uint32_t oso_index_count = m_compile_unit_infos.size();
+ CompileUnitInfo *comp_unit_info = NULL;
+ if (oso_index_count)
+ {
+ comp_unit_info = (CompileUnitInfo*)bsearch(&symbol_idx,
+ &m_compile_unit_infos[0],
+ m_compile_unit_infos.size(),
+ sizeof(CompileUnitInfo),
+ (ComparisonFunction)SymbolContainsSymbolWithIndex);
+ }
+
+ if (oso_idx_ptr)
+ {
+ if (comp_unit_info != NULL)
+ *oso_idx_ptr = comp_unit_info - &m_compile_unit_infos[0];
+ else
+ *oso_idx_ptr = UINT32_MAX;
+ }
+ return comp_unit_info;
+}
+
+SymbolFileDWARFDebugMap::CompileUnitInfo*
+SymbolFileDWARFDebugMap::GetCompileUnitInfoForSymbolWithID (user_id_t symbol_id, uint32_t *oso_idx_ptr)
+{
+ const uint32_t oso_index_count = m_compile_unit_infos.size();
+ CompileUnitInfo *comp_unit_info = NULL;
+ if (oso_index_count)
+ {
+ comp_unit_info = (CompileUnitInfo*)::bsearch (&symbol_id,
+ &m_compile_unit_infos[0],
+ m_compile_unit_infos.size(),
+ sizeof(CompileUnitInfo),
+ (ComparisonFunction)SymbolContainsSymbolWithID);
+ }
+
+ if (oso_idx_ptr)
+ {
+ if (comp_unit_info != NULL)
+ *oso_idx_ptr = comp_unit_info - &m_compile_unit_infos[0];
+ else
+ *oso_idx_ptr = UINT32_MAX;
+ }
+ return comp_unit_info;
+}
+
+
+static void
+RemoveFunctionsWithModuleNotEqualTo (const ModuleSP &module_sp, SymbolContextList &sc_list, uint32_t start_idx)
+{
+ // We found functions in .o files. Not all functions in the .o files
+ // will have made it into the final output file. The ones that did
+ // make it into the final output file will have a section whose module
+ // matches the module from the ObjectFile for this SymbolFile. When
+ // the modules don't match, then we have something that was in a
+ // .o file, but doesn't map to anything in the final executable.
+ uint32_t i=start_idx;
+ while (i < sc_list.GetSize())
+ {
+ SymbolContext sc;
+ sc_list.GetContextAtIndex(i, sc);
+ if (sc.function)
+ {
+ const SectionSP section_sp (sc.function->GetAddressRange().GetBaseAddress().GetSection());
+ if (section_sp->GetModule() != module_sp)
+ {
+ sc_list.RemoveContextAtIndex(i);
+ continue;
+ }
+ }
+ ++i;
+ }
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::FindFunctions(const ConstString &name, const ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARFDebugMap::FindFunctions (name = %s)",
+ name.GetCString());
+
+ uint32_t initial_size = 0;
+ if (append)
+ initial_size = sc_list.GetSize();
+ else
+ sc_list.Clear();
+
+ uint32_t oso_idx = 0;
+ SymbolFileDWARF *oso_dwarf;
+ while ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx++)) != NULL)
+ {
+ uint32_t sc_idx = sc_list.GetSize();
+ if (oso_dwarf->FindFunctions(name, namespace_decl, name_type_mask, include_inlines, true, sc_list))
+ {
+ RemoveFunctionsWithModuleNotEqualTo (m_obj_file->GetModule(), sc_list, sc_idx);
+ }
+ }
+
+ return sc_list.GetSize() - initial_size;
+}
+
+
+uint32_t
+SymbolFileDWARFDebugMap::FindFunctions (const RegularExpression& regex, bool include_inlines, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARFDebugMap::FindFunctions (regex = '%s')",
+ regex.GetText());
+
+ uint32_t initial_size = 0;
+ if (append)
+ initial_size = sc_list.GetSize();
+ else
+ sc_list.Clear();
+
+ uint32_t oso_idx = 0;
+ SymbolFileDWARF *oso_dwarf;
+ while ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx++)) != NULL)
+ {
+ uint32_t sc_idx = sc_list.GetSize();
+
+ if (oso_dwarf->FindFunctions(regex, include_inlines, true, sc_list))
+ {
+ RemoveFunctionsWithModuleNotEqualTo (m_obj_file->GetModule(), sc_list, sc_idx);
+ }
+ }
+
+ return sc_list.GetSize() - initial_size;
+}
+
+size_t
+SymbolFileDWARFDebugMap::GetTypes (SymbolContextScope *sc_scope,
+ uint32_t type_mask,
+ TypeList &type_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileDWARFDebugMap::GetTypes (type_mask = 0x%8.8x)",
+ type_mask);
+
+
+ uint32_t initial_size = type_list.GetSize();
+ SymbolFileDWARF *oso_dwarf = NULL;
+ if (sc_scope)
+ {
+ SymbolContext sc;
+ sc_scope->CalculateSymbolContext(&sc);
+
+ CompileUnitInfo *cu_info = GetCompUnitInfo (sc);
+ if (cu_info)
+ {
+ oso_dwarf = GetSymbolFileByCompUnitInfo (cu_info);
+ if (oso_dwarf)
+ oso_dwarf->GetTypes (sc_scope, type_mask, type_list);
+ }
+ }
+ else
+ {
+ uint32_t oso_idx = 0;
+ while ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx++)) != NULL)
+ {
+ oso_dwarf->GetTypes (sc_scope, type_mask, type_list);
+ }
+ }
+ return type_list.GetSize() - initial_size;
+}
+
+
+TypeSP
+SymbolFileDWARFDebugMap::FindDefinitionTypeForDWARFDeclContext (const DWARFDeclContext &die_decl_ctx)
+{
+ TypeSP type_sp;
+ SymbolFileDWARF *oso_dwarf;
+ for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
+ {
+ type_sp = oso_dwarf->FindDefinitionTypeForDWARFDeclContext (die_decl_ctx);
+ if (type_sp)
+ break;
+ }
+ return type_sp;
+}
+
+
+
+bool
+SymbolFileDWARFDebugMap::Supports_DW_AT_APPLE_objc_complete_type (SymbolFileDWARF *skip_dwarf_oso)
+{
+ if (m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolCalculate)
+ {
+ m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolNo;
+ SymbolFileDWARF *oso_dwarf;
+ for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
+ {
+ if (skip_dwarf_oso != oso_dwarf && oso_dwarf->Supports_DW_AT_APPLE_objc_complete_type(NULL))
+ {
+ m_supports_DW_AT_APPLE_objc_complete_type = eLazyBoolYes;
+ break;
+ }
+ }
+ }
+ return m_supports_DW_AT_APPLE_objc_complete_type == eLazyBoolYes;
+}
+
+TypeSP
+SymbolFileDWARFDebugMap::FindCompleteObjCDefinitionTypeForDIE (const DWARFDebugInfoEntry *die,
+ const ConstString &type_name,
+ bool must_be_implementation)
+{
+ TypeSP type_sp;
+ SymbolFileDWARF *oso_dwarf;
+ for (uint32_t oso_idx = 0; ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
+ {
+ type_sp = oso_dwarf->FindCompleteObjCDefinitionTypeForDIE (die, type_name, must_be_implementation);
+ if (type_sp)
+ break;
+ }
+ return type_sp;
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::FindTypes
+(
+ const SymbolContext& sc,
+ const ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ bool append,
+ uint32_t max_matches,
+ TypeList& types
+)
+{
+ if (!append)
+ types.Clear();
+
+ const uint32_t initial_types_size = types.GetSize();
+ SymbolFileDWARF *oso_dwarf;
+
+ if (sc.comp_unit)
+ {
+ oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ return oso_dwarf->FindTypes (sc, name, namespace_decl, append, max_matches, types);
+ }
+ else
+ {
+ uint32_t oso_idx = 0;
+ while ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx++)) != NULL)
+ oso_dwarf->FindTypes (sc, name, namespace_decl, append, max_matches, types);
+ }
+
+ return types.GetSize() - initial_types_size;
+}
+
+//
+//uint32_t
+//SymbolFileDWARFDebugMap::FindTypes (const SymbolContext& sc, const RegularExpression& regex, bool append, uint32_t max_matches, Type::Encoding encoding, lldb::user_id_t udt_uid, TypeList& types)
+//{
+// SymbolFileDWARF *oso_dwarf = GetSymbolFile (sc);
+// if (oso_dwarf)
+// return oso_dwarf->FindTypes (sc, regex, append, max_matches, encoding, udt_uid, types);
+// return 0;
+//}
+
+
+ClangNamespaceDecl
+SymbolFileDWARFDebugMap::FindNamespace (const lldb_private::SymbolContext& sc,
+ const lldb_private::ConstString &name,
+ const ClangNamespaceDecl *parent_namespace_decl)
+{
+ ClangNamespaceDecl matching_namespace;
+ SymbolFileDWARF *oso_dwarf;
+
+ if (sc.comp_unit)
+ {
+ oso_dwarf = GetSymbolFile (sc);
+ if (oso_dwarf)
+ matching_namespace = oso_dwarf->FindNamespace (sc, name, parent_namespace_decl);
+ }
+ else
+ {
+ for (uint32_t oso_idx = 0;
+ ((oso_dwarf = GetSymbolFileByOSOIndex (oso_idx)) != NULL);
+ ++oso_idx)
+ {
+ matching_namespace = oso_dwarf->FindNamespace (sc, name, parent_namespace_decl);
+
+ if (matching_namespace)
+ break;
+ }
+ }
+
+ return matching_namespace;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+SymbolFileDWARFDebugMap::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SymbolFileDWARFDebugMap::GetPluginVersion()
+{
+ return 1;
+}
+
+lldb::CompUnitSP
+SymbolFileDWARFDebugMap::GetCompileUnit (SymbolFileDWARF *oso_dwarf)
+{
+ if (oso_dwarf)
+ {
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t cu_idx=0; cu_idx<cu_count; ++cu_idx)
+ {
+ SymbolFileDWARF *oso_symfile = GetSymbolFileByCompUnitInfo (&m_compile_unit_infos[cu_idx]);
+ if (oso_symfile == oso_dwarf)
+ {
+ if (!m_compile_unit_infos[cu_idx].compile_unit_sp)
+ m_compile_unit_infos[cu_idx].compile_unit_sp = ParseCompileUnitAtIndex (cu_idx);
+
+ return m_compile_unit_infos[cu_idx].compile_unit_sp;
+ }
+ }
+ }
+ assert(!"this shouldn't happen");
+ return lldb::CompUnitSP();
+}
+
+SymbolFileDWARFDebugMap::CompileUnitInfo *
+SymbolFileDWARFDebugMap::GetCompileUnitInfo (SymbolFileDWARF *oso_dwarf)
+{
+ if (oso_dwarf)
+ {
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t cu_idx=0; cu_idx<cu_count; ++cu_idx)
+ {
+ SymbolFileDWARF *oso_symfile = GetSymbolFileByCompUnitInfo (&m_compile_unit_infos[cu_idx]);
+ if (oso_symfile == oso_dwarf)
+ {
+ return &m_compile_unit_infos[cu_idx];
+ }
+ }
+ }
+ return NULL;
+}
+
+
+void
+SymbolFileDWARFDebugMap::SetCompileUnit (SymbolFileDWARF *oso_dwarf, const CompUnitSP &cu_sp)
+{
+ if (oso_dwarf)
+ {
+ const uint32_t cu_count = GetNumCompileUnits();
+ for (uint32_t cu_idx=0; cu_idx<cu_count; ++cu_idx)
+ {
+ SymbolFileDWARF *oso_symfile = GetSymbolFileByCompUnitInfo (&m_compile_unit_infos[cu_idx]);
+ if (oso_symfile == oso_dwarf)
+ {
+ if (m_compile_unit_infos[cu_idx].compile_unit_sp)
+ {
+ assert (m_compile_unit_infos[cu_idx].compile_unit_sp.get() == cu_sp.get());
+ }
+ else
+ {
+ m_compile_unit_infos[cu_idx].compile_unit_sp = cu_sp;
+ m_obj_file->GetModule()->GetSymbolVendor()->SetCompileUnitAtIndex(cu_idx, cu_sp);
+ }
+ }
+ }
+ }
+}
+
+
+void
+SymbolFileDWARFDebugMap::CompleteTagDecl (void *baton, clang::TagDecl *decl)
+{
+ SymbolFileDWARFDebugMap *symbol_file_dwarf = (SymbolFileDWARFDebugMap *)baton;
+ ClangASTType clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl);
+ if (clang_type)
+ {
+ SymbolFileDWARF *oso_dwarf;
+
+ for (uint32_t oso_idx = 0; ((oso_dwarf = symbol_file_dwarf->GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
+ {
+ if (oso_dwarf->HasForwardDeclForClangType (clang_type))
+ {
+ oso_dwarf->ResolveClangOpaqueTypeDefinition (clang_type);
+ return;
+ }
+ }
+ }
+}
+
+void
+SymbolFileDWARFDebugMap::CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *decl)
+{
+ SymbolFileDWARFDebugMap *symbol_file_dwarf = (SymbolFileDWARFDebugMap *)baton;
+ ClangASTType clang_type = symbol_file_dwarf->GetClangASTContext().GetTypeForDecl (decl);
+ if (clang_type)
+ {
+ SymbolFileDWARF *oso_dwarf;
+
+ for (uint32_t oso_idx = 0; ((oso_dwarf = symbol_file_dwarf->GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
+ {
+ if (oso_dwarf->HasForwardDeclForClangType (clang_type))
+ {
+ oso_dwarf->ResolveClangOpaqueTypeDefinition (clang_type);
+ return;
+ }
+ }
+ }
+}
+
+bool
+SymbolFileDWARFDebugMap::LayoutRecordType (void *baton,
+ const clang::RecordDecl *record_decl,
+ uint64_t &size,
+ uint64_t &alignment,
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets)
+{
+ SymbolFileDWARFDebugMap *symbol_file_dwarf = (SymbolFileDWARFDebugMap *)baton;
+ SymbolFileDWARF *oso_dwarf;
+ for (uint32_t oso_idx = 0; ((oso_dwarf = symbol_file_dwarf->GetSymbolFileByOSOIndex (oso_idx)) != NULL); ++oso_idx)
+ {
+ if (oso_dwarf->LayoutRecordType (record_decl, size, alignment, field_offsets, base_offsets, vbase_offsets))
+ return true;
+ }
+ return false;
+}
+
+
+
+clang::DeclContext*
+SymbolFileDWARFDebugMap::GetClangDeclContextContainingTypeUID (lldb::user_id_t type_uid)
+{
+ const uint64_t oso_idx = GetOSOIndexFromUserID (type_uid);
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx);
+ if (oso_dwarf)
+ return oso_dwarf->GetClangDeclContextContainingTypeUID (type_uid);
+ return NULL;
+}
+
+clang::DeclContext*
+SymbolFileDWARFDebugMap::GetClangDeclContextForTypeUID (const lldb_private::SymbolContext &sc, lldb::user_id_t type_uid)
+{
+ const uint64_t oso_idx = GetOSOIndexFromUserID (type_uid);
+ SymbolFileDWARF *oso_dwarf = GetSymbolFileByOSOIndex (oso_idx);
+ if (oso_dwarf)
+ return oso_dwarf->GetClangDeclContextForTypeUID (sc, type_uid);
+ return NULL;
+}
+
+bool
+SymbolFileDWARFDebugMap::AddOSOFileRange (CompileUnitInfo *cu_info,
+ lldb::addr_t exe_file_addr,
+ lldb::addr_t oso_file_addr,
+ lldb::addr_t oso_byte_size)
+{
+ const uint32_t debug_map_idx = m_debug_map.FindEntryIndexThatContains(exe_file_addr);
+ if (debug_map_idx != UINT32_MAX)
+ {
+ DebugMap::Entry *debug_map_entry = m_debug_map.FindEntryThatContains(exe_file_addr);
+ debug_map_entry->data.SetOSOFileAddress(oso_file_addr);
+ cu_info->file_range_map.Append(FileRangeMap::Entry(oso_file_addr, oso_byte_size, exe_file_addr));
+ return true;
+ }
+ return false;
+}
+
+void
+SymbolFileDWARFDebugMap::FinalizeOSOFileRanges (CompileUnitInfo *cu_info)
+{
+ cu_info->file_range_map.Sort();
+#if defined(DEBUG_OSO_DMAP)
+ const FileRangeMap &oso_file_range_map = cu_info->GetFileRangeMap(this);
+ const size_t n = oso_file_range_map.GetSize();
+ printf ("SymbolFileDWARFDebugMap::FinalizeOSOFileRanges (cu_info = %p) %s\n",
+ cu_info,
+ cu_info->oso_sp->module_sp->GetFileSpec().GetPath().c_str());
+ for (size_t i=0; i<n; ++i)
+ {
+ const FileRangeMap::Entry &entry = oso_file_range_map.GetEntryRef(i);
+ printf ("oso [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ") ==> exe [0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")\n",
+ entry.GetRangeBase(), entry.GetRangeEnd(),
+ entry.data, entry.data + entry.GetByteSize());
+ }
+#endif
+}
+
+lldb::addr_t
+SymbolFileDWARFDebugMap::LinkOSOFileAddress (SymbolFileDWARF *oso_symfile, lldb::addr_t oso_file_addr)
+{
+ CompileUnitInfo *cu_info = GetCompileUnitInfo (oso_symfile);
+ if (cu_info)
+ {
+ const FileRangeMap::Entry *oso_range_entry = cu_info->GetFileRangeMap(this).FindEntryThatContains(oso_file_addr);
+ if (oso_range_entry)
+ {
+ const DebugMap::Entry *debug_map_entry = m_debug_map.FindEntryThatContains(oso_range_entry->data);
+ if (debug_map_entry)
+ {
+ const lldb::addr_t offset = oso_file_addr - oso_range_entry->GetRangeBase();
+ const lldb::addr_t exe_file_addr = debug_map_entry->GetRangeBase() + offset;
+ return exe_file_addr;
+ }
+ }
+ }
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool
+SymbolFileDWARFDebugMap::LinkOSOAddress (Address &addr)
+{
+ // Make sure this address hasn't been fixed already
+ Module *exe_module = GetObjectFile()->GetModule().get();
+ Module *addr_module = addr.GetModule().get();
+ if (addr_module == exe_module)
+ return true; // Address is already in terms of the main executable module
+
+ CompileUnitInfo *cu_info = GetCompileUnitInfo (GetSymbolFileAsSymbolFileDWARF(addr_module->GetSymbolVendor()->GetSymbolFile()));
+ if (cu_info)
+ {
+ const lldb::addr_t oso_file_addr = addr.GetFileAddress();
+ const FileRangeMap::Entry *oso_range_entry = cu_info->GetFileRangeMap(this).FindEntryThatContains(oso_file_addr);
+ if (oso_range_entry)
+ {
+ const DebugMap::Entry *debug_map_entry = m_debug_map.FindEntryThatContains(oso_range_entry->data);
+ if (debug_map_entry)
+ {
+ const lldb::addr_t offset = oso_file_addr - oso_range_entry->GetRangeBase();
+ const lldb::addr_t exe_file_addr = debug_map_entry->GetRangeBase() + offset;
+ return exe_module->ResolveFileAddress(exe_file_addr, addr);
+ }
+ }
+ }
+ return true;
+}
+
+LineTable *
+SymbolFileDWARFDebugMap::LinkOSOLineTable (SymbolFileDWARF *oso_dwarf, LineTable *line_table)
+{
+ CompileUnitInfo *cu_info = GetCompileUnitInfo (oso_dwarf);
+ if (cu_info)
+ return line_table->LinkLineTable(cu_info->GetFileRangeMap(this));
+ return NULL;
+}
+
+size_t
+SymbolFileDWARFDebugMap::AddOSOARanges (SymbolFileDWARF* dwarf2Data, DWARFDebugAranges* debug_aranges)
+{
+ size_t num_line_entries_added = 0;
+ if (debug_aranges && dwarf2Data)
+ {
+ CompileUnitInfo *compile_unit_info = GetCompileUnitInfo(dwarf2Data);
+ if (compile_unit_info)
+ {
+ const FileRangeMap &file_range_map = compile_unit_info->GetFileRangeMap(this);
+ for (size_t idx = 0;
+ idx < file_range_map.GetSize();
+ idx++)
+ {
+ const FileRangeMap::Entry* entry = file_range_map.GetEntryAtIndex(idx);
+ if (entry)
+ {
+ printf ("[0x%16.16" PRIx64 " - 0x%16.16" PRIx64 ")\n", entry->GetRangeBase(), entry->GetRangeEnd());
+ debug_aranges->AppendRange(dwarf2Data->GetID(), entry->GetRangeBase(), entry->GetRangeEnd());
+ num_line_entries_added++;
+ }
+ }
+ }
+ }
+ return num_line_entries_added;
+}
+
diff --git a/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
new file mode 100644
index 000000000000..06330b98dc19
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/SymbolFileDWARFDebugMap.h
@@ -0,0 +1,420 @@
+//===-- SymbolFileDWARFDebugMap.h ------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SymbolFileDWARF_SymbolFileDWARFDebugMap_h_
+#define SymbolFileDWARF_SymbolFileDWARFDebugMap_h_
+
+
+#include <vector>
+#include <bitset>
+
+#include "clang/AST/CharUnits.h"
+
+#include "lldb/Core/RangeMap.h"
+#include "lldb/Symbol/SymbolFile.h"
+
+#include "UniqueDWARFASTType.h"
+
+class SymbolFileDWARF;
+class DWARFCompileUnit;
+class DWARFDebugAranges;
+class DWARFDebugInfoEntry;
+class DWARFDeclContext;
+class DebugMapModule;
+
+class SymbolFileDWARFDebugMap : public lldb_private::SymbolFile
+{
+public:
+
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolFile *
+ CreateInstance (lldb_private::ObjectFile* obj_file);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolFileDWARFDebugMap (lldb_private::ObjectFile* ofile);
+ virtual ~ SymbolFileDWARFDebugMap ();
+
+ virtual uint32_t CalculateAbilities ();
+
+ virtual void InitializeObject();
+
+ //------------------------------------------------------------------
+ // Compile Unit function calls
+ //------------------------------------------------------------------
+ virtual uint32_t GetNumCompileUnits ();
+ virtual lldb::CompUnitSP ParseCompileUnitAtIndex (uint32_t index);
+
+ virtual lldb::LanguageType ParseCompileUnitLanguage (const lldb_private::SymbolContext& sc);
+ virtual size_t ParseCompileUnitFunctions (const lldb_private::SymbolContext& sc);
+ virtual bool ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc);
+ virtual bool ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList &support_files);
+ virtual size_t ParseFunctionBlocks (const lldb_private::SymbolContext& sc);
+ virtual size_t ParseTypes (const lldb_private::SymbolContext& sc);
+ virtual size_t ParseVariablesForContext (const lldb_private::SymbolContext& sc);
+
+ virtual lldb_private::Type* ResolveTypeUID (lldb::user_id_t type_uid);
+ virtual clang::DeclContext* GetClangDeclContextContainingTypeUID (lldb::user_id_t type_uid);
+ virtual clang::DeclContext* GetClangDeclContextForTypeUID (const lldb_private::SymbolContext &sc, lldb::user_id_t type_uid);
+ virtual bool ResolveClangOpaqueTypeDefinition (lldb_private::ClangASTType& clang_type);
+ virtual uint32_t ResolveSymbolContext (const lldb_private::Address& so_addr, uint32_t resolve_scope, lldb_private::SymbolContext& sc);
+ virtual uint32_t ResolveSymbolContext (const lldb_private::FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindGlobalVariables (const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+ virtual uint32_t FindGlobalVariables (const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+ virtual uint32_t FindFunctions (const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindFunctions (const lldb_private::RegularExpression& regex, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list);
+ virtual uint32_t FindTypes (const lldb_private::SymbolContext& sc, const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::TypeList& types);
+ virtual lldb_private::ClangNamespaceDecl
+ FindNamespace (const lldb_private::SymbolContext& sc,
+ const lldb_private::ConstString &name,
+ const lldb_private::ClangNamespaceDecl *parent_namespace_decl);
+ virtual size_t GetTypes (lldb_private::SymbolContextScope *sc_scope,
+ uint32_t type_mask,
+ lldb_private::TypeList &type_list);
+
+
+ //------------------------------------------------------------------
+ // ClangASTContext callbacks for external source lookups.
+ //------------------------------------------------------------------
+ static void
+ CompleteTagDecl (void *baton, clang::TagDecl *);
+
+ static void
+ CompleteObjCInterfaceDecl (void *baton, clang::ObjCInterfaceDecl *);
+
+ static bool
+ LayoutRecordType (void *baton,
+ const clang::RecordDecl *record_decl,
+ uint64_t &size,
+ uint64_t &alignment,
+ llvm::DenseMap <const clang::FieldDecl *, uint64_t> &field_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &base_offsets,
+ llvm::DenseMap <const clang::CXXRecordDecl *, clang::CharUnits> &vbase_offsets);
+
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+protected:
+ enum
+ {
+ kHaveInitializedOSOs = (1 << 0),
+ kNumFlags
+ };
+
+ friend class DWARFCompileUnit;
+ friend class SymbolFileDWARF;
+ friend class DebugMapModule;
+ struct OSOInfo
+ {
+ lldb::ModuleSP module_sp;
+
+ OSOInfo() :
+ module_sp ()
+ {
+ }
+ };
+
+ typedef std::shared_ptr<OSOInfo> OSOInfoSP;
+
+ typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, lldb::addr_t> FileRangeMap;
+
+ //------------------------------------------------------------------
+ // Class specific types
+ //------------------------------------------------------------------
+ struct CompileUnitInfo
+ {
+ lldb_private::FileSpec so_file;
+ lldb_private::ConstString oso_path;
+ lldb_private::TimeValue oso_mod_time;
+ OSOInfoSP oso_sp;
+ lldb::CompUnitSP compile_unit_sp;
+ uint32_t first_symbol_index;
+ uint32_t last_symbol_index;
+ uint32_t first_symbol_id;
+ uint32_t last_symbol_id;
+ FileRangeMap file_range_map;
+ bool file_range_map_valid;
+
+
+ CompileUnitInfo() :
+ so_file (),
+ oso_path (),
+ oso_mod_time (),
+ oso_sp (),
+ compile_unit_sp (),
+ first_symbol_index (UINT32_MAX),
+ last_symbol_index (UINT32_MAX),
+ first_symbol_id (UINT32_MAX),
+ last_symbol_id (UINT32_MAX),
+ file_range_map (),
+ file_range_map_valid (false)
+ {
+ }
+
+ const FileRangeMap &
+ GetFileRangeMap(SymbolFileDWARFDebugMap *exe_symfile);
+ };
+
+ //------------------------------------------------------------------
+ // Protected Member Functions
+ //------------------------------------------------------------------
+ void
+ InitOSO ();
+
+ static uint32_t
+ GetOSOIndexFromUserID (lldb::user_id_t uid)
+ {
+ return (uint32_t)((uid >> 32ull) - 1ull);
+ }
+
+ static SymbolFileDWARF *
+ GetSymbolFileAsSymbolFileDWARF (SymbolFile *sym_file);
+
+ bool
+ GetFileSpecForSO (uint32_t oso_idx, lldb_private::FileSpec &file_spec);
+
+ CompileUnitInfo *
+ GetCompUnitInfo (const lldb_private::SymbolContext& sc);
+
+ size_t
+ GetCompUnitInfosForModule (const lldb_private::Module *oso_module,
+ std::vector<CompileUnitInfo *>& cu_infos);
+
+ lldb_private::Module *
+ GetModuleByCompUnitInfo (CompileUnitInfo *comp_unit_info);
+
+ lldb_private::Module *
+ GetModuleByOSOIndex (uint32_t oso_idx);
+
+ lldb_private::ObjectFile *
+ GetObjectFileByCompUnitInfo (CompileUnitInfo *comp_unit_info);
+
+ lldb_private::ObjectFile *
+ GetObjectFileByOSOIndex (uint32_t oso_idx);
+
+ uint32_t
+ GetCompUnitInfoIndex (const CompileUnitInfo *comp_unit_info);
+
+ SymbolFileDWARF *
+ GetSymbolFile (const lldb_private::SymbolContext& sc);
+
+ SymbolFileDWARF *
+ GetSymbolFileByCompUnitInfo (CompileUnitInfo *comp_unit_info);
+
+ SymbolFileDWARF *
+ GetSymbolFileByOSOIndex (uint32_t oso_idx);
+
+ CompileUnitInfo *
+ GetCompileUnitInfoForSymbolWithIndex (uint32_t symbol_idx, uint32_t *oso_idx_ptr);
+
+ CompileUnitInfo *
+ GetCompileUnitInfoForSymbolWithID (lldb::user_id_t symbol_id, uint32_t *oso_idx_ptr);
+
+ static int
+ SymbolContainsSymbolWithIndex (uint32_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info);
+
+ static int
+ SymbolContainsSymbolWithID (lldb::user_id_t *symbol_idx_ptr, const CompileUnitInfo *comp_unit_info);
+
+ uint32_t
+ PrivateFindGlobalVariables (const lldb_private::ConstString &name,
+ const lldb_private::ClangNamespaceDecl *namespace_decl,
+ const std::vector<uint32_t> &name_symbol_indexes,
+ uint32_t max_matches,
+ lldb_private::VariableList& variables);
+
+
+ void
+ SetCompileUnit (SymbolFileDWARF *oso_dwarf, const lldb::CompUnitSP &cu_sp);
+
+ lldb::CompUnitSP
+ GetCompileUnit (SymbolFileDWARF *oso_dwarf);
+
+ CompileUnitInfo *
+ GetCompileUnitInfo (SymbolFileDWARF *oso_dwarf);
+
+ lldb::TypeSP
+ FindDefinitionTypeForDWARFDeclContext (const DWARFDeclContext &die_decl_ctx);
+
+ bool
+ Supports_DW_AT_APPLE_objc_complete_type (SymbolFileDWARF *skip_dwarf_oso);
+
+ lldb::TypeSP
+ FindCompleteObjCDefinitionTypeForDIE (const DWARFDebugInfoEntry *die,
+ const lldb_private::ConstString &type_name,
+ bool must_be_implementation);
+
+
+ UniqueDWARFASTTypeMap &
+ GetUniqueDWARFASTTypeMap ()
+ {
+ return m_unique_ast_type_map;
+ }
+
+
+ //------------------------------------------------------------------
+ // OSOEntry
+ //------------------------------------------------------------------
+ class OSOEntry
+ {
+ public:
+
+ OSOEntry () :
+ m_exe_sym_idx (UINT32_MAX),
+ m_oso_file_addr (LLDB_INVALID_ADDRESS)
+ {
+ }
+
+ OSOEntry (uint32_t exe_sym_idx,
+ lldb::addr_t oso_file_addr) :
+ m_exe_sym_idx (exe_sym_idx),
+ m_oso_file_addr (oso_file_addr)
+ {
+ }
+
+ uint32_t
+ GetExeSymbolIndex () const
+ {
+ return m_exe_sym_idx;
+ }
+
+ bool
+ operator < (const OSOEntry &rhs) const
+ {
+ return m_exe_sym_idx < rhs.m_exe_sym_idx;
+ }
+
+ lldb::addr_t
+ GetOSOFileAddress () const
+ {
+ return m_oso_file_addr;
+ }
+
+ void
+ SetOSOFileAddress (lldb::addr_t oso_file_addr)
+ {
+ m_oso_file_addr = oso_file_addr;
+ }
+ protected:
+ uint32_t m_exe_sym_idx;
+ lldb::addr_t m_oso_file_addr;
+ };
+
+ typedef lldb_private::RangeDataVector<lldb::addr_t, lldb::addr_t, OSOEntry> DebugMap;
+
+ //------------------------------------------------------------------
+ // Member Variables
+ //------------------------------------------------------------------
+ std::bitset<kNumFlags> m_flags;
+ std::vector<CompileUnitInfo> m_compile_unit_infos;
+ std::vector<uint32_t> m_func_indexes; // Sorted by address
+ std::vector<uint32_t> m_glob_indexes;
+ std::map<lldb_private::ConstString, OSOInfoSP> m_oso_map;
+ UniqueDWARFASTTypeMap m_unique_ast_type_map;
+ lldb_private::LazyBool m_supports_DW_AT_APPLE_objc_complete_type;
+ DebugMap m_debug_map;
+
+ //------------------------------------------------------------------
+ // When an object file from the debug map gets parsed in
+ // SymbolFileDWARF, it needs to tell the debug map about the object
+ // files addresses by calling this function once for each N_FUN,
+ // N_GSYM and N_STSYM and after all entries in the debug map have
+ // been matched up, FinalizeOSOFileRanges() should be called.
+ //------------------------------------------------------------------
+ bool
+ AddOSOFileRange (CompileUnitInfo *cu_info,
+ lldb::addr_t exe_file_addr,
+ lldb::addr_t oso_file_addr,
+ lldb::addr_t oso_byte_size);
+
+ //------------------------------------------------------------------
+ // Called after calling AddOSOFileRange() for each object file debug
+ // map entry to finalize the info for the unlinked compile unit.
+ //------------------------------------------------------------------
+ void
+ FinalizeOSOFileRanges (CompileUnitInfo *cu_info);
+
+ //------------------------------------------------------------------
+ /// Convert \a addr from a .o file address, to an executable address.
+ ///
+ /// @param[in] addr
+ /// A section offset address from a .o file
+ ///
+ /// @return
+ /// Returns true if \a addr was converted to be an executable
+ /// section/offset address, false otherwise.
+ //------------------------------------------------------------------
+ bool
+ LinkOSOAddress (lldb_private::Address &addr);
+
+ //------------------------------------------------------------------
+ /// Convert a .o file "file address" to an executable "file address".
+ ///
+ /// @param[in] oso_symfile
+ /// The DWARF symbol file that contains \a oso_file_addr
+ ///
+ /// @param[in] oso_file_addr
+ /// A .o file "file address" to convert.
+ ///
+ /// @return
+ /// LLDB_INVALID_ADDRESS if \a oso_file_addr is not in the
+ /// linked executable, otherwise a valid "file address" from the
+ /// linked executable that contains the debug map.
+ //------------------------------------------------------------------
+ lldb::addr_t
+ LinkOSOFileAddress (SymbolFileDWARF *oso_symfile, lldb::addr_t oso_file_addr);
+
+ //------------------------------------------------------------------
+ /// Given a line table full of lines with "file adresses" that are
+ /// for a .o file represented by \a oso_symfile, link a new line table
+ /// and return it.
+ ///
+ /// @param[in] oso_symfile
+ /// The DWARF symbol file that produced the \a line_table
+ ///
+ /// @param[in] addr
+ /// A section offset address from a .o file
+ ///
+ /// @return
+ /// Returns a valid line table full of linked addresses, or NULL
+ /// if none of the line table adresses exist in the main
+ /// executable.
+ //------------------------------------------------------------------
+ lldb_private::LineTable *
+ LinkOSOLineTable (SymbolFileDWARF *oso_symfile,
+ lldb_private::LineTable *line_table);
+
+ size_t
+ AddOSOARanges (SymbolFileDWARF* dwarf2Data,
+ DWARFDebugAranges* debug_aranges);
+};
+
+#endif // #ifndef SymbolFileDWARF_SymbolFileDWARFDebugMap_h_
diff --git a/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp
new file mode 100644
index 000000000000..94044c0feb30
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.cpp
@@ -0,0 +1,94 @@
+//===-- UniqueDWARFASTType.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UniqueDWARFASTType.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Symbol/Declaration.h"
+
+#include "DWARFDebugInfoEntry.h"
+
+bool
+UniqueDWARFASTTypeList::Find
+(
+ SymbolFileDWARF *symfile,
+ const DWARFCompileUnit *cu,
+ const DWARFDebugInfoEntry *die,
+ const lldb_private::Declaration &decl,
+ const int32_t byte_size,
+ UniqueDWARFASTType &entry
+) const
+{
+ collection::const_iterator pos, end = m_collection.end();
+ for (pos = m_collection.begin(); pos != end; ++pos)
+ {
+ // Make sure the tags match
+ if (pos->m_die->Tag() == die->Tag())
+ {
+ // Validate byte sizes of both types only if both are valid.
+ if (pos->m_byte_size < 0 || byte_size < 0 || pos->m_byte_size == byte_size)
+ {
+ // Make sure the file and line match
+ if (pos->m_declaration == decl)
+ {
+ // The type has the same name, and was defined on the same
+ // file and line. Now verify all of the parent DIEs match.
+ const DWARFDebugInfoEntry *parent_arg_die = die->GetParent();
+ const DWARFDebugInfoEntry *parend_pos_die = pos->m_die->GetParent();
+ bool match = true;
+ bool done = false;
+ while (!done && match && parent_arg_die && parend_pos_die)
+ {
+ if (parent_arg_die->Tag() == parend_pos_die->Tag())
+ {
+ const dw_tag_t tag = parent_arg_die->Tag();
+ switch (tag)
+ {
+ case DW_TAG_class_type:
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_namespace:
+ {
+ const char *parent_arg_die_name = parent_arg_die->GetName(symfile, cu);
+ if (parent_arg_die_name == NULL) // Anonymous (i.e. no-name) struct
+ {
+ match = false;
+ }
+ else
+ {
+ const char *parent_pos_die_name = parend_pos_die->GetName(pos->m_symfile, pos->m_cu);
+ if (parent_pos_die_name == NULL || strcmp (parent_arg_die_name, parent_pos_die_name))
+ match = false;
+ }
+ }
+ break;
+
+ case DW_TAG_compile_unit:
+ done = true;
+ break;
+ }
+ }
+ parent_arg_die = parent_arg_die->GetParent();
+ parend_pos_die = parend_pos_die->GetParent();
+ }
+
+ if (match)
+ {
+ entry = *pos;
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
diff --git a/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h
new file mode 100644
index 000000000000..c85e175235ca
--- /dev/null
+++ b/source/Plugins/SymbolFile/DWARF/UniqueDWARFASTType.h
@@ -0,0 +1,175 @@
+//===-- UniqueDWARFASTType.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef lldb_UniqueDWARFASTType_h_
+#define lldb_UniqueDWARFASTType_h_
+
+// C Includes
+// C++ Includes
+#include <vector>
+
+// Other libraries and framework includes
+#include "llvm/ADT/DenseMap.h"
+
+// Project includes
+#include "lldb/Symbol/Declaration.h"
+
+class DWARFCompileUnit;
+class DWARFDebugInfoEntry;
+class SymbolFileDWARF;
+
+class UniqueDWARFASTType
+{
+public:
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ UniqueDWARFASTType () :
+ m_type_sp (),
+ m_symfile (NULL),
+ m_cu (NULL),
+ m_die (NULL),
+ m_declaration (),
+ m_byte_size (-1) // Set to negative value to make sure we have a valid value
+ {
+ }
+
+ UniqueDWARFASTType (lldb::TypeSP &type_sp,
+ SymbolFileDWARF *symfile,
+ DWARFCompileUnit *cu,
+ DWARFDebugInfoEntry *die,
+ const lldb_private::Declaration &decl,
+ int32_t byte_size) :
+ m_type_sp (type_sp),
+ m_symfile (symfile),
+ m_cu (cu),
+ m_die (die),
+ m_declaration (decl),
+ m_byte_size (byte_size)
+ {
+ }
+
+ UniqueDWARFASTType (const UniqueDWARFASTType &rhs) :
+ m_type_sp (rhs.m_type_sp),
+ m_symfile (rhs.m_symfile),
+ m_cu (rhs.m_cu),
+ m_die (rhs.m_die),
+ m_declaration (rhs.m_declaration),
+ m_byte_size (rhs.m_byte_size)
+ {
+ }
+
+ ~UniqueDWARFASTType()
+ {
+ }
+
+ UniqueDWARFASTType &
+ operator= (const UniqueDWARFASTType &rhs)
+ {
+ if (this != &rhs)
+ {
+ m_type_sp = rhs.m_type_sp;
+ m_symfile = rhs.m_symfile;
+ m_cu = rhs.m_cu;
+ m_die = rhs.m_die;
+ m_declaration = rhs.m_declaration;
+ m_byte_size = rhs.m_byte_size;
+ }
+ return *this;
+ }
+
+ lldb::TypeSP m_type_sp;
+ SymbolFileDWARF *m_symfile;
+ const DWARFCompileUnit *m_cu;
+ const DWARFDebugInfoEntry *m_die;
+ lldb_private::Declaration m_declaration;
+ int32_t m_byte_size;
+};
+
+class UniqueDWARFASTTypeList
+{
+public:
+ UniqueDWARFASTTypeList () :
+ m_collection()
+ {
+ }
+
+ ~UniqueDWARFASTTypeList ()
+ {
+ }
+
+ uint32_t
+ GetSize()
+ {
+ return (uint32_t)m_collection.size();
+ }
+
+ void
+ Append (const UniqueDWARFASTType &entry)
+ {
+ m_collection.push_back (entry);
+ }
+
+ bool
+ Find (SymbolFileDWARF *symfile,
+ const DWARFCompileUnit *cu,
+ const DWARFDebugInfoEntry *die,
+ const lldb_private::Declaration &decl,
+ const int32_t byte_size,
+ UniqueDWARFASTType &entry) const;
+
+protected:
+ typedef std::vector<UniqueDWARFASTType> collection;
+ collection m_collection;
+};
+
+class UniqueDWARFASTTypeMap
+{
+public:
+ UniqueDWARFASTTypeMap () :
+ m_collection ()
+ {
+ }
+
+ ~UniqueDWARFASTTypeMap ()
+ {
+ }
+
+ void
+ Insert (const lldb_private::ConstString &name,
+ const UniqueDWARFASTType &entry)
+ {
+ m_collection[name.GetCString()].Append (entry);
+ }
+
+ bool
+ Find (const lldb_private::ConstString &name,
+ SymbolFileDWARF *symfile,
+ const DWARFCompileUnit *cu,
+ const DWARFDebugInfoEntry *die,
+ const lldb_private::Declaration &decl,
+ const int32_t byte_size,
+ UniqueDWARFASTType &entry) const
+ {
+ const char *unique_name_cstr = name.GetCString();
+ collection::const_iterator pos = m_collection.find (unique_name_cstr);
+ if (pos != m_collection.end())
+ {
+ return pos->second.Find (symfile, cu, die, decl, byte_size, entry);
+ }
+ return false;
+ }
+
+protected:
+ // A unique name string should be used
+ typedef llvm::DenseMap<const char *, UniqueDWARFASTTypeList> collection;
+ collection m_collection;
+};
+
+#endif // lldb_UniqueDWARFASTType_h_
diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
new file mode 100644
index 000000000000..9beba517ec83
--- /dev/null
+++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.cpp
@@ -0,0 +1,407 @@
+//===-- SymbolFileSymtab.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolFileSymtab.h"
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/RegularExpression.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Symbol/ClangExternalASTSourceCommon.h"
+#include "lldb/Symbol/CompileUnit.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Symbol.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Symtab.h"
+#include "lldb/Symbol/TypeList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+SymbolFileSymtab::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SymbolFileSymtab::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+SymbolFileSymtab::GetPluginNameStatic()
+{
+ static ConstString g_name("symtab");
+ return g_name;
+}
+
+const char *
+SymbolFileSymtab::GetPluginDescriptionStatic()
+{
+ return "Reads debug symbols from an object file's symbol table.";
+}
+
+
+SymbolFile*
+SymbolFileSymtab::CreateInstance (ObjectFile* obj_file)
+{
+ return new SymbolFileSymtab(obj_file);
+}
+
+size_t
+SymbolFileSymtab::GetTypes (SymbolContextScope *sc_scope, uint32_t type_mask, lldb_private::TypeList &type_list)
+{
+ return 0;
+}
+
+SymbolFileSymtab::SymbolFileSymtab(ObjectFile* obj_file) :
+ SymbolFile(obj_file),
+ m_source_indexes(),
+ m_func_indexes(),
+ m_code_indexes(),
+ m_objc_class_name_to_index ()
+{
+}
+
+SymbolFileSymtab::~SymbolFileSymtab()
+{
+}
+
+ClangASTContext &
+SymbolFileSymtab::GetClangASTContext ()
+{
+ ClangASTContext &ast = m_obj_file->GetModule()->GetClangASTContext();
+
+ return ast;
+}
+
+uint32_t
+SymbolFileSymtab::CalculateAbilities ()
+{
+ uint32_t abilities = 0;
+ if (m_obj_file)
+ {
+ const Symtab *symtab = m_obj_file->GetSymtab();
+ if (symtab)
+ {
+ //----------------------------------------------------------------------
+ // The snippet of code below will get the indexes the module symbol
+ // table entries that are code, data, or function related (debug info),
+ // sort them by value (address) and dump the sorted symbols.
+ //----------------------------------------------------------------------
+ if (symtab->AppendSymbolIndexesWithType(eSymbolTypeSourceFile, m_source_indexes))
+ {
+ abilities |= CompileUnits;
+ }
+
+ if (symtab->AppendSymbolIndexesWithType(eSymbolTypeCode, Symtab::eDebugYes, Symtab::eVisibilityAny, m_func_indexes))
+ {
+ symtab->SortSymbolIndexesByValue(m_func_indexes, true);
+ abilities |= Functions;
+ }
+
+ if (symtab->AppendSymbolIndexesWithType(eSymbolTypeCode, Symtab::eDebugNo, Symtab::eVisibilityAny, m_code_indexes))
+ {
+ symtab->SortSymbolIndexesByValue(m_code_indexes, true);
+ }
+
+ if (symtab->AppendSymbolIndexesWithType(eSymbolTypeData, m_data_indexes))
+ {
+ symtab->SortSymbolIndexesByValue(m_data_indexes, true);
+ abilities |= GlobalVariables;
+ }
+
+ lldb_private::Symtab::IndexCollection objc_class_indexes;
+ if (symtab->AppendSymbolIndexesWithType (eSymbolTypeObjCClass, objc_class_indexes))
+ {
+ symtab->AppendSymbolNamesToMap (objc_class_indexes,
+ true,
+ true,
+ m_objc_class_name_to_index);
+ m_objc_class_name_to_index.Sort();
+ }
+ }
+ }
+ return abilities;
+}
+
+uint32_t
+SymbolFileSymtab::GetNumCompileUnits()
+{
+ // If we don't have any source file symbols we will just have one compile unit for
+ // the entire object file
+ if (m_source_indexes.empty())
+ return 0;
+
+ // If we have any source file symbols we will logically orgnize the object symbols
+ // using these.
+ return m_source_indexes.size();
+}
+
+CompUnitSP
+SymbolFileSymtab::ParseCompileUnitAtIndex(uint32_t idx)
+{
+ CompUnitSP cu_sp;
+
+ // If we don't have any source file symbols we will just have one compile unit for
+ // the entire object file
+ if (idx < m_source_indexes.size())
+ {
+ const Symbol *cu_symbol = m_obj_file->GetSymtab()->SymbolAtIndex(m_source_indexes[idx]);
+ if (cu_symbol)
+ cu_sp.reset(new CompileUnit (m_obj_file->GetModule(), NULL, cu_symbol->GetMangled().GetName().AsCString(), 0, eLanguageTypeUnknown));
+ }
+ return cu_sp;
+}
+
+lldb::LanguageType
+SymbolFileSymtab::ParseCompileUnitLanguage (const SymbolContext& sc)
+{
+ return eLanguageTypeUnknown;
+}
+
+
+size_t
+SymbolFileSymtab::ParseCompileUnitFunctions (const SymbolContext &sc)
+{
+ size_t num_added = 0;
+ // We must at least have a valid compile unit
+ assert (sc.comp_unit != NULL);
+ const Symtab *symtab = m_obj_file->GetSymtab();
+ const Symbol *curr_symbol = NULL;
+ const Symbol *next_symbol = NULL;
+// const char *prefix = m_obj_file->SymbolPrefix();
+// if (prefix == NULL)
+// prefix == "";
+//
+// const uint32_t prefix_len = strlen(prefix);
+
+ // If we don't have any source file symbols we will just have one compile unit for
+ // the entire object file
+ if (m_source_indexes.empty())
+ {
+ // The only time we will have a user ID of zero is when we don't have
+ // and source file symbols and we declare one compile unit for the
+ // entire object file
+ if (!m_func_indexes.empty())
+ {
+
+ }
+
+ if (!m_code_indexes.empty())
+ {
+// StreamFile s(stdout);
+// symtab->Dump(&s, m_code_indexes);
+
+ uint32_t idx = 0; // Index into the indexes
+ const uint32_t num_indexes = m_code_indexes.size();
+ for (idx = 0; idx < num_indexes; ++idx)
+ {
+ uint32_t symbol_idx = m_code_indexes[idx];
+ curr_symbol = symtab->SymbolAtIndex(symbol_idx);
+ if (curr_symbol)
+ {
+ // Union of all ranges in the function DIE (if the function is discontiguous)
+ AddressRange func_range(curr_symbol->GetAddress(), 0);
+ if (func_range.GetBaseAddress().IsSectionOffset())
+ {
+ uint32_t symbol_size = curr_symbol->GetByteSize();
+ if (symbol_size != 0 && !curr_symbol->GetSizeIsSibling())
+ func_range.SetByteSize(symbol_size);
+ else if (idx + 1 < num_indexes)
+ {
+ next_symbol = symtab->SymbolAtIndex(m_code_indexes[idx + 1]);
+ if (next_symbol)
+ {
+ func_range.SetByteSize(next_symbol->GetAddress().GetOffset() - curr_symbol->GetAddress().GetOffset());
+ }
+ }
+
+ FunctionSP func_sp(new Function(sc.comp_unit,
+ symbol_idx, // UserID is the DIE offset
+ LLDB_INVALID_UID, // We don't have any type info for this function
+ curr_symbol->GetMangled(), // Linker/mangled name
+ NULL, // no return type for a code symbol...
+ func_range)); // first address range
+
+ if (func_sp.get() != NULL)
+ {
+ sc.comp_unit->AddFunction(func_sp);
+ ++num_added;
+ }
+ }
+ }
+ }
+
+ }
+ }
+ else
+ {
+ // We assume we
+ }
+ return num_added;
+}
+
+bool
+SymbolFileSymtab::ParseCompileUnitLineTable (const SymbolContext &sc)
+{
+ return false;
+}
+
+bool
+SymbolFileSymtab::ParseCompileUnitSupportFiles (const SymbolContext& sc, FileSpecList &support_files)
+{
+ return false;
+}
+
+size_t
+SymbolFileSymtab::ParseFunctionBlocks (const SymbolContext &sc)
+{
+ return 0;
+}
+
+
+size_t
+SymbolFileSymtab::ParseTypes (const SymbolContext &sc)
+{
+ return 0;
+}
+
+
+size_t
+SymbolFileSymtab::ParseVariablesForContext (const SymbolContext& sc)
+{
+ return 0;
+}
+
+Type*
+SymbolFileSymtab::ResolveTypeUID(lldb::user_id_t type_uid)
+{
+ return NULL;
+}
+
+bool
+SymbolFileSymtab::ResolveClangOpaqueTypeDefinition (lldb_private::ClangASTType& clang_opaque_type)
+{
+ return false;
+}
+
+ClangNamespaceDecl
+SymbolFileSymtab::FindNamespace (const SymbolContext& sc, const ConstString &name, const ClangNamespaceDecl *namespace_decl)
+{
+ return ClangNamespaceDecl();
+}
+
+uint32_t
+SymbolFileSymtab::ResolveSymbolContext (const Address& so_addr, uint32_t resolve_scope, SymbolContext& sc)
+{
+ if (m_obj_file->GetSymtab() == NULL)
+ return 0;
+
+ uint32_t resolved_flags = 0;
+ if (resolve_scope & eSymbolContextSymbol)
+ {
+ sc.symbol = m_obj_file->GetSymtab()->FindSymbolContainingFileAddress(so_addr.GetFileAddress());
+ if (sc.symbol)
+ resolved_flags |= eSymbolContextSymbol;
+ }
+ return resolved_flags;
+}
+
+uint32_t
+SymbolFileSymtab::ResolveSymbolContext (const FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, SymbolContextList& sc_list)
+{
+ return 0;
+}
+
+uint32_t
+SymbolFileSymtab::FindGlobalVariables(const ConstString &name, const ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, VariableList& variables)
+{
+ return 0;
+}
+
+uint32_t
+SymbolFileSymtab::FindGlobalVariables(const RegularExpression& regex, bool append, uint32_t max_matches, VariableList& variables)
+{
+ return 0;
+}
+
+uint32_t
+SymbolFileSymtab::FindFunctions(const ConstString &name, const ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileSymtab::FindFunctions (name = '%s')",
+ name.GetCString());
+ // If we ever support finding STABS or COFF debug info symbols,
+ // we will need to add support here. We are not trying to find symbols
+ // here, just "lldb_private::Function" objects that come from complete
+ // debug information. Any symbol queries should go through the symbol
+ // table itself in the module's object file.
+ return 0;
+}
+
+uint32_t
+SymbolFileSymtab::FindFunctions(const RegularExpression& regex, bool include_inlines, bool append, SymbolContextList& sc_list)
+{
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolFileSymtab::FindFunctions (regex = '%s')",
+ regex.GetText());
+ // If we ever support finding STABS or COFF debug info symbols,
+ // we will need to add support here. We are not trying to find symbols
+ // here, just "lldb_private::Function" objects that come from complete
+ // debug information. Any symbol queries should go through the symbol
+ // table itself in the module's object file.
+ return 0;
+}
+
+static int CountMethodArgs(const char *method_signature)
+{
+ int num_args = 0;
+
+ for (const char *colon_pos = strchr(method_signature, ':');
+ colon_pos != NULL;
+ colon_pos = strchr(colon_pos + 1, ':'))
+ {
+ num_args++;
+ }
+
+ return num_args;
+}
+
+uint32_t
+SymbolFileSymtab::FindTypes (const lldb_private::SymbolContext& sc,
+ const lldb_private::ConstString &name,
+ const ClangNamespaceDecl *namespace_decl,
+ bool append,
+ uint32_t max_matches,
+ lldb_private::TypeList& types)
+{
+ return 0;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+lldb_private::ConstString
+SymbolFileSymtab::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SymbolFileSymtab::GetPluginVersion()
+{
+ return 1;
+}
diff --git a/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
new file mode 100644
index 000000000000..914efe6eb3c2
--- /dev/null
+++ b/source/Plugins/SymbolFile/Symtab/SymbolFileSymtab.h
@@ -0,0 +1,142 @@
+//===-- SymbolFileSymtab.h --------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_SymbolFileSymtab_h_
+#define liblldb_SymbolFileSymtab_h_
+
+#include "lldb/Symbol/SymbolFile.h"
+#include "lldb/Symbol/Symtab.h"
+#include <vector>
+
+class SymbolFileSymtab : public lldb_private::SymbolFile
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolFile*
+ CreateInstance (lldb_private::ObjectFile* obj_file);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolFileSymtab(lldb_private::ObjectFile* obj_file);
+
+ virtual
+ ~SymbolFileSymtab();
+
+ virtual uint32_t CalculateAbilities ();
+
+ //------------------------------------------------------------------
+ // Compile Unit function calls
+ //------------------------------------------------------------------
+ virtual uint32_t
+ GetNumCompileUnits();
+
+ virtual lldb::CompUnitSP
+ ParseCompileUnitAtIndex(uint32_t index);
+
+ virtual lldb::LanguageType
+ ParseCompileUnitLanguage (const lldb_private::SymbolContext& sc);
+
+ virtual size_t
+ ParseCompileUnitFunctions (const lldb_private::SymbolContext& sc);
+
+ virtual bool
+ ParseCompileUnitLineTable (const lldb_private::SymbolContext& sc);
+
+ virtual bool
+ ParseCompileUnitSupportFiles (const lldb_private::SymbolContext& sc, lldb_private::FileSpecList &support_files);
+
+ virtual size_t
+ ParseFunctionBlocks (const lldb_private::SymbolContext& sc);
+
+ virtual size_t
+ ParseTypes (const lldb_private::SymbolContext& sc);
+
+ virtual size_t
+ ParseVariablesForContext (const lldb_private::SymbolContext& sc);
+
+ virtual lldb_private::Type*
+ ResolveTypeUID(lldb::user_id_t type_uid);
+
+ virtual bool
+ ResolveClangOpaqueTypeDefinition (lldb_private::ClangASTType& clang_type);
+
+ virtual uint32_t
+ ResolveSymbolContext (const lldb_private::Address& so_addr, uint32_t resolve_scope, lldb_private::SymbolContext& sc);
+
+ virtual uint32_t
+ ResolveSymbolContext (const lldb_private::FileSpec& file_spec, uint32_t line, bool check_inlines, uint32_t resolve_scope, lldb_private::SymbolContextList& sc_list);
+
+ virtual uint32_t
+ FindGlobalVariables(const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+
+ virtual uint32_t
+ FindGlobalVariables(const lldb_private::RegularExpression& regex, bool append, uint32_t max_matches, lldb_private::VariableList& variables);
+
+ virtual uint32_t
+ FindFunctions(const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, uint32_t name_type_mask, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list);
+
+ virtual uint32_t
+ FindFunctions(const lldb_private::RegularExpression& regex, bool include_inlines, bool append, lldb_private::SymbolContextList& sc_list);
+
+ virtual uint32_t
+ FindTypes (const lldb_private::SymbolContext& sc,const lldb_private::ConstString &name, const lldb_private::ClangNamespaceDecl *namespace_decl, bool append, uint32_t max_matches, lldb_private::TypeList& types);
+
+ virtual size_t
+ GetTypes (lldb_private::SymbolContextScope *sc_scope,
+ uint32_t type_mask,
+ lldb_private::TypeList &type_list);
+
+ virtual lldb_private::ClangNamespaceDecl
+ FindNamespace (const lldb_private::SymbolContext& sc,
+ const lldb_private::ConstString &name,
+ const lldb_private::ClangNamespaceDecl *parent_namespace_decl);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+protected:
+ typedef std::map<lldb_private::ConstString, lldb::TypeSP> TypeMap;
+
+ lldb_private::Symtab::IndexCollection m_source_indexes;
+ lldb_private::Symtab::IndexCollection m_func_indexes;
+ lldb_private::Symtab::IndexCollection m_code_indexes;
+ lldb_private::Symtab::IndexCollection m_data_indexes;
+ lldb_private::Symtab::NameToIndexMap m_objc_class_name_to_index;
+ TypeMap m_objc_class_types;
+
+ lldb_private::ClangASTContext &
+ GetClangASTContext ();
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (SymbolFileSymtab);
+};
+
+
+#endif // liblldb_SymbolFileSymtab_h_
diff --git a/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp b/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp
new file mode 100644
index 000000000000..6500aabdcea3
--- /dev/null
+++ b/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.cpp
@@ -0,0 +1,199 @@
+//===-- SymbolVendorELF.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolVendorELF.h"
+
+//#include <libxml/parser.h>
+// #include <libxml/tree.h>
+#include <string.h>
+
+// #include <AvailabilityMacros.h>
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/Section.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Core/Timer.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Host/Symbols.h"
+#include "lldb/Symbol/ObjectFile.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// SymbolVendorELF constructor
+//----------------------------------------------------------------------
+SymbolVendorELF::SymbolVendorELF(const lldb::ModuleSP &module_sp) :
+ SymbolVendor (module_sp)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+SymbolVendorELF::~SymbolVendorELF()
+{
+}
+
+void
+SymbolVendorELF::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+SymbolVendorELF::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+SymbolVendorELF::GetPluginNameStatic()
+{
+ static ConstString g_name("ELF");
+ return g_name;
+}
+
+const char *
+SymbolVendorELF::GetPluginDescriptionStatic()
+{
+ return "Symbol vendor for ELF that looks for dSYM files that match executables.";
+}
+
+
+
+//----------------------------------------------------------------------
+// CreateInstance
+//
+// Platforms can register a callback to use when creating symbol
+// vendors to allow for complex debug information file setups, and to
+// also allow for finding separate debug information files.
+//----------------------------------------------------------------------
+SymbolVendor*
+SymbolVendorELF::CreateInstance (const lldb::ModuleSP &module_sp, lldb_private::Stream *feedback_strm)
+{
+ if (!module_sp)
+ return NULL;
+
+ ObjectFile *obj_file = module_sp->GetObjectFile();
+ if (!obj_file)
+ return NULL;
+
+ static ConstString obj_file_elf("elf");
+ ConstString obj_name = obj_file->GetPluginName();
+ if (obj_name != obj_file_elf)
+ return NULL;
+
+ lldb_private::UUID uuid;
+ if (!obj_file->GetUUID (&uuid))
+ return NULL;
+
+ // Get the .gnu_debuglink file (if specified).
+ FileSpecList file_spec_list = obj_file->GetDebugSymbolFilePaths();
+
+ // If the module specified a filespec, use it first.
+ FileSpec debug_symbol_fspec (module_sp->GetSymbolFileFileSpec());
+ if (debug_symbol_fspec)
+ file_spec_list.Insert (0, debug_symbol_fspec);
+
+ // If we have no debug symbol files, then nothing to do.
+ if (file_spec_list.IsEmpty())
+ return NULL;
+
+ Timer scoped_timer (__PRETTY_FUNCTION__,
+ "SymbolVendorELF::CreateInstance (module = %s)",
+ module_sp->GetFileSpec().GetPath().c_str());
+
+ for (size_t idx = 0; idx < file_spec_list.GetSize(); ++idx)
+ {
+ ModuleSpec module_spec;
+ const FileSpec fspec = file_spec_list.GetFileSpecAtIndex (idx);
+
+ module_spec.GetFileSpec() = obj_file->GetFileSpec();
+ module_spec.GetFileSpec().ResolvePath();
+ module_spec.GetSymbolFileSpec() = fspec;
+ module_spec.GetUUID() = uuid;
+ FileSpec dsym_fspec = Symbols::LocateExecutableSymbolFile (module_spec);
+ if (dsym_fspec)
+ {
+ DataBufferSP dsym_file_data_sp;
+ lldb::offset_t dsym_file_data_offset = 0;
+ ObjectFileSP dsym_objfile_sp = ObjectFile::FindPlugin(module_sp, &dsym_fspec, 0, dsym_fspec.GetByteSize(), dsym_file_data_sp, dsym_file_data_offset);
+ if (dsym_objfile_sp)
+ {
+ // This objfile is for debugging purposes. Sadly, ObjectFileELF won't be able
+ // to figure this out consistently as the symbol file may not have stripped the
+ // code sections, etc.
+ dsym_objfile_sp->SetType (ObjectFile::eTypeDebugInfo);
+
+ SymbolVendorELF* symbol_vendor = new SymbolVendorELF(module_sp);
+ if (symbol_vendor)
+ {
+ // Get the module unified section list and add our debug sections to that.
+ SectionList *module_section_list = module_sp->GetSectionList();
+ SectionList *objfile_section_list = dsym_objfile_sp->GetSectionList();
+
+ static const SectionType g_sections[] =
+ {
+ eSectionTypeDWARFDebugAranges,
+ eSectionTypeDWARFDebugInfo,
+ eSectionTypeDWARFDebugAbbrev,
+ eSectionTypeDWARFDebugFrame,
+ eSectionTypeDWARFDebugLine,
+ eSectionTypeDWARFDebugStr,
+ eSectionTypeDWARFDebugLoc,
+ eSectionTypeDWARFDebugMacInfo,
+ eSectionTypeDWARFDebugPubNames,
+ eSectionTypeDWARFDebugPubTypes,
+ eSectionTypeDWARFDebugRanges,
+ eSectionTypeELFSymbolTable,
+ };
+ for (size_t idx = 0; idx < sizeof(g_sections) / sizeof(g_sections[0]); ++idx)
+ {
+ SectionType section_type = g_sections[idx];
+ SectionSP section_sp (objfile_section_list->FindSectionByType (section_type, true));
+ if (section_sp)
+ {
+ SectionSP module_section_sp (module_section_list->FindSectionByType (section_type, true));
+ if (module_section_sp)
+ module_section_list->ReplaceSection (module_section_sp->GetID(), section_sp);
+ else
+ module_section_list->AddSection (section_sp);
+ }
+ }
+
+ symbol_vendor->AddSymbolFileRepresentation (dsym_objfile_sp);
+ return symbol_vendor;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+//------------------------------------------------------------------
+// PluginInterface protocol
+//------------------------------------------------------------------
+ConstString
+SymbolVendorELF::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+SymbolVendorELF::GetPluginVersion()
+{
+ return 1;
+}
+
diff --git a/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h b/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h
new file mode 100644
index 000000000000..acd62b6cc3ab
--- /dev/null
+++ b/source/Plugins/SymbolVendor/ELF/SymbolVendorELF.h
@@ -0,0 +1,58 @@
+//===-- SymbolVendorELF.h ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_SymbolVendorELF_h_
+#define liblldb_SymbolVendorELF_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Symbol/SymbolVendor.h"
+
+class SymbolVendorELF : public lldb_private::SymbolVendor
+{
+public:
+ //------------------------------------------------------------------
+ // Static Functions
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ static lldb_private::SymbolVendor*
+ CreateInstance (const lldb::ModuleSP &module_sp, lldb_private::Stream *feedback_strm);
+
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ SymbolVendorELF (const lldb::ModuleSP &module_sp);
+
+ virtual
+ ~SymbolVendorELF();
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+private:
+ DISALLOW_COPY_AND_ASSIGN (SymbolVendorELF);
+};
+
+#endif // liblldb_SymbolVendorELF_h_
diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
new file mode 100644
index 000000000000..c93dea9b5d3c
--- /dev/null
+++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
@@ -0,0 +1,670 @@
+//===-- UnwindAssemblyInstEmulation.cpp --------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnwindAssemblyInstEmulation.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Disassembler.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/StreamString.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+
+
+//-----------------------------------------------------------------------------------------------
+// UnwindAssemblyInstEmulation method definitions
+//-----------------------------------------------------------------------------------------------
+
+bool
+UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& range,
+ Thread& thread,
+ UnwindPlan& unwind_plan)
+{
+ if (range.GetByteSize() > 0 &&
+ range.GetBaseAddress().IsValid() &&
+ m_inst_emulator_ap.get())
+ {
+
+ // The the instruction emulation subclass setup the unwind plan for the
+ // first instruction.
+ m_inst_emulator_ap->CreateFunctionEntryUnwind (unwind_plan);
+
+ // CreateFunctionEntryUnwind should have created the first row. If it
+ // doesn't, then we are done.
+ if (unwind_plan.GetRowCount() == 0)
+ return false;
+
+ ExecutionContext exe_ctx;
+ thread.CalculateExecutionContext(exe_ctx);
+ DisassemblerSP disasm_sp (Disassembler::DisassembleRange (m_arch,
+ NULL,
+ NULL,
+ exe_ctx,
+ range));
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+
+ if (disasm_sp)
+ {
+
+ m_range_ptr = &range;
+ m_thread_ptr = &thread;
+ m_unwind_plan_ptr = &unwind_plan;
+
+ const uint32_t addr_byte_size = m_arch.GetAddressByteSize();
+ const bool show_address = true;
+ const bool show_bytes = true;
+ m_inst_emulator_ap->GetRegisterInfo (unwind_plan.GetRegisterKind(),
+ unwind_plan.GetInitialCFARegister(),
+ m_cfa_reg_info);
+
+ m_fp_is_cfa = false;
+ m_register_values.clear();
+ m_pushed_regs.clear();
+
+ // Initialize the CFA with a known value. In the 32 bit case
+ // it will be 0x80000000, and in the 64 bit case 0x8000000000000000.
+ // We use the address byte size to be safe for any future addresss sizes
+ m_initial_sp = (1ull << ((addr_byte_size * 8) - 1));
+ RegisterValue cfa_reg_value;
+ cfa_reg_value.SetUInt (m_initial_sp, m_cfa_reg_info.byte_size);
+ SetRegisterValue (m_cfa_reg_info, cfa_reg_value);
+
+ const InstructionList &inst_list = disasm_sp->GetInstructionList ();
+ const size_t num_instructions = inst_list.GetSize();
+
+ if (num_instructions > 0)
+ {
+ Instruction *inst = inst_list.GetInstructionAtIndex (0).get();
+ const addr_t base_addr = inst->GetAddress().GetFileAddress();
+
+ // Make a copy of the current instruction Row and save it in m_curr_row
+ // so we can add updates as we process the instructions.
+ UnwindPlan::RowSP last_row = unwind_plan.GetLastRow();
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ if (last_row.get())
+ *newrow = *last_row.get();
+ m_curr_row.reset(newrow);
+
+ // Once we've seen the initial prologue instructions complete, save a
+ // copy of the CFI at that point into prologue_completed_row for possible
+ // use later.
+ int instructions_since_last_prologue_insn = 0; // # of insns since last CFI was update
+
+ bool reinstate_prologue_next_instruction = false; // Next iteration, re-install the prologue row of CFI
+
+ bool last_instruction_restored_return_addr_reg = false; // re-install the prologue row of CFI if the next instruction is a branch immediate
+
+ bool return_address_register_has_been_saved = false; // if we've seen the ra register get saved yet
+
+ UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI
+
+ // cache the pc register number (in whatever register numbering this UnwindPlan uses) for
+ // quick reference during instruction parsing.
+ uint32_t pc_reg_num = LLDB_INVALID_REGNUM;
+ RegisterInfo pc_reg_info;
+ if (m_inst_emulator_ap->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info))
+ pc_reg_num = pc_reg_info.kinds[unwind_plan.GetRegisterKind()];
+ else
+ pc_reg_num = LLDB_INVALID_REGNUM;
+
+ // cache the return address register number (in whatever register numbering this UnwindPlan uses) for
+ // quick reference during instruction parsing.
+ uint32_t ra_reg_num = LLDB_INVALID_REGNUM;
+ RegisterInfo ra_reg_info;
+ if (m_inst_emulator_ap->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, ra_reg_info))
+ ra_reg_num = ra_reg_info.kinds[unwind_plan.GetRegisterKind()];
+ else
+ ra_reg_num = LLDB_INVALID_REGNUM;
+
+ for (size_t idx=0; idx<num_instructions; ++idx)
+ {
+ m_curr_row_modified = false;
+ m_curr_insn_restored_a_register = false;
+ inst = inst_list.GetInstructionAtIndex (idx).get();
+ if (inst)
+ {
+ if (log && log->GetVerbose ())
+ {
+ StreamString strm;
+ inst->Dump(&strm, inst_list.GetMaxOpcocdeByteSize (), show_address, show_bytes, NULL);
+ log->PutCString (strm.GetData());
+ }
+
+ m_inst_emulator_ap->SetInstruction (inst->GetOpcode(),
+ inst->GetAddress(),
+ exe_ctx.GetTargetPtr());
+
+ m_inst_emulator_ap->EvaluateInstruction (eEmulateInstructionOptionIgnoreConditions);
+
+ // Were there any changes to the CFI while evaluating this instruction?
+ if (m_curr_row_modified)
+ {
+ reinstate_prologue_next_instruction = false;
+ m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
+ // Append the new row
+ unwind_plan.AppendRow (m_curr_row);
+
+ // Allocate a new Row for m_curr_row, copy the current state into it
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *m_curr_row.get();
+ m_curr_row.reset(newrow);
+
+ // If m_curr_insn_restored_a_register == true, we're looking at an epilogue instruction.
+ // Set instructions_since_last_prologue_insn to a very high number so we don't append
+ // any of these epilogue instructions to our prologue_complete row.
+ if (m_curr_insn_restored_a_register == false && instructions_since_last_prologue_insn < 8)
+ instructions_since_last_prologue_insn = 0;
+ else
+ instructions_since_last_prologue_insn = 99;
+
+ UnwindPlan::Row::RegisterLocation pc_regloc;
+ UnwindPlan::Row::RegisterLocation ra_regloc;
+
+ // While parsing the instructions of this function, if we've ever
+ // seen the return address register (aka lr on arm) in a non-IsSame() state,
+ // it has been saved on the stack. If it's evern back to IsSame(), we've
+ // executed an epilogue.
+ if (ra_reg_num != LLDB_INVALID_REGNUM
+ && m_curr_row->GetRegisterInfo (ra_reg_num, ra_regloc)
+ && !ra_regloc.IsSame())
+ {
+ return_address_register_has_been_saved = true;
+ }
+
+ // If the caller's pc is "same", we've just executed an epilogue and we return to the caller
+ // after this instruction completes executing.
+ // If there are any instructions past this, there must have been flow control over this
+ // epilogue so we'll reinstate the original prologue setup instructions.
+ if (prologue_completed_row.get()
+ && pc_reg_num != LLDB_INVALID_REGNUM
+ && m_curr_row->GetRegisterInfo (pc_reg_num, pc_regloc)
+ && pc_regloc.IsSame())
+ {
+ if (log && log->GetVerbose())
+ log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- pc is <same>, restore prologue instructions.");
+ reinstate_prologue_next_instruction = true;
+ }
+ else if (prologue_completed_row.get()
+ && return_address_register_has_been_saved
+ && ra_reg_num != LLDB_INVALID_REGNUM
+ && m_curr_row->GetRegisterInfo (ra_reg_num, ra_regloc)
+ && ra_regloc.IsSame())
+ {
+ if (log && log->GetVerbose())
+ log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- lr is <same>, restore prologue instruction if the next instruction is a branch immediate.");
+ last_instruction_restored_return_addr_reg = true;
+ }
+ }
+ else
+ {
+ // If the previous instruction was a return-to-caller (epilogue), and we're still executing
+ // instructions in this function, there must be a code path that jumps over that epilogue.
+ // Also detect the case where we epilogue & branch imm to another function (tail-call opt)
+ // instead of a normal pop lr-into-pc exit.
+ // Reinstate the frame setup from the prologue.
+ if (reinstate_prologue_next_instruction
+ || (m_curr_insn_is_branch_immediate && last_instruction_restored_return_addr_reg))
+ {
+ if (log && log->GetVerbose())
+ log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- Reinstating prologue instruction set");
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *prologue_completed_row.get();
+ m_curr_row.reset(newrow);
+ m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr);
+ unwind_plan.AppendRow(m_curr_row);
+
+ newrow = new UnwindPlan::Row;
+ *newrow = *m_curr_row.get();
+ m_curr_row.reset(newrow);
+
+ reinstate_prologue_next_instruction = false;
+ last_instruction_restored_return_addr_reg = false;
+ m_curr_insn_is_branch_immediate = false;
+ }
+
+ // clear both of these if either one wasn't set
+ if (last_instruction_restored_return_addr_reg)
+ {
+ last_instruction_restored_return_addr_reg = false;
+ }
+ if (m_curr_insn_is_branch_immediate)
+ {
+ m_curr_insn_is_branch_immediate = false;
+ }
+
+ // Stop updating the prologue instructions if we've seen 8 non-prologue instructions
+ // in a row.
+ if (instructions_since_last_prologue_insn++ < 8)
+ {
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *m_curr_row.get();
+ prologue_completed_row.reset(newrow);
+ if (log && log->GetVerbose())
+ log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- saving a copy of the current row as the prologue row.");
+ }
+ }
+ }
+ }
+ }
+ // FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
+ // I'll fix that but for now, just clear the list and it will go away nicely.
+ disasm_sp->GetInstructionList().Clear();
+ }
+
+ if (log && log->GetVerbose ())
+ {
+ StreamString strm;
+ lldb::addr_t base_addr = range.GetBaseAddress().GetLoadAddress(thread.CalculateTarget().get());
+ strm.Printf ("Resulting unwind rows for [0x%" PRIx64 " - 0x%" PRIx64 "):", base_addr, base_addr + range.GetByteSize());
+ unwind_plan.Dump(strm, &thread, base_addr);
+ log->PutCString (strm.GetData());
+ }
+ return unwind_plan.GetRowCount() > 0;
+ }
+ return false;
+}
+
+bool
+UnwindAssemblyInstEmulation::GetFastUnwindPlan (AddressRange& func,
+ Thread& thread,
+ UnwindPlan &unwind_plan)
+{
+ return false;
+}
+
+bool
+UnwindAssemblyInstEmulation::FirstNonPrologueInsn (AddressRange& func,
+ const ExecutionContext &exe_ctx,
+ Address& first_non_prologue_insn)
+{
+ return false;
+}
+
+UnwindAssembly *
+UnwindAssemblyInstEmulation::CreateInstance (const ArchSpec &arch)
+{
+ std::unique_ptr<EmulateInstruction> inst_emulator_ap (EmulateInstruction::FindPlugin (arch, eInstructionTypePrologueEpilogue, NULL));
+ // Make sure that all prologue instructions are handled
+ if (inst_emulator_ap.get())
+ return new UnwindAssemblyInstEmulation (arch, inst_emulator_ap.release());
+ return NULL;
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol in UnwindAssemblyParser_x86
+//------------------------------------------------------------------
+ConstString
+UnwindAssemblyInstEmulation::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+uint32_t
+UnwindAssemblyInstEmulation::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+UnwindAssemblyInstEmulation::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+UnwindAssemblyInstEmulation::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+ConstString
+UnwindAssemblyInstEmulation::GetPluginNameStatic()
+{
+ static ConstString g_name("inst-emulation");
+ return g_name;
+}
+
+const char *
+UnwindAssemblyInstEmulation::GetPluginDescriptionStatic()
+{
+ return "Instruction emulation based unwind information.";
+}
+
+
+uint64_t
+UnwindAssemblyInstEmulation::MakeRegisterKindValuePair (const RegisterInfo &reg_info)
+{
+ uint32_t reg_kind, reg_num;
+ if (EmulateInstruction::GetBestRegisterKindAndNumber (&reg_info, reg_kind, reg_num))
+ return (uint64_t)reg_kind << 24 | reg_num;
+ return 0ull;
+}
+
+void
+UnwindAssemblyInstEmulation::SetRegisterValue (const RegisterInfo &reg_info, const RegisterValue &reg_value)
+{
+ m_register_values[MakeRegisterKindValuePair (reg_info)] = reg_value;
+}
+
+bool
+UnwindAssemblyInstEmulation::GetRegisterValue (const RegisterInfo &reg_info, RegisterValue &reg_value)
+{
+ const uint64_t reg_id = MakeRegisterKindValuePair (reg_info);
+ RegisterValueMap::const_iterator pos = m_register_values.find(reg_id);
+ if (pos != m_register_values.end())
+ {
+ reg_value = pos->second;
+ return true; // We had a real value that comes from an opcode that wrote
+ // to it...
+ }
+ // We are making up a value that is recognizable...
+ reg_value.SetUInt(reg_id, reg_info.byte_size);
+ return false;
+}
+
+
+size_t
+UnwindAssemblyInstEmulation::ReadMemory (EmulateInstruction *instruction,
+ void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t dst_len)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+
+ if (log && log->GetVerbose ())
+ {
+ StreamString strm;
+ strm.Printf ("UnwindAssemblyInstEmulation::ReadMemory (addr = 0x%16.16" PRIx64 ", dst = %p, dst_len = %" PRIu64 ", context = ",
+ addr,
+ dst,
+ (uint64_t)dst_len);
+ context.Dump(strm, instruction);
+ log->PutCString (strm.GetData ());
+ }
+ memset (dst, 0, dst_len);
+ return dst_len;
+}
+
+size_t
+UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
+ void *baton,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t dst_len)
+{
+ if (baton && dst && dst_len)
+ return ((UnwindAssemblyInstEmulation *)baton)->WriteMemory (instruction, context, addr, dst, dst_len);
+ return 0;
+}
+
+size_t
+UnwindAssemblyInstEmulation::WriteMemory (EmulateInstruction *instruction,
+ const EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t dst_len)
+{
+ DataExtractor data (dst,
+ dst_len,
+ instruction->GetArchitecture ().GetByteOrder(),
+ instruction->GetArchitecture ().GetAddressByteSize());
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+
+ if (log && log->GetVerbose ())
+ {
+ StreamString strm;
+
+ strm.PutCString ("UnwindAssemblyInstEmulation::WriteMemory (");
+ data.Dump(&strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX, addr, 0, 0);
+ strm.PutCString (", context = ");
+ context.Dump(strm, instruction);
+ log->PutCString (strm.GetData());
+ }
+
+ const bool can_replace = true;
+ const bool cant_replace = false;
+
+ switch (context.type)
+ {
+ default:
+ case EmulateInstruction::eContextInvalid:
+ case EmulateInstruction::eContextReadOpcode:
+ case EmulateInstruction::eContextImmediate:
+ case EmulateInstruction::eContextAdjustBaseRegister:
+ case EmulateInstruction::eContextRegisterPlusOffset:
+ case EmulateInstruction::eContextAdjustPC:
+ case EmulateInstruction::eContextRegisterStore:
+ case EmulateInstruction::eContextRegisterLoad:
+ case EmulateInstruction::eContextRelativeBranchImmediate:
+ case EmulateInstruction::eContextAbsoluteBranchRegister:
+ case EmulateInstruction::eContextSupervisorCall:
+ case EmulateInstruction::eContextTableBranchReadMemory:
+ case EmulateInstruction::eContextWriteRegisterRandomBits:
+ case EmulateInstruction::eContextWriteMemoryRandomBits:
+ case EmulateInstruction::eContextArithmetic:
+ case EmulateInstruction::eContextAdvancePC:
+ case EmulateInstruction::eContextReturnFromException:
+ case EmulateInstruction::eContextPopRegisterOffStack:
+ case EmulateInstruction::eContextAdjustStackPointer:
+ break;
+
+ case EmulateInstruction::eContextPushRegisterOnStack:
+ {
+ uint32_t reg_num = LLDB_INVALID_REGNUM;
+ bool is_return_address_reg = false;
+ const uint32_t unwind_reg_kind = m_unwind_plan_ptr->GetRegisterKind();
+ if (context.info_type == EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset)
+ {
+ reg_num = context.info.RegisterToRegisterPlusOffset.data_reg.kinds[unwind_reg_kind];
+ if (context.info.RegisterToRegisterPlusOffset.data_reg.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_RA)
+ is_return_address_reg = true;
+ }
+ else
+ {
+ assert (!"unhandled case, add code to handle this!");
+ }
+
+ if (reg_num != LLDB_INVALID_REGNUM)
+ {
+ if (m_pushed_regs.find (reg_num) == m_pushed_regs.end())
+ {
+ m_pushed_regs[reg_num] = addr;
+ const int32_t offset = addr - m_initial_sp;
+ m_curr_row->SetRegisterLocationToAtCFAPlusOffset (reg_num, offset, cant_replace);
+ m_curr_row_modified = true;
+ if (is_return_address_reg)
+ {
+ // This push was pushing the return address register,
+ // so this is also how we will unwind the PC...
+ RegisterInfo pc_reg_info;
+ if (instruction->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, pc_reg_info))
+ {
+ uint32_t pc_reg_num = pc_reg_info.kinds[unwind_reg_kind];
+ if (pc_reg_num != LLDB_INVALID_REGNUM)
+ {
+ m_curr_row->SetRegisterLocationToAtCFAPlusOffset (pc_reg_num, offset, can_replace);
+ m_curr_row_modified = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ }
+
+ return dst_len;
+}
+
+bool
+UnwindAssemblyInstEmulation::ReadRegister (EmulateInstruction *instruction,
+ void *baton,
+ const RegisterInfo *reg_info,
+ RegisterValue &reg_value)
+{
+
+ if (baton && reg_info)
+ return ((UnwindAssemblyInstEmulation *)baton)->ReadRegister (instruction, reg_info, reg_value);
+ return false;
+}
+bool
+UnwindAssemblyInstEmulation::ReadRegister (EmulateInstruction *instruction,
+ const RegisterInfo *reg_info,
+ RegisterValue &reg_value)
+{
+ bool synthetic = GetRegisterValue (*reg_info, reg_value);
+
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+
+ if (log && log->GetVerbose ())
+ {
+
+ StreamString strm;
+ strm.Printf ("UnwindAssemblyInstEmulation::ReadRegister (name = \"%s\") => synthetic_value = %i, value = ", reg_info->name, synthetic);
+ reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
+ log->PutCString(strm.GetData());
+ }
+ return true;
+}
+
+bool
+UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
+ void *baton,
+ const EmulateInstruction::Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue &reg_value)
+{
+ if (baton && reg_info)
+ return ((UnwindAssemblyInstEmulation *)baton)->WriteRegister (instruction, context, reg_info, reg_value);
+ return false;
+}
+bool
+UnwindAssemblyInstEmulation::WriteRegister (EmulateInstruction *instruction,
+ const EmulateInstruction::Context &context,
+ const RegisterInfo *reg_info,
+ const RegisterValue &reg_value)
+{
+ Log *log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_UNWIND));
+
+ if (log && log->GetVerbose ())
+ {
+
+ StreamString strm;
+ strm.Printf ("UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ", reg_info->name);
+ reg_value.Dump(&strm, reg_info, false, false, eFormatDefault);
+ strm.PutCString (", context = ");
+ context.Dump(strm, instruction);
+ log->PutCString(strm.GetData());
+ }
+
+ const bool must_replace = true;
+ SetRegisterValue (*reg_info, reg_value);
+
+ switch (context.type)
+ {
+ case EmulateInstruction::eContextInvalid:
+ case EmulateInstruction::eContextReadOpcode:
+ case EmulateInstruction::eContextImmediate:
+ case EmulateInstruction::eContextAdjustBaseRegister:
+ case EmulateInstruction::eContextRegisterPlusOffset:
+ case EmulateInstruction::eContextAdjustPC:
+ case EmulateInstruction::eContextRegisterStore:
+ case EmulateInstruction::eContextRegisterLoad:
+ case EmulateInstruction::eContextAbsoluteBranchRegister:
+ case EmulateInstruction::eContextSupervisorCall:
+ case EmulateInstruction::eContextTableBranchReadMemory:
+ case EmulateInstruction::eContextWriteRegisterRandomBits:
+ case EmulateInstruction::eContextWriteMemoryRandomBits:
+ case EmulateInstruction::eContextArithmetic:
+ case EmulateInstruction::eContextAdvancePC:
+ case EmulateInstruction::eContextReturnFromException:
+ case EmulateInstruction::eContextPushRegisterOnStack:
+// {
+// const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
+// if (reg_num != LLDB_INVALID_REGNUM)
+// {
+// const bool can_replace_only_if_unspecified = true;
+//
+// m_curr_row.SetRegisterLocationToUndefined (reg_num,
+// can_replace_only_if_unspecified,
+// can_replace_only_if_unspecified);
+// m_curr_row_modified = true;
+// }
+// }
+ break;
+
+ case EmulateInstruction::eContextRelativeBranchImmediate:
+ {
+
+ {
+ m_curr_insn_is_branch_immediate = true;
+ }
+ }
+ break;
+
+ case EmulateInstruction::eContextPopRegisterOffStack:
+ {
+ const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
+ if (reg_num != LLDB_INVALID_REGNUM)
+ {
+ m_curr_row->SetRegisterLocationToSame (reg_num, must_replace);
+ m_curr_row_modified = true;
+ m_curr_insn_restored_a_register = true;
+ }
+ }
+ break;
+
+ case EmulateInstruction::eContextSetFramePointer:
+ if (!m_fp_is_cfa)
+ {
+ m_fp_is_cfa = true;
+ m_cfa_reg_info = *reg_info;
+ const uint32_t cfa_reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
+ assert (cfa_reg_num != LLDB_INVALID_REGNUM);
+ m_curr_row->SetCFARegister(cfa_reg_num);
+ m_curr_row->SetCFAOffset(m_initial_sp - reg_value.GetAsUInt64());
+ m_curr_row_modified = true;
+ }
+ break;
+
+ case EmulateInstruction::eContextAdjustStackPointer:
+ // If we have created a frame using the frame pointer, don't follow
+ // subsequent adjustments to the stack pointer.
+ if (!m_fp_is_cfa)
+ {
+ m_curr_row->SetCFAOffset (m_initial_sp - reg_value.GetAsUInt64());
+ m_curr_row_modified = true;
+ }
+ break;
+ }
+ return true;
+}
+
+
diff --git a/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
new file mode 100644
index 000000000000..6a02f0a55104
--- /dev/null
+++ b/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.h
@@ -0,0 +1,185 @@
+//===-- UnwindAssemblyInstEmulation.h ----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_UnwindAssemblyInstEmulation_h_
+#define liblldb_UnwindAssemblyInstEmulation_h_
+
+#include "lldb/lldb-private.h"
+#include "lldb/Core/EmulateInstruction.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/UnwindAssembly.h"
+
+class UnwindAssemblyInstEmulation : public lldb_private::UnwindAssembly
+{
+public:
+
+ virtual
+ ~UnwindAssemblyInstEmulation ()
+ {
+ }
+
+ virtual bool
+ GetNonCallSiteUnwindPlanFromAssembly (lldb_private::AddressRange& func,
+ lldb_private::Thread& thread,
+ lldb_private::UnwindPlan& unwind_plan);
+
+ virtual bool
+ GetFastUnwindPlan (lldb_private::AddressRange& func,
+ lldb_private::Thread& thread,
+ lldb_private::UnwindPlan &unwind_plan);
+
+ // thread may be NULL in which case we only use the Target (e.g. if this is called pre-process-launch).
+ virtual bool
+ FirstNonPrologueInsn (lldb_private::AddressRange& func,
+ const lldb_private::ExecutionContext &exe_ctx,
+ lldb_private::Address& first_non_prologue_insn);
+
+ static lldb_private::UnwindAssembly *
+ CreateInstance (const lldb_private::ArchSpec &arch);
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+private:
+
+ static size_t
+ ReadMemory (lldb_private::EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ void *dst,
+ size_t length);
+
+ static size_t
+ WriteMemory (lldb_private::EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length);
+
+ static bool
+ ReadRegister (lldb_private::EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ static bool
+ WriteRegister (lldb_private::EmulateInstruction *instruction,
+ void *baton,
+ const lldb_private::EmulateInstruction::Context &context,
+ const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value);
+
+
+// size_t
+// ReadMemory (lldb_private::EmulateInstruction *instruction,
+// const lldb_private::EmulateInstruction::Context &context,
+// lldb::addr_t addr,
+// void *dst,
+// size_t length);
+
+ size_t
+ WriteMemory (lldb_private::EmulateInstruction *instruction,
+ const lldb_private::EmulateInstruction::Context &context,
+ lldb::addr_t addr,
+ const void *dst,
+ size_t length);
+
+ bool
+ ReadRegister (lldb_private::EmulateInstruction *instruction,
+ const lldb_private::RegisterInfo *reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ bool
+ WriteRegister (lldb_private::EmulateInstruction *instruction,
+ const lldb_private::EmulateInstruction::Context &context,
+ const lldb_private::RegisterInfo *reg_info,
+ const lldb_private::RegisterValue &reg_value);
+
+ // Call CreateInstance to get an instance of this class
+ UnwindAssemblyInstEmulation (const lldb_private::ArchSpec &arch,
+ lldb_private::EmulateInstruction *inst_emulator) :
+ UnwindAssembly (arch),
+ m_inst_emulator_ap (inst_emulator),
+ m_range_ptr (NULL),
+ m_thread_ptr (NULL),
+ m_unwind_plan_ptr (NULL),
+ m_curr_row (),
+ m_cfa_reg_info (),
+ m_fp_is_cfa (false),
+ m_register_values (),
+ m_pushed_regs(),
+ m_curr_row_modified (false),
+ m_curr_insn_is_branch_immediate (false),
+ m_curr_insn_restored_a_register (false)
+ {
+ if (m_inst_emulator_ap.get())
+ {
+ m_inst_emulator_ap->SetBaton (this);
+ m_inst_emulator_ap->SetCallbacks (ReadMemory, WriteMemory, ReadRegister, WriteRegister);
+ }
+ }
+
+ static uint64_t
+ MakeRegisterKindValuePair (const lldb_private::RegisterInfo &reg_info);
+
+ void
+ SetRegisterValue (const lldb_private::RegisterInfo &reg_info,
+ const lldb_private::RegisterValue &reg_value);
+
+ bool
+ GetRegisterValue (const lldb_private::RegisterInfo &reg_info,
+ lldb_private::RegisterValue &reg_value);
+
+ std::unique_ptr<lldb_private::EmulateInstruction> m_inst_emulator_ap;
+ lldb_private::AddressRange* m_range_ptr;
+ lldb_private::Thread* m_thread_ptr;
+ lldb_private::UnwindPlan* m_unwind_plan_ptr;
+ lldb_private::UnwindPlan::RowSP m_curr_row;
+ typedef std::map<uint64_t, uint64_t> PushedRegisterToAddrMap;
+ uint64_t m_initial_sp;
+ lldb_private::RegisterInfo m_cfa_reg_info;
+ bool m_fp_is_cfa;
+ typedef std::map<uint64_t, lldb_private::RegisterValue> RegisterValueMap;
+ RegisterValueMap m_register_values;
+ PushedRegisterToAddrMap m_pushed_regs;
+
+ // While processing the instruction stream, we need to communicate some state change
+ // information up to the higher level loop that makes decisions about how to push
+ // the unwind instructions for the UnwindPlan we're constructing.
+
+ // The instruction we're processing updated the UnwindPlan::Row contents
+ bool m_curr_row_modified;
+ // The instruction we're examining is a branch immediate instruction
+ bool m_curr_insn_is_branch_immediate;
+ // The instruction we're processing restored a caller's reg value (e.g. in an epilogue)
+ bool m_curr_insn_restored_a_register;
+};
+
+#endif // liblldb_UnwindAssemblyInstEmulation_h_
diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
new file mode 100644
index 000000000000..d491683f6875
--- /dev/null
+++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.cpp
@@ -0,0 +1,973 @@
+//===-- UnwindAssembly-x86.cpp ----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "UnwindAssembly-x86.h"
+
+#include "llvm-c/Disassembler.h"
+#include "llvm/Support/TargetSelect.h"
+
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/ArchSpec.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Symbol/UnwindPlan.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/UnwindAssembly.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+enum CPU {
+ k_i386,
+ k_x86_64
+};
+
+enum i386_register_numbers {
+ k_machine_eax = 0,
+ k_machine_ecx = 1,
+ k_machine_edx = 2,
+ k_machine_ebx = 3,
+ k_machine_esp = 4,
+ k_machine_ebp = 5,
+ k_machine_esi = 6,
+ k_machine_edi = 7,
+ k_machine_eip = 8
+};
+
+enum x86_64_register_numbers {
+ k_machine_rax = 0,
+ k_machine_rcx = 1,
+ k_machine_rdx = 2,
+ k_machine_rbx = 3,
+ k_machine_rsp = 4,
+ k_machine_rbp = 5,
+ k_machine_rsi = 6,
+ k_machine_rdi = 7,
+ k_machine_r8 = 8,
+ k_machine_r9 = 9,
+ k_machine_r10 = 10,
+ k_machine_r11 = 11,
+ k_machine_r12 = 12,
+ k_machine_r13 = 13,
+ k_machine_r14 = 14,
+ k_machine_r15 = 15,
+ k_machine_rip = 16
+};
+
+struct regmap_ent {
+ const char *name;
+ int machine_regno;
+ int lldb_regno;
+};
+
+static struct regmap_ent i386_register_map[] = {
+ {"eax", k_machine_eax, -1},
+ {"ecx", k_machine_ecx, -1},
+ {"edx", k_machine_edx, -1},
+ {"ebx", k_machine_ebx, -1},
+ {"esp", k_machine_esp, -1},
+ {"ebp", k_machine_ebp, -1},
+ {"esi", k_machine_esi, -1},
+ {"edi", k_machine_edi, -1},
+ {"eip", k_machine_eip, -1}
+};
+
+const int size_of_i386_register_map = sizeof (i386_register_map) / sizeof (struct regmap_ent);
+
+static int i386_register_map_initialized = 0;
+
+static struct regmap_ent x86_64_register_map[] = {
+ {"rax", k_machine_rax, -1},
+ {"rcx", k_machine_rcx, -1},
+ {"rdx", k_machine_rdx, -1},
+ {"rbx", k_machine_rbx, -1},
+ {"rsp", k_machine_rsp, -1},
+ {"rbp", k_machine_rbp, -1},
+ {"rsi", k_machine_rsi, -1},
+ {"rdi", k_machine_rdi, -1},
+ {"r8", k_machine_r8, -1},
+ {"r9", k_machine_r9, -1},
+ {"r10", k_machine_r10, -1},
+ {"r11", k_machine_r11, -1},
+ {"r12", k_machine_r12, -1},
+ {"r13", k_machine_r13, -1},
+ {"r14", k_machine_r14, -1},
+ {"r15", k_machine_r15, -1},
+ {"rip", k_machine_rip, -1}
+};
+
+const int size_of_x86_64_register_map = sizeof (x86_64_register_map) / sizeof (struct regmap_ent);
+
+static int x86_64_register_map_initialized = 0;
+
+//-----------------------------------------------------------------------------------------------
+// AssemblyParse_x86 local-file class definition & implementation functions
+//-----------------------------------------------------------------------------------------------
+
+class AssemblyParse_x86 {
+public:
+
+ AssemblyParse_x86 (const ExecutionContext &exe_ctx, int cpu, ArchSpec &arch, AddressRange func);
+
+ ~AssemblyParse_x86 ();
+
+ bool get_non_call_site_unwind_plan (UnwindPlan &unwind_plan);
+
+ bool get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan);
+
+ bool find_first_non_prologue_insn (Address &address);
+
+private:
+ enum { kMaxInstructionByteSize = 32 };
+
+ bool nonvolatile_reg_p (int machine_regno);
+ bool push_rbp_pattern_p ();
+ bool push_0_pattern_p ();
+ bool mov_rsp_rbp_pattern_p ();
+ bool sub_rsp_pattern_p (int& amount);
+ bool push_reg_p (int& regno);
+ bool mov_reg_to_local_stack_frame_p (int& regno, int& fp_offset);
+ bool ret_pattern_p ();
+ uint32_t extract_4 (uint8_t *b);
+ bool machine_regno_to_lldb_regno (int machine_regno, uint32_t& lldb_regno);
+ bool instruction_length (Address addr, int &length);
+
+ const ExecutionContext m_exe_ctx;
+
+ AddressRange m_func_bounds;
+
+ Address m_cur_insn;
+ uint8_t m_cur_insn_bytes[kMaxInstructionByteSize];
+
+ int m_machine_ip_regnum;
+ int m_machine_sp_regnum;
+ int m_machine_fp_regnum;
+
+ int m_lldb_ip_regnum;
+ int m_lldb_sp_regnum;
+ int m_lldb_fp_regnum;
+
+ int m_wordsize;
+ int m_cpu;
+ ArchSpec m_arch;
+ ::LLVMDisasmContextRef m_disasm_context;
+
+ DISALLOW_COPY_AND_ASSIGN (AssemblyParse_x86);
+};
+
+AssemblyParse_x86::AssemblyParse_x86 (const ExecutionContext &exe_ctx, int cpu, ArchSpec &arch, AddressRange func) :
+ m_exe_ctx (exe_ctx),
+ m_func_bounds(func),
+ m_cur_insn (),
+ m_machine_ip_regnum (LLDB_INVALID_REGNUM),
+ m_machine_sp_regnum (LLDB_INVALID_REGNUM),
+ m_machine_fp_regnum (LLDB_INVALID_REGNUM),
+ m_lldb_ip_regnum (LLDB_INVALID_REGNUM),
+ m_lldb_sp_regnum (LLDB_INVALID_REGNUM),
+ m_lldb_fp_regnum (LLDB_INVALID_REGNUM),
+ m_wordsize (-1),
+ m_cpu(cpu),
+ m_arch(arch)
+{
+ int *initialized_flag = NULL;
+ if (cpu == k_i386)
+ {
+ m_machine_ip_regnum = k_machine_eip;
+ m_machine_sp_regnum = k_machine_esp;
+ m_machine_fp_regnum = k_machine_ebp;
+ m_wordsize = 4;
+ initialized_flag = &i386_register_map_initialized;
+ }
+ else
+ {
+ m_machine_ip_regnum = k_machine_rip;
+ m_machine_sp_regnum = k_machine_rsp;
+ m_machine_fp_regnum = k_machine_rbp;
+ m_wordsize = 8;
+ initialized_flag = &x86_64_register_map_initialized;
+ }
+
+ // we only look at prologue - it will be complete earlier than 512 bytes into func
+ if (m_func_bounds.GetByteSize() == 0)
+ m_func_bounds.SetByteSize(512);
+
+ Thread *thread = m_exe_ctx.GetThreadPtr();
+ if (thread && *initialized_flag == 0)
+ {
+ RegisterContext *reg_ctx = thread->GetRegisterContext().get();
+ if (reg_ctx)
+ {
+ struct regmap_ent *ent;
+ int count, i;
+ if (cpu == k_i386)
+ {
+ ent = i386_register_map;
+ count = size_of_i386_register_map;
+ }
+ else
+ {
+ ent = x86_64_register_map;
+ count = size_of_x86_64_register_map;
+ }
+ for (i = 0; i < count; i++, ent++)
+ {
+ const RegisterInfo *ri = reg_ctx->GetRegisterInfoByName (ent->name);
+ if (ri)
+ ent->lldb_regno = ri->kinds[eRegisterKindLLDB];
+ }
+ *initialized_flag = 1;
+ }
+ }
+
+ // on initial construction we may not have a Thread so these have to remain
+ // uninitialized until we can get a RegisterContext to set up the register map table
+ if (*initialized_flag == 1)
+ {
+ uint32_t lldb_regno;
+ if (machine_regno_to_lldb_regno (m_machine_sp_regnum, lldb_regno))
+ m_lldb_sp_regnum = lldb_regno;
+ if (machine_regno_to_lldb_regno (m_machine_fp_regnum, lldb_regno))
+ m_lldb_fp_regnum = lldb_regno;
+ if (machine_regno_to_lldb_regno (m_machine_ip_regnum, lldb_regno))
+ m_lldb_ip_regnum = lldb_regno;
+ }
+
+ m_disasm_context = ::LLVMCreateDisasm(m_arch.GetTriple().getTriple().c_str(),
+ (void*)this,
+ /*TagType=*/1,
+ NULL,
+ NULL);
+}
+
+AssemblyParse_x86::~AssemblyParse_x86 ()
+{
+ ::LLVMDisasmDispose(m_disasm_context);
+}
+
+// This function expects an x86 native register number (i.e. the bits stripped out of the
+// actual instruction), not an lldb register number.
+
+bool
+AssemblyParse_x86::nonvolatile_reg_p (int machine_regno)
+{
+ if (m_cpu == k_i386)
+ {
+ switch (machine_regno) {
+ case k_machine_ebx:
+ case k_machine_ebp: // not actually a nonvolatile but often treated as such by convention
+ case k_machine_esi:
+ case k_machine_edi:
+ case k_machine_esp:
+ return true;
+ default:
+ return false;
+ }
+ }
+ if (m_cpu == k_x86_64)
+ {
+ switch (machine_regno) {
+ case k_machine_rbx:
+ case k_machine_rsp:
+ case k_machine_rbp: // not actually a nonvolatile but often treated as such by convention
+ case k_machine_r12:
+ case k_machine_r13:
+ case k_machine_r14:
+ case k_machine_r15:
+ return true;
+ default:
+ return false;
+ }
+ }
+ return false;
+}
+
+
+// Macro to detect if this is a REX mode prefix byte.
+#define REX_W_PREFIX_P(opcode) (((opcode) & (~0x5)) == 0x48)
+
+// The high bit which should be added to the source register number (the "R" bit)
+#define REX_W_SRCREG(opcode) (((opcode) & 0x4) >> 2)
+
+// The high bit which should be added to the destination register number (the "B" bit)
+#define REX_W_DSTREG(opcode) ((opcode) & 0x1)
+
+// pushq %rbp [0x55]
+bool AssemblyParse_x86::push_rbp_pattern_p () {
+ uint8_t *p = m_cur_insn_bytes;
+ if (*p == 0x55)
+ return true;
+ return false;
+}
+
+// pushq $0 ; the first instruction in start() [0x6a 0x00]
+bool AssemblyParse_x86::push_0_pattern_p ()
+{
+ uint8_t *p = m_cur_insn_bytes;
+ if (*p == 0x6a && *(p + 1) == 0x0)
+ return true;
+ return false;
+}
+
+// movq %rsp, %rbp [0x48 0x8b 0xec] or [0x48 0x89 0xe5]
+// movl %esp, %ebp [0x8b 0xec] or [0x89 0xe5]
+bool AssemblyParse_x86::mov_rsp_rbp_pattern_p () {
+ uint8_t *p = m_cur_insn_bytes;
+ if (m_wordsize == 8 && *p == 0x48)
+ p++;
+ if (*(p) == 0x8b && *(p + 1) == 0xec)
+ return true;
+ if (*(p) == 0x89 && *(p + 1) == 0xe5)
+ return true;
+ return false;
+}
+
+// subq $0x20, %rsp
+bool AssemblyParse_x86::sub_rsp_pattern_p (int& amount) {
+ uint8_t *p = m_cur_insn_bytes;
+ if (m_wordsize == 8 && *p == 0x48)
+ p++;
+ // 8-bit immediate operand
+ if (*p == 0x83 && *(p + 1) == 0xec) {
+ amount = (int8_t) *(p + 2);
+ return true;
+ }
+ // 32-bit immediate operand
+ if (*p == 0x81 && *(p + 1) == 0xec) {
+ amount = (int32_t) extract_4 (p + 2);
+ return true;
+ }
+ // Not handled: [0x83 0xc4] for imm8 with neg values
+ // [0x81 0xc4] for imm32 with neg values
+ return false;
+}
+
+// pushq %rbx
+// pushl $ebx
+bool AssemblyParse_x86::push_reg_p (int& regno) {
+ uint8_t *p = m_cur_insn_bytes;
+ int regno_prefix_bit = 0;
+ // If we have a rex prefix byte, check to see if a B bit is set
+ if (m_wordsize == 8 && *p == 0x41) {
+ regno_prefix_bit = 1 << 3;
+ p++;
+ }
+ if (*p >= 0x50 && *p <= 0x57) {
+ regno = (*p - 0x50) | regno_prefix_bit;
+ return true;
+ }
+ return false;
+}
+
+// Look for an instruction sequence storing a nonvolatile register
+// on to the stack frame.
+
+// movq %rax, -0x10(%rbp) [0x48 0x89 0x45 0xf0]
+// movl %eax, -0xc(%ebp) [0x89 0x45 0xf4]
+bool AssemblyParse_x86::mov_reg_to_local_stack_frame_p (int& regno, int& rbp_offset) {
+ uint8_t *p = m_cur_insn_bytes;
+ int src_reg_prefix_bit = 0;
+ int target_reg_prefix_bit = 0;
+
+ if (m_wordsize == 8 && REX_W_PREFIX_P (*p)) {
+ src_reg_prefix_bit = REX_W_SRCREG (*p) << 3;
+ target_reg_prefix_bit = REX_W_DSTREG (*p) << 3;
+ if (target_reg_prefix_bit == 1) {
+ // rbp/ebp don't need a prefix bit - we know this isn't the
+ // reg we care about.
+ return false;
+ }
+ p++;
+ }
+
+ if (*p == 0x89) {
+ /* Mask off the 3-5 bits which indicate the destination register
+ if this is a ModR/M byte. */
+ int opcode_destreg_masked_out = *(p + 1) & (~0x38);
+
+ /* Is this a ModR/M byte with Mod bits 01 and R/M bits 101
+ and three bits between them, e.g. 01nnn101
+ We're looking for a destination of ebp-disp8 or ebp-disp32. */
+ int immsize;
+ if (opcode_destreg_masked_out == 0x45)
+ immsize = 2;
+ else if (opcode_destreg_masked_out == 0x85)
+ immsize = 4;
+ else
+ return false;
+
+ int offset = 0;
+ if (immsize == 2)
+ offset = (int8_t) *(p + 2);
+ if (immsize == 4)
+ offset = (uint32_t) extract_4 (p + 2);
+ if (offset > 0)
+ return false;
+
+ regno = ((*(p + 1) >> 3) & 0x7) | src_reg_prefix_bit;
+ rbp_offset = offset > 0 ? offset : -offset;
+ return true;
+ }
+ return false;
+}
+
+// ret [0xc9] or [0xc2 imm8] or [0xca imm8]
+bool
+AssemblyParse_x86::ret_pattern_p ()
+{
+ uint8_t *p = m_cur_insn_bytes;
+ if (*p == 0xc9 || *p == 0xc2 || *p == 0xca || *p == 0xc3)
+ return true;
+ return false;
+}
+
+uint32_t
+AssemblyParse_x86::extract_4 (uint8_t *b)
+{
+ uint32_t v = 0;
+ for (int i = 3; i >= 0; i--)
+ v = (v << 8) | b[i];
+ return v;
+}
+
+bool
+AssemblyParse_x86::machine_regno_to_lldb_regno (int machine_regno, uint32_t &lldb_regno)
+{
+ struct regmap_ent *ent;
+ int count, i;
+ if (m_cpu == k_i386)
+ {
+ ent = i386_register_map;
+ count = size_of_i386_register_map;
+ }
+ else
+ {
+ ent = x86_64_register_map;
+ count = size_of_x86_64_register_map;
+ }
+ for (i = 0; i < count; i++, ent++)
+ {
+ if (ent->machine_regno == machine_regno)
+ if (ent->lldb_regno != -1)
+ {
+ lldb_regno = ent->lldb_regno;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool
+AssemblyParse_x86::instruction_length (Address addr, int &length)
+{
+ const uint32_t max_op_byte_size = m_arch.GetMaximumOpcodeByteSize();
+ llvm::SmallVector <uint8_t, 32> opcode_data;
+ opcode_data.resize (max_op_byte_size);
+
+ if (!addr.IsValid())
+ return false;
+
+ const bool prefer_file_cache = true;
+ Error error;
+ Target *target = m_exe_ctx.GetTargetPtr();
+ if (target->ReadMemory (addr, prefer_file_cache, opcode_data.data(), max_op_byte_size, error) == -1)
+ {
+ return false;
+ }
+
+ char out_string[512];
+ const addr_t pc = addr.GetFileAddress();
+ const size_t inst_size = ::LLVMDisasmInstruction (m_disasm_context,
+ opcode_data.data(),
+ max_op_byte_size,
+ pc, // PC value
+ out_string,
+ sizeof(out_string));
+
+ length = inst_size;
+ return true;
+}
+
+
+bool
+AssemblyParse_x86::get_non_call_site_unwind_plan (UnwindPlan &unwind_plan)
+{
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ int non_prologue_insn_count = 0;
+ m_cur_insn = m_func_bounds.GetBaseAddress ();
+ int current_func_text_offset = 0;
+ int current_sp_bytes_offset_from_cfa = 0;
+ UnwindPlan::Row::RegisterLocation initial_regloc;
+ Error error;
+
+ if (!m_cur_insn.IsValid())
+ {
+ return false;
+ }
+
+ unwind_plan.SetPlanValidAddressRange (m_func_bounds);
+ unwind_plan.SetRegisterKind (eRegisterKindLLDB);
+
+ // At the start of the function, find the CFA by adding wordsize to the SP register
+ row->SetOffset (current_func_text_offset);
+ row->SetCFARegister (m_lldb_sp_regnum);
+ row->SetCFAOffset (m_wordsize);
+
+ // caller's stack pointer value before the call insn is the CFA address
+ initial_regloc.SetIsCFAPlusOffset (0);
+ row->SetRegisterInfo (m_lldb_sp_regnum, initial_regloc);
+
+ // saved instruction pointer can be found at CFA - wordsize.
+ current_sp_bytes_offset_from_cfa = m_wordsize;
+ initial_regloc.SetAtCFAPlusOffset (-current_sp_bytes_offset_from_cfa);
+ row->SetRegisterInfo (m_lldb_ip_regnum, initial_regloc);
+
+ unwind_plan.AppendRow (row);
+
+ // Allocate a new Row, populate it with the existing Row contents.
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset(newrow);
+
+ const bool prefer_file_cache = true;
+
+ Target *target = m_exe_ctx.GetTargetPtr();
+ while (m_func_bounds.ContainsFileAddress (m_cur_insn) && non_prologue_insn_count < 10)
+ {
+ int stack_offset, insn_len;
+ int machine_regno; // register numbers masked directly out of instructions
+ uint32_t lldb_regno; // register numbers in lldb's eRegisterKindLLDB numbering scheme
+
+ if (!instruction_length (m_cur_insn, insn_len) || insn_len == 0 || insn_len > kMaxInstructionByteSize)
+ {
+ // An unrecognized/junk instruction
+ break;
+ }
+ if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes, insn_len, error) == -1)
+ {
+ // Error reading the instruction out of the file, stop scanning
+ break;
+ }
+
+ if (push_rbp_pattern_p ())
+ {
+ row->SetOffset (current_func_text_offset + insn_len);
+ current_sp_bytes_offset_from_cfa += m_wordsize;
+ row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ UnwindPlan::Row::RegisterLocation regloc;
+ regloc.SetAtCFAPlusOffset (-row->GetCFAOffset());
+ row->SetRegisterInfo (m_lldb_fp_regnum, regloc);
+ unwind_plan.AppendRow (row);
+ // Allocate a new Row, populate it with the existing Row contents.
+ newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset(newrow);
+ goto loopnext;
+ }
+
+ if (mov_rsp_rbp_pattern_p ())
+ {
+ row->SetOffset (current_func_text_offset + insn_len);
+ row->SetCFARegister (m_lldb_fp_regnum);
+ unwind_plan.AppendRow (row);
+ // Allocate a new Row, populate it with the existing Row contents.
+ newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset(newrow);
+ goto loopnext;
+ }
+
+ // This is the start() function (or a pthread equivalent), it starts with a pushl $0x0 which puts the
+ // saved pc value of 0 on the stack. In this case we want to pretend we didn't see a stack movement at all --
+ // normally the saved pc value is already on the stack by the time the function starts executing.
+ if (push_0_pattern_p ())
+ {
+ goto loopnext;
+ }
+
+ if (push_reg_p (machine_regno))
+ {
+ current_sp_bytes_offset_from_cfa += m_wordsize;
+ if (nonvolatile_reg_p (machine_regno) && machine_regno_to_lldb_regno (machine_regno, lldb_regno))
+ {
+ row->SetOffset (current_func_text_offset + insn_len);
+ if (row->GetCFARegister() == m_lldb_sp_regnum)
+ {
+ row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ }
+ UnwindPlan::Row::RegisterLocation regloc;
+ regloc.SetAtCFAPlusOffset (-current_sp_bytes_offset_from_cfa);
+ row->SetRegisterInfo (lldb_regno, regloc);
+ unwind_plan.AppendRow (row);
+ // Allocate a new Row, populate it with the existing Row contents.
+ newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset(newrow);
+ }
+ goto loopnext;
+ }
+
+ if (mov_reg_to_local_stack_frame_p (machine_regno, stack_offset) && nonvolatile_reg_p (machine_regno))
+ {
+ if (machine_regno_to_lldb_regno (machine_regno, lldb_regno))
+ {
+ row->SetOffset (current_func_text_offset + insn_len);
+ UnwindPlan::Row::RegisterLocation regloc;
+ regloc.SetAtCFAPlusOffset (-row->GetCFAOffset());
+ row->SetRegisterInfo (lldb_regno, regloc);
+ unwind_plan.AppendRow (row);
+ // Allocate a new Row, populate it with the existing Row contents.
+ newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset(newrow);
+ goto loopnext;
+ }
+ }
+
+ if (sub_rsp_pattern_p (stack_offset))
+ {
+ current_sp_bytes_offset_from_cfa += stack_offset;
+ if (row->GetCFARegister() == m_lldb_sp_regnum)
+ {
+ row->SetOffset (current_func_text_offset + insn_len);
+ row->SetCFAOffset (current_sp_bytes_offset_from_cfa);
+ unwind_plan.AppendRow (row);
+ // Allocate a new Row, populate it with the existing Row contents.
+ newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset(newrow);
+ }
+ goto loopnext;
+ }
+
+ if (ret_pattern_p ())
+ {
+ // we know where the end of the function is; set the limit on the PlanValidAddressRange
+ // in case our initial "high pc" value was overly large
+ // int original_size = m_func_bounds.GetByteSize();
+ // int calculated_size = m_cur_insn.GetOffset() - m_func_bounds.GetBaseAddress().GetOffset() + insn_len + 1;
+ // m_func_bounds.SetByteSize (calculated_size);
+ // unwind_plan.SetPlanValidAddressRange (m_func_bounds);
+ break;
+ }
+
+ // FIXME recognize the i386 picbase setup instruction sequence,
+ // 0x1f16: call 0x1f1b ; main + 11 at /private/tmp/a.c:3
+ // 0x1f1b: popl %eax
+ // and record the temporary stack movements if the CFA is not expressed in terms of ebp.
+
+ non_prologue_insn_count++;
+loopnext:
+ m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
+ current_func_text_offset += insn_len;
+ }
+
+ // Now look at the byte at the end of the AddressRange for a limited attempt at describing the
+ // epilogue. We're looking for the sequence
+
+ // [ 0x5d ] mov %rbp, %rsp
+ // [ 0xc3 ] ret
+ // [ 0xe8 xx xx xx xx ] call __stack_chk_fail (this is sometimes the final insn in the function)
+
+ // We want to add a Row describing how to unwind when we're stopped on the 'ret' instruction where the
+ // CFA is no longer defined in terms of rbp, but is now defined in terms of rsp like on function entry.
+
+ uint64_t ret_insn_offset = LLDB_INVALID_ADDRESS;
+ Address end_of_fun(m_func_bounds.GetBaseAddress());
+ end_of_fun.SetOffset (end_of_fun.GetOffset() + m_func_bounds.GetByteSize());
+
+ if (m_func_bounds.GetByteSize() > 7)
+ {
+ uint8_t bytebuf[7];
+ Address last_seven_bytes(end_of_fun);
+ last_seven_bytes.SetOffset (last_seven_bytes.GetOffset() - 7);
+ if (target->ReadMemory (last_seven_bytes, prefer_file_cache, bytebuf, 7, error) != -1)
+ {
+ if (bytebuf[5] == 0x5d && bytebuf[6] == 0xc3) // mov, ret
+ {
+ ret_insn_offset = m_func_bounds.GetByteSize() - 1;
+ }
+ else if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3 && bytebuf[2] == 0xe8) // mov, ret, call
+ {
+ ret_insn_offset = m_func_bounds.GetByteSize() - 6;
+ }
+ }
+ } else if (m_func_bounds.GetByteSize() > 2)
+ {
+ uint8_t bytebuf[2];
+ Address last_two_bytes(end_of_fun);
+ last_two_bytes.SetOffset (last_two_bytes.GetOffset() - 2);
+ if (target->ReadMemory (last_two_bytes, prefer_file_cache, bytebuf, 2, error) != -1)
+ {
+ if (bytebuf[0] == 0x5d && bytebuf[1] == 0xc3) // mov, ret
+ {
+ ret_insn_offset = m_func_bounds.GetByteSize() - 1;
+ }
+ }
+ }
+
+ if (ret_insn_offset != LLDB_INVALID_ADDRESS)
+ {
+ // Create a fresh, empty Row and RegisterLocation - don't mention any other registers
+ UnwindPlan::RowSP epi_row(new UnwindPlan::Row);
+ UnwindPlan::Row::RegisterLocation epi_regloc;
+
+ // When the ret instruction is about to be executed, here's our state
+ epi_row->SetOffset (ret_insn_offset);
+ epi_row->SetCFARegister (m_lldb_sp_regnum);
+ epi_row->SetCFAOffset (m_wordsize);
+
+ // caller's stack pointer value before the call insn is the CFA address
+ epi_regloc.SetIsCFAPlusOffset (0);
+ epi_row->SetRegisterInfo (m_lldb_sp_regnum, epi_regloc);
+
+ // saved instruction pointer can be found at CFA - wordsize
+ epi_regloc.SetAtCFAPlusOffset (-m_wordsize);
+ epi_row->SetRegisterInfo (m_lldb_ip_regnum, epi_regloc);
+
+ unwind_plan.AppendRow (epi_row);
+ }
+
+ unwind_plan.SetSourceName ("assembly insn profiling");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes);
+
+ return true;
+}
+
+/* The "fast unwind plan" is valid for functions that follow the usual convention of
+ using the frame pointer register (ebp, rbp), i.e. the function prologue looks like
+ push %rbp [0x55]
+ mov %rsp,%rbp [0x48 0x89 0xe5] (this is a 2-byte insn seq on i386)
+*/
+
+bool
+AssemblyParse_x86::get_fast_unwind_plan (AddressRange& func, UnwindPlan &unwind_plan)
+{
+ UnwindPlan::RowSP row(new UnwindPlan::Row);
+ UnwindPlan::Row::RegisterLocation pc_reginfo;
+ UnwindPlan::Row::RegisterLocation sp_reginfo;
+ UnwindPlan::Row::RegisterLocation fp_reginfo;
+ unwind_plan.SetRegisterKind (eRegisterKindLLDB);
+
+ if (!func.GetBaseAddress().IsValid())
+ return false;
+
+ Target *target = m_exe_ctx.GetTargetPtr();
+
+ uint8_t bytebuf[4];
+ Error error;
+ const bool prefer_file_cache = true;
+ if (target->ReadMemory (func.GetBaseAddress(), prefer_file_cache, bytebuf, sizeof (bytebuf), error) == -1)
+ return false;
+
+ uint8_t i386_prologue[] = {0x55, 0x89, 0xe5};
+ uint8_t x86_64_prologue[] = {0x55, 0x48, 0x89, 0xe5};
+ int prologue_size;
+
+ if (memcmp (bytebuf, i386_prologue, sizeof (i386_prologue)) == 0)
+ {
+ prologue_size = sizeof (i386_prologue);
+ }
+ else if (memcmp (bytebuf, x86_64_prologue, sizeof (x86_64_prologue)) == 0)
+ {
+ prologue_size = sizeof (x86_64_prologue);
+ }
+ else
+ {
+ return false;
+ }
+
+ pc_reginfo.SetAtCFAPlusOffset (-m_wordsize);
+ row->SetRegisterInfo (m_lldb_ip_regnum, pc_reginfo);
+
+ sp_reginfo.SetIsCFAPlusOffset (0);
+ row->SetRegisterInfo (m_lldb_sp_regnum, sp_reginfo);
+
+ // Zero instructions into the function
+ row->SetCFARegister (m_lldb_sp_regnum);
+ row->SetCFAOffset (m_wordsize);
+ row->SetOffset (0);
+ unwind_plan.AppendRow (row);
+ UnwindPlan::Row *newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset(newrow);
+
+ // push %rbp has executed - stack moved, rbp now saved
+ row->SetCFAOffset (2 * m_wordsize);
+ fp_reginfo.SetAtCFAPlusOffset (2 * -m_wordsize);
+ row->SetRegisterInfo (m_lldb_fp_regnum, fp_reginfo);
+ row->SetOffset (1);
+ unwind_plan.AppendRow (row);
+
+ newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset(newrow);
+
+ // mov %rsp, %rbp has executed
+ row->SetCFARegister (m_lldb_fp_regnum);
+ row->SetCFAOffset (2 * m_wordsize);
+ row->SetOffset (prologue_size); /// 3 or 4 bytes depending on arch
+ unwind_plan.AppendRow (row);
+
+ newrow = new UnwindPlan::Row;
+ *newrow = *row.get();
+ row.reset(newrow);
+
+ unwind_plan.SetPlanValidAddressRange (func);
+ unwind_plan.SetSourceName ("fast unwind assembly profiling");
+ unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
+ unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
+ return true;
+}
+
+bool
+AssemblyParse_x86::find_first_non_prologue_insn (Address &address)
+{
+ m_cur_insn = m_func_bounds.GetBaseAddress ();
+ if (!m_cur_insn.IsValid())
+ {
+ return false;
+ }
+
+ const bool prefer_file_cache = true;
+ Target *target = m_exe_ctx.GetTargetPtr();
+ while (m_func_bounds.ContainsFileAddress (m_cur_insn))
+ {
+ Error error;
+ int insn_len, offset, regno;
+ if (!instruction_length (m_cur_insn, insn_len) || insn_len > kMaxInstructionByteSize || insn_len == 0)
+ {
+ // An error parsing the instruction, i.e. probably data/garbage - stop scanning
+ break;
+ }
+ if (target->ReadMemory (m_cur_insn, prefer_file_cache, m_cur_insn_bytes, insn_len, error) == -1)
+ {
+ // Error reading the instruction out of the file, stop scanning
+ break;
+ }
+
+ if (push_rbp_pattern_p () || mov_rsp_rbp_pattern_p () || sub_rsp_pattern_p (offset)
+ || push_reg_p (regno) || mov_reg_to_local_stack_frame_p (regno, offset))
+ {
+ m_cur_insn.SetOffset (m_cur_insn.GetOffset() + insn_len);
+ continue;
+ }
+
+ // Unknown non-prologue instruction - stop scanning
+ break;
+ }
+
+ address = m_cur_insn;
+ return true;
+}
+
+
+
+
+
+
+//-----------------------------------------------------------------------------------------------
+// UnwindAssemblyParser_x86 method definitions
+//-----------------------------------------------------------------------------------------------
+
+UnwindAssembly_x86::UnwindAssembly_x86 (const ArchSpec &arch, int cpu) :
+ lldb_private::UnwindAssembly(arch),
+ m_cpu(cpu),
+ m_arch(arch)
+{
+}
+
+
+UnwindAssembly_x86::~UnwindAssembly_x86 ()
+{
+}
+
+bool
+UnwindAssembly_x86::GetNonCallSiteUnwindPlanFromAssembly (AddressRange& func, Thread& thread, UnwindPlan& unwind_plan)
+{
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
+ return asm_parse.get_non_call_site_unwind_plan (unwind_plan);
+}
+
+bool
+UnwindAssembly_x86::GetFastUnwindPlan (AddressRange& func, Thread& thread, UnwindPlan &unwind_plan)
+{
+ ExecutionContext exe_ctx (thread.shared_from_this());
+ AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
+ return asm_parse.get_fast_unwind_plan (func, unwind_plan);
+}
+
+bool
+UnwindAssembly_x86::FirstNonPrologueInsn (AddressRange& func, const ExecutionContext &exe_ctx, Address& first_non_prologue_insn)
+{
+ AssemblyParse_x86 asm_parse(exe_ctx, m_cpu, m_arch, func);
+ return asm_parse.find_first_non_prologue_insn (first_non_prologue_insn);
+}
+
+UnwindAssembly *
+UnwindAssembly_x86::CreateInstance (const ArchSpec &arch)
+{
+ const llvm::Triple::ArchType cpu = arch.GetMachine ();
+ if (cpu == llvm::Triple::x86)
+ return new UnwindAssembly_x86 (arch, k_i386);
+ else if (cpu == llvm::Triple::x86_64)
+ return new UnwindAssembly_x86 (arch, k_x86_64);
+ return NULL;
+}
+
+
+//------------------------------------------------------------------
+// PluginInterface protocol in UnwindAssemblyParser_x86
+//------------------------------------------------------------------
+
+ConstString
+UnwindAssembly_x86::GetPluginName()
+{
+ return GetPluginNameStatic();
+}
+
+
+uint32_t
+UnwindAssembly_x86::GetPluginVersion()
+{
+ return 1;
+}
+
+void
+UnwindAssembly_x86::Initialize()
+{
+ PluginManager::RegisterPlugin (GetPluginNameStatic(),
+ GetPluginDescriptionStatic(),
+ CreateInstance);
+}
+
+void
+UnwindAssembly_x86::Terminate()
+{
+ PluginManager::UnregisterPlugin (CreateInstance);
+}
+
+
+lldb_private::ConstString
+UnwindAssembly_x86::GetPluginNameStatic()
+{
+ static ConstString g_name("x86");
+ return g_name;
+}
+
+const char *
+UnwindAssembly_x86::GetPluginDescriptionStatic()
+{
+ return "i386 and x86_64 assembly language profiler plugin.";
+}
diff --git a/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h
new file mode 100644
index 000000000000..eebaa7b6c803
--- /dev/null
+++ b/source/Plugins/UnwindAssembly/x86/UnwindAssembly-x86.h
@@ -0,0 +1,73 @@
+//===-- UnwindAssembly-x86.h -------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_UnwindAssembly_x86_h_
+#define liblldb_UnwindAssembly_x86_h_
+
+#include "llvm-c/Disassembler.h"
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/UnwindAssembly.h"
+
+class UnwindAssembly_x86 : public lldb_private::UnwindAssembly
+{
+public:
+
+ ~UnwindAssembly_x86 ();
+
+ virtual bool
+ GetNonCallSiteUnwindPlanFromAssembly (lldb_private::AddressRange& func,
+ lldb_private::Thread& thread,
+ lldb_private::UnwindPlan& unwind_plan);
+
+ virtual bool
+ GetFastUnwindPlan (lldb_private::AddressRange& func,
+ lldb_private::Thread& thread,
+ lldb_private::UnwindPlan &unwind_plan);
+
+ // thread may be NULL in which case we only use the Target (e.g. if this is called pre-process-launch).
+ virtual bool
+ FirstNonPrologueInsn (lldb_private::AddressRange& func,
+ const lldb_private::ExecutionContext &exe_ctx,
+ lldb_private::Address& first_non_prologue_insn);
+
+ static lldb_private::UnwindAssembly *
+ CreateInstance (const lldb_private::ArchSpec &arch);
+
+
+ //------------------------------------------------------------------
+ // PluginInterface protocol
+ //------------------------------------------------------------------
+ static void
+ Initialize();
+
+ static void
+ Terminate();
+
+ static lldb_private::ConstString
+ GetPluginNameStatic();
+
+ static const char *
+ GetPluginDescriptionStatic();
+
+ virtual lldb_private::ConstString
+ GetPluginName();
+
+ virtual uint32_t
+ GetPluginVersion();
+
+private:
+ UnwindAssembly_x86 (const lldb_private::ArchSpec &arch, int cpu);
+
+ int m_cpu;
+ lldb_private::ArchSpec m_arch;
+};
+
+
+#endif // liblldb_UnwindAssembly_x86_h_