00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "bfd.h"
00031 #include "sysdep.h"
00032 #include "bfdlink.h"
00033 #include "libiberty.h"
00034
00035 #include "ld.h"
00036 #include "ldmain.h"
00037 #include "ldmisc.h"
00038 #include "ldexp.h"
00039 #include "ldlang.h"
00040
00041
00042
00043
00044 struct cref_ref {
00045
00046 struct cref_ref *next;
00047
00048 bfd *abfd;
00049
00050 unsigned int def : 1;
00051
00052 unsigned int common : 1;
00053
00054 unsigned int undef : 1;
00055 };
00056
00057
00058
00059 struct cref_hash_entry {
00060 struct bfd_hash_entry root;
00061
00062 char *demangled;
00063
00064 struct cref_ref *refs;
00065 };
00066
00067
00068
00069 struct cref_hash_table {
00070 struct bfd_hash_table root;
00071 };
00072
00073
00074
00075 static void output_one_cref (FILE *, struct cref_hash_entry *);
00076 static void check_local_sym_xref (lang_input_statement_type *);
00077 static bfd_boolean check_nocrossref (struct cref_hash_entry *, void *);
00078 static void check_refs (const char *, asection *, bfd *,
00079 struct lang_nocrossrefs *);
00080 static void check_reloc_refs (bfd *, asection *, void *);
00081
00082
00083
00084 #define cref_hash_lookup(table, string, create, copy) \
00085 ((struct cref_hash_entry *) \
00086 bfd_hash_lookup (&(table)->root, (string), (create), (copy)))
00087
00088
00089
00090 #define cref_hash_traverse(table, func, info) \
00091 (bfd_hash_traverse \
00092 (&(table)->root, \
00093 (bfd_boolean (*) (struct bfd_hash_entry *, void *)) (func), \
00094 (info)))
00095
00096
00097
00098 static struct cref_hash_table cref_table;
00099
00100
00101
00102 static bfd_boolean cref_initialized;
00103
00104
00105
00106 static size_t cref_symcount;
00107
00108
00109
00110 static struct bfd_hash_entry *
00111 cref_hash_newfunc (struct bfd_hash_entry *entry,
00112 struct bfd_hash_table *table,
00113 const char *string)
00114 {
00115 struct cref_hash_entry *ret = (struct cref_hash_entry *) entry;
00116
00117
00118
00119 if (ret == NULL)
00120 ret = ((struct cref_hash_entry *)
00121 bfd_hash_allocate (table, sizeof (struct cref_hash_entry)));
00122 if (ret == NULL)
00123 return NULL;
00124
00125
00126 ret = ((struct cref_hash_entry *)
00127 bfd_hash_newfunc ((struct bfd_hash_entry *) ret, table, string));
00128 if (ret != NULL)
00129 {
00130
00131 ret->demangled = NULL;
00132 ret->refs = NULL;
00133
00134
00135
00136 ++cref_symcount;
00137 }
00138
00139 return &ret->root;
00140 }
00141
00142
00143
00144
00145 void
00146 add_cref (const char *name,
00147 bfd *abfd,
00148 asection *section,
00149 bfd_vma value ATTRIBUTE_UNUSED)
00150 {
00151 struct cref_hash_entry *h;
00152 struct cref_ref *r;
00153
00154 if (! cref_initialized)
00155 {
00156 if (! bfd_hash_table_init (&cref_table.root, cref_hash_newfunc))
00157 einfo (_("%X%P: bfd_hash_table_init of cref table failed: %E\n"));
00158 cref_initialized = TRUE;
00159 }
00160
00161 h = cref_hash_lookup (&cref_table, name, TRUE, FALSE);
00162 if (h == NULL)
00163 einfo (_("%X%P: cref_hash_lookup failed: %E\n"));
00164
00165 for (r = h->refs; r != NULL; r = r->next)
00166 if (r->abfd == abfd)
00167 break;
00168
00169 if (r == NULL)
00170 {
00171 r = xmalloc (sizeof *r);
00172 r->next = h->refs;
00173 h->refs = r;
00174 r->abfd = abfd;
00175 r->def = FALSE;
00176 r->common = FALSE;
00177 r->undef = FALSE;
00178 }
00179
00180 if (bfd_is_und_section (section))
00181 r->undef = TRUE;
00182 else if (bfd_is_com_section (section))
00183 r->common = TRUE;
00184 else
00185 r->def = TRUE;
00186 }
00187
00188
00189
00190
00191
00192 static bfd_boolean
00193 cref_fill_array (struct cref_hash_entry *h, void *data)
00194 {
00195 struct cref_hash_entry ***pph = data;
00196
00197 ASSERT (h->demangled == NULL);
00198 h->demangled = demangle (h->root.string);
00199
00200 **pph = h;
00201
00202 ++*pph;
00203
00204 return TRUE;
00205 }
00206
00207
00208
00209 static int
00210 cref_sort_array (const void *a1, const void *a2)
00211 {
00212 const struct cref_hash_entry * const *p1 = a1;
00213 const struct cref_hash_entry * const *p2 = a2;
00214
00215 return strcmp ((*p1)->demangled, (*p2)->demangled);
00216 }
00217
00218
00219
00220 #define FILECOL (50)
00221
00222 void
00223 output_cref (FILE *fp)
00224 {
00225 int len;
00226 struct cref_hash_entry **csyms, **csym_fill, **csym, **csym_end;
00227 const char *msg;
00228
00229 fprintf (fp, _("\nCross Reference Table\n\n"));
00230 msg = _("Symbol");
00231 fprintf (fp, "%s", msg);
00232 len = strlen (msg);
00233 while (len < FILECOL)
00234 {
00235 putc (' ', fp);
00236 ++len;
00237 }
00238 fprintf (fp, _("File\n"));
00239
00240 if (! cref_initialized)
00241 {
00242 fprintf (fp, _("No symbols\n"));
00243 return;
00244 }
00245
00246 csyms = xmalloc (cref_symcount * sizeof (*csyms));
00247
00248 csym_fill = csyms;
00249 cref_hash_traverse (&cref_table, cref_fill_array, &csym_fill);
00250 ASSERT ((size_t) (csym_fill - csyms) == cref_symcount);
00251
00252 qsort (csyms, cref_symcount, sizeof (*csyms), cref_sort_array);
00253
00254 csym_end = csyms + cref_symcount;
00255 for (csym = csyms; csym < csym_end; csym++)
00256 output_one_cref (fp, *csym);
00257 }
00258
00259
00260
00261 static void
00262 output_one_cref (FILE *fp, struct cref_hash_entry *h)
00263 {
00264 int len;
00265 struct bfd_link_hash_entry *hl;
00266 struct cref_ref *r;
00267
00268 hl = bfd_link_hash_lookup (link_info.hash, h->root.string, FALSE,
00269 FALSE, TRUE);
00270 if (hl == NULL)
00271 einfo ("%P: symbol `%T' missing from main hash table\n",
00272 h->root.string);
00273 else
00274 {
00275
00276
00277 if (hl->type == bfd_link_hash_defined)
00278 {
00279 if (hl->u.def.section->output_section == NULL)
00280 return;
00281 if (hl->u.def.section->owner != NULL
00282 && (hl->u.def.section->owner->flags & DYNAMIC) != 0)
00283 {
00284 for (r = h->refs; r != NULL; r = r->next)
00285 if ((r->abfd->flags & DYNAMIC) == 0)
00286 break;
00287 if (r == NULL)
00288 return;
00289 }
00290 }
00291 }
00292
00293 fprintf (fp, "%s ", h->demangled);
00294 len = strlen (h->demangled) + 1;
00295
00296 for (r = h->refs; r != NULL; r = r->next)
00297 {
00298 if (r->def)
00299 {
00300 while (len < FILECOL)
00301 {
00302 putc (' ', fp);
00303 ++len;
00304 }
00305 lfinfo (fp, "%B\n", r->abfd);
00306 len = 0;
00307 }
00308 }
00309
00310 for (r = h->refs; r != NULL; r = r->next)
00311 {
00312 if (! r->def)
00313 {
00314 while (len < FILECOL)
00315 {
00316 putc (' ', fp);
00317 ++len;
00318 }
00319 lfinfo (fp, "%B\n", r->abfd);
00320 len = 0;
00321 }
00322 }
00323
00324 ASSERT (len == 0);
00325 }
00326
00327
00328
00329 void
00330 check_nocrossrefs (void)
00331 {
00332 if (! cref_initialized)
00333 return;
00334
00335 cref_hash_traverse (&cref_table, check_nocrossref, NULL);
00336
00337 lang_for_each_file (check_local_sym_xref);
00338 }
00339
00340
00341
00342 static void
00343 check_local_sym_xref (lang_input_statement_type *statement)
00344 {
00345 bfd *abfd;
00346 lang_input_statement_type *li;
00347 asymbol **asymbols, **syms;
00348
00349 abfd = statement->the_bfd;
00350 if (abfd == NULL)
00351 return;
00352
00353 li = abfd->usrdata;
00354 if (li != NULL && li->asymbols != NULL)
00355 asymbols = li->asymbols;
00356 else
00357 {
00358 long symsize;
00359 long symbol_count;
00360
00361 symsize = bfd_get_symtab_upper_bound (abfd);
00362 if (symsize < 0)
00363 einfo (_("%B%F: could not read symbols; %E\n"), abfd);
00364 asymbols = xmalloc (symsize);
00365 symbol_count = bfd_canonicalize_symtab (abfd, asymbols);
00366 if (symbol_count < 0)
00367 einfo (_("%B%F: could not read symbols: %E\n"), abfd);
00368 if (li != NULL)
00369 {
00370 li->asymbols = asymbols;
00371 li->symbol_count = symbol_count;
00372 }
00373 }
00374
00375 for (syms = asymbols; *syms; ++syms)
00376 {
00377 asymbol *sym = *syms;
00378 if (sym->flags & (BSF_GLOBAL | BSF_WARNING | BSF_INDIRECT | BSF_FILE))
00379 continue;
00380 if ((sym->flags & (BSF_LOCAL | BSF_SECTION_SYM)) != 0
00381 && sym->section->output_section != NULL)
00382 {
00383 const char *outsecname, *symname;
00384 struct lang_nocrossrefs *ncrs;
00385 struct lang_nocrossref *ncr;
00386
00387 outsecname = sym->section->output_section->name;
00388 symname = NULL;
00389 if ((sym->flags & BSF_SECTION_SYM) == 0)
00390 symname = sym->name;
00391 for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next)
00392 for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next)
00393 if (strcmp (ncr->name, outsecname) == 0)
00394 check_refs (symname, sym->section, abfd, ncrs);
00395 }
00396 }
00397
00398 if (li == NULL)
00399 free (asymbols);
00400 }
00401
00402
00403
00404 static bfd_boolean
00405 check_nocrossref (struct cref_hash_entry *h, void *ignore ATTRIBUTE_UNUSED)
00406 {
00407 struct bfd_link_hash_entry *hl;
00408 asection *defsec;
00409 const char *defsecname;
00410 struct lang_nocrossrefs *ncrs;
00411 struct lang_nocrossref *ncr;
00412 struct cref_ref *ref;
00413
00414 hl = bfd_link_hash_lookup (link_info.hash, h->root.string, FALSE,
00415 FALSE, TRUE);
00416 if (hl == NULL)
00417 {
00418 einfo (_("%P: symbol `%T' missing from main hash table\n"),
00419 h->root.string);
00420 return TRUE;
00421 }
00422
00423 if (hl->type != bfd_link_hash_defined
00424 && hl->type != bfd_link_hash_defweak)
00425 return TRUE;
00426
00427 defsec = hl->u.def.section->output_section;
00428 if (defsec == NULL)
00429 return TRUE;
00430 defsecname = bfd_get_section_name (defsec->owner, defsec);
00431
00432 for (ncrs = nocrossref_list; ncrs != NULL; ncrs = ncrs->next)
00433 for (ncr = ncrs->list; ncr != NULL; ncr = ncr->next)
00434 if (strcmp (ncr->name, defsecname) == 0)
00435 for (ref = h->refs; ref != NULL; ref = ref->next)
00436 check_refs (hl->root.string, hl->u.def.section, ref->abfd, ncrs);
00437
00438 return TRUE;
00439 }
00440
00441
00442
00443
00444 struct check_refs_info {
00445 const char *sym_name;
00446 asection *defsec;
00447 struct lang_nocrossrefs *ncrs;
00448 asymbol **asymbols;
00449 };
00450
00451
00452
00453
00454
00455
00456 static void
00457 check_refs (const char *name,
00458 asection *sec,
00459 bfd *abfd,
00460 struct lang_nocrossrefs *ncrs)
00461 {
00462 lang_input_statement_type *li;
00463 asymbol **asymbols;
00464 struct check_refs_info info;
00465
00466
00467
00468
00469
00470
00471
00472 li = abfd->usrdata;
00473 if (li != NULL && li->asymbols != NULL)
00474 asymbols = li->asymbols;
00475 else
00476 {
00477 long symsize;
00478 long symbol_count;
00479
00480 symsize = bfd_get_symtab_upper_bound (abfd);
00481 if (symsize < 0)
00482 einfo (_("%B%F: could not read symbols; %E\n"), abfd);
00483 asymbols = xmalloc (symsize);
00484 symbol_count = bfd_canonicalize_symtab (abfd, asymbols);
00485 if (symbol_count < 0)
00486 einfo (_("%B%F: could not read symbols: %E\n"), abfd);
00487 if (li != NULL)
00488 {
00489 li->asymbols = asymbols;
00490 li->symbol_count = symbol_count;
00491 }
00492 }
00493
00494 info.sym_name = name;
00495 info.defsec = sec;
00496 info.ncrs = ncrs;
00497 info.asymbols = asymbols;
00498 bfd_map_over_sections (abfd, check_reloc_refs, &info);
00499
00500 if (li == NULL)
00501 free (asymbols);
00502 }
00503
00504
00505
00506
00507
00508
00509
00510 static void
00511 check_reloc_refs (bfd *abfd, asection *sec, void *iarg)
00512 {
00513 struct check_refs_info *info = iarg;
00514 asection *outsec;
00515 const char *outsecname;
00516 asection *outdefsec;
00517 const char *outdefsecname;
00518 struct lang_nocrossref *ncr;
00519 const char *symname;
00520 long relsize;
00521 arelent **relpp;
00522 long relcount;
00523 arelent **p, **pend;
00524
00525 outsec = sec->output_section;
00526 outsecname = bfd_get_section_name (outsec->owner, outsec);
00527
00528 outdefsec = info->defsec->output_section;
00529 outdefsecname = bfd_get_section_name (outdefsec->owner, outdefsec);
00530
00531
00532 if (strcmp (outsecname, outdefsecname) == 0)
00533 return;
00534
00535 for (ncr = info->ncrs->list; ncr != NULL; ncr = ncr->next)
00536 if (strcmp (outsecname, ncr->name) == 0)
00537 break;
00538
00539 if (ncr == NULL)
00540 return;
00541
00542
00543
00544
00545
00546
00547 symname = info->sym_name;
00548
00549 relsize = bfd_get_reloc_upper_bound (abfd, sec);
00550 if (relsize < 0)
00551 einfo (_("%B%F: could not read relocs: %E\n"), abfd);
00552 if (relsize == 0)
00553 return;
00554
00555 relpp = xmalloc (relsize);
00556 relcount = bfd_canonicalize_reloc (abfd, sec, relpp, info->asymbols);
00557 if (relcount < 0)
00558 einfo (_("%B%F: could not read relocs: %E\n"), abfd);
00559
00560 p = relpp;
00561 pend = p + relcount;
00562 for (; p < pend && *p != NULL; p++)
00563 {
00564 arelent *q = *p;
00565
00566 if (q->sym_ptr_ptr != NULL
00567 && *q->sym_ptr_ptr != NULL
00568 && (symname != NULL
00569 ? strcmp (bfd_asymbol_name (*q->sym_ptr_ptr), symname) == 0
00570 : (((*q->sym_ptr_ptr)->flags & BSF_SECTION_SYM) != 0
00571 && bfd_get_section (*q->sym_ptr_ptr) == info->defsec)))
00572 {
00573
00574
00575
00576
00577 einfo (_("%X%C: prohibited cross reference from %s to `%T' in %s\n"),
00578 abfd, sec, q->address, outsecname,
00579 bfd_asymbol_name (*q->sym_ptr_ptr), outdefsecname);
00580 }
00581 }
00582
00583 free (relpp);
00584 }