* as.c (parse_args): Add option -gdwarf2 to allow requesting
DWARF2 debug info (line information only, at this point). * as.h: Update comment about supported debug formats. * dwarf2dbg.c, dwarf2dbg.h: New files. * Makefile.am (GAS_CFILES, HFILES, GENERIC_OBJS): Add them.
This commit is contained in:
parent
b585bc2c0a
commit
fac0d250c7
6 changed files with 767 additions and 2 deletions
|
@ -1,3 +1,37 @@
|
|||
1999-06-03 David Mosberger <davidm@hpl.hp.com>
|
||||
|
||||
* dwarf2dbg.c (INITIAL_STATE): New macro encapsulating initial
|
||||
state of line state-machine.
|
||||
(struct ls): Collect DWARF2 line state-machine state in new member
|
||||
SM. Add member EMPTY_SEQUENCE to keep track if a code sequence
|
||||
resulted in any DWARF2 directives.
|
||||
(reset_state_machine): New function.
|
||||
(out_end_sequence): Ditto.
|
||||
(dwarf2_gen_line_info): When switching sections or switching to a
|
||||
lower text address, call out_end_sequence() first to terminate the
|
||||
previous code sequence as code sequences MUST have monotonically
|
||||
increasing addresses.
|
||||
(dwarf2_finish): Call out_end_sequence() instead of open coding it.
|
||||
|
||||
1999-06-03 David Mosberger <davidm@hpl.hp.com>
|
||||
|
||||
* as.c (parse_args): Add option -gdwarf2 to allow requesting
|
||||
DWARF2 debug info (line information only, at this point).
|
||||
* as.h: Update comment about supported debug formats.
|
||||
* dwarf2dbg.c, dwarf2dbg.h: New files.
|
||||
* Makefile.am (GAS_CFILES, HFILES, GENERIC_OBJS): Add them.
|
||||
|
||||
* expr.c (operand): Don't use [ for parens if we want an index op.
|
||||
(op_encoding): Switch [ into O_index, if desired.
|
||||
(op_rank): Renumber with O_index on bottom.
|
||||
(expr): If O_index, match closing bracket.
|
||||
* expr.h (O_index): New.
|
||||
|
||||
* read.c (read_a_source_file): Conditionally allow matched "
|
||||
in lines passed to md_assemble.
|
||||
|
||||
* config/obj-elf.c (elf_pseudo_table): Add `common'.
|
||||
|
||||
1999-06-03 Ian Lance Taylor <ian@zembu.com>
|
||||
|
||||
Add support for storing local symbols in a small structure to save
|
||||
|
|
|
@ -134,6 +134,7 @@ GAS_CFILES = \
|
|||
bignum-copy.c \
|
||||
cond.c \
|
||||
depend.c \
|
||||
dwarf2dbg.c \
|
||||
ecoff.c \
|
||||
ehopt.c \
|
||||
expr.c \
|
||||
|
@ -164,6 +165,7 @@ HFILES = \
|
|||
bignum.h \
|
||||
bit_fix.h \
|
||||
cgen.h \
|
||||
dwarf2dbg.h \
|
||||
ecoff.h \
|
||||
emul-target.h \
|
||||
emul.h \
|
||||
|
@ -331,6 +333,7 @@ GENERIC_OBJS = \
|
|||
bignum-copy.o \
|
||||
cond.o \
|
||||
depend.o \
|
||||
dwarf2dbg.o \
|
||||
ehopt.o \
|
||||
expr.o \
|
||||
flonum-konst.o \
|
||||
|
@ -879,6 +882,7 @@ atof-generic.o: atof-generic.c
|
|||
bignum-copy.o: bignum-copy.c
|
||||
cond.o: cond.c macro.h sb.h $(INCDIR)/obstack.h
|
||||
depend.o: depend.c
|
||||
dwarf2dbg.o: dwarf2dbg.c dwarf2dbg.h subsegs.h
|
||||
ecoff.o: ecoff.c
|
||||
ehopt.o: ehopt.c subsegs.h $(INCDIR)/obstack.h $(INCDIR)/elf/dwarf2.h
|
||||
expr.o: expr.c $(INCDIR)/obstack.h
|
||||
|
|
9
gas/as.c
9
gas/as.c
|
@ -143,6 +143,7 @@ Options:\n\
|
|||
m include macro expansions\n\
|
||||
n omit forms processing\n\
|
||||
s include symbols\n\
|
||||
L include line debug statistics (if applicable)\n\
|
||||
=file set listing file name (must be last sub-option)\n"));
|
||||
|
||||
fprintf (stream, _("\
|
||||
|
@ -365,7 +366,9 @@ parse_args (pargc, pargv)
|
|||
#define OPTION_STRIP_LOCAL_ABSOLUTE (OPTION_STD_BASE + 15)
|
||||
{"strip-local-absolute", no_argument, NULL, OPTION_STRIP_LOCAL_ABSOLUTE},
|
||||
#define OPTION_TRADITIONAL_FORMAT (OPTION_STD_BASE + 16)
|
||||
{"traditional-format", no_argument, NULL, OPTION_TRADITIONAL_FORMAT}
|
||||
{"traditional-format", no_argument, NULL, OPTION_TRADITIONAL_FORMAT},
|
||||
#define OPTION_GDWARF2 (OPTION_STD_BASE + 17)
|
||||
{"gdwarf2", no_argument, NULL, OPTION_GDWARF2}
|
||||
};
|
||||
|
||||
/* Construct the option lists from the standard list and the
|
||||
|
@ -546,6 +549,10 @@ the GNU General Public License. This program has absolutely no warranty.\n"));
|
|||
debug_type = DEBUG_STABS;
|
||||
break;
|
||||
|
||||
case OPTION_GDWARF2:
|
||||
debug_type = DEBUG_DWARF2;
|
||||
break;
|
||||
|
||||
case 'J':
|
||||
flag_signed_overflow_ok = 1;
|
||||
break;
|
||||
|
|
2
gas/as.h
2
gas/as.h
|
@ -457,7 +457,7 @@ COMMON int linkrelax;
|
|||
extern int listing;
|
||||
|
||||
/* Type of debugging information we should generate. We currently
|
||||
only support stabs and ECOFF. */
|
||||
support stabs, ECOFF, and DWARF2. */
|
||||
|
||||
enum debug_info_type
|
||||
{
|
||||
|
|
672
gas/dwarf2dbg.c
Normal file
672
gas/dwarf2dbg.c
Normal file
|
@ -0,0 +1,672 @@
|
|||
/* dwarf2dbg.c - DWARF2 debug support
|
||||
Copyright (C) 1999 Hewlett-Packard Co
|
||||
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
|
||||
|
||||
This file is part of GAS, the GNU Assembler.
|
||||
|
||||
GAS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
GAS is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with GAS; see the file COPYING. If not, write to the Free
|
||||
Software Foundation, 59 Temple Place - Suite 330, Boston, MA
|
||||
02111-1307, USA.
|
||||
|
||||
Logical line numbers can be controlled by the compiler via the
|
||||
following two directives:
|
||||
|
||||
.file FILENO "file.c"
|
||||
.loc FILENO LINENO [COLUMN]
|
||||
|
||||
FILENO is the filenumber. */
|
||||
|
||||
#include "ansidecl.h"
|
||||
|
||||
#include "as.h"
|
||||
#include "dwarf2dbg.h"
|
||||
#include "subsegs.h"
|
||||
|
||||
#include <elf/dwarf2.h>
|
||||
|
||||
#define BYTES_PER_ADDRESS (BFD_ARCH_SIZE / 8)
|
||||
|
||||
/* Since we can't generate the prolog until the body is complete, we
|
||||
use three different subsegments for .debug_line: one holding the
|
||||
prolog, one for the directory and filename info, and one for the
|
||||
body ("statement program"). */
|
||||
#define DL_PROLOG 0
|
||||
#define DL_FILES 1
|
||||
#define DL_BODY 2
|
||||
|
||||
/* First special line opcde - leave room for the standard opcodes.
|
||||
Note: If you want to change this, you'll have to update the
|
||||
"standard_opcode_lengths" table that is emitted below in
|
||||
dwarf2_finish(). */
|
||||
#define DWARF2_LINE_OPCODE_BASE 10
|
||||
|
||||
#ifndef DWARF2_LINE_BASE
|
||||
/* Minimum line offset in a special line info. opcode. This value
|
||||
was chosen to give a reasonable range of values. */
|
||||
# define DWARF2_LINE_BASE -5
|
||||
#endif
|
||||
|
||||
/* Range of line offsets in a special line info. opcode. */
|
||||
#ifndef DWARF2_LINE_RANGE
|
||||
# define DWARF2_LINE_RANGE 14
|
||||
#endif
|
||||
|
||||
#ifndef DWARF2_LINE_MIN_INSN_LENGTH
|
||||
/* Define the architecture-dependent minimum instruction length (in
|
||||
bytes). This value should be rather too small than too big. */
|
||||
# define DWARF2_LINE_MIN_INSN_LENGTH 4
|
||||
#endif
|
||||
|
||||
/* Flag that indicates the initial value of the is_stmt_start flag.
|
||||
In the present implementation, we do not mark any lines as
|
||||
the beginning of a source statement, because that information
|
||||
is not made available by the GCC front-end. */
|
||||
#define DWARF2_LINE_DEFAULT_IS_STMT 1
|
||||
|
||||
/* Flag that indicates the initial value of the is_stmt_start flag.
|
||||
In the present implementation, we do not mark any lines as
|
||||
the beginning of a source statement, because that information
|
||||
is not made available by the GCC front-end. */
|
||||
#define DWARF2_LINE_DEFAULT_IS_STMT 1
|
||||
|
||||
/* Given a special op, return the line skip amount: */
|
||||
#define SPECIAL_LINE(op) \
|
||||
(((op) - DWARF2_LINE_OPCODE_BASE)%DWARF2_LINE_RANGE + DWARF2_LINE_BASE)
|
||||
|
||||
/* Given a special op, return the address skip amount (in units of
|
||||
DWARF2_LINE_MIN_INSN_LENGTH. */
|
||||
#define SPECIAL_ADDR(op) (((op) - DWARF2_LINE_OPCODE_BASE)/DWARF2_LINE_RANGE)
|
||||
|
||||
/* The maximum address skip amont that can be encoded with a special op: */
|
||||
#define MAX_SPECIAL_ADDR_DELTA SPECIAL_ADDR(255)
|
||||
|
||||
#define INITIAL_STATE \
|
||||
/* initialize as per DWARF2.0 standard: */ \
|
||||
0, /* address */ \
|
||||
1, /* file */ \
|
||||
1, /* line */ \
|
||||
0, /* column */ \
|
||||
DWARF2_LINE_DEFAULT_IS_STMT, /* is_stmt */ \
|
||||
0, /* basic_block */ \
|
||||
1 /* empty_sequence */
|
||||
|
||||
static struct
|
||||
{
|
||||
/* state machine state as per DWARF2 manual: */
|
||||
struct dwarf2_sm
|
||||
{
|
||||
bfd_vma addr;
|
||||
unsigned int filenum;
|
||||
unsigned int line;
|
||||
unsigned int column;
|
||||
unsigned int
|
||||
is_stmt : 1,
|
||||
basic_block : 1,
|
||||
empty_sequence : 1; /* current code sequence has no DWARF2 directives? */
|
||||
}
|
||||
sm;
|
||||
|
||||
unsigned int
|
||||
any_dwarf2_directives : 1; /* did we emit any DWARF2 line debug directives? */
|
||||
|
||||
segT text_seg; /* text segment "addr" is relative to */
|
||||
subsegT text_subseg;
|
||||
segT line_seg; /* ".debug_line" segment */
|
||||
int last_filename; /* index of last filename that was used */
|
||||
int num_filenames; /* index of last filename in use */
|
||||
int filename_len; /* length of the filename array */
|
||||
struct
|
||||
{
|
||||
int dir; /* valid after gen_dir_list() only */
|
||||
char *name; /* full path before gen_dir_list(), filename afterwards */
|
||||
}
|
||||
*file;
|
||||
|
||||
struct dwarf2_line_info current; /* current source info: */
|
||||
|
||||
/* counters for statistical purposes: */
|
||||
unsigned int num_line_entries;
|
||||
unsigned int opcode_hist[256]; /* histogram of opcode frequencies */
|
||||
}
|
||||
ls =
|
||||
{
|
||||
{
|
||||
INITIAL_STATE
|
||||
},
|
||||
};
|
||||
|
||||
#define out_byte(byte) FRAG_APPEND_1_CHAR(byte)
|
||||
#define out_opcode(opc) (out_byte ((opc)), ++ls.opcode_hist[(opc) & 0xff])
|
||||
|
||||
/* Output an unsigned "little-endian base 128" number. */
|
||||
static void
|
||||
out_uleb128 (bfd_vma value)
|
||||
{
|
||||
unsigned char byte, more = 0x80;
|
||||
|
||||
do
|
||||
{
|
||||
byte = value & 0x7f;
|
||||
value >>= 7;
|
||||
if (value == 0)
|
||||
more = 0;
|
||||
out_byte (more | byte);
|
||||
}
|
||||
while (more);
|
||||
}
|
||||
|
||||
/* Output a signed "little-endian base 128" number. */
|
||||
static void
|
||||
out_sleb128 (bfd_signed_vma value)
|
||||
{
|
||||
unsigned char byte, more = 0x80;
|
||||
|
||||
do
|
||||
{
|
||||
byte = value & 0x7f;
|
||||
value >>= 7;
|
||||
if (((value == 0) && ((byte & 0x40) == 0))
|
||||
|| ((value == -1) && ((byte & 0x40) != 0)))
|
||||
more = 0;
|
||||
out_byte (more | byte);
|
||||
}
|
||||
while (more);
|
||||
}
|
||||
|
||||
/* 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. */
|
||||
static void
|
||||
gen_addr_line (int line_delta, bfd_vma addr_delta)
|
||||
{
|
||||
unsigned int tmp, opcode;
|
||||
|
||||
tmp = line_delta - DWARF2_LINE_BASE;
|
||||
|
||||
if (tmp >= DWARF2_LINE_RANGE)
|
||||
{
|
||||
out_opcode (DW_LNS_advance_line);
|
||||
out_sleb128 (line_delta);
|
||||
tmp = 0 - DWARF2_LINE_BASE;
|
||||
line_delta = 0;
|
||||
}
|
||||
|
||||
tmp += DWARF2_LINE_OPCODE_BASE;
|
||||
|
||||
/* try using a special opcode: */
|
||||
opcode = tmp + addr_delta*DWARF2_LINE_RANGE;
|
||||
if (opcode <= 255)
|
||||
{
|
||||
out_opcode (opcode);
|
||||
return;
|
||||
}
|
||||
|
||||
/* try using DW_LNS_const_add_pc followed by special op: */
|
||||
opcode = tmp + (addr_delta - MAX_SPECIAL_ADDR_DELTA)*DWARF2_LINE_RANGE;
|
||||
if (opcode <= 255)
|
||||
{
|
||||
out_opcode (DW_LNS_const_add_pc);
|
||||
out_opcode (opcode);
|
||||
return;
|
||||
}
|
||||
|
||||
out_opcode (DW_LNS_advance_pc);
|
||||
out_uleb128 (addr_delta);
|
||||
|
||||
if (line_delta)
|
||||
out_opcode (tmp); /* output line-delta */
|
||||
else
|
||||
out_opcode (DW_LNS_copy); /* append new row with current info */
|
||||
}
|
||||
|
||||
static void
|
||||
reset_state_machine (void)
|
||||
{
|
||||
static const struct dwarf2_sm initial_state = { INITIAL_STATE };
|
||||
|
||||
ls.sm = initial_state;
|
||||
}
|
||||
|
||||
/* Set an absolute address (may results in a relocation entry): */
|
||||
static void
|
||||
out_set_addr (bfd_vma addr)
|
||||
{
|
||||
subsegT saved_subseg;
|
||||
segT saved_seg;
|
||||
expressionS expr;
|
||||
symbolS *sym;
|
||||
|
||||
saved_seg = now_seg;
|
||||
saved_subseg = now_subseg;
|
||||
|
||||
subseg_set (ls.text_seg, ls.text_subseg);
|
||||
sym = symbol_new (".L0\001", now_seg, addr, frag_now);
|
||||
|
||||
subseg_set (saved_seg, saved_subseg);
|
||||
|
||||
out_opcode (DW_LNS_extended_op);
|
||||
out_uleb128 (BYTES_PER_ADDRESS + 1);
|
||||
|
||||
out_opcode (DW_LNE_set_address);
|
||||
expr.X_op = O_symbol;
|
||||
expr.X_add_symbol = sym;
|
||||
expr.X_add_number = 0;
|
||||
emit_expr (&expr, BYTES_PER_ADDRESS);
|
||||
}
|
||||
|
||||
/* Emit DW_LNS_end_sequence and reset state machine. Does not
|
||||
preserve the current segment/sub-segment! */
|
||||
static void
|
||||
out_end_sequence (void)
|
||||
{
|
||||
bfd_vma addr, delta;
|
||||
|
||||
if (ls.text_seg)
|
||||
{
|
||||
subseg_set (ls.text_seg, ls.text_subseg);
|
||||
#ifdef md_current_text_addr
|
||||
addr = md_current_text_addr ();
|
||||
#else
|
||||
addr = frag_now_fix ();
|
||||
#endif
|
||||
subseg_set (ls.line_seg, DL_BODY);
|
||||
if (addr < ls.sm.addr)
|
||||
{
|
||||
out_set_addr (addr);
|
||||
ls.sm.addr = addr;
|
||||
}
|
||||
else
|
||||
{
|
||||
delta = addr - ls.sm.addr;
|
||||
if (delta > 0)
|
||||
gen_addr_line (0, delta / DWARF2_LINE_MIN_INSN_LENGTH);
|
||||
}
|
||||
}
|
||||
else
|
||||
subseg_set (ls.line_seg, DL_BODY);
|
||||
|
||||
out_opcode (DW_LNS_extended_op);
|
||||
out_uleb128 (1);
|
||||
out_byte (DW_LNE_end_sequence);
|
||||
|
||||
reset_state_machine ();
|
||||
}
|
||||
|
||||
/* Look up a filenumber either by filename or by filenumber. If both
|
||||
a filenumber and a filename are specified, lookup by filename takes
|
||||
precedence. If the filename cannot be found, it is added to the
|
||||
filetable the filenumber for the new entry is returned. */
|
||||
static int
|
||||
get_filenum (int filenum, char *file)
|
||||
{
|
||||
int i, last = filenum - 1;
|
||||
char char0 = file[0];
|
||||
|
||||
if ((unsigned) last >= ls.num_filenames)
|
||||
last = ls.last_filename;
|
||||
|
||||
/* do a quick check against the previously used filename: */
|
||||
if (ls.num_filenames > 0 && ls.file[last].name[0] == char0
|
||||
&& strcmp (ls.file[last].name + 1, file + 1) == 0)
|
||||
return last + 1;
|
||||
|
||||
/* no match, fall back to simple linear scan: */
|
||||
for (i = 0; i < ls.num_filenames; ++i)
|
||||
{
|
||||
if (ls.file[i].name[0] == char0
|
||||
&& strcmp (ls.file[i].name + 1, file + 1) == 0)
|
||||
{
|
||||
ls.last_filename = i;
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* no match: enter new filename */
|
||||
if (ls.num_filenames >= ls.filename_len)
|
||||
{
|
||||
ls.filename_len += 13;
|
||||
ls.file = xrealloc (ls.file, ls.filename_len * sizeof (ls.file[0]));
|
||||
}
|
||||
ls.file[ls.num_filenames].dir = 0;
|
||||
ls.file[ls.num_filenames].name = file;
|
||||
return ++ls.num_filenames;
|
||||
}
|
||||
|
||||
void
|
||||
dwarf2_gen_line_info (bfd_vma addr, struct dwarf2_line_info *l)
|
||||
{
|
||||
unsigned int filenum = l->filenum;
|
||||
unsigned int any_output = 0;
|
||||
subsegT saved_subseg;
|
||||
segT saved_seg;
|
||||
char *frag;
|
||||
|
||||
if (flag_debug)
|
||||
fprintf (stderr, "line: addr %llx file `%s' line %u col %u flags %lx\n",
|
||||
(long long) addr, l->filename, l->line, l->column, l->flags);
|
||||
|
||||
if (filenum > 0 && !l->filename)
|
||||
{
|
||||
if (filenum >= ls.num_filenames)
|
||||
{
|
||||
as_warn ("Encountered bad file number in line number debug info!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (l->filename)
|
||||
filenum = get_filenum (filenum, l->filename);
|
||||
else
|
||||
return; /* no filename, no filnum => no play */
|
||||
|
||||
if (!ls.line_seg)
|
||||
{
|
||||
symbolS *secsym;
|
||||
|
||||
ls.line_seg = subseg_get (".debug_line", DL_BODY);
|
||||
bfd_set_section_flags (stdoutput, ls.line_seg, SEC_READONLY);
|
||||
secsym = symbol_find (".debug_line");
|
||||
if (secsym)
|
||||
secsym->bsym = ls.line_seg->symbol;
|
||||
else
|
||||
symbol_table_insert (section_symbol (ls.line_seg));
|
||||
}
|
||||
|
||||
saved_seg = now_seg;
|
||||
saved_subseg = now_subseg;
|
||||
subseg_set (ls.line_seg, DL_BODY);
|
||||
|
||||
if (ls.text_seg != saved_seg || ls.text_subseg != saved_subseg)
|
||||
{
|
||||
if (!ls.sm.empty_sequence)
|
||||
{
|
||||
out_end_sequence (); /* terminate previous sequence */
|
||||
ls.sm.empty_sequence = 1;
|
||||
}
|
||||
any_output = 1;
|
||||
ls.text_seg = saved_seg;
|
||||
ls.text_subseg = saved_subseg;
|
||||
out_set_addr (addr);
|
||||
ls.sm.addr = addr;
|
||||
}
|
||||
|
||||
if (ls.sm.filenum != filenum)
|
||||
{
|
||||
any_output = 1;
|
||||
out_opcode (DW_LNS_set_file);
|
||||
out_uleb128 (filenum);
|
||||
ls.sm.filenum = filenum;
|
||||
}
|
||||
|
||||
if (ls.sm.column != l->column)
|
||||
{
|
||||
any_output = 1;
|
||||
out_opcode (DW_LNS_set_column);
|
||||
out_uleb128 (l->column);
|
||||
ls.sm.column = l->column;
|
||||
}
|
||||
|
||||
if (((l->flags & DWARF2_FLAG_BEGIN_STMT) != 0) != ls.sm.is_stmt)
|
||||
{
|
||||
any_output = 1;
|
||||
out_opcode (DW_LNS_negate_stmt);
|
||||
}
|
||||
|
||||
if (l->flags & DWARF2_FLAG_BEGIN_BLOCK)
|
||||
{
|
||||
any_output = 1;
|
||||
out_opcode (DW_LNS_set_basic_block);
|
||||
}
|
||||
|
||||
if (ls.sm.line != l->line)
|
||||
{
|
||||
any_output = 1;
|
||||
if (addr < ls.sm.addr)
|
||||
{
|
||||
if (!ls.sm.empty_sequence)
|
||||
{
|
||||
out_end_sequence ();
|
||||
ls.sm.empty_sequence = 1;
|
||||
}
|
||||
out_set_addr (addr);
|
||||
ls.sm.addr = addr;
|
||||
}
|
||||
gen_addr_line (l->line - ls.sm.line,
|
||||
(addr - ls.sm.addr) / DWARF2_LINE_MIN_INSN_LENGTH);
|
||||
ls.sm.basic_block = 0;
|
||||
ls.sm.line = l->line;
|
||||
ls.sm.addr = addr;
|
||||
}
|
||||
|
||||
subseg_set (saved_seg, saved_subseg);
|
||||
|
||||
ls.num_line_entries += any_output;
|
||||
if (any_output)
|
||||
ls.sm.empty_sequence = 0;
|
||||
}
|
||||
|
||||
static void
|
||||
gen_dir_list (void)
|
||||
{
|
||||
char *str, *slash, *dir_list, *dp, *cp;
|
||||
int i, j, num_dirs;
|
||||
|
||||
dir_list = frag_more (0);
|
||||
num_dirs = 0;
|
||||
|
||||
for (i = 0; i < ls.num_filenames; ++i)
|
||||
{
|
||||
str = ls.file[i].name;
|
||||
slash = strrchr (str, '/');
|
||||
if (slash)
|
||||
{
|
||||
*slash = '\0';
|
||||
for (j = 0, dp = dir_list; j < num_dirs; ++j)
|
||||
{
|
||||
if (strcmp (str, dp) == 0)
|
||||
{
|
||||
ls.file[i].dir = j;
|
||||
break;
|
||||
}
|
||||
dp += strlen (dp);
|
||||
}
|
||||
if (j >= num_dirs)
|
||||
{
|
||||
/* didn't find this directory: append it to the list */
|
||||
size_t size = strlen (str) + 1;
|
||||
cp = frag_more (size);
|
||||
memcpy (cp, str, size);
|
||||
ls.file[i].dir = ++num_dirs;
|
||||
}
|
||||
*slash = '/';
|
||||
ls.file[i].name = slash + 1;
|
||||
}
|
||||
}
|
||||
out_byte ('\0'); /* terminate directory list */
|
||||
}
|
||||
|
||||
static void
|
||||
gen_file_list (void)
|
||||
{
|
||||
size_t size;
|
||||
char *cp;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ls.num_filenames; ++i)
|
||||
{
|
||||
size = strlen (ls.file[i].name) + 1;
|
||||
cp = frag_more (size);
|
||||
memcpy (cp, ls.file[i].name, size);
|
||||
|
||||
out_uleb128 (ls.file[i].dir); /* directory number */
|
||||
out_uleb128 (0); /* last modification timestamp */
|
||||
out_uleb128 (0); /* filesize */
|
||||
}
|
||||
out_byte (0); /* terminate filename list */
|
||||
}
|
||||
|
||||
void
|
||||
print_stats (unsigned long total_size)
|
||||
{
|
||||
static const char *opc_name[] =
|
||||
{
|
||||
"extended", "copy", "advance_pc", "advance_line", "set_file",
|
||||
"set_column", "negate_stmt", "set_basic_block", "const_add_pc",
|
||||
"fixed_advance_pc"
|
||||
};
|
||||
int i, j;
|
||||
|
||||
fprintf (stderr, "Average size: %g bytes/line\n",
|
||||
total_size / (double) ls.num_line_entries);
|
||||
|
||||
fprintf (stderr, "\nStandard opcode histogram:\n");
|
||||
|
||||
for (i = 0; i < sizeof (opc_name)/sizeof (opc_name[0]); ++i)
|
||||
{
|
||||
fprintf (stderr, "%s", opc_name[i]);
|
||||
for (j = strlen (opc_name[i]); j < 16; ++j)
|
||||
fprintf (stderr, " ");
|
||||
fprintf (stderr, ": %u\n", ls.opcode_hist[i]);
|
||||
}
|
||||
|
||||
fprintf (stderr, "\nSpecial opcodes:\naddr\t\t\t\tline skip\n");
|
||||
|
||||
fprintf (stderr, "skip: ");
|
||||
for (j = DWARF2_LINE_BASE; j < DWARF2_LINE_BASE + DWARF2_LINE_RANGE; ++j)
|
||||
fprintf (stderr, "%3d", j);
|
||||
fprintf (stderr, "\n-----");
|
||||
|
||||
for (; i < 256; ++i)
|
||||
{
|
||||
j = SPECIAL_LINE (i);
|
||||
if (j == DWARF2_LINE_BASE)
|
||||
fprintf (stderr, "\n%4u: ",
|
||||
DWARF2_LINE_MIN_INSN_LENGTH*SPECIAL_ADDR (i));
|
||||
fprintf (stderr, " %2u", ls.opcode_hist[i]);
|
||||
}
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
void
|
||||
dwarf2_finish (void)
|
||||
{
|
||||
bfd_vma addr, body_size, total_size, prolog_size;
|
||||
subsegT saved_subseg, line_prolog;
|
||||
segT saved_seg;
|
||||
char *cp;
|
||||
|
||||
if (!ls.line_seg)
|
||||
/* no .debug_line segment, no work to do... */
|
||||
return;
|
||||
|
||||
saved_seg = now_seg;
|
||||
saved_subseg = now_subseg;
|
||||
|
||||
if (!ls.sm.empty_sequence)
|
||||
out_end_sequence ();
|
||||
total_size = body_size = frag_now_fix ();
|
||||
|
||||
/* now generate the directory and file lists: */
|
||||
subseg_set (ls.line_seg, DL_FILES);
|
||||
gen_dir_list ();
|
||||
gen_file_list ();
|
||||
total_size += frag_now_fix ();
|
||||
|
||||
/* and now the header ("statement program prolog", in DWARF2 lingo...) */
|
||||
subseg_set (ls.line_seg, DL_PROLOG);
|
||||
|
||||
cp = frag_more (15 + DWARF2_LINE_OPCODE_BASE - 1);
|
||||
|
||||
total_size += frag_now_fix ();
|
||||
prolog_size = total_size - body_size - 10;
|
||||
|
||||
# define STUFF(val,size) md_number_to_chars (cp, val, size); cp += size;
|
||||
STUFF (total_size - 4, 4); /* length */
|
||||
STUFF (2, 2); /* version */
|
||||
STUFF (prolog_size, 4); /* prologue_length */
|
||||
STUFF (DWARF2_LINE_MIN_INSN_LENGTH, 1);
|
||||
STUFF (DWARF2_LINE_DEFAULT_IS_STMT, 1);
|
||||
STUFF (DWARF2_LINE_BASE, 1);
|
||||
STUFF (DWARF2_LINE_RANGE, 1);
|
||||
STUFF (DWARF2_LINE_OPCODE_BASE, 1);
|
||||
|
||||
/* standard_opcode_lengths: */
|
||||
STUFF (0, 1); /* DW_LNS_copy */
|
||||
STUFF (1, 1); /* DW_LNS_advance_pc */
|
||||
STUFF (1, 1); /* DW_LNS_advance_line */
|
||||
STUFF (1, 1); /* DW_LNS_set_file */
|
||||
STUFF (1, 1); /* DW_LNS_set_column */
|
||||
STUFF (0, 1); /* DW_LNS_negate_stmt */
|
||||
STUFF (0, 1); /* DW_LNS_set_basic_block */
|
||||
STUFF (0, 1); /* DW_LNS_const_add_pc */
|
||||
STUFF (1, 1); /* DW_LNS_fixed_advance_pc */
|
||||
|
||||
subseg_set (saved_seg, saved_subseg);
|
||||
|
||||
if (flag_debug)
|
||||
print_stats (total_size);
|
||||
}
|
||||
|
||||
void
|
||||
dwarf2_directive_file (int dummy)
|
||||
{
|
||||
int len;
|
||||
|
||||
ls.any_dwarf2_directives = 1;
|
||||
|
||||
if (debug_type == DEBUG_NONE)
|
||||
/* Automatically turn on DWARF2 debug info unless something else
|
||||
has been selected. */
|
||||
debug_type = DEBUG_DWARF2;
|
||||
|
||||
ls.current.filenum = get_absolute_expression ();
|
||||
ls.current.filename = demand_copy_C_string (&len);
|
||||
|
||||
demand_empty_rest_of_line ();
|
||||
}
|
||||
|
||||
void
|
||||
dwarf2_directive_loc (int dummy)
|
||||
{
|
||||
ls.any_dwarf2_directives = 1;
|
||||
|
||||
ls.current.filenum = get_absolute_expression ();
|
||||
SKIP_WHITESPACE ();
|
||||
ls.current.line = get_absolute_expression ();
|
||||
SKIP_WHITESPACE ();
|
||||
ls.current.column = get_absolute_expression ();
|
||||
demand_empty_rest_of_line ();
|
||||
|
||||
ls.current.flags = DWARF2_FLAG_BEGIN_STMT;
|
||||
|
||||
#ifndef NO_LISTING
|
||||
if (listing)
|
||||
listing_source_line (ls.current.line);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
dwarf2_where (struct dwarf2_line_info *line)
|
||||
{
|
||||
if (ls.any_dwarf2_directives)
|
||||
*line = ls.current;
|
||||
else
|
||||
{
|
||||
char *filename;
|
||||
|
||||
as_where (&line->filename, &line->line);
|
||||
line->filenum = 0;
|
||||
line->column = 0;
|
||||
line->flags = DWARF2_FLAG_BEGIN_STMT;
|
||||
}
|
||||
}
|
48
gas/dwarf2dbg.h
Normal file
48
gas/dwarf2dbg.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#ifndef AS_DWARF2DBG_H
|
||||
#define AS_DWARF2DBG_H
|
||||
|
||||
#include "as.h"
|
||||
|
||||
#define DWARF2_FLAG_BEGIN_STMT (1 << 0) /* beginning of statement */
|
||||
#define DWARF2_FLAG_BEGIN_BLOCK (1 << 1) /* beginning of basic block */
|
||||
|
||||
struct dwarf2_line_info
|
||||
{
|
||||
char *filename;
|
||||
unsigned int filenum;
|
||||
unsigned int line;
|
||||
unsigned int column;
|
||||
unsigned int flags;
|
||||
};
|
||||
|
||||
/* Implements the .file FILENO "FILENAME" directive. FILENO can be 0
|
||||
to indicate that no file number has been assigned. All real file
|
||||
number must be >0. */
|
||||
extern void dwarf2_directive_file (int dummy);
|
||||
|
||||
/* Implements the .loc FILENO LINENO [COLUMN] directive. FILENO is
|
||||
the file number, LINENO the line number and the (optional) COLUMN
|
||||
the column of the source code that the following instruction
|
||||
corresponds to. FILENO can be 0 to indicate that the filename
|
||||
specified by the textually most recent .file directive should be
|
||||
used. */
|
||||
extern void dwarf2_directive_loc (int dummy);
|
||||
|
||||
/* Returns the current source information. If .file directives have
|
||||
been encountered, the info for the corresponding source file is
|
||||
returned. Otherwise, the info for the assembly source file is
|
||||
returned. */
|
||||
extern void dwarf2_where (struct dwarf2_line_info *l);
|
||||
|
||||
/* This function generates .debug_line info based on the address and
|
||||
source information passed in the arguments. ADDR should be the
|
||||
frag-relative offset of the instruction the information is for and
|
||||
L is the source information that should be associated with that
|
||||
address. */
|
||||
extern void dwarf2_gen_line_info (bfd_vma addr, struct dwarf2_line_info *l);
|
||||
|
||||
/* Must be called after all other input is processed to finish up the
|
||||
.debug_line section. */
|
||||
extern void dwarf2_finish (void);
|
||||
|
||||
#endif /* AS_DWARF2DBG_H */
|
Loading…
Reference in a new issue