summaryrefslogtreecommitdiffstats
path: root/lldb/source/Target/Target.cpp
diff options
context:
space:
mode:
authorBhushan D. Attarde <Bhushan.Attarde@imgtec.com>2015-08-26 06:04:54 +0000
committerBhushan D. Attarde <Bhushan.Attarde@imgtec.com>2015-08-26 06:04:54 +0000
commit7f3daeda9a1c8e2a7691954827c9ea886c8cfa62 (patch)
tree3b935ff9f79f0c5212abf7bd320757b70bff130e /lldb/source/Target/Target.cpp
parentd39bcaed2122c23a44dad3dc94b9e2166f8a3035 (diff)
downloadbcm5719-llvm-7f3daeda9a1c8e2a7691954827c9ea886c8cfa62.tar.gz
bcm5719-llvm-7f3daeda9a1c8e2a7691954827c9ea886c8cfa62.zip
[MIPS] Avoid breakpoint in delay slot
SUMMARY: This patch implements Target::GetBreakableLoadAddress() method that takes an address and checks for any reason there is a better address than this to put a breakpoint on. If there is then return that address. MIPS uses this method to avoid breakpoint in delay slot. Reviewers: clayborg, jingham Subscribers: jingham, mohit.bhakkad, sagar, jaydeep, nitesh.jain, lldb-commits Differential Revision: http://http://reviews.llvm.org/D12184 llvm-svn: 246015
Diffstat (limited to 'lldb/source/Target/Target.cpp')
-rw-r--r--lldb/source/Target/Target.cpp170
1 files changed, 170 insertions, 0 deletions
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index df209b69e64..c0470476e64 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -44,6 +44,8 @@
#include "lldb/Interpreter/Property.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/Function.h"
+#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/ObjCLanguageRuntime.h"
#include "lldb/Target/Process.h"
@@ -344,6 +346,10 @@ 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);
+
// Attempt to resolve our load address if possible, though it is ok if
// it doesn't resolve to section/offset.
@@ -2134,6 +2140,170 @@ Target::GetOpcodeLoadAddress (lldb::addr_t load_addr, AddressClass addr_class) c
return opcode_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.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.GetFlags ();
+ bool IsMips16 = arch_flags & ArchSpec::eMIPSAse_mips16;
+ bool IsMicromips = arch_flags & ArchSpec::eMIPSAse_micromips;
+ SectionLoadList &section_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;
+ uint32_t resolved_mask = temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr, resolve_scope, sc);
+ if (sc.function)
+ {
+ function_start = sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress(this);
+ if (function_start == LLDB_INVALID_ADDRESS)
+ function_start = sc.function->GetAddressRange().GetBaseAddress().GetFileAddress();
+ }
+ else if (sc.symbol)
+ {
+ Address sym_addr = sc.symbol->GetAddress();
+ function_start = sym_addr.GetFileAddress();
+ }
+ 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, NULL, NULL));
+
+ 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;
+
+ uint32_t bytes_disassembled = disasm_sp->ParseInstructions (&exe_ctx, range, NULL, 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;
+}
+
SourceManager &
Target::GetSourceManager ()
{
OpenPOWER on IntegriCloud