| 1 | /* Generic symbol file reading for the GNU debugger, GDB. |
| 2 | Copyright 1990, 1991 Free Software Foundation, Inc. |
| 3 | Contributed by Cygnus Support, using pieces from other GDB modules. |
| 4 | |
| 5 | This file is part of GDB. |
| 6 | |
| 7 | GDB is free software; you can redistribute it and/or modify |
| 8 | it under the terms of the GNU General Public License as published by |
| 9 | the Free Software Foundation; either version 1, or (at your option) |
| 10 | any later version. |
| 11 | |
| 12 | GDB is distributed in the hope that it will be useful, |
| 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 15 | GNU General Public License for more details. |
| 16 | |
| 17 | You should have received a copy of the GNU General Public License |
| 18 | along with GDB; see the file COPYING. If not, write to |
| 19 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ |
| 20 | |
| 21 | #include <stdio.h> |
| 22 | #include "defs.h" |
| 23 | #include "symtab.h" |
| 24 | #include "param.h" |
| 25 | #include "gdbcore.h" |
| 26 | #include "frame.h" |
| 27 | #include "target.h" |
| 28 | #include "value.h" |
| 29 | #include "symfile.h" |
| 30 | #include "gdbcmd.h" |
| 31 | #include "breakpoint.h" |
| 32 | |
| 33 | #include <obstack.h> |
| 34 | #include <assert.h> |
| 35 | |
| 36 | #include <sys/types.h> |
| 37 | #include <fcntl.h> |
| 38 | #include <string.h> |
| 39 | #include <sys/stat.h> |
| 40 | |
| 41 | extern int info_verbose; |
| 42 | |
| 43 | extern int close (); |
| 44 | extern void qsort (); |
| 45 | extern char *getenv (); |
| 46 | |
| 47 | /* Functions this file defines */ |
| 48 | static bfd *symfile_open(); |
| 49 | static struct sym_fns *symfile_init(); |
| 50 | |
| 51 | /* List of all available sym_fns. */ |
| 52 | |
| 53 | struct sym_fns *symtab_fns = NULL; |
| 54 | |
| 55 | /* Saves the sym_fns of the current symbol table, so we can call |
| 56 | the right sym_discard function when we free it. */ |
| 57 | |
| 58 | static struct sym_fns *symfile_fns; |
| 59 | |
| 60 | /* Allocate an obstack to hold objects that should be freed |
| 61 | when we load a new symbol table. |
| 62 | This includes the symbols made by dbxread |
| 63 | and the types that are not permanent. */ |
| 64 | |
| 65 | struct obstack obstack1; |
| 66 | |
| 67 | struct obstack *symbol_obstack = &obstack1; |
| 68 | |
| 69 | /* This obstack will be used for partial_symbol objects. It can |
| 70 | probably actually be the same as the symbol_obstack above, but I'd |
| 71 | like to keep them seperate for now. If I want to later, I'll |
| 72 | replace one with the other. */ |
| 73 | |
| 74 | struct obstack obstack2; |
| 75 | |
| 76 | struct obstack *psymbol_obstack = &obstack2; |
| 77 | |
| 78 | /* File name symbols were loaded from. */ |
| 79 | |
| 80 | char *symfile = 0; |
| 81 | |
| 82 | /* The modification date of the file when they were loaded. */ |
| 83 | |
| 84 | int symfile_mtime = 0; |
| 85 | |
| 86 | /* Structures with which to manage partial symbol allocation. */ |
| 87 | |
| 88 | struct psymbol_allocation_list global_psymbols = {0}, static_psymbols = {0}; |
| 89 | |
| 90 | /* Structure to manage complaints about symbol file contents. */ |
| 91 | |
| 92 | struct complaint complaint_root[1] = { |
| 93 | {(char *)0, 0, complaint_root}, |
| 94 | }; |
| 95 | |
| 96 | \f |
| 97 | /* In the following sort, we always make sure that |
| 98 | register debug symbol declarations always come before regular |
| 99 | debug symbol declarations (as might happen when parameters are |
| 100 | then put into registers by the compiler). */ |
| 101 | |
| 102 | static int |
| 103 | compare_symbols (s1, s2) |
| 104 | struct symbol **s1, **s2; |
| 105 | { |
| 106 | register int namediff; |
| 107 | |
| 108 | /* Compare the initial characters. */ |
| 109 | namediff = SYMBOL_NAME (*s1)[0] - SYMBOL_NAME (*s2)[0]; |
| 110 | if (namediff != 0) return namediff; |
| 111 | |
| 112 | /* If they match, compare the rest of the names. */ |
| 113 | namediff = strcmp (SYMBOL_NAME (*s1), SYMBOL_NAME (*s2)); |
| 114 | if (namediff != 0) return namediff; |
| 115 | |
| 116 | /* For symbols of the same name, registers should come first. */ |
| 117 | return ((SYMBOL_CLASS (*s2) == LOC_REGISTER) |
| 118 | - (SYMBOL_CLASS (*s1) == LOC_REGISTER)); |
| 119 | } |
| 120 | |
| 121 | /* Call sort_block_syms to sort alphabetically the symbols of one block. */ |
| 122 | |
| 123 | void |
| 124 | sort_block_syms (b) |
| 125 | register struct block *b; |
| 126 | { |
| 127 | qsort (&BLOCK_SYM (b, 0), BLOCK_NSYMS (b), |
| 128 | sizeof (struct symbol *), compare_symbols); |
| 129 | } |
| 130 | |
| 131 | /* Call sort_symtab_syms to sort alphabetically |
| 132 | the symbols of each block of one symtab. */ |
| 133 | |
| 134 | void |
| 135 | sort_symtab_syms (s) |
| 136 | register struct symtab *s; |
| 137 | { |
| 138 | register struct blockvector *bv = BLOCKVECTOR (s); |
| 139 | int nbl = BLOCKVECTOR_NBLOCKS (bv); |
| 140 | int i; |
| 141 | register struct block *b; |
| 142 | |
| 143 | for (i = 0; i < nbl; i++) |
| 144 | { |
| 145 | b = BLOCKVECTOR_BLOCK (bv, i); |
| 146 | if (BLOCK_SHOULD_SORT (b)) |
| 147 | sort_block_syms (b); |
| 148 | } |
| 149 | } |
| 150 | |
| 151 | void |
| 152 | sort_all_symtab_syms () |
| 153 | { |
| 154 | register struct symtab *s; |
| 155 | |
| 156 | for (s = symtab_list; s; s = s->next) |
| 157 | { |
| 158 | sort_symtab_syms (s); |
| 159 | } |
| 160 | } |
| 161 | |
| 162 | /* Make a copy of the string at PTR with SIZE characters in the symbol obstack |
| 163 | (and add a null character at the end in the copy). |
| 164 | Returns the address of the copy. */ |
| 165 | |
| 166 | char * |
| 167 | obsavestring (ptr, size) |
| 168 | char *ptr; |
| 169 | int size; |
| 170 | { |
| 171 | register char *p = (char *) obstack_alloc (symbol_obstack, size + 1); |
| 172 | /* Open-coded bcopy--saves function call time. |
| 173 | These strings are usually short. */ |
| 174 | { |
| 175 | register char *p1 = ptr; |
| 176 | register char *p2 = p; |
| 177 | char *end = ptr + size; |
| 178 | while (p1 != end) |
| 179 | *p2++ = *p1++; |
| 180 | } |
| 181 | p[size] = 0; |
| 182 | return p; |
| 183 | } |
| 184 | |
| 185 | /* Concatenate strings S1, S2 and S3; return the new string. |
| 186 | Space is found in the symbol_obstack. */ |
| 187 | |
| 188 | char * |
| 189 | obconcat (s1, s2, s3) |
| 190 | char *s1, *s2, *s3; |
| 191 | { |
| 192 | register int len = strlen (s1) + strlen (s2) + strlen (s3) + 1; |
| 193 | register char *val = (char *) obstack_alloc (symbol_obstack, len); |
| 194 | strcpy (val, s1); |
| 195 | strcat (val, s2); |
| 196 | strcat (val, s3); |
| 197 | return val; |
| 198 | } |
| 199 | \f |
| 200 | /* Accumulate the misc functions in bunches of 127. |
| 201 | At the end, copy them all into one newly allocated structure. */ |
| 202 | |
| 203 | #define MISC_BUNCH_SIZE 127 |
| 204 | |
| 205 | struct misc_bunch |
| 206 | { |
| 207 | struct misc_bunch *next; |
| 208 | struct misc_function contents[MISC_BUNCH_SIZE]; |
| 209 | }; |
| 210 | |
| 211 | /* Bunch currently being filled up. |
| 212 | The next field points to chain of filled bunches. */ |
| 213 | |
| 214 | static struct misc_bunch *misc_bunch; |
| 215 | |
| 216 | /* Number of slots filled in current bunch. */ |
| 217 | |
| 218 | static int misc_bunch_index; |
| 219 | |
| 220 | /* Total number of misc functions recorded so far. */ |
| 221 | |
| 222 | static int misc_count; |
| 223 | |
| 224 | void |
| 225 | init_misc_bunches () |
| 226 | { |
| 227 | misc_count = 0; |
| 228 | misc_bunch = 0; |
| 229 | misc_bunch_index = MISC_BUNCH_SIZE; |
| 230 | } |
| 231 | |
| 232 | void |
| 233 | prim_record_misc_function (name, address, misc_type) |
| 234 | char *name; |
| 235 | CORE_ADDR address; |
| 236 | enum misc_function_type misc_type; |
| 237 | { |
| 238 | register struct misc_bunch *new; |
| 239 | |
| 240 | if (misc_bunch_index == MISC_BUNCH_SIZE) |
| 241 | { |
| 242 | new = (struct misc_bunch *) xmalloc (sizeof (struct misc_bunch)); |
| 243 | misc_bunch_index = 0; |
| 244 | new->next = misc_bunch; |
| 245 | misc_bunch = new; |
| 246 | } |
| 247 | misc_bunch->contents[misc_bunch_index].name = name; |
| 248 | misc_bunch->contents[misc_bunch_index].address = address; |
| 249 | misc_bunch->contents[misc_bunch_index].type = misc_type; |
| 250 | misc_bunch->contents[misc_bunch_index].misc_info = 0; |
| 251 | misc_bunch_index++; |
| 252 | misc_count++; |
| 253 | } |
| 254 | |
| 255 | static int |
| 256 | compare_misc_functions (fn1, fn2) |
| 257 | struct misc_function *fn1, *fn2; |
| 258 | { |
| 259 | /* Return a signed result based on unsigned comparisons |
| 260 | so that we sort into unsigned numeric order. */ |
| 261 | if (fn1->address < fn2->address) |
| 262 | return -1; |
| 263 | if (fn1->address > fn2->address) |
| 264 | return 1; |
| 265 | return 0; |
| 266 | } |
| 267 | |
| 268 | /* ARGSUSED */ |
| 269 | void |
| 270 | discard_misc_bunches (foo) |
| 271 | int foo; |
| 272 | { |
| 273 | register struct misc_bunch *next; |
| 274 | |
| 275 | while (misc_bunch) |
| 276 | { |
| 277 | next = misc_bunch->next; |
| 278 | free (misc_bunch); |
| 279 | misc_bunch = next; |
| 280 | } |
| 281 | } |
| 282 | |
| 283 | /* INCLINK nonzero means bunches are from an incrementally-linked file. |
| 284 | Add them to the existing bunches. |
| 285 | Otherwise INCLINK is zero, and we start from scratch. */ |
| 286 | void |
| 287 | condense_misc_bunches (inclink) |
| 288 | int inclink; |
| 289 | { |
| 290 | register int i, j; |
| 291 | register struct misc_bunch *bunch; |
| 292 | |
| 293 | if (inclink) |
| 294 | { |
| 295 | misc_function_vector |
| 296 | = (struct misc_function *) |
| 297 | xrealloc (misc_function_vector, (misc_count + misc_function_count) |
| 298 | * sizeof (struct misc_function)); |
| 299 | j = misc_function_count; |
| 300 | } |
| 301 | else |
| 302 | { |
| 303 | misc_function_vector |
| 304 | = (struct misc_function *) |
| 305 | xmalloc (misc_count * sizeof (struct misc_function)); |
| 306 | j = 0; |
| 307 | } |
| 308 | |
| 309 | bunch = misc_bunch; |
| 310 | while (bunch) |
| 311 | { |
| 312 | for (i = 0; i < misc_bunch_index; i++, j++) |
| 313 | { |
| 314 | misc_function_vector[j] = bunch->contents[i]; |
| 315 | #ifdef NAMES_HAVE_UNDERSCORE |
| 316 | if (misc_function_vector[j].name[0] == '_') |
| 317 | misc_function_vector[j].name++; |
| 318 | #endif |
| 319 | } |
| 320 | bunch = bunch->next; |
| 321 | misc_bunch_index = MISC_BUNCH_SIZE; |
| 322 | } |
| 323 | |
| 324 | if (misc_function_count + misc_count != j) /* DEBUG */ |
| 325 | printf_filtered ("Function counts are off! %d + %d != %d\n", |
| 326 | misc_function_count, misc_count, j); |
| 327 | |
| 328 | misc_function_count = j; |
| 329 | |
| 330 | /* Sort the misc functions by address. */ |
| 331 | |
| 332 | qsort (misc_function_vector, misc_function_count, |
| 333 | sizeof (struct misc_function), |
| 334 | compare_misc_functions); |
| 335 | } |
| 336 | |
| 337 | |
| 338 | /* Get the symbol table that corresponds to a partial_symtab. |
| 339 | This is fast after the first time you do it. In fact, there |
| 340 | is an even faster macro PSYMTAB_TO_SYMTAB that does the fast |
| 341 | case inline. */ |
| 342 | |
| 343 | struct symtab * |
| 344 | psymtab_to_symtab (pst) |
| 345 | register struct partial_symtab *pst; |
| 346 | { |
| 347 | register struct symtab *result; |
| 348 | |
| 349 | /* If it's been looked up before, return it. */ |
| 350 | if (pst->symtab) |
| 351 | return pst->symtab; |
| 352 | |
| 353 | /* If it has not yet been read in, read it. */ |
| 354 | if (!pst->readin) |
| 355 | { |
| 356 | (*pst->read_symtab) (pst); |
| 357 | } |
| 358 | |
| 359 | /* Search through list for correct name. */ |
| 360 | for (result = symtab_list; result; result = result->next) |
| 361 | if (!strcmp (result->filename, pst->filename)) |
| 362 | { |
| 363 | pst->symtab = result; /* Remember where it was. */ |
| 364 | return result; |
| 365 | } |
| 366 | |
| 367 | return 0; |
| 368 | } |
| 369 | |
| 370 | /* Process a symbol file, as either the main file or as a dynamically |
| 371 | loaded file. |
| 372 | |
| 373 | NAME is the file name (which will be tilde-expanded and made absolute |
| 374 | herein). FROM_TTY says how verbose to be. MAINLINE specifies whether |
| 375 | this is the main symbol file, or whether it's an extra symbol file |
| 376 | such as dynamically loaded code. If !mainline, ADDR is the address |
| 377 | where the text segment was loaded. */ |
| 378 | |
| 379 | void |
| 380 | symbol_file_add (name, from_tty, addr, mainline) |
| 381 | char *name; |
| 382 | int from_tty; |
| 383 | CORE_ADDR addr; |
| 384 | int mainline; |
| 385 | { |
| 386 | bfd *sym_bfd; |
| 387 | asection *text_sect; |
| 388 | struct sym_fns *sf; |
| 389 | char *realname; |
| 390 | |
| 391 | sym_bfd = symfile_open (name); |
| 392 | |
| 393 | entry_point = bfd_get_start_address (sym_bfd); |
| 394 | |
| 395 | if (mainline) |
| 396 | symfile_mtime = bfd_get_mtime (sym_bfd); |
| 397 | |
| 398 | /* There is a distinction between having no symbol table |
| 399 | (we refuse to read the file, leaving the old set of symbols around) |
| 400 | and having no debugging symbols in your symbol table (we read |
| 401 | the file and end up with a mostly empty symbol table). */ |
| 402 | |
| 403 | if (!(bfd_get_file_flags (sym_bfd) & HAS_SYMS)) |
| 404 | { |
| 405 | error ("%s has no symbol-table", name); |
| 406 | } |
| 407 | |
| 408 | if ((symtab_list || partial_symtab_list) |
| 409 | && mainline |
| 410 | && from_tty |
| 411 | && !query ("Load new symbol table from \"%s\"? ", name)) |
| 412 | error ("Not confirmed."); |
| 413 | |
| 414 | if (from_tty) |
| 415 | { |
| 416 | printf ("Reading symbol data from %s...", name); |
| 417 | fflush (stdout); |
| 418 | } |
| 419 | |
| 420 | sf = symfile_init (sym_bfd); |
| 421 | realname = bfd_get_filename (sym_bfd); |
| 422 | realname = savestring (realname, strlen (realname)); |
| 423 | /* FIXME, this probably creates a storage leak... */ |
| 424 | |
| 425 | if (mainline) |
| 426 | { |
| 427 | /* Since no error yet, throw away the old symbol table. */ |
| 428 | |
| 429 | if (symfile) |
| 430 | free (symfile); |
| 431 | symfile = 0; |
| 432 | free_all_symtabs (); |
| 433 | free_all_psymtabs (); |
| 434 | |
| 435 | (*sf->sym_new_init) (); |
| 436 | |
| 437 | /* For mainline, caller didn't know the specified address of the |
| 438 | text section. We fix that here. */ |
| 439 | text_sect = bfd_get_section_by_name (sym_bfd, ".text"); |
| 440 | addr = bfd_section_vma (sym_bfd, text_sect); |
| 441 | } |
| 442 | |
| 443 | clear_complaints(); /* Allow complaints to appear for this new file. */ |
| 444 | |
| 445 | (*sf->sym_read) (sf, addr, mainline); |
| 446 | |
| 447 | /* Don't allow char * to have a typename (else would get caddr_t.) */ |
| 448 | /* Ditto void *. FIXME should do this for all the builtin types. */ |
| 449 | |
| 450 | TYPE_NAME (lookup_pointer_type (builtin_type_char)) = 0; |
| 451 | TYPE_NAME (lookup_pointer_type (builtin_type_void)) = 0; |
| 452 | |
| 453 | if (mainline) |
| 454 | { |
| 455 | /* OK, make it the "real" symbol file. */ |
| 456 | symfile = realname; |
| 457 | symfile_fns = sf; |
| 458 | } |
| 459 | |
| 460 | if (from_tty) |
| 461 | { |
| 462 | printf ("done.\n"); |
| 463 | fflush (stdout); |
| 464 | } |
| 465 | } |
| 466 | |
| 467 | /* This is the symbol-file command. Read the file, analyze its symbols, |
| 468 | and add a struct symtab to symtab_list. */ |
| 469 | |
| 470 | void |
| 471 | symbol_file_command (name, from_tty) |
| 472 | char *name; |
| 473 | int from_tty; |
| 474 | { |
| 475 | |
| 476 | dont_repeat (); |
| 477 | |
| 478 | if (name == 0) |
| 479 | { |
| 480 | if ((symtab_list || partial_symtab_list) |
| 481 | && from_tty |
| 482 | && !query ("Discard symbol table from `%s'? ", symfile)) |
| 483 | error ("Not confirmed."); |
| 484 | if (symfile) |
| 485 | free (symfile); |
| 486 | symfile = 0; |
| 487 | free_all_symtabs (); |
| 488 | free_all_psymtabs (); |
| 489 | /* FIXME, this does not account for the main file and subsequent |
| 490 | files (shared libs, dynloads, etc) having different formats. |
| 491 | It only calls the cleanup routine for the main file's format. */ |
| 492 | (*symfile_fns->sym_new_init) (); |
| 493 | free (symfile_fns); |
| 494 | symfile_fns = 0; |
| 495 | return; |
| 496 | } |
| 497 | |
| 498 | symbol_file_add (name, from_tty, (CORE_ADDR)0, 1); |
| 499 | } |
| 500 | |
| 501 | /* Open NAME and hand it off to BFD for preliminary analysis. Result |
| 502 | is a BFD *, which includes a new copy of NAME dynamically allocated |
| 503 | (which will be freed by the cleanup chain). In case of trouble, |
| 504 | error() is called. */ |
| 505 | |
| 506 | static bfd * |
| 507 | symfile_open (name) |
| 508 | char *name; |
| 509 | { |
| 510 | bfd *sym_bfd; |
| 511 | int desc; |
| 512 | char *absolute_name; |
| 513 | |
| 514 | name = tilde_expand (name); |
| 515 | make_cleanup (free, name); |
| 516 | |
| 517 | desc = openp (getenv ("PATH"), 1, name, O_RDONLY, 0, &absolute_name); |
| 518 | if (desc < 0) |
| 519 | perror_with_name (name); |
| 520 | else |
| 521 | { |
| 522 | make_cleanup (free, absolute_name); |
| 523 | name = absolute_name; |
| 524 | } |
| 525 | |
| 526 | sym_bfd = bfd_fdopenr (name, NULL, desc); |
| 527 | if (!sym_bfd) |
| 528 | { |
| 529 | close (desc); |
| 530 | error ("Could not open `%s' to read symbols: %s", |
| 531 | name, bfd_errmsg (bfd_error)); |
| 532 | } |
| 533 | make_cleanup (bfd_close, sym_bfd); |
| 534 | |
| 535 | if (!bfd_check_format (sym_bfd, bfd_object)) |
| 536 | error ("\"%s\": can't read symbols: %s.", |
| 537 | name, bfd_errmsg (bfd_error)); |
| 538 | |
| 539 | return sym_bfd; |
| 540 | } |
| 541 | |
| 542 | /* Link a new symtab_fns into the global symtab_fns list. |
| 543 | Called by various _initialize routines. */ |
| 544 | |
| 545 | void |
| 546 | add_symtab_fns (sf) |
| 547 | struct sym_fns *sf; |
| 548 | { |
| 549 | sf->next = symtab_fns; |
| 550 | symtab_fns = sf; |
| 551 | } |
| 552 | |
| 553 | |
| 554 | /* Initialize to read symbols from the symbol file sym_bfd. It either |
| 555 | returns or calls error(). The result is a malloc'd struct sym_fns |
| 556 | that contains cached information about the symbol file. */ |
| 557 | |
| 558 | static struct sym_fns * |
| 559 | symfile_init (sym_bfd) |
| 560 | bfd *sym_bfd; |
| 561 | { |
| 562 | struct sym_fns *sf, *sf2; |
| 563 | |
| 564 | for (sf = symtab_fns; sf != NULL; sf = sf->next) |
| 565 | { |
| 566 | if (!strncmp (bfd_get_target (sym_bfd), sf->sym_name, sf->sym_namelen)) |
| 567 | { |
| 568 | sf2 = (struct sym_fns *)xmalloc (sizeof (*sf2)); |
| 569 | /* FIXME, who frees this? */ |
| 570 | *sf2 = *sf; |
| 571 | sf2->sym_bfd = sym_bfd; |
| 572 | sf2->sym_private = 0; /* Not alloc'd yet */ |
| 573 | (*sf2->sym_init) (sf2); |
| 574 | return sf2; |
| 575 | } |
| 576 | } |
| 577 | error ("I'm sorry, Dave, I can't do that. Symbol format unknown."); |
| 578 | } |
| 579 | \f |
| 580 | /* This function runs the load command of our current target. */ |
| 581 | |
| 582 | void |
| 583 | load_command (arg, from_tty) |
| 584 | char *arg; |
| 585 | int from_tty; |
| 586 | { |
| 587 | target_load (arg, from_tty); |
| 588 | } |
| 589 | |
| 590 | /* This function runs the add_syms command of our current target. */ |
| 591 | |
| 592 | void |
| 593 | add_syms_command (args, from_tty) |
| 594 | char *args; |
| 595 | int from_tty; |
| 596 | { |
| 597 | target_add_syms (args, from_tty); |
| 598 | } |
| 599 | |
| 600 | /* This function allows the addition of incrementally linked object files. */ |
| 601 | |
| 602 | void |
| 603 | add_syms_addr_command (arg_string, from_tty) |
| 604 | char* arg_string; |
| 605 | int from_tty; |
| 606 | { |
| 607 | char *name; |
| 608 | CORE_ADDR text_addr; |
| 609 | |
| 610 | if (arg_string == 0) |
| 611 | error ("add-syms takes a file name and an address"); |
| 612 | |
| 613 | arg_string = tilde_expand (arg_string); |
| 614 | make_cleanup (free, arg_string); |
| 615 | |
| 616 | for( ; *arg_string == ' '; arg_string++ ); |
| 617 | name = arg_string; |
| 618 | for( ; *arg_string && *arg_string != ' ' ; arg_string++ ); |
| 619 | *arg_string++ = (char) 0; |
| 620 | |
| 621 | if (name[0] == 0) |
| 622 | error ("add-syms takes a file name and an address"); |
| 623 | |
| 624 | text_addr = parse_and_eval_address (arg_string); |
| 625 | |
| 626 | dont_repeat (); |
| 627 | |
| 628 | if (!query ("add symbol table from file \"%s\" at text_addr = 0x%x\n", |
| 629 | name, text_addr)) |
| 630 | error ("Not confirmed."); |
| 631 | |
| 632 | symbol_file_add (name, 0, text_addr, 0); |
| 633 | } |
| 634 | \f |
| 635 | /* Re-read symbols if the symbol-file has changed. */ |
| 636 | void |
| 637 | reread_symbols () |
| 638 | { |
| 639 | struct stat symstat; |
| 640 | |
| 641 | /* With the addition of shared libraries, this should be modified, |
| 642 | the load time should be saved in the partial symbol tables, since |
| 643 | different tables may come from different source files. FIXME. |
| 644 | This routine should then walk down each partial symbol table |
| 645 | and see if the symbol table that it originates from has been changed |
| 646 | */ |
| 647 | |
| 648 | if (stat (symfile, &symstat) < 0) |
| 649 | /* Can't read symbol-file. Assume it is up to date. */ |
| 650 | return; |
| 651 | |
| 652 | if (symstat.st_mtime > symfile_mtime) |
| 653 | { |
| 654 | printf_filtered ("Symbol file has changed; re-reading symbols.\n"); |
| 655 | symbol_file_command (symfile, 0); |
| 656 | breakpoint_re_set (); |
| 657 | } |
| 658 | } |
| 659 | |
| 660 | |
| 661 | /* This function is really horrible, but to avoid it, there would need |
| 662 | to be more filling in of forward references. */ |
| 663 | int |
| 664 | fill_in_vptr_fieldno (type) |
| 665 | struct type *type; |
| 666 | { |
| 667 | check_stub_type (type); |
| 668 | if (TYPE_VPTR_FIELDNO (type) < 0) |
| 669 | TYPE_VPTR_FIELDNO (type) = |
| 670 | fill_in_vptr_fieldno (TYPE_BASECLASS (type, 1)); |
| 671 | return TYPE_VPTR_FIELDNO (type); |
| 672 | } |
| 673 | \f |
| 674 | /* Functions to handle complaints during symbol reading. */ |
| 675 | |
| 676 | /* How many complaints about a particular thing should be printed before |
| 677 | we stop whining about it? */ |
| 678 | |
| 679 | static unsigned stop_whining = 1; |
| 680 | |
| 681 | /* Print a complaint about the input symbols, and link the complaint block |
| 682 | into a chain for later handling. Result is 1 if the complaint was |
| 683 | printed, 0 if it was suppressed. */ |
| 684 | |
| 685 | int |
| 686 | complain (complaint, val) |
| 687 | struct complaint *complaint; |
| 688 | char *val; |
| 689 | { |
| 690 | complaint->counter++; |
| 691 | if (complaint->next == 0) { |
| 692 | complaint->next = complaint_root->next; |
| 693 | complaint_root->next = complaint; |
| 694 | } |
| 695 | if (complaint->counter > stop_whining) |
| 696 | return 0; |
| 697 | wrap_here (""); |
| 698 | if (!info_verbose) { |
| 699 | puts_filtered ("During symbol reading..."); |
| 700 | } |
| 701 | printf_filtered (complaint->message, val); |
| 702 | puts_filtered ("..."); |
| 703 | wrap_here(""); |
| 704 | if (!info_verbose) |
| 705 | puts_filtered ("\n"); |
| 706 | return 1; |
| 707 | } |
| 708 | |
| 709 | /* Clear out all complaint counters that have ever been incremented. */ |
| 710 | |
| 711 | void |
| 712 | clear_complaints () |
| 713 | { |
| 714 | struct complaint *p; |
| 715 | |
| 716 | for (p = complaint_root->next; p != complaint_root; p = p->next) |
| 717 | p->counter = 0; |
| 718 | } |
| 719 | \f |
| 720 | void |
| 721 | _initialize_symfile () |
| 722 | { |
| 723 | |
| 724 | add_com ("symbol-file", class_files, symbol_file_command, |
| 725 | "Load symbol table from executable file FILE.\n\ |
| 726 | The `file' command can also load symbol tables, as well as setting the file\n\ |
| 727 | to execute."); |
| 728 | |
| 729 | add_com ("add-syms", class_files, add_syms_command, |
| 730 | "Load the symbols from FILE, assuming FILE has been dynamically loaded.\n\ |
| 731 | The second argument provides the starting address of the file's text."); |
| 732 | |
| 733 | add_com ("load", class_files, load_command, |
| 734 | "Dynamically load FILE into the running program, and record its symbols\n\ |
| 735 | for access from GDB."); |
| 736 | |
| 737 | add_show_from_set |
| 738 | (add_set_cmd ("complaints", class_support, var_uinteger, |
| 739 | (char *)&stop_whining, |
| 740 | "Set max number of complaints about incorrect symbols.", |
| 741 | &setlist), |
| 742 | &showlist); |
| 743 | |
| 744 | obstack_init (symbol_obstack); |
| 745 | obstack_init (psymbol_obstack); |
| 746 | } |