btrace: maintenance commands
Add maintenance commands that help debugging the btrace record target. The following new commands are added: maint info btrace Print information about branch tracing internals. maint btrace packet-history Print the raw branch tracing data. maint btrace clear-packet-history Discard the stored raw branch tracing data. maint btrace clear Discard all branch tracing data. It will be fetched and processed anew by the next "record" command. maint set|show btrace pt skip-pad Set and show whether PAD packets are skipped when computing the packet history. gdb/ * btrace.c: Include gdbcmd.h, cli/cli-utils.h, and ctype.h. (maint_btrace_cmdlist, maint_btrace_set_cmdlist) (maint_btrace_show_cmdlist, maint_btrace_pt_set_cmdlist) (maint_btrace_pt_show_cmdlist, maint_btrace_pt_skip_pad) (btrace_maint_clear): New. (btrace_fetch, btrace_clear): Call btrace_maint_clear. (pt_print_packet, btrace_maint_decode_pt) (btrace_maint_update_pt_packets, btrace_maint_update_packets) (btrace_maint_print_packets, get_uint, get_context_size, no_chunk) (maint_btrace_packet_history_cmd) (maint_btrace_clear_packet_history_cmd, maint_btrace_clear_cmd) (maint_btrace_cmd, maint_btrace_set_cmd, maint_btrace_show_cmd) (maint_btrace_pt_set_cmd, maint_btrace_pt_show_cmd) (maint_info_btrace_cmd, _initialize_btrace): New. * btrace.h (btrace_pt_packet, btrace_pt_packet_s) (btrace_maint_packet_history, btrace_maint_info): New. (btrace_thread_info) <maint>: New. * NEWS: Announce it. doc/ * gdb.texinfo (Maintenance Commands): Document "maint btrace" commands.
This commit is contained in:
parent
9be54cae43
commit
b0627500e8
|
@ -1,3 +1,24 @@
|
||||||
|
2015-07-02 Markus Metzger <markus.t.metzger@intel.com>
|
||||||
|
|
||||||
|
* btrace.c: Include gdbcmd.h, cli/cli-utils.h, and ctype.h.
|
||||||
|
(maint_btrace_cmdlist, maint_btrace_set_cmdlist)
|
||||||
|
(maint_btrace_show_cmdlist, maint_btrace_pt_set_cmdlist)
|
||||||
|
(maint_btrace_pt_show_cmdlist, maint_btrace_pt_skip_pad)
|
||||||
|
(btrace_maint_clear): New.
|
||||||
|
(btrace_fetch, btrace_clear): Call btrace_maint_clear.
|
||||||
|
(pt_print_packet, btrace_maint_decode_pt)
|
||||||
|
(btrace_maint_update_pt_packets, btrace_maint_update_packets)
|
||||||
|
(btrace_maint_print_packets, get_uint, get_context_size, no_chunk)
|
||||||
|
(maint_btrace_packet_history_cmd)
|
||||||
|
(maint_btrace_clear_packet_history_cmd, maint_btrace_clear_cmd)
|
||||||
|
(maint_btrace_cmd, maint_btrace_set_cmd, maint_btrace_show_cmd)
|
||||||
|
(maint_btrace_pt_set_cmd, maint_btrace_pt_show_cmd)
|
||||||
|
(maint_info_btrace_cmd, _initialize_btrace): New.
|
||||||
|
* btrace.h (btrace_pt_packet, btrace_pt_packet_s)
|
||||||
|
(btrace_maint_packet_history, btrace_maint_info): New.
|
||||||
|
(btrace_thread_info) <maint>: New.
|
||||||
|
* NEWS: Announce it.
|
||||||
|
|
||||||
2015-07-02 Markus Metzger <markus.t.metzger@intel.com>
|
2015-07-02 Markus Metzger <markus.t.metzger@intel.com>
|
||||||
|
|
||||||
* btrace.c (btrace_fetch): Append the new trace data.
|
* btrace.c (btrace_fetch): Append the new trace data.
|
||||||
|
|
17
gdb/NEWS
17
gdb/NEWS
|
@ -116,6 +116,19 @@ record btrace pt
|
||||||
record pt
|
record pt
|
||||||
Start branch trace recording using Intel(R) Processor Trace format.
|
Start branch trace recording using Intel(R) Processor Trace format.
|
||||||
|
|
||||||
|
maint info btrace
|
||||||
|
Print information about branch tracing internals.
|
||||||
|
|
||||||
|
maint btrace packet-history
|
||||||
|
Print the raw branch tracing data.
|
||||||
|
|
||||||
|
maint btrace clear-packet-history
|
||||||
|
Discard the stored raw branch tracing data.
|
||||||
|
|
||||||
|
maint btrace clear
|
||||||
|
Discard all branch tracing data. It will be fetched and processed
|
||||||
|
anew by the next "record" command.
|
||||||
|
|
||||||
* New options
|
* New options
|
||||||
|
|
||||||
set debug dwarf-die
|
set debug dwarf-die
|
||||||
|
@ -173,6 +186,10 @@ set|show record btrace pt buffer-size
|
||||||
The obtained size may differ from the requested size. Use "info
|
The obtained size may differ from the requested size. Use "info
|
||||||
record" to see the obtained buffer size.
|
record" to see the obtained buffer size.
|
||||||
|
|
||||||
|
maint set|show btrace pt skip-pad
|
||||||
|
Set and show whether PAD packets are skipped when computing the
|
||||||
|
packet history.
|
||||||
|
|
||||||
* The command 'thread apply all' can now support new option '-ascending'
|
* The command 'thread apply all' can now support new option '-ascending'
|
||||||
to call its specified command for all threads in ascending order.
|
to call its specified command for all threads in ascending order.
|
||||||
|
|
||||||
|
|
733
gdb/btrace.c
733
gdb/btrace.c
|
@ -32,8 +32,21 @@
|
||||||
#include "xml-support.h"
|
#include "xml-support.h"
|
||||||
#include "regcache.h"
|
#include "regcache.h"
|
||||||
#include "rsp-low.h"
|
#include "rsp-low.h"
|
||||||
|
#include "gdbcmd.h"
|
||||||
|
#include "cli/cli-utils.h"
|
||||||
|
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
/* Command lists for btrace maintenance commands. */
|
||||||
|
static struct cmd_list_element *maint_btrace_cmdlist;
|
||||||
|
static struct cmd_list_element *maint_btrace_set_cmdlist;
|
||||||
|
static struct cmd_list_element *maint_btrace_show_cmdlist;
|
||||||
|
static struct cmd_list_element *maint_btrace_pt_set_cmdlist;
|
||||||
|
static struct cmd_list_element *maint_btrace_pt_show_cmdlist;
|
||||||
|
|
||||||
|
/* Control whether to skip PAD packets when computing the packet history. */
|
||||||
|
static int maint_btrace_pt_skip_pad = 1;
|
||||||
|
|
||||||
static void btrace_add_pc (struct thread_info *tp);
|
static void btrace_add_pc (struct thread_info *tp);
|
||||||
|
|
||||||
|
@ -1197,6 +1210,33 @@ btrace_clear_history (struct btrace_thread_info *btinfo)
|
||||||
btinfo->replay = NULL;
|
btinfo->replay = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Clear the branch trace maintenance histories in BTINFO. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
btrace_maint_clear (struct btrace_thread_info *btinfo)
|
||||||
|
{
|
||||||
|
switch (btinfo->data.format)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BTRACE_FORMAT_BTS:
|
||||||
|
btinfo->maint.variant.bts.packet_history.begin = 0;
|
||||||
|
btinfo->maint.variant.bts.packet_history.end = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if defined (HAVE_LIBIPT)
|
||||||
|
case BTRACE_FORMAT_PT:
|
||||||
|
xfree (btinfo->maint.variant.pt.packets);
|
||||||
|
|
||||||
|
btinfo->maint.variant.pt.packets = NULL;
|
||||||
|
btinfo->maint.variant.pt.packet_history.begin = 0;
|
||||||
|
btinfo->maint.variant.pt.packet_history.end = 0;
|
||||||
|
break;
|
||||||
|
#endif /* defined (HAVE_LIBIPT) */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* See btrace.h. */
|
/* See btrace.h. */
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1263,6 +1303,7 @@ btrace_fetch (struct thread_info *tp)
|
||||||
/* Store the raw trace data. The stored data will be cleared in
|
/* Store the raw trace data. The stored data will be cleared in
|
||||||
btrace_clear, so we always append the new trace. */
|
btrace_clear, so we always append the new trace. */
|
||||||
btrace_data_append (&btinfo->data, &btrace);
|
btrace_data_append (&btinfo->data, &btrace);
|
||||||
|
btrace_maint_clear (btinfo);
|
||||||
|
|
||||||
btrace_clear_history (btinfo);
|
btrace_clear_history (btinfo);
|
||||||
btrace_compute_ftrace (tp, &btrace);
|
btrace_compute_ftrace (tp, &btrace);
|
||||||
|
@ -1300,6 +1341,8 @@ btrace_clear (struct thread_info *tp)
|
||||||
btinfo->end = NULL;
|
btinfo->end = NULL;
|
||||||
btinfo->ngaps = 0;
|
btinfo->ngaps = 0;
|
||||||
|
|
||||||
|
/* Must clear the maint data before - it depends on BTINFO->DATA. */
|
||||||
|
btrace_maint_clear (btinfo);
|
||||||
btrace_data_clear (&btinfo->data);
|
btrace_data_clear (&btinfo->data);
|
||||||
btrace_clear_history (btinfo);
|
btrace_clear_history (btinfo);
|
||||||
}
|
}
|
||||||
|
@ -2203,3 +2246,693 @@ make_cleanup_btrace_data (struct btrace_data *data)
|
||||||
{
|
{
|
||||||
return make_cleanup (do_btrace_data_cleanup, data);
|
return make_cleanup (do_btrace_data_cleanup, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined (HAVE_LIBIPT)
|
||||||
|
|
||||||
|
/* Print a single packet. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
pt_print_packet (const struct pt_packet *packet)
|
||||||
|
{
|
||||||
|
switch (packet->type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
printf_unfiltered (("[??: %x]"), packet->type);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ppt_psb:
|
||||||
|
printf_unfiltered (("psb"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ppt_psbend:
|
||||||
|
printf_unfiltered (("psbend"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ppt_pad:
|
||||||
|
printf_unfiltered (("pad"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ppt_tip:
|
||||||
|
printf_unfiltered (("tip %u: 0x%" PRIx64 ""),
|
||||||
|
packet->payload.ip.ipc,
|
||||||
|
packet->payload.ip.ip);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ppt_tip_pge:
|
||||||
|
printf_unfiltered (("tip.pge %u: 0x%" PRIx64 ""),
|
||||||
|
packet->payload.ip.ipc,
|
||||||
|
packet->payload.ip.ip);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ppt_tip_pgd:
|
||||||
|
printf_unfiltered (("tip.pgd %u: 0x%" PRIx64 ""),
|
||||||
|
packet->payload.ip.ipc,
|
||||||
|
packet->payload.ip.ip);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ppt_fup:
|
||||||
|
printf_unfiltered (("fup %u: 0x%" PRIx64 ""),
|
||||||
|
packet->payload.ip.ipc,
|
||||||
|
packet->payload.ip.ip);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ppt_tnt_8:
|
||||||
|
printf_unfiltered (("tnt-8 %u: 0x%" PRIx64 ""),
|
||||||
|
packet->payload.tnt.bit_size,
|
||||||
|
packet->payload.tnt.payload);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ppt_tnt_64:
|
||||||
|
printf_unfiltered (("tnt-64 %u: 0x%" PRIx64 ""),
|
||||||
|
packet->payload.tnt.bit_size,
|
||||||
|
packet->payload.tnt.payload);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ppt_pip:
|
||||||
|
printf_unfiltered (("pip %" PRIx64 ""), packet->payload.pip.cr3);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ppt_tsc:
|
||||||
|
printf_unfiltered (("tsc %" PRIx64 ""), packet->payload.tsc.tsc);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ppt_cbr:
|
||||||
|
printf_unfiltered (("cbr %u"), packet->payload.cbr.ratio);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ppt_mode:
|
||||||
|
switch (packet->payload.mode.leaf)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
printf_unfiltered (("mode %u"), packet->payload.mode.leaf);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case pt_mol_exec:
|
||||||
|
printf_unfiltered (("mode.exec%s%s"),
|
||||||
|
packet->payload.mode.bits.exec.csl
|
||||||
|
? (" cs.l") : (""),
|
||||||
|
packet->payload.mode.bits.exec.csd
|
||||||
|
? (" cs.d") : (""));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case pt_mol_tsx:
|
||||||
|
printf_unfiltered (("mode.tsx%s%s"),
|
||||||
|
packet->payload.mode.bits.tsx.intx
|
||||||
|
? (" intx") : (""),
|
||||||
|
packet->payload.mode.bits.tsx.abrt
|
||||||
|
? (" abrt") : (""));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ppt_ovf:
|
||||||
|
printf_unfiltered (("ovf"));
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Decode packets into MAINT using DECODER. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
btrace_maint_decode_pt (struct btrace_maint_info *maint,
|
||||||
|
struct pt_packet_decoder *decoder)
|
||||||
|
{
|
||||||
|
int errcode;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
struct btrace_pt_packet packet;
|
||||||
|
|
||||||
|
errcode = pt_pkt_sync_forward (decoder);
|
||||||
|
if (errcode < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
pt_pkt_get_offset (decoder, &packet.offset);
|
||||||
|
|
||||||
|
errcode = pt_pkt_next (decoder, &packet.packet,
|
||||||
|
sizeof(packet.packet));
|
||||||
|
if (errcode < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (maint_btrace_pt_skip_pad == 0 || packet.packet.type != ppt_pad)
|
||||||
|
{
|
||||||
|
packet.errcode = pt_errcode (errcode);
|
||||||
|
VEC_safe_push (btrace_pt_packet_s, maint->variant.pt.packets,
|
||||||
|
&packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errcode == -pte_eos)
|
||||||
|
break;
|
||||||
|
|
||||||
|
packet.errcode = pt_errcode (errcode);
|
||||||
|
VEC_safe_push (btrace_pt_packet_s, maint->variant.pt.packets,
|
||||||
|
&packet);
|
||||||
|
|
||||||
|
warning (_("Error at trace offset 0x%" PRIx64 ": %s."),
|
||||||
|
packet.offset, pt_errstr (packet.errcode));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errcode != -pte_eos)
|
||||||
|
warning (_("Failed to synchronize onto the Intel(R) Processor Trace "
|
||||||
|
"stream: %s."), pt_errstr (pt_errcode (errcode)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the packet history in BTINFO. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
btrace_maint_update_pt_packets (struct btrace_thread_info *btinfo)
|
||||||
|
{
|
||||||
|
volatile struct gdb_exception except;
|
||||||
|
struct pt_packet_decoder *decoder;
|
||||||
|
struct btrace_data_pt *pt;
|
||||||
|
struct pt_config config;
|
||||||
|
int errcode;
|
||||||
|
|
||||||
|
pt = &btinfo->data.variant.pt;
|
||||||
|
|
||||||
|
/* Nothing to do if there is no trace. */
|
||||||
|
if (pt->size == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
memset (&config, 0, sizeof(config));
|
||||||
|
|
||||||
|
config.size = sizeof (config);
|
||||||
|
config.begin = pt->data;
|
||||||
|
config.end = pt->data + pt->size;
|
||||||
|
|
||||||
|
config.cpu.vendor = pt_translate_cpu_vendor (pt->config.cpu.vendor);
|
||||||
|
config.cpu.family = pt->config.cpu.family;
|
||||||
|
config.cpu.model = pt->config.cpu.model;
|
||||||
|
config.cpu.stepping = pt->config.cpu.stepping;
|
||||||
|
|
||||||
|
errcode = pt_cpu_errata (&config.errata, &config.cpu);
|
||||||
|
if (errcode < 0)
|
||||||
|
error (_("Failed to configure the Intel(R) Processor Trace decoder: %s."),
|
||||||
|
pt_errstr (pt_errcode (errcode)));
|
||||||
|
|
||||||
|
decoder = pt_pkt_alloc_decoder (&config);
|
||||||
|
if (decoder == NULL)
|
||||||
|
error (_("Failed to allocate the Intel(R) Processor Trace decoder."));
|
||||||
|
|
||||||
|
TRY
|
||||||
|
{
|
||||||
|
btrace_maint_decode_pt (&btinfo->maint, decoder);
|
||||||
|
}
|
||||||
|
CATCH (except, RETURN_MASK_ALL)
|
||||||
|
{
|
||||||
|
pt_pkt_free_decoder (decoder);
|
||||||
|
|
||||||
|
if (except.reason < 0)
|
||||||
|
throw_exception (except);
|
||||||
|
}
|
||||||
|
END_CATCH
|
||||||
|
|
||||||
|
pt_pkt_free_decoder (decoder);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !defined (HAVE_LIBIPT) */
|
||||||
|
|
||||||
|
/* Update the packet maintenance information for BTINFO and store the
|
||||||
|
low and high bounds into BEGIN and END, respectively.
|
||||||
|
Store the current iterator state into FROM and TO. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
btrace_maint_update_packets (struct btrace_thread_info *btinfo,
|
||||||
|
unsigned int *begin, unsigned int *end,
|
||||||
|
unsigned int *from, unsigned int *to)
|
||||||
|
{
|
||||||
|
switch (btinfo->data.format)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
*begin = 0;
|
||||||
|
*end = 0;
|
||||||
|
*from = 0;
|
||||||
|
*to = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BTRACE_FORMAT_BTS:
|
||||||
|
/* Nothing to do - we operate directly on BTINFO->DATA. */
|
||||||
|
*begin = 0;
|
||||||
|
*end = VEC_length (btrace_block_s, btinfo->data.variant.bts.blocks);
|
||||||
|
*from = btinfo->maint.variant.bts.packet_history.begin;
|
||||||
|
*to = btinfo->maint.variant.bts.packet_history.end;
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if defined (HAVE_LIBIPT)
|
||||||
|
case BTRACE_FORMAT_PT:
|
||||||
|
if (VEC_empty (btrace_pt_packet_s, btinfo->maint.variant.pt.packets))
|
||||||
|
btrace_maint_update_pt_packets (btinfo);
|
||||||
|
|
||||||
|
*begin = 0;
|
||||||
|
*end = VEC_length (btrace_pt_packet_s, btinfo->maint.variant.pt.packets);
|
||||||
|
*from = btinfo->maint.variant.pt.packet_history.begin;
|
||||||
|
*to = btinfo->maint.variant.pt.packet_history.end;
|
||||||
|
break;
|
||||||
|
#endif /* defined (HAVE_LIBIPT) */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Print packets in BTINFO from BEGIN (inclusive) until END (exclusive) and
|
||||||
|
update the current iterator position. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
btrace_maint_print_packets (struct btrace_thread_info *btinfo,
|
||||||
|
unsigned int begin, unsigned int end)
|
||||||
|
{
|
||||||
|
switch (btinfo->data.format)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BTRACE_FORMAT_BTS:
|
||||||
|
{
|
||||||
|
VEC (btrace_block_s) *blocks;
|
||||||
|
unsigned int blk;
|
||||||
|
|
||||||
|
blocks = btinfo->data.variant.bts.blocks;
|
||||||
|
for (blk = begin; blk < end; ++blk)
|
||||||
|
{
|
||||||
|
const btrace_block_s *block;
|
||||||
|
|
||||||
|
block = VEC_index (btrace_block_s, blocks, blk);
|
||||||
|
|
||||||
|
printf_unfiltered ("%u\tbegin: %s, end: %s\n", blk,
|
||||||
|
core_addr_to_string_nz (block->begin),
|
||||||
|
core_addr_to_string_nz (block->end));
|
||||||
|
}
|
||||||
|
|
||||||
|
btinfo->maint.variant.bts.packet_history.begin = begin;
|
||||||
|
btinfo->maint.variant.bts.packet_history.end = end;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if defined (HAVE_LIBIPT)
|
||||||
|
case BTRACE_FORMAT_PT:
|
||||||
|
{
|
||||||
|
VEC (btrace_pt_packet_s) *packets;
|
||||||
|
unsigned int pkt;
|
||||||
|
|
||||||
|
packets = btinfo->maint.variant.pt.packets;
|
||||||
|
for (pkt = begin; pkt < end; ++pkt)
|
||||||
|
{
|
||||||
|
const struct btrace_pt_packet *packet;
|
||||||
|
|
||||||
|
packet = VEC_index (btrace_pt_packet_s, packets, pkt);
|
||||||
|
|
||||||
|
printf_unfiltered ("%u\t", pkt);
|
||||||
|
printf_unfiltered ("0x%" PRIx64 "\t", packet->offset);
|
||||||
|
|
||||||
|
if (packet->errcode == pte_ok)
|
||||||
|
pt_print_packet (&packet->packet);
|
||||||
|
else
|
||||||
|
printf_unfiltered ("[error: %s]", pt_errstr (packet->errcode));
|
||||||
|
|
||||||
|
printf_unfiltered ("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
btinfo->maint.variant.pt.packet_history.begin = begin;
|
||||||
|
btinfo->maint.variant.pt.packet_history.end = end;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif /* defined (HAVE_LIBIPT) */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a number from an argument string. */
|
||||||
|
|
||||||
|
static unsigned int
|
||||||
|
get_uint (char **arg)
|
||||||
|
{
|
||||||
|
char *begin, *end, *pos;
|
||||||
|
unsigned long number;
|
||||||
|
|
||||||
|
begin = *arg;
|
||||||
|
pos = skip_spaces (begin);
|
||||||
|
|
||||||
|
if (!isdigit (*pos))
|
||||||
|
error (_("Expected positive number, got: %s."), pos);
|
||||||
|
|
||||||
|
number = strtoul (pos, &end, 10);
|
||||||
|
if (number > UINT_MAX)
|
||||||
|
error (_("Number too big."));
|
||||||
|
|
||||||
|
*arg += (end - begin);
|
||||||
|
|
||||||
|
return (unsigned int) number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read a context size from an argument string. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
get_context_size (char **arg)
|
||||||
|
{
|
||||||
|
char *pos;
|
||||||
|
int number;
|
||||||
|
|
||||||
|
pos = skip_spaces (*arg);
|
||||||
|
|
||||||
|
if (!isdigit (*pos))
|
||||||
|
error (_("Expected positive number, got: %s."), pos);
|
||||||
|
|
||||||
|
return strtol (pos, arg, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Complain about junk at the end of an argument string. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
no_chunk (char *arg)
|
||||||
|
{
|
||||||
|
if (*arg != 0)
|
||||||
|
error (_("Junk after argument: %s."), arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The "maintenance btrace packet-history" command. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
maint_btrace_packet_history_cmd (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);
|
||||||
|
if (tp == NULL)
|
||||||
|
error (_("No thread."));
|
||||||
|
|
||||||
|
size = 10;
|
||||||
|
btinfo = &tp->btrace;
|
||||||
|
|
||||||
|
btrace_maint_update_packets (btinfo, &begin, &end, &from, &to);
|
||||||
|
if (begin == end)
|
||||||
|
{
|
||||||
|
printf_unfiltered (_("No trace.\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (arg == NULL || *arg == 0 || strcmp (arg, "+") == 0)
|
||||||
|
{
|
||||||
|
from = to;
|
||||||
|
|
||||||
|
if (end - from < size)
|
||||||
|
size = end - from;
|
||||||
|
to = from + size;
|
||||||
|
}
|
||||||
|
else if (strcmp (arg, "-") == 0)
|
||||||
|
{
|
||||||
|
to = from;
|
||||||
|
|
||||||
|
if (to - begin < size)
|
||||||
|
size = to - begin;
|
||||||
|
from = to - size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
from = get_uint (&arg);
|
||||||
|
if (end <= from)
|
||||||
|
error (_("'%u' is out of range."), from);
|
||||||
|
|
||||||
|
arg = skip_spaces (arg);
|
||||||
|
if (*arg == ',')
|
||||||
|
{
|
||||||
|
arg = skip_spaces (++arg);
|
||||||
|
|
||||||
|
if (*arg == '+')
|
||||||
|
{
|
||||||
|
arg += 1;
|
||||||
|
size = get_context_size (&arg);
|
||||||
|
|
||||||
|
no_chunk (arg);
|
||||||
|
|
||||||
|
if (end - from < size)
|
||||||
|
size = end - from;
|
||||||
|
to = from + size;
|
||||||
|
}
|
||||||
|
else if (*arg == '-')
|
||||||
|
{
|
||||||
|
arg += 1;
|
||||||
|
size = get_context_size (&arg);
|
||||||
|
|
||||||
|
no_chunk (arg);
|
||||||
|
|
||||||
|
/* Include the packet given as first argument. */
|
||||||
|
from += 1;
|
||||||
|
to = from;
|
||||||
|
|
||||||
|
if (to - begin < size)
|
||||||
|
size = to - begin;
|
||||||
|
from = to - size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
to = get_uint (&arg);
|
||||||
|
|
||||||
|
/* Include the packet at the second argument and silently
|
||||||
|
truncate the range. */
|
||||||
|
if (to < end)
|
||||||
|
to += 1;
|
||||||
|
else
|
||||||
|
to = end;
|
||||||
|
|
||||||
|
no_chunk (arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
no_chunk (arg);
|
||||||
|
|
||||||
|
if (end - from < size)
|
||||||
|
size = end - from;
|
||||||
|
to = from + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
dont_repeat ();
|
||||||
|
}
|
||||||
|
|
||||||
|
btrace_maint_print_packets (btinfo, from, to);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The "maintenance btrace clear-packet-history" command. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
maint_btrace_clear_packet_history_cmd (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)
|
||||||
|
error (_("No thread."));
|
||||||
|
|
||||||
|
btinfo = &tp->btrace;
|
||||||
|
|
||||||
|
/* Must clear the maint data before - it depends on BTINFO->DATA. */
|
||||||
|
btrace_maint_clear (btinfo);
|
||||||
|
btrace_data_clear (&btinfo->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The "maintenance btrace clear" command. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
maint_btrace_clear_cmd (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)
|
||||||
|
error (_("No thread."));
|
||||||
|
|
||||||
|
btrace_clear (tp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The "maintenance btrace" command. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
maint_btrace_cmd (char *args, int from_tty)
|
||||||
|
{
|
||||||
|
help_list (maint_btrace_cmdlist, "maintenance btrace ", all_commands,
|
||||||
|
gdb_stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The "maintenance set btrace" command. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
maint_btrace_set_cmd (char *args, int from_tty)
|
||||||
|
{
|
||||||
|
help_list (maint_btrace_set_cmdlist, "maintenance set btrace ", all_commands,
|
||||||
|
gdb_stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The "maintenance show btrace" command. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
maint_btrace_show_cmd (char *args, int from_tty)
|
||||||
|
{
|
||||||
|
help_list (maint_btrace_show_cmdlist, "maintenance show btrace ",
|
||||||
|
all_commands, gdb_stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The "maintenance set btrace pt" command. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
maint_btrace_pt_set_cmd (char *args, int from_tty)
|
||||||
|
{
|
||||||
|
help_list (maint_btrace_pt_set_cmdlist, "maintenance set btrace pt ",
|
||||||
|
all_commands, gdb_stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The "maintenance show btrace pt" command. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
maint_btrace_pt_show_cmd (char *args, int from_tty)
|
||||||
|
{
|
||||||
|
help_list (maint_btrace_pt_show_cmdlist, "maintenance show btrace pt ",
|
||||||
|
all_commands, gdb_stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The "maintenance info btrace" command. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
maint_info_btrace_cmd (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)
|
||||||
|
error (_("No thread."));
|
||||||
|
|
||||||
|
btinfo = &tp->btrace;
|
||||||
|
|
||||||
|
conf = btrace_conf (btinfo);
|
||||||
|
if (conf == NULL)
|
||||||
|
error (_("No btrace configuration."));
|
||||||
|
|
||||||
|
printf_unfiltered (_("Format: %s.\n"),
|
||||||
|
btrace_format_string (conf->format));
|
||||||
|
|
||||||
|
switch (conf->format)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case BTRACE_FORMAT_BTS:
|
||||||
|
printf_unfiltered (_("Number of packets: %u.\n"),
|
||||||
|
VEC_length (btrace_block_s,
|
||||||
|
btinfo->data.variant.bts.blocks));
|
||||||
|
break;
|
||||||
|
|
||||||
|
#if defined (HAVE_LIBIPT)
|
||||||
|
case BTRACE_FORMAT_PT:
|
||||||
|
{
|
||||||
|
struct pt_version version;
|
||||||
|
|
||||||
|
version = pt_library_version ();
|
||||||
|
printf_unfiltered (_("Version: %u.%u.%u%s.\n"), version.major,
|
||||||
|
version.minor, version.build,
|
||||||
|
version.ext != NULL ? version.ext : "");
|
||||||
|
|
||||||
|
btrace_maint_update_pt_packets (btinfo);
|
||||||
|
printf_unfiltered (_("Number of packets: %u.\n"),
|
||||||
|
VEC_length (btrace_pt_packet_s,
|
||||||
|
btinfo->maint.variant.pt.packets));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
#endif /* defined (HAVE_LIBIPT) */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The "maint show btrace pt skip-pad" show value function. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
show_maint_btrace_pt_skip_pad (struct ui_file *file, int from_tty,
|
||||||
|
struct cmd_list_element *c,
|
||||||
|
const char *value)
|
||||||
|
{
|
||||||
|
fprintf_filtered (file, _("Skip PAD packets is %s.\n"), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Initialize btrace maintenance commands. */
|
||||||
|
|
||||||
|
void _initialize_btrace (void);
|
||||||
|
void
|
||||||
|
_initialize_btrace (void)
|
||||||
|
{
|
||||||
|
add_cmd ("btrace", class_maintenance, maint_info_btrace_cmd,
|
||||||
|
_("Info about branch tracing data."), &maintenanceinfolist);
|
||||||
|
|
||||||
|
add_prefix_cmd ("btrace", class_maintenance, maint_btrace_cmd,
|
||||||
|
_("Branch tracing maintenance commands."),
|
||||||
|
&maint_btrace_cmdlist, "maintenance btrace ",
|
||||||
|
0, &maintenancelist);
|
||||||
|
|
||||||
|
add_prefix_cmd ("btrace", class_maintenance, maint_btrace_set_cmd, _("\
|
||||||
|
Set branch tracing specific variables."),
|
||||||
|
&maint_btrace_set_cmdlist, "maintenance set btrace ",
|
||||||
|
0, &maintenance_set_cmdlist);
|
||||||
|
|
||||||
|
add_prefix_cmd ("pt", class_maintenance, maint_btrace_pt_set_cmd, _("\
|
||||||
|
Set Intel(R) Processor Trace specific variables."),
|
||||||
|
&maint_btrace_pt_set_cmdlist, "maintenance set btrace pt ",
|
||||||
|
0, &maint_btrace_set_cmdlist);
|
||||||
|
|
||||||
|
add_prefix_cmd ("btrace", class_maintenance, maint_btrace_show_cmd, _("\
|
||||||
|
Show branch tracing specific variables."),
|
||||||
|
&maint_btrace_show_cmdlist, "maintenance show btrace ",
|
||||||
|
0, &maintenance_show_cmdlist);
|
||||||
|
|
||||||
|
add_prefix_cmd ("pt", class_maintenance, maint_btrace_pt_show_cmd, _("\
|
||||||
|
Show Intel(R) Processor Trace specific variables."),
|
||||||
|
&maint_btrace_pt_show_cmdlist, "maintenance show btrace pt ",
|
||||||
|
0, &maint_btrace_show_cmdlist);
|
||||||
|
|
||||||
|
add_setshow_boolean_cmd ("skip-pad", class_maintenance,
|
||||||
|
&maint_btrace_pt_skip_pad, _("\
|
||||||
|
Set whether PAD packets should be skipped in the btrace packet history."), _("\
|
||||||
|
Show whether PAD packets should be skipped in the btrace packet history."),_("\
|
||||||
|
When enabled, PAD packets are ignored in the btrace packet history."),
|
||||||
|
NULL, show_maint_btrace_pt_skip_pad,
|
||||||
|
&maint_btrace_pt_set_cmdlist,
|
||||||
|
&maint_btrace_pt_show_cmdlist);
|
||||||
|
|
||||||
|
add_cmd ("packet-history", class_maintenance, maint_btrace_packet_history_cmd,
|
||||||
|
_("Print the raw branch tracing data.\n\
|
||||||
|
With no argument, print ten more packets after the previous ten-line print.\n\
|
||||||
|
With '-' as argument print ten packets before a previous ten-line print.\n\
|
||||||
|
One argument specifies the starting packet of a ten-line print.\n\
|
||||||
|
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"),
|
||||||
|
&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\
|
||||||
|
"),
|
||||||
|
&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\
|
||||||
|
"),
|
||||||
|
&maint_btrace_cmdlist);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
63
gdb/btrace.h
63
gdb/btrace.h
|
@ -233,6 +233,66 @@ enum btrace_thread_flag
|
||||||
BTHR_MOVE = (BTHR_STEP | BTHR_RSTEP | BTHR_CONT | BTHR_RCONT)
|
BTHR_MOVE = (BTHR_STEP | BTHR_RSTEP | BTHR_CONT | BTHR_RCONT)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if defined (HAVE_LIBIPT)
|
||||||
|
/* A packet. */
|
||||||
|
struct btrace_pt_packet
|
||||||
|
{
|
||||||
|
/* The offset in the trace stream. */
|
||||||
|
uint64_t offset;
|
||||||
|
|
||||||
|
/* The decode error code. */
|
||||||
|
enum pt_error_code errcode;
|
||||||
|
|
||||||
|
/* The decoded packet. Only valid if ERRCODE == pte_ok. */
|
||||||
|
struct pt_packet packet;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Define functions operating on a vector of packets. */
|
||||||
|
typedef struct btrace_pt_packet btrace_pt_packet_s;
|
||||||
|
DEF_VEC_O (btrace_pt_packet_s);
|
||||||
|
#endif /* defined (HAVE_LIBIPT) */
|
||||||
|
|
||||||
|
/* Branch trace iteration state for "maintenance btrace packet-history". */
|
||||||
|
struct btrace_maint_packet_history
|
||||||
|
{
|
||||||
|
/* The branch trace packet range from BEGIN (inclusive) to
|
||||||
|
END (exclusive) that has been covered last time. */
|
||||||
|
unsigned int begin;
|
||||||
|
unsigned int end;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Branch trace maintenance information per thread.
|
||||||
|
|
||||||
|
This information is used by "maintenance btrace" commands. */
|
||||||
|
struct btrace_maint_info
|
||||||
|
{
|
||||||
|
/* Most information is format-specific.
|
||||||
|
The format can be found in the BTRACE.DATA.FORMAT field of each thread. */
|
||||||
|
union
|
||||||
|
{
|
||||||
|
/* BTRACE.DATA.FORMAT == BTRACE_FORMAT_BTS */
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
/* The packet history iterator.
|
||||||
|
We are iterating over BTRACE.DATA.FORMAT.VARIANT.BTS.BLOCKS. */
|
||||||
|
struct btrace_maint_packet_history packet_history;
|
||||||
|
} bts;
|
||||||
|
|
||||||
|
#if defined (HAVE_LIBIPT)
|
||||||
|
/* BTRACE.DATA.FORMAT == BTRACE_FORMAT_PT */
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
/* A vector of decoded packets. */
|
||||||
|
VEC (btrace_pt_packet_s) *packets;
|
||||||
|
|
||||||
|
/* The packet history iterator.
|
||||||
|
We are iterating over the above PACKETS vector. */
|
||||||
|
struct btrace_maint_packet_history packet_history;
|
||||||
|
} pt;
|
||||||
|
#endif /* defined (HAVE_LIBIPT) */
|
||||||
|
} variant;
|
||||||
|
};
|
||||||
|
|
||||||
/* Branch trace information per thread.
|
/* Branch trace information per thread.
|
||||||
|
|
||||||
This represents the branch trace configuration as well as the entry point
|
This represents the branch trace configuration as well as the entry point
|
||||||
|
@ -284,6 +344,9 @@ struct btrace_thread_info
|
||||||
|
|
||||||
/* Why the thread stopped, if we need to track it. */
|
/* Why the thread stopped, if we need to track it. */
|
||||||
enum target_stop_reason stop_reason;
|
enum target_stop_reason stop_reason;
|
||||||
|
|
||||||
|
/* Maintenance information. */
|
||||||
|
struct btrace_maint_info maint;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Enable branch tracing for a thread. */
|
/* Enable branch tracing for a thread. */
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
2015-07-02 Markus Metzger <markus.t.metzger@intel.com>
|
||||||
|
|
||||||
|
* gdb.texinfo (Maintenance Commands): Document "maint btrace"
|
||||||
|
commands.
|
||||||
|
|
||||||
2015-07-02 Markus Metzger <markus.t.metzger@intel.com>
|
2015-07-02 Markus Metzger <markus.t.metzger@intel.com>
|
||||||
|
|
||||||
* gdb.texinfo (Process Record and Replay): Spell out that variables
|
* gdb.texinfo (Process Record and Replay): Spell out that variables
|
||||||
|
|
|
@ -33980,6 +33980,66 @@ Shared library events.
|
||||||
This prints information about each @code{bfd} object that is known to
|
This prints information about each @code{bfd} object that is known to
|
||||||
@value{GDBN}. @xref{Top, , BFD, bfd, The Binary File Descriptor Library}.
|
@value{GDBN}. @xref{Top, , BFD, bfd, The Binary File Descriptor Library}.
|
||||||
|
|
||||||
|
@kindex maint info btrace
|
||||||
|
@item maint info btrace
|
||||||
|
Pint information about raw branch tracing data.
|
||||||
|
|
||||||
|
@kindex maint btrace packet-history
|
||||||
|
@item maint btrace packet-history
|
||||||
|
Print the raw branch trace packets that are used to compute the
|
||||||
|
execution history for the @samp{record btrace} command. Both the
|
||||||
|
information and the format in which it is printed depend on the btrace
|
||||||
|
recording format.
|
||||||
|
|
||||||
|
@table @code
|
||||||
|
@item bts
|
||||||
|
For the BTS recording format, print a list of blocks of sequential
|
||||||
|
code. For each block, the following information is printed:
|
||||||
|
|
||||||
|
@table @asis
|
||||||
|
@item Block number
|
||||||
|
Newer blocks have higher numbers. The oldest block has number zero.
|
||||||
|
@item Lowest @samp{PC}
|
||||||
|
@item Highest @samp{PC}
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@item pt
|
||||||
|
For the Intel(R) Processor Trace recording format, print a list of
|
||||||
|
Intel(R) Processor Trace packets. For each packet, the following
|
||||||
|
information is printed:
|
||||||
|
|
||||||
|
@table @asis
|
||||||
|
@item Packet number
|
||||||
|
Newer packets have higher numbers. The oldest packet has number zero.
|
||||||
|
@item Trace offset
|
||||||
|
The packet's offset in the trace stream.
|
||||||
|
@item Packet opcode and payload
|
||||||
|
@end table
|
||||||
|
@end table
|
||||||
|
|
||||||
|
@kindex maint btrace clear-packet-history
|
||||||
|
@item maint btrace clear-packet-history
|
||||||
|
Discards the cached packet history printed by the @samp{maint btrace
|
||||||
|
packet-history} command. The history will be computed again when
|
||||||
|
needed.
|
||||||
|
|
||||||
|
@kindex maint btrace clear
|
||||||
|
@item maint btrace clear
|
||||||
|
Discard the branch trace data. The data will be fetched anew and the
|
||||||
|
branch trace will be recomputed when needed.
|
||||||
|
|
||||||
|
This implicitly truncates the branch trace to a single branch trace
|
||||||
|
buffer. When updating branch trace incrementally, the branch trace
|
||||||
|
available to @value{GDBN} may be bigger than a single branch trace
|
||||||
|
buffer.
|
||||||
|
|
||||||
|
@kindex maint set btrace pt skip-pad
|
||||||
|
@item maint set btrace pt skip-pad
|
||||||
|
@kindex maint show btrace pt skip-pad
|
||||||
|
@item maint show btrace pt skip-pad
|
||||||
|
Control whether @value{GDBN} will skip PAD packets when computing the
|
||||||
|
packet history.
|
||||||
|
|
||||||
@kindex set displaced-stepping
|
@kindex set displaced-stepping
|
||||||
@kindex show displaced-stepping
|
@kindex show displaced-stepping
|
||||||
@cindex displaced stepping support
|
@cindex displaced stepping support
|
||||||
|
|
Loading…
Reference in New Issue