2011-04-29 05:31:18 +08:00
|
|
|
#
|
2011-04-29 07:53:16 +08:00
|
|
|
# modify-lldb-python.py
|
2011-04-29 05:31:18 +08:00
|
|
|
#
|
|
|
|
# This script modifies the lldb module (which was automatically generated via
|
2011-04-30 03:22:24 +08:00
|
|
|
# running swig) to support iteration and/or equality operations for certain lldb
|
2011-05-25 05:05:16 +08:00
|
|
|
# objects, implements truth value testing for certain lldb objects, and adds a
|
|
|
|
# global variable 'debugger_unique_id' which is initialized to 0.
|
2011-04-29 05:31:18 +08:00
|
|
|
#
|
2011-07-02 06:14:07 +08:00
|
|
|
# As a cleanup step, it also removes the 'residues' from the autodoc features of
|
|
|
|
# swig. For an example, take a look at SBTarget.h header file, where we take
|
2011-07-03 04:01:09 +08:00
|
|
|
# advantage of the already existing doxygen C++-docblock and make it the Python
|
2011-07-02 06:14:07 +08:00
|
|
|
# docstring for the same method. The 'residues' in this context include the
|
2011-07-04 03:55:50 +08:00
|
|
|
# '#endif', the '#ifdef SWIG', the c comment marker, the trailing blank (SPC's)
|
|
|
|
# line, and the doxygen comment start marker.
|
2011-07-02 06:14:07 +08:00
|
|
|
#
|
2011-07-07 05:55:45 +08:00
|
|
|
# In addition to the 'residues' removal during the cleanup step, it also
|
|
|
|
# transforms the 'char' data type (which was actually 'char *' but the 'autodoc'
|
|
|
|
# feature of swig removes ' *' from it into 'str' (as a Python str type).
|
|
|
|
#
|
2011-04-29 05:31:18 +08:00
|
|
|
# It also calls SBDebugger.Initialize() to initialize the lldb debugger
|
|
|
|
# subsystem.
|
|
|
|
#
|
|
|
|
|
|
|
|
import sys, re, StringIO
|
|
|
|
|
|
|
|
if len (sys.argv) != 2:
|
|
|
|
output_name = "./lldb.py"
|
|
|
|
else:
|
|
|
|
output_name = sys.argv[1] + "/lldb.py"
|
|
|
|
|
|
|
|
# print "output_name is '" + output_name + "'"
|
|
|
|
|
2011-07-07 05:55:45 +08:00
|
|
|
#
|
2011-07-02 06:14:07 +08:00
|
|
|
# Residues to be removed.
|
2011-07-07 05:55:45 +08:00
|
|
|
#
|
2011-07-02 06:14:07 +08:00
|
|
|
c_endif_swig = "#endif"
|
|
|
|
c_ifdef_swig = "#ifdef SWIG"
|
2011-07-03 04:01:09 +08:00
|
|
|
c_comment_marker = "//------------"
|
|
|
|
# The pattern for recognizing the doxygen comment block line.
|
2011-07-17 05:15:39 +08:00
|
|
|
doxygen_comment_start = re.compile("^\s*(/// ?)")
|
2011-07-04 03:55:50 +08:00
|
|
|
# The demarcation point for turning on/off residue removal state.
|
|
|
|
# When bracketed by the lines, the CLEANUP_DOCSTRING state (see below) is ON.
|
|
|
|
toggle_docstring_cleanup_line = ' """'
|
2011-07-02 06:14:07 +08:00
|
|
|
|
2011-07-07 05:55:45 +08:00
|
|
|
def char_to_str_xform(line):
|
|
|
|
"""This transforms the 'char', i.e, 'char *' to 'str', Python string."""
|
|
|
|
line = line.replace(' char', ' str')
|
|
|
|
line = line.replace('char ', 'str ')
|
2011-07-14 08:17:49 +08:00
|
|
|
# Special case handling of 'char **argv' and 'char **envp'.
|
|
|
|
line = line.replace('str argv', 'list argv')
|
|
|
|
line = line.replace('str envp', 'list envp')
|
2011-07-07 05:55:45 +08:00
|
|
|
return line
|
|
|
|
|
|
|
|
#
|
|
|
|
# The one-liner docstring also needs char_to_str transformation, btw.
|
|
|
|
#
|
2011-07-09 07:57:20 +08:00
|
|
|
TWO_SPACES = ' ' * 2
|
|
|
|
EIGHT_SPACES = ' ' * 8
|
|
|
|
one_liner_docstring_pattern = re.compile('^(%s|%s)""".*"""$' % (TWO_SPACES, EIGHT_SPACES))
|
2011-07-07 05:55:45 +08:00
|
|
|
|
2011-04-29 05:31:18 +08:00
|
|
|
#
|
2011-06-02 02:40:11 +08:00
|
|
|
# lldb_iter() should appear before our first SB* class definition.
|
2011-04-29 05:31:18 +08:00
|
|
|
#
|
|
|
|
lldb_iter_def = '''
|
|
|
|
# ===================================
|
|
|
|
# Iterator for lldb container objects
|
|
|
|
# ===================================
|
|
|
|
def lldb_iter(obj, getsize, getelem):
|
|
|
|
"""A generator adaptor to support iteration for lldb container objects."""
|
|
|
|
size = getattr(obj, getsize)
|
|
|
|
elem = getattr(obj, getelem)
|
|
|
|
for i in range(size()):
|
|
|
|
yield elem(i)
|
|
|
|
|
2011-06-02 03:21:08 +08:00
|
|
|
# ==============================================================================
|
|
|
|
# The modify-python-lldb.py script is responsible for post-processing this SWIG-
|
|
|
|
# generated lldb.py module. It is responsible for adding the above lldb_iter()
|
|
|
|
# function definition as well as the supports, in the following, for iteration
|
|
|
|
# protocol: __iter__, rich comparison methods: __eq__ and __ne__, truth value
|
|
|
|
# testing (and built-in operation bool()): __nonzero__, and built-in function
|
|
|
|
# len(): __len__.
|
|
|
|
# ==============================================================================
|
2011-04-29 05:31:18 +08:00
|
|
|
'''
|
|
|
|
|
Provide an add-on API to SBValue class by post-processing to provide a way
to iterate through an SBValue instance by treating it as the head of a linked
list. API program must provide two args to the linked_list_iter() method:
the first being the child member name which points to the next item on the list
and the second being a Python function which an SBValue (for the next item) and
returns True if end of list is reached, otherwise it returns False.
For example, suppose we have the following sample program.
#include <stdio.h>
class Task {
public:
int id;
Task *next;
Task(int i, Task *n):
id(i),
next(n)
{}
};
int main (int argc, char const *argv[])
{
Task *task_head = new Task(-1, NULL);
Task *task1 = new Task(1, NULL);
Task *task2 = new Task(2, NULL);
Task *task3 = new Task(3, NULL); // Orphaned.
Task *task4 = new Task(4, NULL);
Task *task5 = new Task(5, NULL);
task_head->next = task1;
task1->next = task2;
task2->next = task4;
task4->next = task5;
int total = 0; // Break at this line
Task *t = task_head;
while (t != NULL) {
if (t->id >= 0)
++total;
t = t->next;
}
printf("We have a total number of %d tasks\n", total);
return 0;
}
The test program produces the following output while exercising the linked_list_iter() SBVAlue API:
task_head:
TypeName -> Task *
ByteSize -> 8
NumChildren -> 2
Value -> 0x0000000106400380
ValueType -> local_variable
Summary -> None
IsPointerType -> True
Location -> 0x00007fff65f06e60
(Task *) next = 0x0000000106400390
(int) id = 1
(Task *) next = 0x00000001064003a0
(Task *) next = 0x00000001064003a0
(int) id = 2
(Task *) next = 0x00000001064003c0
(Task *) next = 0x00000001064003c0
(int) id = 4
(Task *) next = 0x00000001064003d0
(Task *) next = 0x00000001064003d0
(int) id = 5
(Task *) next = 0x0000000000000000
llvm-svn: 135938
2011-07-26 03:32:35 +08:00
|
|
|
#
|
2011-07-26 07:41:08 +08:00
|
|
|
# linked_list_iter() is a special purpose iterator to treat the SBValue as the
|
|
|
|
# head of a list data structure, where you specify the child member name which
|
|
|
|
# points to the next item on the list and you specify the end-of-list function
|
|
|
|
# which takes an SBValue and returns True if EOL is reached and False if not.
|
Provide an add-on API to SBValue class by post-processing to provide a way
to iterate through an SBValue instance by treating it as the head of a linked
list. API program must provide two args to the linked_list_iter() method:
the first being the child member name which points to the next item on the list
and the second being a Python function which an SBValue (for the next item) and
returns True if end of list is reached, otherwise it returns False.
For example, suppose we have the following sample program.
#include <stdio.h>
class Task {
public:
int id;
Task *next;
Task(int i, Task *n):
id(i),
next(n)
{}
};
int main (int argc, char const *argv[])
{
Task *task_head = new Task(-1, NULL);
Task *task1 = new Task(1, NULL);
Task *task2 = new Task(2, NULL);
Task *task3 = new Task(3, NULL); // Orphaned.
Task *task4 = new Task(4, NULL);
Task *task5 = new Task(5, NULL);
task_head->next = task1;
task1->next = task2;
task2->next = task4;
task4->next = task5;
int total = 0; // Break at this line
Task *t = task_head;
while (t != NULL) {
if (t->id >= 0)
++total;
t = t->next;
}
printf("We have a total number of %d tasks\n", total);
return 0;
}
The test program produces the following output while exercising the linked_list_iter() SBVAlue API:
task_head:
TypeName -> Task *
ByteSize -> 8
NumChildren -> 2
Value -> 0x0000000106400380
ValueType -> local_variable
Summary -> None
IsPointerType -> True
Location -> 0x00007fff65f06e60
(Task *) next = 0x0000000106400390
(int) id = 1
(Task *) next = 0x00000001064003a0
(Task *) next = 0x00000001064003a0
(int) id = 2
(Task *) next = 0x00000001064003c0
(Task *) next = 0x00000001064003c0
(int) id = 4
(Task *) next = 0x00000001064003d0
(Task *) next = 0x00000001064003d0
(int) id = 5
(Task *) next = 0x0000000000000000
llvm-svn: 135938
2011-07-26 03:32:35 +08:00
|
|
|
#
|
|
|
|
linked_list_iter_def = '''
|
|
|
|
# ==================================================
|
|
|
|
# Iterator for lldb.SBValue treated as a linked list
|
|
|
|
# ==================================================
|
2011-07-26 07:44:48 +08:00
|
|
|
def linked_list_iter(self, next_item_name, end_of_list_test):
|
2011-07-26 07:41:08 +08:00
|
|
|
"""Generator adaptor to support iteration for SBValue as a linked list.
|
|
|
|
|
|
|
|
linked_list_iter() is a special purpose iterator to treat the SBValue as
|
|
|
|
the head of a list data structure, where you specify the child member
|
|
|
|
name which points to the next item on the list and you specify the
|
|
|
|
end-of-list test function which takes an SBValue for an item and returns
|
|
|
|
True if EOL is reached and False if not.
|
Provide an add-on API to SBValue class by post-processing to provide a way
to iterate through an SBValue instance by treating it as the head of a linked
list. API program must provide two args to the linked_list_iter() method:
the first being the child member name which points to the next item on the list
and the second being a Python function which an SBValue (for the next item) and
returns True if end of list is reached, otherwise it returns False.
For example, suppose we have the following sample program.
#include <stdio.h>
class Task {
public:
int id;
Task *next;
Task(int i, Task *n):
id(i),
next(n)
{}
};
int main (int argc, char const *argv[])
{
Task *task_head = new Task(-1, NULL);
Task *task1 = new Task(1, NULL);
Task *task2 = new Task(2, NULL);
Task *task3 = new Task(3, NULL); // Orphaned.
Task *task4 = new Task(4, NULL);
Task *task5 = new Task(5, NULL);
task_head->next = task1;
task1->next = task2;
task2->next = task4;
task4->next = task5;
int total = 0; // Break at this line
Task *t = task_head;
while (t != NULL) {
if (t->id >= 0)
++total;
t = t->next;
}
printf("We have a total number of %d tasks\n", total);
return 0;
}
The test program produces the following output while exercising the linked_list_iter() SBVAlue API:
task_head:
TypeName -> Task *
ByteSize -> 8
NumChildren -> 2
Value -> 0x0000000106400380
ValueType -> local_variable
Summary -> None
IsPointerType -> True
Location -> 0x00007fff65f06e60
(Task *) next = 0x0000000106400390
(int) id = 1
(Task *) next = 0x00000001064003a0
(Task *) next = 0x00000001064003a0
(int) id = 2
(Task *) next = 0x00000001064003c0
(Task *) next = 0x00000001064003c0
(int) id = 4
(Task *) next = 0x00000001064003d0
(Task *) next = 0x00000001064003d0
(int) id = 5
(Task *) next = 0x0000000000000000
llvm-svn: 135938
2011-07-26 03:32:35 +08:00
|
|
|
|
|
|
|
For example,
|
|
|
|
|
|
|
|
# Test function to determine end of list.
|
|
|
|
def eol(val):
|
|
|
|
if not val:
|
|
|
|
return True
|
|
|
|
try:
|
|
|
|
# Test the semantics of the item we got.
|
|
|
|
id = val.GetChildMemberWithName("id")
|
|
|
|
if int(id.GetValue()) > 0:
|
|
|
|
return False
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
|
|
|
# If we fall through to here. It could be that exception
|
|
|
|
# occurred or the "id" child member does not qualify as a
|
|
|
|
# valid item. Return True for EOL.
|
|
|
|
return True
|
|
|
|
|
|
|
|
# Get Frame #0.
|
|
|
|
...
|
|
|
|
|
|
|
|
# Get variable 'task_head'.
|
|
|
|
task_head = frame0.FindVariable('task_head')
|
|
|
|
...
|
|
|
|
|
|
|
|
for t in task_head.linked_list_iter('next', eol):
|
|
|
|
print t
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
item = self.GetChildMemberWithName(next_item_name)
|
|
|
|
while item:
|
|
|
|
yield item
|
|
|
|
# Prepare for the next iteration.
|
|
|
|
item = item.GetChildMemberWithName(next_item_name)
|
2011-07-26 07:44:48 +08:00
|
|
|
if end_of_list_test(item):
|
Provide an add-on API to SBValue class by post-processing to provide a way
to iterate through an SBValue instance by treating it as the head of a linked
list. API program must provide two args to the linked_list_iter() method:
the first being the child member name which points to the next item on the list
and the second being a Python function which an SBValue (for the next item) and
returns True if end of list is reached, otherwise it returns False.
For example, suppose we have the following sample program.
#include <stdio.h>
class Task {
public:
int id;
Task *next;
Task(int i, Task *n):
id(i),
next(n)
{}
};
int main (int argc, char const *argv[])
{
Task *task_head = new Task(-1, NULL);
Task *task1 = new Task(1, NULL);
Task *task2 = new Task(2, NULL);
Task *task3 = new Task(3, NULL); // Orphaned.
Task *task4 = new Task(4, NULL);
Task *task5 = new Task(5, NULL);
task_head->next = task1;
task1->next = task2;
task2->next = task4;
task4->next = task5;
int total = 0; // Break at this line
Task *t = task_head;
while (t != NULL) {
if (t->id >= 0)
++total;
t = t->next;
}
printf("We have a total number of %d tasks\n", total);
return 0;
}
The test program produces the following output while exercising the linked_list_iter() SBVAlue API:
task_head:
TypeName -> Task *
ByteSize -> 8
NumChildren -> 2
Value -> 0x0000000106400380
ValueType -> local_variable
Summary -> None
IsPointerType -> True
Location -> 0x00007fff65f06e60
(Task *) next = 0x0000000106400390
(int) id = 1
(Task *) next = 0x00000001064003a0
(Task *) next = 0x00000001064003a0
(int) id = 2
(Task *) next = 0x00000001064003c0
(Task *) next = 0x00000001064003c0
(int) id = 4
(Task *) next = 0x00000001064003d0
(Task *) next = 0x00000001064003d0
(int) id = 5
(Task *) next = 0x0000000000000000
llvm-svn: 135938
2011-07-26 03:32:35 +08:00
|
|
|
break
|
|
|
|
except:
|
|
|
|
# Exception occurred. Stop the generator.
|
|
|
|
pass
|
|
|
|
|
|
|
|
return
|
|
|
|
'''
|
|
|
|
|
2011-04-29 05:31:18 +08:00
|
|
|
# This supports the iteration protocol.
|
|
|
|
iter_def = " def __iter__(self): return lldb_iter(self, '%s', '%s')"
|
|
|
|
module_iter = " def module_iter(self): return lldb_iter(self, '%s', '%s')"
|
|
|
|
breakpoint_iter = " def breakpoint_iter(self): return lldb_iter(self, '%s', '%s')"
|
2011-05-18 06:14:39 +08:00
|
|
|
|
2011-05-17 04:31:18 +08:00
|
|
|
# Called to implement the built-in function len().
|
|
|
|
# Eligible objects are those containers with unambiguous iteration support.
|
|
|
|
len_def = " def __len__(self): return self.%s()"
|
2011-05-18 06:14:39 +08:00
|
|
|
|
2011-04-30 03:03:02 +08:00
|
|
|
# This supports the rich comparison methods of __eq__ and __ne__.
|
2011-05-03 03:05:52 +08:00
|
|
|
eq_def = " def __eq__(self, other): return isinstance(other, %s) and %s"
|
2011-04-30 03:03:02 +08:00
|
|
|
ne_def = " def __ne__(self, other): return not self.__eq__(other)"
|
2011-04-29 05:31:18 +08:00
|
|
|
|
2011-05-18 06:14:39 +08:00
|
|
|
# Called to implement truth value testing and the built-in operation bool();
|
|
|
|
# should return False or True, or their integer equivalents 0 or 1.
|
|
|
|
# Delegate to self.IsValid() if it is defined for the current lldb object.
|
|
|
|
nonzero_def = " def __nonzero__(self): return self.IsValid()"
|
|
|
|
|
2011-04-29 05:31:18 +08:00
|
|
|
#
|
2011-05-25 06:53:03 +08:00
|
|
|
# This dictionary defines a mapping from classname to (getsize, getelem) tuple.
|
2011-04-29 05:31:18 +08:00
|
|
|
#
|
|
|
|
d = { 'SBBreakpoint': ('GetNumLocations', 'GetLocationAtIndex'),
|
|
|
|
'SBCompileUnit': ('GetNumLineEntries', 'GetLineEntryAtIndex'),
|
|
|
|
'SBDebugger': ('GetNumTargets', 'GetTargetAtIndex'),
|
|
|
|
'SBModule': ('GetNumSymbols', 'GetSymbolAtIndex'),
|
|
|
|
'SBProcess': ('GetNumThreads', 'GetThreadAtIndex'),
|
|
|
|
'SBThread': ('GetNumFrames', 'GetFrameAtIndex'),
|
|
|
|
|
|
|
|
'SBInstructionList': ('GetSize', 'GetInstructionAtIndex'),
|
|
|
|
'SBStringList': ('GetSize', 'GetStringAtIndex',),
|
|
|
|
'SBSymbolContextList': ('GetSize', 'GetContextAtIndex'),
|
|
|
|
'SBValueList': ('GetSize', 'GetValueAtIndex'),
|
|
|
|
|
|
|
|
'SBType': ('GetNumberChildren', 'GetChildAtIndex'),
|
|
|
|
'SBValue': ('GetNumChildren', 'GetChildAtIndex'),
|
|
|
|
|
2011-05-25 06:57:42 +08:00
|
|
|
# SBTarget needs special processing, see below.
|
2011-04-29 05:31:18 +08:00
|
|
|
'SBTarget': {'module': ('GetNumModules', 'GetModuleAtIndex'),
|
|
|
|
'breakpoint': ('GetNumBreakpoints', 'GetBreakpointAtIndex')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-30 03:03:02 +08:00
|
|
|
#
|
2011-05-03 03:05:52 +08:00
|
|
|
# This dictionary defines a mapping from classname to equality method name(s).
|
2011-04-30 03:03:02 +08:00
|
|
|
#
|
2011-06-10 06:04:56 +08:00
|
|
|
e = { 'SBAddress': ['GetFileAddress', 'GetModule'],
|
|
|
|
'SBBreakpoint': ['GetID'],
|
2011-05-03 03:05:52 +08:00
|
|
|
'SBFileSpec': ['GetFilename', 'GetDirectory'],
|
|
|
|
'SBModule': ['GetFileSpec', 'GetUUIDString']
|
|
|
|
}
|
|
|
|
|
|
|
|
def list_to_frag(list):
|
|
|
|
"""Transform a list to equality program fragment.
|
|
|
|
|
|
|
|
For example, ['GetID'] is transformed to 'self.GetID() == other.GetID()',
|
|
|
|
and ['GetFilename', 'GetDirectory'] to 'self.GetFilename() == other.GetFilename()
|
|
|
|
and self.GetDirectory() == other.GetDirectory()'.
|
|
|
|
"""
|
|
|
|
if not list:
|
|
|
|
raise Exception("list should be non-empty")
|
|
|
|
frag = StringIO.StringIO()
|
|
|
|
for i in range(len(list)):
|
|
|
|
if i > 0:
|
|
|
|
frag.write(" and ")
|
|
|
|
frag.write("self.{0}() == other.{0}()".format(list[i]))
|
|
|
|
return frag.getvalue()
|
2011-04-30 03:03:02 +08:00
|
|
|
|
2011-07-17 05:15:39 +08:00
|
|
|
class NewContent(StringIO.StringIO):
|
|
|
|
"""Simple facade to keep track of the previous line to be committed."""
|
|
|
|
def __init__(self):
|
|
|
|
StringIO.StringIO.__init__(self)
|
|
|
|
self.prev_line = None
|
|
|
|
def add_line(self, a_line):
|
|
|
|
"""Add a line to the content, if there is a previous line, commit it."""
|
|
|
|
if self.prev_line != None:
|
|
|
|
print >> self, self.prev_line
|
|
|
|
self.prev_line = a_line
|
|
|
|
def del_line(self):
|
|
|
|
"""Forget about the previous line, do not commit it."""
|
|
|
|
self.prev_line = None
|
|
|
|
def del_blank_line(self):
|
|
|
|
"""Forget about the previous line if it is a blank line."""
|
|
|
|
if self.prev_line != None and not self.prev_line.strip():
|
|
|
|
self.prev_line = None
|
|
|
|
def finish(self):
|
|
|
|
"""Call this when you're finished with populating content."""
|
|
|
|
if self.prev_line != None:
|
|
|
|
print >> self, self.prev_line
|
|
|
|
self.prev_line = None
|
|
|
|
|
2011-04-29 05:31:18 +08:00
|
|
|
# The new content will have the iteration protocol defined for our lldb objects.
|
2011-07-17 05:15:39 +08:00
|
|
|
new_content = NewContent()
|
2011-04-29 05:31:18 +08:00
|
|
|
|
|
|
|
with open(output_name, 'r') as f_in:
|
|
|
|
content = f_in.read()
|
|
|
|
|
|
|
|
# The pattern for recognizing the beginning of an SB class definition.
|
|
|
|
class_pattern = re.compile("^class (SB.*)\(_object\):$")
|
|
|
|
|
|
|
|
# The pattern for recognizing the beginning of the __init__ method definition.
|
|
|
|
init_pattern = re.compile("^ def __init__\(self, \*args\):")
|
|
|
|
|
2011-05-18 06:14:39 +08:00
|
|
|
# The pattern for recognizing the beginning of the IsValid method definition.
|
2011-06-14 11:55:41 +08:00
|
|
|
isvalid_pattern = re.compile("^ def IsValid\(")
|
2011-05-18 06:14:39 +08:00
|
|
|
|
2011-05-17 04:31:18 +08:00
|
|
|
# These define the states of our finite state machine.
|
2011-04-29 05:31:18 +08:00
|
|
|
NORMAL = 0
|
|
|
|
DEFINING_ITERATOR = 1
|
2011-04-30 03:03:02 +08:00
|
|
|
DEFINING_EQUALITY = 2
|
2011-07-04 03:55:50 +08:00
|
|
|
CLEANUP_DOCSTRING = 4
|
2011-04-29 05:31:18 +08:00
|
|
|
|
|
|
|
# The lldb_iter_def only needs to be inserted once.
|
|
|
|
lldb_iter_defined = False;
|
|
|
|
|
2011-05-18 06:14:39 +08:00
|
|
|
# Our FSM begins its life in the NORMAL state, and transitions to the
|
|
|
|
# DEFINING_ITERATOR and/or DEFINING_EQUALITY state whenever it encounters the
|
|
|
|
# beginning of certain class definitions, see dictionaries 'd' and 'e' above.
|
|
|
|
#
|
|
|
|
# Note that the two states DEFINING_ITERATOR and DEFINING_EQUALITY are
|
|
|
|
# orthogonal in that our FSM can be in one, the other, or both states at the
|
|
|
|
# same time. During such time, the FSM is eagerly searching for the __init__
|
|
|
|
# method definition in order to insert the appropriate method(s) into the lldb
|
|
|
|
# module.
|
|
|
|
#
|
2011-07-04 03:55:50 +08:00
|
|
|
# The state CLEANUP_DOCSTRING can be entered from either the NORMAL or the
|
|
|
|
# DEFINING_ITERATOR/EQUALITY states. While in this state, the FSM is fixing/
|
|
|
|
# cleaning the Python docstrings generated by the swig docstring features.
|
|
|
|
#
|
2011-05-25 06:29:49 +08:00
|
|
|
# The FSM, in all possible states, also checks the current input for IsValid()
|
|
|
|
# definition, and inserts a __nonzero__() method definition to implement truth
|
|
|
|
# value testing and the built-in operation bool().
|
2011-04-29 05:31:18 +08:00
|
|
|
state = NORMAL
|
|
|
|
for line in content.splitlines():
|
2011-07-04 03:55:50 +08:00
|
|
|
# Handle the state transition into CLEANUP_DOCSTRING state as it is possible
|
|
|
|
# to enter this state from either NORMAL or DEFINING_ITERATOR/EQUALITY.
|
|
|
|
#
|
|
|
|
# If ' """' is the sole line, prepare to transition to the
|
|
|
|
# CLEANUP_DOCSTRING state or out of it.
|
|
|
|
if line == toggle_docstring_cleanup_line:
|
|
|
|
if state & CLEANUP_DOCSTRING:
|
2011-07-17 05:15:39 +08:00
|
|
|
# Special handling of the trailing blank line right before the '"""'
|
|
|
|
# end docstring marker.
|
|
|
|
new_content.del_blank_line()
|
2011-07-04 03:55:50 +08:00
|
|
|
state ^= CLEANUP_DOCSTRING
|
|
|
|
else:
|
|
|
|
state |= CLEANUP_DOCSTRING
|
2011-07-02 06:14:07 +08:00
|
|
|
|
2011-04-29 05:31:18 +08:00
|
|
|
if state == NORMAL:
|
|
|
|
match = class_pattern.search(line)
|
2011-05-18 06:14:39 +08:00
|
|
|
# Inserts the lldb_iter() definition before the first class definition.
|
2011-04-29 05:31:18 +08:00
|
|
|
if not lldb_iter_defined and match:
|
2011-07-17 05:15:39 +08:00
|
|
|
new_content.add_line(lldb_iter_def)
|
2011-04-29 05:31:18 +08:00
|
|
|
lldb_iter_defined = True
|
2011-05-18 06:14:39 +08:00
|
|
|
|
|
|
|
# If we are at the beginning of the class definitions, prepare to
|
|
|
|
# transition to the DEFINING_ITERATOR/DEFINING_EQUALITY state for the
|
|
|
|
# right class names.
|
2011-04-30 03:03:02 +08:00
|
|
|
if match:
|
2011-04-29 05:31:18 +08:00
|
|
|
cls = match.group(1)
|
2011-04-30 03:03:02 +08:00
|
|
|
if cls in d:
|
|
|
|
# Adding support for iteration for the matched SB class.
|
2011-07-04 03:55:50 +08:00
|
|
|
state |= DEFINING_ITERATOR
|
2011-04-30 03:03:02 +08:00
|
|
|
if cls in e:
|
|
|
|
# Adding support for eq and ne for the matched SB class.
|
2011-07-04 03:55:50 +08:00
|
|
|
state |= DEFINING_EQUALITY
|
|
|
|
|
2011-07-16 04:46:19 +08:00
|
|
|
if (state & DEFINING_ITERATOR) or (state & DEFINING_EQUALITY):
|
2011-04-29 05:31:18 +08:00
|
|
|
match = init_pattern.search(line)
|
|
|
|
if match:
|
|
|
|
# We found the beginning of the __init__ method definition.
|
2011-04-30 03:03:02 +08:00
|
|
|
# This is a good spot to insert the iter and/or eq-ne support.
|
2011-04-29 05:31:18 +08:00
|
|
|
#
|
|
|
|
# But note that SBTarget has two types of iterations.
|
|
|
|
if cls == "SBTarget":
|
2011-07-17 05:15:39 +08:00
|
|
|
new_content.add_line(module_iter % (d[cls]['module']))
|
|
|
|
new_content.add_line(breakpoint_iter % (d[cls]['breakpoint']))
|
2011-04-29 05:31:18 +08:00
|
|
|
else:
|
2011-04-30 03:03:02 +08:00
|
|
|
if (state & DEFINING_ITERATOR):
|
2011-07-17 05:15:39 +08:00
|
|
|
new_content.add_line(iter_def % d[cls])
|
|
|
|
new_content.add_line(len_def % d[cls][0])
|
2011-04-30 03:03:02 +08:00
|
|
|
if (state & DEFINING_EQUALITY):
|
2011-07-17 05:15:39 +08:00
|
|
|
new_content.add_line(eq_def % (cls, list_to_frag(e[cls])))
|
|
|
|
new_content.add_line(ne_def)
|
2011-04-30 03:19:13 +08:00
|
|
|
|
Provide an add-on API to SBValue class by post-processing to provide a way
to iterate through an SBValue instance by treating it as the head of a linked
list. API program must provide two args to the linked_list_iter() method:
the first being the child member name which points to the next item on the list
and the second being a Python function which an SBValue (for the next item) and
returns True if end of list is reached, otherwise it returns False.
For example, suppose we have the following sample program.
#include <stdio.h>
class Task {
public:
int id;
Task *next;
Task(int i, Task *n):
id(i),
next(n)
{}
};
int main (int argc, char const *argv[])
{
Task *task_head = new Task(-1, NULL);
Task *task1 = new Task(1, NULL);
Task *task2 = new Task(2, NULL);
Task *task3 = new Task(3, NULL); // Orphaned.
Task *task4 = new Task(4, NULL);
Task *task5 = new Task(5, NULL);
task_head->next = task1;
task1->next = task2;
task2->next = task4;
task4->next = task5;
int total = 0; // Break at this line
Task *t = task_head;
while (t != NULL) {
if (t->id >= 0)
++total;
t = t->next;
}
printf("We have a total number of %d tasks\n", total);
return 0;
}
The test program produces the following output while exercising the linked_list_iter() SBVAlue API:
task_head:
TypeName -> Task *
ByteSize -> 8
NumChildren -> 2
Value -> 0x0000000106400380
ValueType -> local_variable
Summary -> None
IsPointerType -> True
Location -> 0x00007fff65f06e60
(Task *) next = 0x0000000106400390
(int) id = 1
(Task *) next = 0x00000001064003a0
(Task *) next = 0x00000001064003a0
(int) id = 2
(Task *) next = 0x00000001064003c0
(Task *) next = 0x00000001064003c0
(int) id = 4
(Task *) next = 0x00000001064003d0
(Task *) next = 0x00000001064003d0
(int) id = 5
(Task *) next = 0x0000000000000000
llvm-svn: 135938
2011-07-26 03:32:35 +08:00
|
|
|
# This special purpose iterator is for SBValue only!!!
|
|
|
|
if cls == "SBValue":
|
|
|
|
new_content.add_line(linked_list_iter_def)
|
|
|
|
|
2011-04-30 03:19:13 +08:00
|
|
|
# Next state will be NORMAL.
|
|
|
|
state = NORMAL
|
2011-04-29 05:31:18 +08:00
|
|
|
|
2011-07-16 04:46:19 +08:00
|
|
|
if (state & CLEANUP_DOCSTRING):
|
2011-07-04 03:55:50 +08:00
|
|
|
# Cleanse the lldb.py of the autodoc'ed residues.
|
|
|
|
if c_ifdef_swig in line or c_endif_swig in line:
|
|
|
|
continue
|
2011-07-17 05:15:39 +08:00
|
|
|
# As well as the comment marker line.
|
|
|
|
if c_comment_marker in line:
|
2011-07-04 03:55:50 +08:00
|
|
|
continue
|
2011-07-17 05:15:39 +08:00
|
|
|
|
2011-07-16 04:46:19 +08:00
|
|
|
# Also remove the '\a ' and '\b 'substrings.
|
2011-07-04 03:55:50 +08:00
|
|
|
line = line.replace('\a ', '')
|
2011-07-16 04:46:19 +08:00
|
|
|
line = line.replace('\b ', '')
|
2011-07-04 03:55:50 +08:00
|
|
|
# And the leading '///' substring.
|
|
|
|
doxygen_comment_match = doxygen_comment_start.match(line)
|
|
|
|
if doxygen_comment_match:
|
|
|
|
line = line.replace(doxygen_comment_match.group(1), '', 1)
|
|
|
|
|
2011-07-07 05:55:45 +08:00
|
|
|
line = char_to_str_xform(line)
|
|
|
|
|
2011-07-04 03:55:50 +08:00
|
|
|
# Note that the transition out of CLEANUP_DOCSTRING is handled at the
|
|
|
|
# beginning of this function already.
|
|
|
|
|
2011-07-07 05:55:45 +08:00
|
|
|
# This deals with one-liner docstring, for example, SBThread.GetName:
|
|
|
|
# """GetName(self) -> char""".
|
|
|
|
if one_liner_docstring_pattern.match(line):
|
|
|
|
line = char_to_str_xform(line)
|
|
|
|
|
2011-05-25 06:29:49 +08:00
|
|
|
# Look for 'def IsValid(*args):', and once located, add implementation
|
|
|
|
# of truth value testing for this object by delegation.
|
|
|
|
if isvalid_pattern.search(line):
|
2011-07-17 05:15:39 +08:00
|
|
|
new_content.add_line(nonzero_def)
|
2011-05-25 06:29:49 +08:00
|
|
|
|
2011-05-03 01:53:04 +08:00
|
|
|
# Pass the original line of content to new_content.
|
2011-07-17 05:15:39 +08:00
|
|
|
new_content.add_line(line)
|
|
|
|
|
|
|
|
# We are finished with recording new content.
|
|
|
|
new_content.finish()
|
|
|
|
|
2011-04-29 05:31:18 +08:00
|
|
|
with open(output_name, 'w') as f_out:
|
|
|
|
f_out.write(new_content.getvalue())
|
|
|
|
f_out.write("debugger_unique_id = 0\n")
|
|
|
|
f_out.write("SBDebugger.Initialize()\n")
|