Author: ian
Date: Sat May  4 19:50:50 2013
New Revision: 250252
URL: http://svnweb.freebsd.org/changeset/base/250252

Log:
  EABI unwinder enhancements... When it's time to stop unwinding, don't
  exit the loop until after printing info about the current frame.  Also,
  if executing the unwind function for a frame doesn't change the values of
  any registers, log that and exit the loop rather than looping endlessly.

Modified:
  head/sys/arm/arm/db_trace.c

Modified: head/sys/arm/arm/db_trace.c
==============================================================================
--- head/sys/arm/arm/db_trace.c Sat May  4 19:16:26 2013        (r250251)
+++ head/sys/arm/arm/db_trace.c Sat May  4 19:50:50 2013        (r250252)
@@ -342,8 +342,11 @@ db_stack_trace_cmd(struct unwind_state *
        c_db_sym_t sym;
        u_int reg, i;
        char *sep;
+       uint16_t upd_mask;
+       bool finished;
 
-       while (1) {
+       finished = false;
+       while (!finished) {
                /* Reset the mask of updated registers */
                state->update_mask = 0;
 
@@ -353,28 +356,20 @@ db_stack_trace_cmd(struct unwind_state *
                /* Find the item to run */
                index = db_find_index(state->start_pc);
 
-               if (index->insn == EXIDX_CANTUNWIND) {
-                       db_printf("Unable to unwind\n");
-                       break;
-               } else if (index->insn & (1 << 31)) {
-                       /* The data is within the instruction */
-                       state->insn = &index->insn;
-               } else {
-                       /* We have a prel31 offset to the unwind table */
-                       uint32_t prel31_tbl = db_expand_prel31(index->insn);
-
-                       state->insn = (uint32_t *)((uintptr_t)&index->insn +
-                           prel31_tbl);
+               if (index->insn != EXIDX_CANTUNWIND) {
+                       if (index->insn & (1 << 31)) {
+                               /* The data is within the instruction */
+                               state->insn = &index->insn;
+                       } else {
+                               /* A prel31 offset to the unwind table */
+                               state->insn = (uint32_t *)
+                                   ((uintptr_t)&index->insn + 
+                                    db_expand_prel31(index->insn));
+                       }
+                       /* Run the unwind function */
+                       finished = db_unwind_tab(state);
                }
 
-               /* Run the unwind function */
-               if (db_unwind_tab(state) != 0)
-                       break;
-
-               /* This is not a kernel address, stop processing */
-               if (state->registers[PC] < VM_MIN_KERNEL_ADDRESS)
-                       break;
-
                /* Print the frame details */
                sym = db_search_symbol(state->start_pc, DB_STGY_ANY, &offset);
                if (sym == C_DB_SYM_NULL) {
@@ -393,12 +388,11 @@ db_stack_trace_cmd(struct unwind_state *
                    state->registers[SP], state->registers[FP]);
 
                /* Don't print the registers we have already printed */
-               state->update_mask &= ~((1 << SP) | (1 << FP) | (1 << LR) |
-                   (1 << PC));
+               upd_mask = state->update_mask & 
+                   ~((1 << SP) | (1 << FP) | (1 << LR) | (1 << PC));
                sep = "\n\t";
-               for (i = 0, reg = 0; state->update_mask != 0;
-                   state->update_mask >>= 1, reg++) {
-                       if ((state->update_mask & 1) != 0) {
+               for (i = 0, reg = 0; upd_mask != 0; upd_mask >>= 1, reg++) {
+                       if ((upd_mask & 1) != 0) {
                                db_printf("%s%sr%d = 0x%08x", sep,
                                    (reg < 10) ? " " : "", reg,
                                    state->registers[reg]);
@@ -412,6 +406,25 @@ db_stack_trace_cmd(struct unwind_state *
                        }
                }
                db_printf("\n");
+
+               /* Stop if directed to do so, or if we've unwound back to the
+                * kernel entry point, or if the unwind function didn't change
+                * anything (to avoid getting stuck in this loop forever).
+                * If the latter happens, it's an indication that the unwind
+                * information is incorrect somehow for the function named in
+                * the last frame printed before you see the unwind failure
+                * message (maybe it needs a STOP_UNWINDING).
+                */
+               if (index->insn == EXIDX_CANTUNWIND) {
+                       db_printf("Unable to unwind further\n");
+                       finished = true;
+               } else if (state->registers[PC] < VM_MIN_KERNEL_ADDRESS) {
+                       db_printf("Unable to unwind into user mode\n");
+                       finished = true;
+               } else if (state->update_mask == 0) {
+                       db_printf("Unwind failure (no registers changed)\n");
+                       finished = true;
+               }
        }
 }
 #endif
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to