SYSENTER/SYSCALL support
[minix.git] / commands / mdb / sym.c
blob2c2b149413e6d4e97a13acceb3746fdbce6373b9
1 /*
2 * sym.c for mdb
3 */
5 #include "mdb.h"
6 #include <fcntl.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <a.out.h>
12 #include "proto.h"
14 struct symtab_s
16 struct nlist *start;
17 struct nlist *end;
18 int text;
19 int data;
20 unsigned nsym;
23 static struct symtab_s symtab;
24 static int type_of_exec;
26 static int check_exec(struct exec *hdr);
27 static void sortsyms(struct nlist *array , struct nlist *top );
28 static int symeq(char *t , struct nlist *sp );
29 static int symprefix(char *t , struct nlist *sp );
30 static struct nlist *findsname(char *name, int is_text, int allflag);
31 static void outsym(struct nlist *sp, off_t off);
32 static struct nlist *findsval(off_t value, int where);
34 void syminit( filename )
35 char *filename;
37 int fd;
38 struct exec header;
39 register struct symtab_s *tp;
41 tp = &symtab;
42 if ( (fd = open( filename, O_RDONLY)) < 0) {
43 fprintf(stderr, "Couldn't open %s.\n", filename);
44 perror(filename);
45 exit(1);
48 if( read( fd, (char *) &header, sizeof header ) != sizeof header )
50 fprintf(stderr, "Couldn't read %d bytes from %s.\n", sizeof(header), filename);
51 close( fd );
52 exit(1);
54 type_of_exec = check_exec(&header);
56 #if EXTRA_SYMBOLS
57 if ( type_of_exec == GNU_SYMBOLS) {
58 close(fd);
59 gnu_init(filename);
60 return;
62 #endif
64 /* For MINIX EXEC */
65 if ( lseek( fd, A_SYMPOS( header ), 0 ) != A_SYMPOS( header ) )
67 do_error( "mdb - reading header" );
68 close( fd );
69 exit(1);
71 if ( (int) header.a_syms < 0 ||
72 (unsigned) header.a_syms != header.a_syms ||
73 (tp->start = (struct nlist *) malloc( (unsigned) header.a_syms ))
74 == (struct nlist *) NULL &&
75 header.a_syms != 0 )
77 Printf("mdb: no room for symbol table" );
78 close( fd );
79 return;
81 if ( read( fd, (char *) tp->start, (int) header.a_syms ) < 0 )
83 do_error( "mdb - reading symbol table" );
84 close( fd );
85 return;
87 close( fd );
88 tp->nsym = (unsigned) header.a_syms / sizeof (struct nlist);
89 tp->end = tp->start + tp->nsym;
90 tp->text = 0x07;
91 tp->data = 0x0F;
93 /* sort on value only, name search not used much and storage a problem */
94 Printf("Sorting %d MINIX symbols ....", tp->nsym );
95 sortsyms( tp->start, tp->end );
96 Printf("\n");
99 /* Check exec file
100 * return type of exec
101 * or exit
103 static int check_exec(hdr)
104 struct exec *hdr;
106 long magic;
108 /* Check MAGIC number */
109 if (hdr->a_magic[0] != A_MAGIC0 || hdr->a_magic[1] != A_MAGIC1) {
110 Printf("mdb: invalid magic number in exec header - %02x %02x\n",
111 hdr->a_magic[0],
112 hdr->a_magic[1]);
113 exit(1);
116 /* Check CPU */
117 #if defined(__i386__)
118 if (hdr->a_cpu != A_I80386)
119 #endif
121 Printf("mdb: invalid cpu in exec header - %04x\n",
122 hdr->a_cpu);
123 exit(1);
126 is_separate = FALSE;
127 #ifdef MINIX_PC
128 if (hdr->a_flags & A_SEP)
129 is_separate = TRUE;
130 #endif
132 #if GNU_SUPPORT
133 if (hdr->a_flags & A_NSYM)
134 return GNU_SYMBOLS;
135 #endif
138 * A_EXEC is not being set by current cc
139 * It was set in Minix 1.5.0
141 #if 0
142 /* Check flags - separate I & D or not */
143 if (hdr->a_flags & A_EXEC)
144 is_separate = FALSE;
145 else {
146 Printf("mdb: object file not exec %04x\n",
147 hdr->a_flags);
148 exit(1);
150 #endif
151 return MINIX_SYMBOLS;
155 long symbolvalue( name, is_text )
156 char *name;
157 int is_text;
159 register struct nlist *sp;
161 #if EXTRA_SYMBOLS
162 if ( type_of_exec == GNU_SYMBOLS )
163 return gnu_symbolvalue( name, is_text );
164 #endif
166 /* For MINIX EXEC */
167 sp = findsname(name, is_text, 0);
168 if (sp != NULL)
169 return sp->n_value;
170 else
171 return 0L;
174 static struct nlist *findsname( name, is_text, allflag )
175 char *name;
176 int is_text;
177 int allflag;
179 char *s;
180 unsigned char sclass;
181 int schar;
182 char *send;
183 register struct nlist *sp;
184 register struct symtab_s *tp;
186 tp = &symtab;
187 if ( allflag )
189 /* find and print all matching symbols */
190 for ( sp = tp->start; sp < tp->end; ++sp )
192 if ( symprefix( name, sp ) )
194 sp = sp;
195 for ( s = sp->n_name, send = s + sizeof sp->n_name;
196 *s != 0 && s < send; ++s )
197 outbyte( *s );
198 for ( ; s <= send; ++s )
199 outspace();
200 switch( sp->n_sclass & N_SECT )
202 case N_ABS: schar = 'a'; break;
203 case N_TEXT: schar = 't'; break;
204 case N_DATA: schar = 'd'; break;
205 case N_BSS: schar = 'b'; break;
206 default: schar = '?'; break;
208 if ( (sp->n_sclass & N_CLASS) == C_EXT && schar != '?' )
209 schar += 'A' - 'a';
210 outbyte( schar );
211 outspace();
212 outh32( sp->n_value );
213 outbyte('\n');
217 else
219 /* find symbol by dumb linear search */
220 for ( sp = tp->start; sp < tp->end; ++sp )
222 sclass = sp->n_sclass & N_SECT;
223 if ( (is_text && sclass == N_TEXT ||
224 !is_text && (sclass == N_DATA || sclass == N_BSS)) &&
225 symeq( name, sp ) )
226 return sp;
229 return NULL;
232 static struct nlist *findsval( value, where )
233 off_t value;
234 int where;
236 int left;
237 int middle;
238 int right;
239 unsigned char sclass;
240 register struct nlist *sp;
241 register struct symtab_s *tp;
243 tp = &symtab;
245 /* find last symbol with value <= desired one by binary search */
246 for ( left = 0, right = tp->nsym - 1; left <= right; )
248 middle = (left + right) / 2;
249 sp = tp->start + middle;
250 if ( value < sp->n_value )
251 right = middle - 1;
252 else
253 left = middle + 1;
255 if ( right >= 0 )
256 /* otherwise tp->start + right may wrap around to > tp->start !! */
257 for ( sp = tp->start + right; sp >= tp->start; --sp )
259 if ( (sp->n_sclass & N_CLASS) != C_EXT ) continue;
260 sclass = sp->n_sclass & N_SECT;
261 if ( (where == CSEG && sclass == N_TEXT ||
262 where != CSEG && (sclass == N_DATA || sclass == N_BSS)) )
263 return sp;
265 return NULL;
269 void printhex(v)
270 off_t v;
272 if ( v >= 65536L )
273 outh32( v );
274 else if ( v >= 256 )
275 outh16( (u16_t) v );
276 else
277 outh8( (u8_t) v );
281 static void outsym( sp, off )
282 struct nlist *sp;
283 off_t off;
285 register char *s;
286 char *send;
288 for ( s = sp->n_name, send = s + sizeof sp->n_name; *s != 0 && s < send; ++s )
289 outbyte( *s );
290 if ( (off -= sp->n_value) != 0 )
292 outbyte( '+' );
293 printhex(off);
297 /* shell sort symbols on value */
299 static void sortsyms( array, top )
300 struct nlist *array;
301 struct nlist *top;
303 int gap;
304 int i;
305 int j;
306 register struct nlist *left;
307 register struct nlist *right;
308 struct nlist swaptemp;
309 int size;
311 size = top - array;
312 /* choose gaps according to Knuth V3 p95 */
313 for ( gap = 1, i = 4; (j = 3 * i + 1) < size; gap = i, i = j )
317 for ( j = gap; j < size; ++j )
318 for ( i = j - gap; i >= 0; i -= gap )
320 left = array + i;
321 right = array + (i + gap);
322 if ( (off_t) left->n_value <=
323 right->n_value )
324 break;
325 swaptemp = *left;
326 *left = *right;
327 *right = swaptemp;
330 while ( (gap /= 3) != 0 );
333 void symbolic( value, separator )
334 off_t value;
335 int separator;
337 register struct nlist *sp;
338 long off;
340 #if EXTRA_SYMBOLS
341 if ( type_of_exec == GNU_SYMBOLS ) {
342 gnu_symbolic( value, separator );
343 return;
345 #endif
347 /* For MINIX EXEC */
349 if (value < st_addr || value > end_addr) {
350 outstr("0x");
351 printhex(value);
352 outbyte(separator);
353 return;
356 if ( (sp = findsval( value, CSEG )) != NULL )
358 outsym( sp, value );
360 else if ( (sp = findsval( value, DSEG )) != NULL )
362 outsym( sp, value );
364 else
366 outstr("_start");
367 off = value - st_addr;
368 if ( off != 0 )
370 outbyte( '+' );
371 printhex(off);
374 outbyte( separator );
378 static int symeq( t, sp )
379 register char *t;
380 struct nlist *sp;
382 return strncmp( t, sp->n_name, sizeof sp->n_name ) == 0;
385 static int symprefix( t, sp )
386 register char *t;
387 struct nlist *sp;
389 register char *s;
390 char *send;
392 for ( ; *t == '_'; ++t )
394 for ( s = sp->n_name, send = s + sizeof sp->n_name;
395 s < send && *s == '_'; ++s )
397 return strncmp( s, t, (size_t)(send - s) ) == 0;
402 /* list all symbols - test for selection criteria */
404 void listsym(cmd)
405 char *cmd;
407 register struct symtab_s *tp;
408 register struct nlist *sp;
409 char *s;
410 char *send;
411 char schar;
412 char tchar;
414 /* set selection */
415 cmd = skip(cmd+1);
416 if( *cmd == '\n' || *cmd == ';' )
417 tchar = '*';
418 else
419 tchar = *cmd;
421 #if EXTRA_SYMBOLS
422 if ( type_of_exec == GNU_SYMBOLS ) {
423 gnu_listsym(tchar);
424 return;
426 #endif
428 /* For MINIX EXEC */
430 tp = &symtab;
431 for ( sp = tp->start; sp < tp->end; ++sp )
433 switch( sp->n_sclass & N_SECT )
435 case N_ABS: schar = 'a'; break;
436 case N_TEXT: schar = 't'; break;
437 case N_DATA: schar = 'd'; break;
438 case N_BSS: schar = 'b'; break;
439 default: schar = '?'; break;
442 if ( (sp->n_sclass & N_CLASS) == C_EXT && schar != '?' )
443 schar += 'A' - 'a';
445 /* check for selection */
446 if ( tchar != '*' && schar != tchar)
447 continue;
449 /* print symbol type and value */
450 for ( s = sp->n_name, send = s + sizeof sp->n_name;
451 *s != 0 && s < send; ++s ) outbyte( *s );
452 for ( ; s <= send; ++s ) outspace();
453 outbyte( schar );
454 outspace();
455 outh32( sp->n_value );
456 outbyte('\n');
461 int text_symbol(value)
462 off_t value;
464 struct nlist *sp;
466 #if EXTRA_SYMBOLS
467 if ( type_of_exec == GNU_SYMBOLS )
468 return gnu_text_symbol(value);
469 #endif
471 if ((sp = findsval(value, CSEG)) != NULL && sp->n_value == value)
473 outsym(sp, value);
474 return TRUE;
476 else
477 return FALSE;
480 int finds_data(off,data_seg)
481 off_t off;
482 int data_seg;
484 struct nlist *sp;
486 #if EXTRA_SYMBOLS
487 if ( type_of_exec == GNU_SYMBOLS )
488 return gnu_finds_data(off,data_seg);
489 #endif
491 if ((sp = findsval(off, data_seg)) != NULL)
493 outsym(sp, off);
494 return TRUE;
496 else
497 return FALSE;
500 int finds_pc(pc)
501 off_t pc;
503 struct nlist *sp;
505 #if EXTRA_SYMBOLS
506 if ( type_of_exec == GNU_SYMBOLS )
507 return gnu_finds_pc(pc);
508 #endif
510 if ((sp = findsval(pc, CSEG)) != NULL)
512 outsym(sp, pc);
513 return TRUE;
515 else
516 return FALSE;