Add a TRY_CATCH to get_prev_frame_always to better manage errors during unwind.
authorAndrew Burgess <aburgess@broadcom.com>
Wed, 28 May 2014 22:34:43 +0000 (23:34 +0100)
committerAndrew Burgess <aburgess@broadcom.com>
Fri, 30 May 2014 21:44:36 +0000 (22:44 +0100)
  https://sourceware.org/ml/gdb-patches/2014-05/msg00737.html

Currently a MEMORY_ERROR raised during unwinding a frame will cause the
unwind to stop with an error message, for example:

  (gdb) bt
  #0  breakpt () at amd64-invalid-stack-middle.c:27
  #1  0x00000000004008f0 in func5 () at amd64-invalid-stack-middle.c:32
  #2  0x0000000000400900 in func4 () at amd64-invalid-stack-middle.c:38
  #3  0x0000000000400910 in func3 () at amd64-invalid-stack-middle.c:44
  #4  0x0000000000400928 in func2 () at amd64-invalid-stack-middle.c:50
  Cannot access memory at address 0x2aaaaaab0000

However, frame #4 is marked as being the end of the stack unwind, so a
subsequent request for the backtrace looses the error message, such as:

  (gdb) bt
  #0  breakpt () at amd64-invalid-stack-middle.c:27
  #1  0x00000000004008f0 in func5 () at amd64-invalid-stack-middle.c:32
  #2  0x0000000000400900 in func4 () at amd64-invalid-stack-middle.c:38
  #3  0x0000000000400910 in func3 () at amd64-invalid-stack-middle.c:44
  #4  0x0000000000400928 in func2 () at amd64-invalid-stack-middle.c:50

When fetching the backtrace, or requesting the stack depth using the MI
interface the situation is even worse, the first time a request is made
we encounter the memory error and so the MI returns an error instead of
the correct result, for example:

  (gdb) -stack-info-depth
  ^error,msg="Cannot access memory at address 0x2aaaaaab0000"

Or,

  (gdb) -stack-list-frames
  ^error,msg="Cannot access memory at address 0x2aaaaaab0000"

However, once one of these commands has been used gdb has, internally,
walked the stack and figured that out that frame #4 is the bottom of the
stack, so the second time an MI command is tried you'll get the "expected"
result:

  (gdb) -stack-info-depth
  ^done,depth="5"

Or,

  (gdb) -stack-list-frames
  ^done,stack=[frame={level="0", .. snip lots .. }]

After this patch the MEMORY_ERROR encountered during the frame unwind is
attached to frame #4 as the stop reason, and is displayed in the CLI each
time the backtrace is requested.  In the MI, catching the error means that
the "expected" result is returned the first time the MI command is issued.
So, from the CLI the results of the backtrace will be:

  (gdb) bt
  #0  breakpt () at amd64-invalid-stack-middle.c:27
  #1  0x00000000004008f0 in func5 () at amd64-invalid-stack-middle.c:32
  #2  0x0000000000400900 in func4 () at amd64-invalid-stack-middle.c:38
  #3  0x0000000000400910 in func3 () at amd64-invalid-stack-middle.c:44
  #4  0x0000000000400928 in func2 () at amd64-invalid-stack-middle.c:50
  Backtrace stopped: Cannot access memory at address 0x2aaaaaab0000

Each and every time that the backtrace is requested, while the MI output
will similarly be consistently:

  (gdb) -stack-info-depth
  ^done,depth="5"

Or,

  (gdb) -stack-list-frames
  ^done,stack=[frame={level="0", .. snip lots .. }]

gdb/ChangeLog:

* frame.c (struct frame_info): Add stop_string field.
(get_prev_frame_always_1): Renamed from get_prev_frame_always.
(get_prev_frame_always): Old content moved into
get_prev_frame_always_1.  Call get_prev_frame_always_1 inside
TRY_CATCH, handle MEMORY_ERROR exceptions.
(frame_stop_reason_string): New function definition.
* frame.h (unwind_stop_reason_to_string): Extend comment to
mention frame_stop_reason_string.
(frame_stop_reason_string): New function declaration.
* stack.c (frame_info): Switch to frame_stop_reason_string.
(backtrace_command_1): Switch to frame_stop_reason_string.
* unwind_stop_reason.def: Add UNWIND_MEMORY_ERROR.
(LAST_ENTRY): Changed to UNWIND_MEMORY_ERROR.
* guile/lib/gdb.scm: Add FRAME_UNWIND_MEMORY_ERROR to export list.

gdb/doc/ChangeLog:

* guile.texi (Frames In Guile): Mention FRAME_UNWIND_MEMORY_ERROR.
* python.texi (Frames In Python): Mention
gdb.FRAME_UNWIND_MEMORY_ERROR.

gdb/testsuite/ChangeLog:

* gdb.arch/amd64-invalid-stack-middle.exp: Update expected results.
* gdb.arch/amd64-invalid-stack-top.exp: Likewise.

12 files changed:
gdb/ChangeLog
gdb/doc/ChangeLog
gdb/doc/guile.texi
gdb/doc/python.texi
gdb/frame.c
gdb/frame.h
gdb/guile/lib/gdb.scm
gdb/stack.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
gdb/testsuite/gdb.arch/amd64-invalid-stack-top.exp
gdb/unwind_stop_reasons.def

index 11c13643e3a906060fb9e8f1f35af6bafc4d8511..04e368c61a7915d1a9eae95f9765208e7101c645 100644 (file)
@@ -1,3 +1,20 @@
+2014-05-30  Andrew Burgess  <aburgess@broadcom.com>
+
+       * frame.c (struct frame_info): Add stop_string field.
+       (get_prev_frame_always_1): Renamed from get_prev_frame_always.
+       (get_prev_frame_always): Old content moved into
+       get_prev_frame_always_1.  Call get_prev_frame_always_1 inside
+       TRY_CATCH, handle MEMORY_ERROR exceptions.
+       (frame_stop_reason_string): New function definition.
+       * frame.h (unwind_stop_reason_to_string): Extend comment to
+       mention frame_stop_reason_string.
+       (frame_stop_reason_string): New function declaration.
+       * stack.c (frame_info): Switch to frame_stop_reason_string.
+       (backtrace_command_1): Switch to frame_stop_reason_string.
+       * unwind_stop_reason.def: Add UNWIND_MEMORY_ERROR.
+       (LAST_ENTRY): Changed to UNWIND_MEMORY_ERROR.
+       * guile/lib/gdb.scm: Add FRAME_UNWIND_MEMORY_ERROR to export list.
+
 2014-05-30  Andrew Burgess  <aburgess@broadcom.com>
 
        * frame.c (frame_stop_reason_string): Rename to ...
index 18fb24186974b93d17830796cac5b35a38c2e73f..1a07a82cce11ab3908693d967ba143bcfa619287 100644 (file)
@@ -1,3 +1,9 @@
+2014-05-30  Andrew Burgess  <aburgess@broadcom.com>
+
+       * guile.texi (Frames In Guile): Mention FRAME_UNWIND_MEMORY_ERROR.
+       * python.texi (Frames In Python): Mention
+       gdb.FRAME_UNWIND_MEMORY_ERROR.
+
 2014-05-29  Pedro Alves  <palves@redhat.com>
            Tom Tromey  <tromey@redhat.com>
 
index 3e03c7cea73f3a5f286e63bdb33db27cbf129d39..bc2a2ce46a0d077e515a2a03b9b0bad481809959 100644 (file)
@@ -1827,6 +1827,9 @@ stack corruption.
 The frame unwinder did not find any saved PC, but we needed
 one to unwind further.
 
+@item FRAME_UNWIND_MEMORY_ERROR
+The frame unwinder caused an error while trying to access memory.
+
 @item FRAME_UNWIND_FIRST_ERROR
 Any stop reason greater or equal to this value indicates some kind
 of error.  This special value facilitates writing code that tests
index ce8ec78f5b682d9ca594b64c4045299a598a1ce5..006b8733ec3a0944fb4b14d5767b0cd1b5e87a4a 100644 (file)
@@ -3199,6 +3199,9 @@ stack corruption.
 The frame unwinder did not find any saved PC, but we needed
 one to unwind further.
 
+@item gdb.FRAME_UNWIND_MEMORY_ERROR
+The frame unwinder caused an error while trying to access memory.
+
 @item gdb.FRAME_UNWIND_FIRST_ERROR
 Any stop reason greater or equal to this value indicates some kind
 of error.  This special value facilitates writing code that tests
index f44cf5086445f434f53d24f4d6a5891caf2d0ce5..8dea9c4dff0b00f946135c9f339c416754a79f66 100644 (file)
@@ -145,6 +145,10 @@ struct frame_info
   /* The reason why we could not set PREV, or UNWIND_NO_REASON if we
      could.  Only valid when PREV_P is set.  */
   enum unwind_stop_reason stop_reason;
+
+  /* A frame specific string describing the STOP_REASON in more detail.
+     Only valid when PREV_P is set, but even then may still be NULL.  */
+  const char *stop_string;
 };
 
 /* A frame stash used to speed up frame lookups.  Create a hash table
@@ -1798,14 +1802,12 @@ get_prev_frame_if_no_cycle (struct frame_info *this_frame)
   return prev_frame;
 }
 
-/* Return a "struct frame_info" corresponding to the frame that called
-   THIS_FRAME.  Returns NULL if there is no such frame.
-
-   Unlike get_prev_frame, this function always tries to unwind the
-   frame.  */
+/* Helper function for get_prev_frame_always, this is called inside a
+   TRY_CATCH block.  Return the frame that called THIS_FRAME or NULL if
+   there is no such frame.  This may throw an exception.  */
 
-struct frame_info *
-get_prev_frame_always (struct frame_info *this_frame)
+static struct frame_info *
+get_prev_frame_always_1 (struct frame_info *this_frame)
 {
   struct gdbarch *gdbarch;
 
@@ -1955,6 +1957,50 @@ get_prev_frame_always (struct frame_info *this_frame)
   return get_prev_frame_if_no_cycle (this_frame);
 }
 
+/* Return a "struct frame_info" corresponding to the frame that called
+   THIS_FRAME.  Returns NULL if there is no such frame.
+
+   Unlike get_prev_frame, this function always tries to unwind the
+   frame.  */
+
+struct frame_info *
+get_prev_frame_always (struct frame_info *this_frame)
+{
+  volatile struct gdb_exception ex;
+  struct frame_info *prev_frame = NULL;
+
+  TRY_CATCH (ex, RETURN_MASK_ERROR)
+    {
+      prev_frame = get_prev_frame_always_1 (this_frame);
+    }
+  if (ex.reason < 0)
+    {
+      if (ex.error == MEMORY_ERROR)
+       {
+         this_frame->stop_reason = UNWIND_MEMORY_ERROR;
+         if (ex.message != NULL)
+           {
+             char *stop_string;
+             size_t size;
+
+             /* The error needs to live as long as the frame does.
+                Allocate using stack local STOP_STRING then assign the
+                pointer to the frame, this allows the STOP_STRING on the
+                frame to be of type 'const char *'.  */
+             size = strlen (ex.message) + 1;
+             stop_string = frame_obstack_zalloc (size);
+             memcpy (stop_string, ex.message, size);
+             this_frame->stop_string = stop_string;
+           }
+         prev_frame = NULL;
+       }
+      else
+       throw_exception (ex);
+    }
+
+  return prev_frame;
+}
+
 /* Construct a new "struct frame_info" and link it previous to
    this_frame.  */
 
@@ -2576,6 +2622,20 @@ unwind_stop_reason_to_string (enum unwind_stop_reason reason)
     }
 }
 
+const char *
+frame_stop_reason_string (struct frame_info *fi)
+{
+  gdb_assert (fi->prev_p);
+  gdb_assert (fi->prev == NULL);
+
+  /* Return the specific string if we have one.  */
+  if (fi->stop_string != NULL)
+    return fi->stop_string;
+
+  /* Return the generic string if we have nothing better.  */
+  return unwind_stop_reason_to_string (fi->stop_reason);
+}
+
 /* Return the enum symbol name of REASON as a string, to use in debug
    output.  */
 
index 79881521d7a9472d59e3cd4c1ef4228ae5421fc4..59564f9f6609e4e3aebff03e64e841d28fec7307 100644 (file)
@@ -501,10 +501,23 @@ enum unwind_stop_reason
 
 enum unwind_stop_reason get_frame_unwind_stop_reason (struct frame_info *);
 
-/* Translate a reason code to an informative string.  */
+/* Translate a reason code to an informative string.  This converts the
+   generic stop reason codes into a generic string describing the code.
+   For a possibly frame specific string explaining the stop reason, use
+   FRAME_STOP_REASON_STRING instead.  */
 
 const char *unwind_stop_reason_to_string (enum unwind_stop_reason);
 
+/* Return a possibly frame specific string explaining why the unwind
+   stopped here.  E.g., if unwinding tripped on a memory error, this
+   will return the error description string, which includes the address
+   that we failed to access.  If there's no specific reason stored for
+   a frame then a generic reason string will be returned.
+
+   Should only be called for frames that don't have a previous frame.  */
+
+const char *frame_stop_reason_string (struct frame_info *);
+
 /* Unwind the stack frame so that the value of REGNUM, in the previous
    (up, older) frame is returned.  If VALUEP is NULL, don't
    fetch/compute the value.  Instead just return the location of the
index ec739c7e30c7179d272096642d55c2a494b695ec..abc4a67b45d5f11526d4ae8888ff83d6b654b521 100644 (file)
  FRAME_UNWIND_INNER_ID
  FRAME_UNWIND_SAME_ID
  FRAME_UNWIND_NO_SAVED_PC
+ FRAME_UNWIND_MEMORY_ERROR
 
  frame?
  frame-valid?
index 630a3637fd4e64cd5c480dd8f52ed399fe005779..4f16238e95b7e4488b585d7194171584bf1a5f11 100644 (file)
@@ -1529,7 +1529,7 @@ frame_info (char *addr_exp, int from_tty)
       reason = get_frame_unwind_stop_reason (fi);
       if (reason != UNWIND_NO_REASON)
        printf_filtered (_(" Outermost frame: %s\n"),
-                        unwind_stop_reason_to_string (reason));
+                        frame_stop_reason_string (fi));
     }
   else if (get_frame_type (fi) == TAILCALL_FRAME)
     puts_filtered (" tail call frame");
@@ -1848,7 +1848,7 @@ backtrace_command_1 (char *count_exp, int show_locals, int no_filters,
          reason = get_frame_unwind_stop_reason (trailing);
          if (reason >= UNWIND_FIRST_ERROR)
            printf_filtered (_("Backtrace stopped: %s\n"),
-                            unwind_stop_reason_to_string (reason));
+                            frame_stop_reason_string (trailing));
        }
     }
 }
index a8a98f560250f449ebe5fd8e338aed7f922477d8..a931862ad5695a507ba48a4d69fb7d133ce3030c 100644 (file)
@@ -1,3 +1,9 @@
+2014-05-30  Andrew Burgess  <aburgess@broadcom.com>
+
+       * gdb.arch/amd64-invalid-stack-middle.exp: Update expected
+       results.
+       * gdb.arch/amd64-invalid-stack-top.exp: Likewise.
+
 2014-05-30  Andrew Burgess  <aburgess@broadcom.com>
 
        * gdb.arch/amd64-invalid-stack-middle.S: New file.
index 8ad5b18c4f2b3299460cd475a09809e8fc707691..b53ad419112f3f16ece09a6f16171a67412ea583 100644 (file)
@@ -43,27 +43,11 @@ if ![runto breakpt] {
     return -1
 }
 
-gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
         "first backtrace, with error message"
 
-send_gdb "bt\n"
-gdb_expect {
-    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
-       # Currently gdb will not display the error message associated with
-       # the truncated backtrace after the first backtrace has been
-       # completed.  Ideally, we would do this.  If this case is ever hit
-       # then we have started to display the backtrace in all cases and
-       # the xpass should becomd a pass, and the previous pass case below
-       # should be removed, or changed to a fail.
-       xpass "second backtrace, with error message"
-    }
-    -re "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\n$gdb_prompt $" {
-       pass "second backtrace, without error message"
-    }
-    timeout {
-       fail "second backtrace (timeout)"
-    }
-}
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
+        "second backtrace, with error message"
 
 clean_restart ${binfile}
 
@@ -71,16 +55,9 @@ if ![runto breakpt] {
     return -1
 }
 
-set test_name "check mi -stack-info-depth command, first time"
-send_gdb "interpreter-exec mi \"-stack-info-depth\"\n"
-gdb_expect {
-    -re "\\^done,depth=\"4\"\r\n$gdb_prompt $" {
-       pass $test_name
-    }
-    -re "\\^error,msg=\"Cannot access memory at address $hex\"\r\n$gdb_prompt $" {
-       xfail $test_name
-    }
-}
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"4\"" \
+    "check mi -stack-info-depth command, first time"
 
 gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
     "\\^done,depth=\"4\"" \
@@ -92,16 +69,9 @@ if ![runto breakpt] {
     return -1
 }
 
-set test_name "check mi -stack-list-frames command, first time"
-send_gdb "interpreter-exec mi \"-stack-list-frames\"\n"
-gdb_expect {
-    -re "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"breakpt\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"func5\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"func4\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"3\",addr=\"$hex\",func=\"func3\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\}\\\]\r\n$gdb_prompt $" {
-       pass $test_name
-    }
-    -re "\\^error,msg=\"Cannot access memory at address $hex\"\r\n$gdb_prompt $" {
-       xfail $test_name
-    }
-}
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"breakpt\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"func5\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"func4\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"3\",addr=\"$hex\",func=\"func3\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\}\\\]" \
+    "check mi -stack-list-frames command, first time"
 
 gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
     "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"breakpt\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"1\",addr=\"$hex\",func=\"func5\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"2\",addr=\"$hex\",func=\"func4\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\},frame=\{level=\"3\",addr=\"$hex\",func=\"func3\",file=\"\[^\"\]+\",fullname=\"\[^\"\]+\",line=\"${decimal}\"\}\\\]" \
index 0225326331b1fe5c54977e4c15a55a3a0dadb825..17c79d7ca0b5d886caed513e6ea70713e3abf9d1 100644 (file)
@@ -45,27 +45,11 @@ if ![runto breakpt] {
 # Use 'bt no-filters' here as the python filters will raise their own
 # error during initialisation, the no-filters case is simpler.
 
-gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+" \
+gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
         "first backtrace, with error message"
 
-send_gdb "bt no-filters\n"
-gdb_expect {
-    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nCannot access memory at address 0x\[0-9a-f\]+\r\n$gdb_prompt $" {
-       # Currently gdb will not display the error message associated with
-       # the truncated backtrace after the first backtrace has been
-       # completed.  Ideally, we would do this.  If this case is ever hit
-       # then we have started to display the backtrace in all cases and
-       # the xpass should becomd a pass, and the previous pass case below
-       # should be removed, or changed to a fail.
-       xpass "second backtrace, with error message"
-    }
-    -re "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\n$gdb_prompt $" {
-       pass "second backtrace, without error message"
-    }
-    timeout {
-       fail "second backtrace (timeout)"
-    }
-}
+gdb_test "bt no-filters" "^bt no-filters\r\n#0 +$hex in func2 \\(\\)\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
+        "second backtrace, with error message"
 
 clean_restart ${binfile}
 
@@ -73,16 +57,9 @@ if ![runto breakpt] {
     return -1
 }
 
-set test_name "check mi -stack-info-depth command, first time"
-send_gdb "interpreter-exec mi \"-stack-info-depth\"\n"
-gdb_expect {
-    -re "\\^done,depth=\"1\"\r\n$gdb_prompt $" {
-       pass $test_name
-    }
-    -re "\\^error,msg=\"Cannot access memory at address $hex\"\r\n$gdb_prompt $" {
-       xfail $test_name
-    }
-}
+gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
+    "\\^done,depth=\"1\"" \
+    "check mi -stack-info-depth command, first time"
 
 gdb_test "interpreter-exec mi \"-stack-info-depth\"" \
     "\\^done,depth=\"1\"" \
@@ -94,17 +71,9 @@ if ![runto breakpt] {
     return -1
 }
 
-set test_name "check mi -stack-list-frames command, first time"
-send_gdb "interpreter-exec mi \"-stack-list-frames\"\n"
-gdb_expect {
-    -re "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"func2\"\}\\\]\r\n$gdb_prompt $" {
-       pass $test_name
-    }
-    -re "\\^error,msg=\"Cannot access memory at address $hex\"\r\n$gdb_prompt $" {
-       xfail $test_name
-    }
-}
-
+gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
+    "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"func2\"\}\\\]" \
+    "check mi -stack-list-frames command, first time"
 
 gdb_test "interpreter-exec mi \"-stack-list-frames\"" \
     "\\^done,stack=\\\[frame=\{level=\"0\",addr=\"$hex\",func=\"func2\"\}\\\]" \
index d7da7eadaccbc1dceb119b08ba71f7eb943f5a5c..8cef53708c5e2596c5bccb83db460e7b0d298684 100644 (file)
@@ -60,6 +60,9 @@ SET (UNWIND_SAME_ID, "previous frame identical to this frame (corrupt stack?)")
    one to unwind further.  */
 SET (UNWIND_NO_SAVED_PC, "frame did not save the PC")
 
+/* There was an error accessing memory while unwinding this frame.  */
+SET (UNWIND_MEMORY_ERROR, "memory error while unwinding")
+
 #endif /* SET */
 
 
@@ -72,5 +75,5 @@ FIRST_ENTRY (UNWIND_NO_REASON)
 #endif
 
 #ifdef LAST_ENTRY
-LAST_ENTRY (UNWIND_NO_SAVED_PC)
+LAST_ENTRY (UNWIND_MEMORY_ERROR)
 #endif