2011-04-26 05:05:07 +08:00
//===-- UnwindAssemblyInstEmulation.cpp --------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
# include "UnwindAssemblyInstEmulation.h"
# include "lldb/Core/Address.h"
# include "lldb/Core/ArchSpec.h"
2011-04-26 12:39:08 +08:00
# include "lldb/Core/DataBufferHeap.h"
<rdar://problem/11757916>
Make breakpoint setting by file and line much more efficient by only looking for inlined breakpoint locations if we are setting a breakpoint in anything but a source implementation file. Implementing this complex for a many reasons. Turns out that parsing compile units lazily had some issues with respect to how we need to do things with DWARF in .o files. So the fixes in the checkin for this makes these changes:
- Add a new setting called "target.inline-breakpoint-strategy" which can be set to "never", "always", or "headers". "never" will never try and set any inlined breakpoints (fastest). "always" always looks for inlined breakpoint locations (slowest, but most accurate). "headers", which is the default setting, will only look for inlined breakpoint locations if the breakpoint is set in what are consudered to be header files, which is realy defined as "not in an implementation source file".
- modify the breakpoint setting by file and line to check the current "target.inline-breakpoint-strategy" setting and act accordingly
- Modify compile units to be able to get their language and other info lazily. This allows us to create compile units from the debug map and not have to fill all of the details in, and then lazily discover this information as we go on debuggging. This is needed to avoid parsing all .o files when setting breakpoints in implementation only files (no inlines). Otherwise we would need to parse the .o file, the object file (mach-o in our case) and the symbol file (DWARF in the object file) just to see what the compile unit was.
- modify the "SymbolFileDWARFDebugMap" to subclass lldb_private::Module so that the virtual "GetObjectFile()" and "GetSymbolVendor()" functions can be intercepted when the .o file contenst are later lazilly needed. Prior to this fix, when we first instantiated the "SymbolFileDWARFDebugMap" class, we would also make modules, object files and symbol files for every .o file in the debug map because we needed to fix up the sections in the .o files with information that is in the executable debug map. Now we lazily do this in the DebugMapModule::GetObjectFile()
Cleaned up header includes a bit as well.
llvm-svn: 162860
2012-08-30 05:13:06 +08:00
# include "lldb/Core/DataExtractor.h"
2011-04-26 12:39:08 +08:00
# include "lldb/Core/Disassembler.h"
# include "lldb/Core/Error.h"
2011-05-12 02:39:18 +08:00
# include "lldb/Core/Log.h"
2011-04-26 05:05:07 +08:00
# include "lldb/Core/PluginManager.h"
2011-05-12 02:39:18 +08:00
# include "lldb/Core/StreamString.h"
2011-04-26 05:05:07 +08:00
# include "lldb/Target/ExecutionContext.h"
# include "lldb/Target/Process.h"
# include "lldb/Target/Thread.h"
# include "lldb/Target/Target.h"
using namespace lldb ;
using namespace lldb_private ;
//-----------------------------------------------------------------------------------------------
2012-07-09 15:47:47 +08:00
// UnwindAssemblyInstEmulation method definitions
2011-04-26 05:05:07 +08:00
//-----------------------------------------------------------------------------------------------
bool
2011-04-26 12:39:08 +08:00
UnwindAssemblyInstEmulation : : GetNonCallSiteUnwindPlanFromAssembly ( AddressRange & range ,
Thread & thread ,
UnwindPlan & unwind_plan )
2011-04-26 05:05:07 +08:00
{
2011-04-26 12:39:08 +08:00
if ( range . GetByteSize ( ) > 0 & &
range . GetBaseAddress ( ) . IsValid ( ) & &
m_inst_emulator_ap . get ( ) )
{
2011-05-12 02:39:18 +08:00
2014-07-02 05:22:11 +08:00
// The instruction emulation subclass setup the unwind plan for the
2011-05-12 02:39:18 +08:00
// first instruction.
m_inst_emulator_ap - > CreateFunctionEntryUnwind ( unwind_plan ) ;
// CreateFunctionEntryUnwind should have created the first row. If it
// doesn't, then we are done.
if ( unwind_plan . GetRowCount ( ) = = 0 )
return false ;
2011-04-26 12:39:08 +08:00
ExecutionContext exe_ctx ;
thread . CalculateExecutionContext ( exe_ctx ) ;
2013-09-13 07:23:35 +08:00
const bool prefer_file_cache = true ;
2011-04-26 12:39:08 +08:00
DisassemblerSP disasm_sp ( Disassembler : : DisassembleRange ( m_arch ,
2013-03-02 08:26:47 +08:00
NULL ,
2011-04-26 12:39:08 +08:00
NULL ,
exe_ctx ,
2013-09-13 07:23:35 +08:00
range ,
prefer_file_cache ) ) ;
2011-05-12 02:39:18 +08:00
2013-03-28 07:08:40 +08:00
Log * log ( GetLogIfAllCategoriesSet ( LIBLLDB_LOG_UNWIND ) ) ;
2011-05-12 02:39:18 +08:00
2011-04-26 12:39:08 +08:00
if ( disasm_sp )
{
m_range_ptr = & range ;
m_thread_ptr = & thread ;
m_unwind_plan_ptr = & unwind_plan ;
const uint32_t addr_byte_size = m_arch . GetAddressByteSize ( ) ;
const bool show_address = true ;
const bool show_bytes = true ;
2011-05-12 02:39:18 +08:00
m_inst_emulator_ap - > GetRegisterInfo ( unwind_plan . GetRegisterKind ( ) ,
unwind_plan . GetInitialCFARegister ( ) ,
m_cfa_reg_info ) ;
m_fp_is_cfa = false ;
m_register_values . clear ( ) ;
m_pushed_regs . clear ( ) ;
2012-07-09 15:47:47 +08:00
// Initialize the CFA with a known value. In the 32 bit case
// it will be 0x80000000, and in the 64 bit case 0x8000000000000000.
2014-07-02 05:22:11 +08:00
// We use the address byte size to be safe for any future address sizes
2011-05-10 04:18:18 +08:00
m_initial_sp = ( 1ull < < ( ( addr_byte_size * 8 ) - 1 ) ) ;
2011-05-15 09:25:55 +08:00
RegisterValue cfa_reg_value ;
cfa_reg_value . SetUInt ( m_initial_sp , m_cfa_reg_info . byte_size ) ;
SetRegisterValue ( m_cfa_reg_info , cfa_reg_value ) ;
2012-07-14 12:52:53 +08:00
2011-04-26 12:39:08 +08:00
const InstructionList & inst_list = disasm_sp - > GetInstructionList ( ) ;
const size_t num_instructions = inst_list . GetSize ( ) ;
2012-07-14 12:52:53 +08:00
2011-04-30 06:50:31 +08:00
if ( num_instructions > 0 )
2011-04-26 12:39:08 +08:00
{
2011-04-30 06:50:31 +08:00
Instruction * inst = inst_list . GetInstructionAtIndex ( 0 ) . get ( ) ;
const addr_t base_addr = inst - > GetAddress ( ) . GetFileAddress ( ) ;
2012-07-17 09:57:24 +08:00
// Make a copy of the current instruction Row and save it in m_curr_row
// so we can add updates as we process the instructions.
2012-07-14 12:52:53 +08:00
UnwindPlan : : RowSP last_row = unwind_plan . GetLastRow ( ) ;
UnwindPlan : : Row * newrow = new UnwindPlan : : Row ;
if ( last_row . get ( ) )
* newrow = * last_row . get ( ) ;
m_curr_row . reset ( newrow ) ;
2011-04-26 12:39:08 +08:00
2012-07-17 09:57:24 +08:00
// Once we've seen the initial prologue instructions complete, save a
// copy of the CFI at that point into prologue_completed_row for possible
// use later.
int instructions_since_last_prologue_insn = 0 ; // # of insns since last CFI was update
2012-10-17 08:41:14 +08:00
2012-07-17 09:57:24 +08:00
bool reinstate_prologue_next_instruction = false ; // Next iteration, re-install the prologue row of CFI
2012-10-17 08:41:14 +08:00
bool last_instruction_restored_return_addr_reg = false ; // re-install the prologue row of CFI if the next instruction is a branch immediate
2012-10-23 11:08:31 +08:00
bool return_address_register_has_been_saved = false ; // if we've seen the ra register get saved yet
2012-07-17 09:57:24 +08:00
UnwindPlan : : RowSP prologue_completed_row ; // copy of prologue row of CFI
// cache the pc register number (in whatever register numbering this UnwindPlan uses) for
// quick reference during instruction parsing.
uint32_t pc_reg_num = LLDB_INVALID_REGNUM ;
RegisterInfo pc_reg_info ;
if ( m_inst_emulator_ap - > GetRegisterInfo ( eRegisterKindGeneric , LLDB_REGNUM_GENERIC_PC , pc_reg_info ) )
pc_reg_num = pc_reg_info . kinds [ unwind_plan . GetRegisterKind ( ) ] ;
2012-10-17 08:41:14 +08:00
else
pc_reg_num = LLDB_INVALID_REGNUM ;
2012-07-17 09:57:24 +08:00
2012-10-17 08:41:14 +08:00
// cache the return address register number (in whatever register numbering this UnwindPlan uses) for
// quick reference during instruction parsing.
uint32_t ra_reg_num = LLDB_INVALID_REGNUM ;
RegisterInfo ra_reg_info ;
if ( m_inst_emulator_ap - > GetRegisterInfo ( eRegisterKindGeneric , LLDB_REGNUM_GENERIC_RA , ra_reg_info ) )
ra_reg_num = ra_reg_info . kinds [ unwind_plan . GetRegisterKind ( ) ] ;
else
ra_reg_num = LLDB_INVALID_REGNUM ;
2012-07-17 09:57:24 +08:00
2011-04-30 06:50:31 +08:00
for ( size_t idx = 0 ; idx < num_instructions ; + + idx )
{
2012-07-17 09:57:24 +08:00
m_curr_row_modified = false ;
2012-10-23 11:08:31 +08:00
m_curr_insn_restored_a_register = false ;
2011-04-30 06:50:31 +08:00
inst = inst_list . GetInstructionAtIndex ( idx ) . get ( ) ;
if ( inst )
{
2011-09-30 06:34:41 +08:00
if ( log & & log - > GetVerbose ( ) )
2011-05-12 02:39:18 +08:00
{
StreamString strm ;
2014-10-11 07:07:36 +08:00
const char * disassemble_format = " ${frame.pc}: " ;
inst - > Dump ( & strm , inst_list . GetMaxOpcocdeByteSize ( ) , show_address , show_bytes , NULL , NULL , NULL , disassemble_format ) ;
2011-05-12 02:39:18 +08:00
log - > PutCString ( strm . GetData ( ) ) ;
}
2011-04-30 06:50:31 +08:00
m_inst_emulator_ap - > SetInstruction ( inst - > GetOpcode ( ) ,
inst - > GetAddress ( ) ,
2011-09-22 12:58:26 +08:00
exe_ctx . GetTargetPtr ( ) ) ;
2011-04-30 06:50:31 +08:00
m_inst_emulator_ap - > EvaluateInstruction ( eEmulateInstructionOptionIgnoreConditions ) ;
2012-07-17 09:57:24 +08:00
// Were there any changes to the CFI while evaluating this instruction?
if ( m_curr_row_modified )
2011-05-12 02:39:18 +08:00
{
2012-07-17 09:57:24 +08:00
reinstate_prologue_next_instruction = false ;
2012-07-14 12:52:53 +08:00
m_curr_row - > SetOffset ( inst - > GetAddress ( ) . GetFileAddress ( ) + inst - > GetOpcode ( ) . GetByteSize ( ) - base_addr ) ;
2011-05-12 02:39:18 +08:00
// Append the new row
unwind_plan . AppendRow ( m_curr_row ) ;
2012-07-14 12:52:53 +08:00
2012-07-17 09:57:24 +08:00
// Allocate a new Row for m_curr_row, copy the current state into it
2012-07-14 12:52:53 +08:00
UnwindPlan : : Row * newrow = new UnwindPlan : : Row ;
* newrow = * m_curr_row . get ( ) ;
m_curr_row . reset ( newrow ) ;
2012-07-17 09:57:24 +08:00
2012-10-23 11:08:31 +08:00
// If m_curr_insn_restored_a_register == true, we're looking at an epilogue instruction.
// Set instructions_since_last_prologue_insn to a very high number so we don't append
// any of these epilogue instructions to our prologue_complete row.
if ( m_curr_insn_restored_a_register = = false & & instructions_since_last_prologue_insn < 8 )
instructions_since_last_prologue_insn = 0 ;
else
instructions_since_last_prologue_insn = 99 ;
UnwindPlan : : Row : : RegisterLocation pc_regloc ;
UnwindPlan : : Row : : RegisterLocation ra_regloc ;
// While parsing the instructions of this function, if we've ever
// seen the return address register (aka lr on arm) in a non-IsSame() state,
2014-07-02 05:22:11 +08:00
// it has been saved on the stack. If it's ever back to IsSame(), we've
2012-10-23 11:08:31 +08:00
// executed an epilogue.
if ( ra_reg_num ! = LLDB_INVALID_REGNUM
& & m_curr_row - > GetRegisterInfo ( ra_reg_num , ra_regloc )
& & ! ra_regloc . IsSame ( ) )
{
return_address_register_has_been_saved = true ;
}
2012-07-17 09:57:24 +08:00
// If the caller's pc is "same", we've just executed an epilogue and we return to the caller
// after this instruction completes executing.
// If there are any instructions past this, there must have been flow control over this
// epilogue so we'll reinstate the original prologue setup instructions.
2012-10-23 11:08:31 +08:00
if ( prologue_completed_row . get ( )
2012-07-17 09:57:24 +08:00
& & pc_reg_num ! = LLDB_INVALID_REGNUM
& & m_curr_row - > GetRegisterInfo ( pc_reg_num , pc_regloc )
& & pc_regloc . IsSame ( ) )
{
if ( log & & log - > GetVerbose ( ) )
log - > Printf ( " UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- pc is <same>, restore prologue instructions. " ) ;
reinstate_prologue_next_instruction = true ;
}
2012-10-23 11:08:31 +08:00
else if ( prologue_completed_row . get ( )
& & return_address_register_has_been_saved
2012-10-17 08:41:14 +08:00
& & ra_reg_num ! = LLDB_INVALID_REGNUM
& & m_curr_row - > GetRegisterInfo ( ra_reg_num , ra_regloc )
& & ra_regloc . IsSame ( ) )
{
if ( log & & log - > GetVerbose ( ) )
log - > Printf ( " UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- lr is <same>, restore prologue instruction if the next instruction is a branch immediate. " ) ;
last_instruction_restored_return_addr_reg = true ;
}
2012-07-17 09:57:24 +08:00
}
else
{
// If the previous instruction was a return-to-caller (epilogue), and we're still executing
// instructions in this function, there must be a code path that jumps over that epilogue.
2012-10-17 08:41:14 +08:00
// Also detect the case where we epilogue & branch imm to another function (tail-call opt)
// instead of a normal pop lr-into-pc exit.
2012-07-17 09:57:24 +08:00
// Reinstate the frame setup from the prologue.
2012-10-17 08:41:14 +08:00
if ( reinstate_prologue_next_instruction
| | ( m_curr_insn_is_branch_immediate & & last_instruction_restored_return_addr_reg ) )
2012-07-17 09:57:24 +08:00
{
if ( log & & log - > GetVerbose ( ) )
log - > Printf ( " UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- Reinstating prologue instruction set " ) ;
UnwindPlan : : Row * newrow = new UnwindPlan : : Row ;
* newrow = * prologue_completed_row . get ( ) ;
m_curr_row . reset ( newrow ) ;
m_curr_row - > SetOffset ( inst - > GetAddress ( ) . GetFileAddress ( ) + inst - > GetOpcode ( ) . GetByteSize ( ) - base_addr ) ;
unwind_plan . AppendRow ( m_curr_row ) ;
newrow = new UnwindPlan : : Row ;
* newrow = * m_curr_row . get ( ) ;
m_curr_row . reset ( newrow ) ;
reinstate_prologue_next_instruction = false ;
2012-10-17 08:41:14 +08:00
last_instruction_restored_return_addr_reg = false ;
m_curr_insn_is_branch_immediate = false ;
2012-07-17 09:57:24 +08:00
}
2012-10-17 08:41:14 +08:00
// clear both of these if either one wasn't set
if ( last_instruction_restored_return_addr_reg )
{
last_instruction_restored_return_addr_reg = false ;
}
if ( m_curr_insn_is_branch_immediate )
{
m_curr_insn_is_branch_immediate = false ;
}
2012-10-23 11:08:31 +08:00
// Stop updating the prologue instructions if we've seen 8 non-prologue instructions
// in a row.
if ( instructions_since_last_prologue_insn + + < 8 )
2012-07-17 09:57:24 +08:00
{
UnwindPlan : : Row * newrow = new UnwindPlan : : Row ;
* newrow = * m_curr_row . get ( ) ;
prologue_completed_row . reset ( newrow ) ;
if ( log & & log - > GetVerbose ( ) )
2012-10-23 11:08:31 +08:00
log - > Printf ( " UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- saving a copy of the current row as the prologue row. " ) ;
2012-07-17 09:57:24 +08:00
}
2011-05-12 02:39:18 +08:00
}
2011-04-30 06:50:31 +08:00
}
2011-04-26 12:39:08 +08:00
}
}
2013-07-31 10:19:15 +08:00
// FIXME: The DisassemblerLLVMC has a reference cycle and won't go away if it has any active instructions.
// I'll fix that but for now, just clear the list and it will go away nicely.
disasm_sp - > GetInstructionList ( ) . Clear ( ) ;
2011-04-26 12:39:08 +08:00
}
2011-05-12 02:39:18 +08:00
2011-09-30 06:34:41 +08:00
if ( log & & log - > GetVerbose ( ) )
2011-05-12 02:39:18 +08:00
{
StreamString strm ;
2012-02-21 08:09:25 +08:00
lldb : : addr_t base_addr = range . GetBaseAddress ( ) . GetLoadAddress ( thread . CalculateTarget ( ) . get ( ) ) ;
2012-11-30 05:49:15 +08:00
strm . Printf ( " Resulting unwind rows for [0x% " PRIx64 " - 0x% " PRIx64 " ): " , base_addr , base_addr + range . GetByteSize ( ) ) ;
2011-05-12 02:39:18 +08:00
unwind_plan . Dump ( strm , & thread , base_addr ) ;
log - > PutCString ( strm . GetData ( ) ) ;
}
return unwind_plan . GetRowCount ( ) > 0 ;
2011-04-26 12:39:08 +08:00
}
2011-04-26 05:05:07 +08:00
return false ;
}
2014-08-26 04:29:09 +08:00
bool
UnwindAssemblyInstEmulation : : AugmentUnwindPlanFromCallSite ( AddressRange & func ,
Thread & thread ,
UnwindPlan & unwind_plan )
{
return false ;
}
2011-04-26 05:05:07 +08:00
bool
2011-04-26 12:39:08 +08:00
UnwindAssemblyInstEmulation : : GetFastUnwindPlan ( AddressRange & func ,
Thread & thread ,
UnwindPlan & unwind_plan )
2011-04-26 05:05:07 +08:00
{
return false ;
}
bool
2011-04-26 12:39:08 +08:00
UnwindAssemblyInstEmulation : : FirstNonPrologueInsn ( AddressRange & func ,
2012-02-21 08:09:25 +08:00
const ExecutionContext & exe_ctx ,
2011-04-26 12:39:08 +08:00
Address & first_non_prologue_insn )
2011-04-26 05:05:07 +08:00
{
return false ;
}
2011-04-26 05:14:26 +08:00
UnwindAssembly *
2011-04-26 05:05:07 +08:00
UnwindAssemblyInstEmulation : : CreateInstance ( const ArchSpec & arch )
{
2013-04-19 06:45:39 +08:00
std : : unique_ptr < EmulateInstruction > inst_emulator_ap ( EmulateInstruction : : FindPlugin ( arch , eInstructionTypePrologueEpilogue , NULL ) ) ;
2011-04-26 12:39:08 +08:00
// Make sure that all prologue instructions are handled
if ( inst_emulator_ap . get ( ) )
return new UnwindAssemblyInstEmulation ( arch , inst_emulator_ap . release ( ) ) ;
2011-04-26 05:05:07 +08:00
return NULL ;
}
//------------------------------------------------------------------
// PluginInterface protocol in UnwindAssemblyParser_x86
//------------------------------------------------------------------
2013-05-11 05:47:16 +08:00
ConstString
2011-04-26 05:05:07 +08:00
UnwindAssemblyInstEmulation : : GetPluginName ( )
{
2013-05-11 05:47:16 +08:00
return GetPluginNameStatic ( ) ;
2011-04-26 05:05:07 +08:00
}
uint32_t
UnwindAssemblyInstEmulation : : GetPluginVersion ( )
{
return 1 ;
}
void
UnwindAssemblyInstEmulation : : Initialize ( )
{
PluginManager : : RegisterPlugin ( GetPluginNameStatic ( ) ,
GetPluginDescriptionStatic ( ) ,
CreateInstance ) ;
}
void
UnwindAssemblyInstEmulation : : Terminate ( )
{
PluginManager : : UnregisterPlugin ( CreateInstance ) ;
}
2013-05-11 05:47:16 +08:00
ConstString
2011-04-26 05:05:07 +08:00
UnwindAssemblyInstEmulation : : GetPluginNameStatic ( )
{
2013-05-11 05:47:16 +08:00
static ConstString g_name ( " inst-emulation " ) ;
return g_name ;
2011-04-26 05:05:07 +08:00
}
const char *
UnwindAssemblyInstEmulation : : GetPluginDescriptionStatic ( )
{
return " Instruction emulation based unwind information. " ;
}
2011-04-26 12:39:08 +08:00
2011-04-27 07:48:45 +08:00
uint64_t
2011-05-10 04:18:18 +08:00
UnwindAssemblyInstEmulation : : MakeRegisterKindValuePair ( const RegisterInfo & reg_info )
2011-04-27 07:48:45 +08:00
{
2014-07-02 17:51:28 +08:00
lldb : : RegisterKind reg_kind ;
uint32_t reg_num ;
2011-05-10 04:18:18 +08:00
if ( EmulateInstruction : : GetBestRegisterKindAndNumber ( & reg_info , reg_kind , reg_num ) )
2011-04-27 07:48:45 +08:00
return ( uint64_t ) reg_kind < < 24 | reg_num ;
return 0ull ;
}
void
2011-05-10 04:18:18 +08:00
UnwindAssemblyInstEmulation : : SetRegisterValue ( const RegisterInfo & reg_info , const RegisterValue & reg_value )
2011-04-27 07:48:45 +08:00
{
m_register_values [ MakeRegisterKindValuePair ( reg_info ) ] = reg_value ;
}
2011-05-10 04:18:18 +08:00
bool
UnwindAssemblyInstEmulation : : GetRegisterValue ( const RegisterInfo & reg_info , RegisterValue & reg_value )
2011-04-27 07:48:45 +08:00
{
const uint64_t reg_id = MakeRegisterKindValuePair ( reg_info ) ;
RegisterValueMap : : const_iterator pos = m_register_values . find ( reg_id ) ;
if ( pos ! = m_register_values . end ( ) )
2011-05-10 04:18:18 +08:00
{
reg_value = pos - > second ;
return true ; // We had a real value that comes from an opcode that wrote
// to it...
}
// We are making up a value that is recognizable...
reg_value . SetUInt ( reg_id , reg_info . byte_size ) ;
return false ;
2011-04-27 07:48:45 +08:00
}
2011-04-26 12:39:08 +08:00
size_t
UnwindAssemblyInstEmulation : : ReadMemory ( EmulateInstruction * instruction ,
void * baton ,
const EmulateInstruction : : Context & context ,
lldb : : addr_t addr ,
void * dst ,
size_t dst_len )
{
2013-03-28 07:08:40 +08:00
Log * log ( GetLogIfAllCategoriesSet ( LIBLLDB_LOG_UNWIND ) ) ;
2011-05-12 02:39:18 +08:00
2011-09-30 06:34:41 +08:00
if ( log & & log - > GetVerbose ( ) )
2011-05-12 02:39:18 +08:00
{
StreamString strm ;
2012-11-30 05:49:15 +08:00
strm . Printf ( " UnwindAssemblyInstEmulation::ReadMemory (addr = 0x%16.16 " PRIx64 " , dst = %p, dst_len = % " PRIu64 " , context = " ,
2011-05-12 02:39:18 +08:00
addr ,
dst ,
2012-09-19 02:04:04 +08:00
( uint64_t ) dst_len ) ;
2011-05-12 02:39:18 +08:00
context . Dump ( strm , instruction ) ;
log - > PutCString ( strm . GetData ( ) ) ;
}
2012-08-14 05:53:35 +08:00
memset ( dst , 0 , dst_len ) ;
2011-04-26 12:39:08 +08:00
return dst_len ;
}
size_t
UnwindAssemblyInstEmulation : : WriteMemory ( EmulateInstruction * instruction ,
void * baton ,
const EmulateInstruction : : Context & context ,
lldb : : addr_t addr ,
const void * dst ,
size_t dst_len )
{
2011-05-12 02:39:18 +08:00
if ( baton & & dst & & dst_len )
return ( ( UnwindAssemblyInstEmulation * ) baton ) - > WriteMemory ( instruction , context , addr , dst , dst_len ) ;
return 0 ;
}
size_t
UnwindAssemblyInstEmulation : : WriteMemory ( EmulateInstruction * instruction ,
const EmulateInstruction : : Context & context ,
lldb : : addr_t addr ,
const void * dst ,
size_t dst_len )
{
2011-04-26 12:39:08 +08:00
DataExtractor data ( dst ,
dst_len ,
instruction - > GetArchitecture ( ) . GetByteOrder ( ) ,
instruction - > GetArchitecture ( ) . GetAddressByteSize ( ) ) ;
2013-03-28 07:08:40 +08:00
Log * log ( GetLogIfAllCategoriesSet ( LIBLLDB_LOG_UNWIND ) ) ;
2011-05-12 02:39:18 +08:00
2011-09-30 06:34:41 +08:00
if ( log & & log - > GetVerbose ( ) )
2011-05-12 02:39:18 +08:00
{
StreamString strm ;
strm . PutCString ( " UnwindAssemblyInstEmulation::WriteMemory ( " ) ;
data . Dump ( & strm , 0 , eFormatBytes , 1 , dst_len , UINT32_MAX , addr , 0 , 0 ) ;
strm . PutCString ( " , context = " ) ;
context . Dump ( strm , instruction ) ;
log - > PutCString ( strm . GetData ( ) ) ;
}
2011-04-30 06:50:31 +08:00
2011-05-12 02:39:18 +08:00
const bool can_replace = true ;
const bool cant_replace = false ;
2011-04-30 06:50:31 +08:00
switch ( context . type )
{
2011-05-10 04:18:18 +08:00
default :
2011-04-30 06:50:31 +08:00
case EmulateInstruction : : eContextInvalid :
case EmulateInstruction : : eContextReadOpcode :
case EmulateInstruction : : eContextImmediate :
case EmulateInstruction : : eContextAdjustBaseRegister :
case EmulateInstruction : : eContextRegisterPlusOffset :
case EmulateInstruction : : eContextAdjustPC :
case EmulateInstruction : : eContextRegisterStore :
case EmulateInstruction : : eContextRegisterLoad :
case EmulateInstruction : : eContextRelativeBranchImmediate :
case EmulateInstruction : : eContextAbsoluteBranchRegister :
case EmulateInstruction : : eContextSupervisorCall :
case EmulateInstruction : : eContextTableBranchReadMemory :
case EmulateInstruction : : eContextWriteRegisterRandomBits :
case EmulateInstruction : : eContextWriteMemoryRandomBits :
case EmulateInstruction : : eContextArithmetic :
case EmulateInstruction : : eContextAdvancePC :
case EmulateInstruction : : eContextReturnFromException :
case EmulateInstruction : : eContextPopRegisterOffStack :
case EmulateInstruction : : eContextAdjustStackPointer :
break ;
case EmulateInstruction : : eContextPushRegisterOnStack :
{
2011-05-12 02:39:18 +08:00
uint32_t reg_num = LLDB_INVALID_REGNUM ;
bool is_return_address_reg = false ;
const uint32_t unwind_reg_kind = m_unwind_plan_ptr - > GetRegisterKind ( ) ;
if ( context . info_type = = EmulateInstruction : : eInfoTypeRegisterToRegisterPlusOffset )
{
reg_num = context . info . RegisterToRegisterPlusOffset . data_reg . kinds [ unwind_reg_kind ] ;
if ( context . info . RegisterToRegisterPlusOffset . data_reg . kinds [ eRegisterKindGeneric ] = = LLDB_REGNUM_GENERIC_RA )
is_return_address_reg = true ;
}
else
{
assert ( ! " unhandled case, add code to handle this! " ) ;
}
if ( reg_num ! = LLDB_INVALID_REGNUM )
{
if ( m_pushed_regs . find ( reg_num ) = = m_pushed_regs . end ( ) )
2011-04-30 06:50:31 +08:00
{
2011-05-12 02:39:18 +08:00
m_pushed_regs [ reg_num ] = addr ;
const int32_t offset = addr - m_initial_sp ;
2012-07-14 12:52:53 +08:00
m_curr_row - > SetRegisterLocationToAtCFAPlusOffset ( reg_num , offset , cant_replace ) ;
2012-07-17 09:57:24 +08:00
m_curr_row_modified = true ;
2011-05-12 02:39:18 +08:00
if ( is_return_address_reg )
{
// This push was pushing the return address register,
// so this is also how we will unwind the PC...
RegisterInfo pc_reg_info ;
if ( instruction - > GetRegisterInfo ( eRegisterKindGeneric , LLDB_REGNUM_GENERIC_PC , pc_reg_info ) )
{
uint32_t pc_reg_num = pc_reg_info . kinds [ unwind_reg_kind ] ;
if ( pc_reg_num ! = LLDB_INVALID_REGNUM )
2012-07-17 09:57:24 +08:00
{
2012-07-14 12:52:53 +08:00
m_curr_row - > SetRegisterLocationToAtCFAPlusOffset ( pc_reg_num , offset , can_replace ) ;
2012-07-17 09:57:24 +08:00
m_curr_row_modified = true ;
}
2011-05-12 02:39:18 +08:00
}
}
2011-04-30 06:50:31 +08:00
}
2011-05-12 02:39:18 +08:00
}
2011-04-30 06:50:31 +08:00
}
break ;
}
2011-04-26 12:39:08 +08:00
return dst_len ;
}
bool
UnwindAssemblyInstEmulation : : ReadRegister ( EmulateInstruction * instruction ,
void * baton ,
2011-05-10 04:18:18 +08:00
const RegisterInfo * reg_info ,
RegisterValue & reg_value )
2011-04-26 12:39:08 +08:00
{
2011-05-12 02:39:18 +08:00
2011-05-10 04:18:18 +08:00
if ( baton & & reg_info )
2011-05-12 02:39:18 +08:00
return ( ( UnwindAssemblyInstEmulation * ) baton ) - > ReadRegister ( instruction , reg_info , reg_value ) ;
return false ;
}
bool
UnwindAssemblyInstEmulation : : ReadRegister ( EmulateInstruction * instruction ,
const RegisterInfo * reg_info ,
RegisterValue & reg_value )
{
bool synthetic = GetRegisterValue ( * reg_info , reg_value ) ;
2011-04-26 12:39:08 +08:00
2013-03-28 07:08:40 +08:00
Log * log ( GetLogIfAllCategoriesSet ( LIBLLDB_LOG_UNWIND ) ) ;
2011-05-12 02:39:18 +08:00
2011-09-30 06:34:41 +08:00
if ( log & & log - > GetVerbose ( ) )
2011-05-12 02:39:18 +08:00
{
StreamString strm ;
2011-05-10 04:18:18 +08:00
strm . Printf ( " UnwindAssemblyInstEmulation::ReadRegister (name = \" %s \" ) => synthetic_value = %i, value = " , reg_info - > name , synthetic ) ;
2011-05-15 12:12:07 +08:00
reg_value . Dump ( & strm , reg_info , false , false , eFormatDefault ) ;
2011-05-12 02:39:18 +08:00
log - > PutCString ( strm . GetData ( ) ) ;
2011-05-10 04:18:18 +08:00
}
2011-04-26 12:39:08 +08:00
return true ;
}
bool
UnwindAssemblyInstEmulation : : WriteRegister ( EmulateInstruction * instruction ,
void * baton ,
const EmulateInstruction : : Context & context ,
2011-05-10 04:18:18 +08:00
const RegisterInfo * reg_info ,
const RegisterValue & reg_value )
2011-04-26 12:39:08 +08:00
{
2011-05-12 02:39:18 +08:00
if ( baton & & reg_info )
return ( ( UnwindAssemblyInstEmulation * ) baton ) - > WriteRegister ( instruction , context , reg_info , reg_value ) ;
return false ;
}
bool
UnwindAssemblyInstEmulation : : WriteRegister ( EmulateInstruction * instruction ,
const EmulateInstruction : : Context & context ,
const RegisterInfo * reg_info ,
const RegisterValue & reg_value )
{
2013-03-28 07:08:40 +08:00
Log * log ( GetLogIfAllCategoriesSet ( LIBLLDB_LOG_UNWIND ) ) ;
2011-05-10 04:18:18 +08:00
2011-09-30 06:34:41 +08:00
if ( log & & log - > GetVerbose ( ) )
2011-05-12 02:39:18 +08:00
{
StreamString strm ;
strm . Printf ( " UnwindAssemblyInstEmulation::WriteRegister (name = \" %s \" , value = " , reg_info - > name ) ;
2011-05-15 12:12:07 +08:00
reg_value . Dump ( & strm , reg_info , false , false , eFormatDefault ) ;
2011-05-12 02:39:18 +08:00
strm . PutCString ( " , context = " ) ;
context . Dump ( strm , instruction ) ;
log - > PutCString ( strm . GetData ( ) ) ;
}
2011-04-27 07:48:45 +08:00
2011-05-12 02:39:18 +08:00
const bool must_replace = true ;
SetRegisterValue ( * reg_info , reg_value ) ;
2011-04-26 12:39:08 +08:00
switch ( context . type )
{
case EmulateInstruction : : eContextInvalid :
case EmulateInstruction : : eContextReadOpcode :
case EmulateInstruction : : eContextImmediate :
case EmulateInstruction : : eContextAdjustBaseRegister :
case EmulateInstruction : : eContextRegisterPlusOffset :
case EmulateInstruction : : eContextAdjustPC :
case EmulateInstruction : : eContextRegisterStore :
case EmulateInstruction : : eContextRegisterLoad :
case EmulateInstruction : : eContextAbsoluteBranchRegister :
case EmulateInstruction : : eContextSupervisorCall :
case EmulateInstruction : : eContextTableBranchReadMemory :
case EmulateInstruction : : eContextWriteRegisterRandomBits :
case EmulateInstruction : : eContextWriteMemoryRandomBits :
2011-04-27 07:48:45 +08:00
case EmulateInstruction : : eContextArithmetic :
2011-04-26 12:39:08 +08:00
case EmulateInstruction : : eContextAdvancePC :
case EmulateInstruction : : eContextReturnFromException :
case EmulateInstruction : : eContextPushRegisterOnStack :
2011-05-12 02:39:18 +08:00
// {
// const uint32_t reg_num = reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
// if (reg_num != LLDB_INVALID_REGNUM)
// {
// const bool can_replace_only_if_unspecified = true;
//
// m_curr_row.SetRegisterLocationToUndefined (reg_num,
// can_replace_only_if_unspecified,
// can_replace_only_if_unspecified);
2012-07-17 09:57:24 +08:00
// m_curr_row_modified = true;
2011-05-12 02:39:18 +08:00
// }
// }
2011-04-26 12:39:08 +08:00
break ;
2011-04-30 06:50:31 +08:00
2012-10-17 08:41:14 +08:00
case EmulateInstruction : : eContextRelativeBranchImmediate :
{
{
m_curr_insn_is_branch_immediate = true ;
}
}
break ;
2011-04-26 12:39:08 +08:00
case EmulateInstruction : : eContextPopRegisterOffStack :
2011-04-30 06:50:31 +08:00
{
2011-05-12 02:39:18 +08:00
const uint32_t reg_num = reg_info - > kinds [ m_unwind_plan_ptr - > GetRegisterKind ( ) ] ;
if ( reg_num ! = LLDB_INVALID_REGNUM )
2011-04-30 06:50:31 +08:00
{
2012-07-14 12:52:53 +08:00
m_curr_row - > SetRegisterLocationToSame ( reg_num , must_replace ) ;
2012-07-17 09:57:24 +08:00
m_curr_row_modified = true ;
2012-10-23 11:08:31 +08:00
m_curr_insn_restored_a_register = true ;
2011-04-30 06:50:31 +08:00
}
}
2011-04-26 12:39:08 +08:00
break ;
2011-05-12 02:39:18 +08:00
case EmulateInstruction : : eContextSetFramePointer :
if ( ! m_fp_is_cfa )
{
m_fp_is_cfa = true ;
m_cfa_reg_info = * reg_info ;
const uint32_t cfa_reg_num = reg_info - > kinds [ m_unwind_plan_ptr - > GetRegisterKind ( ) ] ;
assert ( cfa_reg_num ! = LLDB_INVALID_REGNUM ) ;
2012-07-14 12:52:53 +08:00
m_curr_row - > SetCFARegister ( cfa_reg_num ) ;
m_curr_row - > SetCFAOffset ( m_initial_sp - reg_value . GetAsUInt64 ( ) ) ;
2012-07-17 09:57:24 +08:00
m_curr_row_modified = true ;
2011-05-12 02:39:18 +08:00
}
break ;
2011-04-26 12:39:08 +08:00
case EmulateInstruction : : eContextAdjustStackPointer :
2011-05-12 02:39:18 +08:00
// If we have created a frame using the frame pointer, don't follow
// subsequent adjustments to the stack pointer.
if ( ! m_fp_is_cfa )
{
2012-07-14 12:52:53 +08:00
m_curr_row - > SetCFAOffset ( m_initial_sp - reg_value . GetAsUInt64 ( ) ) ;
2012-07-17 09:57:24 +08:00
m_curr_row_modified = true ;
2011-05-12 02:39:18 +08:00
}
2011-04-26 12:39:08 +08:00
break ;
}
return true ;
}