From 42bfe59e3a3fef26be6809168756f40740fac1d0 Mon Sep 17 00:00:00 2001 From: Tim Wiederhake Date: Tue, 30 May 2017 12:47:37 +0200 Subject: [PATCH] btrace: Replace struct btrace_function::up. This used to hold a function segment pointer. Change it to hold an index into the vector of function segments instead. --- gdb/ChangeLog | 15 +++++ gdb/btrace.c | 141 ++++++++++++++++++++++++++---------------- gdb/btrace.h | 6 +- gdb/python/py-record-btrace.c | 4 +- gdb/record-btrace.c | 28 ++++++--- 5 files changed, 130 insertions(+), 64 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index b20cb01..b035358 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,20 @@ 2017-05-30 Tim Wiederhake + * btrace.c (ftrace_find_call_by_number): New function. + (ftrace_update_caller, ftrace_new_call, ftrace_new_tailcall, + ftrace_get_caller, ftrace_find_call, ftrace_new_return, + ftrace_match_backtrace, ftrace_connect_bfun, ftrace_connect_backtrace, + ftrace_bridge_gap, btrace_bridge_gaps): Use btrace_function::up as an + index. + * btrace.h (struct btrace_function): Turn UP into an index. + * python/py-record-btrace.c (btpy_call_up): Use btrace_function::up + as an index. + * record-btrace.c (record_btrace_frame_unwind_stop_reason, + record_btrace_frame_prev_register, record_btrace_frame_sniffer, + record_btrace_tailcall_frame_sniffe): Use btrace_find_call_by_number. + +2017-05-30 Tim Wiederhake + * btrace.c (ftrace_new_function, ftrace_new_call, ftrace_new_tailcall, ftrace_new_return, ftrace_new_switch, ftrace_new_gap, ftrace_update_function, ftrace_compute_global_level_offset, diff --git a/gdb/btrace.c b/gdb/btrace.c index 4110c78..f0b8eeb 100644 --- a/gdb/btrace.c +++ b/gdb/btrace.c @@ -156,6 +156,19 @@ ftrace_call_num_insn (const struct btrace_function* bfun) return VEC_length (btrace_insn_s, bfun->insn); } +/* Return the function segment with the given NUMBER or NULL if no such segment + exists. BTINFO is the branch trace information for the current thread. */ + +static struct btrace_function * +ftrace_find_call_by_number (const struct btrace_thread_info *btinfo, + unsigned int number) +{ + if (number == 0 || number > btinfo->functions.size ()) + return NULL; + + return btinfo->functions[number - 1]; +} + /* Return non-zero if BFUN does not match MFUN and FUN, return zero otherwise. */ @@ -249,10 +262,10 @@ ftrace_update_caller (struct btrace_function *bfun, struct btrace_function *caller, enum btrace_function_flag flags) { - if (bfun->up != NULL) + if (bfun->up != 0) ftrace_debug (bfun, "updating caller"); - bfun->up = caller; + bfun->up = caller->number; bfun->flags = flags; ftrace_debug (bfun, "set caller"); @@ -290,8 +303,7 @@ ftrace_new_call (struct btrace_thread_info *btinfo, const unsigned int length = btinfo->functions.size (); struct btrace_function *bfun = ftrace_new_function (btinfo, mfun, fun); - if (length != 0) - bfun->up = btinfo->functions[length - 1]; + bfun->up = length; bfun->level += 1; ftrace_debug (bfun, "new call"); @@ -311,8 +323,7 @@ ftrace_new_tailcall (struct btrace_thread_info *btinfo, const unsigned int length = btinfo->functions.size (); struct btrace_function *bfun = ftrace_new_function (btinfo, mfun, fun); - if (length != 0) - bfun->up = btinfo->functions[length - 1]; + bfun->up = length; bfun->level += 1; bfun->flags |= BFUN_UP_LINKS_TO_TAILCALL; @@ -322,26 +333,30 @@ ftrace_new_tailcall (struct btrace_thread_info *btinfo, } /* Return the caller of BFUN or NULL if there is none. This function skips - tail calls in the call chain. */ + tail calls in the call chain. BTINFO is the branch trace information for + the current thread. */ static struct btrace_function * -ftrace_get_caller (struct btrace_function *bfun) +ftrace_get_caller (struct btrace_thread_info *btinfo, + struct btrace_function *bfun) { - for (; bfun != NULL; bfun = bfun->up) + for (; bfun != NULL; bfun = ftrace_find_call_by_number (btinfo, bfun->up)) if ((bfun->flags & BFUN_UP_LINKS_TO_TAILCALL) == 0) - return bfun->up; + return ftrace_find_call_by_number (btinfo, bfun->up); return NULL; } /* Find the innermost caller in the back trace of BFUN with MFUN/FUN - symbol information. */ + symbol information. BTINFO is the branch trace information for the current + thread. */ static struct btrace_function * -ftrace_find_caller (struct btrace_function *bfun, +ftrace_find_caller (struct btrace_thread_info *btinfo, + struct btrace_function *bfun, struct minimal_symbol *mfun, struct symbol *fun) { - for (; bfun != NULL; bfun = bfun->up) + for (; bfun != NULL; bfun = ftrace_find_call_by_number (btinfo, bfun->up)) { /* Skip functions with incompatible symbol information. */ if (ftrace_function_switched (bfun, mfun, fun)) @@ -356,12 +371,14 @@ ftrace_find_caller (struct btrace_function *bfun, /* Find the innermost caller in the back trace of BFUN, skipping all function segments that do not end with a call instruction (e.g. - tail calls ending with a jump). */ + tail calls ending with a jump). BTINFO is the branch trace information for + the current thread. */ static struct btrace_function * -ftrace_find_call (struct btrace_function *bfun) +ftrace_find_call (struct btrace_thread_info *btinfo, + struct btrace_function *bfun) { - for (; bfun != NULL; bfun = bfun->up) + for (; bfun != NULL; bfun = ftrace_find_call_by_number (btinfo, bfun->up)) { struct btrace_insn *last; @@ -395,7 +412,8 @@ ftrace_new_return (struct btrace_thread_info *btinfo, /* It is important to start at PREV's caller. Otherwise, we might find PREV itself, if PREV is a recursive function. */ - caller = ftrace_find_caller (prev->up, mfun, fun); + caller = ftrace_find_call_by_number (btinfo, prev->up); + caller = ftrace_find_caller (btinfo, caller, mfun, fun); if (caller != NULL) { /* The caller of PREV is the preceding btrace function segment in this @@ -420,7 +438,8 @@ ftrace_new_return (struct btrace_thread_info *btinfo, wrong or that the call is simply not included in the trace. */ /* Let's search for some actual call. */ - caller = ftrace_find_call (prev->up); + caller = ftrace_find_call_by_number (btinfo, prev->up); + caller = ftrace_find_call (btinfo, caller); if (caller == NULL) { /* There is no call in PREV's back trace. We assume that the @@ -428,8 +447,8 @@ ftrace_new_return (struct btrace_thread_info *btinfo, /* Let's find the topmost function and add a new caller for it. This should handle a series of initial tail calls. */ - while (prev->up != NULL) - prev = prev->up; + while (prev->up != 0) + prev = ftrace_find_call_by_number (btinfo, prev->up); bfun->level = prev->level - 1; @@ -449,7 +468,7 @@ ftrace_new_return (struct btrace_thread_info *btinfo, on the same level as they are. This should handle things like schedule () correctly where we're switching contexts. */ - prev->up = bfun; + prev->up = bfun->number; prev->flags = BFUN_UP_LINKS_TO_RET; ftrace_debug (bfun, "new return - unknown caller"); @@ -653,10 +672,11 @@ ftrace_classify_insn (struct gdbarch *gdbarch, CORE_ADDR pc) /* Try to match the back trace at LHS to the back trace at RHS. Returns the number of matching function segments or zero if the back traces do not - match. */ + match. BTINFO is the branch trace information for the current thread. */ static int -ftrace_match_backtrace (struct btrace_function *lhs, +ftrace_match_backtrace (struct btrace_thread_info *btinfo, + struct btrace_function *lhs, struct btrace_function *rhs) { int matches; @@ -666,8 +686,8 @@ ftrace_match_backtrace (struct btrace_function *lhs, if (ftrace_function_switched (lhs, rhs->msym, rhs->sym)) return 0; - lhs = ftrace_get_caller (lhs); - rhs = ftrace_get_caller (rhs); + lhs = ftrace_get_caller (btinfo, lhs); + rhs = ftrace_get_caller (btinfo, rhs); } return matches; @@ -718,10 +738,12 @@ ftrace_compute_global_level_offset (struct btrace_thread_info *btinfo) } /* Connect the function segments PREV and NEXT in a bottom-to-top walk as in - ftrace_connect_backtrace. */ + ftrace_connect_backtrace. BTINFO is the branch trace information for the + current thread. */ static void -ftrace_connect_bfun (struct btrace_function *prev, +ftrace_connect_bfun (struct btrace_thread_info *btinfo, + struct btrace_function *prev, struct btrace_function *next) { DEBUG_FTRACE ("connecting..."); @@ -739,20 +761,26 @@ ftrace_connect_bfun (struct btrace_function *prev, ftrace_fixup_level (next, prev->level - next->level); /* If we run out of back trace for one, let's use the other's. */ - if (prev->up == NULL) + if (prev->up == 0) { - if (next->up != NULL) + const btrace_function_flags flags = next->flags; + + next = ftrace_find_call_by_number (btinfo, next->up); + if (next != NULL) { DEBUG_FTRACE ("using next's callers"); - ftrace_fixup_caller (prev, next->up, next->flags); + ftrace_fixup_caller (prev, next, flags); } } - else if (next->up == NULL) + else if (next->up == 0) { - if (prev->up != NULL) + const btrace_function_flags flags = prev->flags; + + prev = ftrace_find_call_by_number (btinfo, prev->up); + if (prev != NULL) { DEBUG_FTRACE ("using prev's callers"); - ftrace_fixup_caller (next, prev->up, prev->flags); + ftrace_fixup_caller (next, prev, flags); } } else @@ -770,26 +798,29 @@ ftrace_connect_bfun (struct btrace_function *prev, if ((prev->flags & BFUN_UP_LINKS_TO_TAILCALL) != 0) { struct btrace_function *caller; - btrace_function_flags flags; + btrace_function_flags next_flags, prev_flags; /* We checked NEXT->UP above so CALLER can't be NULL. */ - caller = next->up; - flags = next->flags; + caller = ftrace_find_call_by_number (btinfo, next->up); + next_flags = next->flags; + prev_flags = prev->flags; DEBUG_FTRACE ("adding prev's tail calls to next"); - ftrace_fixup_caller (next, prev->up, prev->flags); + prev = ftrace_find_call_by_number (btinfo, prev->up); + ftrace_fixup_caller (next, prev, prev_flags); - for (prev = prev->up; prev != NULL; prev = prev->up) + for (; prev != NULL; prev = ftrace_find_call_by_number (btinfo, + prev->up)) { /* At the end of PREV's back trace, continue with CALLER. */ - if (prev->up == NULL) + if (prev->up == 0) { DEBUG_FTRACE ("fixing up link for tailcall chain"); ftrace_debug (prev, "..top"); ftrace_debug (caller, "..up"); - ftrace_fixup_caller (prev, caller, flags); + ftrace_fixup_caller (prev, caller, next_flags); /* If we skipped any tail calls, this may move CALLER to a different function level. @@ -817,10 +848,12 @@ ftrace_connect_bfun (struct btrace_function *prev, /* Connect function segments on the same level in the back trace at LHS and RHS. The back traces at LHS and RHS are expected to match according to - ftrace_match_backtrace. */ + ftrace_match_backtrace. BTINFO is the branch trace information for the + current thread. */ static void -ftrace_connect_backtrace (struct btrace_function *lhs, +ftrace_connect_backtrace (struct btrace_thread_info *btinfo, + struct btrace_function *lhs, struct btrace_function *rhs) { while (lhs != NULL && rhs != NULL) @@ -833,20 +866,22 @@ ftrace_connect_backtrace (struct btrace_function *lhs, prev = lhs; next = rhs; - lhs = ftrace_get_caller (lhs); - rhs = ftrace_get_caller (rhs); + lhs = ftrace_get_caller (btinfo, lhs); + rhs = ftrace_get_caller (btinfo, rhs); - ftrace_connect_bfun (prev, next); + ftrace_connect_bfun (btinfo, prev, next); } } /* Bridge the gap between two function segments left and right of a gap if their - respective back traces match in at least MIN_MATCHES functions. + respective back traces match in at least MIN_MATCHES functions. BTINFO is + the branch trace information for the current thread. Returns non-zero if the gap could be bridged, zero otherwise. */ static int -ftrace_bridge_gap (struct btrace_function *lhs, struct btrace_function *rhs, +ftrace_bridge_gap (struct btrace_thread_info *btinfo, + struct btrace_function *lhs, struct btrace_function *rhs, int min_matches) { struct btrace_function *best_l, *best_r, *cand_l, *cand_r; @@ -862,12 +897,14 @@ ftrace_bridge_gap (struct btrace_function *lhs, struct btrace_function *rhs, /* We search the back traces of LHS and RHS for valid connections and connect the two functon segments that give the longest combined back trace. */ - for (cand_l = lhs; cand_l != NULL; cand_l = ftrace_get_caller (cand_l)) - for (cand_r = rhs; cand_r != NULL; cand_r = ftrace_get_caller (cand_r)) + for (cand_l = lhs; cand_l != NULL; + cand_l = ftrace_get_caller (btinfo, cand_l)) + for (cand_r = rhs; cand_r != NULL; + cand_r = ftrace_get_caller (btinfo, cand_r)) { int matches; - matches = ftrace_match_backtrace (cand_l, cand_r); + matches = ftrace_match_backtrace (btinfo, cand_l, cand_r); if (best_matches < matches) { best_matches = matches; @@ -894,7 +931,7 @@ ftrace_bridge_gap (struct btrace_function *lhs, struct btrace_function *rhs, BEST_L to BEST_R as they will already be on the same level. */ ftrace_fixup_level (rhs, best_l->level - best_r->level); - ftrace_connect_backtrace (best_l, best_r); + ftrace_connect_backtrace (btinfo, best_l, best_r); return best_matches; } @@ -952,7 +989,7 @@ btrace_bridge_gaps (struct thread_info *tp, VEC (bfun_s) **gaps) if (rhs == NULL) continue; - bridged = ftrace_bridge_gap (lhs, rhs, min_matches); + bridged = ftrace_bridge_gap (&tp->btrace, lhs, rhs, min_matches); /* Keep track of gaps we were not able to bridge and try again. If we just pushed them to the end of GAPS we would risk an diff --git a/gdb/btrace.h b/gdb/btrace.h index 08dd880..8323887 100644 --- a/gdb/btrace.h +++ b/gdb/btrace.h @@ -154,8 +154,10 @@ struct btrace_function /* The previous and next function in control flow order. */ struct btrace_func_link flow; - /* The directly preceding function segment in a (fake) call stack. */ - struct btrace_function *up; + /* The function segment number of the directly preceding function segment in + a (fake) call stack. Will be zero if there is no such function segment in + the record. */ + unsigned int up; /* The instructions in this function segment. The instruction vector will be empty if the function segment diff --git a/gdb/python/py-record-btrace.c b/gdb/python/py-record-btrace.c index d684561..9dd2199 100644 --- a/gdb/python/py-record-btrace.c +++ b/gdb/python/py-record-btrace.c @@ -398,11 +398,11 @@ recpy_bt_func_up (PyObject *self, void *closure) if (func == NULL) return NULL; - if (func->up == NULL) + if (func->up == 0) Py_RETURN_NONE; return recpy_func_new (((recpy_element_object *) self)->ptid, - RECORD_METHOD_BTRACE, func->up->number); + RECORD_METHOD_BTRACE, func->up); } /* Implementation of RecordFunctionSegment.prev [RecordFunctionSegment] for diff --git a/gdb/record-btrace.c b/gdb/record-btrace.c index 5c230e7..41f95b3 100644 --- a/gdb/record-btrace.c +++ b/gdb/record-btrace.c @@ -1570,7 +1570,7 @@ record_btrace_frame_unwind_stop_reason (struct frame_info *this_frame, bfun = cache->bfun; gdb_assert (bfun != NULL); - if (bfun->up == NULL) + if (bfun->up == 0) return UNWIND_UNAVAILABLE; return UNWIND_NO_REASON; @@ -1615,6 +1615,7 @@ record_btrace_frame_prev_register (struct frame_info *this_frame, const struct btrace_frame_cache *cache; const struct btrace_function *bfun, *caller; const struct btrace_insn *insn; + struct btrace_call_iterator it; struct gdbarch *gdbarch; CORE_ADDR pc; int pcreg; @@ -1629,11 +1630,12 @@ record_btrace_frame_prev_register (struct frame_info *this_frame, bfun = cache->bfun; gdb_assert (bfun != NULL); - caller = bfun->up; - if (caller == NULL) + if (btrace_find_call_by_number (&it, &cache->tp->btrace, bfun->up) == 0) throw_error (NOT_AVAILABLE_ERROR, _("No caller in btrace record history")); + caller = btrace_call_get (&it); + if ((bfun->flags & BFUN_UP_LINKS_TO_RET) != 0) { insn = VEC_index (btrace_insn_s, caller->insn, 0); @@ -1683,10 +1685,16 @@ record_btrace_frame_sniffer (const struct frame_unwind *self, else { const struct btrace_function *callee; + struct btrace_call_iterator it; callee = btrace_get_frame_function (next); - if (callee != NULL && (callee->flags & BFUN_UP_LINKS_TO_TAILCALL) == 0) - bfun = callee->up; + if (callee == NULL || (callee->flags & BFUN_UP_LINKS_TO_TAILCALL) != 0) + return 0; + + if (btrace_find_call_by_number (&it, &tp->btrace, callee->up) == 0) + return 0; + + bfun = btrace_call_get (&it); } if (bfun == NULL) @@ -1713,7 +1721,9 @@ record_btrace_tailcall_frame_sniffer (const struct frame_unwind *self, { const struct btrace_function *bfun, *callee; struct btrace_frame_cache *cache; + struct btrace_call_iterator it; struct frame_info *next; + struct thread_info *tinfo; next = get_next_frame (this_frame); if (next == NULL) @@ -1726,16 +1736,18 @@ record_btrace_tailcall_frame_sniffer (const struct frame_unwind *self, if ((callee->flags & BFUN_UP_LINKS_TO_TAILCALL) == 0) return 0; - bfun = callee->up; - if (bfun == NULL) + tinfo = find_thread_ptid (inferior_ptid); + if (btrace_find_call_by_number (&it, &tinfo->btrace, callee->up) == 0) return 0; + bfun = btrace_call_get (&it); + DEBUG ("[frame] sniffed tailcall frame for %s on level %d", btrace_get_bfun_name (bfun), bfun->level); /* This is our frame. Initialize the frame cache. */ cache = bfcache_new (this_frame); - cache->tp = find_thread_ptid (inferior_ptid); + cache->tp = tinfo; cache->bfun = bfun; *this_cache = cache; -- 2.7.4