]>
Commit | Line | Data |
---|---|---|
c611e285 | 1 | /* ldmisc.c |
5bcb7f28 | 2 | Copyright (C) 1991, 92, 93, 94 Free Software Foundation, Inc. |
c611e285 SC |
3 | |
4 | Written by Steve Chamberlain of Cygnus Support. | |
2fa0b342 DHW |
5 | |
6 | This file is part of GLD, the Gnu Linker. | |
7 | ||
8 | GLD is free software; you can redistribute it and/or modify | |
9 | it under the terms of the GNU General Public License as published by | |
c611e285 | 10 | the Free Software Foundation; either version 2, or (at your option) |
2fa0b342 DHW |
11 | any later version. |
12 | ||
13 | GLD is distributed in the hope that it will be useful, | |
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | GNU General Public License for more details. | |
17 | ||
18 | You should have received a copy of the GNU General Public License | |
19 | along with GLD; see the file COPYING. If not, write to | |
7d6439d9 | 20 | the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ |
2fa0b342 | 21 | |
c611e285 | 22 | #include "bfd.h" |
2fa0b342 | 23 | #include "sysdep.h" |
fe2b6209 | 24 | #include <demangle.h> |
23cb3b65 ILT |
25 | |
26 | #ifdef ANSI_PROTOTYPES | |
27 | #include <stdarg.h> | |
28 | #define USE_STDARG 1 | |
7d6439d9 ILT |
29 | #else |
30 | #include <varargs.h> | |
23cb3b65 | 31 | #define USE_STDARG 0 |
7d6439d9 | 32 | #endif |
2fa0b342 DHW |
33 | |
34 | #include "ld.h" | |
35 | #include "ldmisc.h" | |
fcf276c4 | 36 | #include "ldexp.h" |
2fa0b342 | 37 | #include "ldlang.h" |
8bff41c1 | 38 | #include "ldgram.h" |
1418c83b | 39 | #include "ldlex.h" |
fcf276c4 ILT |
40 | #include "ldmain.h" |
41 | #include "ldfile.h" | |
2fa0b342 | 42 | |
7d6439d9 | 43 | |
23cb3b65 ILT |
44 | #if USE_STDARG |
45 | static void finfo PARAMS ((FILE *, const char *, ...)); | |
46 | #else | |
9b0da7f4 KR |
47 | /* VARARGS*/ |
48 | static void finfo (); | |
23cb3b65 | 49 | #endif |
288897f4 DM |
50 | static const char *demangle PARAMS ((const char *string, |
51 | int remove_underscore)); | |
9b0da7f4 | 52 | |
2fa0b342 | 53 | /* |
fcf276c4 | 54 | %% literal % |
2fa0b342 | 55 | %F error is fatal |
fcf276c4 | 56 | %P print program name |
2fa0b342 DHW |
57 | %S print script file and linenumber |
58 | %E current bfd error or errno | |
59 | %I filename from a lang_input_statement_type | |
60 | %B filename from a bfd | |
288897f4 | 61 | %T symbol name |
2fa0b342 DHW |
62 | %X no object output, fail return |
63 | %V hex bfd_vma | |
9b0da7f4 | 64 | %v hex bfd_vma, no leading zeros |
cc23cc69 ILT |
65 | %C clever filename:linenumber with function |
66 | %D like %C, but no function name | |
c611e285 | 67 | %R info about a relent |
fcf276c4 ILT |
68 | %s arbitrary string, like printf |
69 | %d integer, like printf | |
7d6439d9 | 70 | %u integer, like printf |
2fa0b342 | 71 | */ |
9b0da7f4 | 72 | |
288897f4 DM |
73 | static const char * |
74 | demangle (string, remove_underscore) | |
75 | const char *string; | |
76 | int remove_underscore; | |
9b0da7f4 | 77 | { |
288897f4 | 78 | const char *res; |
23cb3b65 ILT |
79 | |
80 | if (remove_underscore | |
81 | && output_bfd != NULL | |
82 | && bfd_get_symbol_leading_char (output_bfd) == string[0]) | |
83 | ++string; | |
84 | ||
85 | /* This is a hack for better error reporting on XCOFF. */ | |
86 | if (remove_underscore && string[0] == '.') | |
87 | ++string; | |
88 | ||
89 | /* Note that there's a memory leak here, we keep buying memory for | |
90 | demangled names, and never free. But if you have so many errors | |
91 | that you run out of VM with the error messages, then there's | |
92 | something up. */ | |
93 | res = cplus_demangle (string, DMGL_ANSI | DMGL_PARAMS); | |
9b0da7f4 KR |
94 | return res ? res : string; |
95 | } | |
96 | ||
c611e285 | 97 | static void |
23cb3b65 | 98 | vfinfo (fp, fmt, arg) |
c611e285 | 99 | FILE *fp; |
23cb3b65 | 100 | const char *fmt; |
c611e285 | 101 | va_list arg; |
2fa0b342 | 102 | { |
2fa0b342 | 103 | boolean fatal = false; |
2a28d8b0 | 104 | |
9d1fe8a4 SC |
105 | while (*fmt) |
106 | { | |
107 | while (*fmt != '%' && *fmt != '\0') | |
108 | { | |
c611e285 | 109 | putc(*fmt, fp); |
2fa0b342 DHW |
110 | fmt++; |
111 | } | |
2a28d8b0 | 112 | |
9d1fe8a4 SC |
113 | if (*fmt == '%') |
114 | { | |
2fa0b342 | 115 | fmt ++; |
9d1fe8a4 SC |
116 | switch (*fmt++) |
117 | { | |
fcf276c4 ILT |
118 | default: |
119 | fprintf(fp,"%%%c", fmt[-1]); | |
120 | break; | |
121 | ||
122 | case '%': | |
123 | /* literal % */ | |
124 | putc('%', fp); | |
125 | break; | |
126 | ||
6bf2e3a7 | 127 | case 'X': |
fcf276c4 | 128 | /* no object output, fail return */ |
2fa0b342 DHW |
129 | config.make_executable = false; |
130 | break; | |
2a28d8b0 | 131 | |
6bf2e3a7 | 132 | case 'V': |
fcf276c4 | 133 | /* hex bfd_vma */ |
2a28d8b0 DM |
134 | { |
135 | bfd_vma value = va_arg(arg, bfd_vma); | |
136 | fprintf_vma(fp, value); | |
137 | } | |
2fa0b342 | 138 | break; |
2a28d8b0 | 139 | |
9b0da7f4 | 140 | case 'v': |
fcf276c4 | 141 | /* hex bfd_vma, no leading zeros */ |
9b0da7f4 KR |
142 | { |
143 | char buf[100]; | |
144 | char *p = buf; | |
145 | bfd_vma value = va_arg (arg, bfd_vma); | |
146 | sprintf_vma (p, value); | |
147 | while (*p == '0') | |
148 | p++; | |
149 | if (!*p) | |
150 | p--; | |
151 | fputs (p, fp); | |
152 | } | |
153 | break; | |
2a28d8b0 | 154 | |
6bf2e3a7 | 155 | case 'T': |
288897f4 DM |
156 | /* Symbol name. */ |
157 | { | |
158 | const char *name = va_arg (arg, const char *); | |
159 | ||
160 | if (name != (const char *) NULL) | |
161 | fprintf (fp, "%s", demangle (name, 1)); | |
162 | else | |
163 | fprintf (fp, "no symbol"); | |
164 | } | |
2fa0b342 | 165 | break; |
2a28d8b0 | 166 | |
6bf2e3a7 | 167 | case 'B': |
fcf276c4 | 168 | /* filename from a bfd */ |
6bf2e3a7 SC |
169 | { |
170 | bfd *abfd = va_arg(arg, bfd *); | |
171 | if (abfd->my_archive) { | |
172 | fprintf(fp,"%s(%s)", abfd->my_archive->filename, | |
173 | abfd->filename); | |
174 | } | |
175 | else { | |
176 | fprintf(fp,"%s", abfd->filename); | |
6bf2e3a7 SC |
177 | } |
178 | } | |
2fa0b342 | 179 | break; |
2a28d8b0 | 180 | |
6bf2e3a7 | 181 | case 'F': |
fcf276c4 | 182 | /* error is fatal */ |
2fa0b342 DHW |
183 | fatal = true; |
184 | break; | |
2a28d8b0 | 185 | |
6bf2e3a7 | 186 | case 'P': |
fcf276c4 | 187 | /* print program name */ |
c611e285 | 188 | fprintf(fp,"%s", program_name); |
2fa0b342 | 189 | break; |
2a28d8b0 | 190 | |
6bf2e3a7 | 191 | case 'E': |
fcf276c4 | 192 | /* current bfd error or errno */ |
5bcb7f28 | 193 | fprintf(fp, bfd_errmsg(bfd_get_error ())); |
2fa0b342 | 194 | break; |
2a28d8b0 | 195 | |
6bf2e3a7 | 196 | case 'I': |
fcf276c4 | 197 | /* filename from a lang_input_statement_type */ |
6bf2e3a7 SC |
198 | { |
199 | lang_input_statement_type *i = | |
200 | va_arg(arg,lang_input_statement_type *); | |
288897f4 DM |
201 | |
202 | if (i->the_bfd->my_archive) | |
203 | fprintf(fp, "(%s)", i->the_bfd->my_archive->filename); | |
6bf2e3a7 SC |
204 | fprintf(fp,"%s", i->local_sym_name); |
205 | } | |
2fa0b342 | 206 | break; |
2a28d8b0 | 207 | |
6bf2e3a7 | 208 | case 'S': |
fcf276c4 | 209 | /* print script file and linenumber */ |
7d6439d9 ILT |
210 | if (parsing_defsym) |
211 | fprintf (fp, "--defsym %s", lex_string); | |
212 | else if (ldfile_input_filename != NULL) | |
213 | fprintf (fp, "%s:%u", ldfile_input_filename, lineno); | |
214 | else | |
215 | fprintf (fp, "built in linker script:%u", lineno); | |
2fa0b342 | 216 | break; |
c611e285 | 217 | |
6bf2e3a7 | 218 | case 'R': |
c611e285 | 219 | /* Print all that's interesting about a relent */ |
6bf2e3a7 SC |
220 | { |
221 | arelent *relent = va_arg(arg, arelent *); | |
c611e285 | 222 | |
9b0da7f4 KR |
223 | finfo (fp, "%s+0x%v (type %s)", |
224 | (*(relent->sym_ptr_ptr))->name, | |
225 | relent->addend, | |
226 | relent->howto->name); | |
6bf2e3a7 | 227 | } |
c611e285 SC |
228 | break; |
229 | ||
6bf2e3a7 | 230 | case 'C': |
cc23cc69 | 231 | case 'D': |
fcf276c4 | 232 | /* Clever filename:linenumber with function name if possible, |
288897f4 DM |
233 | or section name as a last resort. The arguments are a BFD, |
234 | a section, and an offset. */ | |
235 | { | |
7d6439d9 | 236 | static bfd *last_bfd; |
31c27164 ILT |
237 | static char *last_file = NULL; |
238 | static char *last_function = NULL; | |
288897f4 DM |
239 | bfd *abfd; |
240 | asection *section; | |
241 | bfd_vma offset; | |
242 | lang_input_statement_type *entry; | |
243 | asymbol **asymbols; | |
244 | const char *filename; | |
245 | const char *functionname; | |
246 | unsigned int linenumber; | |
31c27164 | 247 | boolean discard_last; |
288897f4 DM |
248 | |
249 | abfd = va_arg (arg, bfd *); | |
250 | section = va_arg (arg, asection *); | |
251 | offset = va_arg (arg, bfd_vma); | |
252 | ||
253 | entry = (lang_input_statement_type *) abfd->usrdata; | |
254 | if (entry != (lang_input_statement_type *) NULL | |
255 | && entry->asymbols != (asymbol **) NULL) | |
256 | asymbols = entry->asymbols; | |
257 | else | |
258 | { | |
8bff41c1 ILT |
259 | long symsize; |
260 | long symbol_count; | |
288897f4 | 261 | |
8bff41c1 ILT |
262 | symsize = bfd_get_symtab_upper_bound (abfd); |
263 | if (symsize < 0) | |
7d6439d9 | 264 | einfo ("%B%F: could not read symbols\n", abfd); |
5bcb7f28 | 265 | asymbols = (asymbol **) xmalloc (symsize); |
288897f4 | 266 | symbol_count = bfd_canonicalize_symtab (abfd, asymbols); |
8bff41c1 | 267 | if (symbol_count < 0) |
7d6439d9 | 268 | einfo ("%B%F: could not read symbols\n", abfd); |
288897f4 DM |
269 | if (entry != (lang_input_statement_type *) NULL) |
270 | { | |
271 | entry->asymbols = asymbols; | |
272 | entry->symbol_count = symbol_count; | |
273 | } | |
274 | } | |
275 | ||
31c27164 | 276 | discard_last = true; |
288897f4 DM |
277 | if (bfd_find_nearest_line (abfd, section, asymbols, offset, |
278 | &filename, &functionname, &linenumber)) | |
279 | { | |
cc23cc69 ILT |
280 | if (functionname != NULL && fmt[-1] == 'C') |
281 | { | |
7d6439d9 ILT |
282 | if (filename == (char *) NULL) |
283 | filename = abfd->filename; | |
284 | ||
285 | if (last_bfd == NULL | |
286 | || last_file == NULL | |
31c27164 | 287 | || last_function == NULL |
7d6439d9 | 288 | || last_bfd != abfd |
31c27164 ILT |
289 | || strcmp (last_file, filename) != 0 |
290 | || strcmp (last_function, functionname) != 0) | |
291 | { | |
7d6439d9 ILT |
292 | /* We use abfd->filename in this initial line, |
293 | in case filename is a .h file or something | |
294 | similarly unhelpful. */ | |
295 | finfo (fp, "%B: In function `%s':\n", | |
296 | abfd, demangle (functionname, 1)); | |
297 | ||
298 | last_bfd = abfd; | |
31c27164 ILT |
299 | if (last_file != NULL) |
300 | free (last_file); | |
301 | last_file = buystring (filename); | |
302 | if (last_function != NULL) | |
303 | free (last_function); | |
304 | last_function = buystring (functionname); | |
305 | } | |
306 | discard_last = false; | |
7d6439d9 ILT |
307 | if (linenumber != 0) |
308 | fprintf (fp, "%s:%u", filename, linenumber); | |
309 | else | |
310 | finfo (fp, "%s(%s+0x%v)", filename, section->name, offset); | |
311 | } | |
312 | else if (filename == NULL | |
313 | || strcmp (filename, abfd->filename) == 0) | |
314 | { | |
315 | finfo (fp, "%B(%s+0x%v)", abfd, section->name, offset); | |
316 | if (linenumber != 0) | |
317 | finfo (fp, "%u", linenumber); | |
cc23cc69 | 318 | } |
288897f4 | 319 | else if (linenumber != 0) |
7d6439d9 | 320 | finfo (fp, "%B:%s:%u", abfd, filename, linenumber); |
288897f4 | 321 | else |
7d6439d9 ILT |
322 | finfo (fp, "%B(%s+0x%v):%s", abfd, section->name, offset, |
323 | filename); | |
288897f4 DM |
324 | } |
325 | else | |
7d6439d9 | 326 | finfo (fp, "%B(%s+0x%v)", abfd, section->name, offset); |
31c27164 ILT |
327 | |
328 | if (discard_last) | |
329 | { | |
7d6439d9 | 330 | last_bfd = NULL; |
31c27164 ILT |
331 | if (last_file != NULL) |
332 | { | |
333 | free (last_file); | |
334 | last_file = NULL; | |
335 | } | |
336 | if (last_function != NULL) | |
337 | { | |
338 | free (last_function); | |
339 | last_function = NULL; | |
340 | } | |
341 | } | |
288897f4 | 342 | } |
2fa0b342 DHW |
343 | break; |
344 | ||
6bf2e3a7 | 345 | case 's': |
fcf276c4 | 346 | /* arbitrary string, like printf */ |
c611e285 | 347 | fprintf(fp,"%s", va_arg(arg, char *)); |
2fa0b342 | 348 | break; |
2a28d8b0 | 349 | |
6bf2e3a7 | 350 | case 'd': |
fcf276c4 | 351 | /* integer, like printf */ |
c611e285 | 352 | fprintf(fp,"%d", va_arg(arg, int)); |
2fa0b342 | 353 | break; |
7d6439d9 ILT |
354 | |
355 | case 'u': | |
356 | /* unsigned integer, like printf */ | |
357 | fprintf(fp,"%u", va_arg(arg, unsigned int)); | |
358 | break; | |
2fa0b342 DHW |
359 | } |
360 | } | |
361 | } | |
2a28d8b0 | 362 | |
6bf2e3a7 | 363 | if (fatal == true) |
5bcb7f28 | 364 | xexit(1); |
c611e285 SC |
365 | } |
366 | ||
367 | /* Format info message and print on stdout. */ | |
368 | ||
23cb3b65 ILT |
369 | /* (You would think this should be called just "info", but then you |
370 | would hosed by LynxOS, which defines that name in its libc.) */ | |
fcf276c4 | 371 | |
23cb3b65 ILT |
372 | void |
373 | #if USE_STDARG | |
374 | info_msg (const char *fmt, ...) | |
375 | #else | |
376 | info_msg (va_alist) | |
288897f4 | 377 | va_dcl |
23cb3b65 | 378 | #endif |
c611e285 | 379 | { |
c611e285 | 380 | va_list arg; |
23cb3b65 ILT |
381 | |
382 | #if ! USE_STDARG | |
383 | const char *fmt; | |
384 | ||
385 | va_start (arg); | |
386 | fmt = va_arg (arg, const char *); | |
387 | #else | |
388 | va_start (arg, fmt); | |
389 | #endif | |
390 | ||
391 | vfinfo (stdout, fmt, arg); | |
392 | va_end (arg); | |
2fa0b342 DHW |
393 | } |
394 | ||
c611e285 SC |
395 | /* ('e' for error.) Format info message and print on stderr. */ |
396 | ||
23cb3b65 ILT |
397 | void |
398 | #if USE_STDARG | |
399 | einfo (const char *fmt, ...) | |
400 | #else | |
401 | einfo (va_alist) | |
288897f4 | 402 | va_dcl |
23cb3b65 | 403 | #endif |
c611e285 | 404 | { |
c611e285 | 405 | va_list arg; |
23cb3b65 ILT |
406 | |
407 | #if ! USE_STDARG | |
408 | const char *fmt; | |
409 | ||
410 | va_start (arg); | |
411 | fmt = va_arg (arg, const char *); | |
412 | #else | |
413 | va_start (arg, fmt); | |
414 | #endif | |
415 | ||
416 | vfinfo (stderr, fmt, arg); | |
417 | va_end (arg); | |
c611e285 | 418 | } |
2fa0b342 DHW |
419 | |
420 | void | |
23cb3b65 ILT |
421 | info_assert (file, line) |
422 | const char *file; | |
2a28d8b0 | 423 | unsigned int line; |
2fa0b342 | 424 | { |
23cb3b65 | 425 | einfo ("%F%P: internal error %s %d\n", file, line); |
2fa0b342 DHW |
426 | } |
427 | ||
9b0da7f4 KR |
428 | char * |
429 | buystring (x) | |
430 | CONST char *CONST x; | |
2fa0b342 | 431 | { |
9b0da7f4 | 432 | size_t l = strlen(x)+1; |
5bcb7f28 | 433 | char *r = xmalloc(l); |
2fa0b342 DHW |
434 | memcpy(r, x,l); |
435 | return r; | |
436 | } | |
c611e285 | 437 | |
9d1fe8a4 SC |
438 | /* ('m' for map) Format info message and print on map. */ |
439 | ||
23cb3b65 ILT |
440 | void |
441 | #if USE_STDARG | |
442 | minfo (const char *fmt, ...) | |
443 | #else | |
444 | minfo (va_alist) | |
288897f4 | 445 | va_dcl |
23cb3b65 | 446 | #endif |
9d1fe8a4 | 447 | { |
9d1fe8a4 | 448 | va_list arg; |
9d1fe8a4 | 449 | |
23cb3b65 ILT |
450 | #if ! USE_STDARG |
451 | const char *fmt; | |
452 | va_start (arg); | |
453 | fmt = va_arg (arg, const char *); | |
454 | #else | |
455 | va_start (arg, fmt); | |
456 | #endif | |
457 | ||
458 | vfinfo (config.map_file, fmt, arg); | |
459 | va_end (arg); | |
460 | } | |
9d1fe8a4 | 461 | |
9b0da7f4 | 462 | static void |
23cb3b65 ILT |
463 | #if USE_STDARG |
464 | finfo (FILE *file, const char *fmt, ...) | |
465 | #else | |
9b0da7f4 KR |
466 | finfo (va_alist) |
467 | va_dcl | |
23cb3b65 | 468 | #endif |
9b0da7f4 | 469 | { |
9b0da7f4 | 470 | va_list arg; |
23cb3b65 ILT |
471 | |
472 | #if ! USE_STDARG | |
473 | FILE *file; | |
474 | const char *fmt; | |
475 | ||
9b0da7f4 KR |
476 | va_start (arg); |
477 | file = va_arg (arg, FILE *); | |
23cb3b65 ILT |
478 | fmt = va_arg (arg, const char *); |
479 | #else | |
480 | va_start (arg, fmt); | |
481 | #endif | |
482 | ||
9b0da7f4 KR |
483 | vfinfo (file, fmt, arg); |
484 | va_end (arg); | |
485 | } | |
23cb3b65 ILT |
486 | \f |
487 | /* Functions to print the link map. */ | |
c611e285 SC |
488 | |
489 | void | |
9b0da7f4 | 490 | print_space () |
c611e285 | 491 | { |
23cb3b65 | 492 | fprintf (config.map_file, " "); |
c611e285 | 493 | } |
23cb3b65 | 494 | |
c611e285 | 495 | void |
9b0da7f4 | 496 | print_nl () |
c611e285 | 497 | { |
23cb3b65 | 498 | fprintf (config.map_file, "\n"); |
c611e285 | 499 | } |
23cb3b65 | 500 | |
c611e285 | 501 | void |
9b0da7f4 KR |
502 | print_address (value) |
503 | bfd_vma value; | |
c611e285 | 504 | { |
23cb3b65 | 505 | fprintf_vma (config.map_file, value); |
c611e285 | 506 | } |