2010-06-09 00:52:24 +08:00
|
|
|
//===-- 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"
|
|
|
|
|
2016-02-27 06:26:21 +08:00
|
|
|
// C Includes
|
|
|
|
// C++ Includes
|
|
|
|
// Other libraries and framework includes
|
|
|
|
#include "llvm/ADT/STLExtras.h"
|
|
|
|
#include "llvm/ADT/Triple.h"
|
|
|
|
|
|
|
|
// Project includes
|
2010-06-09 00:52:24 +08:00
|
|
|
#include "lldb/Core/ConstString.h"
|
|
|
|
#include "lldb/Core/DataExtractor.h"
|
|
|
|
#include "lldb/Core/Error.h"
|
2010-10-08 09:58:41 +08:00
|
|
|
#include "lldb/Core/Log.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
#include "lldb/Core/Module.h"
|
|
|
|
#include "lldb/Core/PluginManager.h"
|
Cleaned up the ABI::PrepareTrivialCall() function to take three argument
pointers:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t *arg1_ptr,
lldb::addr_t *arg2_ptr,
lldb::addr_t *arg3_ptr) const = 0;
Prior to this it was:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t arg,
lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg) const = 0;
This was because the function that called this slowly added more features to
be able to call a C++ member function that might have a "this" pointer, and
then later added "self + cmd" support for objective C. Cleaning this code up
and the code that calls it makes it easier to implement the functions for
new targets.
The MacOSX_arm::PrepareTrivialCall() is now filled in and ready for testing.
llvm-svn: 131221
2011-05-12 10:14:56 +08:00
|
|
|
#include "lldb/Core/RegisterValue.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
#include "lldb/Core/Value.h"
|
2011-12-23 03:12:40 +08:00
|
|
|
#include "lldb/Core/ValueObjectConstResult.h"
|
|
|
|
#include "lldb/Core/ValueObjectRegister.h"
|
|
|
|
#include "lldb/Core/ValueObjectMemory.h"
|
2011-05-12 02:39:18 +08:00
|
|
|
#include "lldb/Symbol/UnwindPlan.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
#include "lldb/Target/Target.h"
|
|
|
|
#include "lldb/Target/Process.h"
|
|
|
|
#include "lldb/Target/RegisterContext.h"
|
2013-11-04 17:33:30 +08:00
|
|
|
#include "lldb/Target/StackFrame.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
#include "lldb/Target/Thread.h"
|
|
|
|
|
|
|
|
using namespace lldb;
|
|
|
|
using namespace lldb_private;
|
|
|
|
|
Clean up register naming conventions inside lldb.
"gcc" register numbers are now correctly referred to as "ehframe"
register numbers. In almost all cases, ehframe and dwarf register
numbers are identical (the one exception is i386 darwin where ehframe
regnums were incorrect).
The old "gdb" register numbers, which I incorrectly thought were
stabs register numbers, are now referred to as "Process Plugin"
register numbers. This is the register numbering scheme that the
remote process controller stub (lldb-server, gdbserver, core file
support, kdp server, remote jtag devices, etc) uses to refer to the
registers. The process plugin register numbers may not be contiguous
- there are remote jtag devices that have gaps in their register
numbering schemes.
I removed all of the enums for "gdb" register numbers that we had
in lldb - these were meaningless - and I put LLDB_INVALID_REGNUM
in all of the register tables for the Process Plugin regnum slot.
This change is almost entirely mechnical; the one actual change in
here is to ProcessGDBRemote.cpp's ParseRegisters() which parses the
qXfer:features:read:target.xml response. As it parses register
definitions from the xml, it will assign sequential numbers as the
eRegisterKindLLDB numbers (the lldb register numberings must be
sequential, without any gaps) and if the xml file specifies register
numbers, those will be used as the eRegisterKindProcessPlugin
register numbers (and those may have gaps). A J-Link jtag device's
target.xml does contain a gap in register numbers, and it only
specifies the register numbers for the registers after that gap.
The device supports many different ARM boards and probably selects
different part of its register file as appropriate.
http://reviews.llvm.org/D12791
<rdar://problem/22623262>
llvm-svn: 247741
2015-09-16 07:20:34 +08:00
|
|
|
enum dwarf_regnums
|
2011-08-22 10:49:39 +08:00
|
|
|
{
|
Clean up register naming conventions inside lldb.
"gcc" register numbers are now correctly referred to as "ehframe"
register numbers. In almost all cases, ehframe and dwarf register
numbers are identical (the one exception is i386 darwin where ehframe
regnums were incorrect).
The old "gdb" register numbers, which I incorrectly thought were
stabs register numbers, are now referred to as "Process Plugin"
register numbers. This is the register numbering scheme that the
remote process controller stub (lldb-server, gdbserver, core file
support, kdp server, remote jtag devices, etc) uses to refer to the
registers. The process plugin register numbers may not be contiguous
- there are remote jtag devices that have gaps in their register
numbering schemes.
I removed all of the enums for "gdb" register numbers that we had
in lldb - these were meaningless - and I put LLDB_INVALID_REGNUM
in all of the register tables for the Process Plugin regnum slot.
This change is almost entirely mechnical; the one actual change in
here is to ProcessGDBRemote.cpp's ParseRegisters() which parses the
qXfer:features:read:target.xml response. As it parses register
definitions from the xml, it will assign sequential numbers as the
eRegisterKindLLDB numbers (the lldb register numberings must be
sequential, without any gaps) and if the xml file specifies register
numbers, those will be used as the eRegisterKindProcessPlugin
register numbers (and those may have gaps). A J-Link jtag device's
target.xml does contain a gap in register numbers, and it only
specifies the register numbers for the registers after that gap.
The device supports many different ARM boards and probably selects
different part of its register file as appropriate.
http://reviews.llvm.org/D12791
<rdar://problem/22623262>
llvm-svn: 247741
2015-09-16 07:20:34 +08:00
|
|
|
dwarf_rax = 0,
|
|
|
|
dwarf_rdx,
|
|
|
|
dwarf_rcx,
|
|
|
|
dwarf_rbx,
|
|
|
|
dwarf_rsi,
|
|
|
|
dwarf_rdi,
|
|
|
|
dwarf_rbp,
|
|
|
|
dwarf_rsp,
|
|
|
|
dwarf_r8,
|
|
|
|
dwarf_r9,
|
|
|
|
dwarf_r10,
|
|
|
|
dwarf_r11,
|
|
|
|
dwarf_r12,
|
|
|
|
dwarf_r13,
|
|
|
|
dwarf_r14,
|
|
|
|
dwarf_r15,
|
|
|
|
dwarf_rip,
|
|
|
|
dwarf_xmm0,
|
|
|
|
dwarf_xmm1,
|
|
|
|
dwarf_xmm2,
|
|
|
|
dwarf_xmm3,
|
|
|
|
dwarf_xmm4,
|
|
|
|
dwarf_xmm5,
|
|
|
|
dwarf_xmm6,
|
|
|
|
dwarf_xmm7,
|
|
|
|
dwarf_xmm8,
|
|
|
|
dwarf_xmm9,
|
|
|
|
dwarf_xmm10,
|
|
|
|
dwarf_xmm11,
|
|
|
|
dwarf_xmm12,
|
|
|
|
dwarf_xmm13,
|
|
|
|
dwarf_xmm14,
|
|
|
|
dwarf_xmm15,
|
|
|
|
dwarf_stmm0,
|
|
|
|
dwarf_stmm1,
|
|
|
|
dwarf_stmm2,
|
|
|
|
dwarf_stmm3,
|
|
|
|
dwarf_stmm4,
|
|
|
|
dwarf_stmm5,
|
|
|
|
dwarf_stmm6,
|
|
|
|
dwarf_stmm7,
|
|
|
|
dwarf_ymm0,
|
|
|
|
dwarf_ymm1,
|
|
|
|
dwarf_ymm2,
|
|
|
|
dwarf_ymm3,
|
|
|
|
dwarf_ymm4,
|
|
|
|
dwarf_ymm5,
|
|
|
|
dwarf_ymm6,
|
|
|
|
dwarf_ymm7,
|
|
|
|
dwarf_ymm8,
|
|
|
|
dwarf_ymm9,
|
|
|
|
dwarf_ymm10,
|
|
|
|
dwarf_ymm11,
|
|
|
|
dwarf_ymm12,
|
|
|
|
dwarf_ymm13,
|
|
|
|
dwarf_ymm14,
|
2016-09-06 19:00:37 +08:00
|
|
|
dwarf_ymm15
|
2011-08-22 10:49:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static RegisterInfo g_register_infos[] =
|
|
|
|
{
|
2016-08-09 06:48:07 +08:00
|
|
|
// NAME ALT SZ OFF ENCODING FORMAT EH_FRAME DWARF GENERIC PROCESS PLUGIN LLDB NATIVE
|
|
|
|
// ======== ======= == === ============= =================== ======================= ===================== =========================== ===================== ======================
|
|
|
|
{ "rax" , nullptr, 8, 0, eEncodingUint , eFormatHex , { dwarf_rax , dwarf_rax , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "rbx" , nullptr, 8, 0, eEncodingUint , eFormatHex , { dwarf_rbx , dwarf_rbx , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "rcx" , "arg4", 8, 0, eEncodingUint , eFormatHex , { dwarf_rcx , dwarf_rcx , LLDB_REGNUM_GENERIC_ARG4 , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "rdx" , "arg3", 8, 0, eEncodingUint , eFormatHex , { dwarf_rdx , dwarf_rdx , LLDB_REGNUM_GENERIC_ARG3 , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "rsi" , "arg2", 8, 0, eEncodingUint , eFormatHex , { dwarf_rsi , dwarf_rsi , LLDB_REGNUM_GENERIC_ARG2 , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "rdi" , "arg1", 8, 0, eEncodingUint , eFormatHex , { dwarf_rdi , dwarf_rdi , LLDB_REGNUM_GENERIC_ARG1 , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "rbp" , "fp", 8, 0, eEncodingUint , eFormatHex , { dwarf_rbp , dwarf_rbp , LLDB_REGNUM_GENERIC_FP , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "rsp" , "sp", 8, 0, eEncodingUint , eFormatHex , { dwarf_rsp , dwarf_rsp , LLDB_REGNUM_GENERIC_SP , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "r8" , "arg5", 8, 0, eEncodingUint , eFormatHex , { dwarf_r8 , dwarf_r8 , LLDB_REGNUM_GENERIC_ARG5 , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "r9" , "arg6", 8, 0, eEncodingUint , eFormatHex , { dwarf_r9 , dwarf_r9 , LLDB_REGNUM_GENERIC_ARG6 , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "r10" , nullptr, 8, 0, eEncodingUint , eFormatHex , { dwarf_r10 , dwarf_r10 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "r11" , nullptr, 8, 0, eEncodingUint , eFormatHex , { dwarf_r11 , dwarf_r11 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "r12" , nullptr, 8, 0, eEncodingUint , eFormatHex , { dwarf_r12 , dwarf_r12 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "r13" , nullptr, 8, 0, eEncodingUint , eFormatHex , { dwarf_r13 , dwarf_r13 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "r14" , nullptr, 8, 0, eEncodingUint , eFormatHex , { dwarf_r14 , dwarf_r14 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "r15" , nullptr, 8, 0, eEncodingUint , eFormatHex , { dwarf_r15 , dwarf_r15 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "rip" , "pc", 8, 0, eEncodingUint , eFormatHex , { dwarf_rip , dwarf_rip , LLDB_REGNUM_GENERIC_PC , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "rflags", nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_REGNUM_GENERIC_FLAGS , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "cs" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ss" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ds" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "es" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "fs" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "gs" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "stmm0" , nullptr,10, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_stmm0 , dwarf_stmm0 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "stmm1" , nullptr,10, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_stmm1 , dwarf_stmm1 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "stmm2" , nullptr,10, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_stmm2 , dwarf_stmm2 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "stmm3" , nullptr,10, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_stmm3 , dwarf_stmm3 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "stmm4" , nullptr,10, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_stmm4 , dwarf_stmm4 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "stmm5" , nullptr,10, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_stmm5 , dwarf_stmm5 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "stmm6" , nullptr,10, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_stmm6 , dwarf_stmm6 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "stmm7" , nullptr,10, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_stmm7 , dwarf_stmm7 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "fctrl" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "fstat" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ftag" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "fiseg" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "fioff" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "foseg" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "fooff" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "fop" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "xmm0" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_xmm0 , dwarf_xmm0 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "xmm1" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_xmm1 , dwarf_xmm1 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "xmm2" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_xmm2 , dwarf_xmm2 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "xmm3" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_xmm3 , dwarf_xmm3 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "xmm4" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_xmm4 , dwarf_xmm4 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "xmm5" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_xmm5 , dwarf_xmm5 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "xmm6" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_xmm6 , dwarf_xmm6 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "xmm7" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_xmm7 , dwarf_xmm7 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "xmm8" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_xmm8 , dwarf_xmm8 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "xmm9" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_xmm9 , dwarf_xmm9 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "xmm10" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_xmm10 , dwarf_xmm10 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "xmm11" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_xmm11 , dwarf_xmm11 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "xmm12" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_xmm12 , dwarf_xmm12 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "xmm13" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_xmm13 , dwarf_xmm13 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "xmm14" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_xmm14 , dwarf_xmm14 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "xmm15" , nullptr,16, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_xmm15 , dwarf_xmm15 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "mxcsr" , nullptr, 4, 0, eEncodingUint , eFormatHex , { LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ymm0" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm0 , dwarf_ymm0 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ymm1" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm1 , dwarf_ymm1 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ymm2" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm2 , dwarf_ymm2 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ymm3" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm3 , dwarf_ymm3 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ymm4" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm4 , dwarf_ymm4 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ymm5" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm5 , dwarf_ymm5 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ymm6" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm6 , dwarf_ymm6 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ymm7" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm7 , dwarf_ymm7 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ymm8" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm8 , dwarf_ymm8 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ymm9" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm9 , dwarf_ymm9 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ymm10" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm10 , dwarf_ymm10 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ymm11" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm11 , dwarf_ymm11 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ymm12" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm12 , dwarf_ymm12 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ymm13" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm13 , dwarf_ymm13 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
|
|
|
{ "ymm14" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm14 , dwarf_ymm14 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 },
|
2016-09-06 19:00:37 +08:00
|
|
|
{ "ymm15" , nullptr,32, 0, eEncodingVector, eFormatVectorOfUInt8, { dwarf_ymm15 , dwarf_ymm15 , LLDB_INVALID_REGNUM , LLDB_INVALID_REGNUM, LLDB_INVALID_REGNUM }, nullptr, nullptr, nullptr, 0 }
|
2011-08-22 10:49:39 +08:00
|
|
|
};
|
|
|
|
|
2014-06-27 13:17:41 +08:00
|
|
|
static const uint32_t k_num_register_infos = llvm::array_lengthof(g_register_infos);
|
2011-08-22 10:49:39 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
Added the "frame diagnose" command and use its output to make crash info better.
When a process stops due to a crash, we get the crashing instruction and the
crashing memory location (if there is one). From the user's perspective it is
often unclear what the reason for the crash is in a symbolic sense.
To address this, I have added new fuctionality to StackFrame to parse the
disassembly and reconstruct the sequence of dereferneces and offsets that were
applied to a known variable (or fuction retrn value) to obtain the invalid
pointer.
This makes use of enhancements in the disassembler, as well as new information
provided by the DWARF expression infrastructure, and is exposed through a
"frame diagnose" command. It is also used to provide symbolic information, when
available, in the event of a crash.
The algorithm is very rudimentary, and it needs a bunch of work, including
- better parsing for assembly, preferably with help from LLVM
- support for non-Apple platforms
- cleanup of the algorithm core, preferably to make it all work in terms of
Operands instead of register/offset pairs
- improvement of the GetExpressioPath() logic to make prettier expression
paths, and
- better handling of vtables.
I welcome all suggestios, improvements, and testcases.
llvm-svn: 280692
2016-09-06 12:48:36 +08:00
|
|
|
bool
|
|
|
|
ABISysV_x86_64::GetPointerReturnRegister (const char *&name)
|
|
|
|
{
|
|
|
|
name = "rax";
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
size_t
|
|
|
|
ABISysV_x86_64::GetRedZoneSize () const
|
|
|
|
{
|
|
|
|
return 128;
|
|
|
|
}
|
|
|
|
|
|
|
|
//------------------------------------------------------------------
|
|
|
|
// Static Functions
|
|
|
|
//------------------------------------------------------------------
|
2016-02-27 06:26:21 +08:00
|
|
|
|
2011-05-12 02:39:18 +08:00
|
|
|
ABISP
|
2011-02-16 05:59:32 +08:00
|
|
|
ABISysV_x86_64::CreateInstance (const ArchSpec &arch)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2011-05-12 02:39:18 +08:00
|
|
|
static ABISP g_abi_sp;
|
2011-02-16 05:59:32 +08:00
|
|
|
if (arch.GetTriple().getArch() == llvm::Triple::x86_64)
|
2011-05-12 02:39:18 +08:00
|
|
|
{
|
|
|
|
if (!g_abi_sp)
|
|
|
|
g_abi_sp.reset (new ABISysV_x86_64);
|
|
|
|
return g_abi_sp;
|
|
|
|
}
|
|
|
|
return ABISP();
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ABISysV_x86_64::PrepareTrivialCall (Thread &thread,
|
2011-05-14 09:50:35 +08:00
|
|
|
addr_t sp,
|
|
|
|
addr_t func_addr,
|
|
|
|
addr_t return_addr,
|
2013-11-08 09:14:26 +08:00
|
|
|
llvm::ArrayRef<addr_t> args) const
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2013-03-28 07:08:40 +08:00
|
|
|
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS));
|
2010-10-08 09:58:41 +08:00
|
|
|
|
|
|
|
if (log)
|
2013-07-12 06:46:58 +08:00
|
|
|
{
|
|
|
|
StreamString s;
|
|
|
|
s.Printf("ABISysV_x86_64::PrepareTrivialCall (tid = 0x%" PRIx64 ", sp = 0x%" PRIx64 ", func_addr = 0x%" PRIx64 ", return_addr = 0x%" PRIx64,
|
|
|
|
thread.GetID(),
|
2010-10-08 09:58:41 +08:00
|
|
|
(uint64_t)sp,
|
Cleaned up the ABI::PrepareTrivialCall() function to take three argument
pointers:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t *arg1_ptr,
lldb::addr_t *arg2_ptr,
lldb::addr_t *arg3_ptr) const = 0;
Prior to this it was:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t arg,
lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg) const = 0;
This was because the function that called this slowly added more features to
be able to call a C++ member function that might have a "this" pointer, and
then later added "self + cmd" support for objective C. Cleaning this code up
and the code that calls it makes it easier to implement the functions for
new targets.
The MacOSX_arm::PrepareTrivialCall() is now filled in and ready for testing.
llvm-svn: 131221
2011-05-12 10:14:56 +08:00
|
|
|
(uint64_t)func_addr,
|
2013-07-12 06:46:58 +08:00
|
|
|
(uint64_t)return_addr);
|
|
|
|
|
2014-04-02 11:51:35 +08:00
|
|
|
for (size_t i = 0; i < args.size(); ++i)
|
2015-03-31 01:46:36 +08:00
|
|
|
s.Printf (", arg%" PRIu64 " = 0x%" PRIx64, static_cast<uint64_t>(i + 1), args[i]);
|
2013-07-12 06:46:58 +08:00
|
|
|
s.PutCString (")");
|
|
|
|
log->PutCString(s.GetString().c_str());
|
|
|
|
}
|
2010-10-08 09:58:41 +08:00
|
|
|
|
2011-01-07 06:15:06 +08:00
|
|
|
RegisterContext *reg_ctx = thread.GetRegisterContext().get();
|
2010-06-09 00:52:24 +08:00
|
|
|
if (!reg_ctx)
|
|
|
|
return false;
|
2010-09-08 05:23:34 +08:00
|
|
|
|
2016-02-27 06:26:21 +08:00
|
|
|
const RegisterInfo *reg_info = nullptr;
|
2013-11-08 09:14:26 +08:00
|
|
|
|
|
|
|
if (args.size() > 6) // TODO handle more than 6 arguments
|
|
|
|
return false;
|
|
|
|
|
2014-04-02 11:51:35 +08:00
|
|
|
for (size_t i = 0; i < args.size(); ++i)
|
Removed the hacky "#define this ___clang_this" handler
for C++ classes. Replaced it with a less hacky approach:
- If an expression is defined in the context of a
method of class A, then that expression is wrapped as
___clang_class::___clang_expr(void*) { ... }
instead of ___clang_expr(void*) { ... }.
- ___clang_class is resolved as the type of the target
of the "this" pointer in the method the expression
is defined in.
- When reporting the type of ___clang_class, a method
with the signature ___clang_expr(void*) is added to
that class, so that Clang doesn't complain about a
method being defined without a corresponding
declaration.
- Whenever the expression gets called, "this" gets
looked up, type-checked, and then passed in as the
first argument.
This required the following changes:
- The ABIs were changed to support passing of the "this"
pointer as part of trivial calls.
- ThreadPlanCallFunction and ClangFunction were changed
to support passing of an optional "this" pointer.
- ClangUserExpression was extended to perform the
wrapping described above.
- ClangASTSource was changed to revert the changes
required by the hack.
- ClangExpressionParser, IRForTarget, and
ClangExpressionDeclMap were changed to handle
different manglings of ___clang_expr flexibly. This
meant no longer searching for a function called
___clang_expr, but rather looking for a function whose
name *contains* ___clang_expr.
- ClangExpressionParser and ClangExpressionDeclMap now
remember whether "this" is required, and know how to
look it up as necessary.
A few inheritance bugs remain, and I'm trying to resolve
these. But it is now possible to use "this" as well as
refer implicitly to member variables, when in the proper
context.
llvm-svn: 114384
2010-09-21 08:44:12 +08:00
|
|
|
{
|
2013-11-08 09:14:26 +08:00
|
|
|
reg_info = reg_ctx->GetRegisterInfo(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1 + i);
|
2010-10-08 09:58:41 +08:00
|
|
|
if (log)
|
2015-03-31 01:46:36 +08:00
|
|
|
log->Printf("About to write arg%" PRIu64 " (0x%" PRIx64 ") into %s", static_cast<uint64_t>(i + 1), args[i], reg_info->name);
|
2013-11-08 09:14:26 +08:00
|
|
|
if (!reg_ctx->WriteRegisterFromUnsigned(reg_info, args[i]))
|
Removed the hacky "#define this ___clang_this" handler
for C++ classes. Replaced it with a less hacky approach:
- If an expression is defined in the context of a
method of class A, then that expression is wrapped as
___clang_class::___clang_expr(void*) { ... }
instead of ___clang_expr(void*) { ... }.
- ___clang_class is resolved as the type of the target
of the "this" pointer in the method the expression
is defined in.
- When reporting the type of ___clang_class, a method
with the signature ___clang_expr(void*) is added to
that class, so that Clang doesn't complain about a
method being defined without a corresponding
declaration.
- Whenever the expression gets called, "this" gets
looked up, type-checked, and then passed in as the
first argument.
This required the following changes:
- The ABIs were changed to support passing of the "this"
pointer as part of trivial calls.
- ThreadPlanCallFunction and ClangFunction were changed
to support passing of an optional "this" pointer.
- ClangUserExpression was extended to perform the
wrapping described above.
- ClangASTSource was changed to revert the changes
required by the hack.
- ClangExpressionParser, IRForTarget, and
ClangExpressionDeclMap were changed to handle
different manglings of ___clang_expr flexibly. This
meant no longer searching for a function called
___clang_expr, but rather looking for a function whose
name *contains* ___clang_expr.
- ClangExpressionParser and ClangExpressionDeclMap now
remember whether "this" is required, and know how to
look it up as necessary.
A few inheritance bugs remain, and I'm trying to resolve
these. But it is now possible to use "this" as well as
refer implicitly to member variables, when in the proper
context.
llvm-svn: 114384
2010-09-21 08:44:12 +08:00
|
|
|
return false;
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
// First, align the SP
|
Cleaned up the ABI::PrepareTrivialCall() function to take three argument
pointers:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t *arg1_ptr,
lldb::addr_t *arg2_ptr,
lldb::addr_t *arg3_ptr) const = 0;
Prior to this it was:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t arg,
lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg) const = 0;
This was because the function that called this slowly added more features to
be able to call a C++ member function that might have a "this" pointer, and
then later added "self + cmd" support for objective C. Cleaning this code up
and the code that calls it makes it easier to implement the functions for
new targets.
The MacOSX_arm::PrepareTrivialCall() is now filled in and ready for testing.
llvm-svn: 131221
2011-05-12 10:14:56 +08:00
|
|
|
|
2010-10-08 09:58:41 +08:00
|
|
|
if (log)
|
2012-11-30 05:49:15 +08:00
|
|
|
log->Printf("16-byte aligning SP: 0x%" PRIx64 " to 0x%" PRIx64, (uint64_t)sp, (uint64_t)(sp & ~0xfull));
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
sp &= ~(0xfull); // 16-byte alignment
|
|
|
|
|
|
|
|
sp -= 8;
|
Cleaned up the ABI::PrepareTrivialCall() function to take three argument
pointers:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t *arg1_ptr,
lldb::addr_t *arg2_ptr,
lldb::addr_t *arg3_ptr) const = 0;
Prior to this it was:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t arg,
lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg) const = 0;
This was because the function that called this slowly added more features to
be able to call a C++ member function that might have a "this" pointer, and
then later added "self + cmd" support for objective C. Cleaning this code up
and the code that calls it makes it easier to implement the functions for
new targets.
The MacOSX_arm::PrepareTrivialCall() is now filled in and ready for testing.
llvm-svn: 131221
2011-05-12 10:14:56 +08:00
|
|
|
|
2013-11-05 09:24:05 +08:00
|
|
|
Error error;
|
|
|
|
const RegisterInfo *pc_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
|
|
|
|
const RegisterInfo *sp_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
|
|
|
|
ProcessSP process_sp (thread.GetProcess());
|
|
|
|
|
2011-05-15 09:25:55 +08:00
|
|
|
RegisterValue reg_value;
|
Cleaned up the ABI::PrepareTrivialCall() function to take three argument
pointers:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t *arg1_ptr,
lldb::addr_t *arg2_ptr,
lldb::addr_t *arg3_ptr) const = 0;
Prior to this it was:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t arg,
lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg) const = 0;
This was because the function that called this slowly added more features to
be able to call a C++ member function that might have a "this" pointer, and
then later added "self + cmd" support for objective C. Cleaning this code up
and the code that calls it makes it easier to implement the functions for
new targets.
The MacOSX_arm::PrepareTrivialCall() is now filled in and ready for testing.
llvm-svn: 131221
2011-05-12 10:14:56 +08:00
|
|
|
|
2013-11-05 09:24:05 +08:00
|
|
|
#if 0
|
|
|
|
// This code adds an extra frame so that we don't lose the function that we came from
|
|
|
|
// by pushing the PC and the FP and then writing the current FP to point to the FP value
|
|
|
|
// we just pushed. It is disabled for now until the stack backtracing code can be debugged.
|
|
|
|
|
|
|
|
// Save current PC
|
|
|
|
const RegisterInfo *fp_reg_info = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
|
|
|
|
if (reg_ctx->ReadRegister(pc_reg_info, reg_value))
|
|
|
|
{
|
|
|
|
if (log)
|
|
|
|
log->Printf("Pushing the current PC onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, reg_value.GetAsUInt64());
|
|
|
|
|
|
|
|
if (!process_sp->WritePointerToMemory(sp, reg_value.GetAsUInt64(), error))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
sp -= 8;
|
|
|
|
|
|
|
|
// Save current FP
|
|
|
|
if (reg_ctx->ReadRegister(fp_reg_info, reg_value))
|
|
|
|
{
|
|
|
|
if (log)
|
|
|
|
log->Printf("Pushing the current FP onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, reg_value.GetAsUInt64());
|
|
|
|
|
|
|
|
if (!process_sp->WritePointerToMemory(sp, reg_value.GetAsUInt64(), error))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Setup FP backchain
|
|
|
|
reg_value.SetUInt64 (sp);
|
|
|
|
|
|
|
|
if (log)
|
|
|
|
log->Printf("Writing FP: 0x%" PRIx64 " (for FP backchain)", reg_value.GetAsUInt64());
|
|
|
|
|
|
|
|
if (!reg_ctx->WriteRegister(fp_reg_info, reg_value))
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
sp -= 8;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2010-10-08 09:58:41 +08:00
|
|
|
if (log)
|
2013-11-05 09:24:05 +08:00
|
|
|
log->Printf("Pushing the return address onto the stack: 0x%" PRIx64 ": 0x%" PRIx64, (uint64_t)sp, (uint64_t)return_addr);
|
Cleaned up the ABI::PrepareTrivialCall() function to take three argument
pointers:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t *arg1_ptr,
lldb::addr_t *arg2_ptr,
lldb::addr_t *arg3_ptr) const = 0;
Prior to this it was:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t arg,
lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg) const = 0;
This was because the function that called this slowly added more features to
be able to call a C++ member function that might have a "this" pointer, and
then later added "self + cmd" support for objective C. Cleaning this code up
and the code that calls it makes it easier to implement the functions for
new targets.
The MacOSX_arm::PrepareTrivialCall() is now filled in and ready for testing.
llvm-svn: 131221
2011-05-12 10:14:56 +08:00
|
|
|
|
2013-11-05 09:24:05 +08:00
|
|
|
// Save return address onto the stack
|
|
|
|
if (!process_sp->WritePointerToMemory(sp, return_addr, error))
|
2010-06-09 00:52:24 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// %rsp is set to the actual stack value.
|
|
|
|
|
2010-10-08 09:58:41 +08:00
|
|
|
if (log)
|
2013-11-05 09:24:05 +08:00
|
|
|
log->Printf("Writing SP: 0x%" PRIx64, (uint64_t)sp);
|
2010-10-08 09:58:41 +08:00
|
|
|
|
2013-11-05 09:24:05 +08:00
|
|
|
if (!reg_ctx->WriteRegisterFromUnsigned (sp_reg_info, sp))
|
2010-06-09 00:52:24 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// %rip is set to the address of the called function.
|
2010-10-08 09:58:41 +08:00
|
|
|
|
|
|
|
if (log)
|
2013-11-05 09:24:05 +08:00
|
|
|
log->Printf("Writing IP: 0x%" PRIx64, (uint64_t)func_addr);
|
Cleaned up the ABI::PrepareTrivialCall() function to take three argument
pointers:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t *arg1_ptr,
lldb::addr_t *arg2_ptr,
lldb::addr_t *arg3_ptr) const = 0;
Prior to this it was:
virtual bool
PrepareTrivialCall (Thread &thread,
lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t returnAddress,
lldb::addr_t arg,
lldb::addr_t *this_arg,
lldb::addr_t *cmd_arg) const = 0;
This was because the function that called this slowly added more features to
be able to call a C++ member function that might have a "this" pointer, and
then later added "self + cmd" support for objective C. Cleaning this code up
and the code that calls it makes it easier to implement the functions for
new targets.
The MacOSX_arm::PrepareTrivialCall() is now filled in and ready for testing.
llvm-svn: 131221
2011-05-12 10:14:56 +08:00
|
|
|
|
2011-05-15 09:25:55 +08:00
|
|
|
if (!reg_ctx->WriteRegisterFromUnsigned (pc_reg_info, func_addr))
|
2010-06-09 00:52:24 +08:00
|
|
|
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 ¤t_argument_register,
|
|
|
|
addr_t ¤t_stack_argument)
|
|
|
|
{
|
|
|
|
if (bit_width > 64)
|
|
|
|
return false; // Scalar can't hold large integer arguments
|
|
|
|
|
|
|
|
if (current_argument_register < 6)
|
|
|
|
{
|
Added new lldb_private::Process memory read/write functions to stop a bunch
of duplicated code from appearing all over LLDB:
lldb::addr_t
Process::ReadPointerFromMemory (lldb::addr_t vm_addr, Error &error);
bool
Process::WritePointerToMemory (lldb::addr_t vm_addr, lldb::addr_t ptr_value, Error &error);
size_t
Process::ReadScalarIntegerFromMemory (lldb::addr_t addr, uint32_t byte_size, bool is_signed, Scalar &scalar, Error &error);
size_t
Process::WriteScalarToMemory (lldb::addr_t vm_addr, const Scalar &scalar, uint32_t size, Error &error);
in lldb_private::Process the following functions were renamed:
From:
uint64_t
Process::ReadUnsignedInteger (lldb::addr_t load_addr,
size_t byte_size,
Error &error);
To:
uint64_t
Process::ReadUnsignedIntegerFromMemory (lldb::addr_t load_addr,
size_t byte_size,
uint64_t fail_value,
Error &error);
Cleaned up a lot of code that was manually doing what the above functions do
to use the functions listed above.
Added the ability to get a scalar value as a buffer that can be written down
to a process (byte swapping the Scalar value if needed):
uint32_t
Scalar::GetAsMemoryData (void *dst,
uint32_t dst_len,
lldb::ByteOrder dst_byte_order,
Error &error) const;
The "dst_len" can be smaller that the size of the scalar and the least
significant bytes will be written. "dst_len" can also be larger and the
most significant bytes will be padded with zeroes.
Centralized the code that adds or removes address bits for callable and opcode
addresses into lldb_private::Target:
lldb::addr_t
Target::GetCallableLoadAddress (lldb::addr_t load_addr, AddressClass addr_class) const;
lldb::addr_t
Target::GetOpcodeLoadAddress (lldb::addr_t load_addr, AddressClass addr_class) const;
All necessary lldb_private::Address functions now use the target versions so
changes should only need to happen in one place if anything needs updating.
Fixed up a lot of places that were calling :
addr_t
Address::GetLoadAddress(Target*);
to call the Address::GetCallableLoadAddress() or Address::GetOpcodeLoadAddress()
as needed. There were many places in the breakpoint code where things could
go wrong for ARM if these weren't used.
llvm-svn: 131878
2011-05-23 06:46:53 +08:00
|
|
|
scalar = thread.GetRegisterContext()->ReadRegisterAsUnsigned(argument_register_ids[current_argument_register], 0);
|
2010-06-09 00:52:24 +08:00
|
|
|
current_argument_register++;
|
Added new lldb_private::Process memory read/write functions to stop a bunch
of duplicated code from appearing all over LLDB:
lldb::addr_t
Process::ReadPointerFromMemory (lldb::addr_t vm_addr, Error &error);
bool
Process::WritePointerToMemory (lldb::addr_t vm_addr, lldb::addr_t ptr_value, Error &error);
size_t
Process::ReadScalarIntegerFromMemory (lldb::addr_t addr, uint32_t byte_size, bool is_signed, Scalar &scalar, Error &error);
size_t
Process::WriteScalarToMemory (lldb::addr_t vm_addr, const Scalar &scalar, uint32_t size, Error &error);
in lldb_private::Process the following functions were renamed:
From:
uint64_t
Process::ReadUnsignedInteger (lldb::addr_t load_addr,
size_t byte_size,
Error &error);
To:
uint64_t
Process::ReadUnsignedIntegerFromMemory (lldb::addr_t load_addr,
size_t byte_size,
uint64_t fail_value,
Error &error);
Cleaned up a lot of code that was manually doing what the above functions do
to use the functions listed above.
Added the ability to get a scalar value as a buffer that can be written down
to a process (byte swapping the Scalar value if needed):
uint32_t
Scalar::GetAsMemoryData (void *dst,
uint32_t dst_len,
lldb::ByteOrder dst_byte_order,
Error &error) const;
The "dst_len" can be smaller that the size of the scalar and the least
significant bytes will be written. "dst_len" can also be larger and the
most significant bytes will be padded with zeroes.
Centralized the code that adds or removes address bits for callable and opcode
addresses into lldb_private::Target:
lldb::addr_t
Target::GetCallableLoadAddress (lldb::addr_t load_addr, AddressClass addr_class) const;
lldb::addr_t
Target::GetOpcodeLoadAddress (lldb::addr_t load_addr, AddressClass addr_class) const;
All necessary lldb_private::Address functions now use the target versions so
changes should only need to happen in one place if anything needs updating.
Fixed up a lot of places that were calling :
addr_t
Address::GetLoadAddress(Target*);
to call the Address::GetCallableLoadAddress() or Address::GetOpcodeLoadAddress()
as needed. There were many places in the breakpoint code where things could
go wrong for ARM if these weren't used.
llvm-svn: 131878
2011-05-23 06:46:53 +08:00
|
|
|
if (is_signed)
|
|
|
|
scalar.SignExtend (bit_width);
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
Added new lldb_private::Process memory read/write functions to stop a bunch
of duplicated code from appearing all over LLDB:
lldb::addr_t
Process::ReadPointerFromMemory (lldb::addr_t vm_addr, Error &error);
bool
Process::WritePointerToMemory (lldb::addr_t vm_addr, lldb::addr_t ptr_value, Error &error);
size_t
Process::ReadScalarIntegerFromMemory (lldb::addr_t addr, uint32_t byte_size, bool is_signed, Scalar &scalar, Error &error);
size_t
Process::WriteScalarToMemory (lldb::addr_t vm_addr, const Scalar &scalar, uint32_t size, Error &error);
in lldb_private::Process the following functions were renamed:
From:
uint64_t
Process::ReadUnsignedInteger (lldb::addr_t load_addr,
size_t byte_size,
Error &error);
To:
uint64_t
Process::ReadUnsignedIntegerFromMemory (lldb::addr_t load_addr,
size_t byte_size,
uint64_t fail_value,
Error &error);
Cleaned up a lot of code that was manually doing what the above functions do
to use the functions listed above.
Added the ability to get a scalar value as a buffer that can be written down
to a process (byte swapping the Scalar value if needed):
uint32_t
Scalar::GetAsMemoryData (void *dst,
uint32_t dst_len,
lldb::ByteOrder dst_byte_order,
Error &error) const;
The "dst_len" can be smaller that the size of the scalar and the least
significant bytes will be written. "dst_len" can also be larger and the
most significant bytes will be padded with zeroes.
Centralized the code that adds or removes address bits for callable and opcode
addresses into lldb_private::Target:
lldb::addr_t
Target::GetCallableLoadAddress (lldb::addr_t load_addr, AddressClass addr_class) const;
lldb::addr_t
Target::GetOpcodeLoadAddress (lldb::addr_t load_addr, AddressClass addr_class) const;
All necessary lldb_private::Address functions now use the target versions so
changes should only need to happen in one place if anything needs updating.
Fixed up a lot of places that were calling :
addr_t
Address::GetLoadAddress(Target*);
to call the Address::GetCallableLoadAddress() or Address::GetOpcodeLoadAddress()
as needed. There were many places in the breakpoint code where things could
go wrong for ARM if these weren't used.
llvm-svn: 131878
2011-05-23 06:46:53 +08:00
|
|
|
uint32_t byte_size = (bit_width + (8-1))/8;
|
2010-06-09 00:52:24 +08:00
|
|
|
Error error;
|
2012-02-21 08:09:25 +08:00
|
|
|
if (thread.GetProcess()->ReadScalarIntegerFromMemory(current_stack_argument, byte_size, is_signed, scalar, error))
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
Added new lldb_private::Process memory read/write functions to stop a bunch
of duplicated code from appearing all over LLDB:
lldb::addr_t
Process::ReadPointerFromMemory (lldb::addr_t vm_addr, Error &error);
bool
Process::WritePointerToMemory (lldb::addr_t vm_addr, lldb::addr_t ptr_value, Error &error);
size_t
Process::ReadScalarIntegerFromMemory (lldb::addr_t addr, uint32_t byte_size, bool is_signed, Scalar &scalar, Error &error);
size_t
Process::WriteScalarToMemory (lldb::addr_t vm_addr, const Scalar &scalar, uint32_t size, Error &error);
in lldb_private::Process the following functions were renamed:
From:
uint64_t
Process::ReadUnsignedInteger (lldb::addr_t load_addr,
size_t byte_size,
Error &error);
To:
uint64_t
Process::ReadUnsignedIntegerFromMemory (lldb::addr_t load_addr,
size_t byte_size,
uint64_t fail_value,
Error &error);
Cleaned up a lot of code that was manually doing what the above functions do
to use the functions listed above.
Added the ability to get a scalar value as a buffer that can be written down
to a process (byte swapping the Scalar value if needed):
uint32_t
Scalar::GetAsMemoryData (void *dst,
uint32_t dst_len,
lldb::ByteOrder dst_byte_order,
Error &error) const;
The "dst_len" can be smaller that the size of the scalar and the least
significant bytes will be written. "dst_len" can also be larger and the
most significant bytes will be padded with zeroes.
Centralized the code that adds or removes address bits for callable and opcode
addresses into lldb_private::Target:
lldb::addr_t
Target::GetCallableLoadAddress (lldb::addr_t load_addr, AddressClass addr_class) const;
lldb::addr_t
Target::GetOpcodeLoadAddress (lldb::addr_t load_addr, AddressClass addr_class) const;
All necessary lldb_private::Address functions now use the target versions so
changes should only need to happen in one place if anything needs updating.
Fixed up a lot of places that were calling :
addr_t
Address::GetLoadAddress(Target*);
to call the Address::GetCallableLoadAddress() or Address::GetOpcodeLoadAddress()
as needed. There were many places in the breakpoint code where things could
go wrong for ARM if these weren't used.
llvm-svn: 131878
2011-05-23 06:46:53 +08:00
|
|
|
current_stack_argument += byte_size;
|
|
|
|
return true;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
Added new lldb_private::Process memory read/write functions to stop a bunch
of duplicated code from appearing all over LLDB:
lldb::addr_t
Process::ReadPointerFromMemory (lldb::addr_t vm_addr, Error &error);
bool
Process::WritePointerToMemory (lldb::addr_t vm_addr, lldb::addr_t ptr_value, Error &error);
size_t
Process::ReadScalarIntegerFromMemory (lldb::addr_t addr, uint32_t byte_size, bool is_signed, Scalar &scalar, Error &error);
size_t
Process::WriteScalarToMemory (lldb::addr_t vm_addr, const Scalar &scalar, uint32_t size, Error &error);
in lldb_private::Process the following functions were renamed:
From:
uint64_t
Process::ReadUnsignedInteger (lldb::addr_t load_addr,
size_t byte_size,
Error &error);
To:
uint64_t
Process::ReadUnsignedIntegerFromMemory (lldb::addr_t load_addr,
size_t byte_size,
uint64_t fail_value,
Error &error);
Cleaned up a lot of code that was manually doing what the above functions do
to use the functions listed above.
Added the ability to get a scalar value as a buffer that can be written down
to a process (byte swapping the Scalar value if needed):
uint32_t
Scalar::GetAsMemoryData (void *dst,
uint32_t dst_len,
lldb::ByteOrder dst_byte_order,
Error &error) const;
The "dst_len" can be smaller that the size of the scalar and the least
significant bytes will be written. "dst_len" can also be larger and the
most significant bytes will be padded with zeroes.
Centralized the code that adds or removes address bits for callable and opcode
addresses into lldb_private::Target:
lldb::addr_t
Target::GetCallableLoadAddress (lldb::addr_t load_addr, AddressClass addr_class) const;
lldb::addr_t
Target::GetOpcodeLoadAddress (lldb::addr_t load_addr, AddressClass addr_class) const;
All necessary lldb_private::Address functions now use the target versions so
changes should only need to happen in one place if anything needs updating.
Fixed up a lot of places that were calling :
addr_t
Address::GetLoadAddress(Target*);
to call the Address::GetCallableLoadAddress() or Address::GetOpcodeLoadAddress()
as needed. There were many places in the breakpoint code where things could
go wrong for ARM if these weren't used.
llvm-svn: 131878
2011-05-23 06:46:53 +08:00
|
|
|
return false;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ABISysV_x86_64::GetArgumentValues (Thread &thread,
|
|
|
|
ValueList &values) const
|
|
|
|
{
|
|
|
|
unsigned int num_values = values.GetSize();
|
|
|
|
unsigned int value_index;
|
2013-07-12 06:46:58 +08:00
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
// Extract the register context so we can read arguments from registers
|
|
|
|
|
2011-01-07 06:15:06 +08:00
|
|
|
RegisterContext *reg_ctx = thread.GetRegisterContext().get();
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
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];
|
|
|
|
|
2013-11-05 09:24:05 +08:00
|
|
|
argument_register_ids[0] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG1)->kinds[eRegisterKindLLDB];
|
|
|
|
argument_register_ids[1] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG2)->kinds[eRegisterKindLLDB];
|
|
|
|
argument_register_ids[2] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG3)->kinds[eRegisterKindLLDB];
|
|
|
|
argument_register_ids[3] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG4)->kinds[eRegisterKindLLDB];
|
|
|
|
argument_register_ids[4] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG5)->kinds[eRegisterKindLLDB];
|
|
|
|
argument_register_ids[5] = reg_ctx->GetRegisterInfo (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_ARG6)->kinds[eRegisterKindLLDB];
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
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?
|
2015-09-24 11:54:50 +08:00
|
|
|
CompilerType compiler_type = value->GetCompilerType();
|
|
|
|
if (!compiler_type)
|
2010-06-09 00:52:24 +08:00
|
|
|
return false;
|
2013-07-12 06:46:58 +08:00
|
|
|
bool is_signed;
|
|
|
|
|
2016-06-25 07:48:00 +08:00
|
|
|
if (compiler_type.IsIntegerOrEnumerationType (is_signed))
|
2013-07-12 06:46:58 +08:00
|
|
|
{
|
|
|
|
ReadIntegerArgument(value->GetScalar(),
|
2015-09-24 11:54:50 +08:00
|
|
|
compiler_type.GetBitSize(&thread),
|
2013-07-12 06:46:58 +08:00
|
|
|
is_signed,
|
|
|
|
thread,
|
|
|
|
argument_register_ids,
|
|
|
|
current_argument_register,
|
|
|
|
current_stack_argument);
|
|
|
|
}
|
2015-09-24 11:54:50 +08:00
|
|
|
else if (compiler_type.IsPointerType ())
|
2013-07-12 06:46:58 +08:00
|
|
|
{
|
|
|
|
ReadIntegerArgument(value->GetScalar(),
|
2015-09-24 11:54:50 +08:00
|
|
|
compiler_type.GetBitSize(&thread),
|
2013-07-12 06:46:58 +08:00
|
|
|
false,
|
|
|
|
thread,
|
|
|
|
argument_register_ids,
|
|
|
|
current_argument_register,
|
|
|
|
current_stack_argument);
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2012-09-27 09:15:29 +08:00
|
|
|
Error
|
2013-11-04 17:33:30 +08:00
|
|
|
ABISysV_x86_64::SetReturnValueObject(lldb::StackFrameSP &frame_sp, lldb::ValueObjectSP &new_value_sp)
|
2012-09-27 09:15:29 +08:00
|
|
|
{
|
|
|
|
Error error;
|
|
|
|
if (!new_value_sp)
|
|
|
|
{
|
|
|
|
error.SetErrorString("Empty value object for return value.");
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2015-09-24 11:54:50 +08:00
|
|
|
CompilerType compiler_type = new_value_sp->GetCompilerType();
|
|
|
|
if (!compiler_type)
|
2012-09-27 09:15:29 +08:00
|
|
|
{
|
|
|
|
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;
|
2016-06-25 07:48:00 +08:00
|
|
|
if (compiler_type.IsIntegerOrEnumerationType (is_signed) || compiler_type.IsPointerType())
|
2012-09-27 09:15:29 +08:00
|
|
|
{
|
|
|
|
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName("rax", 0);
|
|
|
|
|
|
|
|
DataExtractor data;
|
2014-03-01 06:27:53 +08:00
|
|
|
Error data_error;
|
|
|
|
size_t num_bytes = new_value_sp->GetData(data, data_error);
|
|
|
|
if (data_error.Fail())
|
|
|
|
{
|
|
|
|
error.SetErrorStringWithFormat("Couldn't convert return value to raw data: %s", data_error.AsCString());
|
|
|
|
return error;
|
|
|
|
}
|
2013-01-26 02:06:21 +08:00
|
|
|
lldb::offset_t offset = 0;
|
2012-09-27 23:31:38 +08:00
|
|
|
if (num_bytes <= 8)
|
2012-09-27 09:15:29 +08:00
|
|
|
{
|
|
|
|
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.");
|
|
|
|
}
|
|
|
|
}
|
2015-09-24 11:54:50 +08:00
|
|
|
else if (compiler_type.IsFloatingPointType (count, is_complex))
|
2012-09-27 09:15:29 +08:00
|
|
|
{
|
|
|
|
if (is_complex)
|
|
|
|
error.SetErrorString ("We don't support returning complex values at present");
|
|
|
|
else
|
|
|
|
{
|
2015-09-24 11:54:50 +08:00
|
|
|
size_t bit_width = compiler_type.GetBitSize(frame_sp.get());
|
2012-09-27 09:15:29 +08:00
|
|
|
if (bit_width <= 64)
|
|
|
|
{
|
|
|
|
const RegisterInfo *xmm0_info = reg_ctx->GetRegisterInfoByName("xmm0", 0);
|
|
|
|
RegisterValue xmm0_value;
|
|
|
|
DataExtractor data;
|
2014-03-01 06:27:53 +08:00
|
|
|
Error data_error;
|
|
|
|
size_t num_bytes = new_value_sp->GetData(data, data_error);
|
|
|
|
if (data_error.Fail())
|
|
|
|
{
|
|
|
|
error.SetErrorStringWithFormat("Couldn't convert return value to raw data: %s", data_error.AsCString());
|
|
|
|
return error;
|
|
|
|
}
|
|
|
|
|
2012-09-27 09:15:29 +08:00
|
|
|
unsigned char buffer[16];
|
|
|
|
ByteOrder byte_order = data.GetByteOrder();
|
|
|
|
|
2012-10-13 01:34:26 +08:00
|
|
|
data.CopyByteOrderedData (0, num_bytes, buffer, 16, byte_order);
|
2012-09-27 09:15:29 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2011-12-23 03:12:40 +08:00
|
|
|
ValueObjectSP
|
|
|
|
ABISysV_x86_64::GetReturnValueObjectSimple (Thread &thread,
|
2015-09-24 11:54:50 +08:00
|
|
|
CompilerType &return_compiler_type) const
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2011-12-23 03:12:40 +08:00
|
|
|
ValueObjectSP return_valobj_sp;
|
|
|
|
Value value;
|
|
|
|
|
2015-09-24 11:54:50 +08:00
|
|
|
if (!return_compiler_type)
|
2011-12-23 03:12:40 +08:00
|
|
|
return return_valobj_sp;
|
|
|
|
|
2013-07-12 06:46:58 +08:00
|
|
|
//value.SetContext (Value::eContextTypeClangType, return_value_type);
|
2015-09-24 11:54:50 +08:00
|
|
|
value.SetCompilerType (return_compiler_type);
|
2011-12-23 03:12:40 +08:00
|
|
|
|
|
|
|
RegisterContext *reg_ctx = thread.GetRegisterContext().get();
|
|
|
|
if (!reg_ctx)
|
|
|
|
return return_valobj_sp;
|
|
|
|
|
2015-09-24 11:54:50 +08:00
|
|
|
const uint32_t type_flags = return_compiler_type.GetTypeInfo ();
|
2014-10-22 04:52:14 +08:00
|
|
|
if (type_flags & eTypeIsScalar)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2013-04-06 07:27:21 +08:00
|
|
|
value.SetValueType(Value::eValueTypeScalar);
|
|
|
|
|
|
|
|
bool success = false;
|
2014-10-22 04:52:14 +08:00
|
|
|
if (type_flags & eTypeIsInteger)
|
2011-12-23 03:12:40 +08:00
|
|
|
{
|
2013-04-06 07:27:21 +08:00
|
|
|
// Extract the register context so we can read arguments from registers
|
|
|
|
|
2015-09-24 11:54:50 +08:00
|
|
|
const size_t byte_size = return_compiler_type.GetByteSize(nullptr);
|
2013-04-06 07:27:21 +08:00
|
|
|
uint64_t raw_value = thread.GetRegisterContext()->ReadRegisterAsUnsigned(reg_ctx->GetRegisterInfoByName("rax", 0), 0);
|
2014-10-22 04:52:14 +08:00
|
|
|
const bool is_signed = (type_flags & eTypeIsSigned) != 0;
|
2013-04-06 07:27:21 +08:00
|
|
|
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;
|
|
|
|
}
|
2011-12-23 03:12:40 +08:00
|
|
|
}
|
2014-10-22 04:52:14 +08:00
|
|
|
else if (type_flags & eTypeIsFloat)
|
2011-12-23 03:12:40 +08:00
|
|
|
{
|
2014-10-22 04:52:14 +08:00
|
|
|
if (type_flags & eTypeIsComplex)
|
2011-12-23 03:12:40 +08:00
|
|
|
{
|
2013-04-06 07:27:21 +08:00
|
|
|
// Don't handle complex yet.
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-09-24 11:54:50 +08:00
|
|
|
const size_t byte_size = return_compiler_type.GetByteSize(nullptr);
|
2013-04-06 07:27:21 +08:00
|
|
|
if (byte_size <= sizeof(long double))
|
2011-12-23 03:12:40 +08:00
|
|
|
{
|
2013-04-06 07:27:21 +08:00
|
|
|
const RegisterInfo *xmm0_info = reg_ctx->GetRegisterInfoByName("xmm0", 0);
|
|
|
|
RegisterValue xmm0_value;
|
|
|
|
if (reg_ctx->ReadRegister (xmm0_info, xmm0_value))
|
2011-12-23 03:12:40 +08:00
|
|
|
{
|
2013-04-06 07:27:21 +08:00
|
|
|
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...
|
|
|
|
}
|
|
|
|
}
|
2011-12-23 03:12:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-04-06 07:27:21 +08:00
|
|
|
|
|
|
|
if (success)
|
|
|
|
return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(),
|
|
|
|
value,
|
|
|
|
ConstString(""));
|
2011-12-23 03:12:40 +08:00
|
|
|
}
|
2014-10-22 04:52:14 +08:00
|
|
|
else if (type_flags & eTypeIsPointer)
|
2011-12-23 03:12:40 +08:00
|
|
|
{
|
|
|
|
unsigned rax_id = reg_ctx->GetRegisterInfoByName("rax", 0)->kinds[eRegisterKindLLDB];
|
|
|
|
value.GetScalar() = (uint64_t)thread.GetRegisterContext()->ReadRegisterAsUnsigned(rax_id, 0);
|
2013-04-06 07:27:21 +08:00
|
|
|
value.SetValueType(Value::eValueTypeScalar);
|
|
|
|
return_valobj_sp = ValueObjectConstResult::Create (thread.GetStackFrameAtIndex(0).get(),
|
|
|
|
value,
|
|
|
|
ConstString(""));
|
2011-12-23 03:12:40 +08:00
|
|
|
}
|
2014-10-22 04:52:14 +08:00
|
|
|
else if (type_flags & eTypeIsVector)
|
2011-12-23 03:12:40 +08:00
|
|
|
{
|
2015-09-24 11:54:50 +08:00
|
|
|
const size_t byte_size = return_compiler_type.GetByteSize(nullptr);
|
2013-04-06 07:27:21 +08:00
|
|
|
if (byte_size > 0)
|
|
|
|
{
|
2015-07-23 07:47:29 +08:00
|
|
|
const RegisterInfo *altivec_reg = reg_ctx->GetRegisterInfoByName("xmm0", 0);
|
|
|
|
if (altivec_reg == nullptr)
|
|
|
|
altivec_reg = reg_ctx->GetRegisterInfoByName("mm0", 0);
|
2013-04-06 07:27:21 +08:00
|
|
|
|
|
|
|
if (altivec_reg)
|
|
|
|
{
|
|
|
|
if (byte_size <= altivec_reg->byte_size)
|
|
|
|
{
|
|
|
|
ProcessSP process_sp (thread.GetProcess());
|
|
|
|
if (process_sp)
|
|
|
|
{
|
2013-04-19 06:45:39 +08:00
|
|
|
std::unique_ptr<DataBufferHeap> heap_data_ap (new DataBufferHeap(byte_size, 0));
|
2013-04-06 07:27:21 +08:00
|
|
|
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,
|
2015-09-24 11:54:50 +08:00
|
|
|
return_compiler_type,
|
2013-04-06 07:27:21 +08:00
|
|
|
ConstString(""),
|
|
|
|
data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-07-23 07:47:29 +08:00
|
|
|
}
|
|
|
|
else if (byte_size <= altivec_reg->byte_size*2)
|
|
|
|
{
|
|
|
|
const RegisterInfo *altivec_reg2 = reg_ctx->GetRegisterInfoByName("xmm1", 0);
|
|
|
|
if (altivec_reg2)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
RegisterValue reg_value2;
|
|
|
|
if (reg_ctx->ReadRegister(altivec_reg, reg_value) && reg_ctx->ReadRegister(altivec_reg2, reg_value2))
|
|
|
|
{
|
|
|
|
|
|
|
|
Error error;
|
|
|
|
if (reg_value.GetAsMemoryData (altivec_reg,
|
|
|
|
heap_data_ap->GetBytes(),
|
|
|
|
altivec_reg->byte_size,
|
|
|
|
byte_order,
|
|
|
|
error) &&
|
|
|
|
reg_value2.GetAsMemoryData (altivec_reg2,
|
|
|
|
heap_data_ap->GetBytes() + altivec_reg->byte_size,
|
|
|
|
heap_data_ap->GetByteSize() - altivec_reg->byte_size,
|
|
|
|
byte_order,
|
|
|
|
error))
|
|
|
|
{
|
|
|
|
DataExtractor data (DataBufferSP (heap_data_ap.release()),
|
|
|
|
byte_order,
|
|
|
|
process_sp->GetTarget().GetArchitecture().GetAddressByteSize());
|
|
|
|
return_valobj_sp = ValueObjectConstResult::Create (&thread,
|
2015-09-24 11:54:50 +08:00
|
|
|
return_compiler_type,
|
2015-07-23 07:47:29 +08:00
|
|
|
ConstString(""),
|
|
|
|
data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-04-06 07:27:21 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-12-23 03:12:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return return_valobj_sp;
|
|
|
|
}
|
|
|
|
|
|
|
|
ValueObjectSP
|
2015-09-24 11:54:50 +08:00
|
|
|
ABISysV_x86_64::GetReturnValueObjectImpl (Thread &thread, CompilerType &return_compiler_type) const
|
2011-12-23 03:12:40 +08:00
|
|
|
{
|
|
|
|
ValueObjectSP return_valobj_sp;
|
2013-07-12 06:46:58 +08:00
|
|
|
|
2015-09-24 11:54:50 +08:00
|
|
|
if (!return_compiler_type)
|
2013-07-12 06:46:58 +08:00
|
|
|
return return_valobj_sp;
|
2011-12-23 03:12:40 +08:00
|
|
|
|
2012-02-21 08:09:25 +08:00
|
|
|
ExecutionContext exe_ctx (thread.shared_from_this());
|
2015-09-24 11:54:50 +08:00
|
|
|
return_valobj_sp = GetReturnValueObjectSimple(thread, return_compiler_type);
|
2011-12-23 03:12:40 +08:00
|
|
|
if (return_valobj_sp)
|
|
|
|
return return_valobj_sp;
|
|
|
|
|
|
|
|
RegisterContextSP reg_ctx_sp = thread.GetRegisterContext();
|
|
|
|
if (!reg_ctx_sp)
|
|
|
|
return return_valobj_sp;
|
|
|
|
|
2015-09-24 11:54:50 +08:00
|
|
|
const size_t bit_width = return_compiler_type.GetBitSize(&thread);
|
|
|
|
if (return_compiler_type.IsAggregateType())
|
2011-12-23 03:12:40 +08:00
|
|
|
{
|
2012-02-21 08:09:25 +08:00
|
|
|
Target *target = exe_ctx.GetTargetPtr();
|
2011-12-23 03:12:40 +08:00
|
|
|
bool is_memory = true;
|
|
|
|
if (bit_width <= 128)
|
|
|
|
{
|
2012-02-21 08:09:25 +08:00
|
|
|
ByteOrder target_byte_order = target->GetArchitecture().GetByteOrder();
|
2011-12-23 03:12:40 +08:00
|
|
|
DataBufferSP data_sp (new DataBufferHeap(16, 0));
|
|
|
|
DataExtractor return_ext (data_sp,
|
|
|
|
target_byte_order,
|
2012-02-21 08:09:25 +08:00
|
|
|
target->GetArchitecture().GetAddressByteSize());
|
2011-12-23 03:12:40 +08:00
|
|
|
|
|
|
|
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);
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2011-12-23 03:12:40 +08:00
|
|
|
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;
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2011-12-23 03:12:40 +08:00
|
|
|
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
|
|
|
|
|
2015-09-24 11:54:50 +08:00
|
|
|
const uint32_t num_children = return_compiler_type.GetNumFields ();
|
2011-12-23 03:12:40 +08:00
|
|
|
|
|
|
|
// 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++)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2011-12-23 03:12:40 +08:00
|
|
|
std::string name;
|
2012-08-01 07:39:10 +08:00
|
|
|
uint64_t field_bit_offset = 0;
|
2011-12-23 03:12:40 +08:00
|
|
|
bool is_signed;
|
|
|
|
bool is_complex;
|
|
|
|
uint32_t count;
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2016-02-27 06:26:21 +08:00
|
|
|
CompilerType field_compiler_type = return_compiler_type.GetFieldAtIndex(idx, name, &field_bit_offset, nullptr, nullptr);
|
2015-09-24 11:54:50 +08:00
|
|
|
const size_t field_bit_width = field_compiler_type.GetBitSize(&thread);
|
2011-12-23 03:12:40 +08:00
|
|
|
|
2015-04-07 05:39:56 +08:00
|
|
|
// if we don't know the size of the field (e.g. invalid type), just bail out
|
|
|
|
if (field_bit_width == 0)
|
|
|
|
break;
|
|
|
|
|
2011-12-23 03:12:40 +08:00
|
|
|
// If there are any unaligned fields, this is stored in memory.
|
|
|
|
if (field_bit_offset % field_bit_width != 0)
|
|
|
|
{
|
|
|
|
is_memory = true;
|
|
|
|
break;
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2011-12-23 03:12:40 +08:00
|
|
|
uint32_t field_byte_width = field_bit_width/8;
|
|
|
|
uint32_t field_byte_offset = field_bit_offset/8;
|
|
|
|
|
2016-02-27 06:26:21 +08:00
|
|
|
DataExtractor *copy_from_extractor = nullptr;
|
2011-12-23 03:12:40 +08:00
|
|
|
uint32_t copy_from_offset = 0;
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2016-06-25 07:48:00 +08:00
|
|
|
if (field_compiler_type.IsIntegerOrEnumerationType (is_signed) || field_compiler_type.IsPointerType ())
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2011-12-23 03:12:40 +08:00
|
|
|
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;
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
else
|
2011-12-23 03:12:40 +08:00
|
|
|
{
|
|
|
|
// The last field didn't fit. I can't see how that would happen w/o the overall size being
|
2016-02-27 06:26:21 +08:00
|
|
|
// greater than 16 bytes. For now, return a nullptr return value object.
|
2011-12-23 03:12:40 +08:00
|
|
|
return return_valobj_sp;
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2015-09-24 11:54:50 +08:00
|
|
|
else if (field_compiler_type.IsFloatingPointType (count, is_complex))
|
2011-12-23 03:12:40 +08:00
|
|
|
{
|
|
|
|
// 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)
|
2011-12-23 08:30:10 +08:00
|
|
|
in_gpr = false;
|
2011-12-23 03:12:40 +08:00
|
|
|
else
|
|
|
|
{
|
2012-08-01 07:39:10 +08:00
|
|
|
uint64_t next_field_bit_offset = 0;
|
2015-09-24 11:54:50 +08:00
|
|
|
CompilerType next_field_compiler_type = return_compiler_type.GetFieldAtIndex (idx + 1,
|
2013-07-12 06:46:58 +08:00
|
|
|
name,
|
|
|
|
&next_field_bit_offset,
|
2016-02-27 06:26:21 +08:00
|
|
|
nullptr,
|
|
|
|
nullptr);
|
2016-06-25 07:48:00 +08:00
|
|
|
if (next_field_compiler_type.IsIntegerOrEnumerationType (is_signed))
|
2011-12-23 03:12:40 +08:00
|
|
|
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
|
|
|
|
{
|
2012-08-01 07:39:10 +08:00
|
|
|
uint64_t prev_field_bit_offset = 0;
|
2015-09-24 11:54:50 +08:00
|
|
|
CompilerType prev_field_compiler_type = return_compiler_type.GetFieldAtIndex (idx - 1,
|
2013-07-12 06:46:58 +08:00
|
|
|
name,
|
|
|
|
&prev_field_bit_offset,
|
2016-02-27 06:26:21 +08:00
|
|
|
nullptr,
|
|
|
|
nullptr);
|
2016-06-25 07:48:00 +08:00
|
|
|
if (prev_field_compiler_type.IsIntegerOrEnumerationType (is_signed))
|
2011-12-23 03:12:40 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-12-23 08:57:42 +08:00
|
|
|
|
|
|
|
// These two tests are just sanity checks. If I somehow get the
|
|
|
|
// type calculation wrong above it is better to just return nothing
|
2012-09-18 08:00:25 +08:00
|
|
|
// than to assert or crash.
|
2011-12-23 03:12:40 +08:00
|
|
|
if (!copy_from_extractor)
|
|
|
|
return return_valobj_sp;
|
2011-12-23 08:57:42 +08:00
|
|
|
if (copy_from_offset + field_byte_width > copy_from_extractor->GetByteSize())
|
|
|
|
return return_valobj_sp;
|
2011-12-23 03:12:40 +08:00
|
|
|
|
|
|
|
copy_from_extractor->CopyByteOrderedData (copy_from_offset,
|
|
|
|
field_byte_width,
|
|
|
|
data_sp->GetBytes() + field_byte_offset,
|
|
|
|
field_byte_width,
|
|
|
|
target_byte_order);
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2011-12-23 03:12:40 +08:00
|
|
|
|
|
|
|
if (!is_memory)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2011-12-23 03:12:40 +08:00
|
|
|
// The result is in our data buffer. Let's make a variable object out of it:
|
|
|
|
return_valobj_sp = ValueObjectConstResult::Create (&thread,
|
2015-09-24 11:54:50 +08:00
|
|
|
return_compiler_type,
|
2011-12-23 03:12:40 +08:00
|
|
|
ConstString(""),
|
|
|
|
return_ext);
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
}
|
2016-02-27 06:26:21 +08:00
|
|
|
|
2013-04-06 01:39:29 +08:00
|
|
|
// 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.
|
|
|
|
|
2011-12-23 03:12:40 +08:00
|
|
|
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);
|
2016-02-27 06:26:21 +08:00
|
|
|
return_valobj_sp = ValueObjectMemory::Create(&thread,
|
|
|
|
"",
|
|
|
|
Address(storage_addr, nullptr),
|
|
|
|
return_compiler_type);
|
2011-12-23 03:12:40 +08:00
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2011-12-23 03:12:40 +08:00
|
|
|
|
|
|
|
return return_valobj_sp;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
2015-01-17 07:54:15 +08:00
|
|
|
// This defines the CFA as rsp+8
|
|
|
|
// the saved pc is at CFA-8 (i.e. rsp+0)
|
|
|
|
// The saved rsp is CFA+0
|
|
|
|
|
2011-05-12 02:39:18 +08:00
|
|
|
bool
|
|
|
|
ABISysV_x86_64::CreateFunctionEntryUnwindPlan (UnwindPlan &unwind_plan)
|
|
|
|
{
|
2013-08-23 07:13:43 +08:00
|
|
|
unwind_plan.Clear();
|
|
|
|
unwind_plan.SetRegisterKind (eRegisterKindDWARF);
|
|
|
|
|
Clean up register naming conventions inside lldb.
"gcc" register numbers are now correctly referred to as "ehframe"
register numbers. In almost all cases, ehframe and dwarf register
numbers are identical (the one exception is i386 darwin where ehframe
regnums were incorrect).
The old "gdb" register numbers, which I incorrectly thought were
stabs register numbers, are now referred to as "Process Plugin"
register numbers. This is the register numbering scheme that the
remote process controller stub (lldb-server, gdbserver, core file
support, kdp server, remote jtag devices, etc) uses to refer to the
registers. The process plugin register numbers may not be contiguous
- there are remote jtag devices that have gaps in their register
numbering schemes.
I removed all of the enums for "gdb" register numbers that we had
in lldb - these were meaningless - and I put LLDB_INVALID_REGNUM
in all of the register tables for the Process Plugin regnum slot.
This change is almost entirely mechnical; the one actual change in
here is to ProcessGDBRemote.cpp's ParseRegisters() which parses the
qXfer:features:read:target.xml response. As it parses register
definitions from the xml, it will assign sequential numbers as the
eRegisterKindLLDB numbers (the lldb register numberings must be
sequential, without any gaps) and if the xml file specifies register
numbers, those will be used as the eRegisterKindProcessPlugin
register numbers (and those may have gaps). A J-Link jtag device's
target.xml does contain a gap in register numbers, and it only
specifies the register numbers for the registers after that gap.
The device supports many different ARM boards and probably selects
different part of its register file as appropriate.
http://reviews.llvm.org/D12791
<rdar://problem/22623262>
llvm-svn: 247741
2015-09-16 07:20:34 +08:00
|
|
|
uint32_t sp_reg_num = dwarf_rsp;
|
|
|
|
uint32_t pc_reg_num = dwarf_rip;
|
2011-05-12 02:39:18 +08:00
|
|
|
|
2012-07-14 12:52:53 +08:00
|
|
|
UnwindPlan::RowSP row(new UnwindPlan::Row);
|
2015-02-23 18:19:16 +08:00
|
|
|
row->GetCFAValue().SetIsRegisterPlusOffset(sp_reg_num, 8);
|
2012-07-14 12:52:53 +08:00
|
|
|
row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, -8, false);
|
2015-01-17 07:54:15 +08:00
|
|
|
row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
|
2011-05-12 02:39:18 +08:00
|
|
|
unwind_plan.AppendRow (row);
|
2011-09-15 08:44:34 +08:00
|
|
|
unwind_plan.SetSourceName ("x86_64 at-func-entry default");
|
2012-10-26 14:08:58 +08:00
|
|
|
unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
|
2011-05-12 02:39:18 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-01-17 07:54:15 +08:00
|
|
|
// This defines the CFA as rbp+16
|
|
|
|
// The saved pc is at CFA-8 (i.e. rbp+8)
|
|
|
|
// The saved rbp is at CFA-16 (i.e. rbp+0)
|
|
|
|
// The saved rsp is CFA+0
|
|
|
|
|
2011-05-12 02:39:18 +08:00
|
|
|
bool
|
|
|
|
ABISysV_x86_64::CreateDefaultUnwindPlan (UnwindPlan &unwind_plan)
|
|
|
|
{
|
2013-08-23 07:13:43 +08:00
|
|
|
unwind_plan.Clear();
|
|
|
|
unwind_plan.SetRegisterKind (eRegisterKindDWARF);
|
2011-05-12 02:39:18 +08:00
|
|
|
|
Clean up register naming conventions inside lldb.
"gcc" register numbers are now correctly referred to as "ehframe"
register numbers. In almost all cases, ehframe and dwarf register
numbers are identical (the one exception is i386 darwin where ehframe
regnums were incorrect).
The old "gdb" register numbers, which I incorrectly thought were
stabs register numbers, are now referred to as "Process Plugin"
register numbers. This is the register numbering scheme that the
remote process controller stub (lldb-server, gdbserver, core file
support, kdp server, remote jtag devices, etc) uses to refer to the
registers. The process plugin register numbers may not be contiguous
- there are remote jtag devices that have gaps in their register
numbering schemes.
I removed all of the enums for "gdb" register numbers that we had
in lldb - these were meaningless - and I put LLDB_INVALID_REGNUM
in all of the register tables for the Process Plugin regnum slot.
This change is almost entirely mechnical; the one actual change in
here is to ProcessGDBRemote.cpp's ParseRegisters() which parses the
qXfer:features:read:target.xml response. As it parses register
definitions from the xml, it will assign sequential numbers as the
eRegisterKindLLDB numbers (the lldb register numberings must be
sequential, without any gaps) and if the xml file specifies register
numbers, those will be used as the eRegisterKindProcessPlugin
register numbers (and those may have gaps). A J-Link jtag device's
target.xml does contain a gap in register numbers, and it only
specifies the register numbers for the registers after that gap.
The device supports many different ARM boards and probably selects
different part of its register file as appropriate.
http://reviews.llvm.org/D12791
<rdar://problem/22623262>
llvm-svn: 247741
2015-09-16 07:20:34 +08:00
|
|
|
uint32_t fp_reg_num = dwarf_rbp;
|
|
|
|
uint32_t sp_reg_num = dwarf_rsp;
|
|
|
|
uint32_t pc_reg_num = dwarf_rip;
|
2013-08-23 07:13:43 +08:00
|
|
|
|
2012-07-14 12:52:53 +08:00
|
|
|
UnwindPlan::RowSP row(new UnwindPlan::Row);
|
2011-05-12 02:39:18 +08:00
|
|
|
|
|
|
|
const int32_t ptr_size = 8;
|
Clean up register naming conventions inside lldb.
"gcc" register numbers are now correctly referred to as "ehframe"
register numbers. In almost all cases, ehframe and dwarf register
numbers are identical (the one exception is i386 darwin where ehframe
regnums were incorrect).
The old "gdb" register numbers, which I incorrectly thought were
stabs register numbers, are now referred to as "Process Plugin"
register numbers. This is the register numbering scheme that the
remote process controller stub (lldb-server, gdbserver, core file
support, kdp server, remote jtag devices, etc) uses to refer to the
registers. The process plugin register numbers may not be contiguous
- there are remote jtag devices that have gaps in their register
numbering schemes.
I removed all of the enums for "gdb" register numbers that we had
in lldb - these were meaningless - and I put LLDB_INVALID_REGNUM
in all of the register tables for the Process Plugin regnum slot.
This change is almost entirely mechnical; the one actual change in
here is to ProcessGDBRemote.cpp's ParseRegisters() which parses the
qXfer:features:read:target.xml response. As it parses register
definitions from the xml, it will assign sequential numbers as the
eRegisterKindLLDB numbers (the lldb register numberings must be
sequential, without any gaps) and if the xml file specifies register
numbers, those will be used as the eRegisterKindProcessPlugin
register numbers (and those may have gaps). A J-Link jtag device's
target.xml does contain a gap in register numbers, and it only
specifies the register numbers for the registers after that gap.
The device supports many different ARM boards and probably selects
different part of its register file as appropriate.
http://reviews.llvm.org/D12791
<rdar://problem/22623262>
llvm-svn: 247741
2015-09-16 07:20:34 +08:00
|
|
|
row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_rbp, 2 * ptr_size);
|
2012-07-14 12:52:53 +08:00
|
|
|
row->SetOffset (0);
|
2011-05-12 02:39:18 +08:00
|
|
|
|
2012-07-14 12:52:53 +08:00
|
|
|
row->SetRegisterLocationToAtCFAPlusOffset(fp_reg_num, ptr_size * -2, true);
|
|
|
|
row->SetRegisterLocationToAtCFAPlusOffset(pc_reg_num, ptr_size * -1, true);
|
2013-11-05 08:19:09 +08:00
|
|
|
row->SetRegisterLocationToIsCFAPlusOffset(sp_reg_num, 0, true);
|
2011-05-12 02:39:18 +08:00
|
|
|
|
|
|
|
unwind_plan.AppendRow (row);
|
|
|
|
unwind_plan.SetSourceName ("x86_64 default unwind plan");
|
2012-10-26 14:08:58 +08:00
|
|
|
unwind_plan.SetSourcedFromCompiler (eLazyBoolNo);
|
|
|
|
unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolNo);
|
2011-05-12 02:39:18 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ABISysV_x86_64::RegisterIsVolatile (const RegisterInfo *reg_info)
|
|
|
|
{
|
|
|
|
return !RegisterIsCalleeSaved (reg_info);
|
|
|
|
}
|
|
|
|
|
2012-12-11 09:20:57 +08:00
|
|
|
// See "Register Usage" in the
|
|
|
|
// "System V Application Binary Interface"
|
|
|
|
// "AMD64 Architecture Processor Supplement"
|
|
|
|
// (or "x86-64(tm) Architecture Processor Supplement" in earlier revisions)
|
2013-07-26 10:08:48 +08:00
|
|
|
// (this doc is also commonly referred to as the x86-64/AMD64 psABI)
|
2012-12-11 09:20:57 +08:00
|
|
|
// Edited by Michael Matz, Jan Hubicka, Andreas Jaeger, and Mark Mitchell
|
2013-07-25 07:25:27 +08:00
|
|
|
// current version is 0.99.6 released 2012-07-02 at http://refspecs.linuxfoundation.org/elf/x86-64-abi-0.99.pdf
|
2015-01-26 18:07:39 +08:00
|
|
|
// It's being revised & updated at https://github.com/hjl-tools/x86-psABI/
|
2011-08-22 10:49:39 +08:00
|
|
|
|
2011-05-12 02:39:18 +08:00
|
|
|
bool
|
|
|
|
ABISysV_x86_64::RegisterIsCalleeSaved (const RegisterInfo *reg_info)
|
|
|
|
{
|
|
|
|
if (reg_info)
|
|
|
|
{
|
2012-12-11 09:20:57 +08:00
|
|
|
// Preserved registers are :
|
|
|
|
// rbx, rsp, rbp, r12, r13, r14, r15
|
|
|
|
// mxcsr (partially preserved)
|
|
|
|
// x87 control word
|
|
|
|
|
2011-05-12 02:39:18 +08:00
|
|
|
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;
|
|
|
|
|
2012-09-28 13:46:55 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Accept shorter-variant versions, rbx/ebx, rip/ eip, etc.
|
|
|
|
if (name[0] == 'r' || name[0] == 'e')
|
|
|
|
{
|
|
|
|
switch (name[1])
|
|
|
|
{
|
2011-05-12 02:39:18 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2012-12-11 09:20:57 +08:00
|
|
|
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;
|
2011-05-12 02:39:18 +08:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
void
|
|
|
|
ABISysV_x86_64::Initialize()
|
|
|
|
{
|
2013-05-11 05:47:16 +08:00
|
|
|
PluginManager::RegisterPlugin (GetPluginNameStatic(),
|
|
|
|
"System V ABI for x86_64 targets",
|
2010-06-09 00:52:24 +08:00
|
|
|
CreateInstance);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ABISysV_x86_64::Terminate()
|
|
|
|
{
|
|
|
|
PluginManager::UnregisterPlugin (CreateInstance);
|
|
|
|
}
|
|
|
|
|
2013-05-11 05:47:16 +08:00
|
|
|
lldb_private::ConstString
|
|
|
|
ABISysV_x86_64::GetPluginNameStatic()
|
|
|
|
{
|
|
|
|
static ConstString g_name("sysv-x86_64");
|
|
|
|
return g_name;
|
|
|
|
}
|
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
//------------------------------------------------------------------
|
|
|
|
// PluginInterface protocol
|
|
|
|
//------------------------------------------------------------------
|
2016-02-27 06:26:21 +08:00
|
|
|
|
2013-05-11 05:47:16 +08:00
|
|
|
lldb_private::ConstString
|
2010-06-09 00:52:24 +08:00
|
|
|
ABISysV_x86_64::GetPluginName()
|
|
|
|
{
|
2013-05-11 05:47:16 +08:00
|
|
|
return GetPluginNameStatic();
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
ABISysV_x86_64::GetPluginVersion()
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|