2011-04-29 05:31:18 +08:00
|
|
|
#
|
2011-08-06 04:17:27 +08:00
|
|
|
# modify-python-lldb.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'
|
2011-11-09 07:08:03 +08:00
|
|
|
# feature of swig removes ' *' from it) into 'str' (as a Python str type).
|
2011-07-07 05:55:45 +08:00
|
|
|
#
|
2011-04-29 05:31:18 +08:00
|
|
|
# It also calls SBDebugger.Initialize() to initialize the lldb debugger
|
|
|
|
# subsystem.
|
|
|
|
#
|
|
|
|
|
2015-11-07 09:08:25 +08:00
|
|
|
# System modules
|
2016-09-07 04:57:50 +08:00
|
|
|
import sys
|
|
|
|
import re
|
2015-10-07 05:11:28 +08:00
|
|
|
if sys.version_info.major >= 3:
|
|
|
|
import io as StringIO
|
|
|
|
else:
|
|
|
|
import StringIO
|
2011-04-29 05:31:18 +08:00
|
|
|
|
2015-11-07 09:08:25 +08:00
|
|
|
# import use_lldb_suite so we can find third-party and helper modules
|
|
|
|
import use_lldb_suite
|
|
|
|
|
|
|
|
# Third party modules
|
|
|
|
import six
|
|
|
|
|
|
|
|
# LLDB modules
|
|
|
|
|
2015-11-06 07:57:33 +08:00
|
|
|
if len(sys.argv) != 2:
|
2011-04-29 05:31:18 +08:00
|
|
|
output_name = "./lldb.py"
|
|
|
|
else:
|
|
|
|
output_name = sys.argv[1] + "/lldb.py"
|
|
|
|
|
|
|
|
# print "output_name is '" + output_name + "'"
|
|
|
|
|
2015-11-17 06:40:20 +08:00
|
|
|
#
|
|
|
|
# Version string
|
2016-09-07 04:57:50 +08:00
|
|
|
#
|
2015-11-17 06:40:20 +08:00
|
|
|
version_line = "swig_version = %s"
|
|
|
|
|
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
|
|
|
|
2016-09-07 04:57:50 +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
|
2016-09-07 04:57:50 +08:00
|
|
|
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
|
|
|
#
|
Migrate the in_range(symbol, section) and symbol_iter(module, section) utility functions
from lldbutil.py to the lldb.py proper. The in_range() function becomes a function in
the lldb module. And the symbol_iter() function becomes a method within the SBModule
called symbol_in_section_iter(). Example:
# Iterates the text section and prints each symbols within each sub-section.
for subsec in text_sec:
print INDENT + repr(subsec)
for sym in exe_module.symbol_in_section_iter(subsec):
print INDENT2 + repr(sym)
print INDENT2 + 'symbol type: %s' % symbol_type_to_str(sym.GetType())
might produce this following output:
[0x0000000100001780-0x0000000100001d5c) a.out.__TEXT.__text
id = {0x00000004}, name = 'mask_access(MaskAction, unsigned int)', range = [0x00000001000017c0-0x0000000100001870)
symbol type: code
id = {0x00000008}, name = 'thread_func(void*)', range = [0x0000000100001870-0x00000001000019b0)
symbol type: code
id = {0x0000000c}, name = 'main', range = [0x00000001000019b0-0x0000000100001d5c)
symbol type: code
id = {0x00000023}, name = 'start', address = 0x0000000100001780
symbol type: code
[0x0000000100001d5c-0x0000000100001da4) a.out.__TEXT.__stubs
id = {0x00000024}, name = '__stack_chk_fail', range = [0x0000000100001d5c-0x0000000100001d62)
symbol type: trampoline
id = {0x00000028}, name = 'exit', range = [0x0000000100001d62-0x0000000100001d68)
symbol type: trampoline
id = {0x00000029}, name = 'fflush', range = [0x0000000100001d68-0x0000000100001d6e)
symbol type: trampoline
id = {0x0000002a}, name = 'fgets', range = [0x0000000100001d6e-0x0000000100001d74)
symbol type: trampoline
id = {0x0000002b}, name = 'printf', range = [0x0000000100001d74-0x0000000100001d7a)
symbol type: trampoline
id = {0x0000002c}, name = 'pthread_create', range = [0x0000000100001d7a-0x0000000100001d80)
symbol type: trampoline
id = {0x0000002d}, name = 'pthread_join', range = [0x0000000100001d80-0x0000000100001d86)
symbol type: trampoline
id = {0x0000002e}, name = 'pthread_mutex_lock', range = [0x0000000100001d86-0x0000000100001d8c)
symbol type: trampoline
id = {0x0000002f}, name = 'pthread_mutex_unlock', range = [0x0000000100001d8c-0x0000000100001d92)
symbol type: trampoline
id = {0x00000030}, name = 'rand', range = [0x0000000100001d92-0x0000000100001d98)
symbol type: trampoline
id = {0x00000031}, name = 'strtoul', range = [0x0000000100001d98-0x0000000100001d9e)
symbol type: trampoline
id = {0x00000032}, name = 'usleep', range = [0x0000000100001d9e-0x0000000100001da4)
symbol type: trampoline
[0x0000000100001da4-0x0000000100001e2c) a.out.__TEXT.__stub_helper
[0x0000000100001e2c-0x0000000100001f10) a.out.__TEXT.__cstring
[0x0000000100001f10-0x0000000100001f68) a.out.__TEXT.__unwind_info
[0x0000000100001f68-0x0000000100001ff8) a.out.__TEXT.__eh_frame
llvm-svn: 140830
2011-09-30 08:42:49 +08:00
|
|
|
# lldb_helpers and lldb_iter() should appear before our first SB* class definition.
|
2011-04-29 05:31:18 +08:00
|
|
|
#
|
Migrate the in_range(symbol, section) and symbol_iter(module, section) utility functions
from lldbutil.py to the lldb.py proper. The in_range() function becomes a function in
the lldb module. And the symbol_iter() function becomes a method within the SBModule
called symbol_in_section_iter(). Example:
# Iterates the text section and prints each symbols within each sub-section.
for subsec in text_sec:
print INDENT + repr(subsec)
for sym in exe_module.symbol_in_section_iter(subsec):
print INDENT2 + repr(sym)
print INDENT2 + 'symbol type: %s' % symbol_type_to_str(sym.GetType())
might produce this following output:
[0x0000000100001780-0x0000000100001d5c) a.out.__TEXT.__text
id = {0x00000004}, name = 'mask_access(MaskAction, unsigned int)', range = [0x00000001000017c0-0x0000000100001870)
symbol type: code
id = {0x00000008}, name = 'thread_func(void*)', range = [0x0000000100001870-0x00000001000019b0)
symbol type: code
id = {0x0000000c}, name = 'main', range = [0x00000001000019b0-0x0000000100001d5c)
symbol type: code
id = {0x00000023}, name = 'start', address = 0x0000000100001780
symbol type: code
[0x0000000100001d5c-0x0000000100001da4) a.out.__TEXT.__stubs
id = {0x00000024}, name = '__stack_chk_fail', range = [0x0000000100001d5c-0x0000000100001d62)
symbol type: trampoline
id = {0x00000028}, name = 'exit', range = [0x0000000100001d62-0x0000000100001d68)
symbol type: trampoline
id = {0x00000029}, name = 'fflush', range = [0x0000000100001d68-0x0000000100001d6e)
symbol type: trampoline
id = {0x0000002a}, name = 'fgets', range = [0x0000000100001d6e-0x0000000100001d74)
symbol type: trampoline
id = {0x0000002b}, name = 'printf', range = [0x0000000100001d74-0x0000000100001d7a)
symbol type: trampoline
id = {0x0000002c}, name = 'pthread_create', range = [0x0000000100001d7a-0x0000000100001d80)
symbol type: trampoline
id = {0x0000002d}, name = 'pthread_join', range = [0x0000000100001d80-0x0000000100001d86)
symbol type: trampoline
id = {0x0000002e}, name = 'pthread_mutex_lock', range = [0x0000000100001d86-0x0000000100001d8c)
symbol type: trampoline
id = {0x0000002f}, name = 'pthread_mutex_unlock', range = [0x0000000100001d8c-0x0000000100001d92)
symbol type: trampoline
id = {0x00000030}, name = 'rand', range = [0x0000000100001d92-0x0000000100001d98)
symbol type: trampoline
id = {0x00000031}, name = 'strtoul', range = [0x0000000100001d98-0x0000000100001d9e)
symbol type: trampoline
id = {0x00000032}, name = 'usleep', range = [0x0000000100001d9e-0x0000000100001da4)
symbol type: trampoline
[0x0000000100001da4-0x0000000100001e2c) a.out.__TEXT.__stub_helper
[0x0000000100001e2c-0x0000000100001f10) a.out.__TEXT.__cstring
[0x0000000100001f10-0x0000000100001f68) a.out.__TEXT.__unwind_info
[0x0000000100001f68-0x0000000100001ff8) a.out.__TEXT.__eh_frame
llvm-svn: 140830
2011-09-30 08:42:49 +08:00
|
|
|
lldb_helpers = '''
|
2011-10-04 05:48:40 +08:00
|
|
|
# ==================================
|
|
|
|
# Helper function for SBModule class
|
|
|
|
# ==================================
|
Migrate the in_range(symbol, section) and symbol_iter(module, section) utility functions
from lldbutil.py to the lldb.py proper. The in_range() function becomes a function in
the lldb module. And the symbol_iter() function becomes a method within the SBModule
called symbol_in_section_iter(). Example:
# Iterates the text section and prints each symbols within each sub-section.
for subsec in text_sec:
print INDENT + repr(subsec)
for sym in exe_module.symbol_in_section_iter(subsec):
print INDENT2 + repr(sym)
print INDENT2 + 'symbol type: %s' % symbol_type_to_str(sym.GetType())
might produce this following output:
[0x0000000100001780-0x0000000100001d5c) a.out.__TEXT.__text
id = {0x00000004}, name = 'mask_access(MaskAction, unsigned int)', range = [0x00000001000017c0-0x0000000100001870)
symbol type: code
id = {0x00000008}, name = 'thread_func(void*)', range = [0x0000000100001870-0x00000001000019b0)
symbol type: code
id = {0x0000000c}, name = 'main', range = [0x00000001000019b0-0x0000000100001d5c)
symbol type: code
id = {0x00000023}, name = 'start', address = 0x0000000100001780
symbol type: code
[0x0000000100001d5c-0x0000000100001da4) a.out.__TEXT.__stubs
id = {0x00000024}, name = '__stack_chk_fail', range = [0x0000000100001d5c-0x0000000100001d62)
symbol type: trampoline
id = {0x00000028}, name = 'exit', range = [0x0000000100001d62-0x0000000100001d68)
symbol type: trampoline
id = {0x00000029}, name = 'fflush', range = [0x0000000100001d68-0x0000000100001d6e)
symbol type: trampoline
id = {0x0000002a}, name = 'fgets', range = [0x0000000100001d6e-0x0000000100001d74)
symbol type: trampoline
id = {0x0000002b}, name = 'printf', range = [0x0000000100001d74-0x0000000100001d7a)
symbol type: trampoline
id = {0x0000002c}, name = 'pthread_create', range = [0x0000000100001d7a-0x0000000100001d80)
symbol type: trampoline
id = {0x0000002d}, name = 'pthread_join', range = [0x0000000100001d80-0x0000000100001d86)
symbol type: trampoline
id = {0x0000002e}, name = 'pthread_mutex_lock', range = [0x0000000100001d86-0x0000000100001d8c)
symbol type: trampoline
id = {0x0000002f}, name = 'pthread_mutex_unlock', range = [0x0000000100001d8c-0x0000000100001d92)
symbol type: trampoline
id = {0x00000030}, name = 'rand', range = [0x0000000100001d92-0x0000000100001d98)
symbol type: trampoline
id = {0x00000031}, name = 'strtoul', range = [0x0000000100001d98-0x0000000100001d9e)
symbol type: trampoline
id = {0x00000032}, name = 'usleep', range = [0x0000000100001d9e-0x0000000100001da4)
symbol type: trampoline
[0x0000000100001da4-0x0000000100001e2c) a.out.__TEXT.__stub_helper
[0x0000000100001e2c-0x0000000100001f10) a.out.__TEXT.__cstring
[0x0000000100001f10-0x0000000100001f68) a.out.__TEXT.__unwind_info
[0x0000000100001f68-0x0000000100001ff8) a.out.__TEXT.__eh_frame
llvm-svn: 140830
2011-09-30 08:42:49 +08:00
|
|
|
def in_range(symbol, section):
|
2011-09-30 08:49:02 +08:00
|
|
|
"""Test whether a symbol is within the range of a section."""
|
Migrate the in_range(symbol, section) and symbol_iter(module, section) utility functions
from lldbutil.py to the lldb.py proper. The in_range() function becomes a function in
the lldb module. And the symbol_iter() function becomes a method within the SBModule
called symbol_in_section_iter(). Example:
# Iterates the text section and prints each symbols within each sub-section.
for subsec in text_sec:
print INDENT + repr(subsec)
for sym in exe_module.symbol_in_section_iter(subsec):
print INDENT2 + repr(sym)
print INDENT2 + 'symbol type: %s' % symbol_type_to_str(sym.GetType())
might produce this following output:
[0x0000000100001780-0x0000000100001d5c) a.out.__TEXT.__text
id = {0x00000004}, name = 'mask_access(MaskAction, unsigned int)', range = [0x00000001000017c0-0x0000000100001870)
symbol type: code
id = {0x00000008}, name = 'thread_func(void*)', range = [0x0000000100001870-0x00000001000019b0)
symbol type: code
id = {0x0000000c}, name = 'main', range = [0x00000001000019b0-0x0000000100001d5c)
symbol type: code
id = {0x00000023}, name = 'start', address = 0x0000000100001780
symbol type: code
[0x0000000100001d5c-0x0000000100001da4) a.out.__TEXT.__stubs
id = {0x00000024}, name = '__stack_chk_fail', range = [0x0000000100001d5c-0x0000000100001d62)
symbol type: trampoline
id = {0x00000028}, name = 'exit', range = [0x0000000100001d62-0x0000000100001d68)
symbol type: trampoline
id = {0x00000029}, name = 'fflush', range = [0x0000000100001d68-0x0000000100001d6e)
symbol type: trampoline
id = {0x0000002a}, name = 'fgets', range = [0x0000000100001d6e-0x0000000100001d74)
symbol type: trampoline
id = {0x0000002b}, name = 'printf', range = [0x0000000100001d74-0x0000000100001d7a)
symbol type: trampoline
id = {0x0000002c}, name = 'pthread_create', range = [0x0000000100001d7a-0x0000000100001d80)
symbol type: trampoline
id = {0x0000002d}, name = 'pthread_join', range = [0x0000000100001d80-0x0000000100001d86)
symbol type: trampoline
id = {0x0000002e}, name = 'pthread_mutex_lock', range = [0x0000000100001d86-0x0000000100001d8c)
symbol type: trampoline
id = {0x0000002f}, name = 'pthread_mutex_unlock', range = [0x0000000100001d8c-0x0000000100001d92)
symbol type: trampoline
id = {0x00000030}, name = 'rand', range = [0x0000000100001d92-0x0000000100001d98)
symbol type: trampoline
id = {0x00000031}, name = 'strtoul', range = [0x0000000100001d98-0x0000000100001d9e)
symbol type: trampoline
id = {0x00000032}, name = 'usleep', range = [0x0000000100001d9e-0x0000000100001da4)
symbol type: trampoline
[0x0000000100001da4-0x0000000100001e2c) a.out.__TEXT.__stub_helper
[0x0000000100001e2c-0x0000000100001f10) a.out.__TEXT.__cstring
[0x0000000100001f10-0x0000000100001f68) a.out.__TEXT.__unwind_info
[0x0000000100001f68-0x0000000100001ff8) a.out.__TEXT.__eh_frame
llvm-svn: 140830
2011-09-30 08:42:49 +08:00
|
|
|
symSA = symbol.GetStartAddress().GetFileAddress()
|
|
|
|
symEA = symbol.GetEndAddress().GetFileAddress()
|
|
|
|
secSA = section.GetFileAddress()
|
|
|
|
secEA = secSA + section.GetByteSize()
|
|
|
|
|
|
|
|
if symEA != LLDB_INVALID_ADDRESS:
|
|
|
|
if secSA <= symSA and symEA <= secEA:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
if secSA <= symSA and symSA < secEA:
|
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
'''
|
|
|
|
|
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 = '''
|
2011-07-27 04:57:10 +08:00
|
|
|
def __eol_test__(val):
|
|
|
|
"""Default function for end of list test takes an SBValue object.
|
|
|
|
|
|
|
|
Return True if val is invalid or it corresponds to a null pointer.
|
|
|
|
Otherwise, return False.
|
|
|
|
"""
|
2011-08-11 08:49:03 +08:00
|
|
|
if not val or val.GetValueAsUnsigned() == 0:
|
2011-07-27 04:57:10 +08:00
|
|
|
return True
|
|
|
|
else:
|
|
|
|
return False
|
|
|
|
|
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
|
|
|
# ==================================================
|
|
|
|
# Iterator for lldb.SBValue treated as a linked list
|
|
|
|
# ==================================================
|
2011-07-27 04:57:10 +08:00
|
|
|
def linked_list_iter(self, next_item_name, end_of_list_test=__eol_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
|
|
|
|
2011-08-11 09:19:46 +08:00
|
|
|
linked_list_iter() also detects infinite loop and bails out early.
|
|
|
|
|
2011-07-27 04:57:10 +08:00
|
|
|
The end_of_list_test arg, if omitted, defaults to the __eol_test__
|
|
|
|
function above.
|
2011-07-27 04:20:13 +08:00
|
|
|
|
2011-07-27 04:57:10 +08:00
|
|
|
For example,
|
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
|
|
|
|
|
|
|
# Get Frame #0.
|
|
|
|
...
|
|
|
|
|
|
|
|
# Get variable 'task_head'.
|
|
|
|
task_head = frame0.FindVariable('task_head')
|
|
|
|
...
|
|
|
|
|
2011-07-27 04:57:10 +08:00
|
|
|
for t in task_head.linked_list_iter('next'):
|
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
|
|
|
print t
|
|
|
|
"""
|
2011-08-11 08:49:03 +08:00
|
|
|
if end_of_list_test(self):
|
|
|
|
return
|
|
|
|
item = self
|
2011-08-11 09:19:46 +08:00
|
|
|
visited = set()
|
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
|
|
|
try:
|
2011-08-11 09:19:46 +08:00
|
|
|
while not end_of_list_test(item) and not item.GetValueAsUnsigned() in visited:
|
|
|
|
visited.add(item.GetValueAsUnsigned())
|
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
|
|
|
yield item
|
|
|
|
# Prepare for the next iteration.
|
|
|
|
item = item.GetChildMemberWithName(next_item_name)
|
|
|
|
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-10-14 08:42:25 +08:00
|
|
|
watchpoint_iter = " def watchpoint_iter(self): return lldb_iter(self, '%s', '%s')"
|
2011-09-24 12:51:43 +08:00
|
|
|
section_iter = " def section_iter(self): return lldb_iter(self, '%s', '%s')"
|
2012-03-17 05:55:42 +08:00
|
|
|
compile_unit_iter = " def compile_unit_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();
|
2015-11-07 09:08:25 +08:00
|
|
|
# Note that Python 2 uses __nonzero__(), whereas Python 3 uses __bool__()
|
2011-05-18 06:14:39 +08:00
|
|
|
# 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.
|
2015-11-07 09:08:25 +08:00
|
|
|
|
|
|
|
if six.PY2:
|
|
|
|
nonzero_def = " def __nonzero__(self): return self.IsValid()"
|
|
|
|
else:
|
|
|
|
nonzero_def = " def __bool__(self): return self.IsValid()"
|
2011-05-18 06:14:39 +08:00
|
|
|
|
Migrate the in_range(symbol, section) and symbol_iter(module, section) utility functions
from lldbutil.py to the lldb.py proper. The in_range() function becomes a function in
the lldb module. And the symbol_iter() function becomes a method within the SBModule
called symbol_in_section_iter(). Example:
# Iterates the text section and prints each symbols within each sub-section.
for subsec in text_sec:
print INDENT + repr(subsec)
for sym in exe_module.symbol_in_section_iter(subsec):
print INDENT2 + repr(sym)
print INDENT2 + 'symbol type: %s' % symbol_type_to_str(sym.GetType())
might produce this following output:
[0x0000000100001780-0x0000000100001d5c) a.out.__TEXT.__text
id = {0x00000004}, name = 'mask_access(MaskAction, unsigned int)', range = [0x00000001000017c0-0x0000000100001870)
symbol type: code
id = {0x00000008}, name = 'thread_func(void*)', range = [0x0000000100001870-0x00000001000019b0)
symbol type: code
id = {0x0000000c}, name = 'main', range = [0x00000001000019b0-0x0000000100001d5c)
symbol type: code
id = {0x00000023}, name = 'start', address = 0x0000000100001780
symbol type: code
[0x0000000100001d5c-0x0000000100001da4) a.out.__TEXT.__stubs
id = {0x00000024}, name = '__stack_chk_fail', range = [0x0000000100001d5c-0x0000000100001d62)
symbol type: trampoline
id = {0x00000028}, name = 'exit', range = [0x0000000100001d62-0x0000000100001d68)
symbol type: trampoline
id = {0x00000029}, name = 'fflush', range = [0x0000000100001d68-0x0000000100001d6e)
symbol type: trampoline
id = {0x0000002a}, name = 'fgets', range = [0x0000000100001d6e-0x0000000100001d74)
symbol type: trampoline
id = {0x0000002b}, name = 'printf', range = [0x0000000100001d74-0x0000000100001d7a)
symbol type: trampoline
id = {0x0000002c}, name = 'pthread_create', range = [0x0000000100001d7a-0x0000000100001d80)
symbol type: trampoline
id = {0x0000002d}, name = 'pthread_join', range = [0x0000000100001d80-0x0000000100001d86)
symbol type: trampoline
id = {0x0000002e}, name = 'pthread_mutex_lock', range = [0x0000000100001d86-0x0000000100001d8c)
symbol type: trampoline
id = {0x0000002f}, name = 'pthread_mutex_unlock', range = [0x0000000100001d8c-0x0000000100001d92)
symbol type: trampoline
id = {0x00000030}, name = 'rand', range = [0x0000000100001d92-0x0000000100001d98)
symbol type: trampoline
id = {0x00000031}, name = 'strtoul', range = [0x0000000100001d98-0x0000000100001d9e)
symbol type: trampoline
id = {0x00000032}, name = 'usleep', range = [0x0000000100001d9e-0x0000000100001da4)
symbol type: trampoline
[0x0000000100001da4-0x0000000100001e2c) a.out.__TEXT.__stub_helper
[0x0000000100001e2c-0x0000000100001f10) a.out.__TEXT.__cstring
[0x0000000100001f10-0x0000000100001f68) a.out.__TEXT.__unwind_info
[0x0000000100001f68-0x0000000100001ff8) a.out.__TEXT.__eh_frame
llvm-svn: 140830
2011-09-30 08:42:49 +08:00
|
|
|
# A convenience iterator for SBSymbol!
|
|
|
|
symbol_in_section_iter_def = '''
|
|
|
|
def symbol_in_section_iter(self, section):
|
|
|
|
"""Given a module and its contained section, returns an iterator on the
|
|
|
|
symbols within the section."""
|
|
|
|
for sym in self:
|
|
|
|
if in_range(sym, section):
|
|
|
|
yield sym
|
|
|
|
'''
|
|
|
|
|
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
|
|
|
#
|
2016-09-07 04:57:50 +08:00
|
|
|
d = {'SBBreakpoint': ('GetNumLocations', 'GetLocationAtIndex'),
|
|
|
|
'SBCompileUnit': ('GetNumLineEntries', 'GetLineEntryAtIndex'),
|
|
|
|
'SBDebugger': ('GetNumTargets', 'GetTargetAtIndex'),
|
|
|
|
'SBModule': ('GetNumSymbols', 'GetSymbolAtIndex'),
|
|
|
|
'SBProcess': ('GetNumThreads', 'GetThreadAtIndex'),
|
|
|
|
'SBSection': ('GetNumSubSections', 'GetSubSectionAtIndex'),
|
|
|
|
'SBThread': ('GetNumFrames', 'GetFrameAtIndex'),
|
|
|
|
|
|
|
|
'SBInstructionList': ('GetSize', 'GetInstructionAtIndex'),
|
|
|
|
'SBStringList': ('GetSize', 'GetStringAtIndex',),
|
|
|
|
'SBSymbolContextList': ('GetSize', 'GetContextAtIndex'),
|
|
|
|
'SBTypeList': ('GetSize', 'GetTypeAtIndex'),
|
|
|
|
'SBValueList': ('GetSize', 'GetValueAtIndex'),
|
|
|
|
|
|
|
|
'SBType': ('GetNumberChildren', 'GetChildAtIndex'),
|
|
|
|
'SBValue': ('GetNumChildren', 'GetChildAtIndex'),
|
|
|
|
|
|
|
|
# SBTarget needs special processing, see below.
|
|
|
|
'SBTarget': {'module': ('GetNumModules', 'GetModuleAtIndex'),
|
|
|
|
'breakpoint': ('GetNumBreakpoints', 'GetBreakpointAtIndex'),
|
|
|
|
'watchpoint': ('GetNumWatchpoints', 'GetWatchpointAtIndex')
|
|
|
|
},
|
|
|
|
|
|
|
|
# SBModule has an additional section_iter(), see below.
|
|
|
|
'SBModule-section': ('GetNumSections', 'GetSectionAtIndex'),
|
|
|
|
# And compile_unit_iter().
|
|
|
|
'SBModule-compile-unit': ('GetNumCompileUnits', 'GetCompileUnitAtIndex'),
|
|
|
|
# As well as symbol_in_section_iter().
|
|
|
|
'SBModule-symbol-in-section': symbol_in_section_iter_def
|
|
|
|
}
|
2011-04-29 05:31:18 +08:00
|
|
|
|
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
|
|
|
#
|
2016-09-07 04:57:50 +08:00
|
|
|
e = {'SBAddress': ['GetFileAddress', 'GetModule'],
|
|
|
|
'SBBreakpoint': ['GetID'],
|
|
|
|
'SBWatchpoint': ['GetID'],
|
|
|
|
'SBFileSpec': ['GetFilename', 'GetDirectory'],
|
|
|
|
'SBModule': ['GetFileSpec', 'GetUUIDString'],
|
|
|
|
'SBType': ['GetByteSize', 'GetName']
|
|
|
|
}
|
|
|
|
|
2011-05-03 03:05:52 +08:00
|
|
|
|
|
|
|
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
|
|
|
|
2016-09-07 04:57:50 +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."""
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2011-07-17 05:15:39 +08:00
|
|
|
def __init__(self):
|
|
|
|
StringIO.StringIO.__init__(self)
|
|
|
|
self.prev_line = None
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2011-07-17 05:15:39 +08:00
|
|
|
def add_line(self, a_line):
|
|
|
|
"""Add a line to the content, if there is a previous line, commit it."""
|
2016-09-07 04:57:50 +08:00
|
|
|
if self.prev_line is not None:
|
2015-10-07 05:11:28 +08:00
|
|
|
self.write(self.prev_line + "\n")
|
2011-07-17 05:15:39 +08:00
|
|
|
self.prev_line = a_line
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2011-07-17 05:15:39 +08:00
|
|
|
def del_line(self):
|
|
|
|
"""Forget about the previous line, do not commit it."""
|
|
|
|
self.prev_line = None
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2011-07-17 05:15:39 +08:00
|
|
|
def del_blank_line(self):
|
|
|
|
"""Forget about the previous line if it is a blank line."""
|
2016-09-07 04:57:50 +08:00
|
|
|
if self.prev_line is not None and not self.prev_line.strip():
|
2011-07-17 05:15:39 +08:00
|
|
|
self.prev_line = None
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2011-07-17 05:15:39 +08:00
|
|
|
def finish(self):
|
|
|
|
"""Call this when you're finished with populating content."""
|
2016-09-07 04:57:50 +08:00
|
|
|
if self.prev_line is not None:
|
2015-10-07 05:11:28 +08:00
|
|
|
self.write(self.prev_line + "\n")
|
2011-07-17 05:15:39 +08:00
|
|
|
self.prev_line = None
|
|
|
|
|
2016-09-07 04:57:50 +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()
|
|
|
|
|
2015-11-17 06:40:20 +08:00
|
|
|
# The pattern for recognizing the SWIG Version string
|
|
|
|
version_pattern = re.compile("^# Version:? (.*)$")
|
|
|
|
|
2011-04-29 05:31:18 +08:00
|
|
|
# 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.
|
2011-08-05 09:35:49 +08:00
|
|
|
init_pattern = re.compile("^ def __init__\(self.*\):")
|
2011-04-29 05:31:18 +08:00
|
|
|
|
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.
|
2015-11-17 06:40:20 +08:00
|
|
|
EXPECTING_VERSION = 0
|
|
|
|
NORMAL = 1
|
|
|
|
DEFINING_ITERATOR = 2
|
|
|
|
DEFINING_EQUALITY = 4
|
|
|
|
CLEANUP_DOCSTRING = 8
|
2011-04-29 05:31:18 +08:00
|
|
|
|
|
|
|
# The lldb_iter_def only needs to be inserted once.
|
2016-09-07 04:57:50 +08:00
|
|
|
lldb_iter_defined = False
|
2011-04-29 05:31:18 +08:00
|
|
|
|
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().
|
2015-11-17 06:40:20 +08:00
|
|
|
state = EXPECTING_VERSION
|
|
|
|
|
|
|
|
swig_version_tuple = None
|
2011-04-29 05:31:18 +08:00
|
|
|
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.
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2011-07-04 03:55:50 +08:00
|
|
|
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
|
|
|
|
2015-11-17 06:40:20 +08:00
|
|
|
if state == EXPECTING_VERSION:
|
|
|
|
# We haven't read the version yet, read it now.
|
|
|
|
if swig_version_tuple is None:
|
|
|
|
match = version_pattern.search(line)
|
|
|
|
if match:
|
|
|
|
v = match.group(1)
|
|
|
|
swig_version_tuple = tuple(map(int, (v.split("."))))
|
|
|
|
elif not line.startswith('#'):
|
2016-09-07 04:57:50 +08:00
|
|
|
# This is the first non-comment line after the header. Inject the
|
|
|
|
# version
|
2015-11-17 06:40:20 +08:00
|
|
|
new_line = version_line % str(swig_version_tuple)
|
|
|
|
new_content.add_line(new_line)
|
|
|
|
state = NORMAL
|
|
|
|
|
2011-04-29 05:31:18 +08:00
|
|
|
if state == NORMAL:
|
|
|
|
match = class_pattern.search(line)
|
Migrate the in_range(symbol, section) and symbol_iter(module, section) utility functions
from lldbutil.py to the lldb.py proper. The in_range() function becomes a function in
the lldb module. And the symbol_iter() function becomes a method within the SBModule
called symbol_in_section_iter(). Example:
# Iterates the text section and prints each symbols within each sub-section.
for subsec in text_sec:
print INDENT + repr(subsec)
for sym in exe_module.symbol_in_section_iter(subsec):
print INDENT2 + repr(sym)
print INDENT2 + 'symbol type: %s' % symbol_type_to_str(sym.GetType())
might produce this following output:
[0x0000000100001780-0x0000000100001d5c) a.out.__TEXT.__text
id = {0x00000004}, name = 'mask_access(MaskAction, unsigned int)', range = [0x00000001000017c0-0x0000000100001870)
symbol type: code
id = {0x00000008}, name = 'thread_func(void*)', range = [0x0000000100001870-0x00000001000019b0)
symbol type: code
id = {0x0000000c}, name = 'main', range = [0x00000001000019b0-0x0000000100001d5c)
symbol type: code
id = {0x00000023}, name = 'start', address = 0x0000000100001780
symbol type: code
[0x0000000100001d5c-0x0000000100001da4) a.out.__TEXT.__stubs
id = {0x00000024}, name = '__stack_chk_fail', range = [0x0000000100001d5c-0x0000000100001d62)
symbol type: trampoline
id = {0x00000028}, name = 'exit', range = [0x0000000100001d62-0x0000000100001d68)
symbol type: trampoline
id = {0x00000029}, name = 'fflush', range = [0x0000000100001d68-0x0000000100001d6e)
symbol type: trampoline
id = {0x0000002a}, name = 'fgets', range = [0x0000000100001d6e-0x0000000100001d74)
symbol type: trampoline
id = {0x0000002b}, name = 'printf', range = [0x0000000100001d74-0x0000000100001d7a)
symbol type: trampoline
id = {0x0000002c}, name = 'pthread_create', range = [0x0000000100001d7a-0x0000000100001d80)
symbol type: trampoline
id = {0x0000002d}, name = 'pthread_join', range = [0x0000000100001d80-0x0000000100001d86)
symbol type: trampoline
id = {0x0000002e}, name = 'pthread_mutex_lock', range = [0x0000000100001d86-0x0000000100001d8c)
symbol type: trampoline
id = {0x0000002f}, name = 'pthread_mutex_unlock', range = [0x0000000100001d8c-0x0000000100001d92)
symbol type: trampoline
id = {0x00000030}, name = 'rand', range = [0x0000000100001d92-0x0000000100001d98)
symbol type: trampoline
id = {0x00000031}, name = 'strtoul', range = [0x0000000100001d98-0x0000000100001d9e)
symbol type: trampoline
id = {0x00000032}, name = 'usleep', range = [0x0000000100001d9e-0x0000000100001da4)
symbol type: trampoline
[0x0000000100001da4-0x0000000100001e2c) a.out.__TEXT.__stub_helper
[0x0000000100001e2c-0x0000000100001f10) a.out.__TEXT.__cstring
[0x0000000100001f10-0x0000000100001f68) a.out.__TEXT.__unwind_info
[0x0000000100001f68-0x0000000100001ff8) a.out.__TEXT.__eh_frame
llvm-svn: 140830
2011-09-30 08:42:49 +08:00
|
|
|
# Inserts lldb_helpers and the lldb_iter() definition before the first
|
|
|
|
# class definition.
|
2011-04-29 05:31:18 +08:00
|
|
|
if not lldb_iter_defined and match:
|
Migrate the in_range(symbol, section) and symbol_iter(module, section) utility functions
from lldbutil.py to the lldb.py proper. The in_range() function becomes a function in
the lldb module. And the symbol_iter() function becomes a method within the SBModule
called symbol_in_section_iter(). Example:
# Iterates the text section and prints each symbols within each sub-section.
for subsec in text_sec:
print INDENT + repr(subsec)
for sym in exe_module.symbol_in_section_iter(subsec):
print INDENT2 + repr(sym)
print INDENT2 + 'symbol type: %s' % symbol_type_to_str(sym.GetType())
might produce this following output:
[0x0000000100001780-0x0000000100001d5c) a.out.__TEXT.__text
id = {0x00000004}, name = 'mask_access(MaskAction, unsigned int)', range = [0x00000001000017c0-0x0000000100001870)
symbol type: code
id = {0x00000008}, name = 'thread_func(void*)', range = [0x0000000100001870-0x00000001000019b0)
symbol type: code
id = {0x0000000c}, name = 'main', range = [0x00000001000019b0-0x0000000100001d5c)
symbol type: code
id = {0x00000023}, name = 'start', address = 0x0000000100001780
symbol type: code
[0x0000000100001d5c-0x0000000100001da4) a.out.__TEXT.__stubs
id = {0x00000024}, name = '__stack_chk_fail', range = [0x0000000100001d5c-0x0000000100001d62)
symbol type: trampoline
id = {0x00000028}, name = 'exit', range = [0x0000000100001d62-0x0000000100001d68)
symbol type: trampoline
id = {0x00000029}, name = 'fflush', range = [0x0000000100001d68-0x0000000100001d6e)
symbol type: trampoline
id = {0x0000002a}, name = 'fgets', range = [0x0000000100001d6e-0x0000000100001d74)
symbol type: trampoline
id = {0x0000002b}, name = 'printf', range = [0x0000000100001d74-0x0000000100001d7a)
symbol type: trampoline
id = {0x0000002c}, name = 'pthread_create', range = [0x0000000100001d7a-0x0000000100001d80)
symbol type: trampoline
id = {0x0000002d}, name = 'pthread_join', range = [0x0000000100001d80-0x0000000100001d86)
symbol type: trampoline
id = {0x0000002e}, name = 'pthread_mutex_lock', range = [0x0000000100001d86-0x0000000100001d8c)
symbol type: trampoline
id = {0x0000002f}, name = 'pthread_mutex_unlock', range = [0x0000000100001d8c-0x0000000100001d92)
symbol type: trampoline
id = {0x00000030}, name = 'rand', range = [0x0000000100001d92-0x0000000100001d98)
symbol type: trampoline
id = {0x00000031}, name = 'strtoul', range = [0x0000000100001d98-0x0000000100001d9e)
symbol type: trampoline
id = {0x00000032}, name = 'usleep', range = [0x0000000100001d9e-0x0000000100001da4)
symbol type: trampoline
[0x0000000100001da4-0x0000000100001e2c) a.out.__TEXT.__stub_helper
[0x0000000100001e2c-0x0000000100001f10) a.out.__TEXT.__cstring
[0x0000000100001f10-0x0000000100001f68) a.out.__TEXT.__unwind_info
[0x0000000100001f68-0x0000000100001ff8) a.out.__TEXT.__eh_frame
llvm-svn: 140830
2011-09-30 08:42:49 +08:00
|
|
|
new_content.add_line(lldb_helpers)
|
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
|
|
|
#
|
2011-09-27 09:19:20 +08:00
|
|
|
# But note that SBTarget has three types of iterations.
|
2011-04-29 05:31:18 +08:00
|
|
|
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-10-14 08:42:25 +08:00
|
|
|
new_content.add_line(watchpoint_iter % (d[cls]['watchpoint']))
|
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
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
# SBModule has extra SBSection, SBCompileUnit iterators and
|
|
|
|
# symbol_in_section_iter()!
|
2011-09-24 12:51:43 +08:00
|
|
|
if cls == "SBModule":
|
2016-09-07 04:57:50 +08:00
|
|
|
new_content.add_line(section_iter % d[cls + '-section'])
|
|
|
|
new_content.add_line(compile_unit_iter %
|
|
|
|
d[cls + '-compile-unit'])
|
|
|
|
new_content.add_line(d[cls + '-symbol-in-section'])
|
2012-11-02 02:55:16 +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())
|
2012-12-11 03:18:23 +08:00
|
|
|
f_out.write('''debugger_unique_id = 0
|
|
|
|
SBDebugger.Initialize()
|
|
|
|
debugger = None
|
|
|
|
target = SBTarget()
|
|
|
|
process = SBProcess()
|
|
|
|
thread = SBThread()
|
|
|
|
frame = SBFrame()''')
|