diff options
Diffstat (limited to 'gas/dwarf2dbg.c')
-rw-r--r-- | gas/dwarf2dbg.c | 313 |
1 files changed, 304 insertions, 9 deletions
diff --git a/gas/dwarf2dbg.c b/gas/dwarf2dbg.c index e02b6e8..4f70330 100644 --- a/gas/dwarf2dbg.c +++ b/gas/dwarf2dbg.c @@ -162,13 +162,20 @@ #define TC_PARSE_CONS_RETURN_NONE BFD_RELOC_NONE #endif -struct line_entry { +struct line_entry +{ struct line_entry *next; symbolS *label; struct dwarf2_line_info loc; }; -struct line_subseg { +/* Don't change the offset of next in line_entry. set_or_check_view + calls in dwarf2_gen_line_info_1 depend on it. */ +static char unused[offsetof(struct line_entry, next) ? -1 : 1] +ATTRIBUTE_UNUSED; + +struct line_subseg +{ struct line_subseg *next; subsegT subseg; struct line_entry *head; @@ -176,7 +183,8 @@ struct line_subseg { struct line_entry **pmove_tail; }; -struct line_seg { +struct line_seg +{ struct line_seg *next; segT seg; struct line_subseg *head; @@ -188,7 +196,8 @@ struct line_seg { static struct line_seg *all_segs; static struct line_seg **last_seg_ptr; -struct file_entry { +struct file_entry +{ const char *filename; unsigned int dir; }; @@ -212,12 +221,21 @@ bfd_boolean dwarf2_loc_directive_seen; bfd_boolean dwarf2_loc_mark_labels; /* Current location as indicated by the most recent .loc directive. */ -static struct dwarf2_line_info current = { +static struct dwarf2_line_info current = +{ 1, 1, 0, 0, DWARF2_LINE_DEFAULT_IS_STMT ? DWARF2_FLAG_IS_STMT : 0, - 0 + 0, NULL }; +/* This symbol is used to recognize view number forced resets in loc + lists. */ +static symbolS *force_reset_view; + +/* This symbol evaluates to an expression that, if nonzero, indicates + some view assert check failed. */ +static symbolS *view_assert_failed; + /* The size of an address on the target. */ static unsigned int sizeof_address; @@ -283,6 +301,168 @@ get_line_subseg (segT seg, subsegT subseg, bfd_boolean create_p) return lss; } +/* (Un)reverse the line_entry list starting from H. */ + +static struct line_entry * +reverse_line_entry_list (struct line_entry *h) +{ + struct line_entry *p = NULL, *e, *n; + + for (e = h; e; e = n) + { + n = e->next; + e->next = p; + p = e; + } + return p; +} + +/* Compute the view for E based on the previous entry P. If we + introduce an (undefined) view symbol for P, and H is given (P must + be the tail in this case), introduce view symbols for earlier list + entries as well, until one of them is constant. */ + +static void +set_or_check_view (struct line_entry *e, struct line_entry *p, + struct line_entry *h) +{ + expressionS viewx; + + memset (&viewx, 0, sizeof (viewx)); + viewx.X_unsigned = 1; + + /* First, compute !(E->label > P->label), to tell whether or not + we're to reset the view number. If we can't resolve it to a + constant, keep it symbolic. */ + if (!p || (e->loc.view == force_reset_view && force_reset_view)) + { + viewx.X_op = O_constant; + viewx.X_add_number = 0; + viewx.X_add_symbol = NULL; + viewx.X_op_symbol = NULL; + } + else + { + viewx.X_op = O_gt; + viewx.X_add_number = 0; + viewx.X_add_symbol = e->label; + viewx.X_op_symbol = p->label; + resolve_expression (&viewx); + if (viewx.X_op == O_constant) + viewx.X_add_number = !viewx.X_add_number; + else + { + viewx.X_add_symbol = make_expr_symbol (&viewx); + viewx.X_add_number = 0; + viewx.X_op_symbol = NULL; + viewx.X_op = O_logical_not; + } + } + + if (S_IS_DEFINED (e->loc.view) && symbol_constant_p (e->loc.view)) + { + expressionS *value = symbol_get_value_expression (e->loc.view); + /* We can't compare the view numbers at this point, because in + VIEWX we've only determined whether we're to reset it so + far. */ + if (viewx.X_op == O_constant) + { + if (!value->X_add_number != !viewx.X_add_number) + as_bad (_("view number mismatch")); + } + /* Record the expression to check it later. It is the result of + a logical not, thus 0 or 1. We just add up all such deferred + expressions, and resolve it at the end. */ + else if (!value->X_add_number) + { + symbolS *deferred = make_expr_symbol (&viewx); + if (view_assert_failed) + { + expressionS chk; + memset (&chk, 0, sizeof (chk)); + chk.X_unsigned = 1; + chk.X_op = O_add; + chk.X_add_number = 0; + chk.X_add_symbol = view_assert_failed; + chk.X_op_symbol = deferred; + deferred = make_expr_symbol (&chk); + } + view_assert_failed = deferred; + } + } + + if (viewx.X_op != O_constant || viewx.X_add_number) + { + expressionS incv; + + if (!p->loc.view) + { + p->loc.view = symbol_temp_make (); + gas_assert (!S_IS_DEFINED (p->loc.view)); + } + + memset (&incv, 0, sizeof (incv)); + incv.X_unsigned = 1; + incv.X_op = O_symbol; + incv.X_add_symbol = p->loc.view; + incv.X_add_number = 1; + + if (viewx.X_op == O_constant) + { + gas_assert (viewx.X_add_number == 1); + viewx = incv; + } + else + { + viewx.X_add_symbol = make_expr_symbol (&viewx); + viewx.X_add_number = 0; + viewx.X_op_symbol = make_expr_symbol (&incv); + viewx.X_op = O_multiply; + } + } + + if (!S_IS_DEFINED (e->loc.view)) + { + symbol_set_value_expression (e->loc.view, &viewx); + S_SET_SEGMENT (e->loc.view, absolute_section); + symbol_set_frag (e->loc.view, &zero_address_frag); + } + + /* Define and attempt to simplify any earlier views needed to + compute E's. */ + if (h && p && p->loc.view && !S_IS_DEFINED (p->loc.view)) + { + struct line_entry *h2; + /* Reverse the list to avoid quadratic behavior going backwards + in a single-linked list. */ + struct line_entry *r = reverse_line_entry_list (h); + + gas_assert (r == p); + /* Set or check views until we find a defined or absent view. */ + do + set_or_check_view (r, r->next, NULL); + while (r->next && r->next->loc.view && !S_IS_DEFINED (r->next->loc.view) + && (r = r->next)); + + /* Unreverse the list, so that we can go forward again. */ + h2 = reverse_line_entry_list (p); + gas_assert (h2 == h); + + /* Starting from the last view we just defined, attempt to + simplify the view expressions, until we do so to P. */ + do + { + gas_assert (S_IS_DEFINED (r->loc.view)); + resolve_expression (symbol_get_value_expression (r->loc.view)); + } + while (r != p && (r = r->next)); + + /* Now that we've defined and computed all earlier views that might + be needed to compute E's, attempt to simplify it. */ + resolve_expression (symbol_get_value_expression (e->loc.view)); + } +} + /* Record an entry for LOC occurring at LABEL. */ static void @@ -297,6 +477,12 @@ dwarf2_gen_line_info_1 (symbolS *label, struct dwarf2_line_info *loc) e->loc = *loc; lss = get_line_subseg (now_seg, now_subseg, TRUE); + + if (loc->view) + set_or_check_view (e, + !lss->head ? NULL : (struct line_entry *)lss->ptail, + lss->head); + *lss->ptail = e; lss->ptail = &e->next; } @@ -350,12 +536,16 @@ dwarf2_where (struct dwarf2_line_info *line) { if (debug_type == DEBUG_DWARF2) { - const char *filename = as_where (&line->line); + const char *filename; + + memset (line, 0, sizeof (*line)); + filename = as_where (&line->line); line->filenum = get_filenum (filename, 0); line->column = 0; line->flags = DWARF2_FLAG_IS_STMT; line->isa = current.isa; line->discriminator = current.discriminator; + line->view = NULL; } else *line = current; @@ -380,7 +570,9 @@ dwarf2_emit_insn (int size) { struct dwarf2_line_info loc; - if (!dwarf2_loc_directive_seen && debug_type != DEBUG_DWARF2) + if (debug_type != DEBUG_DWARF2 + ? !dwarf2_loc_directive_seen + : !seen_at_least_1_file ()) return; dwarf2_where (&loc); @@ -721,6 +913,54 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED) return; } } + else if (strcmp (p, "view") == 0) + { + symbolS *sym; + + (void) restore_line_pointer (c); + SKIP_WHITESPACE (); + + if (ISDIGIT (*input_line_pointer) + || *input_line_pointer == '-') + { + bfd_boolean force_reset = *input_line_pointer == '-'; + + value = get_absolute_expression (); + if (value != 0) + { + as_bad (_("numeric view can only be asserted to zero")); + return; + } + if (force_reset && force_reset_view) + sym = force_reset_view; + else + { + sym = symbol_temp_new (absolute_section, value, + &zero_address_frag); + if (force_reset) + force_reset_view = sym; + } + } + else + { + char *name = read_symbol_name (); + + if (!name) + return; + sym = symbol_find_or_make (name); + if (S_IS_DEFINED (sym)) + { + if (!S_CAN_BE_REDEFINED (sym)) + as_bad (_("symbol `%s' is already defined"), name); + else + sym = symbol_clone (sym, 1); + S_SET_SEGMENT (sym, undefined_section); + S_SET_VALUE (sym, 0); + symbol_set_frag (sym, &zero_address_frag); + } + } + current.view = sym; + } else { as_bad (_("unknown .loc sub-directive `%s'"), p); @@ -734,6 +974,10 @@ dwarf2_directive_loc (int dummy ATTRIBUTE_UNUSED) demand_empty_rest_of_line (); dwarf2_loc_directive_seen = TRUE; debug_type = DEBUG_NONE; + + /* If we were given a view id, emit the row right away. */ + if (current.view) + dwarf2_emit_insn (0); } void @@ -1362,7 +1606,19 @@ process_entries (segT seg, struct line_entry *e) frag = symbol_get_frag (lab); frag_ofs = S_GET_VALUE (lab); - if (last_frag == NULL) + if (last_frag == NULL + || (e->loc.view == force_reset_view && force_reset_view + /* If we're going to reset the view, but we know we're + advancing the PC, we don't have to force with + set_address. We know we do when we're at the same + address of the same frag, and we know we might when + we're in the beginning of a frag, and we were at the + end of the previous frag. */ + && (frag == last_frag + ? (last_frag_ofs == frag_ofs) + : (frag_ofs == 0 + && ((offsetT)last_frag_ofs + >= get_frag_fix (last_frag, seg)))))) { out_set_addr (lab); out_inc_line_addr (line_delta, 0); @@ -1975,3 +2231,42 @@ dwarf2_finish (void) name_sym, comp_dir_sym, producer_sym); } } + +/* Perform any deferred checks pertaining to debug information. */ + +void +dwarf2dbg_final_check (void) +{ + /* Perform reset-view checks. Don't evaluate view_assert_failed + recursively: it could be very deep. It's a chain of adds, with + each chain element pointing to the next in X_add_symbol, and + holding the check value in X_op_symbol. */ + while (view_assert_failed) + { + expressionS *expr; + symbolS *sym; + offsetT failed; + + gas_assert (!symbol_resolved_p (view_assert_failed)); + + expr = symbol_get_value_expression (view_assert_failed); + sym = view_assert_failed; + + /* If view_assert_failed looks like a compound check in the + chain, break it up. */ + if (expr->X_op == O_add && expr->X_add_number == 0 && expr->X_unsigned) + { + view_assert_failed = expr->X_add_symbol; + sym = expr->X_op_symbol; + } + else + view_assert_failed = NULL; + + failed = resolve_symbol_value (sym); + if (!symbol_resolved_p (sym) || failed) + { + as_bad (_("view number mismatch")); + break; + } + } +} |