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