boinc/lib/mac/QTaskMemory.h

427 lines
17 KiB
C

// This file is part of BOINC.
// http://boinc.berkeley.edu
// Copyright (C) 2008 University of California
//
// 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.
//
// BOINC is distributed in the hope that it will be useful,
// 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.
//
// You should have received a copy of the GNU Lesser General Public License
// along with BOINC. If not, see <http://www.gnu.org/licenses/>.
/*
* QTaskMemory.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: QTaskMemory.h
Contains: Task memory access abstraction.
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: QTaskMemory.h,v $
Revision 1.1 2007/03/02 12:20:40
First checked in.
*/
#ifndef _QTASKMEMORY_H
#define _QTASKMEMORY_H
/////////////////////////////////////////////////////////////////
#include <stdbool.h>
// 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
/////////////////////////////////////////////////////////////////
#ifdef __cplusplus
extern "C" {
#endif
/*!
@header QTaskMemory.h
@abstract Abstraction layer for reading another process's memory.
@discussion This module lets you read memory from another task. It's implemented
using Mach APIs that are designed for that very job. The purpose of
this module is to make those routines easier to call, handling the
various nasty compatibility problems that arise. See the comments
inside "QTaskMemory.c" for the gory details.
When using this module, keep in mind that addresses within a remote
task are represented by an unsigned 64-bit integer (QTMAddr). This
is necessary because it lets a 32-bit tool examine a 64-bit task.
-- Changed for BOINC: See comments in QTaskMemory.c
Because of oddities in the underlying infrastructure (specifically,
mach_vm_read does odd things if you ask for a size of zero -- it
returns KERN_SUCCESS, addrLocal == 0, bytesRead == 0), we don't
allow clients to request a size of zero.
*/
/*!
@functiongroup Main Interface
*/
/////////////////////////////////////////////////////////////////
#pragma mark ***** Main Interface
/*!
@typedef QTMAddr
@abstract Represents an address within a task.
@discussion This type represents an address within a task. We can't just
use use (void *) because we need to be able to represent 64-bit
addresses, even if we're built 32-bit.
*/
#if TARGET_CPU_X86 || TARGET_CPU_X86_64
typedef mach_vm_address_t QTMAddr;
#else
typedef uint64_t QTMAddr;
#endif
/*!
@typedef QTMOffset
@abstract Represents a byte offset between two QTMAddrs.
@discussion This type represents a byte offset between two QTMAddrs. We
can't just use use ptrdiff_t or size_t because we need to be
able to represent a 64-bit offset, even if we're built 32-bit.
*/
#if TARGET_CPU_X86 || TARGET_CPU_X86_64
typedef mach_vm_offset_t QTMOffset;
#else
typedef uint64_t QTMOffset;
#endif
/*!
@function QTMRead
@abstract Reads memory from a task.
@discussion Read size bytes from addrWithinTask of the task to the buffer
specified by addrLocal. There are no partial results; you
either get size bytes of data or an error.
@param task Must be the name of a valid send right for the task control
port of the task whose memory you want to read; mach_task_self
is just fine.
@param addrWithinTask
The address within that task of the memory you want to read.
@param size The number of bytes that you want to read; there must be this
many bytes available in the buffer pointed to by addrLocal.
It must not be zero.
@param addrLocal
The address of the buffer into which you want to read the bytes.
@result An errno-style error code per QTMErrnoFromMachError.
*/
extern int QTMRead(task_t task, QTMAddr addrWithinTask, size_t size, void *addrLocal);
/*!
@function QTMReadAllocated
@abstract Allocates a buffer and reads memory from a task into it.
@discussion Read size bytes from addrWithinTask of the task to a newly
allocated buffer, and return a pointer to that buffer in *bufPtr.
The client is responsible for freeing the buffer by calling QTMFree.
@param task Must be the name of a valid send right for the task control
port of the task whose memory you want to read; mach_task_self
is just fine.
@param addrWithinTask
The address within that task of the memory you want to read.
@param size The number of bytes that you want to read. It must not be zero.
@param bufPtr On entry, bufPtr must not be NULL and *bufPtr must be NULL.
On success, *bufPtr will point to a buffer of at least size bytes.
You must free the buffer by calling QTMFree.
On failure, *bufPtr will be NULL.
@result An errno-style error code per QTMErrnoFromMachError.
*/
extern int QTMReadAllocated(task_t task, QTMAddr addrWithinTask, size_t size, const void **bufPtr);
/*!
@function QTMRemap
@abstract Maps memory from a task into your address space.
@discussion Maps size bytes of memory from addrWithinTask to the current
task and returns the address of the newly mapped data in *bufPtr.
The client is responsible for freeing the buffer by calling
QTMFree.
@param task Must be the name of a valid send right for the task control
port of the task whose memory you want to map; mach_task_self
is just fine.
@param addrWithinTask
The address within that task of the memory you want to map.
@param size The number of bytes that you want to map. It must not be zero.
@param bufPtr On entry, bufPtr must not be NULL and *bufPtr must be NULL.
On success, *bufPtr will point to a buffer of at least size bytes.
You must free the buffer by calling QTMFree.
On failure, *bufPtr will be NULL.
@result An errno-style error code per QTMErrnoFromMachError.
*/
extern int QTMRemap(task_t task, QTMAddr addrWithinTask, size_t size, const void **bufPtr);
/*!
@function QTMFree
@abstract Free data returned by QTMReadAllocated or QTMRemap.
@discussion Free data returned by QTMReadAllocated or QTMRemap.
@param buf The buffer to free. This may be NULL, in which case the routine
does nothing.
@param size The size of the buffer to free. If buf is NULL, this value
is ignored. If buf is not NULL, this must bee the same value
as passed to the routine that allocated the memory (and hence
must not be 0).
*/
extern void QTMFree(const void *buf, size_t size);
/*!
@functiongroup Utilities
*/
/////////////////////////////////////////////////////////////////
#pragma mark ***** Utilities
/*!
@function QTMErrnoFromMachError
@abstract Converts a Mach error code to a errno-style error code.
@discussion Various other modules call Mach directly for various reasons,
and these need to translate Mach-style errors into errno-style
errors. This module already has a helper routine to do that
job, so I export it.
IMPORTANT:
This routine can still return errors outside of the errno range.
What it does is as follows:
1. If the Mach error is something obvious that we recognise,
map it to a specific errno-style error.
2. Failing that, if the Mach error is outside of the errno
range (and thus it's not ambiguous as to whether the error
is a Mach error or an errno error), just return it.
3. For unrecognised Mach errors within the errno range, just
return EINVAL.
The upshot is that if an error is outside of the errno range
[0..ELAST], you should treat it as a Mach error.
@param kr A Mach error code.
@result An errno-style error code.
*/
extern int QTMErrnoFromMachError(kern_return_t kr);
/*!
@enum QTMDarwinOSMajor
@abstract Constants for Darwin OS release major values.
@constant kQTMDarwinOSMajorForMacOSX102
The Darwin OS release major value for Mac OS X 10.2.x.
@constant kQTMDarwinOSMajorForMacOSX103
The Darwin OS release major value for Mac OS X 10.3.x.
@constant kQTMDarwinOSMajorForMacOSX104
The Darwin OS release major value for Mac OS X 10.4.x.
*/
enum QTMDarwinOSMajor {
kQTMDarwinOSMajorForMacOSX102 = 6,
kQTMDarwinOSMajorForMacOSX103 = 7,
kQTMDarwinOSMajorForMacOSX104 = 8
};
/*!
@function QTMGetDarwinOSRelease
@abstract Returns the Darwin OS release numbers.
@discussion Returns the Darwin OS release numbers for the current
system. It gets these values by calling uname and parsing
the results. For example, the major/minor/bug values for
Mac OS X 10.4.8 will be 8/8/x (where x is dependent on the
particular release).
This is useful in environments, like a 64-bit process running
on Mac OS X 10.4.x, where you can't get gestaltSystemVersion.
@param majorPtr May be NULL, in which case no value is return. Otherwise,
on entry, *majorPtr is ignored and, on success, *majorPtr
will be set to the Darwin OS release major component.
@param minorPtr May be NULL, in which case no value is return. Otherwise,
on entry, *minorPtr is ignored and, on success, *minorPtr
will be set to the Darwin OS release minor component.
@param bugPtr May be NULL, in which case no value is return. Otherwise,
on entry, *bugPtr is ignored and, on success, *bugPtr
will be set to the Darwin OS release bug fix component.
@result An errno-style error number.
*/
extern int QTMGetDarwinOSRelease(int *majorPtr, int *minorPtr, int *bugPtr);
// Get the Darwin OS release using uname. I can't use gestaltSystemVersion
// because it's part of CoreServices, and CoreServices is not available
// to 64-bit programs on Mac OS X 10.4.x.
/*!
@function QTMTaskIs64Bit
@abstract Determines whether a task is 64-bit.
@discussion Returns true if the specified task is 64-bit.
@param task Must be the name of a valid send right for the task control
port of the task; mach_task_self should work just fine.
@result Returns true if the task is 64-bit and false otherwise.
If something goes wrong, you get the default value of false.
*/
extern bool QTMTaskIs64Bit(task_t task);
/*!
@function QTMTaskIsNative
@abstract Determines whether a task is native.
@discussion Returns false if the specified task is being run using Rosetta.
@param task Must be the name of a valid send right for the task control
port of the task; mach_task_self should work just fine.
@result Returns false if the task is being run by Rosetta and false
otherwise.
If something goes wrong, you get the default value of true.
*/
extern bool QTMTaskIsNative(task_t task);
// I'm not ever going to try to explain how this works (-:
//
// Apple doesn't generally recommend, and hence doesn't officially document,
// the Mach API. If you search the web for "vm_region", you'll find our
// unofficial documentation.
#ifdef __cplusplus
}
#endif
#endif