vm: fix potential null deref
[minix.git] / commands / mdb / gnu_sym.c
blobbb4b521ee540a46bfa1dfbd05fa29aacb7c0e4ea
1 /*
2 * gnu_sym.c for mdb
3 * copied and modified from sym.c
4 * Support GNU Exec symbol tables
5 */
7 #include "mdb.h"
9 #ifdef EXTRA_SYMBOLS
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <unistd.h>
14 #include <string.h>
15 #include <fcntl.h>
16 #ifdef __NBSD_LIBC
17 #include <compat/a.out.h>
18 #else
19 #include <minix/a.out.h>
20 #endif
21 #include "proto.h"
23 #define NN_UNDF 0
24 #define NN_ABS 2
25 #define NN_TEXT 4
26 #define NN_DATA 6
27 #define NN_BSS 8
28 #define NN_FN 15
29 #define NN_EXT 1
30 #define NN_TYPE 036
32 struct newnlist {
33 union {
34 char *n_name;
35 struct newnlist *n_next;
36 long n_strx;
37 } n_un;
38 unsigned char n_type;
39 char n_other;
40 short n_desc;
41 unsigned long n_value;
44 struct symtab_s
46 struct newnlist *start;
47 struct newnlist *end;
48 unsigned int nsym;
51 static struct symtab_s symtab;
53 static void gnu_sort(struct newnlist *array , struct newnlist *top );
54 static int gnu_symeq(char *t , struct newnlist *sp );
55 static int gnu_symprefix(char *t , struct newnlist *sp );
56 static struct newnlist *gnu_sname(char *name, int is_text, int
57 allflag);
58 static struct newnlist *gnu_sval(off_t value, int where);
59 static void gnu_sym(struct newnlist *sp, off_t off);
62 void gnu_init( filename )
63 char *filename;
65 struct exec header;
66 unsigned int string_size;
67 char *names;
68 struct newnlist *p;
69 int fd;
70 register struct symtab_s *tp;
72 tp = &symtab;
73 if ( (fd = open( filename, O_RDONLY)) < 0 ||
74 read( fd, (char *) &header, sizeof header ) != sizeof header )
76 do_error( "gnu_load - reading header" );
77 if ( fd >= 0) close( fd );
78 return;
81 if ( (string_size = lseek( fd, 0, SEEK_END ) ) == -1 )
83 do_error( "gnu_load - determining file size" );
84 close( fd );
85 return;
88 string_size -= A_SYMPOS( header );
90 if ( (int) header.a_syms < 0 ||
91 (unsigned) header.a_syms != header.a_syms ||
92 (tp->start = (struct newnlist *) malloc( string_size ))
93 == (struct newnlist *) NULL &&
94 header.a_syms != 0 )
96 do_error( "gnu_load - allocating memory" );
97 close( fd );
98 return;
101 if ( lseek( fd, A_SYMPOS( header ), SEEK_SET ) != A_SYMPOS( header ) )
103 do_error( "gnu_load - reading header" );
104 close( fd );
105 return;
108 if ( read( fd, (char *) tp->start, string_size ) < 0 )
110 do_error( "gnu_load - reading symbols" );
111 close( fd );
112 return;
114 close( fd );
116 tp->nsym = (unsigned int) header.a_syms / sizeof (struct newnlist);
117 tp->end = tp->start + tp->nsym;
119 names = (char *) tp->start + header.a_syms;
121 for ( p = tp->start; p < tp->end; p++)
122 if(p->n_un.n_strx)
123 p->n_un.n_name = names + p->n_un.n_strx;
124 else
125 p->n_un.n_name = "";
127 /* sort on value only, name search not used much and storage a problem */
128 Printf("Sorting %d GNU symbols ....", tp->nsym );
129 gnu_sort( tp->start, tp->end );
130 Printf("\n");
134 long gnu_symbolvalue( name, is_text )
135 char *name;
136 int is_text;
138 register struct newnlist *sp;
139 sp = gnu_sname(name,is_text,0);
140 if (sp != NULL)
141 return sp->n_value;
142 else
143 return 0L;
147 static struct newnlist *gnu_sname( name, is_text, allflag )
148 char *name;
149 int is_text;
150 int allflag;
152 char *s;
153 unsigned char sclass;
154 int schar;
155 char *send;
156 register struct newnlist *sp;
157 register struct symtab_s *tp;
159 tp = &symtab;
161 if ( allflag )
163 /* find and print all matching symbols */
164 for ( sp = tp->start; sp < tp->end; ++sp )
166 if ( gnu_symprefix( name, sp ) )
168 sp = sp;
169 for ( s = sp->n_un.n_name, send = s + strlen(s);
170 *s != 0 && s < send; ++s )
171 outbyte( *s );
172 for ( ; s <= send; ++s )
173 outspace();
174 switch( sp->n_type & NN_TYPE )
176 case NN_ABS: schar = 'a'; break;
177 case NN_TEXT: schar = 't'; break;
178 case NN_DATA: schar = 'd'; break;
179 case NN_BSS: schar = 'b'; break;
180 default: schar = '?'; break;
182 if ( (sp->n_type & NN_EXT) && schar != '?' )
183 schar += 'A' - 'a';
184 outbyte( schar );
185 outspace();
186 outh32( sp->n_value );
187 outbyte('\n');
191 else
193 /* find symbol by dumb linear search */
194 for ( sp = tp->start; sp < tp->end; ++sp )
196 sclass = sp->n_type & NN_TYPE;
197 if ( (is_text && sclass == NN_TEXT ||
198 !is_text && (sclass == NN_DATA ||
199 sclass == NN_BSS)) &&
200 gnu_symeq( name, sp ) )
201 return sp;
204 return NULL;
207 static struct newnlist *gnu_sval( value, where )
208 off_t value;
209 int where;
211 int left;
212 int middle;
213 int right;
214 unsigned char sclass;
215 register struct newnlist *sp;
216 register struct symtab_s *tp;
218 tp = &symtab;
220 /* find last symbol with value <= desired one by binary search */
221 for ( left = 0, right = tp->nsym - 1; left <= right; )
223 middle = (left + right) / 2;
224 sp = tp->start + middle;
225 if ( value < sp->n_value )
226 right = middle - 1;
227 else
228 left = middle + 1;
230 if ( right >= 0 )
231 /* otherwise tp->start + right may wrap around to > tp->start !! */
232 for ( sp = tp->start + right; sp >= tp->start; --sp )
234 if ( !(sp->n_type & NN_EXT) ) continue;
235 sclass = sp->n_type & NN_TYPE;
236 if ( (where == CSEG && sclass == NN_TEXT) ||
237 (where != CSEG &&
238 (sclass == NN_DATA || sclass == NN_BSS)) )
239 return sp;
241 return NULL;
245 static void gnu_sym( sp, off )
246 struct newnlist *sp;
247 off_t off;
249 register char *s;
250 char *send;
252 for ( s = sp->n_un.n_name, send = s + strlen(s); *s != 0 && s < send; ++s )
253 outbyte( *s );
254 if ( (off -= sp->n_value) != 0 )
256 outbyte( '+' );
257 printhex(off);
261 /* shell sort symbols on value */
263 static void gnu_sort( array, top )
264 struct newnlist *array;
265 struct newnlist *top;
267 int gap;
268 int i;
269 int j;
270 register struct newnlist *left;
271 register struct newnlist *right;
272 struct newnlist swaptemp;
273 int size;
275 size = top - array;
276 /* choose gaps according to Knuth V3 p95 */
277 for ( gap = 1, i = 4; (j = 3 * i + 1) < size; gap = i, i = j )
281 for ( j = gap; j < size; ++j )
282 for ( i = j - gap; i >= 0; i -= gap )
284 left = array + i;
285 right = array + (i + gap);
286 if ( (off_t) left->n_value <=
287 right->n_value )
288 break;
289 swaptemp = *left;
290 *left = *right;
291 *right = swaptemp;
294 while ( (gap /= 3) != 0 );
297 void gnu_symbolic( value, separator )
298 off_t value;
299 int separator;
301 register struct newnlist *sp;
302 long off;
304 if (value < st_addr || value > end_addr) {
305 outstr("0x");
306 printhex(value);
307 outbyte(separator);
308 return;
311 if ( (sp = gnu_sval( value, CSEG )) != NULL )
313 gnu_sym( sp, value );
315 else if ( (sp = gnu_sval( value, DSEG )) != NULL )
317 gnu_sym( sp, value );
319 else
321 outstr("_start");
322 off = value - st_addr;
323 if ( off != 0 )
325 outbyte( '+' );
326 printhex(off);
329 outbyte( separator );
333 static int gnu_symeq( t, sp )
334 register char *t;
335 struct newnlist *sp;
337 return strncmp( t, sp->n_un.n_name, strlen(t) ) == 0;
340 static int gnu_symprefix( t, sp )
341 register char *t;
342 struct newnlist *sp;
344 register char *s;
345 char *send;
347 for ( ; *t == '_'; ++t )
349 for ( s = sp->n_un.n_name, send = s + strlen(s);
350 s < send && *s == '_'; ++s )
352 return strncmp( s, t, send - s ) == 0;
357 /* list all symbols - test for selection criteria */
359 void gnu_listsym( tchar )
360 char tchar;
362 register struct symtab_s *tp;
363 register struct newnlist *sp;
364 char *s;
365 char *send;
366 char schar;
368 outbyte('\n');
369 tp = &symtab;
370 for ( sp = tp->start; sp < tp->end; ++sp )
372 switch( sp->n_type & NN_TYPE )
374 case NN_ABS: schar = 'a'; break;
375 case NN_TEXT: schar = 't'; break;
376 case NN_DATA: schar = 'd'; break;
377 case NN_BSS: schar = 'b'; break;
378 default: schar = '?'; break;
381 if ( (sp->n_type & NN_EXT) && schar != '?' )
382 schar += 'A' - 'a';
384 /* check for selection */
385 if ( tchar != '*' && schar != tchar)
386 continue;
388 /* print symbol type and value */
389 outh32( sp->n_value );
390 outspace();
391 outbyte( schar );
392 outbyte( '\t' );
393 for ( s = sp->n_un.n_name, send = s + strlen(s);
394 *s != 0 && s < send; ++s ) outbyte( *s );
395 outbyte('\n');
399 int gnu_text_symbol(value)
400 off_t value;
402 struct newnlist *sp;
404 if ((sp = gnu_sval(value, CSEG)) != NULL && sp->n_value == value)
406 gnu_sym(sp, value);
407 return TRUE;
409 else
410 return FALSE;
413 int gnu_finds_data(off,data_seg)
414 off_t off;
415 int data_seg;
417 struct newnlist *sp;
419 if ((sp = gnu_sval(off, data_seg)) != NULL)
421 gnu_sym(sp, off);
422 return TRUE;
424 else
425 return FALSE;
428 int gnu_finds_pc(pc)
429 off_t pc;
431 struct newnlist *sp;
433 if ((sp = gnu_sval(pc, CSEG)) != NULL)
435 gnu_sym(sp, pc);
436 return TRUE;
438 else
439 return FALSE;
443 #endif /* EXTRA_SYMBOLS */