Index: include/lldb/Core/Architecture.h =================================================================== --- include/lldb/Core/Architecture.h +++ include/lldb/Core/Architecture.h @@ -14,6 +14,9 @@ namespace lldb_private { +class Address; +class Instruction; + class Architecture : public PluginInterface { public: Architecture() = default; @@ -67,6 +70,21 @@ virtual void AdjustBreakpointAddress(const Symbol &func, Address &addr) const {} + enum class Feature {eDelaySlot, eFlaggedAddress}; + virtual bool DoesSupport(Feature) const { return false; } + + virtual Instruction *GetInstructionAtAddress( + const ExecutionContext &/*exe_ctx*/, + const Address &/*resolved_addr*/, + lldb::addr_t /*symbol_offset*/) const { + return nullptr; + } + + virtual lldb::addr_t GetAddressFlagMask(lldb::addr_t /*addr*/, + bool /*is_alternate_isa*/) const { + return 0u; + } + private: Architecture(const Architecture &) = delete; void operator=(const Architecture &) = delete; Index: include/lldb/Core/Disassembler.h =================================================================== --- include/lldb/Core/Disassembler.h +++ include/lldb/Core/Disassembler.h @@ -78,7 +78,7 @@ class Instruction { public: Instruction(const Address &address, - AddressClass addr_class = AddressClass::eInvalid); + AddressClass addr_class/* = AddressClass::eInvalid*/); virtual ~Instruction(); Index: source/Plugins/Architecture/Arm/ArchitectureArm.h =================================================================== --- source/Plugins/Architecture/Arm/ArchitectureArm.h +++ source/Plugins/Architecture/Arm/ArchitectureArm.h @@ -26,6 +26,10 @@ void OverrideStopInfo(Thread &thread) const override; private: + bool DoesSupport(Feature) const override; + lldb::addr_t GetAddressFlagMask(lldb::addr_t load_addr, + bool is_alternate_isa) const override; + static std::unique_ptr Create(const ArchSpec &arch); ArchitectureArm() = default; }; Index: source/Plugins/Architecture/Arm/ArchitectureArm.cpp =================================================================== --- source/Plugins/Architecture/Arm/ArchitectureArm.cpp +++ source/Plugins/Architecture/Arm/ArchitectureArm.cpp @@ -33,7 +33,7 @@ } std::unique_ptr ArchitectureArm::Create(const ArchSpec &arch) { - if (arch.GetMachine() != llvm::Triple::arm) + if (arch.GetMachine() != llvm::Triple::arm) // llvm::Triple::thumb? return nullptr; return std::unique_ptr(new ArchitectureArm()); } @@ -126,3 +126,14 @@ } } } + +addr_t ArchitectureArm::GetAddressFlagMask(addr_t code_addr, + bool is_alternate_isa) const { + if ((code_addr & 2u) || is_alternate_isa) + return 1u; + return 0u; +} + +bool ArchitectureArm::DoesSupport(Architecture::Feature feature) const { + return Feature::eFlaggedAddress == feature; +} \ No newline at end of file Index: source/Plugins/Architecture/CMakeLists.txt =================================================================== --- source/Plugins/Architecture/CMakeLists.txt +++ source/Plugins/Architecture/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(Arm) +add_subdirectory(Mips) add_subdirectory(PPC64) Index: source/Plugins/Architecture/Mips/ArchitectureMips.h =================================================================== --- /dev/null +++ source/Plugins/Architecture/Mips/ArchitectureMips.h @@ -0,0 +1,47 @@ +//===-- 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_ARM_H +#define LLDB_PLUGIN_ARCHITECTURE_ARM_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 {} + +private: + bool DoesSupport(Feature) const override; + lldb::addr_t GetAddressFlagMask(lldb::addr_t load_addr, + bool is_alternate_isa) const override; + + Instruction *GetInstructionAtAddress(const ExecutionContext &exe_ctx, + const Address &resolved_addr, + lldb::addr_t symbol_offset) const override; + + + static std::unique_ptr Create(const ArchSpec &arch); + ArchitectureMips(const ArchSpec &arch) : m_arch(arch) {} + + ArchSpec m_arch; +}; + +} // namespace lldb_private + +#endif // LLDB_PLUGIN_ARCHITECTURE_ARM_H Index: source/Plugins/Architecture/Mips/ArchitectureMips.cpp =================================================================== --- /dev/null +++ source/Plugins/Architecture/Mips/ArchitectureMips.cpp @@ -0,0 +1,169 @@ +//===-- 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/Utility/ArchSpec.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 ArchitectureMips::Create(const ArchSpec &arch) { + switch (arch.GetMachine()) { + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + return std::unique_ptr(new ArchitectureMips(arch)); + default: + return nullptr; + } +} + +ConstString ArchitectureMips::GetPluginName() { return GetPluginNameStatic(); } +uint32_t ArchitectureMips::GetPluginVersion() { return 1; } + +addr_t ArchitectureMips::GetAddressFlagMask(addr_t code_addr, + bool is_alternate_isa) const { + if ((code_addr & 2ull) || is_alternate_isa) + return 1u; + return 0u; +} + +bool ArchitectureMips::DoesSupport(Architecture::Feature feature) const { + switch (feature) { + case Feature::eDelaySlot: + case Feature::eFlaggedAddress: + return true; + default: return false; + } +} + +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; +} Index: source/Plugins/Architecture/Mips/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/Architecture/Mips/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lldb_library(lldbPluginArchitectureMips PLUGIN + ArchitectureMips.cpp + + LINK_LIBS + lldbCore + lldbTarget + lldbUtility + LINK_COMPONENTS + Support + ) Index: source/Target/Target.cpp =================================================================== --- source/Target/Target.cpp +++ source/Target/Target.cpp @@ -373,8 +373,6 @@ BreakpointSP Target::CreateBreakpoint(lldb::addr_t addr, bool internal, bool hardware) { - Address so_addr; - // Check for any reason we want to move this breakpoint to other address. addr = GetBreakableLoadAddress(addr); @@ -382,11 +380,13 @@ // doesn't resolve to section/offset. // Try and resolve as a load address if possible + Address so_addr; GetSectionLoadList().ResolveLoadAddress(addr, so_addr); if (!so_addr.IsValid()) { // The address didn't resolve, so just set this as an absolute address so_addr.SetOffset(addr); } + BreakpointSP bp_sp(CreateBreakpoint(so_addr, internal, hardware)); return bp_sp; } @@ -2351,248 +2351,100 @@ 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; + bool alternate_isa = false; - 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; - } + switch (addr_class) { + case AddressClass::eData: + case AddressClass::eDebug: + return LLDB_INVALID_ADDRESS; + case AddressClass::eCodeAlternateISA: + alternate_isa = true; break; + default: break; + } - case llvm::Triple::arm: - case llvm::Triple::thumb: - switch (addr_class) { - case AddressClass::eData: - case AddressClass::eDebug: - return LLDB_INVALID_ADDRESS; + auto arch = GetArchitecturePlugin(); + if (!arch) + return load_addr; + if(arch->DoesSupport(Architecture::Feature::eFlaggedAddress)) + return load_addr | arch->GetAddressFlagMask(load_addr, alternate_isa); - 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; + return GetOpcodeLoadAddress(load_addr, addr_class); } 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; + switch (addr_class) { + case AddressClass::eData: + case AddressClass::eDebug: + return LLDB_INVALID_ADDRESS; + default: break; + } - 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; + return llvm::alignDown(load_addr, + GetArchitecture().GetMinimumOpcodeByteSize()); } 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(); + auto arch = GetArchitecturePlugin(); + if (!arch || !arch->DoesSupport(Architecture::Feature::eDelaySlot)) + return addr; - 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); + Address 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(); + 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); - function_start = sym_addr.GetLoadAddress(this); - if (function_start == LLDB_INVALID_ADDRESS) - function_start = sym_addr.GetFileAddress(); + addr_t current_offset = 0; - if (function_start) - current_offset = addr - function_start; - } + // 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(); - // 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; + addr_t function_start = sym_addr.GetLoadAddress(this); + if (function_start == LLDB_INVALID_ADDRESS) + function_start = sym_addr.GetFileAddress(); - 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; - } + if (function_start) + current_offset = addr - function_start; + } - // Create Disassembler Instance - lldb::DisassemblerSP disasm_sp( - Disassembler::FindPlugin(m_arch.GetSpec(), nullptr, nullptr)); + // If breakpoint address is start of function then we dont have to do + // anything. + if (current_offset == 0) + return addr; - 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; + ExecutionContext ctx; + CalculateExecutionContext(ctx); + auto insn = arch->GetInstructionAtAddress(ctx, current_offset, addr); - 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; + if (nullptr == insn || !insn->HasDelaySlot()) + return addr; - disasm_sp->ParseInstructions(&exe_ctx, range, nullptr, prefer_file_cache); + // 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); - 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; }