|
|
2c2fa1 |
http://sourceware.org/ml/gdb-patches/2012-04/msg00058.html
|
|
|
2c2fa1 |
Subject: [downstream patch FYI] workaround stale frame_info * (PR 13866)
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
Hi,
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
I did not look at which commit caused this regression but apparently it was
|
|
|
2c2fa1 |
introduced at least with multi-inferiors.
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
I understand this fix is not right fix of the crash; but in most GDB cases one
|
|
|
2c2fa1 |
does not use multi-inferior so why to regress single-inferior by it.
|
|
|
2c2fa1 |
Some more simple solutions still fix the single-inferior mode but they
|
|
|
2c2fa1 |
regressed the multi-inferior mode
|
|
|
2c2fa1 |
gdb.threads/no-unwaited-for-left.exp
|
|
|
2c2fa1 |
gdb.multi/base.exp
|
|
|
2c2fa1 |
so I had to put there that sorting magic.
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
With proper C++ sanity check of stale live frame_info references the testcase
|
|
|
2c2fa1 |
would be simple without the "frame_garbage_collection" reproducer below.
|
|
|
2c2fa1 |
It is also reproducible just with valgrind but regularly running the whole
|
|
|
2c2fa1 |
testsuite under valgrind I did not find feasible.
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
No regressions on {x86_64,x86_64-m32,i686}-fedora17-linux-gnu.
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
Thanks,
|
|
|
2c2fa1 |
Jan
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
gdb/
|
|
|
2c2fa1 |
2012-04-04 Jan Kratochvil <jan.kratochvil@redhat.com>
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
Workaround PR backtrace/13866.
|
|
|
2c2fa1 |
* progspace.c (switch_to_program_space_and_thread): Try not to call
|
|
|
2c2fa1 |
switch_to_thread.
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
--- a/gdb/progspace.c
|
|
|
2c2fa1 |
+++ b/gdb/progspace.c
|
|
|
2c2fa1 |
@@ -481,17 +481,28 @@ save_current_space_and_thread (void)
|
|
|
2c2fa1 |
void
|
|
|
2c2fa1 |
switch_to_program_space_and_thread (struct program_space *pspace)
|
|
|
2c2fa1 |
{
|
|
|
2c2fa1 |
- struct inferior *inf;
|
|
|
2c2fa1 |
+ struct inferior *inf = current_inferior ();
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
- inf = find_inferior_for_program_space (pspace);
|
|
|
2c2fa1 |
+ if (inf->pspace != pspace)
|
|
|
2c2fa1 |
+ inf = find_inferior_for_program_space (pspace);
|
|
|
2c2fa1 |
if (inf != NULL)
|
|
|
2c2fa1 |
{
|
|
|
2c2fa1 |
- struct thread_info *tp;
|
|
|
2c2fa1 |
+ struct thread_info *tp, *current_tp = NULL;
|
|
|
2c2fa1 |
+
|
|
|
2c2fa1 |
+ if (ptid_get_pid (inferior_ptid) == inf->pid)
|
|
|
2c2fa1 |
+ current_tp = find_thread_ptid (inferior_ptid);
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
tp = any_live_thread_of_process (inf->pid);
|
|
|
2c2fa1 |
if (tp != NULL)
|
|
|
2c2fa1 |
{
|
|
|
2c2fa1 |
- switch_to_thread (tp->ptid);
|
|
|
2c2fa1 |
+ /* Prefer primarily thread not THREAD_EXITED and secondarily thread
|
|
|
2c2fa1 |
+ not EXECUTING. */
|
|
|
2c2fa1 |
+ if (current_tp == NULL
|
|
|
2c2fa1 |
+ || (tp->state != THREAD_EXITED
|
|
|
2c2fa1 |
+ && current_tp->state == THREAD_EXITED)
|
|
|
2c2fa1 |
+ || (!tp->executing && current_tp->executing))
|
|
|
2c2fa1 |
+ switch_to_thread (tp->ptid);
|
|
|
2c2fa1 |
+
|
|
|
2c2fa1 |
/* Switching thread switches pspace implicitly. We're
|
|
|
2c2fa1 |
done. */
|
|
|
2c2fa1 |
return;
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
Reproducer with:
|
|
|
2c2fa1 |
./gdb -nx ~/t/thread -ex 'b 24' -ex r -ex 'until 25'
|
|
|
2c2fa1 |
Breakpoint 1, main () at /home/jkratoch/t/thread.c:24
|
|
|
2c2fa1 |
24 v++;
|
|
|
2c2fa1 |
Segmentation fault (core dumped)
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
#include <pthread.h>
|
|
|
2c2fa1 |
#include <assert.h>
|
|
|
2c2fa1 |
#include <unistd.h>
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
static int v;
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
static void *start (void *arg)
|
|
|
2c2fa1 |
{
|
|
|
2c2fa1 |
v++;
|
|
|
2c2fa1 |
v++;
|
|
|
2c2fa1 |
v++;
|
|
|
2c2fa1 |
v++;
|
|
|
2c2fa1 |
sleep (100);
|
|
|
2c2fa1 |
return arg;
|
|
|
2c2fa1 |
}
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
int main (void)
|
|
|
2c2fa1 |
{
|
|
|
2c2fa1 |
pthread_t thread1;
|
|
|
2c2fa1 |
int i;
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
i = pthread_create (&thread1, NULL, start, NULL);
|
|
|
2c2fa1 |
assert (i == 0);
|
|
|
2c2fa1 |
v++;
|
|
|
2c2fa1 |
v++;
|
|
|
2c2fa1 |
v++;
|
|
|
2c2fa1 |
v++;
|
|
|
2c2fa1 |
i = pthread_join (thread1, NULL);
|
|
|
2c2fa1 |
assert (i == 0);
|
|
|
2c2fa1 |
|
|
|
2c2fa1 |
return 0;
|
|
|
2c2fa1 |
}
|
|
|
2c2fa1 |
### --- a/gdb/frame.c
|
|
|
2c2fa1 |
### +++ b/gdb/frame.c
|
|
|
2c2fa1 |
### @@ -1522,12 +1522,30 @@ frame_observer_target_changed (struct target_ops *target)
|
|
|
2c2fa1 |
### reinit_frame_cache ();
|
|
|
2c2fa1 |
### }
|
|
|
2c2fa1 |
###
|
|
|
2c2fa1 |
### +typedef struct obstack obstack_s;
|
|
|
2c2fa1 |
### +DEF_VEC_O (obstack_s);
|
|
|
2c2fa1 |
### +static VEC (obstack_s) *frame_poison_vec;
|
|
|
2c2fa1 |
### +
|
|
|
2c2fa1 |
### +void frame_garbage_collection (void);
|
|
|
2c2fa1 |
### +void
|
|
|
2c2fa1 |
### +frame_garbage_collection (void)
|
|
|
2c2fa1 |
### +{
|
|
|
2c2fa1 |
### + struct obstack *obstack_p;
|
|
|
2c2fa1 |
### + int ix;
|
|
|
2c2fa1 |
### +
|
|
|
2c2fa1 |
### + for (ix = 0; VEC_iterate (obstack_s, frame_poison_vec, ix, obstack_p); ix++)
|
|
|
2c2fa1 |
### + obstack_free (obstack_p, 0);
|
|
|
2c2fa1 |
### +
|
|
|
2c2fa1 |
### + VEC_free (obstack_s, frame_poison_vec);
|
|
|
2c2fa1 |
### + frame_poison_vec = NULL;
|
|
|
2c2fa1 |
### +}
|
|
|
2c2fa1 |
### +
|
|
|
2c2fa1 |
### /* Flush the entire frame cache. */
|
|
|
2c2fa1 |
###
|
|
|
2c2fa1 |
### void
|
|
|
2c2fa1 |
### reinit_frame_cache (void)
|
|
|
2c2fa1 |
### {
|
|
|
2c2fa1 |
### - struct frame_info *fi;
|
|
|
2c2fa1 |
### + struct frame_info *fi, *fi_prev;
|
|
|
2c2fa1 |
###
|
|
|
2c2fa1 |
### /* Tear down all frame caches. */
|
|
|
2c2fa1 |
### for (fi = current_frame; fi != NULL; fi = fi->prev)
|
|
|
2c2fa1 |
### @@ -1538,8 +1556,14 @@ reinit_frame_cache (void)
|
|
|
2c2fa1 |
### fi->base->unwind->dealloc_cache (fi, fi->base_cache);
|
|
|
2c2fa1 |
### }
|
|
|
2c2fa1 |
###
|
|
|
2c2fa1 |
### + for (fi = current_frame; fi != NULL; fi = fi_prev)
|
|
|
2c2fa1 |
### + {
|
|
|
2c2fa1 |
### + fi_prev = fi->prev;
|
|
|
2c2fa1 |
### + memset (fi, 0, sizeof (*fi));
|
|
|
2c2fa1 |
### + }
|
|
|
2c2fa1 |
### + VEC_safe_push (obstack_s, frame_poison_vec, &frame_cache_obstack);
|
|
|
2c2fa1 |
### +
|
|
|
2c2fa1 |
### /* Since we can't really be sure what the first object allocated was. */
|
|
|
2c2fa1 |
### - obstack_free (&frame_cache_obstack, 0);
|
|
|
2c2fa1 |
### obstack_init (&frame_cache_obstack);
|
|
|
2c2fa1 |
###
|
|
|
2c2fa1 |
### if (current_frame != NULL)
|
|
|
2c2fa1 |
### --- a/gdb/top.c
|
|
|
2c2fa1 |
### +++ b/gdb/top.c
|
|
|
2c2fa1 |
### @@ -359,6 +359,11 @@ prepare_execute_command (void)
|
|
|
2c2fa1 |
### if (non_stop)
|
|
|
2c2fa1 |
### target_dcache_invalidate ();
|
|
|
2c2fa1 |
###
|
|
|
2c2fa1 |
### + {
|
|
|
2c2fa1 |
### + extern void frame_garbage_collection (void);
|
|
|
2c2fa1 |
### + frame_garbage_collection ();
|
|
|
2c2fa1 |
### + }
|
|
|
2c2fa1 |
### +
|
|
|
2c2fa1 |
### return cleanup;
|
|
|
2c2fa1 |
### }
|
|
|
2c2fa1 |
###
|