forked from OSchip/llvm-project
Add TestTargetAPI.py:
// When stopped on breakppint 1, and then 2, we can get the line entries using // SBFrame API SBFrame.GetLineEntry(). We'll get the start addresses for the // two line entries; with the start address (of SBAddress type), we can then // resolve the symbol context using the SBTarget API // SBTarget.ResolveSymbolContextForAddress(). // // The two symbol context should point to the same symbol, i.e., 'a' function. Add two utility functions to lldbutil.py: o get_stopped_threads(process, reason): return the list of threads with the specified stop reason or an empty list if not found o get_stopped_thread(process, reason): return the first thread with the given stop reason or None if not found llvm-svn: 126916
This commit is contained in:
parent
ec84568904
commit
d61816b5b8
|
@ -146,7 +146,10 @@ class BreakpointConditionsTestCase(TestBase):
|
|||
self.assertTrue(self.process.IsValid(), PROCESS_IS_VALID)
|
||||
|
||||
# Frame #0 should be on self.line1 and the break condition should hold.
|
||||
frame0 = self.process.GetThreadAtIndex(0).GetFrameAtIndex(0)
|
||||
from lldbutil import get_stopped_thread
|
||||
thread = get_stopped_thread(self.process, lldb.eStopReasonPlanComplete)
|
||||
self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint condition")
|
||||
frame0 = thread.GetFrameAtIndex(0)
|
||||
var = frame0.FindValue('val', lldb.eValueTypeVariableArgument)
|
||||
self.assertTrue(frame0.GetLineEntry().GetLine() == self.line1 and
|
||||
var.GetValue(frame0) == '3')
|
||||
|
|
|
@ -110,9 +110,12 @@ class BreakpointIgnoreCountTestCase(TestBase):
|
|||
# Frame#0 should be on main.c:37, frame#1 should be on main.c:25, and
|
||||
# frame#2 should be on main.c:48.
|
||||
#lldbutil.PrintStackTraces(self.process)
|
||||
frame0 = self.process.GetThreadAtIndex(0).GetFrameAtIndex(0)
|
||||
frame1 = self.process.GetThreadAtIndex(0).GetFrameAtIndex(1)
|
||||
frame2 = self.process.GetThreadAtIndex(0).GetFrameAtIndex(2)
|
||||
from lldbutil import get_stopped_thread
|
||||
thread = get_stopped_thread(self.process, lldb.eStopReasonBreakpoint)
|
||||
self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint")
|
||||
frame0 = thread.GetFrameAtIndex(0)
|
||||
frame1 = thread.GetFrameAtIndex(1)
|
||||
frame2 = thread.GetFrameAtIndex(2)
|
||||
self.assertTrue(frame0.GetLineEntry().GetLine() == self.line1 and
|
||||
frame1.GetLineEntry().GetLine() == self.line3 and
|
||||
frame2.GetLineEntry().GetLine() == self.line4,
|
||||
|
|
|
@ -6,6 +6,41 @@ import lldb
|
|||
import sys
|
||||
import StringIO
|
||||
|
||||
# ===========================================
|
||||
# Iterator for lldb aggregate data structures
|
||||
# ===========================================
|
||||
|
||||
def lldb_iter(obj, getsize, getelem):
|
||||
"""A generator adaptor for lldb aggregate data structures.
|
||||
|
||||
API clients pass in an aggregate object or a container of it, the name of
|
||||
the method to get the size of the aggregate, and the name of the method to
|
||||
get the element by index.
|
||||
|
||||
Example usages:
|
||||
|
||||
1. Pass an aggregate as the first argument:
|
||||
|
||||
def disassemble_instructions (insts):
|
||||
from lldbutil import lldb_iter
|
||||
for i in lldb_iter(insts, 'GetSize', 'GetInstructionAtIndex'):
|
||||
print i
|
||||
|
||||
2. Pass a container of aggregate which provides APIs to get to the size and
|
||||
the element of the aggregate:
|
||||
|
||||
# Module is a container of symbol table
|
||||
module = target.FindModule(filespec)
|
||||
for symbol in lldb_iter(module, 'GetNumSymbols', 'GetSymbolAtIndex'):
|
||||
name = symbol.GetName()
|
||||
...
|
||||
"""
|
||||
size = getattr(obj, getsize)
|
||||
elem = getattr(obj, getelem)
|
||||
for i in range(size()):
|
||||
yield elem(i)
|
||||
|
||||
|
||||
# ==========================================================
|
||||
# Integer (byte size 1, 2, 4, and 8) to bytearray conversion
|
||||
# ==========================================================
|
||||
|
@ -61,40 +96,45 @@ def bytearray_to_int(bytes, bytesize):
|
|||
return unpacked[0]
|
||||
|
||||
|
||||
# ===========================================
|
||||
# Iterator for lldb aggregate data structures
|
||||
# ===========================================
|
||||
# ===========================================================
|
||||
# Returns the list of stopped thread(s) given an lldb process
|
||||
# ===========================================================
|
||||
|
||||
def lldb_iter(obj, getsize, getelem):
|
||||
"""A generator adaptor for lldb aggregate data structures.
|
||||
def get_stopped_threads(process, reason):
|
||||
"""Returns the thread(s) with the specified stop reason in a list."""
|
||||
threads = []
|
||||
for t in lldb_iter(process, 'GetNumThreads', 'GetThreadAtIndex'):
|
||||
if t.GetStopReason() == reason:
|
||||
threads.append(t)
|
||||
return threads
|
||||
|
||||
API clients pass in an aggregate object or a container of it, the name of
|
||||
the method to get the size of the aggregate, and the name of the method to
|
||||
get the element by index.
|
||||
def get_stopped_thread(process, reason):
|
||||
"""A convenience function which returns the first thread with the given stop
|
||||
reason or None.
|
||||
|
||||
Example usages:
|
||||
|
||||
1. Pass an aggregate as the first argument:
|
||||
1. Get the stopped thread due to a breakpoint condition
|
||||
|
||||
def disassemble_instructions (insts):
|
||||
from lldbutil import lldb_iter
|
||||
for i in lldb_iter(insts, 'GetSize', 'GetInstructionAtIndex'):
|
||||
print i
|
||||
...
|
||||
from lldbutil import get_stopped_thread
|
||||
thread = get_stopped_thread(self.process, lldb.eStopReasonPlanComplete)
|
||||
self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint condition")
|
||||
...
|
||||
|
||||
2. Pass a container of aggregate which provides APIs to get to the size and
|
||||
the element of the aggregate:
|
||||
2. Get the thread stopped due to a breakpoint
|
||||
|
||||
...
|
||||
from lldbutil import get_stopped_thread
|
||||
thread = get_stopped_thread(self.process, lldb.eStopReasonBreakpoint)
|
||||
self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint")
|
||||
...
|
||||
|
||||
# Module is a container of symbol table
|
||||
module = target.FindModule(filespec)
|
||||
for symbol in lldb_iter(module, 'GetNumSymbols', 'GetSymbolAtIndex'):
|
||||
name = symbol.GetName()
|
||||
...
|
||||
"""
|
||||
size = getattr(obj, getsize)
|
||||
elem = getattr(obj, getelem)
|
||||
for i in range(size()):
|
||||
yield elem(i)
|
||||
|
||||
threads = get_stopped_threads(process, reason)
|
||||
if len(threads) == 0:
|
||||
return None
|
||||
return threads[0]
|
||||
|
||||
# =================================================
|
||||
# Convert some enum value to its string counterpart
|
||||
|
|
|
@ -5,6 +5,7 @@ Test SBProcess APIs, including ReadMemory(), WriteMemory(), and others.
|
|||
import os, time
|
||||
import unittest2
|
||||
import lldb
|
||||
from lldbutil import get_stopped_thread
|
||||
from lldbtest import *
|
||||
|
||||
class ProcessAPITestCase(TestBase):
|
||||
|
@ -71,8 +72,9 @@ class ProcessAPITestCase(TestBase):
|
|||
error = lldb.SBError()
|
||||
self.process = target.Launch (self.dbg.GetListener(), None, None, os.ctermid(), os.ctermid(), os.ctermid(), None, 0, False, error)
|
||||
|
||||
thread = self.process.GetThreadAtIndex(0);
|
||||
frame = thread.GetFrameAtIndex(0);
|
||||
thread = get_stopped_thread(self.process, lldb.eStopReasonBreakpoint)
|
||||
self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint")
|
||||
frame = thread.GetFrameAtIndex(0)
|
||||
|
||||
# Get the SBValue for the global variable 'my_char'.
|
||||
val = frame.FindValue("my_char", lldb.eValueTypeVariableGlobal)
|
||||
|
@ -111,8 +113,9 @@ class ProcessAPITestCase(TestBase):
|
|||
error = lldb.SBError()
|
||||
self.process = target.Launch (self.dbg.GetListener(), None, None, os.ctermid(), os.ctermid(), os.ctermid(), None, 0, False, error)
|
||||
|
||||
thread = self.process.GetThreadAtIndex(0);
|
||||
frame = thread.GetFrameAtIndex(0);
|
||||
thread = get_stopped_thread(self.process, lldb.eStopReasonBreakpoint)
|
||||
self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint")
|
||||
frame = thread.GetFrameAtIndex(0)
|
||||
|
||||
# Get the SBValue for the global variable 'my_char'.
|
||||
val = frame.FindValue("my_char", lldb.eValueTypeVariableGlobal)
|
||||
|
@ -160,8 +163,9 @@ class ProcessAPITestCase(TestBase):
|
|||
error = lldb.SBError()
|
||||
self.process = target.Launch (self.dbg.GetListener(), None, None, os.ctermid(), os.ctermid(), os.ctermid(), None, 0, False, error)
|
||||
|
||||
thread = self.process.GetThreadAtIndex(0);
|
||||
frame = thread.GetFrameAtIndex(0);
|
||||
thread = get_stopped_thread(self.process, lldb.eStopReasonBreakpoint)
|
||||
self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint")
|
||||
frame = thread.GetFrameAtIndex(0)
|
||||
|
||||
# Get the SBValue for the global variable 'my_int'.
|
||||
val = frame.FindValue("my_int", lldb.eValueTypeVariableGlobal)
|
||||
|
|
|
@ -54,7 +54,10 @@ class SymbolContextAPITestCase(TestBase):
|
|||
self.assertTrue(self.process.IsValid(), PROCESS_IS_VALID)
|
||||
|
||||
# Frame #0 should be on self.line.
|
||||
frame0 = self.process.GetThreadAtIndex(0).GetFrameAtIndex(0)
|
||||
from lldbutil import get_stopped_thread
|
||||
thread = get_stopped_thread(self.process, lldb.eStopReasonBreakpoint)
|
||||
self.assertTrue(thread != None, "There should be a thread stopped due to breakpoint")
|
||||
frame0 = thread.GetFrameAtIndex(0)
|
||||
self.assertTrue(frame0.GetLineEntry().GetLine() == self.line)
|
||||
|
||||
# Now get the SBSymbolContext from this frame. We want everything. :-)
|
||||
|
@ -81,6 +84,7 @@ class SymbolContextAPITestCase(TestBase):
|
|||
#print "block:", block
|
||||
|
||||
lineEntry = context.GetLineEntry()
|
||||
#print "line entry:", lineEntry
|
||||
self.expect(lineEntry.GetFileSpec().GetDirectory(), "The line entry should have the correct directory",
|
||||
exe=False,
|
||||
substrs = [self.mydir])
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
LEVEL = ../../make
|
||||
|
||||
C_SOURCES := main.c
|
||||
|
||||
include $(LEVEL)/Makefile.rules
|
|
@ -0,0 +1,114 @@
|
|||
"""
|
||||
Test SBTarget APIs.
|
||||
"""
|
||||
|
||||
import os, time
|
||||
import re
|
||||
import unittest2
|
||||
import lldb, lldbutil
|
||||
from lldbtest import *
|
||||
|
||||
class TargetAPITestCase(TestBase):
|
||||
|
||||
mydir = os.path.join("python_api", "target")
|
||||
|
||||
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
|
||||
@python_api_test
|
||||
def test_with_dsym(self):
|
||||
"""Exercise SBTaget APIs."""
|
||||
self.buildDsym()
|
||||
self.target_api()
|
||||
|
||||
@python_api_test
|
||||
def test_with_dwarf(self):
|
||||
"""Exercise SBTarget APIs."""
|
||||
self.buildDwarf()
|
||||
self.target_api()
|
||||
|
||||
def setUp(self):
|
||||
# Call super's setUp().
|
||||
TestBase.setUp(self)
|
||||
# Find the line number to of function 'c'.
|
||||
self.line1 = line_number('main.c', '// Find the line number for breakpoint 1 here.')
|
||||
self.line2 = line_number('main.c', '// Find the line number for breakpoint 2 here.')
|
||||
|
||||
def target_api(self):
|
||||
"""Exercise SBTarget APIs."""
|
||||
exe = os.path.join(os.getcwd(), "a.out")
|
||||
|
||||
# Create a target by the debugger.
|
||||
target = self.dbg.CreateTarget(exe)
|
||||
self.assertTrue(target.IsValid(), VALID_TARGET)
|
||||
|
||||
# Now create the two breakpoints inside function 'a'.
|
||||
breakpoint1 = target.BreakpointCreateByLocation('main.c', self.line1)
|
||||
breakpoint2 = target.BreakpointCreateByLocation('main.c', self.line2)
|
||||
print "breakpoint1:", breakpoint1
|
||||
print "breakpoint2:", breakpoint2
|
||||
self.assertTrue(breakpoint1.IsValid() and
|
||||
breakpoint1.GetNumLocations() == 1,
|
||||
VALID_BREAKPOINT)
|
||||
self.assertTrue(breakpoint2.IsValid() and
|
||||
breakpoint2.GetNumLocations() == 1,
|
||||
VALID_BREAKPOINT)
|
||||
|
||||
# Now launch the process, and do not stop at entry point.
|
||||
error = lldb.SBError()
|
||||
self.process = target.Launch (self.dbg.GetListener(), None, None, os.ctermid(), os.ctermid(), os.ctermid(), None, 0, False, error)
|
||||
|
||||
self.process = target.GetProcess()
|
||||
self.assertTrue(self.process.IsValid(), PROCESS_IS_VALID)
|
||||
|
||||
# Frame #0 should be on self.line1.
|
||||
self.assertTrue(self.process.GetState() == lldb.eStateStopped)
|
||||
thread = lldbutil.get_stopped_thread(self.process, lldb.eStopReasonBreakpoint)
|
||||
self.runCmd("process status")
|
||||
frame0 = thread.GetFrameAtIndex(0)
|
||||
lineEntry = frame0.GetLineEntry()
|
||||
self.assertTrue(lineEntry.GetLine() == self.line1)
|
||||
|
||||
address1 = lineEntry.GetStartAddress()
|
||||
|
||||
# Continue the inferior, the breakpoint 2 should be hit.
|
||||
self.process.Continue()
|
||||
self.assertTrue(self.process.GetState() == lldb.eStateStopped)
|
||||
thread = lldbutil.get_stopped_thread(self.process, lldb.eStopReasonBreakpoint)
|
||||
self.runCmd("process status")
|
||||
frame0 = thread.GetFrameAtIndex(0)
|
||||
lineEntry = frame0.GetLineEntry()
|
||||
self.assertTrue(lineEntry.GetLine() == self.line2)
|
||||
|
||||
address2 = lineEntry.GetStartAddress()
|
||||
|
||||
print "address1:", address1
|
||||
print "address2:", address2
|
||||
|
||||
# Now call SBTarget.ResolveSymbolContextForAddress() with the addresses from our line entry.
|
||||
context1 = target.ResolveSymbolContextForAddress(address1, lldb.eSymbolContextEverything)
|
||||
context2 = target.ResolveSymbolContextForAddress(address2, lldb.eSymbolContextEverything)
|
||||
|
||||
self.assertTrue(context1.IsValid() and context2.IsValid())
|
||||
print "context1:", context1
|
||||
print "context2:", context2
|
||||
|
||||
# Verify that the context point to the same function 'a'.
|
||||
symbol1 = context1.GetSymbol()
|
||||
symbol2 = context2.GetSymbol()
|
||||
self.assertTrue(symbol1.IsValid() and symbol2.IsValid())
|
||||
print "symbol1:", symbol1
|
||||
print "symbol2:", symbol2
|
||||
|
||||
stream1 = lldb.SBStream()
|
||||
symbol1.GetDescription(stream1)
|
||||
stream2 = lldb.SBStream()
|
||||
symbol2.GetDescription(stream2)
|
||||
|
||||
self.expect(stream1.GetData(), "The two addresses should resolve to the same symbol", exe=False,
|
||||
startstr = stream2.GetData())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import atexit
|
||||
lldb.SBDebugger.Initialize()
|
||||
atexit.register(lambda: lldb.SBDebugger.Terminate())
|
||||
unittest2.main()
|
|
@ -0,0 +1,57 @@
|
|||
//===-- main.c --------------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
#include <stdio.h>
|
||||
|
||||
// This simple program is to test the lldb Python API SBTarget.
|
||||
//
|
||||
// When stopped on breakppint 1, and then 2, we can get the line entries using
|
||||
// SBFrame API SBFrame.GetLineEntry(). We'll get the start addresses for the
|
||||
// two line entries; with the start address (of SBAddress type), we can then
|
||||
// resolve the symbol context using the SBTarget API
|
||||
// SBTarget.ResolveSymbolContextForAddress().
|
||||
//
|
||||
// The two symbol context should point to the same symbol, i.e., 'a' function.
|
||||
|
||||
int a(int);
|
||||
int b(int);
|
||||
int c(int);
|
||||
|
||||
int a(int val)
|
||||
{
|
||||
if (val <= 1) // Find the line number for breakpoint 1 here.
|
||||
val = b(val);
|
||||
else if (val >= 3)
|
||||
val = c(val);
|
||||
|
||||
return val; // Find the line number for breakpoint 2 here.
|
||||
}
|
||||
|
||||
int b(int val)
|
||||
{
|
||||
return c(val);
|
||||
}
|
||||
|
||||
int c(int val)
|
||||
{
|
||||
return val + 3;
|
||||
}
|
||||
|
||||
int main (int argc, char const *argv[])
|
||||
{
|
||||
int A1 = a(1); // a(1) -> b(1) -> c(1)
|
||||
printf("a(1) returns %d\n", A1);
|
||||
|
||||
int B2 = b(2); // b(2) -> c(2)
|
||||
printf("b(2) returns %d\n", B2);
|
||||
|
||||
int A3 = a(3); // a(3) -> c(3)
|
||||
printf("a(3) returns %d\n", A3);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue