This patch introduces support for specifing views in .loc directives, so that the...
[deliverable/binutils-gdb.git] / gas / dwarf2dbg.c
index e02b6e8f020fa19c7e6d912f6ad67f86080e8785..4f703304d5294978127fe49292fc2159038f57b0 100644 (file)
 #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;
 \f
@@ -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;
+       }
+    }
+}
This page took 0.03509 seconds and 4 git commands to generate.