*** This commit represents a complete reformatting of the LLDB source code

*** to conform to clang-format’s LLVM style.  This kind of mass change has
*** two obvious implications:

Firstly, merging this particular commit into a downstream fork may be a huge
effort.  Alternatively, it may be worth merging all changes up to this commit,
performing the same reformatting operation locally, and then discarding the
merge for this particular commit.  The commands used to accomplish this
reformatting were as follows (with current working directory as the root of
the repository):

    find . \( -iname "*.c" -or -iname "*.cpp" -or -iname "*.h" -or -iname "*.mm" \) -exec clang-format -i {} +
    find . -iname "*.py" -exec autopep8 --in-place --aggressive --aggressive {} + ;

The version of clang-format used was 3.9.0, and autopep8 was 1.2.4.

Secondly, “blame” style tools will generally point to this commit instead of
a meaningful prior commit.  There are alternatives available that will attempt
to look through this change and find the appropriate prior commit.  YMMV.

llvm-svn: 280751
This commit is contained in:
Kate Stone 2016-09-06 20:57:50 +00:00
parent d5aa733769
commit b9c1b51e45
2780 changed files with 556690 additions and 597060 deletions

View File

@ -2,6 +2,7 @@
import StringIO import StringIO
def binary(n, width=None): def binary(n, width=None):
""" """
Return a list of (0|1)'s for the binary representation of n where n >= 0. Return a list of (0|1)'s for the binary representation of n where n >= 0.
@ -12,7 +13,7 @@ def binary(n, width=None):
if width and width <= 0: if width and width <= 0:
width = None width = None
while n > 0: while n > 0:
l.append(1 if n&1 else 0) l.append(1 if n & 1 else 0)
n = n >> 1 n = n >> 1
if width: if width:
@ -22,14 +23,15 @@ def binary(n, width=None):
l.reverse() l.reverse()
return l return l
def twos_complement(n, width): def twos_complement(n, width):
""" """
Return a list of (0|1)'s for the binary representation of a width-bit two's Return a list of (0|1)'s for the binary representation of a width-bit two's
complement numeral system of an integer n which may be negative. complement numeral system of an integer n which may be negative.
""" """
val = 2**(width-1) val = 2**(width - 1)
if n >= 0: if n >= 0:
if n > (val-1): if n > (val - 1):
return None return None
# It is safe to represent n with width-bits. # It is safe to represent n with width-bits.
return binary(n, width) return binary(n, width)
@ -38,7 +40,7 @@ def twos_complement(n, width):
if abs(n) > val: if abs(n) > val:
return None return None
# It is safe to represent n (a negative int) with width-bits. # It is safe to represent n (a negative int) with width-bits.
return binary(val*2 - abs(n)) return binary(val * 2 - abs(n))
# print binary(0xABCD) # print binary(0xABCD)
# [1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1] # [1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1]
@ -53,12 +55,13 @@ def twos_complement(n, width):
# print twos_complement(-5, 64) # print twos_complement(-5, 64)
# [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1] # [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1]
def positions(width): def positions(width):
"""Helper function returning a list describing the bit positions. """Helper function returning a list describing the bit positions.
Bit positions greater than 99 are truncated to 2 digits, for example, Bit positions greater than 99 are truncated to 2 digits, for example,
100 -> 00 and 127 -> 27.""" 100 -> 00 and 127 -> 27."""
return ['{0:2}'.format(i)[-2:] for i in reversed(range(width))] return ['{0:2}'.format(i)[-2:] for i in reversed(range(width))]
def utob(debugger, command_line, result, dict): def utob(debugger, command_line, result, dict):
"""Convert the unsigned integer to print its binary representation. """Convert the unsigned integer to print its binary representation.
@ -88,9 +91,10 @@ def utob(debugger, command_line, result, dict):
return return
if verbose and width > 0: if verbose and width > 0:
pos = positions(width) pos = positions(width)
print ' '+' '.join(pos) print ' ' + ' '.join(pos)
print ' %s' % str(bits) print ' %s' % str(bits)
def itob(debugger, command_line, result, dict): def itob(debugger, command_line, result, dict):
"""Convert the integer to print its two's complement representation. """Convert the integer to print its two's complement representation.
args[0] (mandatory) is the integer to be converted args[0] (mandatory) is the integer to be converted
@ -117,6 +121,5 @@ def itob(debugger, command_line, result, dict):
return return
if verbose and width > 0: if verbose and width > 0:
pos = positions(width) pos = positions(width)
print ' '+' '.join(pos) print ' ' + ' '.join(pos)
print ' %s' % str(bits) print ' %s' % str(bits)

View File

@ -1,31 +1,38 @@
import sys,os,lldb import sys
import os
import lldb
def check_has_dir_in_path(dirname): def check_has_dir_in_path(dirname):
return sys.path.__contains__(dirname); return sys.path.__contains__(dirname)
def ensure_has_dir_in_path(dirname): def ensure_has_dir_in_path(dirname):
dirname = os.path.abspath(dirname) dirname = os.path.abspath(dirname)
if not (check_has_dir_in_path(dirname)): if not (check_has_dir_in_path(dirname)):
sys.path.append(dirname); sys.path.append(dirname)
def do_import(debugger, modname):
if (len(modname) > 4 and modname[-4:] == '.pyc'):
modname = modname[:-4]
if (len(modname) > 3 and modname[-3:] == '.py'):
modname = modname[:-3]
debugger.HandleCommand("script import " + modname)
def do_import(debugger,modname):
if (len(modname) > 4 and modname[-4:] == '.pyc'):
modname = modname[:-4]
if (len(modname) > 3 and modname[-3:] == '.py'):
modname = modname[:-3]
debugger.HandleCommand("script import " + modname)
def pyimport_cmd(debugger, args, result, dict): def pyimport_cmd(debugger, args, result, dict):
"""Import a Python module given its full path""" """Import a Python module given its full path"""
print 'WARNING: obsolete feature - use native command "command script import"' print 'WARNING: obsolete feature - use native command "command script import"'
if args == "": if args == "":
return "no module path given"; return "no module path given"
if not (os.sep in args): if not (os.sep in args):
modname = args modname = args
ensure_has_dir_in_path('.') ensure_has_dir_in_path('.')
else: else:
endofdir = args.rfind(os.sep) endofdir = args.rfind(os.sep)
modname = args[endofdir+1:] modname = args[endofdir + 1:]
args = args[0:endofdir] args = args[0:endofdir]
ensure_has_dir_in_path(args) ensure_has_dir_in_path(args)
do_import(debugger,modname) do_import(debugger, modname)
return None return None

View File

@ -1,8 +1,12 @@
"""Utility for changing directories and execution of commands in a subshell.""" """Utility for changing directories and execution of commands in a subshell."""
import os, shlex, subprocess import os
import shlex
import subprocess
# Store the previous working directory for the 'cd -' command. # Store the previous working directory for the 'cd -' command.
class Holder: class Holder:
"""Holds the _prev_dir_ class attribute for chdir() function.""" """Holds the _prev_dir_ class attribute for chdir() function."""
_prev_dir_ = None _prev_dir_ = None
@ -15,6 +19,7 @@ class Holder:
def swap(cls, dir): def swap(cls, dir):
cls._prev_dir_ = dir cls._prev_dir_ = dir
def chdir(debugger, args, result, dict): def chdir(debugger, args, result, dict):
"""Change the working directory, or cd to ${HOME}. """Change the working directory, or cd to ${HOME}.
You can also issue 'cd -' to change to the previous working directory.""" You can also issue 'cd -' to change to the previous working directory."""
@ -33,10 +38,14 @@ def chdir(debugger, args, result, dict):
os.chdir(new_dir) os.chdir(new_dir)
print "Current working directory: %s" % os.getcwd() print "Current working directory: %s" % os.getcwd()
def system(debugger, command_line, result, dict): def system(debugger, command_line, result, dict):
"""Execute the command (a string) in a subshell.""" """Execute the command (a string) in a subshell."""
args = shlex.split(command_line) args = shlex.split(command_line)
process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) process = subprocess.Popen(
args,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
output, error = process.communicate() output, error = process.communicate()
retcode = process.poll() retcode = process.poll()
if output and error: if output and error:

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -19,11 +19,11 @@
#include "LLDB/SBDebugger.h" #include "LLDB/SBDebugger.h"
#include "LLDB/SBFunction.h" #include "LLDB/SBFunction.h"
#include "LLDB/SBModule.h" #include "LLDB/SBModule.h"
#include "LLDB/SBProcess.h"
#include "LLDB/SBStream.h" #include "LLDB/SBStream.h"
#include "LLDB/SBSymbol.h" #include "LLDB/SBSymbol.h"
#include "LLDB/SBTarget.h" #include "LLDB/SBTarget.h"
#include "LLDB/SBThread.h" #include "LLDB/SBThread.h"
#include "LLDB/SBProcess.h"
#endif #endif
#include <string> #include <string>
@ -34,9 +34,9 @@ using namespace lldb;
// This quick sample code shows how to create a debugger instance and // This quick sample code shows how to create a debugger instance and
// create an executable target without adding dependent shared // create an executable target without adding dependent shared
// libraries. It will then set a regular expression breakpoint to get // libraries. It will then set a regular expression breakpoint to get
// breakpoint locations for all functions in the module, and use the // breakpoint locations for all functions in the module, and use the
// locations to extract the symbol context for each location. Then it // locations to extract the symbol context for each location. Then it
// dumps all // information about the function: its name, file address // dumps all // information about the function: its name, file address
// range, the return type (if any), and all argument types. // range, the return type (if any), and all argument types.
// //
// To build the program, type (while in this directory): // To build the program, type (while in this directory):
@ -46,319 +46,301 @@ using namespace lldb;
// then to run this on MacOSX, specify the path to your LLDB.framework // then to run this on MacOSX, specify the path to your LLDB.framework
// library using the DYLD_FRAMEWORK_PATH option and run the executable // library using the DYLD_FRAMEWORK_PATH option and run the executable
// //
// $ DYLD_FRAMEWORK_PATH=/Volumes/data/lldb/tot/build/Debug ./a.out executable_path1 [executable_path2 ...] // $ DYLD_FRAMEWORK_PATH=/Volumes/data/lldb/tot/build/Debug ./a.out
// executable_path1 [executable_path2 ...]
//---------------------------------------------------------------------- //----------------------------------------------------------------------
class LLDBSentry class LLDBSentry {
{
public: public:
LLDBSentry() { LLDBSentry() {
// Initialize LLDB // Initialize LLDB
SBDebugger::Initialize(); SBDebugger::Initialize();
} }
~LLDBSentry() { ~LLDBSentry() {
// Terminate LLDB // Terminate LLDB
SBDebugger::Terminate(); SBDebugger::Terminate();
} }
}; };
static struct option g_long_options[] = static struct option g_long_options[] = {
{ {"arch", required_argument, NULL, 'a'},
{ "arch", required_argument, NULL, 'a' }, {"canonical", no_argument, NULL, 'c'},
{ "canonical", no_argument, NULL, 'c' }, {"extern", no_argument, NULL, 'x'},
{ "extern", no_argument, NULL, 'x' }, {"help", no_argument, NULL, 'h'},
{ "help", no_argument, NULL, 'h' }, {"platform", required_argument, NULL, 'p'},
{ "platform", required_argument, NULL, 'p' }, {"verbose", no_argument, NULL, 'v'},
{ "verbose", no_argument, NULL, 'v' }, {NULL, 0, NULL, 0}};
{ NULL, 0, NULL, 0 }
};
#define PROGRAM_NAME "lldb-functions" #define PROGRAM_NAME "lldb-functions"
void void usage() {
usage () puts("NAME\n"
{ " " PROGRAM_NAME
puts ( " -- extract all function signatures from one or more binaries.\n"
"NAME\n" "\n"
" " PROGRAM_NAME " -- extract all function signatures from one or more binaries.\n" "SYNOPSIS\n"
"\n" " " PROGRAM_NAME " [[--arch=<ARCH>] [--platform=<PLATFORM>] "
"SYNOPSIS\n" "[--verbose] [--help] [--canonical] --] <PATH> "
" " PROGRAM_NAME " [[--arch=<ARCH>] [--platform=<PLATFORM>] [--verbose] [--help] [--canonical] --] <PATH> [<PATH>....]\n" "[<PATH>....]\n"
"\n" "\n"
"DESCRIPTION\n" "DESCRIPTION\n"
" Loads the executable pointed to by <PATH> and dumps complete signatures for all functions that have debug information.\n" " Loads the executable pointed to by <PATH> and dumps complete "
"\n" "signatures for all functions that have debug information.\n"
"EXAMPLE\n" "\n"
" " PROGRAM_NAME " --arch=x86_64 /usr/lib/dyld\n" "EXAMPLE\n"
); " " PROGRAM_NAME " --arch=x86_64 /usr/lib/dyld\n");
exit(0); exit(0);
} }
int int main(int argc, char const *argv[]) {
main (int argc, char const *argv[]) // Use a sentry object to properly initialize/terminate LLDB.
{ LLDBSentry sentry;
// Use a sentry object to properly initialize/terminate LLDB.
LLDBSentry sentry; SBDebugger debugger(SBDebugger::Create());
SBDebugger debugger (SBDebugger::Create()); // Create a debugger instance so we can create a target
if (!debugger.IsValid())
// Create a debugger instance so we can create a target fprintf(stderr, "error: failed to create a debugger object\n");
if (!debugger.IsValid())
fprintf (stderr, "error: failed to create a debugger object\n"); bool show_usage = false;
bool verbose = false;
bool show_usage = false; bool canonical = false;
bool verbose = false; bool external_only = false;
bool canonical = false; const char *arch = NULL;
bool external_only = false; const char *platform = NULL;
const char *arch = NULL; std::string short_options("h?");
const char *platform = NULL; for (const struct option *opt = g_long_options; opt->name; ++opt) {
std::string short_options("h?"); if (isprint(opt->val)) {
for (const struct option *opt = g_long_options; opt->name; ++opt) short_options.append(1, (char)opt->val);
{ switch (opt->has_arg) {
if (isprint(opt->val)) case no_argument:
{ break;
short_options.append(1, (char)opt->val); case required_argument:
switch (opt->has_arg) short_options.append(1, ':');
{ break;
case no_argument: case optional_argument:
break; short_options.append(2, ':');
case required_argument: break;
short_options.append(1, ':'); }
break;
case optional_argument:
short_options.append(2, ':');
break;
}
}
} }
}
#ifdef __GLIBC__ #ifdef __GLIBC__
optind = 0; optind = 0;
#else #else
optreset = 1; optreset = 1;
optind = 1; optind = 1;
#endif #endif
char ch; char ch;
while ((ch = getopt_long_only(argc, (char * const *)argv, short_options.c_str(), g_long_options, 0)) != -1) while ((ch = getopt_long_only(argc, (char *const *)argv,
{ short_options.c_str(), g_long_options, 0)) !=
switch (ch) -1) {
{ switch (ch) {
case 0: case 0:
break; break;
case 'a': case 'a':
if (arch != NULL) if (arch != NULL) {
{ fprintf(stderr,
fprintf (stderr, "error: the --arch option can only be specified once\n"); "error: the --arch option can only be specified once\n");
exit(1); exit(1);
} }
arch = optarg; arch = optarg;
break; break;
case 'c': case 'c':
canonical = true; canonical = true;
break; break;
case 'x': case 'x':
external_only = true; external_only = true;
break; break;
case 'p':
platform = optarg;
break;
case 'v':
verbose = true;
break;
case 'h': case 'p':
case '?': platform = optarg;
default: break;
show_usage = true;
break;
}
}
argc -= optind;
argv += optind;
const bool add_dependent_libs = false;
SBError error;
for (int arg_idx = 0; arg_idx < argc; ++arg_idx)
{
// The first argument is the file path we want to look something up in
const char *exe_file_path = argv[arg_idx];
// Create a target using the executable.
SBTarget target = debugger.CreateTarget (exe_file_path,
arch,
platform,
add_dependent_libs,
error);
if (error.Success())
{
if (target.IsValid())
{
SBFileSpec exe_file_spec (exe_file_path, true);
SBModule module (target.FindModule (exe_file_spec));
SBFileSpecList comp_unit_list;
if (module.IsValid()) case 'v':
{ verbose = true;
char command[1024]; break;
lldb::SBCommandReturnObject command_result;
snprintf (command, sizeof(command), "add-dsym --uuid %s", module.GetUUIDString());
debugger.GetCommandInterpreter().HandleCommand (command, command_result);
if (!command_result.Succeeded())
{
fprintf (stderr, "error: couldn't locate debug symbols for '%s'\n", exe_file_path);
exit(1);
}
SBFileSpecList module_list; case 'h':
module_list.Append(exe_file_spec); case '?':
SBBreakpoint bp = target.BreakpointCreateByRegex (".", module_list, comp_unit_list); default:
show_usage = true;
const size_t num_locations = bp.GetNumLocations(); break;
for (uint32_t bp_loc_idx=0; bp_loc_idx<num_locations; ++bp_loc_idx)
{
SBBreakpointLocation bp_loc = bp.GetLocationAtIndex(bp_loc_idx);
SBSymbolContext sc (bp_loc.GetAddress().GetSymbolContext(eSymbolContextEverything));
if (sc.IsValid())
{
if (sc.GetBlock().GetContainingInlinedBlock().IsValid())
{
// Skip inlined functions
continue;
}
SBFunction function (sc.GetFunction());
if (function.IsValid())
{
addr_t lo_pc = function.GetStartAddress().GetFileAddress();
if (lo_pc == LLDB_INVALID_ADDRESS)
{
// Skip functions that don't have concrete instances in the binary
continue;
}
addr_t hi_pc = function.GetEndAddress().GetFileAddress();
const char *func_demangled_name = function.GetName();
const char *func_mangled_name = function.GetMangledName();
bool dump = true;
const bool is_objc_method = ((func_demangled_name[0] == '-') || (func_demangled_name[0] == '+')) && (func_demangled_name[1] == '[');
if (external_only)
{
// Dump all objective C methods, or external symbols
dump = is_objc_method;
if (!dump)
dump = sc.GetSymbol().IsExternal();
}
if (dump)
{
if (verbose)
{
printf ("\n name: %s\n", func_demangled_name);
if (func_mangled_name)
printf ("mangled: %s\n", func_mangled_name);
printf (" range: [0x%16.16llx - 0x%16.16llx)\n type: ", lo_pc, hi_pc);
}
else
{
printf ("[0x%16.16llx - 0x%16.16llx) ", lo_pc, hi_pc);
}
SBType function_type = function.GetType();
SBType return_type = function_type.GetFunctionReturnType();
if (canonical)
return_type = return_type.GetCanonicalType();
if (func_mangled_name &&
func_mangled_name[0] == '_' &&
func_mangled_name[1] == 'Z')
{
printf ("%s %s\n", return_type.GetName(), func_demangled_name);
}
else
{
SBTypeList function_args = function_type.GetFunctionArgumentTypes();
const size_t num_function_args = function_args.GetSize();
if (is_objc_method)
{
const char *class_name_start = func_demangled_name + 2;
if (num_function_args == 0)
{
printf("%c(%s)[%s\n", func_demangled_name[0], return_type.GetName(), class_name_start);
}
else
{
const char *class_name_end = strchr(class_name_start,' ');
const int class_name_len = class_name_end - class_name_start;
printf ("%c(%s)[%*.*s", func_demangled_name[0], return_type.GetName(), class_name_len, class_name_len, class_name_start);
const char *selector_pos = class_name_end + 1;
for (uint32_t function_arg_idx = 0; function_arg_idx < num_function_args; ++function_arg_idx)
{
const char *selector_end = strchr(selector_pos, ':') + 1;
const int selector_len = selector_end - selector_pos;
SBType function_arg_type = function_args.GetTypeAtIndex(function_arg_idx);
if (canonical)
function_arg_type = function_arg_type.GetCanonicalType();
printf (" %*.*s", selector_len, selector_len, selector_pos);
if (function_arg_type.IsValid())
{
printf ("(%s)", function_arg_type.GetName());
}
else
{
printf ("(?)");
}
selector_pos = selector_end;
}
printf ("]\n");
}
}
else
{
printf ("%s ", return_type.GetName());
if (strchr (func_demangled_name, '('))
printf ("(*)(");
else
printf ("%s(", func_demangled_name);
for (uint32_t function_arg_idx = 0; function_arg_idx < num_function_args; ++function_arg_idx)
{
SBType function_arg_type = function_args.GetTypeAtIndex(function_arg_idx);
if (canonical)
function_arg_type = function_arg_type.GetCanonicalType();
if (function_arg_type.IsValid())
{
printf ("%s%s", function_arg_idx > 0 ? ", " : "", function_arg_type.GetName());
}
else
{
printf ("%s???", function_arg_idx > 0 ? ", " : "");
}
}
printf (")\n");
}
}
}
}
}
}
}
}
}
else
{
fprintf (stderr, "error: %s\n", error.GetCString());
exit(1);
}
} }
}
return 0; argc -= optind;
} argv += optind;
const bool add_dependent_libs = false;
SBError error;
for (int arg_idx = 0; arg_idx < argc; ++arg_idx) {
// The first argument is the file path we want to look something up in
const char *exe_file_path = argv[arg_idx];
// Create a target using the executable.
SBTarget target = debugger.CreateTarget(exe_file_path, arch, platform,
add_dependent_libs, error);
if (error.Success()) {
if (target.IsValid()) {
SBFileSpec exe_file_spec(exe_file_path, true);
SBModule module(target.FindModule(exe_file_spec));
SBFileSpecList comp_unit_list;
if (module.IsValid()) {
char command[1024];
lldb::SBCommandReturnObject command_result;
snprintf(command, sizeof(command), "add-dsym --uuid %s",
module.GetUUIDString());
debugger.GetCommandInterpreter().HandleCommand(command,
command_result);
if (!command_result.Succeeded()) {
fprintf(stderr, "error: couldn't locate debug symbols for '%s'\n",
exe_file_path);
exit(1);
}
SBFileSpecList module_list;
module_list.Append(exe_file_spec);
SBBreakpoint bp =
target.BreakpointCreateByRegex(".", module_list, comp_unit_list);
const size_t num_locations = bp.GetNumLocations();
for (uint32_t bp_loc_idx = 0; bp_loc_idx < num_locations;
++bp_loc_idx) {
SBBreakpointLocation bp_loc = bp.GetLocationAtIndex(bp_loc_idx);
SBSymbolContext sc(
bp_loc.GetAddress().GetSymbolContext(eSymbolContextEverything));
if (sc.IsValid()) {
if (sc.GetBlock().GetContainingInlinedBlock().IsValid()) {
// Skip inlined functions
continue;
}
SBFunction function(sc.GetFunction());
if (function.IsValid()) {
addr_t lo_pc = function.GetStartAddress().GetFileAddress();
if (lo_pc == LLDB_INVALID_ADDRESS) {
// Skip functions that don't have concrete instances in the
// binary
continue;
}
addr_t hi_pc = function.GetEndAddress().GetFileAddress();
const char *func_demangled_name = function.GetName();
const char *func_mangled_name = function.GetMangledName();
bool dump = true;
const bool is_objc_method = ((func_demangled_name[0] == '-') ||
(func_demangled_name[0] == '+')) &&
(func_demangled_name[1] == '[');
if (external_only) {
// Dump all objective C methods, or external symbols
dump = is_objc_method;
if (!dump)
dump = sc.GetSymbol().IsExternal();
}
if (dump) {
if (verbose) {
printf("\n name: %s\n", func_demangled_name);
if (func_mangled_name)
printf("mangled: %s\n", func_mangled_name);
printf(" range: [0x%16.16llx - 0x%16.16llx)\n type: ",
lo_pc, hi_pc);
} else {
printf("[0x%16.16llx - 0x%16.16llx) ", lo_pc, hi_pc);
}
SBType function_type = function.GetType();
SBType return_type = function_type.GetFunctionReturnType();
if (canonical)
return_type = return_type.GetCanonicalType();
if (func_mangled_name && func_mangled_name[0] == '_' &&
func_mangled_name[1] == 'Z') {
printf("%s %s\n", return_type.GetName(),
func_demangled_name);
} else {
SBTypeList function_args =
function_type.GetFunctionArgumentTypes();
const size_t num_function_args = function_args.GetSize();
if (is_objc_method) {
const char *class_name_start = func_demangled_name + 2;
if (num_function_args == 0) {
printf("%c(%s)[%s\n", func_demangled_name[0],
return_type.GetName(), class_name_start);
} else {
const char *class_name_end =
strchr(class_name_start, ' ');
const int class_name_len =
class_name_end - class_name_start;
printf("%c(%s)[%*.*s", func_demangled_name[0],
return_type.GetName(), class_name_len,
class_name_len, class_name_start);
const char *selector_pos = class_name_end + 1;
for (uint32_t function_arg_idx = 0;
function_arg_idx < num_function_args;
++function_arg_idx) {
const char *selector_end =
strchr(selector_pos, ':') + 1;
const int selector_len = selector_end - selector_pos;
SBType function_arg_type =
function_args.GetTypeAtIndex(function_arg_idx);
if (canonical)
function_arg_type =
function_arg_type.GetCanonicalType();
printf(" %*.*s", selector_len, selector_len,
selector_pos);
if (function_arg_type.IsValid()) {
printf("(%s)", function_arg_type.GetName());
} else {
printf("(?)");
}
selector_pos = selector_end;
}
printf("]\n");
}
} else {
printf("%s ", return_type.GetName());
if (strchr(func_demangled_name, '('))
printf("(*)(");
else
printf("%s(", func_demangled_name);
for (uint32_t function_arg_idx = 0;
function_arg_idx < num_function_args;
++function_arg_idx) {
SBType function_arg_type =
function_args.GetTypeAtIndex(function_arg_idx);
if (canonical)
function_arg_type =
function_arg_type.GetCanonicalType();
if (function_arg_type.IsValid()) {
printf("%s%s", function_arg_idx > 0 ? ", " : "",
function_arg_type.GetName());
} else {
printf("%s???", function_arg_idx > 0 ? ", " : "");
}
}
printf(")\n");
}
}
}
}
}
}
}
}
} else {
fprintf(stderr, "error: %s\n", error.GetCString());
exit(1);
}
}
return 0;
}

View File

@ -19,11 +19,11 @@
#include "LLDB/SBDebugger.h" #include "LLDB/SBDebugger.h"
#include "LLDB/SBFunction.h" #include "LLDB/SBFunction.h"
#include "LLDB/SBModule.h" #include "LLDB/SBModule.h"
#include "LLDB/SBProcess.h"
#include "LLDB/SBStream.h" #include "LLDB/SBStream.h"
#include "LLDB/SBSymbol.h" #include "LLDB/SBSymbol.h"
#include "LLDB/SBTarget.h" #include "LLDB/SBTarget.h"
#include "LLDB/SBThread.h" #include "LLDB/SBThread.h"
#include "LLDB/SBProcess.h"
#endif #endif
#include <string> #include <string>
@ -34,8 +34,8 @@ using namespace lldb;
// This quick sample code shows how to create a debugger instance and // This quick sample code shows how to create a debugger instance and
// create an "i386" executable target. Then we can lookup the executable // create an "i386" executable target. Then we can lookup the executable
// module and resolve a file address into a section offset address, // module and resolve a file address into a section offset address,
// and find all symbol context objects (if any) for that address: // and find all symbol context objects (if any) for that address:
// compile unit, function, deepest block, line table entry and the // compile unit, function, deepest block, line table entry and the
// symbol. // symbol.
// //
// To build the program, type (while in this directory): // To build the program, type (while in this directory):
@ -44,192 +44,179 @@ using namespace lldb;
// //
// then (for example): // then (for example):
// //
// $ DYLD_FRAMEWORK_PATH=/Volumes/data/lldb/svn/ToT/build/Debug ./a.out executable_path file_address // $ DYLD_FRAMEWORK_PATH=/Volumes/data/lldb/svn/ToT/build/Debug ./a.out
// executable_path file_address
//---------------------------------------------------------------------- //----------------------------------------------------------------------
class LLDBSentry class LLDBSentry {
{
public: public:
LLDBSentry() { LLDBSentry() {
// Initialize LLDB // Initialize LLDB
SBDebugger::Initialize(); SBDebugger::Initialize();
} }
~LLDBSentry() { ~LLDBSentry() {
// Terminate LLDB // Terminate LLDB
SBDebugger::Terminate(); SBDebugger::Terminate();
} }
}; };
static struct option g_long_options[] = static struct option g_long_options[] = {
{ {"help", no_argument, NULL, 'h'},
{ "help", no_argument, NULL, 'h' }, {"verbose", no_argument, NULL, 'v'},
{ "verbose", no_argument, NULL, 'v' }, {"arch", required_argument, NULL, 'a'},
{ "arch", required_argument, NULL, 'a' }, {"platform", required_argument, NULL, 'p'},
{ "platform", required_argument, NULL, 'p' }, {NULL, 0, NULL, 0}};
{ NULL, 0, NULL, 0 }
};
#define PROGRAM_NAME "lldb-lookup" #define PROGRAM_NAME "lldb-lookup"
void void usage() {
usage () puts("NAME\n"
{ " " PROGRAM_NAME " -- symbolicate addresses using lldb.\n"
puts ( "\n"
"NAME\n" "SYNOPSIS\n"
" " PROGRAM_NAME " -- symbolicate addresses using lldb.\n" " " PROGRAM_NAME " [[--arch=<ARCH>] [--platform=<PLATFORM>] "
"\n" "[--verbose] [--help] --] <PATH> <ADDRESS> "
"SYNOPSIS\n" "[<ADDRESS>....]\n"
" " PROGRAM_NAME " [[--arch=<ARCH>] [--platform=<PLATFORM>] [--verbose] [--help] --] <PATH> <ADDRESS> [<ADDRESS>....]\n" "\n"
"\n" "DESCRIPTION\n"
"DESCRIPTION\n" " Loads the executable pointed to by <PATH> and looks up and "
" Loads the executable pointed to by <PATH> and looks up and <ADDRESS>\n" "<ADDRESS>\n"
" arguments\n" " arguments\n"
"\n" "\n"
"EXAMPLE\n" "EXAMPLE\n"
" " PROGRAM_NAME " --arch=x86_64 -- /usr/lib/dyld 0x100000000\n" " " PROGRAM_NAME " --arch=x86_64 -- /usr/lib/dyld 0x100000000\n");
); exit(0);
exit(0);
} }
int int main(int argc, char const *argv[]) {
main (int argc, char const *argv[]) // Use a sentry object to properly initialize/terminate LLDB.
{ LLDBSentry sentry;
// Use a sentry object to properly initialize/terminate LLDB.
LLDBSentry sentry; SBDebugger debugger(SBDebugger::Create());
SBDebugger debugger (SBDebugger::Create()); // Create a debugger instance so we can create a target
if (!debugger.IsValid())
// Create a debugger instance so we can create a target fprintf(stderr, "error: failed to create a debugger object\n");
if (!debugger.IsValid())
fprintf (stderr, "error: failed to create a debugger object\n"); bool show_usage = false;
bool verbose = false;
bool show_usage = false; const char *arch = NULL;
bool verbose = false; const char *platform = NULL;
const char *arch = NULL; std::string short_options("h?");
const char *platform = NULL; for (const struct option *opt = g_long_options; opt->name; ++opt) {
std::string short_options("h?"); if (isprint(opt->val)) {
for (const struct option *opt = g_long_options; opt->name; ++opt) short_options.append(1, (char)opt->val);
{ switch (opt->has_arg) {
if (isprint(opt->val)) case no_argument:
{ break;
short_options.append(1, (char)opt->val); case required_argument:
switch (opt->has_arg) short_options.append(1, ':');
{ break;
case no_argument: case optional_argument:
break; short_options.append(2, ':');
case required_argument: break;
short_options.append(1, ':'); }
break;
case optional_argument:
short_options.append(2, ':');
break;
}
}
} }
}
#ifdef __GLIBC__ #ifdef __GLIBC__
optind = 0; optind = 0;
#else #else
optreset = 1; optreset = 1;
optind = 1; optind = 1;
#endif #endif
char ch; char ch;
while ((ch = getopt_long_only(argc, (char * const *)argv, short_options.c_str(), g_long_options, 0)) != -1) while ((ch = getopt_long_only(argc, (char *const *)argv,
{ short_options.c_str(), g_long_options, 0)) !=
switch (ch) -1) {
{ switch (ch) {
case 0: case 0:
break; break;
case 'a': case 'a':
if (arch != NULL) if (arch != NULL) {
{ fprintf(stderr,
fprintf (stderr, "error: the --arch option can only be specified once\n"); "error: the --arch option can only be specified once\n");
exit(1); exit(1);
} }
arch = optarg; arch = optarg;
break; break;
case 'p': case 'p':
platform = optarg; platform = optarg;
break; break;
case 'v':
verbose = true;
break;
case 'h': case 'v':
case '?': verbose = true;
default: break;
show_usage = true;
break;
}
}
argc -= optind;
argv += optind;
if (show_usage || argc < 2) case 'h':
usage(); case '?':
default:
show_usage = true;
break;
}
}
argc -= optind;
argv += optind;
int arg_idx = 0; if (show_usage || argc < 2)
// The first argument is the file path we want to look something up in usage();
const char *exe_file_path = argv[arg_idx];
const char *addr_cstr;
const bool add_dependent_libs = false;
SBError error;
SBStream strm;
strm.RedirectToFileHandle (stdout, false);
while ((addr_cstr = argv[++arg_idx]) != NULL) int arg_idx = 0;
{ // The first argument is the file path we want to look something up in
// The second argument in the address that we want to lookup const char *exe_file_path = argv[arg_idx];
lldb::addr_t file_addr = strtoull (addr_cstr, NULL, 0); const char *addr_cstr;
const bool add_dependent_libs = false;
SBError error;
SBStream strm;
strm.RedirectToFileHandle(stdout, false);
// Create a target using the executable. while ((addr_cstr = argv[++arg_idx]) != NULL) {
SBTarget target = debugger.CreateTarget (exe_file_path, // The second argument in the address that we want to lookup
arch, lldb::addr_t file_addr = strtoull(addr_cstr, NULL, 0);
platform,
add_dependent_libs,
error);
if (!error.Success())
{
fprintf (stderr, "error: %s\n", error.GetCString());
exit(1);
}
printf ("%sLooking up 0x%llx in '%s':\n", (arg_idx > 1) ? "\n" : "", file_addr, exe_file_path); // Create a target using the executable.
SBTarget target = debugger.CreateTarget(exe_file_path, arch, platform,
if (target.IsValid()) add_dependent_libs, error);
{ if (!error.Success()) {
// Find the executable module so we can do a lookup inside it fprintf(stderr, "error: %s\n", error.GetCString());
SBFileSpec exe_file_spec (exe_file_path, true); exit(1);
SBModule module (target.FindModule (exe_file_spec));
// Take a file virtual address and resolve it to a section offset
// address that can be used to do a symbol lookup by address
SBAddress addr = module.ResolveFileAddress (file_addr);
bool success = addr.IsValid() && addr.GetSection().IsValid();
if (success)
{
// We can resolve a section offset address in the module
// and only ask for what we need. You can logical or together
// bits from the SymbolContextItem enumeration found in
// lldb-enumeration.h to request only what you want. Here we
// are asking for everything.
//
// NOTE: the less you ask for, the less LLDB will parse as
// LLDB does partial parsing on just about everything.
SBSymbolContext sc (module.ResolveSymbolContextForAddress (addr, eSymbolContextEverything));
strm.Printf (" Address: %s + 0x%llx\n Summary: ", addr.GetSection().GetName (), addr.GetOffset());
addr.GetDescription (strm);
strm.Printf ("\n");
if (verbose)
sc.GetDescription (strm);
}
else
{
printf ("error: 0x%llx does not resolve to a valid file address in '%s'\n", file_addr, exe_file_path);
}
}
} }
return 0; printf("%sLooking up 0x%llx in '%s':\n", (arg_idx > 1) ? "\n" : "",
} file_addr, exe_file_path);
if (target.IsValid()) {
// Find the executable module so we can do a lookup inside it
SBFileSpec exe_file_spec(exe_file_path, true);
SBModule module(target.FindModule(exe_file_spec));
// Take a file virtual address and resolve it to a section offset
// address that can be used to do a symbol lookup by address
SBAddress addr = module.ResolveFileAddress(file_addr);
bool success = addr.IsValid() && addr.GetSection().IsValid();
if (success) {
// We can resolve a section offset address in the module
// and only ask for what we need. You can logical or together
// bits from the SymbolContextItem enumeration found in
// lldb-enumeration.h to request only what you want. Here we
// are asking for everything.
//
// NOTE: the less you ask for, the less LLDB will parse as
// LLDB does partial parsing on just about everything.
SBSymbolContext sc(module.ResolveSymbolContextForAddress(
addr, eSymbolContextEverything));
strm.Printf(" Address: %s + 0x%llx\n Summary: ",
addr.GetSection().GetName(), addr.GetOffset());
addr.GetDescription(strm);
strm.Printf("\n");
if (verbose)
sc.GetDescription(strm);
} else {
printf(
"error: 0x%llx does not resolve to a valid file address in '%s'\n",
file_addr, exe_file_path);
}
}
}
return 0;
}

View File

@ -8,8 +8,10 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
/* /*
An example plugin for LLDB that provides a new foo command with a child subcommand An example plugin for LLDB that provides a new foo command with a child
Compile this into a dylib foo.dylib and load by placing in appropriate locations on disk or subcommand
Compile this into a dylib foo.dylib and load by placing in appropriate locations
on disk or
by typing plugin load foo.dylib at the LLDB command line by typing plugin load foo.dylib at the LLDB command line
*/ */
@ -18,39 +20,28 @@ by typing plugin load foo.dylib at the LLDB command line
#include <LLDB/SBDebugger.h> #include <LLDB/SBDebugger.h>
namespace lldb { namespace lldb {
bool bool PluginInitialize(lldb::SBDebugger debugger);
PluginInitialize (lldb::SBDebugger debugger);
} }
class ChildCommand : public lldb::SBCommandPluginInterface class ChildCommand : public lldb::SBCommandPluginInterface {
{
public: public:
virtual bool virtual bool DoExecute(lldb::SBDebugger debugger, char **command,
DoExecute (lldb::SBDebugger debugger, lldb::SBCommandReturnObject &result) {
char** command, if (command) {
lldb::SBCommandReturnObject &result) const char *arg = *command;
{ while (arg) {
if (command) result.Printf("%s\n", arg);
{ arg = *(++command);
const char* arg = *command; }
while (arg) return true;
{
result.Printf("%s\n",arg);
arg = *(++command);
}
return true;
}
return false;
} }
return false;
}
}; };
bool bool lldb::PluginInitialize(lldb::SBDebugger debugger) {
lldb::PluginInitialize (lldb::SBDebugger debugger) lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
{ lldb::SBCommand foo = interpreter.AddMultiwordCommand("foo", NULL);
lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter(); foo.AddCommand("child", new ChildCommand(), "a child of foo");
lldb::SBCommand foo = interpreter.AddMultiwordCommand("foo",NULL); return true;
foo.AddCommand("child",new ChildCommand(),"a child of foo");
return true;
} }

View File

@ -4,7 +4,7 @@
# Be sure to add the python path that points to the LLDB shared library. # Be sure to add the python path that points to the LLDB shared library.
# #
# # To use this in the embedded python interpreter using "lldb" just # # To use this in the embedded python interpreter using "lldb" just
# import it with the full path using the "command script import" # import it with the full path using the "command script import"
# command # command
# (lldb) command script import /path/to/cmdtemplate.py # (lldb) command script import /path/to/cmdtemplate.py
#---------------------------------------------------------------------- #----------------------------------------------------------------------
@ -14,22 +14,51 @@ import commands
import optparse import optparse
import shlex import shlex
def create_framestats_options(): def create_framestats_options():
usage = "usage: %prog [options]" usage = "usage: %prog [options]"
description='''This command is meant to be an example of how to make an LLDB command that description = '''This command is meant to be an example of how to make an LLDB command that
does something useful, follows best practices, and exploits the SB API. does something useful, follows best practices, and exploits the SB API.
Specifically, this command computes the aggregate and average size of the variables in the current frame Specifically, this command computes the aggregate and average size of the variables in the current frame
and allows you to tweak exactly which variables are to be accounted in the computation. and allows you to tweak exactly which variables are to be accounted in the computation.
''' '''
parser = optparse.OptionParser(description=description, prog='framestats',usage=usage) parser = optparse.OptionParser(
parser.add_option('-i', '--in-scope', action='store_true', dest='inscope', help='in_scope_only = True', default=False) description=description,
parser.add_option('-a', '--arguments', action='store_true', dest='arguments', help='arguments = True', default=False) prog='framestats',
parser.add_option('-l', '--locals', action='store_true', dest='locals', help='locals = True', default=False) usage=usage)
parser.add_option('-s', '--statics', action='store_true', dest='statics', help='statics = True', default=False) parser.add_option(
'-i',
'--in-scope',
action='store_true',
dest='inscope',
help='in_scope_only = True',
default=False)
parser.add_option(
'-a',
'--arguments',
action='store_true',
dest='arguments',
help='arguments = True',
default=False)
parser.add_option(
'-l',
'--locals',
action='store_true',
dest='locals',
help='locals = True',
default=False)
parser.add_option(
'-s',
'--statics',
action='store_true',
dest='statics',
help='statics = True',
default=False)
return parser return parser
def the_framestats_command(debugger, command, result, dict): def the_framestats_command(debugger, command, result, dict):
# Use the Shell Lexer to properly parse up command options just like a # Use the Shell Lexer to properly parse up command options just like a
# shell would # shell would
command_args = shlex.split(command) command_args = shlex.split(command)
parser = create_framestats_options() parser = create_framestats_options()
@ -38,9 +67,9 @@ def the_framestats_command(debugger, command, result, dict):
except: except:
# if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit
# (courtesy of OptParse dealing with argument errors by throwing SystemExit) # (courtesy of OptParse dealing with argument errors by throwing SystemExit)
result.SetError ("option parsing failed") result.SetError("option parsing failed")
return return
# in a command - the lldb.* convenience variables are not to be used # in a command - the lldb.* convenience variables are not to be used
# and their values (if any) are undefined # and their values (if any) are undefined
# this is the best practice to access those objects from within a command # this is the best practice to access those objects from within a command
@ -51,26 +80,33 @@ def the_framestats_command(debugger, command, result, dict):
if not frame.IsValid(): if not frame.IsValid():
return "no frame here" return "no frame here"
# from now on, replace lldb.<thing>.whatever with <thing>.whatever # from now on, replace lldb.<thing>.whatever with <thing>.whatever
variables_list = frame.GetVariables(options.arguments, options.locals, options.statics, options.inscope) variables_list = frame.GetVariables(
options.arguments,
options.locals,
options.statics,
options.inscope)
variables_count = variables_list.GetSize() variables_count = variables_list.GetSize()
if variables_count == 0: if variables_count == 0:
print >> result, "no variables here" print >> result, "no variables here"
return return
total_size = 0 total_size = 0
for i in range(0,variables_count): for i in range(0, variables_count):
variable = variables_list.GetValueAtIndex(i) variable = variables_list.GetValueAtIndex(i)
variable_type = variable.GetType() variable_type = variable.GetType()
total_size = total_size + variable_type.GetByteSize() total_size = total_size + variable_type.GetByteSize()
average_size = float(total_size) / variables_count average_size = float(total_size) / variables_count
print >>result, "Your frame has %d variables. Their total size is %d bytes. The average size is %f bytes" % (variables_count,total_size,average_size) print >>result, "Your frame has %d variables. Their total size is %d bytes. The average size is %f bytes" % (
variables_count, total_size, average_size)
# not returning anything is akin to returning success # not returning anything is akin to returning success
def __lldb_init_module (debugger, dict):
# This initializer is being run from LLDB in the embedded command interpreter def __lldb_init_module(debugger, dict):
# Make the options so we can generate the help text for the new LLDB # This initializer is being run from LLDB in the embedded command interpreter
# Make the options so we can generate the help text for the new LLDB
# command line command prior to registering it with LLDB below # command line command prior to registering it with LLDB below
parser = create_framestats_options() parser = create_framestats_options()
the_framestats_command.__doc__ = parser.format_help() the_framestats_command.__doc__ = parser.format_help()
# Add any commands contained in this module to LLDB # Add any commands contained in this module to LLDB
debugger.HandleCommand('command script add -f cmdtemplate.the_framestats_command framestats') debugger.HandleCommand(
'command script add -f cmdtemplate.the_framestats_command framestats')
print 'The "framestats" command has been installed, type "help framestats" or "framestats --help" for detailed help.' print 'The "framestats" command has been installed, type "help framestats" or "framestats --help" for detailed help.'

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,15 @@
#!/usr/bin/python #!/usr/bin/python
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# This module will enable GDB remote packet logging when the # This module will enable GDB remote packet logging when the
# 'start_gdb_log' command is called with a filename to log to. When the # 'start_gdb_log' command is called with a filename to log to. When the
# 'stop_gdb_log' command is called, it will disable the logging and # 'stop_gdb_log' command is called, it will disable the logging and
# print out statistics about how long commands took to execute and also # print out statistics about how long commands took to execute and also
# will primnt ou # will primnt ou
# Be sure to add the python path that points to the LLDB shared library. # Be sure to add the python path that points to the LLDB shared library.
# #
# To use this in the embedded python interpreter using "lldb" just # To use this in the embedded python interpreter using "lldb" just
# import it with the full path using the "command script import" # import it with the full path using the "command script import"
# command. This can be done from the LLDB command line: # command. This can be done from the LLDB command line:
# (lldb) command script import /path/to/gdbremote.py # (lldb) command script import /path/to/gdbremote.py
# Or it can be added to your ~/.lldbinit file so this module is always # Or it can be added to your ~/.lldbinit file so this module is always
@ -23,13 +23,16 @@ import shlex
import re import re
import tempfile import tempfile
def start_gdb_log(debugger, command, result, dict): def start_gdb_log(debugger, command, result, dict):
'''Start logging GDB remote packets by enabling logging with timestamps and '''Start logging GDB remote packets by enabling logging with timestamps and
thread safe logging. Follow a call to this function with a call to "stop_gdb_log" thread safe logging. Follow a call to this function with a call to "stop_gdb_log"
in order to dump out the commands.''' in order to dump out the commands.'''
global log_file global log_file
if log_file: if log_file:
result.PutCString ('error: logging is already in progress with file "%s"', log_file) result.PutCString(
'error: logging is already in progress with file "%s"',
log_file)
else: else:
args_len = len(args) args_len = len(args)
if args_len == 0: if args_len == 0:
@ -38,36 +41,52 @@ def start_gdb_log(debugger, command, result, dict):
log_file = args[0] log_file = args[0]
if log_file: if log_file:
debugger.HandleCommand('log enable --threadsafe --timestamp --file "%s" gdb-remote packets' % log_file); debugger.HandleCommand(
result.PutCString ("GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics." % log_file) 'log enable --threadsafe --timestamp --file "%s" gdb-remote packets' %
log_file)
result.PutCString(
"GDB packet logging enable with log file '%s'\nUse the 'stop_gdb_log' command to stop logging and show packet statistics." %
log_file)
return return
result.PutCString ('error: invalid log file path') result.PutCString('error: invalid log file path')
result.PutCString (usage) result.PutCString(usage)
def parse_time_log(debugger, command, result, dict): def parse_time_log(debugger, command, result, dict):
# Any commands whose names might be followed by more valid C identifier # Any commands whose names might be followed by more valid C identifier
# characters must be listed here # characters must be listed here
command_args = shlex.split(command) command_args = shlex.split(command)
parse_time_log_args (command_args) parse_time_log_args(command_args)
def parse_time_log_args(command_args): def parse_time_log_args(command_args):
usage = "usage: parse_time_log [options] [<LOGFILEPATH>]" usage = "usage: parse_time_log [options] [<LOGFILEPATH>]"
description='''Parse a log file that contains timestamps and convert the timestamps to delta times between log lines.''' description = '''Parse a log file that contains timestamps and convert the timestamps to delta times between log lines.'''
parser = optparse.OptionParser(description=description, prog='parse_time_log',usage=usage) parser = optparse.OptionParser(
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False) description=description,
prog='parse_time_log',
usage=usage)
parser.add_option(
'-v',
'--verbose',
action='store_true',
dest='verbose',
help='display verbose debug info',
default=False)
try: try:
(options, args) = parser.parse_args(command_args) (options, args) = parser.parse_args(command_args)
except: except:
return return
for log_file in args: for log_file in args:
parse_log_file (log_file, options) parse_log_file(log_file, options)
def parse_log_file(file, options): def parse_log_file(file, options):
'''Parse a log file that was contains timestamps. These logs are typically '''Parse a log file that was contains timestamps. These logs are typically
generated using: generated using:
(lldb) log enable --threadsafe --timestamp --file <FILE> .... (lldb) log enable --threadsafe --timestamp --file <FILE> ....
This log file will contain timestamps and this function will then normalize This log file will contain timestamps and this function will then normalize
those packets to be relative to the first value timestamp that is found and those packets to be relative to the first value timestamp that is found and
show delta times between log lines and also keep track of how long it takes show delta times between log lines and also keep track of how long it takes
@ -86,9 +105,9 @@ def parse_log_file(file, options):
file = open(file) file = open(file)
lines = file.read().splitlines() lines = file.read().splitlines()
for line in lines: for line in lines:
match = timestamp_regex.match (line) match = timestamp_regex.match(line)
if match: if match:
curr_time = float (match.group(2)) curr_time = float(match.group(2))
delta = 0.0 delta = 0.0
if base_time: if base_time:
delta = curr_time - last_time delta = curr_time - last_time
@ -99,17 +118,17 @@ def parse_log_file(file, options):
last_time = curr_time last_time = curr_time
else: else:
print line print line
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys
parse_time_log_args (sys.argv[1:]) parse_time_log_args(sys.argv[1:])
else: else:
import lldb import lldb
if lldb.debugger: if lldb.debugger:
# This initializer is being run from LLDB in the embedded command interpreter # This initializer is being run from LLDB in the embedded command interpreter
# Add any commands contained in this module to LLDB # Add any commands contained in this module to LLDB
lldb.debugger.HandleCommand('command script add -f delta.parse_time_log parse_time_log') lldb.debugger.HandleCommand(
'command script add -f delta.parse_time_log parse_time_log')
print 'The "parse_time_log" command is now installed and ready for use, type "parse_time_log --help" for more information' print 'The "parse_time_log" command is now installed and ready for use, type "parse_time_log --help" for more information'

View File

@ -1,64 +1,67 @@
# This implements the "diagnose-nsstring" command, usually installed in the debug session like # This implements the "diagnose-nsstring" command, usually installed in the debug session like
# command script import lldb.diagnose # command script import lldb.diagnose
# it is used when NSString summary formatter fails to replicate the logic that went into LLDB making the # it is used when NSString summary formatter fails to replicate the logic that went into LLDB making the
# decisions it did and providing some useful context information that can be used for improving the formatter # decisions it did and providing some useful context information that can
# be used for improving the formatter
import lldb import lldb
def read_memory(process,location,size):
data = ""
error = lldb.SBError()
for x in range(0,size-1):
byte = process.ReadUnsignedFromMemory(x+location,1,error)
if error.fail:
data = data + "err%s" % "" if x == size-2 else ":"
else:
try:
data = data + "0x%x" % byte
if byte == 0:
data = data + "(\\0)"
elif byte == 0xa:
data = data + "(\\a)"
elif byte == 0xb:
data = data + "(\\b)"
elif byte == 0xc:
data = data + "(\\c)"
elif byte == '\n':
data = data + "(\\n)"
else:
data = data + "(%s)" % chr(byte)
if x < size-2:
data = data + ":"
except Exception as e:
print e
return data
def diagnose_nsstring_Command_Impl(debugger,command,result,internal_dict): def read_memory(process, location, size):
""" data = ""
A command to diagnose the LLDB NSString data formatter error = lldb.SBError()
invoke as for x in range(0, size - 1):
(lldb) diagnose-nsstring <expr returning NSString> byte = process.ReadUnsignedFromMemory(x + location, 1, error)
e.g. if error.fail:
(lldb) diagnose-nsstring @"Hello world" data = data + "err%s" % "" if x == size - 2 else ":"
""" else:
target = debugger.GetSelectedTarget() try:
process = target.GetProcess() data = data + "0x%x" % byte
thread = process.GetSelectedThread() if byte == 0:
frame = thread.GetSelectedFrame() data = data + "(\\0)"
if not target.IsValid() or not process.IsValid(): elif byte == 0xa:
return "unable to get target/process - cannot proceed" data = data + "(\\a)"
options = lldb.SBExpressionOptions() elif byte == 0xb:
options.SetFetchDynamicValue() data = data + "(\\b)"
error = lldb.SBError() elif byte == 0xc:
if frame.IsValid(): data = data + "(\\c)"
nsstring = frame.EvaluateExpression(command,options) elif byte == '\n':
else: data = data + "(\\n)"
nsstring = target.EvaluateExpression(command,options) else:
print >>result,str(nsstring) data = data + "(%s)" % chr(byte)
nsstring_address = nsstring.GetValueAsUnsigned(0) if x < size - 2:
if nsstring_address == 0: data = data + ":"
return "unable to obtain the string - cannot proceed" except Exception as e:
expression = "\ print e
return data
def diagnose_nsstring_Command_Impl(debugger, command, result, internal_dict):
"""
A command to diagnose the LLDB NSString data formatter
invoke as
(lldb) diagnose-nsstring <expr returning NSString>
e.g.
(lldb) diagnose-nsstring @"Hello world"
"""
target = debugger.GetSelectedTarget()
process = target.GetProcess()
thread = process.GetSelectedThread()
frame = thread.GetSelectedFrame()
if not target.IsValid() or not process.IsValid():
return "unable to get target/process - cannot proceed"
options = lldb.SBExpressionOptions()
options.SetFetchDynamicValue()
error = lldb.SBError()
if frame.IsValid():
nsstring = frame.EvaluateExpression(command, options)
else:
nsstring = target.EvaluateExpression(command, options)
print >>result, str(nsstring)
nsstring_address = nsstring.GetValueAsUnsigned(0)
if nsstring_address == 0:
return "unable to obtain the string - cannot proceed"
expression = "\
struct $__lldb__notInlineMutable {\ struct $__lldb__notInlineMutable {\
char* buffer;\ char* buffer;\
signed long length;\ signed long length;\
@ -97,75 +100,84 @@ struct $__lldb__CFString {\
};\ };\
" "
expression = expression + "*(($__lldb__CFString*) %d)" % nsstring_address expression = expression + "*(($__lldb__CFString*) %d)" % nsstring_address
# print expression # print expression
dumped = target.EvaluateExpression(expression,options) dumped = target.EvaluateExpression(expression, options)
print >>result, str(dumped) print >>result, str(dumped)
little_endian = (target.byte_order == lldb.eByteOrderLittle)
ptr_size = target.addr_size
info_bits = dumped.GetChildMemberWithName("_cfinfo").GetChildAtIndex(0 if little_endian else 3).GetValueAsUnsigned(0)
is_mutable = (info_bits & 1) == 1
is_inline = (info_bits & 0x60) == 0
has_explicit_length = (info_bits & (1 | 4)) != 4
is_unicode = (info_bits & 0x10) == 0x10
is_special = (nsstring.GetDynamicValue(lldb.eDynamicCanRunTarget).GetTypeName() == "NSPathStore2")
has_null = (info_bits & 8) == 8
print >>result,"\nInfo=%d\nMutable=%s\nInline=%s\nExplicit=%s\nUnicode=%s\nSpecial=%s\nNull=%s\n" % \
(info_bits, "yes" if is_mutable else "no","yes" if is_inline else "no","yes" if has_explicit_length else "no","yes" if is_unicode else "no","yes" if is_special else "no","yes" if has_null else "no")
little_endian = (target.byte_order == lldb.eByteOrderLittle)
ptr_size = target.addr_size
explicit_length_offset = 0 info_bits = dumped.GetChildMemberWithName("_cfinfo").GetChildAtIndex(
if not has_null and has_explicit_length and not is_special: 0 if little_endian else 3).GetValueAsUnsigned(0)
explicit_length_offset = 2*ptr_size is_mutable = (info_bits & 1) == 1
if is_mutable and not is_inline: is_inline = (info_bits & 0x60) == 0
explicit_length_offset = explicit_length_offset + ptr_size has_explicit_length = (info_bits & (1 | 4)) != 4
elif is_inline: is_unicode = (info_bits & 0x10) == 0x10
pass is_special = (
elif not is_inline and not is_mutable: nsstring.GetDynamicValue(
explicit_length_offset = explicit_length_offset + ptr_size lldb.eDynamicCanRunTarget).GetTypeName() == "NSPathStore2")
else: has_null = (info_bits & 8) == 8
explicit_length_offset = 0
if explicit_length_offset == 0: print >>result, "\nInfo=%d\nMutable=%s\nInline=%s\nExplicit=%s\nUnicode=%s\nSpecial=%s\nNull=%s\n" % \
print >>result,"There is no explicit length marker - skipping this step\n" (info_bits, "yes" if is_mutable else "no", "yes" if is_inline else "no", "yes" if has_explicit_length else "no", "yes" if is_unicode else "no", "yes" if is_special else "no", "yes" if has_null else "no")
else:
explicit_length_offset = nsstring_address + explicit_length_offset explicit_length_offset = 0
explicit_length = process.ReadUnsignedFromMemory(explicit_length_offset, 4, error) if not has_null and has_explicit_length and not is_special:
print >>result,"Explicit length location is at 0x%x - read value is %d\n" % (explicit_length_offset,explicit_length) explicit_length_offset = 2 * ptr_size
if is_mutable and not is_inline:
explicit_length_offset = explicit_length_offset + ptr_size
elif is_inline:
pass
elif not is_inline and not is_mutable:
explicit_length_offset = explicit_length_offset + ptr_size
else:
explicit_length_offset = 0
if explicit_length_offset == 0:
print >>result, "There is no explicit length marker - skipping this step\n"
else:
explicit_length_offset = nsstring_address + explicit_length_offset
explicit_length = process.ReadUnsignedFromMemory(
explicit_length_offset, 4, error)
print >>result, "Explicit length location is at 0x%x - read value is %d\n" % (
explicit_length_offset, explicit_length)
if is_mutable:
location = 2 * ptr_size + nsstring_address
location = process.ReadPointerFromMemory(location, error)
elif is_inline and has_explicit_length and not is_unicode and not is_special and not is_mutable:
location = 3 * ptr_size + nsstring_address
elif is_unicode:
location = 2 * ptr_size + nsstring_address
if is_inline:
if not has_explicit_length:
print >>result, "Unicode & Inline & !Explicit is a new combo - no formula for it"
else:
location += ptr_size
else:
location = process.ReadPointerFromMemory(location, error)
elif is_special:
location = nsstring_address + ptr_size + 4
elif is_inline:
location = 2 * ptr_size + nsstring_address
if not has_explicit_length:
location += 1
else:
location = 2 * ptr_size + nsstring_address
location = process.ReadPointerFromMemory(location, error)
print >>result, "Expected data location: 0x%x\n" % (location)
print >>result, "1K of data around location: %s\n" % read_memory(
process, location, 1024)
print >>result, "5K of data around string pointer: %s\n" % read_memory(
process, nsstring_address, 1024 * 5)
if is_mutable:
location = 2 * ptr_size + nsstring_address
location = process.ReadPointerFromMemory(location,error)
elif is_inline and has_explicit_length and not is_unicode and not is_special and not is_mutable:
location = 3 * ptr_size + nsstring_address
elif is_unicode:
location = 2 * ptr_size + nsstring_address
if is_inline:
if not has_explicit_length:
print >>result,"Unicode & Inline & !Explicit is a new combo - no formula for it"
else:
location += ptr_size
else:
location = process.ReadPointerFromMemory(location,error)
elif is_special:
location = nsstring_address + ptr_size + 4
elif is_inline:
location = 2 * ptr_size + nsstring_address
if not has_explicit_length:
location += 1
else:
location = 2 * ptr_size + nsstring_address
location = process.ReadPointerFromMemory(location,error)
print >>result,"Expected data location: 0x%x\n" % (location)
print >>result,"1K of data around location: %s\n" % read_memory(process,location,1024)
print >>result,"5K of data around string pointer: %s\n" % read_memory(process,nsstring_address,1024*5)
def __lldb_init_module(debugger, internal_dict): def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand("command script add -f %s.diagnose_nsstring_Command_Impl diagnose-nsstring" % __name__) debugger.HandleCommand(
print 'The "diagnose-nsstring" command has been installed, type "help diagnose-nsstring" for detailed help.' "command script add -f %s.diagnose_nsstring_Command_Impl diagnose-nsstring" %
__name__)
print 'The "diagnose-nsstring" command has been installed, type "help diagnose-nsstring" for detailed help.'
__lldb_init_module(lldb.debugger,None) __lldb_init_module(lldb.debugger, None)
__lldb_init_module = None __lldb_init_module = None

View File

@ -13,258 +13,301 @@ import shlex
# Print the frame number, pc, frame pointer, module UUID and function name # Print the frame number, pc, frame pointer, module UUID and function name
# Returns the SBModule that contains the PC, if it could be found # Returns the SBModule that contains the PC, if it could be found
def backtrace_print_frame (target, frame_num, addr, fp):
process = target.GetProcess()
addr_for_printing = addr
addr_width = process.GetAddressByteSize() * 2
if frame_num > 0:
addr = addr - 1
sbaddr = lldb.SBAddress()
try:
sbaddr.SetLoadAddress(addr, target)
module_description = ""
if sbaddr.GetModule():
module_filename = ""
module_uuid_str = sbaddr.GetModule().GetUUIDString()
if module_uuid_str == None:
module_uuid_str = ""
if sbaddr.GetModule().GetFileSpec():
module_filename = sbaddr.GetModule().GetFileSpec().GetFilename()
if module_filename == None:
module_filename = ""
if module_uuid_str != "" or module_filename != "":
module_description = '%s %s' % (module_filename, module_uuid_str)
except Exception:
print '%2d: pc==0x%-*x fp==0x%-*x' % (frame_num, addr_width, addr_for_printing, addr_width, fp)
return
sym_ctx = target.ResolveSymbolContextForAddress(sbaddr, lldb.eSymbolContextEverything) def backtrace_print_frame(target, frame_num, addr, fp):
if sym_ctx.IsValid() and sym_ctx.GetSymbol().IsValid(): process = target.GetProcess()
function_start = sym_ctx.GetSymbol().GetStartAddress().GetLoadAddress(target) addr_for_printing = addr
offset = addr - function_start addr_width = process.GetAddressByteSize() * 2
print '%2d: pc==0x%-*x fp==0x%-*x %s %s + %d' % (frame_num, addr_width, addr_for_printing, addr_width, fp, module_description, sym_ctx.GetSymbol().GetName(), offset) if frame_num > 0:
else: addr = addr - 1
print '%2d: pc==0x%-*x fp==0x%-*x %s' % (frame_num, addr_width, addr_for_printing, addr_width, fp, module_description)
return sbaddr.GetModule() sbaddr = lldb.SBAddress()
try:
sbaddr.SetLoadAddress(addr, target)
module_description = ""
if sbaddr.GetModule():
module_filename = ""
module_uuid_str = sbaddr.GetModule().GetUUIDString()
if module_uuid_str is None:
module_uuid_str = ""
if sbaddr.GetModule().GetFileSpec():
module_filename = sbaddr.GetModule().GetFileSpec().GetFilename()
if module_filename is None:
module_filename = ""
if module_uuid_str != "" or module_filename != "":
module_description = '%s %s' % (
module_filename, module_uuid_str)
except Exception:
print '%2d: pc==0x%-*x fp==0x%-*x' % (frame_num, addr_width, addr_for_printing, addr_width, fp)
return
sym_ctx = target.ResolveSymbolContextForAddress(
sbaddr, lldb.eSymbolContextEverything)
if sym_ctx.IsValid() and sym_ctx.GetSymbol().IsValid():
function_start = sym_ctx.GetSymbol().GetStartAddress().GetLoadAddress(target)
offset = addr - function_start
print '%2d: pc==0x%-*x fp==0x%-*x %s %s + %d' % (frame_num, addr_width, addr_for_printing, addr_width, fp, module_description, sym_ctx.GetSymbol().GetName(), offset)
else:
print '%2d: pc==0x%-*x fp==0x%-*x %s' % (frame_num, addr_width, addr_for_printing, addr_width, fp, module_description)
return sbaddr.GetModule()
# A simple stack walk algorithm that follows the frame chain. # A simple stack walk algorithm that follows the frame chain.
# Returns a two-element list; the first element is a list of modules # Returns a two-element list; the first element is a list of modules
# seen and the second element is a list of addresses seen during the backtrace. # seen and the second element is a list of addresses seen during the backtrace.
def simple_backtrace(debugger): def simple_backtrace(debugger):
target = debugger.GetSelectedTarget() target = debugger.GetSelectedTarget()
process = target.GetProcess() process = target.GetProcess()
cur_thread = process.GetSelectedThread() cur_thread = process.GetSelectedThread()
initial_fp = cur_thread.GetFrameAtIndex(0).GetFP() initial_fp = cur_thread.GetFrameAtIndex(0).GetFP()
# If the pseudoreg "fp" isn't recognized, on arm hardcode to r7 which is correct for Darwin programs. # If the pseudoreg "fp" isn't recognized, on arm hardcode to r7 which is
if initial_fp == lldb.LLDB_INVALID_ADDRESS and target.triple[0:3] == "arm": # correct for Darwin programs.
for reggroup in cur_thread.GetFrameAtIndex(1).registers: if initial_fp == lldb.LLDB_INVALID_ADDRESS and target.triple[0:3] == "arm":
if reggroup.GetName() == "General Purpose Registers": for reggroup in cur_thread.GetFrameAtIndex(1).registers:
for reg in reggroup: if reggroup.GetName() == "General Purpose Registers":
if reg.GetName() == "r7": for reg in reggroup:
initial_fp = int (reg.GetValue(), 16) if reg.GetName() == "r7":
initial_fp = int(reg.GetValue(), 16)
module_list = [] module_list = []
address_list = [cur_thread.GetFrameAtIndex(0).GetPC()] address_list = [cur_thread.GetFrameAtIndex(0).GetPC()]
this_module = backtrace_print_frame (target, 0, cur_thread.GetFrameAtIndex(0).GetPC(), initial_fp) this_module = backtrace_print_frame(
print_stack_frame (process, initial_fp) target, 0, cur_thread.GetFrameAtIndex(0).GetPC(), initial_fp)
print "" print_stack_frame(process, initial_fp)
if this_module != None: print ""
module_list.append (this_module) if this_module is not None:
if cur_thread.GetNumFrames() < 2: module_list.append(this_module)
if cur_thread.GetNumFrames() < 2:
return [module_list, address_list]
cur_fp = process.ReadPointerFromMemory(initial_fp, lldb.SBError())
cur_pc = process.ReadPointerFromMemory(
initial_fp + process.GetAddressByteSize(), lldb.SBError())
frame_num = 1
while cur_pc != 0 and cur_fp != 0 and cur_pc != lldb.LLDB_INVALID_ADDRESS and cur_fp != lldb.LLDB_INVALID_ADDRESS:
address_list.append(cur_pc)
this_module = backtrace_print_frame(target, frame_num, cur_pc, cur_fp)
print_stack_frame(process, cur_fp)
print ""
if this_module is not None:
module_list.append(this_module)
frame_num = frame_num + 1
next_pc = 0
next_fp = 0
if target.triple[
0:6] == "x86_64" or target.triple[
0:4] == "i386" or target.triple[
0:3] == "arm":
error = lldb.SBError()
next_pc = process.ReadPointerFromMemory(
cur_fp + process.GetAddressByteSize(), error)
if not error.Success():
next_pc = 0
next_fp = process.ReadPointerFromMemory(cur_fp, error)
if not error.Success():
next_fp = 0
# Clear the 0th bit for arm frames - this indicates it is a thumb frame
if target.triple[0:3] == "arm" and (next_pc & 1) == 1:
next_pc = next_pc & ~1
cur_pc = next_pc
cur_fp = next_fp
this_module = backtrace_print_frame(target, frame_num, cur_pc, cur_fp)
print_stack_frame(process, cur_fp)
print ""
if this_module is not None:
module_list.append(this_module)
return [module_list, address_list] return [module_list, address_list]
cur_fp = process.ReadPointerFromMemory (initial_fp, lldb.SBError())
cur_pc = process.ReadPointerFromMemory (initial_fp + process.GetAddressByteSize(), lldb.SBError())
frame_num = 1
while cur_pc != 0 and cur_fp != 0 and cur_pc != lldb.LLDB_INVALID_ADDRESS and cur_fp != lldb.LLDB_INVALID_ADDRESS:
address_list.append (cur_pc)
this_module = backtrace_print_frame (target, frame_num, cur_pc, cur_fp)
print_stack_frame (process, cur_fp)
print ""
if this_module != None:
module_list.append (this_module)
frame_num = frame_num + 1
next_pc = 0
next_fp = 0
if target.triple[0:6] == "x86_64" or target.triple[0:4] == "i386" or target.triple[0:3] == "arm":
error = lldb.SBError()
next_pc = process.ReadPointerFromMemory(cur_fp + process.GetAddressByteSize(), error)
if not error.Success():
next_pc = 0
next_fp = process.ReadPointerFromMemory(cur_fp, error)
if not error.Success():
next_fp = 0
# Clear the 0th bit for arm frames - this indicates it is a thumb frame
if target.triple[0:3] == "arm" and (next_pc & 1) == 1:
next_pc = next_pc & ~1
cur_pc = next_pc
cur_fp = next_fp
this_module = backtrace_print_frame (target, frame_num, cur_pc, cur_fp)
print_stack_frame (process, cur_fp)
print ""
if this_module != None:
module_list.append (this_module)
return [module_list, address_list]
def print_stack_frame(process, fp): def print_stack_frame(process, fp):
if fp == 0 or fp == lldb.LLDB_INVALID_ADDRESS or fp == 1: if fp == 0 or fp == lldb.LLDB_INVALID_ADDRESS or fp == 1:
return return
addr_size = process.GetAddressByteSize() addr_size = process.GetAddressByteSize()
addr = fp - (2 * addr_size) addr = fp - (2 * addr_size)
i = 0 i = 0
outline = "Stack frame from $fp-%d: " % (2 * addr_size) outline = "Stack frame from $fp-%d: " % (2 * addr_size)
error = lldb.SBError() error = lldb.SBError()
try: try:
while i < 5 and error.Success(): while i < 5 and error.Success():
address = process.ReadPointerFromMemory(addr + (i * addr_size), error) address = process.ReadPointerFromMemory(
outline += " 0x%x" % address addr + (i * addr_size), error)
i += 1 outline += " 0x%x" % address
print outline i += 1
except Exception: print outline
return except Exception:
return
def diagnose_unwind(debugger, command, result, dict): def diagnose_unwind(debugger, command, result, dict):
""" """
Gather diagnostic information to help debug incorrect unwind (backtrace) Gather diagnostic information to help debug incorrect unwind (backtrace)
behavior in lldb. When there is a backtrace that doesn't look behavior in lldb. When there is a backtrace that doesn't look
correct, run this command with the correct thread selected and a correct, run this command with the correct thread selected and a
large amount of diagnostic information will be printed, it is likely large amount of diagnostic information will be printed, it is likely
to be helpful when reporting the problem. to be helpful when reporting the problem.
""" """
command_args = shlex.split(command) command_args = shlex.split(command)
parser = create_diagnose_unwind_options() parser = create_diagnose_unwind_options()
try: try:
(options, args) = parser.parse_args(command_args) (options, args) = parser.parse_args(command_args)
except: except:
return return
target = debugger.GetSelectedTarget() target = debugger.GetSelectedTarget()
if target: if target:
process = target.GetProcess() process = target.GetProcess()
if process: if process:
thread = process.GetSelectedThread() thread = process.GetSelectedThread()
if thread: if thread:
lldb_versions_match = re.search(r'[lL][lL][dD][bB]-(\d+)([.](\d+))?([.](\d+))?', debugger.GetVersionString()) lldb_versions_match = re.search(
lldb_version = 0 r'[lL][lL][dD][bB]-(\d+)([.](\d+))?([.](\d+))?',
lldb_minor = 0 debugger.GetVersionString())
if len(lldb_versions_match.groups()) >= 1 and lldb_versions_match.groups()[0]: lldb_version = 0
lldb_major = int(lldb_versions_match.groups()[0]) lldb_minor = 0
if len(lldb_versions_match.groups()) >= 5 and lldb_versions_match.groups()[4]: if len(lldb_versions_match.groups()
lldb_minor = int(lldb_versions_match.groups()[4]) ) >= 1 and lldb_versions_match.groups()[0]:
lldb_major = int(lldb_versions_match.groups()[0])
if len(lldb_versions_match.groups()
) >= 5 and lldb_versions_match.groups()[4]:
lldb_minor = int(lldb_versions_match.groups()[4])
modules_seen = [] modules_seen = []
addresses_seen = [] addresses_seen = []
print 'LLDB version %s' % debugger.GetVersionString() print 'LLDB version %s' % debugger.GetVersionString()
print 'Unwind diagnostics for thread %d' % thread.GetIndexID() print 'Unwind diagnostics for thread %d' % thread.GetIndexID()
print "" print ""
print "=============================================================================================" print "============================================================================================="
print "" print ""
print "OS plugin setting:" print "OS plugin setting:"
debugger.HandleCommand("settings show target.process.python-os-plugin-path") debugger.HandleCommand(
print "" "settings show target.process.python-os-plugin-path")
print "Live register context:" print ""
thread.SetSelectedFrame(0) print "Live register context:"
debugger.HandleCommand("register read") thread.SetSelectedFrame(0)
print "" debugger.HandleCommand("register read")
print "=============================================================================================" print ""
print "" print "============================================================================================="
print "lldb's unwind algorithm:" print ""
print "" print "lldb's unwind algorithm:"
frame_num = 0 print ""
for frame in thread.frames: frame_num = 0
if not frame.IsInlined(): for frame in thread.frames:
this_module = backtrace_print_frame (target, frame_num, frame.GetPC(), frame.GetFP()) if not frame.IsInlined():
print_stack_frame (process, frame.GetFP()) this_module = backtrace_print_frame(
print "" target, frame_num, frame.GetPC(), frame.GetFP())
if this_module != None: print_stack_frame(process, frame.GetFP())
modules_seen.append (this_module) print ""
addresses_seen.append (frame.GetPC()) if this_module is not None:
frame_num = frame_num + 1 modules_seen.append(this_module)
print "" addresses_seen.append(frame.GetPC())
print "=============================================================================================" frame_num = frame_num + 1
print "" print ""
print "Simple stack walk algorithm:" print "============================================================================================="
print "" print ""
(module_list, address_list) = simple_backtrace(debugger) print "Simple stack walk algorithm:"
if module_list and module_list != None: print ""
modules_seen += module_list (module_list, address_list) = simple_backtrace(debugger)
if address_list and address_list != None: if module_list and module_list is not None:
addresses_seen = set(addresses_seen) modules_seen += module_list
addresses_seen.update(set(address_list)) if address_list and address_list is not None:
addresses_seen = set(addresses_seen)
addresses_seen.update(set(address_list))
print "" print ""
print "=============================================================================================" print "============================================================================================="
print "" print ""
print "Modules seen in stack walks:" print "Modules seen in stack walks:"
print "" print ""
modules_already_seen = set() modules_already_seen = set()
for module in modules_seen: for module in modules_seen:
if module != None and module.GetFileSpec().GetFilename() != None: if module is not None and module.GetFileSpec().GetFilename() is not None:
if not module.GetFileSpec().GetFilename() in modules_already_seen: if not module.GetFileSpec().GetFilename() in modules_already_seen:
debugger.HandleCommand('image list %s' % module.GetFileSpec().GetFilename()) debugger.HandleCommand(
modules_already_seen.add(module.GetFileSpec().GetFilename()) 'image list %s' %
module.GetFileSpec().GetFilename())
modules_already_seen.add(
module.GetFileSpec().GetFilename())
print "" print ""
print "=============================================================================================" print "============================================================================================="
print "" print ""
print "Disassembly ofaddresses seen in stack walks:" print "Disassembly ofaddresses seen in stack walks:"
print "" print ""
additional_addresses_to_disassemble = addresses_seen additional_addresses_to_disassemble = addresses_seen
for frame in thread.frames: for frame in thread.frames:
if not frame.IsInlined(): if not frame.IsInlined():
print "--------------------------------------------------------------------------------------" print "--------------------------------------------------------------------------------------"
print "" print ""
print "Disassembly of %s, frame %d, address 0x%x" % (frame.GetFunctionName(), frame.GetFrameID(), frame.GetPC()) print "Disassembly of %s, frame %d, address 0x%x" % (frame.GetFunctionName(), frame.GetFrameID(), frame.GetPC())
print "" print ""
if target.triple[0:6] == "x86_64" or target.triple[0:4] == "i386": if target.triple[
debugger.HandleCommand('disassemble -F att -a 0x%x' % frame.GetPC()) 0:6] == "x86_64" or target.triple[
else: 0:4] == "i386":
debugger.HandleCommand('disassemble -a 0x%x' % frame.GetPC()) debugger.HandleCommand(
if frame.GetPC() in additional_addresses_to_disassemble: 'disassemble -F att -a 0x%x' % frame.GetPC())
additional_addresses_to_disassemble.remove (frame.GetPC()) else:
debugger.HandleCommand(
'disassemble -a 0x%x' %
frame.GetPC())
if frame.GetPC() in additional_addresses_to_disassemble:
additional_addresses_to_disassemble.remove(
frame.GetPC())
for address in list(additional_addresses_to_disassemble): for address in list(additional_addresses_to_disassemble):
print "--------------------------------------------------------------------------------------" print "--------------------------------------------------------------------------------------"
print "" print ""
print "Disassembly of 0x%x" % address print "Disassembly of 0x%x" % address
print "" print ""
if target.triple[0:6] == "x86_64" or target.triple[0:4] == "i386": if target.triple[
debugger.HandleCommand('disassemble -F att -a 0x%x' % address) 0:6] == "x86_64" or target.triple[
else: 0:4] == "i386":
debugger.HandleCommand('disassemble -a 0x%x' % address) debugger.HandleCommand(
'disassemble -F att -a 0x%x' % address)
else:
debugger.HandleCommand('disassemble -a 0x%x' % address)
print "" print ""
print "=============================================================================================" print "============================================================================================="
print "" print ""
additional_addresses_to_show_unwind = addresses_seen additional_addresses_to_show_unwind = addresses_seen
for frame in thread.frames: for frame in thread.frames:
if not frame.IsInlined(): if not frame.IsInlined():
print "--------------------------------------------------------------------------------------" print "--------------------------------------------------------------------------------------"
print "" print ""
print "Unwind instructions for %s, frame %d" % (frame.GetFunctionName(), frame.GetFrameID()) print "Unwind instructions for %s, frame %d" % (frame.GetFunctionName(), frame.GetFrameID())
print "" print ""
debugger.HandleCommand('image show-unwind -a "0x%x"' % frame.GetPC()) debugger.HandleCommand(
if frame.GetPC() in additional_addresses_to_show_unwind: 'image show-unwind -a "0x%x"' % frame.GetPC())
additional_addresses_to_show_unwind.remove (frame.GetPC()) if frame.GetPC() in additional_addresses_to_show_unwind:
additional_addresses_to_show_unwind.remove(
frame.GetPC())
for address in list(additional_addresses_to_show_unwind):
print "--------------------------------------------------------------------------------------"
print ""
print "Unwind instructions for 0x%x" % address
print ""
debugger.HandleCommand(
'image show-unwind -a "0x%x"' % address)
for address in list(additional_addresses_to_show_unwind):
print "--------------------------------------------------------------------------------------"
print ""
print "Unwind instructions for 0x%x" % address
print ""
debugger.HandleCommand('image show-unwind -a "0x%x"' % address)
def create_diagnose_unwind_options(): def create_diagnose_unwind_options():
usage = "usage: %prog" usage = "usage: %prog"
description='''Print diagnostic information about a thread backtrace which will help to debug unwind problems''' description = '''Print diagnostic information about a thread backtrace which will help to debug unwind problems'''
parser = optparse.OptionParser(description=description, prog='diagnose_unwind',usage=usage) parser = optparse.OptionParser(
return parser description=description,
prog='diagnose_unwind',
usage=usage)
return parser
lldb.debugger.HandleCommand('command script add -f %s.diagnose_unwind diagnose-unwind' % __name__) lldb.debugger.HandleCommand(
'command script add -f %s.diagnose_unwind diagnose-unwind' %
__name__)
print 'The "diagnose-unwind" command has been installed, type "help diagnose-unwind" for detailed help.' print 'The "diagnose-unwind" command has been installed, type "help diagnose-unwind" for detailed help.'

View File

@ -1,27 +1,28 @@
class LookupDictionary(dict): class LookupDictionary(dict):
""" """
a dictionary which can lookup value by key, or keys by value a dictionary which can lookup value by key, or keys by value
""" """
def __init__(self, items=[]): def __init__(self, items=[]):
"""items can be a list of pair_lists or a dictionary""" """items can be a list of pair_lists or a dictionary"""
dict.__init__(self, items) dict.__init__(self, items)
def get_keys_for_value(self, value, fail_value = None): def get_keys_for_value(self, value, fail_value=None):
"""find the key(s) as a list given a value""" """find the key(s) as a list given a value"""
list_result = [item[0] for item in self.items() if item[1] == value] list_result = [item[0] for item in self.items() if item[1] == value]
if len(list_result) > 0: if len(list_result) > 0:
return list_result return list_result
return fail_value return fail_value
def get_first_key_for_value(self, value, fail_value = None): def get_first_key_for_value(self, value, fail_value=None):
"""return the first key of this dictionary given the value""" """return the first key of this dictionary given the value"""
list_result = [item[0] for item in self.items() if item[1] == value] list_result = [item[0] for item in self.items() if item[1] == value]
if len(list_result) > 0: if len(list_result) > 0:
return list_result[0] return list_result[0]
return fail_value return fail_value
def get_value(self, key, fail_value = None): def get_value(self, key, fail_value=None):
"""find the value given a key""" """find the value given a key"""
if key in self: if key in self:
return self[key] return self[key]
@ -29,12 +30,12 @@ class LookupDictionary(dict):
class Enum(LookupDictionary): class Enum(LookupDictionary):
def __init__(self, initial_value=0, items=[]): def __init__(self, initial_value=0, items=[]):
"""items can be a list of pair_lists or a dictionary""" """items can be a list of pair_lists or a dictionary"""
LookupDictionary.__init__(self, items) LookupDictionary.__init__(self, items)
self.value = initial_value self.value = initial_value
def set_value(self, v): def set_value(self, v):
v_typename = typeof(v).__name__ v_typename = typeof(v).__name__
if v_typename == 'str': if v_typename == 'str':
@ -44,18 +45,18 @@ class Enum(LookupDictionary):
v = 0 v = 0
else: else:
self.value = v self.value = v
def get_enum_value(self): def get_enum_value(self):
return self.value return self.value
def get_enum_name(self): def get_enum_name(self):
return self.__str__() return self.__str__()
def __str__(self): def __str__(self):
s = self.get_first_key_for_value (self.value, None) s = self.get_first_key_for_value(self.value, None)
if s == None: if s is None:
s = "%#8.8x" % self.value s = "%#8.8x" % self.value
return s return s
def __repr__(self): def __repr__(self):
return self.__str__() return self.__str__()

View File

@ -1,40 +1,82 @@
#!/usr/bin/python #!/usr/bin/python
import argparse, datetime, re, subprocess, sys, time import argparse
import datetime
import re
import subprocess
import sys
import time
parser = argparse.ArgumentParser(description="Run an exhaustive test of the LLDB disassembler for a specific architecture.") parser = argparse.ArgumentParser(
description="Run an exhaustive test of the LLDB disassembler for a specific architecture.")
parser.add_argument('--arch', required=True, action='store', help='The architecture whose disassembler is to be tested') parser.add_argument(
parser.add_argument('--bytes', required=True, action='store', type=int, help='The byte width of instructions for that architecture') '--arch',
parser.add_argument('--random', required=False, action='store_true', help='Enables non-sequential testing') required=True,
parser.add_argument('--start', required=False, action='store', type=int, help='The first instruction value to test') action='store',
parser.add_argument('--skip', required=False, action='store', type=int, help='The interval between instructions to test') help='The architecture whose disassembler is to be tested')
parser.add_argument('--log', required=False, action='store', help='A log file to write the most recent instruction being tested') parser.add_argument(
parser.add_argument('--time', required=False, action='store_true', help='Every 100,000 instructions, print an ETA to standard out') '--bytes',
parser.add_argument('--lldb', required=False, action='store', help='The path to LLDB.framework, if LLDB should be overridden') required=True,
action='store',
type=int,
help='The byte width of instructions for that architecture')
parser.add_argument(
'--random',
required=False,
action='store_true',
help='Enables non-sequential testing')
parser.add_argument(
'--start',
required=False,
action='store',
type=int,
help='The first instruction value to test')
parser.add_argument(
'--skip',
required=False,
action='store',
type=int,
help='The interval between instructions to test')
parser.add_argument(
'--log',
required=False,
action='store',
help='A log file to write the most recent instruction being tested')
parser.add_argument(
'--time',
required=False,
action='store_true',
help='Every 100,000 instructions, print an ETA to standard out')
parser.add_argument(
'--lldb',
required=False,
action='store',
help='The path to LLDB.framework, if LLDB should be overridden')
arguments = sys.argv[1:] arguments = sys.argv[1:]
arg_ns = parser.parse_args(arguments) arg_ns = parser.parse_args(arguments)
def AddLLDBToSysPathOnMacOSX(): def AddLLDBToSysPathOnMacOSX():
def GetLLDBFrameworkPath(): def GetLLDBFrameworkPath():
lldb_path = subprocess.check_output(["xcrun", "-find", "lldb"]) lldb_path = subprocess.check_output(["xcrun", "-find", "lldb"])
re_result = re.match("(.*)/Developer/usr/bin/lldb", lldb_path) re_result = re.match("(.*)/Developer/usr/bin/lldb", lldb_path)
if re_result == None: if re_result is None:
return None return None
xcode_contents_path = re_result.group(1) xcode_contents_path = re_result.group(1)
return xcode_contents_path + "/SharedFrameworks/LLDB.framework" return xcode_contents_path + "/SharedFrameworks/LLDB.framework"
lldb_framework_path = GetLLDBFrameworkPath() lldb_framework_path = GetLLDBFrameworkPath()
if lldb_framework_path == None: if lldb_framework_path is None:
print "Couldn't find LLDB.framework" print "Couldn't find LLDB.framework"
sys.exit(-1) sys.exit(-1)
sys.path.append(lldb_framework_path + "/Resources/Python") sys.path.append(lldb_framework_path + "/Resources/Python")
if arg_ns.lldb == None: if arg_ns.lldb is None:
AddLLDBToSysPathOnMacOSX() AddLLDBToSysPathOnMacOSX()
else: else:
sys.path.append(arg_ns.lldb + "/Resources/Python") sys.path.append(arg_ns.lldb + "/Resources/Python")
@ -53,16 +95,20 @@ if target.IsValid() == False:
print "Couldn't create an SBTarget for architecture " + arg_ns.arch print "Couldn't create an SBTarget for architecture " + arg_ns.arch
sys.exit(-1) sys.exit(-1)
def ResetLogFile(log_file): def ResetLogFile(log_file):
if log_file != sys.stdout: if log_file != sys.stdout:
log_file.seek(0) log_file.seek(0)
def PrintByteArray(log_file, byte_array): def PrintByteArray(log_file, byte_array):
for byte in byte_array: for byte in byte_array:
print >>log_file, hex(byte) + " ", print >>log_file, hex(byte) + " ",
print >>log_file print >>log_file
class SequentialInstructionProvider: class SequentialInstructionProvider:
def __init__(self, byte_width, log_file, start=0, skip=1): def __init__(self, byte_width, log_file, start=0, skip=1):
self.m_byte_width = byte_width self.m_byte_width = byte_width
self.m_log_file = log_file self.m_log_file = log_file
@ -70,70 +116,83 @@ class SequentialInstructionProvider:
self.m_skip = skip self.m_skip = skip
self.m_value = start self.m_value = start
self.m_last = (1 << (byte_width * 8)) - 1 self.m_last = (1 << (byte_width * 8)) - 1
def PrintCurrentState(self, ret): def PrintCurrentState(self, ret):
ResetLogFile(self.m_log_file) ResetLogFile(self.m_log_file)
print >>self.m_log_file, self.m_value print >>self.m_log_file, self.m_value
PrintByteArray(self.m_log_file, ret) PrintByteArray(self.m_log_file, ret)
def GetNextInstruction(self): def GetNextInstruction(self):
if self.m_value > self.m_last: if self.m_value > self.m_last:
return None return None
ret = bytearray(self.m_byte_width) ret = bytearray(self.m_byte_width)
for i in range(self.m_byte_width): for i in range(self.m_byte_width):
ret[self.m_byte_width - (i + 1)] = (self.m_value >> (i * 8)) & 255 ret[self.m_byte_width - (i + 1)] = (self.m_value >> (i * 8)) & 255
self.PrintCurrentState(ret) self.PrintCurrentState(ret)
self.m_value += self.m_skip self.m_value += self.m_skip
return ret return ret
def GetNumInstructions(self): def GetNumInstructions(self):
return (self.m_last - self.m_start) / self.m_skip return (self.m_last - self.m_start) / self.m_skip
def __iter__(self): def __iter__(self):
return self return self
def next(self): def next(self):
ret = self.GetNextInstruction() ret = self.GetNextInstruction()
if ret == None: if ret is None:
raise StopIteration raise StopIteration
return ret return ret
class RandomInstructionProvider: class RandomInstructionProvider:
def __init__(self, byte_width, log_file): def __init__(self, byte_width, log_file):
self.m_byte_width = byte_width self.m_byte_width = byte_width
self.m_log_file = log_file self.m_log_file = log_file
self.m_random_file = open("/dev/random", 'r') self.m_random_file = open("/dev/random", 'r')
def PrintCurrentState(self, ret): def PrintCurrentState(self, ret):
ResetLogFile(self.m_log_file) ResetLogFile(self.m_log_file)
PrintByteArray(self.m_log_file, ret) PrintByteArray(self.m_log_file, ret)
def GetNextInstruction(self): def GetNextInstruction(self):
ret = bytearray(self.m_byte_width) ret = bytearray(self.m_byte_width)
for i in range(self.m_byte_width): for i in range(self.m_byte_width):
ret[i] = self.m_random_file.read(1) ret[i] = self.m_random_file.read(1)
self.PrintCurrentState(ret) self.PrintCurrentState(ret)
return ret return ret
def __iter__(self): def __iter__(self):
return self return self
def next(self): def next(self):
ret = self.GetNextInstruction() ret = self.GetNextInstruction()
if ret == None: if ret is None:
raise StopIteration raise StopIteration
return ret return ret
log_file = None log_file = None
def GetProviderWithArguments(args): def GetProviderWithArguments(args):
global log_file global log_file
if args.log != None: if args.log is not None:
log_file = open(args.log, 'w') log_file = open(args.log, 'w')
else: else:
log_file = sys.stdout log_file = sys.stdout
instruction_provider = None instruction_provider = None
if args.random == True: if args.random:
instruction_provider = RandomInstructionProvider(args.bytes, log_file) instruction_provider = RandomInstructionProvider(args.bytes, log_file)
else: else:
start = 0 start = 0
skip = 1 skip = 1
if args.start != None: if args.start is not None:
start = args.start start = args.start
if args.skip != None: if args.skip is not None:
skip = args.skip skip = args.skip
instruction_provider = SequentialInstructionProvider(args.bytes, log_file, start, skip) instruction_provider = SequentialInstructionProvider(
args.bytes, log_file, start, skip)
return instruction_provider return instruction_provider
instruction_provider = GetProviderWithArguments(arg_ns) instruction_provider = GetProviderWithArguments(arg_ns)
@ -149,10 +208,13 @@ if actually_time:
for inst_bytes in instruction_provider: for inst_bytes in instruction_provider:
if actually_time: if actually_time:
if (num_instructions_logged != 0) and (num_instructions_logged % 100000 == 0): if (num_instructions_logged != 0) and (
num_instructions_logged % 100000 == 0):
curr_time = time.time() curr_time = time.time()
elapsed_time = curr_time - start_time elapsed_time = curr_time - start_time
remaining_time = float(total_num_instructions - num_instructions_logged) * (float(elapsed_time) / float(num_instructions_logged)) remaining_time = float(
total_num_instructions - num_instructions_logged) * (
float(elapsed_time) / float(num_instructions_logged))
print str(datetime.timedelta(seconds=remaining_time)) print str(datetime.timedelta(seconds=remaining_time))
num_instructions_logged = num_instructions_logged + 1 num_instructions_logged = num_instructions_logged + 1
inst_list = target.GetInstructions(fake_address, inst_bytes) inst_list = target.GetInstructions(fake_address, inst_bytes)

View File

@ -12,10 +12,12 @@ import lldb
import os import os
import sys import sys
def disassemble_instructions (insts):
def disassemble_instructions(insts):
for i in insts: for i in insts:
print i print i
def usage(): def usage():
print "Usage: disasm.py [-n name] executable-image" print "Usage: disasm.py [-n name] executable-image"
print " By default, it breaks at and disassembles the 'main' function." print " By default, it breaks at and disassembles the 'main' function."
@ -36,63 +38,69 @@ else:
# Create a new debugger instance # Create a new debugger instance
debugger = lldb.SBDebugger.Create() debugger = lldb.SBDebugger.Create()
# When we step or continue, don't return from the function until the process # When we step or continue, don't return from the function until the process
# stops. We do this by setting the async mode to false. # stops. We do this by setting the async mode to false.
debugger.SetAsync (False) debugger.SetAsync(False)
# Create a target from a file and arch # Create a target from a file and arch
print "Creating a target for '%s'" % exe print "Creating a target for '%s'" % exe
target = debugger.CreateTargetWithFileAndArch (exe, lldb.LLDB_ARCH_DEFAULT) target = debugger.CreateTargetWithFileAndArch(exe, lldb.LLDB_ARCH_DEFAULT)
if target: if target:
# If the target is valid set a breakpoint at main # If the target is valid set a breakpoint at main
main_bp = target.BreakpointCreateByName (fname, target.GetExecutable().GetFilename()); main_bp = target.BreakpointCreateByName(
fname, target.GetExecutable().GetFilename())
print main_bp print main_bp
# Launch the process. Since we specified synchronous mode, we won't return # Launch the process. Since we specified synchronous mode, we won't return
# from this function until we hit the breakpoint at main # from this function until we hit the breakpoint at main
process = target.LaunchSimple (None, None, os.getcwd()) process = target.LaunchSimple(None, None, os.getcwd())
# Make sure the launch went ok # Make sure the launch went ok
if process: if process:
# Print some simple process info # Print some simple process info
state = process.GetState () state = process.GetState()
print process print process
if state == lldb.eStateStopped: if state == lldb.eStateStopped:
# Get the first thread # Get the first thread
thread = process.GetThreadAtIndex (0) thread = process.GetThreadAtIndex(0)
if thread: if thread:
# Print some simple thread info # Print some simple thread info
print thread print thread
# Get the first frame # Get the first frame
frame = thread.GetFrameAtIndex (0) frame = thread.GetFrameAtIndex(0)
if frame: if frame:
# Print some simple frame info # Print some simple frame info
print frame print frame
function = frame.GetFunction() function = frame.GetFunction()
# See if we have debug info (a function) # See if we have debug info (a function)
if function: if function:
# We do have a function, print some info for the function # We do have a function, print some info for the
# function
print function print function
# Now get all instructions for this function and print them # Now get all instructions for this function and print
# them
insts = function.GetInstructions(target) insts = function.GetInstructions(target)
disassemble_instructions (insts) disassemble_instructions(insts)
else: else:
# See if we have a symbol in the symbol table for where we stopped # See if we have a symbol in the symbol table for where
symbol = frame.GetSymbol(); # we stopped
symbol = frame.GetSymbol()
if symbol: if symbol:
# We do have a symbol, print some info for the symbol # We do have a symbol, print some info for the
# symbol
print symbol print symbol
# Now get all instructions for this symbol and print them # Now get all instructions for this symbol and
# print them
insts = symbol.GetInstructions(target) insts = symbol.GetInstructions(target)
disassemble_instructions (insts) disassemble_instructions(insts)
registerList = frame.GetRegisters() registerList = frame.GetRegisters()
print "Frame registers (size of register set = %d):" % registerList.GetSize() print "Frame registers (size of register set = %d):" % registerList.GetSize()
for value in registerList: for value in registerList:
#print value # print value
print "%s (number of children = %d):" % (value.GetName(), value.GetNumChildren()) print "%s (number of children = %d):" % (value.GetName(), value.GetNumChildren())
for child in value: for child in value:
print "Name: ", child.GetName(), " Value: ", child.GetValue() print "Name: ", child.GetName(), " Value: ", child.GetValue()
@ -111,9 +119,8 @@ if target:
elif state == lldb.eStateExited: elif state == lldb.eStateExited:
print "Didn't hit the breakpoint at main, program has exited..." print "Didn't hit the breakpoint at main, program has exited..."
else: else:
print "Unexpected process state: %s, killing process..." % debugger.StateAsCString (state) print "Unexpected process state: %s, killing process..." % debugger.StateAsCString(state)
process.Kill() process.Kill()
lldb.SBDebugger.Terminate() lldb.SBDebugger.Terminate()

View File

@ -4,16 +4,17 @@ import string
import struct import struct
import sys import sys
class FileExtract: class FileExtract:
'''Decode binary data from a file''' '''Decode binary data from a file'''
def __init__(self, f, b = '='): def __init__(self, f, b='='):
'''Initialize with an open binary file and optional byte order''' '''Initialize with an open binary file and optional byte order'''
self.file = f self.file = f
self.byte_order = b self.byte_order = b
self.offsets = list() self.offsets = list()
def set_byte_order(self, b): def set_byte_order(self, b):
'''Set the byte order, valid values are "big", "little", "swap", "native", "<", ">", "@", "="''' '''Set the byte order, valid values are "big", "little", "swap", "native", "<", ">", "@", "="'''
if b == 'big': if b == 'big':
@ -32,18 +33,18 @@ class FileExtract:
def is_in_memory(self): def is_in_memory(self):
return False return False
def seek(self, offset, whence = 0): def seek(self, offset, whence=0):
if self.file: if self.file:
return self.file.seek(offset, whence) return self.file.seek(offset, whence)
raise ValueError raise ValueError
def tell(self): def tell(self):
if self.file: if self.file:
return self.file.tell() return self.file.tell()
raise ValueError raise ValueError
def read_size (self, byte_size): def read_size(self, byte_size):
s = self.file.read(byte_size) s = self.file.read(byte_size)
if len(s) != byte_size: if len(s) != byte_size:
return None return None
@ -53,12 +54,12 @@ class FileExtract:
'''Push the current file offset and seek to "offset"''' '''Push the current file offset and seek to "offset"'''
self.offsets.append(self.file.tell()) self.offsets.append(self.file.tell())
self.file.seek(offset, 0) self.file.seek(offset, 0)
def pop_offset_and_seek(self): def pop_offset_and_seek(self):
'''Pop a previously pushed file offset, or do nothing if there were no previously pushed offsets''' '''Pop a previously pushed file offset, or do nothing if there were no previously pushed offsets'''
if len(self.offsets) > 0: if len(self.offsets) > 0:
self.file.seek(self.offsets.pop()) self.file.seek(self.offsets.pop())
def get_sint8(self, fail_value=0): def get_sint8(self, fail_value=0):
'''Extract a single int8_t from the binary file at the current file position, returns a single integer''' '''Extract a single int8_t from the binary file at the current file position, returns a single integer'''
s = self.read_size(1) s = self.read_size(1)
@ -112,7 +113,7 @@ class FileExtract:
return v return v
else: else:
return fail_value return fail_value
def get_sint64(self, fail_value=0): def get_sint64(self, fail_value=0):
'''Extract a single int64_t from the binary file at the current file position, returns a single integer''' '''Extract a single int64_t from the binary file at the current file position, returns a single integer'''
s = self.read_size(8) s = self.read_size(8)
@ -131,7 +132,11 @@ class FileExtract:
else: else:
return fail_value return fail_value
def get_fixed_length_c_string(self, n, fail_value='', isprint_only_with_space_padding=False): def get_fixed_length_c_string(
self,
n,
fail_value='',
isprint_only_with_space_padding=False):
'''Extract a single fixed length C string from the binary file at the current file position, returns a single C string''' '''Extract a single fixed length C string from the binary file at the current file position, returns a single C string'''
s = self.read_size(n) s = self.read_size(n)
if s: if s:
@ -174,7 +179,7 @@ class FileExtract:
def get_n_sint16(self, n, fail_value=0): def get_n_sint16(self, n, fail_value=0):
'''Extract "n" int16_t integers from the binary file at the current file position, returns a list of integers''' '''Extract "n" int16_t integers from the binary file at the current file position, returns a list of integers'''
s = self.read_size(2*n) s = self.read_size(2 * n)
if s: if s:
return struct.unpack(self.byte_order + ("%u" % n) + 'h', s) return struct.unpack(self.byte_order + ("%u" % n) + 'h', s)
else: else:
@ -182,7 +187,7 @@ class FileExtract:
def get_n_uint16(self, n, fail_value=0): def get_n_uint16(self, n, fail_value=0):
'''Extract "n" uint16_t integers from the binary file at the current file position, returns a list of integers''' '''Extract "n" uint16_t integers from the binary file at the current file position, returns a list of integers'''
s = self.read_size(2*n) s = self.read_size(2 * n)
if s: if s:
return struct.unpack(self.byte_order + ("%u" % n) + 'H', s) return struct.unpack(self.byte_order + ("%u" % n) + 'H', s)
else: else:
@ -190,7 +195,7 @@ class FileExtract:
def get_n_sint32(self, n, fail_value=0): def get_n_sint32(self, n, fail_value=0):
'''Extract "n" int32_t integers from the binary file at the current file position, returns a list of integers''' '''Extract "n" int32_t integers from the binary file at the current file position, returns a list of integers'''
s = self.read_size(4*n) s = self.read_size(4 * n)
if s: if s:
return struct.unpack(self.byte_order + ("%u" % n) + 'i', s) return struct.unpack(self.byte_order + ("%u" % n) + 'i', s)
else: else:
@ -198,7 +203,7 @@ class FileExtract:
def get_n_uint32(self, n, fail_value=0): def get_n_uint32(self, n, fail_value=0):
'''Extract "n" uint32_t integers from the binary file at the current file position, returns a list of integers''' '''Extract "n" uint32_t integers from the binary file at the current file position, returns a list of integers'''
s = self.read_size(4*n) s = self.read_size(4 * n)
if s: if s:
return struct.unpack(self.byte_order + ("%u" % n) + 'I', s) return struct.unpack(self.byte_order + ("%u" % n) + 'I', s)
else: else:
@ -206,7 +211,7 @@ class FileExtract:
def get_n_sint64(self, n, fail_value=0): def get_n_sint64(self, n, fail_value=0):
'''Extract "n" int64_t integers from the binary file at the current file position, returns a list of integers''' '''Extract "n" int64_t integers from the binary file at the current file position, returns a list of integers'''
s = self.read_size(8*n) s = self.read_size(8 * n)
if s: if s:
return struct.unpack(self.byte_order + ("%u" % n) + 'q', s) return struct.unpack(self.byte_order + ("%u" % n) + 'q', s)
else: else:
@ -214,7 +219,7 @@ class FileExtract:
def get_n_uint64(self, n, fail_value=0): def get_n_uint64(self, n, fail_value=0):
'''Extract "n" uint64_t integers from the binary file at the current file position, returns a list of integers''' '''Extract "n" uint64_t integers from the binary file at the current file position, returns a list of integers'''
s = self.read_size(8*n) s = self.read_size(8 * n)
if s: if s:
return struct.unpack(self.byte_order + ("%u" % n) + 'Q', s) return struct.unpack(self.byte_order + ("%u" % n) + 'Q', s)
else: else:

View File

@ -1,5 +1,6 @@
import lldb import lldb
def disassemble(debugger, command, result, dict): def disassemble(debugger, command, result, dict):
if lldb.frame.function: if lldb.frame.function:
instructions = lldb.frame.function.instructions instructions = lldb.frame.function.instructions
@ -9,7 +10,7 @@ def disassemble(debugger, command, result, dict):
instructions = lldb.frame.symbol.instructions instructions = lldb.frame.symbol.instructions
start_addr = lldb.frame.symbol.addr.load_addr start_addr = lldb.frame.symbol.addr.load_addr
name = lldb.frame.symbol.name name = lldb.frame.symbol.name
for inst in instructions: for inst in instructions:
inst_addr = inst.addr.load_addr inst_addr = inst.addr.load_addr
inst_offset = inst_addr - start_addr inst_offset = inst_addr - start_addr
@ -18,7 +19,8 @@ def disassemble(debugger, command, result, dict):
print "<%s + %-4u> 0x%x %8s %s ; %s" % (name, inst_offset, inst_addr, inst.mnemonic, inst.operands, comment) print "<%s + %-4u> 0x%x %8s %s ; %s" % (name, inst_offset, inst_addr, inst.mnemonic, inst.operands, comment)
else: else:
print "<%s + %-4u> 0x%x %8s %s" % (name, inst_offset, inst_addr, inst.mnemonic, inst.operands) print "<%s + %-4u> 0x%x %8s %s" % (name, inst_offset, inst_addr, inst.mnemonic, inst.operands)
# Install the command when the module gets imported # Install the command when the module gets imported
lldb.debugger.HandleCommand('command script add -f gdb_disassemble.disassemble gdb-disassemble') lldb.debugger.HandleCommand(
print 'Installed "gdb-disassemble" command for disassembly' 'command script add -f gdb_disassemble.disassemble gdb-disassemble')
print 'Installed "gdb-disassemble" command for disassembly'

File diff suppressed because it is too large Load Diff

View File

@ -15,58 +15,92 @@ import os
import shlex import shlex
import sys import sys
def get_globals(raw_path, options): def get_globals(raw_path, options):
error = lldb.SBError() error = lldb.SBError()
# Resolve the path if needed # Resolve the path if needed
path = os.path.expanduser(raw_path) path = os.path.expanduser(raw_path)
# Create a target using path + options # Create a target using path + options
target = lldb.debugger.CreateTarget(path, options.arch, options.platform, False, error) target = lldb.debugger.CreateTarget(
path, options.arch, options.platform, False, error)
if target: if target:
# Get the executable module # Get the executable module
module = target.module[target.executable.basename] module = target.module[target.executable.basename]
if module: if module:
# Keep track of which variables we have already looked up # Keep track of which variables we have already looked up
global_names = list() global_names = list()
# Iterate through all symbols in the symbol table and watch for any DATA symbols # Iterate through all symbols in the symbol table and watch for any
# DATA symbols
for symbol in module.symbols: for symbol in module.symbols:
if symbol.type == lldb.eSymbolTypeData: if symbol.type == lldb.eSymbolTypeData:
# The symbol is a DATA symbol, lets try and find all global variables # The symbol is a DATA symbol, lets try and find all global variables
# that match this name and print them # that match this name and print them
global_name = symbol.name global_name = symbol.name
# Make sure we don't lookup the same variable twice # Make sure we don't lookup the same variable twice
if global_name not in global_names: if global_name not in global_names:
global_names.append(global_name) global_names.append(global_name)
# Find all global variables by name # Find all global variables by name
global_variable_list = module.FindGlobalVariables (target, global_name, lldb.UINT32_MAX) global_variable_list = module.FindGlobalVariables(
target, global_name, lldb.UINT32_MAX)
if global_variable_list: if global_variable_list:
# Print results for anything that matched # Print results for anything that matched
for global_variable in global_variable_list: for global_variable in global_variable_list:
print 'name = %s' % global_variable.name # returns the global variable name as a string # returns the global variable name as a string
print 'value = %s' % global_variable.value # Returns the variable value as a string print 'name = %s' % global_variable.name
# Returns the variable value as a string
print 'value = %s' % global_variable.value
print 'type = %s' % global_variable.type # Returns an lldb.SBType object print 'type = %s' % global_variable.type # Returns an lldb.SBType object
print 'addr = %s' % global_variable.addr # Returns an lldb.SBAddress (section offset address) for this global # Returns an lldb.SBAddress (section offset
print 'file_addr = 0x%x' % global_variable.addr.file_addr # Returns the file virtual address for this global # address) for this global
print 'location = %s' % global_variable.location # returns the global variable value as a string print 'addr = %s' % global_variable.addr
print 'size = %s' % global_variable.size # Returns the size in bytes of this global variable # Returns the file virtual address for this
# global
print 'file_addr = 0x%x' % global_variable.addr.file_addr
# returns the global variable value as a string
print 'location = %s' % global_variable.location
# Returns the size in bytes of this global
# variable
print 'size = %s' % global_variable.size
print print
def globals(command_args): def globals(command_args):
'''Extract all globals from any arguments which must be paths to object files.''' '''Extract all globals from any arguments which must be paths to object files.'''
usage = "usage: %prog [options] <PATH> [PATH ...]" usage = "usage: %prog [options] <PATH> [PATH ...]"
description='''This command will find all globals in the specified object file and return an list() of lldb.SBValue objects (which might be empty).''' description = '''This command will find all globals in the specified object file and return an list() of lldb.SBValue objects (which might be empty).'''
parser = optparse.OptionParser(description=description, prog='globals',usage=usage) parser = optparse.OptionParser(
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False) description=description,
parser.add_option('-a', '--arch', type='string', metavar='arch', dest='arch', help='Specify an architecture (or triple) to use when extracting from a file.') prog='globals',
parser.add_option('-p', '--platform', type='string', metavar='platform', dest='platform', help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".') usage=usage)
parser.add_option(
'-v',
'--verbose',
action='store_true',
dest='verbose',
help='display verbose debug info',
default=False)
parser.add_option(
'-a',
'--arch',
type='string',
metavar='arch',
dest='arch',
help='Specify an architecture (or triple) to use when extracting from a file.')
parser.add_option(
'-p',
'--platform',
type='string',
metavar='platform',
dest='platform',
help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".')
try: try:
(options, args) = parser.parse_args(command_args) (options, args) = parser.parse_args(command_args)
except: except:
return return
for path in args: for path in args:
get_globals (path, options) get_globals(path, options)
if __name__ == '__main__': if __name__ == '__main__':
lldb.debugger = lldb.SBDebugger.Create() lldb.debugger = lldb.SBDebugger.Create()
globals (sys.argv[1:]) globals(sys.argv[1:])

View File

@ -1,8 +1,10 @@
import lldb, re import lldb
import re
def parse_linespec (linespec, frame, result):
def parse_linespec(linespec, frame, result):
"""Handles a subset of GDB-style linespecs. Specifically: """Handles a subset of GDB-style linespecs. Specifically:
number - A line in the current file number - A line in the current file
+offset - The line /offset/ lines after this line +offset - The line /offset/ lines after this line
-offset - The line /offset/ lines before this line -offset - The line /offset/ lines before this line
@ -21,65 +23,73 @@ def parse_linespec (linespec, frame, result):
if (not matched): if (not matched):
mo = re.match("^([0-9]+)$", linespec) mo = re.match("^([0-9]+)$", linespec)
if (mo != None): if (mo is not None):
matched = True matched = True
#print "Matched <linenum>" # print "Matched <linenum>"
line_number = int(mo.group(1)) line_number = int(mo.group(1))
line_entry = frame.GetLineEntry() line_entry = frame.GetLineEntry()
if not line_entry.IsValid(): if not line_entry.IsValid():
result.AppendMessage("Specified a line in the current file, but the current frame doesn't have line table information.") result.AppendMessage(
"Specified a line in the current file, but the current frame doesn't have line table information.")
return return
breakpoint = target.BreakpointCreateByLocation (line_entry.GetFileSpec(), line_number) breakpoint = target.BreakpointCreateByLocation(
line_entry.GetFileSpec(), line_number)
if (not matched): if (not matched):
mo = re.match("^\+([0-9]+)$", linespec) mo = re.match("^\+([0-9]+)$", linespec)
if (mo != None): if (mo is not None):
matched = True matched = True
#print "Matched +<count>" # print "Matched +<count>"
line_number = int(mo.group(1)) line_number = int(mo.group(1))
line_entry = frame.GetLineEntry() line_entry = frame.GetLineEntry()
if not line_entry.IsValid(): if not line_entry.IsValid():
result.AppendMessage("Specified a line in the current file, but the current frame doesn't have line table information.") result.AppendMessage(
"Specified a line in the current file, but the current frame doesn't have line table information.")
return return
breakpoint = target.BreakpointCreateByLocation(line_entry.GetFileSpec(), (line_entry.GetLine() + line_number)) breakpoint = target.BreakpointCreateByLocation(
line_entry.GetFileSpec(), (line_entry.GetLine() + line_number))
if (not matched): if (not matched):
mo = re.match("^\-([0-9]+)$", linespec) mo = re.match("^\-([0-9]+)$", linespec)
if (mo != None): if (mo is not None):
matched = True matched = True
#print "Matched -<count>" # print "Matched -<count>"
line_number = int(mo.group(1)) line_number = int(mo.group(1))
line_entry = frame.GetLineEntry() line_entry = frame.GetLineEntry()
if not line_entry.IsValid(): if not line_entry.IsValid():
result.AppendMessage("Specified a line in the current file, but the current frame doesn't have line table information.") result.AppendMessage(
"Specified a line in the current file, but the current frame doesn't have line table information.")
return return
breakpoint = target.BreakpointCreateByLocation(line_entry.GetFileSpec(), (line_entry.GetLine() - line_number)) breakpoint = target.BreakpointCreateByLocation(
line_entry.GetFileSpec(), (line_entry.GetLine() - line_number))
if (not matched): if (not matched):
mo = re.match("^(.*):([0-9]+)$", linespec) mo = re.match("^(.*):([0-9]+)$", linespec)
if (mo != None): if (mo is not None):
matched = True matched = True
#print "Matched <filename>:<linenum>" # print "Matched <filename>:<linenum>"
file_name = mo.group(1) file_name = mo.group(1)
line_number = int(mo.group(2)) line_number = int(mo.group(2))
breakpoint = target.BreakpointCreateByLocation(file_name, line_number) breakpoint = target.BreakpointCreateByLocation(
file_name, line_number)
if (not matched): if (not matched):
mo = re.match("\*((0x)?([0-9a-f]+))$", linespec) mo = re.match("\*((0x)?([0-9a-f]+))$", linespec)
if (mo != None): if (mo is not None):
matched = True matched = True
#print "Matched <address-expression>" # print "Matched <address-expression>"
address = long(mo.group(1), base=0) address = long(mo.group(1), base=0)
breakpoint = target.BreakpointCreateByAddress(address) breakpoint = target.BreakpointCreateByAddress(address)
if (not matched): if (not matched):
#print "Trying <function-name>" # print "Trying <function-name>"
breakpoint = target.BreakpointCreateByName(linespec) breakpoint = target.BreakpointCreateByName(linespec)
num_locations = breakpoint.GetNumLocations() num_locations = breakpoint.GetNumLocations()
if (num_locations == 0): if (num_locations == 0):
result.AppendMessage("The line specification provided doesn't resolve to any addresses.") result.AppendMessage(
"The line specification provided doesn't resolve to any addresses.")
addr_list = [] addr_list = []
@ -91,6 +101,7 @@ def parse_linespec (linespec, frame, result):
return addr_list return addr_list
def usage_string(): def usage_string():
return """ Sets the program counter to a specific address. return """ Sets the program counter to a specific address.
@ -106,7 +117,8 @@ Command Options Usage:
<location-id> serves to disambiguate when multiple locations could be meant.""" <location-id> serves to disambiguate when multiple locations could be meant."""
def jump (debugger, command, result, internal_dict):
def jump(debugger, command, result, internal_dict):
if (command == ""): if (command == ""):
result.AppendMessage(usage_string()) result.AppendMessage(usage_string())
@ -151,17 +163,28 @@ def jump (debugger, command, result, internal_dict):
if (desired_index >= 0) and (desired_index < len(addresses)): if (desired_index >= 0) and (desired_index < len(addresses)):
desired_address = addresses[desired_index] desired_address = addresses[desired_index]
else: else:
result.AppendMessage("Desired index " + args[1] + " is not one of the options.") result.AppendMessage(
"Desired index " +
args[1] +
" is not one of the options.")
return return
else: else:
index = 0 index = 0
result.AppendMessage("The specified location resolves to multiple targets."); result.AppendMessage(
"The specified location resolves to multiple targets.")
for address in addresses: for address in addresses:
stream.Clear() stream.Clear()
address.GetDescription(stream) address.GetDescription(stream)
result.AppendMessage(" Location ID " + str(index) + ": " + stream.GetData()) result.AppendMessage(
" Location ID " +
str(index) +
": " +
stream.GetData())
index = index + 1 index = index + 1
result.AppendMessage("Please type 'jump " + command + " <location-id>' to choose one.") result.AppendMessage(
"Please type 'jump " +
command +
" <location-id>' to choose one.")
return return
frame.SetPC(desired_address.GetLoadAddress(target)) frame.SetPC(desired_address.GetLoadAddress(target))

View File

@ -6,18 +6,29 @@ import shlex
import string import string
import sys import sys
def create_dump_module_line_tables_options ():
def create_dump_module_line_tables_options():
usage = "usage: dump_module_line_tables [options] MODULE1 [MODULE2 ...]" usage = "usage: dump_module_line_tables [options] MODULE1 [MODULE2 ...]"
description='''Dumps all line tables from all compile units for any modules specified as arguments. Specifying the --verbose flag will output address ranges for each line entry.''' description = '''Dumps all line tables from all compile units for any modules specified as arguments. Specifying the --verbose flag will output address ranges for each line entry.'''
parser = optparse.OptionParser(description=description, prog='start_gdb_log',usage=usage) parser = optparse.OptionParser(
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='Display verbose output.', default=False) description=description,
prog='start_gdb_log',
usage=usage)
parser.add_option(
'-v',
'--verbose',
action='store_true',
dest='verbose',
help='Display verbose output.',
default=False)
return parser return parser
def dump_module_line_tables(debugger, command, result, dict): def dump_module_line_tables(debugger, command, result, dict):
'''Dumps all line tables from all compile units for any modules specified as arguments.''' '''Dumps all line tables from all compile units for any modules specified as arguments.'''
command_args = shlex.split(command) command_args = shlex.split(command)
parser = create_dump_module_line_tables_options () parser = create_dump_module_line_tables_options()
try: try:
(options, args) = parser.parse_args(command_args) (options, args) = parser.parse_args(command_args)
except: except:
@ -27,33 +38,41 @@ def dump_module_line_tables(debugger, command, result, dict):
lldb.target = target lldb.target = target
for module_name in command_args: for module_name in command_args:
result.PutCString('Searching for module "%s"' % (module_name,)) result.PutCString('Searching for module "%s"' % (module_name,))
module_fspec = lldb.SBFileSpec (module_name, False) module_fspec = lldb.SBFileSpec(module_name, False)
module = target.FindModule (module_fspec); module = target.FindModule(module_fspec)
if module: if module:
for cu_idx in range (module.GetNumCompileUnits()): for cu_idx in range(module.GetNumCompileUnits()):
cu = module.GetCompileUnitAtIndex(cu_idx) cu = module.GetCompileUnitAtIndex(cu_idx)
result.PutCString("\n%s:" % (cu.file)) result.PutCString("\n%s:" % (cu.file))
for line_idx in range(cu.GetNumLineEntries()): for line_idx in range(cu.GetNumLineEntries()):
line_entry = cu.GetLineEntryAtIndex(line_idx) line_entry = cu.GetLineEntryAtIndex(line_idx)
start_file_addr = line_entry.addr.file_addr start_file_addr = line_entry.addr.file_addr
end_file_addr = line_entry.end_addr.file_addr end_file_addr = line_entry.end_addr.file_addr
# If the two addresses are equal, this line table entry is a termination entry # If the two addresses are equal, this line table entry
# is a termination entry
if options.verbose: if options.verbose:
if start_file_addr != end_file_addr: if start_file_addr != end_file_addr:
result.PutCString('[%#x - %#x): %s' % (start_file_addr, end_file_addr, line_entry)) result.PutCString(
'[%#x - %#x): %s' %
(start_file_addr, end_file_addr, line_entry))
else: else:
if start_file_addr == end_file_addr: if start_file_addr == end_file_addr:
result.PutCString('%#x: END' % (start_file_addr)) result.PutCString('%#x: END' %
(start_file_addr))
else: else:
result.PutCString('%#x: %s' % (start_file_addr, line_entry)) result.PutCString(
'%#x: %s' %
(start_file_addr, line_entry))
if start_file_addr == end_file_addr: if start_file_addr == end_file_addr:
result.Printf("\n") result.Printf("\n")
else: else:
result.PutCString ("no module for '%s'" % module) result.PutCString("no module for '%s'" % module)
else: else:
result.PutCString ("error: invalid target") result.PutCString("error: invalid target")
parser = create_dump_module_line_tables_options () parser = create_dump_module_line_tables_options()
dump_module_line_tables.__doc__ = parser.format_help() dump_module_line_tables.__doc__ = parser.format_help()
lldb.debugger.HandleCommand('command script add -f %s.dump_module_line_tables dump_module_line_tables' % __name__) lldb.debugger.HandleCommand(
print 'Installed "dump_module_line_tables" command' 'command script add -f %s.dump_module_line_tables dump_module_line_tables' %
__name__)
print 'Installed "dump_module_line_tables" command'

View File

@ -6,7 +6,9 @@ import sys
from Tkinter import * from Tkinter import *
import ttk import ttk
class ValueTreeItemDelegate(object): class ValueTreeItemDelegate(object):
def __init__(self, value): def __init__(self, value):
self.value = value self.value = value
@ -24,36 +26,44 @@ class ValueTreeItemDelegate(object):
if summary is None: if summary is None:
summary = '' summary = ''
has_children = self.value.MightHaveChildren() has_children = self.value.MightHaveChildren()
return { '#0' : name, return {'#0': name,
'typename' : typename, 'typename': typename,
'value' : value, 'value': value,
'summary' : summary, 'summary': summary,
'children' : has_children, 'children': has_children,
'tree-item-delegate' : self } 'tree-item-delegate': self}
def get_child_item_dictionaries(self): def get_child_item_dictionaries(self):
item_dicts = list() item_dicts = list()
for i in range(self.value.num_children): for i in range(self.value.num_children):
item_delegate = ValueTreeItemDelegate(self.value.GetChildAtIndex(i)) item_delegate = ValueTreeItemDelegate(
self.value.GetChildAtIndex(i))
item_dicts.append(item_delegate.get_item_dictionary()) item_dicts.append(item_delegate.get_item_dictionary())
return item_dicts return item_dicts
class FrameTreeItemDelegate(object): class FrameTreeItemDelegate(object):
def __init__(self, frame): def __init__(self, frame):
self.frame = frame self.frame = frame
def get_item_dictionary(self): def get_item_dictionary(self):
id = self.frame.GetFrameID() id = self.frame.GetFrameID()
name = 'frame #%u' % (id); name = 'frame #%u' % (id)
value = '0x%16.16x' % (self.frame.GetPC()) value = '0x%16.16x' % (self.frame.GetPC())
stream = lldb.SBStream() stream = lldb.SBStream()
self.frame.GetDescription(stream) self.frame.GetDescription(stream)
summary = stream.GetData().split("`")[1] summary = stream.GetData().split("`")[1]
return { '#0' : name, return {
'value': value, '#0': name,
'summary': summary, 'value': value,
'children' : self.frame.GetVariables(True, True, True, True).GetSize() > 0, 'summary': summary,
'tree-item-delegate' : self } 'children': self.frame.GetVariables(
True,
True,
True,
True).GetSize() > 0,
'tree-item-delegate': self}
def get_child_item_dictionaries(self): def get_child_item_dictionaries(self):
item_dicts = list() item_dicts = list()
@ -64,29 +74,33 @@ class FrameTreeItemDelegate(object):
item_dicts.append(item_delegate.get_item_dictionary()) item_dicts.append(item_delegate.get_item_dictionary())
return item_dicts return item_dicts
class ThreadTreeItemDelegate(object): class ThreadTreeItemDelegate(object):
def __init__(self, thread):
self.thread = thread
def get_item_dictionary(self): def __init__(self, thread):
num_frames = self.thread.GetNumFrames() self.thread = thread
name = 'thread #%u' % (self.thread.GetIndexID())
value = '0x%x' % (self.thread.GetThreadID()) def get_item_dictionary(self):
summary = '%u frames' % (num_frames) num_frames = self.thread.GetNumFrames()
return { '#0' : name, name = 'thread #%u' % (self.thread.GetIndexID())
'value': value, value = '0x%x' % (self.thread.GetThreadID())
summary = '%u frames' % (num_frames)
return {'#0': name,
'value': value,
'summary': summary, 'summary': summary,
'children' : num_frames > 0, 'children': num_frames > 0,
'tree-item-delegate' : self } 'tree-item-delegate': self}
def get_child_item_dictionaries(self):
item_dicts = list()
for frame in self.thread:
item_delegate = FrameTreeItemDelegate(frame)
item_dicts.append(item_delegate.get_item_dictionary())
return item_dicts
def get_child_item_dictionaries(self):
item_dicts = list()
for frame in self.thread:
item_delegate = FrameTreeItemDelegate(frame)
item_dicts.append(item_delegate.get_item_dictionary())
return item_dicts
class ProcessTreeItemDelegate(object): class ProcessTreeItemDelegate(object):
def __init__(self, process): def __init__(self, process):
self.process = process self.process = process
@ -95,11 +109,11 @@ class ProcessTreeItemDelegate(object):
num_threads = self.process.GetNumThreads() num_threads = self.process.GetNumThreads()
value = str(self.process.GetProcessID()) value = str(self.process.GetProcessID())
summary = self.process.target.executable.fullpath summary = self.process.target.executable.fullpath
return { '#0' : 'process', return {'#0': 'process',
'value': value, 'value': value,
'summary': summary, 'summary': summary,
'children' : num_threads > 0, 'children': num_threads > 0,
'tree-item-delegate' : self } 'tree-item-delegate': self}
def get_child_item_dictionaries(self): def get_child_item_dictionaries(self):
item_dicts = list() item_dicts = list()
@ -108,18 +122,20 @@ class ProcessTreeItemDelegate(object):
item_dicts.append(item_delegate.get_item_dictionary()) item_dicts.append(item_delegate.get_item_dictionary())
return item_dicts return item_dicts
class TargetTreeItemDelegate(object): class TargetTreeItemDelegate(object):
def __init__(self, target): def __init__(self, target):
self.target = target self.target = target
def get_item_dictionary(self): def get_item_dictionary(self):
value = str(self.target.triple) value = str(self.target.triple)
summary = self.target.executable.fullpath summary = self.target.executable.fullpath
return { '#0' : 'target', return {'#0': 'target',
'value': value, 'value': value,
'summary': summary, 'summary': summary,
'children' : True, 'children': True,
'tree-item-delegate' : self } 'tree-item-delegate': self}
def get_child_item_dictionaries(self): def get_child_item_dictionaries(self):
item_dicts = list() item_dicts = list()
@ -127,7 +143,9 @@ class TargetTreeItemDelegate(object):
item_dicts.append(image_item_delegate.get_item_dictionary()) item_dicts.append(image_item_delegate.get_item_dictionary())
return item_dicts return item_dicts
class TargetImagesTreeItemDelegate(object): class TargetImagesTreeItemDelegate(object):
def __init__(self, target): def __init__(self, target):
self.target = target self.target = target
@ -135,21 +153,24 @@ class TargetImagesTreeItemDelegate(object):
value = str(self.target.triple) value = str(self.target.triple)
summary = self.target.executable.fullpath summary = self.target.executable.fullpath
num_modules = self.target.GetNumModules() num_modules = self.target.GetNumModules()
return { '#0' : 'images', return {'#0': 'images',
'value': '', 'value': '',
'summary': '%u images' % num_modules, 'summary': '%u images' % num_modules,
'children' : num_modules > 0, 'children': num_modules > 0,
'tree-item-delegate' : self } 'tree-item-delegate': self}
def get_child_item_dictionaries(self): def get_child_item_dictionaries(self):
item_dicts = list() item_dicts = list()
for i in range(self.target.GetNumModules()): for i in range(self.target.GetNumModules()):
module = self.target.GetModuleAtIndex(i) module = self.target.GetModuleAtIndex(i)
image_item_delegate = ModuleTreeItemDelegate(self.target, module, i) image_item_delegate = ModuleTreeItemDelegate(
self.target, module, i)
item_dicts.append(image_item_delegate.get_item_dictionary()) item_dicts.append(image_item_delegate.get_item_dictionary())
return item_dicts return item_dicts
class ModuleTreeItemDelegate(object): class ModuleTreeItemDelegate(object):
def __init__(self, target, module, index): def __init__(self, target, module, index):
self.target = target self.target = target
self.module = module self.module = module
@ -159,25 +180,30 @@ class ModuleTreeItemDelegate(object):
name = 'module %u' % (self.index) name = 'module %u' % (self.index)
value = self.module.file.basename value = self.module.file.basename
summary = self.module.file.dirname summary = self.module.file.dirname
return { '#0' : name, return {'#0': name,
'value': value, 'value': value,
'summary': summary, 'summary': summary,
'children' : True, 'children': True,
'tree-item-delegate' : self } 'tree-item-delegate': self}
def get_child_item_dictionaries(self): def get_child_item_dictionaries(self):
item_dicts = list() item_dicts = list()
sections_item_delegate = ModuleSectionsTreeItemDelegate(self.target, self.module) sections_item_delegate = ModuleSectionsTreeItemDelegate(
self.target, self.module)
item_dicts.append(sections_item_delegate.get_item_dictionary()) item_dicts.append(sections_item_delegate.get_item_dictionary())
symbols_item_delegate = ModuleSymbolsTreeItemDelegate(self.target, self.module) symbols_item_delegate = ModuleSymbolsTreeItemDelegate(
self.target, self.module)
item_dicts.append(symbols_item_delegate.get_item_dictionary()) item_dicts.append(symbols_item_delegate.get_item_dictionary())
comp_units_item_delegate = ModuleCompileUnitsTreeItemDelegate(self.target, self.module) comp_units_item_delegate = ModuleCompileUnitsTreeItemDelegate(
self.target, self.module)
item_dicts.append(comp_units_item_delegate.get_item_dictionary()) item_dicts.append(comp_units_item_delegate.get_item_dictionary())
return item_dicts return item_dicts
class ModuleSectionsTreeItemDelegate(object): class ModuleSectionsTreeItemDelegate(object):
def __init__(self, target, module): def __init__(self, target, module):
self.target = target self.target = target
self.module = module self.module = module
@ -186,11 +212,11 @@ class ModuleSectionsTreeItemDelegate(object):
name = 'sections' name = 'sections'
value = '' value = ''
summary = '%u sections' % (self.module.GetNumSections()) summary = '%u sections' % (self.module.GetNumSections())
return { '#0' : name, return {'#0': name,
'value': value, 'value': value,
'summary': summary, 'summary': summary,
'children' : True, 'children': True,
'tree-item-delegate' : self } 'tree-item-delegate': self}
def get_child_item_dictionaries(self): def get_child_item_dictionaries(self):
item_dicts = list() item_dicts = list()
@ -201,7 +227,9 @@ class ModuleSectionsTreeItemDelegate(object):
item_dicts.append(image_item_delegate.get_item_dictionary()) item_dicts.append(image_item_delegate.get_item_dictionary())
return item_dicts return item_dicts
class SectionTreeItemDelegate(object): class SectionTreeItemDelegate(object):
def __init__(self, target, section): def __init__(self, target, section):
self.target = target self.target = target
self.section = section self.section = section
@ -214,11 +242,11 @@ class SectionTreeItemDelegate(object):
else: else:
value = '0x%16.16x *' % (self.section.file_addr) value = '0x%16.16x *' % (self.section.file_addr)
summary = '' summary = ''
return { '#0' : name, return {'#0': name,
'value': value, 'value': value,
'summary': summary, 'summary': summary,
'children' : self.section.GetNumSubSections() > 0, 'children': self.section.GetNumSubSections() > 0,
'tree-item-delegate' : self } 'tree-item-delegate': self}
def get_child_item_dictionaries(self): def get_child_item_dictionaries(self):
item_dicts = list() item_dicts = list()
@ -226,10 +254,12 @@ class SectionTreeItemDelegate(object):
for i in range(num_sections): for i in range(num_sections):
section = self.section.GetSubSectionAtIndex(i) section = self.section.GetSubSectionAtIndex(i)
image_item_delegate = SectionTreeItemDelegate(self.target, section) image_item_delegate = SectionTreeItemDelegate(self.target, section)
item_dicts.append(image_item_delegate.get_item_dictionary()) item_dicts.append(image_item_delegate.get_item_dictionary())
return item_dicts return item_dicts
class ModuleCompileUnitsTreeItemDelegate(object): class ModuleCompileUnitsTreeItemDelegate(object):
def __init__(self, target, module): def __init__(self, target, module):
self.target = target self.target = target
self.module = module self.module = module
@ -238,11 +268,11 @@ class ModuleCompileUnitsTreeItemDelegate(object):
name = 'compile units' name = 'compile units'
value = '' value = ''
summary = '%u compile units' % (self.module.GetNumSections()) summary = '%u compile units' % (self.module.GetNumSections())
return { '#0' : name, return {'#0': name,
'value': value, 'value': value,
'summary': summary, 'summary': summary,
'children' : self.module.GetNumCompileUnits() > 0, 'children': self.module.GetNumCompileUnits() > 0,
'tree-item-delegate' : self } 'tree-item-delegate': self}
def get_child_item_dictionaries(self): def get_child_item_dictionaries(self):
item_dicts = list() item_dicts = list()
@ -253,7 +283,9 @@ class ModuleCompileUnitsTreeItemDelegate(object):
item_dicts.append(image_item_delegate.get_item_dictionary()) item_dicts.append(image_item_delegate.get_item_dictionary())
return item_dicts return item_dicts
class CompileUnitTreeItemDelegate(object): class CompileUnitTreeItemDelegate(object):
def __init__(self, target, cu): def __init__(self, target, cu):
self.target = target self.target = target
self.cu = cu self.cu = cu
@ -263,11 +295,11 @@ class CompileUnitTreeItemDelegate(object):
value = '' value = ''
num_lines = self.cu.GetNumLineEntries() num_lines = self.cu.GetNumLineEntries()
summary = '' summary = ''
return { '#0' : name, return {'#0': name,
'value': value, 'value': value,
'summary': summary, 'summary': summary,
'children' : num_lines > 0, 'children': num_lines > 0,
'tree-item-delegate' : self } 'tree-item-delegate': self}
def get_child_item_dictionaries(self): def get_child_item_dictionaries(self):
item_dicts = list() item_dicts = list()
@ -275,7 +307,9 @@ class CompileUnitTreeItemDelegate(object):
item_dicts.append(item_delegate.get_item_dictionary()) item_dicts.append(item_delegate.get_item_dictionary())
return item_dicts return item_dicts
class LineTableTreeItemDelegate(object): class LineTableTreeItemDelegate(object):
def __init__(self, target, cu): def __init__(self, target, cu):
self.target = target self.target = target
self.cu = cu self.cu = cu
@ -285,22 +319,25 @@ class LineTableTreeItemDelegate(object):
value = '' value = ''
num_lines = self.cu.GetNumLineEntries() num_lines = self.cu.GetNumLineEntries()
summary = '%u line entries' % (num_lines) summary = '%u line entries' % (num_lines)
return { '#0' : name, return {'#0': name,
'value': value, 'value': value,
'summary': summary, 'summary': summary,
'children' : num_lines > 0, 'children': num_lines > 0,
'tree-item-delegate' : self } 'tree-item-delegate': self}
def get_child_item_dictionaries(self): def get_child_item_dictionaries(self):
item_dicts = list() item_dicts = list()
num_lines = self.cu.GetNumLineEntries() num_lines = self.cu.GetNumLineEntries()
for i in range(num_lines): for i in range(num_lines):
line_entry = self.cu.GetLineEntryAtIndex(i) line_entry = self.cu.GetLineEntryAtIndex(i)
item_delegate = LineEntryTreeItemDelegate(self.target, line_entry, i) item_delegate = LineEntryTreeItemDelegate(
self.target, line_entry, i)
item_dicts.append(item_delegate.get_item_dictionary()) item_dicts.append(item_delegate.get_item_dictionary())
return item_dicts return item_dicts
class LineEntryTreeItemDelegate(object): class LineEntryTreeItemDelegate(object):
def __init__(self, target, line_entry, index): def __init__(self, target, line_entry, index):
self.target = target self.target = target
self.line_entry = line_entry self.line_entry = line_entry
@ -314,18 +351,21 @@ class LineEntryTreeItemDelegate(object):
value = '0x%16.16x' % (load_addr) value = '0x%16.16x' % (load_addr)
else: else:
value = '0x%16.16x *' % (address.file_addr) value = '0x%16.16x *' % (address.file_addr)
summary = self.line_entry.GetFileSpec().fullpath + ':' + str(self.line_entry.line) summary = self.line_entry.GetFileSpec().fullpath + ':' + \
return { '#0' : name, str(self.line_entry.line)
'value': value, return {'#0': name,
'summary': summary, 'value': value,
'children' : False, 'summary': summary,
'tree-item-delegate' : self } 'children': False,
'tree-item-delegate': self}
def get_child_item_dictionaries(self): def get_child_item_dictionaries(self):
item_dicts = list() item_dicts = list()
return item_dicts return item_dicts
class InstructionTreeItemDelegate(object): class InstructionTreeItemDelegate(object):
def __init__(self, target, instr): def __init__(self, target, instr):
self.target = target self.target = target
self.instr = instr self.instr = instr
@ -337,15 +377,18 @@ class InstructionTreeItemDelegate(object):
name = '0x%16.16x' % (load_addr) name = '0x%16.16x' % (load_addr)
else: else:
name = '0x%16.16x *' % (address.file_addr) name = '0x%16.16x *' % (address.file_addr)
value = self.instr.GetMnemonic(self.target) + ' ' + self.instr.GetOperands(self.target) value = self.instr.GetMnemonic(
self.target) + ' ' + self.instr.GetOperands(self.target)
summary = self.instr.GetComment(self.target) summary = self.instr.GetComment(self.target)
return { '#0' : name, return {'#0': name,
'value': value, 'value': value,
'summary': summary, 'summary': summary,
'children' : False, 'children': False,
'tree-item-delegate' : self } 'tree-item-delegate': self}
class ModuleSymbolsTreeItemDelegate(object): class ModuleSymbolsTreeItemDelegate(object):
def __init__(self, target, module): def __init__(self, target, module):
self.target = target self.target = target
self.module = module self.module = module
@ -354,22 +397,25 @@ class ModuleSymbolsTreeItemDelegate(object):
name = 'symbols' name = 'symbols'
value = '' value = ''
summary = '%u symbols' % (self.module.GetNumSymbols()) summary = '%u symbols' % (self.module.GetNumSymbols())
return { '#0' : name, return {'#0': name,
'value': value, 'value': value,
'summary': summary, 'summary': summary,
'children' : True, 'children': True,
'tree-item-delegate' : self } 'tree-item-delegate': self}
def get_child_item_dictionaries(self): def get_child_item_dictionaries(self):
item_dicts = list() item_dicts = list()
num_symbols = self.module.GetNumSymbols() num_symbols = self.module.GetNumSymbols()
for i in range(num_symbols): for i in range(num_symbols):
symbol = self.module.GetSymbolAtIndex(i) symbol = self.module.GetSymbolAtIndex(i)
image_item_delegate = SymbolTreeItemDelegate(self.target, symbol, i) image_item_delegate = SymbolTreeItemDelegate(
self.target, symbol, i)
item_dicts.append(image_item_delegate.get_item_dictionary()) item_dicts.append(image_item_delegate.get_item_dictionary())
return item_dicts return item_dicts
class SymbolTreeItemDelegate(object): class SymbolTreeItemDelegate(object):
def __init__(self, target, symbol, index): def __init__(self, target, symbol, index):
self.target = target self.target = target
self.symbol = symbol self.symbol = symbol
@ -384,20 +430,19 @@ class SymbolTreeItemDelegate(object):
else: else:
value = '0x%16.16x *' % (address.file_addr) value = '0x%16.16x *' % (address.file_addr)
summary = self.symbol.name summary = self.symbol.name
return { '#0' : name, return {'#0': name,
'value': value, 'value': value,
'summary': summary, 'summary': summary,
'children' : False, 'children': False,
'tree-item-delegate' : self } 'tree-item-delegate': self}
def get_child_item_dictionaries(self): def get_child_item_dictionaries(self):
item_dicts = list() item_dicts = list()
return item_dicts return item_dicts
class DelegateTree(ttk.Frame): class DelegateTree(ttk.Frame):
def __init__(self, column_dicts, delegate, title, name): def __init__(self, column_dicts, delegate, title, name):
ttk.Frame.__init__(self, name=name) ttk.Frame.__init__(self, name=name)
self.pack(expand=Y, fill=BOTH) self.pack(expand=Y, fill=BOTH)
@ -409,36 +454,42 @@ class DelegateTree(ttk.Frame):
frame.pack(side=TOP, fill=BOTH, expand=Y) frame.pack(side=TOP, fill=BOTH, expand=Y)
self._create_treeview(frame) self._create_treeview(frame)
self._populate_root() self._populate_root()
def _create_treeview(self, parent): def _create_treeview(self, parent):
frame = ttk.Frame(parent) frame = ttk.Frame(parent)
frame.pack(side=TOP, fill=BOTH, expand=Y) frame.pack(side=TOP, fill=BOTH, expand=Y)
column_ids = list() column_ids = list()
for i in range(1,len(self.columns_dicts)): for i in range(1, len(self.columns_dicts)):
column_ids.append(self.columns_dicts[i]['id']) column_ids.append(self.columns_dicts[i]['id'])
# create the tree and scrollbars # create the tree and scrollbars
self.tree = ttk.Treeview(columns=column_ids) self.tree = ttk.Treeview(columns=column_ids)
scroll_bar_v = ttk.Scrollbar(orient=VERTICAL, command= self.tree.yview) scroll_bar_v = ttk.Scrollbar(orient=VERTICAL, command=self.tree.yview)
scroll_bar_h = ttk.Scrollbar(orient=HORIZONTAL, command= self.tree.xview) scroll_bar_h = ttk.Scrollbar(
orient=HORIZONTAL, command=self.tree.xview)
self.tree['yscroll'] = scroll_bar_v.set self.tree['yscroll'] = scroll_bar_v.set
self.tree['xscroll'] = scroll_bar_h.set self.tree['xscroll'] = scroll_bar_h.set
# setup column headings and columns properties # setup column headings and columns properties
for columns_dict in self.columns_dicts: for columns_dict in self.columns_dicts:
self.tree.heading(columns_dict['id'], text=columns_dict['text'], anchor=columns_dict['anchor']) self.tree.heading(
self.tree.column(columns_dict['id'], stretch=columns_dict['stretch']) columns_dict['id'],
text=columns_dict['text'],
anchor=columns_dict['anchor'])
self.tree.column(
columns_dict['id'],
stretch=columns_dict['stretch'])
# add tree and scrollbars to frame # add tree and scrollbars to frame
self.tree.grid(in_=frame, row=0, column=0, sticky=NSEW) self.tree.grid(in_=frame, row=0, column=0, sticky=NSEW)
scroll_bar_v.grid(in_=frame, row=0, column=1, sticky=NS) scroll_bar_v.grid(in_=frame, row=0, column=1, sticky=NS)
scroll_bar_h.grid(in_=frame, row=1, column=0, sticky=EW) scroll_bar_h.grid(in_=frame, row=1, column=0, sticky=EW)
# set frame resizing priorities # set frame resizing priorities
frame.rowconfigure(0, weight=1) frame.rowconfigure(0, weight=1)
frame.columnconfigure(0, weight=1) frame.columnconfigure(0, weight=1)
# action to perform when a node is expanded # action to perform when a node is expanded
self.tree.bind('<<TreeviewOpen>>', self._update_tree) self.tree.bind('<<TreeviewOpen>>', self._update_tree)
@ -453,22 +504,22 @@ class DelegateTree(ttk.Frame):
first = False first = False
else: else:
values.append(item_dict[columns_dict['id']]) values.append(item_dict[columns_dict['id']])
item_id = self.tree.insert (parent_id, # root item has an empty name item_id = self.tree.insert(parent_id, # root item has an empty name
END, END,
text=name, text=name,
values=values) values=values)
self.item_id_to_item_dict[item_id] = item_dict self.item_id_to_item_dict[item_id] = item_dict
if item_dict['children']: if item_dict['children']:
self.tree.insert(item_id, END, text='dummy') self.tree.insert(item_id, END, text='dummy')
def _populate_root(self): def _populate_root(self):
# use current directory as root node # use current directory as root node
self.insert_items('', self.delegate.get_child_item_dictionaries()) self.insert_items('', self.delegate.get_child_item_dictionaries())
def _update_tree(self, event): def _update_tree(self, event):
# user expanded a node - build the related directory # user expanded a node - build the related directory
item_id = self.tree.focus() # the id of the expanded node item_id = self.tree.focus() # the id of the expanded node
children = self.tree.get_children (item_id) children = self.tree.get_children(item_id)
if len(children): if len(children):
first_child = children[0] first_child = children[0]
# if the node only has a 'dummy' child, remove it and # if the node only has a 'dummy' child, remove it and
@ -477,12 +528,15 @@ class DelegateTree(ttk.Frame):
if self.tree.item(first_child, option='text') == 'dummy': if self.tree.item(first_child, option='text') == 'dummy':
self.tree.delete(first_child) self.tree.delete(first_child)
item_dict = self.item_id_to_item_dict[item_id] item_dict = self.item_id_to_item_dict[item_id]
item_dicts = item_dict['tree-item-delegate'].get_child_item_dictionaries() item_dicts = item_dict[
'tree-item-delegate'].get_child_item_dictionaries()
self.insert_items(item_id, item_dicts) self.insert_items(item_id, item_dicts)
@lldb.command("tk-variables") @lldb.command("tk-variables")
def tk_variable_display(debugger, command, result, dict): def tk_variable_display(debugger, command, result, dict):
sys.argv = ['tk-variables'] # needed for tree creation in TK library as it uses sys.argv... # needed for tree creation in TK library as it uses sys.argv...
sys.argv = ['tk-variables']
target = debugger.GetSelectedTarget() target = debugger.GetSelectedTarget()
if not target: if not target:
print >>result, "invalid target" print >>result, "invalid target"
@ -501,16 +555,22 @@ def tk_variable_display(debugger, command, result, dict):
return return
# Parse command line args # Parse command line args
command_args = shlex.split(command) command_args = shlex.split(command)
column_dicts = [{ 'id' : '#0' , 'text' : 'Name' , 'anchor' : W , 'stretch' : 0 }, column_dicts = [{'id': '#0', 'text': 'Name', 'anchor': W, 'stretch': 0},
{ 'id' : 'typename', 'text' : 'Type' , 'anchor' : W , 'stretch' : 0 }, {'id': 'typename', 'text': 'Type', 'anchor': W, 'stretch': 0},
{ 'id' : 'value' , 'text' : 'Value' , 'anchor' : W , 'stretch' : 0 }, {'id': 'value', 'text': 'Value', 'anchor': W, 'stretch': 0},
{ 'id' : 'summary' , 'text' : 'Summary', 'anchor' : W , 'stretch' : 1 }] {'id': 'summary', 'text': 'Summary', 'anchor': W, 'stretch': 1}]
tree = DelegateTree(column_dicts, FrameTreeItemDelegate(frame), 'Variables', 'lldb-tk-variables') tree = DelegateTree(
column_dicts,
FrameTreeItemDelegate(frame),
'Variables',
'lldb-tk-variables')
tree.mainloop() tree.mainloop()
@lldb.command("tk-process") @lldb.command("tk-process")
def tk_process_display(debugger, command, result, dict): def tk_process_display(debugger, command, result, dict):
sys.argv = ['tk-process'] # needed for tree creation in TK library as it uses sys.argv... # needed for tree creation in TK library as it uses sys.argv...
sys.argv = ['tk-process']
target = debugger.GetSelectedTarget() target = debugger.GetSelectedTarget()
if not target: if not target:
print >>result, "invalid target" print >>result, "invalid target"
@ -520,25 +580,34 @@ def tk_process_display(debugger, command, result, dict):
print >>result, "invalid process" print >>result, "invalid process"
return return
# Parse command line args # Parse command line args
columnd_dicts = [{ 'id' : '#0' , 'text' : 'Name' , 'anchor' : W , 'stretch' : 0 }, columnd_dicts = [{'id': '#0', 'text': 'Name', 'anchor': W, 'stretch': 0},
{ 'id' : 'value' , 'text' : 'Value' , 'anchor' : W , 'stretch' : 0 }, {'id': 'value', 'text': 'Value', 'anchor': W, 'stretch': 0},
{ 'id' : 'summary', 'text' : 'Summary', 'anchor' : W , 'stretch' : 1 }]; {'id': 'summary', 'text': 'Summary', 'anchor': W, 'stretch': 1}]
command_args = shlex.split(command) command_args = shlex.split(command)
tree = DelegateTree(columnd_dicts, ProcessTreeItemDelegate(process), 'Process', 'lldb-tk-process') tree = DelegateTree(
columnd_dicts,
ProcessTreeItemDelegate(process),
'Process',
'lldb-tk-process')
tree.mainloop() tree.mainloop()
@lldb.command("tk-target") @lldb.command("tk-target")
def tk_target_display(debugger, command, result, dict): def tk_target_display(debugger, command, result, dict):
sys.argv = ['tk-target'] # needed for tree creation in TK library as it uses sys.argv... # needed for tree creation in TK library as it uses sys.argv...
sys.argv = ['tk-target']
target = debugger.GetSelectedTarget() target = debugger.GetSelectedTarget()
if not target: if not target:
print >>result, "invalid target" print >>result, "invalid target"
return return
# Parse command line args # Parse command line args
columnd_dicts = [{ 'id' : '#0' , 'text' : 'Name' , 'anchor' : W , 'stretch' : 0 }, columnd_dicts = [{'id': '#0', 'text': 'Name', 'anchor': W, 'stretch': 0},
{ 'id' : 'value' , 'text' : 'Value' , 'anchor' : W , 'stretch' : 0 }, {'id': 'value', 'text': 'Value', 'anchor': W, 'stretch': 0},
{ 'id' : 'summary', 'text' : 'Summary', 'anchor' : W , 'stretch' : 1 }]; {'id': 'summary', 'text': 'Summary', 'anchor': W, 'stretch': 1}]
command_args = shlex.split(command) command_args = shlex.split(command)
tree = DelegateTree(columnd_dicts, TargetTreeItemDelegate(target), 'Target', 'lldb-tk-target') tree = DelegateTree(
columnd_dicts,
TargetTreeItemDelegate(target),
'Target',
'lldb-tk-target')
tree.mainloop() tree.mainloop()

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,7 @@
# Be sure to add the python path that points to the LLDB shared library. # Be sure to add the python path that points to the LLDB shared library.
# #
# # To use this in the embedded python interpreter using "lldb" just # # To use this in the embedded python interpreter using "lldb" just
# import it with the full path using the "command script import" # import it with the full path using the "command script import"
# command # command
# (lldb) command script import /path/to/cmdtemplate.py # (lldb) command script import /path/to/cmdtemplate.py
#---------------------------------------------------------------------- #----------------------------------------------------------------------
@ -15,7 +15,7 @@ import os
import re import re
import sys import sys
try: try:
# Just try for LLDB in case PYTHONPATH is already correctly setup # Just try for LLDB in case PYTHONPATH is already correctly setup
import lldb import lldb
except ImportError: except ImportError:
@ -26,15 +26,20 @@ except ImportError:
# On Darwin, try the currently selected Xcode directory # On Darwin, try the currently selected Xcode directory
xcode_dir = commands.getoutput("xcode-select --print-path") xcode_dir = commands.getoutput("xcode-select --print-path")
if xcode_dir: if xcode_dir:
lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python')) lldb_python_dirs.append(
lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python') os.path.realpath(
lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') xcode_dir +
'/../SharedFrameworks/LLDB.framework/Resources/Python'))
lldb_python_dirs.append(
xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
lldb_python_dirs.append(
'/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
success = False success = False
for lldb_python_dir in lldb_python_dirs: for lldb_python_dir in lldb_python_dirs:
if os.path.exists(lldb_python_dir): if os.path.exists(lldb_python_dir):
if not (sys.path.__contains__(lldb_python_dir)): if not (sys.path.__contains__(lldb_python_dir)):
sys.path.append(lldb_python_dir) sys.path.append(lldb_python_dir)
try: try:
import lldb import lldb
except ImportError: except ImportError:
pass pass
@ -53,52 +58,129 @@ import string
import struct import struct
import time import time
def append_data_callback(option, opt_str, value, parser): def append_data_callback(option, opt_str, value, parser):
if opt_str == "--uint8": if opt_str == "--uint8":
int8 = int(value, 0) int8 = int(value, 0)
parser.values.data += struct.pack('1B',int8) parser.values.data += struct.pack('1B', int8)
if opt_str == "--uint16": if opt_str == "--uint16":
int16 = int(value, 0) int16 = int(value, 0)
parser.values.data += struct.pack('1H',int16) parser.values.data += struct.pack('1H', int16)
if opt_str == "--uint32": if opt_str == "--uint32":
int32 = int(value, 0) int32 = int(value, 0)
parser.values.data += struct.pack('1I',int32) parser.values.data += struct.pack('1I', int32)
if opt_str == "--uint64": if opt_str == "--uint64":
int64 = int(value, 0) int64 = int(value, 0)
parser.values.data += struct.pack('1Q',int64) parser.values.data += struct.pack('1Q', int64)
if opt_str == "--int8": if opt_str == "--int8":
int8 = int(value, 0) int8 = int(value, 0)
parser.values.data += struct.pack('1b',int8) parser.values.data += struct.pack('1b', int8)
if opt_str == "--int16": if opt_str == "--int16":
int16 = int(value, 0) int16 = int(value, 0)
parser.values.data += struct.pack('1h',int16) parser.values.data += struct.pack('1h', int16)
if opt_str == "--int32": if opt_str == "--int32":
int32 = int(value, 0) int32 = int(value, 0)
parser.values.data += struct.pack('1i',int32) parser.values.data += struct.pack('1i', int32)
if opt_str == "--int64": if opt_str == "--int64":
int64 = int(value, 0) int64 = int(value, 0)
parser.values.data += struct.pack('1q',int64) parser.values.data += struct.pack('1q', int64)
def create_memfind_options(): def create_memfind_options():
usage = "usage: %prog [options] STARTADDR [ENDADDR]" usage = "usage: %prog [options] STARTADDR [ENDADDR]"
description='''This command can find data in a specified address range. description = '''This command can find data in a specified address range.
Options are used to specify the data that is to be looked for and the options Options are used to specify the data that is to be looked for and the options
can be specified multiple times to look for longer streams of data. can be specified multiple times to look for longer streams of data.
''' '''
parser = optparse.OptionParser(description=description, prog='memfind',usage=usage) parser = optparse.OptionParser(
parser.add_option('-s', '--size', type='int', metavar='BYTESIZE', dest='size', help='Specify the byte size to search.', default=0) description=description,
parser.add_option('--int8', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 8 bit signed integer value to search for in memory.', default='') prog='memfind',
parser.add_option('--int16', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 16 bit signed integer value to search for in memory.', default='') usage=usage)
parser.add_option('--int32', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 32 bit signed integer value to search for in memory.', default='') parser.add_option(
parser.add_option('--int64', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 64 bit signed integer value to search for in memory.', default='') '-s',
parser.add_option('--uint8', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 8 bit unsigned integer value to search for in memory.', default='') '--size',
parser.add_option('--uint16', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 16 bit unsigned integer value to search for in memory.', default='') type='int',
parser.add_option('--uint32', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 32 bit unsigned integer value to search for in memory.', default='') metavar='BYTESIZE',
parser.add_option('--uint64', action="callback", callback=append_data_callback, type='string', metavar='INT', dest='data', help='Specify a 64 bit unsigned integer value to search for in memory.', default='') dest='size',
help='Specify the byte size to search.',
default=0)
parser.add_option(
'--int8',
action="callback",
callback=append_data_callback,
type='string',
metavar='INT',
dest='data',
help='Specify a 8 bit signed integer value to search for in memory.',
default='')
parser.add_option(
'--int16',
action="callback",
callback=append_data_callback,
type='string',
metavar='INT',
dest='data',
help='Specify a 16 bit signed integer value to search for in memory.',
default='')
parser.add_option(
'--int32',
action="callback",
callback=append_data_callback,
type='string',
metavar='INT',
dest='data',
help='Specify a 32 bit signed integer value to search for in memory.',
default='')
parser.add_option(
'--int64',
action="callback",
callback=append_data_callback,
type='string',
metavar='INT',
dest='data',
help='Specify a 64 bit signed integer value to search for in memory.',
default='')
parser.add_option(
'--uint8',
action="callback",
callback=append_data_callback,
type='string',
metavar='INT',
dest='data',
help='Specify a 8 bit unsigned integer value to search for in memory.',
default='')
parser.add_option(
'--uint16',
action="callback",
callback=append_data_callback,
type='string',
metavar='INT',
dest='data',
help='Specify a 16 bit unsigned integer value to search for in memory.',
default='')
parser.add_option(
'--uint32',
action="callback",
callback=append_data_callback,
type='string',
metavar='INT',
dest='data',
help='Specify a 32 bit unsigned integer value to search for in memory.',
default='')
parser.add_option(
'--uint64',
action="callback",
callback=append_data_callback,
type='string',
metavar='INT',
dest='data',
help='Specify a 64 bit unsigned integer value to search for in memory.',
default='')
return parser return parser
def memfind_command (debugger, command, result, dict):
# Use the Shell Lexer to properly parse up command options just like a def memfind_command(debugger, command, result, dict):
# Use the Shell Lexer to properly parse up command options just like a
# shell would # shell would
command_args = shlex.split(command) command_args = shlex.split(command)
parser = create_memfind_options() parser = create_memfind_options()
@ -111,39 +193,49 @@ def memfind_command (debugger, command, result, dict):
# result.SetStatus (lldb.eReturnStatusFailed) # result.SetStatus (lldb.eReturnStatusFailed)
# print >>result, "error: option parsing failed" # returning a string is the same as returning an error whose description is the string # print >>result, "error: option parsing failed" # returning a string is the same as returning an error whose description is the string
# return # return
memfind (debugger.GetSelectedTarget(), options, args, result) memfind(debugger.GetSelectedTarget(), options, args, result)
def print_error(str, show_usage, result): def print_error(str, show_usage, result):
print >>result, str print >>result, str
if show_usage: if show_usage:
print >>result, create_memfind_options().format_help() print >>result, create_memfind_options().format_help()
def memfind (target, options, args, result):
def memfind(target, options, args, result):
num_args = len(args) num_args = len(args)
start_addr = 0 start_addr = 0
if num_args == 1: if num_args == 1:
if options.size > 0: if options.size > 0:
print_error ("error: --size must be specified if there is no ENDADDR argument", True, result) print_error(
"error: --size must be specified if there is no ENDADDR argument",
True,
result)
return return
start_addr = int(args[0], 0) start_addr = int(args[0], 0)
elif num_args == 2: elif num_args == 2:
if options.size != 0: if options.size != 0:
print_error ("error: --size can't be specified with an ENDADDR argument", True, result) print_error(
"error: --size can't be specified with an ENDADDR argument",
True,
result)
return return
start_addr = int(args[0], 0) start_addr = int(args[0], 0)
end_addr = int(args[1], 0) end_addr = int(args[1], 0)
if start_addr >= end_addr: if start_addr >= end_addr:
print_error ("error: inavlid memory range [%#x - %#x)" % (start_addr, end_addr), True, result) print_error(
"error: inavlid memory range [%#x - %#x)" %
(start_addr, end_addr), True, result)
return return
options.size = end_addr - start_addr options.size = end_addr - start_addr
else: else:
print_error ("error: memfind takes 1 or 2 arguments", True, result) print_error("error: memfind takes 1 or 2 arguments", True, result)
return return
if not options.data: if not options.data:
print >>result, 'error: no data specified to search for' print >>result, 'error: no data specified to search for'
return return
if not target: if not target:
print >>result, 'error: invalid target' print >>result, 'error: invalid target'
return return
@ -151,31 +243,34 @@ def memfind (target, options, args, result):
if not process: if not process:
print >>result, 'error: invalid process' print >>result, 'error: invalid process'
return return
error = lldb.SBError() error = lldb.SBError()
bytes = process.ReadMemory (start_addr, options.size, error) bytes = process.ReadMemory(start_addr, options.size, error)
if error.Success(): if error.Success():
num_matches = 0 num_matches = 0
print >>result, "Searching memory range [%#x - %#x) for" % (start_addr, end_addr), print >>result, "Searching memory range [%#x - %#x) for" % (
start_addr, end_addr),
for byte in options.data: for byte in options.data:
print >>result, '%2.2x' % ord(byte), print >>result, '%2.2x' % ord(byte),
print >>result print >>result
match_index = string.find(bytes, options.data) match_index = string.find(bytes, options.data)
while match_index != -1: while match_index != -1:
num_matches = num_matches + 1 num_matches = num_matches + 1
print >>result, '%#x: %#x + %u' % (start_addr + match_index, start_addr, match_index) print >>result, '%#x: %#x + %u' % (start_addr +
match_index, start_addr, match_index)
match_index = string.find(bytes, options.data, match_index + 1) match_index = string.find(bytes, options.data, match_index + 1)
if num_matches == 0: if num_matches == 0:
print >>result, "error: no matches found" print >>result, "error: no matches found"
else: else:
print >>result, 'error: %s' % (error.GetCString()) print >>result, 'error: %s' % (error.GetCString())
if __name__ == '__main__': if __name__ == '__main__':
print 'error: this script is designed to be used within the embedded script interpreter in LLDB' print 'error: this script is designed to be used within the embedded script interpreter in LLDB'
elif getattr(lldb, 'debugger', None): elif getattr(lldb, 'debugger', None):
memfind_command.__doc__ = create_memfind_options().format_help() memfind_command.__doc__ = create_memfind_options().format_help()
lldb.debugger.HandleCommand('command script add -f memory.memfind_command memfind') lldb.debugger.HandleCommand(
'command script add -f memory.memfind_command memfind')
print '"memfind" command installed, use the "--help" option for detailed help' print '"memfind" command installed, use the "--help" option for detailed help'

View File

@ -3,21 +3,22 @@
import lldb import lldb
import struct import struct
class OperatingSystemPlugIn(object): class OperatingSystemPlugIn(object):
"""Class that provides data for an instance of a LLDB 'OperatingSystemPython' plug-in class""" """Class that provides data for an instance of a LLDB 'OperatingSystemPython' plug-in class"""
def __init__(self, process): def __init__(self, process):
'''Initialization needs a valid.SBProcess object. '''Initialization needs a valid.SBProcess object.
This plug-in will get created after a live process is valid and has stopped for the This plug-in will get created after a live process is valid and has stopped for the
first time.''' first time.'''
self.process = None self.process = None
self.registers = None self.registers = None
self.threads = None self.threads = None
if type(process) is lldb.SBProcess and process.IsValid(): if isinstance(process, lldb.SBProcess) and process.IsValid():
self.process = process self.process = process
self.threads = None # Will be an dictionary containing info for each thread self.threads = None # Will be an dictionary containing info for each thread
def get_target(self): def get_target(self):
# NOTE: Don't use "lldb.target" when trying to get your target as the "lldb.target" # NOTE: Don't use "lldb.target" when trying to get your target as the "lldb.target"
# tracks the current target in the LLDB command interpreter which isn't the # tracks the current target in the LLDB command interpreter which isn't the
@ -26,11 +27,16 @@ class OperatingSystemPlugIn(object):
def create_thread(self, tid, context): def create_thread(self, tid, context):
if tid == 0x444444444: if tid == 0x444444444:
thread_info = { 'tid' : tid, 'name' : 'four' , 'queue' : 'queue4', 'state' : 'stopped', 'stop_reason' : 'none' } thread_info = {
'tid': tid,
'name': 'four',
'queue': 'queue4',
'state': 'stopped',
'stop_reason': 'none'}
self.threads.append(thread_info) self.threads.append(thread_info)
return thread_info return thread_info
return None return None
def get_thread_info(self): def get_thread_info(self):
if not self.threads: if not self.threads:
# The sample dictionary below shows the values that can be returned for a thread # The sample dictionary below shows the values that can be returned for a thread
@ -48,57 +54,178 @@ class OperatingSystemPlugIn(object):
# Specifying this key/value pair for a thread will avoid a call to get_register_data() # Specifying this key/value pair for a thread will avoid a call to get_register_data()
# and can be used when your registers are in a thread context structure that is contiguous # and can be used when your registers are in a thread context structure that is contiguous
# in memory. Don't specify this if your register layout in memory doesn't match the layout # in memory. Don't specify this if your register layout in memory doesn't match the layout
# described by the dictionary returned from a call to the get_register_info() method. # described by the dictionary returned from a call to the
self.threads = [ # get_register_info() method.
{ 'tid' : 0x111111111, 'name' : 'one' , 'queue' : 'queue1', 'state' : 'stopped', 'stop_reason' : 'breakpoint'}, self.threads = [{'tid': 0x111111111,
{ 'tid' : 0x222222222, 'name' : 'two' , 'queue' : 'queue2', 'state' : 'stopped', 'stop_reason' : 'none' }, 'name': 'one',
{ 'tid' : 0x333333333, 'name' : 'three', 'queue' : 'queue3', 'state' : 'stopped', 'stop_reason' : 'trace' , 'register_data_addr' : 0x100000000 } 'queue': 'queue1',
] 'state': 'stopped',
'stop_reason': 'breakpoint'},
{'tid': 0x222222222,
'name': 'two',
'queue': 'queue2',
'state': 'stopped',
'stop_reason': 'none'},
{'tid': 0x333333333,
'name': 'three',
'queue': 'queue3',
'state': 'stopped',
'stop_reason': 'trace',
'register_data_addr': 0x100000000}]
return self.threads return self.threads
def get_register_info(self): def get_register_info(self):
if self.registers == None: if self.registers is None:
self.registers = dict() self.registers = dict()
triple = self.process.target.triple triple = self.process.target.triple
if triple: if triple:
arch = triple.split('-')[0] arch = triple.split('-')[0]
if arch == 'x86_64': if arch == 'x86_64':
self.registers['sets'] = ['GPR', 'FPU', 'EXC'] self.registers['sets'] = ['GPR', 'FPU', 'EXC']
self.registers['registers'] = [ self.registers['registers'] = [
{ 'name':'rax' , 'bitsize' : 64, 'offset' : 0, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 0, 'dwarf' : 0}, {'name': 'rax', 'bitsize': 64, 'offset': 0, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 0, 'dwarf': 0},
{ 'name':'rbx' , 'bitsize' : 64, 'offset' : 8, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 3, 'dwarf' : 3}, {'name': 'rbx', 'bitsize': 64, 'offset': 8, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 3, 'dwarf': 3},
{ 'name':'rcx' , 'bitsize' : 64, 'offset' : 16, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 2, 'dwarf' : 2, 'generic':'arg4', 'alt-name':'arg4', }, {'name': 'rcx', 'bitsize': 64, 'offset': 16, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 2, 'dwarf': 2, 'generic': 'arg4', 'alt-name': 'arg4', },
{ 'name':'rdx' , 'bitsize' : 64, 'offset' : 24, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 1, 'dwarf' : 1, 'generic':'arg3', 'alt-name':'arg3', }, {'name': 'rdx', 'bitsize': 64, 'offset': 24, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 1, 'dwarf': 1, 'generic': 'arg3', 'alt-name': 'arg3', },
{ 'name':'rdi' , 'bitsize' : 64, 'offset' : 32, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 5, 'dwarf' : 5, 'generic':'arg1', 'alt-name':'arg1', }, {'name': 'rdi', 'bitsize': 64, 'offset': 32, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 5, 'dwarf': 5, 'generic': 'arg1', 'alt-name': 'arg1', },
{ 'name':'rsi' , 'bitsize' : 64, 'offset' : 40, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 4, 'dwarf' : 4, 'generic':'arg2', 'alt-name':'arg2', }, {'name': 'rsi', 'bitsize': 64, 'offset': 40, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 4, 'dwarf': 4, 'generic': 'arg2', 'alt-name': 'arg2', },
{ 'name':'rbp' , 'bitsize' : 64, 'offset' : 48, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 6, 'dwarf' : 6, 'generic':'fp' , 'alt-name':'fp', }, {'name': 'rbp', 'bitsize': 64, 'offset': 48, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 6, 'dwarf': 6, 'generic': 'fp', 'alt-name': 'fp', },
{ 'name':'rsp' , 'bitsize' : 64, 'offset' : 56, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 7, 'dwarf' : 7, 'generic':'sp' , 'alt-name':'sp', }, {'name': 'rsp', 'bitsize': 64, 'offset': 56, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 7, 'dwarf': 7, 'generic': 'sp', 'alt-name': 'sp', },
{ 'name':'r8' , 'bitsize' : 64, 'offset' : 64, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 8, 'dwarf' : 8, 'generic':'arg5', 'alt-name':'arg5', }, {'name': 'r8', 'bitsize': 64, 'offset': 64, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 8, 'dwarf': 8, 'generic': 'arg5', 'alt-name': 'arg5', },
{ 'name':'r9' , 'bitsize' : 64, 'offset' : 72, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 9, 'dwarf' : 9, 'generic':'arg6', 'alt-name':'arg6', }, {'name': 'r9', 'bitsize': 64, 'offset': 72, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 9, 'dwarf': 9, 'generic': 'arg6', 'alt-name': 'arg6', },
{ 'name':'r10' , 'bitsize' : 64, 'offset' : 80, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 10, 'dwarf' : 10}, {'name': 'r10', 'bitsize': 64, 'offset': 80, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 10, 'dwarf': 10},
{ 'name':'r11' , 'bitsize' : 64, 'offset' : 88, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 11, 'dwarf' : 11}, {'name': 'r11', 'bitsize': 64, 'offset': 88, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 11, 'dwarf': 11},
{ 'name':'r12' , 'bitsize' : 64, 'offset' : 96, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 12, 'dwarf' : 12}, {'name': 'r12', 'bitsize': 64, 'offset': 96, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 12, 'dwarf': 12},
{ 'name':'r13' , 'bitsize' : 64, 'offset' : 104, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 13, 'dwarf' : 13}, {'name': 'r13', 'bitsize': 64, 'offset': 104, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 13, 'dwarf': 13},
{ 'name':'r14' , 'bitsize' : 64, 'offset' : 112, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 14, 'dwarf' : 14}, {'name': 'r14', 'bitsize': 64, 'offset': 112, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 14, 'dwarf': 14},
{ 'name':'r15' , 'bitsize' : 64, 'offset' : 120, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 15, 'dwarf' : 15}, {'name': 'r15', 'bitsize': 64, 'offset': 120, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 15, 'dwarf': 15},
{ 'name':'rip' , 'bitsize' : 64, 'offset' : 128, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'gcc' : 16, 'dwarf' : 16, 'generic':'pc', 'alt-name':'pc' }, {'name': 'rip', 'bitsize': 64, 'offset': 128, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'gcc': 16, 'dwarf': 16, 'generic': 'pc', 'alt-name': 'pc'},
{ 'name':'rflags' , 'bitsize' : 64, 'offset' : 136, 'encoding':'uint' , 'format':'hex' , 'set': 0, 'generic':'flags', 'alt-name':'flags' }, {'name': 'rflags', 'bitsize': 64, 'offset': 136, 'encoding': 'uint', 'format': 'hex', 'set': 0, 'generic': 'flags', 'alt-name': 'flags'},
{ 'name':'cs' , 'bitsize' : 64, 'offset' : 144, 'encoding':'uint' , 'format':'hex' , 'set': 0 }, {'name': 'cs', 'bitsize': 64, 'offset': 144, 'encoding': 'uint', 'format': 'hex', 'set': 0},
{ 'name':'fs' , 'bitsize' : 64, 'offset' : 152, 'encoding':'uint' , 'format':'hex' , 'set': 0 }, {'name': 'fs', 'bitsize': 64, 'offset': 152, 'encoding': 'uint', 'format': 'hex', 'set': 0},
{ 'name':'gs' , 'bitsize' : 64, 'offset' : 160, 'encoding':'uint' , 'format':'hex' , 'set': 0 }, {'name': 'gs', 'bitsize': 64, 'offset': 160, 'encoding': 'uint', 'format': 'hex', 'set': 0},
] ]
return self.registers return self.registers
def get_register_data(self, tid): def get_register_data(self, tid):
if tid == 0x111111111: if tid == 0x111111111:
return struct.pack('21Q',1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21); return struct.pack(
'21Q',
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21)
elif tid == 0x222222222: elif tid == 0x222222222:
return struct.pack('21Q',11,12,13,14,15,16,17,18,19,110,111,112,113,114,115,116,117,118,119,120,121); return struct.pack(
'21Q',
11,
12,
13,
14,
15,
16,
17,
18,
19,
110,
111,
112,
113,
114,
115,
116,
117,
118,
119,
120,
121)
elif tid == 0x333333333: elif tid == 0x333333333:
return struct.pack('21Q',21,22,23,24,25,26,27,28,29,210,211,212,213,214,215,216,217,218,219,220,221); return struct.pack(
'21Q',
21,
22,
23,
24,
25,
26,
27,
28,
29,
210,
211,
212,
213,
214,
215,
216,
217,
218,
219,
220,
221)
elif tid == 0x444444444: elif tid == 0x444444444:
return struct.pack('21Q',31,32,33,34,35,36,37,38,39,310,311,312,313,314,315,316,317,318,319,320,321); return struct.pack(
'21Q',
31,
32,
33,
34,
35,
36,
37,
38,
39,
310,
311,
312,
313,
314,
315,
316,
317,
318,
319,
320,
321)
else: else:
return struct.pack('21Q',41,42,43,44,45,46,47,48,49,410,411,412,413,414,415,416,417,418,419,420,421); return struct.pack(
'21Q',
41,
42,
43,
44,
45,
46,
47,
48,
49,
410,
411,
412,
413,
414,
415,
416,
417,
418,
419,
420,
421)
return None return None

View File

@ -21,7 +21,7 @@ import types
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# Code that auto imports LLDB # Code that auto imports LLDB
#---------------------------------------------------------------------- #----------------------------------------------------------------------
try: try:
# Just try for LLDB in case PYTHONPATH is already correctly setup # Just try for LLDB in case PYTHONPATH is already correctly setup
import lldb import lldb
except ImportError: except ImportError:
@ -32,15 +32,20 @@ except ImportError:
# On Darwin, try the currently selected Xcode directory # On Darwin, try the currently selected Xcode directory
xcode_dir = commands.getoutput("xcode-select --print-path") xcode_dir = commands.getoutput("xcode-select --print-path")
if xcode_dir: if xcode_dir:
lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python')) lldb_python_dirs.append(
lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python') os.path.realpath(
lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') xcode_dir +
'/../SharedFrameworks/LLDB.framework/Resources/Python'))
lldb_python_dirs.append(
xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
lldb_python_dirs.append(
'/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
success = False success = False
for lldb_python_dir in lldb_python_dirs: for lldb_python_dir in lldb_python_dirs:
if os.path.exists(lldb_python_dir): if os.path.exists(lldb_python_dir):
if not (sys.path.__contains__(lldb_python_dir)): if not (sys.path.__contains__(lldb_python_dir)):
sys.path.append(lldb_python_dir) sys.path.append(lldb_python_dir)
try: try:
import lldb import lldb
except ImportError: except ImportError:
pass pass
@ -53,7 +58,8 @@ except ImportError:
sys.exit(1) sys.exit(1)
class Timer: class Timer:
def __enter__(self): def __enter__(self):
self.start = time.clock() self.start = time.clock()
return self return self
@ -62,30 +68,45 @@ class Timer:
self.end = time.clock() self.end = time.clock()
self.interval = self.end - self.start self.interval = self.end - self.start
class Action(object): class Action(object):
"""Class that encapsulates actions to take when a thread stops for a reason.""" """Class that encapsulates actions to take when a thread stops for a reason."""
def __init__(self, callback = None, callback_owner = None):
def __init__(self, callback=None, callback_owner=None):
self.callback = callback self.callback = callback
self.callback_owner = callback_owner self.callback_owner = callback_owner
def ThreadStopped (self, thread):
def ThreadStopped(self, thread):
assert False, "performance.Action.ThreadStopped(self, thread) must be overridden in a subclass" assert False, "performance.Action.ThreadStopped(self, thread) must be overridden in a subclass"
class PlanCompleteAction (Action): class PlanCompleteAction (Action):
def __init__(self, callback = None, callback_owner = None):
def __init__(self, callback=None, callback_owner=None):
Action.__init__(self, callback, callback_owner) Action.__init__(self, callback, callback_owner)
def ThreadStopped (self, thread):
def ThreadStopped(self, thread):
if thread.GetStopReason() == lldb.eStopReasonPlanComplete: if thread.GetStopReason() == lldb.eStopReasonPlanComplete:
if self.callback: if self.callback:
if self.callback_owner: if self.callback_owner:
self.callback (self.callback_owner, thread) self.callback(self.callback_owner, thread)
else: else:
self.callback (thread) self.callback(thread)
return True return True
return False return False
class BreakpointAction (Action): class BreakpointAction (Action):
def __init__(self, callback = None, callback_owner = None, name = None, module = None, file = None, line = None, breakpoint = None):
def __init__(
self,
callback=None,
callback_owner=None,
name=None,
module=None,
file=None,
line=None,
breakpoint=None):
Action.__init__(self, callback, callback_owner) Action.__init__(self, callback, callback_owner)
self.modules = lldb.SBFileSpecList() self.modules = lldb.SBFileSpecList()
self.files = lldb.SBFileSpecList() self.files = lldb.SBFileSpecList()
@ -97,7 +118,8 @@ class BreakpointAction (Action):
if module: if module:
if isinstance(module, types.ListType): if isinstance(module, types.ListType):
for module_path in module: for module_path in module:
self.modules.Append(lldb.SBFileSpec(module_path, False)) self.modules.Append(
lldb.SBFileSpec(module_path, False))
elif isinstance(module, types.StringTypes): elif isinstance(module, types.StringTypes):
self.modules.Append(lldb.SBFileSpec(module, False)) self.modules.Append(lldb.SBFileSpec(module, False))
if name: if name:
@ -109,22 +131,30 @@ class BreakpointAction (Action):
self.files.Append(lldb.SBFileSpec(f, False)) self.files.Append(lldb.SBFileSpec(f, False))
elif isinstance(file, types.StringTypes): elif isinstance(file, types.StringTypes):
self.files.Append(lldb.SBFileSpec(file, False)) self.files.Append(lldb.SBFileSpec(file, False))
self.breakpoints.append (self.target.BreakpointCreateByName(name, self.modules, self.files)) self.breakpoints.append(
self.target.BreakpointCreateByName(
name, self.modules, self.files))
elif file and line: elif file and line:
self.breakpoints.append (self.target.BreakpointCreateByLocation(file, line)) self.breakpoints.append(
def ThreadStopped (self, thread): self.target.BreakpointCreateByLocation(
file, line))
def ThreadStopped(self, thread):
if thread.GetStopReason() == lldb.eStopReasonBreakpoint: if thread.GetStopReason() == lldb.eStopReasonBreakpoint:
for bp in self.breakpoints: for bp in self.breakpoints:
if bp.GetID() == thread.GetStopReasonDataAtIndex(0): if bp.GetID() == thread.GetStopReasonDataAtIndex(0):
if self.callback: if self.callback:
if self.callback_owner: if self.callback_owner:
self.callback (self.callback_owner, thread) self.callback(self.callback_owner, thread)
else: else:
self.callback (thread) self.callback(thread)
return True return True
return False return False
class TestCase: class TestCase:
"""Class that aids in running performance tests.""" """Class that aids in running performance tests."""
def __init__(self): def __init__(self):
self.verbose = False self.verbose = False
self.debugger = lldb.SBDebugger.Create() self.debugger = lldb.SBDebugger.Create()
@ -137,36 +167,37 @@ class TestCase:
self.user_actions = list() self.user_actions = list()
self.builtin_actions = list() self.builtin_actions = list()
self.bp_id_to_dict = dict() self.bp_id_to_dict = dict()
def Setup(self, args): def Setup(self, args):
self.launch_info = lldb.SBLaunchInfo(args) self.launch_info = lldb.SBLaunchInfo(args)
def Run (self, args): def Run(self, args):
assert False, "performance.TestCase.Run(self, args) must be subclassed" assert False, "performance.TestCase.Run(self, args) must be subclassed"
def Launch(self): def Launch(self):
if self.target: if self.target:
error = lldb.SBError() error = lldb.SBError()
self.process = self.target.Launch (self.launch_info, error) self.process = self.target.Launch(self.launch_info, error)
if not error.Success(): if not error.Success():
print "error: %s" % error.GetCString() print "error: %s" % error.GetCString()
if self.process: if self.process:
self.process.GetBroadcaster().AddListener(self.listener, lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitInterrupt) self.process.GetBroadcaster().AddListener(self.listener,
lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitInterrupt)
return True return True
return False return False
def WaitForNextProcessEvent (self): def WaitForNextProcessEvent(self):
event = None event = None
if self.process: if self.process:
while event is None: while event is None:
process_event = lldb.SBEvent() process_event = lldb.SBEvent()
if self.listener.WaitForEvent (lldb.UINT32_MAX, process_event): if self.listener.WaitForEvent(lldb.UINT32_MAX, process_event):
state = lldb.SBProcess.GetStateFromEvent (process_event) state = lldb.SBProcess.GetStateFromEvent(process_event)
if self.verbose: if self.verbose:
print "event = %s" % (lldb.SBDebugger.StateAsCString(state)) print "event = %s" % (lldb.SBDebugger.StateAsCString(state))
if lldb.SBProcess.GetRestartedFromEvent(process_event): if lldb.SBProcess.GetRestartedFromEvent(process_event):
continue continue
if state == lldb.eStateInvalid or state == lldb.eStateDetached or state == lldb.eStateCrashed or state == lldb.eStateUnloaded or state == lldb.eStateExited: if state == lldb.eStateInvalid or state == lldb.eStateDetached or state == lldb.eStateCrashed or state == lldb.eStateUnloaded or state == lldb.eStateExited:
event = process_event event = process_event
self.done = True self.done = True
elif state == lldb.eStateConnected or state == lldb.eStateAttaching or state == lldb.eStateLaunching or state == lldb.eStateRunning or state == lldb.eStateStepping or state == lldb.eStateSuspended: elif state == lldb.eStateConnected or state == lldb.eStateAttaching or state == lldb.eStateLaunching or state == lldb.eStateRunning or state == lldb.eStateStepping or state == lldb.eStateSuspended:
@ -179,10 +210,10 @@ class TestCase:
for thread in self.process: for thread in self.process:
frame = thread.GetFrameAtIndex(0) frame = thread.GetFrameAtIndex(0)
select_thread = False select_thread = False
stop_reason = thread.GetStopReason() stop_reason = thread.GetStopReason()
if self.verbose: if self.verbose:
print "tid = %#x pc = %#x " % (thread.GetThreadID(),frame.GetPC()), print "tid = %#x pc = %#x " % (thread.GetThreadID(), frame.GetPC()),
if stop_reason == lldb.eStopReasonNone: if stop_reason == lldb.eStopReasonNone:
if self.verbose: if self.verbose:
print "none" print "none"
@ -222,37 +253,53 @@ class TestCase:
select_thread = True select_thread = True
if self.verbose: if self.verbose:
print "signal %d" % (thread.GetStopReasonDataAtIndex(0)) print "signal %d" % (thread.GetStopReasonDataAtIndex(0))
if select_thread and not selected_thread: if select_thread and not selected_thread:
self.thread = thread self.thread = thread
selected_thread = self.process.SetSelectedThread(thread) selected_thread = self.process.SetSelectedThread(
thread)
for action in self.user_actions: for action in self.user_actions:
action.ThreadStopped (thread) action.ThreadStopped(thread)
if fatal: if fatal:
# if self.verbose: # if self.verbose:
# Xcode.RunCommand(self.debugger,"bt all",true) # Xcode.RunCommand(self.debugger,"bt all",true)
sys.exit(1) sys.exit(1)
return event return event
class Measurement: class Measurement:
'''A class that encapsulates a measurement''' '''A class that encapsulates a measurement'''
def __init__(self): def __init__(self):
object.__init__(self) object.__init__(self)
def Measure(self): def Measure(self):
assert False, "performance.Measurement.Measure() must be subclassed" assert False, "performance.Measurement.Measure() must be subclassed"
class MemoryMeasurement(Measurement): class MemoryMeasurement(Measurement):
'''A class that can measure memory statistics for a process.''' '''A class that can measure memory statistics for a process.'''
def __init__(self, pid): def __init__(self, pid):
Measurement.__init__(self) Measurement.__init__(self)
self.pid = pid self.pid = pid
self.stats = ["rprvt","rshrd","rsize","vsize","vprvt","kprvt","kshrd","faults","cow","pageins"] self.stats = [
self.command = "top -l 1 -pid %u -stats %s" % (self.pid, ",".join(self.stats)) "rprvt",
"rshrd",
"rsize",
"vsize",
"vprvt",
"kprvt",
"kshrd",
"faults",
"cow",
"pageins"]
self.command = "top -l 1 -pid %u -stats %s" % (
self.pid, ",".join(self.stats))
self.value = dict() self.value = dict()
def Measure(self): def Measure(self):
output = commands.getoutput(self.command).split("\n")[-1] output = commands.getoutput(self.command).split("\n")[-1]
values = re.split('[-+\s]+', output) values = re.split('[-+\s]+', output)
@ -263,14 +310,14 @@ class MemoryMeasurement(Measurement):
multiplier = 1024 multiplier = 1024
stat = stat[:-1] stat = stat[:-1]
elif stat[-1] == 'M': elif stat[-1] == 'M':
multiplier = 1024*1024 multiplier = 1024 * 1024
stat = stat[:-1] stat = stat[:-1]
elif stat[-1] == 'G': elif stat[-1] == 'G':
multiplier = 1024*1024*1024 multiplier = 1024 * 1024 * 1024
elif stat[-1] == 'T': elif stat[-1] == 'T':
multiplier = 1024*1024*1024*1024 multiplier = 1024 * 1024 * 1024 * 1024
stat = stat[:-1] stat = stat[:-1]
self.value[self.stats[idx]] = int (stat) * multiplier self.value[self.stats[idx]] = int(stat) * multiplier
def __str__(self): def __str__(self):
'''Dump the MemoryMeasurement current value''' '''Dump the MemoryMeasurement current value'''
@ -282,37 +329,47 @@ class MemoryMeasurement(Measurement):
return s return s
class TesterTestCase(TestCase): class TesterTestCase(TestCase):
def __init__(self): def __init__(self):
TestCase.__init__(self) TestCase.__init__(self)
self.verbose = True self.verbose = True
self.num_steps = 5 self.num_steps = 5
def BreakpointHit (self, thread): def BreakpointHit(self, thread):
bp_id = thread.GetStopReasonDataAtIndex(0) bp_id = thread.GetStopReasonDataAtIndex(0)
loc_id = thread.GetStopReasonDataAtIndex(1) loc_id = thread.GetStopReasonDataAtIndex(1)
print "Breakpoint %i.%i hit: %s" % (bp_id, loc_id, thread.process.target.FindBreakpointByID(bp_id)) print "Breakpoint %i.%i hit: %s" % (bp_id, loc_id, thread.process.target.FindBreakpointByID(bp_id))
thread.StepOver() thread.StepOver()
def PlanComplete (self, thread): def PlanComplete(self, thread):
if self.num_steps > 0: if self.num_steps > 0:
thread.StepOver() thread.StepOver()
self.num_steps = self.num_steps - 1 self.num_steps = self.num_steps - 1
else: else:
thread.process.Kill() thread.process.Kill()
def Run (self, args): def Run(self, args):
self.Setup(args) self.Setup(args)
with Timer() as total_time: with Timer() as total_time:
self.target = self.debugger.CreateTarget(args[0]) self.target = self.debugger.CreateTarget(args[0])
if self.target: if self.target:
with Timer() as breakpoint_timer: with Timer() as breakpoint_timer:
bp = self.target.BreakpointCreateByName("main") bp = self.target.BreakpointCreateByName("main")
print('Breakpoint time = %.03f sec.' % breakpoint_timer.interval) print(
'Breakpoint time = %.03f sec.' %
self.user_actions.append (BreakpointAction(breakpoint=bp, callback=TesterTestCase.BreakpointHit, callback_owner=self)) breakpoint_timer.interval)
self.user_actions.append (PlanCompleteAction(callback=TesterTestCase.PlanComplete, callback_owner=self))
self.user_actions.append(
BreakpointAction(
breakpoint=bp,
callback=TesterTestCase.BreakpointHit,
callback_owner=self))
self.user_actions.append(
PlanCompleteAction(
callback=TesterTestCase.PlanComplete,
callback_owner=self))
if self.Launch(): if self.Launch():
while not self.done: while not self.done:
self.WaitForNextProcessEvent() self.WaitForNextProcessEvent()
@ -321,12 +378,12 @@ class TesterTestCase(TestCase):
else: else:
print "error: failed to create target with '%s'" % (args[0]) print "error: failed to create target with '%s'" % (args[0])
print('Total time = %.03f sec.' % total_time.interval) print('Total time = %.03f sec.' % total_time.interval)
if __name__ == '__main__': if __name__ == '__main__':
lldb.SBDebugger.Initialize() lldb.SBDebugger.Initialize()
test = TesterTestCase() test = TesterTestCase()
test.Run (sys.argv[1:]) test.Run(sys.argv[1:])
mem = MemoryMeasurement(os.getpid()) mem = MemoryMeasurement(os.getpid())
mem.Measure() mem.Measure()
print str(mem) print str(mem)

View File

@ -17,7 +17,7 @@ import sys
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# Code that auto imports LLDB # Code that auto imports LLDB
#---------------------------------------------------------------------- #----------------------------------------------------------------------
try: try:
# Just try for LLDB in case PYTHONPATH is already correctly setup # Just try for LLDB in case PYTHONPATH is already correctly setup
import lldb import lldb
except ImportError: except ImportError:
@ -28,15 +28,20 @@ except ImportError:
# On Darwin, try the currently selected Xcode directory # On Darwin, try the currently selected Xcode directory
xcode_dir = commands.getoutput("xcode-select --print-path") xcode_dir = commands.getoutput("xcode-select --print-path")
if xcode_dir: if xcode_dir:
lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python')) lldb_python_dirs.append(
lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python') os.path.realpath(
lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') xcode_dir +
'/../SharedFrameworks/LLDB.framework/Resources/Python'))
lldb_python_dirs.append(
xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
lldb_python_dirs.append(
'/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
success = False success = False
for lldb_python_dir in lldb_python_dirs: for lldb_python_dir in lldb_python_dirs:
if os.path.exists(lldb_python_dir): if os.path.exists(lldb_python_dir):
if not (sys.path.__contains__(lldb_python_dir)): if not (sys.path.__contains__(lldb_python_dir)):
sys.path.append(lldb_python_dir) sys.path.append(lldb_python_dir)
try: try:
import lldb import lldb
except ImportError: except ImportError:
pass pass
@ -48,117 +53,241 @@ except ImportError:
print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly" print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
sys.exit(1) sys.exit(1)
def print_threads(process, options): def print_threads(process, options):
if options.show_threads: if options.show_threads:
for thread in process: for thread in process:
print '%s %s' % (thread, thread.GetFrameAtIndex(0)) print '%s %s' % (thread, thread.GetFrameAtIndex(0))
def run_commands(command_interpreter, commands): def run_commands(command_interpreter, commands):
return_obj = lldb.SBCommandReturnObject() return_obj = lldb.SBCommandReturnObject()
for command in commands: for command in commands:
command_interpreter.HandleCommand( command, return_obj ) command_interpreter.HandleCommand(command, return_obj)
if return_obj.Succeeded(): if return_obj.Succeeded():
print return_obj.GetOutput() print return_obj.GetOutput()
else: else:
print return_obj print return_obj
if options.stop_on_error: if options.stop_on_error:
break break
def main(argv): def main(argv):
description='''Debugs a program using the LLDB python API and uses asynchronous broadcast events to watch for process state changes.''' description = '''Debugs a program using the LLDB python API and uses asynchronous broadcast events to watch for process state changes.'''
epilog='''Examples: epilog = '''Examples:
#---------------------------------------------------------------------- #----------------------------------------------------------------------
# Run "/bin/ls" with the arguments "-lAF /tmp/", and set a breakpoint # Run "/bin/ls" with the arguments "-lAF /tmp/", and set a breakpoint
# at "malloc" and backtrace and read all registers each time we stop # at "malloc" and backtrace and read all registers each time we stop
#---------------------------------------------------------------------- #----------------------------------------------------------------------
% ./process_events.py --breakpoint malloc --stop-command bt --stop-command 'register read' -- /bin/ls -lAF /tmp/ % ./process_events.py --breakpoint malloc --stop-command bt --stop-command 'register read' -- /bin/ls -lAF /tmp/
''' '''
optparse.OptionParser.format_epilog = lambda self, formatter: self.epilog optparse.OptionParser.format_epilog = lambda self, formatter: self.epilog
parser = optparse.OptionParser(description=description, prog='process_events',usage='usage: process_events [options] program [arg1 arg2]', epilog=epilog) parser = optparse.OptionParser(
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help="Enable verbose logging.", default=False) description=description,
parser.add_option('-b', '--breakpoint', action='append', type='string', metavar='BPEXPR', dest='breakpoints', help='Breakpoint commands to create after the target has been created, the values will be sent to the "_regexp-break" command which supports breakpoints by name, file:line, and address.') prog='process_events',
parser.add_option('-a', '--arch', type='string', dest='arch', help='The architecture to use when creating the debug target.', default=None) usage='usage: process_events [options] program [arg1 arg2]',
parser.add_option('--platform', type='string', metavar='platform', dest='platform', help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".', default=None) epilog=epilog)
parser.add_option('-l', '--launch-command', action='append', type='string', metavar='CMD', dest='launch_commands', help='LLDB command interpreter commands to run once after the process has launched. This option can be specified more than once.', default=[]) parser.add_option(
parser.add_option('-s', '--stop-command', action='append', type='string', metavar='CMD', dest='stop_commands', help='LLDB command interpreter commands to run each time the process stops. This option can be specified more than once.', default=[]) '-v',
parser.add_option('-c', '--crash-command', action='append', type='string', metavar='CMD', dest='crash_commands', help='LLDB command interpreter commands to run in case the process crashes. This option can be specified more than once.', default=[]) '--verbose',
parser.add_option('-x', '--exit-command', action='append', type='string', metavar='CMD', dest='exit_commands', help='LLDB command interpreter commands to run once after the process has exited. This option can be specified more than once.', default=[]) action='store_true',
parser.add_option('-T', '--no-threads', action='store_false', dest='show_threads', help="Don't show threads when process stops.", default=True) dest='verbose',
parser.add_option('--ignore-errors', action='store_false', dest='stop_on_error', help="Don't stop executing LLDB commands if the command returns an error. This applies to all of the LLDB command interpreter commands that get run for launch, stop, crash and exit.", default=True) help="Enable verbose logging.",
parser.add_option('-n', '--run-count', type='int', dest='run_count', metavar='N', help='How many times to run the process in case the process exits.', default=1) default=False)
parser.add_option('-t', '--event-timeout', type='int', dest='event_timeout', metavar='SEC', help='Specify the timeout in seconds to wait for process state change events.', default=lldb.UINT32_MAX) parser.add_option(
parser.add_option('-e', '--environment', action='append', type='string', metavar='ENV', dest='env_vars', help='Environment variables to set in the inferior process when launching a process.') '-b',
parser.add_option('-d', '--working-dir', type='string', metavar='DIR', dest='working_dir', help='The the current working directory when launching a process.', default=None) '--breakpoint',
parser.add_option('-p', '--attach-pid', type='int', dest='attach_pid', metavar='PID', help='Specify a process to attach to by process ID.', default=-1) action='append',
parser.add_option('-P', '--attach-name', type='string', dest='attach_name', metavar='PROCESSNAME', help='Specify a process to attach to by name.', default=None) type='string',
parser.add_option('-w', '--attach-wait', action='store_true', dest='attach_wait', help='Wait for the next process to launch when attaching to a process by name.', default=False) metavar='BPEXPR',
dest='breakpoints',
help='Breakpoint commands to create after the target has been created, the values will be sent to the "_regexp-break" command which supports breakpoints by name, file:line, and address.')
parser.add_option(
'-a',
'--arch',
type='string',
dest='arch',
help='The architecture to use when creating the debug target.',
default=None)
parser.add_option(
'--platform',
type='string',
metavar='platform',
dest='platform',
help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".',
default=None)
parser.add_option(
'-l',
'--launch-command',
action='append',
type='string',
metavar='CMD',
dest='launch_commands',
help='LLDB command interpreter commands to run once after the process has launched. This option can be specified more than once.',
default=[])
parser.add_option(
'-s',
'--stop-command',
action='append',
type='string',
metavar='CMD',
dest='stop_commands',
help='LLDB command interpreter commands to run each time the process stops. This option can be specified more than once.',
default=[])
parser.add_option(
'-c',
'--crash-command',
action='append',
type='string',
metavar='CMD',
dest='crash_commands',
help='LLDB command interpreter commands to run in case the process crashes. This option can be specified more than once.',
default=[])
parser.add_option(
'-x',
'--exit-command',
action='append',
type='string',
metavar='CMD',
dest='exit_commands',
help='LLDB command interpreter commands to run once after the process has exited. This option can be specified more than once.',
default=[])
parser.add_option(
'-T',
'--no-threads',
action='store_false',
dest='show_threads',
help="Don't show threads when process stops.",
default=True)
parser.add_option(
'--ignore-errors',
action='store_false',
dest='stop_on_error',
help="Don't stop executing LLDB commands if the command returns an error. This applies to all of the LLDB command interpreter commands that get run for launch, stop, crash and exit.",
default=True)
parser.add_option(
'-n',
'--run-count',
type='int',
dest='run_count',
metavar='N',
help='How many times to run the process in case the process exits.',
default=1)
parser.add_option(
'-t',
'--event-timeout',
type='int',
dest='event_timeout',
metavar='SEC',
help='Specify the timeout in seconds to wait for process state change events.',
default=lldb.UINT32_MAX)
parser.add_option(
'-e',
'--environment',
action='append',
type='string',
metavar='ENV',
dest='env_vars',
help='Environment variables to set in the inferior process when launching a process.')
parser.add_option(
'-d',
'--working-dir',
type='string',
metavar='DIR',
dest='working_dir',
help='The the current working directory when launching a process.',
default=None)
parser.add_option(
'-p',
'--attach-pid',
type='int',
dest='attach_pid',
metavar='PID',
help='Specify a process to attach to by process ID.',
default=-1)
parser.add_option(
'-P',
'--attach-name',
type='string',
dest='attach_name',
metavar='PROCESSNAME',
help='Specify a process to attach to by name.',
default=None)
parser.add_option(
'-w',
'--attach-wait',
action='store_true',
dest='attach_wait',
help='Wait for the next process to launch when attaching to a process by name.',
default=False)
try: try:
(options, args) = parser.parse_args(argv) (options, args) = parser.parse_args(argv)
except: except:
return return
attach_info = None attach_info = None
launch_info = None launch_info = None
exe = None exe = None
if args: if args:
exe = args.pop(0) exe = args.pop(0)
launch_info = lldb.SBLaunchInfo (args) launch_info = lldb.SBLaunchInfo(args)
if options.env_vars: if options.env_vars:
launch_info.SetEnvironmentEntries(options.env_vars, True) launch_info.SetEnvironmentEntries(options.env_vars, True)
if options.working_dir: if options.working_dir:
launch_info.SetWorkingDirectory(options.working_dir) launch_info.SetWorkingDirectory(options.working_dir)
elif options.attach_pid != -1: elif options.attach_pid != -1:
if options.run_count == 1: if options.run_count == 1:
attach_info = lldb.SBAttachInfo (options.attach_pid) attach_info = lldb.SBAttachInfo(options.attach_pid)
else: else:
print "error: --run-count can't be used with the --attach-pid option" print "error: --run-count can't be used with the --attach-pid option"
sys.exit(1) sys.exit(1)
elif not options.attach_name is None: elif not options.attach_name is None:
if options.run_count == 1: if options.run_count == 1:
attach_info = lldb.SBAttachInfo (options.attach_name, options.attach_wait) attach_info = lldb.SBAttachInfo(
options.attach_name, options.attach_wait)
else: else:
print "error: --run-count can't be used with the --attach-name option" print "error: --run-count can't be used with the --attach-name option"
sys.exit(1) sys.exit(1)
else: else:
print 'error: a program path for a program to debug and its arguments are required' print 'error: a program path for a program to debug and its arguments are required'
sys.exit(1) sys.exit(1)
# Create a new debugger instance # Create a new debugger instance
debugger = lldb.SBDebugger.Create() debugger = lldb.SBDebugger.Create()
debugger.SetAsync (True) debugger.SetAsync(True)
command_interpreter = debugger.GetCommandInterpreter() command_interpreter = debugger.GetCommandInterpreter()
# Create a target from a file and arch # Create a target from a file and arch
if exe: if exe:
print "Creating a target for '%s'" % exe print "Creating a target for '%s'" % exe
error = lldb.SBError() error = lldb.SBError()
target = debugger.CreateTarget (exe, options.arch, options.platform, True, error) target = debugger.CreateTarget(
exe, options.arch, options.platform, True, error)
if target: if target:
# Set any breakpoints that were specified in the args if we are launching. We use the # Set any breakpoints that were specified in the args if we are launching. We use the
# command line command to take advantage of the shorthand breakpoint creation # command line command to take advantage of the shorthand breakpoint
# creation
if launch_info and options.breakpoints: if launch_info and options.breakpoints:
for bp in options.breakpoints: for bp in options.breakpoints:
debugger.HandleCommand( "_regexp-break %s" % (bp)) debugger.HandleCommand("_regexp-break %s" % (bp))
run_commands(command_interpreter, ['breakpoint list']) run_commands(command_interpreter, ['breakpoint list'])
for run_idx in range(options.run_count): for run_idx in range(options.run_count):
# Launch the process. Since we specified synchronous mode, we won't return # Launch the process. Since we specified synchronous mode, we won't return
# from this function until we hit the breakpoint at main # from this function until we hit the breakpoint at main
error = lldb.SBError() error = lldb.SBError()
if launch_info: if launch_info:
if options.run_count == 1: if options.run_count == 1:
print 'Launching "%s"...' % (exe) print 'Launching "%s"...' % (exe)
else: else:
print 'Launching "%s"... (launch %u of %u)' % (exe, run_idx + 1, options.run_count) print 'Launching "%s"... (launch %u of %u)' % (exe, run_idx + 1, options.run_count)
process = target.Launch (launch_info, error) process = target.Launch(launch_info, error)
else: else:
if options.attach_pid != -1: if options.attach_pid != -1:
print 'Attaching to process %i...' % (options.attach_pid) print 'Attaching to process %i...' % (options.attach_pid)
@ -167,15 +296,16 @@ def main(argv):
print 'Waiting for next to process named "%s" to launch...' % (options.attach_name) print 'Waiting for next to process named "%s" to launch...' % (options.attach_name)
else: else:
print 'Attaching to existing process named "%s"...' % (options.attach_name) print 'Attaching to existing process named "%s"...' % (options.attach_name)
process = target.Attach (attach_info, error) process = target.Attach(attach_info, error)
# Make sure the launch went ok # Make sure the launch went ok
if process and process.GetProcessID() != lldb.LLDB_INVALID_PROCESS_ID: if process and process.GetProcessID() != lldb.LLDB_INVALID_PROCESS_ID:
pid = process.GetProcessID() pid = process.GetProcessID()
print 'Process is %i' % (pid) print 'Process is %i' % (pid)
if attach_info: if attach_info:
# continue process if we attached as we won't get an initial event # continue process if we attached as we won't get an
# initial event
process.Continue() process.Continue()
listener = debugger.GetListener() listener = debugger.GetListener()
@ -184,9 +314,9 @@ def main(argv):
done = False done = False
while not done: while not done:
event = lldb.SBEvent() event = lldb.SBEvent()
if listener.WaitForEvent (options.event_timeout, event): if listener.WaitForEvent(options.event_timeout, event):
if lldb.SBProcess.EventIsProcessEvent(event): if lldb.SBProcess.EventIsProcessEvent(event):
state = lldb.SBProcess.GetStateFromEvent (event) state = lldb.SBProcess.GetStateFromEvent(event)
if state == lldb.eStateInvalid: if state == lldb.eStateInvalid:
# Not a state event # Not a state event
print 'process event = %s' % (event) print 'process event = %s' % (event)
@ -196,42 +326,51 @@ def main(argv):
if stop_idx == 0: if stop_idx == 0:
if launch_info: if launch_info:
print "process %u launched" % (pid) print "process %u launched" % (pid)
run_commands(command_interpreter, ['breakpoint list']) run_commands(
command_interpreter, ['breakpoint list'])
else: else:
print "attached to process %u" % (pid) print "attached to process %u" % (pid)
for m in target.modules: for m in target.modules:
print m print m
if options.breakpoints: if options.breakpoints:
for bp in options.breakpoints: for bp in options.breakpoints:
debugger.HandleCommand( "_regexp-break %s" % (bp)) debugger.HandleCommand(
run_commands(command_interpreter, ['breakpoint list']) "_regexp-break %s" % (bp))
run_commands (command_interpreter, options.launch_commands) run_commands(
command_interpreter, ['breakpoint list'])
run_commands(
command_interpreter, options.launch_commands)
else: else:
if options.verbose: if options.verbose:
print "process %u stopped" % (pid) print "process %u stopped" % (pid)
run_commands (command_interpreter, options.stop_commands) run_commands(
command_interpreter, options.stop_commands)
stop_idx += 1 stop_idx += 1
print_threads (process, options) print_threads(process, options)
print "continuing process %u" % (pid) print "continuing process %u" % (pid)
process.Continue() process.Continue()
elif state == lldb.eStateExited: elif state == lldb.eStateExited:
exit_desc = process.GetExitDescription() exit_desc = process.GetExitDescription()
if exit_desc: if exit_desc:
print "process %u exited with status %u: %s" % (pid, process.GetExitStatus (), exit_desc) print "process %u exited with status %u: %s" % (pid, process.GetExitStatus(), exit_desc)
else: else:
print "process %u exited with status %u" % (pid, process.GetExitStatus ()) print "process %u exited with status %u" % (pid, process.GetExitStatus())
run_commands (command_interpreter, options.exit_commands) run_commands(
command_interpreter, options.exit_commands)
done = True done = True
elif state == lldb.eStateCrashed: elif state == lldb.eStateCrashed:
print "process %u crashed" % (pid) print "process %u crashed" % (pid)
print_threads (process, options) print_threads(process, options)
run_commands (command_interpreter, options.crash_commands) run_commands(
command_interpreter, options.crash_commands)
done = True done = True
elif state == lldb.eStateDetached: elif state == lldb.eStateDetached:
print "process %u detached" % (pid) print "process %u detached" % (pid)
done = True done = True
elif state == lldb.eStateRunning: elif state == lldb.eStateRunning:
# process is running, don't say anything, we will always get one of these after resuming # process is running, don't say anything,
# we will always get one of these after
# resuming
if options.verbose: if options.verbose:
print "process %u resumed" % (pid) print "process %u resumed" % (pid)
elif state == lldb.eStateUnloaded: elif state == lldb.eStateUnloaded:
@ -262,7 +401,7 @@ def main(argv):
while process_stderr: while process_stderr:
process_stderr = process.GetSTDERR(1024) process_stderr = process.GetSTDERR(1024)
print process_stderr print process_stderr
process.Kill() # kill the process process.Kill() # kill the process
else: else:
if error: if error:
print error print error
@ -271,8 +410,8 @@ def main(argv):
print 'error: launch failed' print 'error: launch failed'
else: else:
print 'error: attach failed' print 'error: attach failed'
lldb.SBDebugger.Terminate() lldb.SBDebugger.Terminate()
if __name__ == '__main__': if __name__ == '__main__':
main(sys.argv[1:]) main(sys.argv[1:])

View File

@ -2,310 +2,342 @@ import sys
import inspect import inspect
from collections import OrderedDict from collections import OrderedDict
class TracebackFancy: class TracebackFancy:
def __init__(self,traceback):
self.t = traceback
def getFrame(self): def __init__(self, traceback):
return FrameFancy(self.t.tb_frame) self.t = traceback
def getLineNumber(self): def getFrame(self):
return self.t.tb_lineno if self.t != None else None return FrameFancy(self.t.tb_frame)
def getNext(self): def getLineNumber(self):
return TracebackFancy(self.t.tb_next) return self.t.tb_lineno if self.t is not None else None
def getNext(self):
return TracebackFancy(self.t.tb_next)
def __str__(self):
if self.t is None:
return ""
str_self = "%s @ %s" % (
self.getFrame().getName(), self.getLineNumber())
return str_self + "\n" + self.getNext().__str__()
def __str__(self):
if self.t == None:
return ""
str_self = "%s @ %s" % (self.getFrame().getName(), self.getLineNumber())
return str_self + "\n" + self.getNext().__str__()
class ExceptionFancy: class ExceptionFancy:
def __init__(self,frame):
self.etraceback = frame.f_exc_traceback
self.etype = frame.exc_type
self.evalue = frame.f_exc_value
def __init__(self,tb,ty,va): def __init__(self, frame):
self.etraceback = tb self.etraceback = frame.f_exc_traceback
self.etype = ty self.etype = frame.exc_type
self.evalue = va self.evalue = frame.f_exc_value
def getTraceback(self): def __init__(self, tb, ty, va):
return TracebackFancy(self.etraceback) self.etraceback = tb
self.etype = ty
self.evalue = va
def __nonzero__(self): def getTraceback(self):
return self.etraceback != None or self.etype != None or self.evalue != None return TracebackFancy(self.etraceback)
def getType(self): def __nonzero__(self):
return str(self.etype) return self.etraceback is not None or self.etype is not None or self.evalue is not None
def getType(self):
return str(self.etype)
def getValue(self):
return self.evalue
def getValue(self):
return self.evalue
class CodeFancy: class CodeFancy:
def __init__(self,code):
self.c = code
def getArgCount(self): def __init__(self, code):
return self.c.co_argcount if self.c != None else 0 self.c = code
def getFilename(self): def getArgCount(self):
return self.c.co_filename if self.c != None else "" return self.c.co_argcount if self.c is not None else 0
def getVariables(self): def getFilename(self):
return self.c.co_varnames if self.c != None else [] return self.c.co_filename if self.c is not None else ""
def getName(self): def getVariables(self):
return self.c.co_name if self.c != None else "" return self.c.co_varnames if self.c is not None else []
def getName(self):
return self.c.co_name if self.c is not None else ""
def getFileName(self):
return self.c.co_filename if self.c is not None else ""
def getFileName(self):
return self.c.co_filename if self.c != None else ""
class ArgsFancy: class ArgsFancy:
def __init__(self,frame,arginfo):
self.f = frame
self.a = arginfo
def __str__(self): def __init__(self, frame, arginfo):
args, varargs, kwargs = self.getArgs(), self.getVarArgs(), self.getKWArgs() self.f = frame
ret = "" self.a = arginfo
count = 0
size = len(args)
for arg in args:
ret = ret + ("%s = %s" % (arg, args[arg]))
count = count + 1
if count < size:
ret = ret + ", "
if varargs:
if size > 0:
ret = ret + " "
ret = ret + "varargs are " + str(varargs)
if kwargs:
if size > 0:
ret = ret + " "
ret = ret + "kwargs are " + str(kwargs)
return ret
def getNumArgs(wantVarargs = False, wantKWArgs=False): def __str__(self):
args, varargs, keywords, values = self.a args, varargs, kwargs = self.getArgs(), self.getVarArgs(), self.getKWArgs()
size = len(args) ret = ""
if varargs and wantVarargs: count = 0
size = size+len(self.getVarArgs()) size = len(args)
if keywords and wantKWArgs: for arg in args:
size = size+len(self.getKWArgs()) ret = ret + ("%s = %s" % (arg, args[arg]))
return size count = count + 1
if count < size:
ret = ret + ", "
if varargs:
if size > 0:
ret = ret + " "
ret = ret + "varargs are " + str(varargs)
if kwargs:
if size > 0:
ret = ret + " "
ret = ret + "kwargs are " + str(kwargs)
return ret
def getArgs(self): def getNumArgs(wantVarargs=False, wantKWArgs=False):
args, _, _, values = self.a args, varargs, keywords, values = self.a
argWValues = OrderedDict() size = len(args)
for arg in args: if varargs and wantVarargs:
argWValues[arg] = values[arg] size = size + len(self.getVarArgs())
return argWValues if keywords and wantKWArgs:
size = size + len(self.getKWArgs())
return size
def getVarArgs(self): def getArgs(self):
_, vargs, _, _ = self.a args, _, _, values = self.a
if vargs: argWValues = OrderedDict()
return self.f.f_locals[vargs] for arg in args:
return () argWValues[arg] = values[arg]
return argWValues
def getVarArgs(self):
_, vargs, _, _ = self.a
if vargs:
return self.f.f_locals[vargs]
return ()
def getKWArgs(self):
_, _, kwargs, _ = self.a
if kwargs:
return self.f.f_locals[kwargs]
return {}
def getKWArgs(self):
_, _, kwargs, _ = self.a
if kwargs:
return self.f.f_locals[kwargs]
return {}
class FrameFancy: class FrameFancy:
def __init__(self,frame):
self.f = frame
def getCaller(self): def __init__(self, frame):
return FrameFancy(self.f.f_back) self.f = frame
def getLineNumber(self): def getCaller(self):
return self.f.f_lineno if self.f != None else 0 return FrameFancy(self.f.f_back)
def getCodeInformation(self): def getLineNumber(self):
return CodeFancy(self.f.f_code) if self.f != None else None return self.f.f_lineno if self.f is not None else 0
def getExceptionInfo(self): def getCodeInformation(self):
return ExceptionFancy(self.f) if self.f != None else None return CodeFancy(self.f.f_code) if self.f is not None else None
def getName(self): def getExceptionInfo(self):
return self.getCodeInformation().getName() if self.f != None else "" return ExceptionFancy(self.f) if self.f is not None else None
def getFileName(self): def getName(self):
return self.getCodeInformation().getFileName() if self.f != None else "" return self.getCodeInformation().getName() if self.f is not None else ""
def getFileName(self):
return self.getCodeInformation().getFileName() if self.f is not None else ""
def getLocals(self):
return self.f.f_locals if self.f is not None else {}
def getArgumentInfo(self):
return ArgsFancy(
self.f, inspect.getargvalues(
self.f)) if self.f is not None else None
def getLocals(self):
return self.f.f_locals if self.f != None else {}
def getArgumentInfo(self):
return ArgsFancy(self.f,inspect.getargvalues(self.f)) if self.f != None else None
class TracerClass: class TracerClass:
def callEvent(self,frame):
pass
def lineEvent(self,frame): def callEvent(self, frame):
pass pass
def returnEvent(self,frame,retval): def lineEvent(self, frame):
pass pass
def exceptionEvent(self,frame,exception,value,traceback): def returnEvent(self, frame, retval):
pass pass
def cCallEvent(self,frame,cfunct): def exceptionEvent(self, frame, exception, value, traceback):
pass pass
def cReturnEvent(self,frame,cfunct): def cCallEvent(self, frame, cfunct):
pass pass
def cExceptionEvent(self,frame,cfunct): def cReturnEvent(self, frame, cfunct):
pass pass
def cExceptionEvent(self, frame, cfunct):
pass
tracer_impl = TracerClass() tracer_impl = TracerClass()
def the_tracer_entrypoint(frame,event,args): def the_tracer_entrypoint(frame, event, args):
if tracer_impl == None: if tracer_impl is None:
return None return None
if event == "call": if event == "call":
call_retval = tracer_impl.callEvent(FrameFancy(frame)) call_retval = tracer_impl.callEvent(FrameFancy(frame))
if call_retval == False: if not call_retval:
return None return None
return the_tracer_entrypoint return the_tracer_entrypoint
elif event == "line": elif event == "line":
line_retval = tracer_impl.lineEvent(FrameFancy(frame)) line_retval = tracer_impl.lineEvent(FrameFancy(frame))
if line_retval == False: if not line_retval:
return None return None
return the_tracer_entrypoint return the_tracer_entrypoint
elif event == "return": elif event == "return":
tracer_impl.returnEvent(FrameFancy(frame),args) tracer_impl.returnEvent(FrameFancy(frame), args)
elif event == "exception": elif event == "exception":
exty,exva,extb = args exty, exva, extb = args
exception_retval = tracer_impl.exceptionEvent(FrameFancy(frame),ExceptionFancy(extb,exty,exva)) exception_retval = tracer_impl.exceptionEvent(
if exception_retval == False: FrameFancy(frame), ExceptionFancy(extb, exty, exva))
return None if not exception_retval:
return the_tracer_entrypoint return None
elif event == "c_call": return the_tracer_entrypoint
tracer_impl.cCallEvent(FrameFancy(frame),args) elif event == "c_call":
elif event == "c_return": tracer_impl.cCallEvent(FrameFancy(frame), args)
tracer_impl.cReturnEvent(FrameFancy(frame),args) elif event == "c_return":
elif event == "c_exception": tracer_impl.cReturnEvent(FrameFancy(frame), args)
tracer_impl.cExceptionEvent(FrameFancy(frame),args) elif event == "c_exception":
return None tracer_impl.cExceptionEvent(FrameFancy(frame), args)
return None
def enable(t=None): def enable(t=None):
global tracer_impl global tracer_impl
if t: if t:
tracer_impl = t tracer_impl = t
sys.settrace(the_tracer_entrypoint) sys.settrace(the_tracer_entrypoint)
def disable(): def disable():
sys.settrace(None) sys.settrace(None)
class LoggingTracer: class LoggingTracer:
def callEvent(self,frame):
print "call " + frame.getName() + " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo())
def lineEvent(self,frame): def callEvent(self, frame):
print "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + " locals are " + str(frame.getLocals()) + " in " + frame.getFileName() print "call " + frame.getName() + " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo())
def returnEvent(self,frame,retval): def lineEvent(self, frame):
print "return from " + frame.getName() + " value is " + str(retval) + " locals are " + str(frame.getLocals()) print "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + " locals are " + str(frame.getLocals()) + " in " + frame.getFileName()
def returnEvent(self, frame, retval):
print "return from " + frame.getName() + " value is " + str(retval) + " locals are " + str(frame.getLocals())
def exceptionEvent(self, frame, exception):
print "exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber())
print "tb: " + str(exception.getTraceback())
# the same functionality as LoggingTracer, but with a little more
# lldb-specific smarts
def exceptionEvent(self,frame,exception):
print "exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber())
print "tb: " + str(exception.getTraceback())
# the same functionality as LoggingTracer, but with a little more lldb-specific smarts
class LLDBAwareTracer: class LLDBAwareTracer:
def callEvent(self,frame):
if frame.getName() == "<module>":
return
if frame.getName() == "run_one_line":
print "call run_one_line(%s)" % (frame.getArgumentInfo().getArgs()["input_string"])
return
if "Python.framework" in frame.getFileName():
print "call into Python at " + frame.getName()
return
if frame.getName() == "__init__" and frame.getCaller().getName() == "run_one_line" and frame.getCaller().getLineNumber() == 101:
return False
strout = "call " + frame.getName()
if (frame.getCaller().getFileName() == ""):
strout += " from LLDB - args are "
args = frame.getArgumentInfo().getArgs()
for arg in args:
if arg == "dict" or arg == "internal_dict":
continue
strout = strout + ("%s = %s " % (arg,args[arg]))
else:
strout += " from " + frame.getCaller().getName() + " @ " + str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo())
print strout
def lineEvent(self,frame): def callEvent(self, frame):
if frame.getName() == "<module>": if frame.getName() == "<module>":
return return
if frame.getName() == "run_one_line": if frame.getName() == "run_one_line":
print "running run_one_line(%s) @ %s" % (frame.getArgumentInfo().getArgs()["input_string"],frame.getLineNumber()) print "call run_one_line(%s)" % (frame.getArgumentInfo().getArgs()["input_string"])
return return
if "Python.framework" in frame.getFileName(): if "Python.framework" in frame.getFileName():
print "running into Python at " + frame.getName() + " @ " + str(frame.getLineNumber()) print "call into Python at " + frame.getName()
return return
strout = "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + " locals are " if frame.getName() == "__init__" and frame.getCaller().getName(
if (frame.getCaller().getFileName() == ""): ) == "run_one_line" and frame.getCaller().getLineNumber() == 101:
locals = frame.getLocals() return False
for local in locals: strout = "call " + frame.getName()
if local == "dict" or local == "internal_dict": if (frame.getCaller().getFileName() == ""):
continue strout += " from LLDB - args are "
strout = strout + ("%s = %s " % (local,locals[local])) args = frame.getArgumentInfo().getArgs()
else: for arg in args:
strout = strout + str(frame.getLocals()) if arg == "dict" or arg == "internal_dict":
strout = strout + " in " + frame.getFileName() continue
print strout strout = strout + ("%s = %s " % (arg, args[arg]))
else:
strout += " from " + frame.getCaller().getName() + " @ " + \
str(frame.getCaller().getLineNumber()) + " args are " + str(frame.getArgumentInfo())
print strout
def returnEvent(self,frame,retval): def lineEvent(self, frame):
if frame.getName() == "<module>": if frame.getName() == "<module>":
return return
if frame.getName() == "run_one_line": if frame.getName() == "run_one_line":
print "return from run_one_line(%s) return value is %s" % (frame.getArgumentInfo().getArgs()["input_string"],retval) print "running run_one_line(%s) @ %s" % (frame.getArgumentInfo().getArgs()["input_string"], frame.getLineNumber())
return return
if "Python.framework" in frame.getFileName(): if "Python.framework" in frame.getFileName():
print "return from Python at " + frame.getName() + " return value is " + str(retval) print "running into Python at " + frame.getName() + " @ " + str(frame.getLineNumber())
return return
strout = "return from " + frame.getName() + " return value is " + str(retval) + " locals are " strout = "running " + frame.getName() + " @ " + str(frame.getLineNumber()) + \
if (frame.getCaller().getFileName() == ""): " locals are "
locals = frame.getLocals() if (frame.getCaller().getFileName() == ""):
for local in locals: locals = frame.getLocals()
if local == "dict" or local == "internal_dict": for local in locals:
continue if local == "dict" or local == "internal_dict":
strout = strout + ("%s = %s " % (local,locals[local])) continue
else: strout = strout + ("%s = %s " % (local, locals[local]))
strout = strout + str(frame.getLocals()) else:
strout = strout + " in " + frame.getFileName() strout = strout + str(frame.getLocals())
print strout strout = strout + " in " + frame.getFileName()
print strout
def exceptionEvent(self,frame,exception): def returnEvent(self, frame, retval):
if frame.getName() == "<module>": if frame.getName() == "<module>":
return return
print "exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber()) if frame.getName() == "run_one_line":
print "tb: " + str(exception.getTraceback()) print "return from run_one_line(%s) return value is %s" % (frame.getArgumentInfo().getArgs()["input_string"], retval)
return
if "Python.framework" in frame.getFileName():
print "return from Python at " + frame.getName() + " return value is " + str(retval)
return
strout = "return from " + frame.getName() + " return value is " + \
str(retval) + " locals are "
if (frame.getCaller().getFileName() == ""):
locals = frame.getLocals()
for local in locals:
if local == "dict" or local == "internal_dict":
continue
strout = strout + ("%s = %s " % (local, locals[local]))
else:
strout = strout + str(frame.getLocals())
strout = strout + " in " + frame.getFileName()
print strout
def exceptionEvent(self, frame, exception):
if frame.getName() == "<module>":
return
print "exception %s %s raised from %s @ %s" % (exception.getType(), str(exception.getValue()), frame.getName(), frame.getLineNumber())
print "tb: " + str(exception.getTraceback())
def f(x, y=None):
if x > 0:
return 2 + f(x - 2)
return 35
def f(x,y=None):
if x > 0:
return 2 + f(x-2)
return 35
def g(x): def g(x):
return 1.134 / x return 1.134 / x
def print_keyword_args(**kwargs): def print_keyword_args(**kwargs):
# kwargs is a dict of the keyword args passed to the function # kwargs is a dict of the keyword args passed to the function
for key, value in kwargs.iteritems(): for key, value in kwargs.iteritems():
print "%s = %s" % (key, value) print "%s = %s" % (key, value)
def total(initial=5, *numbers, **keywords): def total(initial=5, *numbers, **keywords):
count = initial count = initial
@ -316,13 +348,13 @@ def total(initial=5, *numbers, **keywords):
return count return count
if __name__ == "__main__": if __name__ == "__main__":
enable(LoggingTracer()) enable(LoggingTracer())
f(5) f(5)
f(5,1) f(5, 1)
print_keyword_args(first_name="John", last_name="Doe") print_keyword_args(first_name="John", last_name="Doe")
total(10, 1, 2, 3, vegetables=50, fruits=100) total(10, 1, 2, 3, vegetables=50, fruits=100)
try: try:
g(0) g(0)
except: except:
pass pass
disable() disable()

View File

@ -2,6 +2,7 @@
import lldb import lldb
class value(object): class value(object):
'''A class that wraps an lldb.SBValue object and returns an object that '''A class that wraps an lldb.SBValue object and returns an object that
can be used as an object with attribytes:\n can be used as an object with attribytes:\n
@ -24,6 +25,7 @@ class value(object):
argv.num_children - return the number of children this value has argv.num_children - return the number of children this value has
argv.children - return a list of sbvalue objects that represents all of the children of this value argv.children - return a list of sbvalue objects that represents all of the children of this value
''' '''
def __init__(self, sbvalue): def __init__(self, sbvalue):
self.sbvalue = sbvalue self.sbvalue = sbvalue
@ -37,10 +39,12 @@ class value(object):
return self.sbvalue.__str__() return self.sbvalue.__str__()
def __getitem__(self, key): def __getitem__(self, key):
if type(key) is int: if isinstance(key, int):
return value(self.sbvalue.GetChildAtIndex(key, lldb.eNoDynamicValues, True)) return value(
self.sbvalue.GetChildAtIndex(
key, lldb.eNoDynamicValues, True))
raise TypeError raise TypeError
def __getattr__(self, name): def __getattr__(self, name):
if name == 'name': if name == 'name':
return self.sbvalue.GetName() return self.sbvalue.GetName()
@ -55,15 +59,15 @@ class value(object):
if name == 'is_pointer': if name == 'is_pointer':
return self.sbvalue.TypeIsPointerType() return self.sbvalue.TypeIsPointerType()
if name == 'format': if name == 'format':
return self.sbvalue.GetFormat () return self.sbvalue.GetFormat()
if name == 'value': if name == 'value':
return self.sbvalue.GetValue () return self.sbvalue.GetValue()
if name == 'summary': if name == 'summary':
return self.sbvalue.GetSummary () return self.sbvalue.GetSummary()
if name == 'description': if name == 'description':
return self.sbvalue.GetObjectDescription () return self.sbvalue.GetObjectDescription()
if name == 'location': if name == 'location':
return self.sbvalue.GetLocation () return self.sbvalue.GetLocation()
if name == 'target': if name == 'target':
return self.sbvalue.GetTarget() return self.sbvalue.GetTarget()
if name == 'process': if name == 'process':
@ -75,18 +79,25 @@ class value(object):
if name == 'num_children': if name == 'num_children':
return self.sbvalue.GetNumChildren() return self.sbvalue.GetNumChildren()
if name == 'children': if name == 'children':
# Returns an array of sbvalue objects, one for each child of # Returns an array of sbvalue objects, one for each child of
# the value for the lldb.SBValue # the value for the lldb.SBValue
children = [] children = []
for i in range (self.sbvalue.GetNumChildren()): for i in range(self.sbvalue.GetNumChildren()):
children.append(value(self.sbvalue.GetChildAtIndex(i, lldb.eNoDynamicValues, True))) children.append(
value(
self.sbvalue.GetChildAtIndex(
i,
lldb.eNoDynamicValues,
True)))
return children return children
raise AttributeError raise AttributeError
class variable(object): class variable(object):
'''A class that treats a lldb.SBValue and allows it to be used just as '''A class that treats a lldb.SBValue and allows it to be used just as
a variable would be in code. So if you have a Point structure variable a variable would be in code. So if you have a Point structure variable
in your code, you would be able to do: "pt.x + pt.y"''' in your code, you would be able to do: "pt.x + pt.y"'''
def __init__(self, sbvalue): def __init__(self, sbvalue):
self.sbvalue = sbvalue self.sbvalue = sbvalue
@ -101,155 +112,157 @@ class variable(object):
def __getitem__(self, key): def __getitem__(self, key):
# Allow array access if this value has children... # Allow array access if this value has children...
if type(key) is int: if isinstance(key, int):
return variable(self.sbvalue.GetValueForExpressionPath("[%i]" % key)) return variable(
self.sbvalue.GetValueForExpressionPath(
"[%i]" %
key))
raise TypeError raise TypeError
def __getattr__(self, name): def __getattr__(self, name):
child_sbvalue = self.sbvalue.GetChildMemberWithName (name) child_sbvalue = self.sbvalue.GetChildMemberWithName(name)
if child_sbvalue: if child_sbvalue:
return variable(child_sbvalue) return variable(child_sbvalue)
raise AttributeError raise AttributeError
def __add__(self, other): def __add__(self, other):
return int(self) + int(other) return int(self) + int(other)
def __sub__(self, other): def __sub__(self, other):
return int(self) - int(other) return int(self) - int(other)
def __mul__(self, other): def __mul__(self, other):
return int(self) * int(other) return int(self) * int(other)
def __floordiv__(self, other): def __floordiv__(self, other):
return int(self) // int(other) return int(self) // int(other)
def __mod__(self, other): def __mod__(self, other):
return int(self) % int(other) return int(self) % int(other)
def __divmod__(self, other): def __divmod__(self, other):
return int(self) % int(other) return int(self) % int(other)
def __pow__(self, other): def __pow__(self, other):
return int(self) ** int(other) return int(self) ** int(other)
def __lshift__(self, other): def __lshift__(self, other):
return int(self) << int(other) return int(self) << int(other)
def __rshift__(self, other): def __rshift__(self, other):
return int(self) >> int(other) return int(self) >> int(other)
def __and__(self, other): def __and__(self, other):
return int(self) & int(other) return int(self) & int(other)
def __xor__(self, other): def __xor__(self, other):
return int(self) ^ int(other) return int(self) ^ int(other)
def __or__(self, other): def __or__(self, other):
return int(self) | int(other) return int(self) | int(other)
def __div__(self, other): def __div__(self, other):
return int(self) / int(other) return int(self) / int(other)
def __truediv__(self, other): def __truediv__(self, other):
return int(self) / int(other) return int(self) / int(other)
def __iadd__(self, other): def __iadd__(self, other):
result = self.__add__(other) result = self.__add__(other)
self.sbvalue.SetValueFromCString (str(result)) self.sbvalue.SetValueFromCString(str(result))
return result return result
def __isub__(self, other): def __isub__(self, other):
result = self.__sub__(other) result = self.__sub__(other)
self.sbvalue.SetValueFromCString (str(result)) self.sbvalue.SetValueFromCString(str(result))
return result return result
def __imul__(self, other): def __imul__(self, other):
result = self.__mul__(other) result = self.__mul__(other)
self.sbvalue.SetValueFromCString (str(result)) self.sbvalue.SetValueFromCString(str(result))
return result return result
def __idiv__(self, other): def __idiv__(self, other):
result = self.__div__(other) result = self.__div__(other)
self.sbvalue.SetValueFromCString (str(result)) self.sbvalue.SetValueFromCString(str(result))
return result return result
def __itruediv__(self, other): def __itruediv__(self, other):
result = self.__truediv__(other) result = self.__truediv__(other)
self.sbvalue.SetValueFromCString (str(result)) self.sbvalue.SetValueFromCString(str(result))
return result return result
def __ifloordiv__(self, other): def __ifloordiv__(self, other):
result = self.__floordiv__(self, other) result = self.__floordiv__(self, other)
self.sbvalue.SetValueFromCString (str(result)) self.sbvalue.SetValueFromCString(str(result))
return result return result
def __imod__(self, other): def __imod__(self, other):
result = self.__and__(self, other) result = self.__and__(self, other)
self.sbvalue.SetValueFromCString (str(result)) self.sbvalue.SetValueFromCString(str(result))
return result return result
def __ipow__(self, other): def __ipow__(self, other):
result = self.__pow__(self, other) result = self.__pow__(self, other)
self.sbvalue.SetValueFromCString (str(result)) self.sbvalue.SetValueFromCString(str(result))
return result return result
def __ipow__(self, other, modulo): def __ipow__(self, other, modulo):
result = self.__pow__(self, other, modulo) result = self.__pow__(self, other, modulo)
self.sbvalue.SetValueFromCString (str(result)) self.sbvalue.SetValueFromCString(str(result))
return result return result
def __ilshift__(self, other): def __ilshift__(self, other):
result = self.__lshift__(self, other) result = self.__lshift__(self, other)
self.sbvalue.SetValueFromCString (str(result)) self.sbvalue.SetValueFromCString(str(result))
return result return result
def __irshift__(self, other): def __irshift__(self, other):
result = self.__rshift__(self, other) result = self.__rshift__(self, other)
self.sbvalue.SetValueFromCString (str(result)) self.sbvalue.SetValueFromCString(str(result))
return result return result
def __iand__(self, other): def __iand__(self, other):
result = self.__and__(self, other) result = self.__and__(self, other)
self.sbvalue.SetValueFromCString (str(result)) self.sbvalue.SetValueFromCString(str(result))
return result return result
def __ixor__(self, other): def __ixor__(self, other):
result = self.__xor__(self, other) result = self.__xor__(self, other)
self.sbvalue.SetValueFromCString (str(result)) self.sbvalue.SetValueFromCString(str(result))
return result return result
def __ior__(self, other): def __ior__(self, other):
result = self.__ior__(self, other) result = self.__ior__(self, other)
self.sbvalue.SetValueFromCString (str(result)) self.sbvalue.SetValueFromCString(str(result))
return result return result
def __neg__(self): def __neg__(self):
return -int(self) return -int(self)
def __pos__(self): def __pos__(self):
return +int(self) return +int(self)
def __abs__(self): def __abs__(self):
return abs(int(self)) return abs(int(self))
def __invert__(self): def __invert__(self):
return ~int(self) return ~int(self)
def __complex__(self): def __complex__(self):
return complex (int(self)) return complex(int(self))
def __int__(self): def __int__(self):
return self.sbvalue.GetValueAsSigned() return self.sbvalue.GetValueAsSigned()
def __long__(self): def __long__(self):
return self.sbvalue.GetValueAsSigned() return self.sbvalue.GetValueAsSigned()
def __float__(self): def __float__(self):
return float (self.sbvalue.GetValueAsSigned()) return float(self.sbvalue.GetValueAsSigned())
def __oct__(self): def __oct__(self):
return '0%o' % self.sbvalue.GetValueAsSigned() return '0%o' % self.sbvalue.GetValueAsSigned()
def __hex__(self): def __hex__(self):
return '0x%x' % self.sbvalue.GetValueAsSigned() return '0x%x' % self.sbvalue.GetValueAsSigned()

View File

@ -5,15 +5,15 @@
# interface is a reduced version of the full internal mechanism, but captures # interface is a reduced version of the full internal mechanism, but captures
# most of the power with a much simpler interface. # most of the power with a much simpler interface.
# #
# But I'll attempt a brief summary here. # But I'll attempt a brief summary here.
# Stepping in lldb is done independently for each thread. Moreover, the stepping # Stepping in lldb is done independently for each thread. Moreover, the stepping
# operations are stackable. So for instance if you did a "step over", and in # operations are stackable. So for instance if you did a "step over", and in
# the course of stepping over you hit a breakpoint, stopped and stepped again, # the course of stepping over you hit a breakpoint, stopped and stepped again,
# the first "step-over" would be suspended, and the new step operation would # the first "step-over" would be suspended, and the new step operation would
# be enqueued. Then if that step over caused the program to hit another breakpoint, # be enqueued. Then if that step over caused the program to hit another breakpoint,
# lldb would again suspend the second step and return control to the user, so # lldb would again suspend the second step and return control to the user, so
# now there are two pending step overs. Etc. with all the other stepping # now there are two pending step overs. Etc. with all the other stepping
# operations. Then if you hit "continue" the bottom-most step-over would complete, # operations. Then if you hit "continue" the bottom-most step-over would complete,
# and another continue would complete the first "step-over". # and another continue would complete the first "step-over".
# #
# lldb represents this system with a stack of "Thread Plans". Each time a new # lldb represents this system with a stack of "Thread Plans". Each time a new
@ -26,16 +26,16 @@
# the current thread. In the scripted interface, you indicate this by returning # the current thread. In the scripted interface, you indicate this by returning
# False or True respectively from the should_step method. # False or True respectively from the should_step method.
# #
# Each time the process stops the thread plan stack for each thread that stopped # Each time the process stops the thread plan stack for each thread that stopped
# "for a reason", Ii.e. a single-step completed on that thread, or a breakpoint # "for a reason", Ii.e. a single-step completed on that thread, or a breakpoint
# was hit), is queried to determine how to proceed, starting from the most # was hit), is queried to determine how to proceed, starting from the most
# recently pushed plan, in two stages: # recently pushed plan, in two stages:
# #
# 1) Each plan is asked if it "explains" the stop. The first plan to claim the # 1) Each plan is asked if it "explains" the stop. The first plan to claim the
# stop wins. In scripted Thread Plans, this is done by returning True from # stop wins. In scripted Thread Plans, this is done by returning True from
# the "explains_stop method. This is how, for instance, control is returned # the "explains_stop method. This is how, for instance, control is returned
# to the User when the "step-over" plan hits a breakpoint. The step-over # to the User when the "step-over" plan hits a breakpoint. The step-over
# plan doesn't explain the breakpoint stop, so it returns false, and the # plan doesn't explain the breakpoint stop, so it returns false, and the
# breakpoint hit is propagated up the stack to the "base" thread plan, which # breakpoint hit is propagated up the stack to the "base" thread plan, which
# is the one that handles random breakpoint hits. # is the one that handles random breakpoint hits.
# #
@ -50,10 +50,10 @@
# the next time the thread continues. # the next time the thread continues.
# #
# Note that deciding to return control to the user, and deciding your plan # Note that deciding to return control to the user, and deciding your plan
# is done, are orthgonal operations. You could set up the next phase of # is done, are orthgonal operations. You could set up the next phase of
# stepping, and then return True from should_stop, and when the user next # stepping, and then return True from should_stop, and when the user next
# "continued" the process your plan would resume control. Of course, the # "continued" the process your plan would resume control. Of course, the
# user might also "step-over" or some other operation that would push a # user might also "step-over" or some other operation that would push a
# different plan, which would take control till it was done. # different plan, which would take control till it was done.
# #
# One other detail you should be aware of, if the plan below you on the # One other detail you should be aware of, if the plan below you on the
@ -71,8 +71,8 @@
# This is useful, for instance, in the FinishPrintAndContinue plan. What might # This is useful, for instance, in the FinishPrintAndContinue plan. What might
# happen here is that after continuing but before the finish is done, the program # happen here is that after continuing but before the finish is done, the program
# could hit another breakpoint and stop. Then the user could use the step # could hit another breakpoint and stop. Then the user could use the step
# command repeatedly until they leave the frame of interest by stepping. # command repeatedly until they leave the frame of interest by stepping.
# In that case, the step plan is the one that will be responsible for stopping, # In that case, the step plan is the one that will be responsible for stopping,
# and the finish plan won't be asked should_stop, it will just be asked if it # and the finish plan won't be asked should_stop, it will just be asked if it
# is stale. In this case, if the step_out plan that the FinishPrintAndContinue # is stale. In this case, if the step_out plan that the FinishPrintAndContinue
# plan is driving is stale, so is ours, and it is time to do our printing. # plan is driving is stale, so is ours, and it is time to do our printing.
@ -80,7 +80,7 @@
# Both examples show stepping through an address range for 20 bytes from the # Both examples show stepping through an address range for 20 bytes from the
# current PC. The first one does it by single stepping and checking a condition. # current PC. The first one does it by single stepping and checking a condition.
# It doesn't, however handle the case where you step into another frame while # It doesn't, however handle the case where you step into another frame while
# still in the current range in the starting frame. # still in the current range in the starting frame.
# #
# That is better handled in the second example by using the built-in StepOverRange # That is better handled in the second example by using the built-in StepOverRange
# thread plan. # thread plan.
@ -95,76 +95,84 @@
import lldb import lldb
class SimpleStep: class SimpleStep:
def __init__ (self, thread_plan, dict):
def __init__(self, thread_plan, dict):
self.thread_plan = thread_plan self.thread_plan = thread_plan
self.start_address = thread_plan.GetThread().GetFrameAtIndex(0).GetPC() self.start_address = thread_plan.GetThread().GetFrameAtIndex(0).GetPC()
def explains_stop (self, event): def explains_stop(self, event):
# We are stepping, so if we stop for any other reason, it isn't # We are stepping, so if we stop for any other reason, it isn't
# because of us. # because of us.
if self.thread_plan.GetThread().GetStopReason()== lldb.eStopReasonTrace: if self.thread_plan.GetThread().GetStopReason() == lldb.eStopReasonTrace:
return True return True
else: else:
return False return False
def should_stop (self, event): def should_stop(self, event):
cur_pc = self.thread_plan.GetThread().GetFrameAtIndex(0).GetPC() cur_pc = self.thread_plan.GetThread().GetFrameAtIndex(0).GetPC()
if cur_pc < self.start_address or cur_pc >= self.start_address + 20: if cur_pc < self.start_address or cur_pc >= self.start_address + 20:
self.thread_plan.SetPlanComplete(True) self.thread_plan.SetPlanComplete(True)
return True return True
else: else:
return False return False
def should_step (self): def should_step(self):
return True return True
class StepWithPlan: class StepWithPlan:
def __init__ (self, thread_plan, dict):
def __init__(self, thread_plan, dict):
self.thread_plan = thread_plan self.thread_plan = thread_plan
self.start_address = thread_plan.GetThread().GetFrameAtIndex(0).GetPCAddress() self.start_address = thread_plan.GetThread().GetFrameAtIndex(0).GetPCAddress()
self.step_thread_plan =thread_plan.QueueThreadPlanForStepOverRange(self.start_address, 20); self.step_thread_plan = thread_plan.QueueThreadPlanForStepOverRange(
self.start_address, 20)
def explains_stop (self, event): def explains_stop(self, event):
# Since all I'm doing is running a plan, I will only ever get askedthis # Since all I'm doing is running a plan, I will only ever get askedthis
# if myplan doesn't explain the stop, and in that caseI don'teither. # if myplan doesn't explain the stop, and in that caseI don'teither.
return False return False
def should_stop (self, event): def should_stop(self, event):
if self.step_thread_plan.IsPlanComplete(): if self.step_thread_plan.IsPlanComplete():
self.thread_plan.SetPlanComplete(True) self.thread_plan.SetPlanComplete(True)
return True return True
else: else:
return False return False
def should_step (self): def should_step(self):
return False return False
# Here's another example which does "step over" through the current function, # Here's another example which does "step over" through the current function,
# and when it stops at each line, it checks some condition (in this example the # and when it stops at each line, it checks some condition (in this example the
# value of a variable) and stops if that condition is true. # value of a variable) and stops if that condition is true.
class StepCheckingCondition: class StepCheckingCondition:
def __init__ (self, thread_plan, dict):
def __init__(self, thread_plan, dict):
self.thread_plan = thread_plan self.thread_plan = thread_plan
self.start_frame = thread_plan.GetThread().GetFrameAtIndex(0) self.start_frame = thread_plan.GetThread().GetFrameAtIndex(0)
self.queue_next_plan() self.queue_next_plan()
def queue_next_plan (self): def queue_next_plan(self):
cur_frame = self.thread_plan.GetThread().GetFrameAtIndex(0) cur_frame = self.thread_plan.GetThread().GetFrameAtIndex(0)
cur_line_entry = cur_frame.GetLineEntry() cur_line_entry = cur_frame.GetLineEntry()
start_address = cur_line_entry.GetStartAddress() start_address = cur_line_entry.GetStartAddress()
end_address = cur_line_entry.GetEndAddress() end_address = cur_line_entry.GetEndAddress()
line_range = end_address.GetFileAddress() - start_address.GetFileAddress() line_range = end_address.GetFileAddress() - start_address.GetFileAddress()
self.step_thread_plan = self.thread_plan.QueueThreadPlanForStepOverRange(start_address, line_range) self.step_thread_plan = self.thread_plan.QueueThreadPlanForStepOverRange(
start_address, line_range)
def explains_stop (self, event): def explains_stop(self, event):
# We are stepping, so if we stop for any other reason, it isn't # We are stepping, so if we stop for any other reason, it isn't
# because of us. # because of us.
return False return False
def should_stop (self, event): def should_stop(self, event):
if not self.step_thread_plan.IsPlanComplete(): if not self.step_thread_plan.IsPlanComplete():
return False return False
@ -182,7 +190,7 @@ class StepCheckingCondition:
return True return True
error = lldb.SBError() error = lldb.SBError()
a_value = a_var.GetValueAsSigned (error) a_value = a_var.GetValueAsSigned(error)
if not error.Success(): if not error.Success():
print "A value was not good." print "A value was not good."
return True return True
@ -194,7 +202,7 @@ class StepCheckingCondition:
self.queue_next_plan() self.queue_next_plan()
return False return False
def should_step (self): def should_step(self):
return True return True
# Here's an example that steps out of the current frame, gathers some information # Here's an example that steps out of the current frame, gathers some information
@ -202,29 +210,32 @@ class StepCheckingCondition:
# plans are not a safe place to call lldb command-line commands, so the information # plans are not a safe place to call lldb command-line commands, so the information
# is gathered through SB API calls. # is gathered through SB API calls.
class FinishPrintAndContinue: class FinishPrintAndContinue:
def __init__ (self, thread_plan, dict):
def __init__(self, thread_plan, dict):
self.thread_plan = thread_plan self.thread_plan = thread_plan
self.step_out_thread_plan = thread_plan.QueueThreadPlanForStepOut(0, True) self.step_out_thread_plan = thread_plan.QueueThreadPlanForStepOut(
0, True)
self.thread = self.thread_plan.GetThread() self.thread = self.thread_plan.GetThread()
def is_stale (self): def is_stale(self):
if self.step_out_thread_plan.IsPlanStale(): if self.step_out_thread_plan.IsPlanStale():
self.do_print() self.do_print()
return True return True
else: else:
return False return False
def explains_stop (self, event): def explains_stop(self, event):
return False return False
def should_stop (self, event): def should_stop(self, event):
if self.step_out_thread_plan.IsPlanComplete(): if self.step_out_thread_plan.IsPlanComplete():
self.do_print() self.do_print()
self.thread_plan.SetPlanComplete(True) self.thread_plan.SetPlanComplete(True)
return False return False
def do_print (self): def do_print(self):
frame_0 = self.thread.frames[0] frame_0 = self.thread.frames[0]
rax_value = frame_0.FindRegister("rax") rax_value = frame_0.FindRegister("rax")
if rax_value.GetError().Success(): if rax_value.GetError().Success():

View File

@ -3,14 +3,16 @@
import lldb import lldb
import shlex import shlex
@lldb.command("shadow") @lldb.command("shadow")
def check_shadow_command(debugger, command, exe_ctx, result, dict): def check_shadow_command(debugger, command, exe_ctx, result, dict):
'''Check the currently selected stack frame for shadowed variables''' '''Check the currently selected stack frame for shadowed variables'''
process = exe_ctx.GetProcess() process = exe_ctx.GetProcess()
state = process.GetState() state = process.GetState()
if state != lldb.eStateStopped: if state != lldb.eStateStopped:
print >>result, "process must be stopped, state is %s" % lldb.SBDebugger.StateAsCString(state) print >>result, "process must be stopped, state is %s" % lldb.SBDebugger.StateAsCString(
return state)
return
frame = exe_ctx.GetFrame() frame = exe_ctx.GetFrame()
if not frame: if not frame:
print >>result, "invalid frame" print >>result, "invalid frame"
@ -18,10 +20,10 @@ def check_shadow_command(debugger, command, exe_ctx, result, dict):
# Parse command line args # Parse command line args
command_args = shlex.split(command) command_args = shlex.split(command)
# TODO: add support for using arguments that are passed to this command... # TODO: add support for using arguments that are passed to this command...
# Make a dictionary of variable name to "SBBlock and SBValue" # Make a dictionary of variable name to "SBBlock and SBValue"
shadow_dict = {} shadow_dict = {}
num_shadowed_variables = 0 num_shadowed_variables = 0
# Get the deepest most block from the current frame # Get the deepest most block from the current frame
block = frame.GetBlock() block = frame.GetBlock()
@ -40,7 +42,7 @@ def check_shadow_command(debugger, command, exe_ctx, result, dict):
shadow_dict[block_var_name].append(block_var) shadow_dict[block_var_name].append(block_var)
else: else:
shadow_dict[block_var_name] = [block_var] shadow_dict[block_var_name] = [block_var]
# Get the parent block and continue # Get the parent block and continue
block = block.GetParent() block = block.GetParent()
num_shadowed_variables = 0 num_shadowed_variables = 0
@ -54,4 +56,3 @@ def check_shadow_command(debugger, command, exe_ctx, result, dict):
print >>result, str(shadow_var.GetDeclaration()) print >>result, str(shadow_var.GetDeclaration())
if num_shadowed_variables == 0: if num_shadowed_variables == 0:
print >>result, 'no variables are shadowed' print >>result, 'no variables are shadowed'

View File

@ -3,15 +3,17 @@
import lldb import lldb
import shlex import shlex
def dump_module_sources(module, result): def dump_module_sources(module, result):
if module: if module:
print >> result, "Module: %s" % (module.file) print >> result, "Module: %s" % (module.file)
for compile_unit in module.compile_units: for compile_unit in module.compile_units:
if compile_unit.file: if compile_unit.file:
print >> result, " %s" % (compile_unit.file) print >> result, " %s" % (compile_unit.file)
def info_sources(debugger, command, result, dict): def info_sources(debugger, command, result, dict):
description='''This command will dump all compile units in any modules that are listed as arguments, or for all modules if no arguments are supplied.''' description = '''This command will dump all compile units in any modules that are listed as arguments, or for all modules if no arguments are supplied.'''
module_names = shlex.split(command) module_names = shlex.split(command)
target = debugger.GetSelectedTarget() target = debugger.GetSelectedTarget()
if module_names: if module_names:
@ -20,9 +22,10 @@ def info_sources(debugger, command, result, dict):
else: else:
for module in target.modules: for module in target.modules:
dump_module_sources(module, result) dump_module_sources(module, result)
def __lldb_init_module (debugger, dict): def __lldb_init_module(debugger, dict):
# Add any commands contained in this module to LLDB # Add any commands contained in this module to LLDB
debugger.HandleCommand('command script add -f sources.info_sources info_sources') debugger.HandleCommand(
'command script add -f sources.info_sources info_sources')
print 'The "info_sources" command has been installed, type "help info_sources" or "info_sources --help" for detailed help.' print 'The "info_sources" command has been installed, type "help info_sources" or "info_sources --help" for detailed help.'

View File

@ -5,20 +5,28 @@ import commands
import optparse import optparse
import shlex import shlex
def stack_frames(debugger, command, result, dict): def stack_frames(debugger, command, result, dict):
command_args = shlex.split(command) command_args = shlex.split(command)
usage = "usage: %prog [options] <PATH> [PATH ...]" usage = "usage: %prog [options] <PATH> [PATH ...]"
description='''This command will enumerate all stack frames, print the stack size for each, and print an aggregation of which functions have the largest stack frame sizes at the end.''' description = '''This command will enumerate all stack frames, print the stack size for each, and print an aggregation of which functions have the largest stack frame sizes at the end.'''
parser = optparse.OptionParser(description=description, prog='ls',usage=usage) parser = optparse.OptionParser(
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False) description=description, prog='ls', usage=usage)
parser.add_option(
'-v',
'--verbose',
action='store_true',
dest='verbose',
help='display verbose debug info',
default=False)
try: try:
(options, args) = parser.parse_args(command_args) (options, args) = parser.parse_args(command_args)
except: except:
return return
target = debugger.GetSelectedTarget() target = debugger.GetSelectedTarget()
process = target.GetProcess() process = target.GetProcess()
frame_info = {} frame_info = {}
for thread in process: for thread in process:
last_frame = None last_frame = None
@ -28,12 +36,13 @@ def stack_frames(debugger, command, result, dict):
frame_size = 0 frame_size = 0
if frame.idx == 1: if frame.idx == 1:
if frame.fp == last_frame.fp: if frame.fp == last_frame.fp:
# No frame one the first frame (might be right at the entry point) # No frame one the first frame (might be right at the
# entry point)
first_frame_size = 0 first_frame_size = 0
frame_size = frame.fp - frame.sp frame_size = frame.fp - frame.sp
else: else:
# First frame that has a valid size # First frame that has a valid size
first_frame_size = last_frame.fp - last_frame.sp first_frame_size = last_frame.fp - last_frame.sp
print "<%#7x> %s" % (first_frame_size, last_frame) print "<%#7x> %s" % (first_frame_size, last_frame)
if first_frame_size: if first_frame_size:
name = last_frame.name name = last_frame.name
@ -43,7 +52,7 @@ def stack_frames(debugger, command, result, dict):
frame_info[name] += first_frame_size frame_info[name] += first_frame_size
else: else:
# Second or higher frame # Second or higher frame
frame_size = frame.fp - last_frame.fp frame_size = frame.fp - last_frame.fp
print "<%#7x> %s" % (frame_size, frame) print "<%#7x> %s" % (frame_size, frame)
if frame_size > 0: if frame_size > 0:
name = frame.name name = frame.name
@ -53,7 +62,8 @@ def stack_frames(debugger, command, result, dict):
frame_info[name] += frame_size frame_info[name] += frame_size
last_frame = frame last_frame = frame
print frame_info print frame_info
lldb.debugger.HandleCommand("command script add -f stacks.stack_frames stack_frames")
print "A new command called 'stack_frames' was added, type 'stack_frames --help' for more information." lldb.debugger.HandleCommand(
"command script add -f stacks.stack_frames stack_frames")
print "A new command called 'stack_frames' was added, type 'stack_frames --help' for more information."

View File

@ -11,13 +11,13 @@
# "crashlog" command installed, type "crashlog --help" for detailed help # "crashlog" command installed, type "crashlog --help" for detailed help
# (lldb) crashlog ~/Library/Logs/DiagnosticReports/a.crash # (lldb) crashlog ~/Library/Logs/DiagnosticReports/a.crash
# #
# The benefit of running the crashlog command inside lldb in the # The benefit of running the crashlog command inside lldb in the
# embedded python interpreter is when the command completes, there # embedded python interpreter is when the command completes, there
# will be a target with all of the files loaded at the locations # will be a target with all of the files loaded at the locations
# described in the crash log. Only the files that have stack frames # described in the crash log. Only the files that have stack frames
# in the backtrace will be loaded unless the "--load-all" option # in the backtrace will be loaded unless the "--load-all" option
# has been specified. This allows users to explore the program in the # has been specified. This allows users to explore the program in the
# state it was in right at crash time. # state it was in right at crash time.
# #
# On MacOSX csh, tcsh: # On MacOSX csh, tcsh:
# ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash ) # ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash )
@ -37,16 +37,23 @@ import sys
import time import time
import uuid import uuid
class Address: class Address:
"""Class that represents an address that will be symbolicated""" """Class that represents an address that will be symbolicated"""
def __init__(self, target, load_addr): def __init__(self, target, load_addr):
self.target = target self.target = target
self.load_addr = load_addr # The load address that this object represents self.load_addr = load_addr # The load address that this object represents
self.so_addr = None # the resolved lldb.SBAddress (if any), named so_addr for section/offset address # the resolved lldb.SBAddress (if any), named so_addr for
self.sym_ctx = None # The cached symbol context for this address # section/offset address
self.description = None # Any original textual description of this address to be used as a backup in case symbolication fails self.so_addr = None
self.symbolication = None # The cached symbolicated string that describes this address self.sym_ctx = None # The cached symbol context for this address
# Any original textual description of this address to be used as a
# backup in case symbolication fails
self.description = None
self.symbolication = None # The cached symbolicated string that describes this address
self.inlined = False self.inlined = False
def __str__(self): def __str__(self):
s = "%#16.16x" % (self.load_addr) s = "%#16.16x" % (self.load_addr)
if self.symbolication: if self.symbolication:
@ -58,18 +65,19 @@ class Address:
return s return s
def resolve_addr(self): def resolve_addr(self):
if self.so_addr == None: if self.so_addr is None:
self.so_addr = self.target.ResolveLoadAddress (self.load_addr) self.so_addr = self.target.ResolveLoadAddress(self.load_addr)
return self.so_addr return self.so_addr
def is_inlined(self): def is_inlined(self):
return self.inlined return self.inlined
def get_symbol_context(self): def get_symbol_context(self):
if self.sym_ctx == None: if self.sym_ctx is None:
sb_addr = self.resolve_addr() sb_addr = self.resolve_addr()
if sb_addr: if sb_addr:
self.sym_ctx = self.target.ResolveSymbolContextForAddress (sb_addr, lldb.eSymbolContextEverything) self.sym_ctx = self.target.ResolveSymbolContextForAddress(
sb_addr, lldb.eSymbolContextEverything)
else: else:
self.sym_ctx = lldb.SBSymbolContext() self.sym_ctx = lldb.SBSymbolContext()
return self.sym_ctx return self.sym_ctx
@ -82,9 +90,9 @@ class Address:
return function.GetInstructions(self.target) return function.GetInstructions(self.target)
return sym_ctx.GetSymbol().GetInstructions(self.target) return sym_ctx.GetSymbol().GetInstructions(self.target)
return None return None
def symbolicate(self, verbose = False): def symbolicate(self, verbose=False):
if self.symbolication == None: if self.symbolication is None:
self.symbolication = '' self.symbolication = ''
self.inlined = False self.inlined = False
sym_ctx = self.get_symbol_context() sym_ctx = self.get_symbol_context()
@ -101,27 +109,32 @@ class Address:
block = sym_ctx.GetBlock() block = sym_ctx.GetBlock()
line_entry = sym_ctx.GetLineEntry() line_entry = sym_ctx.GetLineEntry()
symbol = sym_ctx.GetSymbol() symbol = sym_ctx.GetSymbol()
inlined_block = block.GetContainingInlinedBlock(); inlined_block = block.GetContainingInlinedBlock()
if function: if function:
self.symbolication += function.GetName() self.symbolication += function.GetName()
if inlined_block: if inlined_block:
self.inlined = True self.inlined = True
self.symbolication += ' [inlined] ' + inlined_block.GetInlinedName(); self.symbolication += ' [inlined] ' + \
block_range_idx = inlined_block.GetRangeIndexForBlockAddress (self.so_addr) inlined_block.GetInlinedName()
block_range_idx = inlined_block.GetRangeIndexForBlockAddress(
self.so_addr)
if block_range_idx < lldb.UINT32_MAX: if block_range_idx < lldb.UINT32_MAX:
block_range_start_addr = inlined_block.GetRangeStartAddress (block_range_idx) block_range_start_addr = inlined_block.GetRangeStartAddress(
function_start_load_addr = block_range_start_addr.GetLoadAddress (self.target) block_range_idx)
function_start_load_addr = block_range_start_addr.GetLoadAddress(
self.target)
if function_start_load_addr == -1: if function_start_load_addr == -1:
function_start_load_addr = function.GetStartAddress().GetLoadAddress (self.target) function_start_load_addr = function.GetStartAddress().GetLoadAddress(self.target)
elif symbol: elif symbol:
self.symbolication += symbol.GetName() self.symbolication += symbol.GetName()
function_start_load_addr = symbol.GetStartAddress().GetLoadAddress (self.target) function_start_load_addr = symbol.GetStartAddress().GetLoadAddress(self.target)
else: else:
self.symbolication = '' self.symbolication = ''
return False return False
# Dump the offset from the current function or symbol if it is non zero # Dump the offset from the current function or symbol if it
# is non zero
function_offset = self.load_addr - function_start_load_addr function_offset = self.load_addr - function_start_load_addr
if function_offset > 0: if function_offset > 0:
self.symbolication += " + %u" % (function_offset) self.symbolication += " + %u" % (function_offset)
@ -135,38 +148,44 @@ class Address:
self.symbolication += ' at %s' % line_entry.GetFileSpec() self.symbolication += ' at %s' % line_entry.GetFileSpec()
else: else:
self.symbolication += ' at %s' % line_entry.GetFileSpec().GetFilename() self.symbolication += ' at %s' % line_entry.GetFileSpec().GetFilename()
self.symbolication += ':%u' % line_entry.GetLine () self.symbolication += ':%u' % line_entry.GetLine()
column = line_entry.GetColumn() column = line_entry.GetColumn()
if column > 0: if column > 0:
self.symbolication += ':%u' % column self.symbolication += ':%u' % column
return True return True
return False return False
class Section: class Section:
"""Class that represents an load address range""" """Class that represents an load address range"""
sect_info_regex = re.compile('(?P<name>[^=]+)=(?P<range>.*)') sect_info_regex = re.compile('(?P<name>[^=]+)=(?P<range>.*)')
addr_regex = re.compile('^\s*(?P<start>0x[0-9A-Fa-f]+)\s*$') addr_regex = re.compile('^\s*(?P<start>0x[0-9A-Fa-f]+)\s*$')
range_regex = re.compile('^\s*(?P<start>0x[0-9A-Fa-f]+)\s*(?P<op>[-+])\s*(?P<end>0x[0-9A-Fa-f]+)\s*$') range_regex = re.compile(
'^\s*(?P<start>0x[0-9A-Fa-f]+)\s*(?P<op>[-+])\s*(?P<end>0x[0-9A-Fa-f]+)\s*$')
def __init__(self, start_addr = None, end_addr = None, name = None): def __init__(self, start_addr=None, end_addr=None, name=None):
self.start_addr = start_addr self.start_addr = start_addr
self.end_addr = end_addr self.end_addr = end_addr
self.name = name self.name = name
@classmethod @classmethod
def InitWithSBTargetAndSBSection(cls, target, section): def InitWithSBTargetAndSBSection(cls, target, section):
sect_load_addr = section.GetLoadAddress(target) sect_load_addr = section.GetLoadAddress(target)
if sect_load_addr != lldb.LLDB_INVALID_ADDRESS: if sect_load_addr != lldb.LLDB_INVALID_ADDRESS:
obj = cls(sect_load_addr, sect_load_addr + section.size, section.name) obj = cls(
sect_load_addr,
sect_load_addr +
section.size,
section.name)
return obj return obj
else: else:
return None return None
def contains(self, addr): def contains(self, addr):
return self.start_addr <= addr and addr < self.end_addr; return self.start_addr <= addr and addr < self.end_addr
def set_from_string(self, s): def set_from_string(self, s):
match = self.sect_info_regex.match (s) match = self.sect_info_regex.match(s)
if match: if match:
self.name = match.group('name') self.name = match.group('name')
range_str = match.group('range') range_str = match.group('range')
@ -192,22 +211,24 @@ class Section:
print '<name>=<base>-<end> __TEXT=0x123000-0x124000 Section from base address and end address' print '<name>=<base>-<end> __TEXT=0x123000-0x124000 Section from base address and end address'
print '<name>=<base>+<size> __TEXT=0x123000+0x1000 Section from base address and size' print '<name>=<base>+<size> __TEXT=0x123000+0x1000 Section from base address and size'
return False return False
def __str__(self): def __str__(self):
if self.name: if self.name:
if self.end_addr != None: if self.end_addr is not None:
if self.start_addr != None: if self.start_addr is not None:
return "%s=[0x%16.16x - 0x%16.16x)" % (self.name, self.start_addr, self.end_addr) return "%s=[0x%16.16x - 0x%16.16x)" % (
self.name, self.start_addr, self.end_addr)
else: else:
if self.start_addr != None: if self.start_addr is not None:
return "%s=0x%16.16x" % (self.name, self.start_addr) return "%s=0x%16.16x" % (self.name, self.start_addr)
return self.name return self.name
return "<invalid>" return "<invalid>"
class Image: class Image:
"""A class that represents an executable image and any associated data""" """A class that represents an executable image and any associated data"""
def __init__(self, path, uuid = None): def __init__(self, path, uuid=None):
self.path = path self.path = path
self.resolved_path = None self.resolved_path = None
self.resolved = False self.resolved = False
@ -220,7 +241,7 @@ class Image:
self.module = None self.module = None
self.symfile = None self.symfile = None
self.slide = None self.slide = None
@classmethod @classmethod
def InitWithSBTargetAndSBModule(cls, target, module): def InitWithSBTargetAndSBModule(cls, target, module):
'''Initialize this Image object with a module from a target.''' '''Initialize this Image object with a module from a target.'''
@ -229,15 +250,16 @@ class Image:
obj.resolved = True obj.resolved = True
obj.arch = module.triple obj.arch = module.triple
for section in module.sections: for section in module.sections:
symb_section = Section.InitWithSBTargetAndSBSection(target, section) symb_section = Section.InitWithSBTargetAndSBSection(
target, section)
if symb_section: if symb_section:
obj.section_infos.append (symb_section) obj.section_infos.append(symb_section)
obj.arch = module.triple obj.arch = module.triple
obj.module = module obj.module = module
obj.symfile = None obj.symfile = None
obj.slide = None obj.slide = None
return obj return obj
def dump(self, prefix): def dump(self, prefix):
print "%s%s" % (prefix, self) print "%s%s" % (prefix, self)
@ -254,7 +276,7 @@ class Image:
print 'module = %s' % (self.module) print 'module = %s' % (self.module)
print 'symfile = "%s"' % (self.symfile) print 'symfile = "%s"' % (self.symfile)
print 'slide = %i (0x%x)' % (self.slide, self.slide) print 'slide = %i (0x%x)' % (self.slide, self.slide)
def __str__(self): def __str__(self):
s = '' s = ''
if self.uuid: if self.uuid:
@ -268,15 +290,15 @@ class Image:
s += "%s " % (resolved_path) s += "%s " % (resolved_path)
for section_info in self.section_infos: for section_info in self.section_infos:
s += ", %s" % (section_info) s += ", %s" % (section_info)
if self.slide != None: if self.slide is not None:
s += ', slide = 0x%16.16x' % self.slide s += ', slide = 0x%16.16x' % self.slide
return s return s
def add_section(self, section): def add_section(self, section):
#print "added '%s' to '%s'" % (section, self.path) # print "added '%s' to '%s'" % (section, self.path)
self.section_infos.append (section) self.section_infos.append(section)
def get_section_containing_load_addr (self, load_addr): def get_section_containing_load_addr(self, load_addr):
for section_info in self.section_infos: for section_info in self.section_infos:
if section_info.contains(load_addr): if section_info.contains(load_addr):
return section_info return section_info
@ -299,13 +321,13 @@ class Image:
if self.symfile: if self.symfile:
return os.path.basename(self.symfile) return os.path.basename(self.symfile)
return None return None
def has_section_load_info(self): def has_section_load_info(self):
return self.section_infos or self.slide != None return self.section_infos or self.slide is not None
def load_module(self, target): def load_module(self, target):
if self.unavailable: if self.unavailable:
return None # We already warned that we couldn't find this module, so don't return an error string return None # We already warned that we couldn't find this module, so don't return an error string
# Load this module into "target" using the section infos to # Load this module into "target" using the section infos to
# set the section load addresses # set the section load addresses
if self.has_section_load_info(): if self.has_section_load_info():
@ -315,9 +337,11 @@ class Image:
num_sections_loaded = 0 num_sections_loaded = 0
for section_info in self.section_infos: for section_info in self.section_infos:
if section_info.name: if section_info.name:
section = self.module.FindSection (section_info.name) section = self.module.FindSection(
section_info.name)
if section: if section:
error = target.SetSectionLoadAddress (section, section_info.start_addr) error = target.SetSectionLoadAddress(
section, section_info.start_addr)
if error.Success(): if error.Success():
num_sections_loaded += 1 num_sections_loaded += 1
else: else:
@ -325,11 +349,13 @@ class Image:
else: else:
return 'error: unable to find the section named "%s"' % section_info.name return 'error: unable to find the section named "%s"' % section_info.name
else: else:
return 'error: unable to find "%s" section in "%s"' % (range.name, self.get_resolved_path()) return 'error: unable to find "%s" section in "%s"' % (
range.name, self.get_resolved_path())
if num_sections_loaded == 0: if num_sections_loaded == 0:
return 'error: no sections were successfully loaded' return 'error: no sections were successfully loaded'
else: else:
err = target.SetModuleLoadAddress(self.module, self.slide) err = target.SetModuleLoadAddress(
self.module, self.slide)
if err.Fail(): if err.Fail():
return err.GetCString() return err.GetCString()
return None return None
@ -339,30 +365,33 @@ class Image:
return 'error: invalid target' return 'error: invalid target'
else: else:
return 'error: no section infos' return 'error: no section infos'
def add_module(self, target): def add_module(self, target):
'''Add the Image described in this object to "target" and load the sections if "load" is True.''' '''Add the Image described in this object to "target" and load the sections if "load" is True.'''
if target: if target:
# Try and find using UUID only first so that paths need not match up # Try and find using UUID only first so that paths need not match
# up
uuid_str = self.get_normalized_uuid_string() uuid_str = self.get_normalized_uuid_string()
if uuid_str: if uuid_str:
self.module = target.AddModule (None, None, uuid_str) self.module = target.AddModule(None, None, uuid_str)
if not self.module: if not self.module:
self.locate_module_and_debug_symbols () self.locate_module_and_debug_symbols()
if self.unavailable: if self.unavailable:
return None return None
resolved_path = self.get_resolved_path() resolved_path = self.get_resolved_path()
self.module = target.AddModule (resolved_path, self.arch, uuid_str, self.symfile) self.module = target.AddModule(
resolved_path, self.arch, uuid_str, self.symfile)
if not self.module: if not self.module:
return 'error: unable to get module for (%s) "%s"' % (self.arch, self.get_resolved_path()) return 'error: unable to get module for (%s) "%s"' % (
self.arch, self.get_resolved_path())
if self.has_section_load_info(): if self.has_section_load_info():
return self.load_module(target) return self.load_module(target)
else: else:
return None # No sections, the module was added to the target, so success return None # No sections, the module was added to the target, so success
else: else:
return 'error: invalid target' return 'error: invalid target'
def locate_module_and_debug_symbols (self): def locate_module_and_debug_symbols(self):
# By default, just use the paths that were supplied in: # By default, just use the paths that were supplied in:
# self.path # self.path
# self.resolved_path # self.resolved_path
@ -371,7 +400,7 @@ class Image:
# Subclasses can inherit from this class and override this function # Subclasses can inherit from this class and override this function
self.resolved = True self.resolved = True
return True return True
def get_uuid(self): def get_uuid(self):
if not self.uuid and self.module: if not self.uuid and self.module:
self.uuid = uuid.UUID(self.module.GetUUIDString()) self.uuid = uuid.UUID(self.module.GetUUIDString())
@ -387,12 +416,13 @@ class Image:
if self.unavailable: if self.unavailable:
return None return None
if self.locate_module_and_debug_symbols (): if self.locate_module_and_debug_symbols():
resolved_path = self.get_resolved_path(); resolved_path = self.get_resolved_path()
path_spec = lldb.SBFileSpec (resolved_path) path_spec = lldb.SBFileSpec(resolved_path)
#result.PutCString ('plist[%s] = %s' % (uuid, self.plist)) #result.PutCString ('plist[%s] = %s' % (uuid, self.plist))
error = lldb.SBError() error = lldb.SBError()
target = lldb.debugger.CreateTarget (resolved_path, self.arch, None, False, error); target = lldb.debugger.CreateTarget(
resolved_path, self.arch, None, False, error)
if target: if target:
self.module = target.FindModule(path_spec) self.module = target.FindModule(path_spec)
if self.has_section_load_info(): if self.has_section_load_info():
@ -405,20 +435,21 @@ class Image:
else: else:
print 'error: unable to locate main executable (%s) "%s"' % (self.arch, self.path) print 'error: unable to locate main executable (%s) "%s"' % (self.arch, self.path)
return None return None
class Symbolicator: class Symbolicator:
def __init__(self): def __init__(self):
"""A class the represents the information needed to symbolicate addresses in a program""" """A class the represents the information needed to symbolicate addresses in a program"""
self.target = None self.target = None
self.images = list() # a list of images to be used when symbolicating self.images = list() # a list of images to be used when symbolicating
self.addr_mask = 0xffffffffffffffff self.addr_mask = 0xffffffffffffffff
@classmethod @classmethod
def InitWithSBTarget(cls, target): def InitWithSBTarget(cls, target):
obj = cls() obj = cls()
obj.target = target obj.target = target
obj.images = list(); obj.images = list()
triple = target.triple triple = target.triple
if triple: if triple:
arch = triple.split('-')[0] arch = triple.split('-')[0]
@ -429,7 +460,7 @@ class Symbolicator:
image = Image.InitWithSBTargetAndSBModule(target, module) image = Image.InitWithSBTargetAndSBModule(target, module)
obj.images.append(image) obj.images.append(image)
return obj return obj
def __str__(self): def __str__(self):
s = "Symbolicator:\n" s = "Symbolicator:\n"
if self.target: if self.target:
@ -441,7 +472,7 @@ class Symbolicator:
for image in self.images: for image in self.images:
s += ' %s\n' % (image) s += ' %s\n' % (image)
return s return s
def find_images_with_identifier(self, identifier): def find_images_with_identifier(self, identifier):
images = list() images = list()
for image in self.images: for image in self.images:
@ -454,20 +485,20 @@ class Symbolicator:
if regex.match(image.identifier): if regex.match(image.identifier):
images.append(image) images.append(image)
return images return images
def find_image_containing_load_addr(self, load_addr): def find_image_containing_load_addr(self, load_addr):
for image in self.images: for image in self.images:
if image.get_section_containing_load_addr (load_addr): if image.get_section_containing_load_addr(load_addr):
return image return image
return None return None
def create_target(self): def create_target(self):
if self.target: if self.target:
return self.target return self.target
if self.images: if self.images:
for image in self.images: for image in self.images:
self.target = image.create_target () self.target = image.create_target()
if self.target: if self.target:
if self.target.GetAddressByteSize() == 4: if self.target.GetAddressByteSize() == 4:
triple = self.target.triple triple = self.target.triple
@ -477,9 +508,8 @@ class Symbolicator:
self.addr_mask = 0xfffffffffffffffe self.addr_mask = 0xfffffffffffffffe
return self.target return self.target
return None return None
def symbolicate(self, load_addr, verbose=False):
def symbolicate(self, load_addr, verbose = False):
if not self.target: if not self.target:
self.create_target() self.create_target()
if self.target: if self.target:
@ -493,51 +523,60 @@ class Symbolicator:
# that a load address belongs to and lazily load its module in the # that a load address belongs to and lazily load its module in the
# target, but we shouldn't do any of this if we have a live process # target, but we shouldn't do any of this if we have a live process
if not live_process: if not live_process:
image = self.find_image_containing_load_addr (load_addr) image = self.find_image_containing_load_addr(load_addr)
if image: if image:
image.add_module (self.target) image.add_module(self.target)
symbolicated_address = Address(self.target, load_addr) symbolicated_address = Address(self.target, load_addr)
if symbolicated_address.symbolicate (verbose): if symbolicated_address.symbolicate(verbose):
if symbolicated_address.so_addr: if symbolicated_address.so_addr:
symbolicated_addresses = list() symbolicated_addresses = list()
symbolicated_addresses.append(symbolicated_address) symbolicated_addresses.append(symbolicated_address)
# See if we were able to reconstruct anything? # See if we were able to reconstruct anything?
while 1: while True:
inlined_parent_so_addr = lldb.SBAddress() inlined_parent_so_addr = lldb.SBAddress()
inlined_parent_sym_ctx = symbolicated_address.sym_ctx.GetParentOfInlinedScope (symbolicated_address.so_addr, inlined_parent_so_addr) inlined_parent_sym_ctx = symbolicated_address.sym_ctx.GetParentOfInlinedScope(
symbolicated_address.so_addr, inlined_parent_so_addr)
if not inlined_parent_sym_ctx: if not inlined_parent_sym_ctx:
break break
if not inlined_parent_so_addr: if not inlined_parent_so_addr:
break break
symbolicated_address = Address(self.target, inlined_parent_so_addr.GetLoadAddress(self.target)) symbolicated_address = Address(
self.target, inlined_parent_so_addr.GetLoadAddress(
self.target))
symbolicated_address.sym_ctx = inlined_parent_sym_ctx symbolicated_address.sym_ctx = inlined_parent_sym_ctx
symbolicated_address.so_addr = inlined_parent_so_addr symbolicated_address.so_addr = inlined_parent_so_addr
symbolicated_address.symbolicate (verbose) symbolicated_address.symbolicate(verbose)
# push the new frame onto the new frame stack # push the new frame onto the new frame stack
symbolicated_addresses.append (symbolicated_address) symbolicated_addresses.append(symbolicated_address)
if symbolicated_addresses: if symbolicated_addresses:
return symbolicated_addresses return symbolicated_addresses
else: else:
print 'error: no target in Symbolicator' print 'error: no target in Symbolicator'
return None return None
def disassemble_instructions (target, instructions, pc, insts_before_pc, insts_after_pc, non_zeroeth_frame): def disassemble_instructions(
target,
instructions,
pc,
insts_before_pc,
insts_after_pc,
non_zeroeth_frame):
lines = list() lines = list()
pc_index = -1 pc_index = -1
comment_column = 50 comment_column = 50
for inst_idx, inst in enumerate(instructions): for inst_idx, inst in enumerate(instructions):
inst_pc = inst.GetAddress().GetLoadAddress(target); inst_pc = inst.GetAddress().GetLoadAddress(target)
if pc == inst_pc: if pc == inst_pc:
pc_index = inst_idx pc_index = inst_idx
mnemonic = inst.GetMnemonic (target) mnemonic = inst.GetMnemonic(target)
operands = inst.GetOperands (target) operands = inst.GetOperands(target)
comment = inst.GetComment (target) comment = inst.GetComment(target)
#data = inst.GetData (target) #data = inst.GetData (target)
lines.append ("%#16.16x: %8s %s" % (inst_pc, mnemonic, operands)) lines.append("%#16.16x: %8s %s" % (inst_pc, mnemonic, operands))
if comment: if comment:
line_len = len(lines[-1]) line_len = len(lines[-1])
if line_len < comment_column: if line_len < comment_column:
@ -545,7 +584,8 @@ def disassemble_instructions (target, instructions, pc, insts_before_pc, insts_a
lines[-1] += "; %s" % comment lines[-1] += "; %s" % comment
if pc_index >= 0: if pc_index >= 0:
# If we are disassembling the non-zeroeth frame, we need to backup the PC by 1 # If we are disassembling the non-zeroeth frame, we need to backup the
# PC by 1
if non_zeroeth_frame and pc_index > 0: if non_zeroeth_frame and pc_index > 0:
pc_index = pc_index - 1 pc_index = pc_index - 1
if insts_before_pc == -1: if insts_before_pc == -1:
@ -560,81 +600,128 @@ def disassemble_instructions (target, instructions, pc, insts_before_pc, insts_a
end_idx = pc_index + insts_after_pc end_idx = pc_index + insts_after_pc
if end_idx > inst_idx: if end_idx > inst_idx:
end_idx = inst_idx end_idx = inst_idx
for i in range(start_idx, end_idx+1): for i in range(start_idx, end_idx + 1):
if i == pc_index: if i == pc_index:
print ' -> ', lines[i] print ' -> ', lines[i]
else: else:
print ' ', lines[i] print ' ', lines[i]
def print_module_section_data (section):
def print_module_section_data(section):
print section print section
section_data = section.GetSectionData() section_data = section.GetSectionData()
if section_data: if section_data:
ostream = lldb.SBStream() ostream = lldb.SBStream()
section_data.GetDescription (ostream, section.GetFileAddress()) section_data.GetDescription(ostream, section.GetFileAddress())
print ostream.GetData() print ostream.GetData()
def print_module_section (section, depth):
def print_module_section(section, depth):
print section print section
if depth > 0: if depth > 0:
num_sub_sections = section.GetNumSubSections() num_sub_sections = section.GetNumSubSections()
for sect_idx in range(num_sub_sections): for sect_idx in range(num_sub_sections):
print_module_section (section.GetSubSectionAtIndex(sect_idx), depth - 1) print_module_section(
section.GetSubSectionAtIndex(sect_idx), depth - 1)
def print_module_sections (module, depth):
def print_module_sections(module, depth):
for sect in module.section_iter(): for sect in module.section_iter():
print_module_section (sect, depth) print_module_section(sect, depth)
def print_module_symbols (module):
def print_module_symbols(module):
for sym in module: for sym in module:
print sym print sym
def Symbolicate(command_args): def Symbolicate(command_args):
usage = "usage: %prog [options] <addr1> [addr2 ...]" usage = "usage: %prog [options] <addr1> [addr2 ...]"
description='''Symbolicate one or more addresses using LLDB's python scripting API..''' description = '''Symbolicate one or more addresses using LLDB's python scripting API..'''
parser = optparse.OptionParser(description=description, prog='crashlog.py',usage=usage) parser = optparse.OptionParser(
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False) description=description,
parser.add_option('-p', '--platform', type='string', metavar='platform', dest='platform', help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".') prog='crashlog.py',
parser.add_option('-f', '--file', type='string', metavar='file', dest='file', help='Specify a file to use when symbolicating') usage=usage)
parser.add_option('-a', '--arch', type='string', metavar='arch', dest='arch', help='Specify a architecture to use when symbolicating') parser.add_option(
parser.add_option('-s', '--slide', type='int', metavar='slide', dest='slide', help='Specify the slide to use on the file specified with the --file option', default=None) '-v',
parser.add_option('--section', type='string', action='append', dest='section_strings', help='specify <sect-name>=<start-addr> or <sect-name>=<start-addr>-<end-addr>') '--verbose',
action='store_true',
dest='verbose',
help='display verbose debug info',
default=False)
parser.add_option(
'-p',
'--platform',
type='string',
metavar='platform',
dest='platform',
help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".')
parser.add_option(
'-f',
'--file',
type='string',
metavar='file',
dest='file',
help='Specify a file to use when symbolicating')
parser.add_option(
'-a',
'--arch',
type='string',
metavar='arch',
dest='arch',
help='Specify a architecture to use when symbolicating')
parser.add_option(
'-s',
'--slide',
type='int',
metavar='slide',
dest='slide',
help='Specify the slide to use on the file specified with the --file option',
default=None)
parser.add_option(
'--section',
type='string',
action='append',
dest='section_strings',
help='specify <sect-name>=<start-addr> or <sect-name>=<start-addr>-<end-addr>')
try: try:
(options, args) = parser.parse_args(command_args) (options, args) = parser.parse_args(command_args)
except: except:
return return
symbolicator = Symbolicator() symbolicator = Symbolicator()
images = list(); images = list()
if options.file: if options.file:
image = Image(options.file); image = Image(options.file)
image.arch = options.arch image.arch = options.arch
# Add any sections that were specified with one or more --section options # Add any sections that were specified with one or more --section
# options
if options.section_strings: if options.section_strings:
for section_str in options.section_strings: for section_str in options.section_strings:
section = Section() section = Section()
if section.set_from_string (section_str): if section.set_from_string(section_str):
image.add_section (section) image.add_section(section)
else: else:
sys.exit(1) sys.exit(1)
if options.slide != None: if options.slide is not None:
image.slide = options.slide image.slide = options.slide
symbolicator.images.append(image) symbolicator.images.append(image)
target = symbolicator.create_target() target = symbolicator.create_target()
if options.verbose: if options.verbose:
print symbolicator print symbolicator
if target: if target:
for addr_str in args: for addr_str in args:
addr = int(addr_str, 0) addr = int(addr_str, 0)
symbolicated_addrs = symbolicator.symbolicate(addr, options.verbose) symbolicated_addrs = symbolicator.symbolicate(
addr, options.verbose)
for symbolicated_addr in symbolicated_addrs: for symbolicated_addr in symbolicated_addrs:
print symbolicated_addr print symbolicated_addr
print print
else: else:
print 'error: no target for %s' % (symbolicator) print 'error: no target for %s' % (symbolicator)
if __name__ == '__main__': if __name__ == '__main__':
# Create a new debugger instance # Create a new debugger instance
lldb.debugger = lldb.SBDebugger.Create() lldb.debugger = lldb.SBDebugger.Create()
Symbolicate (sys.argv[1:]) Symbolicate(sys.argv[1:])

View File

@ -4,7 +4,7 @@
# Be sure to add the python path that points to the LLDB shared library. # Be sure to add the python path that points to the LLDB shared library.
# #
# # To use this in the embedded python interpreter using "lldb" just # # To use this in the embedded python interpreter using "lldb" just
# import it with the full path using the "command script import" # import it with the full path using the "command script import"
# command # command
# (lldb) command script import /path/to/cmdtemplate.py # (lldb) command script import /path/to/cmdtemplate.py
#---------------------------------------------------------------------- #----------------------------------------------------------------------
@ -16,7 +16,7 @@ import re
import signal import signal
import sys import sys
try: try:
# Just try for LLDB in case PYTHONPATH is already correctly setup # Just try for LLDB in case PYTHONPATH is already correctly setup
import lldb import lldb
except ImportError: except ImportError:
@ -27,15 +27,20 @@ except ImportError:
# On Darwin, try the currently selected Xcode directory # On Darwin, try the currently selected Xcode directory
xcode_dir = commands.getoutput("xcode-select --print-path") xcode_dir = commands.getoutput("xcode-select --print-path")
if xcode_dir: if xcode_dir:
lldb_python_dirs.append(os.path.realpath(xcode_dir + '/../SharedFrameworks/LLDB.framework/Resources/Python')) lldb_python_dirs.append(
lldb_python_dirs.append(xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python') os.path.realpath(
lldb_python_dirs.append('/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python') xcode_dir +
'/../SharedFrameworks/LLDB.framework/Resources/Python'))
lldb_python_dirs.append(
xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
lldb_python_dirs.append(
'/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
success = False success = False
for lldb_python_dir in lldb_python_dirs: for lldb_python_dir in lldb_python_dirs:
if os.path.exists(lldb_python_dir): if os.path.exists(lldb_python_dir):
if not (sys.path.__contains__(lldb_python_dir)): if not (sys.path.__contains__(lldb_python_dir)):
sys.path.append(lldb_python_dir) sys.path.append(lldb_python_dir)
try: try:
import lldb import lldb
except ImportError: except ImportError:
pass pass
@ -52,48 +57,111 @@ import optparse
import shlex import shlex
import time import time
def regex_option_callback(option, opt_str, value, parser): def regex_option_callback(option, opt_str, value, parser):
if opt_str == "--std": if opt_str == "--std":
value = '^std::' value = '^std::'
regex = re.compile(value) regex = re.compile(value)
parser.values.skip_type_regexes.append (regex) parser.values.skip_type_regexes.append(regex)
def create_types_options(for_lldb_command): def create_types_options(for_lldb_command):
if for_lldb_command: if for_lldb_command:
usage = "usage: %prog [options]" usage = "usage: %prog [options]"
description='''This command will help check for padding in between description = '''This command will help check for padding in between
base classes and members in structs and classes. It will summarize the types base classes and members in structs and classes. It will summarize the types
and how much padding was found. If no types are specified with the --types TYPENAME and how much padding was found. If no types are specified with the --types TYPENAME
option, all structure and class types will be verified. If no modules are option, all structure and class types will be verified. If no modules are
specified with the --module option, only the target's main executable will be specified with the --module option, only the target's main executable will be
searched. searched.
''' '''
else: else:
usage = "usage: %prog [options] EXEPATH [EXEPATH ...]" usage = "usage: %prog [options] EXEPATH [EXEPATH ...]"
description='''This command will help check for padding in between description = '''This command will help check for padding in between
base classes and members in structures and classes. It will summarize the types base classes and members in structures and classes. It will summarize the types
and how much padding was found. One or more paths to executable files must be and how much padding was found. One or more paths to executable files must be
specified and targets will be created with these modules. If no types are specified and targets will be created with these modules. If no types are
specified with the --types TYPENAME option, all structure and class types will specified with the --types TYPENAME option, all structure and class types will
be verified in all specified modules. be verified in all specified modules.
''' '''
parser = optparse.OptionParser(description=description, prog='framestats',usage=usage) parser = optparse.OptionParser(
description=description,
prog='framestats',
usage=usage)
if not for_lldb_command: if not for_lldb_command:
parser.add_option('-a', '--arch', type='string', dest='arch', help='The architecture to use when creating the debug target.', default=None) parser.add_option(
parser.add_option('-p', '--platform', type='string', metavar='platform', dest='platform', help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".') '-a',
parser.add_option('-m', '--module', action='append', type='string', metavar='MODULE', dest='modules', help='Specify one or more modules which will be used to verify the types.', default=[]) '--arch',
parser.add_option('-d', '--debug', action='store_true', dest='debug', help='Pause 10 seconds to wait for a debugger to attach.', default=False) type='string',
parser.add_option('-t', '--type', action='append', type='string', metavar='TYPENAME', dest='typenames', help='Specify one or more type names which should be verified. If no type names are specified, all class and struct types will be verified.', default=[]) dest='arch',
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='Enable verbose logging and information.', default=False) help='The architecture to use when creating the debug target.',
parser.add_option('-s', '--skip-type-regex', action="callback", callback=regex_option_callback, type='string', metavar='REGEX', dest='skip_type_regexes', help='Regular expressions that, if they match the current member typename, will cause the type to no be recursively displayed.', default=[]) default=None)
parser.add_option('--std', action="callback", callback=regex_option_callback, metavar='REGEX', dest='skip_type_regexes', help="Don't' recurse into types in the std namespace.", default=[]) parser.add_option(
'-p',
'--platform',
type='string',
metavar='platform',
dest='platform',
help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".')
parser.add_option(
'-m',
'--module',
action='append',
type='string',
metavar='MODULE',
dest='modules',
help='Specify one or more modules which will be used to verify the types.',
default=[])
parser.add_option(
'-d',
'--debug',
action='store_true',
dest='debug',
help='Pause 10 seconds to wait for a debugger to attach.',
default=False)
parser.add_option(
'-t',
'--type',
action='append',
type='string',
metavar='TYPENAME',
dest='typenames',
help='Specify one or more type names which should be verified. If no type names are specified, all class and struct types will be verified.',
default=[])
parser.add_option(
'-v',
'--verbose',
action='store_true',
dest='verbose',
help='Enable verbose logging and information.',
default=False)
parser.add_option(
'-s',
'--skip-type-regex',
action="callback",
callback=regex_option_callback,
type='string',
metavar='REGEX',
dest='skip_type_regexes',
help='Regular expressions that, if they match the current member typename, will cause the type to no be recursively displayed.',
default=[])
parser.add_option(
'--std',
action="callback",
callback=regex_option_callback,
metavar='REGEX',
dest='skip_type_regexes',
help="Don't' recurse into types in the std namespace.",
default=[])
return parser return parser
def verify_type (target, options, type):
def verify_type(target, options, type):
print type print type
typename = type.GetName() typename = type.GetName()
# print 'type: %s' % (typename) # print 'type: %s' % (typename)
(end_offset, padding) = verify_type_recursive (target, options, type, None, 0, 0, 0) (end_offset, padding) = verify_type_recursive(
target, options, type, None, 0, 0, 0)
byte_size = type.GetByteSize() byte_size = type.GetByteSize()
# if end_offset < byte_size: # if end_offset < byte_size:
# last_member_padding = byte_size - end_offset # last_member_padding = byte_size - end_offset
@ -105,7 +173,15 @@ def verify_type (target, options, type):
print 'Padding percentage: %2.2f %%' % ((float(padding) / float(byte_size)) * 100.0) print 'Padding percentage: %2.2f %%' % ((float(padding) / float(byte_size)) * 100.0)
print print
def verify_type_recursive (target, options, type, member_name, depth, base_offset, padding):
def verify_type_recursive(
target,
options,
type,
member_name,
depth,
base_offset,
padding):
prev_end_offset = base_offset prev_end_offset = base_offset
typename = type.GetName() typename = type.GetName()
byte_size = type.GetByteSize() byte_size = type.GetByteSize()
@ -113,12 +189,12 @@ def verify_type_recursive (target, options, type, member_name, depth, base_offse
print '%+4u <%3u> %s%s %s;' % (base_offset, byte_size, ' ' * depth, typename, member_name) print '%+4u <%3u> %s%s %s;' % (base_offset, byte_size, ' ' * depth, typename, member_name)
else: else:
print '%+4u {%3u} %s%s' % (base_offset, byte_size, ' ' * depth, typename) print '%+4u {%3u} %s%s' % (base_offset, byte_size, ' ' * depth, typename)
for type_regex in options.skip_type_regexes: for type_regex in options.skip_type_regexes:
match = type_regex.match (typename) match = type_regex.match(typename)
if match: if match:
return (base_offset + byte_size, padding) return (base_offset + byte_size, padding)
members = type.members members = type.members
if members: if members:
for member_idx, member in enumerate(members): for member_idx, member in enumerate(members):
@ -132,7 +208,8 @@ def verify_type_recursive (target, options, type, member_name, depth, base_offse
member_is_class_or_struct = False member_is_class_or_struct = False
if member_type_class == lldb.eTypeClassStruct or member_type_class == lldb.eTypeClassClass: if member_type_class == lldb.eTypeClassStruct or member_type_class == lldb.eTypeClassClass:
member_is_class_or_struct = True member_is_class_or_struct = True
if member_idx == 0 and member_offset == target.GetAddressByteSize() and type.IsPolymorphicClass(): if member_idx == 0 and member_offset == target.GetAddressByteSize(
) and type.IsPolymorphicClass():
ptr_size = target.GetAddressByteSize() ptr_size = target.GetAddressByteSize()
print '%+4u <%3u> %s__vtbl_ptr_type * _vptr;' % (prev_end_offset, ptr_size, ' ' * (depth + 1)) print '%+4u <%3u> %s__vtbl_ptr_type * _vptr;' % (prev_end_offset, ptr_size, ' ' * (depth + 1))
prev_end_offset = ptr_size prev_end_offset = ptr_size
@ -141,9 +218,16 @@ def verify_type_recursive (target, options, type, member_name, depth, base_offse
member_padding = member_total_offset - prev_end_offset member_padding = member_total_offset - prev_end_offset
padding = padding + member_padding padding = padding + member_padding
print '%+4u <%3u> %s<PADDING>' % (prev_end_offset, member_padding, ' ' * (depth + 1)) print '%+4u <%3u> %s<PADDING>' % (prev_end_offset, member_padding, ' ' * (depth + 1))
if member_is_class_or_struct: if member_is_class_or_struct:
(prev_end_offset, padding) = verify_type_recursive (target, options, member_canonical_type, member_name, depth + 1, member_total_offset, padding) (prev_end_offset,
padding) = verify_type_recursive(target,
options,
member_canonical_type,
member_name,
depth + 1,
member_total_offset,
padding)
else: else:
prev_end_offset = member_total_offset + member_byte_size prev_end_offset = member_total_offset + member_byte_size
member_typename = member_type.GetName() member_typename = member_type.GetName()
@ -151,7 +235,7 @@ def verify_type_recursive (target, options, type, member_name, depth, base_offse
print '%+4u <%3u> %s%s:%u %s;' % (member_total_offset, member_byte_size, ' ' * (depth + 1), member_typename, member.GetBitfieldSizeInBits(), member_name) print '%+4u <%3u> %s%s:%u %s;' % (member_total_offset, member_byte_size, ' ' * (depth + 1), member_typename, member.GetBitfieldSizeInBits(), member_name)
else: else:
print '%+4u <%3u> %s%s %s;' % (member_total_offset, member_byte_size, ' ' * (depth + 1), member_typename, member_name) print '%+4u <%3u> %s%s %s;' % (member_total_offset, member_byte_size, ' ' * (depth + 1), member_typename, member_name)
if prev_end_offset < byte_size: if prev_end_offset < byte_size:
last_member_padding = byte_size - prev_end_offset last_member_padding = byte_size - prev_end_offset
print '%+4u <%3u> %s<PADDING>' % (prev_end_offset, last_member_padding, ' ' * (depth + 1)) print '%+4u <%3u> %s<PADDING>' % (prev_end_offset, last_member_padding, ' ' * (depth + 1))
@ -162,11 +246,12 @@ def verify_type_recursive (target, options, type, member_name, depth, base_offse
print '%+4u <%3u> %s__vtbl_ptr_type * _vptr;' % (prev_end_offset, ptr_size, ' ' * (depth + 1)) print '%+4u <%3u> %s__vtbl_ptr_type * _vptr;' % (prev_end_offset, ptr_size, ' ' * (depth + 1))
prev_end_offset = ptr_size prev_end_offset = ptr_size
prev_end_offset = base_offset + byte_size prev_end_offset = base_offset + byte_size
return (prev_end_offset, padding) return (prev_end_offset, padding)
def check_padding_command (debugger, command, result, dict):
# Use the Shell Lexer to properly parse up command options just like a def check_padding_command(debugger, command, result, dict):
# Use the Shell Lexer to properly parse up command options just like a
# shell would # shell would
command_args = shlex.split(command) command_args = shlex.split(command)
parser = create_types_options(True) parser = create_types_options(True)
@ -175,30 +260,33 @@ def check_padding_command (debugger, command, result, dict):
except: except:
# if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit # if you don't handle exceptions, passing an incorrect argument to the OptionParser will cause LLDB to exit
# (courtesy of OptParse dealing with argument errors by throwing SystemExit) # (courtesy of OptParse dealing with argument errors by throwing SystemExit)
result.SetStatus (lldb.eReturnStatusFailed) result.SetStatus(lldb.eReturnStatusFailed)
return "option parsing failed" # returning a string is the same as returning an error whose description is the string # returning a string is the same as returning an error whose
# description is the string
return "option parsing failed"
verify_types(debugger.GetSelectedTarget(), options) verify_types(debugger.GetSelectedTarget(), options)
@lldb.command("parse_all_struct_class_types") @lldb.command("parse_all_struct_class_types")
def parse_all_struct_class_types (debugger, command, result, dict): def parse_all_struct_class_types(debugger, command, result, dict):
command_args = shlex.split(command) command_args = shlex.split(command)
for f in command_args: for f in command_args:
error = lldb.SBError() error = lldb.SBError()
target = debugger.CreateTarget (f, None, None, False, error) target = debugger.CreateTarget(f, None, None, False, error)
module = target.GetModuleAtIndex(0) module = target.GetModuleAtIndex(0)
print "Parsing all types in '%s'" % (module) print "Parsing all types in '%s'" % (module)
types = module.GetTypes(lldb.eTypeClassClass | lldb.eTypeClassStruct) types = module.GetTypes(lldb.eTypeClassClass | lldb.eTypeClassStruct)
for t in types: for t in types:
print t print t
print "" print ""
def verify_types (target, options): def verify_types(target, options):
if not target: if not target:
print 'error: invalid target' print 'error: invalid target'
return return
modules = list() modules = list()
if len(options.modules) == 0: if len(options.modules) == 0:
# Append just the main executable if nothing was specified # Append just the main executable if nothing was specified
@ -210,7 +298,7 @@ def verify_types (target, options):
module = lldb.target.module[module_name] module = lldb.target.module[module_name]
if module: if module:
modules.append(module) modules.append(module)
if modules: if modules:
for module in modules: for module in modules:
print 'module: %s' % (module.file) print 'module: %s' % (module.file)
@ -220,46 +308,49 @@ def verify_types (target, options):
if types.GetSize(): if types.GetSize():
print 'Found %u types matching "%s" in "%s"' % (len(types), typename, module.file) print 'Found %u types matching "%s" in "%s"' % (len(types), typename, module.file)
for type in types: for type in types:
verify_type (target, options, type) verify_type(target, options, type)
else: else:
print 'error: no type matches "%s" in "%s"' % (typename, module.file) print 'error: no type matches "%s" in "%s"' % (typename, module.file)
else: else:
types = module.GetTypes(lldb.eTypeClassClass | lldb.eTypeClassStruct) types = module.GetTypes(
lldb.eTypeClassClass | lldb.eTypeClassStruct)
print 'Found %u types in "%s"' % (len(types), module.file) print 'Found %u types in "%s"' % (len(types), module.file)
for type in types: for type in types:
verify_type (target, options, type) verify_type(target, options, type)
else: else:
print 'error: no modules' print 'error: no modules'
if __name__ == '__main__': if __name__ == '__main__':
debugger = lldb.SBDebugger.Create() debugger = lldb.SBDebugger.Create()
parser = create_types_options(False) parser = create_types_options(False)
# try: # try:
(options, args) = parser.parse_args(sys.argv[1:]) (options, args) = parser.parse_args(sys.argv[1:])
# except: # except:
# print "error: option parsing failed" # print "error: option parsing failed"
# sys.exit(1) # sys.exit(1)
if options.debug: if options.debug:
print "Waiting for debugger to attach to process %d" % os.getpid() print "Waiting for debugger to attach to process %d" % os.getpid()
os.kill(os.getpid(), signal.SIGSTOP) os.kill(os.getpid(), signal.SIGSTOP)
for path in args: for path in args:
# in a command - the lldb.* convenience variables are not to be used # in a command - the lldb.* convenience variables are not to be used
# and their values (if any) are undefined # and their values (if any) are undefined
# this is the best practice to access those objects from within a command # this is the best practice to access those objects from within a
# command
error = lldb.SBError() error = lldb.SBError()
target = debugger.CreateTarget (path, target = debugger.CreateTarget(path,
options.arch, options.arch,
options.platform, options.platform,
True, True,
error) error)
if error.Fail(): if error.Fail():
print error.GetCString() print error.GetCString()
continue continue
verify_types (target, options) verify_types(target, options)
elif getattr(lldb, 'debugger', None): elif getattr(lldb, 'debugger', None):
lldb.debugger.HandleCommand('command script add -f types.check_padding_command check_padding') lldb.debugger.HandleCommand(
print '"check_padding" command installed, use the "--help" option for detailed help' 'command script add -f types.check_padding_command check_padding')
print '"check_padding" command installed, use the "--help" option for detailed help'

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -6,13 +6,12 @@
// License. See LICENSE.TXT for details. // License. See LICENSE.TXT for details.
// //
//===---------------------------------------------------------------------===// //===---------------------------------------------------------------------===//
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h> #include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
typedef struct tree_node typedef struct tree_node {
{
const char *word; const char *word;
struct tree_node *left; struct tree_node *left;
struct tree_node *right; struct tree_node *right;
@ -22,22 +21,20 @@ typedef struct tree_node
alphabet character and ends at the last alphabet character, i.e. it alphabet character and ends at the last alphabet character, i.e. it
strips off beginning or ending quotes, punctuation, etc. */ strips off beginning or ending quotes, punctuation, etc. */
char * char *strip(char **word) {
strip (char **word)
{
char *start = *word; char *start = *word;
int len = strlen (start); int len = strlen(start);
char *end = start + len - 1; char *end = start + len - 1;
while ((start < end) && (!isalpha (start[0]))) while ((start < end) && (!isalpha(start[0])))
start++; start++;
while ((end > start) && (!isalpha (end[0]))) while ((end > start) && (!isalpha(end[0])))
end--; end--;
if (start > end) if (start > end)
return NULL; return NULL;
end[1] = '\0'; end[1] = '\0';
*word = start; *word = start;
@ -48,116 +45,95 @@ strip (char **word)
each node), and a new word, inserts the word at the appropriate each node), and a new word, inserts the word at the appropriate
place in the tree. */ place in the tree. */
void void insert(tree_node *root, char *word) {
insert (tree_node *root, char *word)
{
if (root == NULL) if (root == NULL)
return; return;
int compare_value = strcmp (word, root->word); int compare_value = strcmp(word, root->word);
if (compare_value == 0) if (compare_value == 0)
return; return;
if (compare_value < 0) if (compare_value < 0) {
{ if (root->left != NULL)
if (root->left != NULL) insert(root->left, word);
insert (root->left, word); else {
else tree_node *new_node = (tree_node *)malloc(sizeof(tree_node));
{ new_node->word = strdup(word);
tree_node *new_node = (tree_node *) malloc (sizeof (tree_node)); new_node->left = NULL;
new_node->word = strdup (word); new_node->right = NULL;
new_node->left = NULL; root->left = new_node;
new_node->right = NULL;
root->left = new_node;
}
} }
else } else {
{ if (root->right != NULL)
if (root->right != NULL) insert(root->right, word);
insert (root->right, word); else {
else tree_node *new_node = (tree_node *)malloc(sizeof(tree_node));
{ new_node->word = strdup(word);
tree_node *new_node = (tree_node *) malloc (sizeof (tree_node)); new_node->left = NULL;
new_node->word = strdup (word); new_node->right = NULL;
new_node->left = NULL; root->right = new_node;
new_node->right = NULL;
root->right = new_node;
}
} }
}
} }
/* Read in a text file and storea all the words from the file in a /* Read in a text file and storea all the words from the file in a
binary search tree. */ binary search tree. */
void void populate_dictionary(tree_node **dictionary, char *filename) {
populate_dictionary (tree_node **dictionary, char *filename)
{
FILE *in_file; FILE *in_file;
char word[1024]; char word[1024];
in_file = fopen (filename, "r"); in_file = fopen(filename, "r");
if (in_file) if (in_file) {
{ while (fscanf(in_file, "%s", word) == 1) {
while (fscanf (in_file, "%s", word) == 1) char *new_word = (strdup(word));
{ new_word = strip(&new_word);
char *new_word = (strdup (word)); if (*dictionary == NULL) {
new_word = strip (&new_word); tree_node *new_node = (tree_node *)malloc(sizeof(tree_node));
if (*dictionary == NULL) new_node->word = new_word;
{ new_node->left = NULL;
tree_node *new_node = (tree_node *) malloc (sizeof (tree_node)); new_node->right = NULL;
new_node->word = new_word; *dictionary = new_node;
new_node->left = NULL; } else
new_node->right = NULL; insert(*dictionary, new_word);
*dictionary = new_node;
}
else
insert (*dictionary, new_word);
}
} }
}
} }
/* Given a binary search tree and a word, search for the word /* Given a binary search tree and a word, search for the word
in the binary search tree. */ in the binary search tree. */
int int find_word(tree_node *dictionary, char *word) {
find_word (tree_node *dictionary, char *word)
{
if (!word || !dictionary) if (!word || !dictionary)
return 0; return 0;
int compare_value = strcmp (word, dictionary->word); int compare_value = strcmp(word, dictionary->word);
if (compare_value == 0) if (compare_value == 0)
return 1; return 1;
else if (compare_value < 0) else if (compare_value < 0)
return find_word (dictionary->left, word); return find_word(dictionary->left, word);
else else
return find_word (dictionary->right, word); return find_word(dictionary->right, word);
} }
/* Print out the words in the binary search tree, in sorted order. */ /* Print out the words in the binary search tree, in sorted order. */
void void print_tree(tree_node *dictionary) {
print_tree (tree_node *dictionary)
{
if (!dictionary) if (!dictionary)
return; return;
if (dictionary->left) if (dictionary->left)
print_tree (dictionary->left); print_tree(dictionary->left);
printf ("%s\n", dictionary->word);
printf("%s\n", dictionary->word);
if (dictionary->right) if (dictionary->right)
print_tree (dictionary->right); print_tree(dictionary->right);
} }
int main(int argc, char **argv) {
int
main (int argc, char **argv)
{
tree_node *dictionary = NULL; tree_node *dictionary = NULL;
char buffer[1024]; char buffer[1024];
char *filename; char *filename;
@ -169,32 +145,29 @@ main (int argc, char **argv)
if (!filename) if (!filename)
return -1; return -1;
populate_dictionary (&dictionary, filename); populate_dictionary(&dictionary, filename);
fprintf (stdout, "Dictionary loaded.\nEnter search word: "); fprintf(stdout, "Dictionary loaded.\nEnter search word: ");
while (!done && fgets (buffer, sizeof(buffer), stdin)) while (!done && fgets(buffer, sizeof(buffer), stdin)) {
{ char *word = buffer;
char *word = buffer; int len = strlen(word);
int len = strlen (word); int i;
int i;
for (i = 0; i < len; ++i) for (i = 0; i < len; ++i)
word[i] = tolower (word[i]); word[i] = tolower(word[i]);
if ((len > 0) && (word[len-1] == '\n')) if ((len > 0) && (word[len - 1] == '\n')) {
{ word[len - 1] = '\0';
word[len-1] = '\0'; len = len - 1;
len = len - 1;
}
if (find_word (dictionary, word))
fprintf (stdout, "Yes!\n");
else
fprintf (stdout, "No!\n");
fprintf (stdout, "Enter search word: ");
} }
fprintf (stdout, "\n"); if (find_word(dictionary, word))
fprintf(stdout, "Yes!\n");
else
fprintf(stdout, "No!\n");
fprintf(stdout, "Enter search word: ");
}
fprintf(stdout, "\n");
return 0; return 0;
} }

View File

@ -1,4 +1,4 @@
""" """
# ===-- tree_utils.py ---------------------------------------*- Python -*-===// # ===-- tree_utils.py ---------------------------------------*- Python -*-===//
# #
# The LLVM Compiler Infrastructure # The LLVM Compiler Infrastructure
@ -9,7 +9,7 @@
# ===---------------------------------------------------------------------===// # ===---------------------------------------------------------------------===//
tree_utils.py - A set of functions for examining binary tree_utils.py - A set of functions for examining binary
search trees, based on the example search tree defined in search trees, based on the example search tree defined in
dictionary.c. These functions contain calls to LLDB API dictionary.c. These functions contain calls to LLDB API
functions, and assume that the LLDB Python module has been functions, and assume that the LLDB Python module has been
imported. imported.
@ -20,7 +20,7 @@ http://lldb.llvm.org/scripting.html
""" """
def DFS (root, word, cur_path): def DFS(root, word, cur_path):
""" """
Recursively traverse a binary search tree containing Recursively traverse a binary search tree containing
words sorted alphabetically, searching for a particular words sorted alphabetically, searching for a particular
@ -33,21 +33,21 @@ def DFS (root, word, cur_path):
the one defined in dictionary.c It uses LLDB API the one defined in dictionary.c It uses LLDB API
functions to examine and traverse the tree nodes. functions to examine and traverse the tree nodes.
""" """
# Get pointer field values out of node 'root' # Get pointer field values out of node 'root'
root_word_ptr = root.GetChildMemberWithName ("word") root_word_ptr = root.GetChildMemberWithName("word")
left_child_ptr = root.GetChildMemberWithName ("left") left_child_ptr = root.GetChildMemberWithName("left")
right_child_ptr = root.GetChildMemberWithName ("right") right_child_ptr = root.GetChildMemberWithName("right")
# Get the word out of the word pointer and strip off # Get the word out of the word pointer and strip off
# surrounding quotes (added by call to GetSummary). # surrounding quotes (added by call to GetSummary).
root_word = root_word_ptr.GetSummary() root_word = root_word_ptr.GetSummary()
end = len (root_word) - 1 end = len(root_word) - 1
if root_word[0] == '"' and root_word[end] == '"': if root_word[0] == '"' and root_word[end] == '"':
root_word = root_word[1:end] root_word = root_word[1:end]
end = len (root_word) - 1 end = len(root_word) - 1
if root_word[0] == '\'' and root_word[end] == '\'': if root_word[0] == '\'' and root_word[end] == '\'':
root_word = root_word[1:end] root_word = root_word[1:end]
@ -59,23 +59,23 @@ def DFS (root, word, cur_path):
# Check to see if left child is NULL # Check to see if left child is NULL
if left_child_ptr.GetValue() == None: if left_child_ptr.GetValue() is None:
return "" return ""
else: else:
cur_path = cur_path + "L" cur_path = cur_path + "L"
return DFS (left_child_ptr, word, cur_path) return DFS(left_child_ptr, word, cur_path)
else: else:
# Check to see if right child is NULL # Check to see if right child is NULL
if right_child_ptr.GetValue() == None: if right_child_ptr.GetValue() is None:
return "" return ""
else: else:
cur_path = cur_path + "R" cur_path = cur_path + "R"
return DFS (right_child_ptr, word, cur_path) return DFS(right_child_ptr, word, cur_path)
def tree_size (root):
def tree_size(root):
""" """
Recursively traverse a binary search tree, counting Recursively traverse a binary search tree, counting
the nodes in the tree. Returns the final count. the nodes in the tree. Returns the final count.
@ -84,20 +84,20 @@ def tree_size (root):
the one defined in dictionary.c It uses LLDB API the one defined in dictionary.c It uses LLDB API
functions to examine and traverse the tree nodes. functions to examine and traverse the tree nodes.
""" """
if (root.GetValue == None): if (root.GetValue is None):
return 0 return 0
if (int (root.GetValue(), 16) == 0): if (int(root.GetValue(), 16) == 0):
return 0 return 0
left_size = tree_size (root.GetChildAtIndex(1)); left_size = tree_size(root.GetChildAtIndex(1))
right_size = tree_size (root.GetChildAtIndex(2)); right_size = tree_size(root.GetChildAtIndex(2))
total_size = left_size + right_size + 1 total_size = left_size + right_size + 1
return total_size return total_size
def print_tree (root):
def print_tree(root):
""" """
Recursively traverse a binary search tree, printing out Recursively traverse a binary search tree, printing out
the words at the nodes in alphabetical order (the the words at the nodes in alphabetical order (the
@ -107,12 +107,12 @@ def print_tree (root):
the one defined in dictionary.c It uses LLDB API the one defined in dictionary.c It uses LLDB API
functions to examine and traverse the tree nodes. functions to examine and traverse the tree nodes.
""" """
if (root.GetChildAtIndex(1).GetValue() != None) and (int (root.GetChildAtIndex(1).GetValue(), 16) != 0): if (root.GetChildAtIndex(1).GetValue() is not None) and (
print_tree (root.GetChildAtIndex(1)) int(root.GetChildAtIndex(1).GetValue(), 16) != 0):
print_tree(root.GetChildAtIndex(1))
print root.GetChildAtIndex(0).GetSummary() print root.GetChildAtIndex(0).GetSummary()
if (root.GetChildAtIndex(2).GetValue() != None) and (int (root.GetChildAtIndex(2).GetValue(), 16) != 0): if (root.GetChildAtIndex(2).GetValue() is not None) and (
print_tree (root.GetChildAtIndex(2)) int(root.GetChildAtIndex(2).GetValue(), 16) != 0):
print_tree(root.GetChildAtIndex(2))

View File

@ -22,183 +22,212 @@ statistics.add_metric('code_notrun')
# much less functional than the other two cases below # much less functional than the other two cases below
# just runs code to get to the count and then returns # just runs code to get to the count and then returns
# no children # no children
class NSArrayKVC_SynthProvider: class NSArrayKVC_SynthProvider:
def adjust_for_architecture(self): def adjust_for_architecture(self):
pass pass
def __init__(self, valobj, dict, params): def __init__(self, valobj, dict, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.valobj = valobj; self.valobj = valobj
self.update() self.update()
def update(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.adjust_for_architecture()
def num_children(self): def num_children(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream() stream = lldb.SBStream()
self.valobj.GetExpressionPath(stream) self.valobj.GetExpressionPath(stream)
num_children_vo = self.valobj.CreateValueFromExpression("count","(int)[" + stream.GetData() + " count]"); num_children_vo = self.valobj.CreateValueFromExpression(
if num_children_vo.IsValid(): "count", "(int)[" + stream.GetData() + " count]")
return num_children_vo.GetValueAsUnsigned(0) if num_children_vo.IsValid():
return "<variable is not NSArray>" return num_children_vo.GetValueAsUnsigned(0)
return "<variable is not NSArray>"
# much less functional than the other two cases below # much less functional than the other two cases below
# just runs code to get to the count and then returns # just runs code to get to the count and then returns
# no children # no children
class NSArrayCF_SynthProvider: class NSArrayCF_SynthProvider:
def adjust_for_architecture(self): def adjust_for_architecture(self):
pass pass
def __init__(self, valobj, dict, params): def __init__(self, valobj, dict, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.valobj = valobj; self.valobj = valobj
self.sys_params = params self.sys_params = params
if not (self.sys_params.types_cache.ulong): if not (self.sys_params.types_cache.ulong):
self.sys_params.types_cache.ulong = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong) self.sys_params.types_cache.ulong = self.valobj.GetType(
self.update() ).GetBasicType(lldb.eBasicTypeUnsignedLong)
self.update()
def update(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.adjust_for_architecture()
def num_children(self):
logger = lldb.formatters.Logger.Logger()
num_children_vo = self.valobj.CreateChildAtOffset(
"count", self.sys_params.cfruntime_size, self.sys_params.types_cache.ulong)
return num_children_vo.GetValueAsUnsigned(0)
def num_children(self):
logger = lldb.formatters.Logger.Logger()
num_children_vo = self.valobj.CreateChildAtOffset("count",
self.sys_params.cfruntime_size,
self.sys_params.types_cache.ulong)
return num_children_vo.GetValueAsUnsigned(0)
class NSArrayI_SynthProvider: class NSArrayI_SynthProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, dict, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.long):
self.sys_params.types_cache.long = self.valobj.GetType().GetBasicType(lldb.eBasicTypeLong)
self.update()
def update(self): def __init__(self, valobj, dict, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not(self.sys_params.types_cache.long):
self.sys_params.types_cache.long = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeLong)
self.update()
def update(self):
logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture()
# skip the isa pointer and get at the size
def num_children(self):
logger = lldb.formatters.Logger.Logger()
count = self.valobj.CreateChildAtOffset(
"count",
self.sys_params.pointer_size,
self.sys_params.types_cache.long)
return count.GetValueAsUnsigned(0)
# skip the isa pointer and get at the size
def num_children(self):
logger = lldb.formatters.Logger.Logger()
count = self.valobj.CreateChildAtOffset("count",
self.sys_params.pointer_size,
self.sys_params.types_cache.long);
return count.GetValueAsUnsigned(0)
class NSArrayM_SynthProvider: class NSArrayM_SynthProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, dict, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.long):
self.sys_params.types_cache.long = self.valobj.GetType().GetBasicType(lldb.eBasicTypeLong)
self.update()
def update(self): def __init__(self, valobj, dict, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not(self.sys_params.types_cache.long):
self.sys_params.types_cache.long = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeLong)
self.update()
# skip the isa pointer and get at the size def update(self):
def num_children(self): logger = lldb.formatters.Logger.Logger()
logger = lldb.formatters.Logger.Logger() self.adjust_for_architecture()
count = self.valobj.CreateChildAtOffset("count",
self.sys_params.pointer_size, # skip the isa pointer and get at the size
self.sys_params.types_cache.long); def num_children(self):
return count.GetValueAsUnsigned(0) logger = lldb.formatters.Logger.Logger()
count = self.valobj.CreateChildAtOffset(
"count",
self.sys_params.pointer_size,
self.sys_params.types_cache.long)
return count.GetValueAsUnsigned(0)
# this is the actual synth provider, but is just a wrapper that checks # this is the actual synth provider, but is just a wrapper that checks
# whether valobj is an instance of __NSArrayI or __NSArrayM and sets up an # whether valobj is an instance of __NSArrayI or __NSArrayM and sets up an
# appropriate backend layer to do the computations # appropriate backend layer to do the computations
class NSArray_SynthProvider: class NSArray_SynthProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, dict): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.adjust_for_architecture()
self.error = False
self.wrapper = self.make_wrapper()
self.invalid = (self.wrapper == None)
def num_children(self): def __init__(self, valobj, dict):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
if self.wrapper == None: self.valobj = valobj
return 0; self.adjust_for_architecture()
return self.wrapper.num_children() self.error = False
self.wrapper = self.make_wrapper()
self.invalid = (self.wrapper is None)
def update(self): def num_children(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
if self.wrapper == None: if self.wrapper is None:
return return 0
self.wrapper.update() return self.wrapper.num_children()
# this code acts as our defense against NULL and uninitialized def update(self):
# NSArray pointers, which makes it much longer than it would be otherwise logger = lldb.formatters.Logger.Logger()
def make_wrapper(self): if self.wrapper is None:
logger = lldb.formatters.Logger.Logger() return
if self.valobj.GetValueAsUnsigned() == 0: self.wrapper.update()
self.error = True
return lldb.runtime.objc.objc_runtime.InvalidPointer_Description(True)
else:
global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(self.valobj,statistics)
if wrapper:
self.error = True
return wrapper
name_string = class_data.class_name()
logger >> "Class name is " + str(name_string)
if name_string == '__NSArrayI':
wrapper = NSArrayI_SynthProvider(self.valobj, dict, class_data.sys_params)
statistics.metric_hit('code_notrun',self.valobj.GetName())
elif name_string == '__NSArrayM':
wrapper = NSArrayM_SynthProvider(self.valobj, dict, class_data.sys_params)
statistics.metric_hit('code_notrun',self.valobj.GetName())
elif name_string == '__NSCFArray':
wrapper = NSArrayCF_SynthProvider(self.valobj, dict, class_data.sys_params)
statistics.metric_hit('code_notrun',self.valobj.GetName())
else:
wrapper = NSArrayKVC_SynthProvider(self.valobj, dict, class_data.sys_params)
statistics.metric_hit('unknown_class',str(self.valobj.GetName()) + " seen as " + name_string)
return wrapper;
def CFArray_SummaryProvider (valobj,dict): # this code acts as our defense against NULL and uninitialized
logger = lldb.formatters.Logger.Logger() # NSArray pointers, which makes it much longer than it would be otherwise
provider = NSArray_SynthProvider(valobj,dict); def make_wrapper(self):
if provider.invalid == False: logger = lldb.formatters.Logger.Logger()
if provider.error == True: if self.valobj.GetValueAsUnsigned() == 0:
return provider.wrapper.message() self.error = True
try: return lldb.runtime.objc.objc_runtime.InvalidPointer_Description(
summary = int(provider.num_children()); True)
except: else:
summary = None global statistics
logger >> "provider gave me " + str(summary) class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
if summary == None: self.valobj, statistics)
summary = '<variable is not NSArray>' if wrapper:
elif isinstance(summary,basestring): self.error = True
pass return wrapper
else:
# we format it like it were a CFString to make it look the same as the summary from Xcode
summary = '@"' + str(summary) + (" objects" if summary != 1 else " object") + '"'
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger,dict): name_string = class_data.class_name()
debugger.HandleCommand("type summary add -F CFArray.CFArray_SummaryProvider NSArray CFArrayRef CFMutableArrayRef")
logger >> "Class name is " + str(name_string)
if name_string == '__NSArrayI':
wrapper = NSArrayI_SynthProvider(
self.valobj, dict, class_data.sys_params)
statistics.metric_hit('code_notrun', self.valobj.GetName())
elif name_string == '__NSArrayM':
wrapper = NSArrayM_SynthProvider(
self.valobj, dict, class_data.sys_params)
statistics.metric_hit('code_notrun', self.valobj.GetName())
elif name_string == '__NSCFArray':
wrapper = NSArrayCF_SynthProvider(
self.valobj, dict, class_data.sys_params)
statistics.metric_hit('code_notrun', self.valobj.GetName())
else:
wrapper = NSArrayKVC_SynthProvider(
self.valobj, dict, class_data.sys_params)
statistics.metric_hit(
'unknown_class', str(
self.valobj.GetName()) + " seen as " + name_string)
return wrapper
def CFArray_SummaryProvider(valobj, dict):
logger = lldb.formatters.Logger.Logger()
provider = NSArray_SynthProvider(valobj, dict)
if not provider.invalid:
if provider.error:
return provider.wrapper.message()
try:
summary = int(provider.num_children())
except:
summary = None
logger >> "provider gave me " + str(summary)
if summary is None:
summary = '<variable is not NSArray>'
elif isinstance(summary, basestring):
pass
else:
# we format it like it were a CFString to make it look the same as
# the summary from Xcode
summary = '@"' + str(summary) + \
(" objects" if summary != 1 else " object") + '"'
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger, dict):
debugger.HandleCommand(
"type summary add -F CFArray.CFArray_SummaryProvider NSArray CFArrayRef CFMutableArrayRef")

View File

@ -22,125 +22,142 @@ statistics.add_metric('code_notrun')
# despite the similary to synthetic children providers, these classes are not # despite the similary to synthetic children providers, these classes are not
# trying to provide anything but the length for an CFBag, so they need not # trying to provide anything but the length for an CFBag, so they need not
# obey the interface specification for synthetic children providers # obey the interface specification for synthetic children providers
class CFBagRef_SummaryProvider: class CFBagRef_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update()
# 12 bytes on i386 def update(self):
# 20 bytes on x64 logger = lldb.formatters.Logger.Logger()
# most probably 2 pointers and 4 bytes of data self.adjust_for_architecture()
def offset(self):
logger = lldb.formatters.Logger.Logger()
if self.sys_params.is_64_bit:
return 20
else:
return 12
def length(self): # 12 bytes on i386
logger = lldb.formatters.Logger.Logger() # 20 bytes on x64
size = self.valobj.CreateChildAtOffset("count", # most probably 2 pointers and 4 bytes of data
self.offset(), def offset(self):
self.sys_params.types_cache.NSUInteger) logger = lldb.formatters.Logger.Logger()
return size.GetValueAsUnsigned(0) if self.sys_params.is_64_bit:
return 20
else:
return 12
def length(self):
logger = lldb.formatters.Logger.Logger()
size = self.valobj.CreateChildAtOffset(
"count", self.offset(), self.sys_params.types_cache.NSUInteger)
return size.GetValueAsUnsigned(0)
class CFBagUnknown_SummaryProvider: class CFBagUnknown_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
self.update()
def length(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream() self.adjust_for_architecture()
self.valobj.GetExpressionPath(stream)
num_children_vo = self.valobj.CreateValueFromExpression("count","(int)CFBagGetCount(" + stream.GetData() + " )") def length(self):
if num_children_vo.IsValid(): logger = lldb.formatters.Logger.Logger()
return num_children_vo.GetValueAsUnsigned(0) stream = lldb.SBStream()
return "<variable is not CFBag>" self.valobj.GetExpressionPath(stream)
num_children_vo = self.valobj.CreateValueFromExpression(
"count", "(int)CFBagGetCount(" + stream.GetData() + " )")
if num_children_vo.IsValid():
return num_children_vo.GetValueAsUnsigned(0)
return "<variable is not CFBag>"
def GetSummary_Impl(valobj): def GetSummary_Impl(valobj):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
global statistics global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics) class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
if wrapper: valobj, statistics)
return wrapper if wrapper:
return wrapper
name_string = class_data.class_name()
actual_name = name_string
logger >> "name string got was " + str(name_string) + " but actual name is " + str(actual_name)
if class_data.is_cftype():
# CFBag does not expose an actual NSWrapper type, so we have to check that this is
# an NSCFType and then check we are a pointer-to __CFBag
valobj_type = valobj.GetType()
if valobj_type.IsValid() and valobj_type.IsPointerType():
valobj_type = valobj_type.GetPointeeType()
if valobj_type.IsValid():
actual_name = valobj_type.GetName()
if actual_name == '__CFBag' or \
actual_name == 'const struct __CFBag':
wrapper = CFBagRef_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('code_notrun',valobj)
return wrapper
wrapper = CFBagUnknown_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + actual_name)
return wrapper;
def CFBag_SummaryProvider (valobj,dict): name_string = class_data.class_name()
logger = lldb.formatters.Logger.Logger() actual_name = name_string
provider = GetSummary_Impl(valobj);
if provider != None:
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.length();
except:
summary = None
logger >> "summary got from provider: " + str(summary)
# for some reason, one needs to clear some bits for the count
# to be correct when using CF(Mutable)BagRef on x64
# the bit mask was derived through experimentation
# (if counts start looking weird, then most probably
# the mask needs to be changed)
if summary == None:
summary = '<variable is not CFBag>'
elif isinstance(summary,basestring):
pass
else:
if provider.sys_params.is_64_bit:
summary = summary & ~0x1fff000000000000
if summary == 1:
summary = '@"1 value"'
else:
summary = '@"' + str(summary) + ' values"'
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger,dict): logger >> "name string got was " + \
debugger.HandleCommand("type summary add -F CFBag.CFBag_SummaryProvider CFBagRef CFMutableBagRef") str(name_string) + " but actual name is " + str(actual_name)
if class_data.is_cftype():
# CFBag does not expose an actual NSWrapper type, so we have to check that this is
# an NSCFType and then check we are a pointer-to __CFBag
valobj_type = valobj.GetType()
if valobj_type.IsValid() and valobj_type.IsPointerType():
valobj_type = valobj_type.GetPointeeType()
if valobj_type.IsValid():
actual_name = valobj_type.GetName()
if actual_name == '__CFBag' or \
actual_name == 'const struct __CFBag':
wrapper = CFBagRef_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('code_notrun', valobj)
return wrapper
wrapper = CFBagUnknown_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit(
'unknown_class',
valobj.GetName() +
" seen as " +
actual_name)
return wrapper
def CFBag_SummaryProvider(valobj, dict):
logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj)
if provider is not None:
if isinstance(
provider,
lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.length()
except:
summary = None
logger >> "summary got from provider: " + str(summary)
# for some reason, one needs to clear some bits for the count
# to be correct when using CF(Mutable)BagRef on x64
# the bit mask was derived through experimentation
# (if counts start looking weird, then most probably
# the mask needs to be changed)
if summary is None:
summary = '<variable is not CFBag>'
elif isinstance(summary, basestring):
pass
else:
if provider.sys_params.is_64_bit:
summary = summary & ~0x1fff000000000000
if summary == 1:
summary = '@"1 value"'
else:
summary = '@"' + str(summary) + ' values"'
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger, dict):
debugger.HandleCommand(
"type summary add -F CFBag.CFBag_SummaryProvider CFBagRef CFMutableBagRef")

View File

@ -22,121 +22,140 @@ statistics.add_metric('code_notrun')
# despite the similary to synthetic children providers, these classes are not # despite the similary to synthetic children providers, these classes are not
# trying to provide anything but the length for an CFBinaryHeap, so they need not # trying to provide anything but the length for an CFBinaryHeap, so they need not
# obey the interface specification for synthetic children providers # obey the interface specification for synthetic children providers
class CFBinaryHeapRef_SummaryProvider: class CFBinaryHeapRef_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update()
# 8 bytes on i386 def update(self):
# 16 bytes on x64 logger = lldb.formatters.Logger.Logger()
# most probably 2 pointers self.adjust_for_architecture()
def offset(self):
logger = lldb.formatters.Logger.Logger()
return 2 * self.sys_params.pointer_size
def length(self): # 8 bytes on i386
logger = lldb.formatters.Logger.Logger() # 16 bytes on x64
size = self.valobj.CreateChildAtOffset("count", # most probably 2 pointers
self.offset(), def offset(self):
self.sys_params.types_cache.NSUInteger) logger = lldb.formatters.Logger.Logger()
return size.GetValueAsUnsigned(0) return 2 * self.sys_params.pointer_size
def length(self):
logger = lldb.formatters.Logger.Logger()
size = self.valobj.CreateChildAtOffset(
"count", self.offset(), self.sys_params.types_cache.NSUInteger)
return size.GetValueAsUnsigned(0)
class CFBinaryHeapUnknown_SummaryProvider: class CFBinaryHeapUnknown_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
self.update()
def length(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream() self.adjust_for_architecture()
self.valobj.GetExpressionPath(stream)
num_children_vo = self.valobj.CreateValueFromExpression("count","(int)CFBinaryHeapGetCount(" + stream.GetData() + " )"); def length(self):
if num_children_vo.IsValid(): logger = lldb.formatters.Logger.Logger()
return num_children_vo.GetValueAsUnsigned(0) stream = lldb.SBStream()
return '<variable is not CFBinaryHeap>' self.valobj.GetExpressionPath(stream)
num_children_vo = self.valobj.CreateValueFromExpression(
"count", "(int)CFBinaryHeapGetCount(" + stream.GetData() + " )")
if num_children_vo.IsValid():
return num_children_vo.GetValueAsUnsigned(0)
return '<variable is not CFBinaryHeap>'
def GetSummary_Impl(valobj): def GetSummary_Impl(valobj):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
global statistics global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics) class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
if wrapper: valobj, statistics)
return wrapper if wrapper:
return wrapper
name_string = class_data.class_name()
actual_name = class_data.class_name()
logger >> "name string got was " + str(name_string) + " but actual name is " + str(actual_name)
if class_data.is_cftype():
# CFBinaryHeap does not expose an actual NSWrapper type, so we have to check that this is
# an NSCFType and then check we are a pointer-to CFBinaryHeap
valobj_type = valobj.GetType()
if valobj_type.IsValid() and valobj_type.IsPointerType():
valobj_type = valobj_type.GetPointeeType()
if valobj_type.IsValid():
actual_name = valobj_type.GetName()
if actual_name == '__CFBinaryHeap':
wrapper = CFBinaryHeapRef_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('code_notrun',valobj)
return wrapper
wrapper = CFBinaryHeapUnknown_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string)
return wrapper;
def CFBinaryHeap_SummaryProvider (valobj,dict): name_string = class_data.class_name()
logger = lldb.formatters.Logger.Logger() actual_name = class_data.class_name()
provider = GetSummary_Impl(valobj);
if provider != None:
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.length();
except:
summary = None
logger >> "summary got from provider: " + str(summary)
# for some reason, one needs to clear some bits for the count
# to be correct when using CF(Mutable)BagRef on x64
# the bit mask was derived through experimentation
# (if counts start looking weird, then most probably
# the mask needs to be changed)
if summary == None:
summary = '<variable is not CFBinaryHeap>'
elif isinstance(summary,basestring):
pass
else:
if provider.sys_params.is_64_bit:
summary = summary & ~0x1fff000000000000
if summary == 1:
return '@"1 item"'
else:
summary = '@"' + str(summary) + ' items"'
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger,dict): logger >> "name string got was " + \
debugger.HandleCommand("type summary add -F CFBinaryHeap.CFBinaryHeap_SummaryProvider CFBinaryHeapRef") str(name_string) + " but actual name is " + str(actual_name)
if class_data.is_cftype():
# CFBinaryHeap does not expose an actual NSWrapper type, so we have to check that this is
# an NSCFType and then check we are a pointer-to CFBinaryHeap
valobj_type = valobj.GetType()
if valobj_type.IsValid() and valobj_type.IsPointerType():
valobj_type = valobj_type.GetPointeeType()
if valobj_type.IsValid():
actual_name = valobj_type.GetName()
if actual_name == '__CFBinaryHeap':
wrapper = CFBinaryHeapRef_SummaryProvider(
valobj, class_data.sys_params)
statistics.metric_hit('code_notrun', valobj)
return wrapper
wrapper = CFBinaryHeapUnknown_SummaryProvider(
valobj, class_data.sys_params)
statistics.metric_hit(
'unknown_class',
valobj.GetName() +
" seen as " +
name_string)
return wrapper
def CFBinaryHeap_SummaryProvider(valobj, dict):
logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj)
if provider is not None:
if isinstance(
provider,
lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.length()
except:
summary = None
logger >> "summary got from provider: " + str(summary)
# for some reason, one needs to clear some bits for the count
# to be correct when using CF(Mutable)BagRef on x64
# the bit mask was derived through experimentation
# (if counts start looking weird, then most probably
# the mask needs to be changed)
if summary is None:
summary = '<variable is not CFBinaryHeap>'
elif isinstance(summary, basestring):
pass
else:
if provider.sys_params.is_64_bit:
summary = summary & ~0x1fff000000000000
if summary == 1:
return '@"1 item"'
else:
summary = '@"' + str(summary) + ' items"'
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger, dict):
debugger.HandleCommand(
"type summary add -F CFBinaryHeap.CFBinaryHeap_SummaryProvider CFBinaryHeapRef")

View File

@ -13,23 +13,28 @@ import lldb.formatters.metrics
import lldb.formatters.Logger import lldb.formatters.Logger
# first define some utility functions # first define some utility functions
def byte_index(abs_pos): def byte_index(abs_pos):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
return abs_pos/8 return abs_pos / 8
def bit_index(abs_pos): def bit_index(abs_pos):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
return abs_pos & 7 return abs_pos & 7
def get_bit(byte,index):
logger = lldb.formatters.Logger.Logger()
if index < 0 or index > 7:
return None
return (byte >> (7-index)) & 1
def grab_array_item_data(pointer,index): def get_bit(byte, index):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
return pointer.GetPointeeData(index,1) if index < 0 or index > 7:
return None
return (byte >> (7 - index)) & 1
def grab_array_item_data(pointer, index):
logger = lldb.formatters.Logger.Logger()
return pointer.GetPointeeData(index, 1)
statistics = lldb.formatters.metrics.Metrics() statistics = lldb.formatters.metrics.Metrics()
statistics.add_metric('invalid_isa') statistics.add_metric('invalid_isa')
@ -40,136 +45,162 @@ statistics.add_metric('code_notrun')
# despite the similary to synthetic children providers, these classes are not # despite the similary to synthetic children providers, these classes are not
# trying to provide anything but a summary for a CF*BitVector, so they need not # trying to provide anything but a summary for a CF*BitVector, so they need not
# obey the interface specification for synthetic children providers # obey the interface specification for synthetic children providers
class CFBitVectorKnown_SummaryProvider: class CFBitVectorKnown_SummaryProvider:
def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger()
self.uiint_size = self.sys_params.types_cache.NSUInteger.GetByteSize()
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.valobj = valobj; self.uiint_size = self.sys_params.types_cache.NSUInteger.GetByteSize()
self.sys_params = params pass
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
if not(self.sys_params.types_cache.charptr):
self.sys_params.types_cache.charptr = self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar).GetPointerType()
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedInt)
if not(self.sys_params.types_cache.charptr):
self.sys_params.types_cache.charptr = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeChar).GetPointerType()
self.update()
# we skip the CFRuntimeBase def update(self):
# then the next CFIndex is the count logger = lldb.formatters.Logger.Logger()
# then we skip another CFIndex and then we get at a byte array self.adjust_for_architecture()
# that wraps the individual bits
def contents(self): # we skip the CFRuntimeBase
logger = lldb.formatters.Logger.Logger() # then the next CFIndex is the count
count_vo = self.valobj.CreateChildAtOffset("count",self.sys_params.cfruntime_size, # then we skip another CFIndex and then we get at a byte array
self.sys_params.types_cache.NSUInteger) # that wraps the individual bits
count = count_vo.GetValueAsUnsigned(0)
if count == 0: def contents(self):
return '(empty)' logger = lldb.formatters.Logger.Logger()
count_vo = self.valobj.CreateChildAtOffset(
array_vo = self.valobj.CreateChildAtOffset("data", "count",
self.sys_params.cfruntime_size+2*self.uiint_size, self.sys_params.cfruntime_size,
self.sys_params.types_cache.charptr) self.sys_params.types_cache.NSUInteger)
count = count_vo.GetValueAsUnsigned(0)
data_list = [] if count == 0:
cur_byte_pos = None return '(empty)'
for i in range(0,count):
if cur_byte_pos == None: array_vo = self.valobj.CreateChildAtOffset(
cur_byte_pos = byte_index(i) "data",
cur_byte = grab_array_item_data(array_vo,cur_byte_pos) self.sys_params.cfruntime_size +
cur_byte_val = cur_byte.uint8[0] 2 *
else: self.uiint_size,
byte_pos = byte_index(i) self.sys_params.types_cache.charptr)
# do not fetch the pointee data every single time through
if byte_pos != cur_byte_pos: data_list = []
cur_byte_pos = byte_pos cur_byte_pos = None
cur_byte = grab_array_item_data(array_vo,cur_byte_pos) for i in range(0, count):
cur_byte_val = cur_byte.uint8[0] if cur_byte_pos is None:
bit = get_bit(cur_byte_val,bit_index(i)) cur_byte_pos = byte_index(i)
if (i % 4) == 0: cur_byte = grab_array_item_data(array_vo, cur_byte_pos)
data_list.append(' ') cur_byte_val = cur_byte.uint8[0]
if bit == 1: else:
data_list.append('1') byte_pos = byte_index(i)
else: # do not fetch the pointee data every single time through
data_list.append('0') if byte_pos != cur_byte_pos:
return ''.join(data_list) cur_byte_pos = byte_pos
cur_byte = grab_array_item_data(array_vo, cur_byte_pos)
cur_byte_val = cur_byte.uint8[0]
bit = get_bit(cur_byte_val, bit_index(i))
if (i % 4) == 0:
data_list.append(' ')
if bit == 1:
data_list.append('1')
else:
data_list.append('0')
return ''.join(data_list)
class CFBitVectorUnknown_SummaryProvider: class CFBitVectorUnknown_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
self.update()
def contents(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
return '<unable to summarize this CFBitVector>' self.adjust_for_architecture()
def contents(self):
logger = lldb.formatters.Logger.Logger()
return '<unable to summarize this CFBitVector>'
def GetSummary_Impl(valobj): def GetSummary_Impl(valobj):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
global statistics global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics) class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
if wrapper: valobj, statistics)
return wrapper if wrapper:
return wrapper
name_string = class_data.class_name() name_string = class_data.class_name()
actual_name = name_string actual_name = name_string
logger >> "name string got was " + str(name_string) + " but actual name is " + str(actual_name)
if class_data.is_cftype():
# CFBitVectorRef does not expose an actual NSWrapper type, so we have to check that this is
# an NSCFType and then check we are a pointer-to CFBitVectorRef
valobj_type = valobj.GetType()
if valobj_type.IsValid() and valobj_type.IsPointerType():
valobj_type = valobj_type.GetPointeeType()
if valobj_type.IsValid():
actual_name = valobj_type.GetName()
if actual_name == '__CFBitVector' or actual_name == '__CFMutableBitVector':
wrapper = CFBitVectorKnown_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('code_notrun',valobj)
else:
wrapper = CFBitVectorUnknown_SummaryProvider(valobj, class_data.sys_params)
print actual_name
else:
wrapper = CFBitVectorUnknown_SummaryProvider(valobj, class_data.sys_params)
print name_string
statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string)
return wrapper;
def CFBitVector_SummaryProvider (valobj,dict): logger >> "name string got was " + \
logger = lldb.formatters.Logger.Logger() str(name_string) + " but actual name is " + str(actual_name)
provider = GetSummary_Impl(valobj);
if provider != None:
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.contents();
except:
summary = None
logger >> "summary got from provider: " + str(summary)
if summary == None or summary == '':
summary = '<variable is not CFBitVector>'
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger,dict): if class_data.is_cftype():
debugger.HandleCommand("type summary add -F CFBitVector.CFBitVector_SummaryProvider CFBitVectorRef CFMutableBitVectorRef") # CFBitVectorRef does not expose an actual NSWrapper type, so we have to check that this is
# an NSCFType and then check we are a pointer-to CFBitVectorRef
valobj_type = valobj.GetType()
if valobj_type.IsValid() and valobj_type.IsPointerType():
valobj_type = valobj_type.GetPointeeType()
if valobj_type.IsValid():
actual_name = valobj_type.GetName()
if actual_name == '__CFBitVector' or actual_name == '__CFMutableBitVector':
wrapper = CFBitVectorKnown_SummaryProvider(
valobj, class_data.sys_params)
statistics.metric_hit('code_notrun', valobj)
else:
wrapper = CFBitVectorUnknown_SummaryProvider(
valobj, class_data.sys_params)
print actual_name
else:
wrapper = CFBitVectorUnknown_SummaryProvider(
valobj, class_data.sys_params)
print name_string
statistics.metric_hit(
'unknown_class',
valobj.GetName() +
" seen as " +
name_string)
return wrapper
def CFBitVector_SummaryProvider(valobj, dict):
logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj)
if provider is not None:
if isinstance(
provider,
lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.contents()
except:
summary = None
logger >> "summary got from provider: " + str(summary)
if summary is None or summary == '':
summary = '<variable is not CFBitVector>'
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger, dict):
debugger.HandleCommand(
"type summary add -F CFBitVector.CFBitVector_SummaryProvider CFBitVectorRef CFMutableBitVectorRef")

View File

@ -22,213 +22,242 @@ statistics.add_metric('code_notrun')
# despite the similary to synthetic children providers, these classes are not # despite the similary to synthetic children providers, these classes are not
# trying to provide anything but the count for an NSDictionary, so they need not # trying to provide anything but the count for an NSDictionary, so they need not
# obey the interface specification for synthetic children providers # obey the interface specification for synthetic children providers
class NSCFDictionary_SummaryProvider: class NSCFDictionary_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update()
# empirically determined on both 32 and 64bit desktop Mac OS X def update(self):
# probably boils down to 2 pointers and 4 bytes of data, but logger = lldb.formatters.Logger.Logger()
# the description of __CFDictionary is not readily available so most self.adjust_for_architecture()
# of this is guesswork, plain and simple
def offset(self):
logger = lldb.formatters.Logger.Logger()
if self.sys_params.is_64_bit:
return 20
else:
return 12
def num_children(self): # empirically determined on both 32 and 64bit desktop Mac OS X
logger = lldb.formatters.Logger.Logger() # probably boils down to 2 pointers and 4 bytes of data, but
num_children_vo = self.valobj.CreateChildAtOffset("count", # the description of __CFDictionary is not readily available so most
self.offset(), # of this is guesswork, plain and simple
self.sys_params.types_cache.NSUInteger) def offset(self):
return num_children_vo.GetValueAsUnsigned(0) logger = lldb.formatters.Logger.Logger()
if self.sys_params.is_64_bit:
return 20
else:
return 12
def num_children(self):
logger = lldb.formatters.Logger.Logger()
num_children_vo = self.valobj.CreateChildAtOffset(
"count", self.offset(), self.sys_params.types_cache.NSUInteger)
return num_children_vo.GetValueAsUnsigned(0)
class NSDictionaryI_SummaryProvider: class NSDictionaryI_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update()
# we just need to skip the ISA and the count immediately follows def update(self):
def offset(self): logger = lldb.formatters.Logger.Logger()
logger = lldb.formatters.Logger.Logger() self.adjust_for_architecture()
return self.sys_params.pointer_size
# we just need to skip the ISA and the count immediately follows
def offset(self):
logger = lldb.formatters.Logger.Logger()
return self.sys_params.pointer_size
def num_children(self):
logger = lldb.formatters.Logger.Logger()
num_children_vo = self.valobj.CreateChildAtOffset(
"count", self.offset(), self.sys_params.types_cache.NSUInteger)
value = num_children_vo.GetValueAsUnsigned(0)
if value is not None:
# the MS6bits on immutable dictionaries seem to be taken by the LSB of capacity
# not sure if it is a bug or some weird sort of feature, but masking that out
# gets the count right
if self.sys_params.is_64_bit:
value = value & ~0xFC00000000000000
else:
value = value & ~0xFC000000
return value
def num_children(self):
logger = lldb.formatters.Logger.Logger()
num_children_vo = self.valobj.CreateChildAtOffset("count",
self.offset(),
self.sys_params.types_cache.NSUInteger)
value = num_children_vo.GetValueAsUnsigned(0)
if value != None:
# the MS6bits on immutable dictionaries seem to be taken by the LSB of capacity
# not sure if it is a bug or some weird sort of feature, but masking that out
# gets the count right
if self.sys_params.is_64_bit:
value = value & ~0xFC00000000000000
else:
value = value & ~0xFC000000
return value
class NSDictionaryM_SummaryProvider: class NSDictionaryM_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update()
# we just need to skip the ISA and the count immediately follows def update(self):
def offset(self): logger = lldb.formatters.Logger.Logger()
return self.sys_params.pointer_size self.adjust_for_architecture()
# we just need to skip the ISA and the count immediately follows
def offset(self):
return self.sys_params.pointer_size
def num_children(self):
logger = lldb.formatters.Logger.Logger()
num_children_vo = self.valobj.CreateChildAtOffset(
"count", self.offset(), self.sys_params.types_cache.NSUInteger)
value = num_children_vo.GetValueAsUnsigned(0)
if value is not None:
# the MS6bits on immutable dictionaries seem to be taken by the LSB of capacity
# not sure if it is a bug or some weird sort of feature, but masking that out
# gets the count right
if self.sys_params.is_64_bit:
value = value & ~0xFC00000000000000
else:
value = value & ~0xFC000000
return value
def num_children(self):
logger = lldb.formatters.Logger.Logger()
num_children_vo = self.valobj.CreateChildAtOffset("count",
self.offset(),
self.sys_params.types_cache.NSUInteger)
value = num_children_vo.GetValueAsUnsigned(0)
if value != None:
# the MS6bits on immutable dictionaries seem to be taken by the LSB of capacity
# not sure if it is a bug or some weird sort of feature, but masking that out
# gets the count right
if self.sys_params.is_64_bit:
value = value & ~0xFC00000000000000
else:
value = value & ~0xFC000000
return value
class NSDictionaryUnknown_SummaryProvider: class NSDictionaryUnknown_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
self.update()
def num_children(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream() self.adjust_for_architecture()
self.valobj.GetExpressionPath(stream)
num_children_vo = self.valobj.CreateValueFromExpression("count","(int)[" + stream.GetData() + " count]"); def num_children(self):
if num_children_vo.IsValid(): logger = lldb.formatters.Logger.Logger()
return num_children_vo.GetValueAsUnsigned(0) stream = lldb.SBStream()
return '<variable is not NSDictionary>' self.valobj.GetExpressionPath(stream)
num_children_vo = self.valobj.CreateValueFromExpression(
"count", "(int)[" + stream.GetData() + " count]")
if num_children_vo.IsValid():
return num_children_vo.GetValueAsUnsigned(0)
return '<variable is not NSDictionary>'
def GetSummary_Impl(valobj): def GetSummary_Impl(valobj):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
global statistics global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics) class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
if wrapper: valobj, statistics)
return wrapper if wrapper:
return wrapper
name_string = class_data.class_name()
logger >> "class name is: " + str(name_string)
if name_string == '__NSCFDictionary':
wrapper = NSCFDictionary_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('code_notrun',valobj)
elif name_string == '__NSDictionaryI':
wrapper = NSDictionaryI_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('code_notrun',valobj)
elif name_string == '__NSDictionaryM':
wrapper = NSDictionaryM_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('code_notrun',valobj)
else:
wrapper = NSDictionaryUnknown_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string)
return wrapper;
def CFDictionary_SummaryProvider (valobj,dict): name_string = class_data.class_name()
logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj);
if provider != None:
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.num_children();
except:
summary = None
logger >> "got summary " + str(summary)
if summary == None:
return '<variable is not NSDictionary>'
if isinstance(summary,basestring):
return summary
return str(summary) + (" key/value pairs" if summary != 1 else " key/value pair")
return 'Summary Unavailable'
def CFDictionary_SummaryProvider2 (valobj,dict): logger >> "class name is: " + str(name_string)
logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj);
if provider != None:
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.num_children();
except:
summary = None
logger >> "got summary " + str(summary)
if summary == None:
summary = '<variable is not CFDictionary>'
if isinstance(summary,basestring):
return summary
else:
# needed on OSX Mountain Lion
if provider.sys_params.is_64_bit:
summary = summary & ~0x0f1f000000000000
summary = '@"' + str(summary) + (' entries"' if summary != 1 else ' entry"')
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger,dict): if name_string == '__NSCFDictionary':
debugger.HandleCommand("type summary add -F CFDictionary.CFDictionary_SummaryProvider NSDictionary") wrapper = NSCFDictionary_SummaryProvider(valobj, class_data.sys_params)
debugger.HandleCommand("type summary add -F CFDictionary.CFDictionary_SummaryProvider2 CFDictionaryRef CFMutableDictionaryRef") statistics.metric_hit('code_notrun', valobj)
elif name_string == '__NSDictionaryI':
wrapper = NSDictionaryI_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('code_notrun', valobj)
elif name_string == '__NSDictionaryM':
wrapper = NSDictionaryM_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('code_notrun', valobj)
else:
wrapper = NSDictionaryUnknown_SummaryProvider(
valobj, class_data.sys_params)
statistics.metric_hit(
'unknown_class',
valobj.GetName() +
" seen as " +
name_string)
return wrapper
def CFDictionary_SummaryProvider(valobj, dict):
logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj)
if provider is not None:
if isinstance(
provider,
lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.num_children()
except:
summary = None
logger >> "got summary " + str(summary)
if summary is None:
return '<variable is not NSDictionary>'
if isinstance(summary, basestring):
return summary
return str(summary) + (" key/value pairs" if summary !=
1 else " key/value pair")
return 'Summary Unavailable'
def CFDictionary_SummaryProvider2(valobj, dict):
logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj)
if provider is not None:
if isinstance(
provider,
lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.num_children()
except:
summary = None
logger >> "got summary " + str(summary)
if summary is None:
summary = '<variable is not CFDictionary>'
if isinstance(summary, basestring):
return summary
else:
# needed on OSX Mountain Lion
if provider.sys_params.is_64_bit:
summary = summary & ~0x0f1f000000000000
summary = '@"' + str(summary) + \
(' entries"' if summary != 1 else ' entry"')
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger, dict):
debugger.HandleCommand(
"type summary add -F CFDictionary.CFDictionary_SummaryProvider NSDictionary")
debugger.HandleCommand(
"type summary add -F CFDictionary.CFDictionary_SummaryProvider2 CFDictionaryRef CFMutableDictionaryRef")

View File

@ -11,315 +11,341 @@ import lldb
import lldb.runtime.objc.objc_runtime import lldb.runtime.objc.objc_runtime
import lldb.formatters.Logger import lldb.formatters.Logger
def CFString_SummaryProvider (valobj,dict):
logger = lldb.formatters.Logger.Logger()
provider = CFStringSynthProvider(valobj,dict);
if provider.invalid == False:
try:
summary = provider.get_child_at_index(provider.get_child_index("content"))
if type(summary) == lldb.SBValue:
summary = summary.GetSummary()
else:
summary = '"' + summary + '"'
except:
summary = None
if summary == None:
summary = '<variable is not NSString>'
return '@'+summary
return ''
def CFAttributedString_SummaryProvider (valobj,dict): def CFString_SummaryProvider(valobj, dict):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
offset = valobj.GetTarget().GetProcess().GetAddressByteSize() provider = CFStringSynthProvider(valobj, dict)
pointee = valobj.GetValueAsUnsigned(0) if not provider.invalid:
summary = '<variable is not NSAttributedString>' try:
if pointee != None and pointee != 0: summary = provider.get_child_at_index(
pointee = pointee + offset provider.get_child_index("content"))
child_ptr = valobj.CreateValueFromAddress("string_ptr",pointee,valobj.GetType()) if isinstance(summary, lldb.SBValue):
child = child_ptr.CreateValueFromAddress("string_data",child_ptr.GetValueAsUnsigned(),valobj.GetType()).AddressOf() summary = summary.GetSummary()
provider = CFStringSynthProvider(child,dict); else:
if provider.invalid == False: summary = '"' + summary + '"'
try: except:
summary = provider.get_child_at_index(provider.get_child_index("content")).GetSummary(); summary = None
except: if summary is None:
summary = '<variable is not NSAttributedString>' summary = '<variable is not NSString>'
if summary == None: return '@' + summary
summary = '<variable is not NSAttributedString>' return ''
return '@'+summary
def __lldb_init_module(debugger,dict): def CFAttributedString_SummaryProvider(valobj, dict):
debugger.HandleCommand("type summary add -F CFString.CFString_SummaryProvider NSString CFStringRef CFMutableStringRef") logger = lldb.formatters.Logger.Logger()
debugger.HandleCommand("type summary add -F CFString.CFAttributedString_SummaryProvider NSAttributedString") offset = valobj.GetTarget().GetProcess().GetAddressByteSize()
pointee = valobj.GetValueAsUnsigned(0)
summary = '<variable is not NSAttributedString>'
if pointee is not None and pointee != 0:
pointee = pointee + offset
child_ptr = valobj.CreateValueFromAddress(
"string_ptr", pointee, valobj.GetType())
child = child_ptr.CreateValueFromAddress(
"string_data",
child_ptr.GetValueAsUnsigned(),
valobj.GetType()).AddressOf()
provider = CFStringSynthProvider(child, dict)
if not provider.invalid:
try:
summary = provider.get_child_at_index(
provider.get_child_index("content")).GetSummary()
except:
summary = '<variable is not NSAttributedString>'
if summary is None:
summary = '<variable is not NSAttributedString>'
return '@' + summary
def __lldb_init_module(debugger, dict):
debugger.HandleCommand(
"type summary add -F CFString.CFString_SummaryProvider NSString CFStringRef CFMutableStringRef")
debugger.HandleCommand(
"type summary add -F CFString.CFAttributedString_SummaryProvider NSAttributedString")
class CFStringSynthProvider: class CFStringSynthProvider:
def __init__(self,valobj,dict):
logger = lldb.formatters.Logger.Logger()
self.valobj = valobj;
self.update()
# children other than "content" are for debugging only and must not be used in production code def __init__(self, valobj, dict):
def num_children(self): logger = lldb.formatters.Logger.Logger()
logger = lldb.formatters.Logger.Logger() self.valobj = valobj
if self.invalid: self.update()
return 0;
return 6;
def read_unicode(self, pointer,max_len=2048): # children other than "content" are for debugging only and must not be
logger = lldb.formatters.Logger.Logger() # used in production code
process = self.valobj.GetTarget().GetProcess() def num_children(self):
error = lldb.SBError() logger = lldb.formatters.Logger.Logger()
pystr = u'' if self.invalid:
# cannot do the read at once because the length value has return 0
# a weird encoding. better play it safe here return 6
while max_len > 0:
content = process.ReadMemory(pointer, 2, error)
new_bytes = bytearray(content)
b0 = new_bytes[0]
b1 = new_bytes[1]
pointer = pointer + 2
if b0 == 0 and b1 == 0:
break
# rearrange bytes depending on endianness
# (do we really need this or is Cocoa going to
# use Windows-compatible little-endian even
# if the target is big endian?)
if self.is_little:
value = b1 * 256 + b0
else:
value = b0 * 256 + b1
pystr = pystr + unichr(value)
# read max_len unicode values, not max_len bytes
max_len = max_len - 1
return pystr
# handle the special case strings def read_unicode(self, pointer, max_len=2048):
# only use the custom code for the tested LP64 case logger = lldb.formatters.Logger.Logger()
def handle_special(self): process = self.valobj.GetTarget().GetProcess()
logger = lldb.formatters.Logger.Logger() error = lldb.SBError()
if self.is_64_bit == False: pystr = u''
# for 32bit targets, use safe ObjC code # cannot do the read at once because the length value has
return self.handle_unicode_string_safe() # a weird encoding. better play it safe here
offset = 12 while max_len > 0:
pointer = self.valobj.GetValueAsUnsigned(0) + offset content = process.ReadMemory(pointer, 2, error)
pystr = self.read_unicode(pointer) new_bytes = bytearray(content)
return self.valobj.CreateValueFromExpression("content", b0 = new_bytes[0]
"(char*)\"" + pystr.encode('utf-8') + "\"") b1 = new_bytes[1]
pointer = pointer + 2
if b0 == 0 and b1 == 0:
break
# rearrange bytes depending on endianness
# (do we really need this or is Cocoa going to
# use Windows-compatible little-endian even
# if the target is big endian?)
if self.is_little:
value = b1 * 256 + b0
else:
value = b0 * 256 + b1
pystr = pystr + unichr(value)
# read max_len unicode values, not max_len bytes
max_len = max_len - 1
return pystr
# last resort call, use ObjC code to read; the final aim is to # handle the special case strings
# be able to strip this call away entirely and only do the read # only use the custom code for the tested LP64 case
# ourselves def handle_special(self):
def handle_unicode_string_safe(self): logger = lldb.formatters.Logger.Logger()
return self.valobj.CreateValueFromExpression("content", if not self.is_64_bit:
"(char*)\"" + self.valobj.GetObjectDescription() + "\""); # for 32bit targets, use safe ObjC code
return self.handle_unicode_string_safe()
offset = 12
pointer = self.valobj.GetValueAsUnsigned(0) + offset
pystr = self.read_unicode(pointer)
return self.valobj.CreateValueFromExpression(
"content", "(char*)\"" + pystr.encode('utf-8') + "\"")
def handle_unicode_string(self): # last resort call, use ObjC code to read; the final aim is to
logger = lldb.formatters.Logger.Logger() # be able to strip this call away entirely and only do the read
# step 1: find offset # ourselves
if self.inline: def handle_unicode_string_safe(self):
pointer = self.valobj.GetValueAsUnsigned(0) + self.size_of_cfruntime_base(); return self.valobj.CreateValueFromExpression(
if self.explicit == False: "content", "(char*)\"" + self.valobj.GetObjectDescription() + "\"")
# untested, use the safe code path
return self.handle_unicode_string_safe();
else:
# a full pointer is skipped here before getting to the live data
pointer = pointer + self.pointer_size
else:
pointer = self.valobj.GetValueAsUnsigned(0) + self.size_of_cfruntime_base()
# read 8 bytes here and make an address out of them
try:
char_type = self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar).GetPointerType()
vopointer = self.valobj.CreateValueFromAddress("dummy",pointer,char_type);
pointer = vopointer.GetValueAsUnsigned(0)
except:
return self.valobj.CreateValueFromExpression("content",
'(char*)"@\"invalid NSString\""')
# step 2: read Unicode data at pointer
pystr = self.read_unicode(pointer)
# step 3: return it
return pystr.encode('utf-8')
def handle_inline_explicit(self): def handle_unicode_string(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
offset = 3*self.pointer_size # step 1: find offset
offset = offset + self.valobj.GetValueAsUnsigned(0) if self.inline:
return self.valobj.CreateValueFromExpression("content", pointer = self.valobj.GetValueAsUnsigned(
"(char*)(" + str(offset) + ")") 0) + self.size_of_cfruntime_base()
if not self.explicit:
# untested, use the safe code path
return self.handle_unicode_string_safe()
else:
# a full pointer is skipped here before getting to the live
# data
pointer = pointer + self.pointer_size
else:
pointer = self.valobj.GetValueAsUnsigned(
0) + self.size_of_cfruntime_base()
# read 8 bytes here and make an address out of them
try:
char_type = self.valobj.GetType().GetBasicType(
lldb.eBasicTypeChar).GetPointerType()
vopointer = self.valobj.CreateValueFromAddress(
"dummy", pointer, char_type)
pointer = vopointer.GetValueAsUnsigned(0)
except:
return self.valobj.CreateValueFromExpression(
"content", '(char*)"@\"invalid NSString\""')
# step 2: read Unicode data at pointer
pystr = self.read_unicode(pointer)
# step 3: return it
return pystr.encode('utf-8')
def handle_mutable_string(self): def handle_inline_explicit(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
offset = 2 * self.pointer_size offset = 3 * self.pointer_size
data = self.valobj.CreateChildAtOffset("content", offset = offset + self.valobj.GetValueAsUnsigned(0)
offset, self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar).GetPointerType()); return self.valobj.CreateValueFromExpression(
data_value = data.GetValueAsUnsigned(0) "content", "(char*)(" + str(offset) + ")")
if self.explicit and self.unicode:
return self.read_unicode(data_value).encode('utf-8')
else:
data_value = data_value + 1
return self.valobj.CreateValueFromExpression("content", "(char*)(" + str(data_value) + ")")
def handle_UTF8_inline(self): def handle_mutable_string(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
offset = self.valobj.GetValueAsUnsigned(0) + self.size_of_cfruntime_base(); offset = 2 * self.pointer_size
if self.explicit == False: data = self.valobj.CreateChildAtOffset(
offset = offset + 1; "content", offset, self.valobj.GetType().GetBasicType(
return self.valobj.CreateValueFromAddress("content", lldb.eBasicTypeChar).GetPointerType())
offset, self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar)).AddressOf(); data_value = data.GetValueAsUnsigned(0)
if self.explicit and self.unicode:
return self.read_unicode(data_value).encode('utf-8')
else:
data_value = data_value + 1
return self.valobj.CreateValueFromExpression(
"content", "(char*)(" + str(data_value) + ")")
def handle_UTF8_not_inline(self): def handle_UTF8_inline(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
offset = self.size_of_cfruntime_base(); offset = self.valobj.GetValueAsUnsigned(
return self.valobj.CreateChildAtOffset("content", 0) + self.size_of_cfruntime_base()
offset,self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar).GetPointerType()); if not self.explicit:
offset = offset + 1
return self.valobj.CreateValueFromAddress(
"content", offset, self.valobj.GetType().GetBasicType(
lldb.eBasicTypeChar)).AddressOf()
def get_child_at_index(self,index): def handle_UTF8_not_inline(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
logger >> "Querying for child [" + str(index) + "]" offset = self.size_of_cfruntime_base()
if index == 0: return self.valobj.CreateChildAtOffset(
return self.valobj.CreateValueFromExpression("mutable", "content", offset, self.valobj.GetType().GetBasicType(
str(int(self.mutable))); lldb.eBasicTypeChar).GetPointerType())
if index == 1:
return self.valobj.CreateValueFromExpression("inline",
str(int(self.inline)));
if index == 2:
return self.valobj.CreateValueFromExpression("explicit",
str(int(self.explicit)));
if index == 3:
return self.valobj.CreateValueFromExpression("unicode",
str(int(self.unicode)));
if index == 4:
return self.valobj.CreateValueFromExpression("special",
str(int(self.special)));
if index == 5:
# we are handling the several possible combinations of flags.
# for each known combination we have a function that knows how to
# go fetch the data from memory instead of running code. if a string is not
# correctly displayed, one should start by finding a combination of flags that
# makes it different from these known cases, and provide a new reader function
# if this is not possible, a new flag might have to be made up (like the "special" flag
# below, which is not a real flag in CFString), or alternatively one might need to use
# the ObjC runtime helper to detect the new class and deal with it accordingly
#print 'mutable = ' + str(self.mutable)
#print 'inline = ' + str(self.inline)
#print 'explicit = ' + str(self.explicit)
#print 'unicode = ' + str(self.unicode)
#print 'special = ' + str(self.special)
if self.mutable == True:
return self.handle_mutable_string()
elif self.inline == True and self.explicit == True and \
self.unicode == False and self.special == False and \
self.mutable == False:
return self.handle_inline_explicit()
elif self.unicode == True:
return self.handle_unicode_string();
elif self.special == True:
return self.handle_special();
elif self.inline == True:
return self.handle_UTF8_inline();
else:
return self.handle_UTF8_not_inline();
def get_child_index(self,name): def get_child_at_index(self, index):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
logger >> "Querying for child ['" + str(name) + "']" logger >> "Querying for child [" + str(index) + "]"
if name == "content": if index == 0:
return self.num_children() - 1; return self.valobj.CreateValueFromExpression(
if name == "mutable": "mutable", str(int(self.mutable)))
return 0; if index == 1:
if name == "inline": return self.valobj.CreateValueFromExpression("inline",
return 1; str(int(self.inline)))
if name == "explicit": if index == 2:
return 2; return self.valobj.CreateValueFromExpression(
if name == "unicode": "explicit", str(int(self.explicit)))
return 3; if index == 3:
if name == "special": return self.valobj.CreateValueFromExpression(
return 4; "unicode", str(int(self.unicode)))
if index == 4:
return self.valobj.CreateValueFromExpression(
"special", str(int(self.special)))
if index == 5:
# we are handling the several possible combinations of flags.
# for each known combination we have a function that knows how to
# go fetch the data from memory instead of running code. if a string is not
# correctly displayed, one should start by finding a combination of flags that
# makes it different from these known cases, and provide a new reader function
# if this is not possible, a new flag might have to be made up (like the "special" flag
# below, which is not a real flag in CFString), or alternatively one might need to use
# the ObjC runtime helper to detect the new class and deal with it accordingly
# print 'mutable = ' + str(self.mutable)
# print 'inline = ' + str(self.inline)
# print 'explicit = ' + str(self.explicit)
# print 'unicode = ' + str(self.unicode)
# print 'special = ' + str(self.special)
if self.mutable:
return self.handle_mutable_string()
elif self.inline and self.explicit and \
self.unicode == False and self.special == False and \
self.mutable == False:
return self.handle_inline_explicit()
elif self.unicode:
return self.handle_unicode_string()
elif self.special:
return self.handle_special()
elif self.inline:
return self.handle_UTF8_inline()
else:
return self.handle_UTF8_not_inline()
# CFRuntimeBase is defined as having an additional def get_child_index(self, name):
# 4 bytes (padding?) on LP64 architectures logger = lldb.formatters.Logger.Logger()
# to get its size we add up sizeof(pointer)+4 logger >> "Querying for child ['" + str(name) + "']"
# and then add 4 more bytes if we are on a 64bit system if name == "content":
def size_of_cfruntime_base(self): return self.num_children() - 1
logger = lldb.formatters.Logger.Logger() if name == "mutable":
return self.pointer_size+4+(4 if self.is_64_bit else 0) return 0
if name == "inline":
return 1
if name == "explicit":
return 2
if name == "unicode":
return 3
if name == "special":
return 4
# the info bits are part of the CFRuntimeBase structure # CFRuntimeBase is defined as having an additional
# to get at them we have to skip a uintptr_t and then get # 4 bytes (padding?) on LP64 architectures
# at the least-significant byte of a 4 byte array. If we are # to get its size we add up sizeof(pointer)+4
# on big-endian this means going to byte 3, if we are on # and then add 4 more bytes if we are on a 64bit system
# little endian (OSX & iOS), this means reading byte 0 def size_of_cfruntime_base(self):
def offset_of_info_bits(self): logger = lldb.formatters.Logger.Logger()
logger = lldb.formatters.Logger.Logger() return self.pointer_size + 4 + (4 if self.is_64_bit else 0)
offset = self.pointer_size
if self.is_little == False:
offset = offset + 3;
return offset;
def read_info_bits(self): # the info bits are part of the CFRuntimeBase structure
logger = lldb.formatters.Logger.Logger() # to get at them we have to skip a uintptr_t and then get
cfinfo = self.valobj.CreateChildAtOffset("cfinfo", # at the least-significant byte of a 4 byte array. If we are
self.offset_of_info_bits(), # on big-endian this means going to byte 3, if we are on
self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar)); # little endian (OSX & iOS), this means reading byte 0
cfinfo.SetFormat(11) def offset_of_info_bits(self):
info = cfinfo.GetValue(); logger = lldb.formatters.Logger.Logger()
if info != None: offset = self.pointer_size
self.invalid = False; if not self.is_little:
return int(info,0); offset = offset + 3
else: return offset
self.invalid = True;
return None;
# calculating internal flag bits of the CFString object def read_info_bits(self):
# this stuff is defined and discussed in CFString.c logger = lldb.formatters.Logger.Logger()
def is_mutable(self): cfinfo = self.valobj.CreateChildAtOffset(
logger = lldb.formatters.Logger.Logger() "cfinfo",
return (self.info_bits & 1) == 1; self.offset_of_info_bits(),
self.valobj.GetType().GetBasicType(
lldb.eBasicTypeChar))
cfinfo.SetFormat(11)
info = cfinfo.GetValue()
if info is not None:
self.invalid = False
return int(info, 0)
else:
self.invalid = True
return None
def is_inline(self): # calculating internal flag bits of the CFString object
logger = lldb.formatters.Logger.Logger() # this stuff is defined and discussed in CFString.c
return (self.info_bits & 0x60) == 0; def is_mutable(self):
logger = lldb.formatters.Logger.Logger()
return (self.info_bits & 1) == 1
# this flag's name is ambiguous, it turns out def is_inline(self):
# we must skip a length byte to get at the data logger = lldb.formatters.Logger.Logger()
# when this flag is False return (self.info_bits & 0x60) == 0
def has_explicit_length(self):
logger = lldb.formatters.Logger.Logger()
return (self.info_bits & (1 | 4)) != 4;
# probably a subclass of NSString. obtained this from [str pathExtension] # this flag's name is ambiguous, it turns out
# here info_bits = 0 and Unicode data at the start of the padding word # we must skip a length byte to get at the data
# in the long run using the isa value might be safer as a way to identify this # when this flag is False
# instead of reading the info_bits def has_explicit_length(self):
def is_special_case(self): logger = lldb.formatters.Logger.Logger()
logger = lldb.formatters.Logger.Logger() return (self.info_bits & (1 | 4)) != 4
return self.info_bits == 0;
def is_unicode(self): # probably a subclass of NSString. obtained this from [str pathExtension]
logger = lldb.formatters.Logger.Logger() # here info_bits = 0 and Unicode data at the start of the padding word
return (self.info_bits & 0x10) == 0x10; # in the long run using the isa value might be safer as a way to identify this
# instead of reading the info_bits
def is_special_case(self):
logger = lldb.formatters.Logger.Logger()
return self.info_bits == 0
# preparing ourselves to read into memory def is_unicode(self):
# by adjusting architecture-specific info logger = lldb.formatters.Logger.Logger()
def adjust_for_architecture(self): return (self.info_bits & 0x10) == 0x10
logger = lldb.formatters.Logger.Logger()
self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize()
self.is_64_bit = self.pointer_size == 8
self.is_little = self.valobj.GetTarget().GetProcess().GetByteOrder() == lldb.eByteOrderLittle
# reading info bits out of the CFString and computing # preparing ourselves to read into memory
# useful values to get at the real data # by adjusting architecture-specific info
def compute_flags(self): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.info_bits = self.read_info_bits(); self.pointer_size = self.valobj.GetTarget().GetProcess().GetAddressByteSize()
if self.info_bits == None: self.is_64_bit = self.pointer_size == 8
return; self.is_little = self.valobj.GetTarget().GetProcess(
self.mutable = self.is_mutable(); ).GetByteOrder() == lldb.eByteOrderLittle
self.inline = self.is_inline();
self.explicit = self.has_explicit_length();
self.unicode = self.is_unicode();
self.special = self.is_special_case();
def update(self): # reading info bits out of the CFString and computing
logger = lldb.formatters.Logger.Logger() # useful values to get at the real data
self.adjust_for_architecture(); def compute_flags(self):
self.compute_flags(); logger = lldb.formatters.Logger.Logger()
self.info_bits = self.read_info_bits()
if self.info_bits is None:
return
self.mutable = self.is_mutable()
self.inline = self.is_inline()
self.explicit = self.has_explicit_length()
self.unicode = self.is_unicode()
self.special = self.is_special_case()
def update(self):
logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture()
self.compute_flags()

View File

@ -9,13 +9,14 @@ import lldb
import lldb.runtime.objc.objc_runtime import lldb.runtime.objc.objc_runtime
import lldb.formatters.Logger import lldb.formatters.Logger
def Class_Summary(valobj,dict):
logger = lldb.formatters.Logger.Logger()
runtime =lldb.runtime.objc.objc_runtime.ObjCRuntime.runtime_from_isa(valobj)
if runtime == None or not runtime.is_valid():
return '<error: unknown Class>'
class_data = runtime.read_class_data()
if class_data == None or not class_data.is_valid():
return '<error: unknown Class>'
return class_data.class_name()
def Class_Summary(valobj, dict):
logger = lldb.formatters.Logger.Logger()
runtime = lldb.runtime.objc.objc_runtime.ObjCRuntime.runtime_from_isa(
valobj)
if runtime is None or not runtime.is_valid():
return '<error: unknown Class>'
class_data = runtime.read_class_data()
if class_data is None or not class_data.is_valid():
return '<error: unknown Class>'
return class_data.class_name()

View File

@ -3,120 +3,131 @@ import sys
import os.path import os.path
import inspect import inspect
class NopLogger: class NopLogger:
def __init__(self):
pass
def write(self,data): def __init__(self):
pass pass
def flush(self): def write(self, data):
pass pass
def close(self): def flush(self):
pass pass
def close(self):
pass
class StdoutLogger: class StdoutLogger:
def __init__(self):
pass
def write(self,data): def __init__(self):
print(data) pass
def flush(self): def write(self, data):
pass print(data)
def flush(self):
pass
def close(self):
pass
def close(self):
pass
class FileLogger: class FileLogger:
def __init__(self, name):
self.file = None
try:
name = os.path.abspath(name)
self.file = open(name,'a')
except:
try:
self.file = open('formatters.log','a')
except:
pass
def write(self,data): def __init__(self, name):
if self.file != None: self.file = None
print(data,file=self.file) try:
else: name = os.path.abspath(name)
print(data) self.file = open(name, 'a')
except:
try:
self.file = open('formatters.log', 'a')
except:
pass
def flush(self): def write(self, data):
if self.file != None: if self.file is not None:
self.file.flush() print(data, file=self.file)
else:
print(data)
def close(self): def flush(self):
if self.file != None: if self.file is not None:
self.file.close() self.file.flush()
self.file = None
def close(self):
if self.file is not None:
self.file.close()
self.file = None
# to enable logging: # to enable logging:
# define lldb.formatters.Logger._lldb_formatters_debug_level to any number greater than 0 # define lldb.formatters.Logger._lldb_formatters_debug_level to any number greater than 0
# if you define it to any value greater than 1, the log will be automatically flushed after each write (slower but should make sure most of the stuff makes it to the log even if we crash) # if you define it to any value greater than 1, the log will be automatically flushed after each write (slower but should make sure most of the stuff makes it to the log even if we crash)
# if you define it to any value greater than 2, the calling function's details will automatically be logged (even slower, but provides additional details) # if you define it to any value greater than 2, the calling function's details will automatically be logged (even slower, but provides additional details)
# if you need the log to go to a file instead of on screen, define lldb.formatters.Logger._lldb_formatters_debug_filename to a valid filename # if you need the log to go to a file instead of on screen, define
# lldb.formatters.Logger._lldb_formatters_debug_filename to a valid
# filename
class Logger: class Logger:
def __init__(self,autoflush=False,logcaller=False):
global _lldb_formatters_debug_level
global _lldb_formatters_debug_filename
self.autoflush = autoflush
want_log = False
try:
want_log = (_lldb_formatters_debug_level > 0)
except:
pass
if not (want_log):
self.impl = NopLogger()
return
want_file = False
try:
want_file = (_lldb_formatters_debug_filename != None and _lldb_formatters_debug_filename != '' and _lldb_formatters_debug_filename != 0)
except:
pass
if want_file:
self.impl = FileLogger(_lldb_formatters_debug_filename)
else:
self.impl = StdoutLogger()
try:
self.autoflush = (_lldb_formatters_debug_level > 1)
except:
self.autoflush = autoflush
want_caller_info = False
try:
want_caller_info = (_lldb_formatters_debug_level > 2)
except:
pass
if want_caller_info:
self._log_caller()
def _log_caller(self): def __init__(self, autoflush=False, logcaller=False):
caller = inspect.stack()[2] global _lldb_formatters_debug_level
try: global _lldb_formatters_debug_filename
if caller != None and len(caller) > 3: self.autoflush = autoflush
self.write('Logging from function ' + str(caller)) want_log = False
else: try:
self.write('Caller info not available - Required caller logging not possible') want_log = (_lldb_formatters_debug_level > 0)
finally: except:
del caller # needed per Python docs to avoid keeping objects alive longer than we care pass
if not (want_log):
self.impl = NopLogger()
return
want_file = False
try:
want_file = (_lldb_formatters_debug_filename is not None and _lldb_formatters_debug_filename !=
'' and _lldb_formatters_debug_filename != 0)
except:
pass
if want_file:
self.impl = FileLogger(_lldb_formatters_debug_filename)
else:
self.impl = StdoutLogger()
try:
self.autoflush = (_lldb_formatters_debug_level > 1)
except:
self.autoflush = autoflush
want_caller_info = False
try:
want_caller_info = (_lldb_formatters_debug_level > 2)
except:
pass
if want_caller_info:
self._log_caller()
def write(self,data): def _log_caller(self):
self.impl.write(data) caller = inspect.stack()[2]
if self.autoflush: try:
self.flush() if caller is not None and len(caller) > 3:
self.write('Logging from function ' + str(caller))
else:
self.write(
'Caller info not available - Required caller logging not possible')
finally:
del caller # needed per Python docs to avoid keeping objects alive longer than we care
def __rshift__(self,data): def write(self, data):
self.write(data) self.impl.write(data)
if self.autoflush:
self.flush()
def flush(self): def __rshift__(self, data):
self.impl.flush() self.write(data)
def close(self): def flush(self):
self.impl.close() self.impl.flush()
def close(self):
self.impl.close()

View File

@ -23,105 +23,123 @@ statistics.add_metric('code_notrun')
# despite the similary to synthetic children providers, these classes are not # despite the similary to synthetic children providers, these classes are not
# trying to provide anything but a summary for an NSURL, so they need not # trying to provide anything but a summary for an NSURL, so they need not
# obey the interface specification for synthetic children providers # obey the interface specification for synthetic children providers
class NSBundleKnown_SummaryProvider: class NSBundleKnown_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.NSString):
self.sys_params.types_cache.NSString = self.valobj.GetTarget().FindFirstType('NSString').GetPointerType()
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not(self.sys_params.types_cache.NSString):
self.sys_params.types_cache.NSString = self.valobj.GetTarget(
).FindFirstType('NSString').GetPointerType()
self.update()
# we need to skip the ISA, plus four other values def update(self):
# that are luckily each a pointer in size logger = lldb.formatters.Logger.Logger()
# which makes our computation trivial :-) self.adjust_for_architecture()
def offset(self):
logger = lldb.formatters.Logger.Logger()
return 5 * self.sys_params.pointer_size
def url_text(self): # we need to skip the ISA, plus four other values
logger = lldb.formatters.Logger.Logger() # that are luckily each a pointer in size
global statistics # which makes our computation trivial :-)
text = self.valobj.CreateChildAtOffset("text", def offset(self):
self.offset(), logger = lldb.formatters.Logger.Logger()
self.sys_params.types_cache.NSString) return 5 * self.sys_params.pointer_size
my_string = text.GetSummary()
if (my_string == None) or (my_string == ''): def url_text(self):
statistics.metric_hit('unknown_class',str(self.valobj.GetName()) + " triggered unknown pointer location") logger = lldb.formatters.Logger.Logger()
return NSBundleUnknown_SummaryProvider(self.valobj, self.sys_params).url_text() global statistics
else: text = self.valobj.CreateChildAtOffset(
statistics.metric_hit('code_notrun',self.valobj) "text", self.offset(), self.sys_params.types_cache.NSString)
return my_string my_string = text.GetSummary()
if (my_string is None) or (my_string == ''):
statistics.metric_hit(
'unknown_class', str(
self.valobj.GetName()) + " triggered unknown pointer location")
return NSBundleUnknown_SummaryProvider(
self.valobj, self.sys_params).url_text()
else:
statistics.metric_hit('code_notrun', self.valobj)
return my_string
class NSBundleUnknown_SummaryProvider: class NSBundleUnknown_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
self.update()
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
self.update()
def url_text(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream() self.adjust_for_architecture()
self.valobj.GetExpressionPath(stream)
expr = "(NSString*)[" + stream.GetData() + " bundlePath]" def url_text(self):
url_text_vo = self.valobj.CreateValueFromExpression("path",expr); logger = lldb.formatters.Logger.Logger()
if url_text_vo.IsValid(): stream = lldb.SBStream()
return url_text_vo.GetSummary() self.valobj.GetExpressionPath(stream)
return '<variable is not NSBundle>' expr = "(NSString*)[" + stream.GetData() + " bundlePath]"
url_text_vo = self.valobj.CreateValueFromExpression("path", expr)
if url_text_vo.IsValid():
return url_text_vo.GetSummary()
return '<variable is not NSBundle>'
def GetSummary_Impl(valobj): def GetSummary_Impl(valobj):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
global statistics global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics) class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
if wrapper: valobj, statistics)
return wrapper if wrapper:
return wrapper
name_string = class_data.class_name()
logger >> "class name is: " + str(name_string)
if name_string == 'NSBundle':
wrapper = NSBundleKnown_SummaryProvider(valobj, class_data.sys_params)
# [NSBundle mainBundle] does return an object that is
# not correctly filled out for our purposes, so we still
# end up having to run code in that case
#statistics.metric_hit('code_notrun',valobj)
else:
wrapper = NSBundleUnknown_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string)
return wrapper;
def NSBundle_SummaryProvider (valobj,dict): name_string = class_data.class_name()
logger = lldb.formatters.Logger.Logger() logger >> "class name is: " + str(name_string)
provider = GetSummary_Impl(valobj);
if provider != None:
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.url_text();
except:
summary = None
logger >> "got summary " + str(summary)
if summary == None or summary == '':
summary = '<variable is not NSBundle>'
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger,dict): if name_string == 'NSBundle':
debugger.HandleCommand("type summary add -F NSBundle.NSBundle_SummaryProvider NSBundle") wrapper = NSBundleKnown_SummaryProvider(valobj, class_data.sys_params)
# [NSBundle mainBundle] does return an object that is
# not correctly filled out for our purposes, so we still
# end up having to run code in that case
# statistics.metric_hit('code_notrun',valobj)
else:
wrapper = NSBundleUnknown_SummaryProvider(
valobj, class_data.sys_params)
statistics.metric_hit(
'unknown_class',
valobj.GetName() +
" seen as " +
name_string)
return wrapper
def NSBundle_SummaryProvider(valobj, dict):
logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj)
if provider is not None:
if isinstance(
provider,
lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.url_text()
except:
summary = None
logger >> "got summary " + str(summary)
if summary is None or summary == '':
summary = '<variable is not NSBundle>'
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger, dict):
debugger.HandleCommand(
"type summary add -F NSBundle.NSBundle_SummaryProvider NSBundle")

View File

@ -22,142 +22,161 @@ statistics.add_metric('code_notrun')
# despite the similary to synthetic children providers, these classes are not # despite the similary to synthetic children providers, these classes are not
# trying to provide anything but the length for an NSData, so they need not # trying to provide anything but the length for an NSData, so they need not
# obey the interface specification for synthetic children providers # obey the interface specification for synthetic children providers
class NSConcreteData_SummaryProvider: class NSConcreteData_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
logger >> "NSConcreteData_SummaryProvider __init__"
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update();
def update(self): def __init__(self, valobj, params):
self.adjust_for_architecture(); logger = lldb.formatters.Logger.Logger()
logger >> "NSConcreteData_SummaryProvider __init__"
self.valobj = valobj
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update()
# one pointer is the ISA def update(self):
# then there are 32 bit worth of flags and other data self.adjust_for_architecture()
# however, on 64bit systems these are padded to be a full
# machine word long, which means we actually have two pointers
# worth of data to skip
def offset(self):
return 2 * self.sys_params.pointer_size
def length(self): # one pointer is the ISA
logger = lldb.formatters.Logger.Logger() # then there are 32 bit worth of flags and other data
logger >> "NSConcreteData_SummaryProvider length" # however, on 64bit systems these are padded to be a full
size = self.valobj.CreateChildAtOffset("count", # machine word long, which means we actually have two pointers
self.offset(), # worth of data to skip
self.sys_params.types_cache.NSUInteger) def offset(self):
logger >> str(size) return 2 * self.sys_params.pointer_size
logger >> str(size.GetValueAsUnsigned(0))
return size.GetValueAsUnsigned(0) def length(self):
logger = lldb.formatters.Logger.Logger()
logger >> "NSConcreteData_SummaryProvider length"
size = self.valobj.CreateChildAtOffset(
"count", self.offset(), self.sys_params.types_cache.NSUInteger)
logger >> str(size)
logger >> str(size.GetValueAsUnsigned(0))
return size.GetValueAsUnsigned(0)
class NSDataUnknown_SummaryProvider: class NSDataUnknown_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
logger >> "NSDataUnknown_SummaryProvider __init__"
self.valobj = valobj;
self.sys_params = params
self.update();
def update(self): def __init__(self, valobj, params):
self.adjust_for_architecture(); logger = lldb.formatters.Logger.Logger()
logger >> "NSDataUnknown_SummaryProvider __init__"
self.valobj = valobj
self.sys_params = params
self.update()
def length(self): def update(self):
logger = lldb.formatters.Logger.Logger() self.adjust_for_architecture()
logger >> "NSDataUnknown_SummaryProvider length"
stream = lldb.SBStream() def length(self):
self.valobj.GetExpressionPath(stream) logger = lldb.formatters.Logger.Logger()
logger >> stream.GetData() logger >> "NSDataUnknown_SummaryProvider length"
num_children_vo = self.valobj.CreateValueFromExpression("count","(int)[" + stream.GetData() + " length]"); stream = lldb.SBStream()
logger >> "still in after expression: " + str(num_children_vo) self.valobj.GetExpressionPath(stream)
if num_children_vo.IsValid(): logger >> stream.GetData()
logger >> "wow - expr output is valid: " + str(num_children_vo.GetValueAsUnsigned()) num_children_vo = self.valobj.CreateValueFromExpression(
return num_children_vo.GetValueAsUnsigned(0) "count", "(int)[" + stream.GetData() + " length]")
logger >> "invalid expr output - too bad" logger >> "still in after expression: " + str(num_children_vo)
return '<variable is not NSData>' if num_children_vo.IsValid():
logger >> "wow - expr output is valid: " + \
str(num_children_vo.GetValueAsUnsigned())
return num_children_vo.GetValueAsUnsigned(0)
logger >> "invalid expr output - too bad"
return '<variable is not NSData>'
def GetSummary_Impl(valobj): def GetSummary_Impl(valobj):
global statistics global statistics
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
logger >> "NSData GetSummary_Impl" logger >> "NSData GetSummary_Impl"
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics) class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
if wrapper: valobj, statistics)
logger >> "got a wrapper summary - using it" if wrapper:
return wrapper logger >> "got a wrapper summary - using it"
return wrapper
name_string = class_data.class_name()
logger >> "class name: " + name_string
if name_string == 'NSConcreteData' or \
name_string == 'NSConcreteMutableData' or \
name_string == '__NSCFData':
wrapper = NSConcreteData_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('code_notrun',valobj)
else:
wrapper = NSDataUnknown_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string)
return wrapper;
def NSData_SummaryProvider (valobj,dict): name_string = class_data.class_name()
logger = lldb.formatters.Logger.Logger() logger >> "class name: " + name_string
logger >> "NSData_SummaryProvider" if name_string == 'NSConcreteData' or \
provider = GetSummary_Impl(valobj); name_string == 'NSConcreteMutableData' or \
logger >> "found a summary provider, it is: " + str(provider) name_string == '__NSCFData':
if provider != None: wrapper = NSConcreteData_SummaryProvider(valobj, class_data.sys_params)
try: statistics.metric_hit('code_notrun', valobj)
summary = provider.length(); else:
except: wrapper = NSDataUnknown_SummaryProvider(valobj, class_data.sys_params)
summary = None statistics.metric_hit(
logger >> "got a summary: it is " + str(summary) 'unknown_class',
if summary == None: valobj.GetName() +
summary = '<variable is not NSData>' " seen as " +
elif isinstance(summary,basestring): name_string)
pass return wrapper
else:
if summary == 1:
summary = '1 byte'
else:
summary = str(summary) + ' bytes'
return summary
return 'Summary Unavailable'
def NSData_SummaryProvider2 (valobj,dict):
logger = lldb.formatters.Logger.Logger()
logger >> "NSData_SummaryProvider2"
provider = GetSummary_Impl(valobj);
logger >> "found a summary provider, it is: " + str(provider)
if provider != None:
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.length();
except:
summary = None
logger >> "got a summary: it is " + str(summary)
if summary == None:
summary = '<variable is not CFData>'
elif isinstance(summary,basestring):
pass
else:
if summary == 1:
summary = '@"1 byte"'
else:
summary = '@"' + str(summary) + ' bytes"'
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger,dict): def NSData_SummaryProvider(valobj, dict):
debugger.HandleCommand("type summary add -F NSData.NSData_SummaryProvider NSData") logger = lldb.formatters.Logger.Logger()
debugger.HandleCommand("type summary add -F NSData.NSData_SummaryProvider2 CFDataRef CFMutableDataRef") logger >> "NSData_SummaryProvider"
provider = GetSummary_Impl(valobj)
logger >> "found a summary provider, it is: " + str(provider)
if provider is not None:
try:
summary = provider.length()
except:
summary = None
logger >> "got a summary: it is " + str(summary)
if summary is None:
summary = '<variable is not NSData>'
elif isinstance(summary, basestring):
pass
else:
if summary == 1:
summary = '1 byte'
else:
summary = str(summary) + ' bytes'
return summary
return 'Summary Unavailable'
def NSData_SummaryProvider2(valobj, dict):
logger = lldb.formatters.Logger.Logger()
logger >> "NSData_SummaryProvider2"
provider = GetSummary_Impl(valobj)
logger >> "found a summary provider, it is: " + str(provider)
if provider is not None:
if isinstance(
provider,
lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.length()
except:
summary = None
logger >> "got a summary: it is " + str(summary)
if summary is None:
summary = '<variable is not CFData>'
elif isinstance(summary, basestring):
pass
else:
if summary == 1:
summary = '@"1 byte"'
else:
summary = '@"' + str(summary) + ' bytes"'
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger, dict):
debugger.HandleCommand(
"type summary add -F NSData.NSData_SummaryProvider NSData")
debugger.HandleCommand(
"type summary add -F NSData.NSData_SummaryProvider2 CFDataRef CFMutableDataRef")

View File

@ -27,243 +27,281 @@ statistics.add_metric('code_notrun')
# hence, all we need to know is the epoch year # hence, all we need to know is the epoch year
python_epoch = time.gmtime(0).tm_year python_epoch = time.gmtime(0).tm_year
osx_epoch = datetime.date(2001,1,1).timetuple() osx_epoch = datetime.date(2001, 1, 1).timetuple()
def mkgmtime(t): def mkgmtime(t):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
return time.mktime(t)-time.timezone return time.mktime(t) - time.timezone
osx_epoch = mkgmtime(osx_epoch) osx_epoch = mkgmtime(osx_epoch)
def osx_to_python_time(osx): def osx_to_python_time(osx):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
if python_epoch <= 2001: if python_epoch <= 2001:
return osx + osx_epoch return osx + osx_epoch
else: else:
return osx - osx_epoch return osx - osx_epoch
# represent a struct_time as a string in the format used by Xcode # represent a struct_time as a string in the format used by Xcode
def xcode_format_time(X): def xcode_format_time(X):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
return time.strftime('%Y-%m-%d %H:%M:%S %Z',X) return time.strftime('%Y-%m-%d %H:%M:%S %Z', X)
# represent a count-since-epoch as a string in the format used by Xcode # represent a count-since-epoch as a string in the format used by Xcode
def xcode_format_count(X): def xcode_format_count(X):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
return xcode_format_time(time.localtime(X)) return xcode_format_time(time.localtime(X))
# despite the similary to synthetic children providers, these classes are not # despite the similary to synthetic children providers, these classes are not
# trying to provide anything but the summary for NSDate, so they need not # trying to provide anything but the summary for NSDate, so they need not
# obey the interface specification for synthetic children providers # obey the interface specification for synthetic children providers
class NSTaggedDate_SummaryProvider: class NSTaggedDate_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, info_bits, data, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
self.update();
# NSDate is not using its info_bits for info like NSNumber is
# so we need to regroup info_bits and data
self.data = ((data << 8) | (info_bits << 4))
def update(self): def __init__(self, valobj, info_bits, data, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
self.update()
# NSDate is not using its info_bits for info like NSNumber is
# so we need to regroup info_bits and data
self.data = ((data << 8) | (info_bits << 4))
def value(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
# the value of the date-time object is wrapped into the pointer value self.adjust_for_architecture()
# unfortunately, it is made as a time-delta after Jan 1 2001 midnight GMT
# while all Python knows about is the "epoch", which is a platform-dependent def value(self):
# year (1970 of *nix) whose Jan 1 at midnight is taken as reference logger = lldb.formatters.Logger.Logger()
value_double = struct.unpack('d', struct.pack('Q', self.data))[0] # the value of the date-time object is wrapped into the pointer value
if value_double == -63114076800.0: # unfortunately, it is made as a time-delta after Jan 1 2001 midnight GMT
return '0001-12-30 00:00:00 +0000' # while all Python knows about is the "epoch", which is a platform-dependent
return xcode_format_count(osx_to_python_time(value_double)) # year (1970 of *nix) whose Jan 1 at midnight is taken as reference
value_double = struct.unpack('d', struct.pack('Q', self.data))[0]
if value_double == -63114076800.0:
return '0001-12-30 00:00:00 +0000'
return xcode_format_count(osx_to_python_time(value_double))
class NSUntaggedDate_SummaryProvider: class NSUntaggedDate_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not (self.sys_params.types_cache.double):
self.sys_params.types_cache.double = self.valobj.GetType().GetBasicType(lldb.eBasicTypeDouble)
self.update()
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not (self.sys_params.types_cache.double):
self.sys_params.types_cache.double = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeDouble)
self.update()
def offset(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
return self.sys_params.pointer_size self.adjust_for_architecture()
def offset(self):
logger = lldb.formatters.Logger.Logger()
return self.sys_params.pointer_size
def value(self):
logger = lldb.formatters.Logger.Logger()
value = self.valobj.CreateChildAtOffset(
"value", self.offset(), self.sys_params.types_cache.double)
value_double = struct.unpack(
'd', struct.pack(
'Q', value.GetData().uint64[0]))[0]
if value_double == -63114076800.0:
return '0001-12-30 00:00:00 +0000'
return xcode_format_count(osx_to_python_time(value_double))
def value(self):
logger = lldb.formatters.Logger.Logger()
value = self.valobj.CreateChildAtOffset("value",
self.offset(),
self.sys_params.types_cache.double)
value_double = struct.unpack('d', struct.pack('Q', value.GetData().uint64[0]))[0]
if value_double == -63114076800.0:
return '0001-12-30 00:00:00 +0000'
return xcode_format_count(osx_to_python_time(value_double))
class NSCalendarDate_SummaryProvider: class NSCalendarDate_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not (self.sys_params.types_cache.double):
self.sys_params.types_cache.double = self.valobj.GetType().GetBasicType(lldb.eBasicTypeDouble)
self.update()
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not (self.sys_params.types_cache.double):
self.sys_params.types_cache.double = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeDouble)
self.update()
def offset(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
return 2*self.sys_params.pointer_size self.adjust_for_architecture()
def offset(self):
logger = lldb.formatters.Logger.Logger()
return 2 * self.sys_params.pointer_size
def value(self):
logger = lldb.formatters.Logger.Logger()
value = self.valobj.CreateChildAtOffset(
"value", self.offset(), self.sys_params.types_cache.double)
value_double = struct.unpack(
'd', struct.pack(
'Q', value.GetData().uint64[0]))[0]
return xcode_format_count(osx_to_python_time(value_double))
def value(self):
logger = lldb.formatters.Logger.Logger()
value = self.valobj.CreateChildAtOffset("value",
self.offset(),
self.sys_params.types_cache.double)
value_double = struct.unpack('d', struct.pack('Q', value.GetData().uint64[0]))[0]
return xcode_format_count(osx_to_python_time(value_double))
class NSTimeZoneClass_SummaryProvider: class NSTimeZoneClass_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not (self.sys_params.types_cache.voidptr):
self.sys_params.types_cache.voidptr = self.valobj.GetType().GetBasicType(lldb.eBasicTypeVoid).GetPointerType()
self.update()
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not (self.sys_params.types_cache.voidptr):
self.sys_params.types_cache.voidptr = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeVoid).GetPointerType()
self.update()
def offset(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
return self.sys_params.pointer_size self.adjust_for_architecture()
def offset(self):
logger = lldb.formatters.Logger.Logger()
return self.sys_params.pointer_size
def timezone(self):
logger = lldb.formatters.Logger.Logger()
tz_string = self.valobj.CreateChildAtOffset(
"tz_name", self.offset(), self.sys_params.types_cache.voidptr)
return CFString.CFString_SummaryProvider(tz_string, None)
def timezone(self):
logger = lldb.formatters.Logger.Logger()
tz_string = self.valobj.CreateChildAtOffset("tz_name",
self.offset(),
self.sys_params.types_cache.voidptr)
return CFString.CFString_SummaryProvider(tz_string,None)
class NSUnknownDate_SummaryProvider: class NSUnknownDate_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.update()
def update(self): def __init__(self, valobj):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.update()
def update(self):
logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture()
def value(self):
logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream()
self.valobj.GetExpressionPath(stream)
expr = "(NSString*)[" + stream.GetData() + " description]"
num_children_vo = self.valobj.CreateValueFromExpression("str", expr)
if num_children_vo.IsValid():
return num_children_vo.GetSummary()
return '<variable is not NSDate>'
def value(self):
logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream()
self.valobj.GetExpressionPath(stream)
expr = "(NSString*)[" + stream.GetData() + " description]"
num_children_vo = self.valobj.CreateValueFromExpression("str",expr);
if num_children_vo.IsValid():
return num_children_vo.GetSummary()
return '<variable is not NSDate>'
def GetSummary_Impl(valobj): def GetSummary_Impl(valobj):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
global statistics global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics) class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
if wrapper: valobj, statistics)
return wrapper if wrapper:
return wrapper
name_string = class_data.class_name()
logger >> "class name is: " + str(name_string)
if name_string == 'NSDate' or name_string == '__NSDate' or name_string == '__NSTaggedDate': name_string = class_data.class_name()
if class_data.is_tagged(): logger >> "class name is: " + str(name_string)
wrapper = NSTaggedDate_SummaryProvider(valobj,class_data.info_bits(),class_data.value(), class_data.sys_params)
statistics.metric_hit('code_notrun',valobj) if name_string == 'NSDate' or name_string == '__NSDate' or name_string == '__NSTaggedDate':
else: if class_data.is_tagged():
wrapper = NSUntaggedDate_SummaryProvider(valobj, class_data.sys_params) wrapper = NSTaggedDate_SummaryProvider(
statistics.metric_hit('code_notrun',valobj) valobj, class_data.info_bits(), class_data.value(), class_data.sys_params)
elif name_string == 'NSCalendarDate': statistics.metric_hit('code_notrun', valobj)
wrapper = NSCalendarDate_SummaryProvider(valobj, class_data.sys_params) else:
statistics.metric_hit('code_notrun',valobj) wrapper = NSUntaggedDate_SummaryProvider(
elif name_string == '__NSTimeZone': valobj, class_data.sys_params)
wrapper = NSTimeZoneClass_SummaryProvider(valobj, class_data.sys_params) statistics.metric_hit('code_notrun', valobj)
statistics.metric_hit('code_notrun',valobj) elif name_string == 'NSCalendarDate':
else: wrapper = NSCalendarDate_SummaryProvider(valobj, class_data.sys_params)
wrapper = NSUnknownDate_SummaryProvider(valobj) statistics.metric_hit('code_notrun', valobj)
statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string) elif name_string == '__NSTimeZone':
return wrapper; wrapper = NSTimeZoneClass_SummaryProvider(
valobj, class_data.sys_params)
statistics.metric_hit('code_notrun', valobj)
else:
wrapper = NSUnknownDate_SummaryProvider(valobj)
statistics.metric_hit(
'unknown_class',
valobj.GetName() +
" seen as " +
name_string)
return wrapper
def NSDate_SummaryProvider (valobj,dict): def NSDate_SummaryProvider(valobj, dict):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj); provider = GetSummary_Impl(valobj)
if provider != None: if provider is not None:
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description): if isinstance(
return provider.message() provider,
try: lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
summary = provider.value(); return provider.message()
except: try:
summary = None summary = provider.value()
if summary == None: except:
summary = '<variable is not NSDate>' summary = None
return str(summary) if summary is None:
return 'Summary Unavailable' summary = '<variable is not NSDate>'
return str(summary)
def NSTimeZone_SummaryProvider (valobj,dict): return 'Summary Unavailable'
logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj);
if provider != None:
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.timezone();
except:
summary = None
logger >> "got summary " + str(summary)
if summary == None:
summary = '<variable is not NSTimeZone>'
return str(summary)
return 'Summary Unavailable'
def CFAbsoluteTime_SummaryProvider (valobj,dict): def NSTimeZone_SummaryProvider(valobj, dict):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
try: provider = GetSummary_Impl(valobj)
value_double = struct.unpack('d', struct.pack('Q', valobj.GetData().uint64[0]))[0] if provider is not None:
return xcode_format_count(osx_to_python_time(value_double)) if isinstance(
except: provider,
return 'Summary Unavailable' lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.timezone()
except:
summary = None
logger >> "got summary " + str(summary)
if summary is None:
summary = '<variable is not NSTimeZone>'
return str(summary)
return 'Summary Unavailable'
def __lldb_init_module(debugger,dict): def CFAbsoluteTime_SummaryProvider(valobj, dict):
debugger.HandleCommand("type summary add -F NSDate.NSDate_SummaryProvider NSDate") logger = lldb.formatters.Logger.Logger()
debugger.HandleCommand("type summary add -F NSDate.CFAbsoluteTime_SummaryProvider CFAbsoluteTime") try:
debugger.HandleCommand("type summary add -F NSDate.NSTimeZone_SummaryProvider NSTimeZone CFTimeZoneRef") value_double = struct.unpack(
'd', struct.pack(
'Q', valobj.GetData().uint64[0]))[0]
return xcode_format_count(osx_to_python_time(value_double))
except:
return 'Summary Unavailable'
def __lldb_init_module(debugger, dict):
debugger.HandleCommand(
"type summary add -F NSDate.NSDate_SummaryProvider NSDate")
debugger.HandleCommand(
"type summary add -F NSDate.CFAbsoluteTime_SummaryProvider CFAbsoluteTime")
debugger.HandleCommand(
"type summary add -F NSDate.NSTimeZone_SummaryProvider NSTimeZone CFTimeZoneRef")

View File

@ -18,97 +18,117 @@ statistics.add_metric('invalid_pointer')
statistics.add_metric('unknown_class') statistics.add_metric('unknown_class')
statistics.add_metric('code_notrun') statistics.add_metric('code_notrun')
class NSKnownException_SummaryProvider: class NSKnownException_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not (self.sys_params.types_cache.id):
self.sys_params.types_cache.id = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID)
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not (self.sys_params.types_cache.id):
self.sys_params.types_cache.id = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeObjCID)
self.update()
def offset_name(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
return self.sys_params.pointer_size self.adjust_for_architecture()
def offset_reason(self):
logger = lldb.formatters.Logger.Logger() def offset_name(self):
return 2*self.sys_params.pointer_size logger = lldb.formatters.Logger.Logger()
return self.sys_params.pointer_size
def offset_reason(self):
logger = lldb.formatters.Logger.Logger()
return 2 * self.sys_params.pointer_size
def description(self):
logger = lldb.formatters.Logger.Logger()
name_ptr = self.valobj.CreateChildAtOffset(
"name", self.offset_name(), self.sys_params.types_cache.id)
reason_ptr = self.valobj.CreateChildAtOffset(
"reason", self.offset_reason(), self.sys_params.types_cache.id)
return 'name:' + CFString.CFString_SummaryProvider(
name_ptr, None) + ' reason:' + CFString.CFString_SummaryProvider(reason_ptr, None)
def description(self):
logger = lldb.formatters.Logger.Logger()
name_ptr = self.valobj.CreateChildAtOffset("name",
self.offset_name(),
self.sys_params.types_cache.id)
reason_ptr = self.valobj.CreateChildAtOffset("reason",
self.offset_reason(),
self.sys_params.types_cache.id)
return 'name:' + CFString.CFString_SummaryProvider(name_ptr,None) + ' reason:' + CFString.CFString_SummaryProvider(reason_ptr,None)
class NSUnknownException_SummaryProvider: class NSUnknownException_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
self.update()
def description(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream() self.adjust_for_architecture()
self.valobj.GetExpressionPath(stream)
name_vo = self.valobj.CreateValueFromExpression("name","(NSString*)[" + stream.GetData() + " name]"); def description(self):
reason_vo = self.valobj.CreateValueFromExpression("reason","(NSString*)[" + stream.GetData() + " reason]"); logger = lldb.formatters.Logger.Logger()
if name_vo.IsValid() and reason_vo.IsValid(): stream = lldb.SBStream()
return CFString.CFString_SummaryProvider(name_vo,None) + ' ' + CFString.CFString_SummaryProvider(reason_vo,None) self.valobj.GetExpressionPath(stream)
return '<variable is not NSException>' name_vo = self.valobj.CreateValueFromExpression(
"name", "(NSString*)[" + stream.GetData() + " name]")
reason_vo = self.valobj.CreateValueFromExpression(
"reason", "(NSString*)[" + stream.GetData() + " reason]")
if name_vo.IsValid() and reason_vo.IsValid():
return CFString.CFString_SummaryProvider(
name_vo, None) + ' ' + CFString.CFString_SummaryProvider(reason_vo, None)
return '<variable is not NSException>'
def GetSummary_Impl(valobj): def GetSummary_Impl(valobj):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
global statistics global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics) class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
if wrapper: valobj, statistics)
return wrapper if wrapper:
return wrapper
name_string = class_data.class_name()
logger >> "class name is: " + str(name_string)
if name_string == 'NSException': name_string = class_data.class_name()
wrapper = NSKnownException_SummaryProvider(valobj, class_data.sys_params) logger >> "class name is: " + str(name_string)
statistics.metric_hit('code_notrun',valobj)
else:
wrapper = NSUnknownException_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string)
return wrapper;
def NSException_SummaryProvider (valobj,dict): if name_string == 'NSException':
logger = lldb.formatters.Logger.Logger() wrapper = NSKnownException_SummaryProvider(
provider = GetSummary_Impl(valobj); valobj, class_data.sys_params)
if provider != None: statistics.metric_hit('code_notrun', valobj)
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description): else:
return provider.message() wrapper = NSUnknownException_SummaryProvider(
try: valobj, class_data.sys_params)
summary = provider.description(); statistics.metric_hit(
except: 'unknown_class',
summary = None valobj.GetName() +
logger >> "got summary " + str(summary) " seen as " +
if summary == None: name_string)
summary = '<variable is not NSException>' return wrapper
return str(summary)
return 'Summary Unavailable'
def __lldb_init_module(debugger,dict):
debugger.HandleCommand("type summary add -F NSException.NSException_SummaryProvider NSException") def NSException_SummaryProvider(valobj, dict):
logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj)
if provider is not None:
if isinstance(
provider,
lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.description()
except:
summary = None
logger >> "got summary " + str(summary)
if summary is None:
summary = '<variable is not NSException>'
return str(summary)
return 'Summary Unavailable'
def __lldb_init_module(debugger, dict):
debugger.HandleCommand(
"type summary add -F NSException.NSException_SummaryProvider NSException")

View File

@ -22,129 +22,155 @@ statistics.add_metric('code_notrun')
# despite the similary to synthetic children providers, these classes are not # despite the similary to synthetic children providers, these classes are not
# trying to provide anything but the count of values for an NSIndexSet, so they need not # trying to provide anything but the count of values for an NSIndexSet, so they need not
# obey the interface specification for synthetic children providers # obey the interface specification for synthetic children providers
class NSIndexSetClass_SummaryProvider: class NSIndexSetClass_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
self.sys_params.types_cache.uint32 = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
self.sys_params.types_cache.uint32 = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
if not(self.sys_params.types_cache.uint32):
self.sys_params.types_cache.uint32 = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedLong)
self.sys_params.types_cache.uint32 = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedInt)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedInt)
self.sys_params.types_cache.uint32 = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedInt)
if not(self.sys_params.types_cache.uint32):
self.sys_params.types_cache.uint32 = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update()
# NS(Mutable)IndexSet works in one of two modes: when having a compact block of data (e.g. a Range) def update(self):
# the count is stored in the set itself, 3 pointers into it logger = lldb.formatters.Logger.Logger()
# otherwise, it will store a pointer to an additional data structure (2 pointers into itself) and this self.adjust_for_architecture()
# additional structure will contain the count two pointers deep
# a bunch of flags allow us to detect an empty set, vs. a one-range set, vs. a multi-range set # NS(Mutable)IndexSet works in one of two modes: when having a compact block of data (e.g. a Range)
def count(self): # the count is stored in the set itself, 3 pointers into it
logger = lldb.formatters.Logger.Logger() # otherwise, it will store a pointer to an additional data structure (2 pointers into itself) and this
mode_chooser_vo = self.valobj.CreateChildAtOffset("mode_chooser", # additional structure will contain the count two pointers deep
self.sys_params.pointer_size, # a bunch of flags allow us to detect an empty set, vs. a one-range set,
self.sys_params.types_cache.uint32) # vs. a multi-range set
mode_chooser = mode_chooser_vo.GetValueAsUnsigned(0) def count(self):
if self.sys_params.is_64_bit: logger = lldb.formatters.Logger.Logger()
mode_chooser = mode_chooser & 0x00000000FFFFFFFF mode_chooser_vo = self.valobj.CreateChildAtOffset(
# empty set "mode_chooser",
if mode_chooser & 0x01 == 1: self.sys_params.pointer_size,
return 0 self.sys_params.types_cache.uint32)
# single range mode_chooser = mode_chooser_vo.GetValueAsUnsigned(0)
if mode_chooser & 0x02 == 2: if self.sys_params.is_64_bit:
mode = 1 mode_chooser = mode_chooser & 0x00000000FFFFFFFF
# multi range # empty set
else: if mode_chooser & 0x01 == 1:
mode = 2 return 0
if mode == 1: # single range
count_vo = self.valobj.CreateChildAtOffset("count", if mode_chooser & 0x02 == 2:
3*self.sys_params.pointer_size, mode = 1
self.sys_params.types_cache.NSUInteger) # multi range
else: else:
count_ptr = self.valobj.CreateChildAtOffset("count_ptr", mode = 2
2*self.sys_params.pointer_size, if mode == 1:
self.sys_params.types_cache.NSUInteger) count_vo = self.valobj.CreateChildAtOffset(
count_vo = self.valobj.CreateValueFromAddress("count", "count",
count_ptr.GetValueAsUnsigned()+2*self.sys_params.pointer_size, 3 * self.sys_params.pointer_size,
self.sys_params.types_cache.NSUInteger) self.sys_params.types_cache.NSUInteger)
return count_vo.GetValueAsUnsigned(0) else:
count_ptr = self.valobj.CreateChildAtOffset(
"count_ptr",
2 * self.sys_params.pointer_size,
self.sys_params.types_cache.NSUInteger)
count_vo = self.valobj.CreateValueFromAddress(
"count",
count_ptr.GetValueAsUnsigned() +
2 *
self.sys_params.pointer_size,
self.sys_params.types_cache.NSUInteger)
return count_vo.GetValueAsUnsigned(0)
class NSIndexSetUnknown_SummaryProvider: class NSIndexSetUnknown_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
self.update()
def count(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream() self.adjust_for_architecture()
self.valobj.GetExpressionPath(stream)
expr = "(int)[" + stream.GetData() + " count]" def count(self):
num_children_vo = self.valobj.CreateValueFromExpression("count",expr) logger = lldb.formatters.Logger.Logger()
if num_children_vo.IsValid(): stream = lldb.SBStream()
return num_children_vo.GetValueAsUnsigned(0) self.valobj.GetExpressionPath(stream)
return '<variable is not NSIndexSet>' expr = "(int)[" + stream.GetData() + " count]"
num_children_vo = self.valobj.CreateValueFromExpression("count", expr)
if num_children_vo.IsValid():
return num_children_vo.GetValueAsUnsigned(0)
return '<variable is not NSIndexSet>'
def GetSummary_Impl(valobj): def GetSummary_Impl(valobj):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
global statistics global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics) class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
if wrapper: valobj, statistics)
return wrapper if wrapper:
return wrapper
name_string = class_data.class_name()
logger >> "class name is: " + str(name_string)
if name_string == 'NSIndexSet' or name_string == 'NSMutableIndexSet': name_string = class_data.class_name()
wrapper = NSIndexSetClass_SummaryProvider(valobj, class_data.sys_params) logger >> "class name is: " + str(name_string)
statistics.metric_hit('code_notrun',valobj)
else: if name_string == 'NSIndexSet' or name_string == 'NSMutableIndexSet':
wrapper = NSIndexSetUnknown_SummaryProvider(valobj, class_data.sys_params) wrapper = NSIndexSetClass_SummaryProvider(
statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string) valobj, class_data.sys_params)
return wrapper; statistics.metric_hit('code_notrun', valobj)
else:
wrapper = NSIndexSetUnknown_SummaryProvider(
valobj, class_data.sys_params)
statistics.metric_hit(
'unknown_class',
valobj.GetName() +
" seen as " +
name_string)
return wrapper
def NSIndexSet_SummaryProvider (valobj,dict): def NSIndexSet_SummaryProvider(valobj, dict):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj); provider = GetSummary_Impl(valobj)
if provider != None: if provider is not None:
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description): if isinstance(
return provider.message() provider,
try: lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
summary = provider.count(); return provider.message()
except: try:
summary = None summary = provider.count()
logger >> "got summary " + str(summary) except:
if summary == None: summary = None
summary = '<variable is not NSIndexSet>' logger >> "got summary " + str(summary)
if isinstance(summary, basestring): if summary is None:
return summary summary = '<variable is not NSIndexSet>'
else: if isinstance(summary, basestring):
summary = str(summary) + (' indexes' if summary != 1 else ' index') return summary
return summary else:
return 'Summary Unavailable' summary = str(summary) + (' indexes' if summary != 1 else ' index')
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger,dict): def __lldb_init_module(debugger, dict):
debugger.HandleCommand("type summary add -F NSIndexSet.NSIndexSet_SummaryProvider NSIndexSet NSMutableIndexSet") debugger.HandleCommand(
"type summary add -F NSIndexSet.NSIndexSet_SummaryProvider NSIndexSet NSMutableIndexSet")

View File

@ -22,102 +22,120 @@ statistics.add_metric('code_notrun')
# despite the similary to synthetic children providers, these classes are not # despite the similary to synthetic children providers, these classes are not
# trying to provide anything but the port number of an NSMachPort, so they need not # trying to provide anything but the port number of an NSMachPort, so they need not
# obey the interface specification for synthetic children providers # obey the interface specification for synthetic children providers
class NSMachPortKnown_SummaryProvider: class NSMachPortKnown_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update()
# one pointer is the ISA def update(self):
# then we have one other internal pointer, plus logger = lldb.formatters.Logger.Logger()
# 4 bytes worth of flags. hence, these values self.adjust_for_architecture()
def offset(self):
logger = lldb.formatters.Logger.Logger()
if self.sys_params.is_64_bit:
return 20
else:
return 12
def port(self): # one pointer is the ISA
logger = lldb.formatters.Logger.Logger() # then we have one other internal pointer, plus
vport = self.valobj.CreateChildAtOffset("port", # 4 bytes worth of flags. hence, these values
self.offset(), def offset(self):
self.sys_params.types_cache.NSUInteger) logger = lldb.formatters.Logger.Logger()
return vport.GetValueAsUnsigned(0) if self.sys_params.is_64_bit:
return 20
else:
return 12
def port(self):
logger = lldb.formatters.Logger.Logger()
vport = self.valobj.CreateChildAtOffset(
"port", self.offset(), self.sys_params.types_cache.NSUInteger)
return vport.GetValueAsUnsigned(0)
class NSMachPortUnknown_SummaryProvider: class NSMachPortUnknown_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
self.update()
def port(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream() self.adjust_for_architecture()
self.valobj.GetExpressionPath(stream)
num_children_vo = self.valobj.CreateValueFromExpression("port","(int)[" + stream.GetData() + " machPort]") def port(self):
if num_children_vo.IsValid(): logger = lldb.formatters.Logger.Logger()
return num_children_vo.GetValueAsUnsigned(0) stream = lldb.SBStream()
return '<variable is not NSMachPort>' self.valobj.GetExpressionPath(stream)
num_children_vo = self.valobj.CreateValueFromExpression(
"port", "(int)[" + stream.GetData() + " machPort]")
if num_children_vo.IsValid():
return num_children_vo.GetValueAsUnsigned(0)
return '<variable is not NSMachPort>'
def GetSummary_Impl(valobj): def GetSummary_Impl(valobj):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
global statistics global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics) class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
if wrapper: valobj, statistics)
return wrapper if wrapper:
return wrapper
name_string = class_data.class_name()
logger >> "class name is: " + str(name_string)
if name_string == 'NSMachPort': name_string = class_data.class_name()
wrapper = NSMachPortKnown_SummaryProvider(valobj, class_data.sys_params) logger >> "class name is: " + str(name_string)
statistics.metric_hit('code_notrun',valobj)
else:
wrapper = NSMachPortUnknown_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string)
return wrapper;
def NSMachPort_SummaryProvider (valobj,dict): if name_string == 'NSMachPort':
logger = lldb.formatters.Logger.Logger() wrapper = NSMachPortKnown_SummaryProvider(
provider = GetSummary_Impl(valobj); valobj, class_data.sys_params)
if provider != None: statistics.metric_hit('code_notrun', valobj)
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description): else:
return provider.message() wrapper = NSMachPortUnknown_SummaryProvider(
try: valobj, class_data.sys_params)
summary = provider.port(); statistics.metric_hit(
except: 'unknown_class',
summary = None valobj.GetName() +
logger >> "got summary " + str(summary) " seen as " +
if summary == None: name_string)
summary = '<variable is not NSMachPort>' return wrapper
if isinstance(summary, basestring):
return summay
return 'mach port: ' + str(summary)
return 'Summary Unavailable'
def __lldb_init_module(debugger,dict):
debugger.HandleCommand("type summary add -F NSMachPort.NSMachPort_SummaryProvider NSMachPort") def NSMachPort_SummaryProvider(valobj, dict):
logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj)
if provider is not None:
if isinstance(
provider,
lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.port()
except:
summary = None
logger >> "got summary " + str(summary)
if summary is None:
summary = '<variable is not NSMachPort>'
if isinstance(summary, basestring):
return summay
return 'mach port: ' + str(summary)
return 'Summary Unavailable'
def __lldb_init_module(debugger, dict):
debugger.HandleCommand(
"type summary add -F NSMachPort.NSMachPort_SummaryProvider NSMachPort")

View File

@ -19,92 +19,108 @@ statistics.add_metric('invalid_pointer')
statistics.add_metric('unknown_class') statistics.add_metric('unknown_class')
statistics.add_metric('code_notrun') statistics.add_metric('code_notrun')
class NSConcreteNotification_SummaryProvider: class NSConcreteNotification_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not (self.sys_params.types_cache.id):
self.sys_params.types_cache.id = self.valobj.GetType().GetBasicType(lldb.eBasicTypeObjCID)
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not (self.sys_params.types_cache.id):
self.sys_params.types_cache.id = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeObjCID)
self.update()
# skip the ISA and go to the name pointer def update(self):
def offset(self): logger = lldb.formatters.Logger.Logger()
logger = lldb.formatters.Logger.Logger() self.adjust_for_architecture()
return self.sys_params.pointer_size
def name(self): # skip the ISA and go to the name pointer
logger = lldb.formatters.Logger.Logger() def offset(self):
string_ptr = self.valobj.CreateChildAtOffset("name", logger = lldb.formatters.Logger.Logger()
self.offset(), return self.sys_params.pointer_size
self.sys_params.types_cache.id)
return CFString.CFString_SummaryProvider(string_ptr,None) def name(self):
logger = lldb.formatters.Logger.Logger()
string_ptr = self.valobj.CreateChildAtOffset(
"name", self.offset(), self.sys_params.types_cache.id)
return CFString.CFString_SummaryProvider(string_ptr, None)
class NSNotificationUnknown_SummaryProvider: class NSNotificationUnknown_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
self.update()
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
self.update()
def name(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream() self.adjust_for_architecture()
self.valobj.GetExpressionPath(stream)
name_vo = self.valobj.CreateValueFromExpression("name","(NSString*)[" + stream.GetData() + " name]") def name(self):
if name_vo.IsValid(): logger = lldb.formatters.Logger.Logger()
return CFString.CFString_SummaryProvider(name_vo,None) stream = lldb.SBStream()
return '<variable is not NSNotification>' self.valobj.GetExpressionPath(stream)
name_vo = self.valobj.CreateValueFromExpression(
"name", "(NSString*)[" + stream.GetData() + " name]")
if name_vo.IsValid():
return CFString.CFString_SummaryProvider(name_vo, None)
return '<variable is not NSNotification>'
def GetSummary_Impl(valobj): def GetSummary_Impl(valobj):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
global statistics global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics) class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
if wrapper: valobj, statistics)
return wrapper if wrapper:
return wrapper
name_string = class_data.class_name()
logger >> "class name is: " + str(name_string)
if name_string == 'NSConcreteNotification': name_string = class_data.class_name()
wrapper = NSConcreteNotification_SummaryProvider(valobj, class_data.sys_params) logger >> "class name is: " + str(name_string)
statistics.metric_hit('code_notrun',valobj)
else:
wrapper = NSNotificationUnknown_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string)
return wrapper;
def NSNotification_SummaryProvider (valobj,dict): if name_string == 'NSConcreteNotification':
logger = lldb.formatters.Logger.Logger() wrapper = NSConcreteNotification_SummaryProvider(
provider = GetSummary_Impl(valobj); valobj, class_data.sys_params)
if provider != None: statistics.metric_hit('code_notrun', valobj)
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description): else:
return provider.message() wrapper = NSNotificationUnknown_SummaryProvider(
try: valobj, class_data.sys_params)
summary = provider.name(); statistics.metric_hit(
except: 'unknown_class',
summary = None valobj.GetName() +
logger >> "got summary " + str(summary) " seen as " +
if summary == None: name_string)
summary = '<variable is not NSNotification>' return wrapper
return str(summary)
return 'Summary Unavailable'
def __lldb_init_module(debugger,dict):
debugger.HandleCommand("type summary add -F NSNotification.NSNotification_SummaryProvider NSNotification") def NSNotification_SummaryProvider(valobj, dict):
logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj)
if provider is not None:
if isinstance(
provider,
lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.name()
except:
summary = None
logger >> "got summary " + str(summary)
if summary is None:
summary = '<variable is not NSNotification>'
return str(summary)
return 'Summary Unavailable'
def __lldb_init_module(debugger, dict):
debugger.HandleCommand(
"type summary add -F NSNotification.NSNotification_SummaryProvider NSNotification")

View File

@ -23,213 +23,247 @@ statistics.add_metric('code_notrun')
# despite the similary to synthetic children providers, these classes are not # despite the similary to synthetic children providers, these classes are not
# trying to provide anything but the port number of an NSNumber, so they need not # trying to provide anything but the port number of an NSNumber, so they need not
# obey the interface specification for synthetic children providers # obey the interface specification for synthetic children providers
class NSTaggedNumber_SummaryProvider: class NSTaggedNumber_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, info_bits, data, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
self.info_bits = info_bits
self.data = data
self.update();
def update(self): def __init__(self, valobj, info_bits, data, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
self.info_bits = info_bits
self.data = data
self.update()
def value(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
# in spite of the plenty of types made available by the public NSNumber API self.adjust_for_architecture()
# only a bunch of these are actually used in the internal implementation
# unfortunately, the original type information appears to be lost def value(self):
# so we try to at least recover the proper magnitude of the data logger = lldb.formatters.Logger.Logger()
if self.info_bits == 0: # in spite of the plenty of types made available by the public NSNumber API
return '(char)' + str(ord(ctypes.c_char(chr(self.data % 256)).value)) # only a bunch of these are actually used in the internal implementation
if self.info_bits == 4: # unfortunately, the original type information appears to be lost
return '(short)' + str(ctypes.c_short(self.data % (256*256)).value) # so we try to at least recover the proper magnitude of the data
if self.info_bits == 8: if self.info_bits == 0:
return '(int)' + str(ctypes.c_int(self.data % (256*256*256*256)).value) return '(char)' + \
if self.info_bits == 12: str(ord(ctypes.c_char(chr(self.data % 256)).value))
return '(long)' + str(ctypes.c_long(self.data).value) if self.info_bits == 4:
else: return '(short)' + \
return 'unexpected value:(info=' + str(self.info_bits) + ", value = " + str(self.data) + ')' str(ctypes.c_short(self.data % (256 * 256)).value)
if self.info_bits == 8:
return '(int)' + str(ctypes.c_int(self.data %
(256 * 256 * 256 * 256)).value)
if self.info_bits == 12:
return '(long)' + str(ctypes.c_long(self.data).value)
else:
return 'unexpected value:(info=' + str(self.info_bits) + \
", value = " + str(self.data) + ')'
class NSUntaggedNumber_SummaryProvider: class NSUntaggedNumber_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.char):
self.sys_params.types_cache.char = self.valobj.GetType().GetBasicType(lldb.eBasicTypeChar)
if not(self.sys_params.types_cache.short):
self.sys_params.types_cache.short = self.valobj.GetType().GetBasicType(lldb.eBasicTypeShort)
if not(self.sys_params.types_cache.ushort):
self.sys_params.types_cache.ushort = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedShort)
if not(self.sys_params.types_cache.int):
self.sys_params.types_cache.int = self.valobj.GetType().GetBasicType(lldb.eBasicTypeInt)
if not(self.sys_params.types_cache.long):
self.sys_params.types_cache.long = self.valobj.GetType().GetBasicType(lldb.eBasicTypeLong)
if not(self.sys_params.types_cache.ulong):
self.sys_params.types_cache.ulong = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
if not(self.sys_params.types_cache.longlong):
self.sys_params.types_cache.longlong = self.valobj.GetType().GetBasicType(lldb.eBasicTypeLongLong)
if not(self.sys_params.types_cache.ulonglong):
self.sys_params.types_cache.ulonglong = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLongLong)
if not(self.sys_params.types_cache.float):
self.sys_params.types_cache.float = self.valobj.GetType().GetBasicType(lldb.eBasicTypeFloat)
if not(self.sys_params.types_cache.double):
self.sys_params.types_cache.double = self.valobj.GetType().GetBasicType(lldb.eBasicTypeDouble)
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not(self.sys_params.types_cache.char):
self.sys_params.types_cache.char = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeChar)
if not(self.sys_params.types_cache.short):
self.sys_params.types_cache.short = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeShort)
if not(self.sys_params.types_cache.ushort):
self.sys_params.types_cache.ushort = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedShort)
if not(self.sys_params.types_cache.int):
self.sys_params.types_cache.int = self.valobj.GetType().GetBasicType(lldb.eBasicTypeInt)
if not(self.sys_params.types_cache.long):
self.sys_params.types_cache.long = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeLong)
if not(self.sys_params.types_cache.ulong):
self.sys_params.types_cache.ulong = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedLong)
if not(self.sys_params.types_cache.longlong):
self.sys_params.types_cache.longlong = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeLongLong)
if not(self.sys_params.types_cache.ulonglong):
self.sys_params.types_cache.ulonglong = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedLongLong)
if not(self.sys_params.types_cache.float):
self.sys_params.types_cache.float = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeFloat)
if not(self.sys_params.types_cache.double):
self.sys_params.types_cache.double = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeDouble)
self.update()
def value(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
global statistics self.adjust_for_architecture()
# we need to skip the ISA, then the next byte tells us what to read
# we then skip one other full pointer worth of data and then fetch the contents def value(self):
# if we are fetching an int64 value, one more pointer must be skipped to get at our data logger = lldb.formatters.Logger.Logger()
data_type_vo = self.valobj.CreateChildAtOffset("dt", global statistics
self.sys_params.pointer_size, # we need to skip the ISA, then the next byte tells us what to read
self.sys_params.types_cache.char) # we then skip one other full pointer worth of data and then fetch the contents
data_type = ((data_type_vo.GetValueAsUnsigned(0) % 256) & 0x1F) # if we are fetching an int64 value, one more pointer must be skipped
data_offset = 2 * self.sys_params.pointer_size # to get at our data
if data_type == 0B00001: data_type_vo = self.valobj.CreateChildAtOffset(
data_vo = self.valobj.CreateChildAtOffset("data", "dt", self.sys_params.pointer_size, self.sys_params.types_cache.char)
data_offset, data_type = ((data_type_vo.GetValueAsUnsigned(0) % 256) & 0x1F)
self.sys_params.types_cache.char) data_offset = 2 * self.sys_params.pointer_size
statistics.metric_hit('code_notrun',self.valobj) if data_type == 0B00001:
return '(char)' + str(ord(ctypes.c_char(chr(data_vo.GetValueAsUnsigned(0))).value)) data_vo = self.valobj.CreateChildAtOffset(
elif data_type == 0B0010: "data", data_offset, self.sys_params.types_cache.char)
data_vo = self.valobj.CreateChildAtOffset("data", statistics.metric_hit('code_notrun', self.valobj)
data_offset, return '(char)' + \
self.sys_params.types_cache.short) str(ord(ctypes.c_char(chr(data_vo.GetValueAsUnsigned(0))).value))
statistics.metric_hit('code_notrun',self.valobj) elif data_type == 0B0010:
return '(short)' + str(ctypes.c_short(data_vo.GetValueAsUnsigned(0) % (256*256)).value) data_vo = self.valobj.CreateChildAtOffset(
# IF tagged pointers are possible on 32bit+v2 runtime "data", data_offset, self.sys_params.types_cache.short)
# (of which the only existing instance should be iOS) statistics.metric_hit('code_notrun', self.valobj)
# then values of this type might be tagged return '(short)' + str(
elif data_type == 0B0011: ctypes.c_short(
data_vo = self.valobj.CreateChildAtOffset("data", data_vo.GetValueAsUnsigned(0) %
data_offset, (256 * 256)).value)
self.sys_params.types_cache.int) # IF tagged pointers are possible on 32bit+v2 runtime
statistics.metric_hit('code_notrun',self.valobj) # (of which the only existing instance should be iOS)
return '(int)' + str(ctypes.c_int(data_vo.GetValueAsUnsigned(0)% (256*256*256*256)).value) # then values of this type might be tagged
# apparently, on is_64_bit architectures, these are the only values that will ever elif data_type == 0B0011:
# be represented by a non tagged pointers data_vo = self.valobj.CreateChildAtOffset(
elif data_type == 0B10001: "data", data_offset, self.sys_params.types_cache.int)
data_offset = data_offset + 8 # 8 is needed even if we are on 32bit statistics.metric_hit('code_notrun', self.valobj)
data_vo = self.valobj.CreateChildAtOffset("data", return '(int)' + str(ctypes.c_int(data_vo.GetValueAsUnsigned(0) %
data_offset, (256 * 256 * 256 * 256)).value)
self.sys_params.types_cache.longlong) # apparently, on is_64_bit architectures, these are the only values that will ever
statistics.metric_hit('code_notrun',self.valobj) # be represented by a non tagged pointers
return '(long)' + str(ctypes.c_long(data_vo.GetValueAsUnsigned(0)).value) elif data_type == 0B10001:
elif data_type == 0B0100: data_offset = data_offset + 8 # 8 is needed even if we are on 32bit
if self.sys_params.is_64_bit: data_vo = self.valobj.CreateChildAtOffset(
data_offset = data_offset + self.sys_params.pointer_size "data", data_offset, self.sys_params.types_cache.longlong)
data_vo = self.valobj.CreateChildAtOffset("data", statistics.metric_hit('code_notrun', self.valobj)
data_offset, return '(long)' + \
self.sys_params.types_cache.longlong) str(ctypes.c_long(data_vo.GetValueAsUnsigned(0)).value)
statistics.metric_hit('code_notrun',self.valobj) elif data_type == 0B0100:
return '(long)' + str(ctypes.c_long(data_vo.GetValueAsUnsigned(0)).value) if self.sys_params.is_64_bit:
elif data_type == 0B0101: data_offset = data_offset + self.sys_params.pointer_size
data_vo = self.valobj.CreateChildAtOffset("data", data_vo = self.valobj.CreateChildAtOffset(
data_offset, "data", data_offset, self.sys_params.types_cache.longlong)
self.sys_params.types_cache.longlong) statistics.metric_hit('code_notrun', self.valobj)
data_plain = int(str(data_vo.GetValueAsUnsigned(0) & 0x00000000FFFFFFFF)) return '(long)' + \
packed = struct.pack('I', data_plain) str(ctypes.c_long(data_vo.GetValueAsUnsigned(0)).value)
data_float = struct.unpack('f', packed)[0] elif data_type == 0B0101:
statistics.metric_hit('code_notrun',self.valobj) data_vo = self.valobj.CreateChildAtOffset(
return '(float)' + str(data_float) "data", data_offset, self.sys_params.types_cache.longlong)
elif data_type == 0B0110: data_plain = int(
data_vo = self.valobj.CreateChildAtOffset("data", str(data_vo.GetValueAsUnsigned(0) & 0x00000000FFFFFFFF))
data_offset, packed = struct.pack('I', data_plain)
self.sys_params.types_cache.longlong) data_float = struct.unpack('f', packed)[0]
data_plain = data_vo.GetValueAsUnsigned(0) statistics.metric_hit('code_notrun', self.valobj)
data_double = struct.unpack('d', struct.pack('Q', data_plain))[0] return '(float)' + str(data_float)
statistics.metric_hit('code_notrun',self.valobj) elif data_type == 0B0110:
return '(double)' + str(data_double) data_vo = self.valobj.CreateChildAtOffset(
statistics.metric_hit('unknown_class',str(valobj.GetName()) + " had unknown data_type " + str(data_type)) "data", data_offset, self.sys_params.types_cache.longlong)
return 'unexpected: dt = ' + str(data_type) data_plain = data_vo.GetValueAsUnsigned(0)
data_double = struct.unpack('d', struct.pack('Q', data_plain))[0]
statistics.metric_hit('code_notrun', self.valobj)
return '(double)' + str(data_double)
statistics.metric_hit(
'unknown_class', str(
valobj.GetName()) + " had unknown data_type " + str(data_type))
return 'unexpected: dt = ' + str(data_type)
class NSUnknownNumber_SummaryProvider: class NSUnknownNumber_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
self.update()
def update(self):
logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture()
def value(self):
logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream()
self.valobj.GetExpressionPath(stream)
expr = "(NSString*)[" + stream.GetData() + " stringValue]"
num_children_vo = self.valobj.CreateValueFromExpression("str", expr)
if num_children_vo.IsValid():
return num_children_vo.GetSummary()
return '<variable is not NSNumber>'
def value(self):
logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream()
self.valobj.GetExpressionPath(stream)
expr = "(NSString*)[" + stream.GetData() + " stringValue]"
num_children_vo = self.valobj.CreateValueFromExpression("str",expr)
if num_children_vo.IsValid():
return num_children_vo.GetSummary()
return '<variable is not NSNumber>'
def GetSummary_Impl(valobj): def GetSummary_Impl(valobj):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
global statistics global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics) class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
if wrapper: valobj, statistics)
return wrapper if wrapper:
return wrapper
name_string = class_data.class_name()
logger >> "class name is: " + str(name_string)
if name_string == 'NSNumber' or name_string == '__NSCFNumber': name_string = class_data.class_name()
if class_data.is_tagged(): logger >> "class name is: " + str(name_string)
wrapper = NSTaggedNumber_SummaryProvider(valobj,class_data.info_bits(),class_data.value(), class_data.sys_params)
statistics.metric_hit('code_notrun',valobj) if name_string == 'NSNumber' or name_string == '__NSCFNumber':
else: if class_data.is_tagged():
# the wrapper might be unable to decipher what is into the NSNumber wrapper = NSTaggedNumber_SummaryProvider(
# and then have to run code on it valobj, class_data.info_bits(), class_data.value(), class_data.sys_params)
wrapper = NSUntaggedNumber_SummaryProvider(valobj, class_data.sys_params) statistics.metric_hit('code_notrun', valobj)
else: else:
wrapper = NSUnknownNumber_SummaryProvider(valobj, class_data.sys_params) # the wrapper might be unable to decipher what is into the NSNumber
statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string) # and then have to run code on it
return wrapper; wrapper = NSUntaggedNumber_SummaryProvider(
valobj, class_data.sys_params)
else:
wrapper = NSUnknownNumber_SummaryProvider(
valobj, class_data.sys_params)
statistics.metric_hit(
'unknown_class',
valobj.GetName() +
" seen as " +
name_string)
return wrapper
def NSNumber_SummaryProvider (valobj,dict): def NSNumber_SummaryProvider(valobj, dict):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj); provider = GetSummary_Impl(valobj)
if provider != None: if provider is not None:
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description): if isinstance(
return provider.message() provider,
try: lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
summary = provider.value(); return provider.message()
except Exception as foo: try:
print foo summary = provider.value()
except Exception as foo:
print foo
# except: # except:
summary = None summary = None
logger >> "got summary " + str(summary) logger >> "got summary " + str(summary)
if summary == None: if summary is None:
summary = '<variable is not NSNumber>' summary = '<variable is not NSNumber>'
return str(summary) return str(summary)
return 'Summary Unavailable' return 'Summary Unavailable'
def __lldb_init_module(debugger,dict): def __lldb_init_module(debugger, dict):
debugger.HandleCommand("type summary add -F NSNumber.NSNumber_SummaryProvider NSNumber") debugger.HandleCommand(
debugger.HandleCommand("type summary add -F NSNumber.NSNumber_SummaryProvider __NSCFBoolean") "type summary add -F NSNumber.NSNumber_SummaryProvider NSNumber")
debugger.HandleCommand("type summary add -F NSNumber.NSNumber_SummaryProvider __NSCFNumber") debugger.HandleCommand(
"type summary add -F NSNumber.NSNumber_SummaryProvider __NSCFBoolean")
debugger.HandleCommand(
"type summary add -F NSNumber.NSNumber_SummaryProvider __NSCFNumber")

View File

@ -22,242 +22,268 @@ statistics.add_metric('code_notrun')
# despite the similary to synthetic children providers, these classes are not # despite the similary to synthetic children providers, these classes are not
# trying to provide anything but the port number of an NSMachPort, so they need not # trying to provide anything but the port number of an NSMachPort, so they need not
# obey the interface specification for synthetic children providers # obey the interface specification for synthetic children providers
class NSCFSet_SummaryProvider: class NSCFSet_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update()
# one pointer is the ISA def update(self):
# then we have one other internal pointer, plus logger = lldb.formatters.Logger.Logger()
# 4 bytes worth of flags. hence, these values self.adjust_for_architecture()
def offset(self):
logger = lldb.formatters.Logger.Logger()
if self.sys_params.is_64_bit:
return 20
else:
return 12
def count(self): # one pointer is the ISA
logger = lldb.formatters.Logger.Logger() # then we have one other internal pointer, plus
vcount = self.valobj.CreateChildAtOffset("count", # 4 bytes worth of flags. hence, these values
self.offset(), def offset(self):
self.sys_params.types_cache.NSUInteger) logger = lldb.formatters.Logger.Logger()
return vcount.GetValueAsUnsigned(0) if self.sys_params.is_64_bit:
return 20
else:
return 12
def count(self):
logger = lldb.formatters.Logger.Logger()
vcount = self.valobj.CreateChildAtOffset(
"count", self.offset(), self.sys_params.types_cache.NSUInteger)
return vcount.GetValueAsUnsigned(0)
class NSSetUnknown_SummaryProvider: class NSSetUnknown_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
self.update()
def update(self):
logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture()
def count(self):
logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream()
self.valobj.GetExpressionPath(stream)
expr = "(int)[" + stream.GetData() + " count]"
num_children_vo = self.valobj.CreateValueFromExpression("count", expr)
if num_children_vo.IsValid():
return num_children_vo.GetValueAsUnsigned(0)
return '<variable is not NSSet>'
def count(self):
logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream()
self.valobj.GetExpressionPath(stream)
expr = "(int)[" + stream.GetData() + " count]"
num_children_vo = self.valobj.CreateValueFromExpression("count",expr)
if num_children_vo.IsValid():
return num_children_vo.GetValueAsUnsigned(0)
return '<variable is not NSSet>'
class NSSetI_SummaryProvider: class NSSetI_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update()
# we just need to skip the ISA and the count immediately follows def update(self):
def offset(self): logger = lldb.formatters.Logger.Logger()
logger = lldb.formatters.Logger.Logger() self.adjust_for_architecture()
return self.sys_params.pointer_size
# we just need to skip the ISA and the count immediately follows
def offset(self):
logger = lldb.formatters.Logger.Logger()
return self.sys_params.pointer_size
def count(self):
logger = lldb.formatters.Logger.Logger()
num_children_vo = self.valobj.CreateChildAtOffset(
"count", self.offset(), self.sys_params.types_cache.NSUInteger)
value = num_children_vo.GetValueAsUnsigned(0)
if value is not None:
# the MSB on immutable sets seems to be taken by some other data
# not sure if it is a bug or some weird sort of feature, but masking it out
# gets the count right (unless, of course, someone's dictionaries grow
# too large - but I have not tested this)
if self.sys_params.is_64_bit:
value = value & ~0xFF00000000000000
else:
value = value & ~0xFF000000
return value
def count(self):
logger = lldb.formatters.Logger.Logger()
num_children_vo = self.valobj.CreateChildAtOffset("count",
self.offset(),
self.sys_params.types_cache.NSUInteger)
value = num_children_vo.GetValueAsUnsigned(0)
if value != None:
# the MSB on immutable sets seems to be taken by some other data
# not sure if it is a bug or some weird sort of feature, but masking it out
# gets the count right (unless, of course, someone's dictionaries grow
# too large - but I have not tested this)
if self.sys_params.is_64_bit:
value = value & ~0xFF00000000000000
else:
value = value & ~0xFF000000
return value
class NSSetM_SummaryProvider: class NSSetM_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not(self.sys_params.types_cache.NSUInteger):
if self.sys_params.is_64_bit:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedLong)
else:
self.sys_params.types_cache.NSUInteger = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeUnsignedInt)
self.update()
# we just need to skip the ISA and the count immediately follows def update(self):
def offset(self): logger = lldb.formatters.Logger.Logger()
logger = lldb.formatters.Logger.Logger() self.adjust_for_architecture()
return self.sys_params.pointer_size
def count(self): # we just need to skip the ISA and the count immediately follows
logger = lldb.formatters.Logger.Logger() def offset(self):
num_children_vo = self.valobj.CreateChildAtOffset("count", logger = lldb.formatters.Logger.Logger()
self.offset(), return self.sys_params.pointer_size
self.sys_params.types_cache.NSUInteger)
return num_children_vo.GetValueAsUnsigned(0) def count(self):
logger = lldb.formatters.Logger.Logger()
num_children_vo = self.valobj.CreateChildAtOffset(
"count", self.offset(), self.sys_params.types_cache.NSUInteger)
return num_children_vo.GetValueAsUnsigned(0)
class NSCountedSet_SummaryProvider: class NSCountedSet_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not (self.sys_params.types_cache.voidptr):
self.sys_params.types_cache.voidptr = self.valobj.GetType().GetBasicType(lldb.eBasicTypeVoid).GetPointerType()
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not (self.sys_params.types_cache.voidptr):
self.sys_params.types_cache.voidptr = self.valobj.GetType(
).GetBasicType(lldb.eBasicTypeVoid).GetPointerType()
self.update()
# an NSCountedSet is implemented using a CFBag whose pointer just follows the ISA def update(self):
def offset(self): logger = lldb.formatters.Logger.Logger()
logger = lldb.formatters.Logger.Logger() self.adjust_for_architecture()
return self.sys_params.pointer_size
def count(self): # an NSCountedSet is implemented using a CFBag whose pointer just follows
logger = lldb.formatters.Logger.Logger() # the ISA
cfbag_vo = self.valobj.CreateChildAtOffset("bag_impl", def offset(self):
self.offset(), logger = lldb.formatters.Logger.Logger()
self.sys_params.types_cache.voidptr) return self.sys_params.pointer_size
return CFBag.CFBagRef_SummaryProvider(cfbag_vo,self.sys_params).length()
def count(self):
logger = lldb.formatters.Logger.Logger()
cfbag_vo = self.valobj.CreateChildAtOffset(
"bag_impl", self.offset(), self.sys_params.types_cache.voidptr)
return CFBag.CFBagRef_SummaryProvider(
cfbag_vo, self.sys_params).length()
def GetSummary_Impl(valobj): def GetSummary_Impl(valobj):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
global statistics global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics) class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
if wrapper: valobj, statistics)
return wrapper if wrapper:
return wrapper
name_string = class_data.class_name()
logger >> "class name is: " + str(name_string)
if name_string == '__NSCFSet': name_string = class_data.class_name()
wrapper = NSCFSet_SummaryProvider(valobj, class_data.sys_params) logger >> "class name is: " + str(name_string)
statistics.metric_hit('code_notrun',valobj)
elif name_string == '__NSSetI': if name_string == '__NSCFSet':
wrapper = NSSetI_SummaryProvider(valobj, class_data.sys_params) wrapper = NSCFSet_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('code_notrun',valobj) statistics.metric_hit('code_notrun', valobj)
elif name_string == '__NSSetM': elif name_string == '__NSSetI':
wrapper = NSSetM_SummaryProvider(valobj, class_data.sys_params) wrapper = NSSetI_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('code_notrun',valobj) statistics.metric_hit('code_notrun', valobj)
elif name_string == 'NSCountedSet': elif name_string == '__NSSetM':
wrapper = NSCountedSet_SummaryProvider(valobj, class_data.sys_params) wrapper = NSSetM_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('code_notrun',valobj) statistics.metric_hit('code_notrun', valobj)
else: elif name_string == 'NSCountedSet':
wrapper = NSSetUnknown_SummaryProvider(valobj, class_data.sys_params) wrapper = NSCountedSet_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string) statistics.metric_hit('code_notrun', valobj)
return wrapper; else:
wrapper = NSSetUnknown_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit(
'unknown_class',
valobj.GetName() +
" seen as " +
name_string)
return wrapper
def NSSet_SummaryProvider (valobj,dict): def NSSet_SummaryProvider(valobj, dict):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj); provider = GetSummary_Impl(valobj)
if provider != None: if provider is not None:
try: try:
summary = provider.count(); summary = provider.count()
except: except:
summary = None summary = None
if summary == None: if summary is None:
summary = '<variable is not NSSet>' summary = '<variable is not NSSet>'
if isinstance(summary, basestring): if isinstance(summary, basestring):
return summary return summary
else: else:
summary = str(summary) + (' objects' if summary != 1 else ' object') summary = str(summary) + \
return summary (' objects' if summary != 1 else ' object')
return 'Summary Unavailable' return summary
return 'Summary Unavailable'
def NSSet_SummaryProvider2 (valobj,dict):
logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj);
if provider != None:
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.count();
except:
summary = None
logger >> "got summary " + str(summary)
# for some reason, one needs to clear some bits for the count returned
# to be correct when using directly CF*SetRef as compared to NS*Set
# this only happens on 64bit, and the bit mask was derived through
# experimentation (if counts start looking weird, then most probably
# the mask needs to be changed)
if summary == None:
summary = '<variable is not CFSet>'
if isinstance(summary, basestring):
return summary
else:
if provider.sys_params.is_64_bit:
summary = summary & ~0x1fff000000000000
summary = '@"' + str(summary) + (' values"' if summary != 1 else ' value"')
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger,dict): def NSSet_SummaryProvider2(valobj, dict):
debugger.HandleCommand("type summary add -F NSSet.NSSet_SummaryProvider NSSet") logger = lldb.formatters.Logger.Logger()
debugger.HandleCommand("type summary add -F NSSet.NSSet_SummaryProvider2 CFSetRef CFMutableSetRef") provider = GetSummary_Impl(valobj)
if provider is not None:
if isinstance(
provider,
lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.count()
except:
summary = None
logger >> "got summary " + str(summary)
# for some reason, one needs to clear some bits for the count returned
# to be correct when using directly CF*SetRef as compared to NS*Set
# this only happens on 64bit, and the bit mask was derived through
# experimentation (if counts start looking weird, then most probably
# the mask needs to be changed)
if summary is None:
summary = '<variable is not CFSet>'
if isinstance(summary, basestring):
return summary
else:
if provider.sys_params.is_64_bit:
summary = summary & ~0x1fff000000000000
summary = '@"' + str(summary) + \
(' values"' if summary != 1 else ' value"')
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger, dict):
debugger.HandleCommand(
"type summary add -F NSSet.NSSet_SummaryProvider NSSet")
debugger.HandleCommand(
"type summary add -F NSSet.NSSet_SummaryProvider2 CFSetRef CFMutableSetRef")

View File

@ -22,116 +22,132 @@ statistics.add_metric('code_notrun')
# despite the similary to synthetic children providers, these classes are not # despite the similary to synthetic children providers, these classes are not
# trying to provide anything but a summary for an NSURL, so they need not # trying to provide anything but a summary for an NSURL, so they need not
# obey the interface specification for synthetic children providers # obey the interface specification for synthetic children providers
class NSURLKnown_SummaryProvider: class NSURLKnown_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
if not(self.sys_params.types_cache.NSString):
self.sys_params.types_cache.NSString = self.valobj.GetTarget().FindFirstType('NSString').GetPointerType()
if not(self.sys_params.types_cache.NSURL):
self.sys_params.types_cache.NSURL = self.valobj.GetTarget().FindFirstType('NSURL').GetPointerType()
self.update();
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
if not(self.sys_params.types_cache.NSString):
self.sys_params.types_cache.NSString = self.valobj.GetTarget(
).FindFirstType('NSString').GetPointerType()
if not(self.sys_params.types_cache.NSURL):
self.sys_params.types_cache.NSURL = self.valobj.GetTarget(
).FindFirstType('NSURL').GetPointerType()
self.update()
# one pointer is the ISA def update(self):
# then there is one more pointer and 8 bytes of plain data logger = lldb.formatters.Logger.Logger()
# (which are also present on a 32-bit system) self.adjust_for_architecture()
# then there is a pointer to an NSString which is the url text
# optionally, the next pointer is another NSURL which is the "base"
# of this one when doing NSURLs composition (incidentally, NSURLs can
# recurse the base+text mechanism to any desired depth)
def offset_text(self):
logger = lldb.formatters.Logger.Logger()
return 24 if self.sys_params.is_64_bit else 16
def offset_base(self):
logger = lldb.formatters.Logger.Logger()
return self.offset_text()+self.sys_params.pointer_size
def url_text(self): # one pointer is the ISA
logger = lldb.formatters.Logger.Logger() # then there is one more pointer and 8 bytes of plain data
text = self.valobj.CreateChildAtOffset("text", # (which are also present on a 32-bit system)
self.offset_text(), # then there is a pointer to an NSString which is the url text
self.sys_params.types_cache.NSString) # optionally, the next pointer is another NSURL which is the "base"
base = self.valobj.CreateChildAtOffset("base", # of this one when doing NSURLs composition (incidentally, NSURLs can
self.offset_base(), # recurse the base+text mechanism to any desired depth)
self.sys_params.types_cache.NSURL) def offset_text(self):
my_string = CFString.CFString_SummaryProvider(text,None) logger = lldb.formatters.Logger.Logger()
if len(my_string) > 0 and base.GetValueAsUnsigned(0) != 0: return 24 if self.sys_params.is_64_bit else 16
# remove final " from myself
my_string = my_string[0:len(my_string)-1] def offset_base(self):
my_string = my_string + ' -- ' logger = lldb.formatters.Logger.Logger()
my_base_string = NSURL_SummaryProvider(base,None) return self.offset_text() + self.sys_params.pointer_size
if len(my_base_string) > 2:
# remove @" marker from base URL string def url_text(self):
my_base_string = my_base_string[2:] logger = lldb.formatters.Logger.Logger()
my_string = my_string + my_base_string text = self.valobj.CreateChildAtOffset(
return my_string "text", self.offset_text(), self.sys_params.types_cache.NSString)
base = self.valobj.CreateChildAtOffset(
"base", self.offset_base(), self.sys_params.types_cache.NSURL)
my_string = CFString.CFString_SummaryProvider(text, None)
if len(my_string) > 0 and base.GetValueAsUnsigned(0) != 0:
# remove final " from myself
my_string = my_string[0:len(my_string) - 1]
my_string = my_string + ' -- '
my_base_string = NSURL_SummaryProvider(base, None)
if len(my_base_string) > 2:
# remove @" marker from base URL string
my_base_string = my_base_string[2:]
my_string = my_string + my_base_string
return my_string
class NSURLUnknown_SummaryProvider: class NSURLUnknown_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params): def adjust_for_architecture(self):
logger = lldb.formatters.Logger.Logger() pass
self.valobj = valobj;
self.sys_params = params
self.update()
def update(self): def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture(); self.valobj = valobj
self.sys_params = params
self.update()
def url_text(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream() self.adjust_for_architecture()
self.valobj.GetExpressionPath(stream)
url_text_vo = self.valobj.CreateValueFromExpression("url","(NSString*)[" + stream.GetData() + " description]") def url_text(self):
if url_text_vo.IsValid(): logger = lldb.formatters.Logger.Logger()
return CFString.CFString_SummaryProvider(url_text_vo,None) stream = lldb.SBStream()
return '<variable is not NSURL>' self.valobj.GetExpressionPath(stream)
url_text_vo = self.valobj.CreateValueFromExpression(
"url", "(NSString*)[" + stream.GetData() + " description]")
if url_text_vo.IsValid():
return CFString.CFString_SummaryProvider(url_text_vo, None)
return '<variable is not NSURL>'
def GetSummary_Impl(valobj): def GetSummary_Impl(valobj):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
global statistics global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics) class_data, wrapper = lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(
if wrapper: valobj, statistics)
return wrapper if wrapper:
return wrapper
name_string = class_data.class_name()
logger >> "class name is: " + str(name_string)
if name_string == 'NSURL': name_string = class_data.class_name()
wrapper = NSURLKnown_SummaryProvider(valobj, class_data.sys_params) logger >> "class name is: " + str(name_string)
statistics.metric_hit('code_notrun',valobj)
else:
wrapper = NSURLUnknown_SummaryProvider(valobj, class_data.sys_params)
statistics.metric_hit('unknown_class',valobj.GetName() + " seen as " + name_string)
return wrapper;
def NSURL_SummaryProvider (valobj,dict): if name_string == 'NSURL':
logger = lldb.formatters.Logger.Logger() wrapper = NSURLKnown_SummaryProvider(valobj, class_data.sys_params)
provider = GetSummary_Impl(valobj); statistics.metric_hit('code_notrun', valobj)
if provider != None: else:
if isinstance(provider,lldb.runtime.objc.objc_runtime.SpecialSituation_Description): wrapper = NSURLUnknown_SummaryProvider(valobj, class_data.sys_params)
return provider.message() statistics.metric_hit(
try: 'unknown_class',
summary = provider.url_text(); valobj.GetName() +
except: " seen as " +
summary = None name_string)
logger >> "got summary " + str(summary) return wrapper
if summary == None or summary == '':
summary = '<variable is not NSURL>'
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger,dict):
debugger.HandleCommand("type summary add -F NSURL.NSURL_SummaryProvider NSURL CFURLRef") def NSURL_SummaryProvider(valobj, dict):
logger = lldb.formatters.Logger.Logger()
provider = GetSummary_Impl(valobj)
if provider is not None:
if isinstance(
provider,
lldb.runtime.objc.objc_runtime.SpecialSituation_Description):
return provider.message()
try:
summary = provider.url_text()
except:
summary = None
logger >> "got summary " + str(summary)
if summary is None or summary == '':
summary = '<variable is not NSURL>'
return summary
return 'Summary Unavailable'
def __lldb_init_module(debugger, dict):
debugger.HandleCommand(
"type summary add -F NSURL.NSURL_SummaryProvider NSURL CFURLRef")

View File

@ -7,8 +7,13 @@ License. See LICENSE.TXT for details.
""" """
import lldb import lldb
def SEL_Summary(valobj,dict):
return valobj.Cast(valobj.GetType().GetBasicType(lldb.eBasicTypeChar).GetPointerType()).GetSummary()
def SELPointer_Summary(valobj,dict): def SEL_Summary(valobj, dict):
return valobj.CreateValueFromAddress('text',valobj.GetValueAsUnsigned(0),valobj.GetType().GetBasicType(lldb.eBasicTypeChar)).AddressOf().GetSummary() return valobj.Cast(valobj.GetType().GetBasicType(
lldb.eBasicTypeChar).GetPointerType()).GetSummary()
def SELPointer_Summary(valobj, dict):
return valobj.CreateValueFromAddress(
'text', valobj.GetValueAsUnsigned(0), valobj.GetType().GetBasicType(
lldb.eBasicTypeChar)).AddressOf().GetSummary()

View File

@ -5,34 +5,38 @@ part of The LLVM Compiler Infrastructure
This file is distributed under the University of Illinois Open Source This file is distributed under the University of Illinois Open Source
License. See LICENSE.TXT for details. License. See LICENSE.TXT for details.
""" """
class AttributesDictionary: class AttributesDictionary:
def __init__(self, allow_reset = True):
self.__dict__['_dictionary'] = {} # need to do it this way to prevent endless recursion
self.__dict__['_allow_reset'] = allow_reset
def __getattr__(self,name): def __init__(self, allow_reset=True):
if not self._check_exists(name): # need to do it this way to prevent endless recursion
return None self.__dict__['_dictionary'] = {}
value = self._dictionary[name] self.__dict__['_allow_reset'] = allow_reset
return value
def _set_impl(self,name,value): def __getattr__(self, name):
self._dictionary[name] = value if not self._check_exists(name):
return None
value = self._dictionary[name]
return value
def _check_exists(self,name): def _set_impl(self, name, value):
return name in self._dictionary self._dictionary[name] = value
def __setattr__(self,name,value): def _check_exists(self, name):
if self._allow_reset: return name in self._dictionary
self._set_impl(name,value)
else:
self.set_if_necessary(name,value)
def set_if_necessary(self,name,value): def __setattr__(self, name, value):
if not self._check_exists(name): if self._allow_reset:
self._set_impl(name,value) self._set_impl(name, value)
return True else:
return False self.set_if_necessary(name, value)
def __len__(self): def set_if_necessary(self, name, value):
return len(self._dictionary) if not self._check_exists(name):
self._set_impl(name, value)
return True
return False
def __len__(self):
return len(self._dictionary)

View File

@ -7,29 +7,30 @@ License. See LICENSE.TXT for details.
""" """
import lldb.formatters.metrics import lldb.formatters.metrics
class Cache: class Cache:
def __init__(self):
self.data = {}
self.statistics = lldb.formatters.metrics.Metrics()
self.statistics.add_metric('hit')
self.statistics.add_metric('miss')
def look_for_key(self,key): def __init__(self):
if key in self.data: self.data = {}
return True self.statistics = lldb.formatters.metrics.Metrics()
return False self.statistics.add_metric('hit')
self.statistics.add_metric('miss')
def add_item(self,key,value,ok_to_replace=True): def look_for_key(self, key):
if not(ok_to_replace) and self.look_for_key(key): if key in self.data:
return False return True
self.data[key] = value return False
return True
def get_value(self,key,default=None): def add_item(self, key, value, ok_to_replace=True):
if self.look_for_key(key): if not(ok_to_replace) and self.look_for_key(key):
self.statistics.metric_hit('hit',key) return False
return self.data[key] self.data[key] = value
else: return True
self.statistics.metric_hit('miss',key)
return default
def get_value(self, key, default=None):
if self.look_for_key(key):
self.statistics.metric_hit('hit', key)
return self.data[key]
else:
self.statistics.metric_hit('miss', key)
return default

View File

@ -6,89 +6,107 @@ This file is distributed under the University of Illinois Open Source
License. See LICENSE.TXT for details. License. See LICENSE.TXT for details.
""" """
import lldb import lldb
import time, datetime import time
import datetime
import inspect import inspect
class TimeMetrics: class TimeMetrics:
@staticmethod
def generate(label=None): @staticmethod
return TimeMetrics(label) def generate(label=None):
return TimeMetrics(label)
def __init__(self,lbl=None):
self.label = "" if lbl is None else lbl def __init__(self, lbl=None):
pass self.label = "" if lbl is None else lbl
pass
def __enter__(self):
caller = inspect.stack()[1] def __enter__(self):
self.function = str(caller) caller = inspect.stack()[1]
self.enter_time = time.clock() self.function = str(caller)
self.enter_time = time.clock()
def __exit__(self, a,b,c):
self.exit_time = time.clock() def __exit__(self, a, b, c):
print("It took " + str(self.exit_time - self.enter_time) + " time units to run through " + self.function + self.label) self.exit_time = time.clock()
return False print("It took " + str(self.exit_time - self.enter_time) +
" time units to run through " + self.function + self.label)
return False
class Counter: class Counter:
def __init__(self):
self.count = 0 def __init__(self):
self.list = [] self.count = 0
def update(self,name): self.list = []
self.count = self.count + 1
# avoid getting the full dump of this ValueObject just to save its metrics def update(self, name):
if isinstance(name,lldb.SBValue): self.count = self.count + 1
self.list.append(name.GetName()) # avoid getting the full dump of this ValueObject just to save its
else: # metrics
self.list.append(str(name)) if isinstance(name, lldb.SBValue):
def __str__(self): self.list.append(name.GetName())
return str(self.count) + " times, for items [" + str(self.list) + "]" else:
self.list.append(str(name))
def __str__(self):
return str(self.count) + " times, for items [" + str(self.list) + "]"
class MetricsPrinter_Verbose: class MetricsPrinter_Verbose:
def __init__(self,metrics):
self.metrics = metrics def __init__(self, metrics):
def __str__(self): self.metrics = metrics
string = ""
for key,value in self.metrics.metrics.items(): def __str__(self):
string = string + "metric " + str(key) + ": " + str(value) + "\n" string = ""
return string for key, value in self.metrics.metrics.items():
string = string + "metric " + str(key) + ": " + str(value) + "\n"
return string
class MetricsPrinter_Compact: class MetricsPrinter_Compact:
def __init__(self,metrics):
self.metrics = metrics def __init__(self, metrics):
def __str__(self): self.metrics = metrics
string = ""
for key,value in self.metrics.metrics.items(): def __str__(self):
string = string + "metric " + str(key) + " was hit " + str(value.count) + " times\n" string = ""
return string for key, value in self.metrics.metrics.items():
string = string + "metric " + \
str(key) + " was hit " + str(value.count) + " times\n"
return string
class Metrics: class Metrics:
def __init__(self):
self.metrics = {}
def add_metric(self,name): def __init__(self):
self.metrics[name] = Counter() self.metrics = {}
def metric_hit(self,metric,trigger): def add_metric(self, name):
self.metrics[metric].update(trigger) self.metrics[name] = Counter()
def __getitem__(self,key): def metric_hit(self, metric, trigger):
return self.metrics[key] self.metrics[metric].update(trigger)
def __getattr__(self,name): def __getitem__(self, key):
if name == 'compact': return self.metrics[key]
return MetricsPrinter_Compact(self)
if name == 'verbose':
return MetricsPrinter_Verbose(self)
raise AttributeError("%r object has no attribute %r" %
(type(self).__name__, name))
def __str__(self): def __getattr__(self, name):
return str(self.verbose) if name == 'compact':
return MetricsPrinter_Compact(self)
if name == 'verbose':
return MetricsPrinter_Verbose(self)
raise AttributeError("%r object has no attribute %r" %
(type(self).__name__, name))
def metric_success(self,metric): def __str__(self):
total_count = 0 return str(self.verbose)
metric_count = self[metric].count
for key,value in self.metrics.items(): def metric_success(self, metric):
total_count = total_count + value.count total_count = 0
if total_count > 0: metric_count = self[metric].count
return metric_count / float(total_count) for key, value in self.metrics.items():
return 0 total_count = total_count + value.count
if total_count > 0:
return metric_count / float(total_count)
return 0

File diff suppressed because it is too large Load Diff

View File

@ -1,16 +1,19 @@
# Summaries for common ObjC types that require Python scripting # Summaries for common ObjC types that require Python scripting
# to be generated fit into this file # to be generated fit into this file
def BOOL_SummaryProvider (valobj,dict):
if not (valobj.IsValid()):
return "<invalid>"
if valobj.GetValueAsUnsigned() == 0:
return "NO"
else:
return "YES"
def BOOLRef_SummaryProvider (valobj, dict): def BOOL_SummaryProvider(valobj, dict):
return BOOL_SummaryProvider (valobj.GetChildAtIndex(0),dict) if not (valobj.IsValid()):
return "<invalid>"
if valobj.GetValueAsUnsigned() == 0:
return "NO"
else:
return "YES"
def BOOLPtr_SummaryProvider (valobj,dict):
return BOOL_SummaryProvider (valobj.Dereference(),dict) def BOOLRef_SummaryProvider(valobj, dict):
return BOOL_SummaryProvider(valobj.GetChildAtIndex(0), dict)
def BOOLPtr_SummaryProvider(valobj, dict):
return BOOL_SummaryProvider(valobj.Dereference(), dict)

View File

@ -1,18 +1,24 @@
import lldb import lldb
def pyobj_summary (value,unused):
if value == None or value.IsValid() == False or value.GetValueAsUnsigned(0) == 0: def pyobj_summary(value, unused):
return "<invalid>" if value is None or value.IsValid() == False or value.GetValueAsUnsigned(0) == 0:
refcnt = value.GetChildMemberWithName("ob_refcnt") return "<invalid>"
expr = "(char*)PyString_AsString( (PyObject*)PyObject_Str( (PyObject*)0x%x) )" % (value.GetValueAsUnsigned(0)) refcnt = value.GetChildMemberWithName("ob_refcnt")
expr_summary = value.target.EvaluateExpression(expr,lldb.SBExpressionOptions()).GetSummary() expr = "(char*)PyString_AsString( (PyObject*)PyObject_Str( (PyObject*)0x%x) )" % (
refcnt_value = "rc = %d" % (refcnt.GetValueAsUnsigned(0)) value.GetValueAsUnsigned(0))
return "%s (%s)" % (expr_summary,refcnt_value) expr_summary = value.target.EvaluateExpression(
expr, lldb.SBExpressionOptions()).GetSummary()
refcnt_value = "rc = %d" % (refcnt.GetValueAsUnsigned(0))
return "%s (%s)" % (expr_summary, refcnt_value)
def __lldb_init_module(debugger, unused): def __lldb_init_module(debugger, unused):
debugger.HandleCommand("type summary add PyObject --python-function pysummary.pyobj_summary") debugger.HandleCommand(
debugger.HandleCommand("type summary add lldb_private::PythonObject -s ${var.m_py_obj%S}") "type summary add PyObject --python-function pysummary.pyobj_summary")
debugger.HandleCommand("type summary add lldb_private::PythonDictionary -s ${var.m_py_obj%S}") debugger.HandleCommand(
debugger.HandleCommand("type summary add lldb_private::PythonString -s ${var.m_py_obj%S}") "type summary add lldb_private::PythonObject -s ${var.m_py_obj%S}")
debugger.HandleCommand(
"type summary add lldb_private::PythonDictionary -s ${var.m_py_obj%S}")
debugger.HandleCommand(
"type summary add lldb_private::PythonString -s ${var.m_py_obj%S}")

View File

@ -6,56 +6,79 @@ This file is distributed under the University of Illinois Open Source
License. See LICENSE.TXT for details. License. See LICENSE.TXT for details.
""" """
class SharedPtr_SyntheticChildrenProvider:
def __init__(self,valobj,dict):
self.valobj = valobj
self.update()
def update(self):
pass
def num_children(self):
return 1
def get_child_index(self,name):
if name == "ptr":
return 0
if name == "count":
return 1
return None
def get_child_at_index(self,index):
if index == 0:
return self.valobj.GetChildMemberWithName('_M_ptr')
if index == 1:
return self.valobj.GetChildMemberWithName('_M_refcount').GetChildMemberWithName('_M_pi').GetChildMemberWithName('_M_use_count')
return None
def SharedPtr_SummaryProvider (valobj,dict): class SharedPtr_SyntheticChildrenProvider:
return 'use = ' + str(valobj.GetChildMemberWithName("count").GetValueAsUnsigned())
def __init__(self, valobj, dict):
self.valobj = valobj
self.update()
def update(self):
pass
def num_children(self):
return 1
def get_child_index(self, name):
if name == "ptr":
return 0
if name == "count":
return 1
return None
def get_child_at_index(self, index):
if index == 0:
return self.valobj.GetChildMemberWithName('_M_ptr')
if index == 1:
return self.valobj.GetChildMemberWithName('_M_refcount').GetChildMemberWithName(
'_M_pi').GetChildMemberWithName('_M_use_count')
return None
def SharedPtr_SummaryProvider(valobj, dict):
return 'use = ' + \
str(valobj.GetChildMemberWithName("count").GetValueAsUnsigned())
class ValueObjectSP_SyntheticChildrenProvider: class ValueObjectSP_SyntheticChildrenProvider:
def __init__(self,valobj,dict):
self.valobj = valobj
self.update()
def update(self):
pass
def num_children(self):
return 1
def get_child_index(self,name):
if name == "ptr":
return 0
if name == "count":
return 1
return None
def get_child_at_index(self,index):
if index == 0:
return self.valobj.GetChildMemberWithName('ptr_')
if index == 1:
return self.valobj.GetChildMemberWithName('cntrl_').GetChildMemberWithName('shared_owners_')
return None
def ValueObjectSP_SummaryProvider (valobj,dict): def __init__(self, valobj, dict):
return 'use = ' + str(1 + valobj.GetChildMemberWithName("count").GetValueAsUnsigned()) self.valobj = valobj
self.update()
def update(self):
pass
def num_children(self):
return 1
def get_child_index(self, name):
if name == "ptr":
return 0
if name == "count":
return 1
return None
def get_child_at_index(self, index):
if index == 0:
return self.valobj.GetChildMemberWithName('ptr_')
if index == 1:
return self.valobj.GetChildMemberWithName(
'cntrl_').GetChildMemberWithName('shared_owners_')
return None
def ValueObjectSP_SummaryProvider(valobj, dict):
return 'use = ' + \
str(1 + valobj.GetChildMemberWithName("count").GetValueAsUnsigned())
def __lldb_init_module(debugger, dict): def __lldb_init_module(debugger, dict):
debugger.HandleCommand('type summary add -x ".*ValueObjectSP" --expand -F sp_cp.ValueObjectSP_SummaryProvider') debugger.HandleCommand(
debugger.HandleCommand('type synthetic add -x ".*ValueObjectSP" -l sp_cp.ValueObjectSP_SyntheticChildrenProvider') 'type summary add -x ".*ValueObjectSP" --expand -F sp_cp.ValueObjectSP_SummaryProvider')
debugger.HandleCommand('type summary add -x ".*SP" --expand -F sp_cp.SharedPtr_SummaryProvider') debugger.HandleCommand(
debugger.HandleCommand('type synthetic add -x ".*SP" -l sp_cp.SharedPtr_SyntheticChildrenProvider') 'type synthetic add -x ".*ValueObjectSP" -l sp_cp.ValueObjectSP_SyntheticChildrenProvider')
debugger.HandleCommand(
'type summary add -x ".*SP" --expand -F sp_cp.SharedPtr_SummaryProvider')
debugger.HandleCommand(
'type synthetic add -x ".*SP" -l sp_cp.SharedPtr_SyntheticChildrenProvider')

View File

@ -1,57 +1,66 @@
import lldb import lldb
class PythonObjectSyntheticChildProvider(object): class PythonObjectSyntheticChildProvider(object):
def __init__(self, value, internal_dict):
self.value = value def __init__(self, value, internal_dict):
self.values = self.make_children() self.value = value
self.built_values = {} self.values = self.make_children()
self.bo = self.value.target.byte_order self.built_values = {}
self.ps = self.value.target.addr_size self.bo = self.value.target.byte_order
self.ps = self.value.target.addr_size
def make_children(self):
pass def make_children(self):
pass
def num_children(self):
return len(self.values) def num_children(self):
return len(self.values)
def get_child_index(self, name):
i = 0 def get_child_index(self, name):
for N, value in self.values: i = 0
if N == name: return i for N, value in self.values:
i += 1 if N == name:
return None return i
i += 1
def update(self): return None
pass
def update(self):
def has_children(self): pass
return len(self.values) > 0
def has_children(self):
def gen_child(self, name, value): return len(self.values) > 0
data = None; type = None
if isinstance(value, int): def gen_child(self, name, value):
data = lldb.SBData.CreateDataFromUInt32Array(self.bo, self.ps, [value]) data = None
type = self.value.target.GetBasicType(lldb.eBasicTypeInt) type = None
elif isinstance(value, long): if isinstance(value, int):
data = lldb.SBData.CreateDataFromUInt64Array(self.bo, self.ps, [value]) data = lldb.SBData.CreateDataFromUInt32Array(
type = self.value.target.GetBasicType(lldb.eBasicTypeLong) self.bo, self.ps, [value])
elif isinstance(value, float): type = self.value.target.GetBasicType(lldb.eBasicTypeInt)
data = lldb.SBData.CreateDataFromDoubleArray(self.bo, self.ps, [value]) elif isinstance(value, long):
type = self.value.target.GetBasicType(lldb.eBasicTypeDouble) data = lldb.SBData.CreateDataFromUInt64Array(
elif isinstance(value, str): self.bo, self.ps, [value])
data = lldb.SBData.CreateDataFromCString(self.bo, self.ps, value) type = self.value.target.GetBasicType(lldb.eBasicTypeLong)
type = self.value.target.GetBasicType(lldb.eBasicTypeChar).GetArrayType(len(value)) elif isinstance(value, float):
if (data is not None) and (type is not None): data = lldb.SBData.CreateDataFromDoubleArray(
return self.value.CreateValueFromData(name, data, type) self.bo, self.ps, [value])
return None type = self.value.target.GetBasicType(lldb.eBasicTypeDouble)
elif isinstance(value, str):
def get_child_at_index(self, index): data = lldb.SBData.CreateDataFromCString(self.bo, self.ps, value)
if index in self.built_values: type = self.value.target.GetBasicType(
return self.built_values[index] lldb.eBasicTypeChar).GetArrayType(
len(value))
bv = None if (data is not None) and (type is not None):
return self.value.CreateValueFromData(name, data, type)
name, value = self.values[index] return None
bv = self.gen_child(name, value)
self.built_values[index] = bv def get_child_at_index(self, index):
return bv if index in self.built_values:
return self.built_values[index]
bv = None
name, value = self.values[index]
bv = self.gen_child(name, value)
self.built_values[index] = bv
return bv

View File

@ -11,38 +11,43 @@ License. See LICENSE.TXT for details.
""" """
import lldb import lldb
def utf8_summary(value,unused):
pointer = value.GetChildMemberWithName("first").GetValueAsUnsigned(0)
length = value.GetChildMemberWithName("second").GetValueAsUnsigned(0)
if pointer == 0:
return False
if length == 0:
return '""'
error = lldb.SBError()
string_data = value.process.ReadMemory(pointer, length, error)
return '"%s"' % (string_data) # utf8 is safe to emit as-is on OSX
def utf16_summary(value,unused):
pointer = value.GetChildMemberWithName("first").GetValueAsUnsigned(0)
length = value.GetChildMemberWithName("second").GetValueAsUnsigned(0)
# assume length is in bytes - if in UTF16 chars, just multiply by 2
if pointer == 0:
return False
if length == 0:
return '""'
error = lldb.SBError()
string_data = value.process.ReadMemory(pointer, length, error)
return '"%s"' % (string_data.decode('utf-16').encode('utf-8')) # utf8 is safe to emit as-is on OSX
def utf32_summary(value,unused): def utf8_summary(value, unused):
pointer = value.GetChildMemberWithName("first").GetValueAsUnsigned(0) pointer = value.GetChildMemberWithName("first").GetValueAsUnsigned(0)
length = value.GetChildMemberWithName("second").GetValueAsUnsigned(0) length = value.GetChildMemberWithName("second").GetValueAsUnsigned(0)
# assume length is in bytes - if in UTF32 chars, just multiply by 4 if pointer == 0:
if pointer == 0: return False
return False if length == 0:
if length == 0: return '""'
return '""' error = lldb.SBError()
error = lldb.SBError() string_data = value.process.ReadMemory(pointer, length, error)
string_data = value.process.ReadMemory(pointer, length, error) return '"%s"' % (string_data) # utf8 is safe to emit as-is on OSX
return '"%s"' % (string_data.decode('utf-32').encode('utf-8')) # utf8 is safe to emit as-is on OSX
def utf16_summary(value, unused):
pointer = value.GetChildMemberWithName("first").GetValueAsUnsigned(0)
length = value.GetChildMemberWithName("second").GetValueAsUnsigned(0)
# assume length is in bytes - if in UTF16 chars, just multiply by 2
if pointer == 0:
return False
if length == 0:
return '""'
error = lldb.SBError()
string_data = value.process.ReadMemory(pointer, length, error)
# utf8 is safe to emit as-is on OSX
return '"%s"' % (string_data.decode('utf-16').encode('utf-8'))
def utf32_summary(value, unused):
pointer = value.GetChildMemberWithName("first").GetValueAsUnsigned(0)
length = value.GetChildMemberWithName("second").GetValueAsUnsigned(0)
# assume length is in bytes - if in UTF32 chars, just multiply by 4
if pointer == 0:
return False
if length == 0:
return '""'
error = lldb.SBError()
string_data = value.process.ReadMemory(pointer, length, error)
# utf8 is safe to emit as-is on OSX
return '"%s"' % (string_data.decode('utf-32').encode('utf-8'))

View File

@ -1,100 +1,123 @@
# Synthetic children provider example for class MaskedData # Synthetic children provider example for class MaskedData
# to use me: # to use me:
# command script import ./example.py --allow-reload # command script import ./example.py --allow-reload
# type synthetic add MaskedData --python-class example.MaskedData_SyntheticChildrenProvider # type synthetic add MaskedData --python-class
# example.MaskedData_SyntheticChildrenProvider
class MaskedData_SyntheticChildrenProvider: class MaskedData_SyntheticChildrenProvider:
def __init__(self, valobj, dict):
self.valobj = valobj # remember the SBValue since you will not have another chance to get it :-)
def num_children(self): def __init__(self, valobj, dict):
# you could perform calculations involving the SBValue and/or its children to determine this value # remember the SBValue since you will not have another chance to get it
# here, we have an hardcoded value - but since you have stored the SBValue you could use it to # :-)
# help figure out the correct thing to return here. if you return a number N, you should be prepared to self.valobj = valobj
# answer questions about N children
return 4
def has_children(self): def num_children(self):
# we simply say True here because we know we have 4 children # you could perform calculations involving the SBValue and/or its children to determine this value
# in general, you want to make this calculation as simple as possible # here, we have an hardcoded value - but since you have stored the SBValue you could use it to
# and return True if in doubt (you can always return num_children == 0 later) # help figure out the correct thing to return here. if you return a number N, you should be prepared to
return True # answer questions about N children
return 4
def get_child_index(self,name): def has_children(self):
# given a name, return its index # we simply say True here because we know we have 4 children
# you can return None if you don't know the answer for a given name # in general, you want to make this calculation as simple as possible
if name == "value": # and return True if in doubt (you can always return num_children == 0
return 0 # later)
# here, we are using a reserved C++ keyword as a child name - we could not do that in the source code return True
# but we are free to use the names we like best in the synthetic children provider class
# we are also not respecting the order of declaration in the C++ class itself - as long as
# we are consistent, we can do that freely
if name == "operator":
return 1
if name == "mask":
return 2
# this member does not exist in the original class - we will compute its value and show it to the user
# when returning synthetic children, there is no need to only stick to what already exists in memory
if name == "apply()":
return 3
return None # no clue, just say none
def get_child_at_index(self,index): def get_child_index(self, name):
# precautionary measures # given a name, return its index
if index < 0: # you can return None if you don't know the answer for a given name
return None if name == "value":
if index > self.num_children(): return 0
return None # here, we are using a reserved C++ keyword as a child name - we could not do that in the source code
if self.valobj.IsValid() == False: # but we are free to use the names we like best in the synthetic children provider class
return None # we are also not respecting the order of declaration in the C++ class itself - as long as
if index == 0: # we are consistent, we can do that freely
return self.valobj.GetChildMemberWithName("value") if name == "operator":
if index == 1: return 1
# fetch the value of the operator if name == "mask":
op_chosen = self.valobj.GetChildMemberWithName("oper").GetValueAsUnsigned() return 2
# if it is a known value, return a descriptive string for it # this member does not exist in the original class - we will compute its value and show it to the user
# we are not doing this in the most efficient possible way, but the code is very readable # when returning synthetic children, there is no need to only stick to
# and easy to maintain - if you change the values on the C++ side, the same changes must be made here # what already exists in memory
if op_chosen == 0: if name == "apply()":
return self.valobj.CreateValueFromExpression("operator",'(const char*)"none"') return 3
elif op_chosen == 1: return None # no clue, just say none
return self.valobj.CreateValueFromExpression("operator",'(const char*)"AND"')
elif op_chosen == 2:
return self.valobj.CreateValueFromExpression("operator",'(const char*)"OR"')
elif op_chosen == 3:
return self.valobj.CreateValueFromExpression("operator",'(const char*)"XOR"')
elif op_chosen == 4:
return self.valobj.CreateValueFromExpression("operator",'(const char*)"NAND"')
elif op_chosen == 5:
return self.valobj.CreateValueFromExpression("operator",'(const char*)"NOR"')
else:
return self.valobj.CreateValueFromExpression("operator",'(const char*)"unknown"') # something else
if index == 2:
return self.valobj.GetChildMemberWithName("mask")
if index == 3:
# for this, we must fetch all the other elements
# in an efficient implementation, we would be caching this data for efficiency
value = self.valobj.GetChildMemberWithName("value").GetValueAsUnsigned()
operator = self.valobj.GetChildMemberWithName("oper").GetValueAsUnsigned()
mask = self.valobj.GetChildMemberWithName("mask").GetValueAsUnsigned()
# compute the masked value according to the operator
if operator == 1:
value = value & mask
elif operator == 2:
value = value | mask
elif operator == 3:
value = value ^ mask
elif operator == 4:
value = ~(value & mask)
elif operator == 5:
value = ~(value | mask)
else:
pass
value &= 0xFFFFFFFF # make sure Python does not extend our values to 64-bits
# return it - again, not the most efficient possible way. we should actually be pushing the computed value
# into an SBData, and using the SBData to create an SBValue - this has the advantage of readability
return self.valobj.CreateValueFromExpression("apply()",'(uint32_t)(' + str(value) + ')')
def update(self): def get_child_at_index(self, index):
# we do not do anything special in update - but this would be the right place to lookup # precautionary measures
# the data we use in get_child_at_index and cache it if index < 0:
pass return None
if index > self.num_children():
return None
if self.valobj.IsValid() == False:
return None
if index == 0:
return self.valobj.GetChildMemberWithName("value")
if index == 1:
# fetch the value of the operator
op_chosen = self.valobj.GetChildMemberWithName(
"oper").GetValueAsUnsigned()
# if it is a known value, return a descriptive string for it
# we are not doing this in the most efficient possible way, but the code is very readable
# and easy to maintain - if you change the values on the C++ side,
# the same changes must be made here
if op_chosen == 0:
return self.valobj.CreateValueFromExpression(
"operator", '(const char*)"none"')
elif op_chosen == 1:
return self.valobj.CreateValueFromExpression(
"operator", '(const char*)"AND"')
elif op_chosen == 2:
return self.valobj.CreateValueFromExpression(
"operator", '(const char*)"OR"')
elif op_chosen == 3:
return self.valobj.CreateValueFromExpression(
"operator", '(const char*)"XOR"')
elif op_chosen == 4:
return self.valobj.CreateValueFromExpression(
"operator", '(const char*)"NAND"')
elif op_chosen == 5:
return self.valobj.CreateValueFromExpression(
"operator", '(const char*)"NOR"')
else:
return self.valobj.CreateValueFromExpression(
"operator", '(const char*)"unknown"') # something else
if index == 2:
return self.valobj.GetChildMemberWithName("mask")
if index == 3:
# for this, we must fetch all the other elements
# in an efficient implementation, we would be caching this data for
# efficiency
value = self.valobj.GetChildMemberWithName(
"value").GetValueAsUnsigned()
operator = self.valobj.GetChildMemberWithName(
"oper").GetValueAsUnsigned()
mask = self.valobj.GetChildMemberWithName(
"mask").GetValueAsUnsigned()
# compute the masked value according to the operator
if operator == 1:
value = value & mask
elif operator == 2:
value = value | mask
elif operator == 3:
value = value ^ mask
elif operator == 4:
value = ~(value & mask)
elif operator == 5:
value = ~(value | mask)
else:
pass
value &= 0xFFFFFFFF # make sure Python does not extend our values to 64-bits
# return it - again, not the most efficient possible way. we should actually be pushing the computed value
# into an SBData, and using the SBData to create an SBValue - this
# has the advantage of readability
return self.valobj.CreateValueFromExpression(
"apply()", '(uint32_t)(' + str(value) + ')')
def update(self):
# we do not do anything special in update - but this would be the right place to lookup
# the data we use in get_child_at_index and cache it
pass

View File

@ -1,74 +1,56 @@
typedef unsigned int uint32_t; typedef unsigned int uint32_t;
enum MaskingOperator enum MaskingOperator {
{ eMaskingOperatorDefault = 0,
eMaskingOperatorDefault = 0, eMaskingOperatorAnd = 1,
eMaskingOperatorAnd = 1, eMaskingOperatorOr = 2,
eMaskingOperatorOr = 2, eMaskingOperatorXor = 3,
eMaskingOperatorXor = 3, eMaskingOperatorNand = 4,
eMaskingOperatorNand = 4, eMaskingOperatorNor = 5
eMaskingOperatorNor = 5
}; };
class MaskedData class MaskedData {
{
private: private:
uint32_t value; uint32_t value;
uint32_t mask; uint32_t mask;
MaskingOperator oper; MaskingOperator oper;
public: public:
MaskedData( uint32_t V = 0, MaskedData(uint32_t V = 0, uint32_t M = 0,
uint32_t M = 0, MaskingOperator P = eMaskingOperatorDefault)
MaskingOperator P = eMaskingOperatorDefault) : : value(V), mask(M), oper(P) {}
value(V),
mask(M), uint32_t apply() {
oper(P) switch (oper) {
{ case eMaskingOperatorAnd:
} return value & mask;
case eMaskingOperatorOr:
uint32_t apply() return value | mask;
{ case eMaskingOperatorXor:
switch(oper) return value ^ mask;
{ case eMaskingOperatorNand:
case eMaskingOperatorAnd: return ~(value & mask);
return value & mask; case eMaskingOperatorNor:
case eMaskingOperatorOr: return ~(value | mask);
return value | mask; case eMaskingOperatorDefault: // fall through
case eMaskingOperatorXor: default:
return value ^ mask; return value;
case eMaskingOperatorNand: }
return ~(value & mask); }
case eMaskingOperatorNor:
return ~(value | mask); void setValue(uint32_t V) { value = V; }
case eMaskingOperatorDefault: // fall through
default: void setMask(uint32_t M) { mask = M; }
return value;
} void setOperator(MaskingOperator P) { oper = P; }
}
void setValue(uint32_t V)
{
value = V;
}
void setMask (uint32_t M)
{
mask = M;
}
void setOperator(MaskingOperator P)
{
oper = P;
}
}; };
int main() int main() {
{ MaskedData data_1(0xFF0F, 0xA01F, eMaskingOperatorAnd);
MaskedData data_1(0xFF0F,0xA01F,eMaskingOperatorAnd); MaskedData data_2(data_1.apply(), 0x1AFC, eMaskingOperatorXor);
MaskedData data_2(data_1.apply(),0x1AFC,eMaskingOperatorXor); MaskedData data_3(data_2.apply(), 0xFFCF, eMaskingOperatorOr);
MaskedData data_3(data_2.apply(),0xFFCF,eMaskingOperatorOr); MaskedData data_4(data_3.apply(), 0xAABC, eMaskingOperatorAnd);
MaskedData data_4(data_3.apply(),0xAABC,eMaskingOperatorAnd); MaskedData data_5(data_4.apply(), 0xFFAC, eMaskingOperatorNor);
MaskedData data_5(data_4.apply(),0xFFAC,eMaskingOperatorNor); MaskedData data_6(data_5.apply(), 0x0000BEEF, eMaskingOperatorAnd);
MaskedData data_6(data_5.apply(),0x0000BEEF,eMaskingOperatorAnd); return data_6.apply(); // <-- what comes out of here?
return data_6.apply(); // <-- what comes out of here?
} }

View File

@ -7,446 +7,474 @@ import lldb.formatters.Logger
# You are encouraged to look at the STL implementation for your platform # You are encouraged to look at the STL implementation for your platform
# before relying on these formatters to do the right thing for your setup # before relying on these formatters to do the right thing for your setup
class StdListSynthProvider: class StdListSynthProvider:
def __init__(self, valobj, dict): def __init__(self, valobj, dict):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.valobj = valobj self.valobj = valobj
self.count = None self.count = None
logger >> "Providing synthetic children for a list named " + str(valobj.GetName()) logger >> "Providing synthetic children for a list named " + \
str(valobj.GetName())
def next_node(self,node): def next_node(self, node):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
return node.GetChildMemberWithName('_M_next') return node.GetChildMemberWithName('_M_next')
def is_valid(self,node): def is_valid(self, node):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
valid = self.value(self.next_node(node)) != self.node_address valid = self.value(self.next_node(node)) != self.node_address
if valid: if valid:
logger >> "%s is valid" % str(self.valobj.GetName()) logger >> "%s is valid" % str(self.valobj.GetName())
else: else:
logger >> "synthetic value is not valid" logger >> "synthetic value is not valid"
return valid return valid
def value(self,node): def value(self, node):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
value = node.GetValueAsUnsigned() value = node.GetValueAsUnsigned()
logger >> "synthetic value for {}: {}".format(str(self.valobj.GetName()), value) logger >> "synthetic value for {}: {}".format(
return value str(self.valobj.GetName()), value)
return value
# Floyd's cycle-finding algorithm # Floyd's cycle-finding algorithm
# try to detect if this list has a loop # try to detect if this list has a loop
def has_loop(self): def has_loop(self):
global _list_uses_loop_detector global _list_uses_loop_detector
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
if _list_uses_loop_detector == False: if not _list_uses_loop_detector:
logger >> "Asked not to use loop detection" logger >> "Asked not to use loop detection"
return False return False
slow = self.next slow = self.next
fast1 = self.next fast1 = self.next
fast2 = self.next fast2 = self.next
while self.is_valid(slow): while self.is_valid(slow):
slow_value = self.value(slow) slow_value = self.value(slow)
fast1 = self.next_node(fast2) fast1 = self.next_node(fast2)
fast2 = self.next_node(fast1) fast2 = self.next_node(fast1)
if self.value(fast1) == slow_value or self.value(fast2) == slow_value: if self.value(fast1) == slow_value or self.value(
return True fast2) == slow_value:
slow = self.next_node(slow) return True
return False slow = self.next_node(slow)
return False
def num_children(self): def num_children(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
if self.count is None: if self.count is None:
# libstdc++ 6.0.21 added dedicated count field. # libstdc++ 6.0.21 added dedicated count field.
count_child = self.node.GetChildMemberWithName('_M_data') count_child = self.node.GetChildMemberWithName('_M_data')
if count_child and count_child.IsValid(): if count_child and count_child.IsValid():
self.count = count_child.GetValueAsUnsigned(0) self.count = count_child.GetValueAsUnsigned(0)
if self.count is None: if self.count is None:
self.count = self.num_children_impl() self.count = self.num_children_impl()
return self.count return self.count
def num_children_impl(self): def num_children_impl(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
try: try:
next_val = self.next.GetValueAsUnsigned(0) next_val = self.next.GetValueAsUnsigned(0)
prev_val = self.prev.GetValueAsUnsigned(0) prev_val = self.prev.GetValueAsUnsigned(0)
# After a std::list has been initialized, both next and prev will be non-NULL # After a std::list has been initialized, both next and prev will
if next_val == 0 or prev_val == 0: # be non-NULL
return 0 if next_val == 0 or prev_val == 0:
if next_val == self.node_address: return 0
return 0 if next_val == self.node_address:
if next_val == prev_val: return 0
return 1 if next_val == prev_val:
if self.has_loop(): return 1
return 0 if self.has_loop():
size = 2 return 0
current = self.next size = 2
while current.GetChildMemberWithName('_M_next').GetValueAsUnsigned(0) != self.node_address: current = self.next
size = size + 1 while current.GetChildMemberWithName(
current = current.GetChildMemberWithName('_M_next') '_M_next').GetValueAsUnsigned(0) != self.node_address:
return (size - 1) size = size + 1
except: current = current.GetChildMemberWithName('_M_next')
return 0; return (size - 1)
except:
return 0
def get_child_index(self,name): def get_child_index(self, name):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
try: try:
return int(name.lstrip('[').rstrip(']')) return int(name.lstrip('[').rstrip(']'))
except: except:
return -1 return -1
def get_child_at_index(self,index): def get_child_at_index(self, index):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
logger >> "Fetching child " + str(index) logger >> "Fetching child " + str(index)
if index < 0: if index < 0:
return None; return None
if index >= self.num_children(): if index >= self.num_children():
return None; return None
try: try:
offset = index offset = index
current = self.next current = self.next
while offset > 0: while offset > 0:
current = current.GetChildMemberWithName('_M_next') current = current.GetChildMemberWithName('_M_next')
offset = offset - 1 offset = offset - 1
return current.CreateChildAtOffset('['+str(index)+']',2*current.GetType().GetByteSize(),self.data_type) return current.CreateChildAtOffset(
except: '[' + str(index) + ']',
return None 2 * current.GetType().GetByteSize(),
self.data_type)
except:
return None
def extract_type(self): def extract_type(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
list_type = self.valobj.GetType().GetUnqualifiedType() list_type = self.valobj.GetType().GetUnqualifiedType()
if list_type.IsReferenceType(): if list_type.IsReferenceType():
list_type = list_type.GetDereferencedType() list_type = list_type.GetDereferencedType()
if list_type.GetNumberOfTemplateArguments() > 0: if list_type.GetNumberOfTemplateArguments() > 0:
data_type = list_type.GetTemplateArgumentType(0) data_type = list_type.GetTemplateArgumentType(0)
else: else:
data_type = None data_type = None
return data_type return data_type
def update(self): def update(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
# preemptively setting this to None - we might end up changing our mind later # preemptively setting this to None - we might end up changing our mind
self.count = None # later
try: self.count = None
impl = self.valobj.GetChildMemberWithName('_M_impl') try:
self.node = impl.GetChildMemberWithName('_M_node') impl = self.valobj.GetChildMemberWithName('_M_impl')
self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0) self.node = impl.GetChildMemberWithName('_M_node')
self.next = self.node.GetChildMemberWithName('_M_next') self.node_address = self.valobj.AddressOf().GetValueAsUnsigned(0)
self.prev = self.node.GetChildMemberWithName('_M_prev') self.next = self.node.GetChildMemberWithName('_M_next')
self.data_type = self.extract_type() self.prev = self.node.GetChildMemberWithName('_M_prev')
self.data_size = self.data_type.GetByteSize() self.data_type = self.extract_type()
except: self.data_size = self.data_type.GetByteSize()
pass except:
pass
def has_children(self):
return True
def has_children(self):
return True
class StdVectorSynthProvider: class StdVectorSynthProvider:
class StdVectorImplementation(object): class StdVectorImplementation(object):
def __init__(self, valobj):
self.valobj = valobj
self.count = None
def num_children(self): def __init__(self, valobj):
if self.count == None: self.valobj = valobj
self.count = self.num_children_impl() self.count = None
return self.count
def num_children_impl(self): def num_children(self):
try: if self.count is None:
start_val = self.start.GetValueAsUnsigned(0) self.count = self.num_children_impl()
finish_val = self.finish.GetValueAsUnsigned(0) return self.count
end_val = self.end.GetValueAsUnsigned(0)
# Before a vector has been constructed, it will contain bad values
# so we really need to be careful about the length we return since
# uninitialized data can cause us to return a huge number. We need
# to also check for any of the start, finish or end of storage values
# being zero (NULL). If any are, then this vector has not been
# initialized yet and we should return zero
# Make sure nothing is NULL def num_children_impl(self):
if start_val == 0 or finish_val == 0 or end_val == 0: try:
return 0 start_val = self.start.GetValueAsUnsigned(0)
# Make sure start is less than finish finish_val = self.finish.GetValueAsUnsigned(0)
if start_val >= finish_val: end_val = self.end.GetValueAsUnsigned(0)
return 0 # Before a vector has been constructed, it will contain bad values
# Make sure finish is less than or equal to end of storage # so we really need to be careful about the length we return since
if finish_val > end_val: # uninitialized data can cause us to return a huge number. We need
return 0 # to also check for any of the start, finish or end of storage values
# being zero (NULL). If any are, then this vector has not been
# initialized yet and we should return zero
# if we have a struct (or other data type that the compiler pads to native word size) # Make sure nothing is NULL
# this check might fail, unless the sizeof() we get is itself incremented to take the if start_val == 0 or finish_val == 0 or end_val == 0:
# padding bytes into account - on current clang it looks like this is the case return 0
num_children = (finish_val-start_val) # Make sure start is less than finish
if (num_children % self.data_size) != 0: if start_val >= finish_val:
return 0 return 0
else: # Make sure finish is less than or equal to end of storage
num_children = num_children/self.data_size if finish_val > end_val:
return num_children return 0
except:
return 0;
def get_child_at_index(self, index): # if we have a struct (or other data type that the compiler pads to native word size)
logger = lldb.formatters.Logger.Logger() # this check might fail, unless the sizeof() we get is itself incremented to take the
logger >> "Retrieving child " + str(index) # padding bytes into account - on current clang it looks like
if index < 0: # this is the case
return None; num_children = (finish_val - start_val)
if index >= self.num_children(): if (num_children % self.data_size) != 0:
return None; return 0
try: else:
offset = index * self.data_size num_children = num_children / self.data_size
return self.start.CreateChildAtOffset('['+str(index)+']',offset,self.data_type) return num_children
except: except:
return None return 0
def update(self): def get_child_at_index(self, index):
# preemptively setting this to None - we might end up changing our mind later logger = lldb.formatters.Logger.Logger()
self.count = None logger >> "Retrieving child " + str(index)
try: if index < 0:
impl = self.valobj.GetChildMemberWithName('_M_impl') return None
self.start = impl.GetChildMemberWithName('_M_start') if index >= self.num_children():
self.finish = impl.GetChildMemberWithName('_M_finish') return None
self.end = impl.GetChildMemberWithName('_M_end_of_storage') try:
self.data_type = self.start.GetType().GetPointeeType() offset = index * self.data_size
self.data_size = self.data_type.GetByteSize() return self.start.CreateChildAtOffset(
# if any of these objects is invalid, it means there is no point in trying to fetch anything '[' + str(index) + ']', offset, self.data_type)
if self.start.IsValid() and self.finish.IsValid() and self.end.IsValid() and self.data_type.IsValid(): except:
self.count = None return None
else:
self.count = 0
except:
pass
return True
class StdVBoolImplementation(object): def update(self):
def __init__(self, valobj, bool_type): # preemptively setting this to None - we might end up changing our
self.valobj = valobj # mind later
self.bool_type = bool_type self.count = None
self.valid = False try:
impl = self.valobj.GetChildMemberWithName('_M_impl')
self.start = impl.GetChildMemberWithName('_M_start')
self.finish = impl.GetChildMemberWithName('_M_finish')
self.end = impl.GetChildMemberWithName('_M_end_of_storage')
self.data_type = self.start.GetType().GetPointeeType()
self.data_size = self.data_type.GetByteSize()
# if any of these objects is invalid, it means there is no
# point in trying to fetch anything
if self.start.IsValid() and self.finish.IsValid(
) and self.end.IsValid() and self.data_type.IsValid():
self.count = None
else:
self.count = 0
except:
pass
return True
def num_children(self): class StdVBoolImplementation(object):
if self.valid:
start = self.start_p.GetValueAsUnsigned(0)
finish = self.finish_p.GetValueAsUnsigned(0)
offset = self.offset.GetValueAsUnsigned(0)
if finish >= start:
return (finish - start) * 8 + offset
return 0
def get_child_at_index(self, index): def __init__(self, valobj, bool_type):
if index >= self.num_children(): self.valobj = valobj
return None self.bool_type = bool_type
element_type = self.start_p.GetType().GetPointeeType() self.valid = False
element_bits = 8 * element_type.GetByteSize()
element_offset = (index / element_bits) * element_type.GetByteSize()
bit_offset = index % element_bits
element = self.start_p.CreateChildAtOffset('['+str(index)+']',element_offset,element_type)
bit = element.GetValueAsUnsigned(0) & (1 << bit_offset)
if bit != 0:
value_expr = "(bool)true"
else:
value_expr = "(bool)false"
return self.valobj.CreateValueFromExpression("[%d]" % index, value_expr)
def update(self): def num_children(self):
try: if self.valid:
m_impl = self.valobj.GetChildMemberWithName('_M_impl') start = self.start_p.GetValueAsUnsigned(0)
self.m_start = m_impl.GetChildMemberWithName('_M_start') finish = self.finish_p.GetValueAsUnsigned(0)
self.m_finish = m_impl.GetChildMemberWithName('_M_finish') offset = self.offset.GetValueAsUnsigned(0)
self.start_p = self.m_start.GetChildMemberWithName('_M_p') if finish >= start:
self.finish_p = self.m_finish.GetChildMemberWithName('_M_p') return (finish - start) * 8 + offset
self.offset = self.m_finish.GetChildMemberWithName('_M_offset') return 0
self.valid = True
except:
self.valid = False
return True
def __init__(self, valobj, dict): def get_child_at_index(self, index):
logger = lldb.formatters.Logger.Logger() if index >= self.num_children():
first_template_arg_type = valobj.GetType().GetTemplateArgumentType(0) return None
if str(first_template_arg_type.GetName()) == "bool": element_type = self.start_p.GetType().GetPointeeType()
self.impl = self.StdVBoolImplementation(valobj, first_template_arg_type) element_bits = 8 * element_type.GetByteSize()
else: element_offset = (index / element_bits) * \
self.impl = self.StdVectorImplementation(valobj) element_type.GetByteSize()
logger >> "Providing synthetic children for a vector named " + str(valobj.GetName()) bit_offset = index % element_bits
element = self.start_p.CreateChildAtOffset(
'[' + str(index) + ']', element_offset, element_type)
bit = element.GetValueAsUnsigned(0) & (1 << bit_offset)
if bit != 0:
value_expr = "(bool)true"
else:
value_expr = "(bool)false"
return self.valobj.CreateValueFromExpression(
"[%d]" % index, value_expr)
def num_children(self): def update(self):
return self.impl.num_children() try:
m_impl = self.valobj.GetChildMemberWithName('_M_impl')
self.m_start = m_impl.GetChildMemberWithName('_M_start')
self.m_finish = m_impl.GetChildMemberWithName('_M_finish')
self.start_p = self.m_start.GetChildMemberWithName('_M_p')
self.finish_p = self.m_finish.GetChildMemberWithName('_M_p')
self.offset = self.m_finish.GetChildMemberWithName('_M_offset')
self.valid = True
except:
self.valid = False
return True
def get_child_index(self,name): def __init__(self, valobj, dict):
try: logger = lldb.formatters.Logger.Logger()
return int(name.lstrip('[').rstrip(']')) first_template_arg_type = valobj.GetType().GetTemplateArgumentType(0)
except: if str(first_template_arg_type.GetName()) == "bool":
return -1 self.impl = self.StdVBoolImplementation(
valobj, first_template_arg_type)
else:
self.impl = self.StdVectorImplementation(valobj)
logger >> "Providing synthetic children for a vector named " + \
str(valobj.GetName())
def get_child_at_index(self, index): def num_children(self):
return self.impl.get_child_at_index(index) return self.impl.num_children()
def update(self): def get_child_index(self, name):
return self.impl.update() try:
return int(name.lstrip('[').rstrip(']'))
except:
return -1
def has_children(self): def get_child_at_index(self, index):
return True return self.impl.get_child_at_index(index)
def update(self):
return self.impl.update()
def has_children(self):
return True
class StdMapSynthProvider: class StdMapSynthProvider:
def __init__(self, valobj, dict): def __init__(self, valobj, dict):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
self.valobj = valobj; self.valobj = valobj
self.count = None self.count = None
logger >> "Providing synthetic children for a map named " + str(valobj.GetName()) logger >> "Providing synthetic children for a map named " + \
str(valobj.GetName())
# we need this function as a temporary workaround for rdar://problem/10801549
# which prevents us from extracting the std::pair<K,V> SBType out of the template
# arguments for _Rep_Type _M_t in the map itself - because we have to make up the
# typename and then find it, we may hit the situation were std::string has multiple
# names but only one is actually referenced in the debug information. hence, we need
# to replace the longer versions of std::string with the shorter one in order to be able
# to find the type name
def fixup_class_name(self, class_name):
logger = lldb.formatters.Logger.Logger()
if class_name == 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >':
return 'std::basic_string<char>',True
if class_name == 'basic_string<char, std::char_traits<char>, std::allocator<char> >':
return 'std::basic_string<char>',True
if class_name == 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >':
return 'std::basic_string<char>',True
if class_name == 'basic_string<char, std::char_traits<char>, std::allocator<char> >':
return 'std::basic_string<char>',True
return class_name,False
def update(self): # we need this function as a temporary workaround for rdar://problem/10801549
logger = lldb.formatters.Logger.Logger() # which prevents us from extracting the std::pair<K,V> SBType out of the template
# preemptively setting this to None - we might end up changing our mind later # arguments for _Rep_Type _M_t in the map itself - because we have to make up the
self.count = None # typename and then find it, we may hit the situation were std::string has multiple
try: # names but only one is actually referenced in the debug information. hence, we need
# we will set this to True if we find out that discovering a node in the map takes more steps than the overall size of the RB tree # to replace the longer versions of std::string with the shorter one in order to be able
# if this gets set to True, then we will merrily return None for any child from that moment on # to find the type name
self.garbage = False def fixup_class_name(self, class_name):
self.Mt = self.valobj.GetChildMemberWithName('_M_t') logger = lldb.formatters.Logger.Logger()
self.Mimpl = self.Mt.GetChildMemberWithName('_M_impl') if class_name == 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >':
self.Mheader = self.Mimpl.GetChildMemberWithName('_M_header') return 'std::basic_string<char>', True
if class_name == 'basic_string<char, std::char_traits<char>, std::allocator<char> >':
map_type = self.valobj.GetType() return 'std::basic_string<char>', True
if map_type.IsReferenceType(): if class_name == 'std::basic_string<char, std::char_traits<char>, std::allocator<char> >':
logger >> "Dereferencing type" return 'std::basic_string<char>', True
map_type = map_type.GetDereferencedType() if class_name == 'basic_string<char, std::char_traits<char>, std::allocator<char> >':
return 'std::basic_string<char>', True
return class_name, False
# Get the type of std::pair<key, value>. It is the first template def update(self):
# argument type of the 4th template argument to std::map. logger = lldb.formatters.Logger.Logger()
allocator_type = map_type.GetTemplateArgumentType(3) # preemptively setting this to None - we might end up changing our mind
self.data_type = allocator_type.GetTemplateArgumentType(0) # later
if not self.data_type: self.count = None
# GCC does not emit DW_TAG_template_type_parameter for try:
# std::allocator<...>. For such a case, get the type of # we will set this to True if we find out that discovering a node in the map takes more steps than the overall size of the RB tree
# std::pair from a member of std::map. # if this gets set to True, then we will merrily return None for
rep_type = self.valobj.GetChildMemberWithName('_M_t').GetType() # any child from that moment on
self.data_type = rep_type.GetTypedefedType().GetTemplateArgumentType(1) self.garbage = False
self.Mt = self.valobj.GetChildMemberWithName('_M_t')
# from libstdc++ implementation of _M_root for rbtree self.Mimpl = self.Mt.GetChildMemberWithName('_M_impl')
self.Mroot = self.Mheader.GetChildMemberWithName('_M_parent') self.Mheader = self.Mimpl.GetChildMemberWithName('_M_header')
self.data_size = self.data_type.GetByteSize()
self.skip_size = self.Mheader.GetType().GetByteSize()
except:
pass
def num_children(self): map_type = self.valobj.GetType()
logger = lldb.formatters.Logger.Logger() if map_type.IsReferenceType():
if self.count == None: logger >> "Dereferencing type"
self.count = self.num_children_impl() map_type = map_type.GetDereferencedType()
return self.count
def num_children_impl(self): # Get the type of std::pair<key, value>. It is the first template
logger = lldb.formatters.Logger.Logger() # argument type of the 4th template argument to std::map.
try: allocator_type = map_type.GetTemplateArgumentType(3)
root_ptr_val = self.node_ptr_value(self.Mroot) self.data_type = allocator_type.GetTemplateArgumentType(0)
if root_ptr_val == 0: if not self.data_type:
return 0; # GCC does not emit DW_TAG_template_type_parameter for
count = self.Mimpl.GetChildMemberWithName('_M_node_count').GetValueAsUnsigned(0) # std::allocator<...>. For such a case, get the type of
logger >> "I have " + str(count) + " children available" # std::pair from a member of std::map.
return count rep_type = self.valobj.GetChildMemberWithName('_M_t').GetType()
except: self.data_type = rep_type.GetTypedefedType().GetTemplateArgumentType(1)
return 0;
def get_child_index(self,name): # from libstdc++ implementation of _M_root for rbtree
logger = lldb.formatters.Logger.Logger() self.Mroot = self.Mheader.GetChildMemberWithName('_M_parent')
try: self.data_size = self.data_type.GetByteSize()
return int(name.lstrip('[').rstrip(']')) self.skip_size = self.Mheader.GetType().GetByteSize()
except: except:
return -1 pass
def get_child_at_index(self,index): def num_children(self):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
logger >> "Being asked to fetch child[" + str(index) + "]" if self.count is None:
if index < 0: self.count = self.num_children_impl()
return None return self.count
if index >= self.num_children():
return None;
if self.garbage:
logger >> "Returning None since we are a garbage tree"
return None
try:
offset = index
current = self.left(self.Mheader);
while offset > 0:
current = self.increment_node(current)
offset = offset - 1;
# skip all the base stuff and get at the data
return current.CreateChildAtOffset('['+str(index)+']',self.skip_size,self.data_type)
except:
return None
# utility functions def num_children_impl(self):
def node_ptr_value(self,node): logger = lldb.formatters.Logger.Logger()
logger = lldb.formatters.Logger.Logger() try:
return node.GetValueAsUnsigned(0) root_ptr_val = self.node_ptr_value(self.Mroot)
if root_ptr_val == 0:
return 0
count = self.Mimpl.GetChildMemberWithName(
'_M_node_count').GetValueAsUnsigned(0)
logger >> "I have " + str(count) + " children available"
return count
except:
return 0
def right(self,node): def get_child_index(self, name):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
return node.GetChildMemberWithName("_M_right"); try:
return int(name.lstrip('[').rstrip(']'))
except:
return -1
def left(self,node): def get_child_at_index(self, index):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
return node.GetChildMemberWithName("_M_left"); logger >> "Being asked to fetch child[" + str(index) + "]"
if index < 0:
return None
if index >= self.num_children():
return None
if self.garbage:
logger >> "Returning None since we are a garbage tree"
return None
try:
offset = index
current = self.left(self.Mheader)
while offset > 0:
current = self.increment_node(current)
offset = offset - 1
# skip all the base stuff and get at the data
return current.CreateChildAtOffset(
'[' + str(index) + ']', self.skip_size, self.data_type)
except:
return None
def parent(self,node): # utility functions
logger = lldb.formatters.Logger.Logger() def node_ptr_value(self, node):
return node.GetChildMemberWithName("_M_parent"); logger = lldb.formatters.Logger.Logger()
return node.GetValueAsUnsigned(0)
# from libstdc++ implementation of iterator for rbtree def right(self, node):
def increment_node(self,node): logger = lldb.formatters.Logger.Logger()
logger = lldb.formatters.Logger.Logger() return node.GetChildMemberWithName("_M_right")
max_steps = self.num_children()
if self.node_ptr_value(self.right(node)) != 0:
x = self.right(node);
max_steps -= 1
while self.node_ptr_value(self.left(x)) != 0:
x = self.left(x);
max_steps -= 1
logger >> str(max_steps) + " more to go before giving up"
if max_steps <= 0:
self.garbage = True
return None
return x;
else:
x = node;
y = self.parent(x)
max_steps -= 1
while(self.node_ptr_value(x) == self.node_ptr_value(self.right(y))):
x = y;
y = self.parent(y);
max_steps -= 1
logger >> str(max_steps) + " more to go before giving up"
if max_steps <= 0:
self.garbage = True
return None
if self.node_ptr_value(self.right(x)) != self.node_ptr_value(y):
x = y;
return x;
def has_children(self): def left(self, node):
return True logger = lldb.formatters.Logger.Logger()
return node.GetChildMemberWithName("_M_left")
def parent(self, node):
logger = lldb.formatters.Logger.Logger()
return node.GetChildMemberWithName("_M_parent")
# from libstdc++ implementation of iterator for rbtree
def increment_node(self, node):
logger = lldb.formatters.Logger.Logger()
max_steps = self.num_children()
if self.node_ptr_value(self.right(node)) != 0:
x = self.right(node)
max_steps -= 1
while self.node_ptr_value(self.left(x)) != 0:
x = self.left(x)
max_steps -= 1
logger >> str(max_steps) + " more to go before giving up"
if max_steps <= 0:
self.garbage = True
return None
return x
else:
x = node
y = self.parent(x)
max_steps -= 1
while(self.node_ptr_value(x) == self.node_ptr_value(self.right(y))):
x = y
y = self.parent(y)
max_steps -= 1
logger >> str(max_steps) + " more to go before giving up"
if max_steps <= 0:
self.garbage = True
return None
if self.node_ptr_value(self.right(x)) != self.node_ptr_value(y):
x = y
return x
def has_children(self):
return True
_list_uses_loop_detector = True _list_uses_loop_detector = True

File diff suppressed because it is too large Load Diff

View File

@ -2,109 +2,123 @@ import lldb
_map_capping_size = 255 _map_capping_size = 255
class libcxx_hash_table_SynthProvider: class libcxx_hash_table_SynthProvider:
def __init__(self, valobj, dict):
self.valobj = valobj
self.num_elements = None
self.next_element = None
self.bucket_count = None
def update(self): def __init__(self, valobj, dict):
logger = lldb.formatters.Logger.Logger() self.valobj = valobj
self.num_elements = None self.num_elements = None
self.next_element = None self.next_element = None
self.bucket_count = None self.bucket_count = None
try:
# unordered_map is made up of a hash_map, which has 4 pieces in it:
# bucket list :
# array of buckets
# p1 (pair):
# first - pointer to first loaded element
# p2 (pair):
# first - number of elements
# second - hash function
# p3 (pair):
# first - max_load_factor
# second - equality operator function
#
# For display, we actually don't need to go inside the buckets, since 'p1' has a way to iterate over all
# the elements directly.
#
# We will calculate other values about the map because they will be useful for the summary.
#
table = self.valobj.GetChildMemberWithName('__table_')
bl_ptr = table.GetChildMemberWithName('__bucket_list_').GetChildMemberWithName('__ptr_') def update(self):
self.bucket_array_ptr = bl_ptr.GetChildMemberWithName('__first_').GetValueAsUnsigned(0) logger = lldb.formatters.Logger.Logger()
self.bucket_count = bl_ptr.GetChildMemberWithName('__second_').GetChildMemberWithName('__data_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0) self.num_elements = None
logger >> "Bucket count = %r" % self.bucket_count self.next_element = None
self.bucket_count = None
try:
# unordered_map is made up of a hash_map, which has 4 pieces in it:
# bucket list :
# array of buckets
# p1 (pair):
# first - pointer to first loaded element
# p2 (pair):
# first - number of elements
# second - hash function
# p3 (pair):
# first - max_load_factor
# second - equality operator function
#
# For display, we actually don't need to go inside the buckets, since 'p1' has a way to iterate over all
# the elements directly.
#
# We will calculate other values about the map because they will be useful for the summary.
#
table = self.valobj.GetChildMemberWithName('__table_')
self.begin_ptr = table.GetChildMemberWithName('__p1_').GetChildMemberWithName('__first_').GetChildMemberWithName('__next_') bl_ptr = table.GetChildMemberWithName(
'__bucket_list_').GetChildMemberWithName('__ptr_')
self.bucket_array_ptr = bl_ptr.GetChildMemberWithName(
'__first_').GetValueAsUnsigned(0)
self.bucket_count = bl_ptr.GetChildMemberWithName('__second_').GetChildMemberWithName(
'__data_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0)
logger >> "Bucket count = %r" % self.bucket_count
self.num_elements = table.GetChildMemberWithName('__p2_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0) self.begin_ptr = table.GetChildMemberWithName('__p1_').GetChildMemberWithName(
self.max_load_factor = table.GetChildMemberWithName('__p3_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0) '__first_').GetChildMemberWithName('__next_')
logger >> "Num elements = %r" % self.num_elements
# save the pointers as we get them self.num_elements = table.GetChildMemberWithName(
# -- don't access this first element if num_element==0! '__p2_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0)
self.elements_cache = [] self.max_load_factor = table.GetChildMemberWithName(
if self.num_elements: '__p3_').GetChildMemberWithName('__first_').GetValueAsUnsigned(0)
self.next_element = self.begin_ptr logger >> "Num elements = %r" % self.num_elements
else:
self.next_element = None
except Exception as e:
logger >> "Caught exception: %r" % e
pass
def num_children(self): # save the pointers as we get them
global _map_capping_size # -- don't access this first element if num_element==0!
num_elements = self.num_elements self.elements_cache = []
if num_elements is not None: if self.num_elements:
if num_elements > _map_capping_size: self.next_element = self.begin_ptr
num_elements = _map_capping_size else:
return num_elements self.next_element = None
except Exception as e:
logger >> "Caught exception: %r" % e
pass
def has_children(self): def num_children(self):
return True global _map_capping_size
num_elements = self.num_elements
if num_elements is not None:
if num_elements > _map_capping_size:
num_elements = _map_capping_size
return num_elements
def get_child_index(self,name): def has_children(self):
logger = lldb.formatters.Logger.Logger() return True
try:
return int(name.lstrip('[').rstrip(']'))
except:
return -1
def get_child_at_index(self,index): def get_child_index(self, name):
logger = lldb.formatters.Logger.Logger() logger = lldb.formatters.Logger.Logger()
logger >> "Retrieving child " + str(index) try:
if index < 0: return int(name.lstrip('[').rstrip(']'))
return None except:
if index >= self.num_children(): return -1
return None
# extend def get_child_at_index(self, index):
logger >> " : cache size starts with %d elements" % len(self.elements_cache) logger = lldb.formatters.Logger.Logger()
while index >= len(self.elements_cache): logger >> "Retrieving child " + str(index)
# if we hit the end before we get the index, give up: if index < 0:
if not self.next_element: return None
logger >> " : hit end of list" if index >= self.num_children():
return None return None
node = self.next_element.Dereference() # extend
logger >> " : cache size starts with %d elements" % len(
self.elements_cache)
while index >= len(self.elements_cache):
# if we hit the end before we get the index, give up:
if not self.next_element:
logger >> " : hit end of list"
return None
value = node.GetChildMemberWithName('__value_') node = self.next_element.Dereference()
hash_value = node.GetChildMemberWithName('__hash_').GetValueAsUnsigned()
self.elements_cache.append((value, hash_value))
self.next_element = node.GetChildMemberWithName('__next_') value = node.GetChildMemberWithName('__value_')
if not self.next_element.GetValueAsUnsigned(0): hash_value = node.GetChildMemberWithName(
self.next_element = None '__hash_').GetValueAsUnsigned()
self.elements_cache.append((value, hash_value))
# hit the index! so we have the value self.next_element = node.GetChildMemberWithName('__next_')
logger >> " : cache size ends with %d elements" % len(self.elements_cache) if not self.next_element.GetValueAsUnsigned(0):
value, hash_value = self.elements_cache[index] self.next_element = None
return self.valobj.CreateValueFromData('[%d] <hash %d>'%(index,hash_value), value.GetData(), value.GetType())
# hit the index! so we have the value
logger >> " : cache size ends with %d elements" % len(
self.elements_cache)
value, hash_value = self.elements_cache[index]
return self.valobj.CreateValueFromData(
'[%d] <hash %d>' %
(index, hash_value), value.GetData(), value.GetType())
def __lldb_init_module(debugger,dict): def __lldb_init_module(debugger, dict):
debugger.HandleCommand('type synthetic add -l unordered_multi.libcxx_hash_table_SynthProvider -x "^(std::__1::)unordered_(multi)?(map|set)<.+> >$" -w libcxx') debugger.HandleCommand(
'type synthetic add -l unordered_multi.libcxx_hash_table_SynthProvider -x "^(std::__1::)unordered_(multi)?(map|set)<.+> >$" -w libcxx')

View File

@ -14,7 +14,6 @@
// C++ Includes // C++ Includes
// Other libraries and framework includes // Other libraries and framework includes
// Project includes // Project includes
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBAddress.h" #include "lldb/API/SBAddress.h"
#include "lldb/API/SBAttachInfo.h" #include "lldb/API/SBAttachInfo.h"
#include "lldb/API/SBBlock.h" #include "lldb/API/SBBlock.h"
@ -28,6 +27,7 @@
#include "lldb/API/SBData.h" #include "lldb/API/SBData.h"
#include "lldb/API/SBDebugger.h" #include "lldb/API/SBDebugger.h"
#include "lldb/API/SBDeclaration.h" #include "lldb/API/SBDeclaration.h"
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBError.h" #include "lldb/API/SBError.h"
#include "lldb/API/SBEvent.h" #include "lldb/API/SBEvent.h"
#include "lldb/API/SBExecutionContext.h" #include "lldb/API/SBExecutionContext.h"
@ -77,4 +77,4 @@
#include "lldb/API/SBVariablesOptions.h" #include "lldb/API/SBVariablesOptions.h"
#include "lldb/API/SBWatchpoint.h" #include "lldb/API/SBWatchpoint.h"
#endif // LLDB_LLDB_h_ #endif // LLDB_LLDB_h_

View File

@ -15,138 +15,108 @@
namespace lldb { namespace lldb {
class LLDB_API SBAddress class LLDB_API SBAddress {
{
public: public:
SBAddress();
SBAddress (); SBAddress(const lldb::SBAddress &rhs);
SBAddress (const lldb::SBAddress &rhs); SBAddress(lldb::SBSection section, lldb::addr_t offset);
SBAddress (lldb::SBSection section, lldb::addr_t offset); // Create an address by resolving a load address using the supplied target
SBAddress(lldb::addr_t load_addr, lldb::SBTarget &target);
// Create an address by resolving a load address using the supplied target ~SBAddress();
SBAddress (lldb::addr_t load_addr, lldb::SBTarget &target);
~SBAddress (); const lldb::SBAddress &operator=(const lldb::SBAddress &rhs);
const lldb::SBAddress & bool IsValid() const;
operator = (const lldb::SBAddress &rhs);
bool void Clear();
IsValid () const;
void addr_t GetFileAddress() const;
Clear ();
addr_t addr_t GetLoadAddress(const lldb::SBTarget &target) const;
GetFileAddress () const;
addr_t void SetAddress(lldb::SBSection section, lldb::addr_t offset);
GetLoadAddress (const lldb::SBTarget &target) const;
void void SetLoadAddress(lldb::addr_t load_addr, lldb::SBTarget &target);
SetAddress (lldb::SBSection section, lldb::addr_t offset); bool OffsetAddress(addr_t offset);
void bool GetDescription(lldb::SBStream &description);
SetLoadAddress (lldb::addr_t load_addr,
lldb::SBTarget &target);
bool
OffsetAddress (addr_t offset);
bool // The following queries can lookup symbol information for a given address.
GetDescription (lldb::SBStream &description); // An address might refer to code or data from an existing module, or it
// might refer to something on the stack or heap. The following functions
// will only return valid values if the address has been resolved to a code
// or data address using "void SBAddress::SetLoadAddress(...)" or
// "lldb::SBAddress SBTarget::ResolveLoadAddress (...)".
lldb::SBSymbolContext GetSymbolContext(uint32_t resolve_scope);
// The following queries can lookup symbol information for a given address. // The following functions grab individual objects for a given address and
// An address might refer to code or data from an existing module, or it // are less efficient if you want more than one symbol related objects.
// might refer to something on the stack or heap. The following functions // Use one of the following when you want multiple debug symbol related
// will only return valid values if the address has been resolved to a code // objects for an address:
// or data address using "void SBAddress::SetLoadAddress(...)" or // lldb::SBSymbolContext SBAddress::GetSymbolContext (uint32_t
// "lldb::SBAddress SBTarget::ResolveLoadAddress (...)". // resolve_scope);
lldb::SBSymbolContext // lldb::SBSymbolContext SBTarget::ResolveSymbolContextForAddress (const
GetSymbolContext (uint32_t resolve_scope); // SBAddress &addr, uint32_t resolve_scope);
// One or more bits from the SymbolContextItem enumerations can be logically
// OR'ed together to more efficiently retrieve multiple symbol objects.
lldb::SBSection GetSection();
// The following functions grab individual objects for a given address and
// are less efficient if you want more than one symbol related objects.
// Use one of the following when you want multiple debug symbol related
// objects for an address:
// lldb::SBSymbolContext SBAddress::GetSymbolContext (uint32_t resolve_scope);
// lldb::SBSymbolContext SBTarget::ResolveSymbolContextForAddress (const SBAddress &addr, uint32_t resolve_scope);
// One or more bits from the SymbolContextItem enumerations can be logically
// OR'ed together to more efficiently retrieve multiple symbol objects.
lldb::SBSection lldb::addr_t GetOffset();
GetSection ();
lldb::addr_t lldb::SBModule GetModule();
GetOffset ();
lldb::SBModule lldb::SBCompileUnit GetCompileUnit();
GetModule ();
lldb::SBCompileUnit
GetCompileUnit ();
lldb::SBFunction lldb::SBFunction GetFunction();
GetFunction ();
lldb::SBBlock lldb::SBBlock GetBlock();
GetBlock ();
lldb::SBSymbol lldb::SBSymbol GetSymbol();
GetSymbol ();
lldb::SBLineEntry lldb::SBLineEntry GetLineEntry();
GetLineEntry ();
lldb::AddressClass GetAddressClass();
lldb::AddressClass
GetAddressClass ();
protected: protected:
friend class SBBlock;
friend class SBBreakpointLocation;
friend class SBFrame;
friend class SBFunction;
friend class SBLineEntry;
friend class SBInstruction;
friend class SBModule;
friend class SBSection;
friend class SBSymbol;
friend class SBSymbolContext;
friend class SBTarget;
friend class SBThread;
friend class SBThreadPlan;
friend class SBValue;
friend class SBQueueItem;
friend class SBBlock; lldb_private::Address *operator->();
friend class SBBreakpointLocation;
friend class SBFrame;
friend class SBFunction;
friend class SBLineEntry;
friend class SBInstruction;
friend class SBModule;
friend class SBSection;
friend class SBSymbol;
friend class SBSymbolContext;
friend class SBTarget;
friend class SBThread;
friend class SBThreadPlan;
friend class SBValue;
friend class SBQueueItem;
lldb_private::Address * const lldb_private::Address *operator->() const;
operator->();
const lldb_private::Address * lldb_private::Address *get();
operator->() const;
lldb_private::Address * lldb_private::Address &ref();
get ();
lldb_private::Address & const lldb_private::Address &ref() const;
ref();
const lldb_private::Address & SBAddress(const lldb_private::Address *lldb_object_ptr);
ref() const;
SBAddress (const lldb_private::Address *lldb_object_ptr); void SetAddress(const lldb_private::Address *lldb_object_ptr);
void
SetAddress (const lldb_private::Address *lldb_object_ptr);
private: private:
std::unique_ptr<lldb_private::Address> m_opaque_ap;
std::unique_ptr<lldb_private::Address> m_opaque_ap;
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBAddress_h_ #endif // LLDB_SBAddress_h_

View File

@ -16,209 +16,175 @@ namespace lldb {
class SBTarget; class SBTarget;
class LLDB_API SBAttachInfo class LLDB_API SBAttachInfo {
{
public: public:
SBAttachInfo (); SBAttachInfo();
SBAttachInfo (lldb::pid_t pid); SBAttachInfo(lldb::pid_t pid);
//------------------------------------------------------------------ //------------------------------------------------------------------
/// Attach to a process by name. /// Attach to a process by name.
/// ///
/// This function implies that a future call to SBTarget::Attach(...) /// This function implies that a future call to SBTarget::Attach(...)
/// will be synchronous. /// will be synchronous.
/// ///
/// @param[in] path /// @param[in] path
/// A full or partial name for the process to attach to. /// A full or partial name for the process to attach to.
/// ///
/// @param[in] wait_for /// @param[in] wait_for
/// If \b false, attach to an existing process whose name matches. /// If \b false, attach to an existing process whose name matches.
/// If \b true, then wait for the next process whose name matches. /// If \b true, then wait for the next process whose name matches.
//------------------------------------------------------------------ //------------------------------------------------------------------
SBAttachInfo (const char *path, bool wait_for); SBAttachInfo(const char *path, bool wait_for);
//------------------------------------------------------------------ //------------------------------------------------------------------
/// Attach to a process by name. /// Attach to a process by name.
/// ///
/// Future calls to SBTarget::Attach(...) will be synchronous or /// Future calls to SBTarget::Attach(...) will be synchronous or
/// asynchronous depending on the \a async argument. /// asynchronous depending on the \a async argument.
/// ///
/// @param[in] path /// @param[in] path
/// A full or partial name for the process to attach to. /// A full or partial name for the process to attach to.
/// ///
/// @param[in] wait_for /// @param[in] wait_for
/// If \b false, attach to an existing process whose name matches. /// If \b false, attach to an existing process whose name matches.
/// If \b true, then wait for the next process whose name matches. /// If \b true, then wait for the next process whose name matches.
/// ///
/// @param[in] async /// @param[in] async
/// If \b false, then the SBTarget::Attach(...) call will be a /// If \b false, then the SBTarget::Attach(...) call will be a
/// synchronous call with no way to cancel the attach in /// synchronous call with no way to cancel the attach in
/// progress. /// progress.
/// If \b true, then the SBTarget::Attach(...) function will /// If \b true, then the SBTarget::Attach(...) function will
/// return immediately and clients are expected to wait for a /// return immediately and clients are expected to wait for a
/// process eStateStopped event if a suitable process is /// process eStateStopped event if a suitable process is
/// eventually found. If the client wants to cancel the event, /// eventually found. If the client wants to cancel the event,
/// SBProcess::Stop() can be called and an eStateExited process /// SBProcess::Stop() can be called and an eStateExited process
/// event will be delivered. /// event will be delivered.
//------------------------------------------------------------------ //------------------------------------------------------------------
SBAttachInfo (const char *path, bool wait_for, bool async); SBAttachInfo(const char *path, bool wait_for, bool async);
SBAttachInfo (const SBAttachInfo &rhs); SBAttachInfo(const SBAttachInfo &rhs);
~SBAttachInfo(); ~SBAttachInfo();
SBAttachInfo & SBAttachInfo &operator=(const SBAttachInfo &rhs);
operator = (const SBAttachInfo &rhs);
lldb::pid_t lldb::pid_t GetProcessID();
GetProcessID ();
void void SetProcessID(lldb::pid_t pid);
SetProcessID (lldb::pid_t pid);
void void SetExecutable(const char *path);
SetExecutable (const char *path);
void void SetExecutable(lldb::SBFileSpec exe_file);
SetExecutable (lldb::SBFileSpec exe_file);
bool bool GetWaitForLaunch();
GetWaitForLaunch ();
//------------------------------------------------------------------ //------------------------------------------------------------------
/// Set attach by process name settings. /// Set attach by process name settings.
/// ///
/// Designed to be used after a call to SBAttachInfo::SetExecutable(). /// Designed to be used after a call to SBAttachInfo::SetExecutable().
/// This function implies that a call to SBTarget::Attach(...) will /// This function implies that a call to SBTarget::Attach(...) will
/// be synchronous. /// be synchronous.
/// ///
/// @param[in] wait_for /// @param[in] wait_for
/// If \b false, attach to an existing process whose name matches. /// If \b false, attach to an existing process whose name matches.
/// If \b true, then wait for the next process whose name matches. /// If \b true, then wait for the next process whose name matches.
//------------------------------------------------------------------ //------------------------------------------------------------------
void void SetWaitForLaunch(bool b);
SetWaitForLaunch (bool b);
//------------------------------------------------------------------ //------------------------------------------------------------------
/// Set attach by process name settings. /// Set attach by process name settings.
/// ///
/// Designed to be used after a call to SBAttachInfo::SetExecutable(). /// Designed to be used after a call to SBAttachInfo::SetExecutable().
/// Future calls to SBTarget::Attach(...) will be synchronous or /// Future calls to SBTarget::Attach(...) will be synchronous or
/// asynchronous depending on the \a async argument. /// asynchronous depending on the \a async argument.
/// ///
/// @param[in] wait_for /// @param[in] wait_for
/// If \b false, attach to an existing process whose name matches. /// If \b false, attach to an existing process whose name matches.
/// If \b true, then wait for the next process whose name matches. /// If \b true, then wait for the next process whose name matches.
/// ///
/// @param[in] async /// @param[in] async
/// If \b false, then the SBTarget::Attach(...) call will be a /// If \b false, then the SBTarget::Attach(...) call will be a
/// synchronous call with no way to cancel the attach in /// synchronous call with no way to cancel the attach in
/// progress. /// progress.
/// If \b true, then the SBTarget::Attach(...) function will /// If \b true, then the SBTarget::Attach(...) function will
/// return immediately and clients are expected to wait for a /// return immediately and clients are expected to wait for a
/// process eStateStopped event if a suitable process is /// process eStateStopped event if a suitable process is
/// eventually found. If the client wants to cancel the event, /// eventually found. If the client wants to cancel the event,
/// SBProcess::Stop() can be called and an eStateExited process /// SBProcess::Stop() can be called and an eStateExited process
/// event will be delivered. /// event will be delivered.
//------------------------------------------------------------------ //------------------------------------------------------------------
void void SetWaitForLaunch(bool b, bool async);
SetWaitForLaunch (bool b, bool async);
bool bool GetIgnoreExisting();
GetIgnoreExisting ();
void void SetIgnoreExisting(bool b);
SetIgnoreExisting (bool b);
uint32_t uint32_t GetResumeCount();
GetResumeCount ();
void void SetResumeCount(uint32_t c);
SetResumeCount (uint32_t c);
const char * const char *GetProcessPluginName();
GetProcessPluginName ();
void void SetProcessPluginName(const char *plugin_name);
SetProcessPluginName (const char *plugin_name);
uint32_t uint32_t GetUserID();
GetUserID();
uint32_t uint32_t GetGroupID();
GetGroupID();
bool bool UserIDIsValid();
UserIDIsValid ();
bool bool GroupIDIsValid();
GroupIDIsValid ();
void void SetUserID(uint32_t uid);
SetUserID (uint32_t uid);
void void SetGroupID(uint32_t gid);
SetGroupID (uint32_t gid);
uint32_t uint32_t GetEffectiveUserID();
GetEffectiveUserID();
uint32_t uint32_t GetEffectiveGroupID();
GetEffectiveGroupID();
bool bool EffectiveUserIDIsValid();
EffectiveUserIDIsValid ();
bool bool EffectiveGroupIDIsValid();
EffectiveGroupIDIsValid ();
void void SetEffectiveUserID(uint32_t uid);
SetEffectiveUserID (uint32_t uid);
void void SetEffectiveGroupID(uint32_t gid);
SetEffectiveGroupID (uint32_t gid);
lldb::pid_t lldb::pid_t GetParentProcessID();
GetParentProcessID ();
void void SetParentProcessID(lldb::pid_t pid);
SetParentProcessID (lldb::pid_t pid);
bool bool ParentProcessIDIsValid();
ParentProcessIDIsValid();
//---------------------------------------------------------------------- //----------------------------------------------------------------------
/// Get the listener that will be used to receive process events. /// Get the listener that will be used to receive process events.
/// ///
/// If no listener has been set via a call to /// If no listener has been set via a call to
/// SBLaunchInfo::SetListener(), then an invalid SBListener will be /// SBLaunchInfo::SetListener(), then an invalid SBListener will be
/// returned (SBListener::IsValid() will return false). If a listener /// returned (SBListener::IsValid() will return false). If a listener
/// has been set, then the valid listener object will be returned. /// has been set, then the valid listener object will be returned.
//---------------------------------------------------------------------- //----------------------------------------------------------------------
SBListener SBListener GetListener();
GetListener ();
//----------------------------------------------------------------------
/// Set the listener that will be used to receive process events.
///
/// By default the SBDebugger, which has a listener, that the SBTarget
/// belongs to will listen for the process events. Calling this function
/// allows a different listener to be used to listen for process events.
//----------------------------------------------------------------------
void
SetListener (SBListener &listener);
//----------------------------------------------------------------------
/// Set the listener that will be used to receive process events.
///
/// By default the SBDebugger, which has a listener, that the SBTarget
/// belongs to will listen for the process events. Calling this function
/// allows a different listener to be used to listen for process events.
//----------------------------------------------------------------------
void SetListener(SBListener &listener);
protected: protected:
friend class SBTarget; friend class SBTarget;
lldb_private::ProcessAttachInfo & lldb_private::ProcessAttachInfo &ref();
ref ();
ProcessAttachInfoSP m_opaque_sp; ProcessAttachInfoSP m_opaque_sp;
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBAttachInfo_h_ #endif // LLDB_SBAttachInfo_h_

View File

@ -17,107 +17,80 @@
namespace lldb { namespace lldb {
class LLDB_API SBBlock class LLDB_API SBBlock {
{
public: public:
SBBlock();
SBBlock (); SBBlock(const lldb::SBBlock &rhs);
SBBlock (const lldb::SBBlock &rhs); ~SBBlock();
~SBBlock (); const lldb::SBBlock &operator=(const lldb::SBBlock &rhs);
const lldb::SBBlock & bool IsInlined() const;
operator = (const lldb::SBBlock &rhs);
bool bool IsValid() const;
IsInlined () const;
bool const char *GetInlinedName() const;
IsValid () const;
const char * lldb::SBFileSpec GetInlinedCallSiteFile() const;
GetInlinedName () const;
lldb::SBFileSpec uint32_t GetInlinedCallSiteLine() const;
GetInlinedCallSiteFile () const;
uint32_t uint32_t GetInlinedCallSiteColumn() const;
GetInlinedCallSiteLine () const;
uint32_t lldb::SBBlock GetParent();
GetInlinedCallSiteColumn () const;
lldb::SBBlock lldb::SBBlock GetSibling();
GetParent ();
lldb::SBBlock
GetSibling ();
lldb::SBBlock
GetFirstChild ();
uint32_t lldb::SBBlock GetFirstChild();
GetNumRanges ();
lldb::SBAddress uint32_t GetNumRanges();
GetRangeStartAddress (uint32_t idx);
lldb::SBAddress lldb::SBAddress GetRangeStartAddress(uint32_t idx);
GetRangeEndAddress (uint32_t idx);
uint32_t lldb::SBAddress GetRangeEndAddress(uint32_t idx);
GetRangeIndexForBlockAddress (lldb::SBAddress block_addr);
lldb::SBValueList uint32_t GetRangeIndexForBlockAddress(lldb::SBAddress block_addr);
GetVariables (lldb::SBFrame& frame,
bool arguments,
bool locals,
bool statics,
lldb::DynamicValueType use_dynamic);
lldb::SBValueList
GetVariables (lldb::SBTarget& target,
bool arguments,
bool locals,
bool statics);
//------------------------------------------------------------------
/// Get the inlined block that contains this block.
///
/// @return
/// If this block is inlined, it will return this block, else
/// parent blocks will be searched to see if any contain this
/// block and are themselves inlined. An invalid SBBlock will
/// be returned if this block nor any parent blocks are inlined
/// function blocks.
//------------------------------------------------------------------
lldb::SBBlock
GetContainingInlinedBlock ();
bool lldb::SBValueList GetVariables(lldb::SBFrame &frame, bool arguments,
GetDescription (lldb::SBStream &description); bool locals, bool statics,
lldb::DynamicValueType use_dynamic);
lldb::SBValueList GetVariables(lldb::SBTarget &target, bool arguments,
bool locals, bool statics);
//------------------------------------------------------------------
/// Get the inlined block that contains this block.
///
/// @return
/// If this block is inlined, it will return this block, else
/// parent blocks will be searched to see if any contain this
/// block and are themselves inlined. An invalid SBBlock will
/// be returned if this block nor any parent blocks are inlined
/// function blocks.
//------------------------------------------------------------------
lldb::SBBlock GetContainingInlinedBlock();
bool GetDescription(lldb::SBStream &description);
private: private:
friend class SBAddress; friend class SBAddress;
friend class SBFrame; friend class SBFrame;
friend class SBFunction; friend class SBFunction;
friend class SBSymbolContext; friend class SBSymbolContext;
lldb_private::Block * lldb_private::Block *GetPtr();
GetPtr ();
void void SetPtr(lldb_private::Block *lldb_object_ptr);
SetPtr (lldb_private::Block *lldb_object_ptr);
SBBlock (lldb_private::Block *lldb_object_ptr); SBBlock(lldb_private::Block *lldb_object_ptr);
void void AppendVariables(bool can_create, bool get_parent_variables,
AppendVariables (bool can_create, bool get_parent_variables, lldb_private::VariableList *var_list); lldb_private::VariableList *var_list);
lldb_private::Block *m_opaque_ptr; lldb_private::Block *m_opaque_ptr;
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBBlock_h_ #endif // LLDB_SBBlock_h_

View File

@ -14,180 +14,131 @@
namespace lldb { namespace lldb {
class LLDB_API SBBreakpoint class LLDB_API SBBreakpoint {
{
public: public:
typedef bool (*BreakpointHitCallback)(void *baton, SBProcess &process,
SBThread &thread,
lldb::SBBreakpointLocation &location);
typedef bool (*BreakpointHitCallback) (void *baton, SBBreakpoint();
SBProcess &process,
SBThread &thread,
lldb::SBBreakpointLocation &location);
SBBreakpoint (); SBBreakpoint(const lldb::SBBreakpoint &rhs);
SBBreakpoint (const lldb::SBBreakpoint& rhs); ~SBBreakpoint();
~SBBreakpoint(); const lldb::SBBreakpoint &operator=(const lldb::SBBreakpoint &rhs);
const lldb::SBBreakpoint & // Tests to see if the opaque breakpoint object in this object matches the
operator = (const lldb::SBBreakpoint& rhs); // opaque breakpoint object in "rhs".
bool operator==(const lldb::SBBreakpoint &rhs);
// Tests to see if the opaque breakpoint object in this object matches the
// opaque breakpoint object in "rhs".
bool
operator == (const lldb::SBBreakpoint& rhs);
bool bool operator!=(const lldb::SBBreakpoint &rhs);
operator != (const lldb::SBBreakpoint& rhs);
break_id_t
GetID () const;
bool break_id_t GetID() const;
IsValid() const;
void bool IsValid() const;
ClearAllBreakpointSites ();
lldb::SBBreakpointLocation void ClearAllBreakpointSites();
FindLocationByAddress (lldb::addr_t vm_addr);
lldb::break_id_t lldb::SBBreakpointLocation FindLocationByAddress(lldb::addr_t vm_addr);
FindLocationIDByAddress (lldb::addr_t vm_addr);
lldb::SBBreakpointLocation lldb::break_id_t FindLocationIDByAddress(lldb::addr_t vm_addr);
FindLocationByID (lldb::break_id_t bp_loc_id);
lldb::SBBreakpointLocation lldb::SBBreakpointLocation FindLocationByID(lldb::break_id_t bp_loc_id);
GetLocationAtIndex (uint32_t index);
void lldb::SBBreakpointLocation GetLocationAtIndex(uint32_t index);
SetEnabled (bool enable);
bool void SetEnabled(bool enable);
IsEnabled ();
void
SetOneShot (bool one_shot);
bool bool IsEnabled();
IsOneShot () const;
bool
IsInternal ();
uint32_t void SetOneShot(bool one_shot);
GetHitCount () const;
void bool IsOneShot() const;
SetIgnoreCount (uint32_t count);
uint32_t bool IsInternal();
GetIgnoreCount () const;
void
SetCondition (const char *condition);
const char *
GetCondition ();
void uint32_t GetHitCount() const;
SetThreadID (lldb::tid_t sb_thread_id);
lldb::tid_t void SetIgnoreCount(uint32_t count);
GetThreadID ();
void
SetThreadIndex (uint32_t index);
uint32_t
GetThreadIndex() const;
void
SetThreadName (const char *thread_name);
const char *
GetThreadName () const;
void
SetQueueName (const char *queue_name);
const char *
GetQueueName () const;
void uint32_t GetIgnoreCount() const;
SetCallback (BreakpointHitCallback callback, void *baton);
void
SetScriptCallbackFunction (const char *callback_function_name);
SBError
SetScriptCallbackBody (const char *script_body_text);
bool void SetCondition(const char *condition);
AddName (const char *new_name);
void const char *GetCondition();
RemoveName (const char *name_to_remove);
bool void SetThreadID(lldb::tid_t sb_thread_id);
MatchesName (const char *name);
void lldb::tid_t GetThreadID();
GetNames (SBStringList &names);
size_t
GetNumResolvedLocations() const;
size_t void SetThreadIndex(uint32_t index);
GetNumLocations() const;
bool uint32_t GetThreadIndex() const;
GetDescription (lldb::SBStream &description);
static bool void SetThreadName(const char *thread_name);
EventIsBreakpointEvent (const lldb::SBEvent &event);
static lldb::BreakpointEventType
GetBreakpointEventTypeFromEvent (const lldb::SBEvent& event);
static lldb::SBBreakpoint const char *GetThreadName() const;
GetBreakpointFromEvent (const lldb::SBEvent& event);
static lldb::SBBreakpointLocation
GetBreakpointLocationAtIndexFromEvent (const lldb::SBEvent& event, uint32_t loc_idx);
static uint32_t
GetNumBreakpointLocationsFromEvent (const lldb::SBEvent &event_sp);
void SetQueueName(const char *queue_name);
const char *GetQueueName() const;
void SetCallback(BreakpointHitCallback callback, void *baton);
void SetScriptCallbackFunction(const char *callback_function_name);
SBError SetScriptCallbackBody(const char *script_body_text);
bool AddName(const char *new_name);
void RemoveName(const char *name_to_remove);
bool MatchesName(const char *name);
void GetNames(SBStringList &names);
size_t GetNumResolvedLocations() const;
size_t GetNumLocations() const;
bool GetDescription(lldb::SBStream &description);
static bool EventIsBreakpointEvent(const lldb::SBEvent &event);
static lldb::BreakpointEventType
GetBreakpointEventTypeFromEvent(const lldb::SBEvent &event);
static lldb::SBBreakpoint GetBreakpointFromEvent(const lldb::SBEvent &event);
static lldb::SBBreakpointLocation
GetBreakpointLocationAtIndexFromEvent(const lldb::SBEvent &event,
uint32_t loc_idx);
static uint32_t
GetNumBreakpointLocationsFromEvent(const lldb::SBEvent &event_sp);
private: private:
friend class SBBreakpointLocation; friend class SBBreakpointLocation;
friend class SBTarget; friend class SBTarget;
SBBreakpoint (const lldb::BreakpointSP &bp_sp); SBBreakpoint(const lldb::BreakpointSP &bp_sp);
lldb_private::Breakpoint * lldb_private::Breakpoint *operator->() const;
operator->() const;
lldb_private::Breakpoint * lldb_private::Breakpoint *get() const;
get() const;
lldb::BreakpointSP & lldb::BreakpointSP &operator*();
operator *();
const lldb::BreakpointSP & const lldb::BreakpointSP &operator*() const;
operator *() const;
static bool static bool PrivateBreakpointHitCallback(
PrivateBreakpointHitCallback (void *baton, void *baton, lldb_private::StoppointCallbackContext *context,
lldb_private::StoppointCallbackContext *context, lldb::user_id_t break_id, lldb::user_id_t break_loc_id);
lldb::user_id_t break_id,
lldb::user_id_t break_loc_id); lldb::BreakpointSP m_opaque_sp;
lldb::BreakpointSP m_opaque_sp;
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBBreakpoint_h_ #endif // LLDB_SBBreakpoint_h_

View File

@ -10,105 +10,78 @@
#ifndef LLDB_SBBreakpointLocation_h_ #ifndef LLDB_SBBreakpointLocation_h_
#define LLDB_SBBreakpointLocation_h_ #define LLDB_SBBreakpointLocation_h_
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBBreakpoint.h" #include "lldb/API/SBBreakpoint.h"
#include "lldb/API/SBDefines.h"
namespace lldb { namespace lldb {
class LLDB_API SBBreakpointLocation class LLDB_API SBBreakpointLocation {
{
public: public:
SBBreakpointLocation();
SBBreakpointLocation (); SBBreakpointLocation(const lldb::SBBreakpointLocation &rhs);
SBBreakpointLocation (const lldb::SBBreakpointLocation &rhs); ~SBBreakpointLocation();
~SBBreakpointLocation (); const lldb::SBBreakpointLocation &
operator=(const lldb::SBBreakpointLocation &rhs);
const lldb::SBBreakpointLocation & break_id_t GetID();
operator = (const lldb::SBBreakpointLocation &rhs);
break_id_t bool IsValid() const;
GetID ();
bool
IsValid() const;
lldb::SBAddress lldb::SBAddress GetAddress();
GetAddress ();
lldb::addr_t
GetLoadAddress ();
void lldb::addr_t GetLoadAddress();
SetEnabled(bool enabled);
bool void SetEnabled(bool enabled);
IsEnabled ();
uint32_t bool IsEnabled();
GetIgnoreCount ();
void uint32_t GetIgnoreCount();
SetIgnoreCount (uint32_t n);
void void SetIgnoreCount(uint32_t n);
SetCondition (const char *condition);
const char *
GetCondition ();
void void SetCondition(const char *condition);
SetScriptCallbackFunction (const char *callback_function_name);
SBError const char *GetCondition();
SetScriptCallbackBody (const char *script_body_text);
void
SetThreadID (lldb::tid_t sb_thread_id);
lldb::tid_t void SetScriptCallbackFunction(const char *callback_function_name);
GetThreadID ();
void
SetThreadIndex (uint32_t index);
uint32_t
GetThreadIndex() const;
void
SetThreadName (const char *thread_name);
const char *
GetThreadName () const;
void
SetQueueName (const char *queue_name);
const char *
GetQueueName () const;
bool SBError SetScriptCallbackBody(const char *script_body_text);
IsResolved ();
bool void SetThreadID(lldb::tid_t sb_thread_id);
GetDescription (lldb::SBStream &description, DescriptionLevel level);
SBBreakpoint lldb::tid_t GetThreadID();
GetBreakpoint ();
SBBreakpointLocation (const lldb::BreakpointLocationSP &break_loc_sp); void SetThreadIndex(uint32_t index);
uint32_t GetThreadIndex() const;
void SetThreadName(const char *thread_name);
const char *GetThreadName() const;
void SetQueueName(const char *queue_name);
const char *GetQueueName() const;
bool IsResolved();
bool GetDescription(lldb::SBStream &description, DescriptionLevel level);
SBBreakpoint GetBreakpoint();
SBBreakpointLocation(const lldb::BreakpointLocationSP &break_loc_sp);
private: private:
friend class SBBreakpoint; friend class SBBreakpoint;
void void SetLocation(const lldb::BreakpointLocationSP &break_loc_sp);
SetLocation (const lldb::BreakpointLocationSP &break_loc_sp);
lldb::BreakpointLocationSP m_opaque_sp;
lldb::BreakpointLocationSP m_opaque_sp;
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBBreakpointLocation_h_ #endif // LLDB_SBBreakpointLocation_h_

View File

@ -14,84 +14,70 @@
namespace lldb { namespace lldb {
class LLDB_API SBBroadcaster class LLDB_API SBBroadcaster {
{
public: public:
SBBroadcaster (); SBBroadcaster();
SBBroadcaster (const char *name); SBBroadcaster(const char *name);
SBBroadcaster (const SBBroadcaster &rhs); SBBroadcaster(const SBBroadcaster &rhs);
const SBBroadcaster &
operator = (const SBBroadcaster &rhs);
~SBBroadcaster(); const SBBroadcaster &operator=(const SBBroadcaster &rhs);
bool ~SBBroadcaster();
IsValid () const;
void bool IsValid() const;
Clear ();
void void Clear();
BroadcastEventByType (uint32_t event_type, bool unique = false);
void void BroadcastEventByType(uint32_t event_type, bool unique = false);
BroadcastEvent (const lldb::SBEvent &event, bool unique = false);
void void BroadcastEvent(const lldb::SBEvent &event, bool unique = false);
AddInitialEventsToListener (const lldb::SBListener &listener, uint32_t requested_events);
uint32_t void AddInitialEventsToListener(const lldb::SBListener &listener,
AddListener (const lldb::SBListener &listener, uint32_t event_mask); uint32_t requested_events);
const char * uint32_t AddListener(const lldb::SBListener &listener, uint32_t event_mask);
GetName () const;
bool const char *GetName() const;
EventTypeHasListeners (uint32_t event_type);
bool bool EventTypeHasListeners(uint32_t event_type);
RemoveListener (const lldb::SBListener &listener, uint32_t event_mask = UINT32_MAX);
// This comparison is checking if the internal opaque pointer value bool RemoveListener(const lldb::SBListener &listener,
// is equal to that in "rhs". uint32_t event_mask = UINT32_MAX);
bool
operator == (const lldb::SBBroadcaster &rhs) const;
// This comparison is checking if the internal opaque pointer value // This comparison is checking if the internal opaque pointer value
// is not equal to that in "rhs". // is equal to that in "rhs".
bool bool operator==(const lldb::SBBroadcaster &rhs) const;
operator != (const lldb::SBBroadcaster &rhs) const;
// This comparison is checking if the internal opaque pointer value // This comparison is checking if the internal opaque pointer value
// is less than that in "rhs" so SBBroadcaster objects can be contained // is not equal to that in "rhs".
// in ordered containers. bool operator!=(const lldb::SBBroadcaster &rhs) const;
bool
operator < (const lldb::SBBroadcaster &rhs) const; // This comparison is checking if the internal opaque pointer value
// is less than that in "rhs" so SBBroadcaster objects can be contained
// in ordered containers.
bool operator<(const lldb::SBBroadcaster &rhs) const;
protected: protected:
friend class SBCommandInterpreter; friend class SBCommandInterpreter;
friend class SBCommunication; friend class SBCommunication;
friend class SBEvent; friend class SBEvent;
friend class SBListener; friend class SBListener;
friend class SBProcess; friend class SBProcess;
friend class SBTarget; friend class SBTarget;
SBBroadcaster (lldb_private::Broadcaster *broadcaster, bool owns); SBBroadcaster(lldb_private::Broadcaster *broadcaster, bool owns);
lldb_private::Broadcaster * lldb_private::Broadcaster *get() const;
get () const;
void void reset(lldb_private::Broadcaster *broadcaster, bool owns);
reset (lldb_private::Broadcaster *broadcaster, bool owns);
private: private:
lldb::BroadcasterSP m_opaque_sp; lldb::BroadcasterSP m_opaque_sp;
lldb_private::Broadcaster *m_opaque_ptr; lldb_private::Broadcaster *m_opaque_ptr;
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBBroadcaster_h_ #endif // LLDB_SBBroadcaster_h_

View File

@ -16,311 +16,267 @@
// Other libraries and framework includes // Other libraries and framework includes
// Project includes // Project includes
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBDebugger.h" #include "lldb/API/SBDebugger.h"
#include "lldb/API/SBDefines.h"
namespace lldb { namespace lldb {
class LLDB_API SBCommandInterpreterRunOptions class LLDB_API SBCommandInterpreterRunOptions {
{ friend class SBDebugger;
friend class SBDebugger; friend class SBCommandInterpreter;
friend class SBCommandInterpreter;
public: public:
SBCommandInterpreterRunOptions(); SBCommandInterpreterRunOptions();
~SBCommandInterpreterRunOptions(); ~SBCommandInterpreterRunOptions();
bool bool GetStopOnContinue() const;
GetStopOnContinue () const;
void void SetStopOnContinue(bool);
SetStopOnContinue (bool);
bool bool GetStopOnError() const;
GetStopOnError () const;
void void SetStopOnError(bool);
SetStopOnError (bool);
bool bool GetStopOnCrash() const;
GetStopOnCrash () const;
void void SetStopOnCrash(bool);
SetStopOnCrash (bool);
bool bool GetEchoCommands() const;
GetEchoCommands () const;
void void SetEchoCommands(bool);
SetEchoCommands (bool);
bool bool GetPrintResults() const;
GetPrintResults () const;
void void SetPrintResults(bool);
SetPrintResults (bool);
bool bool GetAddToHistory() const;
GetAddToHistory () const;
void void SetAddToHistory(bool);
SetAddToHistory (bool);
private: private:
lldb_private::CommandInterpreterRunOptions * lldb_private::CommandInterpreterRunOptions *get() const;
get () const;
lldb_private::CommandInterpreterRunOptions & lldb_private::CommandInterpreterRunOptions &ref() const;
ref () const;
// This is set in the constructor and will always be valid. // This is set in the constructor and will always be valid.
mutable std::unique_ptr<lldb_private::CommandInterpreterRunOptions> m_opaque_up; mutable std::unique_ptr<lldb_private::CommandInterpreterRunOptions>
m_opaque_up;
}; };
class SBCommandInterpreter class SBCommandInterpreter {
{
public: public:
enum enum {
{ eBroadcastBitThreadShouldExit = (1 << 0),
eBroadcastBitThreadShouldExit = (1 << 0), eBroadcastBitResetPrompt = (1 << 1),
eBroadcastBitResetPrompt = (1 << 1), eBroadcastBitQuitCommandReceived = (1 << 2), // User entered quit
eBroadcastBitQuitCommandReceived = (1 << 2), // User entered quit eBroadcastBitAsynchronousOutputData = (1 << 3),
eBroadcastBitAsynchronousOutputData = (1 << 3), eBroadcastBitAsynchronousErrorData = (1 << 4)
eBroadcastBitAsynchronousErrorData = (1 << 4) };
};
SBCommandInterpreter (const lldb::SBCommandInterpreter &rhs); SBCommandInterpreter(const lldb::SBCommandInterpreter &rhs);
~SBCommandInterpreter ();
const lldb::SBCommandInterpreter & ~SBCommandInterpreter();
operator = (const lldb::SBCommandInterpreter &rhs);
static const char * const lldb::SBCommandInterpreter &
GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type); operator=(const lldb::SBCommandInterpreter &rhs);
static const char *
GetArgumentDescriptionAsCString (const lldb::CommandArgumentType arg_type);
static bool static const char *
EventIsCommandInterpreterEvent (const lldb::SBEvent &event); GetArgumentTypeAsCString(const lldb::CommandArgumentType arg_type);
bool
IsValid() const;
bool static const char *
CommandExists (const char *cmd); GetArgumentDescriptionAsCString(const lldb::CommandArgumentType arg_type);
bool static bool EventIsCommandInterpreterEvent(const lldb::SBEvent &event);
AliasExists (const char *cmd);
lldb::SBBroadcaster bool IsValid() const;
GetBroadcaster ();
static const char *
GetBroadcasterClass ();
bool bool CommandExists(const char *cmd);
HasCommands ();
bool bool AliasExists(const char *cmd);
HasAliases ();
bool lldb::SBBroadcaster GetBroadcaster();
HasAliasOptions ();
lldb::SBProcess static const char *GetBroadcasterClass();
GetProcess ();
lldb::SBDebugger
GetDebugger ();
lldb::SBCommand
AddMultiwordCommand (const char* name, const char* help);
lldb::SBCommand
AddCommand (const char* name, lldb::SBCommandPluginInterface *impl, const char* help);
lldb::SBCommand bool HasCommands();
AddCommand (const char* name, lldb::SBCommandPluginInterface *impl, const char* help, const char* syntax);
void bool HasAliases();
SourceInitFileInHomeDirectory (lldb::SBCommandReturnObject &result);
void bool HasAliasOptions();
SourceInitFileInCurrentWorkingDirectory (lldb::SBCommandReturnObject &result);
lldb::ReturnStatus lldb::SBProcess GetProcess();
HandleCommand (const char *command_line, lldb::SBCommandReturnObject &result, bool add_to_history = false);
lldb::ReturnStatus lldb::SBDebugger GetDebugger();
HandleCommand (const char *command_line, SBExecutionContext &exe_ctx, SBCommandReturnObject &result, bool add_to_history = false);
void lldb::SBCommand AddMultiwordCommand(const char *name, const char *help);
HandleCommandsFromFile (lldb::SBFileSpec &file,
lldb::SBExecutionContext &override_context,
lldb::SBCommandInterpreterRunOptions &options,
lldb::SBCommandReturnObject result);
// The pointer based interface is not useful in SWIG, since the cursor & last_char arguments are string pointers INTO current_line lldb::SBCommand AddCommand(const char *name,
// and you can't do that in a scripting language interface in general... lldb::SBCommandPluginInterface *impl,
const char *help);
// In either case, the way this works is that the you give it a line and cursor position in the line. The function
// will return the number of completions. The matches list will contain number_of_completions + 1 elements. The first
// element is the common substring after the cursor position for all the matches. The rest of the elements are the
// matches. The first element is useful if you are emulating the common shell behavior where the tab completes
// to the string that is common among all the matches, then you should first check if the first element is non-empty,
// and if so just insert it and move the cursor to the end of the insertion. The next tab will return an empty
// common substring, and a list of choices (if any), at which point you should display the choices and let the user
// type further to disambiguate.
int
HandleCompletion (const char *current_line,
const char *cursor,
const char *last_char,
int match_start_point,
int max_return_elements,
lldb::SBStringList &matches);
int lldb::SBCommand AddCommand(const char *name,
HandleCompletion (const char *current_line, lldb::SBCommandPluginInterface *impl,
uint32_t cursor_pos, const char *help, const char *syntax);
int match_start_point,
int max_return_elements,
lldb::SBStringList &matches);
// Catch commands before they execute by registering a callback that will void SourceInitFileInHomeDirectory(lldb::SBCommandReturnObject &result);
// get called when the command gets executed. This allows GUI or command
// line interfaces to intercept a command and stop it from happening
bool
SetCommandOverrideCallback (const char *command_name,
lldb::CommandOverrideCallback callback,
void *baton);
SBCommandInterpreter(lldb_private::CommandInterpreter *interpreter_ptr = nullptr); // Access using SBDebugger::GetCommandInterpreter();
//----------------------------------------------------------------------
/// Return true if the command interpreter is the active IO handler.
///
/// This indicates that any input coming into the debugger handles will
/// go to the command interpreter and will result in LLDB command line
/// commands being executed.
//----------------------------------------------------------------------
bool
IsActive ();
//----------------------------------------------------------------------
/// Get the string that needs to be written to the debugger stdin file
/// handle when a control character is typed.
///
/// Some GUI programs will intercept "control + char" sequences and want
/// to have them do what normally would happen when using a real
/// terminal, so this function allows GUI programs to emulate this
/// functionality.
///
/// @param[in] ch
/// The character that was typed along with the control key
///
/// @return
/// The string that should be written into the file handle that is
/// feeding the input stream for the debugger, or nullptr if there is
/// no string for this control key.
//----------------------------------------------------------------------
const char *
GetIOHandlerControlSequence(char ch);
bool void
GetPromptOnQuit(); SourceInitFileInCurrentWorkingDirectory(lldb::SBCommandReturnObject &result);
void lldb::ReturnStatus HandleCommand(const char *command_line,
SetPromptOnQuit(bool b); lldb::SBCommandReturnObject &result,
bool add_to_history = false);
//---------------------------------------------------------------------- lldb::ReturnStatus HandleCommand(const char *command_line,
/// Resolve the command just as HandleCommand would, expanding abbreviations SBExecutionContext &exe_ctx,
/// and aliases. If successful, result->GetOutput has the full expansion. SBCommandReturnObject &result,
//---------------------------------------------------------------------- bool add_to_history = false);
void
ResolveCommand(const char *command_line, SBCommandReturnObject &result); void HandleCommandsFromFile(lldb::SBFileSpec &file,
lldb::SBExecutionContext &override_context,
lldb::SBCommandInterpreterRunOptions &options,
lldb::SBCommandReturnObject result);
// The pointer based interface is not useful in SWIG, since the cursor &
// last_char arguments are string pointers INTO current_line
// and you can't do that in a scripting language interface in general...
// In either case, the way this works is that the you give it a line and
// cursor position in the line. The function
// will return the number of completions. The matches list will contain
// number_of_completions + 1 elements. The first
// element is the common substring after the cursor position for all the
// matches. The rest of the elements are the
// matches. The first element is useful if you are emulating the common shell
// behavior where the tab completes
// to the string that is common among all the matches, then you should first
// check if the first element is non-empty,
// and if so just insert it and move the cursor to the end of the insertion.
// The next tab will return an empty
// common substring, and a list of choices (if any), at which point you should
// display the choices and let the user
// type further to disambiguate.
int HandleCompletion(const char *current_line, const char *cursor,
const char *last_char, int match_start_point,
int max_return_elements, lldb::SBStringList &matches);
int HandleCompletion(const char *current_line, uint32_t cursor_pos,
int match_start_point, int max_return_elements,
lldb::SBStringList &matches);
// Catch commands before they execute by registering a callback that will
// get called when the command gets executed. This allows GUI or command
// line interfaces to intercept a command and stop it from happening
bool SetCommandOverrideCallback(const char *command_name,
lldb::CommandOverrideCallback callback,
void *baton);
SBCommandInterpreter(
lldb_private::CommandInterpreter *interpreter_ptr =
nullptr); // Access using SBDebugger::GetCommandInterpreter();
//----------------------------------------------------------------------
/// Return true if the command interpreter is the active IO handler.
///
/// This indicates that any input coming into the debugger handles will
/// go to the command interpreter and will result in LLDB command line
/// commands being executed.
//----------------------------------------------------------------------
bool IsActive();
//----------------------------------------------------------------------
/// Get the string that needs to be written to the debugger stdin file
/// handle when a control character is typed.
///
/// Some GUI programs will intercept "control + char" sequences and want
/// to have them do what normally would happen when using a real
/// terminal, so this function allows GUI programs to emulate this
/// functionality.
///
/// @param[in] ch
/// The character that was typed along with the control key
///
/// @return
/// The string that should be written into the file handle that is
/// feeding the input stream for the debugger, or nullptr if there is
/// no string for this control key.
//----------------------------------------------------------------------
const char *GetIOHandlerControlSequence(char ch);
bool GetPromptOnQuit();
void SetPromptOnQuit(bool b);
//----------------------------------------------------------------------
/// Resolve the command just as HandleCommand would, expanding abbreviations
/// and aliases. If successful, result->GetOutput has the full expansion.
//----------------------------------------------------------------------
void ResolveCommand(const char *command_line, SBCommandReturnObject &result);
protected: protected:
lldb_private::CommandInterpreter & lldb_private::CommandInterpreter &ref();
ref ();
lldb_private::CommandInterpreter * lldb_private::CommandInterpreter *get();
get ();
void void reset(lldb_private::CommandInterpreter *);
reset (lldb_private::CommandInterpreter *);
private: private:
friend class SBDebugger; friend class SBDebugger;
static void static void InitializeSWIG();
InitializeSWIG ();
lldb_private::CommandInterpreter *m_opaque_ptr; lldb_private::CommandInterpreter *m_opaque_ptr;
}; };
class SBCommandPluginInterface class SBCommandPluginInterface {
{
public: public:
virtual virtual ~SBCommandPluginInterface() = default;
~SBCommandPluginInterface() = default;
virtual bool virtual bool DoExecute(lldb::SBDebugger /*debugger*/, char ** /*command*/,
DoExecute (lldb::SBDebugger /*debugger*/, lldb::SBCommandReturnObject & /*result*/) {
char** /*command*/, return false;
lldb::SBCommandReturnObject & /*result*/) }
{
return false;
}
}; };
class SBCommand class SBCommand {
{
public: public:
SBCommand (); SBCommand();
bool bool IsValid();
IsValid ();
const char *GetName();
const char*
GetName (); const char *GetHelp();
const char* const char *GetHelpLong();
GetHelp ();
void SetHelp(const char *);
const char*
GetHelpLong (); void SetHelpLong(const char *);
void uint32_t GetFlags();
SetHelp (const char*);
void SetFlags(uint32_t flags);
void
SetHelpLong (const char*); lldb::SBCommand AddMultiwordCommand(const char *name,
const char *help = nullptr);
uint32_t
GetFlags (); lldb::SBCommand AddCommand(const char *name,
lldb::SBCommandPluginInterface *impl,
void const char *help = nullptr);
SetFlags (uint32_t flags);
lldb::SBCommand AddCommand(const char *name,
lldb::SBCommand lldb::SBCommandPluginInterface *impl,
AddMultiwordCommand(const char* name, const char* help = nullptr); const char *help, const char *syntax);
lldb::SBCommand
AddCommand(const char* name, lldb::SBCommandPluginInterface* impl, const char* help = nullptr);
lldb::SBCommand
AddCommand(const char* name, lldb::SBCommandPluginInterface* impl, const char* help, const char* syntax);
private: private:
friend class SBDebugger; friend class SBDebugger;
friend class SBCommandInterpreter; friend class SBCommandInterpreter;
SBCommand (lldb::CommandObjectSP cmd_sp); SBCommand(lldb::CommandObjectSP cmd_sp);
lldb::CommandObjectSP m_opaque_sp; lldb::CommandObjectSP m_opaque_sp;
}; };
} // namespace lldb } // namespace lldb

View File

@ -22,122 +22,90 @@
namespace lldb { namespace lldb {
class LLDB_API SBCommandReturnObject class LLDB_API SBCommandReturnObject {
{
public: public:
SBCommandReturnObject (); SBCommandReturnObject();
SBCommandReturnObject (const lldb::SBCommandReturnObject &rhs); SBCommandReturnObject(const lldb::SBCommandReturnObject &rhs);
~SBCommandReturnObject (); ~SBCommandReturnObject();
const lldb::SBCommandReturnObject & const lldb::SBCommandReturnObject &
operator = (const lldb::SBCommandReturnObject &rhs); operator=(const lldb::SBCommandReturnObject &rhs);
SBCommandReturnObject (lldb_private::CommandReturnObject *ptr); SBCommandReturnObject(lldb_private::CommandReturnObject *ptr);
lldb_private::CommandReturnObject *
Release ();
bool lldb_private::CommandReturnObject *Release();
IsValid() const;
const char * bool IsValid() const;
GetOutput ();
const char * const char *GetOutput();
GetError ();
size_t const char *GetError();
PutOutput (FILE *fh);
size_t size_t PutOutput(FILE *fh);
GetOutputSize ();
size_t size_t GetOutputSize();
GetErrorSize ();
size_t size_t GetErrorSize();
PutError (FILE *fh);
void size_t PutError(FILE *fh);
Clear();
lldb::ReturnStatus void Clear();
GetStatus();
void
SetStatus (lldb::ReturnStatus status);
bool lldb::ReturnStatus GetStatus();
Succeeded ();
bool void SetStatus(lldb::ReturnStatus status);
HasResult ();
void bool Succeeded();
AppendMessage (const char *message);
bool HasResult();
void AppendMessage(const char *message);
void AppendWarning(const char *message);
bool GetDescription(lldb::SBStream &description);
// deprecated, these two functions do not take
// ownership of file handle
void SetImmediateOutputFile(FILE *fh);
void SetImmediateErrorFile(FILE *fh);
void SetImmediateOutputFile(FILE *fh, bool transfer_ownership);
void SetImmediateErrorFile(FILE *fh, bool transfer_ownership);
void PutCString(const char *string, int len = -1);
size_t Printf(const char *format, ...) __attribute__((format(printf, 2, 3)));
const char *GetOutput(bool only_if_no_immediate);
const char *GetError(bool only_if_no_immediate);
void SetError(lldb::SBError &error,
const char *fallback_error_cstr = nullptr);
void SetError(const char *error_cstr);
void
AppendWarning (const char *message);
bool
GetDescription (lldb::SBStream &description);
// deprecated, these two functions do not take
// ownership of file handle
void
SetImmediateOutputFile (FILE *fh);
void
SetImmediateErrorFile (FILE *fh);
void
SetImmediateOutputFile (FILE *fh, bool transfer_ownership);
void
SetImmediateErrorFile (FILE *fh, bool transfer_ownership);
void
PutCString(const char* string, int len = -1);
size_t
Printf(const char* format, ...) __attribute__ ((format (printf, 2, 3)));
const char *
GetOutput (bool only_if_no_immediate);
const char *
GetError (bool only_if_no_immediate);
void
SetError(lldb::SBError &error,
const char *fallback_error_cstr = nullptr);
void
SetError (const char* error_cstr);
protected: protected:
friend class SBCommandInterpreter; friend class SBCommandInterpreter;
friend class SBOptions; friend class SBOptions;
lldb_private::CommandReturnObject * lldb_private::CommandReturnObject *operator->() const;
operator->() const;
lldb_private::CommandReturnObject * lldb_private::CommandReturnObject *get() const;
get() const;
lldb_private::CommandReturnObject & lldb_private::CommandReturnObject &operator*() const;
operator*() const;
lldb_private::CommandReturnObject & lldb_private::CommandReturnObject &ref() const;
ref() const;
void void SetLLDBObjectPtr(lldb_private::CommandReturnObject *ptr);
SetLLDBObjectPtr (lldb_private::CommandReturnObject *ptr);
private: private:
std::unique_ptr<lldb_private::CommandReturnObject> m_opaque_ap; std::unique_ptr<lldb_private::CommandReturnObject> m_opaque_ap;
}; };
} // namespace lldb } // namespace lldb

View File

@ -15,86 +15,68 @@
namespace lldb { namespace lldb {
class LLDB_API SBCommunication class LLDB_API SBCommunication {
{
public: public:
FLAGS_ANONYMOUS_ENUM() FLAGS_ANONYMOUS_ENUM(){
{ eBroadcastBitDisconnected =
eBroadcastBitDisconnected = (1 << 0), ///< Sent when the communications connection is lost. (1 << 0), ///< Sent when the communications connection is lost.
eBroadcastBitReadThreadGotBytes = (1 << 1), ///< Sent by the read thread when bytes become available. eBroadcastBitReadThreadGotBytes =
eBroadcastBitReadThreadDidExit = (1 << 2), ///< Sent by the read thread when it exits to inform clients. (1 << 1), ///< Sent by the read thread when bytes become available.
eBroadcastBitReadThreadShouldExit = (1 << 3), ///< Sent by clients that need to cancel the read thread. eBroadcastBitReadThreadDidExit =
eBroadcastBitPacketAvailable = (1 << 4), ///< Sent when data received makes a complete packet. (1
eAllEventBits = 0xffffffff << 2), ///< Sent by the read thread when it exits to inform clients.
}; eBroadcastBitReadThreadShouldExit =
(1 << 3), ///< Sent by clients that need to cancel the read thread.
eBroadcastBitPacketAvailable =
(1 << 4), ///< Sent when data received makes a complete packet.
eAllEventBits = 0xffffffff};
typedef void (*ReadThreadBytesReceived) (void *baton, const void *src, size_t src_len); typedef void (*ReadThreadBytesReceived)(void *baton, const void *src,
size_t src_len);
SBCommunication (); SBCommunication();
SBCommunication (const char * broadcaster_name); SBCommunication(const char *broadcaster_name);
~SBCommunication (); ~SBCommunication();
bool IsValid() const;
bool lldb::SBBroadcaster GetBroadcaster();
IsValid () const;
lldb::SBBroadcaster static const char *GetBroadcasterClass();
GetBroadcaster ();
static const char *GetBroadcasterClass();
lldb::ConnectionStatus lldb::ConnectionStatus AdoptFileDesriptor(int fd, bool owns_fd);
AdoptFileDesriptor (int fd, bool owns_fd);
lldb::ConnectionStatus lldb::ConnectionStatus Connect(const char *url);
Connect (const char *url);
lldb::ConnectionStatus lldb::ConnectionStatus Disconnect();
Disconnect ();
bool bool IsConnected() const;
IsConnected () const;
bool bool GetCloseOnEOF();
GetCloseOnEOF ();
void void SetCloseOnEOF(bool b);
SetCloseOnEOF (bool b);
size_t size_t Read(void *dst, size_t dst_len, uint32_t timeout_usec,
Read (void *dst, lldb::ConnectionStatus &status);
size_t dst_len,
uint32_t timeout_usec,
lldb::ConnectionStatus &status);
size_t size_t Write(const void *src, size_t src_len, lldb::ConnectionStatus &status);
Write (const void *src,
size_t src_len,
lldb::ConnectionStatus &status);
bool bool ReadThreadStart();
ReadThreadStart ();
bool bool ReadThreadStop();
ReadThreadStop ();
bool bool ReadThreadIsRunning();
ReadThreadIsRunning ();
bool
SetReadThreadBytesReceivedCallback (ReadThreadBytesReceived callback,
void *callback_baton);
bool SetReadThreadBytesReceivedCallback(ReadThreadBytesReceived callback,
void *callback_baton);
private: private:
DISALLOW_COPY_AND_ASSIGN(SBCommunication);
DISALLOW_COPY_AND_ASSIGN (SBCommunication); lldb_private::Communication *m_opaque;
bool m_opaque_owned;
lldb_private::Communication *m_opaque;
bool m_opaque_owned;
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBCommunication_h_ #endif // LLDB_SBCommunication_h_

View File

@ -15,105 +15,82 @@
namespace lldb { namespace lldb {
class LLDB_API SBCompileUnit class LLDB_API SBCompileUnit {
{
public: public:
SBCompileUnit();
SBCompileUnit (); SBCompileUnit(const lldb::SBCompileUnit &rhs);
SBCompileUnit (const lldb::SBCompileUnit &rhs); ~SBCompileUnit();
~SBCompileUnit (); const lldb::SBCompileUnit &operator=(const lldb::SBCompileUnit &rhs);
const lldb::SBCompileUnit & bool IsValid() const;
operator = (const lldb::SBCompileUnit &rhs);
bool lldb::SBFileSpec GetFileSpec() const;
IsValid () const;
lldb::SBFileSpec uint32_t GetNumLineEntries() const;
GetFileSpec () const;
uint32_t lldb::SBLineEntry GetLineEntryAtIndex(uint32_t idx) const;
GetNumLineEntries () const;
lldb::SBLineEntry uint32_t FindLineEntryIndex(uint32_t start_idx, uint32_t line,
GetLineEntryAtIndex (uint32_t idx) const; lldb::SBFileSpec *inline_file_spec) const;
uint32_t uint32_t FindLineEntryIndex(uint32_t start_idx, uint32_t line,
FindLineEntryIndex (uint32_t start_idx, lldb::SBFileSpec *inline_file_spec,
uint32_t line, bool exact) const;
lldb::SBFileSpec *inline_file_spec) const;
uint32_t SBFileSpec GetSupportFileAtIndex(uint32_t idx) const;
FindLineEntryIndex (uint32_t start_idx,
uint32_t line,
lldb::SBFileSpec *inline_file_spec,
bool exact) const;
SBFileSpec uint32_t GetNumSupportFiles() const;
GetSupportFileAtIndex (uint32_t idx) const;
uint32_t uint32_t FindSupportFileIndex(uint32_t start_idx, const SBFileSpec &sb_file,
GetNumSupportFiles () const; bool full);
uint32_t //------------------------------------------------------------------
FindSupportFileIndex (uint32_t start_idx, const SBFileSpec &sb_file, bool full); /// Get all types matching \a type_mask from debug info in this
/// compile unit.
//------------------------------------------------------------------ ///
/// Get all types matching \a type_mask from debug info in this /// @param[in] type_mask
/// compile unit. /// A bitfield that consists of one or more bits logically OR'ed
/// /// together from the lldb::TypeClass enumeration. This allows
/// @param[in] type_mask /// you to request only structure types, or only class, struct
/// A bitfield that consists of one or more bits logically OR'ed /// and union types. Passing in lldb::eTypeClassAny will return
/// together from the lldb::TypeClass enumeration. This allows /// all types found in the debug information for this compile
/// you to request only structure types, or only class, struct /// unit.
/// and union types. Passing in lldb::eTypeClassAny will return ///
/// all types found in the debug information for this compile /// @return
/// unit. /// A list of types in this compile unit that match \a type_mask
/// //------------------------------------------------------------------
/// @return lldb::SBTypeList GetTypes(uint32_t type_mask = lldb::eTypeClassAny);
/// A list of types in this compile unit that match \a type_mask
//------------------------------------------------------------------
lldb::SBTypeList
GetTypes (uint32_t type_mask = lldb::eTypeClassAny);
lldb::LanguageType lldb::LanguageType GetLanguage();
GetLanguage ();
bool
operator == (const lldb::SBCompileUnit &rhs) const;
bool bool operator==(const lldb::SBCompileUnit &rhs) const;
operator != (const lldb::SBCompileUnit &rhs) const;
bool bool operator!=(const lldb::SBCompileUnit &rhs) const;
GetDescription (lldb::SBStream &description);
bool GetDescription(lldb::SBStream &description);
private: private:
friend class SBAddress; friend class SBAddress;
friend class SBFrame; friend class SBFrame;
friend class SBSymbolContext; friend class SBSymbolContext;
friend class SBModule; friend class SBModule;
SBCompileUnit (lldb_private::CompileUnit *lldb_object_ptr); SBCompileUnit(lldb_private::CompileUnit *lldb_object_ptr);
const lldb_private::CompileUnit * const lldb_private::CompileUnit *operator->() const;
operator->() const;
const lldb_private::CompileUnit & const lldb_private::CompileUnit &operator*() const;
operator*() const;
lldb_private::CompileUnit *
get ();
void
reset (lldb_private::CompileUnit *lldb_object_ptr);
lldb_private::CompileUnit *m_opaque_ptr; lldb_private::CompileUnit *get();
void reset(lldb_private::CompileUnit *lldb_object_ptr);
lldb_private::CompileUnit *m_opaque_ptr;
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBCompileUnit_h_ #endif // LLDB_SBCompileUnit_h_

View File

@ -14,168 +14,143 @@
namespace lldb { namespace lldb {
class LLDB_API SBData class LLDB_API SBData {
{
public: public:
SBData();
SBData (); SBData(const SBData &rhs);
SBData (const SBData &rhs); const SBData &operator=(const SBData &rhs);
const SBData &
operator = (const SBData &rhs);
~SBData (); ~SBData();
uint8_t
GetAddressByteSize ();
void
SetAddressByteSize (uint8_t addr_byte_size);
void
Clear ();
bool
IsValid();
size_t
GetByteSize ();
lldb::ByteOrder
GetByteOrder();
void
SetByteOrder (lldb::ByteOrder endian);
float
GetFloat (lldb::SBError& error, lldb::offset_t offset);
double
GetDouble (lldb::SBError& error, lldb::offset_t offset);
long double uint8_t GetAddressByteSize();
GetLongDouble (lldb::SBError& error, lldb::offset_t offset);
lldb::addr_t
GetAddress (lldb::SBError& error, lldb::offset_t offset);
uint8_t
GetUnsignedInt8 (lldb::SBError& error, lldb::offset_t offset);
uint16_t void SetAddressByteSize(uint8_t addr_byte_size);
GetUnsignedInt16 (lldb::SBError& error, lldb::offset_t offset);
uint32_t void Clear();
GetUnsignedInt32 (lldb::SBError& error, lldb::offset_t offset);
uint64_t bool IsValid();
GetUnsignedInt64 (lldb::SBError& error, lldb::offset_t offset);
size_t GetByteSize();
int8_t
GetSignedInt8 (lldb::SBError& error, lldb::offset_t offset); lldb::ByteOrder GetByteOrder();
int16_t void SetByteOrder(lldb::ByteOrder endian);
GetSignedInt16 (lldb::SBError& error, lldb::offset_t offset);
float GetFloat(lldb::SBError &error, lldb::offset_t offset);
int32_t
GetSignedInt32 (lldb::SBError& error, lldb::offset_t offset); double GetDouble(lldb::SBError &error, lldb::offset_t offset);
int64_t long double GetLongDouble(lldb::SBError &error, lldb::offset_t offset);
GetSignedInt64 (lldb::SBError& error, lldb::offset_t offset);
lldb::addr_t GetAddress(lldb::SBError &error, lldb::offset_t offset);
const char*
GetString (lldb::SBError& error, lldb::offset_t offset); uint8_t GetUnsignedInt8(lldb::SBError &error, lldb::offset_t offset);
size_t uint16_t GetUnsignedInt16(lldb::SBError &error, lldb::offset_t offset);
ReadRawData (lldb::SBError& error,
lldb::offset_t offset, uint32_t GetUnsignedInt32(lldb::SBError &error, lldb::offset_t offset);
void *buf,
size_t size); uint64_t GetUnsignedInt64(lldb::SBError &error, lldb::offset_t offset);
bool int8_t GetSignedInt8(lldb::SBError &error, lldb::offset_t offset);
GetDescription (lldb::SBStream &description, lldb::addr_t base_addr = LLDB_INVALID_ADDRESS);
int16_t GetSignedInt16(lldb::SBError &error, lldb::offset_t offset);
// it would be nice to have SetData(SBError, const void*, size_t) when endianness and address size can be
// inferred from the existing DataExtractor, but having two SetData() signatures triggers a SWIG bug where int32_t GetSignedInt32(lldb::SBError &error, lldb::offset_t offset);
// the typemap isn't applied before resolving the overload, and thus the right function never gets called
void int64_t GetSignedInt64(lldb::SBError &error, lldb::offset_t offset);
SetData (lldb::SBError& error, const void *buf, size_t size, lldb::ByteOrder endian, uint8_t addr_size);
const char *GetString(lldb::SBError &error, lldb::offset_t offset);
// see SetData() for why we don't have Append(const void* buf, size_t size)
bool size_t ReadRawData(lldb::SBError &error, lldb::offset_t offset, void *buf,
Append (const SBData& rhs); size_t size);
static lldb::SBData bool GetDescription(lldb::SBStream &description,
CreateDataFromCString (lldb::ByteOrder endian, uint32_t addr_byte_size, const char* data); lldb::addr_t base_addr = LLDB_INVALID_ADDRESS);
// in the following CreateData*() and SetData*() prototypes, the two parameters array and array_len // it would be nice to have SetData(SBError, const void*, size_t) when
// should not be renamed or rearranged, because doing so will break the SWIG typemap // endianness and address size can be
static lldb::SBData // inferred from the existing DataExtractor, but having two SetData()
CreateDataFromUInt64Array (lldb::ByteOrder endian, uint32_t addr_byte_size, uint64_t* array, size_t array_len); // signatures triggers a SWIG bug where
// the typemap isn't applied before resolving the overload, and thus the right
static lldb::SBData // function never gets called
CreateDataFromUInt32Array (lldb::ByteOrder endian, uint32_t addr_byte_size, uint32_t* array, size_t array_len); void SetData(lldb::SBError &error, const void *buf, size_t size,
lldb::ByteOrder endian, uint8_t addr_size);
static lldb::SBData
CreateDataFromSInt64Array (lldb::ByteOrder endian, uint32_t addr_byte_size, int64_t* array, size_t array_len); // see SetData() for why we don't have Append(const void* buf, size_t size)
bool Append(const SBData &rhs);
static lldb::SBData
CreateDataFromSInt32Array (lldb::ByteOrder endian, uint32_t addr_byte_size, int32_t* array, size_t array_len); static lldb::SBData CreateDataFromCString(lldb::ByteOrder endian,
uint32_t addr_byte_size,
static lldb::SBData const char *data);
CreateDataFromDoubleArray (lldb::ByteOrder endian, uint32_t addr_byte_size, double* array, size_t array_len);
// in the following CreateData*() and SetData*() prototypes, the two
bool // parameters array and array_len
SetDataFromCString (const char* data); // should not be renamed or rearranged, because doing so will break the SWIG
// typemap
bool static lldb::SBData CreateDataFromUInt64Array(lldb::ByteOrder endian,
SetDataFromUInt64Array (uint64_t* array, size_t array_len); uint32_t addr_byte_size,
uint64_t *array,
bool size_t array_len);
SetDataFromUInt32Array (uint32_t* array, size_t array_len);
static lldb::SBData CreateDataFromUInt32Array(lldb::ByteOrder endian,
bool uint32_t addr_byte_size,
SetDataFromSInt64Array (int64_t* array, size_t array_len); uint32_t *array,
size_t array_len);
bool
SetDataFromSInt32Array (int32_t* array, size_t array_len); static lldb::SBData CreateDataFromSInt64Array(lldb::ByteOrder endian,
uint32_t addr_byte_size,
bool int64_t *array,
SetDataFromDoubleArray (double* array, size_t array_len); size_t array_len);
static lldb::SBData CreateDataFromSInt32Array(lldb::ByteOrder endian,
uint32_t addr_byte_size,
int32_t *array,
size_t array_len);
static lldb::SBData CreateDataFromDoubleArray(lldb::ByteOrder endian,
uint32_t addr_byte_size,
double *array,
size_t array_len);
bool SetDataFromCString(const char *data);
bool SetDataFromUInt64Array(uint64_t *array, size_t array_len);
bool SetDataFromUInt32Array(uint32_t *array, size_t array_len);
bool SetDataFromSInt64Array(int64_t *array, size_t array_len);
bool SetDataFromSInt32Array(int32_t *array, size_t array_len);
bool SetDataFromDoubleArray(double *array, size_t array_len);
protected: protected:
// Mimic shared pointer...
// Mimic shared pointer... lldb_private::DataExtractor *get() const;
lldb_private::DataExtractor *
get() const;
lldb_private::DataExtractor *
operator->() const;
lldb::DataExtractorSP &
operator*();
const lldb::DataExtractorSP &
operator*() const;
SBData (const lldb::DataExtractorSP &data_sp); lldb_private::DataExtractor *operator->() const;
void lldb::DataExtractorSP &operator*();
SetOpaque (const lldb::DataExtractorSP &data_sp);
const lldb::DataExtractorSP &operator*() const;
SBData(const lldb::DataExtractorSP &data_sp);
void SetOpaque(const lldb::DataExtractorSP &data_sp);
private: private:
friend class SBInstruction; friend class SBInstruction;
friend class SBProcess; friend class SBProcess;
friend class SBSection; friend class SBSection;
friend class SBTarget; friend class SBTarget;
friend class SBValue; friend class SBValue;
lldb::DataExtractorSP m_opaque_sp; lldb::DataExtractorSP m_opaque_sp;
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBData_h_ #endif // LLDB_SBData_h_

View File

@ -16,349 +16,255 @@
#include "lldb/API/SBPlatform.h" #include "lldb/API/SBPlatform.h"
namespace lldb { namespace lldb {
class LLDB_API SBInputReader
{
public:
SBInputReader() = default;
~SBInputReader() = default;
SBError Initialize(lldb::SBDebugger&, unsigned long (*)(void*, lldb::SBInputReader*, lldb::InputReaderAction, char const*, unsigned long), void*, lldb::InputReaderGranularity, char const*, char const*, bool); class LLDB_API SBInputReader {
void SetIsDone(bool); public:
bool IsActive() const; SBInputReader() = default;
~SBInputReader() = default;
SBError Initialize(lldb::SBDebugger &,
unsigned long (*)(void *, lldb::SBInputReader *,
lldb::InputReaderAction, char const *,
unsigned long),
void *, lldb::InputReaderGranularity, char const *,
char const *, bool);
void SetIsDone(bool);
bool IsActive() const;
}; };
class LLDB_API SBDebugger class LLDB_API SBDebugger {
{
public: public:
SBDebugger(); SBDebugger();
SBDebugger(const lldb::SBDebugger &rhs); SBDebugger(const lldb::SBDebugger &rhs);
SBDebugger(const lldb::DebuggerSP &debugger_sp); SBDebugger(const lldb::DebuggerSP &debugger_sp);
~SBDebugger(); ~SBDebugger();
lldb::SBDebugger & lldb::SBDebugger &operator=(const lldb::SBDebugger &rhs);
operator = (const lldb::SBDebugger &rhs);
static void static void Initialize();
Initialize();
static void
Terminate();
// Deprecated, use the one that takes a source_init_files bool.
static lldb::SBDebugger
Create();
static lldb::SBDebugger static void Terminate();
Create(bool source_init_files);
static lldb::SBDebugger // Deprecated, use the one that takes a source_init_files bool.
Create(bool source_init_files, lldb::LogOutputCallback log_callback, void *baton); static lldb::SBDebugger Create();
static void static lldb::SBDebugger Create(bool source_init_files);
Destroy (lldb::SBDebugger &debugger);
static void static lldb::SBDebugger Create(bool source_init_files,
MemoryPressureDetected (); lldb::LogOutputCallback log_callback,
void *baton);
bool static void Destroy(lldb::SBDebugger &debugger);
IsValid() const;
void static void MemoryPressureDetected();
Clear ();
void bool IsValid() const;
SetAsync (bool b);
bool
GetAsync ();
void void Clear();
SkipLLDBInitFiles (bool b);
void void SetAsync(bool b);
SkipAppInitFiles (bool b);
void bool GetAsync();
SetInputFileHandle (FILE *f, bool transfer_ownership);
void void SkipLLDBInitFiles(bool b);
SetOutputFileHandle (FILE *f, bool transfer_ownership);
void void SkipAppInitFiles(bool b);
SetErrorFileHandle (FILE *f, bool transfer_ownership);
FILE *
GetInputFileHandle ();
FILE * void SetInputFileHandle(FILE *f, bool transfer_ownership);
GetOutputFileHandle ();
FILE * void SetOutputFileHandle(FILE *f, bool transfer_ownership);
GetErrorFileHandle ();
void void SetErrorFileHandle(FILE *f, bool transfer_ownership);
SaveInputTerminalState();
void
RestoreInputTerminalState();
lldb::SBCommandInterpreter FILE *GetInputFileHandle();
GetCommandInterpreter ();
void FILE *GetOutputFileHandle();
HandleCommand (const char *command);
lldb::SBListener FILE *GetErrorFileHandle();
GetListener ();
void void SaveInputTerminalState();
HandleProcessEvent (const lldb::SBProcess &process,
const lldb::SBEvent &event,
FILE *out,
FILE *err);
lldb::SBTarget void RestoreInputTerminalState();
CreateTarget (const char *filename,
const char *target_triple,
const char *platform_name,
bool add_dependent_modules,
lldb::SBError& error);
lldb::SBTarget lldb::SBCommandInterpreter GetCommandInterpreter();
CreateTargetWithFileAndTargetTriple (const char *filename,
const char *target_triple);
lldb::SBTarget void HandleCommand(const char *command);
CreateTargetWithFileAndArch (const char *filename,
const char *archname);
lldb::SBTarget lldb::SBListener GetListener();
CreateTarget (const char *filename);
// Return true if target is deleted from the target list of the debugger.
bool
DeleteTarget (lldb::SBTarget &target);
lldb::SBTarget
GetTargetAtIndex (uint32_t idx);
uint32_t
GetIndexOfTarget (lldb::SBTarget target);
lldb::SBTarget void HandleProcessEvent(const lldb::SBProcess &process,
FindTargetWithProcessID (pid_t pid); const lldb::SBEvent &event, FILE *out, FILE *err);
lldb::SBTarget lldb::SBTarget CreateTarget(const char *filename, const char *target_triple,
FindTargetWithFileAndArch (const char *filename, const char *platform_name,
const char *arch); bool add_dependent_modules, lldb::SBError &error);
uint32_t lldb::SBTarget CreateTargetWithFileAndTargetTriple(const char *filename,
GetNumTargets (); const char *target_triple);
lldb::SBTarget lldb::SBTarget CreateTargetWithFileAndArch(const char *filename,
GetSelectedTarget (); const char *archname);
void lldb::SBTarget CreateTarget(const char *filename);
SetSelectedTarget (SBTarget& target);
lldb::SBPlatform // Return true if target is deleted from the target list of the debugger.
GetSelectedPlatform(); bool DeleteTarget(lldb::SBTarget &target);
void lldb::SBTarget GetTargetAtIndex(uint32_t idx);
SetSelectedPlatform(lldb::SBPlatform &platform);
lldb::SBSourceManager
GetSourceManager ();
// REMOVE: just for a quick fix, need to expose platforms through uint32_t GetIndexOfTarget(lldb::SBTarget target);
// SBPlatform from this class.
lldb::SBError lldb::SBTarget FindTargetWithProcessID(pid_t pid);
SetCurrentPlatform (const char *platform_name);
lldb::SBTarget FindTargetWithFileAndArch(const char *filename,
bool const char *arch);
SetCurrentPlatformSDKRoot (const char *sysroot);
uint32_t GetNumTargets();
// FIXME: Once we get the set show stuff in place, the driver won't need
// an interface to the Set/Get UseExternalEditor. lldb::SBTarget GetSelectedTarget();
bool
SetUseExternalEditor (bool input); void SetSelectedTarget(SBTarget &target);
bool lldb::SBPlatform GetSelectedPlatform();
GetUseExternalEditor ();
void SetSelectedPlatform(lldb::SBPlatform &platform);
bool
SetUseColor (bool use_color); lldb::SBSourceManager GetSourceManager();
bool // REMOVE: just for a quick fix, need to expose platforms through
GetUseColor () const; // SBPlatform from this class.
lldb::SBError SetCurrentPlatform(const char *platform_name);
static bool
GetDefaultArchitecture (char *arch_name, size_t arch_name_len); bool SetCurrentPlatformSDKRoot(const char *sysroot);
static bool // FIXME: Once we get the set show stuff in place, the driver won't need
SetDefaultArchitecture (const char *arch_name); // an interface to the Set/Get UseExternalEditor.
bool SetUseExternalEditor(bool input);
lldb::ScriptLanguage
GetScriptingLanguage (const char *script_language_name); bool GetUseExternalEditor();
static const char * bool SetUseColor(bool use_color);
GetVersionString ();
bool GetUseColor() const;
static const char *
StateAsCString (lldb::StateType state); static bool GetDefaultArchitecture(char *arch_name, size_t arch_name_len);
static bool static bool SetDefaultArchitecture(const char *arch_name);
StateIsRunningState (lldb::StateType state);
lldb::ScriptLanguage GetScriptingLanguage(const char *script_language_name);
static bool
StateIsStoppedState (lldb::StateType state); static const char *GetVersionString();
bool static const char *StateAsCString(lldb::StateType state);
EnableLog (const char *channel, const char **categories);
static bool StateIsRunningState(lldb::StateType state);
void
SetLoggingCallback (lldb::LogOutputCallback log_callback, void *baton); static bool StateIsStoppedState(lldb::StateType state);
// DEPRECATED bool EnableLog(const char *channel, const char **categories);
void
DispatchInput (void* baton, void SetLoggingCallback(lldb::LogOutputCallback log_callback, void *baton);
const void* data,
size_t data_len); // DEPRECATED
void DispatchInput(void *baton, const void *data, size_t data_len);
void
DispatchInput (const void *data, size_t data_len); void DispatchInput(const void *data, size_t data_len);
void void DispatchInputInterrupt();
DispatchInputInterrupt ();
void DispatchInputEndOfFile();
void
DispatchInputEndOfFile (); void PushInputReader(lldb::SBInputReader &reader);
void const char *GetInstanceName();
PushInputReader (lldb::SBInputReader &reader);
static SBDebugger FindDebuggerWithID(int id);
const char *
GetInstanceName (); static lldb::SBError SetInternalVariable(const char *var_name,
const char *value,
static SBDebugger const char *debugger_instance_name);
FindDebuggerWithID (int id);
static lldb::SBStringList
static lldb::SBError GetInternalVariableValue(const char *var_name,
SetInternalVariable (const char *var_name, const char *value, const char *debugger_instance_name); const char *debugger_instance_name);
static lldb::SBStringList bool GetDescription(lldb::SBStream &description);
GetInternalVariableValue (const char *var_name, const char *debugger_instance_name);
uint32_t GetTerminalWidth() const;
bool
GetDescription (lldb::SBStream &description); void SetTerminalWidth(uint32_t term_width);
uint32_t lldb::user_id_t GetID();
GetTerminalWidth () const;
const char *GetPrompt() const;
void
SetTerminalWidth (uint32_t term_width); void SetPrompt(const char *prompt);
lldb::user_id_t lldb::ScriptLanguage GetScriptLanguage() const;
GetID ();
void SetScriptLanguage(lldb::ScriptLanguage script_lang);
const char *
GetPrompt() const; bool GetCloseInputOnEOF() const;
void void SetCloseInputOnEOF(bool b);
SetPrompt (const char *prompt);
SBTypeCategory GetCategory(const char *category_name);
lldb::ScriptLanguage
GetScriptLanguage() const; SBTypeCategory GetCategory(lldb::LanguageType lang_type);
void SBTypeCategory CreateCategory(const char *category_name);
SetScriptLanguage (lldb::ScriptLanguage script_lang);
bool DeleteCategory(const char *category_name);
bool
GetCloseInputOnEOF () const; uint32_t GetNumCategories();
void SBTypeCategory GetCategoryAtIndex(uint32_t);
SetCloseInputOnEOF (bool b);
SBTypeCategory GetDefaultCategory();
SBTypeCategory
GetCategory (const char* category_name); SBTypeFormat GetFormatForType(SBTypeNameSpecifier);
SBTypeCategory
GetCategory (lldb::LanguageType lang_type);
SBTypeCategory
CreateCategory (const char* category_name);
bool
DeleteCategory (const char* category_name);
uint32_t
GetNumCategories ();
SBTypeCategory
GetCategoryAtIndex (uint32_t);
SBTypeCategory
GetDefaultCategory();
SBTypeFormat
GetFormatForType (SBTypeNameSpecifier);
#ifndef LLDB_DISABLE_PYTHON #ifndef LLDB_DISABLE_PYTHON
SBTypeSummary SBTypeSummary GetSummaryForType(SBTypeNameSpecifier);
GetSummaryForType (SBTypeNameSpecifier);
#endif #endif
SBTypeFilter SBTypeFilter GetFilterForType(SBTypeNameSpecifier);
GetFilterForType (SBTypeNameSpecifier);
#ifndef LLDB_DISABLE_PYTHON #ifndef LLDB_DISABLE_PYTHON
SBTypeSynthetic SBTypeSynthetic GetSyntheticForType(SBTypeNameSpecifier);
GetSyntheticForType (SBTypeNameSpecifier);
#endif #endif
void void RunCommandInterpreter(bool auto_handle_events, bool spawn_thread);
RunCommandInterpreter (bool auto_handle_events,
bool spawn_thread);
void void RunCommandInterpreter(bool auto_handle_events, bool spawn_thread,
RunCommandInterpreter (bool auto_handle_events, SBCommandInterpreterRunOptions &options,
bool spawn_thread, int &num_errors, bool &quit_requested,
SBCommandInterpreterRunOptions &options, bool &stopped_for_crash);
int &num_errors,
bool &quit_requested, SBError RunREPL(lldb::LanguageType language, const char *repl_options);
bool &stopped_for_crash);
SBError
RunREPL (lldb::LanguageType language, const char *repl_options);
private: private:
friend class SBCommandInterpreter; friend class SBCommandInterpreter;
friend class SBInputReader; friend class SBInputReader;
friend class SBListener; friend class SBListener;
friend class SBProcess; friend class SBProcess;
friend class SBSourceManager; friend class SBSourceManager;
friend class SBTarget; friend class SBTarget;
lldb::SBTarget
FindTargetWithLLDBProcess (const lldb::ProcessSP &processSP);
void lldb::SBTarget FindTargetWithLLDBProcess(const lldb::ProcessSP &processSP);
reset (const lldb::DebuggerSP &debugger_sp);
lldb_private::Debugger * void reset(const lldb::DebuggerSP &debugger_sp);
get () const;
lldb_private::Debugger & lldb_private::Debugger *get() const;
ref () const;
const lldb::DebuggerSP & lldb_private::Debugger &ref() const;
get_sp () const;
const lldb::DebuggerSP &get_sp() const;
lldb::DebuggerSP m_opaque_sp;
lldb::DebuggerSP m_opaque_sp;
}; // class SBDebugger }; // class SBDebugger

View File

@ -1,4 +1,5 @@
//===-- SBDeclaration.h -------------------------------------------*- C++ -*-===// //===-- SBDeclaration.h -------------------------------------------*- C++
//-*-===//
// //
// The LLVM Compiler Infrastructure // The LLVM Compiler Infrastructure
// //
@ -14,76 +15,56 @@
#include "lldb/API/SBFileSpec.h" #include "lldb/API/SBFileSpec.h"
namespace lldb { namespace lldb {
class LLDB_API SBDeclaration class LLDB_API SBDeclaration {
{ public:
public: SBDeclaration();
SBDeclaration (); SBDeclaration(const lldb::SBDeclaration &rhs);
SBDeclaration (const lldb::SBDeclaration &rhs); ~SBDeclaration();
~SBDeclaration (); const lldb::SBDeclaration &operator=(const lldb::SBDeclaration &rhs);
const lldb::SBDeclaration & bool IsValid() const;
operator = (const lldb::SBDeclaration &rhs);
lldb::SBFileSpec GetFileSpec() const;
bool
IsValid () const; uint32_t GetLine() const;
lldb::SBFileSpec uint32_t GetColumn() const;
GetFileSpec () const;
void SetFileSpec(lldb::SBFileSpec filespec);
uint32_t
GetLine () const; void SetLine(uint32_t line);
uint32_t void SetColumn(uint32_t column);
GetColumn () const;
bool operator==(const lldb::SBDeclaration &rhs) const;
void
SetFileSpec (lldb::SBFileSpec filespec); bool operator!=(const lldb::SBDeclaration &rhs) const;
void bool GetDescription(lldb::SBStream &description);
SetLine (uint32_t line);
protected:
void lldb_private::Declaration *get();
SetColumn (uint32_t column);
private:
bool friend class SBValue;
operator == (const lldb::SBDeclaration &rhs) const;
const lldb_private::Declaration *operator->() const;
bool
operator != (const lldb::SBDeclaration &rhs) const; lldb_private::Declaration &ref();
bool const lldb_private::Declaration &ref() const;
GetDescription (lldb::SBStream &description);
SBDeclaration(const lldb_private::Declaration *lldb_object_ptr);
protected:
void SetDeclaration(const lldb_private::Declaration &lldb_object_ref);
lldb_private::Declaration *
get (); std::unique_ptr<lldb_private::Declaration> m_opaque_ap;
};
private:
friend class SBValue;
const lldb_private::Declaration *
operator->() const;
lldb_private::Declaration &
ref();
const lldb_private::Declaration &
ref() const;
SBDeclaration (const lldb_private::Declaration *lldb_object_ptr);
void
SetDeclaration (const lldb_private::Declaration &lldb_object_ref);
std::unique_ptr<lldb_private::Declaration> m_opaque_ap;
};
} // namespace lldb } // namespace lldb
#endif // LLDB_SBDeclaration_h_ #endif // LLDB_SBDeclaration_h_

View File

@ -96,7 +96,6 @@ class LLDB_API SBValueList;
class LLDB_API SBVariablesOptions; class LLDB_API SBVariablesOptions;
class LLDB_API SBWatchpoint; class LLDB_API SBWatchpoint;
class LLDB_API SBUnixSignals; class LLDB_API SBUnixSignals;
} }
#endif // LLDB_SBDefines_h_ #endif // LLDB_SBDefines_h_

View File

@ -16,94 +16,73 @@ namespace lldb {
class LLDB_API SBError { class LLDB_API SBError {
public: public:
SBError (); SBError();
SBError (const lldb::SBError &rhs); SBError(const lldb::SBError &rhs);
~SBError(); ~SBError();
const SBError & const SBError &operator=(const lldb::SBError &rhs);
operator =(const lldb::SBError &rhs);
const char * const char *GetCString() const;
GetCString () const;
void void Clear();
Clear ();
bool bool Fail() const;
Fail () const;
bool bool Success() const;
Success () const;
uint32_t uint32_t GetError() const;
GetError () const;
lldb::ErrorType lldb::ErrorType GetType() const;
GetType () const;
void void SetError(uint32_t err, lldb::ErrorType type);
SetError (uint32_t err, lldb::ErrorType type);
void void SetErrorToErrno();
SetErrorToErrno ();
void void SetErrorToGenericError();
SetErrorToGenericError ();
void void SetErrorString(const char *err_str);
SetErrorString (const char *err_str);
int int SetErrorStringWithFormat(const char *format, ...)
SetErrorStringWithFormat (const char *format, ...) __attribute__ ((format (printf, 2, 3))); __attribute__((format(printf, 2, 3)));
bool bool IsValid() const;
IsValid () const;
bool bool GetDescription(lldb::SBStream &description);
GetDescription (lldb::SBStream &description);
protected: protected:
friend class SBCommandReturnObject;
friend class SBData;
friend class SBDebugger;
friend class SBCommunication;
friend class SBHostOS;
friend class SBPlatform;
friend class SBProcess;
friend class SBStructuredData;
friend class SBThread;
friend class SBTarget;
friend class SBValue;
friend class SBWatchpoint;
friend class SBBreakpoint;
friend class SBBreakpointLocation;
friend class SBCommandReturnObject; lldb_private::Error *get();
friend class SBData;
friend class SBDebugger;
friend class SBCommunication;
friend class SBHostOS;
friend class SBPlatform;
friend class SBProcess;
friend class SBStructuredData;
friend class SBThread;
friend class SBTarget;
friend class SBValue;
friend class SBWatchpoint;
friend class SBBreakpoint;
friend class SBBreakpointLocation;
lldb_private::Error * lldb_private::Error *operator->();
get();
lldb_private::Error * const lldb_private::Error &operator*() const;
operator->();
const lldb_private::Error & lldb_private::Error &ref();
operator*() const;
lldb_private::Error & void SetError(const lldb_private::Error &lldb_error);
ref();
void
SetError (const lldb_private::Error &lldb_error);
private: private:
std::unique_ptr<lldb_private::Error> m_opaque_ap; std::unique_ptr<lldb_private::Error> m_opaque_ap;
void void CreateIfNeeded();
CreateIfNeeded ();
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBError_h_ #endif // LLDB_SBError_h_

View File

@ -15,91 +15,72 @@
#include <stdio.h> #include <stdio.h>
#include <vector> #include <vector>
namespace lldb { namespace lldb {
class SBBroadcaster; class SBBroadcaster;
class LLDB_API SBEvent class LLDB_API SBEvent {
{
public: public:
SBEvent(); SBEvent();
SBEvent (const lldb::SBEvent &rhs); SBEvent(const lldb::SBEvent &rhs);
// Make an event that contains a C string.
SBEvent (uint32_t event, const char *cstr, uint32_t cstr_len);
SBEvent (lldb::EventSP &event_sp); // Make an event that contains a C string.
SBEvent(uint32_t event, const char *cstr, uint32_t cstr_len);
SBEvent (lldb_private::Event *event_sp); SBEvent(lldb::EventSP &event_sp);
~SBEvent(); SBEvent(lldb_private::Event *event_sp);
const SBEvent & ~SBEvent();
operator = (const lldb::SBEvent &rhs);
bool const SBEvent &operator=(const lldb::SBEvent &rhs);
IsValid() const;
const char * bool IsValid() const;
GetDataFlavor ();
uint32_t const char *GetDataFlavor();
GetType () const;
lldb::SBBroadcaster uint32_t GetType() const;
GetBroadcaster () const;
const char * lldb::SBBroadcaster GetBroadcaster() const;
GetBroadcasterClass () const;
bool const char *GetBroadcasterClass() const;
BroadcasterMatchesPtr (const lldb::SBBroadcaster *broadcaster);
bool bool BroadcasterMatchesPtr(const lldb::SBBroadcaster *broadcaster);
BroadcasterMatchesRef (const lldb::SBBroadcaster &broadcaster);
void bool BroadcasterMatchesRef(const lldb::SBBroadcaster &broadcaster);
Clear();
static const char * void Clear();
GetCStringFromEvent (const lldb::SBEvent &event);
bool static const char *GetCStringFromEvent(const lldb::SBEvent &event);
GetDescription (lldb::SBStream &description);
bool bool GetDescription(lldb::SBStream &description);
GetDescription (lldb::SBStream &description) const;
bool GetDescription(lldb::SBStream &description) const;
protected: protected:
friend class SBListener; friend class SBListener;
friend class SBBroadcaster; friend class SBBroadcaster;
friend class SBBreakpoint; friend class SBBreakpoint;
friend class SBDebugger; friend class SBDebugger;
friend class SBProcess; friend class SBProcess;
friend class SBTarget; friend class SBTarget;
friend class SBThread; friend class SBThread;
friend class SBWatchpoint; friend class SBWatchpoint;
lldb::EventSP & lldb::EventSP &GetSP() const;
GetSP () const;
void void reset(lldb::EventSP &event_sp);
reset (lldb::EventSP &event_sp);
void void reset(lldb_private::Event *event);
reset (lldb_private::Event* event);
lldb_private::Event * lldb_private::Event *get() const;
get () const;
private: private:
mutable lldb::EventSP m_event_sp;
mutable lldb::EventSP m_event_sp; mutable lldb_private::Event *m_opaque_ptr;
mutable lldb_private::Event *m_opaque_ptr;
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBEvent_h_ #endif // LLDB_SBEvent_h_

View File

@ -1,4 +1,5 @@
//===-- SBExecutionContext.h -----------------------------------------*- C++ -*-===// //===-- SBExecutionContext.h -----------------------------------------*- C++
//-*-===//
// //
// The LLVM Compiler Infrastructure // The LLVM Compiler Infrastructure
// //
@ -15,60 +16,51 @@
#include <stdio.h> #include <stdio.h>
#include <vector> #include <vector>
namespace lldb { namespace lldb {
class LLDB_API SBExecutionContext class LLDB_API SBExecutionContext {
{ friend class SBCommandInterpreter;
friend class SBCommandInterpreter;
public: public:
SBExecutionContext(); SBExecutionContext();
SBExecutionContext (const lldb::SBExecutionContext &rhs);
SBExecutionContext (lldb::ExecutionContextRefSP exe_ctx_ref_sp);
SBExecutionContext (const lldb::SBTarget &target);
SBExecutionContext (const lldb::SBProcess &process);
SBExecutionContext (lldb::SBThread thread); // can't be a const& because SBThread::get() isn't itself a const function
SBExecutionContext (const lldb::SBFrame &frame);
~SBExecutionContext();
const SBExecutionContext &
operator = (const lldb::SBExecutionContext &rhs);
SBTarget
GetTarget () const;
SBProcess
GetProcess () const;
SBThread SBExecutionContext(const lldb::SBExecutionContext &rhs);
GetThread () const;
SBExecutionContext(lldb::ExecutionContextRefSP exe_ctx_ref_sp);
SBExecutionContext(const lldb::SBTarget &target);
SBExecutionContext(const lldb::SBProcess &process);
SBExecutionContext(lldb::SBThread thread); // can't be a const& because
// SBThread::get() isn't itself a
// const function
SBExecutionContext(const lldb::SBFrame &frame);
~SBExecutionContext();
const SBExecutionContext &operator=(const lldb::SBExecutionContext &rhs);
SBTarget GetTarget() const;
SBProcess GetProcess() const;
SBThread GetThread() const;
SBFrame GetFrame() const;
SBFrame
GetFrame () const;
protected: protected:
ExecutionContextRefSP & ExecutionContextRefSP &GetSP() const;
GetSP () const;
void reset(lldb::ExecutionContextRefSP &event_sp);
void
reset (lldb::ExecutionContextRefSP &event_sp); lldb_private::ExecutionContextRef *get() const;
lldb_private::ExecutionContextRef *
get () const;
private: private:
mutable lldb::ExecutionContextRefSP m_exe_ctx_sp;
mutable lldb::ExecutionContextRefSP m_exe_ctx_sp;
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBExecutionContext_h_ #endif // LLDB_SBExecutionContext_h_

View File

@ -16,133 +16,100 @@
namespace lldb { namespace lldb {
class LLDB_API SBExpressionOptions {
class LLDB_API SBExpressionOptions
{
public: public:
SBExpressionOptions(); SBExpressionOptions();
SBExpressionOptions (const lldb::SBExpressionOptions &rhs); SBExpressionOptions(const lldb::SBExpressionOptions &rhs);
~SBExpressionOptions();
const SBExpressionOptions & ~SBExpressionOptions();
operator = (const lldb::SBExpressionOptions &rhs);
bool const SBExpressionOptions &operator=(const lldb::SBExpressionOptions &rhs);
GetCoerceResultToId () const;
void
SetCoerceResultToId (bool coerce = true);
bool
GetUnwindOnError () const;
void
SetUnwindOnError (bool unwind = true);
bool
GetIgnoreBreakpoints () const;
void
SetIgnoreBreakpoints (bool ignore = true);
lldb::DynamicValueType
GetFetchDynamicValue () const;
void
SetFetchDynamicValue (lldb::DynamicValueType dynamic = lldb::eDynamicCanRunTarget);
uint32_t
GetTimeoutInMicroSeconds () const;
// Set the timeout for the expression, 0 means wait forever.
void
SetTimeoutInMicroSeconds (uint32_t timeout = 0);
uint32_t
GetOneThreadTimeoutInMicroSeconds () const;
// Set the timeout for running on one thread, 0 means use the default behavior.
// If you set this higher than the overall timeout, you'll get an error when you
// try to run the expression.
void
SetOneThreadTimeoutInMicroSeconds (uint32_t timeout = 0);
bool
GetTryAllThreads () const;
void
SetTryAllThreads (bool run_others = true);
bool
GetStopOthers() const;
void
SetStopOthers(bool stop_others = true);
bool bool GetCoerceResultToId() const;
GetTrapExceptions () const;
void
SetTrapExceptions (bool trap_exceptions = true);
void
SetLanguage (lldb::LanguageType language);
void void SetCoerceResultToId(bool coerce = true);
SetCancelCallback (lldb::ExpressionCancelCallback callback, void *baton);
bool bool GetUnwindOnError() const;
GetGenerateDebugInfo ();
void
SetGenerateDebugInfo (bool b = true);
bool
GetSuppressPersistentResult ();
void
SetSuppressPersistentResult (bool b = false);
const char * void SetUnwindOnError(bool unwind = true);
GetPrefix () const;
void bool GetIgnoreBreakpoints() const;
SetPrefix (const char *prefix);
void
SetAutoApplyFixIts(bool b = true);
bool
GetAutoApplyFixIts();
bool
GetTopLevel ();
void void SetIgnoreBreakpoints(bool ignore = true);
SetTopLevel (bool b = true);
lldb::DynamicValueType GetFetchDynamicValue() const;
void SetFetchDynamicValue(
lldb::DynamicValueType dynamic = lldb::eDynamicCanRunTarget);
uint32_t GetTimeoutInMicroSeconds() const;
// Set the timeout for the expression, 0 means wait forever.
void SetTimeoutInMicroSeconds(uint32_t timeout = 0);
uint32_t GetOneThreadTimeoutInMicroSeconds() const;
// Set the timeout for running on one thread, 0 means use the default
// behavior.
// If you set this higher than the overall timeout, you'll get an error when
// you
// try to run the expression.
void SetOneThreadTimeoutInMicroSeconds(uint32_t timeout = 0);
bool GetTryAllThreads() const;
void SetTryAllThreads(bool run_others = true);
bool GetStopOthers() const;
void SetStopOthers(bool stop_others = true);
bool GetTrapExceptions() const;
void SetTrapExceptions(bool trap_exceptions = true);
void SetLanguage(lldb::LanguageType language);
void SetCancelCallback(lldb::ExpressionCancelCallback callback, void *baton);
bool GetGenerateDebugInfo();
void SetGenerateDebugInfo(bool b = true);
bool GetSuppressPersistentResult();
void SetSuppressPersistentResult(bool b = false);
const char *GetPrefix() const;
void SetPrefix(const char *prefix);
void SetAutoApplyFixIts(bool b = true);
bool GetAutoApplyFixIts();
bool GetTopLevel();
void SetTopLevel(bool b = true);
protected: protected:
SBExpressionOptions(
lldb_private::EvaluateExpressionOptions &expression_options);
SBExpressionOptions (lldb_private::EvaluateExpressionOptions &expression_options); lldb_private::EvaluateExpressionOptions *get() const;
lldb_private::EvaluateExpressionOptions * lldb_private::EvaluateExpressionOptions &ref() const;
get () const;
lldb_private::EvaluateExpressionOptions & friend class SBFrame;
ref () const; friend class SBValue;
friend class SBTarget;
friend class SBFrame;
friend class SBValue;
friend class SBTarget;
private: private:
// This auto_pointer is made in the constructor and is always valid. // This auto_pointer is made in the constructor and is always valid.
mutable std::unique_ptr<lldb_private::EvaluateExpressionOptions> m_opaque_ap; mutable std::unique_ptr<lldb_private::EvaluateExpressionOptions> m_opaque_ap;
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBExpressionOptions_h_ #endif // LLDB_SBExpressionOptions_h_

View File

@ -14,94 +14,76 @@
namespace lldb { namespace lldb {
class LLDB_API SBFileSpec class LLDB_API SBFileSpec {
{
public: public:
SBFileSpec (); SBFileSpec();
SBFileSpec (const lldb::SBFileSpec &rhs); SBFileSpec(const lldb::SBFileSpec &rhs);
SBFileSpec (const char *path);// Deprecated, use SBFileSpec (const char *path, bool resolve) SBFileSpec(const char *path); // Deprecated, use SBFileSpec (const char *path,
// bool resolve)
SBFileSpec (const char *path, bool resolve); SBFileSpec(const char *path, bool resolve);
~SBFileSpec (); ~SBFileSpec();
const SBFileSpec & const SBFileSpec &operator=(const lldb::SBFileSpec &rhs);
operator = (const lldb::SBFileSpec &rhs);
bool bool IsValid() const;
IsValid() const;
bool bool Exists() const;
Exists () const;
bool bool ResolveExecutableLocation();
ResolveExecutableLocation ();
const char * const char *GetFilename() const;
GetFilename() const;
const char * const char *GetDirectory() const;
GetDirectory() const;
void void SetFilename(const char *filename);
SetFilename(const char *filename);
void
SetDirectory(const char *directory);
uint32_t void SetDirectory(const char *directory);
GetPath (char *dst_path, size_t dst_len) const;
static int uint32_t GetPath(char *dst_path, size_t dst_len) const;
ResolvePath (const char *src_path, char *dst_path, size_t dst_len);
bool static int ResolvePath(const char *src_path, char *dst_path, size_t dst_len);
GetDescription (lldb::SBStream &description) const;
void bool GetDescription(lldb::SBStream &description) const;
AppendPathComponent (const char *file_or_directory);
void AppendPathComponent(const char *file_or_directory);
private: private:
friend class SBAttachInfo; friend class SBAttachInfo;
friend class SBBlock; friend class SBBlock;
friend class SBCommandInterpreter; friend class SBCommandInterpreter;
friend class SBCompileUnit; friend class SBCompileUnit;
friend class SBDeclaration; friend class SBDeclaration;
friend class SBFileSpecList; friend class SBFileSpecList;
friend class SBHostOS; friend class SBHostOS;
friend class SBLaunchInfo; friend class SBLaunchInfo;
friend class SBLineEntry; friend class SBLineEntry;
friend class SBModule; friend class SBModule;
friend class SBModuleSpec; friend class SBModuleSpec;
friend class SBPlatform; friend class SBPlatform;
friend class SBProcess; friend class SBProcess;
friend class SBSourceManager; friend class SBSourceManager;
friend class SBThread; friend class SBThread;
friend class SBTarget; friend class SBTarget;
SBFileSpec (const lldb_private::FileSpec& fspec); SBFileSpec(const lldb_private::FileSpec &fspec);
void void SetFileSpec(const lldb_private::FileSpec &fspec);
SetFileSpec (const lldb_private::FileSpec& fspec);
const lldb_private::FileSpec * const lldb_private::FileSpec *operator->() const;
operator->() const;
const lldb_private::FileSpec * const lldb_private::FileSpec *get() const;
get() const;
const lldb_private::FileSpec & const lldb_private::FileSpec &operator*() const;
operator*() const;
const lldb_private::FileSpec & const lldb_private::FileSpec &ref() const;
ref() const;
std::unique_ptr<lldb_private::FileSpec> m_opaque_ap; std::unique_ptr<lldb_private::FileSpec> m_opaque_ap;
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBFileSpec_h_ #endif // LLDB_SBFileSpec_h_

View File

@ -1,4 +1,5 @@
//===-- SBFileSpecList.h --------------------------------------------*- C++ -*-===// //===-- SBFileSpecList.h --------------------------------------------*- C++
//-*-===//
// //
// The LLVM Compiler Infrastructure // The LLVM Compiler Infrastructure
// //
@ -14,59 +15,44 @@
namespace lldb { namespace lldb {
class LLDB_API SBFileSpecList class LLDB_API SBFileSpecList {
{
public: public:
SBFileSpecList (); SBFileSpecList();
SBFileSpecList (const lldb::SBFileSpecList &rhs); SBFileSpecList(const lldb::SBFileSpecList &rhs);
~SBFileSpecList (); ~SBFileSpecList();
const SBFileSpecList & const SBFileSpecList &operator=(const lldb::SBFileSpecList &rhs);
operator = (const lldb::SBFileSpecList &rhs);
uint32_t uint32_t GetSize() const;
GetSize () const;
bool bool GetDescription(SBStream &description) const;
GetDescription (SBStream &description) const;
void Append(const SBFileSpec &sb_file);
void
Append (const SBFileSpec &sb_file); bool AppendIfUnique(const SBFileSpec &sb_file);
bool void Clear();
AppendIfUnique (const SBFileSpec &sb_file);
uint32_t FindFileIndex(uint32_t idx, const SBFileSpec &sb_file, bool full);
void
Clear(); const SBFileSpec GetFileSpecAtIndex(uint32_t idx) const;
uint32_t
FindFileIndex (uint32_t idx, const SBFileSpec &sb_file, bool full);
const SBFileSpec
GetFileSpecAtIndex (uint32_t idx) const;
private: private:
friend class SBTarget;
friend class SBTarget; const lldb_private::FileSpecList *operator->() const;
const lldb_private::FileSpecList * const lldb_private::FileSpecList *get() const;
operator->() const;
const lldb_private::FileSpecList * const lldb_private::FileSpecList &operator*() const;
get() const;
const lldb_private::FileSpecList & const lldb_private::FileSpecList &ref() const;
operator*() const;
const lldb_private::FileSpecList & std::unique_ptr<lldb_private::FileSpecList> m_opaque_ap;
ref() const;
std::unique_ptr<lldb_private::FileSpecList> m_opaque_ap;
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBFileSpecList_h_ #endif // LLDB_SBFileSpecList_h_

View File

@ -15,227 +15,182 @@
namespace lldb { namespace lldb {
class LLDB_API SBFrame class LLDB_API SBFrame {
{
public: public:
SBFrame (); SBFrame();
SBFrame (const lldb::SBFrame &rhs); SBFrame(const lldb::SBFrame &rhs);
const lldb::SBFrame &
operator =(const lldb::SBFrame &rhs);
~SBFrame(); const lldb::SBFrame &operator=(const lldb::SBFrame &rhs);
bool ~SBFrame();
IsEqual (const lldb::SBFrame &that) const;
bool bool IsEqual(const lldb::SBFrame &that) const;
IsValid() const;
uint32_t bool IsValid() const;
GetFrameID () const;
lldb::addr_t uint32_t GetFrameID() const;
GetCFA () const;
lldb::addr_t lldb::addr_t GetCFA() const;
GetPC () const;
bool lldb::addr_t GetPC() const;
SetPC (lldb::addr_t new_pc);
lldb::addr_t bool SetPC(lldb::addr_t new_pc);
GetSP () const;
lldb::addr_t lldb::addr_t GetSP() const;
GetFP () const;
lldb::SBAddress lldb::addr_t GetFP() const;
GetPCAddress () const;
lldb::SBSymbolContext lldb::SBAddress GetPCAddress() const;
GetSymbolContext (uint32_t resolve_scope) const;
lldb::SBModule lldb::SBSymbolContext GetSymbolContext(uint32_t resolve_scope) const;
GetModule () const;
lldb::SBCompileUnit lldb::SBModule GetModule() const;
GetCompileUnit () const;
lldb::SBFunction lldb::SBCompileUnit GetCompileUnit() const;
GetFunction () const;
lldb::SBSymbol lldb::SBFunction GetFunction() const;
GetSymbol () const;
/// Gets the deepest block that contains the frame PC. lldb::SBSymbol GetSymbol() const;
///
/// See also GetFrameBlock().
lldb::SBBlock
GetBlock () const;
/// Get the appropriate function name for this frame. Inlined functions in /// Gets the deepest block that contains the frame PC.
/// LLDB are represented by Blocks that have inlined function information, so ///
/// just looking at the SBFunction or SBSymbol for a frame isn't enough. /// See also GetFrameBlock().
/// This function will return the appropriate function, symbol or inlined lldb::SBBlock GetBlock() const;
/// function name for the frame.
///
/// This function returns:
/// - the name of the inlined function (if there is one)
/// - the name of the concrete function (if there is one)
/// - the name of the symbol (if there is one)
/// - NULL
///
/// See also IsInlined().
const char *
GetFunctionName();
// Get an appropriate function name for this frame that is suitable for display to a user
const char *
GetDisplayFunctionName ();
const char * /// Get the appropriate function name for this frame. Inlined functions in
GetFunctionName() const; /// LLDB are represented by Blocks that have inlined function information, so
/// just looking at the SBFunction or SBSymbol for a frame isn't enough.
/// This function will return the appropriate function, symbol or inlined
/// function name for the frame.
///
/// This function returns:
/// - the name of the inlined function (if there is one)
/// - the name of the concrete function (if there is one)
/// - the name of the symbol (if there is one)
/// - NULL
///
/// See also IsInlined().
const char *GetFunctionName();
/// Return true if this frame represents an inlined function. // Get an appropriate function name for this frame that is suitable for
/// // display to a user
/// See also GetFunctionName(). const char *GetDisplayFunctionName();
bool
IsInlined();
bool const char *GetFunctionName() const;
IsInlined() const;
/// The version that doesn't supply a 'use_dynamic' value will use the /// Return true if this frame represents an inlined function.
/// target's default. ///
lldb::SBValue /// See also GetFunctionName().
EvaluateExpression (const char *expr); bool IsInlined();
lldb::SBValue bool IsInlined() const;
EvaluateExpression (const char *expr, lldb::DynamicValueType use_dynamic);
lldb::SBValue /// The version that doesn't supply a 'use_dynamic' value will use the
EvaluateExpression (const char *expr, lldb::DynamicValueType use_dynamic, bool unwind_on_error); /// target's default.
lldb::SBValue EvaluateExpression(const char *expr);
lldb::SBValue
EvaluateExpression (const char *expr, const SBExpressionOptions &options);
/// Gets the lexical block that defines the stack frame. Another way to think lldb::SBValue EvaluateExpression(const char *expr,
/// of this is it will return the block that contains all of the variables lldb::DynamicValueType use_dynamic);
/// for a stack frame. Inlined functions are represented as SBBlock objects
/// that have inlined function information: the name of the inlined function,
/// where it was called from. The block that is returned will be the first
/// block at or above the block for the PC (SBFrame::GetBlock()) that defines
/// the scope of the frame. When a function contains no inlined functions,
/// this will be the top most lexical block that defines the function.
/// When a function has inlined functions and the PC is currently
/// in one of those inlined functions, this method will return the inlined
/// block that defines this frame. If the PC isn't currently in an inlined
/// function, the lexical block that defines the function is returned.
lldb::SBBlock
GetFrameBlock () const;
lldb::SBLineEntry lldb::SBValue EvaluateExpression(const char *expr,
GetLineEntry () const; lldb::DynamicValueType use_dynamic,
bool unwind_on_error);
lldb::SBThread lldb::SBValue EvaluateExpression(const char *expr,
GetThread () const; const SBExpressionOptions &options);
const char * /// Gets the lexical block that defines the stack frame. Another way to think
Disassemble () const; /// of this is it will return the block that contains all of the variables
/// for a stack frame. Inlined functions are represented as SBBlock objects
/// that have inlined function information: the name of the inlined function,
/// where it was called from. The block that is returned will be the first
/// block at or above the block for the PC (SBFrame::GetBlock()) that defines
/// the scope of the frame. When a function contains no inlined functions,
/// this will be the top most lexical block that defines the function.
/// When a function has inlined functions and the PC is currently
/// in one of those inlined functions, this method will return the inlined
/// block that defines this frame. If the PC isn't currently in an inlined
/// function, the lexical block that defines the function is returned.
lldb::SBBlock GetFrameBlock() const;
void lldb::SBLineEntry GetLineEntry() const;
Clear();
bool lldb::SBThread GetThread() const;
operator == (const lldb::SBFrame &rhs) const;
bool const char *Disassemble() const;
operator != (const lldb::SBFrame &rhs) const;
/// The version that doesn't supply a 'use_dynamic' value will use the void Clear();
/// target's default.
lldb::SBValueList
GetVariables (bool arguments,
bool locals,
bool statics,
bool in_scope_only);
lldb::SBValueList bool operator==(const lldb::SBFrame &rhs) const;
GetVariables (bool arguments,
bool locals,
bool statics,
bool in_scope_only,
lldb::DynamicValueType use_dynamic);
lldb::SBValueList bool operator!=(const lldb::SBFrame &rhs) const;
GetVariables (const lldb::SBVariablesOptions& options);
lldb::SBValueList
GetRegisters ();
lldb::SBValue /// The version that doesn't supply a 'use_dynamic' value will use the
FindRegister (const char *name); /// target's default.
lldb::SBValueList GetVariables(bool arguments, bool locals, bool statics,
bool in_scope_only);
/// The version that doesn't supply a 'use_dynamic' value will use the lldb::SBValueList GetVariables(bool arguments, bool locals, bool statics,
/// target's default. bool in_scope_only,
lldb::SBValue lldb::DynamicValueType use_dynamic);
FindVariable (const char *var_name);
lldb::SBValue lldb::SBValueList GetVariables(const lldb::SBVariablesOptions &options);
FindVariable (const char *var_name, lldb::DynamicValueType use_dynamic);
// Find a value for a variable expression path like "rect.origin.x" or lldb::SBValueList GetRegisters();
// "pt_ptr->x", "*self", "*this->obj_ptr". The returned value is _not_
// and expression result and is not a constant object like
// SBFrame::EvaluateExpression(...) returns, but a child object of
// the variable value.
lldb::SBValue
GetValueForVariablePath (const char *var_expr_cstr,
DynamicValueType use_dynamic);
/// The version that doesn't supply a 'use_dynamic' value will use the lldb::SBValue FindRegister(const char *name);
/// target's default.
lldb::SBValue
GetValueForVariablePath (const char *var_path);
/// Find variables, register sets, registers, or persistent variables using /// The version that doesn't supply a 'use_dynamic' value will use the
/// the frame as the scope. /// target's default.
/// lldb::SBValue FindVariable(const char *var_name);
/// NB. This function does not look up ivars in the function object pointer.
/// To do that use GetValueForVariablePath.
///
/// The version that doesn't supply a 'use_dynamic' value will use the
/// target's default.
lldb::SBValue
FindValue (const char *name, ValueType value_type);
lldb::SBValue lldb::SBValue FindVariable(const char *var_name,
FindValue (const char *name, ValueType value_type, lldb::DynamicValueType use_dynamic); lldb::DynamicValueType use_dynamic);
bool // Find a value for a variable expression path like "rect.origin.x" or
GetDescription (lldb::SBStream &description); // "pt_ptr->x", "*self", "*this->obj_ptr". The returned value is _not_
// and expression result and is not a constant object like
// SBFrame::EvaluateExpression(...) returns, but a child object of
// the variable value.
lldb::SBValue GetValueForVariablePath(const char *var_expr_cstr,
DynamicValueType use_dynamic);
SBFrame (const lldb::StackFrameSP &lldb_object_sp); /// The version that doesn't supply a 'use_dynamic' value will use the
/// target's default.
lldb::SBValue GetValueForVariablePath(const char *var_path);
/// Find variables, register sets, registers, or persistent variables using
/// the frame as the scope.
///
/// NB. This function does not look up ivars in the function object pointer.
/// To do that use GetValueForVariablePath.
///
/// The version that doesn't supply a 'use_dynamic' value will use the
/// target's default.
lldb::SBValue FindValue(const char *name, ValueType value_type);
lldb::SBValue FindValue(const char *name, ValueType value_type,
lldb::DynamicValueType use_dynamic);
bool GetDescription(lldb::SBStream &description);
SBFrame(const lldb::StackFrameSP &lldb_object_sp);
protected: protected:
friend class SBBlock;
friend class SBExecutionContext;
friend class SBInstruction;
friend class SBThread;
friend class SBValue;
friend class SBBlock; lldb::StackFrameSP GetFrameSP() const;
friend class SBExecutionContext;
friend class SBInstruction;
friend class SBThread;
friend class SBValue;
lldb::StackFrameSP void SetFrameSP(const lldb::StackFrameSP &lldb_object_sp);
GetFrameSP() const;
void lldb::ExecutionContextRefSP m_opaque_sp;
SetFrameSP (const lldb::StackFrameSP &lldb_object_sp);
lldb::ExecutionContextRefSP m_opaque_sp;
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBFrame_h_ #endif // LLDB_SBFrame_h_

View File

@ -10,96 +10,72 @@
#ifndef LLDB_SBFunction_h_ #ifndef LLDB_SBFunction_h_
#define LLDB_SBFunction_h_ #define LLDB_SBFunction_h_
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBAddress.h" #include "lldb/API/SBAddress.h"
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBInstructionList.h" #include "lldb/API/SBInstructionList.h"
namespace lldb { namespace lldb {
class LLDB_API SBFunction class LLDB_API SBFunction {
{
public: public:
SBFunction();
SBFunction (); SBFunction(const lldb::SBFunction &rhs);
SBFunction (const lldb::SBFunction &rhs); const lldb::SBFunction &operator=(const lldb::SBFunction &rhs);
const lldb::SBFunction & ~SBFunction();
operator = (const lldb::SBFunction &rhs);
~SBFunction (); bool IsValid() const;
bool const char *GetName() const;
IsValid () const;
const char * const char *GetDisplayName() const;
GetName() const;
const char * const char *GetMangledName() const;
GetDisplayName() const;
const char *
GetMangledName () const;
lldb::SBInstructionList lldb::SBInstructionList GetInstructions(lldb::SBTarget target);
GetInstructions (lldb::SBTarget target);
lldb::SBInstructionList lldb::SBInstructionList GetInstructions(lldb::SBTarget target,
GetInstructions (lldb::SBTarget target, const char *flavor); const char *flavor);
lldb::SBAddress lldb::SBAddress GetStartAddress();
GetStartAddress ();
lldb::SBAddress lldb::SBAddress GetEndAddress();
GetEndAddress ();
const char * const char *GetArgumentName(uint32_t arg_idx);
GetArgumentName (uint32_t arg_idx);
uint32_t uint32_t GetPrologueByteSize();
GetPrologueByteSize ();
lldb::SBType lldb::SBType GetType();
GetType ();
lldb::SBBlock lldb::SBBlock GetBlock();
GetBlock ();
lldb::LanguageType
GetLanguage ();
bool lldb::LanguageType GetLanguage();
GetIsOptimized ();
bool bool GetIsOptimized();
operator == (const lldb::SBFunction &rhs) const;
bool bool operator==(const lldb::SBFunction &rhs) const;
operator != (const lldb::SBFunction &rhs) const;
bool bool operator!=(const lldb::SBFunction &rhs) const;
GetDescription (lldb::SBStream &description);
bool GetDescription(lldb::SBStream &description);
protected: protected:
lldb_private::Function *get();
lldb_private::Function * void reset(lldb_private::Function *lldb_object_ptr);
get ();
void
reset (lldb_private::Function *lldb_object_ptr);
private: private:
friend class SBAddress; friend class SBAddress;
friend class SBFrame; friend class SBFrame;
friend class SBSymbolContext; friend class SBSymbolContext;
SBFunction (lldb_private::Function *lldb_object_ptr); SBFunction(lldb_private::Function *lldb_object_ptr);
lldb_private::Function *m_opaque_ptr;
lldb_private::Function *m_opaque_ptr;
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBFunction_h_ #endif // LLDB_SBFunction_h_

View File

@ -15,49 +15,31 @@
namespace lldb { namespace lldb {
class LLDB_API SBHostOS class LLDB_API SBHostOS {
{
public: public:
static lldb::SBFileSpec GetProgramFileSpec();
static lldb::SBFileSpec static lldb::SBFileSpec GetLLDBPythonPath();
GetProgramFileSpec ();
static lldb::SBFileSpec
GetLLDBPythonPath ();
static lldb::SBFileSpec static lldb::SBFileSpec GetLLDBPath(lldb::PathType path_type);
GetLLDBPath (lldb::PathType path_type);
static lldb::SBFileSpec static lldb::SBFileSpec GetUserHomeDirectory();
GetUserHomeDirectory ();
static void static void ThreadCreated(const char *name);
ThreadCreated (const char *name);
static lldb::thread_t static lldb::thread_t ThreadCreate(const char *name,
ThreadCreate (const char *name, lldb::thread_func_t thread_function,
lldb::thread_func_t thread_function, void *thread_arg, lldb::SBError *err);
void *thread_arg,
lldb::SBError *err);
static bool static bool ThreadCancel(lldb::thread_t thread, lldb::SBError *err);
ThreadCancel (lldb::thread_t thread,
lldb::SBError *err);
static bool
ThreadDetach (lldb::thread_t thread,
lldb::SBError *err);
static bool
ThreadJoin (lldb::thread_t thread,
lldb::thread_result_t *result,
lldb::SBError *err);
static bool ThreadDetach(lldb::thread_t thread, lldb::SBError *err);
static bool ThreadJoin(lldb::thread_t thread, lldb::thread_result_t *result,
lldb::SBError *err);
private: private:
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBHostOS_h_ #endif // LLDB_SBHostOS_h_

View File

@ -10,93 +10,76 @@
#ifndef LLDB_SBInstruction_h_ #ifndef LLDB_SBInstruction_h_
#define LLDB_SBInstruction_h_ #define LLDB_SBInstruction_h_
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBData.h" #include "lldb/API/SBData.h"
#include "lldb/API/SBDefines.h"
#include <stdio.h> #include <stdio.h>
// There's a lot to be fixed here, but need to wait for underlying insn implementation // There's a lot to be fixed here, but need to wait for underlying insn
// implementation
// to be revised & settle down first. // to be revised & settle down first.
class InstructionImpl; class InstructionImpl;
namespace lldb { namespace lldb {
class LLDB_API SBInstruction class LLDB_API SBInstruction {
{
public: public:
SBInstruction();
SBInstruction (); SBInstruction(const SBInstruction &rhs);
SBInstruction (const SBInstruction &rhs); const SBInstruction &operator=(const SBInstruction &rhs);
const SBInstruction &
operator = (const SBInstruction &rhs);
~SBInstruction (); ~SBInstruction();
bool bool IsValid();
IsValid();
SBAddress SBAddress GetAddress();
GetAddress();
lldb::AddressClass
GetAddressClass ();
const char *
GetMnemonic (lldb::SBTarget target);
const char * lldb::AddressClass GetAddressClass();
GetOperands (lldb::SBTarget target);
const char *
GetComment (lldb::SBTarget target);
lldb::SBData const char *GetMnemonic(lldb::SBTarget target);
GetData (lldb::SBTarget target);
size_t const char *GetOperands(lldb::SBTarget target);
GetByteSize ();
bool const char *GetComment(lldb::SBTarget target);
DoesBranch ();
bool lldb::SBData GetData(lldb::SBTarget target);
HasDelaySlot ();
void size_t GetByteSize();
Print (FILE *out);
bool bool DoesBranch();
GetDescription (lldb::SBStream &description);
bool bool HasDelaySlot();
EmulateWithFrame (lldb::SBFrame &frame, uint32_t evaluate_options);
bool void Print(FILE *out);
DumpEmulation (const char * triple); // triple is to specify the architecture, e.g. 'armv6' or 'armv7-apple-ios'
bool GetDescription(lldb::SBStream &description);
bool
TestEmulation (lldb::SBStream &output_stream, const char *test_file); bool EmulateWithFrame(lldb::SBFrame &frame, uint32_t evaluate_options);
bool DumpEmulation(const char *triple); // triple is to specify the
// architecture, e.g. 'armv6' or
// 'armv7-apple-ios'
bool TestEmulation(lldb::SBStream &output_stream, const char *test_file);
protected: protected:
friend class SBInstructionList; friend class SBInstructionList;
SBInstruction(const lldb::DisassemblerSP &disasm_sp, const lldb::InstructionSP &inst_sp); SBInstruction(const lldb::DisassemblerSP &disasm_sp,
const lldb::InstructionSP &inst_sp);
void void SetOpaque(const lldb::DisassemblerSP &disasm_sp,
SetOpaque(const lldb::DisassemblerSP &disasm_sp, const lldb::InstructionSP& inst_sp); const lldb::InstructionSP &inst_sp);
lldb::InstructionSP lldb::InstructionSP GetOpaque();
GetOpaque();
private: private:
std::shared_ptr<InstructionImpl> m_opaque_sp;
std::shared_ptr<InstructionImpl> m_opaque_sp;
}; };
} // namespace lldb } // namespace lldb
#endif // LLDB_SBInstruction_h_ #endif // LLDB_SBInstruction_h_

Some files were not shown because too many files have changed in this diff Show More