aboutsummaryrefslogtreecommitdiff
path: root/source/Plugins
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2013-08-23 17:46:38 +0000
committerEd Maste <emaste@FreeBSD.org>2013-08-23 17:46:38 +0000
commitf034231a6a1fd5d6395206c1651de8cd9402cca3 (patch)
treef561dabc721ad515599172c16da3a4400b7f4aec /source/Plugins
downloadsrc-f034231a6a1fd5d6395206c1651de8cd9402cca3.tar.gz
src-f034231a6a1fd5d6395206c1651de8cd9402cca3.zip
Import lldb as of SVN r188801
(A number of files not required for the FreeBSD build have been removed.) Sponsored by: DARPA, AFRL
Notes
Notes: svn path=/vendor/lldb/dist/; revision=254721
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