Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,41 @@
include(FindDoxygen)
if(DOXYGEN_FOUND)
set(abs_top_srcdir ${CMAKE_CURRENT_SOURCE_DIR}/..)
set(DOT dot)
set(PACKAGE_VERSION mainline)
set(abs_top_builddir ..)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/doxygen.cfg.in
${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg @ONLY)
add_custom_target(lldb-cpp-doc
${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/doxygen.cfg
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Generating LLDB C++ API reference with Doxygen" VERBATIM
)
endif(DOXYGEN_FOUND)
find_package(PythonInterp REQUIRED)
find_program(EPYDOC_EXECUTABLE NAMES epydoc epydoc.py)
if(EPYDOC_EXECUTABLE)
find_program(DOT_EXECUTABLE dot)
if(DOT_EXECUTABLE)
set(EPYDOC_OPTIONS ${EPYDOC_OPTIONS} --graph all --dotpath ${DOT_EXECUTABLE})
endif()
set(DOC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/doc")
file(MAKE_DIRECTORY "${DOC_DIR}")
#set(ENV{PYTHONPATH} ${CMAKE_CURRENT_BINARY_DIR}/../../../lib/python2.7/site-packages)
add_custom_target(lldb-python-doc
${EPYDOC_EXECUTABLE}
--html
lldb
-o ${CMAKE_CURRENT_BINARY_DIR}/python_reference
--name "LLDB python API"
--url "http://lldb.llvm.org"
${EPYDOC_OPTIONS}
DEPENDS swig_wrapper liblldb
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../../../lib${LLVM_LIBDIR_SUFFIX}/python2.7/site-packages
COMMENT "Generating LLDB Python API reference with epydoc" VERBATIM
)
endif(EPYDOC_EXECUTABLE)

View File

@@ -0,0 +1,50 @@
This document describes how to build a debug version of LLVM for use with
LLDB, and how to make LLDB use it.
It assumes that you are using the Xcode 3 series (I used 3.2.4) to build
LLDB. It also assumes that your shell is /bin/bash, and that you are
currently at a shell prompt in a checked-out LLDB repository.
1. Check out LLVM and Clang from their repositories. To determine
the revision to use, consult scripts/build-llvm.pl (this is done
in the first command line below). !!! WARNING Do not use the
name "llvm" for your checkout, for reasons described in part 3
below.
$ export CLANG_REVISION=`cat scripts/build-llvm.pl | grep ^our.*llvm_revision | cut -d \' -f 2,2`
$ svn co -r $CLANG_REVISION http://llvm.org/svn/llvm-project/llvm/trunk llvm.checkout
$ svn co -r $CLANG_REVISION http://llvm.org/svn/llvm-project/cfe/trunk llvm.checkout/tools/clang
2. Configure LLVM/Clang with the proper options and compilers. I use:
$ cd llvm.checkout
$ CC="cc -g -O0" CXX="c++ -g -O0" ./configure --disable-optimized --enable-assertions --enable-targets=x86_64,arm
$ CC="cc -g -O0" CXX="c++ -g -O0" make -j 2
$ cd ..
3. Create a link to the built LLVM. !!! WARNING: Do not rename the
directory! The LLVM builder script that runs as part of the Xcode
build keys off the fact that llvm/ is a symlink to recognize that
we are building with a custom debug build.
$ ln -sf llvm.checkout llvm
4. Make sure that your Xcode project is set up correctly. Open
lldb.xcodeproj and do the following:
Under "Targets" in the Groups & Files navigator, double-click
lldb-tool. In the resulting window, select "Debug" from the
"Configuration:" drop-down. Then, make sure that the setting
"Build Active Architecture Only" is enabled. Close the window.
Under "Targets" in the Groups & Files navigator, double-click
LLDB. In the resulting window, select "Debug" from the
"Configuration:" drop-down. Then, make sure that the setting
"Build Active Architecture Only" is enabled. Close the window.
5. Ensure that Xcode is building the lldb-tool target in Debug
configuration for your architecture (typically x86_64). You
can usually pick these options from the Overview drop-down at
the top left of the Xcode window.
6. Build lldb.xcodeproj.

View File

@@ -0,0 +1,61 @@
On MacOSX lldb needs to be code signed. The Debug, DebugClang and Release
builds are set to code sign using a code signing certificate named
"lldb_codesign".
If you have re-installed a new OS, please delete all old lldb_codesign items
from your keychain. There will be a code signing certification and a public
and private key. Reboot after deleting them. You will also need to delete and
build folders that contained old signed items. The darwin kernel will cache
code signing using the executable's file system node, so you will need to
delete the file so the kernel clears its cache.
If you don't have one yet you will need to:
- Launch /Applications/Utilities/Keychain Access.app
- In Keychain Access select the "login" keychain in the "Keychains"
list in the upper left hand corner of the window.
- Select the following menu item:
Keychain Access->Certificate Assistant->Create a Certificate...
- Set the following settings
Name = lldb_codesign
Identity Type = Self Signed Root
Certificate Type = Code Signing
- Click Create
- Click Continue
- Click Done
- Click on the "My Certificates"
- Double click on your new lldb_codesign certificate
- Turn down the "Trust" disclosure triangle, scroll to the "Code Signing" trust
pulldown menu and select "Always Trust" and authenticate as needed using your
username and password.
- Drag the new "lldb_codesign" code signing certificate (not the public or private
keys of the same name) from the "login" keychain to the "System" keychain in the
Keychains pane on the left hand side of the main Keychain Access window. This will
move this certificate to the "System" keychain. You'll have to authorize a few
more times, set it to be "Always trusted" when asked.
- Remove "~/Desktop/lldb_codesign.cer" file on your desktop if there is one.
- In the Keychain Access GUI, click and drag "lldb_codesign" in the "System" keychain
onto the desktop. The drag will create a "~/Desktop/lldb_codesign.cer" file used in
the next step.
- Switch to Terminal, and run the following:
sudo security add-trust -d -r trustRoot -p basic -p codeSign -k /Library/Keychains/System.keychain ~/Desktop/lldb_codesign.cer
rm -f ~/Desktop/lldb_codesign.cer
- Drag the "lldb_codesign" certificate from the "System" keychain back into the
"login" keychain
- Quit Keychain Access
- Reboot
- Clean by removing all previously creating code signed binaries and rebuild
lldb and you should be able to debug.
When you build your LLDB for the first time, the Xcode GUI will prompt you for permission
to use the "lldb_codesign" keychain. Be sure to click "Always Allow" on your first
build. From here on out, the "lldb_codesign" will be trusted and you can build from the
command line without having to authorize. Also the first time you debug using a LLDB that
was built with this code signing certificate, you will need to authenticate once.

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
<hr>
<p class="footer">
Generated on $datetime for <a href="http://lldb.llvm.org/">$projectname</a> by
<a href="http://www.doxygen.org"><img src="doxygen.png" alt="Doxygen"
align="middle" border="0"/>$doxygenversion</a><br>
Copyright &copy; 2003-2013 University of Illinois at Urbana-Champaign.
All Rights Reserved.</p>
<hr>
<!--#include virtual="/attrib.incl" -->
</body>
</html>

View File

@@ -0,0 +1,9 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html><head>
<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1"/>
<meta name="keywords" content="LLDB,C++,doxygen,API,documentation"/>
<meta name="description" content="C++ source code API documentation for LLDB."/>
<title>LLVM: $title</title>
<link href="doxygen.css" rel="stylesheet" type="text/css"/>
</head><body>
<p class="title">LLDB API Documentation</p>

View File

@@ -0,0 +1,19 @@
/// @mainpage LLDB
///
/// @section main_intro Introduction
/// Welcome to LLDB.
///
/// This documentation describes the @b interface that can drive LLDB.
/// There are no instructions here on how to use LLDB, only the APIs
/// that make up the software. For usage instructions, please see
/// the help command.
///
/// @section main_caveat Caveat
/// This documentation is generated directly from the source code with doxygen.
/// Since LLDB is constantly under active development, what you're about to
/// read is out of date! However, it may still be useful since certain portions
/// of LLDB are very stable.
///
/// @section main_changelog Change Log
/// - Adapted for LLDB 05/25/2013 by Daniel Malea
/// - Original content written 12/30/2003 by Reid Spencer

View File

@@ -0,0 +1,488 @@
Here's a short precis of how to run lldb if you are familiar with the
gdb command set:
1) LLDB Command Structure:
First some details on lldb command structure to help orient you...
Unlike gdb's command set, which is rather free-form, we tried to make
the lldb command syntax fairly structured. The commands are all of the
form
<noun> <verb> [-options [option-value]] [argument [argument...]]
The command line parsing is done before command execution, so it is
uniform across all the commands. The command syntax is very simple,
basically arguments, options and option values are all white-space
separated. If you need to put a backslash or double-quote character
in an argument you back-slash it in the argument. That makes the
command syntax more regular, but it also means you may have to
quote some arguments in lldb that you wouldn't in gdb.
Options can be placed anywhere on the command line, but if the arguments
begin with a "-" then you have to tell lldb that you're done with options
using the "--" option. So for instance, the "process launch" command takes
the "-s" option to mean "stop the process at the first instruction". It's
arguments are the arguments you are passing to the program. So if you wanted
to pass an argument that contained a "-" you would have to do:
(lldb) process launch -- -program_arg value
We also tried to reduce the number of special purpose argument
parsers, which sometimes forces the user to be a little more explicit
about stating their intentions. The first instance you'll note of
this is the breakpoint command. In gdb, to set a breakpoint, you
would just say:
(gdb) break foo.c:12
or
(gdb) break foo
if foo is a function. As time went on, the parser that tells foo.c:12
from foo from foo.c::foo (which means the function foo in the file
foo.c) got more and more complex and bizarre, and especially in C++
there are times where there's really no way to specify the function
you want to break on. The lldb commands are more verbose but also precise.
So you say:
(lldb) breakpoint set -f foo.c -l 12
to set a file & line breakpoint. To set a breakpoint on a function
by name, you do:
(lldb) breakpoint set -n foo
This can allow us to be more expressive, so you can say:
(lldb) breakpoint set -M foo
to break on all C++ methods named foo, or:
(lldb) breakpoint set -S alignLeftEdges:
to set a breakpoint on all ObjC selectors called alignLeftEdges:. It
also makes it easy to compose specifications, like:
(lldb) breakpoint set -s foo.dylib -n foo
for all functions called foo in the shared library foo.dylib. Suggestions
on more interesting primitives of this sort are also very welcome.
So for instance:
(lldb) breakpoint set -n "-[SKTGraphicView alignLeftEdges:]"
Just like gdb, the lldb command interpreter does a shortest unique
string match on command names, so the previous command can also be
typed:
(lldb) b s -n "-[SKTGraphicView alignLeftEdges:]"
lldb also supports command completion for source file names, symbol
names, file names, etc. Completion is initiated by a hitting a <TAB>.
Individual options in a command can have different completers, so for
instance the -f option in "breakpoint" completes to source files, the
-s option to currently loaded shared libraries, etc... We can even do
things like if you specify -s, and are completing on -f, we will only
list source files in the shared library specified by -s...
The individual commands are pretty extensively documented, using
the "help" command. And there is an "apropos" command that will
search the help for a particular word and dump a summary help string
for each matching command.
Finally, there is a mechanism to construct aliases for commonly used
commands. So for instance if you get annoyed typing
(lldb) b s -f foo.c -l 12
you can do:
(lldb) command alias bfl breakpoint set -f %1 -l %2
(lldb) bfl foo.c 12
We have added a few aliases for commonly used commands (e.g. "step",
"next" and "continue") but we haven't tried to be exhaustive because
in our experience it is more convenient to make the basic commands
unique down to a letter or two, and then learn these sequences than
fill the namespace with lots of aliases, and then have to type them
all the way out.
However, users are free to customize lldb's command set however they
like, and since lldb reads the file ~/.lldbinit at startup, you can
store all your aliases there and they will be generally available to
you. Your aliases are also documented in the help command so you can
remind yourself of what you've set up.
lldb also has a built-in Python interpreter, which is accessible by
the "script" command. All the functionality of the debugger is
available as classes in the Python interpreter, so the more complex
commands that in gdb you would introduce with the "define" command can
be done by writing Python functions using the lldb-Python library,
then loading the scripts into your running session and accessing them
with the "script" command.
2) A typical session:
a) Setting the program to debug:
As with gdb, you can start lldb and specify the file you wish to debug
on the command line:
$ lldb /Projects/Sketch/build/Debug/Sketch.app
Current executable set to '/Projects/Sketch/build/Debug/Sketch.app' (x86_64).
or you can specify it after the fact with the "file" command:
(lldb) file /Projects/Sketch/build/Debug/Sketch.app
Current executable set to '/Projects/Sketch/build/Debug/Sketch.app' (x86_64).
b) Setting breakpoints:
We've discussed how to set breakpoints above. You can use "help break set"
to see all the options for breakpoint setting. For instance, we might do:
(lldb) b s -S alignLeftEdges:
Breakpoint created: 1: name = 'alignLeftEdges:', locations = 1, resolved = 1
You can find out about the breakpoints you've set with:
(lldb) break list
Current breakpoints:
1: name = 'alignLeftEdges:', locations = 1, resolved = 1
1.1: where = Sketch`-[SKTGraphicView alignLeftEdges:] + 33 at /Projects/Sketch/SKTGraphicView.m:1405, address = 0x0000000100010d5b, resolved, hit count = 0
Note that each "logical" breakpoint can have multiple "locations".
The logical breakpoint has an integer id, and it's locations have an
id within their parent breakpoint (the two are joined by a ".",
e.g. 1.1 in the example above.)
Also the breakpoints remain "live" so that if another shared library
were to be loaded that had another implementation of the
"alignLeftEdges:" selector, the new location would be added to
breakpoint 1 (e.g. a "1.2" breakpoint would be set on the newly loaded
selector).
The other piece of information in the breakpoint listing is whether the
breakpoint location was "resolved" or not. A location gets resolved when
the file address it corresponds to gets loaded into the program you are
debugging. For instance if you set a breakpoint in a shared library that
then gets unloaded, that breakpoint location will remain, but it will no
longer be "resolved".
One other thing to note for gdb users is that lldb acts like gdb with:
(gdb) set breakpoint pending on
That is, lldb should always make a breakpoint from your specification, even
if it couldn't find any locations that match the specification. You can tell
whether the expression was resolved or not by checking the locations field
in "breakpoint list", and we report the breakpoint as "pending" when you
set it so you can tell you've made a typo more easily, if that was indeed
the reason no locations were found:
(lldb) b s -f no_such_file.c -l 10000000
Breakpoint created: 1: file ='no_such_file.c', line = 10000000, locations = 0 (pending)
You can delete, disable, set conditions and ignore counts either on all the
locations generated by your logical breakpoint, or on particular locations
your specification resolved to. For instance if we wanted to add a command
to print a backtrace when we hit this breakpoint we could do:
(lldb) b command add -c 1.1
Enter your debugger command(s). Type 'DONE' to end.
> bt
> DONE
The "-c" option specifies that the breakpoint command is a set of lldb
command interpreter commands. Use "-s" if you want to implement your
breakpoint command using the Python interface instead.
c) Running the program:
Then you can either launch the process with the command:
(lldb) process launch
or its alias:
(lldb) r
Or you can attach to a process by name with:
(lldb) process attach -n Sketch
The "attach by name" also supports the "-w" option which waits for the
next process of that name to show up, and attaches to that. You can also
attach by PID:
(lldb) process attach -p 12345
Process 46915 Attaching
(lldb) Process 46915 Stopped
1 of 3 threads stopped with reasons:
* thread #1: tid = 0x2c03, 0x00007fff85cac76a, where = libSystem.B.dylib`__getdirentries64 + 10, stop reason = signal = SIGSTOP, queue = com.apple.main-thread
Note that we tell you that "1 of 3 threads stopped with reasons" and
then list those threads. In a multi-threaded environment it is very
common for more than one thread to hit your breakpoint(s) before the
kernel actually returns control to the debugger. In that case, you
will see all the threads that stopped for some interesting reason
listed in the stop message.
d) Controlling execution:
After launching, we can continue until we hit our breakpoint. The primitive
commands for process control all exist under the "thread" command:
(lldb) thread continue
Resuming thread 0x2c03 in process 46915
Resuming process 46915
(lldb)
At present you can only operate on one thread at a time, but the
design will ultimately support saying "step over the function in
Thread 1, and step into the function in Thread 2, and continue Thread
3" etc. When we eventually support keeping some threads running while
others are stopped this will be particularly important. For
convenience, however, all the stepping commands have easy aliases.
So "thread continue" is just "c", etc.
The other program stepping commands are pretty much the same as in gdb.
You've got:
1. (lldb) thread step-in
The same as gdb's "step" -- there is also the alias "s" in lldb
2. (lldb) thread step-over
The same as gdb's "next" -- there is also the alias "n" in lldb
3. (lldb) thread step-out
The same as gdb's "finish" -- there is also the alias "f" in lldb
And the "by instruction" versions:
(lldb) thread step-inst
(lldb) thread step-over-inst
Finally, there's:
(lldb) thread until 100
Which runs the thread in the current frame till it reaches line 100 in
this frame or stops if it leaves the current frame. This is a pretty
close equivalent to gdb's "until" command.
One thing here that might be a little disconcerting to gdb users here is that
when you resume process execution, you immediately get a prompt back. That's
because the lldb interpreter remains live when you are running the target.
This allows you to set a breakpoint, etc without having to explicitly interrupt
the program you are debugging. We're still working out all the operations
that it is safe to do while running. But this way of operation will set us
up for "no stop" debugging when we get to implementing that.
If you want to interrupt a running program do:
(lldb) process interrupt
To find out the state of the program, use:
(lldb) process status
Process 47958 is running.
This is very convenient, but it does have the down-side that debugging
programs that use stdin is no longer as straightforward. For now, you
have to specify another tty to use as the program stdout & stdin using
the appropriate options to "process launch", or start your program in
another terminal and catch it with "process attach -w". We will come
up with some more convenient way to juggle the terminal back & forth
over time.
e) Examining program state:
Once you've stopped, lldb will choose a current thread, usually the
one that stopped "for a reason", and a current frame in that thread.
Many the commands for inspecting state work on this current
thread/frame.
To inspect the current state of your process, you can start with the
threads:
(lldb) thread list
Process 46915 state is Stopped
* thread #1: tid = 0x2c03, 0x00007fff85cac76a, where = libSystem.B.dylib`__getdirentries64 + 10, stop reason = signal = SIGSTOP, queue = com.apple.main-thread
thread #2: tid = 0x2e03, 0x00007fff85cbb08a, where = libSystem.B.dylib`kevent + 10, queue = com.apple.libdispatch-manager
thread #3: tid = 0x2f03, 0x00007fff85cbbeaa, where = libSystem.B.dylib`__workq_kernreturn + 10
The * indicates that Thread 1 is the current thread. To get a
backtrace for that thread, do:
(lldb) thread backtrace
thread #1: tid = 0x2c03, stop reason = breakpoint 1.1, queue = com.apple.main-thread
frame #0: 0x0000000100010d5b, where = Sketch`-[SKTGraphicView alignLeftEdges:] + 33 at /Projects/Sketch/SKTGraphicView.m:1405
frame #1: 0x00007fff8602d152, where = AppKit`-[NSApplication sendAction:to:from:] + 95
frame #2: 0x00007fff860516be, where = AppKit`-[NSMenuItem _corePerformAction] + 365
frame #3: 0x00007fff86051428, where = AppKit`-[NSCarbonMenuImpl performActionWithHighlightingForItemAtIndex:] + 121
frame #4: 0x00007fff860370c1, where = AppKit`-[NSMenu performKeyEquivalent:] + 272
frame #5: 0x00007fff86035e69, where = AppKit`-[NSApplication _handleKeyEquivalent:] + 559
frame #6: 0x00007fff85f06aa1, where = AppKit`-[NSApplication sendEvent:] + 3630
frame #7: 0x00007fff85e9d922, where = AppKit`-[NSApplication run] + 474
frame #8: 0x00007fff85e965f8, where = AppKit`NSApplicationMain + 364
frame #9: 0x0000000100015ae3, where = Sketch`main + 33 at /Projects/Sketch/SKTMain.m:11
frame #10: 0x0000000100000f20, where = Sketch`start + 52
You can also provide a list of threads to backtrace, or the keyword
"all" to see all threads:
(lldb) thread backtrace all
Next task is inspecting data:
The most convenient way to inspect a frame's arguments and local variables is:
(lldb) frame variable
self = (SKTGraphicView *) 0x0000000100208b40
_cmd = (struct objc_selector *) 0x000000010001bae1
sender = (id) 0x00000001001264e0
selection = (NSArray *) 0x00000001001264e0
i = (NSUInteger) 0x00000001001264e0
c = (NSUInteger) 0x00000001001253b0
You can also choose particular variables to view:
(lldb) frame variable self
(SKTGraphicView *) self = 0x0000000100208b40
The frame variable command is not a full expression parser but it
does support some common operations like dereferencing:
(lldb) fr v *self
(SKTGraphicView *) self = 0x0000000100208b40
(NSView) NSView = {
(NSResponder) NSResponder = {
...
and structure element references:
(lldb) frame variable self.isa
(struct objc_class *) self.isa = 0x0000000100023730
The frame variable command will also perform "object printing" operations on
variables (currently we only support NSPrintForDebugger) with:
(lldb) fr v -o self
(SKTGraphicView *) self = 0x0000000100208b40
<SKTGraphicView: 0x100208b40>
You can select another frame to view with:
(lldb) frame select 9
frame #9: 0x0000000100015ae3, where = Sketch`main + 33 at /Projects/Sketch/SKTMain.m:11
8
9
10 int main(int argc, const char *argv[]) {
11 -> return NSApplicationMain(argc, argv);
12 }
13
14
Another neat trick that the variable list does is array references, so:
(lldb) fr v argv[0]
(char const *) argv[0] = 0x00007fff5fbffaf8 "/Projects/Sketch/build/Debug/Sketch.app/Contents/MacOS/Sketch"
If you need to view more complex data or change program data, you can
use the general "expression" command. It takes an expression and
evaluates it in the scope of the currently selected frame. For instance:
(lldb) expr self
$0 = (SKTGraphicView *) 0x0000000100135430
(lldb) expr self = 0x00
$1 = (SKTGraphicView *) 0x0000000000000000
(lldb) frame var self
(SKTGraphicView *) self = 0x0000000000000000
You can also call functions:
(lldb) expr (int) printf ("I have a pointer 0x%llx.\n", self)
$2 = (int) 22
I have a pointer 0x0.
One thing to note from this example is that lldb commands can be defined to
take "raw" input. "expression" is one of these. So in the expression command,
you don't have to quote your whole expression, nor backslash protect quotes,
etc...
Finally, the results of the expressions are stored in persistent variables
(of the form $[0-9]+) that you can use in further expressions, like:
(lldb) expr self = $0
$4 = (SKTGraphicView *) 0x0000000100135430
f) Customization:
You can use the embedded Python interpreter to add the following 'pwd' and 'cd' commands
for your lldb session:
(lldb) script import os
(lldb) command alias pwd script print os.getcwd()
(lldb) command regex cd "s/^(.*)$/script os.chdir(os.path.expanduser('%1'))/"
...
(lldb) cd /tmp
script os.chdir(os.path.expanduser('/tmp'))
(lldb) pwd
/private/tmp
(lldb)
Or for a more capable 'cd' command, create ~/utils.py like this:
import os
def chdir(debugger, args, result, dict):
"""Change the working directory, or cd to ${HOME}."""
dir = args.strip()
if dir:
os.chdir(args)
else:
os.chdir(os.path.expanduser('~'))
print "Current working directory: %s" % os.getcwd()
and, have the following in your ~/.lldbinit file:
script import os, sys
script sys.path.append(os.path.expanduser('~'))
script import utils
command alias pwd script print os.getcwd()
command script add -f utils.chdir cd
and, then in your lldb session, you can have:
(lldb) help cd
Change the working directory, or cd to ${HOME}.
Syntax: cd
(lldb) cd
Current working directory: /Volumes/data/Users/johnny
(lldb) cd /tmp
Current working directory: /private/tmp
(lldb) pwd
/private/tmp
(lldb)
For more examples of customization, look under the ToT/examples/customization
directory.

File diff suppressed because it is too large Load Diff

154
external/llvm-project/lldb/docs/lldb.1 vendored Normal file
View File

@@ -0,0 +1,154 @@
.Dd December 16, 2015 \" DATE
.Dt LLDB 1 \" Program name and manual section number
.Os
.Sh NAME \" Section Header - required - do not modify
.Nm lldb
.Nd The debugger
.Sh SYNOPSIS \" Section Header - required - do not modify
.Nm lldb
.Op Fl hvdexw
.Op Fl a Ar arch
.Op Fl c Ar core-file
.Op Fl l Ar script-language
.Op Fl s Ar lldb-commands
.Op Fl n Ar process-name
.Op Fl p Ar pid
.Ar [[--] <PROGRAM-ARG1> <PROGRAM-ARG2> ...]
.Sh DESCRIPTION \" Section Header - required - do not modify
.Nm
is the command line interface for the LLDB debugger library.
.Nm
can debug C, C++, Objective-C, and Objective-C++ programs.
.Pp
The following options are available:
.Bl -tag -width indent
.It Fl h, -help
Prints out the usage information for the
.Nm
debugger.
The
.Fl -help
text may be more up-to-date and
authoritative than the command line options described in this man
page.
.It Fl v, -version
Prints out the version number of the
.Nm
debugger.
.It Fl a, -arch Ar arch
Specifies which architecture
.Nm
will use when launching the specified program (assuming the provided
executable is built for multiple architectures.)
.It Fl f, -file Ar filename
Specifies the executable file that
.Nm
will be launching / attaching to.
.It Fl n, -attach-name Ar process-name
Specifies the name of a currently-running process to attach to.
(or the name of a process to wait for if
.Fl w
is used.)
.It Fl w, -wait-for
When used in concert with
.Fl n Ar process-name ,
indicates that
.Nm
should wait for a new process of that name to be started -- and attach
to it as early in the process-launch as possible.
.It Fl p, -attach-pid Ar pid
Specifies a currently running process that
.Nm
should attach to.
.It Fl c, -core Ar core-file
Specifies the core file to examine.
.It Fl l, -script-language Ar language
Tells the debugger to use the specified scripting language for
user-defined scripts, rather than the default.
Valid scripting
languages that can be specified include Python, Perl, Ruby and Tcl.
Currently only the Python extensions have been implemented.
.It Fl d, -debug
Tells the debugger to print out extra information for debugging itself.
.It Fl s, -source Ar filename
Tells
.Nm
to read in and execute the file
.Qq Ar filename ,
which should contain
.Nm
commands.
.It Fl e, -editor
Instructs
.Nm
to open source files using the host's "external editor" mechanism.
.It Fl x, -no-lldbinit
Do not automatically parse any '.lldbinit' files.
.Pp
(If you do not provide -f then the first argument will be the file to
be debugged
so 'lldb -- <filename> [<ARG1> [<ARG2>]]' also works.
Remember to end the options with "--" if any of your arguments have
a "-" in them.)
.El
.Sh USING LLDB
In
.Nm
there is a
.Cm help
command which can be used to find descriptions and examples of all
.Nm
commands.
To get help on
.Qq Cm breakpoint set
you would type
.Qq Cm help breakpoint set .
.Pp
There is also an
.Cm apropos
command which will search the help text of all commands
for a given term -- this is useful for locating a command by topic.
For instance,
.Qq Cm apropos breakpoint
will list any command that has the word
.Qq Cm breakpoint
in its help text.
.Sh FILES
.Nm
will read settings/aliases/commands from three files at startup, if they exist.
.Pp
First, it will read a
.Pa ~/.lldbinit-debugger
command file.
If you are using the
.Nm
command line interface, this is
.Pa ~/.lldbinit-lldb .
If you are using
.Nm
inside a GUI debugger like
.Nm Xcode
this will be
.Pa ~/.lldbinit-Xcode .
This is a useful place to put settings that you want to apply only when a given
.Nm
command interpreter is used.
.Pp
Second,
.Pa ~/.lldbinit
is read.
.Pp
Third, an
.Pa .lldbinit
file in the current working directory (where
.Nm
is started) will be read.
.Sh SEE ALSO
The LLDB project page http://lldb.llvm.org/ has many different resources for
.Nm
users -- the gdb/lldb command equivalence page http://lldb.llvm.org/lldb-gdb.html can
be especially helpful for users coming from gdb.
.Sh BUGS
To report bugs, please visit http://llvm.org/bugs/
.Sh AUTHOR
Maintained by the LLDB Team, http://lldb.llvm.org/

View File

@@ -0,0 +1,160 @@
# Change Notes
## Summary
This document describes the DarwinLog logging feature.
## StructuredDataDarwinLog feature
The DarwinLog feature supports logging `os_log`*() and `NSLog`() messages
to the command-line lldb console, as well as making those messages
available to LLDB clients via the event system. Starting with fall
2016 OSes, Apple platforms introduce a new fire-hose, stream-style
logging system where the bulk of the log processing happens on the log
consumer side. This reduces logging impact on the system when there
are no consumers, making it cheaper to include logging at all times.
However, it also increases the work needed on the consumer end when
log messages are desired.
The debugserver binary has been modified to support collection of
`os_log`*()/`NSLog`() messages, selection of which messages appear in the
stream, and fine-grained filtering of what gets passed on to the LLDB
client. DarwinLog also tracks the activity chain (i.e. `os_activity`()
hierarchy) in effect at the time the log messages were issued. The
user is able to configure a number of aspects related to the
formatting of the log message header fields.
The DarwinLog support is written in a way which should support the
lldb client side on non-Apple clients talking to an Apple device or
macOS system; hence, the plugin support is built into all LLDB
clients, not just those built on an Apple platform.
StructuredDataDarwinLog implements the 'DarwinLog' feature type, and
the plugin name for it shows up as `darwin-log`.
The user interface to the darwin-log support is via the following:
* `plugin structured-data darwin-log enable` command
This is the main entry point for enabling the command. It can be
set before launching a process or while the process is running.
If the user wants to squelch seeing info-level or debug-level
messages, which is the default behavior, then the enable command
must be made prior to launching the process; otherwise, the
info-level and debug-level messages will always show up. Also,
there is a similar "echo os_log()/NSLog() messages to target
process stderr" mechanism which is properly disabled when enabling
the DarwinLog support prior to launch. This cannot be squelched
if enabling DarwinLog after launch.
See the help for this command. There are a number of options
to shrink or expand the number of messages that are processed
on the remote side and sent over to the client, and other
options to control the formatting of messages displayed.
This command is sticky. Once enabled, it will stay enabled for
future process launches.
* `plugin structured-data darwin-log disable` command
Executing this command disables os_log() capture in the currently
running process and signals LLDB to stop attempting to launch
new processes with DarwinLog support enabled.
* `settings set
plugin.structured-data.darwin-log.enable-on-startup true`
and
`settings set
plugin.structured-data.darwin-log.auto-enable-options -- `{options}
When `enable-on-startup` is set to `true`, then LLDB will automatically
enable DarwinLog on startup of relevant processes. It will use the
content provided in the auto-enable-options settings as the
options to pass to the enable command.
Note the `--` required after auto-enable-command. That is necessary
for raw commands like settings set. The `--` will not become part
of the options for the enable command.
### Message flow and related performance considerations
`os_log`()-style collection is not free. The more data that must be
processed, the slower it will be. There are several knobs available
to the developer to limit how much data goes through the pipe, and how
much data ultimately goes over the wire to the LLDB client. The
user's goal should be to ensure he or she only collects as many log
messages are needed, but no more.
The flow of data looks like the following:
1. Data comes into debugserver from the low-level OS facility that
receives log messages. The data that comes through this pipe can
be limited or expanded by the `--debug`, `--info` and
`--all-processes` options of the `plugin structured-data darwin-log
enable` command options. Exclude as many categories as possible
here (also the default). The knobs here are very coarse - for
example, whether to include `os_log_info()`-level or
`os_log_debug()`-level info, or to include callstacks in the log
message event data.
2. The debugserver process filters the messages that arrive through a
message log filter that may be fully customized by the user. It
works similar to a rules-based packet filter: a set of rules are
matched against the log message, each rule tried in sequential
order. The first rule that matches then either accepts or rejects
the message. If the log message does not match any rule, then the
message gets the no-match (i.e. fall-through) action. The no-match
action defaults to accepting but may be set to reject.
Filters can be added via the enable command's '`--filter`
{filter-spec}' option. Filters are added in order, and multiple
`--filter` entries can be provided to the enable command.
Filters take the following form:
```
{action} {attribute} {op}
{action} :=
accept |
reject
{attribute} :=
category | // The log message category
subsystem | // The log message subsystem
activity | // The child-most activity in force
// at the time the message was logged.
activity-chain | // The complete activity chain, specified
// as {parent-activity}:{child-activity}:
// {grandchild-activity}
message | // The fully expanded message contents.
// Note this one is expensive because it
// requires expanding the message. Avoid
// this if possible, or add it further
// down the filter chain.
{op} :=
match {exact-match-text} |
regex {search-regex} // uses C++ std::regex
// ECMAScript variant.
```
e.g.
`--filter "accept subsystem match com.example.mycompany.myproduct"`
`--filter "accept subsystem regex com.example.+"`
`--filter "reject category regex spammy-system-[[:digit:]]+"`
3. Messages that are accepted by the log message filter get sent to
the lldb client, where they are mapped to the
StructuredDataDarwinLog plugin. By default, command-line lldb will
issue a Process-level event containing the log message content, and
will request the plugin to print the message if the plugin is
enabled to do so.
### Log message display
Several settings control aspects of displaying log messages in
command-line LLDB. See the `enable` command's help for a description
of these.

View File

@@ -0,0 +1,136 @@
# Change Notes
## Overview
This document describes an infrastructural feature called Structured
Data plugins. See the `DarwinLog.md` doc for a description of one
such plugin that makes use of this feature.
## StructuredDataPlugin
StructuredDataPlugin instances have the following characteristics:
* Each plugin instance is bound to a single Process instance.
* Each StructuredData feature has a type name that identifies the
feature. For instance, the type name for the DarwinLog feature is
"DarwinLog". This feature type name is used in various places.
* The process monitor reports the list of supported StructuredData
features advertised by the process monitor. Process goes through the
list of supported feature type names, and asks each known
StructuredDataPlugin if it can handle the feature. The first plugin
that supports the feature is mapped to that Process instance for
that feature. Plugins are only mapped when the process monitor
advertises that a feature is supported.
* The feature may send asynchronous messages in StructuredData format
to the Process instance. Process instances route the asynchronous
structured data messages to the plugin mapped to that feature type,
if one exists.
* Plugins can request that the Process instance forward on
configuration data to the process monitor if the plugin needs/wants
to configure the feature. Plugins may call the new Process method
```C++
virtual Error
ConfigureStructuredData(const ConstString &type_name,
const StructuredData::ObjectSP &config_sp)
```
where `type_name` is the feature name and `config_sp` points to the
configuration structured data, which may be nullptr.
* Plugins for features present in a process are notified when modules
are loaded into the Process instance via this StructuredDataPlugin
method:
```C++
virtual void
ModulesDidLoad(Process &process, ModuleList &module_list);
```
* Plugins may optionally broadcast their received structured data as
an LLDB process-level event via the following new Process call:
```C++
void
BroadcastStructuredData(const StructuredData::ObjectSP &object_sp,
const lldb::StructuredDataPluginSP &plugin_sp);
```
IDE clients might use this feature to receive information about the
process as it is running to monitor memory usage, CPU usage, and
logging.
Internally, the event type created is an instance of
EventDataStructuredData.
* In the case where a plugin chooses to broadcast a received
StructuredData event, the command-line LLDB Debugger instance
listens for them. The Debugger instance then gives the plugin an
opportunity to display info to either the debugger output or error
stream at a time that is safe to write to them. The plugin can
choose to display something appropriate regarding the structured
data that time.
* Plugins can provide a ProcessLaunchInfo filter method when the
plugin is registered. If such a filter method is provided, then
when a process is about to be launched for debugging, the filter
callback is invoked, given both the launch info and the target. The
plugin may then alter the launch info if needed to better support
the feature of the plugin.
* The plugin is entirely independent of the type of Process-derived
class that it is working with. The only requirements from the
process monitor are the following feature-agnostic elements:
* Provide a way to discover features supported by the process
monitor for the current process.
* Specify the list of supported feature type names to Process.
The process monitor does this by calling the following new
method on Process:
```C++
void
MapSupportedStructuredDataPlugins(const StructuredData::Array
&supported_type_names)
```
The `supported_type_names` specifies an array of string entries,
where each entry specifies the name of a StructuredData feature.
* Provide a way to forward on configuration data for a feature type
to the process monitor. This is the manner by which LLDB can
configure a feature, perhaps based on settings or commands from
the user. The following virtual method on Process (described
earlier) does the job:
```C++
virtual Error
ConfigureStructuredData(const ConstString &type_name,
const StructuredData::ObjectSP &config_sp)
```
* Listen for asynchronous structured data packets from the process
monitor, and forward them on to Process via this new Process
member method:
```C++
bool
RouteAsyncStructuredData(const StructuredData::ObjectSP object_sp)
```
* StructuredData producers must send their top-level data as a
Dictionary type, with a key called 'type' specifying a string value,
where the value is equal to the StructuredData feature/type name
previously advertised. Everything else about the content of the
dictionary is entirely up to the feature.
* StructuredDataPlugin commands show up under `plugin structured-data
plugin-name`.
* StructuredDataPlugin settings show up under
`plugin.structured-data.{plugin-name}`.

View File

@@ -0,0 +1,43 @@
os command: [['/bin/sh', '-c', 'make clean; make']]
stdout: rm -rf "a.out" "a.out.dSYM" main.o main.d
g++ -arch x86_64 -gdwarf-2 -O0 -c -o main.o main.cpp
g++ -arch x86_64 -gdwarf-2 -O0 main.o -o "a.out"
/usr/bin/dsymutil -o "a.out.dSYM" "a.out"
stderr: None
retcode: 0
runCmd: file /Volumes/data/lldb/svn/trunk/test/settings/a.out
output: Current executable set to '/Volumes/data/lldb/svn/trunk/test/settings/a.out' (x86_64).
runCmd: settings set target.process.output-path 'stdout.txt'
output:
runCmd: settings show target.process.output-path
output: target.process.output-path (string) = 'stdout.txt'
Expecting start string: target.process.output-path (string) = 'stdout.txt'
Matched
runCmd: run
output: Process 43533 launched: '/Volumes/data/lldb/svn/trunk/test/settings/a.out' (x86_64)
FAIL
runCmd: process kill
check of return status not required
runCmd failed!
error: Process must be launched.
Traceback (most recent call last):
File "/Volumes/data/lldb/svn/trunk/test/settings/TestSettings.py", line 125, in test_set_output_path
"'stdout.txt' exists due to target.process.output-path.")
AssertionError: False is not True : 'stdout.txt' exists due to target.process.output-path.

View File

@@ -0,0 +1,309 @@
Let's pick test/settings/TestSettings.py as our example. First, notice the file
name "TestSettings.py", the Test*.py pattern is the default mechanism that the
test driver uses for discovery of tests. As to TestSettings.py, it defines a
class:
class SettingsCommandTestCase(TestBase):
derived from TestBase, which is defined in test/lldbtest.py and is itself
derived from Python's unittest framework's TestCase class. See also
http://docs.python.org/library/unittest.html for more details.
To just run the TestSettings.py test, chdir to the lldb test directory, and then
type the following command:
/Volumes/data/lldb/svn/trunk/test $ ./dotest.py settings
----------------------------------------------------------------------
Collected 6 tests
----------------------------------------------------------------------
Ran 6 tests in 8.699s
OK (expected failures=1)
/Volumes/data/lldb/svn/trunk/test $
Pass '-v' option to the test driver to also output verbose descriptions of the
individual test cases and their test status:
/Volumes/data/lldb/svn/trunk/test $ ./dotest.py -v settings
----------------------------------------------------------------------
Collected 6 tests
test_set_auto_confirm (TestSettings.SettingsCommandTestCase)
Test that after 'set auto-confirm true', manual confirmation should not kick in. ... ok
test_set_output_path (TestSettings.SettingsCommandTestCase)
Test that setting target.process.output-path for the launched process works. ... expected failure
test_set_prompt (TestSettings.SettingsCommandTestCase)
Test that 'set prompt' actually changes the prompt. ... ok
test_set_term_width (TestSettings.SettingsCommandTestCase)
Test that 'set term-width' actually changes the term-width. ... ok
test_with_dsym (TestSettings.SettingsCommandTestCase)
Test that run-args and env-vars are passed to the launched process. ... ok
test_with_dwarf (TestSettings.SettingsCommandTestCase)
Test that run-args and env-vars are passed to the launched process. ... ok
----------------------------------------------------------------------
Ran 6 tests in 5.735s
OK (expected failures=1)
/Volumes/data/lldb/svn/trunk/test $
Underneath, the '-v' option passes keyword argument verbosity=2 to the
Python's unittest.TextTestRunner (see also
http://docs.python.org/library/unittest.html#unittest.TextTestRunner). For very
detailed descriptions about what's going on during the test, pass '-t' to the
test driver, which asks the test driver to trace the commands executed and to
display their output. For brevity, the '-t' output is not included here.
Notice the 'expected failures=1' message at the end of the run. This is because
of a bug currently in lldb such that setting target.process.output-path to
'stdout.txt' does not have any effect on the redirection of the standard output
of the subsequent launched process. We are using unittest2 (a backport of new
unittest features for Python 2.4-2.6) to decorate (mark) the particular test
method as such:
@unittest2.expectedFailure
# rdar://problem/8435794
# settings set target.process.output-path does not seem to work
def test_set_output_path(self):
See http://pypi.python.org/pypi/unittest2 for more details.
Now let's look inside the test method:
def test_set_output_path(self):
"""Test that setting target.process.output-path for the launched process works."""
self.buildDefault()
exe = os.path.join(os.getcwd(), "a.out")
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
# Set the output-path and verify it is set.
self.runCmd("settings set target.process.output-path 'stdout.txt'")
self.expect("settings show target.process.output-path",
startstr = "target.process.output-path (string) = 'stdout.txt'")
self.runCmd("run", RUN_SUCCEEDED)
# The 'stdout.txt' file should now exist.
self.assertTrue(os.path.isfile("stdout.txt"),
"'stdout.txt' exists due to target.process.output-path.")
# Read the output file produced by running the program.
with open('stdout.txt', 'r') as f:
output = f.read()
self.expect(output, exe=False,
startstr = "This message should go to standard out.")
The self.buildDefault() statement is used to build a default binary for this
test instance. For this particular test case, since we don't really care what
debugging format is used, we instruct the build subsystem to build the default
binary for us. The base class TestBase has defined three instance methods:
def buildDefault(self, architecture=None, compiler=None, dictionary=None):
"""Platform specific way to build the default binaries."""
module = __import__(sys.platform)
if not module.buildDefault(self, architecture, compiler, dictionary):
raise Exception("Don't know how to build default binary")
def buildDsym(self, architecture=None, compiler=None, dictionary=None):
"""Platform specific way to build binaries with dsym info."""
module = __import__(sys.platform)
if not module.buildDsym(self, architecture, compiler, dictionary):
raise Exception("Don't know how to build binary with dsym")
def buildDwarf(self, architecture=None, compiler=None, dictionary=None):
"""Platform specific way to build binaries with dwarf maps."""
module = __import__(sys.platform)
if not module.buildDwarf(self, architecture, compiler, dictionary):
raise Exception("Don't know how to build binary with dwarf")
And the test/plugins/darwin.py provides the implementation for all three build
methods using the makefile mechanism. We envision that linux plugin can use a
similar approach to accomplish the task of building the binaries.
Mac OS X provides an additional way to manipulate archived DWARF debug symbol
files and produces dSYM files. The buildDsym() instance method is used by the
test method to build the binary with dsym info. For an example of this,
see test/array_types/TestArrayTypes.py:
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
def test_with_dsym_and_run_command(self):
"""Test 'frame variable var_name' on some variables with array types."""
self.buildDsym()
self.array_types()
This method is decorated with a skipUnless decorator so that it will only gets
included into the test suite if the platform it is running on is 'darwin', aka
Mac OS X.
Type 'man dsymutil' for more details.
After the binary is built, it is time to specify the file to be used as the main
executable by lldb:
exe = os.path.join(os.getcwd(), "a.out")
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
This is where the attribute assignment:
class SettingsCommandTestCase(TestBase):
mydir = "settings"
which happens right after the SettingsCommandTestCase class declaration comes
into place. It specifies the relative directory to the top level 'test' so that
the test harness can change its working directory in order to find the
executable as well as the source code files. The runCmd() method is defined in
the TestBase base class (within test/lldbtest.py) and its purpose is to pass the
specified command to the lldb command interpreter. It's like you're typing the
command within an interactive lldb session.
The CURRENT_EXECUTABLE_SET is an assert message defined in the lldbtest module
so that it can be reused from other test modules.
By default, the runCmd() is going to check the return status of the command
execution and fails the test if it is not a success. The assert message, in our
case CURRENT_EXECUTABLE_SET, is used in the exception printout if this happens.
There are cases when we don't care about the return status from the command
execution. This can be accomplished by passing the keyword argument pair
'check=False' to the method.
After the current executable is set, we'll then execute two more commands:
# Set the output-path and verify it is set.
self.runCmd("settings set target.process.output-path 'stdout.txt'")
self.expect("settings show target.process.output-path",
SETTING_MSG("target.process.output-path"),
startstr = "target.process.output-path (string) = 'stdout.txt'")
The first uses the 'settings set' command to set the static setting
target.process.output-path to be 'stdout.txt', instead of the default
'/dev/stdout'. We then immediately issue a 'settings show' command to check
that, indeed, the setting did take place. Notice that we use a new method
expect() to accomplish the task, which in effect issues a runCmd() behind the
door and grabs the output from the command execution and expects to match the
start string of the output against what we pass in as the value of the keyword
argument pair:
startstr = "target.process.output-path (string) = 'stdout.txt'"
Take a look at TestBase.expect() within lldbtest.py for more details. Among
other things, it can also match against a list of regexp patterns as well as a
list of sub strings. And it can also perform negative matching, i.e., instead
of expecting something from the output of command execution, it can perform the
action of 'not expecting' something.
This will launch/run the program:
self.runCmd("run", RUN_SUCCEEDED)
And this asserts that the file 'stdout.txt' should be present after running the
program.
# The 'stdout.txt' file should now exist.
self.assertTrue(os.path.isfile("stdout.txt"),
"'stdout.txt' exists due to target.process.output-path.")
Also take a look at main.cpp which emits some message to the stdout. Now, if we
pass this assertion, it's time to examine the contents of the file to make sure
it contains the same message as programmed in main.cpp:
# Read the output file produced by running the program.
with open('stdout.txt', 'r') as f:
output = f.read()
self.expect(output, exe=False,
startstr = "This message should go to standard out.")
We open the file and read its contents into output, then issue an expect()
method. The 'exe=False' keyword argument pair tells expect() that don't try to
execute the first arg as a command at all. Instead, treat it as a string to
match against whatever is thrown in as keyword argument pairs!
There are also other test methods present in the TestSettings.py mode:
test_set_prompt(), test_set_term_width(), test_set_auto_confirm(),
test_with_dsym(), and test_with_dwarf(). We are using the default test loader
from unittest framework, which uses the 'test' method name prefix to identify
test methods automatically.
This finishes the walkthrough of the test method test_set_output_path(self).
Before we say goodbye, notice the little method definition at the top of the
file:
@classmethod
def classCleanup(cls):
system(["/bin/sh", "-c", "rm -f output.txt"])
system(["/bin/sh", "-c", "rm -f stdout.txt"])
This is a classmethod (as shown by the @classmethod decorator) which allows the
individual test class to perform cleanup actions after the test harness finishes
with the particular test class. This is part of the so-called test fixture in
the unittest framework. From http://docs.python.org/library/unittest.html:
A test fixture represents the preparation needed to perform one or more tests,
and any associate cleanup actions. This may involve, for example, creating
temporary or proxy databases, directories, or starting a server process.
The TestBase class uses such fixture with setUp(self), tearDown(self),
setUpClass(cls), and tearDownClass(cls). And within teraDownClass(cls), it
checks whether the current class has an attribute named 'classCleanup', and
executes as a method if present. In this particular case, the classCleanup()
calls a utility function system() defined in lldbtest.py in order to remove the
files created by running the program as the tests are executed.
This system() function uses the Python subprocess module to spawn the process
and to retrieve its results. If the test instance passes the keyword argument
pair 'sender=self', the detailed command execution through the operating system
also gets recorded in a session object. If the test instance fails or errors,
the session info automatically gets dumped to a file grouped under a directory
named after the timestamp of the particular test suite run.
For simple cases, look for the timestamp directory in the same directory of the
test driver program dotest.py. For example, if we comment out the
@expectedFailure decorator for TestSettings.py, and then run the test module:
/Volumes/data/lldb/svn/trunk/test $ ./dotest.py -v settings
----------------------------------------------------------------------
Collected 6 tests
test_set_auto_confirm (TestSettings.SettingsCommandTestCase)
Test that after 'set auto-confirm true', manual confirmation should not kick in. ... ok
test_set_output_path (TestSettings.SettingsCommandTestCase)
Test that setting target.process.output-path for the launched process works. ... FAIL
test_set_prompt (TestSettings.SettingsCommandTestCase)
Test that 'set prompt' actually changes the prompt. ... ok
test_set_term_width (TestSettings.SettingsCommandTestCase)
Test that 'set term-width' actually changes the term-width. ... ok
test_with_dsym (TestSettings.SettingsCommandTestCase)
Test that run-args and env-vars are passed to the launched process. ... ok
test_with_dwarf (TestSettings.SettingsCommandTestCase)
Test that run-args and env-vars are passed to the launched process. ... ok
======================================================================
FAIL: test_set_output_path (TestSettings.SettingsCommandTestCase)
Test that setting target.process.output-path for the launched process works.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Volumes/data/lldb/svn/trunk/test/settings/TestSettings.py", line 125, in test_set_output_path
"'stdout.txt' exists due to target.process.output-path.")
AssertionError: False is not True : 'stdout.txt' exists due to target.process.output-path.
----------------------------------------------------------------------
Ran 6 tests in 8.219s
FAILED (failures=1)
/Volumes/data/lldb/svn/trunk/test $ ls 2010-10-19-14:10:49.059609
NOTE: This directory name has been changed to not contain the ':' character
which is not allowed in windows platforms. We'll change the ':' to '_'
and get rid of the microsecond resolution by modifying the test driver.
TestSettings.SettingsCommandTestCase.test_set_output_path.log
/Volumes/data/lldb/svn/trunk/test $
We get one failure and a timestamp directory 2010-10-19-14:10:49.059609.
For education purposes, the directory and its contents are reproduced here in
the same directory as the current file.

View File

@@ -0,0 +1,93 @@
This document attempts to point out some best practices that prove to be helpful
when building new test cases in the tot/test directory. Everyone is welcomed to
add/modify contents into this file.
o Do not use hard-coded line numbers in your test case. Instead, try to tag the
line with some distinguishing pattern, and use the function line_number()
defined in lldbtest.py which takes filename and string_to_match as arguments
and returns the line number.
As an example, take a look at test/breakpoint_conditions/main.c which has these
two lines:
return c(val); // Find the line number of c's parent call here.
and
return val + 3; // Find the line number of function "c" here.
The Python test case TestBreakpointConditions.py uses the comment strings to
find the line numbers during setUp(self) and use them later on to verify that
the correct breakpoint is being stopped on and that its parent frame also has
the correct line number as intended through the breakpoint condition.
o Take advantage of the unittest framework's decorator features to properly
mark your test class or method for platform-specific tests.
As an example, take a look at test/forward/TestForwardDeclaration.py which has
these lines:
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
def test_with_dsym_and_run_command(self):
"""Display *bar_ptr when stopped on a function with forward declaration of struct bar."""
self.buildDsym()
self.forward_declaration()
This tells the test harness that unless we are running "darwin", the test should
be skipped. This is because we are asking to build the binaries with dsym debug
info, which is only available on the darwin platforms.
o Cleanup after yourself. A classic example of this can be found in test/types/
TestFloatTypes.py:
def test_float_types_with_dsym(self):
"""Test that float-type variables are displayed correctly."""
d = {'CXX_SOURCES': 'float.cpp'}
self.buildDsym(dictionary=d)
self.setTearDownCleanup(dictionary=d)
self.float_type()
...
def test_double_type_with_dsym(self):
"""Test that double-type variables are displayed correctly."""
d = {'CXX_SOURCES': 'double.cpp'}
self.buildDsym(dictionary=d)
self.setTearDownCleanup(dictionary=d)
self.double_type()
This tests different data structures composed of float types to verify that what
the debugger prints out matches what the compiler does for different variables
of these types. We're using a dictionary to pass the build parameters to the
build system. After a particular test instance is done, it is a good idea to
clean up the files built. This eliminates the chance that some leftover files
can interfere with the build phase for the next test instance and render it
invalid.
TestBase.setTearDownCleanup(self, dictionary) defined in lldbtest.py is created
to cope with this use case by taking the same build parameters in order to do
the cleanup when we are finished with a test instance, during
TestBase.tearDown(self).
o Class-wise cleanup after yourself.
TestBase.tearDownClass(cls) provides a mechanism to invoke the platform-specific
cleanup after finishing with a test class. A test class can have more than one
test methods, so the tearDownClass(cls) method gets run after all the test
methods have been executed by the test harness.
The default cleanup action performed by the plugins/darwin.py module invokes the
"make clean" os command.
If this default cleanup is not enough, individual class can provide an extra
cleanup hook with a class method named classCleanup , for example,
in test/breakpoint_command/TestBreakpointCommand.py:
@classmethod
def classCleanup(cls):
system(["/bin/sh", "-c", "rm -f output.txt"])
The 'output.txt' file gets generated during the test run, so it makes sense to
explicitly spell out the action in the same TestBreakpointCommand.py file to do
the cleanup instead of artificially adding it as part of the default cleanup
action which serves to cleanup those intermediate and a.out files.