2008-08-06 18:36:30 +00:00
|
|
|
// This file is part of BOINC.
|
2007-04-17 02:27:09 +00:00
|
|
|
// http://boinc.berkeley.edu
|
2008-08-06 18:36:30 +00:00
|
|
|
// Copyright (C) 2008 University of California
|
2007-04-17 02:27:09 +00:00
|
|
|
//
|
2008-08-06 18:36:30 +00:00
|
|
|
// BOINC is free software; you can redistribute it and/or modify it
|
|
|
|
// under the terms of the GNU Lesser General Public License
|
|
|
|
// as published by the Free Software Foundation,
|
|
|
|
// either version 3 of the License, or (at your option) any later version.
|
2007-04-17 02:27:09 +00:00
|
|
|
//
|
2008-08-06 18:36:30 +00:00
|
|
|
// BOINC is distributed in the hope that it will be useful,
|
2007-04-17 02:27:09 +00:00
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
// See the GNU Lesser General Public License for more details.
|
|
|
|
//
|
2008-08-06 18:36:30 +00:00
|
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
|
|
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
|
2007-04-17 02:27:09 +00:00
|
|
|
/*
|
|
|
|
* QBacktrace.h
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* This is part of a backtrace generator for boinc project applications.
|
|
|
|
*
|
|
|
|
* Adapted from Apple Developer Technical Support Sample Code QCrashReport
|
|
|
|
*
|
|
|
|
* This code handles Mac OS X 10.3.x through 10.4.9. It may require some
|
|
|
|
* adjustment for future OS versions; see the discussion of _sigtramp and
|
|
|
|
* PowerPC Signal Stack Frames in file QBacktrace.c.
|
|
|
|
*
|
|
|
|
* For useful tips on using backtrace information, see Apple Tech Note 2123:
|
|
|
|
* http://developer.apple.com/technotes/tn2004/tn2123.html#SECNOSYMBOLS
|
|
|
|
*
|
|
|
|
* To convert addresses to correct symbols, use the atos command-line tool:
|
|
|
|
* atos -o path/to/executable/with/symbols address
|
|
|
|
* Note: if address 1a23 is hex, use 0x1a23.
|
|
|
|
*
|
|
|
|
* To demangle mangled C++ symbols, use the c++filt command-line tool.
|
|
|
|
* You may need to prefix C++ symbols with an additonal underscore before
|
|
|
|
* passing them to c++filt (so they begin with two underscore characters).
|
|
|
|
*
|
|
|
|
* A very useful shell script to add symbols to a crash dump can be found at:
|
|
|
|
* http://developer.apple.com/tools/xcode/symbolizingcrashdumps.html
|
|
|
|
* Pipe the output of the shell script through c++filt to demangle C++ symbols.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
File: QBacktrace.h
|
|
|
|
|
|
|
|
Contains: Code for generating backtraces.
|
|
|
|
|
|
|
|
Written by: DTS
|
|
|
|
|
|
|
|
Copyright: Copyright (c) 2007 Apple Inc. All Rights Reserved.
|
|
|
|
|
|
|
|
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Inc.
|
|
|
|
("Apple") in consideration of your agreement to the following
|
|
|
|
terms, and your use, installation, modification or
|
|
|
|
redistribution of this Apple software constitutes acceptance of
|
|
|
|
these terms. If you do not agree with these terms, please do
|
|
|
|
not use, install, modify or redistribute this Apple software.
|
|
|
|
|
|
|
|
In consideration of your agreement to abide by the following
|
|
|
|
terms, and subject to these terms, Apple grants you a personal,
|
|
|
|
non-exclusive license, under Apple's copyrights in this
|
|
|
|
original Apple software (the "Apple Software"), to use,
|
|
|
|
reproduce, modify and redistribute the Apple Software, with or
|
|
|
|
without modifications, in source and/or binary forms; provided
|
|
|
|
that if you redistribute the Apple Software in its entirety and
|
|
|
|
without modifications, you must retain this notice and the
|
|
|
|
following text and disclaimers in all such redistributions of
|
|
|
|
the Apple Software. Neither the name, trademarks, service marks
|
|
|
|
or logos of Apple Inc. may be used to endorse or promote
|
|
|
|
products derived from the Apple Software without specific prior
|
|
|
|
written permission from Apple. Except as expressly stated in
|
|
|
|
this notice, no other rights or licenses, express or implied,
|
|
|
|
are granted by Apple herein, including but not limited to any
|
|
|
|
patent rights that may be infringed by your derivative works or
|
|
|
|
by other works in which the Apple Software may be incorporated.
|
|
|
|
|
|
|
|
The Apple Software is provided by Apple on an "AS IS" basis.
|
|
|
|
APPLE MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
|
|
|
WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
|
|
|
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING
|
|
|
|
THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
|
|
|
|
COMBINATION WITH YOUR PRODUCTS.
|
|
|
|
|
|
|
|
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT,
|
|
|
|
INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
|
|
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
|
|
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY
|
|
|
|
OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
|
|
|
|
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY
|
|
|
|
OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
|
|
|
|
OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF
|
|
|
|
SUCH DAMAGE.
|
|
|
|
|
|
|
|
Change History (most recent first):
|
|
|
|
|
|
|
|
$Log: QBacktrace.h,v $
|
|
|
|
Revision 1.1 2007/03/02 12:19:53
|
|
|
|
First checked in.
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _QBACKTRACE_H
|
|
|
|
#define _QBACKTRACE_H
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
// System Interfaces
|
|
|
|
|
|
|
|
// Put <mach/mach.h> inside extern "C" guards for the C++ build
|
|
|
|
// because the Mach header files don't always have them.
|
|
|
|
|
|
|
|
#if defined(__cplusplus)
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <mach/mach.h>
|
|
|
|
|
|
|
|
#if defined(__cplusplus)
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Our interfaces
|
|
|
|
|
|
|
|
#include "QTaskMemory.h"
|
|
|
|
#include "QSymbols.h"
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
/*!
|
|
|
|
@header QBacktrace.h
|
|
|
|
|
|
|
|
@abstract Comprehensive backtrace generation.
|
|
|
|
|
|
|
|
@discussion This module implements a number of backtrace routines:
|
|
|
|
|
|
|
|
o QBacktraceMachSelf does a backtrace of the current thread.
|
|
|
|
o QBacktraceMachThread does a backtrace of an arbitrary thread
|
|
|
|
within an arbitrary process.
|
|
|
|
|
|
|
|
All of the routines are implemented in terms of a common core.
|
|
|
|
The code is structured in a very generic way. For example,
|
|
|
|
on an Intel-based Macintosh computer, it's possible to
|
|
|
|
backtrace a PowerPC program (run using Rosetta) from a Intel
|
|
|
|
program, and vice versa.
|
|
|
|
|
|
|
|
Backtraces are inherently processor-specific. Internal to this
|
|
|
|
module is a ISA layer than adapts the backtrace for various ISA.
|
|
|
|
Currently it supports PowerPC (32-bit), PowerPC (64-bit),
|
|
|
|
Intel (32-bit), and Intel (64-bit).
|
|
|
|
|
|
|
|
If you're curious about how stack frames work for each ISA,
|
|
|
|
check out the comments in the implementation file. The comments
|
|
|
|
in the header focus on how you use these routines.
|
|
|
|
|
|
|
|
The core of this module is also (mostly) independent of the
|
|
|
|
technology that you use to read the address space of the
|
|
|
|
process that you're backtracing. The current implementation
|
|
|
|
uses Mach APIs to do this, but it is relatively simple to
|
|
|
|
retarget it to use some other API (a previous version of the
|
|
|
|
code read the memory directly and used the Carbon
|
|
|
|
Exception Manager to catch any exceptions that this triggered).
|
|
|
|
However, as we're currently quite wedded to Mach, I've only
|
|
|
|
retained the Mach functionality.
|
|
|
|
|
|
|
|
If you used a previous version of this code (known as
|
|
|
|
MoreBacktrace), please note the following changes:
|
|
|
|
|
|
|
|
o Everything has changed (-:
|
|
|
|
|
|
|
|
I completely rewrote this code to support multiple architectures.
|
|
|
|
By including support for 64-bit ISA, I was forced to
|
|
|
|
eliminate my dependencies on CoreServices (which isn't available
|
|
|
|
to 64-bit programs on Mac OS X 10.4.x), which means now I depend
|
|
|
|
solely on the System framework. Also, because I had to support
|
|
|
|
Intel, which requires Mach-O, I decided to drop support for CFM.
|
|
|
|
My theory is that anyone who wants to adopt the new version of
|
|
|
|
this module is doing so because they're porting to Intel, and
|
|
|
|
those folks have to leave their CFM build behind.
|
|
|
|
|
|
|
|
The good news is that the new implementation is very similar
|
|
|
|
in spirit to the old, and it should be very easy for you to
|
|
|
|
adopt the new code.
|
|
|
|
|
|
|
|
There are a number of approaches for using the routines exported
|
|
|
|
by this module.
|
|
|
|
|
|
|
|
o If you just want a simple backtrace, create an array of N
|
|
|
|
QBTFrame structures and just pass that into the function.
|
|
|
|
You'll get information about the N frames on the top of
|
|
|
|
the stack. Simple and easy.
|
|
|
|
|
|
|
|
o If you want to get all of the frames, you can first call
|
|
|
|
the routine with a NULL frame array. This will return
|
|
|
|
you the number of frames in the backtrace. You can use
|
|
|
|
that value to allocate a QBTFrame array with the appropriate
|
|
|
|
number of elements and then call the function again to
|
|
|
|
get the actual backtrace.
|
|
|
|
|
|
|
|
o You can also use a hybrid of these approaches. Start by
|
|
|
|
allocating an array with N entries, where N is likely to be
|
|
|
|
enough to accomodate a typical backtrace. Then call the
|
|
|
|
backtrace function. If it indicates that you missed some
|
|
|
|
elements, grow the array and call the backtrace function
|
|
|
|
again.
|
|
|
|
|
|
|
|
The backtrace functions generally don't fail with an error.
|
|
|
|
In general, if the chain of frames on the stack runs off the
|
|
|
|
rails, the backtrace function just returns a truncated backtrace.
|
|
|
|
The two situations where the backtrace function do return an
|
|
|
|
error are a) if it can't even start the backtrace, or
|
|
|
|
b) if something wacky happens, like it can't allocate memory,
|
|
|
|
or manipulate the target task, or find the target thread, and
|
|
|
|
so on.
|
|
|
|
|
|
|
|
If the backtrace function succeeds, you may need to dispose
|
|
|
|
of the symbol and library strings that it allocated by calling
|
|
|
|
QBacktraceDisposeSymbols. This is necessary when all of the
|
|
|
|
following are true:
|
|
|
|
|
|
|
|
o The backtrace function succeeds.
|
|
|
|
|
|
|
|
o You pass NULL to the symRef parameter.
|
|
|
|
|
|
|
|
o You pass a non-zero value to the frameArrayCount parameter
|
|
|
|
(and thus passed a non-NULL value to the frameArray
|
|
|
|
parameter).
|
|
|
|
|
|
|
|
To make things simpler, it's generally easiest to always
|
|
|
|
call QBacktraceDisposeSymbols. The module know which symbol
|
|
|
|
and library strings it allocated, and won't try to free anything
|
|
|
|
that it doesn't own. The QBacktraceDisposeSymbols is very
|
|
|
|
flexible about the parameters it accepts, which makes it easy
|
|
|
|
for you to call in all circumstances. See the function description
|
|
|
|
for more details.
|
|
|
|
|
|
|
|
The lifetime of the symbol and library strings returned by the
|
|
|
|
backtrace depends on the symRef parameter. If this is NULL, the
|
|
|
|
strings persist until you call QBacktraceDisposeSymbols. If it
|
|
|
|
is not NULL, the strings persist until you dispose of the symbols
|
|
|
|
object itself.
|
|
|
|
|
|
|
|
This module assumes that the state of the target task is stable;
|
|
|
|
if the task is still running, you may experienc odd artifacts
|
|
|
|
(as, for example, we take a backtrace of a thread then try
|
|
|
|
to find its symbols, only to determine that the Mach-O image
|
|
|
|
has been unloaded in the interim). The best way to prevent this
|
|
|
|
from happening is to suspend the task while you're accessing it.
|
|
|
|
The Mach routine task_suspend is very useful in this situation.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
@enum QBTFlags
|
|
|
|
|
|
|
|
@abstract Flags for a frame within a backtrace.
|
|
|
|
|
|
|
|
@discussion These flags provide information about a specific frame in
|
|
|
|
a backtrace.
|
|
|
|
|
|
|
|
Note: The code also uses this field to store some internal
|
|
|
|
flags. Do not be alarmed if you see bit other than the
|
|
|
|
ones shown below set in a QBTFlags value.
|
|
|
|
|
|
|
|
@constant kQBTFrameBadMask
|
|
|
|
The frame pointer of this frame is bad (for example, no
|
|
|
|
frame could be found or the frame pointer is misaligned or
|
|
|
|
outside of the stack or references unmapped memory).
|
|
|
|
|
|
|
|
IMPORTANT: This flag is set for the last frame in the
|
|
|
|
backtrace (where we've run off the end of the stack), but it
|
|
|
|
can also be set for intermediate frames (where we've detected
|
|
|
|
a frameless leaf routine, either at the top of the stack or
|
|
|
|
as part of crossing a signal frame).
|
|
|
|
|
|
|
|
@constant kQBTPCBadMask
|
|
|
|
The program counter of this frame is bad (for example, the
|
|
|
|
PC is misaligned or references unmapped memory).
|
|
|
|
|
|
|
|
@constant kQBTSignalHandlerMask
|
|
|
|
This frame represents the invocation of a signal handler.
|
|
|
|
*/
|
|
|
|
typedef int QBTFlags;
|
|
|
|
#define kQBTFrameBadMask 0x0001
|
|
|
|
#define kQBTPCBadMask 0x0002
|
|
|
|
#define kQBTSignalHandlerMask 0x0004
|
|
|
|
#if 0
|
|
|
|
enum QBTFlags {
|
|
|
|
kQBTFrameBadMask = 0x0001,
|
|
|
|
kQBTPCBadMask = 0x0002,
|
|
|
|
kQBTSignalHandlerMask = 0x0004
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*!
|
|
|
|
@struct QBTFrame
|
|
|
|
|
|
|
|
@abstract Describes a frame within a backtrace.
|
|
|
|
|
|
|
|
@discussion The end result of a backtrace is an array of QBTFrame
|
|
|
|
structures describing a particular frame in the backtrace.
|
|
|
|
|
|
|
|
IMPORTANT: The PC points to the code that's using the frame.
|
|
|
|
It is not the return address for that code. On architectures
|
|
|
|
where the frame holds the return address (Intel, but not
|
|
|
|
PowerPC), we do the appropriate corrections.
|
|
|
|
|
|
|
|
@field pc The PC for this function invocation.
|
|
|
|
|
|
|
|
@field fp The frame pointer for this function invocation.
|
|
|
|
|
|
|
|
@field flags Various flags; see QBTFlags above.
|
|
|
|
|
|
|
|
@field symbol Name of the symbol containing this PC. May be NULL.
|
|
|
|
|
|
|
|
IMPORTANT: The lifetime of this string is controlled by
|
|
|
|
various factors; see the discussion above for details.
|
|
|
|
|
|
|
|
@field library File path of the library containing this PC. May be NULL.
|
|
|
|
|
|
|
|
IMPORTANT: The lifetime of this string is controlled by
|
|
|
|
various factors; see the discussion above for details.
|
|
|
|
|
|
|
|
@field offset Offset from the symbol to the PC. Only valid if symbol
|
|
|
|
is not NULL.
|
|
|
|
*/
|
|
|
|
struct QBTFrame {
|
|
|
|
QTMAddr pc;
|
|
|
|
QTMAddr fp;
|
|
|
|
QBTFlags flags;
|
|
|
|
const char * symbol;
|
|
|
|
const char * library;
|
|
|
|
QTMOffset offset;
|
|
|
|
};
|
|
|
|
typedef struct QBTFrame QBTFrame;
|
|
|
|
|
|
|
|
/*!
|
|
|
|
@function QBacktraceMachSelf
|
|
|
|
|
|
|
|
@abstract Returns a backtrace of the current thread.
|
|
|
|
|
|
|
|
@discussion Returns a backtrace of the current thread in the array
|
|
|
|
described by frameArray and frameArrayCount. The number
|
|
|
|
of valid frames is returned in *frameCountPtr; this may
|
|
|
|
be larger than frameArrayCount.
|
|
|
|
|
|
|
|
IMPORTANT: You may need to call QBacktraceDisposeSymbols
|
|
|
|
on the resulting frames. See the detailed discussion of this
|
|
|
|
above.
|
|
|
|
|
|
|
|
@param symRef A symbols object for doing symbol to address translation
|
|
|
|
(and vice versa). This may be NULL, in which case the routine
|
|
|
|
will internally create the symbols object.
|
|
|
|
|
|
|
|
IMPORTANT: This parameter affects the lifecycle of the strings
|
|
|
|
returned in the frames array. See the discussion above for details.
|
|
|
|
|
|
|
|
@param frameArray
|
|
|
|
A pointer to an array of frame structures; this routine places
|
|
|
|
the backtrace into this array with the first element being the
|
|
|
|
most recent function invocation.
|
|
|
|
|
|
|
|
On entry, frameArray must not be NULL unless frameArrayCount
|
|
|
|
is zero.
|
|
|
|
|
|
|
|
On entry, if frameArray is not NULL, the contents of the array
|
|
|
|
are ignored.
|
|
|
|
|
|
|
|
On success, if frameArray is not NULL, then
|
|
|
|
MIN(frameArrayCount, *frameCountPtr) elements of the array
|
|
|
|
contain information. You must clean up these elements by
|
|
|
|
calling QBacktraceDisposeSymbols.
|
|
|
|
|
|
|
|
On error, you do not need to clean up this array.
|
|
|
|
|
|
|
|
@param frameArrayCount
|
|
|
|
The size of this array pointed to be frameArray. If this
|
|
|
|
is zero, frameArray may be NULL.
|
|
|
|
|
|
|
|
@param frameCountPtr
|
|
|
|
Returns the number of frames in the backtrace. On entry,
|
|
|
|
frameCountPtr must not be NULL and *frameCountPtr is ignored.
|
|
|
|
On success, *frameCountPtr contains the number frames in the
|
|
|
|
backtrace; this will not be zero. On error, *frameCountPtr
|
|
|
|
will be zero.
|
|
|
|
|
|
|
|
IMPORTANT: On success, *frameCountPtr may be greater than
|
|
|
|
frameArrayCount, in which case the backtrace contains more
|
|
|
|
frames than can be returned in frameArray. If you want to
|
|
|
|
get all of the frames, you can allocate a bigger frame array
|
|
|
|
and call this function again.
|
|
|
|
|
|
|
|
@result An errno-style error code per QTMErrnoFromMachError.
|
|
|
|
*/
|
|
|
|
extern int QBacktraceMachSelf(
|
|
|
|
QSymbolsRef symRef,
|
|
|
|
QBTFrame * frameArray,
|
|
|
|
size_t frameArrayCount,
|
|
|
|
size_t * frameCountPtr
|
|
|
|
);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
@function QBacktraceMachThread
|
|
|
|
|
|
|
|
@abstract Returns a backtrace of an arbitrary thread in an arbitrary process.
|
|
|
|
|
|
|
|
@discussion Returns a backtrace of the specified thread in the specified
|
|
|
|
process. Places the backtrace in the array described by
|
|
|
|
frameArray and frameArrayCount. The number of valid frames
|
|
|
|
is returned in *frameCountPtr; this may be larger than
|
|
|
|
frameArrayCount.
|
|
|
|
|
|
|
|
IMPORTANT: You may need to call QBacktraceDisposeSymbols
|
|
|
|
on the resulting frames. See the detailed discussion of this
|
|
|
|
above.
|
|
|
|
|
|
|
|
@param task Must be the name of a valid send right for the task control
|
|
|
|
port of the process to inspect; mach_task_self is just fine.
|
|
|
|
|
|
|
|
If you do pass in mach_task_self, this routine automatically
|
|
|
|
enables some nice optimisations.
|
|
|
|
|
|
|
|
@param thread Must be the name of a valid send right for the thread control
|
|
|
|
port of the thread to inspect. Passing in mach_thread_self is
|
|
|
|
just fine, although you'd probably be better off calling
|
|
|
|
QBacktraceMachSelf instead.
|
|
|
|
|
|
|
|
@param cputype The CPU type of the dynamic linker from which you want to get
|
|
|
|
the symbols. Typically you would pass CPU_TYPE_ANY to use
|
|
|
|
the first dynamic linker that's discovered. See
|
|
|
|
QMOImageCreateFromTaskDyld for a detailed discussion of this
|
|
|
|
value.
|
|
|
|
|
|
|
|
@param symRef A symbols object for doing symbol to address translation
|
|
|
|
(and vice versa). This may be NULL, in which case the routine
|
|
|
|
will internally create the symbols object.
|
|
|
|
|
|
|
|
IMPORTANT: This parameter affects the lifecycle of the strings
|
|
|
|
returned in the frames array. See the discussion above for details.
|
|
|
|
|
|
|
|
@param stackBottom
|
|
|
|
This parameter, along with stackTop, defines the extent of the
|
|
|
|
stack you are tracing. If this information isn't handy, supply
|
|
|
|
0 for both parameters. Supplying meaningful values can reduce
|
|
|
|
the number of bogus frames reported if the stack is corrupt.
|
|
|
|
|
|
|
|
stackBottom and stackTop must both be zero, or stackBottom
|
|
|
|
must be strictly less than stackTop.
|
|
|
|
|
|
|
|
@param stackTop See the discussion of stackBottom.
|
|
|
|
|
|
|
|
@param frameArray
|
|
|
|
A pointer to an array of frame structures; this routine places
|
|
|
|
the backtrace into this array with the first element being the
|
|
|
|
most recent function invocation.
|
|
|
|
|
|
|
|
On entry, frameArray must not be NULL unless frameArrayCount
|
|
|
|
is zero.
|
|
|
|
|
|
|
|
On entry, if frameArray is not NULL, the contents of the array
|
|
|
|
are ignored.
|
|
|
|
|
|
|
|
On success, if frameArray is not NULL, then
|
|
|
|
MIN(frameArrayCount, *frameCountPtr) elements of the array
|
|
|
|
contain information. You must clean up these elements by
|
|
|
|
calling QBacktraceDisposeSymbols.
|
|
|
|
|
|
|
|
On error, you do not need to clean up this array.
|
|
|
|
|
|
|
|
@param frameArrayCount
|
|
|
|
The size of this array pointed to be frameArray. If this
|
|
|
|
is zero, frameArray may be NULL.
|
|
|
|
|
|
|
|
@param frameCountPtr
|
|
|
|
Returns the number of frames in the backtrace. On entry,
|
|
|
|
frameCountPtr must not be NULL and *frameCountPtr is ignored.
|
|
|
|
On success, *frameCountPtr contains the number frames in the
|
|
|
|
backtrace; this will not be zero. On error, *frameCountPtr
|
|
|
|
will be zero.
|
|
|
|
|
|
|
|
IMPORTANT: On success, *frameCountPtr may be greater than
|
|
|
|
frameArrayCount, in which case the backtrace contains more
|
|
|
|
frames than can be returned in frameArray. If you want to
|
|
|
|
get all of the frames, you can allocate a bigger frame array
|
|
|
|
and call this function again.
|
|
|
|
|
|
|
|
@result An errno-style error code per QTMErrnoFromMachError.
|
|
|
|
*/
|
|
|
|
extern int QBacktraceMachThread(
|
|
|
|
task_t task,
|
|
|
|
thread_t thread,
|
|
|
|
cpu_type_t cputype,
|
|
|
|
QSymbolsRef symRef,
|
|
|
|
QTMAddr stackBottom,
|
|
|
|
QTMAddr stackTop,
|
|
|
|
QBTFrame * frameArray,
|
|
|
|
size_t frameArrayCount,
|
|
|
|
size_t * frameCountPtr
|
|
|
|
);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
@function QBacktraceMachThreadState
|
|
|
|
|
|
|
|
@abstract Returns a backtrace of a thread state within an arbitrary process.
|
|
|
|
|
|
|
|
@discussion Returns a backtrace of the specified thread state in the specified
|
|
|
|
process. Places the backtrace in the array described by
|
|
|
|
frameArray and frameArrayCount. The number of valid frames
|
|
|
|
is returned in *frameCountPtr; this may be larger than
|
|
|
|
frameArrayCount.
|
|
|
|
|
|
|
|
IMPORTANT: You may need to call QBacktraceDisposeSymbols
|
|
|
|
on the resulting frames. See the detailed discussion of this
|
|
|
|
above.
|
|
|
|
|
|
|
|
@param task Must be the name of a valid send right for the task control
|
|
|
|
port of the process to inspect; mach_task_self is just fine.
|
|
|
|
|
|
|
|
If you do pass in mach_task_self, this routine automatically
|
|
|
|
enables some nice optimisations.
|
|
|
|
|
|
|
|
@param stateFlavor
|
|
|
|
The thread state flavor of the thread state. For example,
|
|
|
|
you might pass in PPC_THREAD_STATE or x86_THREAD_STATE64.
|
|
|
|
|
|
|
|
@param state A pointer to a block of memory containing the thread state.
|
|
|
|
For example, if stateFlavor is PPC_THREAD_STATE, this would
|
|
|
|
point to a ppc_thread_state_t.
|
|
|
|
|
|
|
|
@param stateSize
|
|
|
|
The size of the thread state pointed to by the state parameter.
|
|
|
|
For example, if stateFlavor is PPC_THREAD_STATE, you could
|
|
|
|
pass in sizeof(ppc_thread_state_t). Equivalently, you could
|
|
|
|
pass in PPC_THREAD_STATE_COUNT * sizeof(integer_t).
|
|
|
|
|
|
|
|
@param cputype The CPU type of the dynamic linker from which you want to get
|
|
|
|
the symbols. Typically you would pass CPU_TYPE_ANY to use
|
|
|
|
the first dynamic linker that's discovered. See
|
|
|
|
QMOImageCreateFromTaskDyld for a detailed discussion of this
|
|
|
|
value.
|
|
|
|
|
|
|
|
@param symRef A symbols object for doing symbol to address translation
|
|
|
|
(and vice versa). This may be NULL, in which case the routine
|
|
|
|
will internally create the symbols object.
|
|
|
|
|
|
|
|
IMPORTANT: This parameter affects the lifecycle of the strings
|
|
|
|
returned in the frames array. See the discussion above for details.
|
|
|
|
|
|
|
|
@param stackBottom
|
|
|
|
This parameter, along with stackTop, defines the extent of the
|
|
|
|
stack you are tracing. If this information isn't handy, supply
|
|
|
|
0 for both parameters. Supplying meaningful values can reduce
|
|
|
|
the number of bogus frames reported if the stack is corrupt.
|
|
|
|
|
|
|
|
stackBottom and stackTop must both be zero, or stackBottom
|
|
|
|
must be strictly less than stackTop.
|
|
|
|
|
|
|
|
@param stackTop See the discussion of stackBottom.
|
|
|
|
|
|
|
|
@param frameArray
|
|
|
|
A pointer to an array of frame structures; this routine places
|
|
|
|
the backtrace into this array with the first element being the
|
|
|
|
most recent function invocation.
|
|
|
|
|
|
|
|
On entry, frameArray must not be NULL unless frameArrayCount
|
|
|
|
is zero.
|
|
|
|
|
|
|
|
On entry, if frameArray is not NULL, the contents of the array
|
|
|
|
are ignored.
|
|
|
|
|
|
|
|
On success, if frameArray is not NULL, then
|
|
|
|
MIN(frameArrayCount, *frameCountPtr) elements of the array
|
|
|
|
contain information. You must clean up these elements by
|
|
|
|
calling QBacktraceDisposeSymbols.
|
|
|
|
|
|
|
|
On error, you do not need to clean up this array.
|
|
|
|
|
|
|
|
@param frameArrayCount
|
|
|
|
The size of this array pointed to be frameArray. If this
|
|
|
|
is zero, frameArray may be NULL.
|
|
|
|
|
|
|
|
@param frameCountPtr
|
|
|
|
Returns the number of frames in the backtrace. On entry,
|
|
|
|
frameCountPtr must not be NULL and *frameCountPtr is ignored.
|
|
|
|
On success, *frameCountPtr contains the number frames in the
|
|
|
|
backtrace; this will not be zero. On error, *frameCountPtr
|
|
|
|
will be zero.
|
|
|
|
|
|
|
|
IMPORTANT: On success, *frameCountPtr may be greater than
|
|
|
|
frameArrayCount, in which case the backtrace contains more
|
|
|
|
frames than can be returned in frameArray. If you want to
|
|
|
|
get all of the frames, you can allocate a bigger frame array
|
|
|
|
and call this function again.
|
|
|
|
|
|
|
|
@result An errno-style error code per QTMErrnoFromMachError.
|
|
|
|
*/
|
|
|
|
extern int QBacktraceMachThreadState(
|
|
|
|
task_t task,
|
|
|
|
thread_state_flavor_t stateFlavor,
|
|
|
|
const void * state,
|
|
|
|
size_t stateSize,
|
|
|
|
cpu_type_t cputype,
|
|
|
|
QSymbolsRef symRef,
|
|
|
|
QTMAddr stackBottom,
|
|
|
|
QTMAddr stackTop,
|
|
|
|
QBTFrame * frameArray,
|
|
|
|
size_t frameArrayCount,
|
|
|
|
size_t * frameCountPtr
|
|
|
|
);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
@function QBacktraceDisposeSymbols
|
|
|
|
|
|
|
|
@abstract Disposes of the symbol and library strings in a frame array.
|
|
|
|
It is safe to call this function on a frame array that is all
|
|
|
|
zeroes. It is safe to call this function on a frame array
|
|
|
|
that has been passed to any of the backtrace routines,
|
|
|
|
regardless of whether they succeeded or not.
|
|
|
|
|
|
|
|
@discussion Disposes of the symbol and library strings in the specified
|
|
|
|
frame array.
|
|
|
|
|
|
|
|
@param frameArray
|
|
|
|
A pointer to an array of frames with frameCount elements.
|
|
|
|
You may pass NULL, in which case the routine does nothing.
|
|
|
|
|
|
|
|
@param frameCount
|
|
|
|
The size of the array pointed to be frameArray.
|
|
|
|
*/
|
|
|
|
extern void QBacktraceDisposeSymbols(QBTFrame frameArray[], size_t frameCount);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
@function QBTCreateThreadState
|
|
|
|
|
|
|
|
@abstract Gets the thread state of the specified thread.
|
|
|
|
|
|
|
|
@discussion Allocates a memory block and stores the thread state of the
|
|
|
|
specified thread into it.
|
|
|
|
|
|
|
|
To get this information, the routine must inspect the task
|
|
|
|
to see what architecture it's running. Doing this requires a
|
|
|
|
reference to an image object within the task. If you pass
|
|
|
|
in a symbols object, the routine will get it from that.
|
|
|
|
Otherwise, it will create its own temporary image object
|
|
|
|
internally, and to do that it needs you to tell it what
|
|
|
|
CPU type you're interested in.
|
|
|
|
|
|
|
|
@param task Must be the name of a valid send right for the task control
|
|
|
|
port of the process containing the thread; mach_task_self is
|
|
|
|
just fine.
|
|
|
|
|
|
|
|
@param thread Must be the name of a valid send right for the thread control
|
|
|
|
port of the thread whose state you want. Passing mach_thread_self
|
|
|
|
will work, although it won't yield useful results (because
|
|
|
|
the thread state will be for the thread as it entered the
|
|
|
|
kernel in the thread_get_state call, and that state is no
|
|
|
|
longer useful; specifically, the frames that the state refers
|
|
|
|
to have already been destroyed).
|
|
|
|
|
|
|
|
@param cputype This parameter is only consulted if the symRef is parameter
|
|
|
|
is NULL. In that case, the routine has to create an image
|
|
|
|
object for some Mach-O image inside the task and this value
|
|
|
|
controls which dynamic linker it finds. Typically you would
|
|
|
|
pass CPU_TYPE_ANY to use the first dynamic linker that's discovered.
|
|
|
|
See QMOImageCreateFromTaskDyld for a detailed discussion of this
|
|
|
|
value.
|
|
|
|
|
|
|
|
@param symRef A symbols object from which the routine can get an image object
|
|
|
|
for the dynamic linker within the task. This may be NULL,
|
|
|
|
in which case the routine will internally create its own
|
|
|
|
temporary image object.
|
|
|
|
|
|
|
|
@param stateFlavorPtr
|
|
|
|
Must not be NULL. On success, *stateFlavorPtr will contain
|
|
|
|
the thread state flavor for the thread state that's being
|
|
|
|
returned.
|
|
|
|
|
|
|
|
@param statePtr
|
|
|
|
Must not be NULL. On entry, *statePtr must be NULL. On
|
|
|
|
success, *statePtr will contain a pointer to a newly allocated
|
|
|
|
thread state block. The caller is responsible for freeing
|
|
|
|
that memory.
|
|
|
|
|
|
|
|
On error, *statePtr will be NULL.
|
|
|
|
|
|
|
|
@param stateSizePtr
|
|
|
|
Must not be NULL. On success, *stateSizePtr will contain
|
|
|
|
the size of the thread state that's being returned.
|
|
|
|
|
|
|
|
@result An errno-style error code per QTMErrnoFromMachError.
|
|
|
|
*/
|
|
|
|
extern int QBTCreateThreadState(
|
|
|
|
task_t task,
|
|
|
|
thread_t thread,
|
|
|
|
cpu_type_t cputype,
|
|
|
|
QSymbolsRef symRef,
|
|
|
|
thread_state_flavor_t * stateFlavorPtr,
|
|
|
|
void ** statePtr,
|
|
|
|
size_t * stateSizePtr
|
|
|
|
);
|
|
|
|
|
|
|
|
/*!
|
|
|
|
@function QBTCreateThreadStateSelf
|
|
|
|
|
|
|
|
@abstract Gets the thread state of the current thread.
|
|
|
|
|
|
|
|
@discussion Allocates a memory block and stores the thread state of the
|
|
|
|
current thread into it. This state contains only the
|
|
|
|
information needed to do a backtrace; this is architecture
|
|
|
|
dependent, but it is typically the stack pointer, frame pointer
|
|
|
|
and program counter. These correspond to the frame of the
|
|
|
|
caller of this routine.
|
|
|
|
|
|
|
|
IMPORTANT: This routine has the no-inline attribute because,
|
|
|
|
if you inlined it, you'd break its semantics.
|
|
|
|
|
|
|
|
@param stateFlavorPtr
|
|
|
|
Must not be NULL. On success, *stateFlavorPtr will contain
|
|
|
|
the thread state flavor for the thread state that's being
|
|
|
|
returned.
|
|
|
|
|
|
|
|
@param statePtr
|
|
|
|
Must not be NULL. On entry, *statePtr must be NULL. On
|
|
|
|
success, *statePtr will contain a pointer to a newly allocated
|
|
|
|
thread state block. The caller is responsible for freeing
|
|
|
|
that memory.
|
|
|
|
|
|
|
|
On error, *statePtr will be NULL.
|
|
|
|
|
|
|
|
@param stateSizePtr
|
|
|
|
Must not be NULL. On success, *stateSizePtr will contain
|
|
|
|
the size of the thread state that's being returned.
|
|
|
|
|
|
|
|
@result An errno-style error code per QTMErrnoFromMachError.
|
|
|
|
*/
|
|
|
|
extern int QBTCreateThreadStateSelf(
|
|
|
|
thread_state_flavor_t * stateFlavorPtr,
|
|
|
|
void ** statePtr,
|
|
|
|
size_t * stateSizePtr
|
|
|
|
) __attribute__((noinline));
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endif
|