1 |
|
/* |
2 |
|
File rsym_macosx.c |
3 |
|
|
4 |
|
Build an executable rsym for Mac OS X (31 July 2003). |
5 |
|
|
6 |
|
Grab only the external symbols from a Mach-O object file, and put them |
7 |
|
in a simple format. This information will be used for relocation. |
8 |
|
|
9 |
|
To compile in standalone mode: |
10 |
|
gcc -DDEBUG -DSTANDALONE -I../h -o rsym_macosx rsym_macosx.c |
11 |
|
|
12 |
|
Aurelien Chanudet (aurelienDOTchanudetATm4xDOTorg) |
13 |
|
*/ |
14 |
|
|
15 |
|
#include <mach-o/loader.h> |
16 |
|
#include <mach-o/nlist.h> |
17 |
|
|
18 |
|
#include <mach/mach.h> |
19 |
|
|
20 |
|
#ifdef STANDALONE |
21 |
|
#include <stdio.h> |
22 |
|
#define SPECIAL_RSYM |
23 |
|
#endif |
24 |
|
|
25 |
|
#include <fcntl.h> |
26 |
|
#include <stdlib.h> |
27 |
|
#include <unistd.h> |
28 |
|
#include <sys/types.h> |
29 |
|
#include <sys/stat.h> |
30 |
|
|
31 |
|
#define IN_RSYM 1 |
32 |
|
|
33 |
|
/* #include "config.h" */ |
34 |
|
#include "ext_sym.h" |
35 |
|
|
36 |
|
void rsym_error (char *format, ...) |
37 |
|
{ |
38 |
|
va_list ap; |
39 |
|
|
40 |
|
va_start (ap, format); |
41 |
|
fprintf (stderr, "rsym: "); |
42 |
|
vfprintf (stderr, format, ap); |
43 |
|
/* fprintf (stderr, " (%s)", strerror(errno)); */ |
44 |
|
fprintf (stderr, "\n"); |
45 |
|
va_end (ap); |
46 |
|
exit (1); |
47 |
|
} |
48 |
|
|
49 |
|
int rsym_select_symbol(struct nlist *symbol) |
50 |
|
{ |
51 |
|
if (symbol->n_type & N_STAB) { |
52 |
|
return (FALSE); |
53 |
|
} |
54 |
|
if (symbol->n_sect == NO_SECT) { |
55 |
|
return (FALSE); |
56 |
|
} |
57 |
|
return (symbol->n_type & N_EXT); |
58 |
|
} |
59 |
|
|
60 |
|
void rsym_doit2 (struct nlist *symbols, unsigned long nsyms, char *outfile) |
61 |
|
{ |
62 |
|
unsigned long i; |
63 |
|
struct lsymbol_table tab; |
64 |
|
FILE *symout; |
65 |
|
|
66 |
|
if (!(symout = fopen (outfile, "wb"))) { |
67 |
|
rsym_error ("cannot open file for writing: %s", outfile); |
68 |
|
} |
69 |
|
|
70 |
|
tab.n_symbols=0; |
71 |
|
tab.tot_leng=0; |
72 |
|
|
73 |
|
fseek (symout, sizeof(tab), 0); |
74 |
|
|
75 |
|
for (i=0 ; i < nsyms ; i++) |
76 |
|
{ |
77 |
|
int addr = (int) symbols[i].n_value; |
78 |
|
char *name = symbols[i].n_un.n_name; |
79 |
|
|
80 |
|
if (name) |
81 |
|
{ |
82 |
|
tab.n_symbols++; |
83 |
|
fwrite (&addr, sizeof (int), 1, symout); |
84 |
|
while (tab.tot_leng++, *name) |
85 |
|
putc (*name++, symout); |
86 |
|
putc (0, symout); |
87 |
|
} |
88 |
|
else { |
89 |
|
fprintf (stderr, "warning: malformed symbol\n"); |
90 |
|
} |
91 |
|
} |
92 |
|
|
93 |
|
#ifdef DEBUG |
94 |
|
fprintf (stderr, "%d/%d symbol(s) reviewed\n", tab.n_symbols, nsyms); |
95 |
|
#endif |
96 |
|
|
97 |
|
fseek (symout, 0, 0); |
98 |
|
fwrite (&tab, sizeof(tab), 1, symout); |
99 |
|
|
100 |
|
fclose (symout); |
101 |
|
} |
102 |
|
|
103 |
|
void rsym_doit1 (char *infile, char *outfile) |
104 |
|
{ |
105 |
|
struct stat stat_buf; |
106 |
|
struct mach_header *mh; |
107 |
|
struct load_command *lc; |
108 |
|
struct symtab_command *st; |
109 |
|
struct dysymtab_command *dyst; |
110 |
|
unsigned long nsyms, i, size; |
111 |
|
unsigned long strsize; |
112 |
|
struct nlist *symtab, *selected_symbols; |
113 |
|
kern_return_t r; |
114 |
|
char *strtab; |
115 |
|
vm_size_t s; |
116 |
|
char *addr; |
117 |
|
int fd; |
118 |
|
|
119 |
|
if ((fd = open (infile, O_RDONLY, 0)) < 0) { |
120 |
|
rsym_error ("cannot open input file: %s", infile); |
121 |
|
} |
122 |
|
|
123 |
|
if (fstat (fd, &stat_buf) == -1) { |
124 |
|
rsym_error ("cannot fstat file: %s", infile); |
125 |
|
} |
126 |
|
|
127 |
|
size = stat_buf.st_size; |
128 |
|
|
129 |
|
if ((r = map_fd (fd, (vm_offset_t) 0, (vm_offset_t *) &addr, |
130 |
|
(boolean_t) TRUE, (vm_size_t) size)) != KERN_SUCCESS) { |
131 |
|
rsym_error ("cannot map file in memory: %s", infile); |
132 |
|
} |
133 |
|
|
134 |
|
mh = (struct mach_header *) addr; |
135 |
|
lc = (struct load_command *) ((char *) addr + sizeof(struct mach_header)); |
136 |
|
|
137 |
|
for (i=0 ; i < mh->ncmds ; i++) { |
138 |
|
if (lc->cmd == LC_SYMTAB) { |
139 |
|
st = (struct symtab_command *) lc; |
140 |
|
} |
141 |
|
else if (lc->cmd == LC_DYSYMTAB) { |
142 |
|
dyst = (struct dysymtab_command *) lc; |
143 |
|
} |
144 |
|
lc = (struct load_command *) ((char *) lc + lc->cmdsize); |
145 |
|
} |
146 |
|
|
147 |
|
symtab = (struct nlist *) ((char *) addr + st->symoff); |
148 |
|
|
149 |
|
s = sizeof(struct nlist) * st->nsyms; |
150 |
|
if (vm_allocate (mach_task_self (), (vm_address_t *) &selected_symbols, s, 1) != KERN_SUCCESS) { |
151 |
|
rsym_error ("could not vm_allocate"); |
152 |
|
} |
153 |
|
|
154 |
|
nsyms = 0; |
155 |
|
|
156 |
|
for (i = 0 ; i < st->nsyms ; i++) { |
157 |
|
if (rsym_select_symbol (symtab + i)) |
158 |
|
selected_symbols[nsyms++] = symtab[i]; |
159 |
|
} |
160 |
|
|
161 |
|
strtab = addr + st->stroff; |
162 |
|
strsize = st->strsize; |
163 |
|
|
164 |
|
for (i = 0 ; i < nsyms ; i++) { |
165 |
|
if (selected_symbols[i].n_un.n_strx == 0) |
166 |
|
selected_symbols[i].n_un.n_name = ""; |
167 |
|
else if (selected_symbols[i].n_un.n_strx < 0 || |
168 |
|
selected_symbols[i].n_un.n_strx > strsize) |
169 |
|
selected_symbols[i].n_un.n_name = "bad string index"; |
170 |
|
else |
171 |
|
selected_symbols[i].n_un.n_name = selected_symbols[i].n_un.n_strx + strtab; |
172 |
|
|
173 |
|
#if DEBUG |
174 |
|
fprintf (stderr, "debug: %8x %s\n", (unsigned int) selected_symbols[i].n_value, |
175 |
|
selected_symbols[i].n_un.n_name); |
176 |
|
#endif |
177 |
|
} |
178 |
|
|
179 |
|
rsym_doit2 (selected_symbols, nsyms, outfile); |
180 |
|
|
181 |
|
if (vm_deallocate (mach_task_self (), (vm_address_t) selected_symbols, s) != KERN_SUCCESS) { |
182 |
|
fprintf (stderr, "warning: failed to free memory\n"); |
183 |
|
} |
184 |
|
|
185 |
|
if (vm_deallocate (mach_task_self (), (vm_address_t) addr, (vm_size_t) size) != KERN_SUCCESS) { |
186 |
|
fprintf (stderr, "warning: failed to deallocate mapped file\n"); |
187 |
|
} |
188 |
|
|
189 |
|
close (fd); |
190 |
|
} |
191 |
|
|
192 |
|
int main (int argc, char **argv, char **envp) |
193 |
|
{ |
194 |
|
if (argc != 3) { |
195 |
|
fprintf (stderr, "usage: rsym <infile> <outfile>\n"); |
196 |
|
exit (1); |
197 |
|
} |
198 |
|
|
199 |
|
rsym_doit1 (argv[1], argv[2]); |
200 |
|
|
201 |
|
return 0; |
202 |
|
} |