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:
Johnny Chen 2011-03-03 01:41:57 +00:00
parent ec84568904
commit d61816b5b8
8 changed files with 266 additions and 36 deletions

View File

@ -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')

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -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])

View File

@ -0,0 +1,5 @@
LEVEL = ../../make
C_SOURCES := main.c
include $(LEVEL)/Makefile.rules

View File

@ -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()

View File

@ -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;
}