mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 09:36:06 +00:00
Move architecture-specific address adjustment to architecture plugins
Differential Revision: https://reviews.llvm.org/D48623 llvm-svn: 342762
This commit is contained in:
parent
720fbf553d
commit
7aa9e7bc57
@ -67,6 +67,51 @@ public:
|
||||
virtual void AdjustBreakpointAddress(const Symbol &func,
|
||||
Address &addr) const {}
|
||||
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Get \a load_addr as a callable code load address for this target
|
||||
///
|
||||
/// Take \a load_addr and potentially add any address bits that are
|
||||
/// needed to make the address callable. For ARM this can set bit
|
||||
/// zero (if it already isn't) if \a load_addr is a thumb function.
|
||||
/// If \a addr_class is set to AddressClass::eInvalid, then the address
|
||||
/// adjustment will always happen. If it is set to an address class
|
||||
/// that doesn't have code in it, LLDB_INVALID_ADDRESS will be
|
||||
/// returned.
|
||||
//------------------------------------------------------------------
|
||||
virtual lldb::addr_t GetCallableLoadAddress(
|
||||
lldb::addr_t addr, AddressClass addr_class = AddressClass::eInvalid) const {
|
||||
return addr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
/// Get \a load_addr as an opcode for this target.
|
||||
///
|
||||
/// Take \a load_addr and potentially strip any address bits that are
|
||||
/// needed to make the address point to an opcode. For ARM this can
|
||||
/// clear bit zero (if it already isn't) if \a load_addr is a
|
||||
/// thumb function and load_addr is in code.
|
||||
/// If \a addr_class is set to AddressClass::eInvalid, then the address
|
||||
/// adjustment will always happen. If it is set to an address class
|
||||
/// that doesn't have code in it, LLDB_INVALID_ADDRESS will be
|
||||
/// returned.
|
||||
//------------------------------------------------------------------
|
||||
|
||||
virtual lldb::addr_t GetOpcodeLoadAddress(
|
||||
lldb::addr_t addr, AddressClass addr_class = AddressClass::eInvalid) const {
|
||||
return addr;
|
||||
}
|
||||
|
||||
// Get load_addr as breakable load address for this target. Take a addr and
|
||||
// check if for any reason there is a better address than this to put a
|
||||
// breakpoint on. If there is then return that address. For MIPS, if
|
||||
// instruction at addr is a delay slot instruction then this method will find
|
||||
// the address of its previous instruction and return that address.
|
||||
virtual lldb::addr_t GetBreakableLoadAddress(lldb::addr_t addr,
|
||||
Target &target) const {
|
||||
return addr;
|
||||
}
|
||||
|
||||
private:
|
||||
Architecture(const Architecture &) = delete;
|
||||
void operator=(const Architecture &) = delete;
|
||||
|
@ -126,3 +126,33 @@ void ArchitectureArm::OverrideStopInfo(Thread &thread) const {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addr_t ArchitectureArm::GetCallableLoadAddress(addr_t code_addr,
|
||||
AddressClass addr_class) const {
|
||||
bool is_alternate_isa = false;
|
||||
|
||||
switch (addr_class) {
|
||||
case AddressClass::eData:
|
||||
case AddressClass::eDebug:
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
case AddressClass::eCodeAlternateISA:
|
||||
is_alternate_isa = true;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if ((code_addr & 2u) || is_alternate_isa)
|
||||
return code_addr | 1u;
|
||||
return code_addr;
|
||||
}
|
||||
|
||||
addr_t ArchitectureArm::GetOpcodeLoadAddress(addr_t opcode_addr,
|
||||
AddressClass addr_class) const {
|
||||
switch (addr_class) {
|
||||
case AddressClass::eData:
|
||||
case AddressClass::eDebug:
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
default: break;
|
||||
}
|
||||
return opcode_addr & ~(1ull);
|
||||
}
|
@ -25,6 +25,12 @@ public:
|
||||
|
||||
void OverrideStopInfo(Thread &thread) const override;
|
||||
|
||||
lldb::addr_t GetCallableLoadAddress(lldb::addr_t load_addr,
|
||||
AddressClass addr_class) const override;
|
||||
|
||||
lldb::addr_t GetOpcodeLoadAddress(lldb::addr_t load_addr,
|
||||
AddressClass addr_class) const override;
|
||||
|
||||
private:
|
||||
static std::unique_ptr<Architecture> Create(const ArchSpec &arch);
|
||||
ArchitectureArm() = default;
|
||||
|
@ -1,2 +1,3 @@
|
||||
add_subdirectory(Arm)
|
||||
add_subdirectory(Mips)
|
||||
add_subdirectory(PPC64)
|
||||
|
240
lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp
Normal file
240
lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp
Normal file
@ -0,0 +1,240 @@
|
||||
//===-- ArchitectureMips.cpp -------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Plugins/Architecture/Mips/ArchitectureMips.h"
|
||||
#include "lldb/Core/Address.h"
|
||||
#include "lldb/Core/Disassembler.h"
|
||||
#include "lldb/Core/Module.h"
|
||||
#include "lldb/Core/PluginManager.h"
|
||||
#include "lldb/Symbol/Function.h"
|
||||
#include "lldb/Symbol/SymbolContext.h"
|
||||
#include "lldb/Target/SectionLoadList.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
#include "lldb/Utility/ArchSpec.h"
|
||||
#include "lldb/Utility/Log.h"
|
||||
|
||||
using namespace lldb_private;
|
||||
using namespace lldb;
|
||||
|
||||
ConstString ArchitectureMips::GetPluginNameStatic() {
|
||||
return ConstString("mips");
|
||||
}
|
||||
|
||||
void ArchitectureMips::Initialize() {
|
||||
PluginManager::RegisterPlugin(GetPluginNameStatic(),
|
||||
"Mips-specific algorithms",
|
||||
&ArchitectureMips::Create);
|
||||
}
|
||||
|
||||
void ArchitectureMips::Terminate() {
|
||||
PluginManager::UnregisterPlugin(&ArchitectureMips::Create);
|
||||
}
|
||||
|
||||
std::unique_ptr<Architecture> ArchitectureMips::Create(const ArchSpec &arch) {
|
||||
return arch.IsMIPS() ?
|
||||
std::unique_ptr<Architecture>(new ArchitectureMips(arch)) : nullptr;
|
||||
}
|
||||
|
||||
ConstString ArchitectureMips::GetPluginName() { return GetPluginNameStatic(); }
|
||||
uint32_t ArchitectureMips::GetPluginVersion() { return 1; }
|
||||
|
||||
addr_t ArchitectureMips::GetCallableLoadAddress(addr_t code_addr,
|
||||
AddressClass addr_class) const {
|
||||
bool is_alternate_isa = false;
|
||||
|
||||
switch (addr_class) {
|
||||
case AddressClass::eData:
|
||||
case AddressClass::eDebug:
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
case AddressClass::eCodeAlternateISA:
|
||||
is_alternate_isa = true;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
if ((code_addr & 2ull) || is_alternate_isa)
|
||||
return code_addr | 1u;
|
||||
return code_addr;
|
||||
}
|
||||
|
||||
addr_t ArchitectureMips::GetOpcodeLoadAddress(addr_t opcode_addr,
|
||||
AddressClass addr_class) const {
|
||||
switch (addr_class) {
|
||||
case AddressClass::eData:
|
||||
case AddressClass::eDebug:
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
default: break;
|
||||
}
|
||||
return opcode_addr & ~(1ull);
|
||||
}
|
||||
|
||||
lldb::addr_t ArchitectureMips::GetBreakableLoadAddress(lldb::addr_t addr,
|
||||
Target &target) const {
|
||||
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
|
||||
|
||||
Address resolved_addr;
|
||||
|
||||
SectionLoadList §ion_load_list = target.GetSectionLoadList();
|
||||
if (section_load_list.IsEmpty())
|
||||
// No sections are loaded, so we must assume we are not running yet and
|
||||
// need to operate only on file address.
|
||||
target.ResolveFileAddress(addr, resolved_addr);
|
||||
else
|
||||
target.ResolveLoadAddress(addr, resolved_addr);
|
||||
|
||||
addr_t current_offset = 0;
|
||||
|
||||
// Get the function boundaries to make sure we don't scan back before the
|
||||
// beginning of the current function.
|
||||
ModuleSP temp_addr_module_sp(resolved_addr.GetModule());
|
||||
if (temp_addr_module_sp) {
|
||||
SymbolContext sc;
|
||||
uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
|
||||
temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr,
|
||||
resolve_scope, sc);
|
||||
Address sym_addr;
|
||||
if (sc.function)
|
||||
sym_addr = sc.function->GetAddressRange().GetBaseAddress();
|
||||
else if (sc.symbol)
|
||||
sym_addr = sc.symbol->GetAddress();
|
||||
|
||||
addr_t function_start = sym_addr.GetLoadAddress(&target);
|
||||
if (function_start == LLDB_INVALID_ADDRESS)
|
||||
function_start = sym_addr.GetFileAddress();
|
||||
|
||||
if (function_start)
|
||||
current_offset = addr - function_start;
|
||||
}
|
||||
|
||||
// If breakpoint address is start of function then we dont have to do
|
||||
// anything.
|
||||
if (current_offset == 0)
|
||||
return addr;
|
||||
|
||||
ExecutionContext ctx;
|
||||
target.CalculateExecutionContext(ctx);
|
||||
auto insn = GetInstructionAtAddress(ctx, current_offset, addr);
|
||||
|
||||
if (nullptr == insn || !insn->HasDelaySlot())
|
||||
return addr;
|
||||
|
||||
// Adjust the breakable address
|
||||
auto breakable_addr = addr - insn->GetOpcode().GetByteSize();
|
||||
if (log)
|
||||
log->Printf("Target::%s Breakpoint at 0x%8.8" PRIx64
|
||||
" is adjusted to 0x%8.8" PRIx64 " due to delay slot\n",
|
||||
__FUNCTION__, addr, breakable_addr);
|
||||
|
||||
return breakable_addr;
|
||||
}
|
||||
|
||||
Instruction *ArchitectureMips::GetInstructionAtAddress(
|
||||
const ExecutionContext &exe_ctx, const Address &resolved_addr,
|
||||
addr_t symbol_offset) const {
|
||||
|
||||
auto loop_count = symbol_offset / 2;
|
||||
|
||||
uint32_t arch_flags = m_arch.GetFlags();
|
||||
bool IsMips16 = arch_flags & ArchSpec::eMIPSAse_mips16;
|
||||
bool IsMicromips = arch_flags & ArchSpec::eMIPSAse_micromips;
|
||||
|
||||
if (loop_count > 3) {
|
||||
// Scan previous 6 bytes
|
||||
if (IsMips16 | IsMicromips)
|
||||
loop_count = 3;
|
||||
// For mips-only, instructions are always 4 bytes, so scan previous 4
|
||||
// bytes only.
|
||||
else
|
||||
loop_count = 2;
|
||||
}
|
||||
|
||||
// Create Disassembler Instance
|
||||
lldb::DisassemblerSP disasm_sp(
|
||||
Disassembler::FindPlugin(m_arch, nullptr, nullptr));
|
||||
|
||||
InstructionList instruction_list;
|
||||
InstructionSP prev_insn;
|
||||
bool prefer_file_cache = true; // Read from file
|
||||
uint32_t inst_to_choose = 0;
|
||||
|
||||
Address addr = resolved_addr;
|
||||
|
||||
for (uint32_t i = 1; i <= loop_count; i++) {
|
||||
// Adjust the address to read from.
|
||||
addr.Slide(-2);
|
||||
AddressRange range(addr, i * 2);
|
||||
uint32_t insn_size = 0;
|
||||
|
||||
disasm_sp->ParseInstructions(&exe_ctx, range, nullptr, prefer_file_cache);
|
||||
|
||||
uint32_t num_insns = disasm_sp->GetInstructionList().GetSize();
|
||||
if (num_insns) {
|
||||
prev_insn = disasm_sp->GetInstructionList().GetInstructionAtIndex(0);
|
||||
insn_size = prev_insn->GetOpcode().GetByteSize();
|
||||
if (i == 1 && insn_size == 2) {
|
||||
// This looks like a valid 2-byte instruction (but it could be a part
|
||||
// of upper 4 byte instruction).
|
||||
instruction_list.Append(prev_insn);
|
||||
inst_to_choose = 1;
|
||||
}
|
||||
else if (i == 2) {
|
||||
// Here we may get one 4-byte instruction or two 2-byte instructions.
|
||||
if (num_insns == 2) {
|
||||
// Looks like there are two 2-byte instructions above our
|
||||
// breakpoint target address. Now the upper 2-byte instruction is
|
||||
// either a valid 2-byte instruction or could be a part of it's
|
||||
// upper 4-byte instruction. In both cases we don't care because in
|
||||
// this case lower 2-byte instruction is definitely a valid
|
||||
// instruction and whatever i=1 iteration has found out is true.
|
||||
inst_to_choose = 1;
|
||||
break;
|
||||
}
|
||||
else if (insn_size == 4) {
|
||||
// This instruction claims its a valid 4-byte instruction. But it
|
||||
// could be a part of it's upper 4-byte instruction. Lets try
|
||||
// scanning upper 2 bytes to verify this.
|
||||
instruction_list.Append(prev_insn);
|
||||
inst_to_choose = 2;
|
||||
}
|
||||
}
|
||||
else if (i == 3) {
|
||||
if (insn_size == 4)
|
||||
// FIXME: We reached here that means instruction at [target - 4] has
|
||||
// already claimed to be a 4-byte instruction, and now instruction
|
||||
// at [target - 6] is also claiming that it's a 4-byte instruction.
|
||||
// This can not be true. In this case we can not decide the valid
|
||||
// previous instruction so we let lldb set the breakpoint at the
|
||||
// address given by user.
|
||||
inst_to_choose = 0;
|
||||
else
|
||||
// This is straight-forward
|
||||
inst_to_choose = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Decode failed, bytes do not form a valid instruction. So whatever
|
||||
// previous iteration has found out is true.
|
||||
if (i > 1) {
|
||||
inst_to_choose = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we are able to find any valid instruction.
|
||||
if (inst_to_choose) {
|
||||
if (inst_to_choose > instruction_list.GetSize())
|
||||
inst_to_choose--;
|
||||
return instruction_list.GetInstructionAtIndex(inst_to_choose - 1).get();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
52
lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h
Normal file
52
lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h
Normal file
@ -0,0 +1,52 @@
|
||||
//===-- ArchitectureMips.h ---------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLDB_PLUGIN_ARCHITECTURE_MIPS_H
|
||||
#define LLDB_PLUGIN_ARCHITECTURE_MIPS_H
|
||||
|
||||
#include "lldb/Core/Architecture.h"
|
||||
#include "lldb/Utility/ArchSpec.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
class ArchitectureMips : public Architecture {
|
||||
public:
|
||||
static ConstString GetPluginNameStatic();
|
||||
static void Initialize();
|
||||
static void Terminate();
|
||||
|
||||
ConstString GetPluginName() override;
|
||||
uint32_t GetPluginVersion() override;
|
||||
|
||||
void OverrideStopInfo(Thread &thread) const override {}
|
||||
|
||||
lldb::addr_t GetBreakableLoadAddress(lldb::addr_t addr,
|
||||
Target &) const override;
|
||||
|
||||
lldb::addr_t GetCallableLoadAddress(lldb::addr_t load_addr,
|
||||
AddressClass addr_class) const override;
|
||||
|
||||
lldb::addr_t GetOpcodeLoadAddress(lldb::addr_t load_addr,
|
||||
AddressClass addr_class) const override;
|
||||
|
||||
private:
|
||||
Instruction *GetInstructionAtAddress(const ExecutionContext &exe_ctx,
|
||||
const Address &resolved_addr,
|
||||
lldb::addr_t symbol_offset) const;
|
||||
|
||||
|
||||
static std::unique_ptr<Architecture> Create(const ArchSpec &arch);
|
||||
ArchitectureMips(const ArchSpec &arch) : m_arch(arch) {}
|
||||
|
||||
ArchSpec m_arch;
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif // LLDB_PLUGIN_ARCHITECTURE_MIPS_H
|
10
lldb/source/Plugins/Architecture/Mips/CMakeLists.txt
Normal file
10
lldb/source/Plugins/Architecture/Mips/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
add_lldb_library(lldbPluginArchitectureMips PLUGIN
|
||||
ArchitectureMips.cpp
|
||||
|
||||
LINK_LIBS
|
||||
lldbCore
|
||||
lldbTarget
|
||||
lldbUtility
|
||||
LINK_COMPONENTS
|
||||
Support
|
||||
)
|
@ -2428,249 +2428,22 @@ lldb::addr_t Target::GetPersistentSymbol(const ConstString &name) {
|
||||
|
||||
lldb::addr_t Target::GetCallableLoadAddress(lldb::addr_t load_addr,
|
||||
AddressClass addr_class) const {
|
||||
addr_t code_addr = load_addr;
|
||||
switch (m_arch.GetSpec().GetMachine()) {
|
||||
case llvm::Triple::mips:
|
||||
case llvm::Triple::mipsel:
|
||||
case llvm::Triple::mips64:
|
||||
case llvm::Triple::mips64el:
|
||||
switch (addr_class) {
|
||||
case AddressClass::eData:
|
||||
case AddressClass::eDebug:
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
|
||||
case AddressClass::eUnknown:
|
||||
case AddressClass::eInvalid:
|
||||
case AddressClass::eCode:
|
||||
case AddressClass::eCodeAlternateISA:
|
||||
case AddressClass::eRuntime:
|
||||
if ((code_addr & 2ull) || (addr_class == AddressClass::eCodeAlternateISA))
|
||||
code_addr |= 1ull;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case llvm::Triple::arm:
|
||||
case llvm::Triple::thumb:
|
||||
switch (addr_class) {
|
||||
case AddressClass::eData:
|
||||
case AddressClass::eDebug:
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
|
||||
case AddressClass::eUnknown:
|
||||
case AddressClass::eInvalid:
|
||||
case AddressClass::eCode:
|
||||
case AddressClass::eCodeAlternateISA:
|
||||
case AddressClass::eRuntime:
|
||||
// Check if bit zero it no set?
|
||||
if ((code_addr & 1ull) == 0) {
|
||||
// Bit zero isn't set, check if the address is a multiple of 2?
|
||||
if (code_addr & 2ull) {
|
||||
// The address is a multiple of 2 so it must be thumb, set bit zero
|
||||
code_addr |= 1ull;
|
||||
} else if (addr_class == AddressClass::eCodeAlternateISA) {
|
||||
// We checked the address and the address claims to be the alternate
|
||||
// ISA which means thumb, so set bit zero.
|
||||
code_addr |= 1ull;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return code_addr;
|
||||
auto arch_plugin = GetArchitecturePlugin();
|
||||
return arch_plugin ?
|
||||
arch_plugin->GetCallableLoadAddress(load_addr, addr_class) : load_addr;
|
||||
}
|
||||
|
||||
lldb::addr_t Target::GetOpcodeLoadAddress(lldb::addr_t load_addr,
|
||||
AddressClass addr_class) const {
|
||||
addr_t opcode_addr = load_addr;
|
||||
switch (m_arch.GetSpec().GetMachine()) {
|
||||
case llvm::Triple::mips:
|
||||
case llvm::Triple::mipsel:
|
||||
case llvm::Triple::mips64:
|
||||
case llvm::Triple::mips64el:
|
||||
case llvm::Triple::arm:
|
||||
case llvm::Triple::thumb:
|
||||
switch (addr_class) {
|
||||
case AddressClass::eData:
|
||||
case AddressClass::eDebug:
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
|
||||
case AddressClass::eInvalid:
|
||||
case AddressClass::eUnknown:
|
||||
case AddressClass::eCode:
|
||||
case AddressClass::eCodeAlternateISA:
|
||||
case AddressClass::eRuntime:
|
||||
opcode_addr &= ~(1ull);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return opcode_addr;
|
||||
auto arch_plugin = GetArchitecturePlugin();
|
||||
return arch_plugin ?
|
||||
arch_plugin->GetOpcodeLoadAddress(load_addr, addr_class) : load_addr;
|
||||
}
|
||||
|
||||
lldb::addr_t Target::GetBreakableLoadAddress(lldb::addr_t addr) {
|
||||
addr_t breakable_addr = addr;
|
||||
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
|
||||
|
||||
switch (m_arch.GetSpec().GetMachine()) {
|
||||
default:
|
||||
break;
|
||||
case llvm::Triple::mips:
|
||||
case llvm::Triple::mipsel:
|
||||
case llvm::Triple::mips64:
|
||||
case llvm::Triple::mips64el: {
|
||||
addr_t function_start = 0;
|
||||
addr_t current_offset = 0;
|
||||
uint32_t loop_count = 0;
|
||||
Address resolved_addr;
|
||||
uint32_t arch_flags = m_arch.GetSpec().GetFlags();
|
||||
bool IsMips16 = arch_flags & ArchSpec::eMIPSAse_mips16;
|
||||
bool IsMicromips = arch_flags & ArchSpec::eMIPSAse_micromips;
|
||||
SectionLoadList §ion_load_list = GetSectionLoadList();
|
||||
|
||||
if (section_load_list.IsEmpty())
|
||||
// No sections are loaded, so we must assume we are not running yet and
|
||||
// need to operate only on file address.
|
||||
m_images.ResolveFileAddress(addr, resolved_addr);
|
||||
else
|
||||
section_load_list.ResolveLoadAddress(addr, resolved_addr);
|
||||
|
||||
// Get the function boundaries to make sure we don't scan back before the
|
||||
// beginning of the current function.
|
||||
ModuleSP temp_addr_module_sp(resolved_addr.GetModule());
|
||||
if (temp_addr_module_sp) {
|
||||
SymbolContext sc;
|
||||
uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol;
|
||||
temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr,
|
||||
resolve_scope, sc);
|
||||
Address sym_addr;
|
||||
if (sc.function)
|
||||
sym_addr = sc.function->GetAddressRange().GetBaseAddress();
|
||||
else if (sc.symbol)
|
||||
sym_addr = sc.symbol->GetAddress();
|
||||
|
||||
function_start = sym_addr.GetLoadAddress(this);
|
||||
if (function_start == LLDB_INVALID_ADDRESS)
|
||||
function_start = sym_addr.GetFileAddress();
|
||||
|
||||
if (function_start)
|
||||
current_offset = addr - function_start;
|
||||
}
|
||||
|
||||
// If breakpoint address is start of function then we dont have to do
|
||||
// anything.
|
||||
if (current_offset == 0)
|
||||
return breakable_addr;
|
||||
else
|
||||
loop_count = current_offset / 2;
|
||||
|
||||
if (loop_count > 3) {
|
||||
// Scan previous 6 bytes
|
||||
if (IsMips16 | IsMicromips)
|
||||
loop_count = 3;
|
||||
// For mips-only, instructions are always 4 bytes, so scan previous 4
|
||||
// bytes only.
|
||||
else
|
||||
loop_count = 2;
|
||||
}
|
||||
|
||||
// Create Disassembler Instance
|
||||
lldb::DisassemblerSP disasm_sp(
|
||||
Disassembler::FindPlugin(m_arch.GetSpec(), nullptr, nullptr));
|
||||
|
||||
ExecutionContext exe_ctx;
|
||||
CalculateExecutionContext(exe_ctx);
|
||||
InstructionList instruction_list;
|
||||
InstructionSP prev_insn;
|
||||
bool prefer_file_cache = true; // Read from file
|
||||
uint32_t inst_to_choose = 0;
|
||||
|
||||
for (uint32_t i = 1; i <= loop_count; i++) {
|
||||
// Adjust the address to read from.
|
||||
resolved_addr.Slide(-2);
|
||||
AddressRange range(resolved_addr, i * 2);
|
||||
uint32_t insn_size = 0;
|
||||
|
||||
disasm_sp->ParseInstructions(&exe_ctx, range, nullptr, prefer_file_cache);
|
||||
|
||||
uint32_t num_insns = disasm_sp->GetInstructionList().GetSize();
|
||||
if (num_insns) {
|
||||
prev_insn = disasm_sp->GetInstructionList().GetInstructionAtIndex(0);
|
||||
insn_size = prev_insn->GetOpcode().GetByteSize();
|
||||
if (i == 1 && insn_size == 2) {
|
||||
// This looks like a valid 2-byte instruction (but it could be a part
|
||||
// of upper 4 byte instruction).
|
||||
instruction_list.Append(prev_insn);
|
||||
inst_to_choose = 1;
|
||||
} else if (i == 2) {
|
||||
// Here we may get one 4-byte instruction or two 2-byte instructions.
|
||||
if (num_insns == 2) {
|
||||
// Looks like there are two 2-byte instructions above our
|
||||
// breakpoint target address. Now the upper 2-byte instruction is
|
||||
// either a valid 2-byte instruction or could be a part of it's
|
||||
// upper 4-byte instruction. In both cases we don't care because in
|
||||
// this case lower 2-byte instruction is definitely a valid
|
||||
// instruction and whatever i=1 iteration has found out is true.
|
||||
inst_to_choose = 1;
|
||||
break;
|
||||
} else if (insn_size == 4) {
|
||||
// This instruction claims its a valid 4-byte instruction. But it
|
||||
// could be a part of it's upper 4-byte instruction. Lets try
|
||||
// scanning upper 2 bytes to verify this.
|
||||
instruction_list.Append(prev_insn);
|
||||
inst_to_choose = 2;
|
||||
}
|
||||
} else if (i == 3) {
|
||||
if (insn_size == 4)
|
||||
// FIXME: We reached here that means instruction at [target - 4] has
|
||||
// already claimed to be a 4-byte instruction, and now instruction
|
||||
// at [target - 6] is also claiming that it's a 4-byte instruction.
|
||||
// This can not be true. In this case we can not decide the valid
|
||||
// previous instruction so we let lldb set the breakpoint at the
|
||||
// address given by user.
|
||||
inst_to_choose = 0;
|
||||
else
|
||||
// This is straight-forward
|
||||
inst_to_choose = 2;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Decode failed, bytes do not form a valid instruction. So whatever
|
||||
// previous iteration has found out is true.
|
||||
if (i > 1) {
|
||||
inst_to_choose = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we are able to find any valid instruction.
|
||||
if (inst_to_choose) {
|
||||
if (inst_to_choose > instruction_list.GetSize())
|
||||
inst_to_choose--;
|
||||
prev_insn = instruction_list.GetInstructionAtIndex(inst_to_choose - 1);
|
||||
|
||||
if (prev_insn->HasDelaySlot()) {
|
||||
uint32_t shift_size = prev_insn->GetOpcode().GetByteSize();
|
||||
// Adjust the breakable address
|
||||
breakable_addr = addr - shift_size;
|
||||
if (log)
|
||||
log->Printf("Target::%s Breakpoint at 0x%8.8" PRIx64
|
||||
" is adjusted to 0x%8.8" PRIx64 " due to delay slot\n",
|
||||
__FUNCTION__, addr, breakable_addr);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return breakable_addr;
|
||||
auto arch_plugin = GetArchitecturePlugin();
|
||||
return arch_plugin ?
|
||||
arch_plugin->GetBreakableLoadAddress(addr, *this) : addr;
|
||||
}
|
||||
|
||||
SourceManager &Target::GetSourceManager() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user