* $Id: warnings.c,v 1.5 1994/01/12 23:14:07 jkh Exp $
* Print the filename of ENTRY on OUTFILE (a stdio stream),
prline_file_name (entry
, outfile
)
struct file_entry
*entry
;
print_file_name (entry
, outfile
);
* Print the filename of ENTRY on OUTFILE (a stdio stream).
print_file_name (entry
, outfile
)
struct file_entry
*entry
;
fprintf (outfile
, "NULL");
print_file_name (entry
->superfile
, outfile
);
fprintf (outfile
, "(%s)", entry
->filename
);
fprintf (outfile
, "%s", entry
->filename
);
* Return the filename of entry as a string (malloc'd for the purpose)
struct file_entry
*entry
;
return (char *)strdup("NULL");
supfile
= get_file_name (entry
->superfile
);
result
= (char *) xmalloc (strlen(supfile
)
+ strlen(entry
->filename
) + 3);
sprintf (result
, "%s(%s)", supfile
, entry
->filename
);
result
= (char *) xmalloc (strlen (entry
->filename
) + 1);
strcpy (result
, entry
->filename
);
* Report a fatal error. The error message is STRING followed by the
fatal_with_file (char *fmt
, struct file_entry
*entry
, ...)
fatal_with_file (fmt
, entry
, va_alist
)
struct file_entry
*entry
;
(void)fprintf(stderr
, "%s: ", progname
);
(void)vfprintf(stderr
, fmt
, ap
);
print_file_name (entry
, stderr
);
(void)fprintf(stderr
, "\n");
* Report a fatal error using the message for the last failed system call,
* followed by the string NAME.
s
= concat ("", sys_errlist
[errno
], " for %s");
* Report a fatal error using the message for the last failed system call,
* followed by the name of file ENTRY.
struct file_entry
*entry
;
s
= concat ("", sys_errlist
[errno
], " for ");
fatal_with_file (s
, entry
);
/* Print a complete or partial map of the output file. */
static void describe_file_sections
__P((struct file_entry
*, FILE *));
static void list_file_locals
__P((struct file_entry
*, FILE *));
fprintf(outfile
, "\nFiles:\n\n");
each_file(describe_file_sections
, outfile
);
fprintf(outfile
, "\nGlobal symbols:\n\n");
if (sp
->defined
== (N_UNDF
|N_EXT
))
fprintf(outfile
, " %s: common, length %#x\n",
sp
->name
, sp
->common_size
);
if (!(sp
->flags
& GS_REFERENCED
))
fprintf(outfile
, " %s: unreferenced\n", sp
->name
);
fprintf(outfile
, " %s: sodefined\n", sp
->name
);
fprintf(outfile
, " %s: undefined\n", sp
->name
);
fprintf(outfile
, " %s: %#x, size %#x\n",
sp
->name
, sp
->value
, sp
->size
);
each_file(list_file_locals
, outfile
);
describe_file_sections(entry
, outfile
)
struct file_entry
*entry
;
print_file_name(entry
, outfile
);
if (entry
->flags
& (E_JUST_SYMS
| E_DYNAMIC
))
fprintf(outfile
, " symbols only\n", 0);
fprintf(outfile
, " text %x(%x), data %x(%x), bss %x(%x) hex\n",
entry
->text_start_address
, entry
->header
.a_text
,
entry
->data_start_address
, entry
->header
.a_data
,
entry
->bss_start_address
, entry
->header
.a_bss
);
list_file_locals (entry
, outfile
)
struct file_entry
*entry
;
struct localsymbol
*lsp
, *lspend
;
entry
->strings
= (char *) alloca (entry
->string_size
);
read_entry_strings (file_open (entry
), entry
);
fprintf (outfile
, "\nLocal symbols of ");
print_file_name (entry
, outfile
);
fprintf (outfile
, ":\n\n");
lspend
= entry
->symbols
+ entry
->nsymbols
;
for (lsp
= entry
->symbols
; lsp
< lspend
; lsp
++) {
register struct nlist
*p
= &lsp
->nzlist
.nlist
;
* If this is a definition,
* update it if necessary by this file's start address.
if (!(p
->n_type
& (N_STAB
| N_EXT
)))
fprintf(outfile
, " %s: 0x%x\n",
entry
->strings
+ p
->n_un
.n_strx
, p
->n_value
);
entry
->strings
= 0; /* All done with them. */
/* Static vars for do_warnings and subroutines of it */
static int list_unresolved_refs
; /* List unresolved refs */
static int list_warning_symbols
; /* List warning syms */
static int list_multiple_defs
; /* List multiple definitions */
static struct line_debug_entry
*init_debug_scan
__P((int, struct file_entry
*));
static int next_debug_entry
__P((int, struct line_debug_entry
*));
* Structure for communication between do_file_warnings and it's
* helper routines. Will in practice be an array of three of these:
* 0) Current line, 1) Next line, 2) Source file info.
* Helper routines for do_file_warnings.
/* Return an integer less than, equal to, or greater than 0 as per the
relation between the two relocation entries. Used by qsort. */
relocation_entries_relation (rel1
, rel2
)
struct relocation_info
*rel1
, *rel2
;
return RELOC_ADDRESS(rel1
) - RELOC_ADDRESS(rel2
);
/* Moves to the next debugging symbol in the file. USE_DATA_SYMBOLS
determines the type of the debugging symbol to look for (DSLINE or
SLINE). STATE_POINTER keeps track of the old and new locatiosn in
the file. It assumes that state_pointer[1] is valid; ie
that it.sym points into some entry in the symbol table. If
state_pointer[1].sym == 0, this routine should not be called. */
next_debug_entry (use_data_symbols
, state_pointer
)
register int use_data_symbols
;
/* Next must be passed by reference! */
struct line_debug_entry state_pointer
[3];
register struct line_debug_entry
*current
= state_pointer
,
*next
= state_pointer
+ 1,
/* Used to store source file */
*source
= state_pointer
+ 2;
struct file_entry
*entry
= (struct file_entry
*) source
->sym
;
struct localsymbol
*endp
= entry
->symbols
+ entry
->nsymbols
;
current
->sym
= next
->sym
;
current
->line
= next
->line
;
current
->filename
= next
->filename
;
while (++(next
->sym
) < endp
) {
struct nlist
*np
= &next
->sym
->nzlist
.nlist
;
* n_type is a char, and N_SOL, N_EINCL and N_BINCL are > 0x80,
* so may look negative...therefore, must mask to low bits
switch (np
->n_type
& 0xff) {
if (use_data_symbols
) continue;
if (!use_data_symbols
) continue;
next
->filename
= source
->filename
;
source
->filename
= np
->n_un
.n_strx
+ entry
->strings
;
next
->filename
= np
->n_un
.n_strx
+ entry
->strings
;
next
->sym
= (struct localsymbol
*)0;
* Create a structure to save the state of a scan through the debug symbols.
* USE_DATA_SYMBOLS is set if we should be scanning for DSLINE's instead of
* SLINE's. entry is the file entry which points at the symbols to use.
static struct line_debug_entry
*
init_debug_scan(use_data_symbols
, entry
)
struct file_entry
*entry
;
struct line_debug_entry
*state_pointer
= (struct line_debug_entry
*)
xmalloc(3 * sizeof(struct line_debug_entry
));
register struct line_debug_entry
*current
= state_pointer
,
*next
= state_pointer
+ 1,
*source
= state_pointer
+ 2; /* Used to store source file */
for (lsp
= entry
->symbols
; lsp
< entry
->symbols
+entry
->nsymbols
; lsp
++)
if (lsp
->nzlist
.nlist
.n_type
== N_SO
)
if (lsp
>= entry
->symbols
+ entry
->nsymbols
) {
/* I believe this translates to "We lose" */
current
->filename
= next
->filename
= entry
->filename
;
current
->line
= next
->line
= -1;
current
->sym
= next
->sym
= (struct localsymbol
*) 0;
next
->line
= source
->line
= 0;
next
->filename
= source
->filename
= (lsp
->nzlist
.nlist
.n_un
.n_strx
+ entry
->strings
);
source
->sym
= (struct localsymbol
*) entry
;
next_debug_entry(use_data_symbols
, state_pointer
);
if (!next
->sym
) { /* No line numbers for this section; */
/* setup output results as appropriate */
current
->filename
= source
->filename
= entry
->filename
;
current
->line
= -1; /* Don't print lineno */
current
->filename
= source
->filename
;
next_debug_entry(use_data_symbols
, state_pointer
);
* Takes an ADDRESS (in either text or data space) and a STATE_POINTER which
* describes the current location in the implied scan through the debug
* symbols within the file which ADDRESS is within, and returns the source
* line number which corresponds to ADDRESS.
address_to_line(address
, state_pointer
)
/* Next must be passed by reference! */
struct line_debug_entry state_pointer
[3];
*current
= state_pointer
, *next
= state_pointer
+ 1;
struct line_debug_entry
*tmp_pointer
;
(next
->sym
->nzlist
.nlist
.n_type
& N_TYPE
) == N_DATA
;
/* Go back to the beginning if we've already passed it. */
if (current
->sym
->nzlist
.nlist
.n_value
> address
) {
tmp_pointer
= init_debug_scan(use_data_symbols
,
((state_pointer
+ 2)->sym
));
state_pointer
[0] = tmp_pointer
[0];
state_pointer
[1] = tmp_pointer
[1];
state_pointer
[2] = tmp_pointer
[2];
/* If we're still in a bad way, return -1, meaning invalid line. */
if (current
->sym
->nzlist
.nlist
.n_value
> address
)
&& next
->sym
->nzlist
.nlist
.n_value
<= address
&& next_debug_entry(use_data_symbols
, state_pointer
));
/* Macros for manipulating bitvectors. */
#define BIT_SET_P(bv, index) ((bv)[(index) >> 3] & 1 << ((index) & 0x7))
#define SET_BIT(bv, index) ((bv)[(index) >> 3] |= 1 << ((index) & 0x7))
* This routine will scan through the relocation data of file ENTRY, printing
* out references to undefined symbols and references to symbols defined in
* files with N_WARNING symbols. If DATA_SEGMENT is non-zero, it will scan
* the data relocation segment (and use N_DSLINE symbols to track line
* number); otherwise it will scan the text relocation segment. Warnings
* will be printed on the output stream OUTFILE. Eventually, every nlist
* symbol mapped through will be marked in the NLIST_BITVECTOR, so we don't
* repeat ourselves when we scan the nlists themselves.
do_relocation_warnings(entry
, data_segment
, outfile
, nlist_bitvector
)
struct file_entry
*entry
;
unsigned char *nlist_bitvector
;
struct relocation_info
*reloc
, *reloc_start
=
data_segment
? entry
->datarel
: entry
->textrel
;
int reloc_size
= (data_segment
? entry
->ndatarel
: entry
->ntextrel
);
int start_of_segment
= (data_segment
?
entry
->data_start_address
:
entry
->text_start_address
);
struct localsymbol
*start_of_syms
= entry
->symbols
;
struct line_debug_entry
*state_pointer
=
init_debug_scan(data_segment
!= 0, entry
);
register struct line_debug_entry
*current
= state_pointer
;
/* Assigned to generally static values; should not be written into. */
* Assigned to alloca'd values cand copied into; should be freed when
int invalidate_line_number
;
* We need to sort the relocation info here. Sheesh, so much effort
* for one lousy error optimization.
qsort(reloc_start
, reloc_size
, sizeof(struct relocation_info
),
relocation_entries_relation
);
for (reloc
= reloc_start
;
reloc
< (reloc_start
+ reloc_size
);
register struct localsymbol
*s
;
* If the relocation isn't resolved through a symbol,
if (!RELOC_EXTERN_P(reloc
))
s
= &entry
->symbols
[RELOC_SYMBOL(reloc
)];
* Local symbols shouldn't ever be used by relocation info,
* so the next should be safe. This is, of course, wrong.
* References to local BSS symbols can be the targets of
* relocation info, and they can (must) be resolved through
* symbols. However, these must be defined properly, (the
* assembler would have caught it otherwise), so we can
if (!(s
->nzlist
.nz_type
& N_EXT
))
if (!g
->defined
&& !g
->so_defined
&& list_unresolved_refs
) { /* Reference */
/* Mark as being noted by relocation warning pass. */
SET_BIT(nlist_bitvector
, s
- start_of_syms
);
if (g
->undef_refs
>= MAX_UREFS_PRINTED
) /* Listed too many */
/* Undefined symbol which we should mention */
if (++(g
->undef_refs
) == MAX_UREFS_PRINTED
) {
errfmt
= "More undefined symbol %s refs follow";
invalidate_line_number
= 1;
errfmt
= "Undefined symbol %s referenced from %s segment";
invalidate_line_number
= 0;
/* Potential symbol warning here */
/* Mark as being noted by relocation warning pass. */
SET_BIT(nlist_bitvector
, s
- start_of_syms
);
invalidate_line_number
= 0;
/* If errfmt == 0, errmsg has already been defined. */
errmsg
= (char *) xmalloc(strlen(errfmt
) + strlen(nm
) + 1);
sprintf(errmsg
, errfmt
, nm
, data_segment
? "data" : "text");
address_to_line(RELOC_ADDRESS(reloc
) + start_of_segment
,
fprintf(outfile
, "%s:%d: %s\n", current
->filename
,
invalidate_line_number
? 0 : current
->line
, errmsg
);
fprintf(outfile
, "%s: %s\n", current
->filename
, errmsg
);
* Print on OUTFILE a list of all warnings generated by references and/or
* definitions in the file ENTRY. List source file and line number if
* possible, just the .o file if not.
do_file_warnings (entry
, outfile
)
struct file_entry
*entry
;
int number_of_syms
= entry
->nsymbols
;
unsigned char *nlist_bitvector
= (unsigned char *)
alloca ((number_of_syms
>> 3) + 1);
struct line_debug_entry
*text_scan
, *data_scan
;
char *errfmt
, *file_name
;
int dont_allow_symbol_name
;
bzero (nlist_bitvector
, (number_of_syms
>> 3) + 1);
/* Read in the files strings if they aren't available */
entry
->strings
= (char *) alloca (entry
->string_size
);
desc
= file_open (entry
);
read_entry_strings (desc
, entry
);
if (!(entry
->flags
& E_DYNAMIC
)) {
/* Do text warnings based on a scan through the relocation info. */
do_relocation_warnings (entry
, 0, outfile
, nlist_bitvector
);
/* Do data warnings based on a scan through the relocation info. */
do_relocation_warnings (entry
, 1, outfile
, nlist_bitvector
);
/* Scan through all of the nlist entries in this file and pick up
anything that the scan through the relocation stuff didn't. */
text_scan
= init_debug_scan (0, entry
);
data_scan
= init_debug_scan (1, entry
);
for (i
= 0; i
< number_of_syms
; i
++) {
g
= entry
->symbols
[i
].symbol
;
s
= &entry
->symbols
[i
].nzlist
.nlist
;
if (!(s
->n_type
& N_EXT
))
if (!(g
->flags
& GS_REFERENCED
)) {
/* Check for undefined shobj symbols */
for (lsp
= g
->sorefs
; lsp
; lsp
= lsp
->next
) {
type
= lsp
->nzlist
.nz_type
;
type
!= (N_UNDF
| N_EXT
)) {
if (type
== (N_UNDF
| N_EXT
)) {
"Undefined symbol %s referenced from %s\n",
dont_allow_symbol_name
= 0;
if (list_multiple_defs
&& g
->mult_defs
) {
errfmt
= "Definition of symbol %s (multiply defined)";
line_number
= address_to_line (s
->n_value
, text_scan
);
file_name
= text_scan
[0].filename
;
line_number
= address_to_line (s
->n_value
, data_scan
);
file_name
= data_scan
[0].filename
;
errfmt
= "First set element definition of symbol %s (multiply defined)";
printf("multiply defined: %s, type %#x\n", g
->name
, s
->n_type
);
/* Don't print out multiple defs at references.*/
} else if (BIT_SET_P (nlist_bitvector
, i
)) {
} else if (list_unresolved_refs
&& !g
->defined
&& !g
->so_defined
) {
if (g
->undef_refs
>= MAX_UREFS_PRINTED
)
if (++(g
->undef_refs
) == MAX_UREFS_PRINTED
)
errfmt
= "More undefined \"%s\" refs follow";
errfmt
= "Undefined symbol \"%s\" referenced";
* There are two cases in which we don't want to do
* this. The first is if this is a definition instead
* do a reference. The second is if it's the reference
* used by the warning stabs itself.
if (s
->n_type
!= (N_EXT
| N_UNDF
)
|| (i
&& (s
-1)->n_type
== N_WARNING
))
dont_allow_symbol_name
= 1;
fprintf (outfile
, "%s: ", entry
->filename
);
fprintf (outfile
, "%s:%d: ", file_name
, line_number
);
if (dont_allow_symbol_name
)
fprintf (outfile
, "%s", errfmt
);
fprintf (outfile
, errfmt
, g
->name
);
entry
->strings
= 0; /* Since it will dissapear anyway. */
list_unresolved_refs
= !relocatable_output
&&
(undefined_global_sym_count
|| undefined_shobj_sym_count
);
list_warning_symbols
= warning_count
;
list_multiple_defs
= multiple_def_count
!= 0;
if (!(list_unresolved_refs
||
list_warning_symbols
|| list_multiple_defs
))
/* No need to run this routine */
if (entry_symbol
&& !entry_symbol
->defined
)
fprintf (outfile
, "Undefined entry symbol %s\n",
each_file (do_file_warnings
, outfile
);
if (list_unresolved_refs
|| list_multiple_defs
)