with label.
(dwarf2_loc_mark_labels): New.
(dwarf2_gen_line_info_1): Split out of ...
(dwarf2_gen_line_info): ... here. Create the temp symbol here.
(dwarf2_emit_label): New.
(dwarf2_directive_loc_mark_labels): New.
(out_set_addr): Take a symbol instead of frag+ofs.
(relax_inc_line_addr): Likewise.
(emit_inc_line_addr): Assert delta non-negative.
(process_entries): Remove dead code. Update to work with temp
symbols instead of frag+ofs.
* dwarf2dbg.h (dwarf2_directive_loc_mark_labels): Declare.
(dwarf2_emit_label, dwarf2_loc_mark_labels): Declare.
* config/obj-elf.c (elf_pseudo_tab): Add loc_mark_labels.
* config/obj-elf.h (obj_frob_label): New.
* config/tc-alpha.c (alpha_define_label): Call dwarf2_emit_label.
* config/tc-arm.c, config/tc-hppa.c, config/tc-m68k.c,
config/tc-mips.c, config/tc-ppc.c, config/tc-sh.c, config/tc-xtensa.c:
Similarly in the respective tc_frob_label implementation functions.
* config/tc-i386.c (md_pseudo_table): Move file and loc to
non-elf section; add loc_mark_labels.
* config/tc-ia64.c (struct label_fix): Add dw2_mark_labels.
(ia64_flush_insns): Check for marked labels; emit line entry if so.
(emit_one_bundle): Similarly.
(ia64_frob_label): Record marked labels.
* config/tc-m68hc11.h (tc_frob_label): Remove.
* config/tc-ms1.c (md_pseudo_table): Remove file and loc.
* config/tc-sh.h (tc_frob_label): Pass sym to sh_frob_label.
* config/tc-sh64.h (tc_frob_label): Likewise.
* doc/as.texinfo (LNS directives): Docuement .loc_mark_blocks.
+2005-09-20 Richard Henderson <rth@redhat.com>
+
+ * dwarf2dbg.c (struct line_entry): Replace frag and frag_ofs
+ with label.
+ (dwarf2_loc_mark_labels): New.
+ (dwarf2_gen_line_info_1): Split out of ...
+ (dwarf2_gen_line_info): ... here. Create the temp symbol here.
+ (dwarf2_emit_label): New.
+ (dwarf2_directive_loc_mark_labels): New.
+ (out_set_addr): Take a symbol instead of frag+ofs.
+ (relax_inc_line_addr): Likewise.
+ (emit_inc_line_addr): Assert delta non-negative.
+ (process_entries): Remove dead code. Update to work with temp
+ symbols instead of frag+ofs.
+ * dwarf2dbg.h (dwarf2_directive_loc_mark_labels): Declare.
+ (dwarf2_emit_label, dwarf2_loc_mark_labels): Declare.
+ * config/obj-elf.c (elf_pseudo_tab): Add loc_mark_labels.
+ * config/obj-elf.h (obj_frob_label): New.
+ * config/tc-alpha.c (alpha_define_label): Call dwarf2_emit_label.
+ * config/tc-arm.c, config/tc-hppa.c, config/tc-m68k.c,
+ config/tc-mips.c, config/tc-ppc.c, config/tc-sh.c, config/tc-xtensa.c:
+ Similarly in the respective tc_frob_label implementation functions.
+ * config/tc-i386.c (md_pseudo_table): Move file and loc to
+ non-elf section; add loc_mark_labels.
+ * config/tc-ia64.c (struct label_fix): Add dw2_mark_labels.
+ (ia64_flush_insns): Check for marked labels; emit line entry if so.
+ (emit_one_bundle): Similarly.
+ (ia64_frob_label): Record marked labels.
+ * config/tc-m68hc11.h (tc_frob_label): Remove.
+ * config/tc-ms1.c (md_pseudo_table): Remove file and loc.
+ * config/tc-sh.h (tc_frob_label): Pass sym to sh_frob_label.
+ * config/tc-sh64.h (tc_frob_label): Likewise.
+ * doc/as.texinfo (LNS directives): Docuement .loc_mark_blocks.
+
2005-09-20 Alan Modra <amodra@bigpond.net.au>
* read.c (pseudo_set): Set segment of expression syms to expr_section.
/* These are used for dwarf2. */
{ "file", (void (*) (int)) dwarf2_directive_file, 0 },
{ "loc", dwarf2_directive_loc, 0 },
+ { "loc_mark_labels", dwarf2_directive_loc_mark_labels, 0 },
/* We need to trap the section changing calls to handle .previous. */
{"data", obj_elf_data, 0},
#endif
extern void elf_frob_file_after_relocs (void);
+/* If the target doesn't have special processing for labels, take care of
+ dwarf2 output at the object file level. */
+#ifndef tc_frob_label
+#include "dwarf2dbg.h"
+#define obj_frob_label dwarf2_emit_label
+#endif
+
#ifndef obj_app_file
#define obj_app_file elf_file_symbol
#endif
alpha_define_label (symbolS *sym)
{
alpha_insn_label = sym;
+#ifdef OBJ_ELF
+ dwarf2_emit_label (sym);
+#endif
}
/* Return true if we must always emit a reloc for a type and false if
label_is_thumb_function_name = FALSE;
}
+
+#ifdef OBJ_ELF
+ dwarf2_emit_label (sym);
+#endif
}
int
label_symbols_rootp = label_chain;
}
+
+#ifdef OBJ_ELF
+ dwarf2_emit_label (symbol);
+#endif
}
/* Removes a label definition for the current space.
{"code64", set_code_flag, CODE_64BIT},
{"intel_syntax", set_intel_syntax, 1},
{"att_syntax", set_intel_syntax, 0},
- {"file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0},
- {"loc", dwarf2_directive_loc, 0},
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
{"largecomm", handle_large_common, 0},
+#else
+ {"file", (void (*) PARAMS ((int))) dwarf2_directive_file, 0},
+ {"loc", dwarf2_directive_loc, 0},
+ {"loc_mark_labels", dwarf2_directive_loc_mark_labels, 0},
#endif
#ifdef TE_PE
{"secrel32", pe_directive_secrel, 0},
{
struct label_fix *next;
struct symbol *sym;
+ bfd_boolean dw2_mark_labels;
};
/* This is the endianness of the current section. */
segT saved_seg;
subsegT saved_subseg;
unw_rec_list *ptr;
+ bfd_boolean mark;
if (!md.last_text_seg)
return;
emit_one_bundle (); /* force out queued instructions */
/* In case there are labels following the last instruction, resolve
- those now: */
+ those now. */
+ mark = FALSE;
for (lfix = CURR_SLOT.label_fixups; lfix; lfix = lfix->next)
{
- S_SET_VALUE (lfix->sym, frag_now_fix ());
- symbol_set_frag (lfix->sym, frag_now);
+ symbol_set_value_now (lfix->sym);
+ mark |= lfix->dw2_mark_labels;
}
- CURR_SLOT.label_fixups = 0;
- for (lfix = CURR_SLOT.tag_fixups; lfix; lfix = lfix->next)
+ if (mark)
{
- S_SET_VALUE (lfix->sym, frag_now_fix ());
- symbol_set_frag (lfix->sym, frag_now);
+ dwarf2_where (&CURR_SLOT.debug_line);
+ CURR_SLOT.debug_line.flags |= DWARF2_FLAG_BASIC_BLOCK;
+ dwarf2_gen_line_info (frag_now_fix (), &CURR_SLOT.debug_line);
}
+ CURR_SLOT.label_fixups = 0;
+
+ for (lfix = CURR_SLOT.tag_fixups; lfix; lfix = lfix->next)
+ symbol_set_value_now (lfix->sym);
CURR_SLOT.tag_fixups = 0;
/* In case there are unwind directives following the last instruction,
int n, i, j, first, curr, last_slot;
bfd_vma t0 = 0, t1 = 0;
struct label_fix *lfix;
+ bfd_boolean mark_label;
struct insn_fix *ifix;
char mnemonic[16];
fixS *fix;
if (insn_unit != required_unit)
continue; /* Try next slot. */
- if (debug_type == DEBUG_DWARF2 || md.slot[curr].loc_directive_seen)
+ /* Now is a good time to fix up the labels for this insn. */
+ mark_label = FALSE;
+ for (lfix = md.slot[curr].label_fixups; lfix; lfix = lfix->next)
+ {
+ S_SET_VALUE (lfix->sym, frag_now_fix () - 16);
+ symbol_set_frag (lfix->sym, frag_now);
+ mark_label |= lfix->dw2_mark_labels;
+ }
+ for (lfix = md.slot[curr].tag_fixups; lfix; lfix = lfix->next)
+ {
+ S_SET_VALUE (lfix->sym, frag_now_fix () - 16 + i);
+ symbol_set_frag (lfix->sym, frag_now);
+ }
+
+ if (debug_type == DEBUG_DWARF2
+ || md.slot[curr].loc_directive_seen
+ || mark_label)
{
bfd_vma addr = frag_now->fr_address + frag_now_fix () - 16 + i;
md.slot[curr].loc_directive_seen = 0;
+ if (mark_label)
+ md.slot[curr].debug_line.flags |= DWARF2_FLAG_BASIC_BLOCK;
+
dwarf2_gen_line_info (addr, &md.slot[curr].debug_line);
}
--md.num_slots_in_use;
last_slot = i;
- /* now is a good time to fix up the labels for this insn: */
- for (lfix = md.slot[curr].label_fixups; lfix; lfix = lfix->next)
- {
- S_SET_VALUE (lfix->sym, frag_now_fix () - 16);
- symbol_set_frag (lfix->sym, frag_now);
- }
- /* and fix up the tags also. */
- for (lfix = md.slot[curr].tag_fixups; lfix; lfix = lfix->next)
- {
- S_SET_VALUE (lfix->sym, frag_now_fix () - 16 + i);
- symbol_set_frag (lfix->sym, frag_now);
- }
-
for (j = 0; j < md.slot[curr].num_fixups; ++j)
{
ifix = md.slot[curr].fixup + j;
fix = obstack_alloc (¬es, sizeof (*fix));
fix->sym = sym;
fix->next = CURR_SLOT.tag_fixups;
+ fix->dw2_mark_labels = FALSE;
CURR_SLOT.tag_fixups = fix;
return;
fix = obstack_alloc (¬es, sizeof (*fix));
fix->sym = sym;
fix->next = CURR_SLOT.label_fixups;
+ fix->dw2_mark_labels = dwarf2_loc_mark_labels;
CURR_SLOT.label_fixups = fix;
/* Keep track of how many code entry points we've seen. */
extern int tc_m68hc11_fix_adjustable (struct fix *);
#define md_operand(x)
-#define tc_frob_label(sym) do {\
- S_SET_VALUE (sym, (valueT) frag_now_fix ()); \
-} while (0)
#define elf_tc_final_processing m68hc11_elf_final_processing
extern void m68hc11_elf_final_processing (void);
n->text = 0;
labels = n;
current_label = n;
+
+#ifdef OBJ_ELF
+ dwarf2_emit_label (sym);
+#endif
}
/* This is called when a value that is not an instruction is emitted. */
l->label = sym;
l->next = insn_labels;
insn_labels = l;
+
+#ifdef OBJ_ELF
+ dwarf2_emit_label (sym);
+#endif
}
\f
#if defined (OBJ_ELF) || defined (OBJ_MAYBE_ELF)
const pseudo_typeS md_pseudo_table[] =
{
{ "word", cons, 4 },
- { "file", (void (*) (int)) dwarf2_directive_file, 0 },
- { "loc", dwarf2_directive_loc, 0 },
{ NULL, NULL, 0 }
};
&symbol_rootP, &symbol_lastP);
symbol_get_tc (ppc_current_csect)->within = sym;
}
+
+#ifdef OBJ_ELF
+ dwarf2_emit_label (sym);
+#endif
}
/* This variable is set by ppc_frob_symbol if any absolute symbols are
emits a BFD_RELOC_SH_LABEL reloc if necessary. */
void
-sh_frob_label (void)
+sh_frob_label (symbolS *sym)
{
static fragS *last_label_frag;
static int last_label_offset;
last_label_offset = offset;
}
}
+
+ dwarf2_emit_label (sym);
}
/* This routine is called when the assembler is about to output some
/* We call a routine to emit a reloc for a label, so that the linker
can align loads and stores without crossing a label. */
-extern void sh_frob_label (void);
-#define tc_frob_label(sym) sh_frob_label ()
+extern void sh_frob_label (symbolS *);
+#define tc_frob_label(sym) sh_frob_label (sym)
/* We call a routine to flush pending output in order to output a DATA
reloc when required. */
#undef tc_frob_label
#define tc_frob_label(sym) \
- do { sh_frob_label (); sh64_frob_label (sym); } while (0)
+ do { sh_frob_label (sym); sh64_frob_label (sym); } while (0)
#define tc_symbol_new_hook(s) sh64_frob_label (s)
xtensa_set_frag_assembly_state (frag_now);
xtensa_move_labels (frag_now, 0, TRUE);
- }
+ }
/* No target aligning in the absolute section. */
if (now_seg != absolute_section
/* Loops only go forward, so they can be identified here. */
if (symbol_get_tc (sym)->is_loop_target)
symbol_get_frag (sym)->tc_frag_data.is_loop_target = TRUE;
+
+ dwarf2_emit_label (sym);
}
@item isa @var{value}
This directive will set the @code{isa} register in the @code{.debug_line}
state machine to @var{value}, which must be an unsigned integer.
+
+@section @code{.loc_mark_blocks @var{enable}}
+@cindex @code{loc_mark_blocks} directive
+The @code{.loc_mark_blocks} directive makes the assembler emit an entry
+to the @code{.debug_line} line number matrix with the @code{basic_block}
+register in the state machine set whenever a code label is seen.
+The @var{enable} argument should be either 1 or 0, to enable or disable
+this function respectively.
+
@end table
@node Data
struct line_entry {
struct line_entry *next;
- fragS *frag;
- addressT frag_ofs;
+ symbolS *label;
struct dwarf2_line_info loc;
};
doing work when there's nothing to do. */
static bfd_boolean loc_directive_seen;
+/* TRUE when we're supposed to set the basic block mark whenever a
+ label is seen. */
+bfd_boolean dwarf2_loc_mark_labels;
+
/* Current location as indicated by the most recent .loc directive. */
static struct dwarf2_line_info current = {
1, 1, 0, 0,
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 void out_set_addr (symbolS *);
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 relax_inc_line_addr (int, symbolS *, symbolS *);
static void process_entries (segT, struct line_entry *);
static void out_file_list (void);
static void out_debug_line (segT);
return ss;
}
+/* Record an entry for LOC occurring at LABEL. */
+
+static void
+dwarf2_gen_line_info_1 (symbolS *label, struct dwarf2_line_info *loc)
+{
+ struct line_subseg *ss;
+ struct line_entry *e;
+
+ e = (struct line_entry *) xmalloc (sizeof (*e));
+ e->next = NULL;
+ e->label = label;
+ e->loc = *loc;
+
+ ss = get_line_subseg (now_seg, now_subseg);
+ *ss->ptail = e;
+ ss->ptail = &e->next;
+}
+
/* Record an entry for LOC occurring at OFS within the current fragment. */
void
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;
+ symbolS *sym;
+
/* Early out for as-yet incomplete location information. */
if (loc->filenum == 0 || loc->line == 0)
return;
line = loc->line;
filenum = loc->filenum;
- e = (struct line_entry *) xmalloc (sizeof (*e));
- e->next = NULL;
- e->frag = frag_now;
- e->frag_ofs = ofs;
- e->loc = *loc;
-
- ss = get_line_subseg (now_seg, now_subseg);
- *ss->ptail = e;
- ss->ptail = &e->next;
+ sym = symbol_temp_new (now_seg, ofs, frag_now);
+ dwarf2_gen_line_info_1 (sym, loc);
}
/* Returns the current source information. If .file directives have
| DWARF2_FLAG_EPILOGUE_BEGIN);
}
+/* Called for each (preferably code) label. If dwarf2_loc_mark_labels
+ is enabled, emit a basic block marker. */
+
+void
+dwarf2_emit_label (symbolS *label)
+{
+ struct dwarf2_line_info loc;
+
+ if (!dwarf2_loc_mark_labels)
+ return;
+ if (S_GET_SEGMENT (label) != now_seg)
+ return;
+ if (!(bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE))
+ return;
+
+ if (debug_type == DEBUG_DWARF2)
+ dwarf2_where (&loc);
+ else
+ {
+ loc = current;
+ loc_directive_seen = FALSE;
+ }
+
+ loc.flags |= DWARF2_FLAG_BASIC_BLOCK;
+
+ current.flags &= ~(DWARF2_FLAG_BASIC_BLOCK
+ | DWARF2_FLAG_PROLOGUE_END
+ | DWARF2_FLAG_EPILOGUE_BEGIN);
+
+ dwarf2_gen_line_info_1 (label, &loc);
+}
+
/* 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. */
demand_empty_rest_of_line ();
loc_directive_seen = TRUE;
}
+
+void
+dwarf2_directive_loc_mark_labels (int dummy ATTRIBUTE_UNUSED)
+{
+ offsetT value = get_absolute_expression ();
+
+ if (value != 0 && value != 1)
+ {
+ as_bad (_("expected 0 or 1"));
+ ignore_rest_of_line ();
+ }
+ else
+ {
+ dwarf2_loc_mark_labels = value != 0;
+ demand_empty_rest_of_line ();
+ }
+}
\f
static struct frag *
first_frag_for_seg (segT seg)
/* Set an absolute address (may result in a relocation entry). */
static void
-out_set_addr (segT seg, fragS *frag, addressT ofs)
+out_set_addr (symbolS *sym)
{
expressionS expr;
- symbolS *sym;
-
- sym = symbol_temp_new (seg, ofs, frag);
out_opcode (DW_LNS_extended_op);
out_uleb128 (sizeof_address + 1);
int need_copy = 0;
char *end = p + len;
+ /* Line number sequences cannot go backward in addresses. This means
+ we've incorrectly ordered the statements in the sequence. */
+ assert ((offsetT) addr_delta >= 0);
+
/* Scale the address delta by the minimum instruction length. */
scale_addr_delta (&addr_delta);
increments between fragments of the target segment. */
static void
-relax_inc_line_addr (int line_delta, segT seg,
- fragS *to_frag, addressT to_ofs,
- fragS *from_frag, addressT from_ofs)
+relax_inc_line_addr (int line_delta, symbolS *to_sym, symbolS *from_sym)
{
- symbolS *to_sym, *from_sym;
expressionS expr;
int max_chars;
- 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;
expr.X_op_symbol = from_sym;
unsigned column = 0;
unsigned isa = 0;
unsigned flags = DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0;
- fragS *frag = NULL;
- fragS *last_frag;
- addressT frag_ofs = 0;
- addressT last_frag_ofs;
+ fragS *last_frag = NULL, *frag;
+ addressT last_frag_ofs = 0, frag_ofs;
+ symbolS *last_lab, *lab;
struct line_entry *next;
while (e)
{
- int changed = 0;
+ int line_delta;
if (filenum != e->loc.filenum)
{
filenum = e->loc.filenum;
out_opcode (DW_LNS_set_file);
out_uleb128 (filenum);
- changed = 1;
}
if (column != e->loc.column)
column = e->loc.column;
out_opcode (DW_LNS_set_column);
out_uleb128 (column);
- changed = 1;
}
if (isa != e->loc.isa)
isa = e->loc.isa;
out_opcode (DW_LNS_set_isa);
out_uleb128 (isa);
- changed = 1;
}
if ((e->loc.flags ^ flags) & DWARF2_FLAG_IS_STMT)
{
flags = e->loc.flags;
out_opcode (DW_LNS_negate_stmt);
- changed = 1;
}
if (e->loc.flags & DWARF2_FLAG_BASIC_BLOCK)
- {
- out_opcode (DW_LNS_set_basic_block);
- changed = 1;
- }
+ out_opcode (DW_LNS_set_basic_block);
if (e->loc.flags & DWARF2_FLAG_PROLOGUE_END)
- {
- out_opcode (DW_LNS_set_prologue_end);
- changed = 1;
- }
+ out_opcode (DW_LNS_set_prologue_end);
if (e->loc.flags & DWARF2_FLAG_EPILOGUE_BEGIN)
- {
- out_opcode (DW_LNS_set_epilogue_begin);
- changed = 1;
- }
+ out_opcode (DW_LNS_set_epilogue_begin);
/* 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)
- {
- out_set_addr (seg, e->frag, e->frag_ofs);
- out_inc_line_addr (line_delta, 0);
- }
- else if (frag == e->frag)
- out_inc_line_addr (line_delta, e->frag_ofs - frag_ofs);
- else
- relax_inc_line_addr (line_delta, seg, e->frag, e->frag_ofs,
- frag, frag_ofs);
+ line_delta = e->loc.line - line;
+ lab = e->label;
+ frag = symbol_get_frag (lab);
+ frag_ofs = S_GET_VALUE (lab);
- frag = e->frag;
- frag_ofs = e->frag_ofs;
- line = e->loc.line;
- }
- else if (frag == NULL)
+ if (last_frag == NULL)
{
- out_set_addr (seg, e->frag, e->frag_ofs);
- frag = e->frag;
- frag_ofs = e->frag_ofs;
+ out_set_addr (lab);
+ out_inc_line_addr (line_delta, 0);
}
+ else if (frag == last_frag)
+ out_inc_line_addr (line_delta, frag_ofs - last_frag_ofs);
+ else
+ relax_inc_line_addr (line_delta, lab, last_lab);
+
+ line = e->loc.line;
+ last_lab = lab;
+ last_frag = frag;
+ last_frag_ofs = frag_ofs;
next = e->next;
free (e);
}
/* Emit a DW_LNE_end_sequence for the end of the section. */
- last_frag = last_frag_for_seg (seg);
- last_frag_ofs = get_frag_fix (last_frag);
+ frag = last_frag_for_seg (seg);
+ frag_ofs = get_frag_fix (frag);
if (frag == last_frag)
- out_inc_line_addr (INT_MAX, last_frag_ofs - frag_ofs);
+ out_inc_line_addr (INT_MAX, frag_ofs - last_frag_ofs);
else
- relax_inc_line_addr (INT_MAX, seg, last_frag, last_frag_ofs,
- frag, frag_ofs);
+ {
+ lab = symbol_temp_new (seg, frag_ofs, frag);
+ relax_inc_line_addr (INT_MAX, lab, last_lab);
+ }
}
/* Emit the directory and file tables for .debug_line. */
used. */
extern void dwarf2_directive_loc (int dummy);
+/* Implements the .loc_mark_labels {0,1} directive. */
+extern void dwarf2_directive_loc_mark_labels (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
/* Must be called for each generated instruction. */
extern void dwarf2_emit_insn (int);
+/* Should be called for each code label. */
+extern void dwarf2_emit_label (symbolS *);
+
+/* True when we're supposed to set the basic block mark whenever a label
+ is seen. Unless the target is doing Something Weird, just call
+ dwarf2_emit_label. */
+bfd_boolean dwarf2_loc_mark_labels;
+
extern void dwarf2_finish (void);
extern int dwarf2dbg_estimate_size_before_relax (fragS *);