Index: include/lldb/API/SBInstruction.h =================================================================== --- include/lldb/API/SBInstruction.h +++ include/lldb/API/SBInstruction.h @@ -60,6 +60,9 @@ bool DoesBranch (); + bool + HasDelaySlot (); + void Print (FILE *out); Index: packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_in_delayslot/Makefile =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_in_delayslot/Makefile @@ -0,0 +1,6 @@ +LEVEL = ../../../make + +C_SOURCES := main.c + +include $(LEVEL)/Makefile.rules + Index: packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_in_delayslot/TestAvoidBreakpointInDelaySlot.py =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_in_delayslot/TestAvoidBreakpointInDelaySlot.py @@ -0,0 +1,82 @@ +""" +Test specific to MIPS +""" + +import os, time +import re +import unittest2 +import lldb +import lldbsuite.test.lldbutil as lldbutil +from lldbsuite.test.lldbtest import * + +class AvoidBreakpointInDelaySlotAPITestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @skipUnlessArch(archs=re.compile('mips*')) + def test(self): + self.build() + exe = os.path.join(os.getcwd(), "a.out") + self.expect("file " + exe, + patterns = [ "Current executable set to .*a.out.*" ]) + + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + breakpoint = target.BreakpointCreateByName('main', 'a.out') + self.assertTrue(breakpoint and + breakpoint.GetNumLocations() == 1, + VALID_BREAKPOINT) + + # Now launch the process, and do not stop at entry point. + process = target.LaunchSimple (None, None, self.get_process_working_directory()) + self.assertTrue(process, PROCESS_IS_VALID) + + list = target.FindFunctions('foo', lldb.eFunctionNameTypeAuto) + self.assertTrue(list.GetSize() == 1) + sc = list.GetContextAtIndex(0) + self.assertTrue(sc.GetSymbol().GetName() == "foo") + function = sc.GetFunction() + self.assertTrue(function) + self.function(function, target) + + def function (self, function, target): + """Iterate over instructions in function and place a breakpoint on delay slot instruction""" + # Get the list of all instructions in the function + insts = function.GetInstructions(target) + print insts + i = 0 + for inst in insts: + if (inst.HasDelaySlot()): + # Remember the address of branch instruction. + branchinstaddress = inst.GetAddress().GetLoadAddress(target) + + # Get next instruction i.e delay slot instruction. + delayinst = insts.GetInstructionAtIndex(i+1) + delayinstaddr = delayinst.GetAddress().GetLoadAddress(target) + + # Set breakpoint on delay slot instruction + breakpoint = target.BreakpointCreateByAddress(delayinstaddr) + + # Verify the breakpoint. + self.assertTrue(breakpoint and + breakpoint.GetNumLocations() == 1, + VALID_BREAKPOINT) + # Get the location from breakpoint + location = breakpoint.GetLocationAtIndex(0) + + # Get the address where breakpoint is actually set. + bpaddr = location.GetLoadAddress() + + # Breakpoint address should be adjusted to the address of branch instruction. + self.assertTrue(branchinstaddress == bpaddr) + i += 1 + else: + i += 1 + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() Index: packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_in_delayslot/main.c =================================================================== --- /dev/null +++ packages/Python/lldbsuite/test/functionalities/breakpoint/breakpoint_in_delayslot/main.c @@ -0,0 +1,21 @@ +#include + +foo (int a, int b) +{ + int c; + if (a<=b) + c=b-a; + else + c=b+a; + return c; +} + +int main() +{ + int a=7, b=8, c; + + c = foo(a, b); + +return 0; +} + Index: packages/Python/lldbsuite/test/lldbtest.py =================================================================== --- packages/Python/lldbsuite/test/lldbtest.py +++ packages/Python/lldbsuite/test/lldbtest.py @@ -635,6 +635,14 @@ else: return list_or_lambda is None or value is None or list_or_lambda == value +def matchArchitectures(archs, actual_arch): + retype = type(re.compile('hello, world')) + list_passes = isinstance(archs, list) and actual_arch in archs + basestring_passes = isinstance(archs, basestring) and actual_arch == archs + regex_passes = isinstance(archs, retype) and re.match(archs, actual_arch) + + return (list_passes or basestring_passes or regex_passes) + # provide a function to xfail on defined oslist, compiler version, and archs # if none is specified for any argument, that argument won't be checked and thus means for all # for example, @@ -1028,7 +1036,7 @@ return unittest2.skipUnless(getHostPlatform() in oslist, "requires on of %s" % (", ".join(oslist))) -def skipUnlessArch(archlist): +def skipUnlessArch(archs): """Decorate the item to skip tests unless running on one of the listed architectures.""" def myImpl(func): if isinstance(func, type) and issubclass(func, unittest2.TestCase): @@ -1037,9 +1045,8 @@ @wraps(func) def wrapper(*args, **kwargs): self = args[0] - if self.getArchitecture() not in archlist: - self.skipTest("skipping for architecture %s (requires one of %s)" % - (self.getArchitecture(), ", ".join(archlist))) + if not matchArchitectures(archs, self.getArchitecture()): + self.skipTest("skipping for architecture %s" % (self.getArchitecture())) else: func(*args, **kwargs) return wrapper Index: scripts/interface/SBInstruction.i =================================================================== --- scripts/interface/SBInstruction.i +++ scripts/interface/SBInstruction.i @@ -51,6 +51,9 @@ bool DoesBranch (); + bool + HasDelaySlot (); + void Print (FILE *out); Index: source/API/SBInstruction.cpp =================================================================== --- source/API/SBInstruction.cpp +++ source/API/SBInstruction.cpp @@ -160,6 +160,14 @@ return false; } +bool +SBInstruction::HasDelaySlot () +{ + if (m_opaque_sp) + return m_opaque_sp->HasDelaySlot (); + return false; +} + void SBInstruction::SetOpaque (const lldb::InstructionSP &inst_sp) { Index: source/Target/Target.cpp =================================================================== --- source/Target/Target.cpp +++ source/Target/Target.cpp @@ -2442,18 +2442,18 @@ SymbolContext sc; uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr, resolve_scope, sc); + Address sym_addr; if (sc.function) - { - function_start = sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress(this); - if (function_start == LLDB_INVALID_ADDRESS) - function_start = sc.function->GetAddressRange().GetBaseAddress().GetFileAddress(); - } + sym_addr = sc.function->GetAddressRange().GetBaseAddress(); else if (sc.symbol) - { - Address sym_addr = sc.symbol->GetAddress(); + sym_addr = sc.symbol->GetAddress(); + + function_start = sym_addr.GetLoadAddress(this); + if (function_start == LLDB_INVALID_ADDRESS) function_start = sym_addr.GetFileAddress(); - } - current_offset = addr - function_start; + + if (function_start) + current_offset = addr - function_start; } // If breakpoint address is start of function then we dont have to do anything.