X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;ds=sidebyside;f=gas%2Fdwarf2dbg.c;h=3336453a4eeffabbd37fec150f362751c474d4b2;hb=351e2b5aa7a71258e6b682ac1a3228964de8d22c;hp=13f487e9771153f98514173f8fc09fc408fbcb49;hpb=b8f080d6a81ad57342633e068ee3752b65d9c08c;p=deliverable%2Fbinutils-gdb.git diff --git a/gas/dwarf2dbg.c b/gas/dwarf2dbg.c index 13f487e977..3336453a4e 100644 --- a/gas/dwarf2dbg.c +++ b/gas/dwarf2dbg.c @@ -1,5 +1,5 @@ /* dwarf2dbg.c - DWARF2 debug support - Copyright (C) 1999, 2000 Free Software Foundation, Inc. + Copyright 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. Contributed by David Mosberger-Tang This file is part of GAS, the GNU Assembler. @@ -41,9 +41,19 @@ #endif #endif +#include "dwarf2dbg.h" +#include + +#ifndef DWARF2_FORMAT +# define DWARF2_FORMAT() dwarf2_format_32bit +#endif + +#ifndef DWARF2_ADDR_SIZE +# define DWARF2_ADDR_SIZE(bfd) (bfd_arch_bits_per_address (bfd) / 8) +#endif + #ifdef BFD_ASSEMBLER -#include "dwarf2dbg.h" #include "subsegs.h" #include "elf/dwarf2.h" @@ -122,7 +132,7 @@ struct line_seg { static struct line_seg *all_segs; struct file_entry { - char *filename; + const char *filename; unsigned int dir; }; @@ -131,56 +141,67 @@ static struct file_entry *files; static unsigned int files_in_use; static unsigned int files_allocated; -/* Correlate file numbers as given by the user in .file/.loc directives - with the file numbers used in the output debug info. */ -static unsigned int *user_filenum; -static unsigned int user_filenum_allocated; +/* Table of directories used by .debug_line. */ +static char **dirs; +static unsigned int dirs_in_use; +static unsigned int dirs_allocated; -/* True when we've seen a .loc directive recently. Used to avoid +/* TRUE when we've seen a .loc directive recently. Used to avoid doing work when there's nothing to do. */ -static boolean loc_directive_seen; +static bfd_boolean loc_directive_seen; /* Current location as indicated by the most recent .loc directive. */ static struct dwarf2_line_info current; -/* Fake label name. */ -static char const fake_label_name[] = ".L0\001"; - /* The size of an address on the target. */ static unsigned int sizeof_address; -static struct line_subseg *get_line_subseg PARAMS ((segT, subsegT)); -static unsigned int get_filenum PARAMS ((const char *)); -static struct frag *first_frag_for_seg PARAMS ((segT)); -static struct frag *last_frag_for_seg PARAMS ((segT)); -static void out_byte PARAMS ((int)); -static void out_opcode PARAMS ((int)); -static void out_two PARAMS ((int)); -static void out_four PARAMS ((int)); -static void out_abbrev PARAMS ((int, int)); -static void out_uleb128 PARAMS ((addressT)); -static symbolS *symbol_new_now PARAMS ((void)); -static void set_symbol_value_now PARAMS ((symbolS *)); -static offsetT get_frag_fix PARAMS ((fragS *)); -static void out_set_addr PARAMS ((segT, fragS *, addressT)); -static int size_inc_line_addr PARAMS ((int, addressT)); -static void emit_inc_line_addr PARAMS ((int, addressT, char *, int)); -static void out_inc_line_addr PARAMS ((int, addressT)); -static void relax_inc_line_addr PARAMS ((int, segT, fragS *, addressT, - fragS *, addressT)); -static void process_entries PARAMS ((segT, struct line_entry *)); -static void out_file_list PARAMS ((void)); -static void out_debug_line PARAMS ((segT)); -static void out_debug_aranges PARAMS ((segT, segT)); -static void out_debug_abbrev PARAMS ((segT)); -static void out_debug_info PARAMS ((segT, segT, segT)); +static struct line_subseg *get_line_subseg (segT, subsegT); +static unsigned int get_filenum (const char *, unsigned int); +static struct frag *first_frag_for_seg (segT); +static struct frag *last_frag_for_seg (segT); +static void out_byte (int); +static void out_opcode (int); +static void out_two (int); +static void out_four (int); +static void out_abbrev (int, int); +static void out_uleb128 (addressT); +static offsetT get_frag_fix (fragS *); +static void out_set_addr (segT, fragS *, addressT); +static int size_inc_line_addr (int, addressT); +static void emit_inc_line_addr (int, addressT, char *, int); +static void out_inc_line_addr (int, addressT); +static void relax_inc_line_addr (int, segT, fragS *, addressT, + fragS *, addressT); +static void process_entries (segT, struct line_entry *); +static void out_file_list (void); +static void out_debug_line (segT); +static void out_debug_aranges (segT, segT); +static void out_debug_abbrev (segT); +static void out_debug_info (segT, segT, segT); +#ifndef TC_DWARF2_EMIT_OFFSET +# define TC_DWARF2_EMIT_OFFSET generic_dwarf2_emit_offset +static void generic_dwarf2_emit_offset (symbolS *, unsigned int); + +/* Create an offset to .dwarf2_*. */ + +static void +generic_dwarf2_emit_offset (symbolS *symbol, unsigned int size) +{ + expressionS expr; + + expr.X_op = O_symbol; + expr.X_add_symbol = symbol; + expr.X_add_number = 0; + emit_expr (&expr, size); +} +#endif + /* Find or create an entry for SEG+SUBSEG in ALL_SEGS. */ static struct line_subseg * -get_line_subseg (seg, subseg) - segT seg; - subsegT subseg; +get_line_subseg (segT seg, subsegT subseg) { static segT last_seg; static subsegT last_subseg; @@ -226,20 +247,31 @@ get_line_subseg (seg, subseg) return ss; } -/* Record an entry for LOC ocurring at OFS within the current fragment. */ +/* Record an entry for LOC occurring at OFS within the current fragment. */ void -dwarf2_gen_line_info (ofs, loc) - addressT ofs; - struct dwarf2_line_info *loc; +dwarf2_gen_line_info (addressT ofs, struct dwarf2_line_info *loc) { struct line_subseg *ss; struct line_entry *e; + static unsigned int line = -1; + static unsigned int filenum = -1; /* Early out for as-yet incomplete location information. */ if (loc->filenum == 0 || loc->line == 0) return; + /* Don't emit sequences of line symbols for the same line when the + symbols apply to assembler code. It is necessary to emit + duplicate line symbols when a compiler asks for them, because GDB + uses them to determine the end of the prologue. */ + if (debug_type == DEBUG_DWARF2 + && line == loc->line && filenum == loc->filenum) + return; + + line = loc->line; + filenum = loc->filenum; + e = (struct line_entry *) xmalloc (sizeof (*e)); e->next = NULL; e->frag = frag_now; @@ -252,14 +284,13 @@ dwarf2_gen_line_info (ofs, loc) } void -dwarf2_where (line) - struct dwarf2_line_info *line; +dwarf2_where (struct dwarf2_line_info *line) { if (debug_type == DEBUG_DWARF2) { char *filename; as_where (&filename, &line->line); - line->filenum = get_filenum (filename); + line->filenum = get_filenum (filename, 0); line->column = 0; line->flags = DWARF2_FLAG_BEGIN_STMT; } @@ -273,59 +304,140 @@ dwarf2_where (line) for, emit a line statement appropriately. */ void -dwarf2_emit_insn (size) - int size; +dwarf2_emit_insn (int size) { struct dwarf2_line_info loc; - if (debug_type != DEBUG_DWARF2 && ! loc_directive_seen) + if (loc_directive_seen) + { + /* Use the last location established by a .loc directive, not + the value returned by dwarf2_where(). That calls as_where() + which will return either the logical input file name (foo.c) + or the physical input file name (foo.s) and not the file name + specified in the most recent .loc directive (eg foo.h). */ + loc = current; + + /* Unless we generate DWARF2 debugging information for each + assembler line, we only emit one line symbol for one LOC. */ + if (debug_type != DEBUG_DWARF2) + loc_directive_seen = FALSE; + } + else if (debug_type != DEBUG_DWARF2) return; - loc_directive_seen = false; + else + dwarf2_where (& loc); - dwarf2_where (&loc); dwarf2_gen_line_info (frag_now_fix () - size, &loc); } -/* Get a .debug_line file number for FILENAME. */ +/* Get a .debug_line file number for FILENAME. If NUM is nonzero, + allocate it on that file table slot, otherwise return the first + empty one. */ static unsigned int -get_filenum (filename) - const char *filename; +get_filenum (const char *filename, unsigned int num) { - static unsigned int last_used; - unsigned int i; + static unsigned int last_used, last_used_dir_len; + const char *file; + size_t dir_len; + unsigned int i, dir; - if (last_used) - if (strcmp (filename, files[last_used].filename) == 0) - return last_used; + if (num == 0 && last_used) + { + if (! files[last_used].dir + && strcmp (filename, files[last_used].filename) == 0) + return last_used; + if (files[last_used].dir + && strncmp (filename, dirs[files[last_used].dir], + last_used_dir_len) == 0 + && IS_DIR_SEPARATOR (filename [last_used_dir_len]) + && strcmp (filename + last_used_dir_len + 1, + files[last_used].filename) == 0) + return last_used; + } - for (i = 1; i < files_in_use; ++i) - if (strcmp (filename, files[i].filename) == 0) - return i; + file = lbasename (filename); + /* Don't make empty string from / or A: from A:/ . */ +#ifdef HAVE_DOS_BASED_FILE_SYSTEM + if (file <= filename + 3) + file = filename; +#else + if (file == filename + 1) + file = filename; +#endif + dir_len = file - filename; + + dir = 0; + if (dir_len) + { + --dir_len; + for (dir = 1; dir < dirs_in_use; ++dir) + if (strncmp (filename, dirs[dir], dir_len) == 0 + && dirs[dir][dir_len] == '\0') + break; + + if (dir >= dirs_in_use) + { + if (dir >= dirs_allocated) + { + dirs_allocated = dir + 32; + dirs = (char **) + xrealloc (dirs, (dir + 32) * sizeof (const char *)); + } + + dirs[dir] = xmalloc (dir_len + 1); + memcpy (dirs[dir], filename, dir_len); + dirs[dir][dir_len] = '\0'; + dirs_in_use = dir + 1; + } + } + + if (num == 0) + { + for (i = 1; i < files_in_use; ++i) + if (files[i].dir == dir + && files[i].filename + && strcmp (file, files[i].filename) == 0) + { + last_used = i; + last_used_dir_len = dir_len; + return i; + } + } + else + i = num; if (i >= files_allocated) { + unsigned int old = files_allocated; + files_allocated = i + 32; files = (struct file_entry *) xrealloc (files, (i + 32) * sizeof (struct file_entry)); + + memset (files + old, 0, (i + 32 - old) * sizeof (struct file_entry)); } - files[i].filename = xstrdup (filename); - files[i].dir = 0; + files[i].filename = num ? file : xstrdup (file); + files[i].dir = dir; files_in_use = i + 1; last_used = i; + last_used_dir_len = dir_len; return i; } -/* Handle the .file directive. */ +/* Handle two forms of .file directive: + - Pass .file "source.c" to s_app_file + - Handle .file 1 "source.c" by adding an entry to the DWARF-2 file table -void -dwarf2_directive_file (dummy) - int dummy ATTRIBUTE_UNUSED; + If an entry is added to the file table, return a pointer to the filename. */ + +char * +dwarf2_directive_file (int dummy ATTRIBUTE_UNUSED) { offsetT num; - const char *filename; + char *filename; int filename_len; /* Continue to accept a bare string and pass it off. */ @@ -333,37 +445,32 @@ dwarf2_directive_file (dummy) if (*input_line_pointer == '"') { s_app_file (0); - return; + return NULL; } num = get_absolute_expression (); filename = demand_copy_C_string (&filename_len); demand_empty_rest_of_line (); - if (num < 0) + if (num < 1) { - as_bad (_("File number less than zero")); - return; + as_bad (_("file number less than one")); + return NULL; } - if (num >= (int) user_filenum_allocated) + if (num < (int) files_in_use && files[num].filename != 0) { - unsigned int old = user_filenum_allocated; - - user_filenum_allocated = num + 16; - user_filenum = (unsigned int *) - xrealloc (user_filenum, (num + 16) * sizeof (unsigned int)); - - /* Zero the new memory. */ - memset (user_filenum + old, 0, (num + 16 - old) * sizeof (unsigned int)); + as_bad (_("file number %ld already allocated"), (long) num); + return NULL; } - user_filenum[num] = get_filenum (filename); + get_filenum (filename, num); + + return filename; } void -dwarf2_directive_loc (dummy) - int dummy ATTRIBUTE_UNUSED; +dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED) { offsetT filenum, line, column; @@ -374,34 +481,48 @@ dwarf2_directive_loc (dummy) column = get_absolute_expression (); demand_empty_rest_of_line (); - if (filenum < 0) + if (filenum < 1) { - as_bad (_("File number less than zero")); + as_bad (_("file number less than one")); return; } - if (filenum >= (int) user_filenum_allocated - || user_filenum[filenum] == 0) + if (filenum >= (int) files_in_use || files[filenum].filename == 0) { - as_bad (_("Unassigned file number %ld"), (long) filenum); + as_bad (_("unassigned file number %ld"), (long) filenum); return; } - current.filenum = user_filenum[filenum]; + current.filenum = filenum; current.line = line; current.column = column; current.flags = DWARF2_FLAG_BEGIN_STMT; - loc_directive_seen = true; + loc_directive_seen = TRUE; #ifndef NO_LISTING if (listing) - listing_source_line (line); + { + if (files[filenum].dir) + { + size_t dir_len = strlen (dirs[files[filenum].dir]); + size_t file_len = strlen (files[filenum].filename); + char *cp = (char *) alloca (dir_len + 1 + file_len + 1); + + memcpy (cp, dirs[files[filenum].dir], dir_len); + cp[dir_len] = '/'; + memcpy (cp + dir_len + 1, files[filenum].filename, file_len); + cp[dir_len + file_len + 1] = '\0'; + listing_source_file (cp); + } + else + listing_source_file (files[filenum].filename); + listing_source_line (line); + } #endif } static struct frag * -first_frag_for_seg (seg) - segT seg; +first_frag_for_seg (segT seg) { frchainS *f, *first = NULL; @@ -414,8 +535,7 @@ first_frag_for_seg (seg) } static struct frag * -last_frag_for_seg (seg) - segT seg; +last_frag_for_seg (segT seg) { frchainS *f, *last = NULL; @@ -430,8 +550,7 @@ last_frag_for_seg (seg) /* Emit a single byte into the current segment. */ static inline void -out_byte (byte) - int byte; +out_byte (int byte) { FRAG_APPEND_1_CHAR (byte); } @@ -439,8 +558,7 @@ out_byte (byte) /* Emit a statement program opcode into the current segment. */ static inline void -out_opcode (opc) - int opc; +out_opcode (int opc) { out_byte (opc); } @@ -448,8 +566,7 @@ out_opcode (opc) /* Emit a two-byte word into the current segment. */ static inline void -out_two (data) - int data; +out_two (int data) { md_number_to_chars (frag_more (2), data, 2); } @@ -457,8 +574,7 @@ out_two (data) /* Emit a four byte word into the current segment. */ static inline void -out_four (data) - int data; +out_four (int data) { md_number_to_chars (frag_more (4), data, 4); } @@ -466,8 +582,7 @@ out_four (data) /* Emit an unsigned "little-endian base 128" number. */ static void -out_uleb128 (value) - addressT value; +out_uleb128 (addressT value) { output_leb128 (frag_more (sizeof_leb128 (value, 0)), value, 0); } @@ -475,37 +590,16 @@ out_uleb128 (value) /* Emit a tuple for .debug_abbrev. */ static inline void -out_abbrev (name, form) - int name, form; +out_abbrev (int name, int form) { out_uleb128 (name); out_uleb128 (form); } -/* Create a new fake symbol whose value is the current position. */ - -static symbolS * -symbol_new_now () -{ - return symbol_new (fake_label_name, now_seg, frag_now_fix (), frag_now); -} - -/* Set the value of SYM to the current position in the current segment. */ - -static void -set_symbol_value_now (sym) - symbolS *sym; -{ - S_SET_SEGMENT (sym, now_seg); - S_SET_VALUE (sym, frag_now_fix ()); - symbol_set_frag (sym, frag_now); -} - /* Get the size of a fragment. */ static offsetT -get_frag_fix (frag) - fragS *frag; +get_frag_fix (fragS *frag) { frchainS *fr; @@ -517,10 +611,7 @@ get_frag_fix (frag) on some subsegment chain. */ for (fr = frchain_root; fr; fr = fr->frch_next) if (fr->frch_last == frag) - { - return ((char *) obstack_next_free (&fr->frch_obstack) - - frag->fr_literal); - } + return (char *) obstack_next_free (&fr->frch_obstack) - frag->fr_literal; abort (); } @@ -528,15 +619,12 @@ get_frag_fix (frag) /* Set an absolute address (may result in a relocation entry). */ static void -out_set_addr (seg, frag, ofs) - segT seg; - fragS *frag; - addressT ofs; +out_set_addr (segT seg, fragS *frag, addressT ofs) { expressionS expr; symbolS *sym; - sym = symbol_new (fake_label_name, seg, ofs, frag); + sym = symbol_temp_new (seg, ofs, frag); out_opcode (DW_LNS_extended_op); out_uleb128 (sizeof_address + 1); @@ -548,6 +636,25 @@ out_set_addr (seg, frag, ofs) emit_expr (&expr, sizeof_address); } +#if DWARF2_LINE_MIN_INSN_LENGTH > 1 +static void scale_addr_delta (addressT *); + +static void +scale_addr_delta (addressT *addr_delta) +{ + static int printed_this = 0; + if (*addr_delta % DWARF2_LINE_MIN_INSN_LENGTH != 0) + { + if (!printed_this) + as_bad("unaligned opcodes detected in executable segment"); + printed_this = 1; + } + *addr_delta /= DWARF2_LINE_MIN_INSN_LENGTH; +} +#else +#define scale_addr_delta(A) +#endif + /* Encode a pair of line and address skips as efficiently as possible. Note that the line skip is signed, whereas the address skip is unsigned. @@ -556,18 +663,13 @@ out_set_addr (seg, frag, ofs) exactly the expected number of bytes. */ static int -size_inc_line_addr (line_delta, addr_delta) - int line_delta; - addressT addr_delta; +size_inc_line_addr (int line_delta, addressT addr_delta) { unsigned int tmp, opcode; int len = 0; /* Scale the address delta by the minimum instruction length. */ -#if DWARF2_LINE_MIN_INSN_LENGTH > 1 - assert (addr_delta % DWARF2_LINE_MIN_INSN_LENGTH == 0); - addr_delta /= DWARF2_LINE_MIN_INSN_LENGTH; -#endif + scale_addr_delta (&addr_delta); /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence. We cannot use special opcodes here, since we want the end_sequence @@ -620,21 +722,15 @@ size_inc_line_addr (line_delta, addr_delta) } static void -emit_inc_line_addr (line_delta, addr_delta, p, len) - int line_delta; - addressT addr_delta; - char *p; - int len; +emit_inc_line_addr (int line_delta, addressT addr_delta, char *p, int len) { unsigned int tmp, opcode; int need_copy = 0; char *end = p + len; -#if DWARF2_LINE_MIN_INSN_LENGTH > 1 /* Scale the address delta by the minimum instruction length. */ - assert (addr_delta % DWARF2_LINE_MIN_INSN_LENGTH == 0); - addr_delta /= DWARF2_LINE_MIN_INSN_LENGTH; -#endif + scale_addr_delta (&addr_delta); + /* INT_MAX is a signal that this is actually a DW_LNE_end_sequence. We cannot use special opcodes here, since we want the end_sequence to emit the matrix entry. */ @@ -717,9 +813,7 @@ emit_inc_line_addr (line_delta, addr_delta, p, len) /* Handy routine to combine calls to the above two routines. */ static void -out_inc_line_addr (line_delta, addr_delta) - int line_delta; - addressT addr_delta; +out_inc_line_addr (int line_delta, addressT addr_delta) { int len = size_inc_line_addr (line_delta, addr_delta); emit_inc_line_addr (line_delta, addr_delta, frag_more (len), len); @@ -729,18 +823,16 @@ out_inc_line_addr (line_delta, addr_delta) increments between fragments of the target segment. */ static void -relax_inc_line_addr (line_delta, seg, to_frag, to_ofs, from_frag, from_ofs) - int line_delta; - segT seg; - fragS *to_frag, *from_frag; - addressT to_ofs, from_ofs; +relax_inc_line_addr (int line_delta, segT seg, + fragS *to_frag, addressT to_ofs, + fragS *from_frag, addressT from_ofs) { symbolS *to_sym, *from_sym; expressionS expr; int max_chars; - to_sym = symbol_new (fake_label_name, seg, to_ofs, to_frag); - from_sym = symbol_new (fake_label_name, seg, from_ofs, from_frag); + to_sym = symbol_temp_new (seg, to_ofs, to_frag); + from_sym = symbol_temp_new (seg, from_ofs, from_frag); expr.X_op = O_subtract; expr.X_add_symbol = to_sym; @@ -760,13 +852,12 @@ relax_inc_line_addr (line_delta, seg, to_frag, to_ofs, from_frag, from_ofs) the relaxation loop. We set fr_subtype to the expected length. */ int -dwarf2dbg_estimate_size_before_relax (frag) - fragS *frag; +dwarf2dbg_estimate_size_before_relax (fragS *frag) { offsetT addr_delta; int size; - addr_delta = resolve_symbol_value (frag->fr_symbol, 0); + addr_delta = resolve_symbol_value (frag->fr_symbol); size = size_inc_line_addr (frag->fr_offset, addr_delta); frag->fr_subtype = size; @@ -779,8 +870,7 @@ dwarf2dbg_estimate_size_before_relax (frag) of the frag. This returns the change in frag length. */ int -dwarf2dbg_relax_frag (frag) - fragS *frag; +dwarf2dbg_relax_frag (fragS *frag) { int old_size, new_size; @@ -795,12 +885,11 @@ dwarf2dbg_relax_frag (frag) fr_subtype will be the desired length of the frag. */ void -dwarf2dbg_convert_frag (frag) - fragS *frag; +dwarf2dbg_convert_frag (fragS *frag) { offsetT addr_diff; - addr_diff = resolve_symbol_value (frag->fr_symbol, 1); + addr_diff = resolve_symbol_value (frag->fr_symbol); /* fr_var carries the max_chars that we created the fragment with. fr_subtype carries the current expected length. We must, of @@ -820,9 +909,7 @@ dwarf2dbg_convert_frag (frag) beginning at E, for segment SEG. */ static void -process_entries (seg, e) - segT seg; - struct line_entry *e; +process_entries (segT seg, struct line_entry *e) { unsigned filenum = 1; unsigned line = 1; @@ -867,7 +954,11 @@ process_entries (seg, e) changed = 1; } - if (line != e->loc.line || changed) + /* Don't try to optimize away redundant entries; gdb wants two + entries for a function where the code starts on the same line as + the {, and there's no way to identify that case here. Trust gcc + to optimize appropriately. */ + if (1 /* line != e->loc.line || changed */) { int line_delta = e->loc.line - line; if (frag == NULL) @@ -910,17 +1001,32 @@ process_entries (seg, e) /* Emit the directory and file tables for .debug_line. */ static void -out_file_list () +out_file_list (void) { size_t size; char *cp; unsigned int i; - /* Terminate directory list. */ + /* Emit directory list. */ + for (i = 1; i < dirs_in_use; ++i) + { + size = strlen (dirs[i]) + 1; + cp = frag_more (size); + memcpy (cp, dirs[i], size); + } + /* Terminate it. */ out_byte ('\0'); for (i = 1; i < files_in_use; ++i) { + if (files[i].filename == NULL) + { + as_bad (_("unassigned file number %ld"), (long) i); + /* Prevent a crash later, particularly for file 1. */ + files[i].filename = ""; + continue; + } + size = strlen (files[i].filename) + 1; cp = frag_more (size); memcpy (cp, files[i].filename, size); @@ -937,27 +1043,51 @@ out_file_list () /* Emit the collected .debug_line data. */ static void -out_debug_line (line_seg) - segT line_seg; +out_debug_line (segT line_seg) { expressionS expr; symbolS *line_start; symbolS *prologue_end; symbolS *line_end; struct line_seg *s; + enum dwarf2_format d2f; + int sizeof_offset; subseg_set (line_seg, 0); - line_start = symbol_new_now (); - prologue_end = symbol_make (fake_label_name); - line_end = symbol_make (fake_label_name); + line_start = symbol_temp_new_now (); + prologue_end = symbol_temp_make (); + line_end = symbol_temp_make (); /* Total length of the information for this compilation unit. */ expr.X_op = O_subtract; expr.X_add_symbol = line_end; expr.X_op_symbol = line_start; - expr.X_add_number = -4; - emit_expr (&expr, 4); + + d2f = DWARF2_FORMAT (); + if (d2f == dwarf2_format_32bit) + { + expr.X_add_number = -4; + emit_expr (&expr, 4); + sizeof_offset = 4; + } + else if (d2f == dwarf2_format_64bit) + { + expr.X_add_number = -12; + out_four (-1); + emit_expr (&expr, 8); + sizeof_offset = 8; + } + else if (d2f == dwarf2_format_64bit_irix) + { + expr.X_add_number = -8; + emit_expr (&expr, 8); + sizeof_offset = 8; + } + else + { + as_fatal (_("internal error: unknown dwarf2 format")); + } /* Version. */ out_two (2); @@ -967,7 +1097,7 @@ out_debug_line (line_seg) expr.X_add_symbol = prologue_end; expr.X_op_symbol = line_start; expr.X_add_number = - (4 + 2 + 4); - emit_expr (&expr, 4); + emit_expr (&expr, sizeof_offset); /* Parameters of the state machine. */ out_byte (DWARF2_LINE_MIN_INSN_LENGTH); @@ -989,21 +1119,19 @@ out_debug_line (line_seg) out_file_list (); - set_symbol_value_now (prologue_end); + symbol_set_value_now (prologue_end); /* For each section, emit a statement program. */ for (s = all_segs; s; s = s->next) process_entries (s->seg, s->head->head); - set_symbol_value_now (line_end); + symbol_set_value_now (line_end); } /* Emit data for .debug_aranges. */ static void -out_debug_aranges (aranges_seg, info_seg) - segT aranges_seg; - segT info_seg; +out_debug_aranges (segT aranges_seg, segT info_seg) { unsigned int addr_size = sizeof_address; addressT size, skip; @@ -1032,10 +1160,8 @@ out_debug_aranges (aranges_seg, info_seg) out_two (2); /* Offset to .debug_info. */ - expr.X_op = O_symbol; - expr.X_add_symbol = section_symbol (info_seg); - expr.X_add_number = 0; - emit_expr (&expr, 4); + /* ??? sizeof_offset */ + TC_DWARF2_EMIT_OFFSET (section_symbol (info_seg), 4); /* Size of an address (offset portion). */ out_byte (addr_size); @@ -1053,11 +1179,11 @@ out_debug_aranges (aranges_seg, info_seg) symbolS *beg, *end; frag = first_frag_for_seg (s->seg); - beg = symbol_new (fake_label_name, s->seg, 0, frag); + beg = symbol_temp_new (s->seg, 0, frag); s->text_start = beg; frag = last_frag_for_seg (s->seg); - end = symbol_new (fake_label_name, s->seg, get_frag_fix (frag), frag); + end = symbol_temp_new (s->seg, get_frag_fix (frag), frag); s->text_end = end; expr.X_op = O_symbol; @@ -1081,8 +1207,7 @@ out_debug_aranges (aranges_seg, info_seg) sync with out_debug_info below. */ static void -out_debug_abbrev (abbrev_seg) - segT abbrev_seg; +out_debug_abbrev (segT abbrev_seg) { subseg_set (abbrev_seg, 0); @@ -1095,19 +1220,20 @@ out_debug_abbrev (abbrev_seg) out_abbrev (DW_AT_low_pc, DW_FORM_addr); out_abbrev (DW_AT_high_pc, DW_FORM_addr); } + out_abbrev (DW_AT_name, DW_FORM_string); out_abbrev (DW_AT_comp_dir, DW_FORM_string); out_abbrev (DW_AT_producer, DW_FORM_string); out_abbrev (DW_AT_language, DW_FORM_data2); out_abbrev (0, 0); + + /* Terminate the abbreviations for this compilation unit. */ + out_byte (0); } /* Emit a description of this compilation unit for .debug_info. */ static void -out_debug_info (info_seg, abbrev_seg, line_seg) - segT info_seg; - segT abbrev_seg; - segT line_seg; +out_debug_info (segT info_seg, segT abbrev_seg, segT line_seg) { char producer[128]; char *comp_dir; @@ -1116,27 +1242,49 @@ out_debug_info (info_seg, abbrev_seg, line_seg) symbolS *info_end; char *p; int len; + enum dwarf2_format d2f; + int sizeof_offset; subseg_set (info_seg, 0); - info_start = symbol_new_now (); - info_end = symbol_make (fake_label_name); + info_start = symbol_temp_new_now (); + info_end = symbol_temp_make (); /* Compilation Unit length. */ expr.X_op = O_subtract; expr.X_add_symbol = info_end; expr.X_op_symbol = info_start; - expr.X_add_number = -4; - emit_expr (&expr, 4); + + d2f = DWARF2_FORMAT (); + if (d2f == dwarf2_format_32bit) + { + expr.X_add_number = -4; + emit_expr (&expr, 4); + sizeof_offset = 4; + } + else if (d2f == dwarf2_format_64bit) + { + expr.X_add_number = -12; + out_four (-1); + emit_expr (&expr, 8); + sizeof_offset = 8; + } + else if (d2f == dwarf2_format_64bit_irix) + { + expr.X_add_number = -8; + emit_expr (&expr, 8); + sizeof_offset = 8; + } + else + { + as_fatal (_("internal error: unknown dwarf2 format")); + } /* DWARF version. */ out_two (2); /* .debug_abbrev offset */ - expr.X_op = O_symbol; - expr.X_add_symbol = section_symbol (abbrev_seg); - expr.X_add_number = 0; - emit_expr (&expr, 4); + TC_DWARF2_EMIT_OFFSET (section_symbol (abbrev_seg), sizeof_offset); /* Target address size. */ out_byte (sizeof_address); @@ -1145,10 +1293,8 @@ out_debug_info (info_seg, abbrev_seg, line_seg) out_uleb128 (1); /* DW_AT_stmt_list */ - expr.X_op = O_symbol; - expr.X_add_symbol = section_symbol (line_seg); - expr.X_add_number = 0; - emit_expr (&expr, 4); + /* ??? sizeof_offset */ + TC_DWARF2_EMIT_OFFSET (section_symbol (line_seg), 4); /* These two attributes may only be emitted if all of the code is contiguous. Multiple sections are not that. */ @@ -1167,6 +1313,23 @@ out_debug_info (info_seg, abbrev_seg, line_seg) emit_expr (&expr, sizeof_address); } + /* DW_AT_name. We don't have the actual file name that was present + on the command line, so assume files[1] is the main input file. + We're not supposed to get called unless at least one line number + entry was emitted, so this should always be defined. */ + if (!files || files_in_use < 1) + abort (); + if (files[1].dir) + { + len = strlen (dirs[files[1].dir]); + p = frag_more (len + 1); + memcpy (p, dirs[files[1].dir], len); + p[len] = '/'; + } + len = strlen (files[1].filename) + 1; + p = frag_more (len); + memcpy (p, files[1].filename, len); + /* DW_AT_comp_dir */ comp_dir = getpwd (); len = strlen (comp_dir) + 1; @@ -1183,32 +1346,32 @@ out_debug_info (info_seg, abbrev_seg, line_seg) dwarf2 draft has no standard code for assembler. */ out_two (DW_LANG_Mips_Assembler); - set_symbol_value_now (info_end); + symbol_set_value_now (info_end); } void -dwarf2_finish () +dwarf2_finish (void) { segT line_seg; struct line_seg *s; - /* If no debug information was recorded, nothing to do. */ - if (all_segs == NULL) + /* We don't need to do anything unless: + - Some debug information was recorded via .file/.loc + - or, we are generating DWARF2 information ourself (--gdwarf2) + - or, there is a user-provided .debug_info section which could + reference the file table in the .debug_line section we generate + below. */ + if (all_segs == NULL + && debug_type != DEBUG_DWARF2 + && bfd_get_section_by_name (stdoutput, ".debug_info") == NULL) return; /* Calculate the size of an address for the target machine. */ -#ifdef BFD_ASSEMBLER - sizeof_address = bfd_arch_bits_per_address (stdoutput) / 8; -#else - /* FIXME. */ - sizeof_address = 4; -#endif + sizeof_address = DWARF2_ADDR_SIZE (stdoutput); /* Create and switch to the line number section. */ line_seg = subseg_new (".debug_line", 0); -#ifdef BFD_ASSEMBLER bfd_set_section_flags (stdoutput, line_seg, SEC_READONLY); -#endif /* For each subsection, chain the debug entries together. */ for (s = all_segs; s; s = s->next) @@ -1227,7 +1390,7 @@ dwarf2_finish () /* If this is assembler generated line info, we need .debug_info and .debug_abbrev sections as well. */ - if (debug_type == DEBUG_DWARF2) + if (all_segs != NULL && debug_type == DEBUG_DWARF2) { segT abbrev_seg; segT info_seg; @@ -1237,11 +1400,9 @@ dwarf2_finish () abbrev_seg = subseg_new (".debug_abbrev", 0); aranges_seg = subseg_new (".debug_aranges", 0); -#ifdef BFD_ASSEMBLER bfd_set_section_flags (stdoutput, info_seg, SEC_READONLY); bfd_set_section_flags (stdoutput, abbrev_seg, SEC_READONLY); bfd_set_section_flags (stdoutput, aranges_seg, SEC_READONLY); -#endif record_alignment (aranges_seg, ffs (2 * sizeof_address) - 1); @@ -1286,11 +1447,12 @@ dwarf2_emit_insn (size) { } -void +char * dwarf2_directive_file (dummy) int dummy ATTRIBUTE_UNUSED; { - as_fatal (_("dwarf2 is not supported for this object file format")); + s_app_file (0); + return NULL; } void