1/*
2 * tkMacOSXDebug.c --
3 *
4 *	Implementation of Macintosh specific functions for debugging MacOS
5 *	events, regions, etc...
6 *
7 * Copyright 2001-2009, Apple Inc.
8 * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
9 *
10 * See the file "license.terms" for information on usage and redistribution
11 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12 *
13 * RCS: @(#) $Id$
14 */
15
16#include "tkMacOSXPrivate.h"
17#include "tkMacOSXDebug.h"
18
19#ifdef TK_MAC_DEBUG
20
21#include <mach-o/dyld.h>
22#include <mach-o/nlist.h>
23
24/*
25 *----------------------------------------------------------------------
26 *
27 * TkMacOSXGetNamedDebugSymbol --
28 *
29 *	Dynamically acquire address of a named symbol from a loaded dynamic
30 *	library, so that we can use API that may not be available on all OS
31 *	versions. For debugging purposes, if we cannot find the symbol with
32 *	the usual dynamic library APIs, we manually walk the symbol table of
33 *	the loaded library. This allows access to unexported symbols such as
34 *	private_extern internal debugging functions. If module is NULL or the
35 *	empty string, search all loaded libraries (could be very expensive and
36 *	should be avoided).
37 *
38 *	THIS FUCTION IS ONLY TO BE USED FOR DEBUGGING PURPOSES, IT MAY BREAK
39 *	UNEXPECTEDLY IN THE FUTURE!
40 *
41 * Results:
42 *	Address of given symbol or NULL if unavailable.
43 *
44 * Side effects:
45 *	None.
46 *
47 *----------------------------------------------------------------------
48 */
49
50MODULE_SCOPE void *
51TkMacOSXGetNamedDebugSymbol(
52    const char *module,
53    const char *symbol)
54{
55    void *addr = TkMacOSXGetNamedSymbol(module, symbol);
56
57#ifndef __LP64__
58    if (!addr) {
59	const struct mach_header *mh = NULL;
60	uint32_t i, n = _dyld_image_count();
61	size_t module_len = 0;
62
63	if (module && *module) {
64	    module_len = strlen(module);
65	}
66	for (i = 0; i < n; i++) {
67	    if (module && *module) {
68		/* Find image with given module name */
69		char *name;
70		const char *path = _dyld_get_image_name(i);
71
72		if (!path) {
73		    continue;
74		}
75		name = strrchr(path, '/') + 1;
76		if (strncmp(name, module, module_len) != 0) {
77		    continue;
78		}
79	    }
80	    mh = _dyld_get_image_header(i);
81	    if (mh) {
82		struct load_command *lc;
83		struct symtab_command *st = NULL;
84		struct segment_command *sg = NULL;
85		uint32_t j, m, nsect = 0, txtsectx = 0;
86
87		lc = (struct load_command*)((const char*) mh +
88			sizeof(struct mach_header));
89		m = mh->ncmds;
90		for (j = 0; j < m; j++) {
91		    /* Find symbol table and index of __text section */
92		    if (lc->cmd == LC_SEGMENT) {
93			/* Find last segment before symbol table */
94			sg = (struct segment_command*) lc;
95			if (!txtsectx) {
96			    /* Count total sections until (__TEXT, __text) */
97			    uint32_t k, ns = sg->nsects;
98
99			    if (strcmp(sg->segname, SEG_TEXT) == 0) {
100				struct section *s = (struct section *)(
101					(char *)sg +
102					sizeof(struct segment_command));
103
104				for(k = 0; k < ns; k++) {
105				    if (strcmp(s->sectname, SECT_TEXT) == 0) {
106					txtsectx = nsect+k+1;
107					break;
108				    }
109				    s++;
110				}
111			    }
112			    nsect += ns;
113			}
114		    } else if (!st && lc->cmd == LC_SYMTAB) {
115			st = (struct symtab_command *) lc;
116			break;
117		    }
118		    lc = (struct load_command *)((char *) lc + lc->cmdsize);
119		}
120		if (st && sg && txtsectx) {
121		    intptr_t base, slide = _dyld_get_image_vmaddr_slide(i);
122		    char *strings;
123		    struct nlist *sym;
124		    uint32_t strsize = st->strsize;
125		    int32_t strx;
126
127		    /*
128		     * Offset file positions by difference to actual position
129		     * in memory of last segment before symbol table:
130		     */
131
132		    base = (intptr_t) sg->vmaddr + slide - sg->fileoff;
133		    strings = (char *) (base + st->stroff);
134		    sym = (struct nlist *) (base + st->symoff);
135		    m = st->nsyms;
136		    for (j = 0; j < m; j++) {
137			/* Find symbol with given name in __text section */
138			strx = sym->n_un.n_strx;
139			if ((sym->n_type & N_TYPE) == N_SECT &&
140				sym->n_sect == txtsectx &&
141				strx > 0 && (uint32_t) strx < strsize &&
142				strcmp(strings + strx, symbol) == 0) {
143			    addr = (char*) sym->n_value + slide;
144			    break;
145			}
146			sym++;
147		    }
148		}
149	    }
150	    if (module && *module) {
151		/* If given a module name, only search corresponding image */
152		break;
153	    }
154	}
155    }
156#endif /* __LP64__ */
157    return addr;
158}
159#endif /* TK_MAC_DEBUG */
160
161/*
162 * Local Variables:
163 * mode: c
164 * c-basic-offset: 4
165 * fill-column: 79
166 * coding: utf-8
167 * End:
168 */
169