/* Branch trace support for GDB, the GNU debugger.
- Copyright (C) 2013-2018 Free Software Foundation, Inc.
+ Copyright (C) 2013-2019 Free Software Foundation, Inc.
Contributed by Intel Corp. <markus.t.metzger@intel.com>
#include "filenames.h"
#include "xml-support.h"
#include "regcache.h"
-#include "rsp-low.h"
+#include "gdbsupport/rsp-low.h"
#include "gdbcmd.h"
#include "cli/cli-utils.h"
+#include "gdbarch.h"
/* For maintenance commands. */
#include "record-btrace.h"
if (start == pc)
return ftrace_new_tailcall (btinfo, mfun, fun);
+ /* Some versions of _Unwind_RaiseException use an indirect
+ jump to 'return' to the exception handler of the caller
+ handling the exception instead of a return. Let's restrict
+ this heuristic to that and related functions. */
+ const char *fname = ftrace_print_function_name (bfun);
+ if (strncmp (fname, "_Unwind_", strlen ("_Unwind_")) == 0)
+ {
+ struct btrace_function *caller
+ = ftrace_find_call_by_number (btinfo, bfun->up);
+ caller = ftrace_find_caller (btinfo, caller, mfun, fun);
+ if (caller != NULL)
+ return ftrace_new_return (btinfo, mfun, fun);
+ }
+
/* If we can't determine the function for PC, we treat a jump at
the end of the block as tail call if we're switching functions
and as an intra-function branch if we don't. */
enum btrace_insn_class iclass;
iclass = BTRACE_INSN_OTHER;
- TRY
+ try
{
if (gdbarch_insn_is_call (gdbarch, pc))
iclass = BTRACE_INSN_CALL;
else if (gdbarch_insn_is_jump (gdbarch, pc))
iclass = BTRACE_INSN_JUMP;
}
- CATCH (error, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &error)
{
}
- END_CATCH
return iclass;
}
level = std::min (level, bfun->level);
size = 0;
- TRY
+ try
{
size = gdb_insn_length (gdbarch, pc);
}
- CATCH (error, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &error)
{
}
- END_CATCH
insn.pc = pc;
insn.size = size;
int result, errcode;
result = (int) size;
- TRY
+ try
{
errcode = target_read_code ((CORE_ADDR) pc, buffer, size);
if (errcode != 0)
result = -pte_nomap;
}
- CATCH (error, RETURN_MASK_ERROR)
+ catch (const gdb_exception_error &error)
{
result = -pte_nomap;
}
- END_CATCH
return result;
}
if (decoder == NULL)
error (_("Failed to allocate the Intel Processor Trace decoder."));
- TRY
+ try
{
struct pt_image *image;
ftrace_add_pt (btinfo, decoder, &level, gaps);
}
- CATCH (error, RETURN_MASK_ALL)
+ catch (const gdb_exception &error)
{
/* Indicate a gap in the trace if we quit trace processing. */
if (error.reason == RETURN_QUIT && !btinfo->functions.empty ())
btrace_finalize_ftrace_pt (decoder, tp, level);
- throw_exception (error);
+ throw;
}
- END_CATCH
btrace_finalize_ftrace_pt (decoder, tp, level);
}
{
std::vector<unsigned int> gaps;
- TRY
+ try
{
btrace_compute_ftrace_1 (tp, btrace, cpu, gaps);
}
- CATCH (error, RETURN_MASK_ALL)
+ catch (const gdb_exception &error)
{
btrace_finalize_ftrace (tp, gaps);
- throw_exception (error);
+ throw;
}
- END_CATCH
btrace_finalize_ftrace (tp, gaps);
}
struct regcache *regcache;
CORE_ADDR pc;
- regcache = get_thread_regcache (tp->ptid);
+ regcache = get_thread_regcache (tp);
pc = regcache_read_pc (regcache);
btrace.format = BTRACE_FORMAT_BTS;
#endif /* !defined (HAVE_LIBIPT) */
DEBUG ("enable thread %s (%s)", print_thread_id (tp),
- target_pid_to_str (tp->ptid));
+ target_pid_to_str (tp->ptid).c_str ());
tp->btrace.target = target_enable_btrace (tp->ptid, conf);
return;
/* We need to undo the enable in case of errors. */
- TRY
+ try
{
/* Add an entry for the current PC so we start tracing from where we
enabled it.
This is not relevant for BTRACE_FORMAT_PT since the trace will already
start at the PC at which tracing was enabled. */
if (conf->format != BTRACE_FORMAT_PT
- && can_access_registers_ptid (tp->ptid))
+ && can_access_registers_thread (tp))
btrace_add_pc (tp);
}
- CATCH (exception, RETURN_MASK_ALL)
+ catch (const gdb_exception &exception)
{
btrace_disable (tp);
- throw_exception (exception);
+ throw;
}
- END_CATCH
}
/* See btrace.h. */
return;
DEBUG ("disable thread %s (%s)", print_thread_id (tp),
- target_pid_to_str (tp->ptid));
+ target_pid_to_str (tp->ptid).c_str ());
target_disable_btrace (btp->target);
btp->target = NULL;
return;
DEBUG ("teardown thread %s (%s)", print_thread_id (tp),
- target_pid_to_str (tp->ptid));
+ target_pid_to_str (tp->ptid).c_str ());
target_teardown_btrace (btp->target);
btp->target = NULL;
int errcode;
DEBUG ("fetch thread %s (%s)", print_thread_id (tp),
- target_pid_to_str (tp->ptid));
+ target_pid_to_str (tp->ptid).c_str ());
btinfo = &tp->btrace;
tinfo = btinfo->target;
inferior_ptid = tp->ptid;
/* We should not be called on running or exited threads. */
- gdb_assert (can_access_registers_ptid (tp->ptid));
+ gdb_assert (can_access_registers_thread (tp));
/* Let's first try to extend the trace we already have. */
if (!btinfo->functions.empty ())
struct btrace_thread_info *btinfo;
DEBUG ("clear thread %s (%s)", print_thread_id (tp),
- target_pid_to_str (tp->ptid));
+ target_pid_to_str (tp->ptid).c_str ());
/* Make sure btrace frames that may hold a pointer into the branch
trace data are destroyed. */
void
btrace_free_objfile (struct objfile *objfile)
{
- struct thread_info *tp;
-
DEBUG ("free objfile");
- ALL_NON_EXITED_THREADS (tp)
+ for (thread_info *tp : all_non_exited_threads ())
btrace_clear (tp);
}
parse_xml_raw (struct gdb_xml_parser *parser, const char *body_text,
gdb_byte **pdata, size_t *psize)
{
- struct cleanup *cleanup;
- gdb_byte *data, *bin;
+ gdb_byte *bin;
size_t len, size;
len = strlen (body_text);
size = len / 2;
- bin = data = (gdb_byte *) xmalloc (size);
- cleanup = make_cleanup (xfree, data);
+ gdb::unique_xmalloc_ptr<gdb_byte> data ((gdb_byte *) xmalloc (size));
+ bin = data.get ();
- /* We use hex encoding - see common/rsp-low.h. */
+ /* We use hex encoding - see gdbsupport/rsp-low.h. */
while (len > 0)
{
char hi, lo;
len -= 2;
}
- discard_cleanups (cleanup);
-
- *pdata = data;
+ *pdata = data.release ();
*psize = size;
}
void
parse_xml_btrace (struct btrace_data *btrace, const char *buffer)
{
- int errcode;
-
#if defined (HAVE_LIBEXPAT)
+ int errcode;
btrace_data result;
result.format = BTRACE_FORMAT_NONE;
void
parse_xml_btrace_conf (struct btrace_config *conf, const char *xml)
{
- int errcode;
-
#if defined (HAVE_LIBEXPAT)
+ int errcode;
errcode = gdb_xml_parse_quick (_("btrace-conf"), "btrace-conf.dtd",
btrace_conf_elements, xml, conf);
if (errcode != 0)
if (decoder == NULL)
error (_("Failed to allocate the Intel Processor Trace decoder."));
- TRY
+ try
{
btrace_maint_decode_pt (&btinfo->maint, decoder);
}
- CATCH (except, RETURN_MASK_ALL)
+ catch (const gdb_exception &except)
{
pt_pkt_free_decoder (decoder);
if (except.reason < 0)
- throw_exception (except);
+ throw;
}
- END_CATCH
pt_pkt_free_decoder (decoder);
}
maint_btrace_packet_history_cmd (const char *arg, int from_tty)
{
struct btrace_thread_info *btinfo;
- struct thread_info *tp;
unsigned int size, begin, end, from, to;
- tp = find_thread_ptid (inferior_ptid);
+ thread_info *tp = find_thread_ptid (inferior_ptid);
if (tp == NULL)
error (_("No thread."));
static void
maint_btrace_clear_packet_history_cmd (const char *args, int from_tty)
{
- struct btrace_thread_info *btinfo;
- struct thread_info *tp;
-
if (args != NULL && *args != 0)
error (_("Invalid argument."));
- tp = find_thread_ptid (inferior_ptid);
- if (tp == NULL)
+ if (inferior_ptid == null_ptid)
error (_("No thread."));
- btinfo = &tp->btrace;
+ thread_info *tp = inferior_thread ();
+ btrace_thread_info *btinfo = &tp->btrace;
/* Must clear the maint data before - it depends on BTINFO->DATA. */
btrace_maint_clear (btinfo);
static void
maint_btrace_clear_cmd (const char *args, int from_tty)
{
- struct thread_info *tp;
-
if (args != NULL && *args != 0)
error (_("Invalid argument."));
- tp = find_thread_ptid (inferior_ptid);
- if (tp == NULL)
+ if (inferior_ptid == null_ptid)
error (_("No thread."));
+ thread_info *tp = inferior_thread ();
btrace_clear (tp);
}
maint_info_btrace_cmd (const char *args, int from_tty)
{
struct btrace_thread_info *btinfo;
- struct thread_info *tp;
const struct btrace_config *conf;
if (args != NULL && *args != 0)
error (_("Invalid argument."));
- tp = find_thread_ptid (inferior_ptid);
- if (tp == NULL)
+ if (inferior_ptid == null_ptid)
error (_("No thread."));
+ thread_info *tp = inferior_thread ();
+
btinfo = &tp->btrace;
conf = btrace_conf (btinfo);
Two arguments with comma between specify starting and ending packets to \
print.\n\
Preceded with '+'/'-' the second argument specifies the distance from the \
-first.\n"),
+first."),
&maint_btrace_cmdlist);
add_cmd ("clear-packet-history", class_maintenance,
maint_btrace_clear_packet_history_cmd,
_("Clears the branch tracing packet history.\n\
-Discards the raw branch tracing data but not the execution history data.\n\
-"),
+Discards the raw branch tracing data but not the execution history data."),
&maint_btrace_cmdlist);
add_cmd ("clear", class_maintenance, maint_btrace_clear_cmd,
_("Clears the branch tracing data.\n\
Discards the raw branch tracing data and the execution history data.\n\
-The next 'record' command will fetch the branch tracing data anew.\n\
-"),
+The next 'record' command will fetch the branch tracing data anew."),
&maint_btrace_cmdlist);
}