home *** CD-ROM | disk | FTP | other *** search
- /*
- File: DebuggerSupport.h
-
- Contains: Public interface to kernel services for debuggers
-
- Version: Technology: System 8
- Release: Universal Interfaces 3.0d3 on Copland DR1
-
- Copyright: © 1984-1996 by Apple Computer, Inc. All rights reserved.
-
- Bugs?: If you find a problem with this file, send the file and version
- information (from above) and the problem description to:
-
- Internet: apple.bugs@applelink.apple.com
- AppleLink: APPLE.BUGS
-
- */
- #ifndef __DEBUGGERSUPPORT__
- #define __DEBUGGERSUPPORT__
-
- #ifndef __TYPES__
- #include <Types.h>
- #endif
- #ifndef __KERNEL__
- #include <Kernel.h>
- #endif
- #ifndef __MACHINEEXCEPTIONS__
- #include <MachineExceptions.h>
- #endif
-
- #ifdef __cplusplus
- extern "C" {
- #endif
-
- #if PRAGMA_IMPORT_SUPPORTED
- #pragma import on
- #endif
-
- #if PRAGMA_ALIGN_SUPPORTED
- #pragma options align=power
- /* the following contents can only be used by compilers that support PowerPC struct alignment */
-
- #if FOR_SYSTEM8_PREEMPTIVE
- /*
- In addition to the normal kernel API, the kernel provides a set of services
- which are specific to debuggers. These services are all accessed through the
- DebuggerSupport library.
- This first service is debugger registration and unregistration. For a debugger
- to register itself with the kernel, it calls DSRegisterDebugger. (The kernel
- allows only one registered debugger; multiple debuggers can be supported
- externally by registering a dispatching entity as the debugger.) When a debugger
- has successfully registered itself, it is able to receive exceptions from
- debuggable tasks. Unregistering is simply the reverse of registering. The
- kernel automatically unregisters a debugger when it terminates if the debugger
- has not already unregistered itself. DSRegisterDebugger should be the first
- call made to this library.
- To receive an exception, the debugger calls DSWaitForException, passing it a
- pointer to a DSExceptionRecord and a time limit. This call blocks until either
- an exception arrives or the time limit expires (pass kDurationForever to wait
- indefinitely). Note that this semantic essentially requires the debugger to
- be multithreaded.
- A DSExceptionRecord contains the ID of the excepted task, along with the IDs
- of the task's team and address space, and a message ID corresponding to the
- particular exception. The details of the exception are contained in the
- exception record's ExceptionInformation structure, which includes pointers
- to the task's registers and other exception state. The debugger may directly
- modify this exception data, and, within limits, these changes will be forced
- into the task's state upon resuming execution. (Changes to certain parts of
- the exception data, such as the privileged and interrupt enable bits of the
- exception MSR, will be ignored.)
- DSResumeFromException is used to resume the excepted task's execution or to
- propagate the exception on. It takes as parameters the exception ID and an
- exception return status. The status may be either noErr or any nonzero error
- code. noErr signifies that the debugger has cured the exception and the excepted
- task should continue execution, using the state from the exception data. Any
- other status value will cause the exception to be propagated to the installed
- exception handler, if any. If there is no installed handler, or if that handler
- fails to cure the exception, the exception is again presented to the debugger in
- another message. This time, returning a nonzero return status will cause the
- task to be terminated. (Double notification of exceptions allows a debugger to
- catch exceptions either first, last, or at both times.)
- Not all exceptions will be sent to the debugger. Exceptions in kernel tasks
- or in kernel code which runs on behalf of user tasks is not debuggable through
- normal means. Furthermore, exceptions occurring in privileged tasks with
- hardware interrupts disabled, or during execution at secondary interrupt level,
- or while running message system Accept functions, fall into the same category
- as kernel exceptions and are not sent to the debugger.
- The debugger may call DSHoldTasks to request the kernel to hold a task or set
- of tasks, making them ineligible for execution. The tasks are specified with a
- task ID and scope (task only, task and children, task family, or task team). If
- any task to be held is already blocked inside the kernel, e.g. due to a page
- fault, I/O operation, or message send, holding it will cause it to remain
- ineligible even after it has unblocked. Releasing held tasks with DSReleaseTasks
- allows them to become eligible again.
- DSGetTaskState is used to determine a task's scheduler state (runnable or blocked),
- and, if blocked, what its PC and SP values were at the point it blocked. If a
- task is running a software interrupt it will have scheduler state for both its
- normal execution and the execution of the software interrupt.
- DSReadMemory and DSWriteMemory are used to access task memory. To read memory,
- the debugger simply calls DSReadMemory. To modify memory, the debugger must first
- call DSCreateMemoryAccess to obtain a memory write access right to the desired page
- of memory. Using that access right, it may then call DSWriteMemory to perform the
- modification. DSWriteMemory performs appropriate processor cache synchronization and
- backing storage coordination to support modifying code memory, e.g. for instruction
- breakpoints. DSDeleteMemoryAccess is used to release an access right.
- Some implementations of the kernel and hardware may support data breakpoints. To
- find out what data breakpoint support (if any) is available, the debugger calls
- DSGetDataBreakpointInformation. DSSetDataBreakpoint is used to set or clear a
- data breakpoint. The implementation may cause excess exceptions which will have to
- be filtered out by the debugger: breakpoints may occur in the wrong address space
- or on an address which is outside the range specified but which lies within the
- resolution range supported by the implementation.
- Exception notification record
- */
- struct DSExceptionRecord {
- TaskID exceptedTaskID;
- KernelProcessID exceptedKernelProcessID;
- AddressSpaceID exceptedTaskAddrSpaceID;
- MessageID exceptionID;
- ExceptionInformation exception;
- };
- typedef struct DSExceptionRecord DSExceptionRecord;
-
- typedef DSExceptionRecord *DSExceptionRecordPtr;
- /* Task state record*/
- struct DSKernelState {
- SchedulerState kernelState;
- LogicalAddress PC;
- LogicalAddress SP;
- };
- typedef struct DSKernelState DSKernelState;
-
- typedef DSKernelState *DSKernelStatePtr;
- struct DSTaskState {
- DSKernelState taskState;
- DSKernelState swiState;
- };
- typedef struct DSTaskState DSTaskState;
-
- typedef DSTaskState *DSTaskStatePtr;
- /* ID to specify write access rights to a particular page in logical memory*/
- typedef struct OpaqueDSMemoryAccessID* DSMemoryAccessID;
- /* SchedulerState values*/
-
- enum {
- kInactiveState = ' ',
- kPageFaultState = 'PFLT',
- kMessageSendState = 'MSND',
- kMessageReceiveState = 'MRCV',
- kHeldState = 'HELD',
- kEventFlagState = 'EFLG',
- kTerminatingOtherProcessState = 'OTRM',
- kTerminatingCurrentProcessState = 'CTRM',
- kTimerDelayState = 'DLYQ',
- kKernelQueueState = 'QBLK',
- kRunState = 'RUN ',
- kSemaphoreReadState = 'MSRD',
- kSemaphoreWriteState = 'MSWR',
- kTaskStartingState = 'STRT',
- kTaskTerminatingState = 'TERM'
- };
-
- /*
- Describes the data breakpoint facility provided by the current implementation.
- maxBreakpoints is the maximum number of data breakpoints available (may be zero).
- breakpointResolution determines the worst case range of addresses to which a data
- breakpoint applies, as follows: if the nominal breakpoint address is addr, the
- actual range of addresses breakpointed may, in the worst case, be
- [(addr & ~(breakpointResolution - 1)) ..
- (addr & ~(breakpointResolution - 1)) + breakpointResolution - 1].
- */
- struct DSDataBreakpointInformation {
- ItemCount maxBreakpoints;
- ByteCount breakpointResolution;
- };
- typedef struct DSDataBreakpointInformation DSDataBreakpointInformation;
-
- typedef DSDataBreakpointInformation *DSDataBreakpointInformationPtr;
-
- enum {
- kDataBreakpointInformationVersion = 1
- };
-
- /*
- The access types to which a data breakpoint should apply. Use
- kDSBreakDisable to clear a data breakpoint. Note that the implementation
- may not support breakpointing read and write accesses independently; in
- that case specifying either option will have the same effect (break on
- any access).
- */
- typedef OptionBits DSDataBreakpointOptions;
-
- enum {
- kDSBreakDisable = 0x00000000,
- kDSBreakOnReadAccess = 0x00000001,
- kDSBreakOnWriteAccess = 0x00000002
- };
-
- /*
- Debugger Services functions
- Register the debugger. Returns kernelIDErr if there is already a debugger
- registered.
- */
- extern OSStatus DSRegisterDebugger(void );
-
- /*
- Unregister the debugger. This is also done automatically by the kernel if
- the debugger terminates.
- */
- extern OSStatus DSUnregisterDebugger(void );
-
- /* Wait specified amount of time for an exception message from the kernel.*/
- extern OSStatus DSWaitForException(DSExceptionRecord *exceptionRecord, Duration timeLimit);
-
- /*
- Resume execution of a task halted by an earlier exception. If exceptionReturnStatus
- is noErr, resume the task, else propagate the exception. If the propagated exception
- remains unhandled, a second exception notification will be generated.
- */
- extern OSStatus DSResumeFromException(MessageID exceptionID, OSStatus exceptionReturnStatus);
-
- /* Make the specified task(s) ineligible for execution, until released by DSReleaseTasks.*/
- extern OSStatus DSHoldTasks(TaskID taskID, TaskRelationship scope);
-
- /* Make the specified held task(s) eligible again for execution.*/
- extern OSStatus DSReleaseTasks(TaskID taskID, TaskRelationship scope);
-
- /*
- Get the scheduler state for a task. The task may be in a software interrupt or in
- normal execution; if normal, state->swiState.kernelState will be kInactiveState. In
- either case, the appropriate state->taskState.kernelState or state->swiState.kernelState
- will be kRunState if the task is running, and if so the corresponding PC and SP values
- are invalid and will be returned as zero. If the task is blocked in normal execution
- then state->taskState.PC and state->taskState.SP will reflect the PC and SP at the time
- of the system call which caused the task to block. Similarly, if the task is blocked
- in a software interrupt, hence not running, then state->swiState.PC and state->swiState.SP
- will be nonzero.
- */
- extern OSStatus DSGetTaskState(TaskID taskID, DSTaskState *state);
-
- /*
- Create a write access right to the page for logical address dstAddr in address
- space addrSpaceID. This makes the page physically resident and prevents subsequent
- reads or writes of the page from or to backing storage. The access right is returned
- in memAccessID.
- */
- extern OSStatus DSCreateMemoryAccess(AddressSpaceID addrSpaceID, LogicalAddress dstAddr, DSMemoryAccessID *memAccessID);
-
- /*
- Modify the memory to which an access right has been obtained. memAccessID is the access
- right, dstAddr is the target address, srcDataPtr points to the source data to be written,
- and numBytes is the size of the write. The range [dstAddr..dstAddr + numBytes - 1] must lie
- entirely within the page specified by the access right. If the destination memory is code,
- processor caches will be synchronized appropriately.
- */
- extern OSStatus DSWriteMemory(DSMemoryAccessID memAccessID, LogicalAddress dstAddr, void *srcDataPtr, ByteCount numBytes);
-
- /*
- Delete an access right and allow normal backing storage activity for that page. memAccessID
- is the access right. Note: changes to the page up to this point will NOT be written to
- backing storage.
- */
- extern OSStatus DSDeleteMemoryAccess(DSMemoryAccessID memAccessID);
-
- /*
- Read memory. srcAddr is the address to read from, addrSpaceID specifies the address space,
- dstDataPtr points to the debugger buffer into which to copy the data, and numBytes is the
- size of the read.
- */
- extern OSStatus DSReadMemory(AddressSpaceID addrSpaceID, LogicalAddress srcAddr, void *dstDataPtr, ByteCount numBytes);
-
- /*
- Set a data breakpoint. addrSpaceID specifies the address space, which may or may not be
- used. breakAddr is the logical address to break on. numBytes is a hint as to the range
- of addresses to break on. The address range [breakAddr .. (breakAddr + numBytes -1)] must
- lie within the worst case data breakpoint resolution which the implmentation supports, as
- determined via DSGetDataBreakpointInformation. A data breakpoint hit will result in a
- memory access exception of type kDataBreakpointException. The implementation may cause
- excess exceptions which will have to be filtered out by the debugger, e.g. breakpoints
- may occur in the wrong address space or on an address which is outside the range specified
- but which lies within the resolution range supported by the implementation. To "fix up"
- a memory reference which triggered a data breakpoint exception without removing the
- data breakpoint, use DSReadMemory or DSWriteMemory. Data breakpoints may be disallowed
- on certain addresses which are used by system code; DSSetDataBreakpoint will return
- kernelInUseErr for such addresses.
- */
- extern OSStatus DSSetDataBreakpoint(AddressSpaceID addrSpaceID, LogicalAddress breakAddr, ByteCount numBytes, DSDataBreakpointOptions options);
-
- /*
- Get information about data breakpoint support. Returns the number of breakpoints available in
- the current implementation and the worst case address resolution of a data breakpoint.
- */
- extern OSStatus DSGetDataBreakpointInformation(PBVersion version, DSDataBreakpointInformation *info);
-
- #endif
-
- #pragma options align=reset
- #endif /* PRAGMA_ALIGN_SUPPORTED */
-
- #if PRAGMA_IMPORT_SUPPORTED
- #pragma import off
- #endif
-
- #ifdef __cplusplus
- }
- #endif
-
- #endif /* __DEBUGGERSUPPORT__ */
-
-