Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
tree: 4f40dd8905
Fetching contributors…

Cannot retrieve contributors at this time

644 lines (593 sloc) 19.049 kb
/*
* tkMacOSXDebug.c --
*
* Implementation of Macintosh specific functions for debugging MacOS
* events, regions, etc...
*
* Copyright 2001, Apple Computer, Inc.
* Copyright (c) 2006-2007 Daniel A. Steffen <das@users.sourceforge.net>
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
* The following terms apply to all files originating from Apple
* Computer, Inc. ("Apple") and associated with the software
* unless explicitly disclaimed in individual files.
*
*
* Apple hereby grants permission to use, copy, modify,
* distribute, and license this software and its documentation
* for any purpose, provided that existing copyright notices are
* retained in all copies and that this notice is included
* verbatim in any distributions. No written agreement, license,
* or royalty fee is required for any of the authorized
* uses. Modifications to this software may be copyrighted by
* their authors and need not follow the licensing terms
* described here, provided that the new terms are clearly
* indicated on the first page of each file where they apply.
*
*
* IN NO EVENT SHALL APPLE, THE AUTHORS OR DISTRIBUTORS OF THE
* SOFTWARE BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
* INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF
* THIS SOFTWARE, ITS DOCUMENTATION, OR ANY DERIVATIVES THEREOF,
* EVEN IF APPLE OR THE AUTHORS HAVE BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE. APPLE, THE AUTHORS AND
* DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS
* SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND APPLE,THE
* AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
* MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*
* GOVERNMENT USE: If you are acquiring this software on behalf
* of the U.S. government, the Government shall have only
* "Restricted Rights" in the software and related documentation
* as defined in the Federal Acquisition Regulations (FARs) in
* Clause 52.227.19 (c) (2). If you are acquiring the software
* on behalf of the Department of Defense, the software shall be
* classified as "Commercial Computer Software" and the
* Government shall have only "Restricted Rights" as defined in
* Clause 252.227-7013 (c) (1) of DFARs. Notwithstanding the
* foregoing, the authors grant the U.S. Government and others
* acting in its behalf permission to use and distribute the
* software in accordance with the terms specified in this
* license.
*/
#include "tkMacOSXPrivate.h"
#include "tkMacOSXDebug.h"
#ifdef TK_MAC_DEBUG
typedef struct {
EventKind kind;
const char * name;
} MyEventName;
typedef struct {
EventClass c;
MyEventName * names;
} MyEventNameList;
static MyEventName windowEventNames [] = {
{ kEventWindowUpdate,"Update"},
{ kEventWindowDrawContent,"DrawContent"},
{ kEventWindowActivated,"Activated"},
{ kEventWindowDeactivated,"Deactivated"},
{ kEventWindowGetClickActivation,"GetClickActivation"},
{ kEventWindowShowing,"Showing"},
{ kEventWindowHiding,"Hiding"},
{ kEventWindowShown,"Shown"},
{ kEventWindowHidden,"Hidden"},
{ kEventWindowBoundsChanging,"BoundsChanging"},
{ kEventWindowBoundsChanged,"BoundsChanged"},
{ kEventWindowResizeStarted,"ResizeStarted"},
{ kEventWindowResizeCompleted,"ResizeCompleted"},
{ kEventWindowDragStarted,"DragStarted"},
{ kEventWindowDragCompleted,"DragCompleted"},
{ kEventWindowClickDragRgn,"ClickDragRgn"},
{ kEventWindowClickResizeRgn,"ClickResizeRgn"},
{ kEventWindowClickCollapseRgn,"ClickCollapseRgn"},
{ kEventWindowClickCloseRgn,"ClickCloseRgn"},
{ kEventWindowClickZoomRgn,"ClickZoomRgn"},
{ kEventWindowClickContentRgn,"ClickContentRgn"},
{ kEventWindowClickProxyIconRgn,"ClickProxyIconRgn"},
{ kEventWindowCursorChange,"CursorChange" },
{ kEventWindowCollapse,"Collapse"},
{ kEventWindowCollapsed,"Collapsed"},
{ kEventWindowCollapseAll,"CollapseAll"},
{ kEventWindowExpand,"Expand"},
{ kEventWindowExpanded,"Expanded"},
{ kEventWindowExpandAll,"ExpandAll"},
{ kEventWindowCollapse,"Collapse"},
{ kEventWindowClose,"Close"},
{ kEventWindowClosed,"Closed"},
{ kEventWindowCloseAll,"CloseAll"},
{ kEventWindowZoom,"Zoom"},
{ kEventWindowZoomed,"Zoomed"},
{ kEventWindowZoomAll,"ZoomAll"},
{ kEventWindowContextualMenuSelect,"ContextualMenuSelect"},
{ kEventWindowPathSelect,"PathSelect"},
{ kEventWindowGetIdealSize,"GetIdealSize"},
{ kEventWindowGetMinimumSize,"GetMinimumSize"},
{ kEventWindowGetMaximumSize,"GetMaximumSize"},
{ kEventWindowConstrain,"Constrain"},
{ kEventWindowHandleContentClick,"HandleContentClick"},
{ kEventWindowProxyBeginDrag,"ProxyBeginDra}"},
{ kEventWindowProxyEndDrag,"ProxyEndDrag"},
{ kEventWindowFocusAcquired,"FocusAcquired"},
{ kEventWindowFocusRelinquish,"FocusRelinquish"},
{ kEventWindowDrawFrame,"DrawFrame"},
{ kEventWindowDrawPart,"DrawPart"},
{ kEventWindowGetRegion,"GetRegion"},
{ kEventWindowHitTest,"HitTest"},
{ kEventWindowInit,"Init"},
{ kEventWindowDispose,"Dispose"},
{ kEventWindowDragHilite,"DragHilite"},
{ kEventWindowModified,"Modified"},
{ kEventWindowSetupProxyDragImage,"SetupProxyDragImage"},
{ kEventWindowStateChanged,"StateChanged"},
{ kEventWindowMeasureTitle,"MeasureTitle"},
{ kEventWindowDrawGrowBox,"DrawGrowBox"},
{ kEventWindowGetGrowImageRegion,"GetGrowImageRegion"},
{ kEventWindowPaint,"Paint"},
{ 0, NULL },
};
static MyEventName mouseEventNames [] = {
{ kEventMouseMoved, "Moved"},
{ kEventMouseUp, "Up"},
{ kEventMouseDown, "Down"},
{ kEventMouseDragged, "Dragged"},
{ kEventMouseWheelMoved, "WheelMoved"},
{ 0, NULL}
};
static MyEventName keyboardEventNames [] = {
{ kEventRawKeyDown, "Down"},
{ kEventRawKeyRepeat, "Repeat"},
{ kEventRawKeyUp, "Up"},
{ kEventRawKeyModifiersChanged, "ModifiersChanged"},
{ kEventHotKeyPressed, "HotKeyPressed"},
{ kEventHotKeyReleased, "HotKeyReleased"},
{ 0, NULL}
};
static MyEventName appEventNames [] = {
{ kEventAppActivated, "Activated"},
{ kEventAppDeactivated, "Deactivated"},
{ kEventAppQuit, "Quit"},
{ kEventAppLaunchNotification, "LaunchNotification"},
{ kEventAppLaunched, "Launched"},
{ kEventAppTerminated, "Terminated"},
{ kEventAppFrontSwitched, "FrontSwitched"},
{ 0, NULL}
};
static MyEventName menuEventNames [] = {
{ kEventMenuBeginTracking, "BeginTracking"},
{ kEventMenuEndTracking, "EndTracking"},
{ kEventMenuChangeTrackingMode, "ChangeTrackingMode"},
{ kEventMenuOpening, "Opening"},
{ kEventMenuClosed, "Closed"},
{ kEventMenuTargetItem, "TargetItem"},
{ kEventMenuMatchKey, "MatchKey"},
{ kEventMenuEnableItems, "EnableItems"},
{ kEventMenuDispose, "Dispose"},
{ 0, NULL }
};
static MyEventName controlEventNames [] = {
{ kEventControlInitialize, "Initialize" },
{ kEventControlDispose, "Dispose" },
{ kEventControlGetOptimalBounds, "GetOptimalBounds" },
{ kEventControlHit, "Hit" },
{ kEventControlSimulateHit, "SimulateHit" },
{ kEventControlHitTest, "HitTest" },
{ kEventControlDraw, "Draw" },
{ kEventControlApplyBackground, "ApplyBackground" },
{ kEventControlApplyTextColor, "ApplyTextColor" },
{ kEventControlSetFocusPart, "SetFocusPart" },
{ kEventControlGetFocusPart, "GetFocusPart" },
{ kEventControlActivate, "Activate" },
{ kEventControlDeactivate, "Deactivate" },
{ kEventControlSetCursor, "SetCursor" },
{ kEventControlContextualMenuClick, "ContextualMenuClick" },
{ kEventControlClick, "Click" },
{ kEventControlTrack, "Track" },
{ kEventControlGetScrollToHereStartPoint, "GetScrollToHereStartPoint" },
{ kEventControlGetIndicatorDragConstraint, "GetIndicatorDragConstraint" },
{ kEventControlIndicatorMoved, "IndicatorMoved" },
{ kEventControlGhostingFinished, "GhostingFinished" },
{ kEventControlGetActionProcPart, "GetActionProcPart" },
{ kEventControlGetPartRegion, "GetPartRegion" },
{ kEventControlGetPartBounds, "GetPartBounds" },
{ kEventControlSetData, "SetData" },
{ kEventControlGetData, "GetData" },
{ kEventControlValueFieldChanged, "ValueFieldChanged" },
{ kEventControlAddedSubControl, "AddedSubControl" },
{ kEventControlRemovingSubControl, "RemovingSubControl" },
{ kEventControlBoundsChanged, "BoundsChanged" },
{ kEventControlOwningWindowChanged, "OwningWindowChanged" },
{ kEventControlArbitraryMessage, "ArbitraryMessage" },
{ 0, NULL }
};
static MyEventName commandEventNames [] = {
{ kEventCommandProcess, "Process" },
{ kEventCommandUpdateStatus, "UpdateStatus" },
{ 0, NULL }
};
static MyEventNameList eventNameList [] = {
{ kEventClassWindow, windowEventNames },
{ kEventClassMouse, mouseEventNames },
{ kEventClassKeyboard, keyboardEventNames },
{ kEventClassApplication, appEventNames },
{ kEventClassMenu, menuEventNames },
{ kEventClassControl, controlEventNames },
{ kEventClassCommand, commandEventNames },
{ 0, NULL}
};
#ifdef TK_MACOSXDEBUG_UNUSED
static MyEventName classicEventNames [] = {
{ nullEvent,"nullEvent" },
{ mouseDown,"mouseDown" },
{ mouseUp,"mouseUp" },
{ keyDown,"keyDown" },
{ keyUp,"keyUp" },
{ autoKey,"autoKey" },
{ updateEvt,"updateEvt" },
{ diskEvt,"diskEvt" },
{ activateEvt,"activateEvt" },
{ osEvt,"osEvt" },
{ kHighLevelEvent,"kHighLevelEvent" },
{ 0, NULL }
};
#endif /* TK_MACOSXDEBUG_UNUSED */
MODULE_SCOPE char *
TkMacOSXCarbonEventToAscii(
EventRef eventRef)
{
EventClass eventClass;
EventKind eventKind;
MyEventNameList * list = eventNameList;
MyEventName * names = NULL;
static char str[256];
char *buf = str;
int *iPtr = (int*)str;
int found = 0;
eventClass = GetEventClass(eventRef);
eventKind = GetEventKind(eventRef);
*iPtr = eventClass;
buf[4] = 0;
strcat(buf, " ");
buf += strlen(buf);
while (list->names && (!names) ) {
if (eventClass == list->c) {
names = list -> names;
} else {
list++;
}
}
while (names && names->name) {
if (eventKind == names->kind) {
snprintf(buf, 250, "%-20s", names->name);
break;
} else {
names++;
}
}
if (!found) {
snprintf(buf, 250, "%-20d", eventKind);
}
return str;
}
#ifdef TK_MACOSXDEBUG_UNUSED
MODULE_SCOPE char *
TkMacOSXCarbonEventKindToAscii(
EventRef eventRef,
char *buf)
{
EventClass eventClass;
EventKind eventKind;
MyEventNameList *list = eventNameList;
MyEventName *names = NULL;
int found = 0;
eventClass = GetEventClass(eventRef);
eventKind = GetEventKind(eventRef);
while (list->names && (!names) ) {
if (eventClass == list -> c) {
names = list -> names;
} else {
list++;
}
}
if (names) {
found = 0;
while (names->name && !found) {
if (eventKind == names->kind) {
sprintf(buf,"%s",names->name);
found = 1;
} else {
names++;
}
}
}
if (!found) {
sprintf(buf,"%d", eventKind);
} else {
sprintf(buf,"%d", eventKind);
}
return buf;
}
MODULE_SCOPE char *
TkMacOSXClassicEventToAscii(
EventRecord *eventPtr,
char *buf)
{
MyEventName *names = NULL;
int found = 0;
names = classicEventNames;
while (names -> name && !found) {
if (eventPtr->what == names->kind) {
int *iPtr;
char cBuf[8];
iPtr = (int *) &cBuf;
*iPtr = eventPtr->message;
cBuf[4] = 0;
sprintf(buf, "%-16s %08x %04x %s", names->name,
(int) eventPtr->message, eventPtr->modifiers, cBuf);
found = 1;
} else {
names++;
}
}
if (!found) {
sprintf(buf,"%-16d %08x %08x, %s", eventPtr->what,
(int) eventPtr->message, eventPtr->modifiers, buf);
}
return buf;
}
MODULE_SCOPE void
TkMacOSXPrintPoint(
char *tag,
Point *p)
{
TkMacOSXDbgMsg("%s %4d %4d", tag,p->h,p->v );
}
MODULE_SCOPE void
TkMacOSXPrintRect(
char *tag,
Rect *r)
{
TkMacOSXDbgMsg("%s %4d %4d %4d %4d (%dx%d)",
tag, r->left, r->top, r->right, r->bottom,
r->right - r->left + 1, r->bottom - r->top + 1);
}
MODULE_SCOPE void
TkMacOSXPrintRegion(
char *tag,
RgnHandle rgn)
{
Rect r;
GetRegionBounds(rgn,&r);
TkMacOSXPrintRect(tag,&r);
}
MODULE_SCOPE void
TkMacOSXPrintWindowTitle(
char *tag,
WindowRef window)
{
Str255 title;
GetWTitle(window, title);
title[title[0] + 1] = 0;
TkMacOSXDbgMsg("%s %s", tag, title+1);
}
typedef struct {
int msg;
char *name;
} MsgName;
static MsgName msgNames [] = {
{ kMenuDrawMsg, "Draw"},
{ kMenuSizeMsg, "Size"},
{ kMenuPopUpMsg, "PopUp"},
{ kMenuCalcItemMsg, "CalcItem" },
{ kMenuThemeSavvyMsg, "ThemeSavvy"},
{ kMenuInitMsg, "Init" },
{ kMenuDisposeMsg, "Dispose" },
{ kMenuFindItemMsg, "FindItem" },
{ kMenuHiliteItemMsg, "HiliteItem" },
{ kMenuDrawItemsMsg, "DrawItems" },
{ -1, NULL }
};
MODULE_SCOPE char *
TkMacOSXMenuMessageToAscii(
int msg,
char *s)
{
MsgName *msgNamePtr;
for (msgNamePtr=msgNames ; msgNamePtr->name ; msgNamePtr++) {
if (msgNamePtr->msg == msg) {
strcpy(s,msgNamePtr->name);
return s;
}
}
sprintf(s, "unknown : %d", msg);
return s;
}
static MsgName trackingNames [] = {
{ kMouseTrackingMousePressed , "MousePressed " },
{ kMouseTrackingMouseReleased , "MouseReleased " },
{ kMouseTrackingMouseExited , "MouseExited " },
{ kMouseTrackingMouseEntered , "MouseEntered " },
{ kMouseTrackingMouseMoved , "MouseMoved " },
{ kMouseTrackingKeyModifiersChanged, "KeyModifiersChanged" },
{ kMouseTrackingUserCancelled , "UserCancelled " },
{ kMouseTrackingTimedOut , "TimedOut " },
{ -1, NULL }
};
MODULE_SCOPE char *
TkMacOSXMouseTrackingResultToAscii(
MouseTrackingResult r,
char *buf)
{
MsgName *namePtr;
for (namePtr = trackingNames; namePtr->name; namePtr++) {
if (namePtr->msg == r) {
strcpy(buf, namePtr->name);
return buf;
}
}
sprintf(buf, "Unknown mouse tracking result : %d", r);
return buf;
}
#endif /* TK_MACOSXDEBUG_UNUSED */
MODULE_SCOPE void
TkMacOSXDebugFlashRegion(
Drawable d,
HIShapeRef rgn)
{
TkMacOSXInitNamedDebugSymbol(HIToolbox, int, QDDebugFlashRegion,
CGrafPtr port, RgnHandle region);
CFShow(rgn);
if (d && rgn && QDDebugFlashRegion && !HIShapeIsEmpty(rgn)) {
CGrafPtr port = TkMacOSXGetDrawablePort(d);
if (port) {
static RgnHandle qdRgn = NULL;
if (!qdRgn) {
qdRgn = NewRgn();
}
ChkErr(HIShapeGetAsQDRgn, rgn, qdRgn);
/*
* Carbon-internal region flashing SPI (c.f. Technote 2124)
*/
QDDebugFlashRegion(port, qdRgn);
SetEmptyRgn(qdRgn);
}
}
}
#include <mach-o/dyld.h>
#include <mach-o/nlist.h>
/*
*----------------------------------------------------------------------
*
* TkMacOSXGetNamedDebugSymbol --
*
* Dynamically acquire address of a named symbol from a loaded dynamic
* library, so that we can use API that may not be available on all OS
* versions. For debugging purposes, if we cannot find the symbol with
* the usual dynamic library APIs, we manually walk the symbol table of
* the loaded library. This allows access to unexported symbols such as
* private_extern internal debugging functions. If module is NULL or the
* empty string, search all loaded libraries (could be very expensive and
* should be avoided).
*
* THIS FUCTION IS ONLY TO BE USED FOR DEBUGGING PURPOSES, IT MAY BREAK
* UNEXPECTEDLY IN THE FUTURE!
*
* Results:
* Address of given symbol or NULL if unavailable.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
MODULE_SCOPE void *
TkMacOSXGetNamedDebugSymbol(
const char *module,
const char *symbol)
{
void *addr = TkMacOSXGetNamedSymbol(module, symbol);
#ifndef __LP64__
if (!addr) {
const struct mach_header *mh = NULL;
uint32_t i, n = _dyld_image_count();
size_t module_len = 0;
if (module && *module) {
module_len = strlen(module);
}
for (i = 0; i < n; i++) {
if (module && *module) {
/* Find image with given module name */
char *name;
const char *path = _dyld_get_image_name(i);
if (!path) {
continue;
}
name = strrchr(path, '/') + 1;
if (strncmp(name, module, module_len) != 0) {
continue;
}
}
mh = _dyld_get_image_header(i);
if (mh) {
struct load_command *lc;
struct symtab_command *st = NULL;
struct segment_command *sg = NULL;
uint32_t j, m, nsect = 0, txtsectx = 0;
lc = (struct load_command*)((const char*) mh +
sizeof(struct mach_header));
m = mh->ncmds;
for (j = 0; j < m; j++) {
/* Find symbol table and index of __text section */
if (lc->cmd == LC_SEGMENT) {
/* Find last segment before symbol table */
sg = (struct segment_command*) lc;
if (!txtsectx) {
/* Count total sections until (__TEXT, __text) */
uint32_t k, ns = sg->nsects;
if (strcmp(sg->segname, SEG_TEXT) == 0) {
struct section *s = (struct section *)(
(char *)sg +
sizeof(struct segment_command));
for(k = 0; k < ns; k++) {
if (strcmp(s->sectname, SECT_TEXT) == 0) {
txtsectx = nsect+k+1;
break;
}
s++;
}
}
nsect += ns;
}
} else if (!st && lc->cmd == LC_SYMTAB) {
st = (struct symtab_command *) lc;
break;
}
lc = (struct load_command *)((char *) lc + lc->cmdsize);
}
if (st && sg && txtsectx) {
intptr_t base, slide = _dyld_get_image_vmaddr_slide(i);
char *strings;
struct nlist *sym;
uint32_t strsize = st->strsize;
int32_t strx;
/*
* Offset file positions by difference to actual position
* in memory of last segment before symbol table:
*/
base = (intptr_t) sg->vmaddr + slide - sg->fileoff;
strings = (char *) (base + st->stroff);
sym = (struct nlist *) (base + st->symoff);
m = st->nsyms;
for (j = 0; j < m; j++) {
/* Find symbol with given name in __text section */
strx = sym->n_un.n_strx;
if ((sym->n_type & N_TYPE) == N_SECT &&
sym->n_sect == txtsectx &&
strx > 0 && (uint32_t) strx < strsize &&
strcmp(strings + strx, symbol) == 0) {
addr = (char*) sym->n_value + slide;
break;
}
sym++;
}
}
}
if (module && *module) {
/* If given a module name, only search corresponding image */
break;
}
}
}
#endif /* __LP64__ */
return addr;
}
#endif /* TK_MAC_DEBUG */
/*
* Local Variables:
* c-basic-offset: 4
* fill-column: 78
* End:
*/
Jump to Line
Something went wrong with that request. Please try again.