Commit | Line | Data |
---|---|---|
920dae64 AT |
1 | // ========== Copyright Header Begin ========================================== |
2 | // | |
3 | // OpenSPARC T2 Processor File: symbols.cc | |
4 | // Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved. | |
5 | // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES. | |
6 | // | |
7 | // The above named program is free software; you can redistribute it and/or | |
8 | // modify it under the terms of the GNU General Public | |
9 | // License version 2 as published by the Free Software Foundation. | |
10 | // | |
11 | // The above named program is distributed in the hope that it will be | |
12 | // useful, but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | // General Public License for more details. | |
15 | // | |
16 | // You should have received a copy of the GNU General Public | |
17 | // License along with this work; if not, write to the Free Software | |
18 | // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 | // | |
20 | // ========== Copyright Header End ============================================ | |
21 | //////////////////////////////////////////////////////////// | |
22 | // | |
23 | // File: symbols.cc | |
24 | // | |
25 | // Symbol table submodule | |
26 | // | |
27 | // Copyright (C) 2006 Sun Microsystems, Inc. | |
28 | // All rights reserved. | |
29 | // | |
30 | // Symbol table implementation file | |
31 | // | |
32 | ||
33 | #include <stdio.h> | |
34 | #include <stdlib.h> | |
35 | #include <ctype.h> | |
36 | #include "types.h" | |
37 | #include "symbols.h" | |
38 | #include "ui.h" | |
39 | ||
40 | ||
41 | #define DEBUG_ON 0 | |
42 | ||
43 | ///////////////////////////////////////////////////////// | |
44 | // | |
45 | // Symbol class | |
46 | // | |
47 | ||
48 | Symbol::Symbol | |
49 | ( | |
50 | char* mname, // module name | |
51 | char* sname, // symbol name | |
52 | uint64_t vaddr, // starting address | |
53 | uint64_t size, // size of address space taken this symbol | |
54 | uint32_t context // symbol context | |
55 | ) | |
56 | : SymBase(NULL) | |
57 | { | |
58 | // add module name | |
59 | if (sname != NULL) | |
60 | { | |
61 | char sym_name[128]; | |
62 | sprintf (sym_name, "%s:%s", mname, sname); | |
63 | m_name = strdup(sym_name); | |
64 | m_sname = strdup(sname); | |
65 | } | |
66 | else | |
67 | { | |
68 | m_name = NULL; | |
69 | m_sname = NULL; | |
70 | } | |
71 | m_next = NULL; | |
72 | ||
73 | m_vaddr = vaddr; | |
74 | m_size = size; | |
75 | ||
76 | m_context = context; | |
77 | } | |
78 | ||
79 | // destructor | |
80 | Symbol::~Symbol () | |
81 | { | |
82 | if (m_name ) free(m_name); | |
83 | if (m_sname) free(m_sname); | |
84 | } | |
85 | ||
86 | ////////////////////////////////////////////////////////////// | |
87 | // | |
88 | // Container class for all symbols | |
89 | // | |
90 | ||
91 | // constructor | |
92 | SymTable::SymTable | |
93 | ( | |
94 | uint32_t levels, // total number of table levels +1 | |
95 | uint32_t *idx_width // number of bits for table index | |
96 | // on each level, plus last offset | |
97 | ) | |
98 | { | |
99 | ||
100 | int i; | |
101 | uint32_t *wd = idx_width; | |
102 | ||
103 | const uint32_t default_level = MAX_LEVEL+1; // number of tables + 1 | |
104 | uint32_t default_width[default_level] = {12,10,10,10,10,10,2}; | |
105 | ||
106 | ||
107 | if ((idx_width == NULL) || (levels > default_level )) | |
108 | { | |
109 | levels = default_level; | |
110 | wd = default_width; | |
111 | } | |
112 | ||
113 | m_lev = levels-2; | |
114 | int max_lev = m_lev + 1; | |
115 | ||
116 | for (i=max_lev; i>=0; i--) | |
117 | { | |
118 | m_width[i] = wd[i]; | |
119 | m_size [i] = 1<<m_width[i]; | |
120 | m_mask [i] = m_size[i] -1; | |
121 | ||
122 | m_sft [i] = (i==max_lev) ? 0 : m_width[i+1]; | |
123 | if ( i < max_lev) | |
124 | m_sft [i] += m_sft[i+1]; | |
125 | #if(DEBUG_ON) | |
126 | ui->verbose("\n symbol tbl level=%d, sft=%d, width=%d, size=0x%x, mask=0x%llx\n", | |
127 | i, m_sft[i],m_width[i],m_size[i],m_mask[i]); | |
128 | #endif | |
129 | ||
130 | } | |
131 | ||
132 | m_tbl = (void **) calloc(m_size[0], sizeof(void*)); | |
133 | ||
134 | for (int j=0; j<SYM_TBL_SIZE; j++) | |
135 | m_bucket[j] = NULL; | |
136 | ||
137 | m_empty = true; | |
138 | } | |
139 | ||
140 | // destructor | |
141 | SymTable::~SymTable () | |
142 | { | |
143 | for (int j=0; j<SYM_TBL_SIZE; j++) | |
144 | { | |
145 | if (m_bucket[j] != NULL) | |
146 | delete m_bucket[j]; | |
147 | } | |
148 | ||
149 | delete_tbl ( m_tbl, 0 ); | |
150 | } | |
151 | ||
152 | // get a pointer in multi level addr tables; | |
153 | // nested tables are allocated if needed | |
154 | void ** SymTable::alloc( uint64_t addr ) | |
155 | { | |
156 | void ** tbl = m_tbl; | |
157 | void ** ptr = NULL; | |
158 | ||
159 | ||
160 | for ( int i=0; i<m_lev; i++) | |
161 | { | |
162 | ptr = tbl + ((addr>>m_sft[i]) & m_mask[i]); | |
163 | void **next = (void**)(*ptr); | |
164 | if (next == NULL) | |
165 | { | |
166 | // allocate a new table | |
167 | next = (void **) calloc ( m_size[i+1], sizeof(void*)); | |
168 | ||
169 | // insert a pointer | |
170 | *ptr = next; | |
171 | } | |
172 | tbl = next; | |
173 | } | |
174 | ||
175 | // get a pointer to the leaf table entry | |
176 | return (tbl + ((addr>>m_sft[m_lev]) & m_mask[m_lev])); | |
177 | } | |
178 | ||
179 | // recursively delete all tables on deeper levels | |
180 | void SymTable::delete_tbl ( void ** tbl, uint32_t level) | |
181 | { | |
182 | if ( level == m_lev ) | |
183 | { | |
184 | // leaf table | |
185 | for ( int i=0; i<m_size[level]; i++ ) | |
186 | { | |
187 | // remove all links | |
188 | SymBase *s = (SymBase *)tbl[i]; | |
189 | ||
190 | while (s) | |
191 | { | |
192 | SymBase *r = s; | |
193 | s = s->m_link; | |
194 | if (r->m_origin) | |
195 | delete (r); | |
196 | else | |
197 | { | |
198 | delete ( (Symbol*)r); | |
199 | } | |
200 | } | |
201 | ||
202 | } | |
203 | free ( tbl ); | |
204 | } | |
205 | else | |
206 | { | |
207 | for ( int i=0; i<m_size[level]; i++ ) | |
208 | { | |
209 | if (tbl[i]) // nested table | |
210 | delete_tbl ( (void **)tbl[i], level+1 ); | |
211 | free ( tbl[i] ); | |
212 | } | |
213 | } | |
214 | } | |
215 | ||
216 | ||
217 | // search for symbols specified by symbol name; | |
218 | // return pointer to symbol if found; 0 otherwise | |
219 | Symbol* SymTable::find | |
220 | ( | |
221 | char* name, // symbol name | |
222 | Symbol* start // start search from this one | |
223 | ) | |
224 | { | |
225 | if ( this->is_empty() ) | |
226 | return NULL; | |
227 | ||
228 | Symbol *sym = start ? start->m_next : NULL; | |
229 | ||
230 | if (start == NULL) | |
231 | { | |
232 | // hash index for the bucket | |
233 | sym = m_bucket[sym_hash(name)]; | |
234 | } | |
235 | ||
236 | ||
237 | while (sym) // possibly iterate through the list | |
238 | { | |
239 | // check if name match | |
240 | if ( strcmp (sym->m_sname, name) == 0 ) | |
241 | { | |
242 | return sym; | |
243 | } | |
244 | // traverse the list for this bucket | |
245 | sym = sym->m_next; | |
246 | } | |
247 | ||
248 | return NULL; | |
249 | } | |
250 | ||
251 | // find symbol specified by address ; | |
252 | // return 1 if found, 0 otherwise; | |
253 | SymBase* SymTable::find | |
254 | ( | |
255 | uint64_t addr, // address used to lookup the symbol | |
256 | SymBase* start // start from this symbol | |
257 | ) | |
258 | { | |
259 | SymBase* res = NULL; | |
260 | ||
261 | ||
262 | SymBase* s = start ? start->m_link : NULL; | |
263 | ||
264 | if(start==NULL) | |
265 | s = find ( addr ); | |
266 | ||
267 | if ( s == NULL ) | |
268 | return 0; // not found | |
269 | ||
270 | while (s) | |
271 | { | |
272 | Symbol *sym = (s->m_origin) ? (Symbol*)(s->m_origin) : (Symbol*)s; | |
273 | ||
274 | // check the range | |
275 | if ( (addr >= sym->m_vaddr) && | |
276 | (addr < (sym->m_vaddr+ sym->m_size)) ) | |
277 | { | |
278 | // symbol is in the range | |
279 | res = (SymBase*)sym; | |
280 | return res; | |
281 | } | |
282 | ||
283 | s = s->m_link; | |
284 | } | |
285 | return res; | |
286 | } | |
287 | ||
288 | // find and output address for all symbols specified by name; | |
289 | // return 1 if found, 0 otherwise; | |
290 | int SymTable::fputs | |
291 | ( | |
292 | char *name, // name used to lookup the symbol | |
293 | uint32_t context, // symbol context | |
294 | FILE * fp // output symbol name to stream if found | |
295 | ) | |
296 | { | |
297 | int res = 0; | |
298 | ||
299 | if ( this->is_empty() ) | |
300 | return 0; | |
301 | ||
302 | // hash index for the bucket | |
303 | int hindex = sym_hash ( name ); | |
304 | ||
305 | Symbol *sym = m_bucket[hindex]; | |
306 | ||
307 | while (sym) // possibly iterate over the list | |
308 | { | |
309 | // check if name match | |
310 | if ( | |
311 | (context == Symbol::ANY_CONTEXT || context == sym->m_context) && | |
312 | (strcmp (sym->m_sname, name) == 0) | |
313 | ) | |
314 | { | |
315 | fprintf(fp,"\n%s at address=0x%llx, size=0x%llx \n", sym->m_name, sym->m_vaddr, sym->m_size); | |
316 | res = 1; | |
317 | } | |
318 | ||
319 | // traverse the list for this bucket | |
320 | sym = sym->m_next; | |
321 | } | |
322 | ||
323 | return res; | |
324 | } | |
325 | ||
326 | ||
327 | // find and output full symbol name by specified address ; | |
328 | // return 1 if found, 0 otherwise; | |
329 | int SymTable::fputs | |
330 | ( | |
331 | uint64_t addr, // address used to lookup the symbol | |
332 | uint32_t context, // symbol context | |
333 | FILE * fp // output symbol name to stream if found | |
334 | ) | |
335 | { | |
336 | int res = 0; | |
337 | SymBase *s = find ( addr ); | |
338 | ||
339 | ||
340 | if ( s == NULL ) | |
341 | return 0; // not found | |
342 | ||
343 | while (s) | |
344 | { | |
345 | Symbol *sym = (s->m_origin) ? (Symbol*)(s->m_origin) : (Symbol*)s; | |
346 | ||
347 | // check the range | |
348 | if ( | |
349 | (context == Symbol::ANY_CONTEXT || context == sym->m_context) && | |
350 | (addr >= sym->m_vaddr) && | |
351 | (addr < (sym->m_vaddr+ sym->m_size)) | |
352 | ) | |
353 | { | |
354 | // symbol is in the range | |
355 | fprintf (fp, "%s+0x%llx ", sym->m_name, addr - sym->m_vaddr); | |
356 | res = 1; | |
357 | } | |
358 | ||
359 | #if(DEBUG_ON) | |
360 | // debug print out | |
361 | if (s->m_origin) fprintf (fp, "\nredirected to ->"); | |
362 | fprintf(fp, "0x%016llx : 0x%016llx : %s , sp=0x%llx \n", | |
363 | sym->m_vaddr, sym->m_size, sym->m_name, s); | |
364 | #endif | |
365 | ||
366 | s = s->m_link; | |
367 | } | |
368 | return res; | |
369 | } | |
370 | ||
371 | // add a new symbol to the symbol table | |
372 | // return 1 if added, 0 otherwise | |
373 | int SymTable::add | |
374 | ( | |
375 | char * mname, // module name | |
376 | char * name, // symbol name | |
377 | uint64_t vaddr, // starting address | |
378 | uint64_t size, // range covered | |
379 | uint32_t context // symbol context | |
380 | ) | |
381 | { | |
382 | if ((vaddr == ~uint64_t(0)) || (size == 0)) | |
383 | return 0; | |
384 | ||
385 | uint32_t awidth = m_width[0] + m_sft[0]; | |
386 | uint64_t max_addr = awidth < 64 ? (uint64_t(1)<<awidth) - 1 : ~uint64_t(0); | |
387 | ||
388 | ||
389 | if ( ~max_addr && (vaddr & ~max_addr) ) | |
390 | { | |
391 | ui->warning( "Symbol: %s ingnored, address 0x%llx exceeds max addr 0x%llx for the sym table. \n", | |
392 | name, vaddr, max_addr); | |
393 | return 0; | |
394 | } | |
395 | ||
396 | // create a new symbol | |
397 | Symbol *sym = new Symbol(mname, name, vaddr, size, context); | |
398 | ||
399 | uint64_t addr = vaddr; | |
400 | ||
401 | // block size | |
402 | uint32_t bsize = m_size[m_lev+1]; | |
403 | ||
404 | // cover all range | |
405 | for (uint64_t offset = 0; ((vaddr+offset) & ~m_mask[m_lev+1]) <= (vaddr+size); offset += bsize) | |
406 | { | |
407 | SymBase *new_sym = (SymBase *)sym; | |
408 | ||
409 | if (offset !=0 ) // not first symbol in the range | |
410 | { | |
411 | new_sym = sym->dup(); | |
412 | } | |
413 | ||
414 | // find a spot in address tables | |
415 | SymBase **p_sym = (SymBase **)this->alloc(addr); | |
416 | ||
417 | ||
418 | if (*p_sym==NULL) // table slot is empty | |
419 | { | |
420 | // insert new symbol | |
421 | *p_sym = new_sym; | |
422 | } | |
423 | else // something is already there | |
424 | { | |
425 | // overlap with another symbol | |
426 | (*p_sym)->attach ( new_sym ); | |
427 | #if(DEBUG_ON) | |
428 | ui->verbose("\nnew_sym=0x%llx: %s+0x%llx was attached to p_sym=0x%llx(0x%llx) \n", | |
429 | new_sym, sym->m_name, offset, *p_sym, p_sym); | |
430 | #endif | |
431 | } | |
432 | ||
433 | addr += bsize; | |
434 | } | |
435 | ||
436 | ||
437 | ||
438 | // insert symbol into hash list | |
439 | int hindex = sym_hash (name); // hash index | |
440 | sym->m_next = m_bucket[hindex]; | |
441 | m_bucket[hindex] = sym; | |
442 | ||
443 | m_empty = false; | |
444 | ||
445 | return 1; | |
446 | } | |
447 | ||
448 | // print all symbols | |
449 | // from low to upper addresses | |
450 | void SymTable::print ( char *filename, uint32_t context ) | |
451 | { | |
452 | uint64_t total = 0; | |
453 | ||
454 | ||
455 | if(filename) | |
456 | { | |
457 | FILE* fp = fopen (filename, "w"); | |
458 | ||
459 | if ( fp == NULL ) | |
460 | { | |
461 | ui->error("cannot open %s\n", filename); | |
462 | return; | |
463 | } | |
464 | else | |
465 | { | |
466 | ui->verbose("Collect symbols to %s file\n", filename); | |
467 | } | |
468 | ||
469 | if (print_tbl ( fp, m_tbl, 0, total, context )==0) | |
470 | fprintf(fp, "Total number of symbols: %i \n", total); | |
471 | ||
472 | fclose(fp); | |
473 | } | |
474 | else | |
475 | { | |
476 | if (print_tbl ( ui->get_output_file(), m_tbl, 0, total, context )==0) | |
477 | fprintf(ui->get_output_file(), "Total number of symbols: %i \n", total); | |
478 | ||
479 | // When logging is enabled we replicate output to log file. | |
480 | if (ui->get_log_file() | |
481 | && (print_tbl ( ui->get_log_file(), m_tbl, 0, total, context )==0)) | |
482 | fprintf(ui->get_log_file(), "Total number of symbols: %i \n", total); | |
483 | } | |
484 | } | |
485 | ||
486 | // print one symbol | |
487 | int print_sym ( FILE *fp, Symbol *s, uint32_t context ) | |
488 | { | |
489 | if (context != Symbol::ANY_CONTEXT && context != s->context()) | |
490 | return 0; | |
491 | ||
492 | fprintf(fp, "0x%016llx : 0x%016llx ", | |
493 | s->vaddr(), s->size()); | |
494 | ||
495 | if (s->context() < Symbol::NO_CONTEXT) | |
496 | fprintf(fp, ": 0x%08lx : %s \n", s->context(), s->name()); | |
497 | else | |
498 | fprintf(fp, ": %s \n", s->name()); | |
499 | ||
500 | return 1; | |
501 | } | |
502 | ||
503 | // recursively print symbols for all tables on deeper levels | |
504 | int SymTable::print_tbl | |
505 | ( | |
506 | FILE *fp, // output to the stream | |
507 | void ** tbl, // table pointer | |
508 | uint32_t level, // table level | |
509 | uint64_t &total, // symbol counter | |
510 | uint32_t context | |
511 | ) | |
512 | { | |
513 | if ( level == m_lev ) | |
514 | { | |
515 | // leaf table | |
516 | for ( int j=0; j<m_size[level]; j++ ) | |
517 | { | |
518 | SymBase *sym = (Symbol *)tbl[j]; | |
519 | ||
520 | while (sym) | |
521 | { | |
522 | if (sym->m_origin) // range mark - skip it | |
523 | { | |
524 | sym = sym->m_link; | |
525 | continue; | |
526 | } | |
527 | ||
528 | Symbol *s = (Symbol *)sym; | |
529 | ||
530 | if (print_sym (fp, s, context)) | |
531 | { | |
532 | total++; | |
533 | if ((fp == ui->get_output_file()) && ((total % 40) == 0)) | |
534 | { | |
535 | fprintf ( fp, "more? space, n - next page, q - quit\n"); | |
536 | char c; | |
537 | scanf("%c", &c); | |
538 | if (c == 'q') | |
539 | return 1; | |
540 | } | |
541 | } | |
542 | sym = sym->m_link; | |
543 | } | |
544 | } | |
545 | return 0; | |
546 | ||
547 | } | |
548 | else | |
549 | { | |
550 | for ( int i=0; i<m_size[level]; i++ ) | |
551 | { | |
552 | if (tbl[i]) // nested table | |
553 | if (print_tbl ( fp, (void **)tbl[i], level+1, total, context ) != 0) | |
554 | return 1; // quit | |
555 | } | |
556 | } | |
557 | return 0; | |
558 | } | |
559 | ||
560 | // print all symbols without any order - | |
561 | // hash table order | |
562 | int SymTable::hprint ( char *filename, uint32_t context ) | |
563 | { | |
564 | int index_max = 0; | |
565 | int icount_max = 0; | |
566 | int total = 0; | |
567 | int cont = 0; | |
568 | ||
569 | FILE *fp = ui->get_output_file(); | |
570 | ||
571 | if(filename) | |
572 | { | |
573 | fp = fopen (filename, "w"); | |
574 | if ( fp == NULL ) | |
575 | { | |
576 | ui->error("cannot open %s\n", filename); | |
577 | return 1; | |
578 | } | |
579 | else | |
580 | { | |
581 | ui->verbose("Collect symbols to %s file\n", filename); | |
582 | } | |
583 | } | |
584 | fprintf(fp, "Symbol table: \n"); | |
585 | ||
586 | for ( int j = 0; j<SYM_TBL_SIZE; j++) | |
587 | { | |
588 | Symbol *sym = m_bucket[j]; | |
589 | Symbol *prev = NULL; | |
590 | ||
591 | int count = 0; | |
592 | ||
593 | while (sym) // possibly iterate through the list | |
594 | { | |
595 | if (print_sym (fp, sym, context)) | |
596 | { | |
597 | count +=1; | |
598 | total +=1; | |
599 | if ((cont == 0) && (fp == ui->get_output_file()) && | |
600 | ((total % 40) == 0)) | |
601 | { | |
602 | fprintf ( fp, "more? space, n - next page, q - quit\n"); | |
603 | char c; | |
604 | scanf("%c", &c); | |
605 | if (c == 'q') | |
606 | goto quiting; | |
607 | else if ( c == 'c' ) | |
608 | cont = 1; | |
609 | } | |
610 | } | |
611 | sym = sym->m_next; | |
612 | } | |
613 | ||
614 | if (icount_max < count) | |
615 | { | |
616 | icount_max = count; | |
617 | index_max = j; | |
618 | } | |
619 | ||
620 | ||
621 | ||
622 | } //for j | |
623 | ||
624 | quiting: | |
625 | fprintf(fp, "Total number of symbols: %i \n", total); | |
626 | ||
627 | fprintf(fp, "max list size = %i at idx = %i \n", icount_max, index_max); | |
628 | ||
629 | ||
630 | return 0; | |
631 | } | |
632 | ||
633 |