1 Commits

Author SHA1 Message Date
41f05bd8d7 Initial import of lldb
Change-Id: Ib244e837bee349effa12b2ff6ffffbe3d730e929
2018-03-26 17:37:53 +02:00
5293 changed files with 1323992 additions and 463 deletions

View File

@@ -1,17 +0,0 @@
# Build MINIX/arm with clang
It is now possible to build a full minix distribution for BeaglBone White/Black and BeagleBoardxM using clang instead of GCC.
This also add support to run the Kuya tests on ARM, which was not possible when GCC was used, because of problems in the C++ exception handling.
## Known Bugs
The following tests still fails:
1. 53: Division by zero does not trigger exceptions
2. 75: ru.tv_secs can't be zero (and is zero)
3. 85: hangs
4. isofs: Fails because of an out of memory condition
5. vnd: crash
6. Running two times the kyua tests in a row, without rebooting in between will lead to a mostly failed second run because of copy-on-write errors.

View File

@@ -1,4 +1,4 @@
/* $NetBSD: cat.c,v 1.57 2016/06/16 00:52:37 sevan Exp $ */
/* $NetBSD: cat.c,v 1.55 2015/07/25 16:17:01 sevan Exp $ */
/*
* Copyright (c) 1989, 1993
@@ -44,7 +44,7 @@ __COPYRIGHT(
#if 0
static char sccsid[] = "@(#)cat.c 8.2 (Berkeley) 4/27/95";
#else
__RCSID("$NetBSD: cat.c,v 1.57 2016/06/16 00:52:37 sevan Exp $");
__RCSID("$NetBSD: cat.c,v 1.55 2015/07/25 16:17:01 sevan Exp $");
#endif
#endif /* not lint */
@@ -113,7 +113,6 @@ main(int argc, char *argv[])
vflag = 1;
break;
default:
case '?':
(void)fprintf(stderr,
"Usage: %s [-beflnstuv] [-B bsize] [-] "
"[file ...]\n", getprogname());
@@ -175,16 +174,18 @@ cook_buf(FILE *fp)
line = gobble = 0;
for (prev = '\n'; (ch = getc(fp)) != EOF; prev = ch) {
if (prev == '\n') {
if (sflag) {
if (ch == '\n') {
if (gobble)
continue;
if (ch == '\n') {
if (sflag) {
if (!gobble && nflag && !bflag)
(void)fprintf(stdout,
"%6d\t\n", ++line);
else if (!gobble && putchar(ch) == EOF)
break;
gobble = 1;
} else
gobble = 0;
continue;
}
if (nflag) {
if (!bflag || ch != '\n') {
if (!bflag) {
(void)fprintf(stdout,
"%6d\t", ++line);
if (ferror(stdout))
@@ -196,7 +197,13 @@ cook_buf(FILE *fp)
break;
}
}
} else if (nflag) {
(void)fprintf(stdout, "%6d\t", ++line);
if (ferror(stdout))
break;
}
}
gobble = 0;
if (ch == '\n') {
if (eflag)
if (putchar('$') == EOF)

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: chmod.1,v 1.26 2016/08/11 00:10:42 sevan Exp $
.\" $NetBSD: chmod.1,v 1.25 2013/12/17 09:54:08 apb Exp $
.\"
.\" Copyright (c) 1989, 1990, 1993, 1994
.\" The Regents of the University of California. All rights reserved.
@@ -32,7 +32,7 @@
.\"
.\" @(#)chmod.1 8.4 (Berkeley) 3/31/94
.\"
.Dd August 11, 2016
.Dd October 22, 2012
.Dt CHMOD 1
.Os
.Sh NAME
@@ -304,11 +304,6 @@ compatible with the exception of the
symbol
.Dq t
which is not included in that standard.
.Sh HISTORY
A
.Nm
utility appeared in
.At v1 .
.Sh BUGS
There's no
.Ar perm

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: cp.1,v 1.45 2016/08/11 00:17:23 sevan Exp $
.\" $NetBSD: cp.1,v 1.44 2015/06/28 16:22:54 wiz Exp $
.\"
.\" Copyright (c) 1989, 1990, 1993, 1994
.\" The Regents of the University of California. All rights reserved.
@@ -32,7 +32,7 @@
.\"
.\" @(#)cp.1 8.3 (Berkeley) 4/18/94
.\"
.Dd August 11, 2016
.Dd March 25, 2012
.Dt CP 1
.Os
.Sh NAME
@@ -255,8 +255,3 @@ The
.Fl v
option is an extension to
.St -p1003.2 .
.Sh HISTORY
A
.Nm
utility appeared in
.At v1 .

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: csh.1,v 1.53 2016/08/10 17:16:47 sevan Exp $
.\" $NetBSD: csh.1,v 1.52 2013/01/22 21:20:26 wiz Exp $
.\"
.\" Copyright (c) 1980, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -29,7 +29,7 @@
.\"
.\" @(#)csh.1 8.2 (Berkeley) 1/21/94
.\"
.Dd August 8, 2016
.Dd January 22, 2013
.Dt CSH 1
.Os
.Sh NAME
@@ -2233,7 +2233,7 @@ substitutions on a single line to 20.
.Sh HISTORY
.Nm
appeared in
.Bx 2 .
.Bx 3 .
It was a first implementation of a command language interpreter
incorporating a history mechanism (see
.Sx History substitutions ) ,

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: date.1,v 1.44 2017/01/03 16:01:05 abhinav Exp $
.\" $NetBSD: date.1,v 1.42 2012/04/06 11:36:56 wiz Exp $
.\"
.\" Copyright (c) 1980, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -32,7 +32,7 @@
.\"
.\" @(#)date.1 8.3 (Berkeley) 4/28/95
.\"
.Dd August 11, 2016
.Dd November 15, 2006
.Dt DATE 1
.Os
.Sh NAME
@@ -148,7 +148,7 @@ The hour of the day, from 00 to 23.
.It Ar MM
The minute of the hour, from 00 to 59.
.It Ar SS
The second of the minute, from 00 to 60.
The second of the minute, from 00 to 61.
.El
.Pp
Everything but the minutes is optional.
@@ -244,8 +244,3 @@ The
.Nm
utility is expected to be compatible with
.St -p1003.2 .
.Sh HISTORY
A
.Nm
utility appeared in
.At v1 .

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: dd.1,v 1.32 2016/08/18 22:43:49 sevan Exp $
.\" $NetBSD: dd.1,v 1.27 2015/03/18 13:30:13 wiz Exp $
.\"
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -32,7 +32,7 @@
.\"
.\" @(#)dd.1 8.2 (Berkeley) 1/13/94
.\"
.Dd August 18, 2016
.Dd March 18, 2015
.Dt DD 1
.Os
.Sh NAME
@@ -209,7 +209,7 @@ in order to output to a nonexistent file.
The default or specified value is or'ed with
.Va rdwr
for a first
.Xr open 2
.Xt open 2
attempt, then on failure with
.Va wronly
on a second attempt.
@@ -486,6 +486,7 @@ To print summary information in human-readable form:
.Pp
To customize the information summary output and print it through
.Xr unvis 3 :
.Pp
.Bd -literal -offset indent
dd if=/dev/zero of=/dev/null count=1 \e
msgfmt='speed:%E, in %s seconds\en' 2\*[Gt]\*[Am]1 | unvis
@@ -515,8 +516,3 @@ and
values are extensions to the
.Tn POSIX
standard.
.Sh HISTORY
A
.Nm
utility appeared in
.At v5 .

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: df.1,v 1.46 2016/08/10 23:48:14 sevan Exp $
.\" $NetBSD: df.1,v 1.44 2010/04/05 21:17:28 joerg Exp $
.\"
.\" Copyright (c) 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -29,7 +29,7 @@
.\"
.\" @(#)df.1 8.2 (Berkeley) 1/13/92
.\"
.Dd August 10, 2016
.Dd March 4, 2008
.Dt DF 1
.Os
.Sh NAME
@@ -203,4 +203,4 @@ size block.
A
.Nm
utility appeared in
.At v1 .
.At v6 .

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: echo.1,v 1.15 2016/08/14 22:59:22 sevan Exp $
.\" $NetBSD: echo.1,v 1.13 2003/08/07 09:05:12 agc Exp $
.\"
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -32,7 +32,7 @@
.\"
.\" @(#)echo.1 8.1 (Berkeley) 7/22/93
.\"
.Dd August 14, 2016
.Dd July 22, 1993
.Dt ECHO 1
.Os
.Sh NAME
@@ -66,8 +66,3 @@ The
utility is expected to be
.St -p1003.2
compatible.
.Sh HISTORY
An
.Nm
utility appeared in
.At v2 .

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: expr.1,v 1.36 2016/08/23 20:34:23 sevan Exp $
.\" $NetBSD: expr.1,v 1.33 2012/08/12 17:27:04 wiz Exp $
.\"
.\" Copyright (c) 2000,2003 The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -27,7 +27,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd August 23, 2016
.Dd April 20, 2004
.Dt EXPR 1
.Os
.Sh NAME
@@ -214,7 +214,7 @@ treat it as a delimiter to mark the end of command
line options, and ignore it.
Some
.Nm
implementations do not recognize it at all; others
implementations don't recognize it at all; others
might ignore it even in cases where doing so results in syntax
error.
There should be same result for both following examples,
@@ -242,28 +242,15 @@ The
.Ar length
keyword is an extension for compatibility with GNU
.Nm .
.Sh HISTORY
An
.Nm
utility first appeared in the Programmer's Workbench (PWB/UNIX).
A public domain version of
.Nm
written by
.An Pace Willisson
.Aq pace@blitz.com
appeared in
.Bx 386 0.1 .
.Sh AUTHORS
Initial implementation by
.An Pace Willisson Aq Mt pace@blitz.com
was largely rewritten by
.An -nosplit
.An J.T. Conklin Aq Mt jtc@NetBSD.org .
It was rewritten again for
Original implementation was written by
.An J.T. Conklin
.Aq jtc@NetBSD.org .
It was rewritten for
.Nx 1.6
by
.An -nosplit
.An Jaromir Dolecek Aq Mt jdolecek@NetBSD.org .
.An Jaromir Dolecek
.Aq jdolecek@NetBSD.org .
.Sh NOTES
The empty string
.Do Dc

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: kill.1,v 1.28 2017/04/22 23:01:36 christos Exp $
.\" $NetBSD: kill.1,v 1.22 2012/03/22 07:58:17 wiz Exp $
.\"
.\" Copyright (c) 1980, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -32,7 +32,7 @@
.\"
.\" @(#)kill.1 8.2 (Berkeley) 4/28/95
.\"
.Dd April 22, 2017
.Dd April 28, 1995
.Dt KILL 1
.Os
.Sh NAME
@@ -63,6 +63,7 @@ by the pid operand(s).
Only the super-user may send signals to other users' processes.
.Pp
The options are as follows:
.Pp
.Bl -tag -width Ds
.It Fl s Ar signal_name
A symbolic signal name specifying the signal to be sent instead of the
@@ -103,9 +104,6 @@ belonging to the user.
.Pp
Some of the more commonly used signals:
.Bl -tag -width Ds -compact
.It 0
0 (does not affect the process; can be used to test whether the
process exists)
.It 1
HUP (hang up)
.It 2
@@ -132,8 +130,6 @@ arguments.
See
.Xr csh 1
for details.
.Sh DIAGNOSTICS
.Ex -std
.Sh SEE ALSO
.Xr csh 1 ,
.Xr pgrep 1 ,
@@ -145,12 +141,11 @@ for details.
.Sh STANDARDS
The
.Nm
utility is expected to be
function is expected to be
.St -p1003.2
compatible.
.Sh HISTORY
A
.Nm
command appeared in
.At v3
in section 8 of the manual.
.At v6 .

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: ls.1,v 1.79 2016/08/10 17:45:12 sevan Exp $
.\" $NetBSD: ls.1,v 1.78 2014/10/18 01:49:01 jschauma Exp $
.\"
.\" Copyright (c) 1980, 1990, 1991, 1993, 1994
.\" The Regents of the University of California. All rights reserved.
@@ -32,7 +32,7 @@
.\"
.\" @(#)ls.1 8.7 (Berkeley) 7/29/94
.\"
.Dd August 10, 2016
.Dd October 17, 2014
.Dt LS 1
.Os
.Sh NAME
@@ -513,4 +513,4 @@ specification.
An
.Nm
utility appeared in
.At v1 .
.At v5 .

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: mkdir.1,v 1.19 2016/08/10 18:42:00 sevan Exp $
.\" $NetBSD: mkdir.1,v 1.17 2012/03/22 07:58:17 wiz Exp $
.\"
.\" Copyright (c) 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -32,7 +32,7 @@
.\"
.\" @(#)mkdir.1 8.2 (Berkeley) 1/25/94
.\"
.Dd August 10, 2016
.Dd January 25, 1994
.Dt MKDIR 1
.Os
.Sh NAME
@@ -92,8 +92,3 @@ The
utility is expected to be
.St -p1003.2
compatible.
.Sh HISTORY
A
.Nm
utility appeared in
.At v1 .

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: mv.1,v 1.28 2016/08/10 18:08:14 sevan Exp $
.\" $NetBSD: mv.1,v 1.26 2012/03/22 07:58:17 wiz Exp $
.\"
.\" Copyright (c) 1989, 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -32,7 +32,7 @@
.\"
.\" @(#)mv.1 8.1 (Berkeley) 5/31/93
.\"
.Dd August 10, 2016
.Dd December 26, 2002
.Dt MV 1
.Os
.Sh NAME
@@ -144,8 +144,3 @@ The
.Fl v
option is an extension to
.St -p1003.2 .
.Sh HISTORY
An
.Nm
utility appeared in
.At v1 .

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: cpio.1,v 1.14 2015/12/19 18:48:33 wiz Exp $
.\" $NetBSD: cpio.1,v 1.13 2011/06/19 07:34:24 wiz Exp $
.\"
.\" Copyright (c) 1997 SigmaSoft, Th. Lockert
.\" All rights reserved.
@@ -297,8 +297,7 @@ specific archive format specification.
.Xr pax 1 ,
.Xr tar 1
.Sh AUTHORS
.An Keith Muller
at the University of California, San Diego.
Keith Muller at the University of California, San Diego.
.Sh BUGS
The
.Fl s

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: pwd.1,v 1.25 2016/08/12 02:03:26 sevan Exp $
.\" $NetBSD: pwd.1,v 1.24 2003/10/30 14:58:23 wiz Exp $
.\"
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -32,7 +32,7 @@
.\"
.\" @(#)pwd.1 8.2 (Berkeley) 4/28/95
.\"
.Dd August 12, 2016
.Dd October 30, 2003
.Dt PWD 1
.Os
.Sh NAME
@@ -87,11 +87,6 @@ except that the default is
.Fl P
not
.Fl L .
.Sh HISTORY
A
.Nm
utility appeared in
.At v5 .
.Sh BUGS
In
.Xr csh 1

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: rm.1,v 1.28 2016/08/12 02:26:42 sevan Exp $
.\" $NetBSD: rm.1,v 1.27 2013/04/26 19:34:34 wiz Exp $
.\"
.\" Copyright (c) 1990, 1993, 1994, 2003
.\" The Regents of the University of California. All rights reserved.
@@ -32,7 +32,7 @@
.\"
.\" @(#)rm.1 8.5 (Berkeley) 12/5/94
.\"
.Dd August 12, 2016
.Dd April 26, 2013
.Dt RM 1
.Os
.Sh NAME
@@ -190,11 +190,6 @@ magnetic disk.
.Em Because these requirements are not met, the
.Fl P
.Em option does not conform to the standard .
.Sh HISTORY
An
.Nm
utility appeared in
.At v1 .
.Sh BUGS
The
.Fl P

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: rmdir.1,v 1.16 2016/08/12 02:30:37 sevan Exp $
.\" $NetBSD: rmdir.1,v 1.15 2003/08/07 09:05:29 agc Exp $
.\"
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -32,7 +32,7 @@
.\"
.\" @(#)rmdir.1 8.1 (Berkeley) 5/31/93
.\"
.Dd August 12, 2016
.Dd May 31, 1993
.Dt RMDIR 1
.Os
.Sh NAME
@@ -88,8 +88,3 @@ The
utility is expected to be
.St -p1003.2
compatible.
.Sh HISTORY
An
.Nm
utility appeared in
.At v1 .

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: sleep.1,v 1.23 2016/08/12 02:36:38 sevan Exp $
.\" $NetBSD: sleep.1,v 1.22 2011/08/15 14:45:36 wiz Exp $
.\"
.\" Copyright (c) 1990, 1993, 1994
.\" The Regents of the University of California. All rights reserved.
@@ -32,7 +32,7 @@
.\"
.\" @(#)sleep.1 8.3 (Berkeley) 4/18/94
.\"
.Dd August 12, 2016
.Dd August 13, 2011
.Dt SLEEP 1
.Os
.Sh NAME
@@ -121,8 +121,3 @@ The
command is expected to be
.St -p1003.2
compatible.
.Sh HISTORY
A
.Nm
utility appeared in
.At v4 .

View File

@@ -1,4 +1,4 @@
.\" $NetBSD: stty.1,v 1.43 2016/08/14 23:29:43 sevan Exp $
.\" $NetBSD: stty.1,v 1.41 2012/06/20 14:19:39 wiz Exp $
.\"
.\" Copyright (c) 1990, 1993, 1994
.\" The Regents of the University of California. All rights reserved.
@@ -32,7 +32,7 @@
.\"
.\" @(#)stty.1 8.5 (Berkeley) 6/1/94
.\"
.Dd August 15, 2016
.Dd June 16, 2012
.Dt STTY 1
.Os
.Sh NAME
@@ -633,8 +633,3 @@ and
flags are
extensions to the standard, as are the operands mentioned in the control
operations section.
.Sh HISTORY
An
.Nm
utility appeared in
.At v2 .

View File

@@ -81,9 +81,6 @@
./usr/include/arm/vm.h minix-comp
./usr/include/arm/vmparam.h minix-comp
./usr/include/arm/wchar_limits.h minix-comp
./usr/include/clang-3.6/arm_acle.h minix-comp llvm,llvmcmds
./usr/include/clang-3.6/arm_neon.h minix-comp llvm,llvmcmds
./usr/include/clang-3.6/stdatomic.h minix-comp llvm,llvmcmds
./usr/include/evbarm minix-comp
./usr/include/evbarm/disklabel.h minix-comp
./usr/include/evbarm/intr.h minix-comp

View File

@@ -7,10 +7,6 @@ MAN= named.8 lwresd.8 named.conf.5
BINDIR= /usr/sbin
LINKS= ${BINDIR}/named ${BINDIR}/lwresd
.if defined(__MINIX)
CWARNFLAGS.gcc+= -Wno-maybe-uninitialized
.endif # defined(__MINIX)
.include "${.CURDIR}/../Makefile.inc"
DIST=${IDIST}/bin/named

View File

@@ -606,21 +606,15 @@ lwres_conf_parse(lwres_context_t *ctx, const char *filename) {
FILE *fp = NULL;
char word[256];
lwres_result_t rval, ret;
#if !defined(NDEBUG) && defined(__minix)
lwres_conf_t *confdata;
#endif /* !defined(NDEBUG) && defined(__minix) */
int stopchar;
REQUIRE(ctx != NULL);
#if !defined(NDEBUG) && defined(__minix)
confdata = &ctx->confdata;
#endif /* !defined(NDEBUG) && defined(__minix) */
REQUIRE(filename != NULL);
REQUIRE(strlen(filename) > 0U);
#if !defined(NDEBUG) && defined(__minix)
REQUIRE(confdata != NULL);
#endif /* !defined(NDEBUG) && defined(__minix) */
errno = 0;
if ((fp = fopen(filename, "r")) == NULL)

View File

@@ -7,11 +7,6 @@ LIB=dns
.include "${.CURDIR}/../Makefile.inc"
.if defined(__MINIX)
#LSC: -Wno-maybe-uninitialized while compiling with -DNDEBUG -Os
CWARNFLAGS.gcc+= -Wno-maybe-uninitialized
.endif # defined(__MINIX)
DIST= ${IDIST}/lib/dns
.include "${DIST}/api"
.include "${DIST}/mapapi"

View File

@@ -5,11 +5,6 @@ LIB=isc
.include <bsd.own.mk>
.if defined(__MINIX)
#LSC: -Wno-maybe-uninitialized while compiling with -DNDEBUG -Os
CWARNFLAGS.gcc+= -Wno-maybe-uninitialized
.endif # defined(__MINIX)
.include "${.CURDIR}/../Makefile.inc"
DIST= ${IDIST}/lib/isc

View File

@@ -12,11 +12,3 @@ MAN = dhcp-options.5 dhcp-eval.5
DHCPSRCDIR= common
.include <bsd.lib.mk>
.if defined(__MINIX)
.if !empty(DBG:M-Og) || !empty(CFLAGS:M-Og) || \
!empty(DBG:M-g) || !empty(CFLAGS:M-g)
#LSC: -Wno-maybe-uninitialized while compiling with -DNDEBUG -Og
CWARNFLAGS.gcc+= -Wno-maybe-uninitialized
.endif
.endif # defined(__MINIX)

View File

@@ -14,10 +14,6 @@ CPPFLAGS+= -DHAVE_CONFIG_H
.include <bsd.own.mk>
.if defined(__MINIX)
CWARNFLAGS.gcc+= -Wno-maybe-uninitialized
.endif # defined(__MINIX)
SRCS+= auth.c hmac_md5.c
USE_INET?= yes

View File

@@ -3816,7 +3816,6 @@ class ARMTargetInfo : public TargetInfo {
SizeType = UnsignedInt;
switch (T.getOS()) {
case llvm::Triple::Minix:
case llvm::Triple::NetBSD:
WCharType = SignedInt;
break;

View File

@@ -275,7 +275,7 @@ std::string ToolChain::ComputeLLVMTriple(const ArgList &Args,
// FIXME: Thumb should just be another -target-feaure, not in the triple.
#if defined(__minix) || 1
// Minix/ARM-specific force to ARMv7 and EABI.
StringRef Suffix = "v7a";
StringRef Suffix = "v7";
Triple.setEnvironment(llvm::Triple::EABI);
#else
StringRef Suffix = Triple.isOSBinFormatMachO()

View File

@@ -665,10 +665,6 @@ StringRef tools::arm::getARMFloatABI(const Driver &D, const ArgList &Args,
}
break;
case llvm::Triple::Minix:
FloatABI = "softfp";
break;
default:
switch(Triple.getEnvironment()) {
case llvm::Triple::GNUEABIHF:
@@ -800,9 +796,6 @@ void Clang::AddARMTargetArgs(const ArgList &Args,
ABIName = "aapcs";
break;
default:
if (Triple.getOS() == llvm::Triple::Minix)
ABIName = "apcs-gnu";
if (Triple.getOS() == llvm::Triple::NetBSD)
ABIName = "apcs-gnu";
else
@@ -7740,11 +7733,6 @@ void minix::Link::ConstructJob(Compilation &C, const JobAction &JA,
// Many NetBSD architectures support more than one ABI.
// Determine the correct emulation for ld.
switch (getToolChain().getArch()) {
case llvm::Triple::arm:
case llvm::Triple::thumb:
CmdArgs.push_back("-m");
CmdArgs.push_back("armelf_minix");
break;
case llvm::Triple::x86:
CmdArgs.push_back("-m");
CmdArgs.push_back("elf_i386_minix");

View File

@@ -638,8 +638,6 @@ llvm::Optional<ProgramStateRef> MallocChecker::performKernelMalloc(
if (!KernelZeroFlagVal.hasValue()) {
if (OS == llvm::Triple::FreeBSD)
KernelZeroFlagVal = 0x0100;
else if (OS == llvm::Triple::Minix)
KernelZeroFlagVal = 0x0002;
else if (OS == llvm::Triple::NetBSD)
KernelZeroFlagVal = 0x0002;
else if (OS == llvm::Triple::OpenBSD)

View File

@@ -0,0 +1,4 @@
{
"project_id" : "lldb",
"conduit_uri" : "http://llvm-reviews.chandlerc.com/"
}

View File

@@ -0,0 +1,275 @@
if ( CMAKE_SYSTEM_NAME MATCHES "Windows" )
set(LLDB_DEFAULT_DISABLE_PYTHON 1)
else()
set(LLDB_DEFAULT_DISABLE_PYTHON 0)
endif()
set(LLDB_DISABLE_PYTHON ${LLDB_DEFAULT_DISABLE_PYTHON} CACHE BOOL
"Disables the Python scripting integration.")
# If we are not building as a part of LLVM, build LLDB as an
# standalone project, using LLVM as an external library:
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
project(lldb)
cmake_minimum_required(VERSION 2.8)
set(LLDB_PATH_TO_LLVM_SOURCE "" CACHE PATH
"Path to LLVM source code. Not necessary if using an installed LLVM.")
set(LLDB_PATH_TO_LLVM_BUILD "" CACHE PATH
"Path to the directory where LLVM was built or installed.")
set(LLDB_PATH_TO_CLANG_SOURCE "" CACHE PATH
"Path to Clang source code. Not necessary if using an installed Clang.")
set(LLDB_PATH_TO_CLANG_BUILD "" CACHE PATH
"Path to the directory where Clang was built or installed.")
if (LLDB_PATH_TO_LLVM_SOURCE)
if (NOT EXISTS "${LLDB_PATH_TO_LLVM_SOURCE}/cmake/config-ix.cmake")
message(FATAL_ERROR "Please set LLDB_PATH_TO_LLVM_SOURCE to the root "
"directory of LLVM source code.")
else()
get_filename_component(LLVM_MAIN_SRC_DIR ${LLDB_PATH_TO_LLVM_SOURCE}
ABSOLUTE)
list(APPEND CMAKE_MODULE_PATH "${LLVM_MAIN_SRC_DIR}/cmake/modules")
endif()
endif()
if (LLDB_PATH_TO_CLANG_SOURCE)
get_filename_component(CLANG_MAIN_SRC_DIR ${LLDB_PATH_TO_CLANG_SOURCE}
ABSOLUTE)
endif()
list(APPEND CMAKE_MODULE_PATH "${LLDB_PATH_TO_LLVM_BUILD}/share/llvm/cmake")
get_filename_component(PATH_TO_LLVM_BUILD ${LLDB_PATH_TO_LLVM_BUILD}
ABSOLUTE)
get_filename_component(PATH_TO_CLANG_BUILD ${LLDB_PATH_TO_CLANG_BUILD}
ABSOLUTE)
include(AddLLVM)
include("${LLDB_PATH_TO_LLVM_BUILD}/share/llvm/cmake/LLVMConfig.cmake")
include(HandleLLVMOptions)
set(PACKAGE_VERSION "${LLVM_PACKAGE_VERSION}")
set(LLVM_MAIN_INCLUDE_DIR "${LLVM_MAIN_SRC_DIR}/include")
set(LLVM_BINARY_DIR ${CMAKE_BINARY_DIR})
set(CLANG_MAIN_INCLUDE_DIR "${CLANG_MAIN_SRC_DIR}/include")
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories("${PATH_TO_LLVM_BUILD}/include"
"${LLVM_MAIN_INCLUDE_DIR}"
"${PATH_TO_CLANG_BUILD}/include"
"${CLANG_MAIN_INCLUDE_DIR}"
"${CMAKE_CURRENT_SOURCE_DIR}/source")
link_directories("${PATH_TO_LLVM_BUILD}/lib"
"${PATH_TO_CLANG_BUILD}/lib")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(LLDB_BUILT_STANDALONE 1)
endif()
if (LLDB_DISABLE_PYTHON)
add_definitions( -DLLDB_DISABLE_PYTHON )
endif()
macro(add_lldb_definitions)
# We don't want no semicolons on LLDB_DEFINITIONS:
foreach(arg ${ARGN})
set(LLDB_DEFINITIONS "${LLVM_DEFINITIONS} ${arg}")
endforeach(arg)
add_definitions( ${ARGN} )
endmacro(add_lldb_definitions)
if (NOT LLDB_DISABLE_PYTHON)
find_package(PythonLibs REQUIRED)
include_directories(${PYTHON_INCLUDE_DIRS})
endif()
include_directories(../clang/include)
include_directories("${CMAKE_CURRENT_BINARY_DIR}/../clang/include")
# lldb requires c++11 to build. Make sure that we have a compiler and standard
# library combination that can do that.
if (NOT MSVC)
# gcc and clang require the -std=c++0x or -std=c++11 flag.
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU" OR
"${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
if (NOT ("${CMAKE_CXX_FLAGS}" MATCHES "-std=c\\+\\+0x" OR
"${CMAKE_CXX_FLAGS}" MATCHES "-std=gnu\\+\\+0x" OR
"${CMAKE_CXX_FLAGS}" MATCHES "-std=c\\+\\+11" OR
"${CMAKE_CXX_FLAGS}" MATCHES "-std=gnu\\+\\+11"))
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.7")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif()
else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
endif()
endif()
endif()
elseif (MSVC_VERSION LESS 1700)
message(FATAL_ERROR "The selected compiler does not support c++11 which is "
"required to build lldb.")
endif()
# Disable Clang warnings
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
add_lldb_definitions(
-Wno-deprecated-declarations # Suppress "deprecated auto_ptr" warnings
)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "3.3")
add_lldb_definitions(
-Wno-deprecated-register # Suppress "deprecated register keyword" warnings
)
endif()
# Disable MSVC warnings
if( MSVC )
add_lldb_definitions(
-wd4018 # Suppress 'warning C4018: '>=' : signed/unsigned mismatch'
-wd4068 # Suppress 'warning C4068: unknown pragma'
-wd4150 # Suppress 'warning C4150: deletion of pointer to incomplete type'
-wd4521 # Suppress 'warning C4521: 'type' : multiple copy constructors specified'
)
endif()
# If building on a 32-bit system, make sure off_t can store offsets > 2GB
if( CMAKE_SIZEOF_VOID_P EQUAL 4 )
add_lldb_definitions(
-D_LARGEFILE_SOURCE
-D_FILE_OFFSET_BITS=64
)
endif()
set(LLDB_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(LLDB_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
message(FATAL_ERROR "In-source builds are not allowed. CMake would overwrite "
"the makefiles distributed with LLDB. Please create a directory and run cmake "
"from there, passing the path to this source directory as the last argument. "
"This process created the file `CMakeCache.txt' and the directory "
"`CMakeFiles'. Please delete them.")
endif()
# Compute the LLDB version from the LLVM version.
string(REGEX MATCH "[0-9]+\\.[0-9]+(\\.[0-9]+)?" LLDB_VERSION
${PACKAGE_VERSION})
message(STATUS "LLDB version: ${LLDB_VERSION}")
macro(add_lldb_library name)
llvm_process_sources(srcs ${ARGN})
if (MSVC_IDE OR XCODE)
string(REGEX MATCHALL "/[^/]+" split_path ${CMAKE_CURRENT_SOURCE_DIR})
list(GET split_path -1 dir)
file(GLOB_RECURSE headers
../../include/lldb${dir}/*.h)
set(srcs ${srcs} ${headers})
endif()
if (MODULE)
set(libkind MODULE)
elseif (SHARED_LIBRARY)
set(libkind SHARED)
else()
set(libkind STATIC)
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
add_library(${name} ${libkind} ${srcs})
#if (LLVM_COMMON_DEPENDS)
##add_dependencies(${name} ${LLVM_COMMON_DEPENDS})
#endif()
if(LLDB_USED_LIBS)
if (CMAKE_SYSTEM_NAME MATCHES "Linux" OR CMAKE_SYSTEM_NAME MATCHES "FreeBSD" OR CMAKE_SYSTEM_NAME MATCHES "Windows")
target_link_libraries(${name} -Wl,--start-group ${LLDB_USED_LIBS} -Wl,--end-group)
else()
target_link_libraries(${name} ${LLDB_USED_LIBS})
endif()
endif()
target_link_libraries(${name} ${CLANG_USED_LIBS})
target_link_libraries(${name} ${LLVM_USED_LIBS})
llvm_config(${name} ${LLVM_LINK_COMPONENTS})
target_link_libraries(${name} ${LLVM_COMMON_LIBS})
link_system_libs(${name})
if (LLVM_COMMON_DEPENDS)
add_dependencies(${name} ${LLVM_COMMON_DEPENDS})
endif()
# Hack: only some LLDB libraries depend on the clang autogenerated headers,
# but it is simple enough to make all of LLDB depend on some of those
# headers without negatively impacting much of anything.
set (LLDB_DEPENDENCIES
libclang
)
add_dependencies(${name} ${LLDB_DEPENDENCIES})
install(TARGETS ${name}
LIBRARY DESTINATION lib${LLVM_LIBDIR_SUFFIX}
ARCHIVE DESTINATION lib${LLVM_LIBDIR_SUFFIX})
set_target_properties(${name} PROPERTIES FOLDER "lldb libraries")
endmacro(add_lldb_library)
macro(add_lldb_executable name)
#add_llvm_executable(${name} ${ARGN})
llvm_process_sources( ALL_FILES ${ARGN} )
add_executable(${name} ${ALL_FILES})
#target_link_libraries(${name} ${CLANG_USED_LIBS})
#llvm_config( ${name} ${LLVM_LINK_COMPONENTS} )
#link_system_libs( ${name} )
#if (LLVM_COMMON_DEPENDS)
#add_dependencies(${name} ${LLVM_COMMON_DEPENDS})
#endif()
set_target_properties(${name} PROPERTIES FOLDER "lldb executables")
endmacro(add_lldb_executable)
include_directories(BEFORE
${CMAKE_CURRENT_BINARY_DIR}/include
${CMAKE_CURRENT_SOURCE_DIR}/include
)
install(DIRECTORY include/
DESTINATION include
FILES_MATCHING
PATTERN "*.h"
PATTERN ".svn" EXCLUDE
)
# Find libraries or frameworks that may be needed
if (CMAKE_SYSTEM_NAME MATCHES "Darwin")
find_library(CARBON_LIBRARY Carbon)
find_library(FOUNDATION_LIBRARY Foundation)
find_library(CORE_FOUNDATION_LIBRARY CoreFoundation)
find_library(CORE_SERVICES_LIBRARY CoreServices)
find_library(SECURITY_LIBRARY Security)
find_library(DEBUG_SYMBOLS_LIBRARY DebugSymbols PATHS "/System/Library/PrivateFrameworks")
set(LIBXML2_INCLUDE_DIR "/usr/include/libxml2")
list(APPEND system_libs xml2)
list(APPEND system_libs ${CARBON_LIBRARY} ${FOUNDATION_LIBRARY}
${CORE_FOUNDATION_LIBRARY} ${CORE_SERVICES_LIBRARY} ${SECURITY_LIBRARY}
${DEBUG_SYMBOLS_LIBRARY})
endif()
# On FreeBSD, link libexecinfo because libc is missing backtrace()
if (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
list(APPEND system_libs execinfo)
endif()
#add_subdirectory(include)
add_subdirectory(docs)
if (NOT CMAKE_SYSTEM_NAME MATCHES "Windows")
add_subdirectory(scripts)
endif()
add_subdirectory(source)
add_subdirectory(test)
add_subdirectory(tools)

13
external/bsd/llvm/dist/lldb/INSTALL.txt vendored Normal file
View File

@@ -0,0 +1,13 @@
LLDB Installation Instructions
==============================
LLDB builds on Mac OS X (with Xcode) and Linux (with GCC or Clang).
On Mac OS X, in addition to using Xcode you'll need to enable code signing
on your system to either build lldb or debug using lldb. Please see the code
signing documentation in docs/code-signing.txt for more detailed directions.
For instructions to build LLDB on Linux, or more details about supported
compiler versions, other dependencies, and build flags, see:
http://lldb.llvm.org/build.html

38
external/bsd/llvm/dist/lldb/LICENSE.TXT vendored Normal file
View File

@@ -0,0 +1,38 @@
University of Illinois/NCSA
Open Source License
Copyright (c) 2010 Apple Inc.
All rights reserved.
Developed by:
LLDB Team
http://lldb.llvm.org/
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal with
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimers.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimers in the
documentation and/or other materials provided with the distribution.
* Neither the names of the LLDB Team, copyright holders, nor the names of
its contributors may be used to endorse or promote products derived from
this Software without specific prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
SOFTWARE.

117
external/bsd/llvm/dist/lldb/Makefile vendored Normal file
View File

@@ -0,0 +1,117 @@
##===- Makefile --------------------------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
# If LLDB_LEVEL is not set, then we are the top-level Makefile. Otherwise, we
# are being included from a subdirectory makefile.
ifndef LLDB_LEVEL
IS_TOP_LEVEL := 1
LLDB_LEVEL := .
DIRS := include source lib tools
PARALLEL_DIRS :=
endif
###
# Common Makefile code, shared by all LLDB Makefiles.
# Set LLVM source root level.
LEVEL := $(LLDB_LEVEL)/../..
# Include LLVM common makefile.
include $(LEVEL)/Makefile.common
# Set common LLDB build flags.
CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/include
CPP.Flags += -I$(PROJ_OBJ_DIR)/$(LLDB_LEVEL)/include
CPP.Flags += -I$(LLVM_SRC_ROOT)/tools/clang/include
CPP.Flags += -I$(LLVM_OBJ_ROOT)/tools/clang/include
CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/source
CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/source/Utility
CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/source/Plugins/Process/Utility
CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLDB_LEVEL)/source/Plugins/Process/POSIX
ifeq (,$(findstring -DLLDB_DISABLE_PYTHON,$(CXXFLAGS)))
# Set Python include directory
PYTHON_INC_DIR = $(shell python-config --includes)
CPP.Flags += $(PYTHON_INC_DIR)
endif
ifeq ($(HOST_OS),Darwin)
CPP.Flags += $(subst -I,-I$(SDKROOT),$(PYTHON_INC_DIR))
CPP.Flags += -F$(SDKROOT)/System/Library/Frameworks
CPP.Flags += -F$(SDKROOT)/System/Library/PrivateFrameworks
CPP.Flags += -I$(SDKROOT)/usr/include/libxml2
endif
ifdef LLDB_VENDOR
CPP.Flags += -DLLDB_VENDOR='"$(LLDB_VENDOR) "'
endif
# If building on a 32-bit system, make sure off_t can store offsets > 2GB
ifneq "$(HOST_ARCH)" "x86_64"
CPP.Flags += -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
endif
# Disable -fstrict-aliasing. Darwin disables it by default (and LLVM doesn't
# work with it enabled with GCC), Clang/llvm-gc don't support it yet, and newer
# GCC's have false positive warnings with it on Linux (which prove a pain to
# fix). For example:
# http://gcc.gnu.org/PR41874
# http://gcc.gnu.org/PR41838
#
# We can revisit this when LLVM/Clang support it.
CXX.Flags += -fno-strict-aliasing
# Do not warn about pragmas. In particular, we are looking to ignore the
# "#pragma mark" construct which GCC warns about on platforms other than Darwin.
EXTRA_OPTIONS += -Wno-unknown-pragmas
# Drop -Wsign-compare, which we are not currently clean with.
EXTRA_OPTIONS += -Wno-sign-compare
# Drop -Wunused-function and -Wunneeded-internal-declaration, which we are not
# currently clean with.
EXTRA_OPTIONS += -Wno-sign-compare -Wno-unused-function
###
# LLDB Top Level specific stuff.
ifeq ($(IS_TOP_LEVEL),1)
ifneq ($(PROJ_SRC_ROOT),$(PROJ_OBJ_ROOT))
$(RecursiveTargets)::
$(Verb) if [ ! -f test/Makefile ]; then \
$(MKDIR) test; \
$(CP) $(PROJ_SRC_DIR)/test/Makefile test/Makefile; \
fi
endif
test::
@ $(MAKE) -C test
#report::
# @ $(MAKE) -C test report
#clean::
# @ $(MAKE) -C test clean
tags::
$(Verb) etags `find . -type f -name '*.h' -or -name '*.cpp' | \
grep -v /lib/Headers | grep -v /test/`
cscope.files:
find tools lib include -name '*.cpp' \
-or -name '*.def' \
-or -name '*.td' \
-or -name '*.h' > cscope.files
.PHONY: test report clean cscope.files
endif

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/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 3: 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 sigining 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

119
external/bsd/llvm/dist/lldb/docs/lldb.1 vendored Normal file
View File

@@ -0,0 +1,119 @@
.Dd 7 June, 2012 \" DATE
.Dt LLDB 1 \" Program name and manual section number
.Os Darwin \" Operating System
.Sh NAME \" Section Header - required - don't modify
.Nm lldb
.Nd The debugger
.Sh SYNOPSIS \" Section Header - required - don't modify
.Nm lldb
.Op Fl hvdexw
.Op Fl a Ar arch
.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 - don't 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 \fB\-\-help\fR 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 \fB\-w\fR is used.)
.It Fl w, -wait-for
When used in concert with \&\fB\-n process-name\-E\fR, 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 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 "\fBfilename\fR", 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 don't 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 \fBhelp\fR command which can be used to find descriptions and examples of
all
.Nm
commands. To get help on "\fBbreakpoint set\fR" you would type "\fBhelp breakpoint set\fR".
.Pp
There is also an \fBapropos\fR 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, "\fBapropos breakpoint\fR"
will list any command that has the word \fBbreakpoint\fR 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 \fB~/.lldbinit-\fIdebugger\fR command file. If you are using the
.Nm
command line interface, this is \fB~/.lldbinit-lldb\fR. If you are using
.Nm
inside a GUI debugger like
.Nm Xcode
this will be \fB~/.lldbinit-Xcode\fR. This is a useful place to put settings that you
want to apply only when a given
.Nm
command interpreter is used.
.Pp
Second, \fB~/.lldbinit\fR is read.
.Pp
Third, an \fR.lldbinit\fR 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,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.

View File

@@ -0,0 +1,5 @@
# So that ~/binutils.py takes precedence.
script sys.path[:0] = [os.path.expanduser('~')]
script import binutils
command script add -f binutils.itob itob
command script add -f binutils.utob utob

View File

@@ -0,0 +1,36 @@
Files in this directory:
o .lldbinit:
An example lldb init file that imports the binutils.py module and adds the
following commands: 'itob' and 'utob'.
o binutils.py:
Python module which provides implementation for the 'itob' and 'utob' commands.
o README:
The file you are reading now.
================================================================================
The following terminal output shows an interaction with lldb using the .lldbinit
and the binutils.py files which are located in my HOME directory. The lldb init
file imports the utils Python module and adds the 'itob' and 'utob' commands.
$ /Volumes/data/lldb/svn/trunk/build/Debug/lldb
(lldb) help itob
Convert the integer to print its two's complement representation.
args[0] (mandatory) is the integer to be converted
args[1] (mandatory) is the bit width of the two's complement representation
args[2] (optional) if specified, turns on verbose printing
Syntax: itob
(lldb) itob -5 4
[1, 0, 1, 1]
(lldb) itob -5 32 v
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 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, 0, 1, 1]
(lldb) utob 0xABCD 32 v
31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1]
(lldb)

View File

@@ -0,0 +1,122 @@
"Collection of tools for displaying bit representation of numbers."""
import StringIO
def binary(n, width=None):
"""
Return a list of (0|1)'s for the binary representation of n where n >= 0.
If you specify a width, it must be > 0, otherwise it is ignored. The list
could be padded with 0 bits if width is specified.
"""
l = []
if width and width <= 0:
width = None
while n > 0:
l.append(1 if n&1 else 0)
n = n >> 1
if width:
for i in range(width - len(l)):
l.append(0)
l.reverse()
return l
def twos_complement(n, width):
"""
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.
"""
val = 2**(width-1)
if n >= 0:
if n > (val-1):
return None
# It is safe to represent n with width-bits.
return binary(n, width)
if n < 0:
if abs(n) > val:
return None
# It is safe to represent n (a negative int) with width-bits.
return binary(val*2 - abs(n))
# print binary(0xABCD)
# [1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1]
# print binary(0x1F, 8)
# [0, 0, 0, 1, 1, 1, 1, 1]
# print twos_complement(-5, 4)
# [1, 0, 1, 1]
# print twos_complement(7, 4)
# [0, 1, 1, 1]
# print binary(7)
# [1, 1, 1]
# 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]
def positions(width):
"""Helper function returning a list describing the bit positions.
Bit positions greater than 99 are truncated to 2 digits, for example,
100 -> 00 and 127 -> 27."""
return ['{0:2}'.format(i)[-2:] for i in reversed(range(width))]
def utob(debugger, command_line, result, dict):
"""Convert the unsigned integer to print its binary representation.
args[0] (mandatory) is the unsigned integer to be converted
args[1] (optional) is the bit width of the binary representation
args[2] (optional) if specified, turns on verbose printing"""
args = command_line.split()
try:
n = int(args[0], 0)
width = None
if len(args) > 1:
width = int(args[1], 0)
if width < 0:
width = 0
except:
print utob.__doc__
return
if len(args) > 2:
verbose = True
else:
verbose = False
bits = binary(n, width)
if not bits:
print "insufficient width value: %d" % width
return
if verbose and width > 0:
pos = positions(width)
print ' '+' '.join(pos)
print ' %s' % str(bits)
def itob(debugger, command_line, result, dict):
"""Convert the integer to print its two's complement representation.
args[0] (mandatory) is the integer to be converted
args[1] (mandatory) is the bit width of the two's complement representation
args[2] (optional) if specified, turns on verbose printing"""
args = command_line.split()
try:
n = int(args[0], 0)
width = int(args[1], 0)
if width < 0:
width = 0
except:
print itob.__doc__
return
if len(args) > 2:
verbose = True
else:
verbose = False
bits = twos_complement(n, width)
if not bits:
print "insufficient width value: %d" % width
return
if verbose and width > 0:
pos = positions(width)
print ' '+' '.join(pos)
print ' %s' % str(bits)

View File

@@ -0,0 +1,40 @@
Files in this directory:
o importcmd.py:
Python module which provides implementation for the 'import' command.
o README:
The file you are reading now.
================================================================================
The import command defined by importcmd.py can be used in LLDB to load a Python
module given its full pathname.
The command works by extending Python's sys.path lookup to include the path to
the module to be imported when required, and then going through the language
ordinary 'import' mechanism. In this respect, modules imported from LLDB command
line should not be distinguishable from those imported using the script interpreter.
The following terminal output shows an interaction with lldb using this new command.
Enrico-Granatas-MacBook-Pro:Debug enricogranata$ ./lldb
(lldb) script import importcmd
(lldb) command script add import -f importcmd.pyimport_cmd
(lldb) import ../demo.py
(lldb) script demo.test_function('hello world')
I am a Python function that says hello world
(lldb) quit
Enrico-Granatas-MacBook-Pro:Debug enricogranata$
Of course, the commands to import the importcmd.py module and to define the import
command, can be included in the .lldbinit file to make this feature available at
debugger startup
WARNING: The import command defined by importcmd.py is now obsolete
In TOT LLDB, you can say:
(lldb) command script import ../demo.py
(lldb) script demo.test_function('hello world')
I am a Python function that says hello world
(lldb) quit
using the native "command script import" command, which offers a superset of what the import command provided by importcmd.py does

View File

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

View File

@@ -0,0 +1,7 @@
script import os, sys
# So that ~/utils.py takes precedence.
script sys.path[:0] = [os.path.expanduser('~')]
script import utils
command alias pwd script print os.getcwd()
command script add -f utils.chdir cd
command script add -f utils.system system

View File

@@ -0,0 +1,41 @@
Files in this directory:
o .lldbinit:
An example lldb init file that imports the utils.py module and adds the
following commands: 'pwd', 'cd', and 'system'.
o utils.py:
Python module which provides implementation for the 'cd' and 'system' commands.
o README:
The file you are reading now.
================================================================================
The following terminal output shows an interaction with lldb using the .lldbinit
and the utils.py files which are located in my HOME directory. The lldb init
file imports the utils Python module and adds the 'pwd', 'cd', and 'system'
commands.
Johnnys-MacBook-Pro:multiple_threads johnny$ pwd
/Volumes/data/lldb/svn/trunk/test/functionalities/watchpoint/multiple_threads
Johnnys-MacBook-Pro:multiple_threads johnny$ lldb
(lldb) pwd
/Volumes/data/lldb/svn/trunk/test/functionalities/watchpoint/multiple_threads
(lldb) cd ..
Current working directory: /Volumes/data/lldb/svn/trunk/test/functionalities/watchpoint
(lldb) help system
Execute the command (a string) in a subshell.
Syntax: system
(lldb) system ls -l
total 0
drwxr-xr-x 7 johnny admin 238 Oct 11 17:24 hello_watchlocation
drwxr-xr-x 7 johnny admin 238 Oct 11 17:24 hello_watchpoint
drwxr-xr-x 7 johnny admin 238 Oct 11 17:24 multiple_threads
drwxr-xr-x 7 johnny admin 238 Oct 11 17:24 watchpoint_commands
retcode: 0
(lldb)

View File

@@ -0,0 +1,49 @@
"""Utility for changing directories and execution of commands in a subshell."""
import os, shlex, subprocess
# Store the previous working directory for the 'cd -' command.
class Holder:
"""Holds the _prev_dir_ class attribute for chdir() function."""
_prev_dir_ = None
@classmethod
def prev_dir(cls):
return cls._prev_dir_
@classmethod
def swap(cls, dir):
cls._prev_dir_ = dir
def chdir(debugger, args, result, dict):
"""Change the working directory, or cd to ${HOME}.
You can also issue 'cd -' to change to the previous working directory."""
new_dir = args.strip()
if not new_dir:
new_dir = os.path.expanduser('~')
elif new_dir == '-':
if not Holder.prev_dir():
# Bad directory, not changing.
print "bad directory, not changing"
return
else:
new_dir = Holder.prev_dir()
Holder.swap(os.getcwd())
os.chdir(new_dir)
print "Current working directory: %s" % os.getcwd()
def system(debugger, command_line, result, dict):
"""Execute the command (a string) in a subshell."""
args = shlex.split(command_line)
process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
output, error = process.communicate()
retcode = process.poll()
if output and error:
print "stdout=>\n", output
print "stderr=>\n", error
elif output:
print output
elif error:
print error
print "retcode:", retcode

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
#----------------------------------------------------------------------
# Fill in the source files to build
#----------------------------------------------------------------------
# Uncomment line below for debugging shell commands
# SHELL = /bin/sh -x
#----------------------------------------------------------------------
# Change any build/tool options needed
#----------------------------------------------------------------------
ARCH ?= x86_64
CFLAGS ?=-arch $(ARCH) -gdwarf-2 -O0
CXX ?= $(shell xcrun -find clang++)
EXE ?= libheap.dylib
DSYM ?= $(EXE).dSYM
#----------------------------------------------------------------------
# Compile the executable from all the objects (default rule) with no
# dsym file.
#----------------------------------------------------------------------
$(EXE) : heap_find.cpp
$(CXX) $(CFLAGS) -install_name "@executable_path/libheap.dylib" -dynamiclib -lobjc heap_find.cpp -o "$(EXE)"
#----------------------------------------------------------------------
# Include all of the makefiles for each source file so we don't have
# to manually track all of the prerequisites for each source file.
#----------------------------------------------------------------------
.PHONY: clean
all: $(EXE)
clean:
rm -rf "$(EXE)" "$(DSYM)"

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
LEVEL = ../../test/make
CXX_SOURCES := main.cpp
EXE := lldb-functions
USE_LIBCPP := 1
MY_OS = $(shell uname -s)
ifeq "$(MY_OS)" "Darwin"
LLDB_BUILD_DIR ?= /Applications/Xcode.app/Contents/SharedFrameworks
LD_EXTRAS ?= -framework LLDB -Wl,-rpath,"$(LLDB_BUILD_DIR)"
FRAMEWORK_INCLUDES=-F"$(LLDB_BUILD_DIR)"
else
LD_EXTRAS ?= $(LLDB_BUILD_DIR)/_lldb.so
endif
include $(LEVEL)/Makefile.rules

View File

@@ -0,0 +1,364 @@
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <getopt.h>
#include <stdint.h>
#include <stdlib.h>
#if defined(__APPLE__)
#include <LLDB/LLDB.h>
#else
#include "LLDB/SBBlock.h"
#include "LLDB/SBCompileUnit.h"
#include "LLDB/SBDebugger.h"
#include "LLDB/SBFunction.h"
#include "LLDB/SBModule.h"
#include "LLDB/SBStream.h"
#include "LLDB/SBSymbol.h"
#include "LLDB/SBTarget.h"
#include "LLDB/SBThread.h"
#include "LLDB/SBProcess.h"
#endif
#include <string>
using namespace lldb;
//----------------------------------------------------------------------
// This quick sample code shows how to create a debugger instance and
// create an executable target without adding dependent shared
// libraries. It will then set a regular expression breakpoint to get
// breakpoint locations for all functions in the module, and use the
// locations to extract the symbol context for each location. Then it
// dumps all // information about the function: its name, file address
// range, the return type (if any), and all argument types.
//
// To build the program, type (while in this directory):
//
// $ make
//
// then to run this on MacOSX, specify the path to your LLDB.framework
// 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 ...]
//----------------------------------------------------------------------
class LLDBSentry
{
public:
LLDBSentry() {
// Initialize LLDB
SBDebugger::Initialize();
}
~LLDBSentry() {
// Terminate LLDB
SBDebugger::Terminate();
}
};
static struct option g_long_options[] =
{
{ "arch", required_argument, NULL, 'a' },
{ "canonical", no_argument, NULL, 'c' },
{ "extern", no_argument, NULL, 'x' },
{ "help", no_argument, NULL, 'h' },
{ "platform", required_argument, NULL, 'p' },
{ "verbose", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0 }
};
#define PROGRAM_NAME "lldb-functions"
void
usage ()
{
puts (
"NAME\n"
" " PROGRAM_NAME " -- extract all function signatures from one or more binaries.\n"
"\n"
"SYNOPSIS\n"
" " PROGRAM_NAME " [[--arch=<ARCH>] [--platform=<PLATFORM>] [--verbose] [--help] [--canonical] --] <PATH> [<PATH>....]\n"
"\n"
"DESCRIPTION\n"
" Loads the executable pointed to by <PATH> and dumps complete signatures for all functions that have debug information.\n"
"\n"
"EXAMPLE\n"
" " PROGRAM_NAME " --arch=x86_64 /usr/lib/dyld\n"
);
exit(0);
}
int
main (int argc, char const *argv[])
{
// Use a sentry object to properly initialize/terminate LLDB.
LLDBSentry sentry;
SBDebugger debugger (SBDebugger::Create());
// Create a debugger instance so we can create a target
if (!debugger.IsValid())
fprintf (stderr, "error: failed to create a debugger object\n");
bool show_usage = false;
bool verbose = false;
bool canonical = false;
bool external_only = false;
const char *arch = NULL;
const char *platform = NULL;
std::string short_options("h?");
for (const struct option *opt = g_long_options; opt->name; ++opt)
{
if (isprint(opt->val))
{
short_options.append(1, (char)opt->val);
switch (opt->has_arg)
{
case no_argument:
break;
case required_argument:
short_options.append(1, ':');
break;
case optional_argument:
short_options.append(2, ':');
break;
}
}
}
#ifdef __GLIBC__
optind = 0;
#else
optreset = 1;
optind = 1;
#endif
char ch;
while ((ch = getopt_long_only(argc, (char * const *)argv, short_options.c_str(), g_long_options, 0)) != -1)
{
switch (ch)
{
case 0:
break;
case 'a':
if (arch != NULL)
{
fprintf (stderr, "error: the --arch option can only be specified once\n");
exit(1);
}
arch = optarg;
break;
case 'c':
canonical = true;
break;
case 'x':
external_only = true;
break;
case 'p':
platform = optarg;
break;
case 'v':
verbose = true;
break;
case 'h':
case '?':
default:
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())
{
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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
LEVEL = ../../../../test/make
DYLIB_NAME := FDInterposing
DYLIB_ONLY := YES
DYLIB_CXX_SOURCES := FDInterposing.cpp
include $(LEVEL)/Makefile.rules

View File

@@ -0,0 +1,17 @@
LEVEL = ../../test/make
CXX_SOURCES := main.cpp
EXE := lldb-lookup
USE_LIBCPP := 1
MY_OS = $(shell uname -s)
ifeq "$(MY_OS)" "Darwin"
LLDB_BUILD_DIR ?= /Applications/Xcode.app/Contents/SharedFrameworks
LD_EXTRAS ?= -framework LLDB -Wl,-rpath,"$(LLDB_BUILD_DIR)"
FRAMEWORK_INCLUDES=-F"$(LLDB_BUILD_DIR)"
else
LD_EXTRAS ?= $(LLDB_BUILD_DIR)/_lldb.so
endif
include $(LEVEL)/Makefile.rules

View File

@@ -0,0 +1,235 @@
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <getopt.h>
#include <stdint.h>
#include <stdlib.h>
#if defined(__APPLE__)
#include <LLDB/LLDB.h>
#else
#include "LLDB/SBBlock.h"
#include "LLDB/SBCompileUnit.h"
#include "LLDB/SBDebugger.h"
#include "LLDB/SBFunction.h"
#include "LLDB/SBModule.h"
#include "LLDB/SBStream.h"
#include "LLDB/SBSymbol.h"
#include "LLDB/SBTarget.h"
#include "LLDB/SBThread.h"
#include "LLDB/SBProcess.h"
#endif
#include <string>
using namespace lldb;
//----------------------------------------------------------------------
// This quick sample code shows how to create a debugger instance and
// create an "i386" executable target. Then we can lookup the executable
// module and resolve a file address into a section offset address,
// and find all symbol context objects (if any) for that address:
// compile unit, function, deepest block, line table entry and the
// symbol.
//
// To build the program, type (while in this directory):
//
// $ make
//
// then (for example):
//
// $ DYLD_FRAMEWORK_PATH=/Volumes/data/lldb/svn/ToT/build/Debug ./a.out executable_path file_address
//----------------------------------------------------------------------
class LLDBSentry
{
public:
LLDBSentry() {
// Initialize LLDB
SBDebugger::Initialize();
}
~LLDBSentry() {
// Terminate LLDB
SBDebugger::Terminate();
}
};
static struct option g_long_options[] =
{
{ "help", no_argument, NULL, 'h' },
{ "verbose", no_argument, NULL, 'v' },
{ "arch", required_argument, NULL, 'a' },
{ "platform", required_argument, NULL, 'p' },
{ NULL, 0, NULL, 0 }
};
#define PROGRAM_NAME "lldb-lookup"
void
usage ()
{
puts (
"NAME\n"
" " PROGRAM_NAME " -- symbolicate addresses using lldb.\n"
"\n"
"SYNOPSIS\n"
" " PROGRAM_NAME " [[--arch=<ARCH>] [--platform=<PLATFORM>] [--verbose] [--help] --] <PATH> <ADDRESS> [<ADDRESS>....]\n"
"\n"
"DESCRIPTION\n"
" Loads the executable pointed to by <PATH> and looks up and <ADDRESS>\n"
" arguments\n"
"\n"
"EXAMPLE\n"
" " PROGRAM_NAME " --arch=x86_64 -- /usr/lib/dyld 0x100000000\n"
);
exit(0);
}
int
main (int argc, char const *argv[])
{
// Use a sentry object to properly initialize/terminate LLDB.
LLDBSentry sentry;
SBDebugger debugger (SBDebugger::Create());
// Create a debugger instance so we can create a target
if (!debugger.IsValid())
fprintf (stderr, "error: failed to create a debugger object\n");
bool show_usage = false;
bool verbose = false;
const char *arch = NULL;
const char *platform = NULL;
std::string short_options("h?");
for (const struct option *opt = g_long_options; opt->name; ++opt)
{
if (isprint(opt->val))
{
short_options.append(1, (char)opt->val);
switch (opt->has_arg)
{
case no_argument:
break;
case required_argument:
short_options.append(1, ':');
break;
case optional_argument:
short_options.append(2, ':');
break;
}
}
}
#ifdef __GLIBC__
optind = 0;
#else
optreset = 1;
optind = 1;
#endif
char ch;
while ((ch = getopt_long_only(argc, (char * const *)argv, short_options.c_str(), g_long_options, 0)) != -1)
{
switch (ch)
{
case 0:
break;
case 'a':
if (arch != NULL)
{
fprintf (stderr, "error: the --arch option can only be specified once\n");
exit(1);
}
arch = optarg;
break;
case 'p':
platform = optarg;
break;
case 'v':
verbose = true;
break;
case 'h':
case '?':
default:
show_usage = true;
break;
}
}
argc -= optind;
argv += optind;
if (show_usage || argc < 2)
usage();
int arg_idx = 0;
// The first argument is the file path we want to look something up in
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)
{
// The second argument in the address that we want to lookup
lldb::addr_t file_addr = strtoull (addr_cstr, NULL, 0);
// Create a target using the executable.
SBTarget target = debugger.CreateTarget (exe_file_path,
arch,
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);
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

@@ -0,0 +1,56 @@
//===-- fooplugin.cpp -------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
/*
An example plugin for LLDB that provides a new foo command with a child 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
*/
#include <LLDB/SBCommandInterpreter.h>
#include <LLDB/SBCommandReturnObject.h>
#include <LLDB/SBDebugger.h>
namespace lldb {
bool
PluginInitialize (lldb::SBDebugger debugger);
}
class ChildCommand : public lldb::SBCommandPluginInterface
{
public:
virtual bool
DoExecute (lldb::SBDebugger debugger,
char** command,
lldb::SBCommandReturnObject &result)
{
if (command)
{
const char* arg = *command;
while (arg)
{
result.Printf("%s\n",arg);
arg = *(++command);
}
return true;
}
return false;
}
};
bool
lldb::PluginInitialize (lldb::SBDebugger debugger)
{
lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter();
lldb::SBCommand foo = interpreter.AddMultiwordCommand("foo",NULL);
foo.AddCommand("child",new ChildCommand(),"a child of foo");
return true;
}

View File

@@ -0,0 +1,76 @@
#!/usr/bin/python
#----------------------------------------------------------------------
# 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
# import it with the full path using the "command script import"
# command
# (lldb) command script import /path/to/cmdtemplate.py
#----------------------------------------------------------------------
import lldb
import commands
import optparse
import shlex
def create_framestats_options():
usage = "usage: %prog [options]"
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.
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.
'''
parser = optparse.OptionParser(description=description, prog='framestats',usage=usage)
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
def the_framestats_command(debugger, command, result, dict):
# Use the Shell Lexer to properly parse up command options just like a
# shell would
command_args = shlex.split(command)
parser = create_framestats_options()
try:
(options, args) = parser.parse_args(command_args)
except:
# 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)
result.SetError ("option parsing failed")
return
# in a command - the lldb.* convenience variables are not to be used
# and their values (if any) are undefined
# this is the best practice to access those objects from within a command
target = debugger.GetSelectedTarget()
process = target.GetProcess()
thread = process.GetSelectedThread()
frame = thread.GetSelectedFrame()
if not frame.IsValid():
return "no frame here"
# from now on, replace lldb.<thing>.whatever with <thing>.whatever
variables_list = frame.GetVariables(options.arguments, options.locals, options.statics, options.inscope)
variables_count = variables_list.GetSize()
if variables_count == 0:
print >> result, "no variables here"
return
total_size = 0
for i in range(0,variables_count):
variable = variables_list.GetValueAtIndex(i)
variable_type = variable.GetType()
total_size = total_size + variable_type.GetByteSize()
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)
# 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
# Make the options so we can generate the help text for the new LLDB
# command line command prior to registering it with LLDB below
parser = create_framestats_options()
the_framestats_command.__doc__ = parser.format_help()
# Add any commands contained in this module to LLDB
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.'

View File

@@ -0,0 +1,782 @@
#!/usr/bin/python
#----------------------------------------------------------------------
# Be sure to add the python path that points to the LLDB shared library.
#
# To use this in the embedded python interpreter using "lldb":
#
# cd /path/containing/crashlog.py
# lldb
# (lldb) script import crashlog
# "crashlog" command installed, type "crashlog --help" for detailed help
# (lldb) crashlog ~/Library/Logs/DiagnosticReports/a.crash
#
# The benefit of running the crashlog command inside lldb in the
# embedded python interpreter is when the command completes, there
# 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
# in the backtrace will be loaded unless the "--load-all" option
# has been specified. This allows users to explore the program in the
# state it was in right at crash time.
#
# On MacOSX csh, tcsh:
# ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash )
#
# On MacOSX sh, bash:
# PYTHONPATH=/path/to/LLDB.framework/Resources/Python ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash
#----------------------------------------------------------------------
import commands
import cmd
import datetime
import glob
import optparse
import os
import platform
import plistlib
import pprint # pp = pprint.PrettyPrinter(indent=4); pp.pprint(command_args)
import re
import shlex
import string
import sys
import time
import uuid
try:
# Just try for LLDB in case PYTHONPATH is already correctly setup
import lldb
except ImportError:
lldb_python_dirs = list()
# lldb is not in the PYTHONPATH, try some defaults for the current platform
platform_system = platform.system()
if platform_system == 'Darwin':
# On Darwin, try the currently selected Xcode directory
xcode_dir = commands.getoutput("xcode-select --print-path")
if xcode_dir:
lldb_python_dirs.append(os.path.realpath(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
for lldb_python_dir in lldb_python_dirs:
if os.path.exists(lldb_python_dir):
if not (sys.path.__contains__(lldb_python_dir)):
sys.path.append(lldb_python_dir)
try:
import lldb
except ImportError:
pass
else:
print 'imported lldb from: "%s"' % (lldb_python_dir)
success = True
break
if not success:
print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
sys.exit(1)
from lldb.utils import symbolication
PARSE_MODE_NORMAL = 0
PARSE_MODE_THREAD = 1
PARSE_MODE_IMAGES = 2
PARSE_MODE_THREGS = 3
PARSE_MODE_SYSTEM = 4
class CrashLog(symbolication.Symbolicator):
"""Class that does parses darwin crash logs"""
parent_process_regex = re.compile('^Parent Process:\s*(.*)\[(\d+)\]');
thread_state_regex = re.compile('^Thread ([0-9]+) crashed with')
thread_regex = re.compile('^Thread ([0-9]+)([^:]*):(.*)')
frame_regex = re.compile('^([0-9]+) +([^ ]+) *\t?(0x[0-9a-fA-F]+) +(.*)')
image_regex_uuid = re.compile('(0x[0-9a-fA-F]+)[- ]+(0x[0-9a-fA-F]+) +[+]?([^ ]+) +([^<]+)<([-0-9a-fA-F]+)> (.*)');
image_regex_no_uuid = re.compile('(0x[0-9a-fA-F]+)[- ]+(0x[0-9a-fA-F]+) +[+]?([^ ]+) +([^/]+)/(.*)');
empty_line_regex = re.compile('^$')
class Thread:
"""Class that represents a thread in a darwin crash log"""
def __init__(self, index):
self.index = index
self.frames = list()
self.idents = list()
self.registers = dict()
self.reason = None
self.queue = None
def dump(self, prefix):
print "%sThread[%u] %s" % (prefix, self.index, self.reason)
if self.frames:
print "%s Frames:" % (prefix)
for frame in self.frames:
frame.dump(prefix + ' ')
if self.registers:
print "%s Registers:" % (prefix)
for reg in self.registers.keys():
print "%s %-5s = %#16.16x" % (prefix, reg, self.registers[reg])
def add_ident(self, ident):
if not ident in self.idents:
self.idents.append(ident)
def did_crash(self):
return self.reason != None
def __str__(self):
s = "Thread[%u]" % self.index
if self.reason:
s += ' %s' % self.reason
return s
class Frame:
"""Class that represents a stack frame in a thread in a darwin crash log"""
def __init__(self, index, pc, description):
self.pc = pc
self.description = description
self.index = index
def __str__(self):
if self.description:
return "[%3u] 0x%16.16x %s" % (self.index, self.pc, self.description)
else:
return "[%3u] 0x%16.16x" % (self.index, self.pc)
def dump(self, prefix):
print "%s%s" % (prefix, str(self))
class DarwinImage(symbolication.Image):
"""Class that represents a binary images in a darwin crash log"""
dsymForUUIDBinary = os.path.expanduser('~rc/bin/dsymForUUID')
if not os.path.exists(dsymForUUIDBinary):
dsymForUUIDBinary = commands.getoutput('which dsymForUUID')
dwarfdump_uuid_regex = re.compile('UUID: ([-0-9a-fA-F]+) \(([^\(]+)\) .*')
def __init__(self, text_addr_lo, text_addr_hi, identifier, version, uuid, path):
symbolication.Image.__init__(self, path, uuid);
self.add_section (symbolication.Section(text_addr_lo, text_addr_hi, "__TEXT"))
self.identifier = identifier
self.version = version
def locate_module_and_debug_symbols(self):
# Don't load a module twice...
if self.resolved:
return True
# Mark this as resolved so we don't keep trying
self.resolved = True
uuid_str = self.get_normalized_uuid_string()
print 'Getting symbols for %s %s...' % (uuid_str, self.path),
if os.path.exists(self.dsymForUUIDBinary):
dsym_for_uuid_command = '%s %s' % (self.dsymForUUIDBinary, uuid_str)
s = commands.getoutput(dsym_for_uuid_command)
if s:
plist_root = plistlib.readPlistFromString (s)
if plist_root:
plist = plist_root[uuid_str]
if plist:
if 'DBGArchitecture' in plist:
self.arch = plist['DBGArchitecture']
if 'DBGDSYMPath' in plist:
self.symfile = os.path.realpath(plist['DBGDSYMPath'])
if 'DBGSymbolRichExecutable' in plist:
self.resolved_path = os.path.expanduser (plist['DBGSymbolRichExecutable'])
if not self.resolved_path and os.path.exists(self.path):
dwarfdump_cmd_output = commands.getoutput('dwarfdump --uuid "%s"' % self.path)
self_uuid = self.get_uuid()
for line in dwarfdump_cmd_output.splitlines():
match = self.dwarfdump_uuid_regex.search (line)
if match:
dwarf_uuid_str = match.group(1)
dwarf_uuid = uuid.UUID(dwarf_uuid_str)
if self_uuid == dwarf_uuid:
self.resolved_path = self.path
self.arch = match.group(2)
break;
if not self.resolved_path:
self.unavailable = True
print "error\n error: unable to locate '%s' with UUID %s" % (self.path, uuid_str)
return False
if (self.resolved_path and os.path.exists(self.resolved_path)) or (self.path and os.path.exists(self.path)):
print 'ok'
# if self.resolved_path:
# print ' exe = "%s"' % self.resolved_path
# if self.symfile:
# print ' dsym = "%s"' % self.symfile
return True
else:
self.unavailable = True
return False
def __init__(self, path):
"""CrashLog constructor that take a path to a darwin crash log file"""
symbolication.Symbolicator.__init__(self);
self.path = os.path.expanduser(path);
self.info_lines = list()
self.system_profile = list()
self.threads = list()
self.idents = list() # A list of the required identifiers for doing all stack backtraces
self.crashed_thread_idx = -1
self.version = -1
self.error = None
# With possible initial component of ~ or ~user replaced by that user's home directory.
try:
f = open(self.path)
except IOError:
self.error = 'error: cannot open "%s"' % self.path
return
self.file_lines = f.read().splitlines()
parse_mode = PARSE_MODE_NORMAL
thread = None
for line in self.file_lines:
# print line
line_len = len(line)
if line_len == 0:
if thread:
if parse_mode == PARSE_MODE_THREAD:
if thread.index == self.crashed_thread_idx:
thread.reason = ''
if self.thread_exception:
thread.reason += self.thread_exception
if self.thread_exception_data:
thread.reason += " (%s)" % self.thread_exception_data
self.threads.append(thread)
thread = None
else:
# only append an extra empty line if the previous line
# in the info_lines wasn't empty
if len(self.info_lines) > 0 and len(self.info_lines[-1]):
self.info_lines.append(line)
parse_mode = PARSE_MODE_NORMAL
# print 'PARSE_MODE_NORMAL'
elif parse_mode == PARSE_MODE_NORMAL:
if line.startswith ('Process:'):
(self.process_name, pid_with_brackets) = line[8:].strip().split(' [')
self.process_id = pid_with_brackets.strip('[]')
elif line.startswith ('Path:'):
self.process_path = line[5:].strip()
elif line.startswith ('Identifier:'):
self.process_identifier = line[11:].strip()
elif line.startswith ('Version:'):
version_string = line[8:].strip()
matched_pair = re.search("(.+)\((.+)\)", version_string)
if matched_pair:
self.process_version = matched_pair.group(1)
self.process_compatability_version = matched_pair.group(2)
else:
self.process = version_string
self.process_compatability_version = version_string
elif self.parent_process_regex.search(line):
parent_process_match = self.parent_process_regex.search(line)
self.parent_process_name = parent_process_match.group(1)
self.parent_process_id = parent_process_match.group(2)
elif line.startswith ('Exception Type:'):
self.thread_exception = line[15:].strip()
continue
elif line.startswith ('Exception Codes:'):
self.thread_exception_data = line[16:].strip()
continue
elif line.startswith ('Crashed Thread:'):
self.crashed_thread_idx = int(line[15:].strip().split()[0])
continue
elif line.startswith ('Report Version:'):
self.version = int(line[15:].strip())
continue
elif line.startswith ('System Profile:'):
parse_mode = PARSE_MODE_SYSTEM
continue
elif (line.startswith ('Interval Since Last Report:') or
line.startswith ('Crashes Since Last Report:') or
line.startswith ('Per-App Interval Since Last Report:') or
line.startswith ('Per-App Crashes Since Last Report:') or
line.startswith ('Sleep/Wake UUID:') or
line.startswith ('Anonymous UUID:')):
# ignore these
continue
elif line.startswith ('Thread'):
thread_state_match = self.thread_state_regex.search (line)
if thread_state_match:
thread_state_match = self.thread_regex.search (line)
thread_idx = int(thread_state_match.group(1))
parse_mode = PARSE_MODE_THREGS
thread = self.threads[thread_idx]
else:
thread_match = self.thread_regex.search (line)
if thread_match:
# print 'PARSE_MODE_THREAD'
parse_mode = PARSE_MODE_THREAD
thread_idx = int(thread_match.group(1))
thread = CrashLog.Thread(thread_idx)
continue
elif line.startswith ('Binary Images:'):
parse_mode = PARSE_MODE_IMAGES
continue
self.info_lines.append(line.strip())
elif parse_mode == PARSE_MODE_THREAD:
if line.startswith ('Thread'):
continue
frame_match = self.frame_regex.search(line)
if frame_match:
ident = frame_match.group(2)
thread.add_ident(ident)
if not ident in self.idents:
self.idents.append(ident)
thread.frames.append (CrashLog.Frame(int(frame_match.group(1)), int(frame_match.group(3), 0), frame_match.group(4)))
else:
print 'error: frame regex failed for line: "%s"' % line
elif parse_mode == PARSE_MODE_IMAGES:
image_match = self.image_regex_uuid.search (line)
if image_match:
image = CrashLog.DarwinImage (int(image_match.group(1),0),
int(image_match.group(2),0),
image_match.group(3).strip(),
image_match.group(4).strip(),
uuid.UUID(image_match.group(5)),
image_match.group(6))
self.images.append (image)
else:
image_match = self.image_regex_no_uuid.search (line)
if image_match:
image = CrashLog.DarwinImage (int(image_match.group(1),0),
int(image_match.group(2),0),
image_match.group(3).strip(),
image_match.group(4).strip(),
None,
image_match.group(5))
self.images.append (image)
else:
print "error: image regex failed for: %s" % line
elif parse_mode == PARSE_MODE_THREGS:
stripped_line = line.strip()
# "r12: 0x00007fff6b5939c8 r13: 0x0000000007000006 r14: 0x0000000000002a03 r15: 0x0000000000000c00"
reg_values = re.findall ('([a-zA-Z0-9]+: 0[Xx][0-9a-fA-F]+) *', stripped_line);
for reg_value in reg_values:
#print 'reg_value = "%s"' % reg_value
(reg, value) = reg_value.split(': ')
#print 'reg = "%s"' % reg
#print 'value = "%s"' % value
thread.registers[reg.strip()] = int(value, 0)
elif parse_mode == PARSE_MODE_SYSTEM:
self.system_profile.append(line)
f.close()
def dump(self):
print "Crash Log File: %s" % (self.path)
print "\nThreads:"
for thread in self.threads:
thread.dump(' ')
print "\nImages:"
for image in self.images:
image.dump(' ')
def find_image_with_identifier(self, identifier):
for image in self.images:
if image.identifier == identifier:
return image
return None
def create_target(self):
#print 'crashlog.create_target()...'
target = symbolication.Symbolicator.create_target(self)
if target:
return target
# We weren't able to open the main executable as, but we can still symbolicate
print 'crashlog.create_target()...2'
if self.idents:
for ident in self.idents:
image = self.find_image_with_identifier (ident)
if image:
target = image.create_target ()
if target:
return target # success
print 'crashlog.create_target()...3'
for image in self.images:
target = image.create_target ()
if target:
return target # success
print 'crashlog.create_target()...4'
print 'error: unable to locate any executables from the crash log'
return None
def usage():
print "Usage: lldb-symbolicate.py [-n name] executable-image"
sys.exit(0)
class Interactive(cmd.Cmd):
'''Interactive prompt for analyzing one or more Darwin crash logs, type "help" to see a list of supported commands.'''
image_option_parser = None
def __init__(self, crash_logs):
cmd.Cmd.__init__(self)
self.use_rawinput = False
self.intro = 'Interactive crashlogs prompt, type "help" to see a list of supported commands.'
self.crash_logs = crash_logs
self.prompt = '% '
def default(self, line):
'''Catch all for unknown command, which will exit the interpreter.'''
print "uknown command: %s" % line
return True
def do_q(self, line):
'''Quit command'''
return True
def do_quit(self, line):
'''Quit command'''
return True
def do_symbolicate(self, line):
description='''Symbolicate one or more darwin crash log files by index to provide source file and line information,
inlined stack frames back to the concrete functions, and disassemble the location of the crash
for the first frame of the crashed thread.'''
option_parser = CreateSymbolicateCrashLogOptions ('symbolicate', description, False)
command_args = shlex.split(line)
try:
(options, args) = option_parser.parse_args(command_args)
except:
return
if args:
# We have arguments, they must valid be crash log file indexes
for idx_str in args:
idx = int(idx_str)
if idx < len(self.crash_logs):
SymbolicateCrashLog (self.crash_logs[idx], options)
else:
print 'error: crash log index %u is out of range' % (idx)
else:
# No arguments, symbolicate all crash logs using the options provided
for idx in range(len(self.crash_logs)):
SymbolicateCrashLog (self.crash_logs[idx], options)
def do_list(self, line=None):
'''Dump a list of all crash logs that are currently loaded.
USAGE: list'''
print '%u crash logs are loaded:' % len(self.crash_logs)
for (crash_log_idx, crash_log) in enumerate(self.crash_logs):
print '[%u] = %s' % (crash_log_idx, crash_log.path)
def do_image(self, line):
'''Dump information about one or more binary images in the crash log given an image basename, or all images if no arguments are provided.'''
usage = "usage: %prog [options] <PATH> [PATH ...]"
description='''Dump information about one or more images in all crash logs. The <PATH> can be a full path, image basename, or partial path. Searches are done in this order.'''
command_args = shlex.split(line)
if not self.image_option_parser:
self.image_option_parser = optparse.OptionParser(description=description, prog='image',usage=usage)
self.image_option_parser.add_option('-a', '--all', action='store_true', help='show all images', default=False)
try:
(options, args) = self.image_option_parser.parse_args(command_args)
except:
return
if args:
for image_path in args:
fullpath_search = image_path[0] == '/'
for (crash_log_idx, crash_log) in enumerate(self.crash_logs):
matches_found = 0
for (image_idx, image) in enumerate(crash_log.images):
if fullpath_search:
if image.get_resolved_path() == image_path:
matches_found += 1
print '[%u] ' % (crash_log_idx), image
else:
image_basename = image.get_resolved_path_basename()
if image_basename == image_path:
matches_found += 1
print '[%u] ' % (crash_log_idx), image
if matches_found == 0:
for (image_idx, image) in enumerate(crash_log.images):
resolved_image_path = image.get_resolved_path()
if resolved_image_path and string.find(image.get_resolved_path(), image_path) >= 0:
print '[%u] ' % (crash_log_idx), image
else:
for crash_log in self.crash_logs:
for (image_idx, image) in enumerate(crash_log.images):
print '[%u] %s' % (image_idx, image)
return False
def interactive_crashlogs(options, args):
crash_log_files = list()
for arg in args:
for resolved_path in glob.glob(arg):
crash_log_files.append(resolved_path)
crash_logs = list();
for crash_log_file in crash_log_files:
#print 'crash_log_file = "%s"' % crash_log_file
crash_log = CrashLog(crash_log_file)
if crash_log.error:
print crash_log.error
continue
if options.debug:
crash_log.dump()
if not crash_log.images:
print 'error: no images in crash log "%s"' % (crash_log)
continue
else:
crash_logs.append(crash_log)
interpreter = Interactive(crash_logs)
# List all crash logs that were imported
interpreter.do_list()
interpreter.cmdloop()
def save_crashlog(debugger, command, result, dict):
usage = "usage: %prog [options] <output-path>"
description='''Export the state of current target into a crashlog file'''
parser = optparse.OptionParser(description=description, prog='save_crashlog',usage=usage)
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
try:
(options, args) = parser.parse_args(shlex.split(command))
except:
result.PutCString ("error: invalid options");
return
if len(args) != 1:
result.PutCString ("error: invalid arguments, a single output file is the only valid argument")
return
out_file = open(args[0], 'w')
if not out_file:
result.PutCString ("error: failed to open file '%s' for writing...", args[0]);
return
if lldb.target:
identifier = lldb.target.executable.basename
if lldb.process:
pid = lldb.process.id
if pid != lldb.LLDB_INVALID_PROCESS_ID:
out_file.write('Process: %s [%u]\n' % (identifier, pid))
out_file.write('Path: %s\n' % (lldb.target.executable.fullpath))
out_file.write('Identifier: %s\n' % (identifier))
out_file.write('\nDate/Time: %s\n' % (datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
out_file.write('OS Version: Mac OS X %s (%s)\n' % (platform.mac_ver()[0], commands.getoutput('sysctl -n kern.osversion')));
out_file.write('Report Version: 9\n')
for thread_idx in range(lldb.process.num_threads):
thread = lldb.process.thread[thread_idx]
out_file.write('\nThread %u:\n' % (thread_idx))
for (frame_idx, frame) in enumerate(thread.frames):
frame_pc = frame.pc
frame_offset = 0
if frame.function:
block = frame.GetFrameBlock()
block_range = block.range[frame.addr]
if block_range:
block_start_addr = block_range[0]
frame_offset = frame_pc - block_start_addr.load_addr
else:
frame_offset = frame_pc - frame.function.addr.load_addr
elif frame.symbol:
frame_offset = frame_pc - frame.symbol.addr.load_addr
out_file.write('%-3u %-32s 0x%16.16x %s' % (frame_idx, frame.module.file.basename, frame_pc, frame.name))
if frame_offset > 0:
out_file.write(' + %u' % (frame_offset))
line_entry = frame.line_entry
if line_entry:
if options.verbose:
# This will output the fullpath + line + column
out_file.write(' %s' % (line_entry))
else:
out_file.write(' %s:%u' % (line_entry.file.basename, line_entry.line))
column = line_entry.column
if column:
out_file.write(':%u' % (column))
out_file.write('\n')
out_file.write('\nBinary Images:\n')
for module in lldb.target.modules:
text_segment = module.section['__TEXT']
if text_segment:
text_segment_load_addr = text_segment.GetLoadAddress(lldb.target)
if text_segment_load_addr != lldb.LLDB_INVALID_ADDRESS:
text_segment_end_load_addr = text_segment_load_addr + text_segment.size
identifier = module.file.basename
module_version = '???'
module_version_array = module.GetVersion()
if module_version_array:
module_version = '.'.join(map(str,module_version_array))
out_file.write (' 0x%16.16x - 0x%16.16x %s (%s - ???) <%s> %s\n' % (text_segment_load_addr, text_segment_end_load_addr, identifier, module_version, module.GetUUIDString(), module.file.fullpath))
out_file.close()
else:
result.PutCString ("error: invalid target");
def Symbolicate(debugger, command, result, dict):
try:
SymbolicateCrashLogs (shlex.split(command))
except:
result.PutCString ("error: python exception %s" % sys.exc_info()[0])
def SymbolicateCrashLog(crash_log, options):
if crash_log.error:
print crash_log.error
return
if options.debug:
crash_log.dump()
if not crash_log.images:
print 'error: no images in crash log'
return
if options.dump_image_list:
print "Binary Images:"
for image in crash_log.images:
if options.verbose:
print image.debug_dump()
else:
print image
target = crash_log.create_target ()
if not target:
return
exe_module = target.GetModuleAtIndex(0)
images_to_load = list()
loaded_images = list()
if options.load_all_images:
# --load-all option was specified, load everything up
for image in crash_log.images:
images_to_load.append(image)
else:
# Only load the images found in stack frames for the crashed threads
if options.crashed_only:
for thread in crash_log.threads:
if thread.did_crash():
for ident in thread.idents:
images = crash_log.find_images_with_identifier (ident)
if images:
for image in images:
images_to_load.append(image)
else:
print 'error: can\'t find image for identifier "%s"' % ident
else:
for ident in crash_log.idents:
images = crash_log.find_images_with_identifier (ident)
if images:
for image in images:
images_to_load.append(image)
else:
print 'error: can\'t find image for identifier "%s"' % ident
for image in images_to_load:
if image in loaded_images:
print "warning: skipping %s loaded at %#16.16x duplicate entry (probably commpage)" % (image.path, image.text_addr_lo)
else:
err = image.add_module (target)
if err:
print err
else:
#print 'loaded %s' % image
loaded_images.append(image)
for thread in crash_log.threads:
this_thread_crashed = thread.did_crash()
if options.crashed_only and this_thread_crashed == False:
continue
print "%s" % thread
#prev_frame_index = -1
display_frame_idx = -1
for frame_idx, frame in enumerate(thread.frames):
disassemble = (this_thread_crashed or options.disassemble_all_threads) and frame_idx < options.disassemble_depth;
if frame_idx == 0:
symbolicated_frame_addresses = crash_log.symbolicate (frame.pc & crash_log.addr_mask, options.verbose)
else:
# Any frame above frame zero and we have to subtract one to get the previous line entry
symbolicated_frame_addresses = crash_log.symbolicate ((frame.pc & crash_log.addr_mask) - 1, options.verbose)
if symbolicated_frame_addresses:
symbolicated_frame_address_idx = 0
for symbolicated_frame_address in symbolicated_frame_addresses:
display_frame_idx += 1
print '[%3u] %s' % (frame_idx, symbolicated_frame_address)
if (options.source_all or thread.did_crash()) and display_frame_idx < options.source_frames and options.source_context:
source_context = options.source_context
line_entry = symbolicated_frame_address.get_symbol_context().line_entry
if line_entry.IsValid():
strm = lldb.SBStream()
if line_entry:
lldb.debugger.GetSourceManager().DisplaySourceLinesWithLineNumbers(line_entry.file, line_entry.line, source_context, source_context, "->", strm)
source_text = strm.GetData()
if source_text:
# Indent the source a bit
indent_str = ' '
join_str = '\n' + indent_str
print '%s%s' % (indent_str, join_str.join(source_text.split('\n')))
if symbolicated_frame_address_idx == 0:
if disassemble:
instructions = symbolicated_frame_address.get_instructions()
if instructions:
print
symbolication.disassemble_instructions (target,
instructions,
frame.pc,
options.disassemble_before,
options.disassemble_after, frame.index > 0)
print
symbolicated_frame_address_idx += 1
else:
print frame
print
def CreateSymbolicateCrashLogOptions(command_name, description, add_interactive_options):
usage = "usage: %prog [options] <FILE> [FILE ...]"
option_parser = optparse.OptionParser(description=description, prog='crashlog',usage=usage)
option_parser.add_option('--verbose' , '-v', action='store_true', dest='verbose', help='display verbose debug info', default=False)
option_parser.add_option('--debug' , '-g', action='store_true', dest='debug', help='display verbose debug logging', default=False)
option_parser.add_option('--load-all' , '-a', action='store_true', dest='load_all_images', help='load all executable images, not just the images found in the crashed stack frames', default=False)
option_parser.add_option('--images' , action='store_true', dest='dump_image_list', help='show image list', default=False)
option_parser.add_option('--debug-delay' , type='int', dest='debug_delay', metavar='NSEC', help='pause for NSEC seconds for debugger', default=0)
option_parser.add_option('--crashed-only' , '-c', action='store_true', dest='crashed_only', help='only symbolicate the crashed thread', default=False)
option_parser.add_option('--disasm-depth' , '-d', type='int', dest='disassemble_depth', help='set the depth in stack frames that should be disassembled (default is 1)', default=1)
option_parser.add_option('--disasm-all' , '-D', action='store_true', dest='disassemble_all_threads', help='enabled disassembly of frames on all threads (not just the crashed thread)', default=False)
option_parser.add_option('--disasm-before' , '-B', type='int', dest='disassemble_before', help='the number of instructions to disassemble before the frame PC', default=4)
option_parser.add_option('--disasm-after' , '-A', type='int', dest='disassemble_after', help='the number of instructions to disassemble after the frame PC', default=4)
option_parser.add_option('--source-context', '-C', type='int', metavar='NLINES', dest='source_context', help='show NLINES source lines of source context (default = 4)', default=4)
option_parser.add_option('--source-frames' , type='int', metavar='NFRAMES', dest='source_frames', help='show source for NFRAMES (default = 4)', default=4)
option_parser.add_option('--source-all' , action='store_true', dest='source_all', help='show source for all threads, not just the crashed thread', default=False)
if add_interactive_options:
option_parser.add_option('-i', '--interactive', action='store_true', help='parse all crash logs and enter interactive mode', default=False)
return option_parser
def SymbolicateCrashLogs(command_args):
description='''Symbolicate one or more darwin crash log files to provide source file and line information,
inlined stack frames back to the concrete functions, and disassemble the location of the crash
for the first frame of the crashed thread.
If this script is imported into the LLDB command interpreter, a "crashlog" command will be added to the interpreter
for use at the LLDB command line. After a crash log has been parsed and symbolicated, a target will have been
created that has all of the shared libraries loaded at the load addresses found in the crash log file. This allows
you to explore the program as if it were stopped at the locations described in the crash log and functions can
be disassembled and lookups can be performed using the addresses found in the crash log.'''
option_parser = CreateSymbolicateCrashLogOptions ('crashlog', description, True)
try:
(options, args) = option_parser.parse_args(command_args)
except:
return
if options.debug:
print 'command_args = %s' % command_args
print 'options', options
print 'args', args
if options.debug_delay > 0:
print "Waiting %u seconds for debugger to attach..." % options.debug_delay
time.sleep(options.debug_delay)
error = lldb.SBError()
if args:
if options.interactive:
interactive_crashlogs(options, args)
else:
for crash_log_file in args:
crash_log = CrashLog(crash_log_file)
SymbolicateCrashLog (crash_log, options)
if __name__ == '__main__':
# Create a new debugger instance
lldb.debugger = lldb.SBDebugger.Create()
SymbolicateCrashLogs (sys.argv[1:])
elif getattr(lldb, 'debugger', None):
lldb.debugger.HandleCommand('command script add -f lldb.macosx.crashlog.Symbolicate crashlog')
lldb.debugger.HandleCommand('command script add -f lldb.macosx.crashlog.save_crashlog save_crashlog')
print '"crashlog" and "save_crashlog" command installed, use the "--help" option for detailed help'

View File

@@ -0,0 +1,115 @@
#!/usr/bin/python
#----------------------------------------------------------------------
# This module will enable GDB remote packet logging 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
# print out statistics about how long commands took to execute and also
# will primnt ou
# 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
# import it with the full path using the "command script import"
# command. This can be done from the LLDB command line:
# (lldb) command script import /path/to/gdbremote.py
# Or it can be added to your ~/.lldbinit file so this module is always
# available.
#----------------------------------------------------------------------
import commands
import optparse
import os
import shlex
import re
import tempfile
def start_gdb_log(debugger, command, result, dict):
'''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"
in order to dump out the commands.'''
global log_file
if log_file:
result.PutCString ('error: logging is already in progress with file "%s"', log_file)
else:
args_len = len(args)
if args_len == 0:
log_file = tempfile.mktemp()
elif len(args) == 1:
log_file = args[0]
if log_file:
debugger.HandleCommand('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
result.PutCString ('error: invalid log file path')
result.PutCString (usage)
def parse_time_log(debugger, command, result, dict):
# Any commands whose names might be followed by more valid C identifier
# characters must be listed here
command_args = shlex.split(command)
parse_time_log_args (command_args)
def parse_time_log_args(command_args):
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.'''
parser = optparse.OptionParser(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:
(options, args) = parser.parse_args(command_args)
except:
return
for log_file in args:
parse_log_file (log_file, options)
def parse_log_file(file, options):
'''Parse a log file that was contains timestamps. These logs are typically
generated using:
(lldb) log enable --threadsafe --timestamp --file <FILE> ....
This log file will contain timestamps and this fucntion will then normalize
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
for GDB remote commands to make a send/receive round trip. This can be
handy when trying to figure out why some operation in the debugger is taking
a long time during a preset set of debugger commands.'''
print '#----------------------------------------------------------------------'
print "# Log file: '%s'" % file
print '#----------------------------------------------------------------------'
timestamp_regex = re.compile('(\s*)([1-9][0-9]+\.[0-9]+)([^0-9].*)$')
base_time = 0.0
last_time = 0.0
file = open(file)
lines = file.read().splitlines()
for line in lines:
match = timestamp_regex.match (line)
if match:
curr_time = float (match.group(2))
delta = 0.0
if base_time:
delta = curr_time - last_time
else:
base_time = curr_time
print '%s%.6f %+.6f%s' % (match.group(1), curr_time - base_time, delta, match.group(3))
last_time = curr_time
else:
print line
if __name__ == '__main__':
import sys
parse_time_log_args (sys.argv[1:])
else:
import lldb
if lldb.debugger:
# This initializer is being run from LLDB in the embedded command interpreter
# Add any commands contained in this module to LLDB
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'

View File

@@ -0,0 +1,171 @@
# This implements the "diagnose-nsstring" command, usually installed in the debug session like
# command script import lldb.diagnose
# 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
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):
"""
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 {\
char* buffer;\
signed long length;\
signed long capacity;\
unsigned int hasGap:1;\
unsigned int isFixedCapacity:1;\
unsigned int isExternalMutable:1;\
unsigned int capacityProvidedExternally:1;\n\
#if __LP64__\n\
unsigned long desiredCapacity:60;\n\
#else\n\
unsigned long desiredCapacity:28;\n\
#endif\n\
void* contentsAllocator;\
};\
\
struct $__lldb__CFString {\
void* _cfisa;\
uint8_t _cfinfo[4];\
uint32_t _rc;\
union {\
struct __inline1 {\
signed long length;\
} inline1;\
struct __notInlineImmutable1 {\
char* buffer;\
signed long length;\
void* contentsDeallocator;\
} notInlineImmutable1;\
struct __notInlineImmutable2 {\
char* buffer;\
void* contentsDeallocator;\
} notInlineImmutable2;\
struct $__lldb__notInlineMutable notInlineMutable;\
} variants;\
};\
"
expression = expression + "*(($__lldb__CFString*) %d)" % nsstring_address
# print expression
dumped = target.EvaluateExpression(expression,options)
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")
explicit_length_offset = 0
if not has_null and has_explicit_length and not is_special:
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)
def __lldb_init_module(debugger, internal_dict):
debugger.HandleCommand("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 = None

View File

@@ -0,0 +1,270 @@
# This implements the "diagnose-unwind" command, usually installed
# in the debug session like
# command script import lldb.diagnose
# it is used when lldb's backtrace fails -- it collects and prints
# information about the stack frames, and tries an alternate unwind
# algorithm, that will help to understand why lldb's unwind algorithm
# did not succeed.
import optparse
import lldb
import re
import shlex
# Print the frame number, pc, frame pointer, module UUID and function name
# 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)
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.
# 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.
def simple_backtrace(debugger):
target = debugger.GetSelectedTarget()
process = target.GetProcess()
cur_thread = process.GetSelectedThread()
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 initial_fp == lldb.LLDB_INVALID_ADDRESS and target.triple[0:3] == "arm":
for reggroup in cur_thread.GetFrameAtIndex(1).registers:
if reggroup.GetName() == "General Purpose Registers":
for reg in reggroup:
if reg.GetName() == "r7":
initial_fp = int (reg.GetValue(), 16)
module_list = []
address_list = [cur_thread.GetFrameAtIndex(0).GetPC()]
this_module = backtrace_print_frame (target, 0, cur_thread.GetFrameAtIndex(0).GetPC(), initial_fp)
print_stack_frame (process, initial_fp)
print ""
if this_module != None:
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 != 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):
if fp == 0 or fp == lldb.LLDB_INVALID_ADDRESS or fp == 1:
return
addr_size = process.GetAddressByteSize()
addr = fp - (2 * addr_size)
i = 0
outline = "Stack frame from $fp-%d: " % (2 * addr_size)
error = lldb.SBError()
try:
while i < 5 and error.Success():
address = process.ReadPointerFromMemory(addr + (i * addr_size), error)
outline += " 0x%x" % address
i += 1
print outline
except Exception:
return
def diagnose_unwind(debugger, command, result, dict):
"""
Gather diagnostic information to help debug incorrect unwind (backtrace)
behavior in lldb. When there is a backtrace that doesn't look
correct, run this command with the correct thread selected and a
large amount of diagnostic information will be printed, it is likely
to be helpful when reporting the problem.
"""
command_args = shlex.split(command)
parser = create_diagnose_unwind_options()
try:
(options, args) = parser.parse_args(command_args)
except:
return
target = debugger.GetSelectedTarget()
if target:
process = target.GetProcess()
if process:
thread = process.GetSelectedThread()
if thread:
lldb_versions_match = re.search(r'[lL][lL][dD][bB]-(\d+)([.](\d+))?([.](\d+))?', debugger.GetVersionString())
lldb_version = 0
lldb_minor = 0
if len(lldb_versions_match.groups()) >= 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 = []
addresses_seen = []
print 'LLDB version %s' % debugger.GetVersionString()
print 'Unwind diagnostics for thread %d' % thread.GetIndexID()
print ""
print "============================================================================================="
print ""
print "OS plugin setting:"
debugger.HandleCommand("settings show target.process.python-os-plugin-path")
print ""
print "Live register context:"
thread.SetSelectedFrame(0)
debugger.HandleCommand("register read")
print ""
print "============================================================================================="
print ""
print "lldb's unwind algorithm:"
print ""
frame_num = 0
for frame in thread.frames:
if not frame.IsInlined():
this_module = backtrace_print_frame (target, frame_num, frame.GetPC(), frame.GetFP())
print_stack_frame (process, frame.GetFP())
print ""
if this_module != None:
modules_seen.append (this_module)
addresses_seen.append (frame.GetPC())
frame_num = frame_num + 1
print ""
print "============================================================================================="
print ""
print "Simple stack walk algorithm:"
print ""
(module_list, address_list) = simple_backtrace(debugger)
if module_list and module_list != None:
modules_seen += module_list
if address_list and address_list != None:
addresses_seen = set(addresses_seen)
addresses_seen.update(set(address_list))
print ""
print "============================================================================================="
print ""
print "Modules seen in stack walks:"
print ""
modules_already_seen = set()
for module in modules_seen:
if module != None and module.GetFileSpec().GetFilename() != None:
if not module.GetFileSpec().GetFilename() in modules_already_seen:
debugger.HandleCommand('image list %s' % module.GetFileSpec().GetFilename())
modules_already_seen.add(module.GetFileSpec().GetFilename())
print ""
print "============================================================================================="
print ""
print "Disassembly ofaddresses seen in stack walks:"
print ""
additional_addresses_to_disassemble = addresses_seen
for frame in thread.frames:
if not frame.IsInlined():
print "--------------------------------------------------------------------------------------"
print ""
print "Disassembly of %s, frame %d, address 0x%x" % (frame.GetFunctionName(), frame.GetFrameID(), frame.GetPC())
print ""
if target.triple[0:6] == "x86_64" or target.triple[0:4] == "i386":
debugger.HandleCommand('disassemble -F att -a 0x%x' % 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):
print "--------------------------------------------------------------------------------------"
print ""
print "Disassembly of 0x%x" % address
print ""
if target.triple[0:6] == "x86_64" or target.triple[0:4] == "i386":
debugger.HandleCommand('disassemble -F att -a 0x%x' % address)
else:
debugger.HandleCommand('disassemble -a 0x%x' % address)
print ""
print "============================================================================================="
print ""
additional_addresses_to_show_unwind = addresses_seen
for frame in thread.frames:
if not frame.IsInlined():
print "--------------------------------------------------------------------------------------"
print ""
print "Unwind instructions for %s, frame %d" % (frame.GetFunctionName(), frame.GetFrameID())
print ""
debugger.HandleCommand('image show-unwind -a "0x%x"' % 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)
def create_diagnose_unwind_options():
usage = "usage: %prog"
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)
return parser
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.'

View File

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

View File

@@ -0,0 +1,168 @@
#!/usr/bin/python
import argparse, datetime, re, subprocess, sys, time
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('--bytes', 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:]
arg_ns = parser.parse_args(arguments)
def AddLLDBToSysPathOnMacOSX():
def GetLLDBFrameworkPath():
lldb_path = subprocess.check_output(["xcrun", "-find", "lldb"])
re_result = re.match("(.*)/Developer/usr/bin/lldb", lldb_path)
if re_result == None:
return None
xcode_contents_path = re_result.group(1)
return xcode_contents_path + "/SharedFrameworks/LLDB.framework"
lldb_framework_path = GetLLDBFrameworkPath()
if lldb_framework_path == None:
print "Couldn't find LLDB.framework"
sys.exit(-1)
sys.path.append(lldb_framework_path + "/Resources/Python")
if arg_ns.lldb == None:
AddLLDBToSysPathOnMacOSX()
else:
sys.path.append(arg_ns.lldb + "/Resources/Python")
import lldb
debugger = lldb.SBDebugger.Create()
if debugger.IsValid() == False:
print "Couldn't create an SBDebugger"
sys.exit(-1)
target = debugger.CreateTargetWithFileAndArch(None, arg_ns.arch)
if target.IsValid() == False:
print "Couldn't create an SBTarget for architecture " + arg_ns.arch
sys.exit(-1)
def ResetLogFile(log_file):
if log_file != sys.stdout:
log_file.seek(0)
def PrintByteArray(log_file, byte_array):
for byte in byte_array:
print >>log_file, hex(byte) + " ",
print >>log_file
class SequentialInstructionProvider:
def __init__(self, byte_width, log_file, start=0, skip=1):
self.m_byte_width = byte_width
self.m_log_file = log_file
self.m_start = start
self.m_skip = skip
self.m_value = start
self.m_last = (1 << (byte_width * 8)) - 1
def PrintCurrentState(self, ret):
ResetLogFile(self.m_log_file)
print >>self.m_log_file, self.m_value
PrintByteArray(self.m_log_file, ret)
def GetNextInstruction(self):
if self.m_value > self.m_last:
return None
ret = bytearray(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
self.PrintCurrentState(ret)
self.m_value += self.m_skip
return ret
def GetNumInstructions(self):
return (self.m_last - self.m_start) / self.m_skip
def __iter__(self):
return self
def next(self):
ret = self.GetNextInstruction()
if ret == None:
raise StopIteration
return ret
class RandomInstructionProvider:
def __init__(self, byte_width, log_file):
self.m_byte_width = byte_width
self.m_log_file = log_file
self.m_random_file = open("/dev/random", 'r')
def PrintCurrentState(self, ret):
ResetLogFile(self.m_log_file)
PrintByteArray(self.m_log_file, ret)
def GetNextInstruction(self):
ret = bytearray(self.m_byte_width)
for i in range(self.m_byte_width):
ret[i] = self.m_random_file.read(1)
self.PrintCurrentState(ret)
return ret
def __iter__(self):
return self
def next(self):
ret = self.GetNextInstruction()
if ret == None:
raise StopIteration
return ret
log_file = None
def GetProviderWithArguments(args):
global log_file
if args.log != None:
log_file = open(args.log, 'w')
else:
log_file = sys.stdout
instruction_provider = None
if args.random == True:
instruction_provider = RandomInstructionProvider(args.bytes, log_file)
else:
start = 0
skip = 1
if args.start != None:
start = args.start
if args.skip != None:
skip = args.skip
instruction_provider = SequentialInstructionProvider(args.bytes, log_file, start, skip)
return instruction_provider
instruction_provider = GetProviderWithArguments(arg_ns)
fake_address = lldb.SBAddress()
actually_time = arg_ns.time and not arg_ns.random
if actually_time:
num_instructions_logged = 0
total_num_instructions = instruction_provider.GetNumInstructions()
start_time = time.time()
for inst_bytes in instruction_provider:
if actually_time:
if (num_instructions_logged != 0) and (num_instructions_logged % 100000 == 0):
curr_time = time.time()
elapsed_time = curr_time - start_time
remaining_time = float(total_num_instructions - num_instructions_logged) * (float(elapsed_time) / float(num_instructions_logged))
print str(datetime.timedelta(seconds=remaining_time))
num_instructions_logged = num_instructions_logged + 1
inst_list = target.GetInstructions(fake_address, inst_bytes)
if not inst_list.IsValid():
print >>log_file, "Invalid instruction list"
continue
inst = inst_list.GetInstructionAtIndex(0)
if not inst.IsValid():
print >>log_file, "Invalid instruction"
continue
instr_output_stream = lldb.SBStream()
inst.GetDescription(instr_output_stream)
print >>log_file, instr_output_stream.GetData()

View File

@@ -0,0 +1,119 @@
#!/usr/bin/python
#----------------------------------------------------------------------
# Be sure to add the python path that points to the LLDB shared library.
# On MacOSX csh, tcsh:
# setenv PYTHONPATH /Developer/Library/PrivateFrameworks/LLDB.framework/Resources/Python
# On MacOSX sh, bash:
# export PYTHONPATH=/Developer/Library/PrivateFrameworks/LLDB.framework/Resources/Python
#----------------------------------------------------------------------
import lldb
import os
import sys
def disassemble_instructions (insts):
for i in insts:
print i
def usage():
print "Usage: disasm.py [-n name] executable-image"
print " By default, it breaks at and disassembles the 'main' function."
sys.exit(0)
if len(sys.argv) == 2:
fname = 'main'
exe = sys.argv[1]
elif len(sys.argv) == 4:
if sys.argv[1] != '-n':
usage()
else:
fname = sys.argv[2]
exe = sys.argv[3]
else:
usage()
# Create a new debugger instance
debugger = lldb.SBDebugger.Create()
# 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.
debugger.SetAsync (False)
# Create a target from a file and arch
print "Creating a target for '%s'" % exe
target = debugger.CreateTargetWithFileAndArch (exe, lldb.LLDB_ARCH_DEFAULT)
if target:
# If the target is valid set a breakpoint at main
main_bp = target.BreakpointCreateByName (fname, target.GetExecutable().GetFilename());
print main_bp
# Launch the process. Since we specified synchronous mode, we won't return
# from this function until we hit the breakpoint at main
process = target.LaunchSimple (None, None, os.getcwd())
# Make sure the launch went ok
if process:
# Print some simple process info
state = process.GetState ()
print process
if state == lldb.eStateStopped:
# Get the first thread
thread = process.GetThreadAtIndex (0)
if thread:
# Print some simple thread info
print thread
# Get the first frame
frame = thread.GetFrameAtIndex (0)
if frame:
# Print some simple frame info
print frame
function = frame.GetFunction()
# See if we have debug info (a function)
if function:
# We do have a function, print some info for the function
print function
# Now get all instructions for this function and print them
insts = function.GetInstructions(target)
disassemble_instructions (insts)
else:
# See if we have a symbol in the symbol table for where we stopped
symbol = frame.GetSymbol();
if symbol:
# We do have a symbol, print some info for the symbol
print symbol
# Now get all instructions for this symbol and print them
insts = symbol.GetInstructions(target)
disassemble_instructions (insts)
registerList = frame.GetRegisters()
print "Frame registers (size of register set = %d):" % registerList.GetSize()
for value in registerList:
#print value
print "%s (number of children = %d):" % (value.GetName(), value.GetNumChildren())
for child in value:
print "Name: ", child.GetName(), " Value: ", child.GetValue()
print "Hit the breakpoint at main, enter to continue and wait for program to exit or 'Ctrl-D'/'quit' to terminate the program"
next = sys.stdin.readline()
if not next or next.rstrip('\n') == 'quit':
print "Terminating the inferior process..."
process.Kill()
else:
# Now continue to the program exit
process.Continue()
# When we return from the above function we will hopefully be at the
# program exit. Print out some process info
print process
elif state == lldb.eStateExited:
print "Didn't hit the breakpoint at main, program has exited..."
else:
print "Unexpected process state: %s, killing process..." % debugger.StateAsCString (state)
process.Kill()
lldb.SBDebugger.Terminate()

View File

@@ -0,0 +1,221 @@
#! /usr/bin/env python
import string
import struct
import sys
class FileExtract:
'''Decode binary data from a file'''
def __init__(self, f, b = '='):
'''Initialize with an open binary file and optional byte order'''
self.file = f
self.byte_order = b
self.offsets = list()
def set_byte_order(self, b):
'''Set the byte order, valid values are "big", "little", "swap", "native", "<", ">", "@", "="'''
if b == 'big':
self.byte_order = '>'
elif b == 'little':
self.byte_order = '<'
elif b == 'swap':
# swap what ever the current byte order is
self.byte_order = swap_unpack_char()
elif b == 'native':
self.byte_order = '='
elif b == '<' or b == '>' or b == '@' or b == '=':
self.byte_order = b
else:
print "error: invalid byte order specified: '%s'" % b
def is_in_memory(self):
return False
def seek(self, offset, whence = 0):
if self.file:
return self.file.seek(offset, whence)
raise ValueError
def tell(self):
if self.file:
return self.file.tell()
raise ValueError
def read_size (self, byte_size):
s = self.file.read(byte_size)
if len(s) != byte_size:
return None
return s
def push_offset_and_seek(self, offset):
'''Push the current file offset and seek to "offset"'''
self.offsets.append(self.file.tell())
self.file.seek(offset, 0)
def pop_offset_and_seek(self):
'''Pop a previously pushed file offset, or do nothing if there were no previously pushed offsets'''
if len(self.offsets) > 0:
self.file.seek(self.offsets.pop())
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'''
s = self.read_size(1)
if s:
v, = struct.unpack(self.byte_order + 'b', s)
return v
else:
return fail_value
def get_uint8(self, fail_value=0):
'''Extract a single uint8_t from the binary file at the current file position, returns a single integer'''
s = self.read_size(1)
if s:
v, = struct.unpack(self.byte_order + 'B', s)
return v
else:
return fail_value
def get_sint16(self, fail_value=0):
'''Extract a single int16_t from the binary file at the current file position, returns a single integer'''
s = self.read_size(2)
if s:
v, = struct.unpack(self.byte_order + 'h', s)
return v
else:
return fail_value
def get_uint16(self, fail_value=0):
'''Extract a single uint16_t from the binary file at the current file position, returns a single integer'''
s = self.read_size(2)
if s:
v, = struct.unpack(self.byte_order + 'H', s)
return v
else:
return fail_value
def get_sint32(self, fail_value=0):
'''Extract a single int32_t from the binary file at the current file position, returns a single integer'''
s = self.read_size(4)
if s:
v, = struct.unpack(self.byte_order + 'i', s)
return v
else:
return fail_value
def get_uint32(self, fail_value=0):
'''Extract a single uint32_t from the binary file at the current file position, returns a single integer'''
s = self.read_size(4)
if s:
v, = struct.unpack(self.byte_order + 'I', s)
return v
else:
return fail_value
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'''
s = self.read_size(8)
if s:
v, = struct.unpack(self.byte_order + 'q', s)
return v
else:
return fail_value
def get_uint64(self, fail_value=0):
'''Extract a single uint64_t from the binary file at the current file position, returns a single integer'''
s = self.read_size(8)
if s:
v, = struct.unpack(self.byte_order + 'Q', s)
return v
else:
return fail_value
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'''
s = self.read_size(n)
if s:
cstr, = struct.unpack(self.byte_order + ("%i" % n) + 's', s)
# Strip trialing NULLs
cstr = string.strip(cstr, "\0")
if isprint_only_with_space_padding:
for c in cstr:
if c in string.printable or ord(c) == 0:
continue
return fail_value
return cstr
else:
return fail_value
def get_c_string(self):
'''Extract a single NULL terminated C string from the binary file at the current file position, returns a single C string'''
cstr = ''
byte = self.get_uint8()
while byte != 0:
cstr += "%c" % byte
byte = self.get_uint8()
return cstr
def get_n_sint8(self, n, fail_value=0):
'''Extract "n" int8_t integers from the binary file at the current file position, returns a list of integers'''
s = self.read_size(n)
if s:
return struct.unpack(self.byte_order + ("%u" % n) + 'b', s)
else:
return (fail_value,) * n
def get_n_uint8(self, n, fail_value=0):
'''Extract "n" uint8_t integers from the binary file at the current file position, returns a list of integers'''
s = self.read_size(n)
if s:
return struct.unpack(self.byte_order + ("%u" % n) + 'B', s)
else:
return (fail_value,) * n
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'''
s = self.read_size(2*n)
if s:
return struct.unpack(self.byte_order + ("%u" % n) + 'h', s)
else:
return (fail_value,) * n
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'''
s = self.read_size(2*n)
if s:
return struct.unpack(self.byte_order + ("%u" % n) + 'H', s)
else:
return (fail_value,) * n
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'''
s = self.read_size(4*n)
if s:
return struct.unpack(self.byte_order + ("%u" % n) + 'i', s)
else:
return (fail_value,) * n
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'''
s = self.read_size(4*n)
if s:
return struct.unpack(self.byte_order + ("%u" % n) + 'I', s)
else:
return (fail_value,) * n
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'''
s = self.read_size(8*n)
if s:
return struct.unpack(self.byte_order + ("%u" % n) + 'q', s)
else:
return (fail_value,) * n
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'''
s = self.read_size(8*n)
if s:
return struct.unpack(self.byte_order + ("%u" % n) + 'Q', s)
else:
return (fail_value,) * n

View File

@@ -0,0 +1,24 @@
import lldb
def disassemble(debugger, command, result, dict):
if lldb.frame.function:
instructions = lldb.frame.function.instructions
start_addr = lldb.frame.function.addr.load_addr
name = lldb.frame.function.name
elif lldb.frame.symbol:
instructions = lldb.frame.symbol.instructions
start_addr = lldb.frame.symbol.addr.load_addr
name = lldb.frame.symbol.name
for inst in instructions:
inst_addr = inst.addr.load_addr
inst_offset = inst_addr - start_addr
comment = inst.comment
if comment:
print "<%s + %-4u> 0x%x %8s %s ; %s" % (name, inst_offset, inst_addr, inst.mnemonic, inst.operands, comment)
else:
print "<%s + %-4u> 0x%x %8s %s" % (name, inst_offset, inst_addr, inst.mnemonic, inst.operands)
# Install the command when the module gets imported
lldb.debugger.HandleCommand('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

@@ -0,0 +1,72 @@
#!/usr/bin/python
#----------------------------------------------------------------------
# For the shells csh, tcsh:
# ( setenv PYTHONPATH /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python ; ./globals.py <path> [<path> ...])
#
# For the shells sh, bash:
# PYTHONPATH=/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python ./globals.py <path> [<path> ...]
#----------------------------------------------------------------------
import lldb
import commands
import optparse
import os
import shlex
import sys
def get_globals(raw_path, options):
error = lldb.SBError()
# Resolve the path if needed
path = os.path.expanduser(raw_path)
# Create a target using path + options
target = lldb.debugger.CreateTarget(path, options.arch, options.platform, False, error)
if target:
# Get the executable module
module = target.module[target.executable.basename]
if module:
# Keep track of which variables we have already looked up
global_names = list()
# Iterate through all symbols in the symbol table and watch for any DATA symbols
for symbol in module.symbols:
if symbol.type == lldb.eSymbolTypeData:
# The symbol is a DATA symbol, lets try and find all global variables
# that match this name and print them
global_name = symbol.name
# Make sure we don't lookup the same variable twice
if global_name not in global_names:
global_names.append(global_name)
# Find all global variables by name
global_variable_list = module.FindGlobalVariables (target, global_name, lldb.UINT32_MAX)
if global_variable_list:
# Print results for anything that matched
for global_variable in global_variable_list:
print 'name = %s' % global_variable.name # returns the global variable name as a string
print 'value = %s' % global_variable.value # Returns the variable value as a string
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
print 'file_addr = 0x%x' % global_variable.addr.file_addr # Returns the file virtual address for this global
print 'location = %s' % global_variable.location # returns the global variable value as a string
print 'size = %s' % global_variable.size # Returns the size in bytes of this global variable
print
def globals(command_args):
'''Extract all globals from any arguments which must be paths to object files.'''
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).'''
parser = optparse.OptionParser(description=description, prog='globals',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:
(options, args) = parser.parse_args(command_args)
except:
return
for path in args:
get_globals (path, options)
if __name__ == '__main__':
lldb.debugger = lldb.SBDebugger.Create()
globals (sys.argv[1:])

View File

@@ -0,0 +1,173 @@
import lldb, re
def parse_linespec (linespec, frame, result):
"""Handles a subset of GDB-style linespecs. Specifically:
number - A line in the current file
+offset - The line /offset/ lines after this line
-offset - The line /offset/ lines before this line
filename:number - Line /number/ in file /filename/
function - The start of /function/
*address - The pointer target of /address/, which must be a literal (but see `` in LLDB)
We explicitly do not handle filename:function because it is ambiguous in Objective-C.
This function returns a list of addresses."""
breakpoint = None
target = frame.GetThread().GetProcess().GetTarget()
matched = False
if (not matched):
mo = re.match("^([0-9]+)$", linespec)
if (mo != None):
matched = True
#print "Matched <linenum>"
line_number = int(mo.group(1))
line_entry = frame.GetLineEntry()
if not line_entry.IsValid():
result.AppendMessage("Specified a line in the current file, but the current frame doesn't have line table information.")
return
breakpoint = target.BreakpointCreateByLocation (line_entry.GetFileSpec(), line_number)
if (not matched):
mo = re.match("^\+([0-9]+)$", linespec)
if (mo != None):
matched = True
#print "Matched +<count>"
line_number = int(mo.group(1))
line_entry = frame.GetLineEntry()
if not line_entry.IsValid():
result.AppendMessage("Specified a line in the current file, but the current frame doesn't have line table information.")
return
breakpoint = target.BreakpointCreateByLocation(line_entry.GetFileSpec(), (line_entry.GetLine() + line_number))
if (not matched):
mo = re.match("^\-([0-9]+)$", linespec)
if (mo != None):
matched = True
#print "Matched -<count>"
line_number = int(mo.group(1))
line_entry = frame.GetLineEntry()
if not line_entry.IsValid():
result.AppendMessage("Specified a line in the current file, but the current frame doesn't have line table information.")
return
breakpoint = target.BreakpointCreateByLocation(line_entry.GetFileSpec(), (line_entry.GetLine() - line_number))
if (not matched):
mo = re.match("^(.*):([0-9]+)$", linespec)
if (mo != None):
matched = True
#print "Matched <filename>:<linenum>"
file_name = mo.group(1)
line_number = int(mo.group(2))
breakpoint = target.BreakpointCreateByLocation(file_name, line_number)
if (not matched):
mo = re.match("\*((0x)?([0-9a-f]+))$", linespec)
if (mo != None):
matched = True
#print "Matched <address-expression>"
address = long(mo.group(1), base=0)
breakpoint = target.BreakpointCreateByAddress(address)
if (not matched):
#print "Trying <function-name>"
breakpoint = target.BreakpointCreateByName(linespec)
num_locations = breakpoint.GetNumLocations()
if (num_locations == 0):
result.AppendMessage("The line specification provided doesn't resolve to any addresses.")
addr_list = []
for location_index in range(num_locations):
location = breakpoint.GetLocationAtIndex(location_index)
addr_list.append(location.GetAddress())
target.BreakpointDelete(breakpoint.GetID())
return addr_list
def usage_string():
return """ Sets the program counter to a specific address.
Syntax: jump <linespec> [<location-id>]
Command Options Usage:
jump <linenum>
jump +<count>
jump -<count>
jump <filename>:<linenum>
jump <function-name>
jump *<address-expression>
<location-id> serves to disambiguate when multiple locations could be meant."""
def jump (debugger, command, result, internal_dict):
if (command == ""):
result.AppendMessage(usage_string())
args = command.split()
if not debugger.IsValid():
result.AppendMessage("Invalid debugger!")
return
target = debugger.GetSelectedTarget()
if not target.IsValid():
result.AppendMessage("jump requires a valid target.")
return
process = target.GetProcess()
if not process.IsValid():
result.AppendMessage("jump requires a valid process.")
return
thread = process.GetSelectedThread()
if not thread.IsValid():
result.AppendMessage("jump requires a valid thread.")
return
frame = thread.GetSelectedFrame()
if not frame.IsValid():
result.AppendMessage("jump requires a valid frame.")
return
addresses = parse_linespec(args[0], frame, result)
stream = lldb.SBStream()
if len(addresses) == 0:
return
desired_address = addresses[0]
if len(addresses) > 1:
if len(args) == 2:
desired_index = int(args[1])
if (desired_index >= 0) and (desired_index < len(addresses)):
desired_address = addresses[desired_index]
else:
result.AppendMessage("Desired index " + args[1] + " is not one of the options.")
return
else:
index = 0
result.AppendMessage("The specified location resolves to multiple targets.");
for address in addresses:
stream.Clear()
address.GetDescription(stream)
result.AppendMessage(" Location ID " + str(index) + ": " + stream.GetData())
index = index + 1
result.AppendMessage("Please type 'jump " + command + " <location-id>' to choose one.")
return
frame.SetPC(desired_address.GetLoadAddress(target))
if lldb.debugger:
# Module is being run inside the LLDB interpreter
jump.__doc__ = usage_string()
lldb.debugger.HandleCommand('command script add -f jump.jump jump')
print 'The "jump" command has been installed, type "help jump" or "jump <ENTER>" for detailed help.'

View File

@@ -0,0 +1,59 @@
#!/usr/bin/python
import lldb
import optparse
import shlex
import string
import sys
def create_dump_module_line_tables_options ():
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.'''
parser = optparse.OptionParser(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
def dump_module_line_tables(debugger, command, result, dict):
'''Dumps all line tables from all compile units for any modules specified as arguments.'''
command_args = shlex.split(command)
parser = create_dump_module_line_tables_options ()
try:
(options, args) = parser.parse_args(command_args)
except:
return
if command_args:
target = debugger.GetSelectedTarget()
lldb.target = target
for module_name in command_args:
result.PutCString('Searching for module "%s"' % (module_name,))
module_fspec = lldb.SBFileSpec (module_name, False)
module = target.FindModule (module_fspec);
if module:
for cu_idx in range (module.GetNumCompileUnits()):
cu = module.GetCompileUnitAtIndex(cu_idx)
result.PutCString("\n%s:" % (cu.file))
for line_idx in range(cu.GetNumLineEntries()):
line_entry = cu.GetLineEntryAtIndex(line_idx)
start_file_addr = line_entry.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 options.verbose:
if start_file_addr != end_file_addr:
result.PutCString('[%#x - %#x): %s' % (start_file_addr, end_file_addr, line_entry))
else:
if start_file_addr == end_file_addr:
result.PutCString('%#x: END' % (start_file_addr))
else:
result.PutCString('%#x: %s' % (start_file_addr, line_entry))
if start_file_addr == end_file_addr:
result.Printf("\n")
else:
result.PutCString ("no module for '%s'" % module)
else:
result.PutCString ("error: invalid target")
parser = create_dump_module_line_tables_options ()
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__)
print 'Installed "dump_module_line_tables" command'

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,181 @@
#!/usr/bin/python
#----------------------------------------------------------------------
# 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
# import it with the full path using the "command script import"
# command
# (lldb) command script import /path/to/cmdtemplate.py
#----------------------------------------------------------------------
import commands
import platform
import os
import re
import sys
try:
# Just try for LLDB in case PYTHONPATH is already correctly setup
import lldb
except ImportError:
lldb_python_dirs = list()
# lldb is not in the PYTHONPATH, try some defaults for the current platform
platform_system = platform.system()
if platform_system == 'Darwin':
# On Darwin, try the currently selected Xcode directory
xcode_dir = commands.getoutput("xcode-select --print-path")
if xcode_dir:
lldb_python_dirs.append(os.path.realpath(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
for lldb_python_dir in lldb_python_dirs:
if os.path.exists(lldb_python_dir):
if not (sys.path.__contains__(lldb_python_dir)):
sys.path.append(lldb_python_dir)
try:
import lldb
except ImportError:
pass
else:
print 'imported lldb from: "%s"' % (lldb_python_dir)
success = True
break
if not success:
print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
sys.exit(1)
import commands
import optparse
import shlex
import string
import struct
import time
def append_data_callback(option, opt_str, value, parser):
if opt_str == "--uint8":
int8 = int(value, 0)
parser.values.data += struct.pack('1B',int8)
if opt_str == "--uint16":
int16 = int(value, 0)
parser.values.data += struct.pack('1H',int16)
if opt_str == "--uint32":
int32 = int(value, 0)
parser.values.data += struct.pack('1I',int32)
if opt_str == "--uint64":
int64 = int(value, 0)
parser.values.data += struct.pack('1Q',int64)
if opt_str == "--int8":
int8 = int(value, 0)
parser.values.data += struct.pack('1b',int8)
if opt_str == "--int16":
int16 = int(value, 0)
parser.values.data += struct.pack('1h',int16)
if opt_str == "--int32":
int32 = int(value, 0)
parser.values.data += struct.pack('1i',int32)
if opt_str == "--int64":
int64 = int(value, 0)
parser.values.data += struct.pack('1q',int64)
def create_memfind_options():
usage = "usage: %prog [options] STARTADDR [ENDADDR]"
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
can be specified multiple times to look for longer streams of data.
'''
parser = optparse.OptionParser(description=description, prog='memfind',usage=usage)
parser.add_option('-s', '--size', type='int', metavar='BYTESIZE', 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
def memfind_command (debugger, command, result, dict):
# Use the Shell Lexer to properly parse up command options just like a
# shell would
command_args = shlex.split(command)
parser = create_memfind_options()
(options, args) = parser.parse_args(command_args)
# try:
# (options, args) = parser.parse_args(command_args)
# except:
# # 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)
# 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
# return
memfind (debugger.GetSelectedTarget(), options, args, result)
def print_error(str, show_usage, result):
print >>result, str
if show_usage:
print >>result, create_memfind_options().format_help()
def memfind (target, options, args, result):
num_args = len(args)
start_addr = 0
if num_args == 1:
if options.size > 0:
print_error ("error: --size must be specified if there is no ENDADDR argument", True, result)
return
start_addr = int(args[0], 0)
elif num_args == 2:
if options.size != 0:
print_error ("error: --size can't be specified with an ENDADDR argument", True, result)
return
start_addr = int(args[0], 0)
end_addr = int(args[1], 0)
if start_addr >= end_addr:
print_error ("error: inavlid memory range [%#x - %#x)" % (start_addr, end_addr), True, result)
return
options.size = end_addr - start_addr
else:
print_error ("error: memfind takes 1 or 2 arguments", True, result)
return
if not options.data:
print >>result, 'error: no data specified to search for'
return
if not target:
print >>result, 'error: invalid target'
return
process = target.process
if not process:
print >>result, 'error: invalid process'
return
error = lldb.SBError()
bytes = process.ReadMemory (start_addr, options.size, error)
if error.Success():
num_matches = 0
print >>result, "Searching memory range [%#x - %#x) for" % (start_addr, end_addr),
for byte in options.data:
print >>result, '%2.2x' % ord(byte),
print >>result
match_index = string.find(bytes, options.data)
while match_index != -1:
num_matches = num_matches + 1
print >>result, '%#x: %#x + %u' % (start_addr + match_index, start_addr, match_index)
match_index = string.find(bytes, options.data, match_index + 1)
if num_matches == 0:
print >>result, "error: no matches found"
else:
print >>result, 'error: %s' % (error.GetCString())
if __name__ == '__main__':
print 'error: this script is designed to be used within the embedded script interpreter in LLDB'
elif getattr(lldb, 'debugger', None):
memfind_command.__doc__ = create_memfind_options().format_help()
lldb.debugger.HandleCommand('command script add -f memory.memfind_command memfind')
print '"memfind" command installed, use the "--help" option for detailed help'

View File

@@ -0,0 +1,104 @@
#!/usr/bin/python
import lldb
import struct
class OperatingSystemPlugIn(object):
"""Class that provides data for an instance of a LLDB 'OperatingSystemPython' plug-in class"""
def __init__(self, process):
'''Initialization needs a valid.SBProcess object.
This plug-in will get created after a live process is valid and has stopped for the
first time.'''
self.process = None
self.registers = None
self.threads = None
if type(process) is lldb.SBProcess and process.IsValid():
self.process = process
self.threads = None # Will be an dictionary containing info for each thread
def get_target(self):
# 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
# correct thing to use for this plug-in.
return self.process.target
def create_thread(self, tid, context):
if tid == 0x444444444:
thread_info = { 'tid' : tid, 'name' : 'four' , 'queue' : 'queue4', 'state' : 'stopped', 'stop_reason' : 'none' }
self.threads.append(thread_info)
return thread_info
return None
def get_thread_info(self):
if not self.threads:
# The sample dictionary below shows the values that can be returned for a thread
# tid => thread ID (mandatory)
# name => thread name (optional key/value pair)
# queue => thread dispatch queue name (optional key/value pair)
# state => thred state (mandatory, set to 'stopped' for now)
# stop_reason => thread stop reason. (mandatory, usually set to 'none')
# Possible values include:
# 'breakpoint' if the thread is stopped at a breakpoint
# 'none' thread is just stopped because the process is stopped
# 'trace' the thread just single stepped
# The usual value for this while threads are in memory is 'none'
# register_data_addr => the address of the register data in memory (optional key/value pair)
# 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
# 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.
self.threads = [
{ 'tid' : 0x111111111, 'name' : 'one' , '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
def get_register_info(self):
if self.registers == None:
self.registers = dict()
triple = self.process.target.triple
if triple:
arch = triple.split('-')[0]
if arch == 'x86_64':
self.registers['sets'] = ['GPR', 'FPU', 'EXC']
self.registers['registers'] = [
{ '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':'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':'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':'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':'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':'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':'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':'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':'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':'cs' , 'bitsize' : 64, 'offset' : 144, '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 },
]
return self.registers
def get_register_data(self, tid):
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);
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);
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);
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);
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 None

View File

@@ -0,0 +1,335 @@
#!/usr/bin/python
#----------------------------------------------------------------------
# Be sure to add the python path that points to the LLDB shared library.
# On MacOSX csh, tcsh:
# setenv PYTHONPATH /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
# On MacOSX sh, bash:
# export PYTHONPATH=/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
#----------------------------------------------------------------------
import commands
import optparse
import os
import platform
import re
import resource
import sys
import time
import types
#----------------------------------------------------------------------
# Code that auto imports LLDB
#----------------------------------------------------------------------
try:
# Just try for LLDB in case PYTHONPATH is already correctly setup
import lldb
except ImportError:
lldb_python_dirs = list()
# lldb is not in the PYTHONPATH, try some defaults for the current platform
platform_system = platform.system()
if platform_system == 'Darwin':
# On Darwin, try the currently selected Xcode directory
xcode_dir = commands.getoutput("xcode-select --print-path")
if xcode_dir:
lldb_python_dirs.append(os.path.realpath(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
for lldb_python_dir in lldb_python_dirs:
if os.path.exists(lldb_python_dir):
if not (sys.path.__contains__(lldb_python_dir)):
sys.path.append(lldb_python_dir)
try:
import lldb
except ImportError:
pass
else:
print 'imported lldb from: "%s"' % (lldb_python_dir)
success = True
break
if not success:
print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
sys.exit(1)
class Timer:
def __enter__(self):
self.start = time.clock()
return self
def __exit__(self, *args):
self.end = time.clock()
self.interval = self.end - self.start
class Action(object):
"""Class that encapsulates actions to take when a thread stops for a reason."""
def __init__(self, callback = None, callback_owner = None):
self.callback = callback
self.callback_owner = callback_owner
def ThreadStopped (self, thread):
assert False, "performance.Action.ThreadStopped(self, thread) must be overridden in a subclass"
class PlanCompleteAction (Action):
def __init__(self, callback = None, callback_owner = None):
Action.__init__(self, callback, callback_owner)
def ThreadStopped (self, thread):
if thread.GetStopReason() == lldb.eStopReasonPlanComplete:
if self.callback:
if self.callback_owner:
self.callback (self.callback_owner, thread)
else:
self.callback (thread)
return True
return False
class BreakpointAction (Action):
def __init__(self, callback = None, callback_owner = None, name = None, module = None, file = None, line = None, breakpoint = None):
Action.__init__(self, callback, callback_owner)
self.modules = lldb.SBFileSpecList()
self.files = lldb.SBFileSpecList()
self.breakpoints = list()
# "module" can be a list or a string
if breakpoint:
self.breakpoints.append(breakpoint)
else:
if module:
if isinstance(module, types.ListType):
for module_path in module:
self.modules.Append(lldb.SBFileSpec(module_path, False))
elif isinstance(module, types.StringTypes):
self.modules.Append(lldb.SBFileSpec(module, False))
if name:
# "file" can be a list or a string
if file:
if isinstance(file, types.ListType):
self.files = lldb.SBFileSpecList()
for f in file:
self.files.Append(lldb.SBFileSpec(f, False))
elif isinstance(file, types.StringTypes):
self.files.Append(lldb.SBFileSpec(file, False))
self.breakpoints.append (self.target.BreakpointCreateByName(name, self.modules, self.files))
elif file and line:
self.breakpoints.append (self.target.BreakpointCreateByLocation(file, line))
def ThreadStopped (self, thread):
if thread.GetStopReason() == lldb.eStopReasonBreakpoint:
for bp in self.breakpoints:
if bp.GetID() == thread.GetStopReasonDataAtIndex(0):
if self.callback:
if self.callback_owner:
self.callback (self.callback_owner, thread)
else:
self.callback (thread)
return True
return False
class TestCase:
"""Class that aids in running performance tests."""
def __init__(self):
self.verbose = False
self.debugger = lldb.SBDebugger.Create()
self.target = None
self.process = None
self.thread = None
self.launch_info = None
self.done = False
self.listener = self.debugger.GetListener()
self.user_actions = list()
self.builtin_actions = list()
self.bp_id_to_dict = dict()
def Setup(self, args):
self.launch_info = lldb.SBLaunchInfo(args)
def Run (self, args):
assert False, "performance.TestCase.Run(self, args) must be subclassed"
def Launch(self):
if self.target:
error = lldb.SBError()
self.process = self.target.Launch (self.launch_info, error)
if not error.Success():
print "error: %s" % error.GetCString()
if self.process:
self.process.GetBroadcaster().AddListener(self.listener, lldb.SBProcess.eBroadcastBitStateChanged | lldb.SBProcess.eBroadcastBitInterrupt)
return True
return False
def WaitForNextProcessEvent (self):
event = None
if self.process:
while event is None:
process_event = lldb.SBEvent()
if self.listener.WaitForEvent (lldb.UINT32_MAX, process_event):
state = lldb.SBProcess.GetStateFromEvent (process_event)
if self.verbose:
print "event = %s" % (lldb.SBDebugger.StateAsCString(state))
if lldb.SBProcess.GetRestartedFromEvent(process_event):
continue
if state == lldb.eStateInvalid or state == lldb.eStateDetached or state == lldb.eStateCrashed or state == lldb.eStateUnloaded or state == lldb.eStateExited:
event = process_event
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:
continue
elif state == lldb.eStateStopped:
event = process_event
call_test_step = True
fatal = False
selected_thread = False
for thread in self.process:
frame = thread.GetFrameAtIndex(0)
select_thread = False
stop_reason = thread.GetStopReason()
if self.verbose:
print "tid = %#x pc = %#x " % (thread.GetThreadID(),frame.GetPC()),
if stop_reason == lldb.eStopReasonNone:
if self.verbose:
print "none"
elif stop_reason == lldb.eStopReasonTrace:
select_thread = True
if self.verbose:
print "trace"
elif stop_reason == lldb.eStopReasonPlanComplete:
select_thread = True
if self.verbose:
print "plan complete"
elif stop_reason == lldb.eStopReasonThreadExiting:
if self.verbose:
print "thread exiting"
elif stop_reason == lldb.eStopReasonExec:
if self.verbose:
print "exec"
elif stop_reason == lldb.eStopReasonInvalid:
if self.verbose:
print "invalid"
elif stop_reason == lldb.eStopReasonException:
select_thread = True
if self.verbose:
print "exception"
fatal = True
elif stop_reason == lldb.eStopReasonBreakpoint:
select_thread = True
bp_id = thread.GetStopReasonDataAtIndex(0)
bp_loc_id = thread.GetStopReasonDataAtIndex(1)
if self.verbose:
print "breakpoint id = %d.%d" % (bp_id, bp_loc_id)
elif stop_reason == lldb.eStopReasonWatchpoint:
select_thread = True
if self.verbose:
print "watchpoint id = %d" % (thread.GetStopReasonDataAtIndex(0))
elif stop_reason == lldb.eStopReasonSignal:
select_thread = True
if self.verbose:
print "signal %d" % (thread.GetStopReasonDataAtIndex(0))
if select_thread and not selected_thread:
self.thread = thread
selected_thread = self.process.SetSelectedThread(thread)
for action in self.user_actions:
action.ThreadStopped (thread)
if fatal:
# if self.verbose:
# Xcode.RunCommand(self.debugger,"bt all",true)
sys.exit(1)
return event
class Measurement:
'''A class that encapsulates a measurement'''
def __init__(self):
object.__init__(self)
def Measure(self):
assert False, "performance.Measurement.Measure() must be subclassed"
class MemoryMeasurement(Measurement):
'''A class that can measure memory statistics for a process.'''
def __init__(self, pid):
Measurement.__init__(self)
self.pid = pid
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()
def Measure(self):
output = commands.getoutput(self.command).split("\n")[-1]
values = re.split('[-+\s]+', output)
for (idx, stat) in enumerate(values):
multiplier = 1
if stat:
if stat[-1] == 'K':
multiplier = 1024
stat = stat[:-1]
elif stat[-1] == 'M':
multiplier = 1024*1024
stat = stat[:-1]
elif stat[-1] == 'G':
multiplier = 1024*1024*1024
elif stat[-1] == 'T':
multiplier = 1024*1024*1024*1024
stat = stat[:-1]
self.value[self.stats[idx]] = int (stat) * multiplier
def __str__(self):
'''Dump the MemoryMeasurement current value'''
s = ''
for key in self.value.keys():
if s:
s += "\n"
s += "%8s = %s" % (key, self.value[key])
return s
class TesterTestCase(TestCase):
def __init__(self):
TestCase.__init__(self)
self.verbose = True
self.num_steps = 5
def BreakpointHit (self, thread):
bp_id = thread.GetStopReasonDataAtIndex(0)
loc_id = thread.GetStopReasonDataAtIndex(1)
print "Breakpoint %i.%i hit: %s" % (bp_id, loc_id, thread.process.target.FindBreakpointByID(bp_id))
thread.StepOver()
def PlanComplete (self, thread):
if self.num_steps > 0:
thread.StepOver()
self.num_steps = self.num_steps - 1
else:
thread.process.Kill()
def Run (self, args):
self.Setup(args)
with Timer() as total_time:
self.target = self.debugger.CreateTarget(args[0])
if self.target:
with Timer() as breakpoint_timer:
bp = self.target.BreakpointCreateByName("main")
print('Breakpoint time = %.03f sec.' % breakpoint_timer.interval)
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():
while not self.done:
self.WaitForNextProcessEvent()
else:
print "error: failed to launch process"
else:
print "error: failed to create target with '%s'" % (args[0])
print('Total time = %.03f sec.' % total_time.interval)
if __name__ == '__main__':
lldb.SBDebugger.Initialize()
test = TesterTestCase()
test.Run (sys.argv[1:])
mem = MemoryMeasurement(os.getpid())
mem.Measure()
print str(mem)
lldb.SBDebugger.Terminate()
# print "sleeeping for 100 seconds"
# time.sleep(100)

View File

@@ -0,0 +1,272 @@
#!/usr/bin/python
#----------------------------------------------------------------------
# Be sure to add the python path that points to the LLDB shared library.
# On MacOSX csh, tcsh:
# setenv PYTHONPATH /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
# On MacOSX sh, bash:
# export PYTHONPATH=/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
#----------------------------------------------------------------------
import commands
import optparse
import os
import platform
import sys
#----------------------------------------------------------------------
# Code that auto imports LLDB
#----------------------------------------------------------------------
try:
# Just try for LLDB in case PYTHONPATH is already correctly setup
import lldb
except ImportError:
lldb_python_dirs = list()
# lldb is not in the PYTHONPATH, try some defaults for the current platform
platform_system = platform.system()
if platform_system == 'Darwin':
# On Darwin, try the currently selected Xcode directory
xcode_dir = commands.getoutput("xcode-select --print-path")
if xcode_dir:
lldb_python_dirs.append(os.path.realpath(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
for lldb_python_dir in lldb_python_dirs:
if os.path.exists(lldb_python_dir):
if not (sys.path.__contains__(lldb_python_dir)):
sys.path.append(lldb_python_dir)
try:
import lldb
except ImportError:
pass
else:
print 'imported lldb from: "%s"' % (lldb_python_dir)
success = True
break
if not success:
print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
sys.exit(1)
def print_threads(process, options):
if options.show_threads:
for thread in process:
print '%s %s' % (thread, thread.GetFrameAtIndex(0))
def run_commands(command_interpreter, commands):
return_obj = lldb.SBCommandReturnObject()
for command in commands:
command_interpreter.HandleCommand( command, return_obj )
if return_obj.Succeeded():
print return_obj.GetOutput()
else:
print return_obj
if options.stop_on_error:
break
def main(argv):
description='''Debugs a program using the LLDB python API and uses asynchronous broadcast events to watch for process state changes.'''
epilog='''Examples:
#----------------------------------------------------------------------
# Run "/bin/ls" with the arguments "-lAF /tmp/", and set a breakpoint
# 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/
'''
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.add_option('-v', '--verbose', action='store_true', dest='verbose', help="Enable verbose logging.", default=False)
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.')
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:
(options, args) = parser.parse_args(argv)
except:
return
attach_info = None
launch_info = None
exe = None
if args:
exe = args.pop(0)
launch_info = lldb.SBLaunchInfo (args)
if options.env_vars:
launch_info.SetEnvironmentEntries(options.env_vars, True)
if options.working_dir:
launch_info.SetWorkingDirectory(options.working_dir)
elif options.attach_pid != -1:
if options.run_count == 1:
attach_info = lldb.SBAttachInfo (options.attach_pid)
else:
print "error: --run-count can't be used with the --attach-pid option"
sys.exit(1)
elif not options.attach_name is None:
if options.run_count == 1:
attach_info = lldb.SBAttachInfo (options.attach_name, options.attach_wait)
else:
print "error: --run-count can't be used with the --attach-name option"
sys.exit(1)
else:
print 'error: a program path for a program to debug and its arguments are required'
sys.exit(1)
# Create a new debugger instance
debugger = lldb.SBDebugger.Create()
debugger.SetAsync (True)
command_interpreter = debugger.GetCommandInterpreter()
# Create a target from a file and arch
if exe:
print "Creating a target for '%s'" % exe
error = lldb.SBError()
target = debugger.CreateTarget (exe, options.arch, options.platform, True, error)
if target:
# 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
if launch_info and options.breakpoints:
for bp in options.breakpoints:
debugger.HandleCommand( "_regexp-break %s" % (bp))
run_commands(command_interpreter, ['breakpoint list'])
for run_idx in range(options.run_count):
# Launch the process. Since we specified synchronous mode, we won't return
# from this function until we hit the breakpoint at main
error = lldb.SBError()
if launch_info:
if options.run_count == 1:
print 'Launching "%s"...' % (exe)
else:
print 'Launching "%s"... (launch %u of %u)' % (exe, run_idx + 1, options.run_count)
process = target.Launch (launch_info, error)
else:
if options.attach_pid != -1:
print 'Attaching to process %i...' % (options.attach_pid)
else:
if options.attach_wait:
print 'Waiting for next to process named "%s" to launch...' % (options.attach_name)
else:
print 'Attaching to existing process named "%s"...' % (options.attach_name)
process = target.Attach (attach_info, error)
# Make sure the launch went ok
if process and process.GetProcessID() != lldb.LLDB_INVALID_PROCESS_ID:
pid = process.GetProcessID()
listener = debugger.GetListener()
# sign up for process state change events
stop_idx = 0
done = False
while not done:
event = lldb.SBEvent()
if listener.WaitForEvent (options.event_timeout, event):
if lldb.SBProcess.EventIsProcessEvent(event):
state = lldb.SBProcess.GetStateFromEvent (event)
if state == lldb.eStateInvalid:
# Not a state event
print 'process event = %s' % (event)
else:
print "process state changed event: %s" % (lldb.SBDebugger.StateAsCString(state))
if state == lldb.eStateStopped:
if stop_idx == 0:
if launch_info:
print "process %u launched" % (pid)
run_commands(command_interpreter, ['breakpoint list'])
else:
print "attached to process %u" % (pid)
for m in target.modules:
print m
if options.breakpoints:
for bp in options.breakpoints:
debugger.HandleCommand( "_regexp-break %s" % (bp))
run_commands(command_interpreter, ['breakpoint list'])
run_commands (command_interpreter, options.launch_commands)
else:
if options.verbose:
print "process %u stopped" % (pid)
run_commands (command_interpreter, options.stop_commands)
stop_idx += 1
print_threads (process, options)
print "continuing process %u" % (pid)
process.Continue()
elif state == lldb.eStateExited:
exit_desc = process.GetExitDescription()
if exit_desc:
print "process %u exited with status %u: %s" % (pid, process.GetExitStatus (), exit_desc)
else:
print "process %u exited with status %u" % (pid, process.GetExitStatus ())
run_commands (command_interpreter, options.exit_commands)
done = True
elif state == lldb.eStateCrashed:
print "process %u crashed" % (pid)
print_threads (process, options)
run_commands (command_interpreter, options.crash_commands)
done = True
elif state == lldb.eStateDetached:
print "process %u detached" % (pid)
done = True
elif state == lldb.eStateRunning:
# process is running, don't say anything, we will always get one of these after resuming
if options.verbose:
print "process %u resumed" % (pid)
elif state == lldb.eStateUnloaded:
print "process %u unloaded, this shouldn't happen" % (pid)
done = True
elif state == lldb.eStateConnected:
print "process connected"
elif state == lldb.eStateAttaching:
print "process attaching"
elif state == lldb.eStateLaunching:
print "process launching"
else:
print 'event = %s' % (event)
else:
# timeout waiting for an event
print "no process event for %u seconds, killing the process..." % (options.event_timeout)
done = True
# Now that we are done dump the stdout and stderr
process_stdout = process.GetSTDOUT(1024)
if process_stdout:
print "Process STDOUT:\n%s" % (process_stdout)
while process_stdout:
process_stdout = process.GetSTDOUT(1024)
print process_stdout
process_stderr = process.GetSTDERR(1024)
if process_stderr:
print "Process STDERR:\n%s" % (process_stderr)
while process_stderr:
process_stderr = process.GetSTDERR(1024)
print process_stderr
process.Kill() # kill the process
else:
if error:
print error
else:
if launch_info:
print 'error: launch failed'
else:
print 'error: attach failed'
lldb.SBDebugger.Terminate()
if __name__ == '__main__':
main(sys.argv[1:])

View File

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

View File

@@ -0,0 +1,255 @@
#!/usr/bin/python
import lldb
class value(object):
'''A class that wraps an lldb.SBValue object and returns an object that
can be used as an object with attribytes:\n
argv = a.value(lldb.frame.FindVariable('argv'))\n
argv.name - return the name of the value that this object contains\n
argv.type - return the lldb.SBType for this value
argv.type_name - return the name of the type
argv.size - return the byte size of this value
argv.is_in_scope - return true if this value is currently in scope
argv.is_pointer - return true if this value is a pointer
argv.format - return the current format for this value
argv.value - return the value's value as a string
argv.summary - return a summary of this value's value
argv.description - return the runtime description for this value
argv.location - return a string that represents the values location (address, register, etc)
argv.target - return the lldb.SBTarget for this value
argv.process - return the lldb.SBProcess for this value
argv.thread - return the lldb.SBThread for this value
argv.frame - return the lldb.SBFrame for this value
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
'''
def __init__(self, sbvalue):
self.sbvalue = sbvalue
def __nonzero__(self):
return self.sbvalue.__nonzero__()
def __repr__(self):
return self.sbvalue.__repr__()
def __str__(self):
return self.sbvalue.__str__()
def __getitem__(self, key):
if type(key) is int:
return value(self.sbvalue.GetChildAtIndex(key, lldb.eNoDynamicValues, True))
raise TypeError
def __getattr__(self, name):
if name == 'name':
return self.sbvalue.GetName()
if name == 'type':
return self.sbvalue.GetType()
if name == 'type_name':
return self.sbvalue.GetTypeName()
if name == 'size':
return self.sbvalue.GetByteSize()
if name == 'is_in_scope':
return self.sbvalue.IsInScope()
if name == 'is_pointer':
return self.sbvalue.TypeIsPointerType()
if name == 'format':
return self.sbvalue.GetFormat ()
if name == 'value':
return self.sbvalue.GetValue ()
if name == 'summary':
return self.sbvalue.GetSummary ()
if name == 'description':
return self.sbvalue.GetObjectDescription ()
if name == 'location':
return self.sbvalue.GetLocation ()
if name == 'target':
return self.sbvalue.GetTarget()
if name == 'process':
return self.sbvalue.GetProcess()
if name == 'thread':
return self.sbvalue.GetThread()
if name == 'frame':
return self.sbvalue.GetFrame()
if name == 'num_children':
return self.sbvalue.GetNumChildren()
if name == 'children':
# Returns an array of sbvalue objects, one for each child of
# the value for the lldb.SBValue
children = []
for i in range (self.sbvalue.GetNumChildren()):
children.append(value(self.sbvalue.GetChildAtIndex(i, lldb.eNoDynamicValues, True)))
return children
raise AttributeError
class variable(object):
'''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
in your code, you would be able to do: "pt.x + pt.y"'''
def __init__(self, sbvalue):
self.sbvalue = sbvalue
def __nonzero__(self):
return self.sbvalue.__nonzero__()
def __repr__(self):
return self.sbvalue.__repr__()
def __str__(self):
return self.sbvalue.__str__()
def __getitem__(self, key):
# Allow array access if this value has children...
if type(key) is int:
return variable(self.sbvalue.GetValueForExpressionPath("[%i]" % key))
raise TypeError
def __getattr__(self, name):
child_sbvalue = self.sbvalue.GetChildMemberWithName (name)
if child_sbvalue:
return variable(child_sbvalue)
raise AttributeError
def __add__(self, other):
return int(self) + int(other)
def __sub__(self, other):
return int(self) - int(other)
def __mul__(self, other):
return int(self) * int(other)
def __floordiv__(self, other):
return int(self) // int(other)
def __mod__(self, other):
return int(self) % int(other)
def __divmod__(self, other):
return int(self) % int(other)
def __pow__(self, other):
return int(self) ** int(other)
def __lshift__(self, other):
return int(self) << int(other)
def __rshift__(self, other):
return int(self) >> int(other)
def __and__(self, other):
return int(self) & int(other)
def __xor__(self, other):
return int(self) ^ int(other)
def __or__(self, other):
return int(self) | int(other)
def __div__(self, other):
return int(self) / int(other)
def __truediv__(self, other):
return int(self) / int(other)
def __iadd__(self, other):
result = self.__add__(other)
self.sbvalue.SetValueFromCString (str(result))
return result
def __isub__(self, other):
result = self.__sub__(other)
self.sbvalue.SetValueFromCString (str(result))
return result
def __imul__(self, other):
result = self.__mul__(other)
self.sbvalue.SetValueFromCString (str(result))
return result
def __idiv__(self, other):
result = self.__div__(other)
self.sbvalue.SetValueFromCString (str(result))
return result
def __itruediv__(self, other):
result = self.__truediv__(other)
self.sbvalue.SetValueFromCString (str(result))
return result
def __ifloordiv__(self, other):
result = self.__floordiv__(self, other)
self.sbvalue.SetValueFromCString (str(result))
return result
def __imod__(self, other):
result = self.__and__(self, other)
self.sbvalue.SetValueFromCString (str(result))
return result
def __ipow__(self, other):
result = self.__pow__(self, other)
self.sbvalue.SetValueFromCString (str(result))
return result
def __ipow__(self, other, modulo):
result = self.__pow__(self, other, modulo)
self.sbvalue.SetValueFromCString (str(result))
return result
def __ilshift__(self, other):
result = self.__lshift__(self, other)
self.sbvalue.SetValueFromCString (str(result))
return result
def __irshift__(self, other):
result = self.__rshift__(self, other)
self.sbvalue.SetValueFromCString (str(result))
return result
def __iand__(self, other):
result = self.__and__(self, other)
self.sbvalue.SetValueFromCString (str(result))
return result
def __ixor__(self, other):
result = self.__xor__(self, other)
self.sbvalue.SetValueFromCString (str(result))
return result
def __ior__(self, other):
result = self.__ior__(self, other)
self.sbvalue.SetValueFromCString (str(result))
return result
def __neg__(self):
return -int(self)
def __pos__(self):
return +int(self)
def __abs__(self):
return abs(int(self))
def __invert__(self):
return ~int(self)
def __complex__(self):
return complex (int(self))
def __int__(self):
return self.sbvalue.GetValueAsSigned()
def __long__(self):
return self.sbvalue.GetValueAsSigned()
def __float__(self):
return float (self.sbvalue.GetValueAsSigned())
def __oct__(self):
return '0%o' % self.sbvalue.GetValueAsSigned()
def __hex__(self):
return '0x%x' % self.sbvalue.GetValueAsSigned()

View File

@@ -0,0 +1,28 @@
#!/usr/bin/python
import lldb
import shlex
def dump_module_sources(module, result):
if module:
print >> result, "Module: %s" % (module.file)
for compile_unit in module.compile_units:
if compile_unit.file:
print >> result, " %s" % (compile_unit.file)
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.'''
module_names = shlex.split(command)
target = debugger.GetSelectedTarget()
if module_names:
for module_name in module_names:
dump_module_sources(target.module[module_name], result)
else:
for module in target.modules:
dump_module_sources(module, result)
def __lldb_init_module (debugger, dict):
# Add any commands contained in this module to LLDB
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.'

View File

@@ -0,0 +1,56 @@
#!/usr/bin/python
import lldb
import commands
import optparse
import shlex
def stack_frames(debugger, command, result, dict):
command_args = shlex.split(command)
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.'''
parser = optparse.OptionParser(description=description, prog='ls',usage=usage)
parser.add_option('-v', '--verbose', action='store_true', dest='verbose', help='display verbose debug info', default=False)
try:
(options, args) = parser.parse_args(command_args)
except:
return
frame_info = {}
for thread in lldb.process:
last_frame = None
print "thread %u" % (thread.id)
for frame in thread.frames:
if last_frame:
frame_size = 0
if frame.idx == 1:
if frame.fp == last_frame.fp:
# No frame one the first frame (might be right at the entry point)
first_frame_size = 0
frame_size = frame.fp - frame.sp
else:
# First frame that has a valid size
first_frame_size = last_frame.fp - last_frame.sp
print "<%#7x> %s" % (first_frame_size, last_frame)
if first_frame_size:
name = last_frame.name
if name not in frame_info:
frame_info[name] = first_frame_size
else:
frame_info[name] += first_frame_size
else:
# Second or higher frame
frame_size = frame.fp - last_frame.fp
print "<%#7x> %s" % (frame_size, frame)
if frame_size > 0:
name = frame.name
if name not in frame_info:
frame_info[name] = frame_size
else:
frame_info[name] += frame_size
last_frame = frame
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."

View File

@@ -0,0 +1,583 @@
#!/usr/bin/python
#----------------------------------------------------------------------
# Be sure to add the python path that points to the LLDB shared library.
#
# To use this in the embedded python interpreter using "lldb":
#
# cd /path/containing/crashlog.py
# lldb
# (lldb) script import crashlog
# "crashlog" command installed, type "crashlog --help" for detailed help
# (lldb) crashlog ~/Library/Logs/DiagnosticReports/a.crash
#
# The benefit of running the crashlog command inside lldb in the
# embedded python interpreter is when the command completes, there
# 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
# in the backtrace will be loaded unless the "--load-all" option
# has been specified. This allows users to explore the program in the
# state it was in right at crash time.
#
# On MacOSX csh, tcsh:
# ( setenv PYTHONPATH /path/to/LLDB.framework/Resources/Python ; ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash )
#
# On MacOSX sh, bash:
# PYTHONPATH=/path/to/LLDB.framework/Resources/Python ./crashlog.py ~/Library/Logs/DiagnosticReports/a.crash
#----------------------------------------------------------------------
import lldb
import commands
import optparse
import os
import plistlib
import re
import shlex
import sys
import time
import uuid
class Address:
"""Class that represents an address that will be symbolicated"""
def __init__(self, target, load_addr):
self.target = target
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
self.sym_ctx = None # The cached symbol context for this address
self.description = None # Any original textual description of this address to be used as a backup in case symbolication fails
self.symbolication = None # The cached symbolicated string that describes this address
self.inlined = False
def __str__(self):
s = "%#16.16x" % (self.load_addr)
if self.symbolication:
s += " %s" % (self.symbolication)
elif self.description:
s += " %s" % (self.description)
elif self.so_addr:
s += " %s" % (self.so_addr)
return s
def resolve_addr(self):
if self.so_addr == None:
self.so_addr = self.target.ResolveLoadAddress (self.load_addr)
return self.so_addr
def is_inlined(self):
return self.inlined
def get_symbol_context(self):
if self.sym_ctx == None:
sb_addr = self.resolve_addr()
if sb_addr:
self.sym_ctx = self.target.ResolveSymbolContextForAddress (sb_addr, lldb.eSymbolContextEverything)
else:
self.sym_ctx = lldb.SBSymbolContext()
return self.sym_ctx
def get_instructions(self):
sym_ctx = self.get_symbol_context()
if sym_ctx:
function = sym_ctx.GetFunction()
if function:
return function.GetInstructions(self.target)
return sym_ctx.GetSymbol().GetInstructions(self.target)
return None
def symbolicate(self, verbose = False):
if self.symbolication == None:
self.symbolication = ''
self.inlined = False
sym_ctx = self.get_symbol_context()
if sym_ctx:
module = sym_ctx.GetModule()
if module:
# Print full source file path in verbose mode
if verbose:
self.symbolication += str(module.GetFileSpec()) + '`'
else:
self.symbolication += module.GetFileSpec().GetFilename() + '`'
function_start_load_addr = -1
function = sym_ctx.GetFunction()
block = sym_ctx.GetBlock()
line_entry = sym_ctx.GetLineEntry()
symbol = sym_ctx.GetSymbol()
inlined_block = block.GetContainingInlinedBlock();
if function:
self.symbolication += function.GetName()
if inlined_block:
self.inlined = True
self.symbolication += ' [inlined] ' + inlined_block.GetInlinedName();
block_range_idx = inlined_block.GetRangeIndexForBlockAddress (self.so_addr)
if block_range_idx < lldb.UINT32_MAX:
block_range_start_addr = inlined_block.GetRangeStartAddress (block_range_idx)
function_start_load_addr = block_range_start_addr.GetLoadAddress (self.target)
if function_start_load_addr == -1:
function_start_load_addr = function.GetStartAddress().GetLoadAddress (self.target)
elif symbol:
self.symbolication += symbol.GetName()
function_start_load_addr = symbol.GetStartAddress().GetLoadAddress (self.target)
else:
self.symbolication = ''
return False
# Dump the offset from the current function or symbol if it is non zero
function_offset = self.load_addr - function_start_load_addr
if function_offset > 0:
self.symbolication += " + %u" % (function_offset)
elif function_offset < 0:
self.symbolication += " %i (invalid negative offset, file a bug) " % function_offset
# Print out any line information if any is available
if line_entry.GetFileSpec():
# Print full source file path in verbose mode
if verbose:
self.symbolication += ' at %s' % line_entry.GetFileSpec()
else:
self.symbolication += ' at %s' % line_entry.GetFileSpec().GetFilename()
self.symbolication += ':%u' % line_entry.GetLine ()
column = line_entry.GetColumn()
if column > 0:
self.symbolication += ':%u' % column
return True
return False
class Section:
"""Class that represents an load address range"""
sect_info_regex = re.compile('(?P<name>[^=]+)=(?P<range>.*)')
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*$')
def __init__(self, start_addr = None, end_addr = None, name = None):
self.start_addr = start_addr
self.end_addr = end_addr
self.name = name
def contains(self, addr):
return self.start_addr <= addr and addr < self.end_addr;
def set_from_string(self, s):
match = self.sect_info_regex.match (s)
if match:
self.name = match.group('name')
range_str = match.group('range')
addr_match = self.addr_regex.match(range_str)
if addr_match:
self.start_addr = int(addr_match.group('start'), 16)
self.end_addr = None
return True
range_match = self.range_regex.match(range_str)
if range_match:
self.start_addr = int(range_match.group('start'), 16)
self.end_addr = int(range_match.group('end'), 16)
op = range_match.group('op')
if op == '+':
self.end_addr += self.start_addr
return True
print 'error: invalid section info string "%s"' % s
print 'Valid section info formats are:'
print 'Format Example Description'
print '--------------------- -----------------------------------------------'
print '<name>=<base> __TEXT=0x123000 Section from base address only'
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'
return False
def __str__(self):
if self.name:
if self.end_addr != None:
if self.start_addr != None:
return "%s=[0x%16.16x - 0x%16.16x)" % (self.name, self.start_addr, self.end_addr)
else:
if self.start_addr != None:
return "%s=0x%16.16x" % (self.name, self.start_addr)
return self.name
return "<invalid>"
class Image:
"""A class that represents an executable image and any associated data"""
def __init__(self, path, uuid = None):
self.path = path
self.resolved_path = None
self.resolved = False
self.unavailable = False
self.uuid = uuid
self.section_infos = list()
self.identifier = None
self.version = None
self.arch = None
self.module = None
self.symfile = None
self.slide = None
def dump(self, prefix):
print "%s%s" % (prefix, self)
def debug_dump(self):
print 'path = "%s"' % (self.path)
print 'resolved_path = "%s"' % (self.resolved_path)
print 'resolved = %i' % (self.resolved)
print 'unavailable = %i' % (self.unavailable)
print 'uuid = %s' % (self.uuid)
print 'section_infos = %s' % (self.section_infos)
print 'identifier = "%s"' % (self.identifier)
print 'version = %s' % (self.version)
print 'arch = %s' % (self.arch)
print 'module = %s' % (self.module)
print 'symfile = "%s"' % (self.symfile)
print 'slide = %i (0x%x)' % (self.slide, self.slide)
def __str__(self):
s = "%s %s %s" % (self.get_uuid(), self.version, self.get_resolved_path())
for section_info in self.section_infos:
s += ", %s" % (section_info)
if self.slide != None:
s += ', slide = 0x%16.16x' % self.slide
return s
def add_section(self, section):
#print "added '%s' to '%s'" % (section, self.path)
self.section_infos.append (section)
def get_section_containing_load_addr (self, load_addr):
for section_info in self.section_infos:
if section_info.contains(load_addr):
return section_info
return None
def get_resolved_path(self):
if self.resolved_path:
return self.resolved_path
elif self.path:
return self.path
return None
def get_resolved_path_basename(self):
path = self.get_resolved_path()
if path:
return os.path.basename(path)
return None
def symfile_basename(self):
if self.symfile:
return os.path.basename(self.symfile)
return None
def has_section_load_info(self):
return self.section_infos or self.slide != None
def load_module(self, target):
if self.unavailable:
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
# set the section load addresses
if self.has_section_load_info():
if target:
if self.module:
if self.section_infos:
num_sections_loaded = 0
for section_info in self.section_infos:
if section_info.name:
section = self.module.FindSection (section_info.name)
if section:
error = target.SetSectionLoadAddress (section, section_info.start_addr)
if error.Success():
num_sections_loaded += 1
else:
return 'error: %s' % error.GetCString()
else:
return 'error: unable to find the section named "%s"' % section_info.name
else:
return 'error: unable to find "%s" section in "%s"' % (range.name, self.get_resolved_path())
if num_sections_loaded == 0:
return 'error: no sections were successfully loaded'
else:
err = target.SetModuleLoadAddress(self.module, self.slide)
if err.Fail():
return err.GetCString()
return None
else:
return 'error: invalid module'
else:
return 'error: invalid target'
else:
return 'error: no section infos'
def add_module(self, target):
'''Add the Image described in this object to "target" and load the sections if "load" is True.'''
if target:
# Try and find using UUID only first so that paths need not match up
uuid_str = self.get_normalized_uuid_string()
if uuid_str:
self.module = target.AddModule (None, None, uuid_str)
if not self.module:
self.locate_module_and_debug_symbols ()
if self.unavailable:
return None
resolved_path = self.get_resolved_path()
self.module = target.AddModule (resolved_path, self.arch, uuid_str, self.symfile)
if not self.module:
return 'error: unable to get module for (%s) "%s"' % (self.arch, self.get_resolved_path())
if self.has_section_load_info():
return self.load_module(target)
else:
return None # No sections, the module was added to the target, so success
else:
return 'error: invalid target'
def locate_module_and_debug_symbols (self):
# By default, just use the paths that were supplied in:
# self.path
# self.resolved_path
# self.module
# self.symfile
# Subclasses can inherit from this class and override this function
self.resolved = True
return True
def get_uuid(self):
if not self.uuid and self.module:
self.uuid = uuid.UUID(self.module.GetUUIDString())
return self.uuid
def get_normalized_uuid_string(self):
if self.uuid:
return str(self.uuid).upper()
return None
def create_target(self):
'''Create a target using the information in this Image object.'''
if self.unavailable:
return None
if self.locate_module_and_debug_symbols ():
resolved_path = self.get_resolved_path();
path_spec = lldb.SBFileSpec (resolved_path)
#result.PutCString ('plist[%s] = %s' % (uuid, self.plist))
error = lldb.SBError()
target = lldb.debugger.CreateTarget (resolved_path, self.arch, None, False, error);
if target:
self.module = target.FindModule(path_spec)
if self.has_section_load_info():
err = self.load_module(target)
if err:
print 'ERROR: ', err
return target
else:
print 'error: unable to create a valid target for (%s) "%s"' % (self.arch, self.path)
else:
print 'error: unable to locate main executable (%s) "%s"' % (self.arch, self.path)
return None
class Symbolicator:
def __init__(self):
"""A class the represents the information needed to symbolicate addresses in a program"""
self.target = None
self.images = list() # a list of images to be used when symbolicating
self.addr_mask = 0xffffffffffffffff
def __str__(self):
s = "Symbolicator:\n"
if self.target:
s += "Target = '%s'\n" % (self.target)
s += "Target modules:'\n"
for m in self.target.modules:
print m
s += "Images:\n"
for image in self.images:
s += ' %s\n' % (image)
return s
def find_images_with_identifier(self, identifier):
images = list()
for image in self.images:
if image.identifier == identifier:
images.append(image)
return images
def find_image_containing_load_addr(self, load_addr):
for image in self.images:
if image.get_section_containing_load_addr (load_addr):
return image
return None
def create_target(self):
if self.target:
return self.target
if self.images:
for image in self.images:
self.target = image.create_target ()
if self.target:
if self.target.GetAddressByteSize() == 4:
triple = self.target.triple
if triple:
arch = triple.split('-')[0]
if "arm" in arch:
self.addr_mask = 0xfffffffffffffffe
return self.target
return None
def symbolicate(self, load_addr, verbose = False):
if not self.target:
self.create_target()
if self.target:
live_process = False
process = self.target.process
if process:
state = process.state
if state > lldb.eStateUnloaded and state < lldb.eStateDetached:
live_process = True
# If we don't have a live process, we can attempt to find the image
# 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
if not live_process:
image = self.find_image_containing_load_addr (load_addr)
if image:
image.add_module (self.target)
symbolicated_address = Address(self.target, load_addr)
if symbolicated_address.symbolicate (verbose):
if symbolicated_address.so_addr:
symbolicated_addresses = list()
symbolicated_addresses.append(symbolicated_address)
# See if we were able to reconstruct anything?
while 1:
inlined_parent_so_addr = lldb.SBAddress()
inlined_parent_sym_ctx = symbolicated_address.sym_ctx.GetParentOfInlinedScope (symbolicated_address.so_addr, inlined_parent_so_addr)
if not inlined_parent_sym_ctx:
break
if not inlined_parent_so_addr:
break
symbolicated_address = Address(self.target, inlined_parent_so_addr.GetLoadAddress(self.target))
symbolicated_address.sym_ctx = inlined_parent_sym_ctx
symbolicated_address.so_addr = inlined_parent_so_addr
symbolicated_address.symbolicate (verbose)
# push the new frame onto the new frame stack
symbolicated_addresses.append (symbolicated_address)
if symbolicated_addresses:
return symbolicated_addresses
else:
print 'error: no target in Symbolicator'
return None
def disassemble_instructions (target, instructions, pc, insts_before_pc, insts_after_pc, non_zeroeth_frame):
lines = list()
pc_index = -1
comment_column = 50
for inst_idx, inst in enumerate(instructions):
inst_pc = inst.GetAddress().GetLoadAddress(target);
if pc == inst_pc:
pc_index = inst_idx
mnemonic = inst.GetMnemonic (target)
operands = inst.GetOperands (target)
comment = inst.GetComment (target)
#data = inst.GetData (target)
lines.append ("%#16.16x: %8s %s" % (inst_pc, mnemonic, operands))
if comment:
line_len = len(lines[-1])
if line_len < comment_column:
lines[-1] += ' ' * (comment_column - line_len)
lines[-1] += "; %s" % comment
if pc_index >= 0:
# If we are disassembling the non-zeroeth frame, we need to backup the PC by 1
if non_zeroeth_frame and pc_index > 0:
pc_index = pc_index - 1
if insts_before_pc == -1:
start_idx = 0
else:
start_idx = pc_index - insts_before_pc
if start_idx < 0:
start_idx = 0
if insts_before_pc == -1:
end_idx = inst_idx
else:
end_idx = pc_index + insts_after_pc
if end_idx > inst_idx:
end_idx = inst_idx
for i in range(start_idx, end_idx+1):
if i == pc_index:
print ' -> ', lines[i]
else:
print ' ', lines[i]
def print_module_section_data (section):
print section
section_data = section.GetSectionData()
if section_data:
ostream = lldb.SBStream()
section_data.GetDescription (ostream, section.GetFileAddress())
print ostream.GetData()
def print_module_section (section, depth):
print section
if depth > 0:
num_sub_sections = section.GetNumSubSections()
for sect_idx in range(num_sub_sections):
print_module_section (section.GetSubSectionAtIndex(sect_idx), depth - 1)
def print_module_sections (module, depth):
for sect in module.section_iter():
print_module_section (sect, depth)
def print_module_symbols (module):
for sym in module:
print sym
def Symbolicate(command_args):
usage = "usage: %prog [options] <addr1> [addr2 ...]"
description='''Symbolicate one or more addresses using LLDB's python scripting API..'''
parser = optparse.OptionParser(description=description, prog='crashlog.py',usage=usage)
parser.add_option('-v', '--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:
(options, args) = parser.parse_args(command_args)
except:
return
symbolicator = Symbolicator()
images = list();
if options.file:
image = Image(options.file);
image.arch = options.arch
# Add any sections that were specified with one or more --section options
if options.section_strings:
for section_str in options.section_strings:
section = Section()
if section.set_from_string (section_str):
image.add_section (section)
else:
sys.exit(1)
if options.slide != None:
image.slide = options.slide
symbolicator.images.append(image)
target = symbolicator.create_target()
if options.verbose:
print symbolicator
if target:
for addr_str in args:
addr = int(addr_str, 0)
symbolicated_addrs = symbolicator.symbolicate(addr, options.verbose)
for symbolicated_addr in symbolicated_addrs:
print symbolicated_addr
print
else:
print 'error: no target for %s' % (symbolicator)
if __name__ == '__main__':
# Create a new debugger instance
lldb.debugger = lldb.SBDebugger.Create()
Symbolicate (sys.argv[1:])

View File

@@ -0,0 +1,252 @@
#!/usr/bin/python
#----------------------------------------------------------------------
# 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
# import it with the full path using the "command script import"
# command
# (lldb) command script import /path/to/cmdtemplate.py
#----------------------------------------------------------------------
import commands
import platform
import os
import re
import signal
import sys
try:
# Just try for LLDB in case PYTHONPATH is already correctly setup
import lldb
except ImportError:
lldb_python_dirs = list()
# lldb is not in the PYTHONPATH, try some defaults for the current platform
platform_system = platform.system()
if platform_system == 'Darwin':
# On Darwin, try the currently selected Xcode directory
xcode_dir = commands.getoutput("xcode-select --print-path")
if xcode_dir:
lldb_python_dirs.append(os.path.realpath(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
for lldb_python_dir in lldb_python_dirs:
if os.path.exists(lldb_python_dir):
if not (sys.path.__contains__(lldb_python_dir)):
sys.path.append(lldb_python_dir)
try:
import lldb
except ImportError:
pass
else:
print 'imported lldb from: "%s"' % (lldb_python_dir)
success = True
break
if not success:
print "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
sys.exit(1)
import commands
import optparse
import shlex
import time
def regex_option_callback(option, opt_str, value, parser):
if opt_str == "--std":
value = '^std::'
regex = re.compile(value)
parser.values.skip_type_regexes.append (regex)
def create_types_options(for_lldb_command):
if for_lldb_command:
usage = "usage: %prog [options]"
description='''This command will help check for padding in between
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
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
searched.
'''
else:
usage = "usage: %prog [options] EXEPATH [EXEPATH ...]"
description='''This command will help check for padding in between
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
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
be verified in all specified modules.
'''
parser = optparse.OptionParser(description=description, prog='framestats',usage=usage)
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('-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
def verify_type (target, options, type):
print type
typename = type.GetName()
# print 'type: %s' % (typename)
(end_offset, padding) = verify_type_recursive (target, options, type, None, 0, 0, 0)
byte_size = type.GetByteSize()
# if end_offset < byte_size:
# last_member_padding = byte_size - end_offset
# print '%+4u <%u> padding' % (end_offset, last_member_padding)
# padding += last_member_padding
print 'Total byte size: %u' % (byte_size)
print 'Total pad bytes: %u' % (padding)
if padding > 0:
print 'Padding percentage: %2.2f %%' % ((float(padding) / float(byte_size)) * 100.0)
print
def verify_type_recursive (target, options, type, member_name, depth, base_offset, padding):
prev_end_offset = base_offset
typename = type.GetName()
byte_size = type.GetByteSize()
if member_name and member_name != typename:
print '%+4u <%3u> %s%s %s;' % (base_offset, byte_size, ' ' * depth, typename, member_name)
else:
print '%+4u {%3u} %s%s' % (base_offset, byte_size, ' ' * depth, typename)
for type_regex in options.skip_type_regexes:
match = type_regex.match (typename)
if match:
return (base_offset + byte_size, padding)
members = type.members
if members:
for member_idx, member in enumerate(members):
member_type = member.GetType()
member_canonical_type = member_type.GetCanonicalType()
member_type_class = member_canonical_type.GetTypeClass()
member_name = member.GetName()
member_offset = member.GetOffsetInBytes()
member_total_offset = member_offset + base_offset
member_byte_size = member_type.GetByteSize()
member_is_class_or_struct = False
if member_type_class == lldb.eTypeClassStruct or member_type_class == lldb.eTypeClassClass:
member_is_class_or_struct = True
if member_idx == 0 and member_offset == target.GetAddressByteSize() and type.IsPolymorphicClass():
ptr_size = target.GetAddressByteSize()
print '%+4u <%3u> %s__vtbl_ptr_type * _vptr;' % (prev_end_offset, ptr_size, ' ' * (depth + 1))
prev_end_offset = ptr_size
else:
if prev_end_offset < member_total_offset:
member_padding = member_total_offset - prev_end_offset
padding = padding + member_padding
print '%+4u <%3u> %s<PADDING>' % (prev_end_offset, member_padding, ' ' * (depth + 1))
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)
else:
prev_end_offset = member_total_offset + member_byte_size
member_typename = member_type.GetName()
if member.IsBitfield():
print '%+4u <%3u> %s%s:%u %s;' % (member_total_offset, member_byte_size, ' ' * (depth + 1), member_typename, member.GetBitfieldSizeInBits(), member_name)
else:
print '%+4u <%3u> %s%s %s;' % (member_total_offset, member_byte_size, ' ' * (depth + 1), member_typename, member_name)
if prev_end_offset < byte_size:
last_member_padding = byte_size - prev_end_offset
print '%+4u <%3u> %s<PADDING>' % (prev_end_offset, last_member_padding, ' ' * (depth + 1))
padding += last_member_padding
else:
if type.IsPolymorphicClass():
ptr_size = target.GetAddressByteSize()
print '%+4u <%3u> %s__vtbl_ptr_type * _vptr;' % (prev_end_offset, ptr_size, ' ' * (depth + 1))
prev_end_offset = ptr_size
prev_end_offset = base_offset + byte_size
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
# shell would
command_args = shlex.split(command)
parser = create_types_options(True)
try:
(options, args) = parser.parse_args(command_args)
except:
# 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)
result.SetStatus (lldb.eReturnStatusFailed)
return "option parsing failed" # returning a string is the same as returning an error whose description is the string
verify_types(options, debugger.GetSelectedTarget(), command_args)
def verify_types (target, options):
if not target:
print 'error: invalid target'
return
modules = list()
if len(options.modules) == 0:
# Append just the main executable if nothing was specified
module = target.modules[0]
if module:
modules.append(module)
else:
for module_name in options.modules:
module = lldb.target.module[module_name]
if module:
modules.append(module)
if modules:
for module in modules:
print 'module: %s' % (module.file)
if options.typenames:
for typename in options.typenames:
types = module.FindTypes(typename)
if types.GetSize():
print 'Found %u types matching "%s" in "%s"' % (len(types), typename, module.file)
for type in types:
verify_type (target, options, type)
else:
print 'error: no type matches "%s" in "%s"' % (typename, module.file)
else:
types = module.GetTypes(lldb.eTypeClassClass | lldb.eTypeClassStruct)
print 'Found %u types in "%s"' % (len(types), module.file)
for type in types:
verify_type (target, options, type)
else:
print 'error: no modules'
if __name__ == '__main__':
debugger = lldb.SBDebugger.Create()
parser = create_types_options(False)
# try:
(options, args) = parser.parse_args(sys.argv[1:])
# except:
# print "error: option parsing failed"
# sys.exit(1)
if options.debug:
print "Waiting for debugger to attach to process %d" % os.getpid()
os.kill(os.getpid(), signal.SIGSTOP)
for path in args:
# in a command - the lldb.* convenience variables are not to be used
# and their values (if any) are undefined
# this is the best practice to access those objects from within a command
error = lldb.SBError()
target = debugger.CreateTarget (path,
options.arch,
options.platform,
True,
error)
if error.Fail():
print error.GetCString()
continue
verify_types (target, options)
elif getattr(lldb, 'debugger', None):
lldb.debugger.HandleCommand('command script add -f types.check_padding_command check_padding')
print '"check_padding" command installed, use the "--help" option for detailed help'

View File

@@ -0,0 +1,353 @@
#!/usr/bin/python
#===-- x86_64_linux_target_definition.py -----------------------------*- C++ -*-===//
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===//
#----------------------------------------------------------------------
# DESCRIPTION
#
# This file can be used with the following setting:
# plugin.process.gdb-remote.target-definition-file
# This setting should be used when you are trying to connect to a
# remote GDB server that doesn't support any of the register discovery
# packets that LLDB normally uses.
#
# Why is this necessary? LLDB doesn't require a new build of LLDB that
# targets each new architecture you will debug with. Instead, all
# architectures are supported and LLDB relies on extra GDB server
# packets to discover the target we are connecting to so that is can
# show the right registers for each target. This allows the GDB server
# to change and add new registers without requiring a new LLDB build
# just so we can see new registers.
#
# This file implements the x86_64 registers for the darwin version of
# GDB and allows you to connect to servers that use this register set.
#
# USAGE
#
# (lldb) settings set plugin.process.gdb-remote.target-definition-file /path/to/x86_64_linux_target_definition.py
# (lldb) gdb-remote other.baz.com:1234
#
# The target definition file will get used if and only if the
# qRegisterInfo packets are not supported when connecting to a remote
# GDB server.
#----------------------------------------------------------------------
from lldb import *
# Compiler and DWARF register numbers
name_to_gcc_dwarf_regnum = {
'rax' : 0 ,
'rdx' : 1 ,
'rcx' : 2 ,
'rbx' : 3 ,
'rsi' : 4 ,
'rdi' : 5 ,
'rbp' : 6 ,
'rsp' : 7 ,
'r8' : 8 ,
'r9' : 9 ,
'r10' : 10,
'r11' : 11,
'r12' : 12,
'r13' : 13,
'r14' : 14,
'r15' : 15,
'rip' : 16,
'xmm0' : 17,
'xmm1' : 18,
'xmm2' : 19,
'xmm3' : 20,
'xmm4' : 21,
'xmm5' : 22,
'xmm6' : 23,
'xmm7' : 24,
'xmm8' : 25,
'xmm9' : 26,
'xmm10' : 27,
'xmm11' : 28,
'xmm12' : 29,
'xmm13' : 30,
'xmm14' : 31,
'xmm15' : 32,
'stmm0' : 33,
'stmm1' : 34,
'stmm2' : 35,
'stmm3' : 36,
'stmm4' : 37,
'stmm5' : 38,
'stmm6' : 39,
'stmm7' : 30,
'ymm0' : 41,
'ymm1' : 42,
'ymm2' : 43,
'ymm3' : 44,
'ymm4' : 45,
'ymm5' : 46,
'ymm6' : 47,
'ymm7' : 48,
'ymm8' : 49,
'ymm9' : 40,
'ymm10' : 41,
'ymm11' : 42,
'ymm12' : 43,
'ymm13' : 44,
'ymm14' : 45,
'ymm15' : 46
};
name_to_gdb_regnum = {
'rax' : 0,
'rbx' : 1,
'rcx' : 2,
'rdx' : 3,
'rsi' : 4,
'rdi' : 5,
'rbp' : 6,
'rsp' : 7,
'r8' : 8,
'r9' : 9,
'r10' : 10,
'r11' : 11,
'r12' : 12,
'r13' : 13,
'r14' : 14,
'r15' : 15,
'rip' : 16,
'rflags': 17,
'cs' : 18,
'ss' : 19,
'ds' : 20,
'es' : 21,
'fs' : 22,
'gs' : 23,
'stmm0' : 24,
'stmm1' : 25,
'stmm2' : 26,
'stmm3' : 27,
'stmm4' : 28,
'stmm5' : 29,
'stmm6' : 30,
'stmm7' : 31,
'fctrl' : 32,
'fstat' : 33,
'ftag' : 34,
'fiseg' : 35,
'fioff' : 36,
'foseg' : 37,
'fooff' : 38,
'fop' : 39,
'xmm0' : 40,
'xmm1' : 41,
'xmm2' : 42,
'xmm3' : 43,
'xmm4' : 44,
'xmm5' : 45,
'xmm6' : 46,
'xmm7' : 47,
'xmm8' : 48,
'xmm9' : 49,
'xmm10' : 50,
'xmm11' : 51,
'xmm12' : 52,
'xmm13' : 53,
'xmm14' : 54,
'xmm15' : 55,
'mxcsr' : 56,
'ymm0' : 57,
'ymm1' : 58,
'ymm2' : 59,
'ymm3' : 60,
'ymm4' : 61,
'ymm5' : 62,
'ymm6' : 63,
'ymm7' : 64,
'ymm8' : 65,
'ymm9' : 66,
'ymm10' : 67,
'ymm11' : 68,
'ymm12' : 69,
'ymm13' : 70,
'ymm14' : 71,
'ymm15' : 72
};
name_to_generic_regnum = {
'rip' : LLDB_REGNUM_GENERIC_PC,
'rsp' : LLDB_REGNUM_GENERIC_SP,
'rbp' : LLDB_REGNUM_GENERIC_FP,
'rdi' : LLDB_REGNUM_GENERIC_ARG1,
'rsi' : LLDB_REGNUM_GENERIC_ARG2,
'rdx' : LLDB_REGNUM_GENERIC_ARG3,
'rcx' : LLDB_REGNUM_GENERIC_ARG4,
'r8' : LLDB_REGNUM_GENERIC_ARG5,
'r9' : LLDB_REGNUM_GENERIC_ARG6
};
def get_reg_num (reg_num_dict, reg_name):
if reg_name in reg_num_dict:
return reg_num_dict[reg_name]
return LLDB_INVALID_REGNUM
x86_64_register_infos = [
{ 'name':'rax' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
{ 'name':'rbx' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
{ 'name':'rcx' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg4' },
{ 'name':'rdx' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg3' },
{ 'name':'rsi' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg2' },
{ 'name':'rdi' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg1' },
{ 'name':'rbp' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'fp' },
{ 'name':'rsp' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'sp' },
{ 'name':'r8' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg5' },
{ 'name':'r9' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg6' },
{ 'name':'r10' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
{ 'name':'r11' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
{ 'name':'r12' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
{ 'name':'r13' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
{ 'name':'r14' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
{ 'name':'r15' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
{ 'name':'rip' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'pc' },
{ 'name':'rflags', 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'cs' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'ss' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'ds' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'es' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'fs' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'gs' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'stmm0' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'stmm1' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'stmm2' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'stmm3' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'stmm4' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'stmm5' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'stmm6' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'stmm7' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'fctrl' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'fstat' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'ftag' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'fiseg' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'fioff' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'foseg' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'fooff' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'fop' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'xmm0' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm1' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm2' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm3' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm4' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm5' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm6' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm7' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm8' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm9' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm10' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm11' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm12' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm13' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm14' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm15' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'mxcsr' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'orig_rax' , 'set':1, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatHex },
# Registers that are contained in or composed of one of more other registers
{ 'name':'eax' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[31:0]' },
{ 'name':'ebx' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[31:0]' },
{ 'name':'ecx' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[31:0]' },
{ 'name':'edx' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[31:0]' },
{ 'name':'edi' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdi[31:0]' },
{ 'name':'esi' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsi[31:0]' },
{ 'name':'ebp' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbp[31:0]' },
{ 'name':'esp' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsp[31:0]' },
{ 'name':'r8d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r8[31:0]' },
{ 'name':'r9d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r9[31:0]' },
{ 'name':'r10d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r10[31:0]' },
{ 'name':'r11d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r11[31:0]' },
{ 'name':'r12d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r12[31:0]' },
{ 'name':'r13d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r13[31:0]' },
{ 'name':'r14d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r14[31:0]' },
{ 'name':'r15d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r15[31:0]' },
{ 'name':'ax' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[15:0]' },
{ 'name':'bx' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[15:0]' },
{ 'name':'cx' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[15:0]' },
{ 'name':'dx' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[15:0]' },
{ 'name':'di' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdi[15:0]' },
{ 'name':'si' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsi[15:0]' },
{ 'name':'bp' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbp[15:0]' },
{ 'name':'sp' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsp[15:0]' },
{ 'name':'r8w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r8[15:0]' },
{ 'name':'r9w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r9[15:0]' },
{ 'name':'r10w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r10[15:0]' },
{ 'name':'r11w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r11[15:0]' },
{ 'name':'r12w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r12[15:0]' },
{ 'name':'r13w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r13[15:0]' },
{ 'name':'r14w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r14[15:0]' },
{ 'name':'r15w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r15[15:0]' },
{ 'name':'ah' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[15:8]' },
{ 'name':'bh' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[15:8]' },
{ 'name':'ch' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[15:8]' },
{ 'name':'dh' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[15:8]' },
{ 'name':'al' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[7:0]' },
{ 'name':'bl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[7:0]' },
{ 'name':'cl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[7:0]' },
{ 'name':'dl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[7:0]' },
{ 'name':'dil' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdi[7:0]' },
{ 'name':'sil' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsi[7:0]' },
{ 'name':'bpl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbp[7:0]' },
{ 'name':'spl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsp[7:0]' },
{ 'name':'r8l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r8[7:0]' },
{ 'name':'r9l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r9[7:0]' },
{ 'name':'r10l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r10[7:0]' },
{ 'name':'r11l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r11[7:0]' },
{ 'name':'r12l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r12[7:0]' },
{ 'name':'r13l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r13[7:0]' },
{ 'name':'r14l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r14[7:0]' },
{ 'name':'r15l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r15[7:0]' },
];
g_target_definition = None
def get_target_definition ():
global g_target_definition
if g_target_definition == None:
g_target_definition = {}
offset = 0
for reg_info in x86_64_register_infos:
reg_name = reg_info['name']
# Only fill in the offset if there is no 'slice' in the register info
if 'slice' not in reg_info and 'composite' not in reg_info:
reg_info['offset'] = offset
offset += reg_info['bitsize']/8
# Set the GCC/DWARF register number for this register if it has one
reg_num = get_reg_num(name_to_gcc_dwarf_regnum, reg_name)
if reg_num != LLDB_INVALID_REGNUM:
reg_info['gcc'] = reg_num
reg_info['dwarf'] = reg_num
# Set the generic register number for this register if it has one
reg_num = get_reg_num(name_to_generic_regnum, reg_name)
if reg_num != LLDB_INVALID_REGNUM:
reg_info['generic'] = reg_num
# Set the GDB register number for this register if it has one
reg_num = get_reg_num(name_to_gdb_regnum, reg_name)
if reg_num != LLDB_INVALID_REGNUM:
reg_info['gdb'] = reg_num
g_target_definition['sets'] = ['General Purpose Registers', 'Floating Point Registers']
g_target_definition['registers'] = x86_64_register_infos
g_target_definition['host-info'] = { 'triple' : 'x86_64-*-linux', 'endian': eByteOrderLittle }
g_target_definition['g-packet-size'] = offset
g_target_definition['breakpoint-pc-offset'] = -1
return g_target_definition
def get_dynamic_setting(target, setting_name):
if setting_name == 'gdb-server-target-definition':
return get_target_definition()

View File

@@ -0,0 +1,357 @@
#!/usr/bin/python
#===-- x86_64_target_definition.py -----------------------------*- C++ -*-===//
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
#===----------------------------------------------------------------------===//
#----------------------------------------------------------------------
# DESCRIPTION
#
# This file can be used with the following setting:
# plugin.process.gdb-remote.target-definition-file
# This setting should be used when you are trying to connect to a
# remote GDB server that doesn't support any of the register discovery
# packets that LLDB normally uses.
#
# Why is this necessary? LLDB doesn't require a new build of LLDB that
# targets each new architecture you will debug with. Instead, all
# architectures are supported and LLDB relies on extra GDB server
# packets to discover the target we are connecting to so that is can
# show the right registers for each target. This allows the GDB server
# to change and add new registers without requiring a new LLDB build
# just so we can see new registers.
#
# This file implements the x86_64 registers for the darwin version of
# GDB and allows you to connect to servers that use this register set.
#
# USAGE
#
# (lldb) settings set plugin.process.gdb-remote.target-definition-file /path/to/x86_64_target_definition.py
# (lldb) gdb-remote other.baz.com:1234
#
# The target definition file will get used if and only if the
# qRegisterInfo packets are not supported when connecting to a remote
# GDB server.
#----------------------------------------------------------------------
from lldb import *
# Compiler and DWARF register numbers
name_to_gcc_dwarf_regnum = {
'rax' : 0 ,
'rdx' : 1 ,
'rcx' : 2 ,
'rbx' : 3 ,
'rsi' : 4 ,
'rdi' : 5 ,
'rbp' : 6 ,
'rsp' : 7 ,
'r8' : 8 ,
'r9' : 9 ,
'r10' : 10,
'r11' : 11,
'r12' : 12,
'r13' : 13,
'r14' : 14,
'r15' : 15,
'rip' : 16,
'xmm0' : 17,
'xmm1' : 18,
'xmm2' : 19,
'xmm3' : 20,
'xmm4' : 21,
'xmm5' : 22,
'xmm6' : 23,
'xmm7' : 24,
'xmm8' : 25,
'xmm9' : 26,
'xmm10' : 27,
'xmm11' : 28,
'xmm12' : 29,
'xmm13' : 30,
'xmm14' : 31,
'xmm15' : 32,
'stmm0' : 33,
'stmm1' : 34,
'stmm2' : 35,
'stmm3' : 36,
'stmm4' : 37,
'stmm5' : 38,
'stmm6' : 39,
'stmm7' : 30,
'ymm0' : 41,
'ymm1' : 42,
'ymm2' : 43,
'ymm3' : 44,
'ymm4' : 45,
'ymm5' : 46,
'ymm6' : 47,
'ymm7' : 48,
'ymm8' : 49,
'ymm9' : 40,
'ymm10' : 41,
'ymm11' : 42,
'ymm12' : 43,
'ymm13' : 44,
'ymm14' : 45,
'ymm15' : 46
};
name_to_gdb_regnum = {
'rax' : 0,
'rbx' : 1,
'rcx' : 2,
'rdx' : 3,
'rsi' : 4,
'rdi' : 5,
'rbp' : 6,
'rsp' : 7,
'r8' : 8,
'r9' : 9,
'r10' : 10,
'r11' : 11,
'r12' : 12,
'r13' : 13,
'r14' : 14,
'r15' : 15,
'rip' : 16,
'rflags': 17,
'cs' : 18,
'ss' : 19,
'ds' : 20,
'es' : 21,
'fs' : 22,
'gs' : 23,
'stmm0' : 24,
'stmm1' : 25,
'stmm2' : 26,
'stmm3' : 27,
'stmm4' : 28,
'stmm5' : 29,
'stmm6' : 30,
'stmm7' : 31,
'fctrl' : 32,
'fstat' : 33,
'ftag' : 34,
'fiseg' : 35,
'fioff' : 36,
'foseg' : 37,
'fooff' : 38,
'fop' : 39,
'xmm0' : 40,
'xmm1' : 41,
'xmm2' : 42,
'xmm3' : 43,
'xmm4' : 44,
'xmm5' : 45,
'xmm6' : 46,
'xmm7' : 47,
'xmm8' : 48,
'xmm9' : 49,
'xmm10' : 50,
'xmm11' : 51,
'xmm12' : 52,
'xmm13' : 53,
'xmm14' : 54,
'xmm15' : 55,
'mxcsr' : 56,
'ymm0' : 57,
'ymm1' : 58,
'ymm2' : 59,
'ymm3' : 60,
'ymm4' : 61,
'ymm5' : 62,
'ymm6' : 63,
'ymm7' : 64,
'ymm8' : 65,
'ymm9' : 66,
'ymm10' : 67,
'ymm11' : 68,
'ymm12' : 69,
'ymm13' : 70,
'ymm14' : 71,
'ymm15' : 72
};
name_to_generic_regnum = {
'rip' : LLDB_REGNUM_GENERIC_PC,
'rsp' : LLDB_REGNUM_GENERIC_SP,
'rbp' : LLDB_REGNUM_GENERIC_FP,
'rdi' : LLDB_REGNUM_GENERIC_ARG1,
'rsi' : LLDB_REGNUM_GENERIC_ARG2,
'rdx' : LLDB_REGNUM_GENERIC_ARG3,
'rcx' : LLDB_REGNUM_GENERIC_ARG4,
'r8' : LLDB_REGNUM_GENERIC_ARG5,
'r9' : LLDB_REGNUM_GENERIC_ARG6
};
def get_reg_num (reg_num_dict, reg_name):
if reg_name in reg_num_dict:
return reg_num_dict[reg_name]
return LLDB_INVALID_REGNUM
def get_reg_num (reg_num_dict, reg_name):
if reg_name in reg_num_dict:
return reg_num_dict[reg_name]
return LLDB_INVALID_REGNUM
x86_64_register_infos = [
{ 'name':'rax' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
{ 'name':'rbx' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
{ 'name':'rcx' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg4' },
{ 'name':'rdx' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg3' },
{ 'name':'rsi' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg2' },
{ 'name':'rdi' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg1' },
{ 'name':'rbp' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'fp' },
{ 'name':'rsp' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'sp' },
{ 'name':'r8' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg5' },
{ 'name':'r9' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'arg6' },
{ 'name':'r10' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
{ 'name':'r11' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
{ 'name':'r12' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
{ 'name':'r13' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
{ 'name':'r14' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
{ 'name':'r15' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo },
{ 'name':'rip' , 'set':0, 'bitsize':64 , 'encoding':eEncodingUint , 'format':eFormatAddressInfo, 'alt-name':'pc' },
{ 'name':'rflags', 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'cs' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'ss' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'ds' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'es' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'fs' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'gs' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'stmm0' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'stmm1' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'stmm2' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'stmm3' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'stmm4' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'stmm5' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'stmm6' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'stmm7' , 'set':1, 'bitsize':80 , 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'fctrl' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'fstat' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'ftag' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'fiseg' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'fioff' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'foseg' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'fooff' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'fop' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
{ 'name':'xmm0' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm1' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm2' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm3' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm4' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm5' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm6' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm7' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm8' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm9' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm10' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm11' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm12' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm13' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm14' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'xmm15' , 'set':1, 'bitsize':128, 'encoding':eEncodingVector, 'format':eFormatVectorOfUInt8 },
{ 'name':'mxcsr' , 'set':1, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex },
# Registers that are contained in or composed of one of more other registers
{ 'name':'eax' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[31:0]' },
{ 'name':'ebx' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[31:0]' },
{ 'name':'ecx' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[31:0]' },
{ 'name':'edx' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[31:0]' },
{ 'name':'edi' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdi[31:0]' },
{ 'name':'esi' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsi[31:0]' },
{ 'name':'ebp' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbp[31:0]' },
{ 'name':'esp' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsp[31:0]' },
{ 'name':'r8d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r8[31:0]' },
{ 'name':'r9d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r9[31:0]' },
{ 'name':'r10d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r10[31:0]' },
{ 'name':'r11d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r11[31:0]' },
{ 'name':'r12d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r12[31:0]' },
{ 'name':'r13d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r13[31:0]' },
{ 'name':'r14d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r14[31:0]' },
{ 'name':'r15d' , 'set':0, 'bitsize':32 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r15[31:0]' },
{ 'name':'ax' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[15:0]' },
{ 'name':'bx' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[15:0]' },
{ 'name':'cx' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[15:0]' },
{ 'name':'dx' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[15:0]' },
{ 'name':'di' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdi[15:0]' },
{ 'name':'si' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsi[15:0]' },
{ 'name':'bp' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbp[15:0]' },
{ 'name':'sp' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsp[15:0]' },
{ 'name':'r8w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r8[15:0]' },
{ 'name':'r9w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r9[15:0]' },
{ 'name':'r10w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r10[15:0]' },
{ 'name':'r11w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r11[15:0]' },
{ 'name':'r12w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r12[15:0]' },
{ 'name':'r13w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r13[15:0]' },
{ 'name':'r14w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r14[15:0]' },
{ 'name':'r15w' , 'set':0, 'bitsize':16 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r15[15:0]' },
{ 'name':'ah' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[15:8]' },
{ 'name':'bh' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[15:8]' },
{ 'name':'ch' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[15:8]' },
{ 'name':'dh' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[15:8]' },
{ 'name':'al' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rax[7:0]' },
{ 'name':'bl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbx[7:0]' },
{ 'name':'cl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rcx[7:0]' },
{ 'name':'dl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdx[7:0]' },
{ 'name':'dil' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rdi[7:0]' },
{ 'name':'sil' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsi[7:0]' },
{ 'name':'bpl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rbp[7:0]' },
{ 'name':'spl' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'rsp[7:0]' },
{ 'name':'r8l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r8[7:0]' },
{ 'name':'r9l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r9[7:0]' },
{ 'name':'r10l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r10[7:0]' },
{ 'name':'r11l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r11[7:0]' },
{ 'name':'r12l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r12[7:0]' },
{ 'name':'r13l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r13[7:0]' },
{ 'name':'r14l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r14[7:0]' },
{ 'name':'r15l' , 'set':0, 'bitsize':8 , 'encoding':eEncodingUint , 'format':eFormatHex , 'slice': 'r15[7:0]' },
];
g_target_definition = None
def get_target_definition ():
global g_target_definition
if g_target_definition == None:
g_target_definition = {}
offset = 0
for reg_info in x86_64_register_infos:
reg_name = reg_info['name']
# Only fill in the offset if there is no 'slice' in the register info
if 'slice' not in reg_info and 'composite' not in reg_info:
reg_info['offset'] = offset
# Set the GCC/DWARF register number for this register if it has one
reg_num = get_reg_num(name_to_gcc_dwarf_regnum, reg_name)
if reg_num != LLDB_INVALID_REGNUM:
reg_info['gcc'] = reg_num
reg_info['dwarf'] = reg_num
# Set the generic register number for this register if it has one
reg_num = get_reg_num(name_to_generic_regnum, reg_name)
if reg_num != LLDB_INVALID_REGNUM:
reg_info['generic'] = reg_num
# Set the GDB register number for this register if it has one
reg_num = get_reg_num(name_to_gdb_regnum, reg_name)
if reg_num != LLDB_INVALID_REGNUM:
reg_info['gdb'] = reg_num
offset += reg_info['bitsize']/8
g_target_definition['sets'] = ['General Purpose Registers', 'Floating Point Registers']
g_target_definition['registers'] = x86_64_register_infos
g_target_definition['host-info'] = { 'triple' : 'x86_64-apple-macosx', 'endian': eByteOrderLittle }
g_target_definition['g-packet-size'] = offset
return g_target_definition
def get_dynamic_setting(target, setting_name):
if setting_name == 'gdb-server-target-definition':
return get_target_definition()

View File

@@ -0,0 +1,200 @@
//===-- dictionary.c ---------------------------------------------*- C -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===---------------------------------------------------------------------===//
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
typedef struct tree_node
{
const char *word;
struct tree_node *left;
struct tree_node *right;
} tree_node;
/* Given a char*, returns a substring that starts at the first
alphabet character and ends at the last alphabet character, i.e. it
strips off beginning or ending quotes, punctuation, etc. */
char *
strip (char **word)
{
char *start = *word;
int len = strlen (start);
char *end = start + len - 1;
while ((start < end) && (!isalpha (start[0])))
start++;
while ((end > start) && (!isalpha (end[0])))
end--;
if (start > end)
return NULL;
end[1] = '\0';
*word = start;
return start;
}
/* Given a binary search tree (sorted alphabetically by the word at
each node), and a new word, inserts the word at the appropriate
place in the tree. */
void
insert (tree_node *root, char *word)
{
if (root == NULL)
return;
int compare_value = strcmp (word, root->word);
if (compare_value == 0)
return;
if (compare_value < 0)
{
if (root->left != NULL)
insert (root->left, word);
else
{
tree_node *new_node = (tree_node *) malloc (sizeof (tree_node));
new_node->word = strdup (word);
new_node->left = NULL;
new_node->right = NULL;
root->left = new_node;
}
}
else
{
if (root->right != NULL)
insert (root->right, word);
else
{
tree_node *new_node = (tree_node *) malloc (sizeof (tree_node));
new_node->word = strdup (word);
new_node->left = NULL;
new_node->right = NULL;
root->right = new_node;
}
}
}
/* Read in a text file and storea all the words from the file in a
binary search tree. */
void
populate_dictionary (tree_node **dictionary, char *filename)
{
FILE *in_file;
char word[1024];
in_file = fopen (filename, "r");
if (in_file)
{
while (fscanf (in_file, "%s", word) == 1)
{
char *new_word = (strdup (word));
new_word = strip (&new_word);
if (*dictionary == NULL)
{
tree_node *new_node = (tree_node *) malloc (sizeof (tree_node));
new_node->word = new_word;
new_node->left = NULL;
new_node->right = NULL;
*dictionary = new_node;
}
else
insert (*dictionary, new_word);
}
}
}
/* Given a binary search tree and a word, search for the word
in the binary search tree. */
int
find_word (tree_node *dictionary, char *word)
{
if (!word || !dictionary)
return 0;
int compare_value = strcmp (word, dictionary->word);
if (compare_value == 0)
return 1;
else if (compare_value < 0)
return find_word (dictionary->left, word);
else
return find_word (dictionary->right, word);
}
/* Print out the words in the binary search tree, in sorted order. */
void
print_tree (tree_node *dictionary)
{
if (!dictionary)
return;
if (dictionary->left)
print_tree (dictionary->left);
printf ("%s\n", dictionary->word);
if (dictionary->right)
print_tree (dictionary->right);
}
int
main (int argc, char **argv)
{
tree_node *dictionary = NULL;
char buffer[1024];
char *filename;
int done = 0;
if (argc == 2)
filename = argv[1];
if (!filename)
return -1;
populate_dictionary (&dictionary, filename);
fprintf (stdout, "Dictionary loaded.\nEnter search word: ");
while (!done && fgets (buffer, sizeof(buffer), stdin))
{
char *word = buffer;
int len = strlen (word);
int i;
for (i = 0; i < len; ++i)
word[i] = tolower (word[i]);
if ((len > 0) && (word[len-1] == '\n'))
{
word[len-1] = '\0';
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");
return 0;
}

View File

@@ -0,0 +1,118 @@
"""
# ===-- tree_utils.py ---------------------------------------*- Python -*-===//
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
# ===---------------------------------------------------------------------===//
tree_utils.py - A set of functions for examining binary
search trees, based on the example search tree defined in
dictionary.c. These functions contain calls to LLDB API
functions, and assume that the LLDB Python module has been
imported.
For a thorough explanation of how the DFS function works, and
for more information about dictionary.c go to
http://lldb.llvm.org/scripting.html
"""
def DFS (root, word, cur_path):
"""
Recursively traverse a binary search tree containing
words sorted alphabetically, searching for a particular
word in the tree. Also maintains a string representing
the path from the root of the tree to the current node.
If the word is found in the tree, return the path string.
Otherwise return an empty string.
This function assumes the binary search tree is
the one defined in dictionary.c It uses LLDB API
functions to examine and traverse the tree nodes.
"""
# Get pointer field values out of node 'root'
root_word_ptr = root.GetChildMemberWithName ("word")
left_child_ptr = root.GetChildMemberWithName ("left")
right_child_ptr = root.GetChildMemberWithName ("right")
# Get the word out of the word pointer and strip off
# surrounding quotes (added by call to GetSummary).
root_word = root_word_ptr.GetSummary()
end = len (root_word) - 1
if root_word[0] == '"' and root_word[end] == '"':
root_word = root_word[1:end]
end = len (root_word) - 1
if root_word[0] == '\'' and root_word[end] == '\'':
root_word = root_word[1:end]
# Main depth first search
if root_word == word:
return cur_path
elif word < root_word:
# Check to see if left child is NULL
if left_child_ptr.GetValue() == None:
return ""
else:
cur_path = cur_path + "L"
return DFS (left_child_ptr, word, cur_path)
else:
# Check to see if right child is NULL
if right_child_ptr.GetValue() == None:
return ""
else:
cur_path = cur_path + "R"
return DFS (right_child_ptr, word, cur_path)
def tree_size (root):
"""
Recursively traverse a binary search tree, counting
the nodes in the tree. Returns the final count.
This function assumes the binary search tree is
the one defined in dictionary.c It uses LLDB API
functions to examine and traverse the tree nodes.
"""
if (root.GetValue == None):
return 0
if (int (root.GetValue(), 16) == 0):
return 0
left_size = tree_size (root.GetChildAtIndex(1));
right_size = tree_size (root.GetChildAtIndex(2));
total_size = left_size + right_size + 1
return total_size
def print_tree (root):
"""
Recursively traverse a binary search tree, printing out
the words at the nodes in alphabetical order (the
search order for the binary tree).
This function assumes the binary search tree is
the one defined in dictionary.c It uses LLDB API
functions to examine and traverse the tree nodes.
"""
if (root.GetChildAtIndex(1).GetValue() != None) and (int (root.GetChildAtIndex(1).GetValue(), 16) != 0):
print_tree (root.GetChildAtIndex(1))
print root.GetChildAtIndex(0).GetSummary()
if (root.GetChildAtIndex(2).GetValue() != None) and (int (root.GetChildAtIndex(2).GetValue(), 16) != 0):
print_tree (root.GetChildAtIndex(2))

View File

@@ -0,0 +1,204 @@
"""
LLDB AppKit formatters
part of The LLVM Compiler Infrastructure
This file is distributed under the University of Illinois Open Source
License. See LICENSE.TXT for details.
"""
# example summary provider for NSArray
# the real summary is now C++ code built into LLDB
import lldb
import ctypes
import lldb.runtime.objc.objc_runtime
import lldb.formatters.metrics
import lldb.formatters.Logger
statistics = lldb.formatters.metrics.Metrics()
statistics.add_metric('invalid_isa')
statistics.add_metric('invalid_pointer')
statistics.add_metric('unknown_class')
statistics.add_metric('code_notrun')
# much less functional than the other two cases below
# just runs code to get to the count and then returns
# no children
class NSArrayKVC_SynthProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, dict, params):
logger = lldb.formatters.Logger.Logger()
self.valobj = valobj;
self.update()
def update(self):
logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture();
def num_children(self):
logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream()
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 NSArray>"
# much less functional than the other two cases below
# just runs code to get to the count and then returns
# no children
class NSArrayCF_SynthProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, dict, params):
logger = lldb.formatters.Logger.Logger()
self.valobj = valobj;
self.sys_params = params
if not (self.sys_params.types_cache.ulong):
self.sys_params.types_cache.ulong = self.valobj.GetType().GetBasicType(lldb.eBasicTypeUnsignedLong)
self.update()
def update(self):
logger = lldb.formatters.Logger.Logger()
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)
class NSArrayI_SynthProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, dict, params):
logger = lldb.formatters.Logger.Logger()
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)
class NSArrayM_SynthProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, dict, params):
logger = lldb.formatters.Logger.Logger()
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)
# 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
# appropriate backend layer to do the computations
class NSArray_SynthProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, dict):
logger = lldb.formatters.Logger.Logger()
self.valobj = valobj;
self.adjust_for_architecture()
self.error = False
self.wrapper = self.make_wrapper()
self.invalid = (self.wrapper == None)
def num_children(self):
logger = lldb.formatters.Logger.Logger()
if self.wrapper == None:
return 0;
return self.wrapper.num_children()
def update(self):
logger = lldb.formatters.Logger.Logger()
if self.wrapper == None:
return
self.wrapper.update()
# this code acts as our defense against NULL and unitialized
# NSArray pointers, which makes it much longer than it would be otherwise
def make_wrapper(self):
logger = lldb.formatters.Logger.Logger()
if self.valobj.GetValueAsUnsigned() == 0:
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):
logger = lldb.formatters.Logger.Logger()
provider = NSArray_SynthProvider(valobj,dict);
if provider.invalid == False:
if provider.error == True:
return provider.wrapper.message()
try:
summary = int(provider.num_children());
except:
summary = None
logger >> "provider gave me " + str(summary)
if summary == 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

@@ -0,0 +1,146 @@
"""
LLDB AppKit formatters
part of The LLVM Compiler Infrastructure
This file is distributed under the University of Illinois Open Source
License. See LICENSE.TXT for details.
"""
# example summary provider for CFBag
# the real summary is now C++ code built into LLDB
import lldb
import ctypes
import lldb.runtime.objc.objc_runtime
import lldb.formatters.metrics
import lldb.formatters.Logger
statistics = lldb.formatters.metrics.Metrics()
statistics.add_metric('invalid_isa')
statistics.add_metric('invalid_pointer')
statistics.add_metric('unknown_class')
statistics.add_metric('code_notrun')
# 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
# obey the interface specification for synthetic children providers
class CFBagRef_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger()
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):
logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture();
# 12 bytes on i386
# 20 bytes on x64
# most probably 2 pointers and 4 bytes of data
def offset(self):
logger = lldb.formatters.Logger.Logger()
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:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger()
self.valobj = valobj;
self.sys_params = params
self.update();
def update(self):
logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture();
def length(self):
logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream()
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):
logger = lldb.formatters.Logger.Logger()
global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics)
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):
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.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):
debugger.HandleCommand("type summary add -F CFBag.CFBag_SummaryProvider CFBagRef CFMutableBagRef")

View File

@@ -0,0 +1,142 @@
"""
LLDB AppKit formatters
part of The LLVM Compiler Infrastructure
This file is distributed under the University of Illinois Open Source
License. See LICENSE.TXT for details.
"""
# example summary provider for CFBinaryHeap
# the real summary is now C++ code built into LLDB
import lldb
import ctypes
import lldb.runtime.objc.objc_runtime
import lldb.formatters.metrics
import lldb.formatters.Logger
statistics = lldb.formatters.metrics.Metrics()
statistics.add_metric('invalid_isa')
statistics.add_metric('invalid_pointer')
statistics.add_metric('unknown_class')
statistics.add_metric('code_notrun')
# 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
# obey the interface specification for synthetic children providers
class CFBinaryHeapRef_SummaryProvider:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger()
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):
logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture();
# 8 bytes on i386
# 16 bytes on x64
# most probably 2 pointers
def offset(self):
logger = lldb.formatters.Logger.Logger()
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:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger()
self.valobj = valobj;
self.sys_params = params
self.update();
def update(self):
logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture();
def length(self):
logger = lldb.formatters.Logger.Logger()
stream = lldb.SBStream()
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):
logger = lldb.formatters.Logger.Logger()
global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics)
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):
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.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):
debugger.HandleCommand("type summary add -F CFBinaryHeap.CFBinaryHeap_SummaryProvider CFBinaryHeapRef")

View File

@@ -0,0 +1,175 @@
"""
LLDB AppKit formatters
part of The LLVM Compiler Infrastructure
This file is distributed under the University of Illinois Open Source
License. See LICENSE.TXT for details.
"""
# summary provider for CF(Mutable)BitVector
import lldb
import ctypes
import lldb.runtime.objc.objc_runtime
import lldb.formatters.metrics
import lldb.formatters.Logger
# first define some utility functions
def byte_index(abs_pos):
logger = lldb.formatters.Logger.Logger()
return abs_pos/8
def bit_index(abs_pos):
logger = lldb.formatters.Logger.Logger()
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):
logger = lldb.formatters.Logger.Logger()
return pointer.GetPointeeData(index,1)
statistics = lldb.formatters.metrics.Metrics()
statistics.add_metric('invalid_isa')
statistics.add_metric('invalid_pointer')
statistics.add_metric('unknown_class')
statistics.add_metric('code_notrun')
# 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
# obey the interface specification for synthetic children providers
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):
logger = lldb.formatters.Logger.Logger()
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();
def update(self):
logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture();
# we skip the CFRuntimeBase
# then the next CFIndex is the count
# then we skip another CFIndex and then we get at a byte array
# that wraps the individual bits
def contents(self):
logger = lldb.formatters.Logger.Logger()
count_vo = self.valobj.CreateChildAtOffset("count",self.sys_params.cfruntime_size,
self.sys_params.types_cache.NSUInteger)
count = count_vo.GetValueAsUnsigned(0)
if count == 0:
return '(empty)'
array_vo = self.valobj.CreateChildAtOffset("data",
self.sys_params.cfruntime_size+2*self.uiint_size,
self.sys_params.types_cache.charptr)
data_list = []
cur_byte_pos = None
for i in range(0,count):
if cur_byte_pos == None:
cur_byte_pos = byte_index(i)
cur_byte = grab_array_item_data(array_vo,cur_byte_pos)
cur_byte_val = cur_byte.uint8[0]
else:
byte_pos = byte_index(i)
# do not fetch the pointee data every single time through
if byte_pos != cur_byte_pos:
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:
def adjust_for_architecture(self):
pass
def __init__(self, valobj, params):
logger = lldb.formatters.Logger.Logger()
self.valobj = valobj;
self.sys_params = params
self.update();
def update(self):
logger = lldb.formatters.Logger.Logger()
self.adjust_for_architecture();
def contents(self):
logger = lldb.formatters.Logger.Logger()
return '<unable to summarize this CFBitVector>'
def GetSummary_Impl(valobj):
logger = lldb.formatters.Logger.Logger()
global statistics
class_data,wrapper =lldb.runtime.objc.objc_runtime.Utilities.prepare_class_detection(valobj,statistics)
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():
# 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 != 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):
debugger.HandleCommand("type summary add -F CFBitVector.CFBitVector_SummaryProvider CFBitVectorRef CFMutableBitVectorRef")

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