* [PATCH v3 13/15] Test on saving tracepoint defs.
2013-03-09 3:48 [PATCH v3 00/15] CTF Support Yao Qi
@ 2013-03-09 3:49 ` Yao Qi
2013-03-12 20:10 ` Tom Tromey
2013-03-09 3:49 ` [PATCH v3 06/15] Write status to CTF and read Yao Qi
` (14 subsequent siblings)
15 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-09 3:49 UTC (permalink / raw)
To: gdb-patches
Presently, we don't have a test on writing actions of tracepoints to
trace file, and read trace file back to see if any differences on
tracepoints actions. This is what this patch tries to do. This is
useful to exercise the code on saving actions and restoring actions
from trace file.
It also paves the way for test CTF in this area.
gdb/testsuite:
2013-03-08 Yao Qi <yao@codesourcery.com>
* gdb.trace/actions.exp (check_tracepoint): New.
(top level): Start the tracing and check the actions of
tracepoints. Save trace data to tfile format. Restart GDB
and read trace file in tfile target. Check the actions of
tracepoints again.
* gdb.trace/while-stepping.exp: Likewise.
---
gdb/testsuite/gdb.trace/actions.exp | 82 ++++++++++++++++++++++++++++
gdb/testsuite/gdb.trace/while-stepping.exp | 42 ++++++++++++++
2 files changed, 124 insertions(+), 0 deletions(-)
diff --git a/gdb/testsuite/gdb.trace/actions.exp b/gdb/testsuite/gdb.trace/actions.exp
index f8a5266..7bbe6b6 100644
--- a/gdb/testsuite/gdb.trace/actions.exp
+++ b/gdb/testsuite/gdb.trace/actions.exp
@@ -235,3 +235,85 @@ gdb_test "info tracepoints" \
\[\t \]+not installed on target." \
"5.10a: verify teval actions set for two tracepoints"
+gdb_test "break main"
+gdb_run_cmd
+gdb_test "" "Breakpoint .*"
+if ![gdb_target_supports_trace] {
+ unsupported "target does not support trace"
+ return -1;
+}
+
+gdb_trace_setactions "set actions for first tracepoint" \
+ "$trcpt1" \
+ "collect \$regs" "^$" \
+ "end" ""
+
+# Check the definition of tracepoints. These tracepoints may have
+# different number in different runs.
+
+proc check_tracepoint { data_source } { with_test_prefix "$data_source" {
+ global gdb_prompt
+ global srcfile
+
+ set tp_on_gdb_c_test 0
+ set tp_on_gdb_asm_test 0
+ set tp_on_gdb_recursion_test 0
+
+ # Since the three tracepoints may appear in different orders, so
+ # we can't do 'info tracepoints' to match the output. Instead, we
+ # show each tracepoint one by one and record the number of each
+ # tracepoint shown up the output. Check the number finally.
+ for {set i 1} {$i < 4} {incr i 1} {
+ set test "info tracepoints $i"
+ gdb_test_multiple "info tracepoints $i" $test {
+ -re "\[0-9\]+\[\t \]+tracepoint keep y.* in gdb_c_test at .*$srcfile:\[0-9\]+\\r\\n\[\t \]+collect \\\$regs\\r\\n\[\t \]+installed on target" {
+ incr tp_on_gdb_c_test
+ exp_continue
+ }
+ -re "\[0-9\]+\[\t \]+tracepoint keep y.* in gdb_asm_test at .*$srcfile:\[0-9\]+\\r\\n\[\t \]+teval \\\$tsv \\+= 1\\r\\n\[\t \]+installed on target" {
+ incr tp_on_gdb_asm_test
+ exp_continue
+ }
+ -re "\[0-9\]+\[\t \]+tracepoint keep y.* in gdb_recursion_test at .*$srcfile:\[0-9\]+\\r\\n\[\t \]+collect gdb_long_test\\r\\n\[\t \]+installed on target" {
+ incr tp_on_gdb_recursion_test
+ exp_continue
+ }
+ -re "${gdb_prompt} $" {
+ }
+ }
+ }
+
+ if {$tp_on_gdb_c_test == 1} {
+ pass "tracepoint on gdb_c_test"
+ } else {
+ fail "tracepoint on gdb_c_test"
+ }
+ if {$tp_on_gdb_asm_test == 1} {
+ pass "tracepoint on gdb_asm_test"
+ } else {
+ fail "tracepoint on gdb_asm_test"
+ }
+ if {$tp_on_gdb_recursion_test == 1} {
+ pass "tracepoint on gdb_recursion_test"
+ } else {
+ fail "tracepoint on gdb_recursion_test $tp_on_gdb_recursion_test"
+ }
+
+}}
+
+# Start and stop the tracing, so that we can save tracepoints
+# definitions to trace file.
+gdb_test_no_output "tstart" ""
+check_tracepoint "live"
+gdb_test_no_output "tstop" ""
+gdb_test "tsave ${testfile}.tf" \
+ "Trace data saved to file '${testfile}.tf'\.\\r"
+
+# Restart GDB and read the trace data in tfile target.
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_file_cmd $binfile
+gdb_test "target tfile ${testfile}.tf" ".*" \
+ "change to tfile target"
+check_tracepoint "tfile"
diff --git a/gdb/testsuite/gdb.trace/while-stepping.exp b/gdb/testsuite/gdb.trace/while-stepping.exp
index b80132b..0f316eb 100644
--- a/gdb/testsuite/gdb.trace/while-stepping.exp
+++ b/gdb/testsuite/gdb.trace/while-stepping.exp
@@ -99,3 +99,45 @@ gdb_test "info tracepoints" \
.*end.*" \
"5.16: confirm actions, step without collecting anything"
+gdb_test "break main"
+gdb_run_cmd
+gdb_test "" "Breakpoint .*"
+if ![gdb_target_supports_trace] {
+ unsupported "target does not support trace"
+ return -1;
+}
+
+gdb_trace_setactions "set stepcount to $stepcount" \
+ "" \
+ "while-stepping $stepcount" "" \
+ "collect \$regs " "^$" \
+ "collect \$locals " "^$" \
+ "end" ""
+
+proc check_tracepoint { data_source } { with_test_prefix "$data_source" {
+ global srcfile
+ global stepcount
+
+ gdb_test "info tracepoints" \
+ "Num Type\[ \]+Disp Enb Address\[ \]+What.*
+\[0-9\]+\[\t \]+tracepoint keep y.* in gdb_c_test at .*$srcfile:\[0-9\]+.
+\[\t \]+while-stepping $stepcount.*
+\[\t \]+collect \\\$regs.*
+\[\t \]+collect \\\$locals.*
+\[\t \]+end.*"
+}}
+
+gdb_test_no_output "tstart"
+check_tracepoint "live"
+gdb_test_no_output "tstop"
+gdb_test "tsave ${testfile}.tf" \
+ "Trace data saved to file '${testfile}.tf'\.\\r"
+
+# Restart GDB and read the trace data in tfile target.
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_file_cmd $binfile
+gdb_test "target tfile ${testfile}.tf" ".*" \
+ "change to tfile target"
+check_tracepoint "tfile"
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 13/15] Test on saving tracepoint defs.
2013-03-09 3:49 ` [PATCH v3 13/15] Test on saving tracepoint defs Yao Qi
@ 2013-03-12 20:10 ` Tom Tromey
2013-03-13 9:48 ` Yao Qi
0 siblings, 1 reply; 60+ messages in thread
From: Tom Tromey @ 2013-03-12 20:10 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes:
Yao> 2013-03-08 Yao Qi <yao@codesourcery.com>
Yao> * gdb.trace/actions.exp (check_tracepoint): New.
Yao> (top level): Start the tracing and check the actions of
Yao> tracepoints. Save trace data to tfile format. Restart GDB
Yao> and read trace file in tfile target. Check the actions of
Yao> tracepoints again.
Yao> * gdb.trace/while-stepping.exp: Likewise.
Yao> +gdb_test "break main"
Yao> +gdb_run_cmd
Yao> +gdb_test "" "Breakpoint .*"
I'd prefer some refactoring of gdb_run_cmd or runto instead.
gdb_test with an empty argument has always struck me as iffy.
Yao> +if ![gdb_target_supports_trace] {
Yao> + unsupported "target does not support trace"
Yao> + return -1;
No semicolon.
Yao> +gdb_test "tsave ${testfile}.tf" \
Yao> + "Trace data saved to file '${testfile}.tf'\.\\r"
Would you mind using standard_output_file?
Yao> +# Restart GDB and read the trace data in tfile target.
Yao> +gdb_exit
Yao> +gdb_start
Yao> +gdb_reinitialize_dir $srcdir/$subdir
Yao> +gdb_file_cmd $binfile
clean_restart?
Yao> +gdb_test "break main"
Yao> +gdb_run_cmd
Yao> +gdb_test "" "Breakpoint .*"
Yao> +if ![gdb_target_supports_trace] {
Yao> + unsupported "target does not support trace"
Yao> + return -1;
Yao> +}
Same comments here.
Yao> +proc check_tracepoint { data_source } { with_test_prefix "$data_source" {
Formatting of with_test_prefix.
(I forgot to mention it, but same in the other file.)
Yao> +# Restart GDB and read the trace data in tfile target.
Yao> +gdb_exit
Yao> +gdb_start
Yao> +gdb_reinitialize_dir $srcdir/$subdir
Yao> +gdb_file_cmd $binfile
clean_restart?
Yao> +gdb_test "target tfile ${testfile}.tf" ".*" \
Yao> + "change to tfile target"
standard_output_file
Tom
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 13/15] Test on saving tracepoint defs.
2013-03-12 20:10 ` Tom Tromey
@ 2013-03-13 9:48 ` Yao Qi
2013-03-13 14:58 ` Tom Tromey
0 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-13 9:48 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 03/13/2013 04:10 AM, Tom Tromey wrote:
> Yao> +gdb_test "break main"
> Yao> +gdb_run_cmd
> Yao> +gdb_test "" "Breakpoint .*"
>
> I'd prefer some refactoring of gdb_run_cmd or runto instead.
> gdb_test with an empty argument has always struck me as iffy.
I'll figure out a refactor of runto to replace existing gdb_test with an
empty argument in the whole testsuite.
>
> Yao> +if ![gdb_target_supports_trace] {
> Yao> + unsupported "target does not support trace"
> Yao> + return -1;
>
> No semicolon.
>
OK, I'll fix it here and somewhere else.
> Yao> +# Restart GDB and read the trace data in tfile target.
> Yao> +gdb_exit
> Yao> +gdb_start
> Yao> +gdb_reinitialize_dir $srcdir/$subdir
> Yao> +gdb_file_cmd $binfile
>
> clean_restart?
>
proc clean_restart doesn't help here, because we need "gdb_file_cmd" in
the last step instead of "gdb_load".
--
Yao (é½å°§)
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 13/15] Test on saving tracepoint defs.
2013-03-13 9:48 ` Yao Qi
@ 2013-03-13 14:58 ` Tom Tromey
0 siblings, 0 replies; 60+ messages in thread
From: Tom Tromey @ 2013-03-13 14:58 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
Yao> +# Restart GDB and read the trace data in tfile target.
Yao> +gdb_exit
Yao> +gdb_start
Yao> +gdb_reinitialize_dir $srcdir/$subdir
Yao> +gdb_file_cmd $binfile
Tom> clean_restart?
Yao> proc clean_restart doesn't help here, because we need "gdb_file_cmd"
Yao> in the last step instead of "gdb_load".
Oh yeah -- sorry about that.
Tom
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v3 06/15] Write status to CTF and read.
2013-03-09 3:48 [PATCH v3 00/15] CTF Support Yao Qi
2013-03-09 3:49 ` [PATCH v3 13/15] Test on saving tracepoint defs Yao Qi
@ 2013-03-09 3:49 ` Yao Qi
2013-03-12 19:31 ` Tom Tromey
2013-03-14 18:06 ` Doug Evans
2013-03-09 3:49 ` [PATCH v3 11/15] Write tsv definition in " Yao Qi
` (13 subsequent siblings)
15 siblings, 2 replies; 60+ messages in thread
From: Yao Qi @ 2013-03-09 3:49 UTC (permalink / raw)
To: gdb-patches
This patch teaches GDB to write trace status to CTF and also read
trace status from CTF trace file.
gdb:
2013-03-08 Yao Qi <yao@codesourcery.com>
* ctf.c (CTF_EVENT_ID_STATUS, ctf_save_write_int32): New
macros.
(ctf_save_metadata_header): Define new type alias in
metadata.
(ctf_write_header): Start a new faked packet for trace status.
(ctf_write_status): Write trace status to CTF.
(ctf_write_definition_end): End the faked packet.
(start_pos): New variable.
(SET_INT32_FIELD): New macro.
(ctf_read_status): New.
(ctf_open): Skip the first faked packet and assert on some
event types.
(ctf_trace_find): Set the iterator to the beginning of packet
including trace frames, instead of the first packet.
(ctf_get_trace_status): New.
(init_ctf_ops): Install ctf_get_trace_status to field
'to_get_trace_status'.
---
gdb/ctf.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 120 insertions(+), 7 deletions(-)
diff --git a/gdb/ctf.c b/gdb/ctf.c
index ec35b17..7be9bb6 100644
--- a/gdb/ctf.c
+++ b/gdb/ctf.c
@@ -34,7 +34,8 @@
1. The length (in bytes) of register cache. Event "register" will
be defined in metadata, which includes the length.
- 2. Trace status. Not implemented yet in CTF writer.
+ 2. Trace status. Event "status" is defined in metadata, which
+ includes all aspects of trace status.
3. Uploaded trace variables and tracepoints. Not implemented yet
in CTF writer.
@@ -65,6 +66,7 @@
#define CTF_EVENT_ID_TSV 1
#define CTF_EVENT_ID_MEMORY 2
#define CTF_EVENT_ID_FRAME 3
+#define CTF_EVENT_ID_STATUS 4
/* The state kept while writing the CTF datastream file. */
@@ -119,6 +121,12 @@ ctf_save_write (struct trace_write_handler *handler,
#define ctf_save_write_uint32(HANDLER, U32) \
ctf_save_write (HANDLER, (gdb_byte *) &U32, 4)
+/* Write a signed 32-bit integer to datastream file represented by
+ HANDLER. */
+
+#define ctf_save_write_int32(HANDLER, INT32) \
+ ctf_save_write (HANDLER, (gdb_byte *) &INT32, 4)
+
/* Set datastream file position. Update HANDLER->content_size
if WHENCE is SEEK_CUR. */
@@ -217,6 +225,9 @@ ctf_save_metadata_header (struct trace_write_handler *handler)
"typealias integer { size = 64; align = 64;"
"signed = false; base = hex;}"
" := uint64_t;\n");
+ ctf_save_write_metadata (handler,
+ "typealias integer { size = 32; align = 32;"
+ "signed = true; } := int32_t;\n");
ctf_save_write_metadata (handler, "\n");
ctf_save_write_metadata (handler, metadata_fmt,
@@ -343,6 +354,9 @@ ctf_write_header (struct trace_file_writer *self)
gdb_assert (writer->tcs.content_size == 0);
gdb_assert (writer->tcs.packet_start == 0);
+
+ /* Create a new packet to contain this event. */
+ self->ops->frame_ops->start (self, 0);
}
/* This is the implementation of trace_file_write_ops method
@@ -373,8 +387,39 @@ static void
ctf_write_status (struct trace_file_writer *self,
struct trace_status *ts)
{
- /* It is not supported yet to write trace status into CTF trace
- data. */
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ uint32_t id;
+ int32_t int32;
+
+ ctf_save_write_metadata (&writer->tcs, "\n");
+ ctf_save_write_metadata (&writer->tcs,
+ "event {\n\tname = \"status\";\n\tid = %u;\n"
+ "\tfields := struct { \n"
+ "\t\tint32_t stop_reason;\n"
+ "\t\tint32_t stopping_tracepoint;\n"
+ "\t\tint32_t traceframe_count;\n"
+ "\t\tint32_t traceframes_created;\n"
+ "\t\tint32_t buffer_free;\n"
+ "\t\tint32_t buffer_size;\n"
+ "\t\tint32_t disconnected_tracing;\n"
+ "\t\tint32_t circular_buffer;\n"
+ "\t};\n"
+ "};\n",
+ CTF_EVENT_ID_STATUS);
+
+ id = CTF_EVENT_ID_STATUS;
+ /* Event Id. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
+
+ ctf_save_write_int32 (&writer->tcs, ts->stop_reason);
+ ctf_save_write_int32 (&writer->tcs, ts->stopping_tracepoint);
+ ctf_save_write_int32 (&writer->tcs, ts->traceframe_count);
+ ctf_save_write_int32 (&writer->tcs, ts->traceframes_created);
+ ctf_save_write_int32 (&writer->tcs, ts->buffer_free);
+ ctf_save_write_int32 (&writer->tcs, ts->buffer_size);
+ ctf_save_write_int32 (&writer->tcs, ts->disconnected_tracing);
+ ctf_save_write_int32 (&writer->tcs, ts->circular_buffer);
}
/* This is the implementation of trace_file_write_ops method
@@ -405,7 +450,10 @@ ctf_write_uploaded_tp (struct trace_file_writer *self,
static void
ctf_write_definition_end (struct trace_file_writer *self)
{
- /* Nothing to do for CTF. */
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+
+ self->ops->frame_ops->end (self);
}
/* The minimal file size of data stream. It is required by
@@ -661,6 +709,9 @@ ctf_trace_file_writer_new (void)
/* The struct pointer for current CTF directory. */
static struct bt_context *ctx = NULL;
static struct bt_ctf_iter *ctf_iter = NULL;
+/* The position of the first packet containing trace frame. */
+struct bt_iter_pos *start_pos;
+
/* The name of CTF directory. */
static char *trace_dirname;
@@ -747,15 +798,66 @@ ctf_open_dir (char *dirname)
}
+#define SET_INT32_FIELD(EVENT, SCOPE, VAR, FIELD) \
+ VAR->FIELD = (int) bt_ctf_get_int64 (bt_ctf_get_field (EVENT, \
+ SCOPE, \
+ #FIELD))
+
+/* EVENT is the "status" event and TS is filled in. */
+
+static void
+ctf_read_status (struct bt_ctf_event *event, struct trace_status *ts)
+{
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event, BT_EVENT_FIELDS);
+
+ SET_INT32_FIELD (event, scope, ts, stop_reason);
+ SET_INT32_FIELD (event, scope, ts, stopping_tracepoint);
+ SET_INT32_FIELD (event, scope, ts, traceframe_count);
+ SET_INT32_FIELD (event, scope, ts, traceframes_created);
+ SET_INT32_FIELD (event, scope, ts, buffer_free);
+ SET_INT32_FIELD (event, scope, ts, buffer_size);
+ SET_INT32_FIELD (event, scope, ts, disconnected_tracing);
+ SET_INT32_FIELD (event, scope, ts, circular_buffer);
+}
+
static void
ctf_open (char *dirname, int from_tty)
{
+ struct bt_ctf_event *event;
+ uint32_t event_id;
+ const struct bt_definition *scope;
+
target_preopen (from_tty);
if (!dirname)
error (_("No CTF directory specified."));
ctf_open_dir (dirname);
+ /* Skip the first packet which about the trace status. The first
+ event is "frame". */
+ event = bt_ctf_iter_read_event (ctf_iter);
+ scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
+ event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+ gdb_assert (event_id == CTF_EVENT_ID_FRAME);
+ /* The second event is "status". */
+ gdb_assert (bt_iter_next (bt_ctf_get_iter (ctf_iter)) >= 0);
+ event = bt_ctf_iter_read_event (ctf_iter);
+ scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
+ event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+ gdb_assert (event_id == CTF_EVENT_ID_STATUS);
+ ctf_read_status (event, current_trace_status ());
+
+ /* The third event is "frame". A new packet. */
+ gdb_assert (bt_iter_next (bt_ctf_get_iter (ctf_iter)) >= 0);
+ event = bt_ctf_iter_read_event (ctf_iter);
+ scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
+ event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+ gdb_assert (event_id == CTF_EVENT_ID_FRAME);
+
+ start_pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (start_pos->type == BT_SEEK_RESTORE);
+
trace_dirname = xstrdup (dirname);
push_target (&ctf_ops);
}
@@ -1176,9 +1278,8 @@ ctf_trace_find (enum trace_find_type type, int num,
return -1;
}
- /* Set iterator back to the beginning. */
- pos.type = BT_SEEK_BEGIN;
- bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), &pos);
+ /* Set iterator back to the start. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), start_pos);
while (1)
{
@@ -1347,6 +1448,17 @@ ctf_traceframe_info (void)
return info;
}
+/* The trace status for a file is that tracing can never be run. */
+
+static int
+ctf_get_trace_status (struct trace_status *ts)
+{
+ /* Other bits of trace status were collected as part of opening the
+ trace files, so nothing to do here. */
+
+ return -1;
+}
+
static void
init_ctf_ops (void)
{
@@ -1359,6 +1471,7 @@ Specify the filename of the CTF directory.";
ctf_ops.to_fetch_registers = ctf_fetch_registers;
ctf_ops.to_xfer_partial = ctf_xfer_partial;
ctf_ops.to_files_info = ctf_files_info;
+ ctf_ops.to_get_trace_status = ctf_get_trace_status;
ctf_ops.to_trace_find = ctf_trace_find;
ctf_ops.to_get_trace_state_variable_value
= ctf_get_trace_state_variable_value;
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 06/15] Write status to CTF and read.
2013-03-09 3:49 ` [PATCH v3 06/15] Write status to CTF and read Yao Qi
@ 2013-03-12 19:31 ` Tom Tromey
2013-03-14 18:06 ` Doug Evans
1 sibling, 0 replies; 60+ messages in thread
From: Tom Tromey @ 2013-03-12 19:31 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes:
Yao> +/* The position of the first packet containing trace frame. */
Yao> +struct bt_iter_pos *start_pos;
It seems like this can be static.
Tom
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v3 06/15] Write status to CTF and read.
2013-03-09 3:49 ` [PATCH v3 06/15] Write status to CTF and read Yao Qi
2013-03-12 19:31 ` Tom Tromey
@ 2013-03-14 18:06 ` Doug Evans
2013-03-29 14:46 ` Yao Qi
1 sibling, 1 reply; 60+ messages in thread
From: Doug Evans @ 2013-03-14 18:06 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
Yao Qi writes:
> 2013-03-08 Yao Qi <yao@codesourcery.com>
>
> * ctf.c (CTF_EVENT_ID_STATUS, ctf_save_write_int32): New
> macros.
> (ctf_save_metadata_header): Define new type alias in
> metadata.
> (ctf_write_header): Start a new faked packet for trace status.
> (ctf_write_status): Write trace status to CTF.
> (ctf_write_definition_end): End the faked packet.
> (start_pos): New variable.
> (SET_INT32_FIELD): New macro.
> (ctf_read_status): New.
> (ctf_open): Skip the first faked packet and assert on some
> event types.
> (ctf_trace_find): Set the iterator to the beginning of packet
> including trace frames, instead of the first packet.
> (ctf_get_trace_status): New.
> (init_ctf_ops): Install ctf_get_trace_status to field
> 'to_get_trace_status'.
> @@ -747,15 +798,66 @@ ctf_open_dir (char *dirname)
>
> }
> [...]
> +#define SET_INT32_FIELD(EVENT, SCOPE, VAR, FIELD) \
> + VAR->FIELD = (int) bt_ctf_get_int64 (bt_ctf_get_field (EVENT, \
> + SCOPE, \
> + #FIELD))
Macros like this should be in a do { } while (0).
do { \
...; \
} while (0)
Plus wrap params in parens (except #FIELD of course).
> static void
> ctf_open (char *dirname, int from_tty)
> {
> + struct bt_ctf_event *event;
> + uint32_t event_id;
> + const struct bt_definition *scope;
> +
> target_preopen (from_tty);
> if (!dirname)
> error (_("No CTF directory specified."));
>
> ctf_open_dir (dirname);
>
> + /* Skip the first packet which about the trace status. The first
> + event is "frame". */
> + event = bt_ctf_iter_read_event (ctf_iter);
> + scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
> + event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
> + gdb_assert (event_id == CTF_EVENT_ID_FRAME);
Question: Will these asserts trigger on bad input data?
[If so, you need to use something else besides gdb_assert.]
> + /* The second event is "status". */
> + gdb_assert (bt_iter_next (bt_ctf_get_iter (ctf_iter)) >= 0);
> + event = bt_ctf_iter_read_event (ctf_iter);
> + scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
> + event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
> + gdb_assert (event_id == CTF_EVENT_ID_STATUS);
> + ctf_read_status (event, current_trace_status ());
> +
> + /* The third event is "frame". A new packet. */
> + gdb_assert (bt_iter_next (bt_ctf_get_iter (ctf_iter)) >= 0);
> + event = bt_ctf_iter_read_event (ctf_iter);
> + scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
> + event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
> + gdb_assert (event_id == CTF_EVENT_ID_FRAME);
> +
> + start_pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
> + gdb_assert (start_pos->type == BT_SEEK_RESTORE);
> +
> trace_dirname = xstrdup (dirname);
> push_target (&ctf_ops);
> }
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 06/15] Write status to CTF and read.
2013-03-14 18:06 ` Doug Evans
@ 2013-03-29 14:46 ` Yao Qi
2013-03-29 16:47 ` Doug Evans
0 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-29 14:46 UTC (permalink / raw)
To: Doug Evans; +Cc: gdb-patches
On 03/15/2013 02:06 AM, Doug Evans wrote:
> > +#define SET_INT32_FIELD(EVENT, SCOPE, VAR, FIELD) \
> > + VAR->FIELD = (int) bt_ctf_get_int64 (bt_ctf_get_field (EVENT, \
> > + SCOPE, \
> > + #FIELD))
>
> Macros like this should be in a do { } while (0).
> do { \
> ...; \
> } while (0)
>
Do we really need do/while loop for this single-line macro?
> Plus wrap params in parens (except #FIELD of course).
>
Of course.
> > static void
> > ctf_open (char *dirname, int from_tty)
> > {
> > + struct bt_ctf_event *event;
> > + uint32_t event_id;
> > + const struct bt_definition *scope;
> > +
> > target_preopen (from_tty);
> > if (!dirname)
> > error (_("No CTF directory specified."));
> >
> > ctf_open_dir (dirname);
> >
> > + /* Skip the first packet which about the trace status. The first
> > + event is "frame". */
> > + event = bt_ctf_iter_read_event (ctf_iter);
> > + scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
> > + event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
> > + gdb_assert (event_id == CTF_EVENT_ID_FRAME);
>
> Question: Will these asserts trigger on bad input data?
> [If so, you need to use something else besides gdb_assert.]
Yes, bad data will trigger assert. I change them to error.
--
Yao (é½å°§)
gdb:
2013-03-29 Yao Qi <yao@codesourcery.com>
* ctf.c (CTF_EVENT_ID_STATUS, ctf_save_write_int32): New
macros.
(ctf_save_metadata_header): Define new type alias in
metadata.
(ctf_write_header): Start a new faked packet for trace status.
(ctf_write_status): Write trace status to CTF.
(ctf_write_definition_end): End the faked packet.
(start_pos): New variable.
(SET_INT32_FIELD): New macro.
(ctf_read_status): New.
(ctf_open): Skip the first faked packet and assert on some
event types.
(ctf_trace_find): Set the iterator to the beginning of packet
including trace frames, instead of the first packet.
(ctf_get_trace_status): New.
(init_ctf_ops): Install ctf_get_trace_status to field
'to_get_trace_status'.
---
gdb/ctf.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 123 insertions(+), 7 deletions(-)
diff --git a/gdb/ctf.c b/gdb/ctf.c
index 14482f4..35b779d 100644
--- a/gdb/ctf.c
+++ b/gdb/ctf.c
@@ -35,7 +35,8 @@
1. The length (in bytes) of register cache. Event "register" will
be defined in metadata, which includes the length.
- 2. Trace status. Not implemented yet in CTF writer.
+ 2. Trace status. Event "status" is defined in metadata, which
+ includes all aspects of trace status.
3. Uploaded trace variables and tracepoints. Not implemented yet
in CTF writer.
@@ -66,6 +67,7 @@
#define CTF_EVENT_ID_TSV 1
#define CTF_EVENT_ID_MEMORY 2
#define CTF_EVENT_ID_FRAME 3
+#define CTF_EVENT_ID_STATUS 4
/* The state kept while writing the CTF datastream file. */
@@ -120,6 +122,12 @@ ctf_save_write (struct trace_write_handler *handler,
#define ctf_save_write_uint32(HANDLER, U32) \
ctf_save_write (HANDLER, (gdb_byte *) &U32, 4)
+/* Write a signed 32-bit integer to datastream file represented by
+ HANDLER. */
+
+#define ctf_save_write_int32(HANDLER, INT32) \
+ ctf_save_write ((HANDLER), (gdb_byte *) &(INT32), 4)
+
/* Set datastream file position. Update HANDLER->content_size
if WHENCE is SEEK_CUR. */
@@ -218,6 +226,9 @@ ctf_save_metadata_header (struct trace_write_handler *handler)
"typealias integer { size = 64; align = 64;"
"signed = false; base = hex;}"
" := uint64_t;\n");
+ ctf_save_write_metadata (handler,
+ "typealias integer { size = 32; align = 32;"
+ "signed = true; } := int32_t;\n");
ctf_save_write_metadata (handler, "\n");
/* Get the byte order of the host and write CTF data in this byte
@@ -368,6 +379,9 @@ ctf_write_header (struct trace_file_writer *self)
gdb_assert (writer->tcs.content_size == 0);
gdb_assert (writer->tcs.packet_start == 0);
+
+ /* Create a new packet to contain this event. */
+ self->ops->frame_ops->start (self, 0);
}
/* This is the implementation of trace_file_write_ops method
@@ -398,8 +412,39 @@ static void
ctf_write_status (struct trace_file_writer *self,
struct trace_status *ts)
{
- /* It is not supported yet to write trace status into CTF trace
- data. */
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ uint32_t id;
+ int32_t int32;
+
+ ctf_save_write_metadata (&writer->tcs, "\n");
+ ctf_save_write_metadata (&writer->tcs,
+ "event {\n\tname = \"status\";\n\tid = %u;\n"
+ "\tfields := struct { \n"
+ "\t\tint32_t stop_reason;\n"
+ "\t\tint32_t stopping_tracepoint;\n"
+ "\t\tint32_t traceframe_count;\n"
+ "\t\tint32_t traceframes_created;\n"
+ "\t\tint32_t buffer_free;\n"
+ "\t\tint32_t buffer_size;\n"
+ "\t\tint32_t disconnected_tracing;\n"
+ "\t\tint32_t circular_buffer;\n"
+ "\t};\n"
+ "};\n",
+ CTF_EVENT_ID_STATUS);
+
+ id = CTF_EVENT_ID_STATUS;
+ /* Event Id. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
+
+ ctf_save_write_int32 (&writer->tcs, ts->stop_reason);
+ ctf_save_write_int32 (&writer->tcs, ts->stopping_tracepoint);
+ ctf_save_write_int32 (&writer->tcs, ts->traceframe_count);
+ ctf_save_write_int32 (&writer->tcs, ts->traceframes_created);
+ ctf_save_write_int32 (&writer->tcs, ts->buffer_free);
+ ctf_save_write_int32 (&writer->tcs, ts->buffer_size);
+ ctf_save_write_int32 (&writer->tcs, ts->disconnected_tracing);
+ ctf_save_write_int32 (&writer->tcs, ts->circular_buffer);
}
/* This is the implementation of trace_file_write_ops method
@@ -430,7 +475,10 @@ ctf_write_uploaded_tp (struct trace_file_writer *self,
static void
ctf_write_definition_end (struct trace_file_writer *self)
{
- /* Nothing to do for CTF. */
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+
+ self->ops->frame_ops->end (self);
}
/* The minimal file size of data stream. It is required by
@@ -685,6 +733,9 @@ ctf_trace_file_writer_new (void)
/* The struct pointer for current CTF directory. */
static struct bt_context *ctx = NULL;
static struct bt_ctf_iter *ctf_iter = NULL;
+/* The position of the first packet containing trace frame. */
+static struct bt_iter_pos *start_pos;
+
/* The name of CTF directory. */
static char *trace_dirname;
@@ -773,6 +824,29 @@ ctf_open_dir (char *dirname)
}
+#define SET_INT32_FIELD(EVENT, SCOPE, VAR, FIELD) \
+ (VAR)->FIELD = (int) bt_ctf_get_int64 (bt_ctf_get_field ((EVENT), \
+ (SCOPE), \
+ #FIELD))
+
+/* EVENT is the "status" event and TS is filled in. */
+
+static void
+ctf_read_status (struct bt_ctf_event *event, struct trace_status *ts)
+{
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event, BT_EVENT_FIELDS);
+
+ SET_INT32_FIELD (event, scope, ts, stop_reason);
+ SET_INT32_FIELD (event, scope, ts, stopping_tracepoint);
+ SET_INT32_FIELD (event, scope, ts, traceframe_count);
+ SET_INT32_FIELD (event, scope, ts, traceframes_created);
+ SET_INT32_FIELD (event, scope, ts, buffer_free);
+ SET_INT32_FIELD (event, scope, ts, buffer_size);
+ SET_INT32_FIELD (event, scope, ts, disconnected_tracing);
+ SET_INT32_FIELD (event, scope, ts, circular_buffer);
+}
+
/* This is the implementation of target_ops method to_open. Open CTF
trace data, read trace status, trace state variables and tracepoint
definitions from the first packet. Set the start position at the
@@ -781,12 +855,42 @@ ctf_open_dir (char *dirname)
static void
ctf_open (char *dirname, int from_tty)
{
+ struct bt_ctf_event *event;
+ uint32_t event_id;
+ const struct bt_definition *scope;
+
if (!dirname)
error (_("No CTF directory specified."));
ctf_open_dir (dirname);
target_preopen (from_tty);
+
+ /* Skip the first packet which about the trace status. The first
+ event is "frame". */
+ event = bt_ctf_iter_read_event (ctf_iter);
+ scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
+ event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+ if (event_id != CTF_EVENT_ID_FRAME)
+ error (_("Wrong event id of the first event"));
+ /* The second event is "status". */
+ event = bt_ctf_iter_read_event (ctf_iter);
+ scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
+ event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+ if (event_id != CTF_EVENT_ID_STATUS)
+ error (_("Wrong event id of the second event"));
+ ctf_read_status (event, current_trace_status ());
+
+ /* The third event is "frame". A new packet. */
+ event = bt_ctf_iter_read_event (ctf_iter);
+ scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
+ event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+ if (event_id != CTF_EVENT_ID_FRAME)
+ error (_("Wrong event id of the first event of the second packet"));
+
+ start_pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (start_pos->type == BT_SEEK_RESTORE);
+
trace_dirname = xstrdup (dirname);
push_target (&ctf_ops);
}
@@ -1218,9 +1322,8 @@ ctf_trace_find (enum trace_find_type type, int num,
}
gdb_assert (ctf_iter != NULL);
- /* Set iterator back to the beginning. */
- pos.type = BT_SEEK_BEGIN;
- bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), &pos);
+ /* Set iterator back to the start. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), start_pos);
while (1)
{
@@ -1380,6 +1483,18 @@ ctf_traceframe_info (void)
return info;
}
+/* This is the implementation of target_ops method to_get_trace_status.
+ The trace status for a file is that tracing can never be run. */
+
+static int
+ctf_get_trace_status (struct trace_status *ts)
+{
+ /* Other bits of trace status were collected as part of opening the
+ trace files, so nothing to do here. */
+
+ return -1;
+}
+
static void
init_ctf_ops (void)
{
@@ -1394,6 +1509,7 @@ Specify the filename of the CTF directory.";
ctf_ops.to_fetch_registers = ctf_fetch_registers;
ctf_ops.to_xfer_partial = ctf_xfer_partial;
ctf_ops.to_files_info = ctf_files_info;
+ ctf_ops.to_get_trace_status = ctf_get_trace_status;
ctf_ops.to_trace_find = ctf_trace_find;
ctf_ops.to_get_trace_state_variable_value
= ctf_get_trace_state_variable_value;
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 06/15] Write status to CTF and read.
2013-03-29 14:46 ` Yao Qi
@ 2013-03-29 16:47 ` Doug Evans
0 siblings, 0 replies; 60+ messages in thread
From: Doug Evans @ 2013-03-29 16:47 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
On Fri, Mar 29, 2013 at 12:23 AM, Yao Qi <yao@codesourcery.com> wrote:
> On 03/15/2013 02:06 AM, Doug Evans wrote:
>> > +#define SET_INT32_FIELD(EVENT, SCOPE, VAR, FIELD) \
>> > + VAR->FIELD = (int) bt_ctf_get_int64 (bt_ctf_get_field (EVENT, \
>> > + SCOPE, \
>> > + #FIELD))
>>
>> Macros like this should be in a do { } while (0).
>> do { \
>> ...; \
>> } while (0)
>>
>
> Do we really need do/while loop for this single-line macro?
Always IMO.
>> Plus wrap params in parens (except #FIELD of course).
>>
>
> Of course.
Look at it as wrapping the statement in a do/while is like wrapping
the params in parens. :-)
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v3 11/15] Write tsv definition in CTF and read
2013-03-09 3:48 [PATCH v3 00/15] CTF Support Yao Qi
2013-03-09 3:49 ` [PATCH v3 13/15] Test on saving tracepoint defs Yao Qi
2013-03-09 3:49 ` [PATCH v3 06/15] Write status to CTF and read Yao Qi
@ 2013-03-09 3:49 ` Yao Qi
2013-03-12 19:56 ` Tom Tromey
2013-03-09 3:49 ` [PATCH v3 01/15] Refactor 'tsave' Yao Qi
` (12 subsequent siblings)
15 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-09 3:49 UTC (permalink / raw)
To: gdb-patches
This patch teaches GDB to write uploaded tsv to CTF, and also read
them out from CTF.
gdb:
2013-03-08 Yao Qi <yao@codesourcery.com>
* ctf.c (CTF_EVENT_ID_TSV_DEF): New macro.
(ctf_save_metadata_header): Define new type alias in
metadata.
(ctf_write_header): Define new event type "tsv_def".
(ctf_write_uploaded_tsv): Write TSV to CTF.
(ctf_read_tsv): New.
(ctf_open): Call ctf_read_tsv and
merge_uploaded_trace_state_variables.
* tracepoint.c (get_uploaded_tsv): Remove 'static'.
* tracepoint.h (get_uploaded_tsv): Declare.
---
gdb/ctf.c | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++---
gdb/tracepoint.c | 2 +-
gdb/tracepoint.h | 2 +
3 files changed, 97 insertions(+), 6 deletions(-)
diff --git a/gdb/ctf.c b/gdb/ctf.c
index 7be9bb6..934ba10 100644
--- a/gdb/ctf.c
+++ b/gdb/ctf.c
@@ -37,8 +37,9 @@
2. Trace status. Event "status" is defined in metadata, which
includes all aspects of trace status.
- 3. Uploaded trace variables and tracepoints. Not implemented yet
- in CTF writer.
+ 3. Uploaded trace variables. Event "tsv_def" is defined in metata,
+ which is about all aspects of a uploaded trace variable.
+ Uploaded tracepoints. Not implemented yet in CTF writer.
4. Trace frames. Each trace frame is composed by several blocks
of different types ('R', 'M', 'V'). One trace frame is saved in
@@ -67,6 +68,7 @@
#define CTF_EVENT_ID_MEMORY 2
#define CTF_EVENT_ID_FRAME 3
#define CTF_EVENT_ID_STATUS 4
+#define CTF_EVENT_ID_TSV_DEF 5
/* The state kept while writing the CTF datastream file. */
@@ -228,6 +230,12 @@ ctf_save_metadata_header (struct trace_write_handler *handler)
ctf_save_write_metadata (handler,
"typealias integer { size = 32; align = 32;"
"signed = true; } := int32_t;\n");
+ ctf_save_write_metadata (handler,
+ "typealias integer { size = 64; align = 64;"
+ "signed = true; } := int64_t;\n");
+ ctf_save_write_metadata (handler,
+ "typealias string { encoding = ascii;"
+ " } := chars;\n");
ctf_save_write_metadata (handler, "\n");
ctf_save_write_metadata (handler, metadata_fmt,
@@ -352,6 +360,17 @@ ctf_write_header (struct trace_file_writer *self)
"\t};\n"
"};\n", CTF_EVENT_ID_FRAME);
+ ctf_save_write_metadata (&writer->tcs, "\n");
+ ctf_save_write_metadata (&writer->tcs,
+ "event {\n\tname = \"tsv_def\";\n"
+ "\tid = %u;\n\tfields := struct { \n"
+ "\t\tint64_t initial_value;\n"
+ "\t\tint32_t number;\n"
+ "\t\tint32_t builtin;\n"
+ "\t\tchars name;\n"
+ "\t};\n"
+ "};\n", CTF_EVENT_ID_TSV_DEF);
+
gdb_assert (writer->tcs.content_size == 0);
gdb_assert (writer->tcs.packet_start == 0);
@@ -429,8 +448,31 @@ static void
ctf_write_uploaded_tsv (struct trace_file_writer *self,
struct uploaded_tsv *tsv)
{
- /* It is not supported yet to write uploaded trace variables
- into CTF trace data. */
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ int32_t int32;
+ int64_t int64;
+ unsigned int len;
+ const gdb_byte zero = 0;
+
+ /* Event Id. */
+ int32 = CTF_EVENT_ID_TSV_DEF;
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &int32, 4, 4);
+
+ /* initial_value */
+ int64 = tsv->initial_value;
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &int64, 8, 8);
+
+ /* number */
+ ctf_save_write_int32 (&writer->tcs, tsv->number);
+
+ /* builtin */
+ ctf_save_write_int32 (&writer->tcs, tsv->builtin);
+
+ /* name */
+ if (tsv->name != NULL)
+ ctf_save_write (&writer->tcs, tsv->name, strlen (tsv->name));
+ ctf_save_write (&writer->tcs, &zero, 1);
}
/* This is the implementation of trace_file_write_ops method
@@ -821,12 +863,56 @@ ctf_read_status (struct bt_ctf_event *event, struct trace_status *ts)
SET_INT32_FIELD (event, scope, ts, circular_buffer);
}
+/* Read the events "tsv_def" one by one, extract its contents and fill
+ in the list UPLOADED_TSVS. */
+
+static void
+ctf_read_tsv (struct uploaded_tsv **uploaded_tsvs)
+{
+ while (1)
+ {
+ struct bt_ctf_event *event;
+ const struct bt_definition *scope;
+ const struct bt_definition *def;
+ uint32_t event_id;
+ struct uploaded_tsv *utsv = NULL;
+
+ event = bt_ctf_iter_read_event (ctf_iter);
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_STREAM_EVENT_HEADER);
+ event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope,
+ "id"));
+ if (event_id != CTF_EVENT_ID_TSV_DEF)
+ break;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+
+ def = bt_ctf_get_field (event, scope, "number");
+ utsv = get_uploaded_tsv ((int32_t) bt_ctf_get_int64 (def),
+ uploaded_tsvs);
+
+ def = bt_ctf_get_field (event, scope, "builtin");
+ utsv->builtin = (int32_t) bt_ctf_get_int64 (def);
+ def = bt_ctf_get_field (event, scope, "initial_value");
+ utsv->initial_value = bt_ctf_get_int64 (def);
+
+ def = bt_ctf_get_field (event, scope, "name");
+ utsv->name = xstrdup (bt_ctf_get_string (def));
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+}
+
static void
ctf_open (char *dirname, int from_tty)
{
struct bt_ctf_event *event;
uint32_t event_id;
const struct bt_definition *scope;
+ struct uploaded_tsv *uploaded_tsvs = NULL;
target_preopen (from_tty);
if (!dirname)
@@ -848,8 +934,9 @@ ctf_open (char *dirname, int from_tty)
gdb_assert (event_id == CTF_EVENT_ID_STATUS);
ctf_read_status (event, current_trace_status ());
- /* The third event is "frame". A new packet. */
gdb_assert (bt_iter_next (bt_ctf_get_iter (ctf_iter)) >= 0);
+ ctf_read_tsv (&uploaded_tsvs);
+
event = bt_ctf_iter_read_event (ctf_iter);
scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
@@ -860,6 +947,8 @@ ctf_open (char *dirname, int from_tty)
trace_dirname = xstrdup (dirname);
push_target (&ctf_ops);
+
+ merge_uploaded_trace_state_variables (&uploaded_tsvs);
}
static void
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 850adb9..3656767 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -3798,7 +3798,7 @@ free_uploaded_tps (struct uploaded_tp **utpp)
/* Given a number and address, return an uploaded tracepoint with that
number, creating if necessary. */
-static struct uploaded_tsv *
+struct uploaded_tsv *
get_uploaded_tsv (int num, struct uploaded_tsv **utsvp)
{
struct uploaded_tsv *utsv;
diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
index 8762d1c..765f455 100644
--- a/gdb/tracepoint.h
+++ b/gdb/tracepoint.h
@@ -378,6 +378,8 @@ extern void parse_tsv_definition (char *line, struct uploaded_tsv **utsvp);
extern struct uploaded_tp *get_uploaded_tp (int num, ULONGEST addr,
struct uploaded_tp **utpp);
+extern struct uploaded_tsv *get_uploaded_tsv (int num,
+ struct uploaded_tsv **utsvp);
extern struct tracepoint *create_tracepoint_from_upload (struct uploaded_tp *utp);
extern void merge_uploaded_tracepoints (struct uploaded_tp **utpp);
extern void merge_uploaded_trace_state_variables (struct uploaded_tsv **utsvp);
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 11/15] Write tsv definition in CTF and read
2013-03-09 3:49 ` [PATCH v3 11/15] Write tsv definition in " Yao Qi
@ 2013-03-12 19:56 ` Tom Tromey
0 siblings, 0 replies; 60+ messages in thread
From: Tom Tromey @ 2013-03-12 19:56 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes:
Yao> 2013-03-08 Yao Qi <yao@codesourcery.com>
Yao> * ctf.c (CTF_EVENT_ID_TSV_DEF): New macro.
Yao> (ctf_save_metadata_header): Define new type alias in
Yao> metadata.
Yao> (ctf_write_header): Define new event type "tsv_def".
Yao> (ctf_write_uploaded_tsv): Write TSV to CTF.
Yao> (ctf_read_tsv): New.
Yao> (ctf_open): Call ctf_read_tsv and
Yao> merge_uploaded_trace_state_variables.
Yao> * tracepoint.c (get_uploaded_tsv): Remove 'static'.
Yao> * tracepoint.h (get_uploaded_tsv): Declare.
Yao> + 3. Uploaded trace variables. Event "tsv_def" is defined in metata,
Typo, "metadata".
Otherwise this looks ok to me.
Tom
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v3 01/15] Refactor 'tsave'
2013-03-09 3:48 [PATCH v3 00/15] CTF Support Yao Qi
` (2 preceding siblings ...)
2013-03-09 3:49 ` [PATCH v3 11/15] Write tsv definition in " Yao Qi
@ 2013-03-09 3:49 ` Yao Qi
2013-03-12 18:30 ` Tom Tromey
2013-03-09 3:49 ` [PATCH v3 08/15] Write 'stop_desc' of trace status to tfile Yao Qi
` (11 subsequent siblings)
15 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-09 3:49 UTC (permalink / raw)
To: gdb-patches
Hello,
The existing GDB code on saving trace data to trace file is highly
related to TFILE format, which makes some difficulties on supporting a
new trace file format, such as CTF. It is idea to de-couple trace
saving with actual trace file format. This is what this patch does.
With this patch applied, "tsave" command uses some operations vectors
to write data and the logic in "tsave" is not related to any specific
trace format.
gdb:
2013-03-08 Yao Qi <yao@codesourcery.com>
* tracepoint.c (trace_file_writer_xfree): New.
(struct tfile_writer_data): New.
(tfile_can_target_save, tfile_start): New.
(tfile_write_header, tfile_write_regblock_type): New.
(tfile_write_status, tfile_write_uploaded_tsv): New.
(tfile_write_uploaded_tp, tfile_write_definition_end): New.
(tfile_write_raw_data, (tfile_end): New.
(tfile_write_ops): New global variable.
(TRACE_WRITE_R_BLOCK): New macro.
(TRACE_WRITE_M_BLOCK_HEADER): New macro.
(TRACE_WRITE_M_BLOCK_MEMORY): New macro.
(TRACE_WRITE_V_BLOCK): New macro.
(trace_save): Add extra one parameter WRITER. Make it static.
Use WRITER to writer trace.
(tfile_trace_file_writer_new): New.
(trace_save_command): Caller update.
(trace_save_tfile): Write trace data in TFILE format.
* tracepoint.h (struct trace_frame_write_ops): New.
(struct trace_file_write_ops): New.
(struct trace_file_writer): New.
(trace_save): Remove its declaration.
(trace_save_tfile): Declare it.
* mi/mi-main.c (mi_cmd_trace_save): Call trace_save_tfile
instead of trace_save.
---
gdb/mi/mi-main.c | 2 +-
gdb/tracepoint.c | 627 +++++++++++++++++++++++++++++++++++++++++++-----------
gdb/tracepoint.h | 104 +++++++++-
3 files changed, 602 insertions(+), 131 deletions(-)
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 37294e0..206b626 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -2495,7 +2495,7 @@ mi_cmd_trace_save (char *command, char **argv, int argc)
filename = argv[0];
}
- trace_save (filename, target_saves);
+ trace_save_tfile (filename, target_saves);
}
void
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 2a4b245..e3a42e2 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -2969,90 +2969,326 @@ encode_source_string (int tpnum, ULONGEST addr,
return -1;
}
-extern int trace_regblock_size;
+/* Free trace file writer. */
-/* Save tracepoint data to file named FILENAME. If TARGET_DOES_SAVE is
- non-zero, the save is performed on the target, otherwise GDB obtains all
- trace data and saves it locally. */
+static void
+trace_file_writer_xfree (void *arg)
+{
+ xfree (arg);
+}
-void
-trace_save (const char *filename, int target_does_save)
+/* TFILE trace writer. */
+
+struct tfile_trace_file_writer
{
- struct cleanup *cleanup;
- char *pathname;
- struct trace_status *ts = current_trace_status ();
- int err, status;
+ struct trace_file_writer base;
+
+ /* File pointer to tfile trace file. */
FILE *fp;
- struct uploaded_tp *uploaded_tps = NULL, *utp;
- struct uploaded_tsv *uploaded_tsvs = NULL, *utsv;
- int a;
- char *act;
- LONGEST gotten = 0;
- ULONGEST offset = 0;
-#define MAX_TRACE_UPLOAD 2000
- gdb_byte buf[MAX_TRACE_UPLOAD];
- int written;
+ /* Path name of the tfile trace file. */
+ char *pathname;
- /* If the target is to save the data to a file on its own, then just
- send the command and be done with it. */
- if (target_does_save)
- {
- err = target_save_trace_data (filename);
- if (err < 0)
- error (_("Target failed to save trace data to '%s'."),
- filename);
- return;
- }
+ struct cleanup *cleanup;
+};
- /* Get the trace status first before opening the file, so if the
- target is losing, we can get out without touching files. */
- status = target_get_trace_status (ts);
+/* This is the implementation of trace_file_write_ops method
+ target_save. We just call the generic target
+ target_save_trace_data to do target-side saving. */
+
+static int
+tfile_target_save (struct trace_file_writer *self,
+ const char *filename)
+{
+ int err = target_save_trace_data (filename);
- pathname = tilde_expand (filename);
- cleanup = make_cleanup (xfree, pathname);
+ return (err >= 0);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ start. It creates the trace file FILENAME and registers some
+ cleanups. */
- fp = fopen (pathname, "wb");
- if (!fp)
+static void
+tfile_start (struct trace_file_writer *self, const char *filename)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ writer->pathname = tilde_expand (filename);
+ writer->cleanup = make_cleanup (xfree, writer->pathname);
+ writer->fp = fopen (writer->pathname, "wb");
+ if (writer->fp == NULL)
error (_("Unable to open file '%s' for saving trace data (%s)"),
filename, safe_strerror (errno));
- make_cleanup_fclose (fp);
+ make_cleanup_fclose (writer->fp);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_header. Write the TFILE header. */
+
+static void
+tfile_write_header (struct trace_file_writer *self)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+ int written;
/* Write a file header, with a high-bit-set char to indicate a
binary file, plus a hint as what this file is, and a version
number in case of future needs. */
- written = fwrite ("\x7fTRACE0\n", 8, 1, fp);
+ written = fwrite ("\x7fTRACE0\n", 8, 1, writer->fp);
if (written < 1)
- perror_with_name (pathname);
+ perror_with_name (writer->pathname);
+}
- /* Write descriptive info. */
+/* This is the implementation of trace_file_write_ops method
+ write_regblock_type. Write the size of register block. */
- /* Write out the size of a register block. */
- fprintf (fp, "R %x\n", trace_regblock_size);
+static void
+tfile_write_regblock_type (struct trace_file_writer *self, int size)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
- /* Write out status of the tracing run (aka "tstatus" info). */
- fprintf (fp, "status %c;%s",
+ fprintf (writer->fp, "R %x\n", size);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_status. */
+
+static void
+tfile_write_status (struct trace_file_writer *self,
+ struct trace_status *ts)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ fprintf (writer->fp, "status %c;%s",
(ts->running ? '1' : '0'), stop_reason_names[ts->stop_reason]);
if (ts->stop_reason == tracepoint_error)
{
char *buf = (char *) alloca (strlen (ts->stop_desc) * 2 + 1);
bin2hex ((gdb_byte *) ts->stop_desc, buf, 0);
- fprintf (fp, ":%s", buf);
+ fprintf (writer->fp, ":%s", buf);
}
- fprintf (fp, ":%x", ts->stopping_tracepoint);
+ fprintf (writer->fp, ":%x", ts->stopping_tracepoint);
if (ts->traceframe_count >= 0)
- fprintf (fp, ";tframes:%x", ts->traceframe_count);
+ fprintf (writer->fp, ";tframes:%x", ts->traceframe_count);
if (ts->traceframes_created >= 0)
- fprintf (fp, ";tcreated:%x", ts->traceframes_created);
+ fprintf (writer->fp, ";tcreated:%x", ts->traceframes_created);
if (ts->buffer_free >= 0)
- fprintf (fp, ";tfree:%x", ts->buffer_free);
+ fprintf (writer->fp, ";tfree:%x", ts->buffer_free);
if (ts->buffer_size >= 0)
- fprintf (fp, ";tsize:%x", ts->buffer_size);
+ fprintf (writer->fp, ";tsize:%x", ts->buffer_size);
if (ts->disconnected_tracing)
- fprintf (fp, ";disconn:%x", ts->disconnected_tracing);
+ fprintf (writer->fp, ";disconn:%x", ts->disconnected_tracing);
if (ts->circular_buffer)
- fprintf (fp, ";circular:%x", ts->circular_buffer);
- fprintf (fp, "\n");
+ fprintf (writer->fp, ";circular:%x", ts->circular_buffer);
+ fprintf (writer->fp, "\n");
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_uploaded_tsv. */
+
+static void
+tfile_write_uploaded_tsv (struct trace_file_writer *self,
+ struct uploaded_tsv *utsv)
+{
+ char *buf = "";
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ if (utsv->name)
+ {
+ buf = (char *) xmalloc (strlen (utsv->name) * 2 + 1);
+ bin2hex ((gdb_byte *) (utsv->name), buf, 0);
+ }
+
+ fprintf (writer->fp, "tsv %x:%s:%x:%s\n",
+ utsv->number, phex_nz (utsv->initial_value, 8),
+ utsv->builtin, buf);
+
+ if (utsv->name)
+ xfree (buf);
+}
+
+#define MAX_TRACE_UPLOAD 2000
+
+/* This is the implementation of trace_file_write_ops method
+ write_uploaded_tp. */
+
+static void
+tfile_write_uploaded_tp (struct trace_file_writer *self,
+ struct uploaded_tp *utp)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+ int a;
+ char *act;
+ gdb_byte buf[MAX_TRACE_UPLOAD];
+
+ fprintf (writer->fp, "tp T%x:%s:%c:%x:%x",
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
+ (utp->enabled ? 'E' : 'D'), utp->step, utp->pass);
+ if (utp->type == bp_fast_tracepoint)
+ fprintf (writer->fp, ":F%x", utp->orig_size);
+ if (utp->cond)
+ fprintf (writer->fp,
+ ":X%x,%s", (unsigned int) strlen (utp->cond) / 2,
+ utp->cond);
+ fprintf (writer->fp, "\n");
+ for (a = 0; VEC_iterate (char_ptr, utp->actions, a, act); ++a)
+ fprintf (writer->fp, "tp A%x:%s:%s\n",
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
+ for (a = 0; VEC_iterate (char_ptr, utp->step_actions, a, act); ++a)
+ fprintf (writer->fp, "tp S%x:%s:%s\n",
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
+ if (utp->at_string)
+ {
+ encode_source_string (utp->number, utp->addr,
+ "at", utp->at_string, buf, MAX_TRACE_UPLOAD);
+ fprintf (writer->fp, "tp Z%s\n", buf);
+ }
+ if (utp->cond_string)
+ {
+ encode_source_string (utp->number, utp->addr,
+ "cond", utp->cond_string,
+ buf, MAX_TRACE_UPLOAD);
+ fprintf (writer->fp, "tp Z%s\n", buf);
+ }
+ for (a = 0; VEC_iterate (char_ptr, utp->cmd_strings, a, act); ++a)
+ {
+ encode_source_string (utp->number, utp->addr, "cmd", act,
+ buf, MAX_TRACE_UPLOAD);
+ fprintf (writer->fp, "tp Z%s\n", buf);
+ }
+ fprintf (writer->fp, "tp V%x:%s:%x:%s\n",
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
+ utp->hit_count,
+ phex_nz (utp->traceframe_usage,
+ sizeof (utp->traceframe_usage)));
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_definition_end. */
+
+static void
+tfile_write_definition_end (struct trace_file_writer *self)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ fprintf (writer->fp, "\n");
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_raw_data. */
+
+static void
+tfile_write_raw_data (struct trace_file_writer *self, gdb_byte *buf,
+ LONGEST len)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ if (fwrite (buf, len, 1, writer->fp) < 1)
+ perror_with_name (writer->pathname);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ end. */
+
+static void
+tfile_end (struct trace_file_writer *self)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+ uint32_t gotten = 0;
+
+ /* Mark the end of trace data. */
+ if (fwrite (&gotten, 4, 1, writer->fp) < 1)
+ perror_with_name (writer->pathname);
+
+ do_cleanups (writer->cleanup);
+}
+
+/* Operations to write trace buffers into TFILE format. */
+
+static const struct trace_file_write_ops tfile_write_ops =
+{
+ tfile_target_save,
+ tfile_start,
+ tfile_write_header,
+ tfile_write_regblock_type,
+ tfile_write_status,
+ tfile_write_uploaded_tsv,
+ tfile_write_uploaded_tp,
+ tfile_write_definition_end,
+ tfile_write_raw_data,
+ NULL,
+ tfile_end,
+};
+
+/* Helper macros. */
+
+#define TRACE_WRITE_R_BLOCK(writer, buf, size) \
+ writer->ops->frame_ops->write_r_block ((writer), (buf), (size))
+#define TRACE_WRITE_M_BLOCK_HEADER(writer, addr, size) \
+ writer->ops->frame_ops->write_m_block_header ((writer), (addr), \
+ (size))
+#define TRACE_WRITE_M_BLOCK_MEMORY(writer, buf, size) \
+ writer->ops->frame_ops->write_m_block_memory ((writer), (buf), \
+ (size))
+#define TRACE_WRITE_V_BLOCK(writer, num, val) \
+ writer->ops->frame_ops->write_v_block ((writer), (num), (val))
+
+extern int trace_regblock_size;
+
+/* Save tracepoint data to file named FILENAME through WRITER. WRITER
+ determines the trace file format. If TARGET_DOES_SAVE is non-zero,
+ the save is performed on the target, otherwise GDB obtains all trace
+ data and saves it locally. */
+
+static void
+trace_save (const char *filename, struct trace_file_writer *writer,
+ int target_does_save)
+{
+ struct trace_status *ts = current_trace_status ();
+ int status;
+ struct uploaded_tp *uploaded_tps = NULL, *utp;
+ struct uploaded_tsv *uploaded_tsvs = NULL, *utsv;
+
+ ULONGEST offset = 0;
+ gdb_byte buf[MAX_TRACE_UPLOAD];
+ int written;
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
+
+ /* If the target is to save the data to a file on its own, then just
+ send the command and be done with it. */
+ if (target_does_save)
+ {
+ if (!writer->ops->target_save (writer, filename))
+ error (_("Target failed to save trace data to '%s'."),
+ filename);
+ return;
+ }
+
+ /* Get the trace status first before opening the file, so if the
+ target is losing, we can get out without touching files. */
+ status = target_get_trace_status (ts);
+
+ writer->ops->start (writer, filename);
+
+ writer->ops->write_header (writer);
+
+ /* Write descriptive info. */
+
+ /* Write out the size of a register block. */
+ writer->ops->write_regblock_type (writer, trace_regblock_size);
+
+ /* Write out status of the tracing run (aka "tstatus" info). */
+ writer->ops->write_status (writer, ts);
/* Note that we want to upload tracepoints and save those, rather
than simply writing out the local ones, because the user may have
@@ -3067,22 +3303,7 @@ trace_save (const char *filename, int target_does_save)
target_upload_trace_state_variables (&uploaded_tsvs);
for (utsv = uploaded_tsvs; utsv; utsv = utsv->next)
- {
- char *buf = "";
-
- if (utsv->name)
- {
- buf = (char *) xmalloc (strlen (utsv->name) * 2 + 1);
- bin2hex ((gdb_byte *) (utsv->name), buf, 0);
- }
-
- fprintf (fp, "tsv %x:%s:%x:%s\n",
- utsv->number, phex_nz (utsv->initial_value, 8),
- utsv->builtin, buf);
-
- if (utsv->name)
- xfree (buf);
- }
+ writer->ops->write_uploaded_tsv (writer, utsv);
free_uploaded_tsvs (&uploaded_tsvs);
@@ -3092,76 +3313,205 @@ trace_save (const char *filename, int target_does_save)
target_get_tracepoint_status (NULL, utp);
for (utp = uploaded_tps; utp; utp = utp->next)
+ writer->ops->write_uploaded_tp (writer, utp);
+
+ free_uploaded_tps (&uploaded_tps);
+
+ /* Mark the end of the definition section. */
+ writer->ops->write_definition_end (writer);
+
+ /* Get and write the trace data proper. */
+ while (1)
{
- fprintf (fp, "tp T%x:%s:%c:%x:%x",
- utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
- (utp->enabled ? 'E' : 'D'), utp->step, utp->pass);
- if (utp->type == bp_fast_tracepoint)
- fprintf (fp, ":F%x", utp->orig_size);
- if (utp->cond)
- fprintf (fp, ":X%x,%s", (unsigned int) strlen (utp->cond) / 2,
- utp->cond);
- fprintf (fp, "\n");
- for (a = 0; VEC_iterate (char_ptr, utp->actions, a, act); ++a)
- fprintf (fp, "tp A%x:%s:%s\n",
- utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
- for (a = 0; VEC_iterate (char_ptr, utp->step_actions, a, act); ++a)
- fprintf (fp, "tp S%x:%s:%s\n",
- utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
- if (utp->at_string)
- {
- encode_source_string (utp->number, utp->addr,
- "at", utp->at_string, buf, MAX_TRACE_UPLOAD);
- fprintf (fp, "tp Z%s\n", buf);
- }
- if (utp->cond_string)
+ LONGEST gotten = 0;
+
+ /* The writer supports writing the contents of trace buffer
+ directly to trace file. Don't parse the contents of trace
+ buffer. */
+ if (writer->ops->write_trace_buffer != NULL)
{
- encode_source_string (utp->number, utp->addr,
- "cond", utp->cond_string,
- buf, MAX_TRACE_UPLOAD);
- fprintf (fp, "tp Z%s\n", buf);
+ /* We ask for big blocks, in the hopes of efficiency, but
+ will take less if the target has packet size limitations
+ or some such. */
+ gotten = target_get_raw_trace_data (buf, offset,
+ MAX_TRACE_UPLOAD);
+ if (gotten < 0)
+ error (_("Failure to get requested trace buffer data"));
+ /* No more data is forthcoming, we're done. */
+ if (gotten == 0)
+ break;
+
+ writer->ops->write_trace_buffer (writer, buf, gotten);
+
+ offset += gotten;
}
- for (a = 0; VEC_iterate (char_ptr, utp->cmd_strings, a, act); ++a)
+ else
{
- encode_source_string (utp->number, utp->addr, "cmd", act,
- buf, MAX_TRACE_UPLOAD);
- fprintf (fp, "tp Z%s\n", buf);
+ uint16_t tp_num;
+ uint32_t tf_size;
+ /* Parse the trace buffers according to how data are stored
+ in trace buffer in GDBserver. */
+
+ gotten = target_get_raw_trace_data (buf, offset, 6);
+
+ if (gotten == 0)
+ break;
+
+ /* Read the first six bytes in, which is the tracepoint
+ number and trace frame size. */
+ tp_num = (uint16_t)
+ extract_unsigned_integer (&buf[0], 2, byte_order);
+
+ tf_size = (uint32_t)
+ extract_unsigned_integer (&buf[2], 4, byte_order);
+
+ writer->ops->frame_ops->start (writer, tp_num);
+ gotten = 6;
+
+ if (tf_size > 0)
+ {
+ unsigned int block;
+
+ offset += 6;
+
+ for (block = 0; block < tf_size; )
+ {
+ gdb_byte block_type;
+
+ /* We'll fetch one block each time, in order to
+ handle the extremely large 'M' block. We first
+ fetch one byte to get the type of the block. */
+ gotten = target_get_raw_trace_data (buf, offset, 1);
+ if (gotten < 1)
+ error (_("Failure to get requested trace buffer data"));
+
+ gotten = 1;
+ block += 1;
+ offset += 1;
+
+ block_type = buf[0];
+ switch (block_type)
+ {
+ case 'R':
+ gotten
+ = target_get_raw_trace_data (buf, offset,
+ trace_regblock_size);
+ if (gotten < trace_regblock_size)
+ error (_("Failure to get requested trace"
+ " buffer data"));
+
+ TRACE_WRITE_R_BLOCK (writer, buf,
+ trace_regblock_size);
+ break;
+ case 'M':
+ {
+ unsigned short mlen;
+ ULONGEST addr;
+ LONGEST t;
+ int j;
+
+ t = target_get_raw_trace_data (buf,offset, 10);
+ if (t < 10)
+ error (_("Failure to get requested trace"
+ " buffer data"));
+
+ offset += 10;
+ block += 10;
+
+ gotten = 0;
+ addr = (ULONGEST)
+ extract_unsigned_integer (buf, 8,
+ byte_order);
+ mlen = (unsigned short)
+ extract_unsigned_integer (&buf[8], 2,
+ byte_order);
+
+ TRACE_WRITE_M_BLOCK_HEADER (writer, addr,
+ mlen);
+
+ /* The memory contents in 'M' block may be
+ very large. Fetch the data from the target
+ and write them into file one by one. */
+ for (j = 0; j < mlen; )
+ {
+ unsigned int read_length;
+
+ if (mlen - j > MAX_TRACE_UPLOAD)
+ read_length = MAX_TRACE_UPLOAD;
+ else
+ read_length = mlen - j;
+
+ t = target_get_raw_trace_data (buf,
+ offset + j,
+ read_length);
+ if (t < read_length)
+ error (_("Failure to get requested"
+ " trace buffer data"));
+
+ TRACE_WRITE_M_BLOCK_MEMORY (writer, buf,
+ read_length);
+
+ j += read_length;
+ gotten += read_length;
+ }
+
+ break;
+ }
+ case 'V':
+ {
+ int vnum;
+ LONGEST val;
+
+ gotten
+ = target_get_raw_trace_data (buf, offset,
+ 12);
+ if (gotten < 12)
+ error (_("Failure to get requested"
+ " trace buffer data"));
+
+ vnum = (int) extract_signed_integer (buf,
+ 4,
+ byte_order);
+ val
+ = extract_signed_integer (&buf[4], 8,
+ byte_order);
+
+ TRACE_WRITE_V_BLOCK (writer, vnum, val);
+ }
+ break;
+ default:
+ error (_("Unknown block type '%c' (0x%x) in"
+ " trace frame"),
+ block_type, block_type);
+ }
+
+ block += gotten;
+ offset += gotten;
+ }
+ }
+ else
+ offset += gotten;
+
+ writer->ops->frame_ops->end (writer);
}
- fprintf (fp, "tp V%x:%s:%x:%s\n",
- utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
- utp->hit_count,
- phex_nz (utp->traceframe_usage,
- sizeof (utp->traceframe_usage)));
}
- free_uploaded_tps (&uploaded_tps);
+ writer->ops->end (writer);
+}
- /* Mark the end of the definition section. */
- fprintf (fp, "\n");
+/* Return a trace writer for TFILE format. */
- /* Get and write the trace data proper. We ask for big blocks, in
- the hopes of efficiency, but will take less if the target has
- packet size limitations or some such. */
- while (1)
- {
- gotten = target_get_raw_trace_data (buf, offset, MAX_TRACE_UPLOAD);
- if (gotten < 0)
- error (_("Failure to get requested trace buffer data"));
- /* No more data is forthcoming, we're done. */
- if (gotten == 0)
- break;
- written = fwrite (buf, gotten, 1, fp);
- if (written < 1)
- perror_with_name (pathname);
- offset += gotten;
- }
+static struct trace_file_writer *
+tfile_trace_file_writer_new (void)
+{
+ struct tfile_trace_file_writer *writer
+ = xmalloc (sizeof (struct tfile_trace_file_writer));
- /* Mark the end of trace data. (We know that gotten is 0 at this point.) */
- written = fwrite (&gotten, 4, 1, fp);
- if (written < 1)
- perror_with_name (pathname);
+ writer->base.ops = &tfile_write_ops;
+ writer->fp = NULL;
+ writer->pathname = NULL;
- do_cleanups (cleanup);
+ return (struct trace_file_writer *) writer;
}
static void
@@ -3171,6 +3521,7 @@ trace_save_command (char *args, int from_tty)
char **argv;
char *filename = NULL;
struct cleanup *back_to;
+ struct trace_file_writer *writer = NULL;
if (args == NULL)
error_no_arg (_("file in which to save trace data"));
@@ -3191,7 +3542,11 @@ trace_save_command (char *args, int from_tty)
if (!filename)
error_no_arg (_("file in which to save trace data"));
- trace_save (filename, target_does_save);
+ writer = tfile_trace_file_writer_new ();
+
+ make_cleanup (trace_file_writer_xfree, writer);
+
+ trace_save (filename, writer, target_does_save);
if (from_tty)
printf_filtered (_("Trace data saved to file '%s'.\n"), filename);
@@ -3199,6 +3554,20 @@ trace_save_command (char *args, int from_tty)
do_cleanups (back_to);
}
+/* Save the trace data to file FILENAME of tfile format. */
+
+void
+trace_save_tfile (const char *filename, int target_does_save)
+{
+ struct trace_file_writer *writer;
+ struct cleanup *back_to;
+
+ writer = tfile_trace_file_writer_new ();
+ back_to = make_cleanup (trace_file_writer_xfree, writer);
+ trace_save (filename, writer, target_does_save);
+ do_cleanups (back_to);
+}
+
/* Tell the target what to do with an ongoing tracing run if GDB
disconnects for some reason. */
diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
index b2b9d7c..d6664e7 100644
--- a/gdb/tracepoint.h
+++ b/gdb/tracepoint.h
@@ -205,6 +205,107 @@ struct static_tracepoint_marker
char *extra;
};
+struct trace_file_writer;
+
+/* Operations to write trace frames to a specific trace format. */
+
+struct trace_frame_write_ops
+{
+ /* Write a new trace frame. The tracepoint number of this trace
+ frame is TPNUM. */
+ void (*start) (struct trace_file_writer *self, uint16_t tpnum);
+
+ /* Write an 'R' block. Buffer BUF contains its contents and SIZE is
+ its size. */
+ void (*write_r_block) (struct trace_file_writer *self,
+ gdb_byte *buf, int32_t size);
+
+ /* Write an 'M' block, the header and memory contents respectively.
+ The header of 'M' block is composed of the start address and the
+ length of memory collection, and the memory contents contain
+ the collected memory contents in tracing.
+ For extremely large M block, GDB is unable to get its contents
+ and write them into trace file in one go, due to the limitation
+ of the remote target or the size of internal buffer, we split
+ the operation to 'M' block to two operations. */
+ /* Write the head of 'M' block. ADDR is the start address of
+ collected memory and LENGTH is the length of memory contents. */
+ void (*write_m_block_header) (struct trace_file_writer *self,
+ uint64_t addr, uint16_t length);
+ /* Write the memory contents of 'M' block. Buffer BUF contains
+ its contents and LENGTH is its length. This method can be called
+ multiple times to write large memory contents of a single 'M'
+ block. */
+ void (*write_m_block_memory) (struct trace_file_writer *self,
+ gdb_byte *buf, uint16_t length);
+
+ /* Write a 'V' block. NUM is the trace variable number and VAL is
+ the value of the trace variable. */
+ void (*write_v_block) (struct trace_file_writer *self, int32_t num,
+ uint64_t val);
+
+ /* The end of the trace frame. */
+ void (*end) (struct trace_file_writer *self);
+};
+
+/* Operations to write trace buffers to a specific trace format. */
+
+struct trace_file_write_ops
+{
+ /* Save the data to file or directory NAME of desired format in
+ target side. Return true for success, otherwise return
+ false. */
+ int (*target_save) (struct trace_file_writer *self,
+ const char *name);
+
+ /* Write the trace buffers to file or directory NAME. */
+ void (*start) (struct trace_file_writer *self,
+ const char *name);
+
+ /* Write the trace header. */
+ void (*write_header) (struct trace_file_writer *self);
+
+ /* Write the type of block about registers. SIZE is the size of
+ all registers on the target. */
+ void (*write_regblock_type) (struct trace_file_writer *self,
+ int size);
+
+ /* Write trace status TS. */
+ void (*write_status) (struct trace_file_writer *self,
+ struct trace_status *ts);
+
+ /* Write the uploaded TSV. */
+ void (*write_uploaded_tsv) (struct trace_file_writer *self,
+ struct uploaded_tsv *tsv);
+
+ /* Write the uploaded tracepoint TP. */
+ void (*write_uploaded_tp) (struct trace_file_writer *self,
+ struct uploaded_tp *tp);
+
+ /* Write to mark the end of the definition part. */
+ void (*write_definition_end) (struct trace_file_writer *self);
+
+ /* Write the data of trace buffer without parsing. The content is
+ in BUF and length is LEN. */
+ void (*write_trace_buffer) (struct trace_file_writer *self,
+ gdb_byte *buf, LONGEST len);
+
+ /* Operations to write trace frames. The user of this field is
+ responsible to parse the data of trace buffer. Either field
+ 'write_trace_buffer' or field ' frame_ops' is NULL. */
+ const struct trace_frame_write_ops *frame_ops;
+
+ /* The end of writing trace buffers. */
+ void (*end) (struct trace_file_writer *self);
+};
+
+/* Trace file writer for a given format. */
+
+struct trace_file_writer
+{
+ const struct trace_file_write_ops *ops;
+};
+
extern void parse_static_tracepoint_marker_definition
(char *line, char **pp,
struct static_tracepoint_marker *marker);
@@ -281,7 +382,8 @@ extern void tfind_1 (enum trace_find_type type, int num,
ULONGEST addr1, ULONGEST addr2,
int from_tty);
-extern void trace_save (const char *filename, int target_does_save);
+extern void trace_save_tfile (const char *filename,
+ int target_does_save);
extern struct traceframe_info *parse_traceframe_info (const char *tframe_info);
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 01/15] Refactor 'tsave'
2013-03-09 3:49 ` [PATCH v3 01/15] Refactor 'tsave' Yao Qi
@ 2013-03-12 18:30 ` Tom Tromey
2013-03-13 10:33 ` Yao Qi
0 siblings, 1 reply; 60+ messages in thread
From: Tom Tromey @ 2013-03-12 18:30 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes:
Yao> +struct tfile_trace_file_writer
Yao> {
[...]
Yao> + struct cleanup *cleanup;
Yao> +};
This makes it seem as though the writer has a cleanup chain separate
from the global chain. But, this isn't the case.
This says to me that this field is a trap waiting to be sprung, say by
some future code rearrangement not taking this into account.
So, I think it would be better to have an explicit "dtor" method that is
called to clean up.
Yao> + writer->ops->start (writer, filename);
Yao> +
Yao> + writer->ops->write_header (writer);
Yao> +
Yao> + /* Write descriptive info. */
Yao> +
Yao> + /* Write out the size of a register block. */
Yao> + writer->ops->write_regblock_type (writer, trace_regblock_size);
Yao> +
Yao> + /* Write out status of the tracing run (aka "tstatus" info). */
Yao> + writer->ops->write_status (writer, ts);
It is strange to see multiple virtual calls in a row like this.
Is there some reason not to collapse them into a single call?
Tom
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 01/15] Refactor 'tsave'
2013-03-12 18:30 ` Tom Tromey
@ 2013-03-13 10:33 ` Yao Qi
2013-03-13 19:26 ` Tom Tromey
0 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-13 10:33 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 03/13/2013 02:30 AM, Tom Tromey wrote:
> Yao> +struct tfile_trace_file_writer
> Yao> {
> [...]
> Yao> + struct cleanup *cleanup;
> Yao> +};
>
> This makes it seem as though the writer has a cleanup chain separate
> from the global chain. But, this isn't the case.
>
> This says to me that this field is a trap waiting to be sprung, say by
> some future code rearrangement not taking this into account.
>
> So, I think it would be better to have an explicit "dtor" method that is
> called to clean up.
I Agree. A new field <dtor> is added in 'struct trace_file_write_ops',
which is responsible for release file descriptor and memory. The
<dtor> will be called in trace_file_writer_xfree.
>
> Yao> + writer->ops->start (writer, filename);
> Yao> +
> Yao> + writer->ops->write_header (writer);
> Yao> +
> Yao> + /* Write descriptive info. */
> Yao> +
> Yao> + /* Write out the size of a register block. */
> Yao> + writer->ops->write_regblock_type (writer, trace_regblock_size);
> Yao> +
> Yao> + /* Write out status of the tracing run (aka "tstatus" info). */
> Yao> + writer->ops->write_status (writer, ts);
>
> It is strange to see multiple virtual calls in a row like this.
>
> Is there some reason not to collapse them into a single call?
It is useful to reduce the complexity of each hook function of 'struct
trace_file_write_ops'. Each function will be small and clear.
--
Yao (é½å°§)
gdb:
2013-03-13 Yao Qi <yao@codesourcery.com>
* tracepoint.c (trace_file_writer_xfree): New.
(struct tfile_writer_data): New.
(tfile_dtor, tfile_can_target_save, tfile_start): New.
(tfile_write_header, tfile_write_regblock_type): New.
(tfile_write_status, tfile_write_uploaded_tsv): New.
(tfile_write_uploaded_tp, tfile_write_definition_end): New.
(tfile_write_raw_data, (tfile_end): New.
(tfile_write_ops): New global variable.
(TRACE_WRITE_R_BLOCK): New macro.
(TRACE_WRITE_M_BLOCK_HEADER): New macro.
(TRACE_WRITE_M_BLOCK_MEMORY): New macro.
(TRACE_WRITE_V_BLOCK): New macro.
(trace_save): Add extra one parameter WRITER. Make it static.
Use WRITER to writer trace.
(tfile_trace_file_writer_new): New.
(trace_save_command): Caller update.
(trace_save_tfile): Write trace data in TFILE format.
* tracepoint.h (struct trace_frame_write_ops): New.
(struct trace_file_write_ops): New.
(struct trace_file_writer): New.
(trace_save): Remove its declaration.
(trace_save_tfile): Declare it.
* mi/mi-main.c (mi_cmd_trace_save): Call trace_save_tfile
instead of trace_save.
---
gdb/mi/mi-main.c | 2 +-
gdb/tracepoint.c | 638 +++++++++++++++++++++++++++++++++++++++++++-----------
gdb/tracepoint.h | 108 +++++++++-
3 files changed, 617 insertions(+), 131 deletions(-)
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 20777a3..085439b 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -2495,7 +2495,7 @@ mi_cmd_trace_save (char *command, char **argv, int argc)
filename = argv[0];
}
- trace_save (filename, target_saves);
+ trace_save_tfile (filename, target_saves);
}
void
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 513dccc..bf60d75 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -2987,90 +2987,337 @@ encode_source_string (int tpnum, ULONGEST addr,
return -1;
}
-extern int trace_regblock_size;
+/* Free trace file writer. */
-/* Save tracepoint data to file named FILENAME. If TARGET_DOES_SAVE is
- non-zero, the save is performed on the target, otherwise GDB obtains all
- trace data and saves it locally. */
+static void
+trace_file_writer_xfree (void *arg)
+{
+ struct trace_file_writer *writer = arg;
-void
-trace_save (const char *filename, int target_does_save)
+ writer->ops->dtor (writer);
+ xfree (writer);
+}
+
+/* TFILE trace writer. */
+
+struct tfile_trace_file_writer
{
- struct cleanup *cleanup;
- char *pathname;
- struct trace_status *ts = current_trace_status ();
- int err, status;
+ struct trace_file_writer base;
+
+ /* File pointer to tfile trace file. */
FILE *fp;
- struct uploaded_tp *uploaded_tps = NULL, *utp;
- struct uploaded_tsv *uploaded_tsvs = NULL, *utsv;
- int a;
- char *act;
- LONGEST gotten = 0;
- ULONGEST offset = 0;
-#define MAX_TRACE_UPLOAD 2000
- gdb_byte buf[MAX_TRACE_UPLOAD];
- int written;
+ /* Path name of the tfile trace file. */
+ char *pathname;
+};
- /* If the target is to save the data to a file on its own, then just
- send the command and be done with it. */
- if (target_does_save)
- {
- err = target_save_trace_data (filename);
- if (err < 0)
- error (_("Target failed to save trace data to '%s'."),
- filename);
- return;
- }
+/* This is the implementation of trace_file_write_ops method
+ target_save. We just call the generic target
+ target_save_trace_data to do target-side saving. */
- /* Get the trace status first before opening the file, so if the
- target is losing, we can get out without touching files. */
- status = target_get_trace_status (ts);
+static int
+tfile_target_save (struct trace_file_writer *self,
+ const char *filename)
+{
+ int err = target_save_trace_data (filename);
+
+ return (err >= 0);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ dtor. */
+
+static void
+tfile_dtor (struct trace_file_writer *self)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ xfree (writer->pathname);
+ fclose (writer->fp);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ start. It creates the trace file FILENAME and registers some
+ cleanups. */
- pathname = tilde_expand (filename);
- cleanup = make_cleanup (xfree, pathname);
+static void
+tfile_start (struct trace_file_writer *self, const char *filename)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
- fp = fopen (pathname, "wb");
- if (!fp)
+ writer->pathname = tilde_expand (filename);
+ writer->fp = fopen (writer->pathname, "wb");
+ if (writer->fp == NULL)
error (_("Unable to open file '%s' for saving trace data (%s)"),
filename, safe_strerror (errno));
- make_cleanup_fclose (fp);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_header. Write the TFILE header. */
+
+static void
+tfile_write_header (struct trace_file_writer *self)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+ int written;
/* Write a file header, with a high-bit-set char to indicate a
binary file, plus a hint as what this file is, and a version
number in case of future needs. */
- written = fwrite ("\x7fTRACE0\n", 8, 1, fp);
+ written = fwrite ("\x7fTRACE0\n", 8, 1, writer->fp);
if (written < 1)
- perror_with_name (pathname);
+ perror_with_name (writer->pathname);
+}
- /* Write descriptive info. */
+/* This is the implementation of trace_file_write_ops method
+ write_regblock_type. Write the size of register block. */
- /* Write out the size of a register block. */
- fprintf (fp, "R %x\n", trace_regblock_size);
+static void
+tfile_write_regblock_type (struct trace_file_writer *self, int size)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
- /* Write out status of the tracing run (aka "tstatus" info). */
- fprintf (fp, "status %c;%s",
+ fprintf (writer->fp, "R %x\n", size);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_status. */
+
+static void
+tfile_write_status (struct trace_file_writer *self,
+ struct trace_status *ts)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ fprintf (writer->fp, "status %c;%s",
(ts->running ? '1' : '0'), stop_reason_names[ts->stop_reason]);
if (ts->stop_reason == tracepoint_error)
{
char *buf = (char *) alloca (strlen (ts->stop_desc) * 2 + 1);
bin2hex ((gdb_byte *) ts->stop_desc, buf, 0);
- fprintf (fp, ":%s", buf);
+ fprintf (writer->fp, ":%s", buf);
}
- fprintf (fp, ":%x", ts->stopping_tracepoint);
+ fprintf (writer->fp, ":%x", ts->stopping_tracepoint);
if (ts->traceframe_count >= 0)
- fprintf (fp, ";tframes:%x", ts->traceframe_count);
+ fprintf (writer->fp, ";tframes:%x", ts->traceframe_count);
if (ts->traceframes_created >= 0)
- fprintf (fp, ";tcreated:%x", ts->traceframes_created);
+ fprintf (writer->fp, ";tcreated:%x", ts->traceframes_created);
if (ts->buffer_free >= 0)
- fprintf (fp, ";tfree:%x", ts->buffer_free);
+ fprintf (writer->fp, ";tfree:%x", ts->buffer_free);
if (ts->buffer_size >= 0)
- fprintf (fp, ";tsize:%x", ts->buffer_size);
+ fprintf (writer->fp, ";tsize:%x", ts->buffer_size);
if (ts->disconnected_tracing)
- fprintf (fp, ";disconn:%x", ts->disconnected_tracing);
+ fprintf (writer->fp, ";disconn:%x", ts->disconnected_tracing);
if (ts->circular_buffer)
- fprintf (fp, ";circular:%x", ts->circular_buffer);
- fprintf (fp, "\n");
+ fprintf (writer->fp, ";circular:%x", ts->circular_buffer);
+ fprintf (writer->fp, "\n");
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_uploaded_tsv. */
+
+static void
+tfile_write_uploaded_tsv (struct trace_file_writer *self,
+ struct uploaded_tsv *utsv)
+{
+ char *buf = "";
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ if (utsv->name)
+ {
+ buf = (char *) xmalloc (strlen (utsv->name) * 2 + 1);
+ bin2hex ((gdb_byte *) (utsv->name), buf, 0);
+ }
+
+ fprintf (writer->fp, "tsv %x:%s:%x:%s\n",
+ utsv->number, phex_nz (utsv->initial_value, 8),
+ utsv->builtin, buf);
+
+ if (utsv->name)
+ xfree (buf);
+}
+
+#define MAX_TRACE_UPLOAD 2000
+
+/* This is the implementation of trace_file_write_ops method
+ write_uploaded_tp. */
+
+static void
+tfile_write_uploaded_tp (struct trace_file_writer *self,
+ struct uploaded_tp *utp)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+ int a;
+ char *act;
+ gdb_byte buf[MAX_TRACE_UPLOAD];
+
+ fprintf (writer->fp, "tp T%x:%s:%c:%x:%x",
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
+ (utp->enabled ? 'E' : 'D'), utp->step, utp->pass);
+ if (utp->type == bp_fast_tracepoint)
+ fprintf (writer->fp, ":F%x", utp->orig_size);
+ if (utp->cond)
+ fprintf (writer->fp,
+ ":X%x,%s", (unsigned int) strlen (utp->cond) / 2,
+ utp->cond);
+ fprintf (writer->fp, "\n");
+ for (a = 0; VEC_iterate (char_ptr, utp->actions, a, act); ++a)
+ fprintf (writer->fp, "tp A%x:%s:%s\n",
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
+ for (a = 0; VEC_iterate (char_ptr, utp->step_actions, a, act); ++a)
+ fprintf (writer->fp, "tp S%x:%s:%s\n",
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
+ if (utp->at_string)
+ {
+ encode_source_string (utp->number, utp->addr,
+ "at", utp->at_string, buf, MAX_TRACE_UPLOAD);
+ fprintf (writer->fp, "tp Z%s\n", buf);
+ }
+ if (utp->cond_string)
+ {
+ encode_source_string (utp->number, utp->addr,
+ "cond", utp->cond_string,
+ buf, MAX_TRACE_UPLOAD);
+ fprintf (writer->fp, "tp Z%s\n", buf);
+ }
+ for (a = 0; VEC_iterate (char_ptr, utp->cmd_strings, a, act); ++a)
+ {
+ encode_source_string (utp->number, utp->addr, "cmd", act,
+ buf, MAX_TRACE_UPLOAD);
+ fprintf (writer->fp, "tp Z%s\n", buf);
+ }
+ fprintf (writer->fp, "tp V%x:%s:%x:%s\n",
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
+ utp->hit_count,
+ phex_nz (utp->traceframe_usage,
+ sizeof (utp->traceframe_usage)));
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_definition_end. */
+
+static void
+tfile_write_definition_end (struct trace_file_writer *self)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ fprintf (writer->fp, "\n");
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_raw_data. */
+
+static void
+tfile_write_raw_data (struct trace_file_writer *self, gdb_byte *buf,
+ LONGEST len)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ if (fwrite (buf, len, 1, writer->fp) < 1)
+ perror_with_name (writer->pathname);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ end. */
+
+static void
+tfile_end (struct trace_file_writer *self)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+ uint32_t gotten = 0;
+
+ /* Mark the end of trace data. */
+ if (fwrite (&gotten, 4, 1, writer->fp) < 1)
+ perror_with_name (writer->pathname);
+}
+
+/* Operations to write trace buffers into TFILE format. */
+
+static const struct trace_file_write_ops tfile_write_ops =
+{
+ tfile_dtor,
+ tfile_target_save,
+ tfile_start,
+ tfile_write_header,
+ tfile_write_regblock_type,
+ tfile_write_status,
+ tfile_write_uploaded_tsv,
+ tfile_write_uploaded_tp,
+ tfile_write_definition_end,
+ tfile_write_raw_data,
+ NULL,
+ tfile_end,
+};
+
+/* Helper macros. */
+
+#define TRACE_WRITE_R_BLOCK(writer, buf, size) \
+ writer->ops->frame_ops->write_r_block ((writer), (buf), (size))
+#define TRACE_WRITE_M_BLOCK_HEADER(writer, addr, size) \
+ writer->ops->frame_ops->write_m_block_header ((writer), (addr), \
+ (size))
+#define TRACE_WRITE_M_BLOCK_MEMORY(writer, buf, size) \
+ writer->ops->frame_ops->write_m_block_memory ((writer), (buf), \
+ (size))
+#define TRACE_WRITE_V_BLOCK(writer, num, val) \
+ writer->ops->frame_ops->write_v_block ((writer), (num), (val))
+
+extern int trace_regblock_size;
+
+/* Save tracepoint data to file named FILENAME through WRITER. WRITER
+ determines the trace file format. If TARGET_DOES_SAVE is non-zero,
+ the save is performed on the target, otherwise GDB obtains all trace
+ data and saves it locally. */
+
+static void
+trace_save (const char *filename, struct trace_file_writer *writer,
+ int target_does_save)
+{
+ struct trace_status *ts = current_trace_status ();
+ int status;
+ struct uploaded_tp *uploaded_tps = NULL, *utp;
+ struct uploaded_tsv *uploaded_tsvs = NULL, *utsv;
+
+ ULONGEST offset = 0;
+ gdb_byte buf[MAX_TRACE_UPLOAD];
+ int written;
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
+
+ /* If the target is to save the data to a file on its own, then just
+ send the command and be done with it. */
+ if (target_does_save)
+ {
+ if (!writer->ops->target_save (writer, filename))
+ error (_("Target failed to save trace data to '%s'."),
+ filename);
+ return;
+ }
+
+ /* Get the trace status first before opening the file, so if the
+ target is losing, we can get out without touching files. */
+ status = target_get_trace_status (ts);
+
+ writer->ops->start (writer, filename);
+
+ writer->ops->write_header (writer);
+
+ /* Write descriptive info. */
+
+ /* Write out the size of a register block. */
+ writer->ops->write_regblock_type (writer, trace_regblock_size);
+
+ /* Write out status of the tracing run (aka "tstatus" info). */
+ writer->ops->write_status (writer, ts);
/* Note that we want to upload tracepoints and save those, rather
than simply writing out the local ones, because the user may have
@@ -3085,22 +3332,7 @@ trace_save (const char *filename, int target_does_save)
target_upload_trace_state_variables (&uploaded_tsvs);
for (utsv = uploaded_tsvs; utsv; utsv = utsv->next)
- {
- char *buf = "";
-
- if (utsv->name)
- {
- buf = (char *) xmalloc (strlen (utsv->name) * 2 + 1);
- bin2hex ((gdb_byte *) (utsv->name), buf, 0);
- }
-
- fprintf (fp, "tsv %x:%s:%x:%s\n",
- utsv->number, phex_nz (utsv->initial_value, 8),
- utsv->builtin, buf);
-
- if (utsv->name)
- xfree (buf);
- }
+ writer->ops->write_uploaded_tsv (writer, utsv);
free_uploaded_tsvs (&uploaded_tsvs);
@@ -3110,76 +3342,205 @@ trace_save (const char *filename, int target_does_save)
target_get_tracepoint_status (NULL, utp);
for (utp = uploaded_tps; utp; utp = utp->next)
+ writer->ops->write_uploaded_tp (writer, utp);
+
+ free_uploaded_tps (&uploaded_tps);
+
+ /* Mark the end of the definition section. */
+ writer->ops->write_definition_end (writer);
+
+ /* Get and write the trace data proper. */
+ while (1)
{
- fprintf (fp, "tp T%x:%s:%c:%x:%x",
- utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
- (utp->enabled ? 'E' : 'D'), utp->step, utp->pass);
- if (utp->type == bp_fast_tracepoint)
- fprintf (fp, ":F%x", utp->orig_size);
- if (utp->cond)
- fprintf (fp, ":X%x,%s", (unsigned int) strlen (utp->cond) / 2,
- utp->cond);
- fprintf (fp, "\n");
- for (a = 0; VEC_iterate (char_ptr, utp->actions, a, act); ++a)
- fprintf (fp, "tp A%x:%s:%s\n",
- utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
- for (a = 0; VEC_iterate (char_ptr, utp->step_actions, a, act); ++a)
- fprintf (fp, "tp S%x:%s:%s\n",
- utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
- if (utp->at_string)
- {
- encode_source_string (utp->number, utp->addr,
- "at", utp->at_string, buf, MAX_TRACE_UPLOAD);
- fprintf (fp, "tp Z%s\n", buf);
- }
- if (utp->cond_string)
+ LONGEST gotten = 0;
+
+ /* The writer supports writing the contents of trace buffer
+ directly to trace file. Don't parse the contents of trace
+ buffer. */
+ if (writer->ops->write_trace_buffer != NULL)
{
- encode_source_string (utp->number, utp->addr,
- "cond", utp->cond_string,
- buf, MAX_TRACE_UPLOAD);
- fprintf (fp, "tp Z%s\n", buf);
+ /* We ask for big blocks, in the hopes of efficiency, but
+ will take less if the target has packet size limitations
+ or some such. */
+ gotten = target_get_raw_trace_data (buf, offset,
+ MAX_TRACE_UPLOAD);
+ if (gotten < 0)
+ error (_("Failure to get requested trace buffer data"));
+ /* No more data is forthcoming, we're done. */
+ if (gotten == 0)
+ break;
+
+ writer->ops->write_trace_buffer (writer, buf, gotten);
+
+ offset += gotten;
}
- for (a = 0; VEC_iterate (char_ptr, utp->cmd_strings, a, act); ++a)
+ else
{
- encode_source_string (utp->number, utp->addr, "cmd", act,
- buf, MAX_TRACE_UPLOAD);
- fprintf (fp, "tp Z%s\n", buf);
+ uint16_t tp_num;
+ uint32_t tf_size;
+ /* Parse the trace buffers according to how data are stored
+ in trace buffer in GDBserver. */
+
+ gotten = target_get_raw_trace_data (buf, offset, 6);
+
+ if (gotten == 0)
+ break;
+
+ /* Read the first six bytes in, which is the tracepoint
+ number and trace frame size. */
+ tp_num = (uint16_t)
+ extract_unsigned_integer (&buf[0], 2, byte_order);
+
+ tf_size = (uint32_t)
+ extract_unsigned_integer (&buf[2], 4, byte_order);
+
+ writer->ops->frame_ops->start (writer, tp_num);
+ gotten = 6;
+
+ if (tf_size > 0)
+ {
+ unsigned int block;
+
+ offset += 6;
+
+ for (block = 0; block < tf_size; )
+ {
+ gdb_byte block_type;
+
+ /* We'll fetch one block each time, in order to
+ handle the extremely large 'M' block. We first
+ fetch one byte to get the type of the block. */
+ gotten = target_get_raw_trace_data (buf, offset, 1);
+ if (gotten < 1)
+ error (_("Failure to get requested trace buffer data"));
+
+ gotten = 1;
+ block += 1;
+ offset += 1;
+
+ block_type = buf[0];
+ switch (block_type)
+ {
+ case 'R':
+ gotten
+ = target_get_raw_trace_data (buf, offset,
+ trace_regblock_size);
+ if (gotten < trace_regblock_size)
+ error (_("Failure to get requested trace"
+ " buffer data"));
+
+ TRACE_WRITE_R_BLOCK (writer, buf,
+ trace_regblock_size);
+ break;
+ case 'M':
+ {
+ unsigned short mlen;
+ ULONGEST addr;
+ LONGEST t;
+ int j;
+
+ t = target_get_raw_trace_data (buf,offset, 10);
+ if (t < 10)
+ error (_("Failure to get requested trace"
+ " buffer data"));
+
+ offset += 10;
+ block += 10;
+
+ gotten = 0;
+ addr = (ULONGEST)
+ extract_unsigned_integer (buf, 8,
+ byte_order);
+ mlen = (unsigned short)
+ extract_unsigned_integer (&buf[8], 2,
+ byte_order);
+
+ TRACE_WRITE_M_BLOCK_HEADER (writer, addr,
+ mlen);
+
+ /* The memory contents in 'M' block may be
+ very large. Fetch the data from the target
+ and write them into file one by one. */
+ for (j = 0; j < mlen; )
+ {
+ unsigned int read_length;
+
+ if (mlen - j > MAX_TRACE_UPLOAD)
+ read_length = MAX_TRACE_UPLOAD;
+ else
+ read_length = mlen - j;
+
+ t = target_get_raw_trace_data (buf,
+ offset + j,
+ read_length);
+ if (t < read_length)
+ error (_("Failure to get requested"
+ " trace buffer data"));
+
+ TRACE_WRITE_M_BLOCK_MEMORY (writer, buf,
+ read_length);
+
+ j += read_length;
+ gotten += read_length;
+ }
+
+ break;
+ }
+ case 'V':
+ {
+ int vnum;
+ LONGEST val;
+
+ gotten
+ = target_get_raw_trace_data (buf, offset,
+ 12);
+ if (gotten < 12)
+ error (_("Failure to get requested"
+ " trace buffer data"));
+
+ vnum = (int) extract_signed_integer (buf,
+ 4,
+ byte_order);
+ val
+ = extract_signed_integer (&buf[4], 8,
+ byte_order);
+
+ TRACE_WRITE_V_BLOCK (writer, vnum, val);
+ }
+ break;
+ default:
+ error (_("Unknown block type '%c' (0x%x) in"
+ " trace frame"),
+ block_type, block_type);
+ }
+
+ block += gotten;
+ offset += gotten;
+ }
+ }
+ else
+ offset += gotten;
+
+ writer->ops->frame_ops->end (writer);
}
- fprintf (fp, "tp V%x:%s:%x:%s\n",
- utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
- utp->hit_count,
- phex_nz (utp->traceframe_usage,
- sizeof (utp->traceframe_usage)));
}
- free_uploaded_tps (&uploaded_tps);
+ writer->ops->end (writer);
+}
- /* Mark the end of the definition section. */
- fprintf (fp, "\n");
+/* Return a trace writer for TFILE format. */
- /* Get and write the trace data proper. We ask for big blocks, in
- the hopes of efficiency, but will take less if the target has
- packet size limitations or some such. */
- while (1)
- {
- gotten = target_get_raw_trace_data (buf, offset, MAX_TRACE_UPLOAD);
- if (gotten < 0)
- error (_("Failure to get requested trace buffer data"));
- /* No more data is forthcoming, we're done. */
- if (gotten == 0)
- break;
- written = fwrite (buf, gotten, 1, fp);
- if (written < 1)
- perror_with_name (pathname);
- offset += gotten;
- }
+static struct trace_file_writer *
+tfile_trace_file_writer_new (void)
+{
+ struct tfile_trace_file_writer *writer
+ = xmalloc (sizeof (struct tfile_trace_file_writer));
- /* Mark the end of trace data. (We know that gotten is 0 at this point.) */
- written = fwrite (&gotten, 4, 1, fp);
- if (written < 1)
- perror_with_name (pathname);
+ writer->base.ops = &tfile_write_ops;
+ writer->fp = NULL;
+ writer->pathname = NULL;
- do_cleanups (cleanup);
+ return (struct trace_file_writer *) writer;
}
static void
@@ -3189,6 +3550,7 @@ trace_save_command (char *args, int from_tty)
char **argv;
char *filename = NULL;
struct cleanup *back_to;
+ struct trace_file_writer *writer = NULL;
if (args == NULL)
error_no_arg (_("file in which to save trace data"));
@@ -3209,7 +3571,11 @@ trace_save_command (char *args, int from_tty)
if (!filename)
error_no_arg (_("file in which to save trace data"));
- trace_save (filename, target_does_save);
+ writer = tfile_trace_file_writer_new ();
+
+ make_cleanup (trace_file_writer_xfree, writer);
+
+ trace_save (filename, writer, target_does_save);
if (from_tty)
printf_filtered (_("Trace data saved to file '%s'.\n"), filename);
@@ -3217,6 +3583,20 @@ trace_save_command (char *args, int from_tty)
do_cleanups (back_to);
}
+/* Save the trace data to file FILENAME of tfile format. */
+
+void
+trace_save_tfile (const char *filename, int target_does_save)
+{
+ struct trace_file_writer *writer;
+ struct cleanup *back_to;
+
+ writer = tfile_trace_file_writer_new ();
+ back_to = make_cleanup (trace_file_writer_xfree, writer);
+ trace_save (filename, writer, target_does_save);
+ do_cleanups (back_to);
+}
+
/* Tell the target what to do with an ongoing tracing run if GDB
disconnects for some reason. */
diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
index b2b9d7c..2d21fda 100644
--- a/gdb/tracepoint.h
+++ b/gdb/tracepoint.h
@@ -205,6 +205,111 @@ struct static_tracepoint_marker
char *extra;
};
+struct trace_file_writer;
+
+/* Operations to write trace frames to a specific trace format. */
+
+struct trace_frame_write_ops
+{
+ /* Write a new trace frame. The tracepoint number of this trace
+ frame is TPNUM. */
+ void (*start) (struct trace_file_writer *self, uint16_t tpnum);
+
+ /* Write an 'R' block. Buffer BUF contains its contents and SIZE is
+ its size. */
+ void (*write_r_block) (struct trace_file_writer *self,
+ gdb_byte *buf, int32_t size);
+
+ /* Write an 'M' block, the header and memory contents respectively.
+ The header of 'M' block is composed of the start address and the
+ length of memory collection, and the memory contents contain
+ the collected memory contents in tracing.
+ For extremely large M block, GDB is unable to get its contents
+ and write them into trace file in one go, due to the limitation
+ of the remote target or the size of internal buffer, we split
+ the operation to 'M' block to two operations. */
+ /* Write the head of 'M' block. ADDR is the start address of
+ collected memory and LENGTH is the length of memory contents. */
+ void (*write_m_block_header) (struct trace_file_writer *self,
+ uint64_t addr, uint16_t length);
+ /* Write the memory contents of 'M' block. Buffer BUF contains
+ its contents and LENGTH is its length. This method can be called
+ multiple times to write large memory contents of a single 'M'
+ block. */
+ void (*write_m_block_memory) (struct trace_file_writer *self,
+ gdb_byte *buf, uint16_t length);
+
+ /* Write a 'V' block. NUM is the trace variable number and VAL is
+ the value of the trace variable. */
+ void (*write_v_block) (struct trace_file_writer *self, int32_t num,
+ uint64_t val);
+
+ /* The end of the trace frame. */
+ void (*end) (struct trace_file_writer *self);
+};
+
+/* Operations to write trace buffers to a specific trace format. */
+
+struct trace_file_write_ops
+{
+ /* Destructor. Releases everything from SELF (but not SELF
+ itself). */
+ void (*dtor) (struct trace_file_writer *self);
+
+ /* Save the data to file or directory NAME of desired format in
+ target side. Return true for success, otherwise return
+ false. */
+ int (*target_save) (struct trace_file_writer *self,
+ const char *name);
+
+ /* Write the trace buffers to file or directory NAME. */
+ void (*start) (struct trace_file_writer *self,
+ const char *name);
+
+ /* Write the trace header. */
+ void (*write_header) (struct trace_file_writer *self);
+
+ /* Write the type of block about registers. SIZE is the size of
+ all registers on the target. */
+ void (*write_regblock_type) (struct trace_file_writer *self,
+ int size);
+
+ /* Write trace status TS. */
+ void (*write_status) (struct trace_file_writer *self,
+ struct trace_status *ts);
+
+ /* Write the uploaded TSV. */
+ void (*write_uploaded_tsv) (struct trace_file_writer *self,
+ struct uploaded_tsv *tsv);
+
+ /* Write the uploaded tracepoint TP. */
+ void (*write_uploaded_tp) (struct trace_file_writer *self,
+ struct uploaded_tp *tp);
+
+ /* Write to mark the end of the definition part. */
+ void (*write_definition_end) (struct trace_file_writer *self);
+
+ /* Write the data of trace buffer without parsing. The content is
+ in BUF and length is LEN. */
+ void (*write_trace_buffer) (struct trace_file_writer *self,
+ gdb_byte *buf, LONGEST len);
+
+ /* Operations to write trace frames. The user of this field is
+ responsible to parse the data of trace buffer. Either field
+ 'write_trace_buffer' or field ' frame_ops' is NULL. */
+ const struct trace_frame_write_ops *frame_ops;
+
+ /* The end of writing trace buffers. */
+ void (*end) (struct trace_file_writer *self);
+};
+
+/* Trace file writer for a given format. */
+
+struct trace_file_writer
+{
+ const struct trace_file_write_ops *ops;
+};
+
extern void parse_static_tracepoint_marker_definition
(char *line, char **pp,
struct static_tracepoint_marker *marker);
@@ -281,7 +386,8 @@ extern void tfind_1 (enum trace_find_type type, int num,
ULONGEST addr1, ULONGEST addr2,
int from_tty);
-extern void trace_save (const char *filename, int target_does_save);
+extern void trace_save_tfile (const char *filename,
+ int target_does_save);
extern struct traceframe_info *parse_traceframe_info (const char *tframe_info);
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 01/15] Refactor 'tsave'
2013-03-13 10:33 ` Yao Qi
@ 2013-03-13 19:26 ` Tom Tromey
2013-03-14 9:17 ` Yao Qi
0 siblings, 1 reply; 60+ messages in thread
From: Tom Tromey @ 2013-03-13 19:26 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes:
Tom> So, I think it would be better to have an explicit "dtor" method that is
Tom> called to clean up.
Yao> I Agree. A new field <dtor> is added in 'struct trace_file_write_ops',
Yao> which is responsible for release file descriptor and memory. The
Yao> <dtor> will be called in trace_file_writer_xfree.
Thanks.
Tom> It is strange to see multiple virtual calls in a row like this.
Tom> Is there some reason not to collapse them into a single call?
Yao> It is useful to reduce the complexity of each hook function of 'struct
Yao> trace_file_write_ops'. Each function will be small and clear.
Nothing constrains the implementation to be one huge function.
But, that said, this is fine as is.
Yao> +static void
Yao> +tfile_dtor (struct trace_file_writer *self)
Yao> +{
Yao> + struct tfile_trace_file_writer *writer
Yao> + = (struct tfile_trace_file_writer *) self;
Yao> +
Yao> + xfree (writer->pathname);
Yao> + fclose (writer->fp);
I think this needs a NULL check.
Otherwise I think on error this may crash.
Ok with that fixed.
Tom
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 01/15] Refactor 'tsave'
2013-03-13 19:26 ` Tom Tromey
@ 2013-03-14 9:17 ` Yao Qi
0 siblings, 0 replies; 60+ messages in thread
From: Yao Qi @ 2013-03-14 9:17 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 03/14/2013 03:26 AM, Tom Tromey wrote:
> I think this needs a NULL check.
> Otherwise I think on error this may crash.
Done.
>
> Ok with that fixed.
Thanks for the review. Patch below is what I committed.
--
Yao (é½å°§)
gdb:
2013-03-14 Yao Qi <yao@codesourcery.com>
* tracepoint.c (trace_file_writer_xfree): New.
(struct tfile_writer_data): New.
(tfile_dtor, tfile_can_target_save, tfile_start): New.
(tfile_write_header, tfile_write_regblock_type): New.
(tfile_write_status, tfile_write_uploaded_tsv): New.
(tfile_write_uploaded_tp, tfile_write_definition_end): New.
(tfile_write_raw_data, (tfile_end): New.
(tfile_write_ops): New global variable.
(TRACE_WRITE_R_BLOCK): New macro.
(TRACE_WRITE_M_BLOCK_HEADER): New macro.
(TRACE_WRITE_M_BLOCK_MEMORY): New macro.
(TRACE_WRITE_V_BLOCK): New macro.
(trace_save): Add extra one parameter WRITER. Make it static.
Use WRITER to writer trace.
(tfile_trace_file_writer_new): New.
(trace_save_command): Caller update.
(trace_save_tfile): Write trace data in TFILE format.
* tracepoint.h (struct trace_frame_write_ops): New.
(struct trace_file_write_ops): New.
(struct trace_file_writer): New.
(trace_save): Remove its declaration.
(trace_save_tfile): Declare it.
* mi/mi-main.c (mi_cmd_trace_save): Call trace_save_tfile
instead of trace_save.
---
gdb/mi/mi-main.c | 2 +-
gdb/tracepoint.c | 640 +++++++++++++++++++++++++++++++++++++++++++-----------
gdb/tracepoint.h | 108 +++++++++-
3 files changed, 619 insertions(+), 131 deletions(-)
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 20777a3..085439b 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -2495,7 +2495,7 @@ mi_cmd_trace_save (char *command, char **argv, int argc)
filename = argv[0];
}
- trace_save (filename, target_saves);
+ trace_save_tfile (filename, target_saves);
}
void
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 4db93ca..2bfa500 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -2979,90 +2979,339 @@ encode_source_string (int tpnum, ULONGEST addr,
return -1;
}
-extern int trace_regblock_size;
+/* Free trace file writer. */
-/* Save tracepoint data to file named FILENAME. If TARGET_DOES_SAVE is
- non-zero, the save is performed on the target, otherwise GDB obtains all
- trace data and saves it locally. */
+static void
+trace_file_writer_xfree (void *arg)
+{
+ struct trace_file_writer *writer = arg;
-void
-trace_save (const char *filename, int target_does_save)
+ writer->ops->dtor (writer);
+ xfree (writer);
+}
+
+/* TFILE trace writer. */
+
+struct tfile_trace_file_writer
{
- struct cleanup *cleanup;
- char *pathname;
- struct trace_status *ts = current_trace_status ();
- int err, status;
+ struct trace_file_writer base;
+
+ /* File pointer to tfile trace file. */
FILE *fp;
- struct uploaded_tp *uploaded_tps = NULL, *utp;
- struct uploaded_tsv *uploaded_tsvs = NULL, *utsv;
- int a;
- char *act;
- LONGEST gotten = 0;
- ULONGEST offset = 0;
-#define MAX_TRACE_UPLOAD 2000
- gdb_byte buf[MAX_TRACE_UPLOAD];
- int written;
+ /* Path name of the tfile trace file. */
+ char *pathname;
+};
- /* If the target is to save the data to a file on its own, then just
- send the command and be done with it. */
- if (target_does_save)
- {
- err = target_save_trace_data (filename);
- if (err < 0)
- error (_("Target failed to save trace data to '%s'."),
- filename);
- return;
- }
+/* This is the implementation of trace_file_write_ops method
+ target_save. We just call the generic target
+ target_save_trace_data to do target-side saving. */
- /* Get the trace status first before opening the file, so if the
- target is losing, we can get out without touching files. */
- status = target_get_trace_status (ts);
+static int
+tfile_target_save (struct trace_file_writer *self,
+ const char *filename)
+{
+ int err = target_save_trace_data (filename);
+
+ return (err >= 0);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ dtor. */
+
+static void
+tfile_dtor (struct trace_file_writer *self)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ xfree (writer->pathname);
+
+ if (writer->fp != NULL)
+ fclose (writer->fp);
+}
- pathname = tilde_expand (filename);
- cleanup = make_cleanup (xfree, pathname);
+/* This is the implementation of trace_file_write_ops method
+ start. It creates the trace file FILENAME and registers some
+ cleanups. */
- fp = fopen (pathname, "wb");
- if (!fp)
+static void
+tfile_start (struct trace_file_writer *self, const char *filename)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ writer->pathname = tilde_expand (filename);
+ writer->fp = fopen (writer->pathname, "wb");
+ if (writer->fp == NULL)
error (_("Unable to open file '%s' for saving trace data (%s)"),
filename, safe_strerror (errno));
- make_cleanup_fclose (fp);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_header. Write the TFILE header. */
+
+static void
+tfile_write_header (struct trace_file_writer *self)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+ int written;
/* Write a file header, with a high-bit-set char to indicate a
binary file, plus a hint as what this file is, and a version
number in case of future needs. */
- written = fwrite ("\x7fTRACE0\n", 8, 1, fp);
+ written = fwrite ("\x7fTRACE0\n", 8, 1, writer->fp);
if (written < 1)
- perror_with_name (pathname);
+ perror_with_name (writer->pathname);
+}
- /* Write descriptive info. */
+/* This is the implementation of trace_file_write_ops method
+ write_regblock_type. Write the size of register block. */
- /* Write out the size of a register block. */
- fprintf (fp, "R %x\n", trace_regblock_size);
+static void
+tfile_write_regblock_type (struct trace_file_writer *self, int size)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
- /* Write out status of the tracing run (aka "tstatus" info). */
- fprintf (fp, "status %c;%s",
+ fprintf (writer->fp, "R %x\n", size);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_status. */
+
+static void
+tfile_write_status (struct trace_file_writer *self,
+ struct trace_status *ts)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ fprintf (writer->fp, "status %c;%s",
(ts->running ? '1' : '0'), stop_reason_names[ts->stop_reason]);
if (ts->stop_reason == tracepoint_error)
{
char *buf = (char *) alloca (strlen (ts->stop_desc) * 2 + 1);
bin2hex ((gdb_byte *) ts->stop_desc, buf, 0);
- fprintf (fp, ":%s", buf);
+ fprintf (writer->fp, ":%s", buf);
}
- fprintf (fp, ":%x", ts->stopping_tracepoint);
+ fprintf (writer->fp, ":%x", ts->stopping_tracepoint);
if (ts->traceframe_count >= 0)
- fprintf (fp, ";tframes:%x", ts->traceframe_count);
+ fprintf (writer->fp, ";tframes:%x", ts->traceframe_count);
if (ts->traceframes_created >= 0)
- fprintf (fp, ";tcreated:%x", ts->traceframes_created);
+ fprintf (writer->fp, ";tcreated:%x", ts->traceframes_created);
if (ts->buffer_free >= 0)
- fprintf (fp, ";tfree:%x", ts->buffer_free);
+ fprintf (writer->fp, ";tfree:%x", ts->buffer_free);
if (ts->buffer_size >= 0)
- fprintf (fp, ";tsize:%x", ts->buffer_size);
+ fprintf (writer->fp, ";tsize:%x", ts->buffer_size);
if (ts->disconnected_tracing)
- fprintf (fp, ";disconn:%x", ts->disconnected_tracing);
+ fprintf (writer->fp, ";disconn:%x", ts->disconnected_tracing);
if (ts->circular_buffer)
- fprintf (fp, ";circular:%x", ts->circular_buffer);
- fprintf (fp, "\n");
+ fprintf (writer->fp, ";circular:%x", ts->circular_buffer);
+ fprintf (writer->fp, "\n");
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_uploaded_tsv. */
+
+static void
+tfile_write_uploaded_tsv (struct trace_file_writer *self,
+ struct uploaded_tsv *utsv)
+{
+ char *buf = "";
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ if (utsv->name)
+ {
+ buf = (char *) xmalloc (strlen (utsv->name) * 2 + 1);
+ bin2hex ((gdb_byte *) (utsv->name), buf, 0);
+ }
+
+ fprintf (writer->fp, "tsv %x:%s:%x:%s\n",
+ utsv->number, phex_nz (utsv->initial_value, 8),
+ utsv->builtin, buf);
+
+ if (utsv->name)
+ xfree (buf);
+}
+
+#define MAX_TRACE_UPLOAD 2000
+
+/* This is the implementation of trace_file_write_ops method
+ write_uploaded_tp. */
+
+static void
+tfile_write_uploaded_tp (struct trace_file_writer *self,
+ struct uploaded_tp *utp)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+ int a;
+ char *act;
+ gdb_byte buf[MAX_TRACE_UPLOAD];
+
+ fprintf (writer->fp, "tp T%x:%s:%c:%x:%x",
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
+ (utp->enabled ? 'E' : 'D'), utp->step, utp->pass);
+ if (utp->type == bp_fast_tracepoint)
+ fprintf (writer->fp, ":F%x", utp->orig_size);
+ if (utp->cond)
+ fprintf (writer->fp,
+ ":X%x,%s", (unsigned int) strlen (utp->cond) / 2,
+ utp->cond);
+ fprintf (writer->fp, "\n");
+ for (a = 0; VEC_iterate (char_ptr, utp->actions, a, act); ++a)
+ fprintf (writer->fp, "tp A%x:%s:%s\n",
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
+ for (a = 0; VEC_iterate (char_ptr, utp->step_actions, a, act); ++a)
+ fprintf (writer->fp, "tp S%x:%s:%s\n",
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
+ if (utp->at_string)
+ {
+ encode_source_string (utp->number, utp->addr,
+ "at", utp->at_string, buf, MAX_TRACE_UPLOAD);
+ fprintf (writer->fp, "tp Z%s\n", buf);
+ }
+ if (utp->cond_string)
+ {
+ encode_source_string (utp->number, utp->addr,
+ "cond", utp->cond_string,
+ buf, MAX_TRACE_UPLOAD);
+ fprintf (writer->fp, "tp Z%s\n", buf);
+ }
+ for (a = 0; VEC_iterate (char_ptr, utp->cmd_strings, a, act); ++a)
+ {
+ encode_source_string (utp->number, utp->addr, "cmd", act,
+ buf, MAX_TRACE_UPLOAD);
+ fprintf (writer->fp, "tp Z%s\n", buf);
+ }
+ fprintf (writer->fp, "tp V%x:%s:%x:%s\n",
+ utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
+ utp->hit_count,
+ phex_nz (utp->traceframe_usage,
+ sizeof (utp->traceframe_usage)));
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_definition_end. */
+
+static void
+tfile_write_definition_end (struct trace_file_writer *self)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ fprintf (writer->fp, "\n");
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_raw_data. */
+
+static void
+tfile_write_raw_data (struct trace_file_writer *self, gdb_byte *buf,
+ LONGEST len)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+
+ if (fwrite (buf, len, 1, writer->fp) < 1)
+ perror_with_name (writer->pathname);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ end. */
+
+static void
+tfile_end (struct trace_file_writer *self)
+{
+ struct tfile_trace_file_writer *writer
+ = (struct tfile_trace_file_writer *) self;
+ uint32_t gotten = 0;
+
+ /* Mark the end of trace data. */
+ if (fwrite (&gotten, 4, 1, writer->fp) < 1)
+ perror_with_name (writer->pathname);
+}
+
+/* Operations to write trace buffers into TFILE format. */
+
+static const struct trace_file_write_ops tfile_write_ops =
+{
+ tfile_dtor,
+ tfile_target_save,
+ tfile_start,
+ tfile_write_header,
+ tfile_write_regblock_type,
+ tfile_write_status,
+ tfile_write_uploaded_tsv,
+ tfile_write_uploaded_tp,
+ tfile_write_definition_end,
+ tfile_write_raw_data,
+ NULL,
+ tfile_end,
+};
+
+/* Helper macros. */
+
+#define TRACE_WRITE_R_BLOCK(writer, buf, size) \
+ writer->ops->frame_ops->write_r_block ((writer), (buf), (size))
+#define TRACE_WRITE_M_BLOCK_HEADER(writer, addr, size) \
+ writer->ops->frame_ops->write_m_block_header ((writer), (addr), \
+ (size))
+#define TRACE_WRITE_M_BLOCK_MEMORY(writer, buf, size) \
+ writer->ops->frame_ops->write_m_block_memory ((writer), (buf), \
+ (size))
+#define TRACE_WRITE_V_BLOCK(writer, num, val) \
+ writer->ops->frame_ops->write_v_block ((writer), (num), (val))
+
+extern int trace_regblock_size;
+
+/* Save tracepoint data to file named FILENAME through WRITER. WRITER
+ determines the trace file format. If TARGET_DOES_SAVE is non-zero,
+ the save is performed on the target, otherwise GDB obtains all trace
+ data and saves it locally. */
+
+static void
+trace_save (const char *filename, struct trace_file_writer *writer,
+ int target_does_save)
+{
+ struct trace_status *ts = current_trace_status ();
+ int status;
+ struct uploaded_tp *uploaded_tps = NULL, *utp;
+ struct uploaded_tsv *uploaded_tsvs = NULL, *utsv;
+
+ ULONGEST offset = 0;
+ gdb_byte buf[MAX_TRACE_UPLOAD];
+ int written;
+ enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
+
+ /* If the target is to save the data to a file on its own, then just
+ send the command and be done with it. */
+ if (target_does_save)
+ {
+ if (!writer->ops->target_save (writer, filename))
+ error (_("Target failed to save trace data to '%s'."),
+ filename);
+ return;
+ }
+
+ /* Get the trace status first before opening the file, so if the
+ target is losing, we can get out without touching files. */
+ status = target_get_trace_status (ts);
+
+ writer->ops->start (writer, filename);
+
+ writer->ops->write_header (writer);
+
+ /* Write descriptive info. */
+
+ /* Write out the size of a register block. */
+ writer->ops->write_regblock_type (writer, trace_regblock_size);
+
+ /* Write out status of the tracing run (aka "tstatus" info). */
+ writer->ops->write_status (writer, ts);
/* Note that we want to upload tracepoints and save those, rather
than simply writing out the local ones, because the user may have
@@ -3077,22 +3326,7 @@ trace_save (const char *filename, int target_does_save)
target_upload_trace_state_variables (&uploaded_tsvs);
for (utsv = uploaded_tsvs; utsv; utsv = utsv->next)
- {
- char *buf = "";
-
- if (utsv->name)
- {
- buf = (char *) xmalloc (strlen (utsv->name) * 2 + 1);
- bin2hex ((gdb_byte *) (utsv->name), buf, 0);
- }
-
- fprintf (fp, "tsv %x:%s:%x:%s\n",
- utsv->number, phex_nz (utsv->initial_value, 8),
- utsv->builtin, buf);
-
- if (utsv->name)
- xfree (buf);
- }
+ writer->ops->write_uploaded_tsv (writer, utsv);
free_uploaded_tsvs (&uploaded_tsvs);
@@ -3102,76 +3336,205 @@ trace_save (const char *filename, int target_does_save)
target_get_tracepoint_status (NULL, utp);
for (utp = uploaded_tps; utp; utp = utp->next)
+ writer->ops->write_uploaded_tp (writer, utp);
+
+ free_uploaded_tps (&uploaded_tps);
+
+ /* Mark the end of the definition section. */
+ writer->ops->write_definition_end (writer);
+
+ /* Get and write the trace data proper. */
+ while (1)
{
- fprintf (fp, "tp T%x:%s:%c:%x:%x",
- utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
- (utp->enabled ? 'E' : 'D'), utp->step, utp->pass);
- if (utp->type == bp_fast_tracepoint)
- fprintf (fp, ":F%x", utp->orig_size);
- if (utp->cond)
- fprintf (fp, ":X%x,%s", (unsigned int) strlen (utp->cond) / 2,
- utp->cond);
- fprintf (fp, "\n");
- for (a = 0; VEC_iterate (char_ptr, utp->actions, a, act); ++a)
- fprintf (fp, "tp A%x:%s:%s\n",
- utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
- for (a = 0; VEC_iterate (char_ptr, utp->step_actions, a, act); ++a)
- fprintf (fp, "tp S%x:%s:%s\n",
- utp->number, phex_nz (utp->addr, sizeof (utp->addr)), act);
- if (utp->at_string)
- {
- encode_source_string (utp->number, utp->addr,
- "at", utp->at_string, buf, MAX_TRACE_UPLOAD);
- fprintf (fp, "tp Z%s\n", buf);
- }
- if (utp->cond_string)
+ LONGEST gotten = 0;
+
+ /* The writer supports writing the contents of trace buffer
+ directly to trace file. Don't parse the contents of trace
+ buffer. */
+ if (writer->ops->write_trace_buffer != NULL)
{
- encode_source_string (utp->number, utp->addr,
- "cond", utp->cond_string,
- buf, MAX_TRACE_UPLOAD);
- fprintf (fp, "tp Z%s\n", buf);
+ /* We ask for big blocks, in the hopes of efficiency, but
+ will take less if the target has packet size limitations
+ or some such. */
+ gotten = target_get_raw_trace_data (buf, offset,
+ MAX_TRACE_UPLOAD);
+ if (gotten < 0)
+ error (_("Failure to get requested trace buffer data"));
+ /* No more data is forthcoming, we're done. */
+ if (gotten == 0)
+ break;
+
+ writer->ops->write_trace_buffer (writer, buf, gotten);
+
+ offset += gotten;
}
- for (a = 0; VEC_iterate (char_ptr, utp->cmd_strings, a, act); ++a)
+ else
{
- encode_source_string (utp->number, utp->addr, "cmd", act,
- buf, MAX_TRACE_UPLOAD);
- fprintf (fp, "tp Z%s\n", buf);
+ uint16_t tp_num;
+ uint32_t tf_size;
+ /* Parse the trace buffers according to how data are stored
+ in trace buffer in GDBserver. */
+
+ gotten = target_get_raw_trace_data (buf, offset, 6);
+
+ if (gotten == 0)
+ break;
+
+ /* Read the first six bytes in, which is the tracepoint
+ number and trace frame size. */
+ tp_num = (uint16_t)
+ extract_unsigned_integer (&buf[0], 2, byte_order);
+
+ tf_size = (uint32_t)
+ extract_unsigned_integer (&buf[2], 4, byte_order);
+
+ writer->ops->frame_ops->start (writer, tp_num);
+ gotten = 6;
+
+ if (tf_size > 0)
+ {
+ unsigned int block;
+
+ offset += 6;
+
+ for (block = 0; block < tf_size; )
+ {
+ gdb_byte block_type;
+
+ /* We'll fetch one block each time, in order to
+ handle the extremely large 'M' block. We first
+ fetch one byte to get the type of the block. */
+ gotten = target_get_raw_trace_data (buf, offset, 1);
+ if (gotten < 1)
+ error (_("Failure to get requested trace buffer data"));
+
+ gotten = 1;
+ block += 1;
+ offset += 1;
+
+ block_type = buf[0];
+ switch (block_type)
+ {
+ case 'R':
+ gotten
+ = target_get_raw_trace_data (buf, offset,
+ trace_regblock_size);
+ if (gotten < trace_regblock_size)
+ error (_("Failure to get requested trace"
+ " buffer data"));
+
+ TRACE_WRITE_R_BLOCK (writer, buf,
+ trace_regblock_size);
+ break;
+ case 'M':
+ {
+ unsigned short mlen;
+ ULONGEST addr;
+ LONGEST t;
+ int j;
+
+ t = target_get_raw_trace_data (buf,offset, 10);
+ if (t < 10)
+ error (_("Failure to get requested trace"
+ " buffer data"));
+
+ offset += 10;
+ block += 10;
+
+ gotten = 0;
+ addr = (ULONGEST)
+ extract_unsigned_integer (buf, 8,
+ byte_order);
+ mlen = (unsigned short)
+ extract_unsigned_integer (&buf[8], 2,
+ byte_order);
+
+ TRACE_WRITE_M_BLOCK_HEADER (writer, addr,
+ mlen);
+
+ /* The memory contents in 'M' block may be
+ very large. Fetch the data from the target
+ and write them into file one by one. */
+ for (j = 0; j < mlen; )
+ {
+ unsigned int read_length;
+
+ if (mlen - j > MAX_TRACE_UPLOAD)
+ read_length = MAX_TRACE_UPLOAD;
+ else
+ read_length = mlen - j;
+
+ t = target_get_raw_trace_data (buf,
+ offset + j,
+ read_length);
+ if (t < read_length)
+ error (_("Failure to get requested"
+ " trace buffer data"));
+
+ TRACE_WRITE_M_BLOCK_MEMORY (writer, buf,
+ read_length);
+
+ j += read_length;
+ gotten += read_length;
+ }
+
+ break;
+ }
+ case 'V':
+ {
+ int vnum;
+ LONGEST val;
+
+ gotten
+ = target_get_raw_trace_data (buf, offset,
+ 12);
+ if (gotten < 12)
+ error (_("Failure to get requested"
+ " trace buffer data"));
+
+ vnum = (int) extract_signed_integer (buf,
+ 4,
+ byte_order);
+ val
+ = extract_signed_integer (&buf[4], 8,
+ byte_order);
+
+ TRACE_WRITE_V_BLOCK (writer, vnum, val);
+ }
+ break;
+ default:
+ error (_("Unknown block type '%c' (0x%x) in"
+ " trace frame"),
+ block_type, block_type);
+ }
+
+ block += gotten;
+ offset += gotten;
+ }
+ }
+ else
+ offset += gotten;
+
+ writer->ops->frame_ops->end (writer);
}
- fprintf (fp, "tp V%x:%s:%x:%s\n",
- utp->number, phex_nz (utp->addr, sizeof (utp->addr)),
- utp->hit_count,
- phex_nz (utp->traceframe_usage,
- sizeof (utp->traceframe_usage)));
}
- free_uploaded_tps (&uploaded_tps);
+ writer->ops->end (writer);
+}
- /* Mark the end of the definition section. */
- fprintf (fp, "\n");
+/* Return a trace writer for TFILE format. */
- /* Get and write the trace data proper. We ask for big blocks, in
- the hopes of efficiency, but will take less if the target has
- packet size limitations or some such. */
- while (1)
- {
- gotten = target_get_raw_trace_data (buf, offset, MAX_TRACE_UPLOAD);
- if (gotten < 0)
- error (_("Failure to get requested trace buffer data"));
- /* No more data is forthcoming, we're done. */
- if (gotten == 0)
- break;
- written = fwrite (buf, gotten, 1, fp);
- if (written < 1)
- perror_with_name (pathname);
- offset += gotten;
- }
+static struct trace_file_writer *
+tfile_trace_file_writer_new (void)
+{
+ struct tfile_trace_file_writer *writer
+ = xmalloc (sizeof (struct tfile_trace_file_writer));
- /* Mark the end of trace data. (We know that gotten is 0 at this point.) */
- written = fwrite (&gotten, 4, 1, fp);
- if (written < 1)
- perror_with_name (pathname);
+ writer->base.ops = &tfile_write_ops;
+ writer->fp = NULL;
+ writer->pathname = NULL;
- do_cleanups (cleanup);
+ return (struct trace_file_writer *) writer;
}
static void
@@ -3181,6 +3544,7 @@ trace_save_command (char *args, int from_tty)
char **argv;
char *filename = NULL;
struct cleanup *back_to;
+ struct trace_file_writer *writer = NULL;
if (args == NULL)
error_no_arg (_("file in which to save trace data"));
@@ -3201,7 +3565,11 @@ trace_save_command (char *args, int from_tty)
if (!filename)
error_no_arg (_("file in which to save trace data"));
- trace_save (filename, target_does_save);
+ writer = tfile_trace_file_writer_new ();
+
+ make_cleanup (trace_file_writer_xfree, writer);
+
+ trace_save (filename, writer, target_does_save);
if (from_tty)
printf_filtered (_("Trace data saved to file '%s'.\n"), filename);
@@ -3209,6 +3577,20 @@ trace_save_command (char *args, int from_tty)
do_cleanups (back_to);
}
+/* Save the trace data to file FILENAME of tfile format. */
+
+void
+trace_save_tfile (const char *filename, int target_does_save)
+{
+ struct trace_file_writer *writer;
+ struct cleanup *back_to;
+
+ writer = tfile_trace_file_writer_new ();
+ back_to = make_cleanup (trace_file_writer_xfree, writer);
+ trace_save (filename, writer, target_does_save);
+ do_cleanups (back_to);
+}
+
/* Tell the target what to do with an ongoing tracing run if GDB
disconnects for some reason. */
diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
index b03c95b..a5d3d42 100644
--- a/gdb/tracepoint.h
+++ b/gdb/tracepoint.h
@@ -205,6 +205,111 @@ struct static_tracepoint_marker
char *extra;
};
+struct trace_file_writer;
+
+/* Operations to write trace frames to a specific trace format. */
+
+struct trace_frame_write_ops
+{
+ /* Write a new trace frame. The tracepoint number of this trace
+ frame is TPNUM. */
+ void (*start) (struct trace_file_writer *self, uint16_t tpnum);
+
+ /* Write an 'R' block. Buffer BUF contains its contents and SIZE is
+ its size. */
+ void (*write_r_block) (struct trace_file_writer *self,
+ gdb_byte *buf, int32_t size);
+
+ /* Write an 'M' block, the header and memory contents respectively.
+ The header of 'M' block is composed of the start address and the
+ length of memory collection, and the memory contents contain
+ the collected memory contents in tracing.
+ For extremely large M block, GDB is unable to get its contents
+ and write them into trace file in one go, due to the limitation
+ of the remote target or the size of internal buffer, we split
+ the operation to 'M' block to two operations. */
+ /* Write the head of 'M' block. ADDR is the start address of
+ collected memory and LENGTH is the length of memory contents. */
+ void (*write_m_block_header) (struct trace_file_writer *self,
+ uint64_t addr, uint16_t length);
+ /* Write the memory contents of 'M' block. Buffer BUF contains
+ its contents and LENGTH is its length. This method can be called
+ multiple times to write large memory contents of a single 'M'
+ block. */
+ void (*write_m_block_memory) (struct trace_file_writer *self,
+ gdb_byte *buf, uint16_t length);
+
+ /* Write a 'V' block. NUM is the trace variable number and VAL is
+ the value of the trace variable. */
+ void (*write_v_block) (struct trace_file_writer *self, int32_t num,
+ uint64_t val);
+
+ /* The end of the trace frame. */
+ void (*end) (struct trace_file_writer *self);
+};
+
+/* Operations to write trace buffers to a specific trace format. */
+
+struct trace_file_write_ops
+{
+ /* Destructor. Releases everything from SELF (but not SELF
+ itself). */
+ void (*dtor) (struct trace_file_writer *self);
+
+ /* Save the data to file or directory NAME of desired format in
+ target side. Return true for success, otherwise return
+ false. */
+ int (*target_save) (struct trace_file_writer *self,
+ const char *name);
+
+ /* Write the trace buffers to file or directory NAME. */
+ void (*start) (struct trace_file_writer *self,
+ const char *name);
+
+ /* Write the trace header. */
+ void (*write_header) (struct trace_file_writer *self);
+
+ /* Write the type of block about registers. SIZE is the size of
+ all registers on the target. */
+ void (*write_regblock_type) (struct trace_file_writer *self,
+ int size);
+
+ /* Write trace status TS. */
+ void (*write_status) (struct trace_file_writer *self,
+ struct trace_status *ts);
+
+ /* Write the uploaded TSV. */
+ void (*write_uploaded_tsv) (struct trace_file_writer *self,
+ struct uploaded_tsv *tsv);
+
+ /* Write the uploaded tracepoint TP. */
+ void (*write_uploaded_tp) (struct trace_file_writer *self,
+ struct uploaded_tp *tp);
+
+ /* Write to mark the end of the definition part. */
+ void (*write_definition_end) (struct trace_file_writer *self);
+
+ /* Write the data of trace buffer without parsing. The content is
+ in BUF and length is LEN. */
+ void (*write_trace_buffer) (struct trace_file_writer *self,
+ gdb_byte *buf, LONGEST len);
+
+ /* Operations to write trace frames. The user of this field is
+ responsible to parse the data of trace buffer. Either field
+ 'write_trace_buffer' or field ' frame_ops' is NULL. */
+ const struct trace_frame_write_ops *frame_ops;
+
+ /* The end of writing trace buffers. */
+ void (*end) (struct trace_file_writer *self);
+};
+
+/* Trace file writer for a given format. */
+
+struct trace_file_writer
+{
+ const struct trace_file_write_ops *ops;
+};
+
extern void parse_static_tracepoint_marker_definition
(char *line, char **pp,
struct static_tracepoint_marker *marker);
@@ -281,7 +386,8 @@ extern void tfind_1 (enum trace_find_type type, int num,
ULONGEST addr1, ULONGEST addr2,
int from_tty);
-extern void trace_save (const char *filename, int target_does_save);
+extern void trace_save_tfile (const char *filename,
+ int target_does_save);
extern struct traceframe_info *parse_traceframe_info (const char *tframe_info);
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v3 08/15] Write 'stop_desc' of trace status to tfile
2013-03-09 3:48 [PATCH v3 00/15] CTF Support Yao Qi
` (3 preceding siblings ...)
2013-03-09 3:49 ` [PATCH v3 01/15] Refactor 'tsave' Yao Qi
@ 2013-03-09 3:49 ` Yao Qi
2013-03-12 19:15 ` Tom Tromey
2013-03-09 3:49 ` [PATCH v3 09/15] Check the tstatus output on tfile target Yao Qi
` (10 subsequent siblings)
15 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-09 3:49 UTC (permalink / raw)
To: gdb-patches
The field "stop_desc" of "struct trace_status" is parsed (in
parse_trace_status) when the stop reason is tstop_command or
tracepoint_error. However, the "stop_desc" is only written to tfile
when stop_reason is tracepoint_error. Here is an inconsistency.
This patch fixes this inconsistency, as a result, the "tstatus" output
on tfile target is the same as its output on live target.
gdb:
2013-03-08 Yao Qi <yao@codesourcery.com>
* tracepoint.c (tfile_write_status): Write 'stop_desc' of trace
status to tfile if trace is stopped by command 'tstop'.
---
gdb/tracepoint.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 2525b1b..850adb9 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -3058,7 +3058,8 @@ tfile_write_status (struct trace_file_writer *self,
fprintf (writer->fp, "status %c;%s",
(ts->running ? '1' : '0'), stop_reason_names[ts->stop_reason]);
- if (ts->stop_reason == tracepoint_error)
+ if (ts->stop_reason == tracepoint_error
+ || ts->stop_reason == tstop_command)
{
char *buf = (char *) alloca (strlen (ts->stop_desc) * 2 + 1);
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* [PATCH v3 09/15] Check the tstatus output on tfile target
2013-03-09 3:48 [PATCH v3 00/15] CTF Support Yao Qi
` (4 preceding siblings ...)
2013-03-09 3:49 ` [PATCH v3 08/15] Write 'stop_desc' of trace status to tfile Yao Qi
@ 2013-03-09 3:49 ` Yao Qi
2013-03-12 19:45 ` Tom Tromey
2013-03-09 3:49 ` [PATCH v3 07/15] Write trace notes and username into tfile Yao Qi
` (9 subsequent siblings)
15 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-09 3:49 UTC (permalink / raw)
To: gdb-patches
There is no reason that the "tstatus" output on tfile target is
different from its output on live target (except for "Using a trace
file"). In this patch, we capture the output of "tstatus" in live
target, and use it to check the "tstatus" output in tfile target. It
is quite useful to expose the differences in "tstatus" output and the
previous two patches are to fix these differences.
gdb/testsuite:
2013-03-08 Yao Qi <yao@codesourcery.com>
* gdb.trace/tstatus.exp (run_trace_experiment): Save the output
of 'tstatus' into tstatus_output.
(top level): Save the trace data to tfile. Read trace file in
tfile target. Check the trace status.
---
gdb/testsuite/gdb.trace/tstatus.exp | 32 ++++++++++++++++++++++++++++++--
1 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/gdb/testsuite/gdb.trace/tstatus.exp b/gdb/testsuite/gdb.trace/tstatus.exp
index 743db91..c105048 100644
--- a/gdb/testsuite/gdb.trace/tstatus.exp
+++ b/gdb/testsuite/gdb.trace/tstatus.exp
@@ -34,9 +34,12 @@ if ![gdb_target_supports_trace] {
return -1
}
+set tstatus_output ""
+
proc run_trace_experiment {} {
global gdb_prompt
global decimal
+ global tstatus_output
# gdb_test_no_output "set debug remote 1" ""
@@ -93,10 +96,12 @@ proc run_trace_experiment {} {
set test "tstatus reports trace stop reason"
gdb_test_multiple "tstatus" $test {
- -re "Trace stopped by a tstop command \\(because I can\\)\..*Trace will stop if GDB disconnects\.\[\r\n\]+Trace user is me me me\.\[\r\n\]+Trace notes: different note\.\[\r\n\]+Not looking at any trace frame\..*\r\n$gdb_prompt $" {
+ -re "(Trace stopped by a tstop command \\(because I can\\)\..*Trace will stop if GDB disconnects\.\[\r\n\]+Trace user is me me me\.\[\r\n\]+Trace notes: different note\.\[\r\n\]+Not looking at any trace frame\.).*\r\n$gdb_prompt $" {
+ set tstatus_output $expect_out(1,string)
pass $test
}
- -re "Trace stopped by a tstop command\..*\r\n$gdb_prompt $" {
+ -re "(Trace stopped by a tstop command\.).*\r\n$gdb_prompt $" {
+ set tstatus_output $expect_out(1,string)
unsupported $test
}
}
@@ -131,3 +136,26 @@ proc test_tracepoints {} {
}
test_tracepoints
+
+# Save trace frames to tfile.
+gdb_test "tsave tstatus.tf" "Trace data saved to file 'tstatus.tf'.*"
+
+# Change target to tfile.
+set test "change to tfile target"
+gdb_test_multiple "target tfile tstatus.tf" "$test" {
+ -re "A program is being debugged already. Kill it. .y or n. " {
+ send_gdb "y\n"
+ exp_continue
+ }
+ -re "$gdb_prompt $" {
+ pass "$test"
+ }
+}
+
+# Convert "(because I can) to "\(because I can\)"
+set tstatus_output [string map {\( \\(} $tstatus_output]
+set tstatus_output [string map {\) \\)} $tstatus_output]
+
+# The status should be identical to the status of live inferior.
+gdb_test "tstatus" "Using a trace file\.\r\n${tstatus_output}.*" \
+ "tstatus on tfile target"
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* [PATCH v3 07/15] Write trace notes and username into tfile.
2013-03-09 3:48 [PATCH v3 00/15] CTF Support Yao Qi
` (5 preceding siblings ...)
2013-03-09 3:49 ` [PATCH v3 09/15] Check the tstatus output on tfile target Yao Qi
@ 2013-03-09 3:49 ` Yao Qi
2013-03-12 19:35 ` Tom Tromey
2013-03-09 3:49 ` [PATCH v3 05/15] ctf test: report.exp Yao Qi
` (8 subsequent siblings)
15 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-09 3:49 UTC (permalink / raw)
To: gdb-patches
The fields "notes" and "user_name" in "struct trace_status" are used
in the output of "tstatus". When in tfile target, the "notes" and
"user name" are missing the output of "tstatus", because GDB doesn't
write them into tfile. With this patch, GDB starts to write them into
tfile, and the corresponding information will be shown when GDB reads
trace status from the tfile target.
gdb:
2013-03-08 Yao Qi <yao@codesourcery.com>
* tracepoint.c (tfile_write_status): Write trace notes and user
name into tfile if they are not NULL.
---
gdb/tracepoint.c | 14 ++++++++++++++
1 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index d224e14..2525b1b 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -3078,6 +3078,20 @@ tfile_write_status (struct trace_file_writer *self,
fprintf (writer->fp, ";disconn:%x", ts->disconnected_tracing);
if (ts->circular_buffer)
fprintf (writer->fp, ";circular:%x", ts->circular_buffer);
+ if (ts->notes != NULL)
+ {
+ char *buf = (char *) alloca (strlen (ts->notes) * 2 + 1);
+
+ bin2hex ((gdb_byte *) ts->notes, buf, 0);
+ fprintf (writer->fp, ";notes:%s", buf);
+ }
+ if (ts->user_name != NULL)
+ {
+ char *buf = (char *) alloca (strlen (ts->user_name) * 2 + 1);
+
+ bin2hex ((gdb_byte *) ts->user_name, buf, 0);
+ fprintf (writer->fp, ";username:%s", buf);
+ }
fprintf (writer->fp, "\n");
}
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* [PATCH v3 05/15] ctf test: report.exp
2013-03-09 3:48 [PATCH v3 00/15] CTF Support Yao Qi
` (6 preceding siblings ...)
2013-03-09 3:49 ` [PATCH v3 07/15] Write trace notes and username into tfile Yao Qi
@ 2013-03-09 3:49 ` Yao Qi
2013-03-12 19:25 ` Tom Tromey
2013-03-09 3:49 ` [PATCH v3 14/15] Test on saving tracepoint defs: CTF Yao Qi
` (7 subsequent siblings)
15 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-09 3:49 UTC (permalink / raw)
To: gdb-patches
This is a test to see GDB gets the same output as live target and
TFILE trace format.
In V3, we remove the code checking target 'ctf' exists or not, just
issue the command "target ctf report.ctf", if the command is
recognized by GDB, do the tests otherwise, do nothing.
gdb/testsuite:
2013-03-08 Yao Qi <yao@codesourcery.com>
* gdb.trace/report.exp: Test GDB saves trace data to CTF
format and read CTF trace file if GDB supports.
---
gdb/testsuite/gdb.trace/report.exp | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/gdb/testsuite/gdb.trace/report.exp b/gdb/testsuite/gdb.trace/report.exp
index b32bca1..fc5f711 100644
--- a/gdb/testsuite/gdb.trace/report.exp
+++ b/gdb/testsuite/gdb.trace/report.exp
@@ -408,6 +408,10 @@ gdb_tfind_test "finished: make sure not debugging any trace frame" \
# Save trace frames to tfile.
gdb_test "tsave report.tf" "Trace data saved to file 'report.tf'.*"
+# Save trace frames to ctf.
+gdb_test "tsave -ctf ${testfile}.ctf" \
+ "Trace data saved to directory '${testfile}.ctf'.*"
+
# Change target to tfile.
set test "change to tfile target"
gdb_test_multiple "target tfile report.tf" "$test" {
@@ -421,3 +425,12 @@ gdb_test_multiple "target tfile report.tf" "$test" {
}
# Test the collected trace frames from tfile.
use_collected_data "tfile"
+
+# Try to read ctf data if GDB supports.
+gdb_test_multiple "target ctf ${testfile}.ctf" "" {
+ -re "Undefined target command: \"ctf ${testfile}.ctf\"\. Try \"help target\"\.\r\n$gdb_prompt $" {
+ }
+ -re ".*\r\n$gdb_prompt $" {
+ use_collected_data "ctf"
+ }
+}
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* [PATCH v3 14/15] Test on saving tracepoint defs: CTF
2013-03-09 3:48 [PATCH v3 00/15] CTF Support Yao Qi
` (7 preceding siblings ...)
2013-03-09 3:49 ` [PATCH v3 05/15] ctf test: report.exp Yao Qi
@ 2013-03-09 3:49 ` Yao Qi
2013-03-12 20:23 ` Tom Tromey
2013-03-09 3:49 ` [PATCH v3 15/15] MAINTAINERS Yao Qi
` (6 subsequent siblings)
15 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-09 3:49 UTC (permalink / raw)
To: gdb-patches
Similarly, we have to exercise the CTF code on writing actions to
trace file and restoring them.
gdb/testsuite:
2013-03-08 Yao Qi <yao@codesourcery.com>
* gdb.trace/actions.exp: Save trace data to CTF.
Change to ctf target if GDB supports, read CTF data in ctf
target, and check the actions of tracepoints.
* gdb.trace/while-stepping.exp: Likewise.
---
gdb/testsuite/gdb.trace/actions.exp | 17 +++++++++++++++++
gdb/testsuite/gdb.trace/while-stepping.exp | 17 +++++++++++++++++
2 files changed, 34 insertions(+), 0 deletions(-)
diff --git a/gdb/testsuite/gdb.trace/actions.exp b/gdb/testsuite/gdb.trace/actions.exp
index 7bbe6b6..0a77365 100644
--- a/gdb/testsuite/gdb.trace/actions.exp
+++ b/gdb/testsuite/gdb.trace/actions.exp
@@ -308,6 +308,8 @@ check_tracepoint "live"
gdb_test_no_output "tstop" ""
gdb_test "tsave ${testfile}.tf" \
"Trace data saved to file '${testfile}.tf'\.\\r"
+gdb_test "tsave -ctf ${testfile}.ctf" \
+ "Trace data saved to directory '${testfile}.ctf'\.\\r"
# Restart GDB and read the trace data in tfile target.
gdb_exit
@@ -317,3 +319,18 @@ gdb_file_cmd $binfile
gdb_test "target tfile ${testfile}.tf" ".*" \
"change to tfile target"
check_tracepoint "tfile"
+
+# Try to read ctf data if GDB supports.
+gdb_test_multiple "target ctf ${testfile}.ctf" "" {
+ -re "Undefined target command: \"ctf ${testfile}.ctf\"\. Try \"help target\"\.\r\n$gdb_prompt $" {
+ }
+ -re ".*\r\n$gdb_prompt $" {
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_file_cmd $binfile
+ gdb_test "target ctf ${testfile}.ctf" ".*" \
+ "change to ctf target"
+ check_tracepoint "ctf"
+ }
+}
diff --git a/gdb/testsuite/gdb.trace/while-stepping.exp b/gdb/testsuite/gdb.trace/while-stepping.exp
index 0f316eb..e057fab 100644
--- a/gdb/testsuite/gdb.trace/while-stepping.exp
+++ b/gdb/testsuite/gdb.trace/while-stepping.exp
@@ -132,6 +132,8 @@ check_tracepoint "live"
gdb_test_no_output "tstop"
gdb_test "tsave ${testfile}.tf" \
"Trace data saved to file '${testfile}.tf'\.\\r"
+gdb_test "tsave -ctf ${testfile}.ctf" \
+ "Trace data saved to directory '${testfile}.ctf'\.\\r"
# Restart GDB and read the trace data in tfile target.
gdb_exit
@@ -141,3 +143,18 @@ gdb_file_cmd $binfile
gdb_test "target tfile ${testfile}.tf" ".*" \
"change to tfile target"
check_tracepoint "tfile"
+
+# Try to read ctf data if GDB supports.
+gdb_test_multiple "target ctf ${testfile}.ctf" "" {
+ -re "Undefined target command: \"ctf ${testfile}.ctf\"\. Try \"help target\"\.\r\n$gdb_prompt $" {
+ }
+ -re ".*\r\n$gdb_prompt $" {
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_file_cmd $binfile
+ gdb_test "target ctf ${testfile}.ctf" ".*" \
+ "change to ctf target"
+ check_tracepoint "ctf"
+ }
+}
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 14/15] Test on saving tracepoint defs: CTF
2013-03-09 3:49 ` [PATCH v3 14/15] Test on saving tracepoint defs: CTF Yao Qi
@ 2013-03-12 20:23 ` Tom Tromey
2013-03-13 9:55 ` Yao Qi
0 siblings, 1 reply; 60+ messages in thread
From: Tom Tromey @ 2013-03-12 20:23 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes:
Yao> +gdb_test "tsave -ctf ${testfile}.ctf" \
Yao> + "Trace data saved to directory '${testfile}.ctf'\.\\r"
standard_output_file if you don't mind.
Yao> +gdb_test_multiple "target ctf ${testfile}.ctf" "" {
Yao> + -re "Undefined target command: \"ctf ${testfile}.ctf\"\. Try \"help target\"\.\r\n$gdb_prompt $" {
Yao> + }
Yao> + -re ".*\r\n$gdb_prompt $" {
Yao> + gdb_exit
Yao> + gdb_start
Yao> + gdb_reinitialize_dir $srcdir/$subdir
Yao> + gdb_file_cmd $binfile
Yao> + gdb_test "target ctf ${testfile}.ctf" ".*" \
Yao> + "change to ctf target"
Yao> + check_tracepoint "ctf"
It seems very iffy to me to restart gdb inside a call to gdb_test_multiple.
I would instead recommend setting a flag and checking it outside this
command.
Tom
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 14/15] Test on saving tracepoint defs: CTF
2013-03-12 20:23 ` Tom Tromey
@ 2013-03-13 9:55 ` Yao Qi
2013-03-13 15:49 ` Tom Tromey
0 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-13 9:55 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 03/13/2013 04:23 AM, Tom Tromey wrote:
> standard_output_file if you don't mind.
>
'standard_output_file' is used in the patch 13/15, and save the file
name in 'tracefile'. We use $tracefile here.
> Yao> +gdb_test_multiple "target ctf ${testfile}.ctf" "" {
> Yao> + -re "Undefined target command: \"ctf ${testfile}.ctf\"\. Try \"help target\"\.\r\n$gdb_prompt $" {
> Yao> + }
> Yao> + -re ".*\r\n$gdb_prompt $" {
> Yao> + gdb_exit
> Yao> + gdb_start
> Yao> + gdb_reinitialize_dir $srcdir/$subdir
> Yao> + gdb_file_cmd $binfile
> Yao> + gdb_test "target ctf ${testfile}.ctf" ".*" \
> Yao> + "change to ctf target"
> Yao> + check_tracepoint "ctf"
>
> It seems very iffy to me to restart gdb inside a call to gdb_test_multiple.
> I would instead recommend setting a flag and checking it outside this
> command.
Fixed as you suggested.
--
Yao (é½å°§)
gdb/testsuite:
2013-03-11 Yao Qi <yao@codesourcery.com>
* gdb.trace/actions.exp: Save trace data to CTF.
Change to ctf target if GDB supports, read CTF data in ctf
target, and check the actions of tracepoints.
* gdb.trace/while-stepping.exp: Likewise.
---
gdb/testsuite/gdb.trace/actions.exp | 23 +++++++++++++++++++++++
gdb/testsuite/gdb.trace/while-stepping.exp | 23 +++++++++++++++++++++++
2 files changed, 46 insertions(+), 0 deletions(-)
diff --git a/gdb/testsuite/gdb.trace/actions.exp b/gdb/testsuite/gdb.trace/actions.exp
index 5fa1b97..74db104 100644
--- a/gdb/testsuite/gdb.trace/actions.exp
+++ b/gdb/testsuite/gdb.trace/actions.exp
@@ -310,6 +310,8 @@ gdb_test_no_output "tstop" ""
set tracefile [standard_output_file ${testfile}]
gdb_test "tsave ${tracefile}.tf" \
"Trace data saved to file '${tracefile}.tf'\.\\r"
+gdb_test "tsave -ctf ${tracefile}.ctf" \
+ "Trace data saved to directory '${tracefile}.ctf'\.\\r"
# Restart GDB and read the trace data in tfile target.
gdb_exit
@@ -319,3 +321,24 @@ gdb_file_cmd $binfile
gdb_test "target tfile ${tracefile}.tf" ".*" \
"change to tfile target"
check_tracepoint "tfile"
+
+# Try to read ctf data if GDB supports.
+set gdb_can_read_ctf_data 0
+gdb_test_multiple "target ctf" "" {
+ -re "Undefined target command: \"ctf\"\. Try \"help target\"\.\r\n$gdb_prompt $" {
+ set gdb_can_read_ctf_data 0
+ }
+ -re "No CTF directory specified.*\r\n$gdb_prompt $" {
+ set gdb_can_read_ctf_data 1
+ }
+}
+
+if { $gdb_can_read_ctf_data } {
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_file_cmd $binfile
+ gdb_test "target ctf ${tracefile}.ctf" ".*" \
+ "change to ctf target"
+ check_tracepoint "ctf"
+}
diff --git a/gdb/testsuite/gdb.trace/while-stepping.exp b/gdb/testsuite/gdb.trace/while-stepping.exp
index 0b823a4..c74281f 100644
--- a/gdb/testsuite/gdb.trace/while-stepping.exp
+++ b/gdb/testsuite/gdb.trace/while-stepping.exp
@@ -136,6 +136,8 @@ set tracefile [standard_output_file ${testfile}]
gdb_test "tsave ${tracefile}.tf" \
"Trace data saved to file '${tracefile}.tf'\.\\r" \
"save tfile trace file"
+gdb_test "tsave -ctf ${tracefile}.ctf" \
+ "Trace data saved to directory '${tracefile}.ctf'\.\\r"
# Restart GDB and read the trace data in tfile target.
gdb_exit
@@ -145,3 +147,24 @@ gdb_file_cmd $binfile
gdb_test "target tfile ${tracefile}.tf" ".*" \
"change to tfile target"
check_tracepoint "tfile"
+
+# Try to read ctf data if GDB supports.
+set gdb_can_read_ctf_data 0
+gdb_test_multiple "target ctf" "" {
+ -re "Undefined target command: \"ctf\"\. Try \"help target\"\.\r\n$gdb_prompt $" {
+ set gdb_can_read_ctf_data 0
+ }
+ -re "No CTF directory specified.*\r\n$gdb_prompt $" {
+ set gdb_can_read_ctf_data 1
+ }
+}
+
+if { $gdb_can_read_ctf_data } {
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_file_cmd $binfile
+ gdb_test "target ctf ${tracefile}.ctf" ".*" \
+ "change to ctf target"
+ check_tracepoint "ctf"
+}
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 14/15] Test on saving tracepoint defs: CTF
2013-03-13 9:55 ` Yao Qi
@ 2013-03-13 15:49 ` Tom Tromey
0 siblings, 0 replies; 60+ messages in thread
From: Tom Tromey @ 2013-03-13 15:49 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes:
Yao> 2013-03-11 Yao Qi <yao@codesourcery.com>
Yao> * gdb.trace/actions.exp: Save trace data to CTF.
Yao> Change to ctf target if GDB supports, read CTF data in ctf
Yao> target, and check the actions of tracepoints.
Yao> * gdb.trace/while-stepping.exp: Likewise.
Thanks, this is ok.
Tom
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v3 15/15] MAINTAINERS
2013-03-09 3:48 [PATCH v3 00/15] CTF Support Yao Qi
` (8 preceding siblings ...)
2013-03-09 3:49 ` [PATCH v3 14/15] Test on saving tracepoint defs: CTF Yao Qi
@ 2013-03-09 3:49 ` Yao Qi
2013-03-09 3:49 ` [PATCH v3 12/15] Write tracepoint definition in CTF and read Yao Qi
` (5 subsequent siblings)
15 siblings, 0 replies; 60+ messages in thread
From: Yao Qi @ 2013-03-09 3:49 UTC (permalink / raw)
To: gdb-patches
Last bu not least,
I'd like to nominate myself as a CTF related code maintainer. Is
there any objection?
gdb:
2013-03-08 Yao Qi <yao@codesourcery.com>
* MAINTAINERS (Responsible Maintainers/misc): Add myself as
responsible of ctf.h and ctf.c.
---
gdb/MAINTAINERS | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/gdb/MAINTAINERS b/gdb/MAINTAINERS
index 53c5e7c..df75f50 100644
--- a/gdb/MAINTAINERS
+++ b/gdb/MAINTAINERS
@@ -410,6 +410,7 @@ tcl/ tk/ itcl/ ALL
contrib/ari Pierre Muller muller@sourceware.org
+ctf.h, ctf.c Yao Qi yao@codesourcery.com
Authorized Committers
---------------------
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* [PATCH v3 12/15] Write tracepoint definition in CTF and read.
2013-03-09 3:48 [PATCH v3 00/15] CTF Support Yao Qi
` (9 preceding siblings ...)
2013-03-09 3:49 ` [PATCH v3 15/15] MAINTAINERS Yao Qi
@ 2013-03-09 3:49 ` Yao Qi
2013-03-12 20:02 ` Tom Tromey
2013-03-14 18:34 ` Doug Evans
2013-03-09 3:49 ` [PATCH v3 10/15] tstatus.exp: ctf Yao Qi
` (4 subsequent siblings)
15 siblings, 2 replies; 60+ messages in thread
From: Yao Qi @ 2013-03-09 3:49 UTC (permalink / raw)
To: gdb-patches
This patch teaches GDB to write uploaded tracepoints to CTF, and also
read them out from CTF.
gdb:
2013-03-08 Yao Qi <yao@codesourcery.com>
* ctf.c (CTF_EVENT_ID_TP_DEF): New macro.
ctf_write_header): Define event type "tp_def" in metadata.
(ctf_write_uploaded_tp): Write tracepoint definition to CTF.
(SET_ARRAY_FIELD, SET_STRING_FIELD): New macros.
(ctf_read_tp): New.
(ctf_open): Call ctf_read_tp. Adjust the event id checking.
Call merge_uploaded_tracepoints.
---
gdb/ctf.c | 218 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 files changed, 212 insertions(+), 6 deletions(-)
diff --git a/gdb/ctf.c b/gdb/ctf.c
index 934ba10..e46b183 100644
--- a/gdb/ctf.c
+++ b/gdb/ctf.c
@@ -39,7 +39,10 @@
3. Uploaded trace variables. Event "tsv_def" is defined in metata,
which is about all aspects of a uploaded trace variable.
- Uploaded tracepoints. Not implemented yet in CTF writer.
+ Uploaded tracepoints. Event "tp_def" is defined in meta, which
+ is about all aspects of a uploaded tracepoint. Note that the
+ "sequence" (a CTF type, which is a dynamically-sized array.) is
+ used for "actions" "step_actions" and "cmd_strings".
4. Trace frames. Each trace frame is composed by several blocks
of different types ('R', 'M', 'V'). One trace frame is saved in
@@ -69,6 +72,7 @@
#define CTF_EVENT_ID_FRAME 3
#define CTF_EVENT_ID_STATUS 4
#define CTF_EVENT_ID_TSV_DEF 5
+#define CTF_EVENT_ID_TP_DEF 6
/* The state kept while writing the CTF datastream file. */
@@ -371,6 +375,34 @@ ctf_write_header (struct trace_file_writer *self)
"\t};\n"
"};\n", CTF_EVENT_ID_TSV_DEF);
+ ctf_save_write_metadata (&writer->tcs, "\n");
+ ctf_save_write_metadata (&writer->tcs,
+ "event {\n\tname = \"tp_def\";\n"
+ "\tid = %u;\n\tfields := struct { \n"
+ "\t\tuint64_t addr;\n"
+ "\t\tuint64_t traceframe_usage;\n"
+ "\t\tint32_t number;\n"
+ "\t\tint32_t enabled;\n"
+ "\t\tint32_t step;\n"
+ "\t\tint32_t pass;\n"
+ "\t\tint32_t hit_count;\n"
+ "\t\tint32_t type;\n"
+ "\t\tchars cond;\n"
+
+ "\t\tuint32_t action_num;\n"
+ "\t\tchars actions[action_num];\n"
+
+ "\t\tuint32_t step_action_num;\n"
+ "\t\tchars step_actions[step_action_num];\n"
+
+ "\t\tchars at_string;\n"
+ "\t\tchars cond_string;\n"
+
+ "\t\tuint32_t cmd_num;\n"
+ "\t\tchars cmd_strings[cmd_num];\n"
+ "\t};\n"
+ "};\n", CTF_EVENT_ID_TP_DEF);
+
gdb_assert (writer->tcs.content_size == 0);
gdb_assert (writer->tcs.packet_start == 0);
@@ -482,8 +514,81 @@ static void
ctf_write_uploaded_tp (struct trace_file_writer *self,
struct uploaded_tp *tp)
{
- /* It is not supported yet to write uploaded tracepoints
- into CTF trace data. */
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ int32_t int32;
+ int64_t int64;
+ uint32_t u32;
+ const gdb_byte zero = 0;
+ int a;
+ char *act;
+
+ /* Event Id. */
+ int32 = CTF_EVENT_ID_TP_DEF;
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &int32, 4, 4);
+
+ /* address */
+ int64 = tp->addr;
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &int64, 8, 8);
+
+ /* traceframe_usage */
+ int64 = tp->traceframe_usage;
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &int64, 8, 8);
+
+ /* number */
+ ctf_save_write_int32 (&writer->tcs, tp->number);
+
+ /* enabled */
+ ctf_save_write_int32 (&writer->tcs, tp->enabled);
+
+ /* step */
+ ctf_save_write_int32 (&writer->tcs, tp->step);
+
+ /* pass */
+ ctf_save_write_int32 (&writer->tcs, tp->pass);
+
+ /* hit_count */
+ ctf_save_write_int32 (&writer->tcs, tp->hit_count);
+
+ /* type */
+ ctf_save_write_int32 (&writer->tcs, tp->type);
+
+ /* condition */
+ if (tp->cond != NULL)
+ ctf_save_write (&writer->tcs, tp->cond, strlen (tp->cond));
+ ctf_save_write (&writer->tcs, &zero, 1);
+
+ /* actions */
+ u32 = VEC_length (char_ptr, tp->actions);
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &u32, 4, 4);
+ for (a = 0; VEC_iterate (char_ptr, tp->actions, a, act); ++a)
+ ctf_save_write (&writer->tcs, act, strlen (act) + 1);
+
+
+ /* step_actions */
+ u32 = VEC_length (char_ptr, tp->step_actions);
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &u32, 4, 4);
+ for (a = 0; VEC_iterate (char_ptr, tp->step_actions, a, act); ++a)
+ ctf_save_write (&writer->tcs, act, strlen (act) + 1);
+
+ /* at_string */
+ if (tp->at_string != NULL)
+ ctf_save_write (&writer->tcs, tp->at_string,
+ strlen (tp->at_string));
+ ctf_save_write (&writer->tcs, &zero, 1);
+
+ /* cond_string */
+ if (tp->cond_string != NULL)
+ ctf_save_write (&writer->tcs, tp->cond_string,
+ strlen (tp->cond_string));
+ ctf_save_write (&writer->tcs, &zero, 1);
+
+ /* cmd_strings */
+ u32 = VEC_length (char_ptr, tp->cmd_strings);
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &u32, 4, 4);
+ for (a = 0; VEC_iterate (char_ptr, tp->cmd_strings, a, act); ++a)
+ ctf_save_write (&writer->tcs, act, strlen (act) + 1);
+
}
/* This is the implementation of trace_file_write_ops method
@@ -906,6 +1011,96 @@ ctf_read_tsv (struct uploaded_tsv **uploaded_tsvs)
}
+#define SET_ARRAY_FIELD(EVENT, SCOPE, VAR, NUM, ARRAY) \
+ do \
+ { \
+ uint32_t u32, i; \
+ const struct bt_definition *def; \
+ \
+ u32 = (uint32_t ) bt_ctf_get_uint64 (bt_ctf_get_field (EVENT, \
+ SCOPE, \
+ #NUM)); \
+ def = bt_ctf_get_field (event, scope, #ARRAY); \
+ for (i = 0; i < u32; i++) \
+ { \
+ const struct bt_definition *element \
+ = bt_ctf_get_index (event, def, i); \
+ \
+ VEC_safe_push (char_ptr, VAR->ARRAY, \
+ xstrdup (bt_ctf_get_string (element))); \
+ } \
+ } \
+ while (0)
+
+#define SET_STRING_FIELD(EVENT, SCOPE, VAR, FIELD) \
+ do \
+ { \
+ const char *p = bt_ctf_get_string (bt_ctf_get_field (EVENT, \
+ SCOPE, \
+ #FIELD)); \
+ \
+ if (strlen (p) > 0) \
+ VAR->FIELD = xstrdup (p); \
+ else \
+ VAR->FIELD = NULL; \
+ } \
+ while (0)
+
+/* Read the events "tp_def" one by one, extract its contents and fill
+ in the list UPLOADED_TPS. */
+
+static void
+ctf_read_tp (struct uploaded_tp **uploaded_tps)
+{
+ while (1)
+ {
+ struct bt_ctf_event *event;
+ const struct bt_definition *scope;
+ uint32_t u32;
+ int32_t int32;
+ uint64_t u64;
+ struct uploaded_tp *utp = NULL;
+
+ event = bt_ctf_iter_read_event (ctf_iter);
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_STREAM_EVENT_HEADER);
+ u32 = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope,
+ "id"));
+ if (u32 != CTF_EVENT_ID_TP_DEF)
+ break;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ int32 = (int32_t ) bt_ctf_get_int64 (bt_ctf_get_field (event,
+ scope,
+ "number"));
+ u64 = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope,
+ "addr"));
+ utp = get_uploaded_tp (int32, u64, uploaded_tps);
+
+ SET_INT32_FIELD (event, scope, utp, enabled);
+ SET_INT32_FIELD (event, scope, utp, step);
+ SET_INT32_FIELD (event, scope, utp, pass);
+ SET_INT32_FIELD (event, scope, utp, hit_count);
+ SET_INT32_FIELD (event, scope, utp, type);
+
+ /* Read 'cmd_strings'. */
+ SET_ARRAY_FIELD (event, scope, utp, cmd_num, cmd_strings);
+ /* Read 'actions'. */
+ SET_ARRAY_FIELD (event, scope, utp, action_num, actions);
+ /* Read 'step_actions'. */
+ SET_ARRAY_FIELD (event, scope, utp, step_action_num,
+ step_actions);
+
+ SET_STRING_FIELD(event, scope, utp, at_string);
+ SET_STRING_FIELD(event, scope, utp, cond_string);
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+}
+
+
static void
ctf_open (char *dirname, int from_tty)
{
@@ -913,6 +1108,7 @@ ctf_open (char *dirname, int from_tty)
uint32_t event_id;
const struct bt_definition *scope;
struct uploaded_tsv *uploaded_tsvs = NULL;
+ struct uploaded_tp *uploaded_tps = NULL;
target_preopen (from_tty);
if (!dirname)
@@ -937,10 +1133,19 @@ ctf_open (char *dirname, int from_tty)
gdb_assert (bt_iter_next (bt_ctf_get_iter (ctf_iter)) >= 0);
ctf_read_tsv (&uploaded_tsvs);
+ ctf_read_tp (&uploaded_tps);
+
event = bt_ctf_iter_read_event (ctf_iter);
- scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
- event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
- gdb_assert (event_id == CTF_EVENT_ID_FRAME);
+ /* EVENT can be NULL if we've already gone to the end of stream of
+ events. */
+ if (event != NULL)
+ {
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_STREAM_EVENT_HEADER);
+ event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event,
+ scope, "id"));
+ gdb_assert (event_id == CTF_EVENT_ID_FRAME);
+ }
start_pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
gdb_assert (start_pos->type == BT_SEEK_RESTORE);
@@ -949,6 +1154,7 @@ ctf_open (char *dirname, int from_tty)
push_target (&ctf_ops);
merge_uploaded_trace_state_variables (&uploaded_tsvs);
+ merge_uploaded_tracepoints (&uploaded_tps);
}
static void
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 12/15] Write tracepoint definition in CTF and read.
2013-03-09 3:49 ` [PATCH v3 12/15] Write tracepoint definition in CTF and read Yao Qi
@ 2013-03-12 20:02 ` Tom Tromey
2013-03-14 18:34 ` Doug Evans
1 sibling, 0 replies; 60+ messages in thread
From: Tom Tromey @ 2013-03-12 20:02 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes:
Yao> 2013-03-08 Yao Qi <yao@codesourcery.com>
Yao> * ctf.c (CTF_EVENT_ID_TP_DEF): New macro.
Yao> ctf_write_header): Define event type "tp_def" in metadata.
Yao> (ctf_write_uploaded_tp): Write tracepoint definition to CTF.
Yao> (SET_ARRAY_FIELD, SET_STRING_FIELD): New macros.
Yao> (ctf_read_tp): New.
Yao> (ctf_open): Call ctf_read_tp. Adjust the event id checking.
Yao> Call merge_uploaded_tracepoints.
This looks good to me, with one tiny nit:
Yao> + is about all aspects of a uploaded tracepoint. Note that the
"an uploaded".
Tom
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v3 12/15] Write tracepoint definition in CTF and read.
2013-03-09 3:49 ` [PATCH v3 12/15] Write tracepoint definition in CTF and read Yao Qi
2013-03-12 20:02 ` Tom Tromey
@ 2013-03-14 18:34 ` Doug Evans
1 sibling, 0 replies; 60+ messages in thread
From: Doug Evans @ 2013-03-14 18:34 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
Yao Qi writes:
> This patch teaches GDB to write uploaded tracepoints to CTF, and also
> read them out from CTF.
>
> gdb:
>
> 2013-03-08 Yao Qi <yao@codesourcery.com>
>
> * ctf.c (CTF_EVENT_ID_TP_DEF): New macro.
> ctf_write_header): Define event type "tp_def" in metadata.
> (ctf_write_uploaded_tp): Write tracepoint definition to CTF.
> (SET_ARRAY_FIELD, SET_STRING_FIELD): New macros.
> (ctf_read_tp): New.
> (ctf_open): Call ctf_read_tp. Adjust the event id checking.
> Call merge_uploaded_tracepoints.
>[...]
> @@ -371,6 +375,34 @@ ctf_write_header (struct trace_file_writer *self)
> "\t};\n"
> "};\n", CTF_EVENT_ID_TSV_DEF);
>
> + ctf_save_write_metadata (&writer->tcs, "\n");
> + ctf_save_write_metadata (&writer->tcs,
> + "event {\n\tname = \"tp_def\";\n"
> + "\tid = %u;\n\tfields := struct { \n"
> + "\t\tuint64_t addr;\n"
> + "\t\tuint64_t traceframe_usage;\n"
> + "\t\tint32_t number;\n"
> + "\t\tint32_t enabled;\n"
> + "\t\tint32_t step;\n"
> + "\t\tint32_t pass;\n"
> + "\t\tint32_t hit_count;\n"
> + "\t\tint32_t type;\n"
> + "\t\tchars cond;\n"
> +
> + "\t\tuint32_t action_num;\n"
> + "\t\tchars actions[action_num];\n"
> +
> + "\t\tuint32_t step_action_num;\n"
> + "\t\tchars step_actions[step_action_num];\n"
> +
> + "\t\tchars at_string;\n"
> + "\t\tchars cond_string;\n"
> +
> + "\t\tuint32_t cmd_num;\n"
> + "\t\tchars cmd_strings[cmd_num];\n"
> + "\t};\n"
> + "};\n", CTF_EVENT_ID_TP_DEF);
Nit: CTF_EVENT_ID_TP_DEF is a lonnggg way from the %u that uses it.
Split into two pieces?
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v3 10/15] tstatus.exp: ctf
2013-03-09 3:48 [PATCH v3 00/15] CTF Support Yao Qi
` (10 preceding siblings ...)
2013-03-09 3:49 ` [PATCH v3 12/15] Write tracepoint definition in CTF and read Yao Qi
@ 2013-03-09 3:49 ` Yao Qi
2013-03-12 19:48 ` Tom Tromey
2013-03-09 3:49 ` [PATCH v3 02/15] Save trace into CTF format Yao Qi
` (3 subsequent siblings)
15 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-09 3:49 UTC (permalink / raw)
To: gdb-patches
Similarly, the output of "tstatus" should be identical to the output
when trace status is read from tfile or live target.
gdb/testsuite:
2013-03-08 Yao Qi <yao@codesourcery.com>
* gdb.trace/tstatus.exp: Save trace data to CTF. If ctf
target is supported, change to ctf target, read trace data and
check output of command "tstatus".
---
gdb/testsuite/gdb.trace/tstatus.exp | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/gdb/testsuite/gdb.trace/tstatus.exp b/gdb/testsuite/gdb.trace/tstatus.exp
index c105048..7668240 100644
--- a/gdb/testsuite/gdb.trace/tstatus.exp
+++ b/gdb/testsuite/gdb.trace/tstatus.exp
@@ -139,6 +139,9 @@ test_tracepoints
# Save trace frames to tfile.
gdb_test "tsave tstatus.tf" "Trace data saved to file 'tstatus.tf'.*"
+# Save trace frames to CTF.
+gdb_test "tsave -ctf ${testfile}.ctf" \
+ "Trace data saved to directory 'tstatus.ctf'.*"
# Change target to tfile.
set test "change to tfile target"
@@ -159,3 +162,13 @@ set tstatus_output [string map {\) \\)} $tstatus_output]
# The status should be identical to the status of live inferior.
gdb_test "tstatus" "Using a trace file\.\r\n${tstatus_output}.*" \
"tstatus on tfile target"
+
+# Change target to ctf if GDB supports.
+gdb_test_multiple "target ctf ${testfile}.ctf" "" {
+ -re "Undefined target command: \"ctf ${testfile}.ctf\"\. Try \"help target\"\.\r\n$gdb_prompt $" {
+ }
+ -re ".*\r\n$gdb_prompt $" {
+ gdb_test "tstatus" "Using a trace file\.\r\n${tstatus_output}.*" \
+ "tstatus on ctf target"
+ }
+}
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* [PATCH v3 02/15] Save trace into CTF format
2013-03-09 3:48 [PATCH v3 00/15] CTF Support Yao Qi
` (11 preceding siblings ...)
2013-03-09 3:49 ` [PATCH v3 10/15] tstatus.exp: ctf Yao Qi
@ 2013-03-09 3:49 ` Yao Qi
2013-03-12 18:49 ` Tom Tromey
2013-03-09 3:49 ` [PATCH v3 04/15] ctf doc and NEWS Yao Qi
` (2 subsequent siblings)
15 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-09 3:49 UTC (permalink / raw)
To: gdb-patches
This patch is to teach GDB to save trace data into CTF format. In
this patch, struct trace_frame_write_ops and struct
trace_file_write_ops are implemented, so that GDB is able to write
trace data in CTF format.
Note that we don't use ui-file to write trace file, because
ui_file_write doesn't handle error well. We can migrate to ui-file
once ui_file_write starts to handle error.
gdb:
2013-03-08 Hui Zhu <hui_zhu@mentor.com>
Yao Qi <yao@codesourcery.com>
* Makefile.in (REMOTE_OBS): Add ctf.o.
(SFILES): Add ctf.c.
(HFILES_NO_SRCDIR): Add ctf.h.
* ctf.c, ctf.h: New files.
* tracepoint.c : Include 'ctf.h'.
(collect_pseudocommand): Remove static.
(trace_save_command): Parse option "-ctf".
Produce different trace file writers per option.
Adjust output message.
(trace_save_tfile, trace_save_ctf): New.
* tracepoint.h (trace_save_tfile, trace_save_ctf): Declare.
* mi/mi-main.c: Include 'ctf.h'.
(mi_cmd_trace_save): Handle option '-ctf'. Call either
trace_save_tfile or trace_save_ctf.
---
gdb/Makefile.in | 6 +-
gdb/ctf.c | 648 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/ctf.h | 25 ++
gdb/mi/mi-main.c | 47 +++-
gdb/tracepoint.c | 28 +++-
gdb/tracepoint.h | 2 +
6 files changed, 738 insertions(+), 18 deletions(-)
create mode 100644 gdb/ctf.c
create mode 100644 gdb/ctf.h
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index ed30db5..5be6c77 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -510,7 +510,7 @@ SER_HARDWIRE = @SER_HARDWIRE@
# The `remote' debugging target is supported for most architectures,
# but not all (e.g. 960)
REMOTE_OBS = remote.o dcache.o tracepoint.o ax-general.o ax-gdb.o remote-fileio.o \
- remote-notif.o
+ remote-notif.o ctf.o
# This is remote-sim.o if a simulator is to be linked in.
SIM_OBS = @SIM_OBS@
@@ -759,7 +759,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
regset.c sol-thread.c windows-termcap.c \
common/gdb_vecs.c common/common-utils.c common/xml-utils.c \
common/ptid.c common/buffer.c gdb-dlfcn.c common/agent.c \
- common/format.c
+ common/format.c ctf.c
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@@ -835,7 +835,7 @@ gnulib/import/stddef.in.h gnulib/import/inttypes.in.h inline-frame.h skip.h \
common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \
common/format.h common/host-defs.h utils.h common/queue.h \
common/linux-osdata.h gdb-dlfcn.h auto-load.h probe.h stap-probe.h \
-gdb_bfd.h sparc-ravenscar-thread.h ppc-ravenscar-thread.h
+gdb_bfd.h sparc-ravenscar-thread.h ppc-ravenscar-thread.h ctf.h
# Header files that already have srcdir in them, or which are in objdir.
diff --git a/gdb/ctf.c b/gdb/ctf.c
new file mode 100644
index 0000000..909b769
--- /dev/null
+++ b/gdb/ctf.c
@@ -0,0 +1,648 @@
+/* CTF format support.
+
+ Copyright (C) 2012-2013 Free Software Foundation, Inc.
+ Contributed by Hui Zhu <hui_zhu@mentor.com>
+ Contributed by Yao Qi <yao@codesourcery.com>
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "ctf.h"
+#include "tracepoint.h"
+#include "regcache.h"
+
+#include <ctype.h>
+
+/* GDB saves trace buffers and other information (such as trace
+ status) got from the remote target into Common Trace Format (CTF).
+ The following types of information are expected to save in CTF:
+
+ 1. The length (in bytes) of register cache. Event "register" will
+ be defined in metadata, which includes the length.
+
+ 2. Trace status. Not implemented yet in CTF writer.
+
+ 3. Uploaded trace variables and tracepoints. Not implemented yet
+ in CTF writer.
+
+ 4. Trace frames. Each trace frame is composed by several blocks
+ of different types ('R', 'M', 'V'). One trace frame is saved in
+ one CTF packet and the blocks of this frame are saved as events.
+ 4.1: The trace frame related information (such as the number of
+ tracepoint associated with this frame) is saved in the packet
+ context.
+ 4.2: The block 'M', 'R' and 'V' are saved in event "memory",
+ "register" and "tsv" respectively.
+ 4.3: When iterating over events, babeltrace can't tell iterator
+ goes to a new packet, so we need a marker or anchor to tell GDB
+ that iterator goes into a new packet or frame. We define event
+ "frame". */
+
+#define CTF_MAGIC 0xC1FC1FC1
+#define CTF_SAVE_MAJOR 1
+#define CTF_SAVE_MINOR 8
+
+#define CTF_METADATA_NAME "metadata"
+#define CTF_DATASTREAM_NAME "datastream"
+
+/* Reserved event id. */
+
+#define CTF_EVENT_ID_REGISTER 0
+#define CTF_EVENT_ID_TSV 1
+#define CTF_EVENT_ID_MEMORY 2
+#define CTF_EVENT_ID_FRAME 3
+
+/* The state kept while writing the CTF datastream file. */
+
+struct trace_write_handler
+{
+ /* File descriptor of metadata. */
+ FILE *metadata_fd;
+ /* File descriptor of traceframes. */
+ FILE *datastream_fd;
+
+ /* This is the content size of the current packet. */
+ size_t content_size;
+
+ /* This is the start offset of current packet. */
+ long packet_start;
+};
+
+/* Write metadata in FORMAT. */
+
+static void
+ctf_save_write_metadata (struct trace_write_handler *handler,
+ const char *format, ...)
+{
+ va_list args;
+
+ va_start (args, format);
+ if (vfprintf (handler->metadata_fd, format, args) < 0)
+ error (_("Unable to write metadata file (%s)"),
+ safe_strerror (errno));
+ va_end (args);
+}
+
+/* Write BUF of length SIZE to datastream file represented by
+ HANDLER. */
+
+static int
+ctf_save_write (struct trace_write_handler *handler,
+ const gdb_byte *buf, size_t size)
+{
+ if (fwrite (buf, size, 1, handler->datastream_fd) != 1)
+ error (_("Unable to write file for saving trace data (%s)"),
+ safe_strerror (errno));
+
+ handler->content_size += size;
+
+ return 0;
+}
+
+/* Write a unsigned 32-bit integer to datastream file represented by
+ HANDLER. */
+
+#define ctf_save_write_uint32(HANDLER, U32) \
+ ctf_save_write (HANDLER, (gdb_byte *) &U32, 4)
+
+/* Set datastream file position. Update HANDLER->content_size
+ if WHENCE is SEEK_CUR. */
+
+static int
+ctf_save_fseek (struct trace_write_handler *handler, long offset,
+ int whence)
+{
+ gdb_assert (whence != SEEK_END);
+ gdb_assert (whence != SEEK_SET
+ || offset <= handler->content_size + handler->packet_start);
+
+ if (fseek (handler->datastream_fd, offset, whence))
+ error (_("Unable to seek file for saving trace data (%s)"),
+ safe_strerror (errno));
+
+ if (whence == SEEK_CUR)
+ handler->content_size += offset;
+
+ return 0;
+}
+
+/* Change the datastream file position to align on ALIGN_SIZE,
+ and write BUF to datastream file. The size of BUF is SIZE. */
+
+static int
+ctf_save_align_write (struct trace_write_handler *handler,
+ const gdb_byte *buf,
+ size_t size, size_t align_size)
+{
+ long offset
+ = (align_up (handler->content_size, align_size)
+ - handler->content_size);
+
+ if (ctf_save_fseek (handler, offset, SEEK_CUR))
+ return -1;
+
+ if (ctf_save_write (handler, buf, size))
+ return -1;
+
+ return 0;
+}
+
+/* Write events to next new packet. */
+
+static void
+ctf_save_next_packet (struct trace_write_handler *handler)
+{
+ handler->packet_start += (handler->content_size + 4);
+ ctf_save_fseek (handler, handler->packet_start, SEEK_SET);
+ handler->content_size = 0;
+}
+
+/* Write the CTF metadata header. */
+
+static void
+ctf_save_metadata_header (struct trace_write_handler *handler)
+{
+ const char metadata_fmt[] =
+ "\ntrace {\n"
+ " major = %u;\n"
+ " minor = %u;\n"
+ " byte_order = %s;\n" /* be or le */
+ " packet.header := struct {\n"
+ " uint32_t magic;\n"
+ " };\n"
+ "};\n"
+ "\n"
+ "stream {\n"
+ " packet.context := struct {\n"
+ " uint32_t content_size;\n"
+ " uint32_t packet_size;\n"
+ " uint16_t tpnum;\n"
+ " };\n"
+ " event.header := struct {\n"
+ " uint32_t id;\n"
+ " };\n"
+ "};\n";
+
+ ctf_save_write_metadata (handler, "/* CTF %d.%d */\n",
+ CTF_SAVE_MAJOR, CTF_SAVE_MINOR);
+ ctf_save_write_metadata (handler,
+ "typealias integer { size = 8; align = 8; "
+ "signed = false; encoding = ascii;}"
+ " := ascii;\n");
+ ctf_save_write_metadata (handler,
+ "typealias integer { size = 8; align = 8; "
+ "signed = false; }"
+ " := uint8_t;\n");
+ ctf_save_write_metadata (handler,
+ "typealias integer { size = 16; align = 16;"
+ "signed = false; } := uint16_t;\n");
+ ctf_save_write_metadata (handler,
+ "typealias integer { size = 32; align = 32;"
+ "signed = false; } := uint32_t;\n");
+ ctf_save_write_metadata (handler,
+ "typealias integer { size = 64; align = 64;"
+ "signed = false; base = hex;}"
+ " := uint64_t;\n");
+ ctf_save_write_metadata (handler, "\n");
+
+ ctf_save_write_metadata (handler, metadata_fmt,
+ CTF_SAVE_MAJOR, CTF_SAVE_MINOR,
+ BYTE_ORDER == LITTLE_ENDIAN ? "le" : "be");
+ ctf_save_write_metadata (handler, "\n");
+}
+
+/* Cleanup function. */
+
+static void
+ctf_save_cleanup (void *p)
+{
+ struct trace_write_handler *handler = p;
+
+ if (handler->metadata_fd != NULL)
+ fclose (handler->metadata_fd);
+
+ if (handler->datastream_fd != NULL)
+ fclose (handler->datastream_fd);
+}
+
+/* CTF trace writer. */
+
+struct ctf_trace_file_writer
+{
+ struct trace_file_writer base;
+
+ struct trace_write_handler tcs;
+
+ struct cleanup *cleanup;
+};
+
+/* This is the implementation of trace_file_write_ops method
+ target_save. */
+
+static int
+ctf_target_save (struct trace_file_writer *self,
+ const char *dirname)
+{
+ /* Don't support save trace file to CTF format in the target. */
+ return 0;
+}
+
+/* This is the implementation of trace_file_write_ops method
+ start. It creates the directory DIRNAME, metadata and datastream
+ in the directory. */
+
+static void
+ctf_start (struct trace_file_writer *self, const char *dirname)
+{
+ char *file_name;
+ struct cleanup *old_chain;
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ int i;
+
+ /* Create DIRNAME. */
+ if (mkdir (dirname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
+ && errno != EEXIST)
+ error (_("Unable to open directory '%s' for saving trace data (%s)"),
+ dirname, safe_strerror (errno));
+
+ memset (&writer->tcs, '\0', sizeof (writer->tcs));
+
+ file_name = xstrprintf ("%s/%s", dirname, CTF_METADATA_NAME);
+ old_chain = make_cleanup (xfree, file_name);
+
+ writer->tcs.metadata_fd = fopen (file_name, "w");
+ if (writer->tcs.metadata_fd == NULL)
+ error (_("Unable to open file '%s' for saving trace data (%s)"),
+ file_name, safe_strerror (errno));
+ do_cleanups (old_chain);
+
+ ctf_save_metadata_header (&writer->tcs);
+
+ file_name = xstrprintf ("%s/%s", dirname, CTF_DATASTREAM_NAME);
+ old_chain = make_cleanup (xfree, file_name);
+ writer->tcs.datastream_fd = fopen (file_name, "w");
+ if (writer->tcs.datastream_fd == NULL)
+ error (_("Unable to open file '%s' for saving trace data (%s)"),
+ file_name, safe_strerror (errno));
+ do_cleanups (old_chain);
+
+ writer->cleanup = make_cleanup (ctf_save_cleanup, &writer->tcs);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_header. Write the types of events on trace variable and
+ frame. */
+
+static void
+ctf_write_header (struct trace_file_writer *self)
+{
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+
+
+ ctf_save_write_metadata (&writer->tcs, "\n");
+ ctf_save_write_metadata (&writer->tcs,
+ "event {\n\tname = \"memory\";\n\tid = %u;\n"
+ "\tfields := struct { \n"
+ "\t\tuint64_t address;\n"
+ "\t\tuint16_t length;\n"
+ "\t\tuint8_t contents[length];\n"
+ "\t};\n"
+ "};\n", CTF_EVENT_ID_MEMORY);
+
+ ctf_save_write_metadata (&writer->tcs, "\n");
+ ctf_save_write_metadata (&writer->tcs,
+ "event {\n\tname = \"tsv\";\n\tid = %u;\n"
+ "\tfields := struct { \n"
+ "\t\tuint64_t val;\n"
+ "\t\tuint32_t num;\n"
+ "\t};\n"
+ "};\n", CTF_EVENT_ID_TSV);
+
+ ctf_save_write_metadata (&writer->tcs, "\n");
+ ctf_save_write_metadata (&writer->tcs,
+ "event {\n\tname = \"frame\";\n\tid = %u;\n"
+ "\tfields := struct { \n"
+ "\t};\n"
+ "};\n", CTF_EVENT_ID_FRAME);
+
+ gdb_assert (writer->tcs.content_size == 0);
+ gdb_assert (writer->tcs.packet_start == 0);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_regblock_type. Write the type of register event in
+ metadata. */
+
+static void
+ctf_write_regblock_type (struct trace_file_writer *self, int size)
+{
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+
+ ctf_save_write_metadata (&writer->tcs, "\n");
+
+ ctf_save_write_metadata (&writer->tcs,
+ "event {\n\tname = \"register\";\n\tid = %u;\n"
+ "\tfields := struct { \n"
+ "\t\tascii contents[%d];\n"
+ "\t};\n"
+ "};\n",
+ CTF_EVENT_ID_REGISTER, size);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_status. */
+
+static void
+ctf_write_status (struct trace_file_writer *self,
+ struct trace_status *ts)
+{
+ /* It is not supported yet to write trace status into CTF trace
+ data. */
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_uploaded_tsv. */
+
+static void
+ctf_write_uploaded_tsv (struct trace_file_writer *self,
+ struct uploaded_tsv *tsv)
+{
+ /* It is not supported yet to write uploaded trace variables
+ into CTF trace data. */
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_uploaded_tp. */
+
+static void
+ctf_write_uploaded_tp (struct trace_file_writer *self,
+ struct uploaded_tp *tp)
+{
+ /* It is not supported yet to write uploaded tracepoints
+ into CTF trace data. */
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_definition_end. */
+
+static void
+ctf_write_definition_end (struct trace_file_writer *self)
+{
+ /* Nothing to do for CTF. */
+}
+
+/* The minimal file size of data stream. It is required by
+ babeltrace. */
+
+#define CTF_FILE_MIN_SIZE 4096
+
+/* This is the implementation of trace_file_write_ops method
+ end. */
+
+static void
+ctf_end (struct trace_file_writer *self)
+{
+ struct ctf_trace_file_writer *writer = (struct ctf_trace_file_writer *) self;
+
+ gdb_assert (writer->tcs.content_size == 0);
+ /* The babeltrace requires or assumes that the size of datastream
+ file is greater than 4096 bytes. If we don't generate enough
+ packets and events, create a fake packet which has zero event,
+ to use up the space. */
+ if (writer->tcs.packet_start < CTF_FILE_MIN_SIZE)
+ {
+ uint32_t u32;
+
+ /* magic. */
+ u32 = CTF_MAGIC;
+ ctf_save_write_uint32 (&writer->tcs, u32);
+
+ /* content_size. */
+ u32 = 0;
+ ctf_save_write_uint32 (&writer->tcs, u32);
+
+ /* packet_size. */
+ u32 = 12;
+ if (writer->tcs.packet_start + u32 < CTF_FILE_MIN_SIZE)
+ u32 = CTF_FILE_MIN_SIZE - writer->tcs.packet_start;
+
+ u32 *= TARGET_CHAR_BIT;
+ ctf_save_write_uint32 (&writer->tcs, u32);
+
+ /* tpnum. */
+ u32 = 0;
+ ctf_save_write (&writer->tcs, (gdb_byte *) &u32, 2);
+
+ /* Enlarge the file to CTF_FILE_MIN_SIZE is it is still less
+ than that. */
+ if (CTF_FILE_MIN_SIZE
+ > (writer->tcs.packet_start + writer->tcs.content_size))
+ {
+ gdb_byte b = 0;
+
+ /* Fake the content size to avoid assertion failure in
+ ctf_save_fseek. */
+ writer->tcs.content_size = (CTF_FILE_MIN_SIZE
+ - 1 - writer->tcs.packet_start);
+ ctf_save_fseek (&writer->tcs, CTF_FILE_MIN_SIZE - 1,
+ SEEK_SET);
+ ctf_save_write (&writer->tcs, &b, 1);
+ }
+ }
+
+ do_cleanups (writer->cleanup);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+ start. */
+
+static void
+ctf_write_frame_start (struct trace_file_writer *self, uint16_t tpnum)
+{
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ uint32_t id = CTF_EVENT_ID_FRAME;
+ uint32_t u32;
+
+ /* Step 1: Write packet context. */
+ /* magic. */
+ u32 = CTF_MAGIC;
+ ctf_save_write_uint32 (&writer->tcs, u32);
+ /* content_size and packet_size.. We still don't know the value,
+ write it later. */
+ ctf_save_fseek (&writer->tcs, 4, SEEK_CUR);
+ ctf_save_fseek (&writer->tcs, 4, SEEK_CUR);
+ /* Tracepoint number. */
+ ctf_save_write (&writer->tcs, (gdb_byte *) &tpnum, 2);
+
+ /* Step 2: Write event "frame". */
+ /* Event Id. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+ write_r_block. */
+
+static void
+ctf_write_frame_r_block (struct trace_file_writer *self,
+ gdb_byte *buf, int32_t size)
+{
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ uint32_t id = CTF_EVENT_ID_REGISTER;
+
+ /* Event Id. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
+
+ /* array contents. */
+ ctf_save_align_write (&writer->tcs, buf, size, 1);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+ write_m_block_header. */
+
+static void
+ctf_write_frame_m_block_header (struct trace_file_writer *self,
+ uint64_t addr, uint16_t length)
+{
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ uint32_t event_id = CTF_EVENT_ID_MEMORY;
+
+ /* Event Id. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &event_id, 4, 4);
+
+ /* Address. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &addr, 8, 8);
+
+ /* Length. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &length, 2, 2);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+ write_m_block_memory. */
+
+static void
+ctf_write_frame_m_block_memory (struct trace_file_writer *self,
+ gdb_byte *buf, uint16_t length)
+{
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+
+ /* Contents. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) buf, length, 1);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+ write_v_block. */
+
+static void
+ctf_write_frame_v_block (struct trace_file_writer *self,
+ int32_t num, uint64_t val)
+{
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ uint32_t id = CTF_EVENT_ID_TSV;
+
+ /* Event Id. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
+
+ /* val. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &val, 8, 8);
+ /* num. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &num, 4, 4);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+ end. */
+
+static void
+ctf_write_frame_end (struct trace_file_writer *self)
+{
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ uint32_t u32;
+ uint32_t t;
+
+ /* Write the content size to packet header. */
+ ctf_save_fseek (&writer->tcs, writer->tcs.packet_start + 4,
+ SEEK_SET);
+ u32 = writer->tcs.content_size * TARGET_CHAR_BIT;
+
+ t = writer->tcs.content_size;
+ ctf_save_write_uint32 (&writer->tcs, u32);
+
+ /* Write the packet size. */
+ u32 += 4 * TARGET_CHAR_BIT;
+ ctf_save_write_uint32 (&writer->tcs, u32);
+
+ writer->tcs.content_size = t;
+
+ /* Write zero at the end of the packet. */
+ ctf_save_fseek (&writer->tcs, writer->tcs.packet_start + t,
+ SEEK_SET);
+ u32 = 0;
+ ctf_save_write_uint32 (&writer->tcs, u32);
+ writer->tcs.content_size = t;
+
+ ctf_save_next_packet (&writer->tcs);
+}
+
+/* Operations to write various types of trace frames into CTF
+ format. */
+
+static const struct trace_frame_write_ops ctf_write_frame_ops =
+{
+ ctf_write_frame_start,
+ ctf_write_frame_r_block,
+ ctf_write_frame_m_block_header,
+ ctf_write_frame_m_block_memory,
+ ctf_write_frame_v_block,
+ ctf_write_frame_end,
+};
+
+/* Operations to write trace buffers into CTF format. */
+
+static const struct trace_file_write_ops ctf_write_ops =
+{
+ ctf_target_save,
+ ctf_start,
+ ctf_write_header,
+ ctf_write_regblock_type,
+ ctf_write_status,
+ ctf_write_uploaded_tsv,
+ ctf_write_uploaded_tp,
+ ctf_write_definition_end,
+ NULL,
+ &ctf_write_frame_ops,
+ ctf_end,
+};
+
+/* Return a trace writer for CTF format. */
+
+struct trace_file_writer *
+ctf_trace_file_writer_new (void)
+{
+ struct ctf_trace_file_writer *writer
+ = xmalloc (sizeof (struct ctf_trace_file_writer));
+
+ writer->base.ops = &ctf_write_ops;
+
+ return (struct trace_file_writer *) writer;
+}
diff --git a/gdb/ctf.h b/gdb/ctf.h
new file mode 100644
index 0000000..6a61cf3
--- /dev/null
+++ b/gdb/ctf.h
@@ -0,0 +1,25 @@
+/* CTF format support.
+
+ Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef CTF_H
+#define CTF_H
+
+extern struct trace_file_writer *ctf_trace_file_writer_new (void);
+
+#endif
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 206b626..5ee5cfa 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -49,6 +49,7 @@
#include "osdata.h"
#include "splay-tree.h"
#include "tracepoint.h"
+#include "ctf.h"
#include "ada-lang.h"
#include "linespec.h"
@@ -2477,25 +2478,45 @@ void
mi_cmd_trace_save (char *command, char **argv, int argc)
{
int target_saves = 0;
+ int generate_ctf = 0;
char *filename;
+ int oind = 0;
+ char *oarg;
- if (argc != 1 && argc != 2)
- error (_("Usage: -trace-save [-r] filename"));
-
- if (argc == 2)
+ enum opt
+ {
+ TARGET_SAVE_OPT, CTF_OPT
+ };
+ static const struct mi_opt opts[] =
{
- filename = argv[1];
- if (strcmp (argv[0], "-r") == 0)
- target_saves = 1;
- else
- error (_("Invalid option: %s"), argv[0]);
- }
- else
+ {"r", TARGET_SAVE_OPT, 0},
+ {"ctf", CTF_OPT, 0},
+ { 0, 0, 0 }
+ };
+
+ while (1)
{
- filename = argv[0];
+ int opt = mi_getopt ("-trace-save", argc, argv, opts,
+ &oind, &oarg);
+
+ if (opt < 0)
+ break;
+ switch ((enum opt) opt)
+ {
+ case TARGET_SAVE_OPT:
+ target_saves = 1;
+ break;
+ case CTF_OPT:
+ generate_ctf = 1;
+ break;
+ }
}
+ filename = argv[oind];
- trace_save_tfile (filename, target_saves);
+ if (generate_ctf)
+ trace_save_ctf (filename, target_saves);
+ else
+ trace_save_tfile (filename, target_saves);
}
void
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index e3a42e2..de59102 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -53,6 +53,7 @@
#include "exceptions.h"
#include "cli/cli-utils.h"
#include "probe.h"
+#include "ctf.h"
/* readline include files */
#include "readline/readline.h"
@@ -3521,6 +3522,7 @@ trace_save_command (char *args, int from_tty)
char **argv;
char *filename = NULL;
struct cleanup *back_to;
+ int generate_ctf = 0;
struct trace_file_writer *writer = NULL;
if (args == NULL)
@@ -3533,6 +3535,8 @@ trace_save_command (char *args, int from_tty)
{
if (strcmp (*argv, "-r") == 0)
target_does_save = 1;
+ if (strcmp (*argv, "-ctf") == 0)
+ generate_ctf = 1;
else if (**argv == '-')
error (_("unknown option `%s'"), *argv);
else
@@ -3542,14 +3546,18 @@ trace_save_command (char *args, int from_tty)
if (!filename)
error_no_arg (_("file in which to save trace data"));
- writer = tfile_trace_file_writer_new ();
+ if (generate_ctf)
+ writer = ctf_trace_file_writer_new ();
+ else
+ writer = tfile_trace_file_writer_new ();
make_cleanup (trace_file_writer_xfree, writer);
trace_save (filename, writer, target_does_save);
if (from_tty)
- printf_filtered (_("Trace data saved to file '%s'.\n"), filename);
+ printf_filtered (_("Trace data saved to %s '%s'.\n"),
+ generate_ctf ? "directory" : "file", filename);
do_cleanups (back_to);
}
@@ -3568,6 +3576,21 @@ trace_save_tfile (const char *filename, int target_does_save)
do_cleanups (back_to);
}
+/* Save the trace data to dir DIRNAME of ctf format. */
+
+void
+trace_save_ctf (const char *dirname, int target_does_save)
+{
+ struct trace_file_writer *writer;
+ struct cleanup *back_to;
+
+ writer = ctf_trace_file_writer_new ();
+ back_to = make_cleanup (trace_file_writer_xfree, writer);
+
+ trace_save (dirname, writer, target_does_save);
+ do_cleanups (back_to);
+}
+
/* Tell the target what to do with an ongoing tracing run if GDB
disconnects for some reason. */
@@ -5623,6 +5646,7 @@ _initialize_tracepoint (void)
add_com ("tsave", class_trace, trace_save_command, _("\
Save the trace data to a file.\n\
+Use the '-ctf' option to save the data to CTF format.\n\
Use the '-r' option to direct the target to save directly to the file,\n\
using its own filesystem."));
diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
index d6664e7..ab11574 100644
--- a/gdb/tracepoint.h
+++ b/gdb/tracepoint.h
@@ -384,6 +384,8 @@ extern void tfind_1 (enum trace_find_type type, int num,
extern void trace_save_tfile (const char *filename,
int target_does_save);
+extern void trace_save_ctf (const char *dirname,
+ int target_does_save);
extern struct traceframe_info *parse_traceframe_info (const char *tframe_info);
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 02/15] Save trace into CTF format
2013-03-09 3:49 ` [PATCH v3 02/15] Save trace into CTF format Yao Qi
@ 2013-03-12 18:49 ` Tom Tromey
2013-03-13 10:33 ` Yao Qi
0 siblings, 1 reply; 60+ messages in thread
From: Tom Tromey @ 2013-03-12 18:49 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes:
Yao> This patch is to teach GDB to save trace data into CTF format. In
Yao> this patch, struct trace_frame_write_ops and struct
Yao> trace_file_write_ops are implemented, so that GDB is able to write
Yao> trace data in CTF format.
Yao> + struct cleanup *cleanup;
The cleanup issue, as with patch 01, is the only issue I found.
The rest looks good.
Tom
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v3 02/15] Save trace into CTF format
2013-03-12 18:49 ` Tom Tromey
@ 2013-03-13 10:33 ` Yao Qi
2013-03-13 19:30 ` Tom Tromey
2013-03-14 17:49 ` Doug Evans
0 siblings, 2 replies; 60+ messages in thread
From: Yao Qi @ 2013-03-13 10:33 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 03/13/2013 02:48 AM, Tom Tromey wrote:
> Yao> This patch is to teach GDB to save trace data into CTF format. In
> Yao> this patch, struct trace_frame_write_ops and struct
> Yao> trace_file_write_ops are implemented, so that GDB is able to write
> Yao> trace data in CTF format.
>
> Yao> + struct cleanup *cleanup;
>
> The cleanup issue, as with patch 01, is the only issue I found.
> The rest looks good.
Patch 02 is updated along with 01, to fix the cleanup issue.
--
Yao (é½å°§)
gdb:
2013-03-13 Hui Zhu <hui_zhu@mentor.com>
Yao Qi <yao@codesourcery.com>
* Makefile.in (REMOTE_OBS): Add ctf.o.
(SFILES): Add ctf.c.
(HFILES_NO_SRCDIR): Add ctf.h.
* ctf.c, ctf.h: New files.
* tracepoint.c : Include 'ctf.h'.
(collect_pseudocommand): Remove static.
(trace_save_command): Parse option "-ctf".
Produce different trace file writers per option.
Adjust output message.
(trace_save_tfile, trace_save_ctf): New.
* tracepoint.h (trace_save_tfile, trace_save_ctf): Declare.
* mi/mi-main.c: Include 'ctf.h'.
(mi_cmd_trace_save): Handle option '-ctf'. Call either
trace_save_tfile or trace_save_ctf.
---
gdb/Makefile.in | 7 +-
gdb/ctf.c | 647 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/ctf.h | 25 ++
gdb/mi/mi-main.c | 47 +++-
gdb/tracepoint.c | 28 +++-
gdb/tracepoint.h | 2 +
6 files changed, 738 insertions(+), 18 deletions(-)
create mode 100644 gdb/ctf.c
create mode 100644 gdb/ctf.h
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5366d9e..9bab01c 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -511,7 +511,7 @@ SER_HARDWIRE = @SER_HARDWIRE@
# The `remote' debugging target is supported for most architectures,
# but not all (e.g. 960)
REMOTE_OBS = remote.o dcache.o tracepoint.o ax-general.o ax-gdb.o remote-fileio.o \
- remote-notif.o
+ remote-notif.o ctf.o
# This is remote-sim.o if a simulator is to be linked in.
SIM_OBS = @SIM_OBS@
@@ -760,7 +760,7 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
regset.c sol-thread.c windows-termcap.c \
common/gdb_vecs.c common/common-utils.c common/xml-utils.c \
common/ptid.c common/buffer.c gdb-dlfcn.c common/agent.c \
- common/format.c btrace.c record-btrace.c
+ common/format.c btrace.c record-btrace.c ctf.c
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@@ -837,7 +837,8 @@ gnulib/import/stddef.in.h gnulib/import/inttypes.in.h inline-frame.h skip.h \
common/common-utils.h common/xml-utils.h common/buffer.h common/ptid.h \
common/format.h common/host-defs.h utils.h common/queue.h \
common/linux-osdata.h gdb-dlfcn.h auto-load.h probe.h stap-probe.h \
-gdb_bfd.h sparc-ravenscar-thread.h ppc-ravenscar-thread.h common/linux-btrace.h
+gdb_bfd.h sparc-ravenscar-thread.h ppc-ravenscar-thread.h common/linux-btrace.h \
+ctf.h
# Header files that already have srcdir in them, or which are in objdir.
diff --git a/gdb/ctf.c b/gdb/ctf.c
new file mode 100644
index 0000000..d2ff862
--- /dev/null
+++ b/gdb/ctf.c
@@ -0,0 +1,647 @@
+/* CTF format support.
+
+ Copyright (C) 2012-2013 Free Software Foundation, Inc.
+ Contributed by Hui Zhu <hui_zhu@mentor.com>
+ Contributed by Yao Qi <yao@codesourcery.com>
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "defs.h"
+#include "ctf.h"
+#include "tracepoint.h"
+#include "regcache.h"
+
+#include <ctype.h>
+
+/* GDB saves trace buffers and other information (such as trace
+ status) got from the remote target into Common Trace Format (CTF).
+ The following types of information are expected to save in CTF:
+
+ 1. The length (in bytes) of register cache. Event "register" will
+ be defined in metadata, which includes the length.
+
+ 2. Trace status. Not implemented yet in CTF writer.
+
+ 3. Uploaded trace variables and tracepoints. Not implemented yet
+ in CTF writer.
+
+ 4. Trace frames. Each trace frame is composed by several blocks
+ of different types ('R', 'M', 'V'). One trace frame is saved in
+ one CTF packet and the blocks of this frame are saved as events.
+ 4.1: The trace frame related information (such as the number of
+ tracepoint associated with this frame) is saved in the packet
+ context.
+ 4.2: The block 'M', 'R' and 'V' are saved in event "memory",
+ "register" and "tsv" respectively.
+ 4.3: When iterating over events, babeltrace can't tell iterator
+ goes to a new packet, so we need a marker or anchor to tell GDB
+ that iterator goes into a new packet or frame. We define event
+ "frame". */
+
+#define CTF_MAGIC 0xC1FC1FC1
+#define CTF_SAVE_MAJOR 1
+#define CTF_SAVE_MINOR 8
+
+#define CTF_METADATA_NAME "metadata"
+#define CTF_DATASTREAM_NAME "datastream"
+
+/* Reserved event id. */
+
+#define CTF_EVENT_ID_REGISTER 0
+#define CTF_EVENT_ID_TSV 1
+#define CTF_EVENT_ID_MEMORY 2
+#define CTF_EVENT_ID_FRAME 3
+
+/* The state kept while writing the CTF datastream file. */
+
+struct trace_write_handler
+{
+ /* File descriptor of metadata. */
+ FILE *metadata_fd;
+ /* File descriptor of traceframes. */
+ FILE *datastream_fd;
+
+ /* This is the content size of the current packet. */
+ size_t content_size;
+
+ /* This is the start offset of current packet. */
+ long packet_start;
+};
+
+/* Write metadata in FORMAT. */
+
+static void
+ctf_save_write_metadata (struct trace_write_handler *handler,
+ const char *format, ...)
+{
+ va_list args;
+
+ va_start (args, format);
+ if (vfprintf (handler->metadata_fd, format, args) < 0)
+ error (_("Unable to write metadata file (%s)"),
+ safe_strerror (errno));
+ va_end (args);
+}
+
+/* Write BUF of length SIZE to datastream file represented by
+ HANDLER. */
+
+static int
+ctf_save_write (struct trace_write_handler *handler,
+ const gdb_byte *buf, size_t size)
+{
+ if (fwrite (buf, size, 1, handler->datastream_fd) != 1)
+ error (_("Unable to write file for saving trace data (%s)"),
+ safe_strerror (errno));
+
+ handler->content_size += size;
+
+ return 0;
+}
+
+/* Write a unsigned 32-bit integer to datastream file represented by
+ HANDLER. */
+
+#define ctf_save_write_uint32(HANDLER, U32) \
+ ctf_save_write (HANDLER, (gdb_byte *) &U32, 4)
+
+/* Set datastream file position. Update HANDLER->content_size
+ if WHENCE is SEEK_CUR. */
+
+static int
+ctf_save_fseek (struct trace_write_handler *handler, long offset,
+ int whence)
+{
+ gdb_assert (whence != SEEK_END);
+ gdb_assert (whence != SEEK_SET
+ || offset <= handler->content_size + handler->packet_start);
+
+ if (fseek (handler->datastream_fd, offset, whence))
+ error (_("Unable to seek file for saving trace data (%s)"),
+ safe_strerror (errno));
+
+ if (whence == SEEK_CUR)
+ handler->content_size += offset;
+
+ return 0;
+}
+
+/* Change the datastream file position to align on ALIGN_SIZE,
+ and write BUF to datastream file. The size of BUF is SIZE. */
+
+static int
+ctf_save_align_write (struct trace_write_handler *handler,
+ const gdb_byte *buf,
+ size_t size, size_t align_size)
+{
+ long offset
+ = (align_up (handler->content_size, align_size)
+ - handler->content_size);
+
+ if (ctf_save_fseek (handler, offset, SEEK_CUR))
+ return -1;
+
+ if (ctf_save_write (handler, buf, size))
+ return -1;
+
+ return 0;
+}
+
+/* Write events to next new packet. */
+
+static void
+ctf_save_next_packet (struct trace_write_handler *handler)
+{
+ handler->packet_start += (handler->content_size + 4);
+ ctf_save_fseek (handler, handler->packet_start, SEEK_SET);
+ handler->content_size = 0;
+}
+
+/* Write the CTF metadata header. */
+
+static void
+ctf_save_metadata_header (struct trace_write_handler *handler)
+{
+ const char metadata_fmt[] =
+ "\ntrace {\n"
+ " major = %u;\n"
+ " minor = %u;\n"
+ " byte_order = %s;\n" /* be or le */
+ " packet.header := struct {\n"
+ " uint32_t magic;\n"
+ " };\n"
+ "};\n"
+ "\n"
+ "stream {\n"
+ " packet.context := struct {\n"
+ " uint32_t content_size;\n"
+ " uint32_t packet_size;\n"
+ " uint16_t tpnum;\n"
+ " };\n"
+ " event.header := struct {\n"
+ " uint32_t id;\n"
+ " };\n"
+ "};\n";
+
+ ctf_save_write_metadata (handler, "/* CTF %d.%d */\n",
+ CTF_SAVE_MAJOR, CTF_SAVE_MINOR);
+ ctf_save_write_metadata (handler,
+ "typealias integer { size = 8; align = 8; "
+ "signed = false; encoding = ascii;}"
+ " := ascii;\n");
+ ctf_save_write_metadata (handler,
+ "typealias integer { size = 8; align = 8; "
+ "signed = false; }"
+ " := uint8_t;\n");
+ ctf_save_write_metadata (handler,
+ "typealias integer { size = 16; align = 16;"
+ "signed = false; } := uint16_t;\n");
+ ctf_save_write_metadata (handler,
+ "typealias integer { size = 32; align = 32;"
+ "signed = false; } := uint32_t;\n");
+ ctf_save_write_metadata (handler,
+ "typealias integer { size = 64; align = 64;"
+ "signed = false; base = hex;}"
+ " := uint64_t;\n");
+ ctf_save_write_metadata (handler, "\n");
+
+ ctf_save_write_metadata (handler, metadata_fmt,
+ CTF_SAVE_MAJOR, CTF_SAVE_MINOR,
+ BYTE_ORDER == LITTLE_ENDIAN ? "le" : "be");
+ ctf_save_write_metadata (handler, "\n");
+}
+
+/* CTF trace writer. */
+
+struct ctf_trace_file_writer
+{
+ struct trace_file_writer base;
+
+ /* States related to writing CTF trace file. */
+ struct trace_write_handler tcs;
+};
+
+/* This is the implementation of trace_file_write_ops method
+ dtor. */
+
+static void
+ctf_dtor (struct trace_file_writer *self)
+{
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+
+ if (writer->tcs.metadata_fd != NULL)
+ fclose (writer->tcs.metadata_fd);
+
+ if (writer->tcs.datastream_fd != NULL)
+ fclose (writer->tcs.datastream_fd);
+
+}
+
+/* This is the implementation of trace_file_write_ops method
+ target_save. */
+
+static int
+ctf_target_save (struct trace_file_writer *self,
+ const char *dirname)
+{
+ /* Don't support save trace file to CTF format in the target. */
+ return 0;
+}
+
+/* This is the implementation of trace_file_write_ops method
+ start. It creates the directory DIRNAME, metadata and datastream
+ in the directory. */
+
+static void
+ctf_start (struct trace_file_writer *self, const char *dirname)
+{
+ char *file_name;
+ struct cleanup *old_chain;
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ int i;
+
+ /* Create DIRNAME. */
+ if (mkdir (dirname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
+ && errno != EEXIST)
+ error (_("Unable to open directory '%s' for saving trace data (%s)"),
+ dirname, safe_strerror (errno));
+
+ memset (&writer->tcs, '\0', sizeof (writer->tcs));
+
+ file_name = xstrprintf ("%s/%s", dirname, CTF_METADATA_NAME);
+ old_chain = make_cleanup (xfree, file_name);
+
+ writer->tcs.metadata_fd = fopen (file_name, "w");
+ if (writer->tcs.metadata_fd == NULL)
+ error (_("Unable to open file '%s' for saving trace data (%s)"),
+ file_name, safe_strerror (errno));
+ do_cleanups (old_chain);
+
+ ctf_save_metadata_header (&writer->tcs);
+
+ file_name = xstrprintf ("%s/%s", dirname, CTF_DATASTREAM_NAME);
+ old_chain = make_cleanup (xfree, file_name);
+ writer->tcs.datastream_fd = fopen (file_name, "w");
+ if (writer->tcs.datastream_fd == NULL)
+ error (_("Unable to open file '%s' for saving trace data (%s)"),
+ file_name, safe_strerror (errno));
+ do_cleanups (old_chain);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_header. Write the types of events on trace variable and
+ frame. */
+
+static void
+ctf_write_header (struct trace_file_writer *self)
+{
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+
+
+ ctf_save_write_metadata (&writer->tcs, "\n");
+ ctf_save_write_metadata (&writer->tcs,
+ "event {\n\tname = \"memory\";\n\tid = %u;\n"
+ "\tfields := struct { \n"
+ "\t\tuint64_t address;\n"
+ "\t\tuint16_t length;\n"
+ "\t\tuint8_t contents[length];\n"
+ "\t};\n"
+ "};\n", CTF_EVENT_ID_MEMORY);
+
+ ctf_save_write_metadata (&writer->tcs, "\n");
+ ctf_save_write_metadata (&writer->tcs,
+ "event {\n\tname = \"tsv\";\n\tid = %u;\n"
+ "\tfields := struct { \n"
+ "\t\tuint64_t val;\n"
+ "\t\tuint32_t num;\n"
+ "\t};\n"
+ "};\n", CTF_EVENT_ID_TSV);
+
+ ctf_save_write_metadata (&writer->tcs, "\n");
+ ctf_save_write_metadata (&writer->tcs,
+ "event {\n\tname = \"frame\";\n\tid = %u;\n"
+ "\tfields := struct { \n"
+ "\t};\n"
+ "};\n", CTF_EVENT_ID_FRAME);
+
+ gdb_assert (writer->tcs.content_size == 0);
+ gdb_assert (writer->tcs.packet_start == 0);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_regblock_type. Write the type of register event in
+ metadata. */
+
+static void
+ctf_write_regblock_type (struct trace_file_writer *self, int size)
+{
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+
+ ctf_save_write_metadata (&writer->tcs, "\n");
+
+ ctf_save_write_metadata (&writer->tcs,
+ "event {\n\tname = \"register\";\n\tid = %u;\n"
+ "\tfields := struct { \n"
+ "\t\tascii contents[%d];\n"
+ "\t};\n"
+ "};\n",
+ CTF_EVENT_ID_REGISTER, size);
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_status. */
+
+static void
+ctf_write_status (struct trace_file_writer *self,
+ struct trace_status *ts)
+{
+ /* It is not supported yet to write trace status into CTF trace
+ data. */
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_uploaded_tsv. */
+
+static void
+ctf_write_uploaded_tsv (struct trace_file_writer *self,
+ struct uploaded_tsv *tsv)
+{
+ /* It is not supported yet to write uploaded trace variables
+ into CTF trace data. */
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_uploaded_tp. */
+
+static void
+ctf_write_uploaded_tp (struct trace_file_writer *self,
+ struct uploaded_tp *tp)
+{
+ /* It is not supported yet to write uploaded tracepoints
+ into CTF trace data. */
+}
+
+/* This is the implementation of trace_file_write_ops method
+ write_definition_end. */
+
+static void
+ctf_write_definition_end (struct trace_file_writer *self)
+{
+ /* Nothing to do for CTF. */
+}
+
+/* The minimal file size of data stream. It is required by
+ babeltrace. */
+
+#define CTF_FILE_MIN_SIZE 4096
+
+/* This is the implementation of trace_file_write_ops method
+ end. */
+
+static void
+ctf_end (struct trace_file_writer *self)
+{
+ struct ctf_trace_file_writer *writer = (struct ctf_trace_file_writer *) self;
+
+ gdb_assert (writer->tcs.content_size == 0);
+ /* The babeltrace requires or assumes that the size of datastream
+ file is greater than 4096 bytes. If we don't generate enough
+ packets and events, create a fake packet which has zero event,
+ to use up the space. */
+ if (writer->tcs.packet_start < CTF_FILE_MIN_SIZE)
+ {
+ uint32_t u32;
+
+ /* magic. */
+ u32 = CTF_MAGIC;
+ ctf_save_write_uint32 (&writer->tcs, u32);
+
+ /* content_size. */
+ u32 = 0;
+ ctf_save_write_uint32 (&writer->tcs, u32);
+
+ /* packet_size. */
+ u32 = 12;
+ if (writer->tcs.packet_start + u32 < CTF_FILE_MIN_SIZE)
+ u32 = CTF_FILE_MIN_SIZE - writer->tcs.packet_start;
+
+ u32 *= TARGET_CHAR_BIT;
+ ctf_save_write_uint32 (&writer->tcs, u32);
+
+ /* tpnum. */
+ u32 = 0;
+ ctf_save_write (&writer->tcs, (gdb_byte *) &u32, 2);
+
+ /* Enlarge the file to CTF_FILE_MIN_SIZE is it is still less
+ than that. */
+ if (CTF_FILE_MIN_SIZE
+ > (writer->tcs.packet_start + writer->tcs.content_size))
+ {
+ gdb_byte b = 0;
+
+ /* Fake the content size to avoid assertion failure in
+ ctf_save_fseek. */
+ writer->tcs.content_size = (CTF_FILE_MIN_SIZE
+ - 1 - writer->tcs.packet_start);
+ ctf_save_fseek (&writer->tcs, CTF_FILE_MIN_SIZE - 1,
+ SEEK_SET);
+ ctf_save_write (&writer->tcs, &b, 1);
+ }
+ }
+}
+
+/* This is the implementation of trace_frame_write_ops method
+ start. */
+
+static void
+ctf_write_frame_start (struct trace_file_writer *self, uint16_t tpnum)
+{
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ uint32_t id = CTF_EVENT_ID_FRAME;
+ uint32_t u32;
+
+ /* Step 1: Write packet context. */
+ /* magic. */
+ u32 = CTF_MAGIC;
+ ctf_save_write_uint32 (&writer->tcs, u32);
+ /* content_size and packet_size.. We still don't know the value,
+ write it later. */
+ ctf_save_fseek (&writer->tcs, 4, SEEK_CUR);
+ ctf_save_fseek (&writer->tcs, 4, SEEK_CUR);
+ /* Tracepoint number. */
+ ctf_save_write (&writer->tcs, (gdb_byte *) &tpnum, 2);
+
+ /* Step 2: Write event "frame". */
+ /* Event Id. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+ write_r_block. */
+
+static void
+ctf_write_frame_r_block (struct trace_file_writer *self,
+ gdb_byte *buf, int32_t size)
+{
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ uint32_t id = CTF_EVENT_ID_REGISTER;
+
+ /* Event Id. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
+
+ /* array contents. */
+ ctf_save_align_write (&writer->tcs, buf, size, 1);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+ write_m_block_header. */
+
+static void
+ctf_write_frame_m_block_header (struct trace_file_writer *self,
+ uint64_t addr, uint16_t length)
+{
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ uint32_t event_id = CTF_EVENT_ID_MEMORY;
+
+ /* Event Id. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &event_id, 4, 4);
+
+ /* Address. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &addr, 8, 8);
+
+ /* Length. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &length, 2, 2);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+ write_m_block_memory. */
+
+static void
+ctf_write_frame_m_block_memory (struct trace_file_writer *self,
+ gdb_byte *buf, uint16_t length)
+{
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+
+ /* Contents. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) buf, length, 1);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+ write_v_block. */
+
+static void
+ctf_write_frame_v_block (struct trace_file_writer *self,
+ int32_t num, uint64_t val)
+{
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ uint32_t id = CTF_EVENT_ID_TSV;
+
+ /* Event Id. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
+
+ /* val. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &val, 8, 8);
+ /* num. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &num, 4, 4);
+}
+
+/* This is the implementation of trace_frame_write_ops method
+ end. */
+
+static void
+ctf_write_frame_end (struct trace_file_writer *self)
+{
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ uint32_t u32;
+ uint32_t t;
+
+ /* Write the content size to packet header. */
+ ctf_save_fseek (&writer->tcs, writer->tcs.packet_start + 4,
+ SEEK_SET);
+ u32 = writer->tcs.content_size * TARGET_CHAR_BIT;
+
+ t = writer->tcs.content_size;
+ ctf_save_write_uint32 (&writer->tcs, u32);
+
+ /* Write the packet size. */
+ u32 += 4 * TARGET_CHAR_BIT;
+ ctf_save_write_uint32 (&writer->tcs, u32);
+
+ writer->tcs.content_size = t;
+
+ /* Write zero at the end of the packet. */
+ ctf_save_fseek (&writer->tcs, writer->tcs.packet_start + t,
+ SEEK_SET);
+ u32 = 0;
+ ctf_save_write_uint32 (&writer->tcs, u32);
+ writer->tcs.content_size = t;
+
+ ctf_save_next_packet (&writer->tcs);
+}
+
+/* Operations to write various types of trace frames into CTF
+ format. */
+
+static const struct trace_frame_write_ops ctf_write_frame_ops =
+{
+ ctf_write_frame_start,
+ ctf_write_frame_r_block,
+ ctf_write_frame_m_block_header,
+ ctf_write_frame_m_block_memory,
+ ctf_write_frame_v_block,
+ ctf_write_frame_end,
+};
+
+/* Operations to write trace buffers into CTF format. */
+
+static const struct trace_file_write_ops ctf_write_ops =
+{
+ ctf_dtor,
+ ctf_target_save,
+ ctf_start,
+ ctf_write_header,
+ ctf_write_regblock_type,
+ ctf_write_status,
+ ctf_write_uploaded_tsv,
+ ctf_write_uploaded_tp,
+ ctf_write_definition_end,
+ NULL,
+ &ctf_write_frame_ops,
+ ctf_end,
+};
+
+/* Return a trace writer for CTF format. */
+
+struct trace_file_writer *
+ctf_trace_file_writer_new (void)
+{
+ struct ctf_trace_file_writer *writer
+ = xmalloc (sizeof (struct ctf_trace_file_writer));
+
+ writer->base.ops = &ctf_write_ops;
+
+ return (struct trace_file_writer *) writer;
+}
diff --git a/gdb/ctf.h b/gdb/ctf.h
new file mode 100644
index 0000000..6a61cf3
--- /dev/null
+++ b/gdb/ctf.h
@@ -0,0 +1,25 @@
+/* CTF format support.
+
+ Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+ This file is part of GDB.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifndef CTF_H
+#define CTF_H
+
+extern struct trace_file_writer *ctf_trace_file_writer_new (void);
+
+#endif
diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c
index 085439b..94fda8f 100644
--- a/gdb/mi/mi-main.c
+++ b/gdb/mi/mi-main.c
@@ -49,6 +49,7 @@
#include "osdata.h"
#include "splay-tree.h"
#include "tracepoint.h"
+#include "ctf.h"
#include "ada-lang.h"
#include "linespec.h"
@@ -2477,25 +2478,45 @@ void
mi_cmd_trace_save (char *command, char **argv, int argc)
{
int target_saves = 0;
+ int generate_ctf = 0;
char *filename;
+ int oind = 0;
+ char *oarg;
- if (argc != 1 && argc != 2)
- error (_("Usage: -trace-save [-r] filename"));
-
- if (argc == 2)
+ enum opt
+ {
+ TARGET_SAVE_OPT, CTF_OPT
+ };
+ static const struct mi_opt opts[] =
{
- filename = argv[1];
- if (strcmp (argv[0], "-r") == 0)
- target_saves = 1;
- else
- error (_("Invalid option: %s"), argv[0]);
- }
- else
+ {"r", TARGET_SAVE_OPT, 0},
+ {"ctf", CTF_OPT, 0},
+ { 0, 0, 0 }
+ };
+
+ while (1)
{
- filename = argv[0];
+ int opt = mi_getopt ("-trace-save", argc, argv, opts,
+ &oind, &oarg);
+
+ if (opt < 0)
+ break;
+ switch ((enum opt) opt)
+ {
+ case TARGET_SAVE_OPT:
+ target_saves = 1;
+ break;
+ case CTF_OPT:
+ generate_ctf = 1;
+ break;
+ }
}
+ filename = argv[oind];
- trace_save_tfile (filename, target_saves);
+ if (generate_ctf)
+ trace_save_ctf (filename, target_saves);
+ else
+ trace_save_tfile (filename, target_saves);
}
void
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index bf60d75..ee22b61 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -53,6 +53,7 @@
#include "exceptions.h"
#include "cli/cli-utils.h"
#include "probe.h"
+#include "ctf.h"
/* readline include files */
#include "readline/readline.h"
@@ -3550,6 +3551,7 @@ trace_save_command (char *args, int from_tty)
char **argv;
char *filename = NULL;
struct cleanup *back_to;
+ int generate_ctf = 0;
struct trace_file_writer *writer = NULL;
if (args == NULL)
@@ -3562,6 +3564,8 @@ trace_save_command (char *args, int from_tty)
{
if (strcmp (*argv, "-r") == 0)
target_does_save = 1;
+ if (strcmp (*argv, "-ctf") == 0)
+ generate_ctf = 1;
else if (**argv == '-')
error (_("unknown option `%s'"), *argv);
else
@@ -3571,14 +3575,18 @@ trace_save_command (char *args, int from_tty)
if (!filename)
error_no_arg (_("file in which to save trace data"));
- writer = tfile_trace_file_writer_new ();
+ if (generate_ctf)
+ writer = ctf_trace_file_writer_new ();
+ else
+ writer = tfile_trace_file_writer_new ();
make_cleanup (trace_file_writer_xfree, writer);
trace_save (filename, writer, target_does_save);
if (from_tty)
- printf_filtered (_("Trace data saved to file '%s'.\n"), filename);
+ printf_filtered (_("Trace data saved to %s '%s'.\n"),
+ generate_ctf ? "directory" : "file", filename);
do_cleanups (back_to);
}
@@ -3597,6 +3605,21 @@ trace_save_tfile (const char *filename, int target_does_save)
do_cleanups (back_to);
}
+/* Save the trace data to dir DIRNAME of ctf format. */
+
+void
+trace_save_ctf (const char *dirname, int target_does_save)
+{
+ struct trace_file_writer *writer;
+ struct cleanup *back_to;
+
+ writer = ctf_trace_file_writer_new ();
+ back_to = make_cleanup (trace_file_writer_xfree, writer);
+
+ trace_save (dirname, writer, target_does_save);
+ do_cleanups (back_to);
+}
+
/* Tell the target what to do with an ongoing tracing run if GDB
disconnects for some reason. */
@@ -5663,6 +5686,7 @@ _initialize_tracepoint (void)
add_com ("tsave", class_trace, trace_save_command, _("\
Save the trace data to a file.\n\
+Use the '-ctf' option to save the data to CTF format.\n\
Use the '-r' option to direct the target to save directly to the file,\n\
using its own filesystem."));
diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
index 2d21fda..ae43b8a 100644
--- a/gdb/tracepoint.h
+++ b/gdb/tracepoint.h
@@ -388,6 +388,8 @@ extern void tfind_1 (enum trace_find_type type, int num,
extern void trace_save_tfile (const char *filename,
int target_does_save);
+extern void trace_save_ctf (const char *dirname,
+ int target_does_save);
extern struct traceframe_info *parse_traceframe_info (const char *tframe_info);
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 02/15] Save trace into CTF format
2013-03-13 10:33 ` Yao Qi
@ 2013-03-13 19:30 ` Tom Tromey
2013-03-14 17:49 ` Doug Evans
1 sibling, 0 replies; 60+ messages in thread
From: Tom Tromey @ 2013-03-13 19:30 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes:
Yao> Patch 02 is updated along with 01, to fix the cleanup issue.
Ok.
Tom
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v3 02/15] Save trace into CTF format
2013-03-13 10:33 ` Yao Qi
2013-03-13 19:30 ` Tom Tromey
@ 2013-03-14 17:49 ` Doug Evans
1 sibling, 0 replies; 60+ messages in thread
From: Doug Evans @ 2013-03-14 17:49 UTC (permalink / raw)
To: Yao Qi; +Cc: Tom Tromey, gdb-patches
Hi. Just some nits.
Yao Qi writes:
> 2013-03-13 Hui Zhu <hui_zhu@mentor.com>
> Yao Qi <yao@codesourcery.com>
>
> * Makefile.in (REMOTE_OBS): Add ctf.o.
> (SFILES): Add ctf.c.
> (HFILES_NO_SRCDIR): Add ctf.h.
> * ctf.c, ctf.h: New files.
> * tracepoint.c : Include 'ctf.h'.
> (collect_pseudocommand): Remove static.
> (trace_save_command): Parse option "-ctf".
> Produce different trace file writers per option.
> Adjust output message.
> (trace_save_tfile, trace_save_ctf): New.
> * tracepoint.h (trace_save_tfile, trace_save_ctf): Declare.
> * mi/mi-main.c: Include 'ctf.h'.
> (mi_cmd_trace_save): Handle option '-ctf'. Call either
> trace_save_tfile or trace_save_ctf.
> +/* Write a unsigned 32-bit integer to datastream file represented by
> + HANDLER. */
> +
> +#define ctf_save_write_uint32(HANDLER, U32) \
> + ctf_save_write (HANDLER, (gdb_byte *) &U32, 4)
Technically speaking, HANDLE and U32 should be in parens.
Also, I think convention is that they be lowercase
(still uppercase in the comment).
[One might also just want to make this a function instead of a macro,
but either way is fine with me at least for now.]
> +/* This is the implementation of trace_file_write_ops method
> + start. It creates the directory DIRNAME, metadata and datastream
> + in the directory. */
> +
> +static void
> +ctf_start (struct trace_file_writer *self, const char *dirname)
> +{
> + char *file_name;
> + struct cleanup *old_chain;
> + struct ctf_trace_file_writer *writer
> + = (struct ctf_trace_file_writer *) self;
> + int i;
> +
> + /* Create DIRNAME. */
> + if (mkdir (dirname, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
> + && errno != EEXIST)
> + error (_("Unable to open directory '%s' for saving trace data (%s)"),
> + dirname, safe_strerror (errno));
I see remote-fileio.c doesn't assume S_IXGRP,et.al. are portable.
Probably want to do the same here.
^ permalink raw reply [flat|nested] 60+ messages in thread
* [PATCH v3 04/15] ctf doc and NEWS.
2013-03-09 3:48 [PATCH v3 00/15] CTF Support Yao Qi
` (12 preceding siblings ...)
2013-03-09 3:49 ` [PATCH v3 02/15] Save trace into CTF format Yao Qi
@ 2013-03-09 3:49 ` Yao Qi
2013-03-09 3:49 ` [PATCH v3 03/15] Read CTF by the ctf target Yao Qi
2013-04-10 19:16 ` [PATCH v3 00/15] CTF Support Yao Qi
15 siblings, 0 replies; 60+ messages in thread
From: Yao Qi @ 2013-03-09 3:49 UTC (permalink / raw)
To: gdb-patches
The doc bit was reviewed by Eli here
http://sourceware.org/ml/gdb-patches/2013-02/msg00695.html and
comments are addressed.
2013-03-08 Hui Zhu <hui_zhu@mentor.com>
Yao Qi <yao@codesourcery.com>
* gdb.texinfo (Trace Files): Add "tsave -ctf" and target ctf.
* NEWS: Mention these changes.
---
gdb/NEWS | 7 +++++++
gdb/doc/gdb.texinfo | 38 ++++++++++++++++++++++++++++++++------
2 files changed, 39 insertions(+), 6 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index 05fa498..dd03780 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -70,6 +70,8 @@ x86_64/Cygwin x86_64-*-cygwin*
* The command 'info tracepoints' can now display 'installed on target'
or 'not installed on target' for each non-pending location of tracepoint.
+* The command 'tsave' can now support new option '-ctf' to save trace
+ buffer in Common Trace Format.
* New configure options
@@ -79,6 +81,9 @@ x86_64/Cygwin x86_64-*-cygwin*
Release versions, on the other hand, are built without -lmcheck
by default. The --enable-libmcheck/--disable-libmcheck configure
options allow the user to override that default.
+--with-babeltrace/--with-babeltrace-include/--with-babeltrace-lib
+ This configure option allows the user to build GDB with
+ libbabeltrace using which GDB can read Common Trace Format data.
* New commands (for set/show, see "New options" below)
@@ -154,6 +159,8 @@ show filename-display
** Output of the "-trace-status" command includes a "trace-file" field
containing the name of the trace file being examined. This field is
optional, and only present when examining a trace file.
+ ** The -trace-save MI command can optionally save trace buffer in Common
+ Trace Format now.
* GDB now supports the "mini debuginfo" section, .gnu_debugdata.
You must have the LZMA library available when configuring GDB for this
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 5f39d2e..5f35483 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -12120,6 +12120,7 @@ of trace data, via the @code{target tfile} command.
@kindex tsave
@item tsave [ -r ] @var{filename}
+@itemx tsave [-ctf] @var{dirname}
Save the trace data to @var{filename}. By default, this command
assumes that @var{filename} refers to the host filesystem, so if
necessary @value{GDBN} will copy raw trace data up from the target and
@@ -12128,16 +12129,41 @@ optional argument @code{-r} (``remote'') to direct the target to save
the data directly into @var{filename} in its own filesystem, which may be
more efficient if the trace buffer is very large. (Note, however, that
@code{target tfile} can only read from files accessible to the host.)
+By default, this command will save trace frame in tfile format.
+You can supply the optional argument @code{-ctf} to save date in CTF
+format. The @dfn{Common Trace Format} (CTF) is proposed as a trace format
+that can be shared by multiple debugging and tracing tools. Please go to
+@indicateurl{http://www.efficios.com/ctf} to get more information.
@kindex target tfile
@kindex tfile
+@kindex target ctf
+@kindex ctf
@item target tfile @var{filename}
-Use the file named @var{filename} as a source of trace data. Commands
-that examine data work as they do with a live target, but it is not
-possible to run any new trace experiments. @code{tstatus} will report
-the state of the trace run at the moment the data was saved, as well
-as the current trace frame you are examining. @var{filename} must be
-on a filesystem accessible to the host.
+@itemx target ctf @var{dirname}
+Use the file named @var{filename} or directory named @var{dirname} as
+a source of trace data. Commands that examine data work as they do with
+a live target, but it is not possible to run any new trace experiments.
+@code{tstatus} will report the state of the trace run at the moment
+the data was saved, as well as the current trace frame you are examining.
+@var{filename} or @var{dirname} must be on a filesystem accessible to
+the host.
+
+@smallexample
+(@value{GDBP}) target ctf ctf.ctf
+(@value{GDBP}) tfind
+Found trace frame 0, tracepoint 2
+39 ++a; /* set tracepoint 1 here */
+(@value{GDBP}) tdump
+Data collected at tracepoint 2, trace frame 0:
+i = 0
+a = 0
+b = 1 '\001'
+c = @{"123", "456", "789", "123", "456", "789"@}
+d = @{@{@{a = 1, b = 2@}, @{a = 3, b = 4@}@}, @{@{a = 5, b = 6@}, @{a = 7, b = 8@}@}@}
+(@value{GDBP}) p b
+$1 = 1
+@end smallexample
@end table
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* [PATCH v3 03/15] Read CTF by the ctf target
2013-03-09 3:48 [PATCH v3 00/15] CTF Support Yao Qi
` (13 preceding siblings ...)
2013-03-09 3:49 ` [PATCH v3 04/15] ctf doc and NEWS Yao Qi
@ 2013-03-09 3:49 ` Yao Qi
2013-03-13 20:09 ` Tom Tromey
2013-04-10 19:16 ` [PATCH v3 00/15] CTF Support Yao Qi
15 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-09 3:49 UTC (permalink / raw)
To: gdb-patches
This patch adds a new target 'ctf' in GDB, so GDB can read CTF trace
data in this target. Some of the implementations of target vector for
ctf target are copied from tfile target, so some of them can be shared
in the future.
We use libbabeltrace to read CTF data, because libbabeltrace is
designed to do this, and we don't have to reinvent the wheel again in
GDB. Some configure stuff is modified to check whether the
libbabeltrace is installed.
In V3, we fix a bug in configure.ac on checking broken libbabeltrace,
and fix some code violations like "if (foo)".
gdb:
2013-03-08 Hui Zhu <hui_zhu@mentor.com>
Yao Qi <yao@codesourcery.com>
* configure.ac: Check libbabeltrace is installed.
* config.in: Regenerate.
* configure: Regenerate.
* Makefile.in (LIBBABELTRACE, LIBBABELTRACE_CFLAGS): New.
(INTERNAL_CFLAGS_BASE): Append LIBBABELTRACE_CFLAGS.
(CLIBS): Add LIBBABELTRACE.
* ctf.c (ctx, ctf_iter, trace_dirname): New.
(ctf_close_dir, ctf_open_dir, ctf_open): New.
(ctf_close, ctf_files_info): New.
(ctf_fetch_registers, ctf_xfer_partial): New.
(ctf_get_trace_state_variable_value): New.
(ctf_get_tpnum_from_frame_event): New.
(ctf_get_traceframe_address): New.
(ctf_trace_find, ctf_has_all_memory): New.
(ctf_has_memory, ctf_has_stack): New.
(ctf_has_registers, ctf_thread_alive): New.
(ctf_traceframe_info, init_ctf_ops): New.
(_initialize_ctf): New.
* tracepoint.c (traceframe_number, tracepoint_number): Remove
'static'.
(struct traceframe_info, trace_regblock_size): Move it to ...
* tracepoint.h: ... here.
(tracepoint_number, tracepoint_number): Declare.
---
gdb/Makefile.in | 11 +-
gdb/config.in | 3 +
gdb/configure | 141 +++++++++++
gdb/configure.ac | 82 ++++++
gdb/ctf.c | 741 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/tracepoint.c | 14 +-
gdb/tracepoint.h | 14 +
7 files changed, 992 insertions(+), 14 deletions(-)
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 5be6c77..9275b12 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -154,6 +154,12 @@ LIBEXPAT = @LIBEXPAT@
# Where is lzma? This will be empty if lzma was not available.
LIBLZMA = @LIBLZMA@
+# Where is libbabeltrace? This will be empty if lbabeltrace was not
+# available.
+LIBBABELTRACE = @LIBBABELTRACE@
+LIBBABELTRACE_CFLAGS = @LIBBABELTRACE_CFLAGS@
+
+
WARN_CFLAGS = @WARN_CFLAGS@
WERROR_CFLAGS = @WERROR_CFLAGS@
GDB_WARN_CFLAGS = $(WARN_CFLAGS)
@@ -453,7 +459,8 @@ INTERNAL_CFLAGS_BASE = \
$(CFLAGS) $(GLOBAL_CFLAGS) $(PROFILE_CFLAGS) \
$(GDB_CFLAGS) $(OPCODES_CFLAGS) $(READLINE_CFLAGS) \
$(BFD_CFLAGS) $(INCLUDE_CFLAGS) $(LIBDECNUMBER_CFLAGS) \
- $(INTL_CFLAGS) $(INCGNU) $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS)
+ $(INTL_CFLAGS) $(INCGNU) $(LIBBABELTRACE_CFLAGS) \
+ $(ENABLE_CFLAGS) $(INTERNAL_CPPFLAGS)
INTERNAL_WARN_CFLAGS = $(INTERNAL_CFLAGS_BASE) $(GDB_WARN_CFLAGS)
INTERNAL_CFLAGS = $(INTERNAL_WARN_CFLAGS) $(GDB_WERROR_CFLAGS)
@@ -475,7 +482,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_
# LIBIBERTY appears twice on purpose.
CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
$(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ @PYTHON_LIBS@ \
- $(LIBEXPAT) $(LIBLZMA) \
+ $(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) \
$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU)
CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
diff --git a/gdb/config.in b/gdb/config.in
index 9e21325..c4e8eaa 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -180,6 +180,9 @@
/* Define if your <locale.h> file defines LC_MESSAGES. */
#undef HAVE_LC_MESSAGES
+/* Define if libbabeltrace is available */
+#undef HAVE_LIBBABELTRACE
+
/* Define to 1 if you have the `dl' library (-ldl). */
#undef HAVE_LIBDL
diff --git a/gdb/configure b/gdb/configure
index c54709c..e739420 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -592,6 +592,8 @@ enable_option_checking=no
ac_subst_vars='LTLIBOBJS
LIBOBJS
GDB_NM_FILE
+LIBBABELTRACE_CFLAGS
+LIBBABELTRACE
frags
target_subdir
CONFIG_UNINSTALL
@@ -819,6 +821,9 @@ with_x
enable_sim
enable_multi_ice
enable_gdbserver
+with_babeltrace
+with_bt_include
+with_bt_lib
'
ac_precious_vars='build_alias
host_alias
@@ -1532,6 +1537,15 @@ Optional Packages:
--with-tcl directory containing tcl configuration (tclConfig.sh)
--with-tk directory containing tk configuration (tkConfig.sh)
--with-x use the X Window System
+ --with-babeltrace Specify prefix directory for the installed
+ BABELTRACE package Equivalent to
+ --with-babeltrace-include=PATH/include plus
+ --with-babeltrace-lib=PATH/lib
+ --with-babeltrace-include
+ Specify directory for installed babeltrace include
+ files
+ --with-babeltrace-lib Specify the directory for the installed babeltrace
+ library
Some influential environment variables:
CC C compiler command
@@ -14090,6 +14104,133 @@ if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then
as_fn_error "Automatic gdbserver build is not supported for this configuration" "$LINENO" 5
fi
+# Check for babeltrace and babeltrace-ctf
+LIBBABELTRACE
+LIBBABELTRACE_CFLAGS
+
+
+# Check whether --with-babeltrace was given.
+if test "${with_babeltrace+set}" = set; then :
+ withval=$with_babeltrace;
+fi
+
+
+
+# Check whether --with-bt_include was given.
+if test "${with_bt_include+set}" = set; then :
+ withval=$with_bt_include;
+fi
+
+
+# Check whether --with-bt_lib was given.
+if test "${with_bt_lib+set}" = set; then :
+ withval=$with_bt_lib;
+fi
+
+
+case $with_babeltrace in
+ no)
+ LIBBABELTRACE=
+ LIBBABELTRACE_CFLAGS=
+ ;;
+ "" | yes)
+ LIBBABELTRACE=" -lbabeltrace -lbabeltrace-ctf "
+ LIBBABELTRACE_CFLAGS=""
+ ;;
+ *)
+ LIBBABELTRACE="-L$with_babeltrace/lib -lbabeltrace -lbabeltrace-ctf"
+ LIBBABELTRACE_CFLAGS="-I$with_babeltrace/include "
+ ;;
+esac
+if test "x$with_bt_include" != x; then
+ LIBBABELTRACE_CFLAGS="-I$with_bt_include "
+fi
+if test "x$with_bt_lib" != x; then
+ LIBBABELTRACE="-L$with_bt_lib -lbabeltrace -lbabeltrace-ctf"
+fi
+
+if test "x$with_babeltrace" != "xno"; then
+ saved_CFLAGS=$CFLAGS
+ saved_LIBS=$LIBS
+
+ CFLAGS="$CFLAGS $LIBBABELTRACE_CFLAGS"
+ LIBS="$LIBS $LIBBABELTRACE"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for babeltrace" >&5
+$as_echo_n "checking for babeltrace... " >&6; }
+if test "${ac_cv_has_babeltrace_header+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/iterator.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; ac_cv_has_babeltrace_header=yes
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }; ac_cv_has_babeltrace_header=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_has_babeltrace_header" >&5
+$as_echo "$ac_cv_has_babeltrace_header" >&6; }
+
+ if test "x$ac_cv_has_babeltrace_header" != "xno"; then
+ # Check whether there is a function named 'lookup_enum' in
+ # babeltrace library. We can't use the babeltrace library
+ # in which function 'lookup_enum' is defined. This function
+ # is renamed to 'bt_lookup_name' in recent babeltrace.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken babeltrace" >&5
+$as_echo_n "checking for broken babeltrace... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+lookup_enum (NULL, NULL, 0)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }; LIBBABELTRACE= ; LIBBABELTRACE_CFLAGS=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; };
+$as_echo "#define HAVE_LIBBABELTRACE 1" >>confdefs.h
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ else
+ LIBBABELTRACE=
+ LIBBABELTRACE_CFLAGS=
+ fi
+
+ CFLAGS="$saved_CFLAGS"
+ LIBS="$saved_LIBS"
+fi
+
+# Flags needed for babeltrace.
+
+
+
+
# If nativefile (NAT_FILE) is not set in config/*/*.m[ht] files, we link
# to an empty version.
diff --git a/gdb/configure.ac b/gdb/configure.ac
index e501766..0b784c6 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -2318,6 +2318,88 @@ if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then
AC_MSG_ERROR(Automatic gdbserver build is not supported for this configuration)
fi
+# Check for babeltrace and babeltrace-ctf
+LIBBABELTRACE
+LIBBABELTRACE_CFLAGS
+
+AC_ARG_WITH(babeltrace,
+ AC_HELP_STRING([--with-babeltrace],
+ [Specify prefix directory for the installed
+ BABELTRACE package Equivalent to
+ --with-babeltrace-include=PATH/include
+ plus --with-babeltrace-lib=PATH/lib]))
+
+AC_ARG_WITH(bt_include,
+ AC_HELP_STRING([--with-babeltrace-include],
+ [Specify directory for installed babeltrace include
+ files]))
+AC_ARG_WITH(bt_lib,
+ AC_HELP_STRING([--with-babeltrace-lib],
+ [Specify the directory for the installed babeltrace
+ library]))
+
+case $with_babeltrace in
+ no)
+ LIBBABELTRACE=
+ LIBBABELTRACE_CFLAGS=
+ ;;
+ "" | yes)
+ LIBBABELTRACE=" -lbabeltrace -lbabeltrace-ctf "
+ LIBBABELTRACE_CFLAGS=""
+ ;;
+ *)
+ LIBBABELTRACE="-L$with_babeltrace/lib -lbabeltrace -lbabeltrace-ctf"
+ LIBBABELTRACE_CFLAGS="-I$with_babeltrace/include "
+ ;;
+esac
+if test "x$with_bt_include" != x; then
+ LIBBABELTRACE_CFLAGS="-I$with_bt_include "
+fi
+if test "x$with_bt_lib" != x; then
+ LIBBABELTRACE="-L$with_bt_lib -lbabeltrace -lbabeltrace-ctf"
+fi
+
+if test "x$with_babeltrace" != "xno"; then
+ saved_CFLAGS=$CFLAGS
+ saved_LIBS=$LIBS
+
+ CFLAGS="$CFLAGS $LIBBABELTRACE_CFLAGS"
+ LIBS="$LIBS $LIBBABELTRACE"
+
+ AC_CACHE_CHECK([for babeltrace], ac_cv_has_babeltrace_header,
+ [AC_TRY_COMPILE([
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/iterator.h>
+ ],[],
+ [AC_MSG_RESULT([yes]); ac_cv_has_babeltrace_header=yes],
+ [AC_MSG_RESULT([no]); ac_cv_has_babeltrace_header=no])])
+
+ if test "x$ac_cv_has_babeltrace_header" != "xno"; then
+ # Check whether there is a function named 'lookup_enum' in
+ # babeltrace library. We can't use the babeltrace library
+ # in which function 'lookup_enum' is defined. This function
+ # is renamed to 'bt_lookup_name' in recent babeltrace.
+ AC_MSG_CHECKING([for broken babeltrace])
+ AC_TRY_LINK([#include <stdio.h>],
+ [lookup_enum (NULL, NULL, 0)],
+ [AC_MSG_RESULT([yes]); LIBBABELTRACE= ; LIBBABELTRACE_CFLAGS= ],
+ [AC_MSG_RESULT([no]); AC_DEFINE(HAVE_LIBBABELTRACE, 1,
+ [Define if libbabeltrace is available])])
+ else
+ LIBBABELTRACE=
+ LIBBABELTRACE_CFLAGS=
+ fi
+
+ CFLAGS="$saved_CFLAGS"
+ LIBS="$saved_LIBS"
+fi
+
+# Flags needed for babeltrace.
+AC_SUBST(LIBBABELTRACE)
+AC_SUBST(LIBBABELTRACE_CFLAGS)
+
+
# If nativefile (NAT_FILE) is not set in config/*/*.m[ht] files, we link
# to an empty version.
diff --git a/gdb/ctf.c b/gdb/ctf.c
index 909b769..ec35b17 100644
--- a/gdb/ctf.c
+++ b/gdb/ctf.c
@@ -23,6 +23,7 @@
#include "ctf.h"
#include "tracepoint.h"
#include "regcache.h"
+#include "exec.h"
#include <ctype.h>
@@ -646,3 +647,743 @@ ctf_trace_file_writer_new (void)
return (struct trace_file_writer *) writer;
}
+
+#ifdef HAVE_LIBBABELTRACE
+/* Use libbabeltrace to read CTF data. The libbabeltrace provides
+ iterator to iterate over each event in CTF data and APIs to get
+ details of event and packet, so it is very convenient to use
+ libbabeltrace to access events in CTF. */
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/iterator.h>
+
+/* The struct pointer for current CTF directory. */
+static struct bt_context *ctx = NULL;
+static struct bt_ctf_iter *ctf_iter = NULL;
+/* The name of CTF directory. */
+static char *trace_dirname;
+
+static struct target_ops ctf_ops;
+
+static void
+ctf_close_dir (void)
+{
+ if (ctf_iter != NULL)
+ {
+ bt_ctf_iter_destroy (ctf_iter);
+ ctf_iter = NULL;
+ }
+ if (ctx != NULL)
+ {
+ bt_context_put (ctx);
+ ctx = NULL;
+ }
+}
+
+/* Open CTF trace data in DIRNAME. */
+
+static void
+ctf_open_dir (char *dirname)
+{
+ int ret;
+ struct bt_iter_pos begin_pos;
+ struct bt_iter_pos *pos;
+
+ ctx = bt_context_create ();
+ if (ctx == NULL)
+ error (_("Unable to initialize libbabeltrace"));
+ ret = bt_context_add_trace (ctx, dirname, "ctf", NULL, NULL, NULL);
+ if (ret < 0)
+ {
+ ctf_close_dir ();
+ error (_("Unable to use libbabeltrace open \"%s\""), dirname);
+ }
+
+ begin_pos.type = BT_SEEK_BEGIN;
+ ctf_iter = bt_ctf_iter_create (ctx, &begin_pos, NULL);
+ if (ctf_iter == NULL)
+ {
+ ctf_close_dir ();
+ error (_("Unable to use libbabeltrace open \"%s\""), dirname);
+ }
+
+ /* Iterate over events, and look for an event for register block
+ to set trace_regblock_size. */
+
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event;
+
+ event = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (name == NULL)
+ break;
+ else if (strcmp (name, "register") == 0)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+
+ trace_regblock_size
+ = bt_ctf_get_array_len (bt_ctf_get_decl_from_def (array));
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+}
+
+static void
+ctf_open (char *dirname, int from_tty)
+{
+ target_preopen (from_tty);
+ if (!dirname)
+ error (_("No CTF directory specified."));
+
+ ctf_open_dir (dirname);
+
+ trace_dirname = xstrdup (dirname);
+ push_target (&ctf_ops);
+}
+
+static void
+ctf_close (int quitting)
+{
+ ctf_close_dir ();
+ xfree (trace_dirname);
+ trace_dirname = NULL;
+}
+
+static void
+ctf_files_info (struct target_ops *t)
+{
+ printf_filtered ("\t`%s'\n", trace_dirname);
+}
+
+/* Iterate over events whose name is "register" in current frame,
+ extract contents from events, and set REGCACHE with the contents.
+ If no matched events are found, mark registers unavailable. */
+
+static void
+ctf_fetch_registers (struct target_ops *ops,
+ struct regcache *regcache, int regno)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ int offset, regn, regsize, pc_regno;
+ char *regs = NULL;
+ struct bt_ctf_event *event = NULL;
+ struct bt_iter_pos *pos;
+
+ /* An uninitialized reg size says we're not going to be
+ successful at getting register blocks. */
+ if (trace_regblock_size == 0)
+ return;
+
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event1;
+
+ event1 = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event1);
+
+ if (name == NULL || strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "register") == 0)
+ {
+ event = event1;
+ break;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ if (event != NULL)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+
+ regs = bt_ctf_get_char_array (array);
+ /* Assume the block is laid out in GDB register number order,
+ each register with the size that it has in GDB. */
+ offset = 0;
+ for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+ {
+ regsize = register_size (gdbarch, regn);
+ /* Make sure we stay within block bounds. */
+ if (offset + regsize >= trace_regblock_size)
+ break;
+ if (regcache_register_status (regcache, regn) == REG_UNKNOWN)
+ {
+ if (regno == regn)
+ {
+ regcache_raw_supply (regcache, regno, regs + offset);
+ break;
+ }
+ else if (regno == -1)
+ {
+ regcache_raw_supply (regcache, regn, regs + offset);
+ }
+ }
+ offset += regsize;
+ }
+ return;
+ }
+
+ regs = alloca (trace_regblock_size);
+
+ /* We get here if no register data has been found. Mark registers
+ as unavailable. */
+ for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+ regcache_raw_supply (regcache, regn, NULL);
+
+ /* We can often usefully guess that the PC is going to be the same
+ as the address of the tracepoint. */
+ pc_regno = gdbarch_pc_regnum (gdbarch);
+ if (pc_regno >= 0 && (regno == -1 || regno == pc_regno))
+ {
+ struct tracepoint *tp = get_tracepoint (tracepoint_number);
+
+ if (tp != NULL && tp->base.loc)
+ {
+ /* But don't try to guess if tracepoint is multi-location... */
+ if (tp->base.loc->next != NULL)
+ {
+ warning (_("Tracepoint %d has multiple "
+ "locations, cannot infer $pc"),
+ tp->base.number);
+ return;
+ }
+ /* ... or does while-stepping. */
+ if (tp->step_count > 0)
+ {
+ warning (_("Tracepoint %d does while-stepping, "
+ "cannot infer $pc"),
+ tp->base.number);
+ return;
+ }
+
+ store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
+ gdbarch_byte_order (gdbarch),
+ tp->base.loc->address);
+ regcache_raw_supply (regcache, pc_regno, regs);
+ }
+ }
+}
+
+/* Iterate over events whose name is "memory" in
+ current frame, extract the address and length from events. If
+ OFFSET is within the range, read the contents from events to
+ READBUF. */
+
+static LONGEST
+ctf_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf, ULONGEST offset,
+ LONGEST len)
+{
+ /* We're only doing regular memory for now. */
+ if (object != TARGET_OBJECT_MEMORY)
+ return -1;
+
+ if (readbuf == NULL)
+ error (_("ctf_xfer_partial: trace file is read-only"));
+
+ if (traceframe_number != -1)
+ {
+ struct bt_iter_pos *pos;
+ int i = 0;
+
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ /* Iterate through the traceframe's blocks, looking for
+ memory. */
+ while (1)
+ {
+ ULONGEST maddr, amt;
+ uint16_t mlen;
+ enum bfd_endian byte_order
+ = gdbarch_byte_order (target_gdbarch ());
+ const struct bt_definition *scope;
+ const struct bt_definition *def;
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+ const char *name = bt_ctf_event_name (event);
+
+ if (strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "memory") != 0)
+ {
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+
+ continue;
+ }
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+
+ def = bt_ctf_get_field (event, scope, "address");
+ maddr = bt_ctf_get_uint64 (def);
+ def = bt_ctf_get_field (event, scope, "length");
+ mlen = (uint16_t) bt_ctf_get_uint64 (def);
+
+ /* If the block includes the first part of the desired
+ range, return as much it has; GDB will re-request the
+ remainder, which might be in a different block of this
+ trace frame. */
+ if (maddr <= offset && offset < (maddr + mlen))
+ {
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+ const struct bt_declaration *decl
+ = bt_ctf_get_decl_from_def (array);
+ gdb_byte *contents;
+ int k;
+
+ /*
+ gdb_assert (mlen == bt_ctf_get_array_len (decl));
+ contents = bt_ctf_get_char_array (array);
+ */
+ contents = xmalloc (mlen);
+
+ for (k = 0; k < mlen; k++)
+ {
+ const struct bt_definition *element
+ = bt_ctf_get_index (event, array, k);
+
+ contents[k] = (gdb_byte) bt_ctf_get_uint64 (element);
+ }
+
+ amt = (maddr + mlen) - offset;
+ if (amt > len)
+ amt = len;
+
+ memcpy (readbuf, &contents[offset - maddr], amt);
+
+ xfree (contents);
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return amt;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+ }
+
+ /* It's unduly pedantic to refuse to look at the executable for
+ read-only pieces; so do the equivalent of readonly regions aka
+ QTro packet. */
+ if (exec_bfd != NULL)
+ {
+ asection *s;
+ bfd_size_type size;
+ bfd_vma vma;
+
+ for (s = exec_bfd->sections; s; s = s->next)
+ {
+ if ((s->flags & SEC_LOAD) == 0
+ || (s->flags & SEC_READONLY) == 0)
+ continue;
+
+ vma = s->vma;
+ size = bfd_get_section_size (s);
+ if (vma <= offset && offset < (vma + size))
+ {
+ ULONGEST amt;
+
+ amt = (vma + size) - offset;
+ if (amt > len)
+ amt = len;
+
+ amt = bfd_get_section_contents (exec_bfd, s,
+ readbuf, offset - vma, amt);
+ return amt;
+ }
+ }
+ }
+
+ /* Indicate failure to find the requested memory block. */
+ return -1;
+}
+
+/* Iterate over events whose name is "tsv" in current frame. When the
+ trace variable is found, set the value of it to *VAL and return
+ true, otherwise return false. */
+
+static int
+ctf_get_trace_state_variable_value (int tsvnum, LONGEST *val)
+{
+ struct bt_iter_pos *pos;
+ int found = 0;
+
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ /* Iterate through the traceframe's blocks, looking for 'V'
+ block. */
+ while (1)
+ {
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+ const char *name = bt_ctf_event_name (event);
+
+ if (strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "tsv") == 0)
+ {
+ const struct bt_definition *scope;
+ const struct bt_definition *def;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+
+ def = bt_ctf_get_field (event, scope, "num");
+ if (tsvnum == (int32_t) bt_ctf_get_uint64 (def))
+ {
+ def = bt_ctf_get_field (event, scope, "val");
+ *val = bt_ctf_get_uint64 (def);
+
+ found = 1;
+ break;
+ }
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return found;
+}
+
+/* Return the tracepoint number in "frame" event. */
+
+static int
+ctf_get_tpnum_from_frame_event (struct bt_ctf_event *event)
+{
+ /* The packet context of events has a field "tpnum". */
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event, BT_STREAM_PACKET_CONTEXT);
+ uint64_t tpnum
+ = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "tpnum"));
+
+ return (int) tpnum;
+}
+
+/* Return the address at which the current frame was collected. */
+
+static ULONGEST
+ctf_get_traceframe_address (void)
+{
+ struct bt_ctf_event *event = NULL;
+ struct bt_iter_pos *pos
+ = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ ULONGEST addr = 0;
+
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event1;
+
+ event1 = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event1);
+
+ if (name == NULL)
+ break;
+ else if (strcmp (name, "frame") == 0)
+ {
+ event = event1;
+ break;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ if (event != NULL)
+ {
+ int tpnum = ctf_get_tpnum_from_frame_event (event);
+ struct tracepoint *tp
+ = get_tracepoint_by_number_on_target (tpnum);
+
+ if (tp && tp->base.loc)
+ addr = tp->base.loc->address;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return addr;
+}
+
+/* Iterate the events whose name is "frame", extract the tracepoint
+ number in it. Return traceframe number when matched. */
+
+static int
+ctf_trace_find (enum trace_find_type type, int num,
+ ULONGEST addr1, ULONGEST addr2, int *tpp)
+{
+ int ret = -1;
+ int tfnum = 0;
+ int found = 0;
+ struct bt_iter_pos pos;
+
+ if (num == -1)
+ {
+ if (tpp != NULL)
+ *tpp = -1;
+ return -1;
+ }
+
+ /* Set iterator back to the beginning. */
+ pos.type = BT_SEEK_BEGIN;
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), &pos);
+
+ while (1)
+ {
+ int id;
+ struct bt_ctf_event *event;
+ const char *name;
+
+ event = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (event == NULL || name == NULL)
+ return -1;
+
+ if (strcmp (name, "frame") == 0)
+ {
+ ULONGEST tfaddr;
+
+ if (type == tfind_number)
+ {
+ /* Looking for a specific trace frame. */
+ if (tfnum == num)
+ found = 1;
+ }
+ else
+ {
+ /* Start from the _next_ trace frame. */
+ if (tfnum > traceframe_number)
+ {
+ switch (type)
+ {
+ case tfind_tp:
+ {
+ struct tracepoint *tp = get_tracepoint (num);
+
+ if (tp != NULL
+ && (tp->number_on_target
+ == ctf_get_tpnum_from_frame_event (event)))
+ found = 1;
+ break;
+ }
+ case tfind_pc:
+ tfaddr = ctf_get_traceframe_address ();
+ if (tfaddr == addr1)
+ found = 1;
+ break;
+ case tfind_range:
+ tfaddr = ctf_get_traceframe_address ();
+ if (addr1 <= tfaddr && tfaddr <= addr2)
+ found = 1;
+ break;
+ case tfind_outside:
+ tfaddr = ctf_get_traceframe_address ();
+ if (!(addr1 <= tfaddr && tfaddr <= addr2))
+ found = 1;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, _("unknown tfind type"));
+ }
+ }
+ }
+ if (found)
+ {
+ if (tpp != NULL)
+ *tpp = ctf_get_tpnum_from_frame_event (event);
+
+ /* Skip the event "frame". */
+ bt_iter_next (bt_ctf_get_iter (ctf_iter));
+
+ return tfnum;
+ }
+ tfnum++;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ return -1;
+ }
+
+ return -1;
+}
+
+static int
+ctf_has_all_memory (struct target_ops *ops)
+{
+ return 0;
+}
+
+static int
+ctf_has_memory (struct target_ops *ops)
+{
+ return 0;
+}
+
+static int
+ctf_has_stack (struct target_ops *ops)
+{
+ return traceframe_number != -1;
+}
+
+static int
+ctf_has_registers (struct target_ops *ops)
+{
+ return traceframe_number != -1;
+}
+
+static int
+ctf_thread_alive (struct target_ops *ops, ptid_t ptid)
+{
+ return 1;
+}
+
+/* Iterate the events whose name is "memory", in current
+ frame, extract memory range information, and return them in
+ traceframe_info. */
+
+static struct traceframe_info *
+ctf_traceframe_info (void)
+{
+ struct traceframe_info *info = XCNEW (struct traceframe_info);
+ const char *name;
+ struct bt_iter_pos *pos;
+
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ do
+ {
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (name == NULL || strcmp (name, "register") == 0
+ || strcmp (name, "frame") == 0)
+ ;
+ else if (strcmp (name, "memory") == 0)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *def;
+ struct mem_range *r;
+
+ r = VEC_safe_push (mem_range_s, info->memory, NULL);
+ def = bt_ctf_get_field (event, scope, "address");
+ r->start = bt_ctf_get_uint64 (def);
+
+ def = bt_ctf_get_field (event, scope, "length");
+ r->length = (uint16_t) bt_ctf_get_uint64 (def);
+ }
+ else
+ warning (_("Unhandled trace block type (%s) "
+ "while building trace frame info."),
+ name);
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+ while (name != NULL && strcmp (name, "frame") != 0);
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ /* traceframe_walk_blocks (build_traceframe_info, 0, info); */
+ return info;
+}
+
+static void
+init_ctf_ops (void)
+{
+ ctf_ops.to_shortname = "ctf";
+ ctf_ops.to_longname = "CTF file";
+ ctf_ops.to_doc = "Use a CTF directory as a target.\n\
+Specify the filename of the CTF directory.";
+ ctf_ops.to_open = ctf_open;
+ ctf_ops.to_close = ctf_close;
+ ctf_ops.to_fetch_registers = ctf_fetch_registers;
+ ctf_ops.to_xfer_partial = ctf_xfer_partial;
+ ctf_ops.to_files_info = ctf_files_info;
+ ctf_ops.to_trace_find = ctf_trace_find;
+ ctf_ops.to_get_trace_state_variable_value
+ = ctf_get_trace_state_variable_value;
+ ctf_ops.to_stratum = process_stratum;
+ ctf_ops.to_has_all_memory = ctf_has_all_memory;
+ ctf_ops.to_has_memory = ctf_has_memory;
+ ctf_ops.to_has_stack = ctf_has_stack;
+ ctf_ops.to_has_registers = ctf_has_registers;
+ ctf_ops.to_traceframe_info = ctf_traceframe_info;
+ ctf_ops.to_thread_alive = ctf_thread_alive;
+ ctf_ops.to_magic = OPS_MAGIC;
+}
+
+#endif
+
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_ctf;
+
+/* module initialization */
+void
+_initialize_ctf (void)
+{
+#ifdef HAVE_LIBBABELTRACE
+ init_ctf_ops ();
+
+ add_target (&ctf_ops);
+#endif
+}
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index de59102..d224e14 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -126,14 +126,6 @@ extern void (*deprecated_readline_end_hook) (void);
typedef struct trace_state_variable tsv_s;
DEF_VEC_O(tsv_s);
-/* An object describing the contents of a traceframe. */
-
-struct traceframe_info
-{
- /* Collected memory. */
- VEC(mem_range_s) *memory;
-};
-
static VEC(tsv_s) *tvariables;
/* The next integer to assign to a variable. */
@@ -141,10 +133,10 @@ static VEC(tsv_s) *tvariables;
static int next_tsv_number = 1;
/* Number of last traceframe collected. */
-static int traceframe_number;
+int traceframe_number;
/* Tracepoint for last traceframe collected. */
-static int tracepoint_number;
+int tracepoint_number;
/* Symbol for function for last traceframe collected. */
static struct symbol *traceframe_fun;
@@ -3244,8 +3236,6 @@ static const struct trace_file_write_ops tfile_write_ops =
#define TRACE_WRITE_V_BLOCK(writer, num, val) \
writer->ops->frame_ops->write_v_block ((writer), (num), (val))
-extern int trace_regblock_size;
-
/* Save tracepoint data to file named FILENAME through WRITER. WRITER
determines the trace file format. If TARGET_DOES_SAVE is non-zero,
the save is performed on the target, otherwise GDB obtains all trace
diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
index ab11574..8762d1c 100644
--- a/gdb/tracepoint.h
+++ b/gdb/tracepoint.h
@@ -24,6 +24,14 @@
#include "memrange.h"
#include "gdb_vecs.h"
+/* An object describing the contents of a traceframe. */
+
+struct traceframe_info
+{
+ /* Collected memory. */
+ VEC(mem_range_s) *memory;
+};
+
/* A trace state variable is a value managed by a target being
traced. A trace state variable (or tsv for short) can be accessed
and assigned to by tracepoint actions and conditionals, but is not
@@ -142,6 +150,12 @@ struct trace_status *current_trace_status (void);
extern char *default_collect;
+extern int tracepoint_number;
+
+extern int traceframe_number;
+
+extern int trace_regblock_size;
+
/* Struct to collect random info about tracepoints on the target. */
struct uploaded_tp
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 03/15] Read CTF by the ctf target
2013-03-09 3:49 ` [PATCH v3 03/15] Read CTF by the ctf target Yao Qi
@ 2013-03-13 20:09 ` Tom Tromey
2013-03-14 13:23 ` Yao Qi
2013-03-14 16:57 ` Doug Evans
0 siblings, 2 replies; 60+ messages in thread
From: Tom Tromey @ 2013-03-13 20:09 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes:
Yao> +AC_ARG_WITH(babeltrace,
Yao> + AC_HELP_STRING([--with-babeltrace],
Yao> + [Specify prefix directory for the installed
Yao> + BABELTRACE package Equivalent to
Yao> + --with-babeltrace-include=PATH/include
Yao> + plus --with-babeltrace-lib=PATH/lib]))
I think this is missing a period and a space between "package" and
"Equivalent", but see below.
Yao> +if test "x$with_bt_include" != x; then
Yao> + LIBBABELTRACE_CFLAGS="-I$with_bt_include "
Yao> +fi
Yao> +if test "x$with_bt_lib" != x; then
Yao> + LIBBABELTRACE="-L$with_bt_lib -lbabeltrace -lbabeltrace-ctf"
Yao> +fi
Yao> +
Yao> +if test "x$with_babeltrace" != "xno"; then
This only checks for libbabeltrace if --with-babeltrace is specified.
So, the text above about equivalency isn't really correct, at least the
way I read it; if you want to give --with-babeltrace-include, you have
to also give --with-babeltrace.
I'm not sure how to reword the above to make it more clear.
Perhaps spelling out the options.
Yao> +
Yao> +static void
Yao> +ctf_close_dir (void)
Lots of functions missing intro comments.
Most of the comments can be really short, since these are just
implementations of target methods.
Yao> + /*
Yao> + gdb_assert (mlen == bt_ctf_get_array_len (decl));
Yao> + contents = bt_ctf_get_char_array (array);
Yao> + */
I think just delete this.
Yao> +static int
Yao> +ctf_has_all_memory (struct target_ops *ops)
Yao> +{
Yao> + return 0;
Yao> +}
Unfortunately for you there is plenty of this patch I don't feel
competent to review. I don't know much about the target API.
If nobody else looks after a decent interval, ping me and I will ok it.
I suppose if these methods parallel the existing tfile target, then that
is pretty good evidence for it being ok.
The rest seems ok to me.
Tom
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 03/15] Read CTF by the ctf target
2013-03-13 20:09 ` Tom Tromey
@ 2013-03-14 13:23 ` Yao Qi
2013-03-14 14:59 ` Tom Tromey
2013-03-14 16:57 ` Doug Evans
1 sibling, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-14 13:23 UTC (permalink / raw)
To: Tom Tromey; +Cc: gdb-patches
On 03/14/2013 04:08 AM, Tom Tromey wrote:
> Yao> +if test "x$with_bt_include" != x; then
> Yao> + LIBBABELTRACE_CFLAGS="-I$with_bt_include "
> Yao> +fi
> Yao> +if test "x$with_bt_lib" != x; then
> Yao> + LIBBABELTRACE="-L$with_bt_lib -lbabeltrace -lbabeltrace-ctf"
> Yao> +fi
> Yao> +
> Yao> +if test "x$with_babeltrace" != "xno"; then
>
> This only checks for libbabeltrace if --with-babeltrace is specified.
> So, the text above about equivalency isn't really correct, at least the
> way I read it; if you want to give --with-babeltrace-include, you have
> to also give --with-babeltrace.
>
It works if we only give --with-babeltrace-include and
--with-babeltrace-lib (without giving --with-babeltrace). In this case,
$with_babeltrace is empty, and the condition above is still true. I
tried to configure with --with-babeltrace-include=/usr/include and
--with-babeltrace-lib=/usr/lib, everything looks OK.
> Yao> +static int
> Yao> +ctf_has_all_memory (struct target_ops *ops)
> Yao> +{
> Yao> + return 0;
> Yao> +}
>
> Unfortunately for you there is plenty of this patch I don't feel
> competent to review. I don't know much about the target API.
>
> If nobody else looks after a decent interval, ping me and I will ok it.
> I suppose if these methods parallel the existing tfile target, then that
> is pretty good evidence for it being ok.
Most of them are copied from tfile target, and I'll examine them (in
both tfile target and ctf target) one by one. I'll give an updated
version tomorrow.
--
Yao (é½å°§)
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 03/15] Read CTF by the ctf target
2013-03-14 13:23 ` Yao Qi
@ 2013-03-14 14:59 ` Tom Tromey
0 siblings, 0 replies; 60+ messages in thread
From: Tom Tromey @ 2013-03-14 14:59 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes:
Yao> It works if we only give --with-babeltrace-include and
Yao> --with-babeltrace-lib (without giving --with-babeltrace). In this
Yao> case, $with_babeltrace is empty, and the condition above is still
Yao> true. I tried to configure with
Yao> --with-babeltrace-include=/usr/include and
Yao> --with-babeltrace-lib=/usr/lib, everything looks OK.
That skips the checks for the bad version of libbabeltrace.
Tom
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v3 03/15] Read CTF by the ctf target
2013-03-13 20:09 ` Tom Tromey
2013-03-14 13:23 ` Yao Qi
@ 2013-03-14 16:57 ` Doug Evans
2013-03-14 17:39 ` Doug Evans
1 sibling, 1 reply; 60+ messages in thread
From: Doug Evans @ 2013-03-14 16:57 UTC (permalink / raw)
To: Tom Tromey; +Cc: Yao Qi, gdb-patches
On Wed, Mar 13, 2013 at 1:08 PM, Tom Tromey <tromey@redhat.com> wrote:
>>>>>> "Yao" == Yao Qi <yao@codesourcery.com> writes:
>
> Yao> +AC_ARG_WITH(babeltrace,
> Yao> + AC_HELP_STRING([--with-babeltrace],
> Yao> + [Specify prefix directory for the installed
> Yao> + BABELTRACE package Equivalent to
> Yao> + --with-babeltrace-include=PATH/include
> Yao> + plus --with-babeltrace-lib=PATH/lib]))
>
> I think this is missing a period and a space between "package" and
> "Equivalent", but see below.
>
> Yao> +if test "x$with_bt_include" != x; then
> Yao> + LIBBABELTRACE_CFLAGS="-I$with_bt_include "
> Yao> +fi
> Yao> +if test "x$with_bt_lib" != x; then
> Yao> + LIBBABELTRACE="-L$with_bt_lib -lbabeltrace -lbabeltrace-ctf"
> Yao> +fi
> Yao> +
> Yao> +if test "x$with_babeltrace" != "xno"; then
>
> This only checks for libbabeltrace if --with-babeltrace is specified.
> So, the text above about equivalency isn't really correct, at least the
> way I read it; if you want to give --with-babeltrace-include, you have
> to also give --with-babeltrace.
>
> I'm not sure how to reword the above to make it more clear.
> Perhaps spelling out the options.
Is there a compelling need for with-babeltrace-{include,lib}?
We don't have with-expat-{include,lib} for example.
I think we should punt on them for now if there's no real need for them.
> Unfortunately for you there is plenty of this patch I don't feel
> competent to review. I don't know much about the target API.
>
> If nobody else looks after a decent interval, ping me and I will ok it.
> I suppose if these methods parallel the existing tfile target, then that
> is pretty good evidence for it being ok.
The nice thing here is that I don't mind of the implementation isn't
100% perfect.
[We're not adding something to an API for example.]
It looks good enough to me (and in such areas I like giving people
some freedom).
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 03/15] Read CTF by the ctf target
2013-03-14 16:57 ` Doug Evans
@ 2013-03-14 17:39 ` Doug Evans
2013-03-25 13:33 ` Yao Qi
0 siblings, 1 reply; 60+ messages in thread
From: Doug Evans @ 2013-03-14 17:39 UTC (permalink / raw)
To: Tom Tromey, Yao Qi; +Cc: gdb-patches
Doug Evans writes:
> Is there a compelling need for with-babeltrace-{include,lib}?
> We don't have with-expat-{include,lib} for example.
> I think we should punt on them for now if there's no real need for them.
Running ./configure --help I see expat provides a different means
for specifying the location.
--with-expat include expat support (auto/yes/no)
--with-libexpat-prefix[=DIR] search for libexpat in DIR/include and DIR/lib
--without-libexpat-prefix don't search for libexpat in includedir and libdir
Ideally we should be consistent.
IIUC, expat support does this:
AC_LIB_HAVE_LINKFLAGS([expat], [], [#include "expat.h"],
[XML_Parser p = XML_ParserCreate (0);])
and that drags in the rest of the support from src/config/lib*.m4.
[One needn't necessarily do the same thing, but I think the end result,
as far as configure options goes, should be the same.]
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 03/15] Read CTF by the ctf target
2013-03-14 17:39 ` Doug Evans
@ 2013-03-25 13:33 ` Yao Qi
2013-03-25 17:14 ` Doug Evans
0 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-25 13:33 UTC (permalink / raw)
To: Doug Evans; +Cc: Tom Tromey, gdb-patches
On 03/15/2013 01:39 AM, Doug Evans wrote:
> Running ./configure --help I see expat provides a different means
> for specifying the location.
>
> --with-expat include expat support (auto/yes/no)
> --with-libexpat-prefix[=DIR] search for libexpat in DIR/include and DIR/lib
> --without-libexpat-prefix don't search for libexpat in includedir and libdir
>
> Ideally we should be consistent.
>
> IIUC, expat support does this:
>
> AC_LIB_HAVE_LINKFLAGS([expat], [], [#include "expat.h"],
> [XML_Parser p = XML_ParserCreate (0);])
Doug and Tom,
I start to use AC_LIB_HAVE_LINKFLAGS in the new patch below, and the
'configure --help' is like this:
--with-babeltrace include babeltrace support (auto/yes/no)
--with-libbabeltrace-prefix[=DIR] search for libbabeltrace in DIR/include and DIR/lib
--without-libbabeltrace-prefix don't search for libbabeltrace in includedir and libdir
This version also includes several changes compared with the last one:
- Update ctf_close because of the change in 'to_close' field of
'struct target_ops'.
- Don't expose some variables out of tracepoint.c. Add and use
functions to access them.
- Remove some unnecessary target_ops hooks.
I also test this patch with babeltrace 1.1.0 release which was released
yesterday. Test looks right. I also build GDB with mingw32 and mingw-w64
cross gcc. Is it OK?
--
Yao (é½å°§)
gdb:
2013-03-25 Hui Zhu <hui@codesourcery.com>
Yao Qi <yao@codesourcery.com>
* configure.ac: Check libbabeltrace is installed.
* config.in: Regenerate.
* configure: Regenerate.
* Makefile.in (LIBBABELTRACE): New.
(CLIBS): Add LIBBABELTRACE.
* ctf.c (ctx, ctf_iter, trace_dirname): New.
(ctf_destroy, ctf_open_dir, ctf_open): New.
(ctf_close, ctf_files_info): New.
(ctf_fetch_registers, ctf_xfer_partial): New.
(ctf_get_trace_state_variable_value): New.
(ctf_get_tpnum_from_frame_event): New.
(ctf_get_traceframe_address): New.
(ctf_trace_find, ctf_has_stack): New.
(ctf_has_registers, ctf_traceframe_info, init_ctf_ops): New.
(_initialize_ctf): New.
* tracepoint.c (get_tracepoint_number): New
(struct traceframe_info, trace_regblock_size): Move it to ...
* tracepoint.h: ... here.
(get_tracepoint_number): Declare it.
---
gdb/Makefile.in | 6 +-
gdb/config.in | 3 +
gdb/configure | 535 +++++++++++++++++++++++++++++++++++++++
gdb/configure.ac | 41 +++
gdb/ctf.c | 743 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/tracepoint.c | 16 +-
gdb/tracepoint.h | 13 +
7 files changed, 1346 insertions(+), 11 deletions(-)
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9bab01c..f474897 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -154,6 +154,10 @@ LIBEXPAT = @LIBEXPAT@
# Where is lzma? This will be empty if lzma was not available.
LIBLZMA = @LIBLZMA@
+# Where is libbabeltrace? This will be empty if lbabeltrace was not
+# available.
+LIBBABELTRACE = @LIBBABELTRACE@
+
WARN_CFLAGS = @WARN_CFLAGS@
WERROR_CFLAGS = @WERROR_CFLAGS@
GDB_WARN_CFLAGS = $(WARN_CFLAGS)
@@ -475,7 +479,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_
# LIBIBERTY appears twice on purpose.
CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
$(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ @PYTHON_LIBS@ \
- $(LIBEXPAT) $(LIBLZMA) \
+ $(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) \
$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU)
CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
diff --git a/gdb/config.in b/gdb/config.in
index 9e21325..c4e8eaa 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -180,6 +180,9 @@
/* Define if your <locale.h> file defines LC_MESSAGES. */
#undef HAVE_LC_MESSAGES
+/* Define if libbabeltrace is available */
+#undef HAVE_LIBBABELTRACE
+
/* Define to 1 if you have the `dl' library (-ldl). */
#undef HAVE_LIBDL
diff --git a/gdb/configure b/gdb/configure
index 0dd67f0..db4c023 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -592,6 +592,9 @@ enable_option_checking=no
ac_subst_vars='LTLIBOBJS
LIBOBJS
GDB_NM_FILE
+LTLIBBABELTRACE
+LIBBABELTRACE
+HAVE_LIBBABELTRACE
frags
target_subdir
CONFIG_UNINSTALL
@@ -819,6 +822,8 @@ with_x
enable_sim
enable_multi_ice
enable_gdbserver
+with_babeltrace
+with_libbabeltrace_prefix
'
ac_precious_vars='build_alias
host_alias
@@ -1532,6 +1537,9 @@ Optional Packages:
--with-tcl directory containing tcl configuration (tclConfig.sh)
--with-tk directory containing tk configuration (tkConfig.sh)
--with-x use the X Window System
+ --with-babeltrace include babeltrace support (auto/yes/no)
+ --with-libbabeltrace-prefix[=DIR] search for libbabeltrace in DIR/include and DIR/lib
+ --without-libbabeltrace-prefix don't search for libbabeltrace in includedir and libdir
Some influential environment variables:
CC C compiler command
@@ -14093,6 +14101,533 @@ if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then
as_fn_error "Automatic gdbserver build is not supported for this configuration" "$LINENO" 5
fi
+# Check for babeltrace and babeltrace-ctf
+
+# Check whether --with-babeltrace was given.
+if test "${with_babeltrace+set}" = set; then :
+ withval=$with_babeltrace;
+else
+ with_babeltrace=auto
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use babeltrace" >&5
+$as_echo_n "checking whether to use babeltrace... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_babeltrace" >&5
+$as_echo "$with_babeltrace" >&6; }
+
+if test "x$with_babeltrace" = "xno"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: babletrace support disabled; GDB is unable to read CTF data." >&5
+$as_echo "$as_me: WARNING: babletrace support disabled; GDB is unable to read CTF data." >&2;}
+else
+
+
+
+
+
+
+
+
+ use_additional=yes
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+
+# Check whether --with-libbabeltrace-prefix was given.
+if test "${with_libbabeltrace_prefix+set}" = set; then :
+ withval=$with_libbabeltrace_prefix;
+ if test "X$withval" = "Xno"; then
+ use_additional=no
+ else
+ if test "X$withval" = "X"; then
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ else
+ additional_includedir="$withval/include"
+ additional_libdir="$withval/lib"
+ fi
+ fi
+
+fi
+
+ LIBBABELTRACE=
+ LTLIBBABELTRACE=
+ INCBABELTRACE=
+ rpathdirs=
+ ltrpathdirs=
+ names_already_handled=
+ names_next_round='babeltrace babeltrace-ctf'
+ while test -n "$names_next_round"; do
+ names_this_round="$names_next_round"
+ names_next_round=
+ for name in $names_this_round; do
+ already_handled=
+ for n in $names_already_handled; do
+ if test "$n" = "$name"; then
+ already_handled=yes
+ break
+ fi
+ done
+ if test -z "$already_handled"; then
+ names_already_handled="$names_already_handled $name"
+ uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+ eval value=\"\$HAVE_LIB$uppername\"
+ if test -n "$value"; then
+ if test "$value" = yes; then
+ eval value=\"\$LIB$uppername\"
+ test -z "$value" || LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$value"
+ eval value=\"\$LTLIB$uppername\"
+ test -z "$value" || LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }$value"
+ else
+ :
+ fi
+ else
+ found_dir=
+ found_la=
+ found_so=
+ found_a=
+ if test $use_additional = yes; then
+ if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then
+ found_dir="$additional_libdir"
+ found_so="$additional_libdir/lib$name.$shlibext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ else
+ if test -f "$additional_libdir/lib$name.$libext"; then
+ found_dir="$additional_libdir"
+ found_a="$additional_libdir/lib$name.$libext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ fi
+ fi
+ fi
+ if test "X$found_dir" = "X"; then
+ for x in $LDFLAGS $LTLIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ case "$x" in
+ -L*)
+ dir=`echo "X$x" | sed -e 's/^X-L//'`
+ if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then
+ found_dir="$dir"
+ found_so="$dir/lib$name.$shlibext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ else
+ if test -f "$dir/lib$name.$libext"; then
+ found_dir="$dir"
+ found_a="$dir/lib$name.$libext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ if test "X$found_dir" != "X"; then
+ break
+ fi
+ done
+ fi
+ if test "X$found_dir" != "X"; then
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-L$found_dir -l$name"
+ if test "X$found_so" != "X"; then
+ if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ else
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $found_dir"
+ fi
+ if test "$hardcode_direct" = yes; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ else
+ if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $found_dir"
+ fi
+ else
+ haveit=
+ for x in $LDFLAGS $LIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$found_dir"
+ fi
+ if test "$hardcode_minus_L" != no; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ else
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-l$name"
+ fi
+ fi
+ fi
+ fi
+ else
+ if test "X$found_a" != "X"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_a"
+ else
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$found_dir -l$name"
+ fi
+ fi
+ additional_includedir=
+ case "$found_dir" in
+ */lib | */lib/)
+ basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'`
+ additional_includedir="$basedir/include"
+ ;;
+ esac
+ if test "X$additional_includedir" != "X"; then
+ if test "X$additional_includedir" != "X/usr/include"; then
+ haveit=
+ if test "X$additional_includedir" = "X/usr/local/include"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ for x in $CPPFLAGS $INCBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-I$additional_includedir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_includedir"; then
+ INCBABELTRACE="${INCBABELTRACE}${INCBABELTRACE:+ }-I$additional_includedir"
+ fi
+ fi
+ fi
+ fi
+ fi
+ if test -n "$found_la"; then
+ save_libdir="$libdir"
+ case "$found_la" in
+ */* | *\\*) . "$found_la" ;;
+ *) . "./$found_la" ;;
+ esac
+ libdir="$save_libdir"
+ for dep in $dependency_libs; do
+ case "$dep" in
+ -L*)
+ additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+ if test "X$additional_libdir" != "X/usr/lib"; then
+ haveit=
+ if test "X$additional_libdir" = "X/usr/local/lib"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ haveit=
+ for x in $LDFLAGS $LIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$additional_libdir"
+ fi
+ fi
+ haveit=
+ for x in $LDFLAGS $LTLIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-L$additional_libdir"
+ fi
+ fi
+ fi
+ fi
+ ;;
+ -R*)
+ dir=`echo "X$dep" | sed -e 's/^X-R//'`
+ if test "$enable_rpath" != no; then
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $dir"
+ fi
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $dir"
+ fi
+ fi
+ ;;
+ -l*)
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+ ;;
+ *.la)
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+ ;;
+ *)
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$dep"
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }$dep"
+ ;;
+ esac
+ done
+ fi
+ else
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-l$name"
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-l$name"
+ fi
+ fi
+ fi
+ done
+ done
+ if test "X$rpathdirs" != "X"; then
+ if test -n "$hardcode_libdir_separator"; then
+ alldirs=
+ for found_dir in $rpathdirs; do
+ alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+ done
+ acl_save_libdir="$libdir"
+ libdir="$alldirs"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$flag"
+ else
+ for found_dir in $rpathdirs; do
+ acl_save_libdir="$libdir"
+ libdir="$found_dir"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$flag"
+ done
+ fi
+ fi
+ if test "X$ltrpathdirs" != "X"; then
+ for found_dir in $ltrpathdirs; do
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-R$found_dir"
+ done
+ fi
+
+
+ ac_save_CPPFLAGS="$CPPFLAGS"
+
+ for element in $INCBABELTRACE; do
+ haveit=
+ for x in $CPPFLAGS; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X$element"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element"
+ fi
+ done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libbabeltrace" >&5
+$as_echo_n "checking for libbabeltrace... " >&6; }
+if test "${ac_cv_libbabeltrace+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ac_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIBBABELTRACE"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <babeltrace/babeltrace.h>
+ #include <babeltrace/ctf/events.h>
+ #include <babeltrace/ctf/iterator.h>
+int
+main ()
+{
+struct bt_iter_pos *pos = bt_iter_get_pos (bt_ctf_get_iter (NULL));
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_libbabeltrace=yes
+else
+ ac_cv_libbabeltrace=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$ac_save_LIBS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libbabeltrace" >&5
+$as_echo "$ac_cv_libbabeltrace" >&6; }
+ if test "$ac_cv_libbabeltrace" = yes; then
+ HAVE_LIBBABELTRACE=yes
+
+$as_echo "#define HAVE_LIBBABELTRACE 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libbabeltrace" >&5
+$as_echo_n "checking how to link with libbabeltrace... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBBABELTRACE" >&5
+$as_echo "$LIBBABELTRACE" >&6; }
+ else
+ HAVE_LIBBABELTRACE=no
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIBBABELTRACE=
+ LTLIBBABELTRACE=
+ fi
+
+
+
+
+
+
+
+ if test "$HAVE_LIBBABELTRACE" != yes; then
+ if test "$wit_babeltrace" = yes; then
+ as_fn_error "babeltrace is missing or unusable" "$LINENO" 5
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: babeltrace is missing or unusable; GDB is unable to read CTF data." >&5
+$as_echo "$as_me: WARNING: babeltrace is missing or unusable; GDB is unable to read CTF data." >&2;}
+ fi
+ else
+ # Check whether there is a function named 'lookup_enum' in
+ # babeltrace library. We can't use the babeltrace library
+ # in which function 'lookup_enum' is defined. This function
+ # is renamed to 'bt_lookup_enum' in recent babeltrace.
+ saved_LIBS=$LIBS
+ LIBS="$LIBS $LIBBABELTRACE"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for broken babeltrace" >&5
+$as_echo_n "checking for broken babeltrace... " >&6; }
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+lookup_enum (NULL, NULL, 0)
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; };
+$as_echo "#define HAVE_LIBBABELTRACE 0" >>confdefs.h
+
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+
+ LIBS=$save_LIBS
+ fi
+fi
+
# If nativefile (NAT_FILE) is not set in config/*/*.m[ht] files, we link
# to an empty version.
diff --git a/gdb/configure.ac b/gdb/configure.ac
index c17f587..874294b 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -2321,6 +2321,47 @@ if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then
AC_MSG_ERROR(Automatic gdbserver build is not supported for this configuration)
fi
+# Check for babeltrace and babeltrace-ctf
+AC_ARG_WITH(babeltrace,
+ AC_HELP_STRING([--with-babeltrace], [include babeltrace support (auto/yes/no)]),
+ [], [with_babeltrace=auto])
+AC_MSG_CHECKING([whether to use babeltrace])
+AC_MSG_RESULT([$with_babeltrace])
+
+if test "x$with_babeltrace" = "xno"; then
+ AC_MSG_WARN([babletrace support disabled; GDB is unable to read CTF data.])
+else
+ AC_LIB_HAVE_LINKFLAGS([babeltrace], [babeltrace-ctf],
+ [#include <babeltrace/babeltrace.h>
+ #include <babeltrace/ctf/events.h>
+ #include <babeltrace/ctf/iterator.h>],
+ [struct bt_iter_pos *pos = bt_iter_get_pos (bt_ctf_get_iter (NULL));])
+
+ if test "$HAVE_LIBBABELTRACE" != yes; then
+ if test "$wit_babeltrace" = yes; then
+ AC_MSG_ERROR([babeltrace is missing or unusable])
+ else
+ AC_MSG_WARN([babeltrace is missing or unusable; GDB is unable to read CTF data.])
+ fi
+ else
+ # Check whether there is a function named 'lookup_enum' in
+ # babeltrace library. We can't use the babeltrace library
+ # in which function 'lookup_enum' is defined. This function
+ # is renamed to 'bt_lookup_enum' in recent babeltrace.
+ saved_LIBS=$LIBS
+ LIBS="$LIBS $LIBBABELTRACE"
+
+ AC_MSG_CHECKING([for broken babeltrace])
+ AC_TRY_LINK([#include <stdio.h>],
+ [lookup_enum (NULL, NULL, 0)],
+ [AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_LIBBABELTRACE, 0,
+ [Define if libbabeltrace is available])],
+ [AC_MSG_RESULT([no])])
+
+ LIBS=$save_LIBS
+ fi
+fi
+
# If nativefile (NAT_FILE) is not set in config/*/*.m[ht] files, we link
# to an empty version.
diff --git a/gdb/ctf.c b/gdb/ctf.c
index 6b55986..99a7fef 100644
--- a/gdb/ctf.c
+++ b/gdb/ctf.c
@@ -24,6 +24,7 @@
#include "tracepoint.h"
#include "regcache.h"
#include "gdb_stat.h"
+#include "exec.h"
#include <ctype.h>
@@ -669,3 +670,745 @@ ctf_trace_file_writer_new (void)
return (struct trace_file_writer *) writer;
}
+
+#if HAVE_LIBBABELTRACE
+/* Use libbabeltrace to read CTF data. The libbabeltrace provides
+ iterator to iterate over each event in CTF data and APIs to get
+ details of event and packet, so it is very convenient to use
+ libbabeltrace to access events in CTF. */
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/iterator.h>
+
+/* The struct pointer for current CTF directory. */
+static struct bt_context *ctx = NULL;
+static struct bt_ctf_iter *ctf_iter = NULL;
+/* The name of CTF directory. */
+static char *trace_dirname;
+
+static struct target_ops ctf_ops;
+
+/* Destroy ctf iterator and context. */
+
+static void
+ctf_destroy (void)
+{
+ if (ctf_iter != NULL)
+ {
+ bt_ctf_iter_destroy (ctf_iter);
+ ctf_iter = NULL;
+ }
+ if (ctx != NULL)
+ {
+ bt_context_put (ctx);
+ ctx = NULL;
+ }
+}
+
+/* Open CTF trace data in DIRNAME. */
+
+static void
+ctf_open_dir (char *dirname)
+{
+ int ret;
+ struct bt_iter_pos begin_pos;
+ struct bt_iter_pos *pos;
+
+ ctx = bt_context_create ();
+ if (ctx == NULL)
+ error (_("Unable to initialize libbabeltrace"));
+ ret = bt_context_add_trace (ctx, dirname, "ctf", NULL, NULL, NULL);
+ if (ret < 0)
+ {
+ ctf_destroy ();
+ error (_("Unable to use libbabeltrace open \"%s\""), dirname);
+ }
+
+ begin_pos.type = BT_SEEK_BEGIN;
+ ctf_iter = bt_ctf_iter_create (ctx, &begin_pos, NULL);
+ if (ctf_iter == NULL)
+ {
+ ctf_destroy ();
+ error (_("Unable to use libbabeltrace open \"%s\""), dirname);
+ }
+
+ /* Iterate over events, and look for an event for register block
+ to set trace_regblock_size. */
+
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event;
+
+ event = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (name == NULL)
+ break;
+ else if (strcmp (name, "register") == 0)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+
+ trace_regblock_size
+ = bt_ctf_get_array_len (bt_ctf_get_decl_from_def (array));
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+}
+
+/* This is the implementation of target_ops method to_open. Open CTF
+ trace data, read trace status, trace state variables and tracepoint
+ definitions from the first packet. Set the start position at the
+ second packet which contains events on trace blocks. */
+
+static void
+ctf_open (char *dirname, int from_tty)
+{
+ target_preopen (from_tty);
+ if (!dirname)
+ error (_("No CTF directory specified."));
+
+ ctf_open_dir (dirname);
+
+ trace_dirname = xstrdup (dirname);
+ push_target (&ctf_ops);
+}
+
+/* This is the implementation of target_ops method to_close. Destroy
+ CTF iterator and context. */
+
+static void
+ctf_close (void)
+{
+ ctf_destroy ();
+ xfree (trace_dirname);
+ trace_dirname = NULL;
+}
+
+/* This is the implementation of target_ops method to_files_info.
+ Print the directory name of CTF trace data. */
+
+static void
+ctf_files_info (struct target_ops *t)
+{
+ printf_filtered ("\t`%s'\n", trace_dirname);
+}
+
+/* This is the implementation of target_ops method to_fetch_registers.
+ Iterate over events whose name is "register" in current frame,
+ extract contents from events, and set REGCACHE with the contents.
+ If no matched events are found, mark registers unavailable. */
+
+static void
+ctf_fetch_registers (struct target_ops *ops,
+ struct regcache *regcache, int regno)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ int offset, regn, regsize, pc_regno;
+ char *regs = NULL;
+ struct bt_ctf_event *event = NULL;
+ struct bt_iter_pos *pos;
+
+ /* An uninitialized reg size says we're not going to be
+ successful at getting register blocks. */
+ if (trace_regblock_size == 0)
+ return;
+
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event1;
+
+ event1 = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event1);
+
+ if (name == NULL || strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "register") == 0)
+ {
+ event = event1;
+ break;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ if (event != NULL)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+
+ regs = bt_ctf_get_char_array (array);
+ /* Assume the block is laid out in GDB register number order,
+ each register with the size that it has in GDB. */
+ offset = 0;
+ for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+ {
+ regsize = register_size (gdbarch, regn);
+ /* Make sure we stay within block bounds. */
+ if (offset + regsize >= trace_regblock_size)
+ break;
+ if (regcache_register_status (regcache, regn) == REG_UNKNOWN)
+ {
+ if (regno == regn)
+ {
+ regcache_raw_supply (regcache, regno, regs + offset);
+ break;
+ }
+ else if (regno == -1)
+ {
+ regcache_raw_supply (regcache, regn, regs + offset);
+ }
+ }
+ offset += regsize;
+ }
+ return;
+ }
+
+ regs = alloca (trace_regblock_size);
+
+ /* We get here if no register data has been found. Mark registers
+ as unavailable. */
+ for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+ regcache_raw_supply (regcache, regn, NULL);
+
+ /* We can often usefully guess that the PC is going to be the same
+ as the address of the tracepoint. */
+ pc_regno = gdbarch_pc_regnum (gdbarch);
+ if (pc_regno >= 0 && (regno == -1 || regno == pc_regno))
+ {
+ struct tracepoint *tp = get_tracepoint (get_tracepoint_number ());
+
+ if (tp != NULL && tp->base.loc)
+ {
+ /* But don't try to guess if tracepoint is multi-location... */
+ if (tp->base.loc->next != NULL)
+ {
+ warning (_("Tracepoint %d has multiple "
+ "locations, cannot infer $pc"),
+ tp->base.number);
+ return;
+ }
+ /* ... or does while-stepping. */
+ if (tp->step_count > 0)
+ {
+ warning (_("Tracepoint %d does while-stepping, "
+ "cannot infer $pc"),
+ tp->base.number);
+ return;
+ }
+
+ store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
+ gdbarch_byte_order (gdbarch),
+ tp->base.loc->address);
+ regcache_raw_supply (regcache, pc_regno, regs);
+ }
+ }
+}
+
+/* This is the implementation of target_ops method to_xfer_partial.
+ Iterate over events whose name is "memory" in
+ current frame, extract the address and length from events. If
+ OFFSET is within the range, read the contents from events to
+ READBUF. */
+
+static LONGEST
+ctf_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf, ULONGEST offset,
+ LONGEST len)
+{
+ /* We're only doing regular memory for now. */
+ if (object != TARGET_OBJECT_MEMORY)
+ return -1;
+
+ if (readbuf == NULL)
+ error (_("ctf_xfer_partial: trace file is read-only"));
+
+ if (get_traceframe_number () != -1)
+ {
+ struct bt_iter_pos *pos;
+ int i = 0;
+
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ /* Iterate through the traceframe's blocks, looking for
+ memory. */
+ while (1)
+ {
+ ULONGEST maddr, amt;
+ uint16_t mlen;
+ enum bfd_endian byte_order
+ = gdbarch_byte_order (target_gdbarch ());
+ const struct bt_definition *scope;
+ const struct bt_definition *def;
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+ const char *name = bt_ctf_event_name (event);
+
+ if (strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "memory") != 0)
+ {
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+
+ continue;
+ }
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+
+ def = bt_ctf_get_field (event, scope, "address");
+ maddr = bt_ctf_get_uint64 (def);
+ def = bt_ctf_get_field (event, scope, "length");
+ mlen = (uint16_t) bt_ctf_get_uint64 (def);
+
+ /* If the block includes the first part of the desired
+ range, return as much it has; GDB will re-request the
+ remainder, which might be in a different block of this
+ trace frame. */
+ if (maddr <= offset && offset < (maddr + mlen))
+ {
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+ const struct bt_declaration *decl
+ = bt_ctf_get_decl_from_def (array);
+ gdb_byte *contents;
+ int k;
+
+ contents = xmalloc (mlen);
+
+ for (k = 0; k < mlen; k++)
+ {
+ const struct bt_definition *element
+ = bt_ctf_get_index (event, array, k);
+
+ contents[k] = (gdb_byte) bt_ctf_get_uint64 (element);
+ }
+
+ amt = (maddr + mlen) - offset;
+ if (amt > len)
+ amt = len;
+
+ memcpy (readbuf, &contents[offset - maddr], amt);
+
+ xfree (contents);
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return amt;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+ }
+
+ /* It's unduly pedantic to refuse to look at the executable for
+ read-only pieces; so do the equivalent of readonly regions aka
+ QTro packet. */
+ if (exec_bfd != NULL)
+ {
+ asection *s;
+ bfd_size_type size;
+ bfd_vma vma;
+
+ for (s = exec_bfd->sections; s; s = s->next)
+ {
+ if ((s->flags & SEC_LOAD) == 0
+ || (s->flags & SEC_READONLY) == 0)
+ continue;
+
+ vma = s->vma;
+ size = bfd_get_section_size (s);
+ if (vma <= offset && offset < (vma + size))
+ {
+ ULONGEST amt;
+
+ amt = (vma + size) - offset;
+ if (amt > len)
+ amt = len;
+
+ amt = bfd_get_section_contents (exec_bfd, s,
+ readbuf, offset - vma, amt);
+ return amt;
+ }
+ }
+ }
+
+ /* Indicate failure to find the requested memory block. */
+ return -1;
+}
+
+/* This is the implementation of target_ops method
+ to_get_trace_state_variable_value.
+ Iterate over events whose name is "tsv" in current frame. When the
+ trace variable is found, set the value of it to *VAL and return
+ true, otherwise return false. */
+
+static int
+ctf_get_trace_state_variable_value (int tsvnum, LONGEST *val)
+{
+ struct bt_iter_pos *pos;
+ int found = 0;
+
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ /* Iterate through the traceframe's blocks, looking for 'V'
+ block. */
+ while (1)
+ {
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+ const char *name = bt_ctf_event_name (event);
+
+ if (name == NULL || strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "tsv") == 0)
+ {
+ const struct bt_definition *scope;
+ const struct bt_definition *def;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+
+ def = bt_ctf_get_field (event, scope, "num");
+ if (tsvnum == (int32_t) bt_ctf_get_uint64 (def))
+ {
+ def = bt_ctf_get_field (event, scope, "val");
+ *val = bt_ctf_get_uint64 (def);
+
+ found = 1;
+ }
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return found;
+}
+
+/* Return the tracepoint number in "frame" event. */
+
+static int
+ctf_get_tpnum_from_frame_event (struct bt_ctf_event *event)
+{
+ /* The packet context of events has a field "tpnum". */
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event, BT_STREAM_PACKET_CONTEXT);
+ uint64_t tpnum
+ = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "tpnum"));
+
+ return (int) tpnum;
+}
+
+/* Return the address at which the current frame was collected. */
+
+static ULONGEST
+ctf_get_traceframe_address (void)
+{
+ struct bt_ctf_event *event = NULL;
+ struct bt_iter_pos *pos
+ = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ ULONGEST addr = 0;
+
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event1;
+
+ event1 = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event1);
+
+ if (name == NULL)
+ break;
+ else if (strcmp (name, "frame") == 0)
+ {
+ event = event1;
+ break;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ if (event != NULL)
+ {
+ int tpnum = ctf_get_tpnum_from_frame_event (event);
+ struct tracepoint *tp
+ = get_tracepoint_by_number_on_target (tpnum);
+
+ if (tp && tp->base.loc)
+ addr = tp->base.loc->address;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return addr;
+}
+
+/* This is the implementation of target_ops method to_trace_find.
+ Iterate the events whose name is "frame", extract the tracepoint
+ number in it. Return traceframe number when matched. */
+
+static int
+ctf_trace_find (enum trace_find_type type, int num,
+ ULONGEST addr1, ULONGEST addr2, int *tpp)
+{
+ int ret = -1;
+ int tfnum = 0;
+ int found = 0;
+ struct bt_iter_pos pos;
+
+ if (num == -1)
+ {
+ if (tpp != NULL)
+ *tpp = -1;
+ return -1;
+ }
+
+ /* Set iterator back to the beginning. */
+ pos.type = BT_SEEK_BEGIN;
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), &pos);
+
+ while (1)
+ {
+ int id;
+ struct bt_ctf_event *event;
+ const char *name;
+
+ event = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (event == NULL || name == NULL)
+ return -1;
+
+ if (strcmp (name, "frame") == 0)
+ {
+ ULONGEST tfaddr;
+
+ if (type == tfind_number)
+ {
+ /* Looking for a specific trace frame. */
+ if (tfnum == num)
+ found = 1;
+ }
+ else
+ {
+ /* Start from the _next_ trace frame. */
+ if (tfnum > get_traceframe_number ())
+ {
+ switch (type)
+ {
+ case tfind_tp:
+ {
+ struct tracepoint *tp = get_tracepoint (num);
+
+ if (tp != NULL
+ && (tp->number_on_target
+ == ctf_get_tpnum_from_frame_event (event)))
+ found = 1;
+ break;
+ }
+ case tfind_pc:
+ tfaddr = ctf_get_traceframe_address ();
+ if (tfaddr == addr1)
+ found = 1;
+ break;
+ case tfind_range:
+ tfaddr = ctf_get_traceframe_address ();
+ if (addr1 <= tfaddr && tfaddr <= addr2)
+ found = 1;
+ break;
+ case tfind_outside:
+ tfaddr = ctf_get_traceframe_address ();
+ if (!(addr1 <= tfaddr && tfaddr <= addr2))
+ found = 1;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, _("unknown tfind type"));
+ }
+ }
+ }
+ if (found)
+ {
+ if (tpp != NULL)
+ *tpp = ctf_get_tpnum_from_frame_event (event);
+
+ /* Skip the event "frame". */
+ bt_iter_next (bt_ctf_get_iter (ctf_iter));
+
+ return tfnum;
+ }
+ tfnum++;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ return -1;
+ }
+
+ return -1;
+}
+
+/* This is the implementation of target_ops method to_has_stack.
+ The target has a stack when GDB has already selected one trace
+ frame. */
+
+static int
+ctf_has_stack (struct target_ops *ops)
+{
+ return get_traceframe_number () != -1;
+}
+
+/* This is the implementation of target_ops method to_has_registers.
+ The target has registers when GDB has already selected one trace
+ frame. */
+
+static int
+ctf_has_registers (struct target_ops *ops)
+{
+ return get_traceframe_number () != -1;
+}
+
+/* This is the implementation of target_ops method to_traceframe_info.
+ Iterate the events whose name is "memory", in current
+ frame, extract memory range information, and return them in
+ traceframe_info. */
+
+static struct traceframe_info *
+ctf_traceframe_info (void)
+{
+ struct traceframe_info *info = XCNEW (struct traceframe_info);
+ const char *name;
+ struct bt_iter_pos *pos;
+
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ do
+ {
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (name == NULL || strcmp (name, "register") == 0
+ || strcmp (name, "frame") == 0)
+ ;
+ else if (strcmp (name, "memory") == 0)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *def;
+ struct mem_range *r;
+
+ r = VEC_safe_push (mem_range_s, info->memory, NULL);
+ def = bt_ctf_get_field (event, scope, "address");
+ r->start = bt_ctf_get_uint64 (def);
+
+ def = bt_ctf_get_field (event, scope, "length");
+ r->length = (uint16_t) bt_ctf_get_uint64 (def);
+ }
+ else
+ warning (_("Unhandled trace block type (%s) "
+ "while building trace frame info."),
+ name);
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+ while (name != NULL && strcmp (name, "frame") != 0);
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return info;
+}
+
+static void
+init_ctf_ops (void)
+{
+ memset (&ctf_ops, 0, sizeof (ctf_ops));
+
+ ctf_ops.to_shortname = "ctf";
+ ctf_ops.to_longname = "CTF file";
+ ctf_ops.to_doc = "Use a CTF directory as a target.\n\
+Specify the filename of the CTF directory.";
+ ctf_ops.to_open = ctf_open;
+ ctf_ops.to_close = ctf_close;
+ ctf_ops.to_fetch_registers = ctf_fetch_registers;
+ ctf_ops.to_xfer_partial = ctf_xfer_partial;
+ ctf_ops.to_files_info = ctf_files_info;
+ ctf_ops.to_trace_find = ctf_trace_find;
+ ctf_ops.to_get_trace_state_variable_value
+ = ctf_get_trace_state_variable_value;
+ ctf_ops.to_stratum = process_stratum;
+ ctf_ops.to_has_stack = ctf_has_stack;
+ ctf_ops.to_has_registers = ctf_has_registers;
+ ctf_ops.to_traceframe_info = ctf_traceframe_info;
+ ctf_ops.to_magic = OPS_MAGIC;
+}
+
+#endif
+
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_ctf;
+
+/* module initialization */
+void
+_initialize_ctf (void)
+{
+#if HAVE_LIBBABELTRACE
+ init_ctf_ops ();
+
+ add_target (&ctf_ops);
+#endif
+}
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 9a2425b..6a30f6f 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -126,14 +126,6 @@ extern void (*deprecated_readline_end_hook) (void);
typedef struct trace_state_variable tsv_s;
DEF_VEC_O(tsv_s);
-/* An object describing the contents of a traceframe. */
-
-struct traceframe_info
-{
- /* Collected memory. */
- VEC(mem_range_s) *memory;
-};
-
static VEC(tsv_s) *tvariables;
/* The next integer to assign to a variable. */
@@ -3302,8 +3294,6 @@ static const struct trace_file_write_ops tfile_write_ops =
#define TRACE_WRITE_V_BLOCK(writer, num, val) \
writer->ops->frame_ops->write_v_block ((writer), (num), (val))
-extern int trace_regblock_size;
-
/* Save tracepoint data to file named FILENAME through WRITER. WRITER
determines the trace file format. If TARGET_DOES_SAVE is non-zero,
the save is performed on the target, otherwise GDB obtains all trace
@@ -3740,6 +3730,12 @@ get_traceframe_number (void)
return traceframe_number;
}
+int
+get_tracepoint_number (void)
+{
+ return tracepoint_number;
+}
+
/* Make the traceframe NUM be the current trace frame. Does nothing
if NUM is already current. */
diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
index c7eef7b..bad8d49 100644
--- a/gdb/tracepoint.h
+++ b/gdb/tracepoint.h
@@ -24,6 +24,14 @@
#include "memrange.h"
#include "gdb_vecs.h"
+/* An object describing the contents of a traceframe. */
+
+struct traceframe_info
+{
+ /* Collected memory. */
+ VEC(mem_range_s) *memory;
+};
+
/* A trace state variable is a value managed by a target being
traced. A trace state variable (or tsv for short) can be accessed
and assigned to by tracepoint actions and conditionals, but is not
@@ -142,6 +150,8 @@ struct trace_status *current_trace_status (void);
extern char *default_collect;
+extern int trace_regblock_size;
+
/* Struct to collect random info about tracepoints on the target. */
struct uploaded_tp
@@ -324,6 +334,9 @@ extern void (*deprecated_trace_start_stop_hook) (int start, int from_tty);
/* Returns the current traceframe number. */
extern int get_traceframe_number (void);
+/* Returns the tracepoint number for current traceframe. */
+extern int get_tracepoint_number (void);
+
/* Make the traceframe NUM be the current GDB trace frame number, and
do nothing more. In particular, this does not flush the
register/frame caches or notify the target about the trace frame
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 03/15] Read CTF by the ctf target
2013-03-25 13:33 ` Yao Qi
@ 2013-03-25 17:14 ` Doug Evans
2013-03-26 16:16 ` Yao Qi
0 siblings, 1 reply; 60+ messages in thread
From: Doug Evans @ 2013-03-25 17:14 UTC (permalink / raw)
To: Yao Qi; +Cc: Tom Tromey, gdb-patches
Yao Qi writes:
> I also test this patch with babeltrace 1.1.0 release which was released
> yesterday. Test looks right. I also build GDB with mingw32 and mingw-w64
> cross gcc. Is it OK?
Hi. Getting there.
Just a few comments inline.
> 2013-03-25 Hui Zhu <hui@codesourcery.com>
> Yao Qi <yao@codesourcery.com>
>
> * configure.ac: Check libbabeltrace is installed.
> * config.in: Regenerate.
> * configure: Regenerate.
> * Makefile.in (LIBBABELTRACE): New.
> (CLIBS): Add LIBBABELTRACE.
> * ctf.c (ctx, ctf_iter, trace_dirname): New.
> (ctf_destroy, ctf_open_dir, ctf_open): New.
> (ctf_close, ctf_files_info): New.
> (ctf_fetch_registers, ctf_xfer_partial): New.
> (ctf_get_trace_state_variable_value): New.
> (ctf_get_tpnum_from_frame_event): New.
> (ctf_get_traceframe_address): New.
> (ctf_trace_find, ctf_has_stack): New.
> (ctf_has_registers, ctf_traceframe_info, init_ctf_ops): New.
> (_initialize_ctf): New.
> * tracepoint.c (get_tracepoint_number): New
> (struct traceframe_info, trace_regblock_size): Move it to ...
> * tracepoint.h: ... here.
> (get_tracepoint_number): Declare it.
> ---
> gdb/Makefile.in | 6 +-
> gdb/config.in | 3 +
> gdb/configure | 535 +++++++++++++++++++++++++++++++++++++++
> gdb/configure.ac | 41 +++
> gdb/ctf.c | 743 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> gdb/tracepoint.c | 16 +-
> gdb/tracepoint.h | 13 +
> 7 files changed, 1346 insertions(+), 11 deletions(-)
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 9bab01c..f474897 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -154,6 +154,10 @@ LIBEXPAT = @LIBEXPAT@
> # Where is lzma? This will be empty if lzma was not available.
> LIBLZMA = @LIBLZMA@
>
> +# Where is libbabeltrace? This will be empty if lbabeltrace was not
> +# available.
> +LIBBABELTRACE = @LIBBABELTRACE@
> +
> WARN_CFLAGS = @WARN_CFLAGS@
> WERROR_CFLAGS = @WERROR_CFLAGS@
> GDB_WARN_CFLAGS = $(WARN_CFLAGS)
> @@ -475,7 +479,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_
> # LIBIBERTY appears twice on purpose.
> CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
> $(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ @PYTHON_LIBS@ \
> - $(LIBEXPAT) $(LIBLZMA) \
> + $(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) \
> $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU)
> CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
> $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
> diff --git a/gdb/config.in b/gdb/config.in
> index 9e21325..c4e8eaa 100644
> --- a/gdb/config.in
> +++ b/gdb/config.in
> @@ -180,6 +180,9 @@
> /* Define if your <locale.h> file defines LC_MESSAGES. */
> #undef HAVE_LC_MESSAGES
>
> +/* Define if libbabeltrace is available */
> +#undef HAVE_LIBBABELTRACE
> +
> /* Define to 1 if you have the `dl' library (-ldl). */
> #undef HAVE_LIBDL
>
> [...]
>
> diff --git a/gdb/configure.ac b/gdb/configure.ac
> index c17f587..874294b 100644
> --- a/gdb/configure.ac
> +++ b/gdb/configure.ac
> @@ -2321,6 +2321,47 @@ if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then
> AC_MSG_ERROR(Automatic gdbserver build is not supported for this configuration)
> fi
>
> +# Check for babeltrace and babeltrace-ctf
> +AC_ARG_WITH(babeltrace,
> + AC_HELP_STRING([--with-babeltrace], [include babeltrace support (auto/yes/no)]),
> + [], [with_babeltrace=auto])
> +AC_MSG_CHECKING([whether to use babeltrace])
> +AC_MSG_RESULT([$with_babeltrace])
> +
> +if test "x$with_babeltrace" = "xno"; then
> + AC_MSG_WARN([babletrace support disabled; GDB is unable to read CTF data.])
> +else
> + AC_LIB_HAVE_LINKFLAGS([babeltrace], [babeltrace-ctf],
> + [#include <babeltrace/babeltrace.h>
> + #include <babeltrace/ctf/events.h>
> + #include <babeltrace/ctf/iterator.h>],
> + [struct bt_iter_pos *pos = bt_iter_get_pos (bt_ctf_get_iter (NULL));])
> +
> + if test "$HAVE_LIBBABELTRACE" != yes; then
> + if test "$wit_babeltrace" = yes; then
typo: $with_babeltrace
> + AC_MSG_ERROR([babeltrace is missing or unusable])
> + else
> + AC_MSG_WARN([babeltrace is missing or unusable; GDB is unable to read CTF data.])
> + fi
> + else
> + # Check whether there is a function named 'lookup_enum' in
> + # babeltrace library. We can't use the babeltrace library
> + # in which function 'lookup_enum' is defined. This function
> + # is renamed to 'bt_lookup_enum' in recent babeltrace.
> + saved_LIBS=$LIBS
> + LIBS="$LIBS $LIBBABELTRACE"
> +
> + AC_MSG_CHECKING([for broken babeltrace])
> + AC_TRY_LINK([#include <stdio.h>],
> + [lookup_enum (NULL, NULL, 0)],
> + [AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_LIBBABELTRACE, 0,
> + [Define if libbabeltrace is available])],
This seems suspect. Can it result in
#define HAVE_LIBBABELTRACE 1
#define HAVE_LIBBABELTRACE 0
appearing on config.h?
> + [AC_MSG_RESULT([no])])
> +
> + LIBS=$save_LIBS
> + fi
> +fi
> +
> # If nativefile (NAT_FILE) is not set in config/*/*.m[ht] files, we link
> # to an empty version.
>
> diff --git a/gdb/ctf.c b/gdb/ctf.c
> index 6b55986..99a7fef 100644
> --- a/gdb/ctf.c
> +++ b/gdb/ctf.c
> @@ -24,6 +24,7 @@
> #include "tracepoint.h"
> #include "regcache.h"
> #include "gdb_stat.h"
> +#include "exec.h"
>
> #include <ctype.h>
>
> @@ -669,3 +670,745 @@ ctf_trace_file_writer_new (void)
>
> return (struct trace_file_writer *) writer;
> }
> +
> +#if HAVE_LIBBABELTRACE
> +/* Use libbabeltrace to read CTF data. The libbabeltrace provides
> + iterator to iterate over each event in CTF data and APIs to get
> + details of event and packet, so it is very convenient to use
> + libbabeltrace to access events in CTF. */
> +
> +#include <babeltrace/babeltrace.h>
> +#include <babeltrace/ctf/events.h>
> +#include <babeltrace/ctf/iterator.h>
> +
> +/* The struct pointer for current CTF directory. */
> +static struct bt_context *ctx = NULL;
> +static struct bt_ctf_iter *ctf_iter = NULL;
> +/* The name of CTF directory. */
> +static char *trace_dirname;
> +
> +static struct target_ops ctf_ops;
> +
> +/* Destroy ctf iterator and context. */
> +
> +static void
> +ctf_destroy (void)
> +{
> + if (ctf_iter != NULL)
> + {
> + bt_ctf_iter_destroy (ctf_iter);
> + ctf_iter = NULL;
> + }
> + if (ctx != NULL)
> + {
> + bt_context_put (ctx);
> + ctx = NULL;
> + }
> +}
> +
> +/* Open CTF trace data in DIRNAME. */
> +
> +static void
> +ctf_open_dir (char *dirname)
> +{
> + int ret;
> + struct bt_iter_pos begin_pos;
> + struct bt_iter_pos *pos;
> +
> + ctx = bt_context_create ();
> + if (ctx == NULL)
> + error (_("Unable to initialize libbabeltrace"));
> + ret = bt_context_add_trace (ctx, dirname, "ctf", NULL, NULL, NULL);
> + if (ret < 0)
> + {
> + ctf_destroy ();
> + error (_("Unable to use libbabeltrace open \"%s\""), dirname);
> + }
> +
> + begin_pos.type = BT_SEEK_BEGIN;
> + ctf_iter = bt_ctf_iter_create (ctx, &begin_pos, NULL);
> + if (ctf_iter == NULL)
> + {
> + ctf_destroy ();
> + error (_("Unable to use libbabeltrace open \"%s\""), dirname);
> + }
> +
> + /* Iterate over events, and look for an event for register block
> + to set trace_regblock_size. */
> +
> + /* Save the current position. */
> + pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
> + gdb_assert (pos->type == BT_SEEK_RESTORE);
> +
> + while (1)
> + {
> + const char *name;
> + struct bt_ctf_event *event;
> +
> + event = bt_ctf_iter_read_event (ctf_iter);
> +
> + name = bt_ctf_event_name (event);
> +
> + if (name == NULL)
> + break;
> + else if (strcmp (name, "register") == 0)
> + {
> + const struct bt_definition *scope
> + = bt_ctf_get_top_level_scope (event,
> + BT_EVENT_FIELDS);
> + const struct bt_definition *array
> + = bt_ctf_get_field (event, scope, "contents");
> +
> + trace_regblock_size
> + = bt_ctf_get_array_len (bt_ctf_get_decl_from_def (array));
> + }
> +
> + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> + break;
> + }
> +
> + /* Restore the position. */
> + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
> +
> +}
> +
> +/* This is the implementation of target_ops method to_open. Open CTF
> + trace data, read trace status, trace state variables and tracepoint
> + definitions from the first packet. Set the start position at the
> + second packet which contains events on trace blocks. */
> +
> +static void
> +ctf_open (char *dirname, int from_tty)
> +{
> + target_preopen (from_tty);
> + if (!dirname)
> + error (_("No CTF directory specified."));
It seems cleaner to error check dirname and then call target_preopen.
> +
> + ctf_open_dir (dirname);
> +
> + trace_dirname = xstrdup (dirname);
> + push_target (&ctf_ops);
> +}
> +
> +/* This is the implementation of target_ops method to_close. Destroy
> + CTF iterator and context. */
> +
> +static void
> +ctf_close (void)
> +{
> + ctf_destroy ();
> + xfree (trace_dirname);
> + trace_dirname = NULL;
> +}
> +
> +/* This is the implementation of target_ops method to_files_info.
> + Print the directory name of CTF trace data. */
> +
> +static void
> +ctf_files_info (struct target_ops *t)
> +{
> + printf_filtered ("\t`%s'\n", trace_dirname);
> +}
> +
> +/* This is the implementation of target_ops method to_fetch_registers.
> + Iterate over events whose name is "register" in current frame,
> + extract contents from events, and set REGCACHE with the contents.
> + If no matched events are found, mark registers unavailable. */
> +
> +static void
> +ctf_fetch_registers (struct target_ops *ops,
> + struct regcache *regcache, int regno)
> +{
> + struct gdbarch *gdbarch = get_regcache_arch (regcache);
> + int offset, regn, regsize, pc_regno;
> + char *regs = NULL;
> + struct bt_ctf_event *event = NULL;
> + struct bt_iter_pos *pos;
> +
> + /* An uninitialized reg size says we're not going to be
> + successful at getting register blocks. */
> + if (trace_regblock_size == 0)
> + return;
> +
> + /* Save the current position. */
> + pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
IWBN in every function that uses ctf_iter to assert it's non-NULL.
> + gdb_assert (pos->type == BT_SEEK_RESTORE);
> +
> + while (1)
> + {
> + const char *name;
> + struct bt_ctf_event *event1;
> +
> + event1 = bt_ctf_iter_read_event (ctf_iter);
> +
> + name = bt_ctf_event_name (event1);
> +
> + if (name == NULL || strcmp (name, "frame") == 0)
> + break;
> + else if (strcmp (name, "register") == 0)
> + {
> + event = event1;
> + break;
> + }
> +
> + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> + break;
> + }
> +
> + /* Restore the position. */
> + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
> +
> + if (event != NULL)
> + {
> + const struct bt_definition *scope
> + = bt_ctf_get_top_level_scope (event,
> + BT_EVENT_FIELDS);
> + const struct bt_definition *array
> + = bt_ctf_get_field (event, scope, "contents");
> +
> + regs = bt_ctf_get_char_array (array);
> + /* Assume the block is laid out in GDB register number order,
> + each register with the size that it has in GDB. */
> + offset = 0;
> + for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
> + {
> + regsize = register_size (gdbarch, regn);
> + /* Make sure we stay within block bounds. */
> + if (offset + regsize >= trace_regblock_size)
> + break;
> + if (regcache_register_status (regcache, regn) == REG_UNKNOWN)
> + {
> + if (regno == regn)
> + {
> + regcache_raw_supply (regcache, regno, regs + offset);
> + break;
> + }
> + else if (regno == -1)
> + {
> + regcache_raw_supply (regcache, regn, regs + offset);
> + }
> + }
> + offset += regsize;
> + }
> + return;
> + }
> +
> + regs = alloca (trace_regblock_size);
> +
> + /* We get here if no register data has been found. Mark registers
> + as unavailable. */
> + for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
> + regcache_raw_supply (regcache, regn, NULL);
> +
> + /* We can often usefully guess that the PC is going to be the same
> + as the address of the tracepoint. */
> + pc_regno = gdbarch_pc_regnum (gdbarch);
> + if (pc_regno >= 0 && (regno == -1 || regno == pc_regno))
> + {
> + struct tracepoint *tp = get_tracepoint (get_tracepoint_number ());
> +
> + if (tp != NULL && tp->base.loc)
> + {
> + /* But don't try to guess if tracepoint is multi-location... */
> + if (tp->base.loc->next != NULL)
> + {
> + warning (_("Tracepoint %d has multiple "
> + "locations, cannot infer $pc"),
> + tp->base.number);
> + return;
> + }
> + /* ... or does while-stepping. */
> + if (tp->step_count > 0)
> + {
> + warning (_("Tracepoint %d does while-stepping, "
> + "cannot infer $pc"),
> + tp->base.number);
> + return;
> + }
> +
> + store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
> + gdbarch_byte_order (gdbarch),
> + tp->base.loc->address);
> + regcache_raw_supply (regcache, pc_regno, regs);
> + }
> + }
> +}
> +
> +/* This is the implementation of target_ops method to_xfer_partial.
> + Iterate over events whose name is "memory" in
> + current frame, extract the address and length from events. If
> + OFFSET is within the range, read the contents from events to
> + READBUF. */
> +
> +static LONGEST
> +ctf_xfer_partial (struct target_ops *ops, enum target_object object,
> + const char *annex, gdb_byte *readbuf,
> + const gdb_byte *writebuf, ULONGEST offset,
> + LONGEST len)
> +{
> + /* We're only doing regular memory for now. */
> + if (object != TARGET_OBJECT_MEMORY)
> + return -1;
> +
> + if (readbuf == NULL)
> + error (_("ctf_xfer_partial: trace file is read-only"));
> +
> + if (get_traceframe_number () != -1)
> + {
> + struct bt_iter_pos *pos;
> + int i = 0;
> +
> + /* Save the current position. */
> + pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
> + gdb_assert (pos->type == BT_SEEK_RESTORE);
> +
> + /* Iterate through the traceframe's blocks, looking for
> + memory. */
> + while (1)
> + {
> + ULONGEST maddr, amt;
> + uint16_t mlen;
> + enum bfd_endian byte_order
> + = gdbarch_byte_order (target_gdbarch ());
> + const struct bt_definition *scope;
> + const struct bt_definition *def;
> + struct bt_ctf_event *event
> + = bt_ctf_iter_read_event (ctf_iter);
> + const char *name = bt_ctf_event_name (event);
> +
> + if (strcmp (name, "frame") == 0)
> + break;
> + else if (strcmp (name, "memory") != 0)
> + {
> + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> + break;
> +
> + continue;
> + }
> +
> + scope = bt_ctf_get_top_level_scope (event,
> + BT_EVENT_FIELDS);
> +
> + def = bt_ctf_get_field (event, scope, "address");
> + maddr = bt_ctf_get_uint64 (def);
> + def = bt_ctf_get_field (event, scope, "length");
> + mlen = (uint16_t) bt_ctf_get_uint64 (def);
> +
> + /* If the block includes the first part of the desired
> + range, return as much it has; GDB will re-request the
> + remainder, which might be in a different block of this
> + trace frame. */
> + if (maddr <= offset && offset < (maddr + mlen))
> + {
> + const struct bt_definition *array
> + = bt_ctf_get_field (event, scope, "contents");
> + const struct bt_declaration *decl
> + = bt_ctf_get_decl_from_def (array);
> + gdb_byte *contents;
> + int k;
> +
> + contents = xmalloc (mlen);
> +
> + for (k = 0; k < mlen; k++)
> + {
> + const struct bt_definition *element
> + = bt_ctf_get_index (event, array, k);
> +
> + contents[k] = (gdb_byte) bt_ctf_get_uint64 (element);
> + }
> +
> + amt = (maddr + mlen) - offset;
> + if (amt > len)
> + amt = len;
> +
> + memcpy (readbuf, &contents[offset - maddr], amt);
> +
> + xfree (contents);
> +
> + /* Restore the position. */
> + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
> +
> + return amt;
> + }
> +
> + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> + break;
> + }
> +
> + /* Restore the position. */
> + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
> + }
> +
> + /* It's unduly pedantic to refuse to look at the executable for
> + read-only pieces; so do the equivalent of readonly regions aka
> + QTro packet. */
> + if (exec_bfd != NULL)
> + {
> + asection *s;
> + bfd_size_type size;
> + bfd_vma vma;
> +
> + for (s = exec_bfd->sections; s; s = s->next)
> + {
> + if ((s->flags & SEC_LOAD) == 0
> + || (s->flags & SEC_READONLY) == 0)
> + continue;
> +
> + vma = s->vma;
> + size = bfd_get_section_size (s);
> + if (vma <= offset && offset < (vma + size))
> + {
> + ULONGEST amt;
> +
> + amt = (vma + size) - offset;
> + if (amt > len)
> + amt = len;
> +
> + amt = bfd_get_section_contents (exec_bfd, s,
> + readbuf, offset - vma, amt);
> + return amt;
> + }
> + }
> + }
> +
> + /* Indicate failure to find the requested memory block. */
> + return -1;
> +}
> +
> +/* This is the implementation of target_ops method
> + to_get_trace_state_variable_value.
> + Iterate over events whose name is "tsv" in current frame. When the
> + trace variable is found, set the value of it to *VAL and return
> + true, otherwise return false. */
> +
> +static int
> +ctf_get_trace_state_variable_value (int tsvnum, LONGEST *val)
> +{
> + struct bt_iter_pos *pos;
> + int found = 0;
> +
> + /* Save the current position. */
> + pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
> + gdb_assert (pos->type == BT_SEEK_RESTORE);
> +
> + /* Iterate through the traceframe's blocks, looking for 'V'
> + block. */
> + while (1)
> + {
> + struct bt_ctf_event *event
> + = bt_ctf_iter_read_event (ctf_iter);
> + const char *name = bt_ctf_event_name (event);
> +
> + if (name == NULL || strcmp (name, "frame") == 0)
> + break;
> + else if (strcmp (name, "tsv") == 0)
> + {
> + const struct bt_definition *scope;
> + const struct bt_definition *def;
> +
> + scope = bt_ctf_get_top_level_scope (event,
> + BT_EVENT_FIELDS);
> +
> + def = bt_ctf_get_field (event, scope, "num");
> + if (tsvnum == (int32_t) bt_ctf_get_uint64 (def))
> + {
> + def = bt_ctf_get_field (event, scope, "val");
> + *val = bt_ctf_get_uint64 (def);
> +
> + found = 1;
> + }
> + }
> +
> + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> + break;
> + }
> +
> + /* Restore the position. */
> + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
> +
> + return found;
> +}
> +
> +/* Return the tracepoint number in "frame" event. */
> +
> +static int
> +ctf_get_tpnum_from_frame_event (struct bt_ctf_event *event)
> +{
> + /* The packet context of events has a field "tpnum". */
> + const struct bt_definition *scope
> + = bt_ctf_get_top_level_scope (event, BT_STREAM_PACKET_CONTEXT);
> + uint64_t tpnum
> + = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "tpnum"));
> +
> + return (int) tpnum;
> +}
> +
> +/* Return the address at which the current frame was collected. */
> +
> +static ULONGEST
> +ctf_get_traceframe_address (void)
> +{
> + struct bt_ctf_event *event = NULL;
> + struct bt_iter_pos *pos
> + = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
> + ULONGEST addr = 0;
> +
> + gdb_assert (pos->type == BT_SEEK_RESTORE);
> +
> + while (1)
> + {
> + const char *name;
> + struct bt_ctf_event *event1;
> +
> + event1 = bt_ctf_iter_read_event (ctf_iter);
> +
> + name = bt_ctf_event_name (event1);
> +
> + if (name == NULL)
> + break;
> + else if (strcmp (name, "frame") == 0)
> + {
> + event = event1;
> + break;
> + }
> +
> + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> + break;
> + }
> +
> + if (event != NULL)
> + {
> + int tpnum = ctf_get_tpnum_from_frame_event (event);
> + struct tracepoint *tp
> + = get_tracepoint_by_number_on_target (tpnum);
> +
> + if (tp && tp->base.loc)
> + addr = tp->base.loc->address;
> + }
> +
> + /* Restore the position. */
> + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
> +
> + return addr;
> +}
> +
> +/* This is the implementation of target_ops method to_trace_find.
> + Iterate the events whose name is "frame", extract the tracepoint
> + number in it. Return traceframe number when matched. */
> +
> +static int
> +ctf_trace_find (enum trace_find_type type, int num,
> + ULONGEST addr1, ULONGEST addr2, int *tpp)
> +{
> + int ret = -1;
> + int tfnum = 0;
> + int found = 0;
> + struct bt_iter_pos pos;
> +
> + if (num == -1)
> + {
> + if (tpp != NULL)
> + *tpp = -1;
> + return -1;
> + }
> +
> + /* Set iterator back to the beginning. */
> + pos.type = BT_SEEK_BEGIN;
> + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), &pos);
> +
> + while (1)
> + {
> + int id;
> + struct bt_ctf_event *event;
> + const char *name;
> +
> + event = bt_ctf_iter_read_event (ctf_iter);
> +
> + name = bt_ctf_event_name (event);
> +
> + if (event == NULL || name == NULL)
> + return -1;
> +
> + if (strcmp (name, "frame") == 0)
> + {
> + ULONGEST tfaddr;
> +
> + if (type == tfind_number)
> + {
> + /* Looking for a specific trace frame. */
> + if (tfnum == num)
> + found = 1;
> + }
> + else
> + {
> + /* Start from the _next_ trace frame. */
> + if (tfnum > get_traceframe_number ())
> + {
> + switch (type)
> + {
> + case tfind_tp:
> + {
> + struct tracepoint *tp = get_tracepoint (num);
> +
> + if (tp != NULL
> + && (tp->number_on_target
> + == ctf_get_tpnum_from_frame_event (event)))
> + found = 1;
> + break;
> + }
> + case tfind_pc:
> + tfaddr = ctf_get_traceframe_address ();
> + if (tfaddr == addr1)
> + found = 1;
> + break;
> + case tfind_range:
> + tfaddr = ctf_get_traceframe_address ();
> + if (addr1 <= tfaddr && tfaddr <= addr2)
> + found = 1;
> + break;
> + case tfind_outside:
> + tfaddr = ctf_get_traceframe_address ();
> + if (!(addr1 <= tfaddr && tfaddr <= addr2))
> + found = 1;
> + break;
> + default:
> + internal_error (__FILE__, __LINE__, _("unknown tfind type"));
> + }
> + }
> + }
> + if (found)
> + {
> + if (tpp != NULL)
> + *tpp = ctf_get_tpnum_from_frame_event (event);
> +
> + /* Skip the event "frame". */
> + bt_iter_next (bt_ctf_get_iter (ctf_iter));
> +
> + return tfnum;
> + }
> + tfnum++;
> + }
> +
> + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> + return -1;
> + }
> +
> + return -1;
The code never gets here (AFAICT).
Either replace "return -1;" with "/* NOTREACHED */"
or replace the preceding "return -1;" with "break;".
For consistency with other functions, I'd suggest the latter.
> +}
> +
> +/* This is the implementation of target_ops method to_has_stack.
> + The target has a stack when GDB has already selected one trace
> + frame. */
> +
> +static int
> +ctf_has_stack (struct target_ops *ops)
> +{
> + return get_traceframe_number () != -1;
> +}
> +
> +/* This is the implementation of target_ops method to_has_registers.
> + The target has registers when GDB has already selected one trace
> + frame. */
> +
> +static int
> +ctf_has_registers (struct target_ops *ops)
> +{
> + return get_traceframe_number () != -1;
> +}
> +
> +/* This is the implementation of target_ops method to_traceframe_info.
> + Iterate the events whose name is "memory", in current
> + frame, extract memory range information, and return them in
> + traceframe_info. */
> +
> +static struct traceframe_info *
> +ctf_traceframe_info (void)
> +{
> + struct traceframe_info *info = XCNEW (struct traceframe_info);
> + const char *name;
> + struct bt_iter_pos *pos;
> +
> + /* Save the current position. */
> + pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
> + gdb_assert (pos->type == BT_SEEK_RESTORE);
> +
> + do
> + {
> + struct bt_ctf_event *event
> + = bt_ctf_iter_read_event (ctf_iter);
> +
> + name = bt_ctf_event_name (event);
> +
> + if (name == NULL || strcmp (name, "register") == 0
> + || strcmp (name, "frame") == 0)
> + ;
> + else if (strcmp (name, "memory") == 0)
> + {
> + const struct bt_definition *scope
> + = bt_ctf_get_top_level_scope (event,
> + BT_EVENT_FIELDS);
> + const struct bt_definition *def;
> + struct mem_range *r;
> +
> + r = VEC_safe_push (mem_range_s, info->memory, NULL);
> + def = bt_ctf_get_field (event, scope, "address");
> + r->start = bt_ctf_get_uint64 (def);
> +
> + def = bt_ctf_get_field (event, scope, "length");
> + r->length = (uint16_t) bt_ctf_get_uint64 (def);
> + }
> + else
> + warning (_("Unhandled trace block type (%s) "
> + "while building trace frame info."),
> + name);
> +
> + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> + break;
> + }
> + while (name != NULL && strcmp (name, "frame") != 0);
> +
> + /* Restore the position. */
> + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
> +
> + return info;
> +}
> +
> +static void
> +init_ctf_ops (void)
> +{
> + memset (&ctf_ops, 0, sizeof (ctf_ops));
> +
> + ctf_ops.to_shortname = "ctf";
> + ctf_ops.to_longname = "CTF file";
> + ctf_ops.to_doc = "Use a CTF directory as a target.\n\
> +Specify the filename of the CTF directory.";
> + ctf_ops.to_open = ctf_open;
> + ctf_ops.to_close = ctf_close;
> + ctf_ops.to_fetch_registers = ctf_fetch_registers;
> + ctf_ops.to_xfer_partial = ctf_xfer_partial;
> + ctf_ops.to_files_info = ctf_files_info;
> + ctf_ops.to_trace_find = ctf_trace_find;
> + ctf_ops.to_get_trace_state_variable_value
> + = ctf_get_trace_state_variable_value;
> + ctf_ops.to_stratum = process_stratum;
> + ctf_ops.to_has_stack = ctf_has_stack;
> + ctf_ops.to_has_registers = ctf_has_registers;
> + ctf_ops.to_traceframe_info = ctf_traceframe_info;
> + ctf_ops.to_magic = OPS_MAGIC;
> +}
> +
> +#endif
> +
> +/* -Wmissing-prototypes */
> +extern initialize_file_ftype _initialize_ctf;
> +
> +/* module initialization */
> +void
> +_initialize_ctf (void)
> +{
> +#if HAVE_LIBBABELTRACE
> + init_ctf_ops ();
> +
> + add_target (&ctf_ops);
> +#endif
> +}
> diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
> index 9a2425b..6a30f6f 100644
> --- a/gdb/tracepoint.c
> +++ b/gdb/tracepoint.c
> @@ -126,14 +126,6 @@ extern void (*deprecated_readline_end_hook) (void);
> typedef struct trace_state_variable tsv_s;
> DEF_VEC_O(tsv_s);
>
> -/* An object describing the contents of a traceframe. */
> -
> -struct traceframe_info
> -{
> - /* Collected memory. */
> - VEC(mem_range_s) *memory;
> -};
> -
> static VEC(tsv_s) *tvariables;
>
> /* The next integer to assign to a variable. */
> @@ -3302,8 +3294,6 @@ static const struct trace_file_write_ops tfile_write_ops =
> #define TRACE_WRITE_V_BLOCK(writer, num, val) \
> writer->ops->frame_ops->write_v_block ((writer), (num), (val))
>
> -extern int trace_regblock_size;
> -
> /* Save tracepoint data to file named FILENAME through WRITER. WRITER
> determines the trace file format. If TARGET_DOES_SAVE is non-zero,
> the save is performed on the target, otherwise GDB obtains all trace
> @@ -3740,6 +3730,12 @@ get_traceframe_number (void)
> return traceframe_number;
> }
>
> +int
> +get_tracepoint_number (void)
> +{
> + return tracepoint_number;
> +}
> +
> /* Make the traceframe NUM be the current trace frame. Does nothing
> if NUM is already current. */
>
> diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
> index c7eef7b..bad8d49 100644
> --- a/gdb/tracepoint.h
> +++ b/gdb/tracepoint.h
> @@ -24,6 +24,14 @@
> #include "memrange.h"
> #include "gdb_vecs.h"
>
> +/* An object describing the contents of a traceframe. */
> +
> +struct traceframe_info
> +{
> + /* Collected memory. */
> + VEC(mem_range_s) *memory;
> +};
> +
> /* A trace state variable is a value managed by a target being
> traced. A trace state variable (or tsv for short) can be accessed
> and assigned to by tracepoint actions and conditionals, but is not
> @@ -142,6 +150,8 @@ struct trace_status *current_trace_status (void);
>
> extern char *default_collect;
>
> +extern int trace_regblock_size;
> +
> /* Struct to collect random info about tracepoints on the target. */
>
> struct uploaded_tp
> @@ -324,6 +334,9 @@ extern void (*deprecated_trace_start_stop_hook) (int start, int from_tty);
> /* Returns the current traceframe number. */
> extern int get_traceframe_number (void);
>
> +/* Returns the tracepoint number for current traceframe. */
> +extern int get_tracepoint_number (void);
> +
> /* Make the traceframe NUM be the current GDB trace frame number, and
> do nothing more. In particular, this does not flush the
> register/frame caches or notify the target about the trace frame
> --
> 1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 03/15] Read CTF by the ctf target
2013-03-25 17:14 ` Doug Evans
@ 2013-03-26 16:16 ` Yao Qi
2013-03-29 17:56 ` Doug Evans
0 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-03-26 16:16 UTC (permalink / raw)
To: Doug Evans; +Cc: Tom Tromey, gdb-patches
On 03/25/2013 11:44 PM, Doug Evans wrote:
> > +if test "x$with_babeltrace" = "xno"; then
> > + AC_MSG_WARN([babletrace support disabled; GDB is unable to read CTF data.])
> > +else
> > + AC_LIB_HAVE_LINKFLAGS([babeltrace], [babeltrace-ctf],
> > + [#include <babeltrace/babeltrace.h>
> > + #include <babeltrace/ctf/events.h>
> > + #include <babeltrace/ctf/iterator.h>],
> > + [struct bt_iter_pos *pos = bt_iter_get_pos (bt_ctf_get_iter (NULL));])
> > +
> > + if test "$HAVE_LIBBABELTRACE" != yes; then
> > + if test "$wit_babeltrace" = yes; then
>
> typo: $with_babeltrace
>
Fixed.
> > + AC_MSG_ERROR([babeltrace is missing or unusable])
> > + else
> > + AC_MSG_WARN([babeltrace is missing or unusable; GDB is unable to read CTF data.])
> > + fi
> > + else
> > + # Check whether there is a function named 'lookup_enum' in
> > + # babeltrace library. We can't use the babeltrace library
> > + # in which function 'lookup_enum' is defined. This function
> > + # is renamed to 'bt_lookup_enum' in recent babeltrace.
> > + saved_LIBS=$LIBS
> > + LIBS="$LIBS $LIBBABELTRACE"
> > +
> > + AC_MSG_CHECKING([for broken babeltrace])
> > + AC_TRY_LINK([#include <stdio.h>],
> > + [lookup_enum (NULL, NULL, 0)],
> > + [AC_MSG_RESULT([yes]); AC_DEFINE(HAVE_LIBBABELTRACE, 0,
> > + [Define if libbabeltrace is available])],
>
> This seems suspect. Can it result in
> #define HAVE_LIBBABELTRACE 1
> #define HAVE_LIBBABELTRACE 0
> appearing on config.h?
>
I considered this when I wrote the patch, but looks this won't happen.
I use something simpler in the new patch to avoid this. The babeltrace
1.1.0 was released recently, and it has the fix to rename "lookup_enum"
to "bt_lookup_enum". We only have to check whether the installed
babeltrace is 1.1.0. In the "testcode" of AC_LIB_HAVE_LINKFLAGS, I use
structure renamed in 1.1.0, such as "struct bt_definition" (it was
"struct definition" in babeltrace 1.0.3), however, the warning
"assignment from incompatible pointer type" is not caught by
configure. Then, I append "-Werror" in CFLAGS when using
AC_LIB_HAVE_LINKFLAGS, everything works correctly.
> > +
> > +/* This is the implementation of target_ops method to_open. Open CTF
> > + trace data, read trace status, trace state variables and tracepoint
> > + definitions from the first packet. Set the start position at the
> > + second packet which contains events on trace blocks. */
> > +
> > +static void
> > +ctf_open (char *dirname, int from_tty)
> > +{
> > + target_preopen (from_tty);
> > + if (!dirname)
> > + error (_("No CTF directory specified."));
>
> It seems cleaner to error check dirname and then call target_preopen.
>
OK. Move target_preopen after 'ctf_open_dir'.
> > +
> > + ctf_open_dir (dirname);
> > +
> > + trace_dirname = xstrdup (dirname);
> > + push_target (&ctf_ops);
> > +}
> > +
> > +static void
> > +ctf_fetch_registers (struct target_ops *ops,
> > + struct regcache *regcache, int regno)
> > +{
> > + struct gdbarch *gdbarch = get_regcache_arch (regcache);
> > + int offset, regn, regsize, pc_regno;
> > + char *regs = NULL;
> > + struct bt_ctf_event *event = NULL;
> > + struct bt_iter_pos *pos;
> > +
> > + /* An uninitialized reg size says we're not going to be
> > + successful at getting register blocks. */
> > + if (trace_regblock_size == 0)
> > + return;
> > +
> > + /* Save the current position. */
> > + pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
>
> IWBN in every function that uses ctf_iter to assert it's non-NULL.
>
The assert is added.
> > +
> > +/* This is the implementation of target_ops method to_trace_find.
> > + Iterate the events whose name is "frame", extract the tracepoint
> > + number in it. Return traceframe number when matched. */
> > +
> > +static int
> > +ctf_trace_find (enum trace_find_type type, int num,
> > + ULONGEST addr1, ULONGEST addr2, int *tpp)
> > +{
> > + int ret = -1;
> > + int tfnum = 0;
> > + int found = 0;
> > + struct bt_iter_pos pos;
> > +
> > + if (num == -1)
> > + {
> > + if (tpp != NULL)
> > + *tpp = -1;
> > + return -1;
> > + }
> > +
> > + /* Set iterator back to the beginning. */
> > + pos.type = BT_SEEK_BEGIN;
> > + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), &pos);
> > +
> > + while (1)
> > + {
> > + int id;
> > + struct bt_ctf_event *event;
> > + const char *name;
> > +
> > + event = bt_ctf_iter_read_event (ctf_iter);
> > +
> > + name = bt_ctf_event_name (event);
> > +
> > + if (event == NULL || name == NULL)
> > + return -1;
> > +
> > + if (strcmp (name, "frame") == 0)
> > + {
> > + ULONGEST tfaddr;
> > +
> > + if (type == tfind_number)
> > + {
> > + /* Looking for a specific trace frame. */
> > + if (tfnum == num)
> > + found = 1;
> > + }
> > + else
> > + {
> > + /* Start from the_next_ trace frame. */
> > + if (tfnum > get_traceframe_number ())
> > + {
> > + switch (type)
> > + {
> > + case tfind_tp:
> > + {
> > + struct tracepoint *tp = get_tracepoint (num);
> > +
> > + if (tp != NULL
> > + && (tp->number_on_target
> > + == ctf_get_tpnum_from_frame_event (event)))
> > + found = 1;
> > + break;
> > + }
> > + case tfind_pc:
> > + tfaddr = ctf_get_traceframe_address ();
> > + if (tfaddr == addr1)
> > + found = 1;
> > + break;
> > + case tfind_range:
> > + tfaddr = ctf_get_traceframe_address ();
> > + if (addr1 <= tfaddr && tfaddr <= addr2)
> > + found = 1;
> > + break;
> > + case tfind_outside:
> > + tfaddr = ctf_get_traceframe_address ();
> > + if (!(addr1 <= tfaddr && tfaddr <= addr2))
> > + found = 1;
> > + break;
> > + default:
> > + internal_error (__FILE__, __LINE__, _("unknown tfind type"));
> > + }
> > + }
> > + }
> > + if (found)
> > + {
> > + if (tpp != NULL)
> > + *tpp = ctf_get_tpnum_from_frame_event (event);
> > +
> > + /* Skip the event "frame". */
> > + bt_iter_next (bt_ctf_get_iter (ctf_iter));
> > +
> > + return tfnum;
> > + }
> > + tfnum++;
> > + }
> > +
> > + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> > + return -1;
> > + }
> > +
> > + return -1;
>
> The code never gets here (AFAICT).
> Either replace "return -1;" with "/* NOTREACHED */"
> or replace the preceding "return -1;" with "break;".
> For consistency with other functions, I'd suggest the latter.
>
OK. Replace "return -1" with "break".
--
Yao (é½å°§)
gdb:
2013-03-26 Hui Zhu <hui@codesourcery.com>
Yao Qi <yao@codesourcery.com>
* configure.ac: Check libbabeltrace is installed.
* config.in: Regenerate.
* configure: Regenerate.
* Makefile.in (LIBBABELTRACE): New.
(CLIBS): Add LIBBABELTRACE.
* ctf.c (ctx, ctf_iter, trace_dirname): New.
(ctf_destroy, ctf_open_dir, ctf_open): New.
(ctf_close, ctf_files_info): New.
(ctf_fetch_registers, ctf_xfer_partial): New.
(ctf_get_trace_state_variable_value): New.
(ctf_get_tpnum_from_frame_event): New.
(ctf_get_traceframe_address): New.
(ctf_trace_find, ctf_has_stack): New.
(ctf_has_registers, ctf_traceframe_info, init_ctf_ops): New.
(_initialize_ctf): New.
* tracepoint.c (get_tracepoint_number): New
(struct traceframe_info, trace_regblock_size): Move it to ...
* tracepoint.h: ... here.
(get_tracepoint_number): Declare it.
---
gdb/Makefile.in | 6 +-
gdb/config.in | 3 +
gdb/configure | 517 +++++++++++++++++++++++++++++++++++++
gdb/configure.ac | 41 +++
gdb/ctf.c | 749 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/tracepoint.c | 16 +-
gdb/tracepoint.h | 13 +
7 files changed, 1334 insertions(+), 11 deletions(-)
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 9bab01c..f474897 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -154,6 +154,10 @@ LIBEXPAT = @LIBEXPAT@
# Where is lzma? This will be empty if lzma was not available.
LIBLZMA = @LIBLZMA@
+# Where is libbabeltrace? This will be empty if lbabeltrace was not
+# available.
+LIBBABELTRACE = @LIBBABELTRACE@
+
WARN_CFLAGS = @WARN_CFLAGS@
WERROR_CFLAGS = @WERROR_CFLAGS@
GDB_WARN_CFLAGS = $(WARN_CFLAGS)
@@ -475,7 +479,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_
# LIBIBERTY appears twice on purpose.
CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
$(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ @PYTHON_LIBS@ \
- $(LIBEXPAT) $(LIBLZMA) \
+ $(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) \
$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU)
CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
diff --git a/gdb/config.in b/gdb/config.in
index 9e21325..c4e8eaa 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -180,6 +180,9 @@
/* Define if your <locale.h> file defines LC_MESSAGES. */
#undef HAVE_LC_MESSAGES
+/* Define if libbabeltrace is available */
+#undef HAVE_LIBBABELTRACE
+
/* Define to 1 if you have the `dl' library (-ldl). */
#undef HAVE_LIBDL
diff --git a/gdb/configure b/gdb/configure
index 0dd67f0..6588c72 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -592,6 +592,9 @@ enable_option_checking=no
ac_subst_vars='LTLIBOBJS
LIBOBJS
GDB_NM_FILE
+LTLIBBABELTRACE
+LIBBABELTRACE
+HAVE_LIBBABELTRACE
frags
target_subdir
CONFIG_UNINSTALL
@@ -819,6 +822,8 @@ with_x
enable_sim
enable_multi_ice
enable_gdbserver
+with_babeltrace
+with_libbabeltrace_prefix
'
ac_precious_vars='build_alias
host_alias
@@ -1532,6 +1537,9 @@ Optional Packages:
--with-tcl directory containing tcl configuration (tclConfig.sh)
--with-tk directory containing tk configuration (tkConfig.sh)
--with-x use the X Window System
+ --with-babeltrace include babeltrace support (auto/yes/no)
+ --with-libbabeltrace-prefix[=DIR] search for libbabeltrace in DIR/include and DIR/lib
+ --without-libbabeltrace-prefix don't search for libbabeltrace in includedir and libdir
Some influential environment variables:
CC C compiler command
@@ -14093,6 +14101,515 @@ if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then
as_fn_error "Automatic gdbserver build is not supported for this configuration" "$LINENO" 5
fi
+# Check for babeltrace and babeltrace-ctf
+
+# Check whether --with-babeltrace was given.
+if test "${with_babeltrace+set}" = set; then :
+ withval=$with_babeltrace;
+else
+ with_babeltrace=auto
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use babeltrace" >&5
+$as_echo_n "checking whether to use babeltrace... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_babeltrace" >&5
+$as_echo "$with_babeltrace" >&6; }
+
+if test "x$with_babeltrace" = "xno"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: babletrace support disabled; GDB is unable to read CTF data." >&5
+$as_echo "$as_me: WARNING: babletrace support disabled; GDB is unable to read CTF data." >&2;}
+else
+ # Append -Werror to CFLAGS so that configure can catch the warning
+ # "assignment from incompatible pointer type", which is related to
+ # the babeltrace change from 1.0.3 to 1.1.0. Babeltrace 1.1.0 works
+ # in GDB, while babeltrace 1.0.3 is broken.
+ # AC_LIB_HAVE_LINKFLAGS may modify CPPFLAGS in it, so it should be
+ # safe to save and restore CFLAGS here.
+ saved_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS -Werror"
+
+
+
+
+
+
+
+
+ use_additional=yes
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+
+# Check whether --with-libbabeltrace-prefix was given.
+if test "${with_libbabeltrace_prefix+set}" = set; then :
+ withval=$with_libbabeltrace_prefix;
+ if test "X$withval" = "Xno"; then
+ use_additional=no
+ else
+ if test "X$withval" = "X"; then
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ else
+ additional_includedir="$withval/include"
+ additional_libdir="$withval/lib"
+ fi
+ fi
+
+fi
+
+ LIBBABELTRACE=
+ LTLIBBABELTRACE=
+ INCBABELTRACE=
+ rpathdirs=
+ ltrpathdirs=
+ names_already_handled=
+ names_next_round='babeltrace babeltrace-ctf'
+ while test -n "$names_next_round"; do
+ names_this_round="$names_next_round"
+ names_next_round=
+ for name in $names_this_round; do
+ already_handled=
+ for n in $names_already_handled; do
+ if test "$n" = "$name"; then
+ already_handled=yes
+ break
+ fi
+ done
+ if test -z "$already_handled"; then
+ names_already_handled="$names_already_handled $name"
+ uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+ eval value=\"\$HAVE_LIB$uppername\"
+ if test -n "$value"; then
+ if test "$value" = yes; then
+ eval value=\"\$LIB$uppername\"
+ test -z "$value" || LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$value"
+ eval value=\"\$LTLIB$uppername\"
+ test -z "$value" || LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }$value"
+ else
+ :
+ fi
+ else
+ found_dir=
+ found_la=
+ found_so=
+ found_a=
+ if test $use_additional = yes; then
+ if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then
+ found_dir="$additional_libdir"
+ found_so="$additional_libdir/lib$name.$shlibext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ else
+ if test -f "$additional_libdir/lib$name.$libext"; then
+ found_dir="$additional_libdir"
+ found_a="$additional_libdir/lib$name.$libext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ fi
+ fi
+ fi
+ if test "X$found_dir" = "X"; then
+ for x in $LDFLAGS $LTLIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ case "$x" in
+ -L*)
+ dir=`echo "X$x" | sed -e 's/^X-L//'`
+ if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then
+ found_dir="$dir"
+ found_so="$dir/lib$name.$shlibext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ else
+ if test -f "$dir/lib$name.$libext"; then
+ found_dir="$dir"
+ found_a="$dir/lib$name.$libext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ if test "X$found_dir" != "X"; then
+ break
+ fi
+ done
+ fi
+ if test "X$found_dir" != "X"; then
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-L$found_dir -l$name"
+ if test "X$found_so" != "X"; then
+ if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ else
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $found_dir"
+ fi
+ if test "$hardcode_direct" = yes; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ else
+ if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $found_dir"
+ fi
+ else
+ haveit=
+ for x in $LDFLAGS $LIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$found_dir"
+ fi
+ if test "$hardcode_minus_L" != no; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ else
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-l$name"
+ fi
+ fi
+ fi
+ fi
+ else
+ if test "X$found_a" != "X"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_a"
+ else
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$found_dir -l$name"
+ fi
+ fi
+ additional_includedir=
+ case "$found_dir" in
+ */lib | */lib/)
+ basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'`
+ additional_includedir="$basedir/include"
+ ;;
+ esac
+ if test "X$additional_includedir" != "X"; then
+ if test "X$additional_includedir" != "X/usr/include"; then
+ haveit=
+ if test "X$additional_includedir" = "X/usr/local/include"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ for x in $CPPFLAGS $INCBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-I$additional_includedir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_includedir"; then
+ INCBABELTRACE="${INCBABELTRACE}${INCBABELTRACE:+ }-I$additional_includedir"
+ fi
+ fi
+ fi
+ fi
+ fi
+ if test -n "$found_la"; then
+ save_libdir="$libdir"
+ case "$found_la" in
+ */* | *\\*) . "$found_la" ;;
+ *) . "./$found_la" ;;
+ esac
+ libdir="$save_libdir"
+ for dep in $dependency_libs; do
+ case "$dep" in
+ -L*)
+ additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+ if test "X$additional_libdir" != "X/usr/lib"; then
+ haveit=
+ if test "X$additional_libdir" = "X/usr/local/lib"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ haveit=
+ for x in $LDFLAGS $LIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$additional_libdir"
+ fi
+ fi
+ haveit=
+ for x in $LDFLAGS $LTLIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-L$additional_libdir"
+ fi
+ fi
+ fi
+ fi
+ ;;
+ -R*)
+ dir=`echo "X$dep" | sed -e 's/^X-R//'`
+ if test "$enable_rpath" != no; then
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $dir"
+ fi
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $dir"
+ fi
+ fi
+ ;;
+ -l*)
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+ ;;
+ *.la)
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+ ;;
+ *)
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$dep"
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }$dep"
+ ;;
+ esac
+ done
+ fi
+ else
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-l$name"
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-l$name"
+ fi
+ fi
+ fi
+ done
+ done
+ if test "X$rpathdirs" != "X"; then
+ if test -n "$hardcode_libdir_separator"; then
+ alldirs=
+ for found_dir in $rpathdirs; do
+ alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+ done
+ acl_save_libdir="$libdir"
+ libdir="$alldirs"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$flag"
+ else
+ for found_dir in $rpathdirs; do
+ acl_save_libdir="$libdir"
+ libdir="$found_dir"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$flag"
+ done
+ fi
+ fi
+ if test "X$ltrpathdirs" != "X"; then
+ for found_dir in $ltrpathdirs; do
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-R$found_dir"
+ done
+ fi
+
+
+ ac_save_CPPFLAGS="$CPPFLAGS"
+
+ for element in $INCBABELTRACE; do
+ haveit=
+ for x in $CPPFLAGS; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X$element"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element"
+ fi
+ done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libbabeltrace" >&5
+$as_echo_n "checking for libbabeltrace... " >&6; }
+if test "${ac_cv_libbabeltrace+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ac_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIBBABELTRACE"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <babeltrace/babeltrace.h>
+ #include <babeltrace/ctf/events.h>
+ #include <babeltrace/ctf/iterator.h>
+int
+main ()
+{
+struct bt_iter_pos *pos = bt_iter_get_pos (bt_ctf_get_iter (NULL));
+ struct bt_ctf_event *event = NULL;
+ const struct bt_definition *scope;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_STREAM_EVENT_HEADER);
+ bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_libbabeltrace=yes
+else
+ ac_cv_libbabeltrace=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$ac_save_LIBS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libbabeltrace" >&5
+$as_echo "$ac_cv_libbabeltrace" >&6; }
+ if test "$ac_cv_libbabeltrace" = yes; then
+ HAVE_LIBBABELTRACE=yes
+
+$as_echo "#define HAVE_LIBBABELTRACE 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libbabeltrace" >&5
+$as_echo_n "checking how to link with libbabeltrace... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBBABELTRACE" >&5
+$as_echo "$LIBBABELTRACE" >&6; }
+ else
+ HAVE_LIBBABELTRACE=no
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIBBABELTRACE=
+ LTLIBBABELTRACE=
+ fi
+
+
+
+
+
+
+ CFLAGS=$saved_CFLAGS
+
+ if test "$HAVE_LIBBABELTRACE" != yes; then
+ if test "$with_babeltrace" = yes; then
+ as_fn_error "babeltrace is missing or unusable" "$LINENO" 5
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: babeltrace is missing or unusable; GDB is unable to read CTF data." >&5
+$as_echo "$as_me: WARNING: babeltrace is missing or unusable; GDB is unable to read CTF data." >&2;}
+ fi
+ fi
+fi
+
# If nativefile (NAT_FILE) is not set in config/*/*.m[ht] files, we link
# to an empty version.
diff --git a/gdb/configure.ac b/gdb/configure.ac
index c17f587..149ac37 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -2321,6 +2321,47 @@ if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then
AC_MSG_ERROR(Automatic gdbserver build is not supported for this configuration)
fi
+# Check for babeltrace and babeltrace-ctf
+AC_ARG_WITH(babeltrace,
+ AC_HELP_STRING([--with-babeltrace], [include babeltrace support (auto/yes/no)]),
+ [], [with_babeltrace=auto])
+AC_MSG_CHECKING([whether to use babeltrace])
+AC_MSG_RESULT([$with_babeltrace])
+
+if test "x$with_babeltrace" = "xno"; then
+ AC_MSG_WARN([babletrace support disabled; GDB is unable to read CTF data.])
+else
+ # Append -Werror to CFLAGS so that configure can catch the warning
+ # "assignment from incompatible pointer type", which is related to
+ # the babeltrace change from 1.0.3 to 1.1.0. Babeltrace 1.1.0 works
+ # in GDB, while babeltrace 1.0.3 is broken.
+ # AC_LIB_HAVE_LINKFLAGS may modify CPPFLAGS in it, so it should be
+ # safe to save and restore CFLAGS here.
+ saved_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS -Werror"
+ AC_LIB_HAVE_LINKFLAGS([babeltrace], [babeltrace-ctf],
+ [#include <babeltrace/babeltrace.h>
+ #include <babeltrace/ctf/events.h>
+ #include <babeltrace/ctf/iterator.h>],
+ [struct bt_iter_pos *pos = bt_iter_get_pos (bt_ctf_get_iter (NULL));
+ struct bt_ctf_event *event = NULL;
+ const struct bt_definition *scope;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_STREAM_EVENT_HEADER);
+ bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+ ])
+ CFLAGS=$saved_CFLAGS
+
+ if test "$HAVE_LIBBABELTRACE" != yes; then
+ if test "$with_babeltrace" = yes; then
+ AC_MSG_ERROR([babeltrace is missing or unusable])
+ else
+ AC_MSG_WARN([babeltrace is missing or unusable; GDB is unable to read CTF data.])
+ fi
+ fi
+fi
+
# If nativefile (NAT_FILE) is not set in config/*/*.m[ht] files, we link
# to an empty version.
diff --git a/gdb/ctf.c b/gdb/ctf.c
index 6b55986..80f57c1 100644
--- a/gdb/ctf.c
+++ b/gdb/ctf.c
@@ -24,6 +24,7 @@
#include "tracepoint.h"
#include "regcache.h"
#include "gdb_stat.h"
+#include "exec.h"
#include <ctype.h>
@@ -669,3 +670,751 @@ ctf_trace_file_writer_new (void)
return (struct trace_file_writer *) writer;
}
+
+#if HAVE_LIBBABELTRACE
+/* Use libbabeltrace to read CTF data. The libbabeltrace provides
+ iterator to iterate over each event in CTF data and APIs to get
+ details of event and packet, so it is very convenient to use
+ libbabeltrace to access events in CTF. */
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/iterator.h>
+
+/* The struct pointer for current CTF directory. */
+static struct bt_context *ctx = NULL;
+static struct bt_ctf_iter *ctf_iter = NULL;
+/* The name of CTF directory. */
+static char *trace_dirname;
+
+static struct target_ops ctf_ops;
+
+/* Destroy ctf iterator and context. */
+
+static void
+ctf_destroy (void)
+{
+ if (ctf_iter != NULL)
+ {
+ bt_ctf_iter_destroy (ctf_iter);
+ ctf_iter = NULL;
+ }
+ if (ctx != NULL)
+ {
+ bt_context_put (ctx);
+ ctx = NULL;
+ }
+}
+
+/* Open CTF trace data in DIRNAME. */
+
+static void
+ctf_open_dir (char *dirname)
+{
+ int ret;
+ struct bt_iter_pos begin_pos;
+ struct bt_iter_pos *pos;
+
+ ctx = bt_context_create ();
+ if (ctx == NULL)
+ error (_("Unable to initialize libbabeltrace"));
+ ret = bt_context_add_trace (ctx, dirname, "ctf", NULL, NULL, NULL);
+ if (ret < 0)
+ {
+ ctf_destroy ();
+ error (_("Unable to use libbabeltrace open \"%s\""), dirname);
+ }
+
+ begin_pos.type = BT_SEEK_BEGIN;
+ ctf_iter = bt_ctf_iter_create (ctx, &begin_pos, NULL);
+ if (ctf_iter == NULL)
+ {
+ ctf_destroy ();
+ error (_("Unable to use libbabeltrace open \"%s\""), dirname);
+ }
+
+ /* Iterate over events, and look for an event for register block
+ to set trace_regblock_size. */
+
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event;
+
+ event = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (name == NULL)
+ break;
+ else if (strcmp (name, "register") == 0)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+
+ trace_regblock_size
+ = bt_ctf_get_array_len (bt_ctf_get_decl_from_def (array));
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+}
+
+/* This is the implementation of target_ops method to_open. Open CTF
+ trace data, read trace status, trace state variables and tracepoint
+ definitions from the first packet. Set the start position at the
+ second packet which contains events on trace blocks. */
+
+static void
+ctf_open (char *dirname, int from_tty)
+{
+ if (!dirname)
+ error (_("No CTF directory specified."));
+
+ ctf_open_dir (dirname);
+
+ target_preopen (from_tty);
+ trace_dirname = xstrdup (dirname);
+ push_target (&ctf_ops);
+}
+
+/* This is the implementation of target_ops method to_close. Destroy
+ CTF iterator and context. */
+
+static void
+ctf_close (void)
+{
+ ctf_destroy ();
+ xfree (trace_dirname);
+ trace_dirname = NULL;
+}
+
+/* This is the implementation of target_ops method to_files_info.
+ Print the directory name of CTF trace data. */
+
+static void
+ctf_files_info (struct target_ops *t)
+{
+ printf_filtered ("\t`%s'\n", trace_dirname);
+}
+
+/* This is the implementation of target_ops method to_fetch_registers.
+ Iterate over events whose name is "register" in current frame,
+ extract contents from events, and set REGCACHE with the contents.
+ If no matched events are found, mark registers unavailable. */
+
+static void
+ctf_fetch_registers (struct target_ops *ops,
+ struct regcache *regcache, int regno)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ int offset, regn, regsize, pc_regno;
+ char *regs = NULL;
+ struct bt_ctf_event *event = NULL;
+ struct bt_iter_pos *pos;
+
+ /* An uninitialized reg size says we're not going to be
+ successful at getting register blocks. */
+ if (trace_regblock_size == 0)
+ return;
+
+ gdb_assert (ctf_iter != NULL);
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event1;
+
+ event1 = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event1);
+
+ if (name == NULL || strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "register") == 0)
+ {
+ event = event1;
+ break;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ if (event != NULL)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+
+ regs = bt_ctf_get_char_array (array);
+ /* Assume the block is laid out in GDB register number order,
+ each register with the size that it has in GDB. */
+ offset = 0;
+ for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+ {
+ regsize = register_size (gdbarch, regn);
+ /* Make sure we stay within block bounds. */
+ if (offset + regsize >= trace_regblock_size)
+ break;
+ if (regcache_register_status (regcache, regn) == REG_UNKNOWN)
+ {
+ if (regno == regn)
+ {
+ regcache_raw_supply (regcache, regno, regs + offset);
+ break;
+ }
+ else if (regno == -1)
+ {
+ regcache_raw_supply (regcache, regn, regs + offset);
+ }
+ }
+ offset += regsize;
+ }
+ return;
+ }
+
+ regs = alloca (trace_regblock_size);
+
+ /* We get here if no register data has been found. Mark registers
+ as unavailable. */
+ for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+ regcache_raw_supply (regcache, regn, NULL);
+
+ /* We can often usefully guess that the PC is going to be the same
+ as the address of the tracepoint. */
+ pc_regno = gdbarch_pc_regnum (gdbarch);
+ if (pc_regno >= 0 && (regno == -1 || regno == pc_regno))
+ {
+ struct tracepoint *tp = get_tracepoint (get_tracepoint_number ());
+
+ if (tp != NULL && tp->base.loc)
+ {
+ /* But don't try to guess if tracepoint is multi-location... */
+ if (tp->base.loc->next != NULL)
+ {
+ warning (_("Tracepoint %d has multiple "
+ "locations, cannot infer $pc"),
+ tp->base.number);
+ return;
+ }
+ /* ... or does while-stepping. */
+ if (tp->step_count > 0)
+ {
+ warning (_("Tracepoint %d does while-stepping, "
+ "cannot infer $pc"),
+ tp->base.number);
+ return;
+ }
+
+ store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
+ gdbarch_byte_order (gdbarch),
+ tp->base.loc->address);
+ regcache_raw_supply (regcache, pc_regno, regs);
+ }
+ }
+}
+
+/* This is the implementation of target_ops method to_xfer_partial.
+ Iterate over events whose name is "memory" in
+ current frame, extract the address and length from events. If
+ OFFSET is within the range, read the contents from events to
+ READBUF. */
+
+static LONGEST
+ctf_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf, ULONGEST offset,
+ LONGEST len)
+{
+ /* We're only doing regular memory for now. */
+ if (object != TARGET_OBJECT_MEMORY)
+ return -1;
+
+ if (readbuf == NULL)
+ error (_("ctf_xfer_partial: trace file is read-only"));
+
+ if (get_traceframe_number () != -1)
+ {
+ struct bt_iter_pos *pos;
+ int i = 0;
+
+ gdb_assert (ctf_iter != NULL);
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ /* Iterate through the traceframe's blocks, looking for
+ memory. */
+ while (1)
+ {
+ ULONGEST maddr, amt;
+ uint16_t mlen;
+ enum bfd_endian byte_order
+ = gdbarch_byte_order (target_gdbarch ());
+ const struct bt_definition *scope;
+ const struct bt_definition *def;
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+ const char *name = bt_ctf_event_name (event);
+
+ if (strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "memory") != 0)
+ {
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+
+ continue;
+ }
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+
+ def = bt_ctf_get_field (event, scope, "address");
+ maddr = bt_ctf_get_uint64 (def);
+ def = bt_ctf_get_field (event, scope, "length");
+ mlen = (uint16_t) bt_ctf_get_uint64 (def);
+
+ /* If the block includes the first part of the desired
+ range, return as much it has; GDB will re-request the
+ remainder, which might be in a different block of this
+ trace frame. */
+ if (maddr <= offset && offset < (maddr + mlen))
+ {
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+ const struct bt_declaration *decl
+ = bt_ctf_get_decl_from_def (array);
+ gdb_byte *contents;
+ int k;
+
+ contents = xmalloc (mlen);
+
+ for (k = 0; k < mlen; k++)
+ {
+ const struct bt_definition *element
+ = bt_ctf_get_index (event, array, k);
+
+ contents[k] = (gdb_byte) bt_ctf_get_uint64 (element);
+ }
+
+ amt = (maddr + mlen) - offset;
+ if (amt > len)
+ amt = len;
+
+ memcpy (readbuf, &contents[offset - maddr], amt);
+
+ xfree (contents);
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return amt;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+ }
+
+ /* It's unduly pedantic to refuse to look at the executable for
+ read-only pieces; so do the equivalent of readonly regions aka
+ QTro packet. */
+ if (exec_bfd != NULL)
+ {
+ asection *s;
+ bfd_size_type size;
+ bfd_vma vma;
+
+ for (s = exec_bfd->sections; s; s = s->next)
+ {
+ if ((s->flags & SEC_LOAD) == 0
+ || (s->flags & SEC_READONLY) == 0)
+ continue;
+
+ vma = s->vma;
+ size = bfd_get_section_size (s);
+ if (vma <= offset && offset < (vma + size))
+ {
+ ULONGEST amt;
+
+ amt = (vma + size) - offset;
+ if (amt > len)
+ amt = len;
+
+ amt = bfd_get_section_contents (exec_bfd, s,
+ readbuf, offset - vma, amt);
+ return amt;
+ }
+ }
+ }
+
+ /* Indicate failure to find the requested memory block. */
+ return -1;
+}
+
+/* This is the implementation of target_ops method
+ to_get_trace_state_variable_value.
+ Iterate over events whose name is "tsv" in current frame. When the
+ trace variable is found, set the value of it to *VAL and return
+ true, otherwise return false. */
+
+static int
+ctf_get_trace_state_variable_value (int tsvnum, LONGEST *val)
+{
+ struct bt_iter_pos *pos;
+ int found = 0;
+
+ gdb_assert (ctf_iter != NULL);
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ /* Iterate through the traceframe's blocks, looking for 'V'
+ block. */
+ while (1)
+ {
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+ const char *name = bt_ctf_event_name (event);
+
+ if (name == NULL || strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "tsv") == 0)
+ {
+ const struct bt_definition *scope;
+ const struct bt_definition *def;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+
+ def = bt_ctf_get_field (event, scope, "num");
+ if (tsvnum == (int32_t) bt_ctf_get_uint64 (def))
+ {
+ def = bt_ctf_get_field (event, scope, "val");
+ *val = bt_ctf_get_uint64 (def);
+
+ found = 1;
+ }
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return found;
+}
+
+/* Return the tracepoint number in "frame" event. */
+
+static int
+ctf_get_tpnum_from_frame_event (struct bt_ctf_event *event)
+{
+ /* The packet context of events has a field "tpnum". */
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event, BT_STREAM_PACKET_CONTEXT);
+ uint64_t tpnum
+ = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "tpnum"));
+
+ return (int) tpnum;
+}
+
+/* Return the address at which the current frame was collected. */
+
+static ULONGEST
+ctf_get_traceframe_address (void)
+{
+ struct bt_ctf_event *event = NULL;
+ struct bt_iter_pos *pos;
+ ULONGEST addr = 0;
+
+ gdb_assert (ctf_iter != NULL);
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event1;
+
+ event1 = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event1);
+
+ if (name == NULL)
+ break;
+ else if (strcmp (name, "frame") == 0)
+ {
+ event = event1;
+ break;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ if (event != NULL)
+ {
+ int tpnum = ctf_get_tpnum_from_frame_event (event);
+ struct tracepoint *tp
+ = get_tracepoint_by_number_on_target (tpnum);
+
+ if (tp && tp->base.loc)
+ addr = tp->base.loc->address;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return addr;
+}
+
+/* This is the implementation of target_ops method to_trace_find.
+ Iterate the events whose name is "frame", extract the tracepoint
+ number in it. Return traceframe number when matched. */
+
+static int
+ctf_trace_find (enum trace_find_type type, int num,
+ ULONGEST addr1, ULONGEST addr2, int *tpp)
+{
+ int ret = -1;
+ int tfnum = 0;
+ int found = 0;
+ struct bt_iter_pos pos;
+
+ if (num == -1)
+ {
+ if (tpp != NULL)
+ *tpp = -1;
+ return -1;
+ }
+
+ gdb_assert (ctf_iter != NULL);
+ /* Set iterator back to the beginning. */
+ pos.type = BT_SEEK_BEGIN;
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), &pos);
+
+ while (1)
+ {
+ int id;
+ struct bt_ctf_event *event;
+ const char *name;
+
+ event = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (event == NULL || name == NULL)
+ break;
+
+ if (strcmp (name, "frame") == 0)
+ {
+ ULONGEST tfaddr;
+
+ if (type == tfind_number)
+ {
+ /* Looking for a specific trace frame. */
+ if (tfnum == num)
+ found = 1;
+ }
+ else
+ {
+ /* Start from the _next_ trace frame. */
+ if (tfnum > get_traceframe_number ())
+ {
+ switch (type)
+ {
+ case tfind_tp:
+ {
+ struct tracepoint *tp = get_tracepoint (num);
+
+ if (tp != NULL
+ && (tp->number_on_target
+ == ctf_get_tpnum_from_frame_event (event)))
+ found = 1;
+ break;
+ }
+ case tfind_pc:
+ tfaddr = ctf_get_traceframe_address ();
+ if (tfaddr == addr1)
+ found = 1;
+ break;
+ case tfind_range:
+ tfaddr = ctf_get_traceframe_address ();
+ if (addr1 <= tfaddr && tfaddr <= addr2)
+ found = 1;
+ break;
+ case tfind_outside:
+ tfaddr = ctf_get_traceframe_address ();
+ if (!(addr1 <= tfaddr && tfaddr <= addr2))
+ found = 1;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, _("unknown tfind type"));
+ }
+ }
+ }
+ if (found)
+ {
+ if (tpp != NULL)
+ *tpp = ctf_get_tpnum_from_frame_event (event);
+
+ /* Skip the event "frame". */
+ bt_iter_next (bt_ctf_get_iter (ctf_iter));
+
+ return tfnum;
+ }
+ tfnum++;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ return -1;
+}
+
+/* This is the implementation of target_ops method to_has_stack.
+ The target has a stack when GDB has already selected one trace
+ frame. */
+
+static int
+ctf_has_stack (struct target_ops *ops)
+{
+ return get_traceframe_number () != -1;
+}
+
+/* This is the implementation of target_ops method to_has_registers.
+ The target has registers when GDB has already selected one trace
+ frame. */
+
+static int
+ctf_has_registers (struct target_ops *ops)
+{
+ return get_traceframe_number () != -1;
+}
+
+/* This is the implementation of target_ops method to_traceframe_info.
+ Iterate the events whose name is "memory", in current
+ frame, extract memory range information, and return them in
+ traceframe_info. */
+
+static struct traceframe_info *
+ctf_traceframe_info (void)
+{
+ struct traceframe_info *info = XCNEW (struct traceframe_info);
+ const char *name;
+ struct bt_iter_pos *pos;
+
+ gdb_assert (ctf_iter != NULL);
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ do
+ {
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (name == NULL || strcmp (name, "register") == 0
+ || strcmp (name, "frame") == 0)
+ ;
+ else if (strcmp (name, "memory") == 0)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *def;
+ struct mem_range *r;
+
+ r = VEC_safe_push (mem_range_s, info->memory, NULL);
+ def = bt_ctf_get_field (event, scope, "address");
+ r->start = bt_ctf_get_uint64 (def);
+
+ def = bt_ctf_get_field (event, scope, "length");
+ r->length = (uint16_t) bt_ctf_get_uint64 (def);
+ }
+ else
+ warning (_("Unhandled trace block type (%s) "
+ "while building trace frame info."),
+ name);
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+ while (name != NULL && strcmp (name, "frame") != 0);
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return info;
+}
+
+static void
+init_ctf_ops (void)
+{
+ memset (&ctf_ops, 0, sizeof (ctf_ops));
+
+ ctf_ops.to_shortname = "ctf";
+ ctf_ops.to_longname = "CTF file";
+ ctf_ops.to_doc = "Use a CTF directory as a target.\n\
+Specify the filename of the CTF directory.";
+ ctf_ops.to_open = ctf_open;
+ ctf_ops.to_close = ctf_close;
+ ctf_ops.to_fetch_registers = ctf_fetch_registers;
+ ctf_ops.to_xfer_partial = ctf_xfer_partial;
+ ctf_ops.to_files_info = ctf_files_info;
+ ctf_ops.to_trace_find = ctf_trace_find;
+ ctf_ops.to_get_trace_state_variable_value
+ = ctf_get_trace_state_variable_value;
+ ctf_ops.to_stratum = process_stratum;
+ ctf_ops.to_has_stack = ctf_has_stack;
+ ctf_ops.to_has_registers = ctf_has_registers;
+ ctf_ops.to_traceframe_info = ctf_traceframe_info;
+ ctf_ops.to_magic = OPS_MAGIC;
+}
+
+#endif
+
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_ctf;
+
+/* module initialization */
+void
+_initialize_ctf (void)
+{
+#if HAVE_LIBBABELTRACE
+ init_ctf_ops ();
+
+ add_target (&ctf_ops);
+#endif
+}
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 9a2425b..6a30f6f 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -126,14 +126,6 @@ extern void (*deprecated_readline_end_hook) (void);
typedef struct trace_state_variable tsv_s;
DEF_VEC_O(tsv_s);
-/* An object describing the contents of a traceframe. */
-
-struct traceframe_info
-{
- /* Collected memory. */
- VEC(mem_range_s) *memory;
-};
-
static VEC(tsv_s) *tvariables;
/* The next integer to assign to a variable. */
@@ -3302,8 +3294,6 @@ static const struct trace_file_write_ops tfile_write_ops =
#define TRACE_WRITE_V_BLOCK(writer, num, val) \
writer->ops->frame_ops->write_v_block ((writer), (num), (val))
-extern int trace_regblock_size;
-
/* Save tracepoint data to file named FILENAME through WRITER. WRITER
determines the trace file format. If TARGET_DOES_SAVE is non-zero,
the save is performed on the target, otherwise GDB obtains all trace
@@ -3740,6 +3730,12 @@ get_traceframe_number (void)
return traceframe_number;
}
+int
+get_tracepoint_number (void)
+{
+ return tracepoint_number;
+}
+
/* Make the traceframe NUM be the current trace frame. Does nothing
if NUM is already current. */
diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
index c7eef7b..bad8d49 100644
--- a/gdb/tracepoint.h
+++ b/gdb/tracepoint.h
@@ -24,6 +24,14 @@
#include "memrange.h"
#include "gdb_vecs.h"
+/* An object describing the contents of a traceframe. */
+
+struct traceframe_info
+{
+ /* Collected memory. */
+ VEC(mem_range_s) *memory;
+};
+
/* A trace state variable is a value managed by a target being
traced. A trace state variable (or tsv for short) can be accessed
and assigned to by tracepoint actions and conditionals, but is not
@@ -142,6 +150,8 @@ struct trace_status *current_trace_status (void);
extern char *default_collect;
+extern int trace_regblock_size;
+
/* Struct to collect random info about tracepoints on the target. */
struct uploaded_tp
@@ -324,6 +334,9 @@ extern void (*deprecated_trace_start_stop_hook) (int start, int from_tty);
/* Returns the current traceframe number. */
extern int get_traceframe_number (void);
+/* Returns the tracepoint number for current traceframe. */
+extern int get_tracepoint_number (void);
+
/* Make the traceframe NUM be the current GDB trace frame number, and
do nothing more. In particular, this does not flush the
register/frame caches or notify the target about the trace frame
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 03/15] Read CTF by the ctf target
2013-03-26 16:16 ` Yao Qi
@ 2013-03-29 17:56 ` Doug Evans
2013-04-08 14:19 ` Yao Qi
0 siblings, 1 reply; 60+ messages in thread
From: Doug Evans @ 2013-03-29 17:56 UTC (permalink / raw)
To: Yao Qi; +Cc: Tom Tromey, gdb-patches
Yao Qi writes:
> 2013-03-26 Hui Zhu <hui@codesourcery.com>
> Yao Qi <yao@codesourcery.com>
>
> * configure.ac: Check libbabeltrace is installed.
> * config.in: Regenerate.
> * configure: Regenerate.
> * Makefile.in (LIBBABELTRACE): New.
> (CLIBS): Add LIBBABELTRACE.
> * ctf.c (ctx, ctf_iter, trace_dirname): New.
> (ctf_destroy, ctf_open_dir, ctf_open): New.
> (ctf_close, ctf_files_info): New.
> (ctf_fetch_registers, ctf_xfer_partial): New.
> (ctf_get_trace_state_variable_value): New.
> (ctf_get_tpnum_from_frame_event): New.
> (ctf_get_traceframe_address): New.
> (ctf_trace_find, ctf_has_stack): New.
> (ctf_has_registers, ctf_traceframe_info, init_ctf_ops): New.
> (_initialize_ctf): New.
> * tracepoint.c (get_tracepoint_number): New
> (struct traceframe_info, trace_regblock_size): Move it to ...
> * tracepoint.h: ... here.
> (get_tracepoint_number): Declare it.
> [...]
> +/* Return the address at which the current frame was collected. */
> +
> +static ULONGEST
> +ctf_get_traceframe_address (void)
> +{
> + struct bt_ctf_event *event = NULL;
> + struct bt_iter_pos *pos;
> + ULONGEST addr = 0;
> +
> + gdb_assert (ctf_iter != NULL);
> + pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
> + gdb_assert (pos->type == BT_SEEK_RESTORE);
> +
> + while (1)
> + {
> + const char *name;
> + struct bt_ctf_event *event1;
> +
> + event1 = bt_ctf_iter_read_event (ctf_iter);
> +
> + name = bt_ctf_event_name (event1);
> +
> + if (name == NULL)
> + break;
> + else if (strcmp (name, "frame") == 0)
> + {
> + event = event1;
> + break;
> + }
> +
> + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> + break;
> + }
> +
> + if (event != NULL)
> + {
> + int tpnum = ctf_get_tpnum_from_frame_event (event);
> + struct tracepoint *tp
> + = get_tracepoint_by_number_on_target (tpnum);
> +
> + if (tp && tp->base.loc)
> + addr = tp->base.loc->address;
> + }
> +
> + /* Restore the position. */
> + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
> +
> + return addr;
> +}
One last thing. Apologies for not bringing this up earlier.
I'm not sure we have any conventions explicitly saying to use CORE_ADDR
instead of {,U}LONGEST for addresses, but tp->base.loc->address is a CORE_ADDR.
It feels like everywhere you're using ULONGEST for addresses you need to
use CORE_ADDR instead.
Or maybe there's a specific reason to use ULONGEST?
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 03/15] Read CTF by the ctf target
2013-03-29 17:56 ` Doug Evans
@ 2013-04-08 14:19 ` Yao Qi
2013-04-08 21:48 ` Doug Evans
0 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-04-08 14:19 UTC (permalink / raw)
To: Doug Evans; +Cc: Tom Tromey, gdb-patches
On 03/30/2013 12:27 AM, Doug Evans wrote:
> One last thing. Apologies for not bringing this up earlier.
>
> I'm not sure we have any conventions explicitly saying to use CORE_ADDR
> instead of {,U}LONGEST for addresses, but tp->base.loc->address is a CORE_ADDR.
> It feels like everywhere you're using ULONGEST for addresses you need to
> use CORE_ADDR instead.
>
> Or maybe there's a specific reason to use ULONGEST?
Doug, good point. We should use CORE_ADDR here. This patch
<http://sourceware.org/ml/gdb-patches/2013-03/msg01126.html> has
converted ULONGEST in to_trace_find method of target_ops to CORE_ADDR.
CTF stuffs start to use CORE_ADDR in the updated patch below. Is it OK?
--
Yao (é½å°§)
gdb:
2013-04-08 Hui Zhu <hui@codesourcery.com>
Yao Qi <yao@codesourcery.com>
* configure.ac: Check libbabeltrace is installed.
* config.in: Regenerate.
* configure: Regenerate.
* Makefile.in (LIBBABELTRACE): New.
(CLIBS): Add LIBBABELTRACE.
* ctf.c (ctx, ctf_iter, trace_dirname): New.
(ctf_destroy, ctf_open_dir, ctf_open): New.
(ctf_close, ctf_files_info): New.
(ctf_fetch_registers, ctf_xfer_partial): New.
(ctf_get_trace_state_variable_value): New.
(ctf_get_tpnum_from_frame_event): New.
(ctf_get_traceframe_address): New.
(ctf_trace_find, ctf_has_stack): New.
(ctf_has_registers, ctf_traceframe_info, init_ctf_ops): New.
(_initialize_ctf): New.
* tracepoint.c (get_tracepoint_number): New
(struct traceframe_info, trace_regblock_size): Move it to ...
* tracepoint.h: ... here.
(get_tracepoint_number): Declare it.
---
gdb/Makefile.in | 6 +-
gdb/config.in | 3 +
gdb/configure | 517 +++++++++++++++++++++++++++++++++++++
gdb/configure.ac | 41 +++
gdb/ctf.c | 750 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/tracepoint.c | 16 +-
gdb/tracepoint.h | 13 +
7 files changed, 1335 insertions(+), 11 deletions(-)
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 498d42a..0814bcb 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -154,6 +154,10 @@ LIBEXPAT = @LIBEXPAT@
# Where is lzma? This will be empty if lzma was not available.
LIBLZMA = @LIBLZMA@
+# Where is libbabeltrace? This will be empty if lbabeltrace was not
+# available.
+LIBBABELTRACE = @LIBBABELTRACE@
+
WARN_CFLAGS = @WARN_CFLAGS@
WERROR_CFLAGS = @WERROR_CFLAGS@
GDB_WARN_CFLAGS = $(WARN_CFLAGS)
@@ -475,7 +479,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_
# LIBIBERTY appears twice on purpose.
CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
$(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ @PYTHON_LIBS@ \
- $(LIBEXPAT) $(LIBLZMA) \
+ $(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) \
$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU)
CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
diff --git a/gdb/config.in b/gdb/config.in
index 9e21325..c4e8eaa 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -180,6 +180,9 @@
/* Define if your <locale.h> file defines LC_MESSAGES. */
#undef HAVE_LC_MESSAGES
+/* Define if libbabeltrace is available */
+#undef HAVE_LIBBABELTRACE
+
/* Define to 1 if you have the `dl' library (-ldl). */
#undef HAVE_LIBDL
diff --git a/gdb/configure b/gdb/configure
index 0dd67f0..6588c72 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -592,6 +592,9 @@ enable_option_checking=no
ac_subst_vars='LTLIBOBJS
LIBOBJS
GDB_NM_FILE
+LTLIBBABELTRACE
+LIBBABELTRACE
+HAVE_LIBBABELTRACE
frags
target_subdir
CONFIG_UNINSTALL
@@ -819,6 +822,8 @@ with_x
enable_sim
enable_multi_ice
enable_gdbserver
+with_babeltrace
+with_libbabeltrace_prefix
'
ac_precious_vars='build_alias
host_alias
@@ -1532,6 +1537,9 @@ Optional Packages:
--with-tcl directory containing tcl configuration (tclConfig.sh)
--with-tk directory containing tk configuration (tkConfig.sh)
--with-x use the X Window System
+ --with-babeltrace include babeltrace support (auto/yes/no)
+ --with-libbabeltrace-prefix[=DIR] search for libbabeltrace in DIR/include and DIR/lib
+ --without-libbabeltrace-prefix don't search for libbabeltrace in includedir and libdir
Some influential environment variables:
CC C compiler command
@@ -14093,6 +14101,515 @@ if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then
as_fn_error "Automatic gdbserver build is not supported for this configuration" "$LINENO" 5
fi
+# Check for babeltrace and babeltrace-ctf
+
+# Check whether --with-babeltrace was given.
+if test "${with_babeltrace+set}" = set; then :
+ withval=$with_babeltrace;
+else
+ with_babeltrace=auto
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use babeltrace" >&5
+$as_echo_n "checking whether to use babeltrace... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_babeltrace" >&5
+$as_echo "$with_babeltrace" >&6; }
+
+if test "x$with_babeltrace" = "xno"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: babletrace support disabled; GDB is unable to read CTF data." >&5
+$as_echo "$as_me: WARNING: babletrace support disabled; GDB is unable to read CTF data." >&2;}
+else
+ # Append -Werror to CFLAGS so that configure can catch the warning
+ # "assignment from incompatible pointer type", which is related to
+ # the babeltrace change from 1.0.3 to 1.1.0. Babeltrace 1.1.0 works
+ # in GDB, while babeltrace 1.0.3 is broken.
+ # AC_LIB_HAVE_LINKFLAGS may modify CPPFLAGS in it, so it should be
+ # safe to save and restore CFLAGS here.
+ saved_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS -Werror"
+
+
+
+
+
+
+
+
+ use_additional=yes
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+
+# Check whether --with-libbabeltrace-prefix was given.
+if test "${with_libbabeltrace_prefix+set}" = set; then :
+ withval=$with_libbabeltrace_prefix;
+ if test "X$withval" = "Xno"; then
+ use_additional=no
+ else
+ if test "X$withval" = "X"; then
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ else
+ additional_includedir="$withval/include"
+ additional_libdir="$withval/lib"
+ fi
+ fi
+
+fi
+
+ LIBBABELTRACE=
+ LTLIBBABELTRACE=
+ INCBABELTRACE=
+ rpathdirs=
+ ltrpathdirs=
+ names_already_handled=
+ names_next_round='babeltrace babeltrace-ctf'
+ while test -n "$names_next_round"; do
+ names_this_round="$names_next_round"
+ names_next_round=
+ for name in $names_this_round; do
+ already_handled=
+ for n in $names_already_handled; do
+ if test "$n" = "$name"; then
+ already_handled=yes
+ break
+ fi
+ done
+ if test -z "$already_handled"; then
+ names_already_handled="$names_already_handled $name"
+ uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+ eval value=\"\$HAVE_LIB$uppername\"
+ if test -n "$value"; then
+ if test "$value" = yes; then
+ eval value=\"\$LIB$uppername\"
+ test -z "$value" || LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$value"
+ eval value=\"\$LTLIB$uppername\"
+ test -z "$value" || LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }$value"
+ else
+ :
+ fi
+ else
+ found_dir=
+ found_la=
+ found_so=
+ found_a=
+ if test $use_additional = yes; then
+ if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then
+ found_dir="$additional_libdir"
+ found_so="$additional_libdir/lib$name.$shlibext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ else
+ if test -f "$additional_libdir/lib$name.$libext"; then
+ found_dir="$additional_libdir"
+ found_a="$additional_libdir/lib$name.$libext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ fi
+ fi
+ fi
+ if test "X$found_dir" = "X"; then
+ for x in $LDFLAGS $LTLIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ case "$x" in
+ -L*)
+ dir=`echo "X$x" | sed -e 's/^X-L//'`
+ if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then
+ found_dir="$dir"
+ found_so="$dir/lib$name.$shlibext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ else
+ if test -f "$dir/lib$name.$libext"; then
+ found_dir="$dir"
+ found_a="$dir/lib$name.$libext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ if test "X$found_dir" != "X"; then
+ break
+ fi
+ done
+ fi
+ if test "X$found_dir" != "X"; then
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-L$found_dir -l$name"
+ if test "X$found_so" != "X"; then
+ if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ else
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $found_dir"
+ fi
+ if test "$hardcode_direct" = yes; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ else
+ if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $found_dir"
+ fi
+ else
+ haveit=
+ for x in $LDFLAGS $LIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$found_dir"
+ fi
+ if test "$hardcode_minus_L" != no; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ else
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-l$name"
+ fi
+ fi
+ fi
+ fi
+ else
+ if test "X$found_a" != "X"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_a"
+ else
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$found_dir -l$name"
+ fi
+ fi
+ additional_includedir=
+ case "$found_dir" in
+ */lib | */lib/)
+ basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'`
+ additional_includedir="$basedir/include"
+ ;;
+ esac
+ if test "X$additional_includedir" != "X"; then
+ if test "X$additional_includedir" != "X/usr/include"; then
+ haveit=
+ if test "X$additional_includedir" = "X/usr/local/include"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ for x in $CPPFLAGS $INCBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-I$additional_includedir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_includedir"; then
+ INCBABELTRACE="${INCBABELTRACE}${INCBABELTRACE:+ }-I$additional_includedir"
+ fi
+ fi
+ fi
+ fi
+ fi
+ if test -n "$found_la"; then
+ save_libdir="$libdir"
+ case "$found_la" in
+ */* | *\\*) . "$found_la" ;;
+ *) . "./$found_la" ;;
+ esac
+ libdir="$save_libdir"
+ for dep in $dependency_libs; do
+ case "$dep" in
+ -L*)
+ additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+ if test "X$additional_libdir" != "X/usr/lib"; then
+ haveit=
+ if test "X$additional_libdir" = "X/usr/local/lib"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ haveit=
+ for x in $LDFLAGS $LIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$additional_libdir"
+ fi
+ fi
+ haveit=
+ for x in $LDFLAGS $LTLIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-L$additional_libdir"
+ fi
+ fi
+ fi
+ fi
+ ;;
+ -R*)
+ dir=`echo "X$dep" | sed -e 's/^X-R//'`
+ if test "$enable_rpath" != no; then
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $dir"
+ fi
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $dir"
+ fi
+ fi
+ ;;
+ -l*)
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+ ;;
+ *.la)
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+ ;;
+ *)
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$dep"
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }$dep"
+ ;;
+ esac
+ done
+ fi
+ else
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-l$name"
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-l$name"
+ fi
+ fi
+ fi
+ done
+ done
+ if test "X$rpathdirs" != "X"; then
+ if test -n "$hardcode_libdir_separator"; then
+ alldirs=
+ for found_dir in $rpathdirs; do
+ alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+ done
+ acl_save_libdir="$libdir"
+ libdir="$alldirs"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$flag"
+ else
+ for found_dir in $rpathdirs; do
+ acl_save_libdir="$libdir"
+ libdir="$found_dir"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$flag"
+ done
+ fi
+ fi
+ if test "X$ltrpathdirs" != "X"; then
+ for found_dir in $ltrpathdirs; do
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-R$found_dir"
+ done
+ fi
+
+
+ ac_save_CPPFLAGS="$CPPFLAGS"
+
+ for element in $INCBABELTRACE; do
+ haveit=
+ for x in $CPPFLAGS; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X$element"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element"
+ fi
+ done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libbabeltrace" >&5
+$as_echo_n "checking for libbabeltrace... " >&6; }
+if test "${ac_cv_libbabeltrace+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ac_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIBBABELTRACE"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <babeltrace/babeltrace.h>
+ #include <babeltrace/ctf/events.h>
+ #include <babeltrace/ctf/iterator.h>
+int
+main ()
+{
+struct bt_iter_pos *pos = bt_iter_get_pos (bt_ctf_get_iter (NULL));
+ struct bt_ctf_event *event = NULL;
+ const struct bt_definition *scope;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_STREAM_EVENT_HEADER);
+ bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_libbabeltrace=yes
+else
+ ac_cv_libbabeltrace=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$ac_save_LIBS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libbabeltrace" >&5
+$as_echo "$ac_cv_libbabeltrace" >&6; }
+ if test "$ac_cv_libbabeltrace" = yes; then
+ HAVE_LIBBABELTRACE=yes
+
+$as_echo "#define HAVE_LIBBABELTRACE 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libbabeltrace" >&5
+$as_echo_n "checking how to link with libbabeltrace... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBBABELTRACE" >&5
+$as_echo "$LIBBABELTRACE" >&6; }
+ else
+ HAVE_LIBBABELTRACE=no
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIBBABELTRACE=
+ LTLIBBABELTRACE=
+ fi
+
+
+
+
+
+
+ CFLAGS=$saved_CFLAGS
+
+ if test "$HAVE_LIBBABELTRACE" != yes; then
+ if test "$with_babeltrace" = yes; then
+ as_fn_error "babeltrace is missing or unusable" "$LINENO" 5
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: babeltrace is missing or unusable; GDB is unable to read CTF data." >&5
+$as_echo "$as_me: WARNING: babeltrace is missing or unusable; GDB is unable to read CTF data." >&2;}
+ fi
+ fi
+fi
+
# If nativefile (NAT_FILE) is not set in config/*/*.m[ht] files, we link
# to an empty version.
diff --git a/gdb/configure.ac b/gdb/configure.ac
index c17f587..149ac37 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -2321,6 +2321,47 @@ if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then
AC_MSG_ERROR(Automatic gdbserver build is not supported for this configuration)
fi
+# Check for babeltrace and babeltrace-ctf
+AC_ARG_WITH(babeltrace,
+ AC_HELP_STRING([--with-babeltrace], [include babeltrace support (auto/yes/no)]),
+ [], [with_babeltrace=auto])
+AC_MSG_CHECKING([whether to use babeltrace])
+AC_MSG_RESULT([$with_babeltrace])
+
+if test "x$with_babeltrace" = "xno"; then
+ AC_MSG_WARN([babletrace support disabled; GDB is unable to read CTF data.])
+else
+ # Append -Werror to CFLAGS so that configure can catch the warning
+ # "assignment from incompatible pointer type", which is related to
+ # the babeltrace change from 1.0.3 to 1.1.0. Babeltrace 1.1.0 works
+ # in GDB, while babeltrace 1.0.3 is broken.
+ # AC_LIB_HAVE_LINKFLAGS may modify CPPFLAGS in it, so it should be
+ # safe to save and restore CFLAGS here.
+ saved_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS -Werror"
+ AC_LIB_HAVE_LINKFLAGS([babeltrace], [babeltrace-ctf],
+ [#include <babeltrace/babeltrace.h>
+ #include <babeltrace/ctf/events.h>
+ #include <babeltrace/ctf/iterator.h>],
+ [struct bt_iter_pos *pos = bt_iter_get_pos (bt_ctf_get_iter (NULL));
+ struct bt_ctf_event *event = NULL;
+ const struct bt_definition *scope;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_STREAM_EVENT_HEADER);
+ bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+ ])
+ CFLAGS=$saved_CFLAGS
+
+ if test "$HAVE_LIBBABELTRACE" != yes; then
+ if test "$with_babeltrace" = yes; then
+ AC_MSG_ERROR([babeltrace is missing or unusable])
+ else
+ AC_MSG_WARN([babeltrace is missing or unusable; GDB is unable to read CTF data.])
+ fi
+ fi
+fi
+
# If nativefile (NAT_FILE) is not set in config/*/*.m[ht] files, we link
# to an empty version.
diff --git a/gdb/ctf.c b/gdb/ctf.c
index de54051..53daf91 100644
--- a/gdb/ctf.c
+++ b/gdb/ctf.c
@@ -24,6 +24,7 @@
#include "tracepoint.h"
#include "regcache.h"
#include "gdb_stat.h"
+#include "exec.h"
#include <ctype.h>
@@ -670,3 +671,752 @@ ctf_trace_file_writer_new (void)
return (struct trace_file_writer *) writer;
}
+
+#if HAVE_LIBBABELTRACE
+/* Use libbabeltrace to read CTF data. The libbabeltrace provides
+ iterator to iterate over each event in CTF data and APIs to get
+ details of event and packet, so it is very convenient to use
+ libbabeltrace to access events in CTF. */
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/iterator.h>
+
+/* The struct pointer for current CTF directory. */
+static struct bt_context *ctx = NULL;
+static struct bt_ctf_iter *ctf_iter = NULL;
+/* The name of CTF directory. */
+static char *trace_dirname;
+
+static struct target_ops ctf_ops;
+
+/* Destroy ctf iterator and context. */
+
+static void
+ctf_destroy (void)
+{
+ if (ctf_iter != NULL)
+ {
+ bt_ctf_iter_destroy (ctf_iter);
+ ctf_iter = NULL;
+ }
+ if (ctx != NULL)
+ {
+ bt_context_put (ctx);
+ ctx = NULL;
+ }
+}
+
+/* Open CTF trace data in DIRNAME. */
+
+static void
+ctf_open_dir (char *dirname)
+{
+ int ret;
+ struct bt_iter_pos begin_pos;
+ struct bt_iter_pos *pos;
+
+ ctx = bt_context_create ();
+ if (ctx == NULL)
+ error (_("Unable to initialize libbabeltrace"));
+ ret = bt_context_add_trace (ctx, dirname, "ctf", NULL, NULL, NULL);
+ if (ret < 0)
+ {
+ ctf_destroy ();
+ error (_("Unable to use libbabeltrace open \"%s\""), dirname);
+ }
+
+ begin_pos.type = BT_SEEK_BEGIN;
+ ctf_iter = bt_ctf_iter_create (ctx, &begin_pos, NULL);
+ if (ctf_iter == NULL)
+ {
+ ctf_destroy ();
+ error (_("Unable to use libbabeltrace open \"%s\""), dirname);
+ }
+
+ /* Iterate over events, and look for an event for register block
+ to set trace_regblock_size. */
+
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event;
+
+ event = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (name == NULL)
+ break;
+ else if (strcmp (name, "register") == 0)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+
+ trace_regblock_size
+ = bt_ctf_get_array_len (bt_ctf_get_decl_from_def (array));
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+}
+
+/* This is the implementation of target_ops method to_open. Open CTF
+ trace data, read trace status, trace state variables and tracepoint
+ definitions from the first packet. Set the start position at the
+ second packet which contains events on trace blocks. */
+
+static void
+ctf_open (char *dirname, int from_tty)
+{
+ if (!dirname)
+ error (_("No CTF directory specified."));
+
+ ctf_open_dir (dirname);
+
+ target_preopen (from_tty);
+ trace_dirname = xstrdup (dirname);
+ push_target (&ctf_ops);
+}
+
+/* This is the implementation of target_ops method to_close. Destroy
+ CTF iterator and context. */
+
+static void
+ctf_close (void)
+{
+ ctf_destroy ();
+ xfree (trace_dirname);
+ trace_dirname = NULL;
+}
+
+/* This is the implementation of target_ops method to_files_info.
+ Print the directory name of CTF trace data. */
+
+static void
+ctf_files_info (struct target_ops *t)
+{
+ printf_filtered ("\t`%s'\n", trace_dirname);
+}
+
+/* This is the implementation of target_ops method to_fetch_registers.
+ Iterate over events whose name is "register" in current frame,
+ extract contents from events, and set REGCACHE with the contents.
+ If no matched events are found, mark registers unavailable. */
+
+static void
+ctf_fetch_registers (struct target_ops *ops,
+ struct regcache *regcache, int regno)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ int offset, regn, regsize, pc_regno;
+ char *regs = NULL;
+ struct bt_ctf_event *event = NULL;
+ struct bt_iter_pos *pos;
+
+ /* An uninitialized reg size says we're not going to be
+ successful at getting register blocks. */
+ if (trace_regblock_size == 0)
+ return;
+
+ gdb_assert (ctf_iter != NULL);
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event1;
+
+ event1 = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event1);
+
+ if (name == NULL || strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "register") == 0)
+ {
+ event = event1;
+ break;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ if (event != NULL)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+
+ regs = bt_ctf_get_char_array (array);
+ /* Assume the block is laid out in GDB register number order,
+ each register with the size that it has in GDB. */
+ offset = 0;
+ for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+ {
+ regsize = register_size (gdbarch, regn);
+ /* Make sure we stay within block bounds. */
+ if (offset + regsize >= trace_regblock_size)
+ break;
+ if (regcache_register_status (regcache, regn) == REG_UNKNOWN)
+ {
+ if (regno == regn)
+ {
+ regcache_raw_supply (regcache, regno, regs + offset);
+ break;
+ }
+ else if (regno == -1)
+ {
+ regcache_raw_supply (regcache, regn, regs + offset);
+ }
+ }
+ offset += regsize;
+ }
+ return;
+ }
+
+ regs = alloca (trace_regblock_size);
+
+ /* We get here if no register data has been found. Mark registers
+ as unavailable. */
+ for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+ regcache_raw_supply (regcache, regn, NULL);
+
+ /* We can often usefully guess that the PC is going to be the same
+ as the address of the tracepoint. */
+ pc_regno = gdbarch_pc_regnum (gdbarch);
+ if (pc_regno >= 0 && (regno == -1 || regno == pc_regno))
+ {
+ struct tracepoint *tp = get_tracepoint (get_tracepoint_number ());
+
+ if (tp != NULL && tp->base.loc)
+ {
+ /* But don't try to guess if tracepoint is multi-location... */
+ if (tp->base.loc->next != NULL)
+ {
+ warning (_("Tracepoint %d has multiple "
+ "locations, cannot infer $pc"),
+ tp->base.number);
+ return;
+ }
+ /* ... or does while-stepping. */
+ if (tp->step_count > 0)
+ {
+ warning (_("Tracepoint %d does while-stepping, "
+ "cannot infer $pc"),
+ tp->base.number);
+ return;
+ }
+
+ store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
+ gdbarch_byte_order (gdbarch),
+ tp->base.loc->address);
+ regcache_raw_supply (regcache, pc_regno, regs);
+ }
+ }
+}
+
+/* This is the implementation of target_ops method to_xfer_partial.
+ Iterate over events whose name is "memory" in
+ current frame, extract the address and length from events. If
+ OFFSET is within the range, read the contents from events to
+ READBUF. */
+
+static LONGEST
+ctf_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf, ULONGEST offset,
+ LONGEST len)
+{
+ /* We're only doing regular memory for now. */
+ if (object != TARGET_OBJECT_MEMORY)
+ return -1;
+
+ if (readbuf == NULL)
+ error (_("ctf_xfer_partial: trace file is read-only"));
+
+ if (get_traceframe_number () != -1)
+ {
+ struct bt_iter_pos *pos;
+ int i = 0;
+
+ gdb_assert (ctf_iter != NULL);
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ /* Iterate through the traceframe's blocks, looking for
+ memory. */
+ while (1)
+ {
+ ULONGEST amt;
+ uint64_t maddr;
+ uint16_t mlen;
+ enum bfd_endian byte_order
+ = gdbarch_byte_order (target_gdbarch ());
+ const struct bt_definition *scope;
+ const struct bt_definition *def;
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+ const char *name = bt_ctf_event_name (event);
+
+ if (strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "memory") != 0)
+ {
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+
+ continue;
+ }
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+
+ def = bt_ctf_get_field (event, scope, "address");
+ maddr = bt_ctf_get_uint64 (def);
+ def = bt_ctf_get_field (event, scope, "length");
+ mlen = (uint16_t) bt_ctf_get_uint64 (def);
+
+ /* If the block includes the first part of the desired
+ range, return as much it has; GDB will re-request the
+ remainder, which might be in a different block of this
+ trace frame. */
+ if (maddr <= offset && offset < (maddr + mlen))
+ {
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+ const struct bt_declaration *decl
+ = bt_ctf_get_decl_from_def (array);
+ gdb_byte *contents;
+ int k;
+
+ contents = xmalloc (mlen);
+
+ for (k = 0; k < mlen; k++)
+ {
+ const struct bt_definition *element
+ = bt_ctf_get_index (event, array, k);
+
+ contents[k] = (gdb_byte) bt_ctf_get_uint64 (element);
+ }
+
+ amt = (maddr + mlen) - offset;
+ if (amt > len)
+ amt = len;
+
+ memcpy (readbuf, &contents[offset - maddr], amt);
+
+ xfree (contents);
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return amt;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+ }
+
+ /* It's unduly pedantic to refuse to look at the executable for
+ read-only pieces; so do the equivalent of readonly regions aka
+ QTro packet. */
+ if (exec_bfd != NULL)
+ {
+ asection *s;
+ bfd_size_type size;
+ bfd_vma vma;
+
+ for (s = exec_bfd->sections; s; s = s->next)
+ {
+ if ((s->flags & SEC_LOAD) == 0
+ || (s->flags & SEC_READONLY) == 0)
+ continue;
+
+ vma = s->vma;
+ size = bfd_get_section_size (s);
+ if (vma <= offset && offset < (vma + size))
+ {
+ ULONGEST amt;
+
+ amt = (vma + size) - offset;
+ if (amt > len)
+ amt = len;
+
+ amt = bfd_get_section_contents (exec_bfd, s,
+ readbuf, offset - vma, amt);
+ return amt;
+ }
+ }
+ }
+
+ /* Indicate failure to find the requested memory block. */
+ return -1;
+}
+
+/* This is the implementation of target_ops method
+ to_get_trace_state_variable_value.
+ Iterate over events whose name is "tsv" in current frame. When the
+ trace variable is found, set the value of it to *VAL and return
+ true, otherwise return false. */
+
+static int
+ctf_get_trace_state_variable_value (int tsvnum, LONGEST *val)
+{
+ struct bt_iter_pos *pos;
+ int found = 0;
+
+ gdb_assert (ctf_iter != NULL);
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ /* Iterate through the traceframe's blocks, looking for 'V'
+ block. */
+ while (1)
+ {
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+ const char *name = bt_ctf_event_name (event);
+
+ if (name == NULL || strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "tsv") == 0)
+ {
+ const struct bt_definition *scope;
+ const struct bt_definition *def;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+
+ def = bt_ctf_get_field (event, scope, "num");
+ if (tsvnum == (int32_t) bt_ctf_get_uint64 (def))
+ {
+ def = bt_ctf_get_field (event, scope, "val");
+ *val = bt_ctf_get_uint64 (def);
+
+ found = 1;
+ }
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return found;
+}
+
+/* Return the tracepoint number in "frame" event. */
+
+static int
+ctf_get_tpnum_from_frame_event (struct bt_ctf_event *event)
+{
+ /* The packet context of events has a field "tpnum". */
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event, BT_STREAM_PACKET_CONTEXT);
+ uint64_t tpnum
+ = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "tpnum"));
+
+ return (int) tpnum;
+}
+
+/* Return the address at which the current frame was collected. */
+
+static CORE_ADDR
+ctf_get_traceframe_address (void)
+{
+ struct bt_ctf_event *event = NULL;
+ struct bt_iter_pos *pos;
+ CORE_ADDR addr = 0;
+
+ gdb_assert (ctf_iter != NULL);
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event1;
+
+ event1 = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event1);
+
+ if (name == NULL)
+ break;
+ else if (strcmp (name, "frame") == 0)
+ {
+ event = event1;
+ break;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ if (event != NULL)
+ {
+ int tpnum = ctf_get_tpnum_from_frame_event (event);
+ struct tracepoint *tp
+ = get_tracepoint_by_number_on_target (tpnum);
+
+ if (tp && tp->base.loc)
+ addr = tp->base.loc->address;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return addr;
+}
+
+/* This is the implementation of target_ops method to_trace_find.
+ Iterate the events whose name is "frame", extract the tracepoint
+ number in it. Return traceframe number when matched. */
+
+static int
+ctf_trace_find (enum trace_find_type type, int num,
+ CORE_ADDR addr1, CORE_ADDR addr2, int *tpp)
+{
+ int ret = -1;
+ int tfnum = 0;
+ int found = 0;
+ struct bt_iter_pos pos;
+
+ if (num == -1)
+ {
+ if (tpp != NULL)
+ *tpp = -1;
+ return -1;
+ }
+
+ gdb_assert (ctf_iter != NULL);
+ /* Set iterator back to the beginning. */
+ pos.type = BT_SEEK_BEGIN;
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), &pos);
+
+ while (1)
+ {
+ int id;
+ struct bt_ctf_event *event;
+ const char *name;
+
+ event = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (event == NULL || name == NULL)
+ break;
+
+ if (strcmp (name, "frame") == 0)
+ {
+ CORE_ADDR tfaddr;
+
+ if (type == tfind_number)
+ {
+ /* Looking for a specific trace frame. */
+ if (tfnum == num)
+ found = 1;
+ }
+ else
+ {
+ /* Start from the _next_ trace frame. */
+ if (tfnum > get_traceframe_number ())
+ {
+ switch (type)
+ {
+ case tfind_tp:
+ {
+ struct tracepoint *tp = get_tracepoint (num);
+
+ if (tp != NULL
+ && (tp->number_on_target
+ == ctf_get_tpnum_from_frame_event (event)))
+ found = 1;
+ break;
+ }
+ case tfind_pc:
+ tfaddr = ctf_get_traceframe_address ();
+ if (tfaddr == addr1)
+ found = 1;
+ break;
+ case tfind_range:
+ tfaddr = ctf_get_traceframe_address ();
+ if (addr1 <= tfaddr && tfaddr <= addr2)
+ found = 1;
+ break;
+ case tfind_outside:
+ tfaddr = ctf_get_traceframe_address ();
+ if (!(addr1 <= tfaddr && tfaddr <= addr2))
+ found = 1;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, _("unknown tfind type"));
+ }
+ }
+ }
+ if (found)
+ {
+ if (tpp != NULL)
+ *tpp = ctf_get_tpnum_from_frame_event (event);
+
+ /* Skip the event "frame". */
+ bt_iter_next (bt_ctf_get_iter (ctf_iter));
+
+ return tfnum;
+ }
+ tfnum++;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ return -1;
+}
+
+/* This is the implementation of target_ops method to_has_stack.
+ The target has a stack when GDB has already selected one trace
+ frame. */
+
+static int
+ctf_has_stack (struct target_ops *ops)
+{
+ return get_traceframe_number () != -1;
+}
+
+/* This is the implementation of target_ops method to_has_registers.
+ The target has registers when GDB has already selected one trace
+ frame. */
+
+static int
+ctf_has_registers (struct target_ops *ops)
+{
+ return get_traceframe_number () != -1;
+}
+
+/* This is the implementation of target_ops method to_traceframe_info.
+ Iterate the events whose name is "memory", in current
+ frame, extract memory range information, and return them in
+ traceframe_info. */
+
+static struct traceframe_info *
+ctf_traceframe_info (void)
+{
+ struct traceframe_info *info = XCNEW (struct traceframe_info);
+ const char *name;
+ struct bt_iter_pos *pos;
+
+ gdb_assert (ctf_iter != NULL);
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ do
+ {
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (name == NULL || strcmp (name, "register") == 0
+ || strcmp (name, "frame") == 0)
+ ;
+ else if (strcmp (name, "memory") == 0)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *def;
+ struct mem_range *r;
+
+ r = VEC_safe_push (mem_range_s, info->memory, NULL);
+ def = bt_ctf_get_field (event, scope, "address");
+ r->start = bt_ctf_get_uint64 (def);
+
+ def = bt_ctf_get_field (event, scope, "length");
+ r->length = (uint16_t) bt_ctf_get_uint64 (def);
+ }
+ else
+ warning (_("Unhandled trace block type (%s) "
+ "while building trace frame info."),
+ name);
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+ while (name != NULL && strcmp (name, "frame") != 0);
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return info;
+}
+
+static void
+init_ctf_ops (void)
+{
+ memset (&ctf_ops, 0, sizeof (ctf_ops));
+
+ ctf_ops.to_shortname = "ctf";
+ ctf_ops.to_longname = "CTF file";
+ ctf_ops.to_doc = "Use a CTF directory as a target.\n\
+Specify the filename of the CTF directory.";
+ ctf_ops.to_open = ctf_open;
+ ctf_ops.to_close = ctf_close;
+ ctf_ops.to_fetch_registers = ctf_fetch_registers;
+ ctf_ops.to_xfer_partial = ctf_xfer_partial;
+ ctf_ops.to_files_info = ctf_files_info;
+ ctf_ops.to_trace_find = ctf_trace_find;
+ ctf_ops.to_get_trace_state_variable_value
+ = ctf_get_trace_state_variable_value;
+ ctf_ops.to_stratum = process_stratum;
+ ctf_ops.to_has_stack = ctf_has_stack;
+ ctf_ops.to_has_registers = ctf_has_registers;
+ ctf_ops.to_traceframe_info = ctf_traceframe_info;
+ ctf_ops.to_magic = OPS_MAGIC;
+}
+
+#endif
+
+/* -Wmissing-prototypes */
+extern initialize_file_ftype _initialize_ctf;
+
+/* module initialization */
+void
+_initialize_ctf (void)
+{
+#if HAVE_LIBBABELTRACE
+ init_ctf_ops ();
+
+ add_target (&ctf_ops);
+#endif
+}
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 3d8b131..962e632 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -127,14 +127,6 @@ extern void (*deprecated_readline_end_hook) (void);
typedef struct trace_state_variable tsv_s;
DEF_VEC_O(tsv_s);
-/* An object describing the contents of a traceframe. */
-
-struct traceframe_info
-{
- /* Collected memory. */
- VEC(mem_range_s) *memory;
-};
-
static VEC(tsv_s) *tvariables;
/* The next integer to assign to a variable. */
@@ -3303,8 +3295,6 @@ static const struct trace_file_write_ops tfile_write_ops =
#define TRACE_WRITE_V_BLOCK(writer, num, val) \
writer->ops->frame_ops->write_v_block ((writer), (num), (val))
-extern int trace_regblock_size;
-
/* Save tracepoint data to file named FILENAME through WRITER. WRITER
determines the trace file format. If TARGET_DOES_SAVE is non-zero,
the save is performed on the target, otherwise GDB obtains all trace
@@ -3741,6 +3731,12 @@ get_traceframe_number (void)
return traceframe_number;
}
+int
+get_tracepoint_number (void)
+{
+ return tracepoint_number;
+}
+
/* Make the traceframe NUM be the current trace frame. Does nothing
if NUM is already current. */
diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
index 8df906f..378824e 100644
--- a/gdb/tracepoint.h
+++ b/gdb/tracepoint.h
@@ -24,6 +24,14 @@
#include "memrange.h"
#include "gdb_vecs.h"
+/* An object describing the contents of a traceframe. */
+
+struct traceframe_info
+{
+ /* Collected memory. */
+ VEC(mem_range_s) *memory;
+};
+
/* A trace state variable is a value managed by a target being
traced. A trace state variable (or tsv for short) can be accessed
and assigned to by tracepoint actions and conditionals, but is not
@@ -142,6 +150,8 @@ struct trace_status *current_trace_status (void);
extern char *default_collect;
+extern int trace_regblock_size;
+
/* Struct to collect random info about tracepoints on the target. */
struct uploaded_tp
@@ -324,6 +334,9 @@ extern void (*deprecated_trace_start_stop_hook) (int start, int from_tty);
/* Returns the current traceframe number. */
extern int get_traceframe_number (void);
+/* Returns the tracepoint number for current traceframe. */
+extern int get_tracepoint_number (void);
+
/* Make the traceframe NUM be the current GDB trace frame number, and
do nothing more. In particular, this does not flush the
register/frame caches or notify the target about the trace frame
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 03/15] Read CTF by the ctf target
2013-04-08 14:19 ` Yao Qi
@ 2013-04-08 21:48 ` Doug Evans
2013-04-09 15:23 ` Yao Qi
0 siblings, 1 reply; 60+ messages in thread
From: Doug Evans @ 2013-04-08 21:48 UTC (permalink / raw)
To: Yao Qi; +Cc: Tom Tromey, gdb-patches
Yao Qi writes:
> On 03/30/2013 12:27 AM, Doug Evans wrote:
> > One last thing. Apologies for not bringing this up earlier.
> >
> > I'm not sure we have any conventions explicitly saying to use CORE_ADDR
> > instead of {,U}LONGEST for addresses, but tp->base.loc->address is a CORE_ADDR.
> > It feels like everywhere you're using ULONGEST for addresses you need to
> > use CORE_ADDR instead.
> >
> > Or maybe there's a specific reason to use ULONGEST?
>
> Doug, good point. We should use CORE_ADDR here. This patch
> <http://sourceware.org/ml/gdb-patches/2013-03/msg01126.html> has
> converted ULONGEST in to_trace_find method of target_ops to CORE_ADDR.
> CTF stuffs start to use CORE_ADDR in the updated patch below. Is it OK?
Hi. Just a few nits, inline.
> 2013-04-08 Hui Zhu <hui@codesourcery.com>
> Yao Qi <yao@codesourcery.com>
>
> * configure.ac: Check libbabeltrace is installed.
> * config.in: Regenerate.
> * configure: Regenerate.
> * Makefile.in (LIBBABELTRACE): New.
> (CLIBS): Add LIBBABELTRACE.
> * ctf.c (ctx, ctf_iter, trace_dirname): New.
> (ctf_destroy, ctf_open_dir, ctf_open): New.
> (ctf_close, ctf_files_info): New.
> (ctf_fetch_registers, ctf_xfer_partial): New.
> (ctf_get_trace_state_variable_value): New.
> (ctf_get_tpnum_from_frame_event): New.
> (ctf_get_traceframe_address): New.
> (ctf_trace_find, ctf_has_stack): New.
> (ctf_has_registers, ctf_traceframe_info, init_ctf_ops): New.
> (_initialize_ctf): New.
> * tracepoint.c (get_tracepoint_number): New
> (struct traceframe_info, trace_regblock_size): Move it to ...
> * tracepoint.h: ... here.
> (get_tracepoint_number): Declare it.
> ---
> gdb/Makefile.in | 6 +-
> gdb/config.in | 3 +
> gdb/configure | 517 +++++++++++++++++++++++++++++++++++++
> gdb/configure.ac | 41 +++
> gdb/ctf.c | 750 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
> gdb/tracepoint.c | 16 +-
> gdb/tracepoint.h | 13 +
> 7 files changed, 1335 insertions(+), 11 deletions(-)
>
> diff --git a/gdb/Makefile.in b/gdb/Makefile.in
> index 498d42a..0814bcb 100644
> --- a/gdb/Makefile.in
> +++ b/gdb/Makefile.in
> @@ -154,6 +154,10 @@ LIBEXPAT = @LIBEXPAT@
> # Where is lzma? This will be empty if lzma was not available.
> LIBLZMA = @LIBLZMA@
>
> +# Where is libbabeltrace? This will be empty if lbabeltrace was not
> +# available.
> +LIBBABELTRACE = @LIBBABELTRACE@
> +
> WARN_CFLAGS = @WARN_CFLAGS@
> WERROR_CFLAGS = @WERROR_CFLAGS@
> GDB_WARN_CFLAGS = $(WARN_CFLAGS)
> @@ -475,7 +479,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_
> # LIBIBERTY appears twice on purpose.
> CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
> $(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ @PYTHON_LIBS@ \
> - $(LIBEXPAT) $(LIBLZMA) \
> + $(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) \
> $(LIBIBERTY) $(WIN32LIBS) $(LIBGNU)
> CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
> $(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
> diff --git a/gdb/config.in b/gdb/config.in
> index 9e21325..c4e8eaa 100644
> --- a/gdb/config.in
> +++ b/gdb/config.in
> @@ -180,6 +180,9 @@
> /* Define if your <locale.h> file defines LC_MESSAGES. */
> #undef HAVE_LC_MESSAGES
>
> +/* Define if libbabeltrace is available */
> +#undef HAVE_LIBBABELTRACE
> +
> /* Define to 1 if you have the `dl' library (-ldl). */
> #undef HAVE_LIBDL
>
> [...]
>
> diff --git a/gdb/configure.ac b/gdb/configure.ac
> index c17f587..149ac37 100644
> --- a/gdb/configure.ac
> +++ b/gdb/configure.ac
> @@ -2321,6 +2321,47 @@ if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then
> AC_MSG_ERROR(Automatic gdbserver build is not supported for this configuration)
> fi
>
> +# Check for babeltrace and babeltrace-ctf
> +AC_ARG_WITH(babeltrace,
> + AC_HELP_STRING([--with-babeltrace], [include babeltrace support (auto/yes/no)]),
> + [], [with_babeltrace=auto])
> +AC_MSG_CHECKING([whether to use babeltrace])
> +AC_MSG_RESULT([$with_babeltrace])
> +
> +if test "x$with_babeltrace" = "xno"; then
> + AC_MSG_WARN([babletrace support disabled; GDB is unable to read CTF data.])
> +else
> + # Append -Werror to CFLAGS so that configure can catch the warning
> + # "assignment from incompatible pointer type", which is related to
> + # the babeltrace change from 1.0.3 to 1.1.0. Babeltrace 1.1.0 works
> + # in GDB, while babeltrace 1.0.3 is broken.
> + # AC_LIB_HAVE_LINKFLAGS may modify CPPFLAGS in it, so it should be
> + # safe to save and restore CFLAGS here.
> + saved_CFLAGS=$CFLAGS
> + CFLAGS="$CFLAGS -Werror"
> + AC_LIB_HAVE_LINKFLAGS([babeltrace], [babeltrace-ctf],
> + [#include <babeltrace/babeltrace.h>
> + #include <babeltrace/ctf/events.h>
> + #include <babeltrace/ctf/iterator.h>],
> + [struct bt_iter_pos *pos = bt_iter_get_pos (bt_ctf_get_iter (NULL));
> + struct bt_ctf_event *event = NULL;
> + const struct bt_definition *scope;
> +
> + scope = bt_ctf_get_top_level_scope (event,
> + BT_STREAM_EVENT_HEADER);
> + bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
> + ])
> + CFLAGS=$saved_CFLAGS
> +
> + if test "$HAVE_LIBBABELTRACE" != yes; then
> + if test "$with_babeltrace" = yes; then
> + AC_MSG_ERROR([babeltrace is missing or unusable])
> + else
> + AC_MSG_WARN([babeltrace is missing or unusable; GDB is unable to read CTF data.])
> + fi
> + fi
> +fi
> +
> # If nativefile (NAT_FILE) is not set in config/*/*.m[ht] files, we link
> # to an empty version.
>
> diff --git a/gdb/ctf.c b/gdb/ctf.c
> index de54051..53daf91 100644
> --- a/gdb/ctf.c
> +++ b/gdb/ctf.c
> @@ -24,6 +24,7 @@
> #include "tracepoint.h"
> #include "regcache.h"
> #include "gdb_stat.h"
> +#include "exec.h"
>
> #include <ctype.h>
>
> @@ -670,3 +671,752 @@ ctf_trace_file_writer_new (void)
>
> return (struct trace_file_writer *) writer;
> }
> +
> +#if HAVE_LIBBABELTRACE
> +/* Use libbabeltrace to read CTF data. The libbabeltrace provides
> + iterator to iterate over each event in CTF data and APIs to get
> + details of event and packet, so it is very convenient to use
> + libbabeltrace to access events in CTF. */
> +
> +#include <babeltrace/babeltrace.h>
> +#include <babeltrace/ctf/events.h>
> +#include <babeltrace/ctf/iterator.h>
> +
> +/* The struct pointer for current CTF directory. */
> +static struct bt_context *ctx = NULL;
> +static struct bt_ctf_iter *ctf_iter = NULL;
> +/* The name of CTF directory. */
> +static char *trace_dirname;
> +
> +static struct target_ops ctf_ops;
> +
> +/* Destroy ctf iterator and context. */
> +
> +static void
> +ctf_destroy (void)
> +{
> + if (ctf_iter != NULL)
> + {
> + bt_ctf_iter_destroy (ctf_iter);
> + ctf_iter = NULL;
> + }
> + if (ctx != NULL)
> + {
> + bt_context_put (ctx);
> + ctx = NULL;
> + }
> +}
> +
> +/* Open CTF trace data in DIRNAME. */
> +
> +static void
> +ctf_open_dir (char *dirname)
> +{
> + int ret;
> + struct bt_iter_pos begin_pos;
> + struct bt_iter_pos *pos;
> +
> + ctx = bt_context_create ();
> + if (ctx == NULL)
> + error (_("Unable to initialize libbabeltrace"));
> + ret = bt_context_add_trace (ctx, dirname, "ctf", NULL, NULL, NULL);
> + if (ret < 0)
> + {
> + ctf_destroy ();
> + error (_("Unable to use libbabeltrace open \"%s\""), dirname);
The wording of this error message (here and below) is awkward.
I don't know libbabeltrace enough to know if this is accurate, but
it reads better.
error (_("Unable to use libbabeltrace on \"%s\""), dirname);
or
error (_("Unable to use libbabeltrace on directory \"%s\""), dirname);
Also, IWBN to add a more specific reason for the failure,
but I'm not sure how easy that would be.
Is there a bt_foo function akin to strerror?
> + }
> +
> + begin_pos.type = BT_SEEK_BEGIN;
> + ctf_iter = bt_ctf_iter_create (ctx, &begin_pos, NULL);
> + if (ctf_iter == NULL)
> + {
> + ctf_destroy ();
> + error (_("Unable to use libbabeltrace open \"%s\""), dirname);
> + }
> +
> + /* Iterate over events, and look for an event for register block
> + to set trace_regblock_size. */
> +
> + /* Save the current position. */
> + pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
> + gdb_assert (pos->type == BT_SEEK_RESTORE);
> +
> + while (1)
> + {
> + const char *name;
> + struct bt_ctf_event *event;
> +
> + event = bt_ctf_iter_read_event (ctf_iter);
> +
> + name = bt_ctf_event_name (event);
> +
> + if (name == NULL)
> + break;
> + else if (strcmp (name, "register") == 0)
> + {
> + const struct bt_definition *scope
> + = bt_ctf_get_top_level_scope (event,
> + BT_EVENT_FIELDS);
> + const struct bt_definition *array
> + = bt_ctf_get_field (event, scope, "contents");
> +
> + trace_regblock_size
> + = bt_ctf_get_array_len (bt_ctf_get_decl_from_def (array));
> + }
> +
> + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> + break;
> + }
> +
> + /* Restore the position. */
> + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
> +
Remove blank line.
> +}
> +
> +/* This is the implementation of target_ops method to_open. Open CTF
> + trace data, read trace status, trace state variables and tracepoint
> + definitions from the first packet. Set the start position at the
> + second packet which contains events on trace blocks. */
> +
> +static void
> +ctf_open (char *dirname, int from_tty)
> +{
> + if (!dirname)
> + error (_("No CTF directory specified."));
> +
> + ctf_open_dir (dirname);
> +
> + target_preopen (from_tty);
> + trace_dirname = xstrdup (dirname);
> + push_target (&ctf_ops);
> +}
> +
> +/* This is the implementation of target_ops method to_close. Destroy
> + CTF iterator and context. */
> +
> +static void
> +ctf_close (void)
> +{
> + ctf_destroy ();
> + xfree (trace_dirname);
> + trace_dirname = NULL;
> +}
> +
> +/* This is the implementation of target_ops method to_files_info.
> + Print the directory name of CTF trace data. */
> +
> +static void
> +ctf_files_info (struct target_ops *t)
> +{
> + printf_filtered ("\t`%s'\n", trace_dirname);
> +}
> +
> +/* This is the implementation of target_ops method to_fetch_registers.
> + Iterate over events whose name is "register" in current frame,
> + extract contents from events, and set REGCACHE with the contents.
> + If no matched events are found, mark registers unavailable. */
> +
> +static void
> +ctf_fetch_registers (struct target_ops *ops,
> + struct regcache *regcache, int regno)
> +{
> + struct gdbarch *gdbarch = get_regcache_arch (regcache);
> + int offset, regn, regsize, pc_regno;
> + char *regs = NULL;
> + struct bt_ctf_event *event = NULL;
> + struct bt_iter_pos *pos;
> +
> + /* An uninitialized reg size says we're not going to be
> + successful at getting register blocks. */
> + if (trace_regblock_size == 0)
> + return;
> +
> + gdb_assert (ctf_iter != NULL);
> + /* Save the current position. */
> + pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
> + gdb_assert (pos->type == BT_SEEK_RESTORE);
> +
> + while (1)
> + {
> + const char *name;
> + struct bt_ctf_event *event1;
> +
> + event1 = bt_ctf_iter_read_event (ctf_iter);
> +
> + name = bt_ctf_event_name (event1);
> +
> + if (name == NULL || strcmp (name, "frame") == 0)
> + break;
> + else if (strcmp (name, "register") == 0)
> + {
> + event = event1;
> + break;
> + }
> +
> + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> + break;
> + }
> +
> + /* Restore the position. */
> + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
> +
> + if (event != NULL)
> + {
> + const struct bt_definition *scope
> + = bt_ctf_get_top_level_scope (event,
> + BT_EVENT_FIELDS);
> + const struct bt_definition *array
> + = bt_ctf_get_field (event, scope, "contents");
> +
> + regs = bt_ctf_get_char_array (array);
> + /* Assume the block is laid out in GDB register number order,
> + each register with the size that it has in GDB. */
> + offset = 0;
> + for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
> + {
> + regsize = register_size (gdbarch, regn);
> + /* Make sure we stay within block bounds. */
> + if (offset + regsize >= trace_regblock_size)
> + break;
> + if (regcache_register_status (regcache, regn) == REG_UNKNOWN)
> + {
> + if (regno == regn)
> + {
> + regcache_raw_supply (regcache, regno, regs + offset);
> + break;
> + }
> + else if (regno == -1)
> + {
> + regcache_raw_supply (regcache, regn, regs + offset);
> + }
> + }
> + offset += regsize;
> + }
> + return;
> + }
> +
> + regs = alloca (trace_regblock_size);
> +
> + /* We get here if no register data has been found. Mark registers
> + as unavailable. */
> + for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
> + regcache_raw_supply (regcache, regn, NULL);
> +
> + /* We can often usefully guess that the PC is going to be the same
> + as the address of the tracepoint. */
> + pc_regno = gdbarch_pc_regnum (gdbarch);
> + if (pc_regno >= 0 && (regno == -1 || regno == pc_regno))
> + {
> + struct tracepoint *tp = get_tracepoint (get_tracepoint_number ());
> +
> + if (tp != NULL && tp->base.loc)
> + {
> + /* But don't try to guess if tracepoint is multi-location... */
> + if (tp->base.loc->next != NULL)
> + {
> + warning (_("Tracepoint %d has multiple "
> + "locations, cannot infer $pc"),
> + tp->base.number);
> + return;
> + }
> + /* ... or does while-stepping. */
> + if (tp->step_count > 0)
> + {
> + warning (_("Tracepoint %d does while-stepping, "
> + "cannot infer $pc"),
> + tp->base.number);
> + return;
> + }
> +
> + store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
> + gdbarch_byte_order (gdbarch),
> + tp->base.loc->address);
> + regcache_raw_supply (regcache, pc_regno, regs);
> + }
> + }
> +}
> +
> +/* This is the implementation of target_ops method to_xfer_partial.
> + Iterate over events whose name is "memory" in
> + current frame, extract the address and length from events. If
> + OFFSET is within the range, read the contents from events to
> + READBUF. */
> +
> +static LONGEST
> +ctf_xfer_partial (struct target_ops *ops, enum target_object object,
> + const char *annex, gdb_byte *readbuf,
> + const gdb_byte *writebuf, ULONGEST offset,
> + LONGEST len)
> +{
> + /* We're only doing regular memory for now. */
> + if (object != TARGET_OBJECT_MEMORY)
> + return -1;
> +
> + if (readbuf == NULL)
> + error (_("ctf_xfer_partial: trace file is read-only"));
> +
> + if (get_traceframe_number () != -1)
> + {
> + struct bt_iter_pos *pos;
> + int i = 0;
> +
> + gdb_assert (ctf_iter != NULL);
> + /* Save the current position. */
> + pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
> + gdb_assert (pos->type == BT_SEEK_RESTORE);
> +
> + /* Iterate through the traceframe's blocks, looking for
> + memory. */
> + while (1)
> + {
> + ULONGEST amt;
> + uint64_t maddr;
> + uint16_t mlen;
> + enum bfd_endian byte_order
> + = gdbarch_byte_order (target_gdbarch ());
> + const struct bt_definition *scope;
> + const struct bt_definition *def;
> + struct bt_ctf_event *event
> + = bt_ctf_iter_read_event (ctf_iter);
> + const char *name = bt_ctf_event_name (event);
> +
> + if (strcmp (name, "frame") == 0)
> + break;
> + else if (strcmp (name, "memory") != 0)
> + {
> + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> + break;
> +
> + continue;
> + }
> +
> + scope = bt_ctf_get_top_level_scope (event,
> + BT_EVENT_FIELDS);
> +
> + def = bt_ctf_get_field (event, scope, "address");
> + maddr = bt_ctf_get_uint64 (def);
> + def = bt_ctf_get_field (event, scope, "length");
> + mlen = (uint16_t) bt_ctf_get_uint64 (def);
I don't know libbabeltrace, I'm assuming length can be at most 16 bits.
> +
> + /* If the block includes the first part of the desired
> + range, return as much it has; GDB will re-request the
> + remainder, which might be in a different block of this
> + trace frame. */
> + if (maddr <= offset && offset < (maddr + mlen))
> + {
> + const struct bt_definition *array
> + = bt_ctf_get_field (event, scope, "contents");
> + const struct bt_declaration *decl
> + = bt_ctf_get_decl_from_def (array);
> + gdb_byte *contents;
> + int k;
> +
> + contents = xmalloc (mlen);
> +
> + for (k = 0; k < mlen; k++)
> + {
> + const struct bt_definition *element
> + = bt_ctf_get_index (event, array, k);
> +
> + contents[k] = (gdb_byte) bt_ctf_get_uint64 (element);
> + }
> +
> + amt = (maddr + mlen) - offset;
> + if (amt > len)
> + amt = len;
> +
> + memcpy (readbuf, &contents[offset - maddr], amt);
> +
> + xfree (contents);
> +
> + /* Restore the position. */
> + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
> +
> + return amt;
> + }
> +
> + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> + break;
> + }
> +
> + /* Restore the position. */
> + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
> + }
> +
> + /* It's unduly pedantic to refuse to look at the executable for
> + read-only pieces; so do the equivalent of readonly regions aka
> + QTro packet. */
> + if (exec_bfd != NULL)
> + {
> + asection *s;
> + bfd_size_type size;
> + bfd_vma vma;
> +
> + for (s = exec_bfd->sections; s; s = s->next)
> + {
> + if ((s->flags & SEC_LOAD) == 0
> + || (s->flags & SEC_READONLY) == 0)
> + continue;
> +
> + vma = s->vma;
> + size = bfd_get_section_size (s);
> + if (vma <= offset && offset < (vma + size))
> + {
> + ULONGEST amt;
> +
> + amt = (vma + size) - offset;
> + if (amt > len)
> + amt = len;
> +
> + amt = bfd_get_section_contents (exec_bfd, s,
> + readbuf, offset - vma, amt);
> + return amt;
> + }
> + }
> + }
> +
> + /* Indicate failure to find the requested memory block. */
> + return -1;
> +}
> +
> +/* This is the implementation of target_ops method
> + to_get_trace_state_variable_value.
> + Iterate over events whose name is "tsv" in current frame. When the
> + trace variable is found, set the value of it to *VAL and return
> + true, otherwise return false. */
> +
> +static int
> +ctf_get_trace_state_variable_value (int tsvnum, LONGEST *val)
> +{
> + struct bt_iter_pos *pos;
> + int found = 0;
> +
> + gdb_assert (ctf_iter != NULL);
> + /* Save the current position. */
> + pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
> + gdb_assert (pos->type == BT_SEEK_RESTORE);
> +
> + /* Iterate through the traceframe's blocks, looking for 'V'
> + block. */
> + while (1)
> + {
> + struct bt_ctf_event *event
> + = bt_ctf_iter_read_event (ctf_iter);
> + const char *name = bt_ctf_event_name (event);
> +
> + if (name == NULL || strcmp (name, "frame") == 0)
> + break;
> + else if (strcmp (name, "tsv") == 0)
> + {
> + const struct bt_definition *scope;
> + const struct bt_definition *def;
> +
> + scope = bt_ctf_get_top_level_scope (event,
> + BT_EVENT_FIELDS);
> +
> + def = bt_ctf_get_field (event, scope, "num");
> + if (tsvnum == (int32_t) bt_ctf_get_uint64 (def))
> + {
> + def = bt_ctf_get_field (event, scope, "val");
> + *val = bt_ctf_get_uint64 (def);
> +
> + found = 1;
> + }
> + }
> +
> + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> + break;
> + }
> +
> + /* Restore the position. */
> + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
> +
> + return found;
> +}
> +
> +/* Return the tracepoint number in "frame" event. */
> +
> +static int
> +ctf_get_tpnum_from_frame_event (struct bt_ctf_event *event)
> +{
> + /* The packet context of events has a field "tpnum". */
> + const struct bt_definition *scope
> + = bt_ctf_get_top_level_scope (event, BT_STREAM_PACKET_CONTEXT);
> + uint64_t tpnum
> + = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "tpnum"));
> +
> + return (int) tpnum;
> +}
> +
> +/* Return the address at which the current frame was collected. */
> +
> +static CORE_ADDR
> +ctf_get_traceframe_address (void)
> +{
> + struct bt_ctf_event *event = NULL;
> + struct bt_iter_pos *pos;
> + CORE_ADDR addr = 0;
> +
> + gdb_assert (ctf_iter != NULL);
> + pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
> + gdb_assert (pos->type == BT_SEEK_RESTORE);
> +
> + while (1)
> + {
> + const char *name;
> + struct bt_ctf_event *event1;
> +
> + event1 = bt_ctf_iter_read_event (ctf_iter);
> +
> + name = bt_ctf_event_name (event1);
> +
> + if (name == NULL)
> + break;
> + else if (strcmp (name, "frame") == 0)
> + {
> + event = event1;
> + break;
> + }
> +
> + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> + break;
> + }
> +
> + if (event != NULL)
> + {
> + int tpnum = ctf_get_tpnum_from_frame_event (event);
> + struct tracepoint *tp
> + = get_tracepoint_by_number_on_target (tpnum);
> +
> + if (tp && tp->base.loc)
> + addr = tp->base.loc->address;
> + }
> +
> + /* Restore the position. */
> + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
> +
> + return addr;
> +}
> +
> +/* This is the implementation of target_ops method to_trace_find.
> + Iterate the events whose name is "frame", extract the tracepoint
> + number in it. Return traceframe number when matched. */
> +
> +static int
> +ctf_trace_find (enum trace_find_type type, int num,
> + CORE_ADDR addr1, CORE_ADDR addr2, int *tpp)
> +{
> + int ret = -1;
> + int tfnum = 0;
> + int found = 0;
> + struct bt_iter_pos pos;
> +
> + if (num == -1)
> + {
> + if (tpp != NULL)
> + *tpp = -1;
> + return -1;
> + }
> +
> + gdb_assert (ctf_iter != NULL);
> + /* Set iterator back to the beginning. */
> + pos.type = BT_SEEK_BEGIN;
> + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), &pos);
> +
> + while (1)
> + {
> + int id;
> + struct bt_ctf_event *event;
> + const char *name;
> +
> + event = bt_ctf_iter_read_event (ctf_iter);
> +
> + name = bt_ctf_event_name (event);
> +
> + if (event == NULL || name == NULL)
> + break;
> +
> + if (strcmp (name, "frame") == 0)
> + {
> + CORE_ADDR tfaddr;
> +
> + if (type == tfind_number)
> + {
> + /* Looking for a specific trace frame. */
> + if (tfnum == num)
> + found = 1;
> + }
> + else
> + {
> + /* Start from the _next_ trace frame. */
> + if (tfnum > get_traceframe_number ())
> + {
> + switch (type)
> + {
> + case tfind_tp:
> + {
> + struct tracepoint *tp = get_tracepoint (num);
> +
> + if (tp != NULL
> + && (tp->number_on_target
> + == ctf_get_tpnum_from_frame_event (event)))
> + found = 1;
> + break;
> + }
> + case tfind_pc:
> + tfaddr = ctf_get_traceframe_address ();
> + if (tfaddr == addr1)
> + found = 1;
> + break;
> + case tfind_range:
> + tfaddr = ctf_get_traceframe_address ();
> + if (addr1 <= tfaddr && tfaddr <= addr2)
> + found = 1;
> + break;
> + case tfind_outside:
> + tfaddr = ctf_get_traceframe_address ();
> + if (!(addr1 <= tfaddr && tfaddr <= addr2))
> + found = 1;
> + break;
> + default:
> + internal_error (__FILE__, __LINE__, _("unknown tfind type"));
> + }
> + }
> + }
> + if (found)
> + {
> + if (tpp != NULL)
> + *tpp = ctf_get_tpnum_from_frame_event (event);
> +
> + /* Skip the event "frame". */
> + bt_iter_next (bt_ctf_get_iter (ctf_iter));
> +
> + return tfnum;
> + }
> + tfnum++;
> + }
> +
> + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> + break;
> + }
> +
> + return -1;
> +}
> +
> +/* This is the implementation of target_ops method to_has_stack.
> + The target has a stack when GDB has already selected one trace
> + frame. */
> +
> +static int
> +ctf_has_stack (struct target_ops *ops)
> +{
> + return get_traceframe_number () != -1;
> +}
> +
> +/* This is the implementation of target_ops method to_has_registers.
> + The target has registers when GDB has already selected one trace
> + frame. */
> +
> +static int
> +ctf_has_registers (struct target_ops *ops)
> +{
> + return get_traceframe_number () != -1;
> +}
> +
> +/* This is the implementation of target_ops method to_traceframe_info.
> + Iterate the events whose name is "memory", in current
> + frame, extract memory range information, and return them in
> + traceframe_info. */
> +
> +static struct traceframe_info *
> +ctf_traceframe_info (void)
> +{
> + struct traceframe_info *info = XCNEW (struct traceframe_info);
> + const char *name;
> + struct bt_iter_pos *pos;
> +
> + gdb_assert (ctf_iter != NULL);
> + /* Save the current position. */
> + pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
> + gdb_assert (pos->type == BT_SEEK_RESTORE);
> +
> + do
> + {
> + struct bt_ctf_event *event
> + = bt_ctf_iter_read_event (ctf_iter);
> +
> + name = bt_ctf_event_name (event);
> +
> + if (name == NULL || strcmp (name, "register") == 0
> + || strcmp (name, "frame") == 0)
> + ;
> + else if (strcmp (name, "memory") == 0)
> + {
> + const struct bt_definition *scope
> + = bt_ctf_get_top_level_scope (event,
> + BT_EVENT_FIELDS);
> + const struct bt_definition *def;
> + struct mem_range *r;
> +
> + r = VEC_safe_push (mem_range_s, info->memory, NULL);
> + def = bt_ctf_get_field (event, scope, "address");
> + r->start = bt_ctf_get_uint64 (def);
> +
> + def = bt_ctf_get_field (event, scope, "length");
> + r->length = (uint16_t) bt_ctf_get_uint64 (def);
> + }
> + else
> + warning (_("Unhandled trace block type (%s) "
> + "while building trace frame info."),
> + name);
These days we prefer multi-line single statements for if/else/etc.
to be wrapped in braces. i.e.,
{
warning (_("Unhandled trace block type (%s) "
"while building trace frame info."),
name);
}
> +
> + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> + break;
> + }
> + while (name != NULL && strcmp (name, "frame") != 0);
> +
> + /* Restore the position. */
> + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
> +
> + return info;
> +}
> +
> +static void
> +init_ctf_ops (void)
> +{
> + memset (&ctf_ops, 0, sizeof (ctf_ops));
> +
> + ctf_ops.to_shortname = "ctf";
> + ctf_ops.to_longname = "CTF file";
> + ctf_ops.to_doc = "Use a CTF directory as a target.\n\
> +Specify the filename of the CTF directory.";
> + ctf_ops.to_open = ctf_open;
> + ctf_ops.to_close = ctf_close;
> + ctf_ops.to_fetch_registers = ctf_fetch_registers;
> + ctf_ops.to_xfer_partial = ctf_xfer_partial;
> + ctf_ops.to_files_info = ctf_files_info;
> + ctf_ops.to_trace_find = ctf_trace_find;
> + ctf_ops.to_get_trace_state_variable_value
> + = ctf_get_trace_state_variable_value;
> + ctf_ops.to_stratum = process_stratum;
> + ctf_ops.to_has_stack = ctf_has_stack;
> + ctf_ops.to_has_registers = ctf_has_registers;
> + ctf_ops.to_traceframe_info = ctf_traceframe_info;
> + ctf_ops.to_magic = OPS_MAGIC;
> +}
> +
> +#endif
> +
> +/* -Wmissing-prototypes */
> +extern initialize_file_ftype _initialize_ctf;
> +
> +/* module initialization */
blank line
> +void
> +_initialize_ctf (void)
> +{
> +#if HAVE_LIBBABELTRACE
> + init_ctf_ops ();
> +
> + add_target (&ctf_ops);
> +#endif
> +}
> diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
> index 3d8b131..962e632 100644
> --- a/gdb/tracepoint.c
> +++ b/gdb/tracepoint.c
> @@ -127,14 +127,6 @@ extern void (*deprecated_readline_end_hook) (void);
> typedef struct trace_state_variable tsv_s;
> DEF_VEC_O(tsv_s);
>
> -/* An object describing the contents of a traceframe. */
> -
> -struct traceframe_info
> -{
> - /* Collected memory. */
> - VEC(mem_range_s) *memory;
> -};
> -
> static VEC(tsv_s) *tvariables;
>
> /* The next integer to assign to a variable. */
> @@ -3303,8 +3295,6 @@ static const struct trace_file_write_ops tfile_write_ops =
> #define TRACE_WRITE_V_BLOCK(writer, num, val) \
> writer->ops->frame_ops->write_v_block ((writer), (num), (val))
>
> -extern int trace_regblock_size;
> -
> /* Save tracepoint data to file named FILENAME through WRITER. WRITER
> determines the trace file format. If TARGET_DOES_SAVE is non-zero,
> the save is performed on the target, otherwise GDB obtains all trace
> @@ -3741,6 +3731,12 @@ get_traceframe_number (void)
> return traceframe_number;
> }
>
> +int
> +get_tracepoint_number (void)
> +{
> + return tracepoint_number;
> +}
> +
> /* Make the traceframe NUM be the current trace frame. Does nothing
> if NUM is already current. */
>
> diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
> index 8df906f..378824e 100644
> --- a/gdb/tracepoint.h
> +++ b/gdb/tracepoint.h
> @@ -24,6 +24,14 @@
> #include "memrange.h"
> #include "gdb_vecs.h"
>
> +/* An object describing the contents of a traceframe. */
> +
> +struct traceframe_info
> +{
> + /* Collected memory. */
> + VEC(mem_range_s) *memory;
> +};
> +
> /* A trace state variable is a value managed by a target being
> traced. A trace state variable (or tsv for short) can be accessed
> and assigned to by tracepoint actions and conditionals, but is not
> @@ -142,6 +150,8 @@ struct trace_status *current_trace_status (void);
>
> extern char *default_collect;
>
> +extern int trace_regblock_size;
> +
> /* Struct to collect random info about tracepoints on the target. */
>
> struct uploaded_tp
> @@ -324,6 +334,9 @@ extern void (*deprecated_trace_start_stop_hook) (int start, int from_tty);
> /* Returns the current traceframe number. */
> extern int get_traceframe_number (void);
>
> +/* Returns the tracepoint number for current traceframe. */
> +extern int get_tracepoint_number (void);
> +
> /* Make the traceframe NUM be the current GDB trace frame number, and
> do nothing more. In particular, this does not flush the
> register/frame caches or notify the target about the trace frame
> --
> 1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 03/15] Read CTF by the ctf target
2013-04-08 21:48 ` Doug Evans
@ 2013-04-09 15:23 ` Yao Qi
2013-04-09 18:41 ` Doug Evans
0 siblings, 1 reply; 60+ messages in thread
From: Yao Qi @ 2013-04-09 15:23 UTC (permalink / raw)
To: Doug Evans; +Cc: Tom Tromey, gdb-patches
On 04/09/2013 12:58 AM, Doug Evans wrote:
>> + if (ret < 0)
> > + {
> > + ctf_destroy ();
> > + error (_("Unable to use libbabeltrace open \"%s\""), dirname);
>
> The wording of this error message (here and below) is awkward.
> I don't know libbabeltrace enough to know if this is accurate, but
> it reads better.
>
> error (_("Unable to use libbabeltrace on \"%s\""), dirname);
>
> or
>
> error (_("Unable to use libbabeltrace on directory \"%s\""), dirname);
I changed the message to
error (_("Unable to use libbabeltrace on directory \"%s\""),
dirname);
>
> Also, IWBN to add a more specific reason for the failure,
> but I'm not sure how easy that would be.
> Is there a bt_foo function akin to strerror?
>
Unfortunately, there isn't such function.
> > +
> > + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> > + break;
> > + }
> > +
> > + /* Restore the position. */
> > + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
> > +
>
> Remove blank line.
>
> > +}
Removed.
> > +
> > + scope = bt_ctf_get_top_level_scope (event,
> > + BT_EVENT_FIELDS);
> > +
> > + def = bt_ctf_get_field (event, scope, "address");
> > + maddr = bt_ctf_get_uint64 (def);
> > + def = bt_ctf_get_field (event, scope, "length");
> > + mlen = (uint16_t) bt_ctf_get_uint64 (def);
>
> I don't know libbabeltrace, I'm assuming length can be at most 16 bits.
>
Right. "length" is defined as uint16_t in metadata, on the other hand,
"length" is got from the remote target, which is 16-bit as well.
> > +
> > +/* This is the implementation of target_ops method to_traceframe_info.
> > + Iterate the events whose name is "memory", in current
> > + frame, extract memory range information, and return them in
> > + traceframe_info. */
> > +
> > +static struct traceframe_info *
> > +ctf_traceframe_info (void)
> > +{
> > + struct traceframe_info *info = XCNEW (struct traceframe_info);
> > + const char *name;
> > + struct bt_iter_pos *pos;
> > +
> > + gdb_assert (ctf_iter != NULL);
> > + /* Save the current position. */
> > + pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
> > + gdb_assert (pos->type == BT_SEEK_RESTORE);
> > +
> > + do
> > + {
> > + struct bt_ctf_event *event
> > + = bt_ctf_iter_read_event (ctf_iter);
> > +
> > + name = bt_ctf_event_name (event);
> > +
> > + if (name == NULL || strcmp (name, "register") == 0
> > + || strcmp (name, "frame") == 0)
> > + ;
> > + else if (strcmp (name, "memory") == 0)
> > + {
> > + const struct bt_definition *scope
> > + = bt_ctf_get_top_level_scope (event,
> > + BT_EVENT_FIELDS);
> > + const struct bt_definition *def;
> > + struct mem_range *r;
> > +
> > + r = VEC_safe_push (mem_range_s, info->memory, NULL);
> > + def = bt_ctf_get_field (event, scope, "address");
> > + r->start = bt_ctf_get_uint64 (def);
> > +
> > + def = bt_ctf_get_field (event, scope, "length");
> > + r->length = (uint16_t) bt_ctf_get_uint64 (def);
> > + }
> > + else
> > + warning (_("Unhandled trace block type (%s) "
> > + "while building trace frame info."),
> > + name);
>
> These days we prefer multi-line single statements for if/else/etc.
> to be wrapped in braces. i.e.,
>
> {
> warning (_("Unhandled trace block type (%s) "
> "while building trace frame info."),
> name);
> }
>
Fixed. I knew that single statement with comments should be warped by
braces, like:
if (foo)
/* Comments. */
bar ();
after reading GDB internals, I realize that "warning message in
multiple lines" falls into this category as well. You are right.
> > +
> > +/* module initialization */
>
> blank line
>
> > +void
> > +_initialize_ctf (void)
Fixed.
--
Yao (é½å°§)
gdb:
2013-04-09 Hui Zhu <hui@codesourcery.com>
Yao Qi <yao@codesourcery.com>
* configure.ac: Check libbabeltrace is installed.
* config.in: Regenerate.
* configure: Regenerate.
* Makefile.in (LIBBABELTRACE): New.
(CLIBS): Add LIBBABELTRACE.
* ctf.c (ctx, ctf_iter, trace_dirname): New.
(ctf_destroy, ctf_open_dir, ctf_open): New.
(ctf_close, ctf_files_info): New.
(ctf_fetch_registers, ctf_xfer_partial): New.
(ctf_get_trace_state_variable_value): New.
(ctf_get_tpnum_from_frame_event): New.
(ctf_get_traceframe_address): New.
(ctf_trace_find, ctf_has_stack): New.
(ctf_has_registers, ctf_traceframe_info, init_ctf_ops): New.
(_initialize_ctf): New.
* tracepoint.c (get_tracepoint_number): New
(struct traceframe_info, trace_regblock_size): Move it to ...
* tracepoint.h: ... here.
(get_tracepoint_number): Declare it.
---
gdb/Makefile.in | 6 +-
gdb/config.in | 3 +
gdb/configure | 517 +++++++++++++++++++++++++++++++++++++
gdb/configure.ac | 41 +++
gdb/ctf.c | 754 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
gdb/tracepoint.c | 16 +-
gdb/tracepoint.h | 13 +
7 files changed, 1339 insertions(+), 11 deletions(-)
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 498d42a..0814bcb 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -154,6 +154,10 @@ LIBEXPAT = @LIBEXPAT@
# Where is lzma? This will be empty if lzma was not available.
LIBLZMA = @LIBLZMA@
+# Where is libbabeltrace? This will be empty if lbabeltrace was not
+# available.
+LIBBABELTRACE = @LIBBABELTRACE@
+
WARN_CFLAGS = @WARN_CFLAGS@
WERROR_CFLAGS = @WERROR_CFLAGS@
GDB_WARN_CFLAGS = $(WARN_CFLAGS)
@@ -475,7 +479,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_
# LIBIBERTY appears twice on purpose.
CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
$(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ @PYTHON_LIBS@ \
- $(LIBEXPAT) $(LIBLZMA) \
+ $(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) \
$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU)
CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
diff --git a/gdb/config.in b/gdb/config.in
index 9e21325..c4e8eaa 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -180,6 +180,9 @@
/* Define if your <locale.h> file defines LC_MESSAGES. */
#undef HAVE_LC_MESSAGES
+/* Define if libbabeltrace is available */
+#undef HAVE_LIBBABELTRACE
+
/* Define to 1 if you have the `dl' library (-ldl). */
#undef HAVE_LIBDL
diff --git a/gdb/configure b/gdb/configure
index 0dd67f0..6588c72 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -592,6 +592,9 @@ enable_option_checking=no
ac_subst_vars='LTLIBOBJS
LIBOBJS
GDB_NM_FILE
+LTLIBBABELTRACE
+LIBBABELTRACE
+HAVE_LIBBABELTRACE
frags
target_subdir
CONFIG_UNINSTALL
@@ -819,6 +822,8 @@ with_x
enable_sim
enable_multi_ice
enable_gdbserver
+with_babeltrace
+with_libbabeltrace_prefix
'
ac_precious_vars='build_alias
host_alias
@@ -1532,6 +1537,9 @@ Optional Packages:
--with-tcl directory containing tcl configuration (tclConfig.sh)
--with-tk directory containing tk configuration (tkConfig.sh)
--with-x use the X Window System
+ --with-babeltrace include babeltrace support (auto/yes/no)
+ --with-libbabeltrace-prefix[=DIR] search for libbabeltrace in DIR/include and DIR/lib
+ --without-libbabeltrace-prefix don't search for libbabeltrace in includedir and libdir
Some influential environment variables:
CC C compiler command
@@ -14093,6 +14101,515 @@ if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then
as_fn_error "Automatic gdbserver build is not supported for this configuration" "$LINENO" 5
fi
+# Check for babeltrace and babeltrace-ctf
+
+# Check whether --with-babeltrace was given.
+if test "${with_babeltrace+set}" = set; then :
+ withval=$with_babeltrace;
+else
+ with_babeltrace=auto
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use babeltrace" >&5
+$as_echo_n "checking whether to use babeltrace... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_babeltrace" >&5
+$as_echo "$with_babeltrace" >&6; }
+
+if test "x$with_babeltrace" = "xno"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: babletrace support disabled; GDB is unable to read CTF data." >&5
+$as_echo "$as_me: WARNING: babletrace support disabled; GDB is unable to read CTF data." >&2;}
+else
+ # Append -Werror to CFLAGS so that configure can catch the warning
+ # "assignment from incompatible pointer type", which is related to
+ # the babeltrace change from 1.0.3 to 1.1.0. Babeltrace 1.1.0 works
+ # in GDB, while babeltrace 1.0.3 is broken.
+ # AC_LIB_HAVE_LINKFLAGS may modify CPPFLAGS in it, so it should be
+ # safe to save and restore CFLAGS here.
+ saved_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS -Werror"
+
+
+
+
+
+
+
+
+ use_additional=yes
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+
+# Check whether --with-libbabeltrace-prefix was given.
+if test "${with_libbabeltrace_prefix+set}" = set; then :
+ withval=$with_libbabeltrace_prefix;
+ if test "X$withval" = "Xno"; then
+ use_additional=no
+ else
+ if test "X$withval" = "X"; then
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ else
+ additional_includedir="$withval/include"
+ additional_libdir="$withval/lib"
+ fi
+ fi
+
+fi
+
+ LIBBABELTRACE=
+ LTLIBBABELTRACE=
+ INCBABELTRACE=
+ rpathdirs=
+ ltrpathdirs=
+ names_already_handled=
+ names_next_round='babeltrace babeltrace-ctf'
+ while test -n "$names_next_round"; do
+ names_this_round="$names_next_round"
+ names_next_round=
+ for name in $names_this_round; do
+ already_handled=
+ for n in $names_already_handled; do
+ if test "$n" = "$name"; then
+ already_handled=yes
+ break
+ fi
+ done
+ if test -z "$already_handled"; then
+ names_already_handled="$names_already_handled $name"
+ uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+ eval value=\"\$HAVE_LIB$uppername\"
+ if test -n "$value"; then
+ if test "$value" = yes; then
+ eval value=\"\$LIB$uppername\"
+ test -z "$value" || LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$value"
+ eval value=\"\$LTLIB$uppername\"
+ test -z "$value" || LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }$value"
+ else
+ :
+ fi
+ else
+ found_dir=
+ found_la=
+ found_so=
+ found_a=
+ if test $use_additional = yes; then
+ if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then
+ found_dir="$additional_libdir"
+ found_so="$additional_libdir/lib$name.$shlibext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ else
+ if test -f "$additional_libdir/lib$name.$libext"; then
+ found_dir="$additional_libdir"
+ found_a="$additional_libdir/lib$name.$libext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ fi
+ fi
+ fi
+ if test "X$found_dir" = "X"; then
+ for x in $LDFLAGS $LTLIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ case "$x" in
+ -L*)
+ dir=`echo "X$x" | sed -e 's/^X-L//'`
+ if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then
+ found_dir="$dir"
+ found_so="$dir/lib$name.$shlibext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ else
+ if test -f "$dir/lib$name.$libext"; then
+ found_dir="$dir"
+ found_a="$dir/lib$name.$libext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ if test "X$found_dir" != "X"; then
+ break
+ fi
+ done
+ fi
+ if test "X$found_dir" != "X"; then
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-L$found_dir -l$name"
+ if test "X$found_so" != "X"; then
+ if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ else
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $found_dir"
+ fi
+ if test "$hardcode_direct" = yes; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ else
+ if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $found_dir"
+ fi
+ else
+ haveit=
+ for x in $LDFLAGS $LIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$found_dir"
+ fi
+ if test "$hardcode_minus_L" != no; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ else
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-l$name"
+ fi
+ fi
+ fi
+ fi
+ else
+ if test "X$found_a" != "X"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_a"
+ else
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$found_dir -l$name"
+ fi
+ fi
+ additional_includedir=
+ case "$found_dir" in
+ */lib | */lib/)
+ basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'`
+ additional_includedir="$basedir/include"
+ ;;
+ esac
+ if test "X$additional_includedir" != "X"; then
+ if test "X$additional_includedir" != "X/usr/include"; then
+ haveit=
+ if test "X$additional_includedir" = "X/usr/local/include"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ for x in $CPPFLAGS $INCBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-I$additional_includedir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_includedir"; then
+ INCBABELTRACE="${INCBABELTRACE}${INCBABELTRACE:+ }-I$additional_includedir"
+ fi
+ fi
+ fi
+ fi
+ fi
+ if test -n "$found_la"; then
+ save_libdir="$libdir"
+ case "$found_la" in
+ */* | *\\*) . "$found_la" ;;
+ *) . "./$found_la" ;;
+ esac
+ libdir="$save_libdir"
+ for dep in $dependency_libs; do
+ case "$dep" in
+ -L*)
+ additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+ if test "X$additional_libdir" != "X/usr/lib"; then
+ haveit=
+ if test "X$additional_libdir" = "X/usr/local/lib"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ haveit=
+ for x in $LDFLAGS $LIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$additional_libdir"
+ fi
+ fi
+ haveit=
+ for x in $LDFLAGS $LTLIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-L$additional_libdir"
+ fi
+ fi
+ fi
+ fi
+ ;;
+ -R*)
+ dir=`echo "X$dep" | sed -e 's/^X-R//'`
+ if test "$enable_rpath" != no; then
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $dir"
+ fi
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $dir"
+ fi
+ fi
+ ;;
+ -l*)
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+ ;;
+ *.la)
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+ ;;
+ *)
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$dep"
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }$dep"
+ ;;
+ esac
+ done
+ fi
+ else
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-l$name"
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-l$name"
+ fi
+ fi
+ fi
+ done
+ done
+ if test "X$rpathdirs" != "X"; then
+ if test -n "$hardcode_libdir_separator"; then
+ alldirs=
+ for found_dir in $rpathdirs; do
+ alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+ done
+ acl_save_libdir="$libdir"
+ libdir="$alldirs"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$flag"
+ else
+ for found_dir in $rpathdirs; do
+ acl_save_libdir="$libdir"
+ libdir="$found_dir"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$flag"
+ done
+ fi
+ fi
+ if test "X$ltrpathdirs" != "X"; then
+ for found_dir in $ltrpathdirs; do
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-R$found_dir"
+ done
+ fi
+
+
+ ac_save_CPPFLAGS="$CPPFLAGS"
+
+ for element in $INCBABELTRACE; do
+ haveit=
+ for x in $CPPFLAGS; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X$element"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element"
+ fi
+ done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libbabeltrace" >&5
+$as_echo_n "checking for libbabeltrace... " >&6; }
+if test "${ac_cv_libbabeltrace+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ac_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIBBABELTRACE"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <babeltrace/babeltrace.h>
+ #include <babeltrace/ctf/events.h>
+ #include <babeltrace/ctf/iterator.h>
+int
+main ()
+{
+struct bt_iter_pos *pos = bt_iter_get_pos (bt_ctf_get_iter (NULL));
+ struct bt_ctf_event *event = NULL;
+ const struct bt_definition *scope;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_STREAM_EVENT_HEADER);
+ bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_libbabeltrace=yes
+else
+ ac_cv_libbabeltrace=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$ac_save_LIBS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libbabeltrace" >&5
+$as_echo "$ac_cv_libbabeltrace" >&6; }
+ if test "$ac_cv_libbabeltrace" = yes; then
+ HAVE_LIBBABELTRACE=yes
+
+$as_echo "#define HAVE_LIBBABELTRACE 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libbabeltrace" >&5
+$as_echo_n "checking how to link with libbabeltrace... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBBABELTRACE" >&5
+$as_echo "$LIBBABELTRACE" >&6; }
+ else
+ HAVE_LIBBABELTRACE=no
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIBBABELTRACE=
+ LTLIBBABELTRACE=
+ fi
+
+
+
+
+
+
+ CFLAGS=$saved_CFLAGS
+
+ if test "$HAVE_LIBBABELTRACE" != yes; then
+ if test "$with_babeltrace" = yes; then
+ as_fn_error "babeltrace is missing or unusable" "$LINENO" 5
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: babeltrace is missing or unusable; GDB is unable to read CTF data." >&5
+$as_echo "$as_me: WARNING: babeltrace is missing or unusable; GDB is unable to read CTF data." >&2;}
+ fi
+ fi
+fi
+
# If nativefile (NAT_FILE) is not set in config/*/*.m[ht] files, we link
# to an empty version.
diff --git a/gdb/configure.ac b/gdb/configure.ac
index c17f587..149ac37 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -2321,6 +2321,47 @@ if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then
AC_MSG_ERROR(Automatic gdbserver build is not supported for this configuration)
fi
+# Check for babeltrace and babeltrace-ctf
+AC_ARG_WITH(babeltrace,
+ AC_HELP_STRING([--with-babeltrace], [include babeltrace support (auto/yes/no)]),
+ [], [with_babeltrace=auto])
+AC_MSG_CHECKING([whether to use babeltrace])
+AC_MSG_RESULT([$with_babeltrace])
+
+if test "x$with_babeltrace" = "xno"; then
+ AC_MSG_WARN([babletrace support disabled; GDB is unable to read CTF data.])
+else
+ # Append -Werror to CFLAGS so that configure can catch the warning
+ # "assignment from incompatible pointer type", which is related to
+ # the babeltrace change from 1.0.3 to 1.1.0. Babeltrace 1.1.0 works
+ # in GDB, while babeltrace 1.0.3 is broken.
+ # AC_LIB_HAVE_LINKFLAGS may modify CPPFLAGS in it, so it should be
+ # safe to save and restore CFLAGS here.
+ saved_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS -Werror"
+ AC_LIB_HAVE_LINKFLAGS([babeltrace], [babeltrace-ctf],
+ [#include <babeltrace/babeltrace.h>
+ #include <babeltrace/ctf/events.h>
+ #include <babeltrace/ctf/iterator.h>],
+ [struct bt_iter_pos *pos = bt_iter_get_pos (bt_ctf_get_iter (NULL));
+ struct bt_ctf_event *event = NULL;
+ const struct bt_definition *scope;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_STREAM_EVENT_HEADER);
+ bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+ ])
+ CFLAGS=$saved_CFLAGS
+
+ if test "$HAVE_LIBBABELTRACE" != yes; then
+ if test "$with_babeltrace" = yes; then
+ AC_MSG_ERROR([babeltrace is missing or unusable])
+ else
+ AC_MSG_WARN([babeltrace is missing or unusable; GDB is unable to read CTF data.])
+ fi
+ fi
+fi
+
# If nativefile (NAT_FILE) is not set in config/*/*.m[ht] files, we link
# to an empty version.
diff --git a/gdb/ctf.c b/gdb/ctf.c
index de54051..1829aa8 100644
--- a/gdb/ctf.c
+++ b/gdb/ctf.c
@@ -24,6 +24,7 @@
#include "tracepoint.h"
#include "regcache.h"
#include "gdb_stat.h"
+#include "exec.h"
#include <ctype.h>
@@ -670,3 +671,756 @@ ctf_trace_file_writer_new (void)
return (struct trace_file_writer *) writer;
}
+
+#if HAVE_LIBBABELTRACE
+/* Use libbabeltrace to read CTF data. The libbabeltrace provides
+ iterator to iterate over each event in CTF data and APIs to get
+ details of event and packet, so it is very convenient to use
+ libbabeltrace to access events in CTF. */
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/iterator.h>
+
+/* The struct pointer for current CTF directory. */
+static struct bt_context *ctx = NULL;
+static struct bt_ctf_iter *ctf_iter = NULL;
+/* The name of CTF directory. */
+static char *trace_dirname;
+
+static struct target_ops ctf_ops;
+
+/* Destroy ctf iterator and context. */
+
+static void
+ctf_destroy (void)
+{
+ if (ctf_iter != NULL)
+ {
+ bt_ctf_iter_destroy (ctf_iter);
+ ctf_iter = NULL;
+ }
+ if (ctx != NULL)
+ {
+ bt_context_put (ctx);
+ ctx = NULL;
+ }
+}
+
+/* Open CTF trace data in DIRNAME. */
+
+static void
+ctf_open_dir (char *dirname)
+{
+ int ret;
+ struct bt_iter_pos begin_pos;
+ struct bt_iter_pos *pos;
+
+ ctx = bt_context_create ();
+ if (ctx == NULL)
+ error (_("Unable to create bt_context"));
+ ret = bt_context_add_trace (ctx, dirname, "ctf", NULL, NULL, NULL);
+ if (ret < 0)
+ {
+ ctf_destroy ();
+ error (_("Unable to use libbabeltrace on directory \"%s\""),
+ dirname);
+ }
+
+ begin_pos.type = BT_SEEK_BEGIN;
+ ctf_iter = bt_ctf_iter_create (ctx, &begin_pos, NULL);
+ if (ctf_iter == NULL)
+ {
+ ctf_destroy ();
+ error (_("Unable to create bt_iterator"));
+ }
+
+ /* Iterate over events, and look for an event for register block
+ to set trace_regblock_size. */
+
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event;
+
+ event = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (name == NULL)
+ break;
+ else if (strcmp (name, "register") == 0)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+
+ trace_regblock_size
+ = bt_ctf_get_array_len (bt_ctf_get_decl_from_def (array));
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+}
+
+/* This is the implementation of target_ops method to_open. Open CTF
+ trace data, read trace status, trace state variables and tracepoint
+ definitions from the first packet. Set the start position at the
+ second packet which contains events on trace blocks. */
+
+static void
+ctf_open (char *dirname, int from_tty)
+{
+ if (!dirname)
+ error (_("No CTF directory specified."));
+
+ ctf_open_dir (dirname);
+
+ target_preopen (from_tty);
+ trace_dirname = xstrdup (dirname);
+ push_target (&ctf_ops);
+}
+
+/* This is the implementation of target_ops method to_close. Destroy
+ CTF iterator and context. */
+
+static void
+ctf_close (void)
+{
+ ctf_destroy ();
+ xfree (trace_dirname);
+ trace_dirname = NULL;
+}
+
+/* This is the implementation of target_ops method to_files_info.
+ Print the directory name of CTF trace data. */
+
+static void
+ctf_files_info (struct target_ops *t)
+{
+ printf_filtered ("\t`%s'\n", trace_dirname);
+}
+
+/* This is the implementation of target_ops method to_fetch_registers.
+ Iterate over events whose name is "register" in current frame,
+ extract contents from events, and set REGCACHE with the contents.
+ If no matched events are found, mark registers unavailable. */
+
+static void
+ctf_fetch_registers (struct target_ops *ops,
+ struct regcache *regcache, int regno)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ int offset, regn, regsize, pc_regno;
+ char *regs = NULL;
+ struct bt_ctf_event *event = NULL;
+ struct bt_iter_pos *pos;
+
+ /* An uninitialized reg size says we're not going to be
+ successful at getting register blocks. */
+ if (trace_regblock_size == 0)
+ return;
+
+ gdb_assert (ctf_iter != NULL);
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event1;
+
+ event1 = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event1);
+
+ if (name == NULL || strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "register") == 0)
+ {
+ event = event1;
+ break;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ if (event != NULL)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+
+ regs = bt_ctf_get_char_array (array);
+ /* Assume the block is laid out in GDB register number order,
+ each register with the size that it has in GDB. */
+ offset = 0;
+ for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+ {
+ regsize = register_size (gdbarch, regn);
+ /* Make sure we stay within block bounds. */
+ if (offset + regsize >= trace_regblock_size)
+ break;
+ if (regcache_register_status (regcache, regn) == REG_UNKNOWN)
+ {
+ if (regno == regn)
+ {
+ regcache_raw_supply (regcache, regno, regs + offset);
+ break;
+ }
+ else if (regno == -1)
+ {
+ regcache_raw_supply (regcache, regn, regs + offset);
+ }
+ }
+ offset += regsize;
+ }
+ return;
+ }
+
+ regs = alloca (trace_regblock_size);
+
+ /* We get here if no register data has been found. Mark registers
+ as unavailable. */
+ for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+ regcache_raw_supply (regcache, regn, NULL);
+
+ /* We can often usefully guess that the PC is going to be the same
+ as the address of the tracepoint. */
+ pc_regno = gdbarch_pc_regnum (gdbarch);
+ if (pc_regno >= 0 && (regno == -1 || regno == pc_regno))
+ {
+ struct tracepoint *tp = get_tracepoint (get_tracepoint_number ());
+
+ if (tp != NULL && tp->base.loc)
+ {
+ /* But don't try to guess if tracepoint is multi-location... */
+ if (tp->base.loc->next != NULL)
+ {
+ warning (_("Tracepoint %d has multiple "
+ "locations, cannot infer $pc"),
+ tp->base.number);
+ return;
+ }
+ /* ... or does while-stepping. */
+ if (tp->step_count > 0)
+ {
+ warning (_("Tracepoint %d does while-stepping, "
+ "cannot infer $pc"),
+ tp->base.number);
+ return;
+ }
+
+ store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
+ gdbarch_byte_order (gdbarch),
+ tp->base.loc->address);
+ regcache_raw_supply (regcache, pc_regno, regs);
+ }
+ }
+}
+
+/* This is the implementation of target_ops method to_xfer_partial.
+ Iterate over events whose name is "memory" in
+ current frame, extract the address and length from events. If
+ OFFSET is within the range, read the contents from events to
+ READBUF. */
+
+static LONGEST
+ctf_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf, ULONGEST offset,
+ LONGEST len)
+{
+ /* We're only doing regular memory for now. */
+ if (object != TARGET_OBJECT_MEMORY)
+ return -1;
+
+ if (readbuf == NULL)
+ error (_("ctf_xfer_partial: trace file is read-only"));
+
+ if (get_traceframe_number () != -1)
+ {
+ struct bt_iter_pos *pos;
+ int i = 0;
+
+ gdb_assert (ctf_iter != NULL);
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ /* Iterate through the traceframe's blocks, looking for
+ memory. */
+ while (1)
+ {
+ ULONGEST amt;
+ uint64_t maddr;
+ uint16_t mlen;
+ enum bfd_endian byte_order
+ = gdbarch_byte_order (target_gdbarch ());
+ const struct bt_definition *scope;
+ const struct bt_definition *def;
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+ const char *name = bt_ctf_event_name (event);
+
+ if (strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "memory") != 0)
+ {
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+
+ continue;
+ }
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+
+ def = bt_ctf_get_field (event, scope, "address");
+ maddr = bt_ctf_get_uint64 (def);
+ def = bt_ctf_get_field (event, scope, "length");
+ mlen = (uint16_t) bt_ctf_get_uint64 (def);
+
+ /* If the block includes the first part of the desired
+ range, return as much it has; GDB will re-request the
+ remainder, which might be in a different block of this
+ trace frame. */
+ if (maddr <= offset && offset < (maddr + mlen))
+ {
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+ const struct bt_declaration *decl
+ = bt_ctf_get_decl_from_def (array);
+ gdb_byte *contents;
+ int k;
+
+ contents = xmalloc (mlen);
+
+ for (k = 0; k < mlen; k++)
+ {
+ const struct bt_definition *element
+ = bt_ctf_get_index (event, array, k);
+
+ contents[k] = (gdb_byte) bt_ctf_get_uint64 (element);
+ }
+
+ amt = (maddr + mlen) - offset;
+ if (amt > len)
+ amt = len;
+
+ memcpy (readbuf, &contents[offset - maddr], amt);
+
+ xfree (contents);
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return amt;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+ }
+
+ /* It's unduly pedantic to refuse to look at the executable for
+ read-only pieces; so do the equivalent of readonly regions aka
+ QTro packet. */
+ if (exec_bfd != NULL)
+ {
+ asection *s;
+ bfd_size_type size;
+ bfd_vma vma;
+
+ for (s = exec_bfd->sections; s; s = s->next)
+ {
+ if ((s->flags & SEC_LOAD) == 0
+ || (s->flags & SEC_READONLY) == 0)
+ continue;
+
+ vma = s->vma;
+ size = bfd_get_section_size (s);
+ if (vma <= offset && offset < (vma + size))
+ {
+ ULONGEST amt;
+
+ amt = (vma + size) - offset;
+ if (amt > len)
+ amt = len;
+
+ amt = bfd_get_section_contents (exec_bfd, s,
+ readbuf, offset - vma, amt);
+ return amt;
+ }
+ }
+ }
+
+ /* Indicate failure to find the requested memory block. */
+ return -1;
+}
+
+/* This is the implementation of target_ops method
+ to_get_trace_state_variable_value.
+ Iterate over events whose name is "tsv" in current frame. When the
+ trace variable is found, set the value of it to *VAL and return
+ true, otherwise return false. */
+
+static int
+ctf_get_trace_state_variable_value (int tsvnum, LONGEST *val)
+{
+ struct bt_iter_pos *pos;
+ int found = 0;
+
+ gdb_assert (ctf_iter != NULL);
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ /* Iterate through the traceframe's blocks, looking for 'V'
+ block. */
+ while (1)
+ {
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+ const char *name = bt_ctf_event_name (event);
+
+ if (name == NULL || strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "tsv") == 0)
+ {
+ const struct bt_definition *scope;
+ const struct bt_definition *def;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+
+ def = bt_ctf_get_field (event, scope, "num");
+ if (tsvnum == (int32_t) bt_ctf_get_uint64 (def))
+ {
+ def = bt_ctf_get_field (event, scope, "val");
+ *val = bt_ctf_get_uint64 (def);
+
+ found = 1;
+ }
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return found;
+}
+
+/* Return the tracepoint number in "frame" event. */
+
+static int
+ctf_get_tpnum_from_frame_event (struct bt_ctf_event *event)
+{
+ /* The packet context of events has a field "tpnum". */
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event, BT_STREAM_PACKET_CONTEXT);
+ uint64_t tpnum
+ = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "tpnum"));
+
+ return (int) tpnum;
+}
+
+/* Return the address at which the current frame was collected. */
+
+static CORE_ADDR
+ctf_get_traceframe_address (void)
+{
+ struct bt_ctf_event *event = NULL;
+ struct bt_iter_pos *pos;
+ CORE_ADDR addr = 0;
+
+ gdb_assert (ctf_iter != NULL);
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event1;
+
+ event1 = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event1);
+
+ if (name == NULL)
+ break;
+ else if (strcmp (name, "frame") == 0)
+ {
+ event = event1;
+ break;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ if (event != NULL)
+ {
+ int tpnum = ctf_get_tpnum_from_frame_event (event);
+ struct tracepoint *tp
+ = get_tracepoint_by_number_on_target (tpnum);
+
+ if (tp && tp->base.loc)
+ addr = tp->base.loc->address;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return addr;
+}
+
+/* This is the implementation of target_ops method to_trace_find.
+ Iterate the events whose name is "frame", extract the tracepoint
+ number in it. Return traceframe number when matched. */
+
+static int
+ctf_trace_find (enum trace_find_type type, int num,
+ CORE_ADDR addr1, CORE_ADDR addr2, int *tpp)
+{
+ int ret = -1;
+ int tfnum = 0;
+ int found = 0;
+ struct bt_iter_pos pos;
+
+ if (num == -1)
+ {
+ if (tpp != NULL)
+ *tpp = -1;
+ return -1;
+ }
+
+ gdb_assert (ctf_iter != NULL);
+ /* Set iterator back to the beginning. */
+ pos.type = BT_SEEK_BEGIN;
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), &pos);
+
+ while (1)
+ {
+ int id;
+ struct bt_ctf_event *event;
+ const char *name;
+
+ event = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (event == NULL || name == NULL)
+ break;
+
+ if (strcmp (name, "frame") == 0)
+ {
+ CORE_ADDR tfaddr;
+
+ if (type == tfind_number)
+ {
+ /* Looking for a specific trace frame. */
+ if (tfnum == num)
+ found = 1;
+ }
+ else
+ {
+ /* Start from the _next_ trace frame. */
+ if (tfnum > get_traceframe_number ())
+ {
+ switch (type)
+ {
+ case tfind_tp:
+ {
+ struct tracepoint *tp = get_tracepoint (num);
+
+ if (tp != NULL
+ && (tp->number_on_target
+ == ctf_get_tpnum_from_frame_event (event)))
+ found = 1;
+ break;
+ }
+ case tfind_pc:
+ tfaddr = ctf_get_traceframe_address ();
+ if (tfaddr == addr1)
+ found = 1;
+ break;
+ case tfind_range:
+ tfaddr = ctf_get_traceframe_address ();
+ if (addr1 <= tfaddr && tfaddr <= addr2)
+ found = 1;
+ break;
+ case tfind_outside:
+ tfaddr = ctf_get_traceframe_address ();
+ if (!(addr1 <= tfaddr && tfaddr <= addr2))
+ found = 1;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, _("unknown tfind type"));
+ }
+ }
+ }
+ if (found)
+ {
+ if (tpp != NULL)
+ *tpp = ctf_get_tpnum_from_frame_event (event);
+
+ /* Skip the event "frame". */
+ bt_iter_next (bt_ctf_get_iter (ctf_iter));
+
+ return tfnum;
+ }
+ tfnum++;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ return -1;
+}
+
+/* This is the implementation of target_ops method to_has_stack.
+ The target has a stack when GDB has already selected one trace
+ frame. */
+
+static int
+ctf_has_stack (struct target_ops *ops)
+{
+ return get_traceframe_number () != -1;
+}
+
+/* This is the implementation of target_ops method to_has_registers.
+ The target has registers when GDB has already selected one trace
+ frame. */
+
+static int
+ctf_has_registers (struct target_ops *ops)
+{
+ return get_traceframe_number () != -1;
+}
+
+/* This is the implementation of target_ops method to_traceframe_info.
+ Iterate the events whose name is "memory", in current
+ frame, extract memory range information, and return them in
+ traceframe_info. */
+
+static struct traceframe_info *
+ctf_traceframe_info (void)
+{
+ struct traceframe_info *info = XCNEW (struct traceframe_info);
+ const char *name;
+ struct bt_iter_pos *pos;
+
+ gdb_assert (ctf_iter != NULL);
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ do
+ {
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (name == NULL || strcmp (name, "register") == 0
+ || strcmp (name, "frame") == 0)
+ ;
+ else if (strcmp (name, "memory") == 0)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *def;
+ struct mem_range *r;
+
+ r = VEC_safe_push (mem_range_s, info->memory, NULL);
+ def = bt_ctf_get_field (event, scope, "address");
+ r->start = bt_ctf_get_uint64 (def);
+
+ def = bt_ctf_get_field (event, scope, "length");
+ r->length = (uint16_t) bt_ctf_get_uint64 (def);
+ }
+ else
+ {
+ warning (_("Unhandled trace block type (%s) "
+ "while building trace frame info."),
+ name);
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+ while (name != NULL && strcmp (name, "frame") != 0);
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return info;
+}
+
+static void
+init_ctf_ops (void)
+{
+ memset (&ctf_ops, 0, sizeof (ctf_ops));
+
+ ctf_ops.to_shortname = "ctf";
+ ctf_ops.to_longname = "CTF file";
+ ctf_ops.to_doc = "Use a CTF directory as a target.\n\
+Specify the filename of the CTF directory.";
+ ctf_ops.to_open = ctf_open;
+ ctf_ops.to_close = ctf_close;
+ ctf_ops.to_fetch_registers = ctf_fetch_registers;
+ ctf_ops.to_xfer_partial = ctf_xfer_partial;
+ ctf_ops.to_files_info = ctf_files_info;
+ ctf_ops.to_trace_find = ctf_trace_find;
+ ctf_ops.to_get_trace_state_variable_value
+ = ctf_get_trace_state_variable_value;
+ ctf_ops.to_stratum = process_stratum;
+ ctf_ops.to_has_stack = ctf_has_stack;
+ ctf_ops.to_has_registers = ctf_has_registers;
+ ctf_ops.to_traceframe_info = ctf_traceframe_info;
+ ctf_ops.to_magic = OPS_MAGIC;
+}
+
+#endif
+
+/* -Wmissing-prototypes */
+
+extern initialize_file_ftype _initialize_ctf;
+
+/* module initialization */
+
+void
+_initialize_ctf (void)
+{
+#if HAVE_LIBBABELTRACE
+ init_ctf_ops ();
+
+ add_target (&ctf_ops);
+#endif
+}
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 3d8b131..962e632 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -127,14 +127,6 @@ extern void (*deprecated_readline_end_hook) (void);
typedef struct trace_state_variable tsv_s;
DEF_VEC_O(tsv_s);
-/* An object describing the contents of a traceframe. */
-
-struct traceframe_info
-{
- /* Collected memory. */
- VEC(mem_range_s) *memory;
-};
-
static VEC(tsv_s) *tvariables;
/* The next integer to assign to a variable. */
@@ -3303,8 +3295,6 @@ static const struct trace_file_write_ops tfile_write_ops =
#define TRACE_WRITE_V_BLOCK(writer, num, val) \
writer->ops->frame_ops->write_v_block ((writer), (num), (val))
-extern int trace_regblock_size;
-
/* Save tracepoint data to file named FILENAME through WRITER. WRITER
determines the trace file format. If TARGET_DOES_SAVE is non-zero,
the save is performed on the target, otherwise GDB obtains all trace
@@ -3741,6 +3731,12 @@ get_traceframe_number (void)
return traceframe_number;
}
+int
+get_tracepoint_number (void)
+{
+ return tracepoint_number;
+}
+
/* Make the traceframe NUM be the current trace frame. Does nothing
if NUM is already current. */
diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
index 8df906f..378824e 100644
--- a/gdb/tracepoint.h
+++ b/gdb/tracepoint.h
@@ -24,6 +24,14 @@
#include "memrange.h"
#include "gdb_vecs.h"
+/* An object describing the contents of a traceframe. */
+
+struct traceframe_info
+{
+ /* Collected memory. */
+ VEC(mem_range_s) *memory;
+};
+
/* A trace state variable is a value managed by a target being
traced. A trace state variable (or tsv for short) can be accessed
and assigned to by tracepoint actions and conditionals, but is not
@@ -142,6 +150,8 @@ struct trace_status *current_trace_status (void);
extern char *default_collect;
+extern int trace_regblock_size;
+
/* Struct to collect random info about tracepoints on the target. */
struct uploaded_tp
@@ -324,6 +334,9 @@ extern void (*deprecated_trace_start_stop_hook) (int start, int from_tty);
/* Returns the current traceframe number. */
extern int get_traceframe_number (void);
+/* Returns the tracepoint number for current traceframe. */
+extern int get_tracepoint_number (void);
+
/* Make the traceframe NUM be the current GDB trace frame number, and
do nothing more. In particular, this does not flush the
register/frame caches or notify the target about the trace frame
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: [PATCH v3 03/15] Read CTF by the ctf target
2013-04-09 15:23 ` Yao Qi
@ 2013-04-09 18:41 ` Doug Evans
0 siblings, 0 replies; 60+ messages in thread
From: Doug Evans @ 2013-04-09 18:41 UTC (permalink / raw)
To: Yao Qi; +Cc: Tom Tromey, gdb-patches
Yao Qi writes:
> On 04/09/2013 12:58 AM, Doug Evans wrote:
> >> + if (ret < 0)
> > > + {
> > > + ctf_destroy ();
> > > + error (_("Unable to use libbabeltrace open \"%s\""), dirname);
> >
> > The wording of this error message (here and below) is awkward.
> > I don't know libbabeltrace enough to know if this is accurate, but
> > it reads better.
> >
> > error (_("Unable to use libbabeltrace on \"%s\""), dirname);
> >
> > or
> >
> > error (_("Unable to use libbabeltrace on directory \"%s\""), dirname);
>
> I changed the message to
>
> error (_("Unable to use libbabeltrace on directory \"%s\""),
> dirname);
>
> >
> > Also, IWBN to add a more specific reason for the failure,
> > but I'm not sure how easy that would be.
> > Is there a bt_foo function akin to strerror?
> >
>
> Unfortunately, there isn't such function.
>
>
> > > +
> > > + if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
> > > + break;
> > > + }
> > > +
> > > + /* Restore the position. */
> > > + bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
> > > +
> >
> > Remove blank line.
> >
> > > +}
>
> Removed.
>
>
> > > +
> > > + scope = bt_ctf_get_top_level_scope (event,
> > > + BT_EVENT_FIELDS);
> > > +
> > > + def = bt_ctf_get_field (event, scope, "address");
> > > + maddr = bt_ctf_get_uint64 (def);
> > > + def = bt_ctf_get_field (event, scope, "length");
> > > + mlen = (uint16_t) bt_ctf_get_uint64 (def);
> >
> > I don't know libbabeltrace, I'm assuming length can be at most 16 bits.
> >
>
> Right. "length" is defined as uint16_t in metadata, on the other hand,
> "length" is got from the remote target, which is 16-bit as well.
>
> > > +
> > > +/* This is the implementation of target_ops method to_traceframe_info.
> > > + Iterate the events whose name is "memory", in current
> > > + frame, extract memory range information, and return them in
> > > + traceframe_info. */
> > > +
> > > +static struct traceframe_info *
> > > +ctf_traceframe_info (void)
> > > +{
> > > + struct traceframe_info *info = XCNEW (struct traceframe_info);
> > > + const char *name;
> > > + struct bt_iter_pos *pos;
> > > +
> > > + gdb_assert (ctf_iter != NULL);
> > > + /* Save the current position. */
> > > + pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
> > > + gdb_assert (pos->type == BT_SEEK_RESTORE);
> > > +
> > > + do
> > > + {
> > > + struct bt_ctf_event *event
> > > + = bt_ctf_iter_read_event (ctf_iter);
> > > +
> > > + name = bt_ctf_event_name (event);
> > > +
> > > + if (name == NULL || strcmp (name, "register") == 0
> > > + || strcmp (name, "frame") == 0)
> > > + ;
> > > + else if (strcmp (name, "memory") == 0)
> > > + {
> > > + const struct bt_definition *scope
> > > + = bt_ctf_get_top_level_scope (event,
> > > + BT_EVENT_FIELDS);
> > > + const struct bt_definition *def;
> > > + struct mem_range *r;
> > > +
> > > + r = VEC_safe_push (mem_range_s, info->memory, NULL);
> > > + def = bt_ctf_get_field (event, scope, "address");
> > > + r->start = bt_ctf_get_uint64 (def);
> > > +
> > > + def = bt_ctf_get_field (event, scope, "length");
> > > + r->length = (uint16_t) bt_ctf_get_uint64 (def);
> > > + }
> > > + else
> > > + warning (_("Unhandled trace block type (%s) "
> > > + "while building trace frame info."),
> > > + name);
> >
> > These days we prefer multi-line single statements for if/else/etc.
> > to be wrapped in braces. i.e.,
> >
> > {
> > warning (_("Unhandled trace block type (%s) "
> > "while building trace frame info."),
> > name);
> > }
> >
>
> Fixed. I knew that single statement with comments should be warped by
> braces, like:
>
> if (foo)
> /* Comments. */
> bar ();
>
> after reading GDB internals, I realize that "warning message in
> multiple lines" falls into this category as well. You are right.
>
> > > +
> > > +/* module initialization */
> >
> > blank line
> >
> > > +void
> > > +_initialize_ctf (void)
>
> Fixed.
>
> --
> Yao ( )
>
> gdb:
>
> 2013-04-09 Hui Zhu <hui@codesourcery.com>
> Yao Qi <yao@codesourcery.com>
>
> * configure.ac: Check libbabeltrace is installed.
> * config.in: Regenerate.
> * configure: Regenerate.
> * Makefile.in (LIBBABELTRACE): New.
> (CLIBS): Add LIBBABELTRACE.
> * ctf.c (ctx, ctf_iter, trace_dirname): New.
> (ctf_destroy, ctf_open_dir, ctf_open): New.
> (ctf_close, ctf_files_info): New.
> (ctf_fetch_registers, ctf_xfer_partial): New.
> (ctf_get_trace_state_variable_value): New.
> (ctf_get_tpnum_from_frame_event): New.
> (ctf_get_traceframe_address): New.
> (ctf_trace_find, ctf_has_stack): New.
> (ctf_has_registers, ctf_traceframe_info, init_ctf_ops): New.
> (_initialize_ctf): New.
> * tracepoint.c (get_tracepoint_number): New
> (struct traceframe_info, trace_regblock_size): Move it to ...
> * tracepoint.h: ... here.
> (get_tracepoint_number): Declare it.
Thanks.
The patch is ok.
^ permalink raw reply [flat|nested] 60+ messages in thread
* Re: [PATCH v3 00/15] CTF Support
2013-03-09 3:48 [PATCH v3 00/15] CTF Support Yao Qi
` (14 preceding siblings ...)
2013-03-09 3:49 ` [PATCH v3 03/15] Read CTF by the ctf target Yao Qi
@ 2013-04-10 19:16 ` Yao Qi
2013-04-11 22:59 ` [patch] Regenerate config.in [Re: [PATCH v3 00/15] CTF Support] Jan Kratochvil
2014-08-04 18:59 ` Incorrect placement of babeltrace gdb/NEWS item " Jan Kratochvil
15 siblings, 2 replies; 60+ messages in thread
From: Yao Qi @ 2013-04-10 19:16 UTC (permalink / raw)
To: gdb-patches
On 03/09/2013 11:47 AM, Yao Qi wrote:
> This patch series is about supporting writing GDB trace data to
> Common Trace Format (CTF) and read CTF file in a new target 'ctf'.
>
> Patch 1/15 ~ 5/15 are from V2, with all Pedro and Tom's comments
> addressed, but also make use of advanced CTF event type "sequences"
> which simplifies the design a little bit.
> The rest of the patches are new added to write trace
> status (by patch 6/15), uploaded tsv (by patch 11/15) and uploaded
> tracepoints (by patch 12/15) to CTF. So this patch series is a
> complete support to CTF, "complete" here means that the information
> saved in tfile is the same the information saved in ctf, no more
> and no less.
>
> Patch 7/15 ~ 9/15, 13/15 are not related to CTF. They are about
> writing some fields of trace status into tfile, and test the "tstatus"
> output and tracepoint actions in tfile target. They can be posted
> separately but looks more meaningful in this context.
>
> Note that this series don't include these patches:
>
> [PATCH 0/5] Look for the last matched V block in trace frame
> http://sourceware.org/ml/gdb-patches/2013-03/msg00252.html
>
> which are regarded as a bug fix to all three targets (live, tfile,
> ctf) on looking for V block in traceframe.
>
> This series is regression tested with {native, gdbserver} x w/
> babeltrace on x86 Fedora 16 and {native, gdbserver} x /wo
> babeltrace on x86_64 Lucid.
>
Patches 03 ~ 06, 10 ~ 12, 14 are approved and they are committed as a
whole, shown below. Now, the whole CTF stuff (except the patch to
MAINTAINER) goes into trunk. Thanks everyone who reviewed this series.
--
Yao (é½å°§)
gdb:
2013-04-10 Hui Zhu <hui@codesourcery.com>
Yao Qi <yao@codesourcery.com>
* configure.ac: Check libbabeltrace is installed.
* config.in: Regenerate.
* configure: Regenerate.
* Makefile.in (LIBBABELTRACE): New.
(CLIBS): Add LIBBABELTRACE.
* ctf.c: Include "exec.h".
(CTF_EVENT_ID_STATUS, CTF_EVENT_ID_TSV_DEF): New macros.
(CTF_EVENT_ID_TP_DEF, ctf_save_write_int32): New macros.
(ctf_save_metadata_header): Define new type aliases in
metadata.
(ctf_write_header): Define event type "tsv_def" and "tp_def"
in metadata. Start a new faked packet for trace status.
(ctf_write_status): Write trace status to CTF.
(ctf_write_uploaded_tsv): Write TSV to CTF.
(ctf_write_uploaded_tp): Write tracepoint definition to CTF.
(ctf_write_definition_end): End the faked packet.
(ctx, ctf_iter, trace_dirname): New.
(start_pos): New variable.
(ctf_destroy, ctf_open_dir, ctf_open): New.
(SET_INT32_FIELD, SET_ARRAY_FIELD, SET_STRING_FIELD): New
macros.
(ctf_read_tsv, ctf_read_tp, ctf_close, ctf_files_info): New.
(ctf_fetch_registers, ctf_xfer_partial): New.
(ctf_get_trace_state_variable_value): New.
(ctf_get_tpnum_from_frame_event): New.
(ctf_get_traceframe_address): New.
(ctf_trace_find, ctf_has_stack): New.
(ctf_has_registers, ctf_traceframe_info, init_ctf_ops): New.
(ctf_get_trace_status, ctf_read_status): New.
(_initialize_ctf): New.
* tracepoint.c (get_tracepoint_number): New
(get_uploaded_tsv): Remove 'static'.
(struct traceframe_info, trace_regblock_size): Move it to ...
* tracepoint.h: ... here.
(get_tracepoint_number): Declare it.
(get_uploaded_tsv): Declare it.
* NEWS: Mention new configure option.
gdb/doc:
2013-04-10 Yao Qi <yao@codesourcery.com>
* gdb.texinfo (Trace Files): Add "target ctf".
gdb/testsuite:
2013-04-10 Yao Qi <yao@codesourcery.com>
* gdb.trace/actions.exp: Save trace data to CTF.
Change to ctf target if GDB supports, read CTF data in ctf
target, and check the actions of tracepoints.
* gdb.trace/while-stepping.exp: Likewise.
* gdb.trace/report.exp: Test GDB saves trace data to CTF
format and read CTF trace file if GDB supports.
* gdb.trace/tstatus.exp: Save trace data to CTF. If ctf
target is supported, change to ctf target, read trace data and
check output of command "tstatus".
* gdb.trace/tsv.exp: Save trace frame to CTF. If GDB supports,
read CTF data by target ctf and call check_tsv.
---
gdb/Makefile.in | 6 +-
gdb/NEWS | 3 +
gdb/config.in | 3 +
gdb/configure | 517 ++++++++++++
gdb/configure.ac | 41 +
gdb/ctf.c | 1196 +++++++++++++++++++++++++++-
gdb/doc/gdb.texinfo | 32 +-
gdb/testsuite/gdb.trace/actions.exp | 24 +
gdb/testsuite/gdb.trace/report.exp | 14 +
gdb/testsuite/gdb.trace/tstatus.exp | 14 +
gdb/testsuite/gdb.trace/tsv.exp | 13 +
gdb/testsuite/gdb.trace/while-stepping.exp | 24 +
gdb/tracepoint.c | 18 +-
gdb/tracepoint.h | 15 +
14 files changed, 1892 insertions(+), 28 deletions(-)
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 498d42a..0814bcb 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -154,6 +154,10 @@ LIBEXPAT = @LIBEXPAT@
# Where is lzma? This will be empty if lzma was not available.
LIBLZMA = @LIBLZMA@
+# Where is libbabeltrace? This will be empty if lbabeltrace was not
+# available.
+LIBBABELTRACE = @LIBBABELTRACE@
+
WARN_CFLAGS = @WARN_CFLAGS@
WERROR_CFLAGS = @WERROR_CFLAGS@
GDB_WARN_CFLAGS = $(WARN_CFLAGS)
@@ -475,7 +479,7 @@ INTERNAL_LDFLAGS = $(CFLAGS) $(GLOBAL_CFLAGS) $(MH_LDFLAGS) $(LDFLAGS) $(CONFIG_
# LIBIBERTY appears twice on purpose.
CLIBS = $(SIM) $(READLINE) $(OPCODES) $(BFD) $(INTL) $(LIBIBERTY) $(LIBDECNUMBER) \
$(XM_CLIBS) $(NAT_CLIBS) $(GDBTKLIBS) @LIBS@ @PYTHON_LIBS@ \
- $(LIBEXPAT) $(LIBLZMA) \
+ $(LIBEXPAT) $(LIBLZMA) $(LIBBABELTRACE) \
$(LIBIBERTY) $(WIN32LIBS) $(LIBGNU)
CDEPS = $(XM_CDEPS) $(NAT_CDEPS) $(SIM) $(BFD) $(READLINE_DEPS) \
$(OPCODES) $(INTL_DEPS) $(LIBIBERTY) $(CONFIG_DEPS) $(LIBGNU)
diff --git a/gdb/NEWS b/gdb/NEWS
index 6f202e2..86716e0 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -135,6 +135,9 @@ Tilera TILE-Gx GNU/Linux tilegx*-*-linux
Release versions, on the other hand, are built without -lmcheck
by default. The --enable-libmcheck/--disable-libmcheck configure
options allow the user to override that default.
+--with-babeltrace/--with-babeltrace-include/--with-babeltrace-lib
+ This configure option allows the user to build GDB with
+ libbabeltrace using which GDB can read Common Trace Format data.
* New commands (for set/show, see "New options" below)
diff --git a/gdb/config.in b/gdb/config.in
index 9e21325..c4e8eaa 100644
--- a/gdb/config.in
+++ b/gdb/config.in
@@ -180,6 +180,9 @@
/* Define if your <locale.h> file defines LC_MESSAGES. */
#undef HAVE_LC_MESSAGES
+/* Define if libbabeltrace is available */
+#undef HAVE_LIBBABELTRACE
+
/* Define to 1 if you have the `dl' library (-ldl). */
#undef HAVE_LIBDL
diff --git a/gdb/configure b/gdb/configure
index 0dd67f0..6588c72 100755
--- a/gdb/configure
+++ b/gdb/configure
@@ -592,6 +592,9 @@ enable_option_checking=no
ac_subst_vars='LTLIBOBJS
LIBOBJS
GDB_NM_FILE
+LTLIBBABELTRACE
+LIBBABELTRACE
+HAVE_LIBBABELTRACE
frags
target_subdir
CONFIG_UNINSTALL
@@ -819,6 +822,8 @@ with_x
enable_sim
enable_multi_ice
enable_gdbserver
+with_babeltrace
+with_libbabeltrace_prefix
'
ac_precious_vars='build_alias
host_alias
@@ -1532,6 +1537,9 @@ Optional Packages:
--with-tcl directory containing tcl configuration (tclConfig.sh)
--with-tk directory containing tk configuration (tkConfig.sh)
--with-x use the X Window System
+ --with-babeltrace include babeltrace support (auto/yes/no)
+ --with-libbabeltrace-prefix[=DIR] search for libbabeltrace in DIR/include and DIR/lib
+ --without-libbabeltrace-prefix don't search for libbabeltrace in includedir and libdir
Some influential environment variables:
CC C compiler command
@@ -14093,6 +14101,515 @@ if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then
as_fn_error "Automatic gdbserver build is not supported for this configuration" "$LINENO" 5
fi
+# Check for babeltrace and babeltrace-ctf
+
+# Check whether --with-babeltrace was given.
+if test "${with_babeltrace+set}" = set; then :
+ withval=$with_babeltrace;
+else
+ with_babeltrace=auto
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to use babeltrace" >&5
+$as_echo_n "checking whether to use babeltrace... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_babeltrace" >&5
+$as_echo "$with_babeltrace" >&6; }
+
+if test "x$with_babeltrace" = "xno"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: babletrace support disabled; GDB is unable to read CTF data." >&5
+$as_echo "$as_me: WARNING: babletrace support disabled; GDB is unable to read CTF data." >&2;}
+else
+ # Append -Werror to CFLAGS so that configure can catch the warning
+ # "assignment from incompatible pointer type", which is related to
+ # the babeltrace change from 1.0.3 to 1.1.0. Babeltrace 1.1.0 works
+ # in GDB, while babeltrace 1.0.3 is broken.
+ # AC_LIB_HAVE_LINKFLAGS may modify CPPFLAGS in it, so it should be
+ # safe to save and restore CFLAGS here.
+ saved_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS -Werror"
+
+
+
+
+
+
+
+
+ use_additional=yes
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+
+# Check whether --with-libbabeltrace-prefix was given.
+if test "${with_libbabeltrace_prefix+set}" = set; then :
+ withval=$with_libbabeltrace_prefix;
+ if test "X$withval" = "Xno"; then
+ use_additional=no
+ else
+ if test "X$withval" = "X"; then
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+
+ eval additional_includedir=\"$includedir\"
+ eval additional_libdir=\"$libdir\"
+
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ else
+ additional_includedir="$withval/include"
+ additional_libdir="$withval/lib"
+ fi
+ fi
+
+fi
+
+ LIBBABELTRACE=
+ LTLIBBABELTRACE=
+ INCBABELTRACE=
+ rpathdirs=
+ ltrpathdirs=
+ names_already_handled=
+ names_next_round='babeltrace babeltrace-ctf'
+ while test -n "$names_next_round"; do
+ names_this_round="$names_next_round"
+ names_next_round=
+ for name in $names_this_round; do
+ already_handled=
+ for n in $names_already_handled; do
+ if test "$n" = "$name"; then
+ already_handled=yes
+ break
+ fi
+ done
+ if test -z "$already_handled"; then
+ names_already_handled="$names_already_handled $name"
+ uppername=`echo "$name" | sed -e 'y|abcdefghijklmnopqrstuvwxyz./-|ABCDEFGHIJKLMNOPQRSTUVWXYZ___|'`
+ eval value=\"\$HAVE_LIB$uppername\"
+ if test -n "$value"; then
+ if test "$value" = yes; then
+ eval value=\"\$LIB$uppername\"
+ test -z "$value" || LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$value"
+ eval value=\"\$LTLIB$uppername\"
+ test -z "$value" || LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }$value"
+ else
+ :
+ fi
+ else
+ found_dir=
+ found_la=
+ found_so=
+ found_a=
+ if test $use_additional = yes; then
+ if test -n "$shlibext" && test -f "$additional_libdir/lib$name.$shlibext"; then
+ found_dir="$additional_libdir"
+ found_so="$additional_libdir/lib$name.$shlibext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ else
+ if test -f "$additional_libdir/lib$name.$libext"; then
+ found_dir="$additional_libdir"
+ found_a="$additional_libdir/lib$name.$libext"
+ if test -f "$additional_libdir/lib$name.la"; then
+ found_la="$additional_libdir/lib$name.la"
+ fi
+ fi
+ fi
+ fi
+ if test "X$found_dir" = "X"; then
+ for x in $LDFLAGS $LTLIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ case "$x" in
+ -L*)
+ dir=`echo "X$x" | sed -e 's/^X-L//'`
+ if test -n "$shlibext" && test -f "$dir/lib$name.$shlibext"; then
+ found_dir="$dir"
+ found_so="$dir/lib$name.$shlibext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ else
+ if test -f "$dir/lib$name.$libext"; then
+ found_dir="$dir"
+ found_a="$dir/lib$name.$libext"
+ if test -f "$dir/lib$name.la"; then
+ found_la="$dir/lib$name.la"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ if test "X$found_dir" != "X"; then
+ break
+ fi
+ done
+ fi
+ if test "X$found_dir" != "X"; then
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-L$found_dir -l$name"
+ if test "X$found_so" != "X"; then
+ if test "$enable_rpath" = no || test "X$found_dir" = "X/usr/lib"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ else
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $found_dir"
+ fi
+ if test "$hardcode_direct" = yes; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ else
+ if test -n "$hardcode_libdir_flag_spec" && test "$hardcode_minus_L" = no; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $found_dir"
+ fi
+ else
+ haveit=
+ for x in $LDFLAGS $LIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$found_dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$found_dir"
+ fi
+ if test "$hardcode_minus_L" != no; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_so"
+ else
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-l$name"
+ fi
+ fi
+ fi
+ fi
+ else
+ if test "X$found_a" != "X"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$found_a"
+ else
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$found_dir -l$name"
+ fi
+ fi
+ additional_includedir=
+ case "$found_dir" in
+ */lib | */lib/)
+ basedir=`echo "X$found_dir" | sed -e 's,^X,,' -e 's,/lib/*$,,'`
+ additional_includedir="$basedir/include"
+ ;;
+ esac
+ if test "X$additional_includedir" != "X"; then
+ if test "X$additional_includedir" != "X/usr/include"; then
+ haveit=
+ if test "X$additional_includedir" = "X/usr/local/include"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ for x in $CPPFLAGS $INCBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-I$additional_includedir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_includedir"; then
+ INCBABELTRACE="${INCBABELTRACE}${INCBABELTRACE:+ }-I$additional_includedir"
+ fi
+ fi
+ fi
+ fi
+ fi
+ if test -n "$found_la"; then
+ save_libdir="$libdir"
+ case "$found_la" in
+ */* | *\\*) . "$found_la" ;;
+ *) . "./$found_la" ;;
+ esac
+ libdir="$save_libdir"
+ for dep in $dependency_libs; do
+ case "$dep" in
+ -L*)
+ additional_libdir=`echo "X$dep" | sed -e 's/^X-L//'`
+ if test "X$additional_libdir" != "X/usr/lib"; then
+ haveit=
+ if test "X$additional_libdir" = "X/usr/local/lib"; then
+ if test -n "$GCC"; then
+ case $host_os in
+ linux*) haveit=yes;;
+ esac
+ fi
+ fi
+ if test -z "$haveit"; then
+ haveit=
+ for x in $LDFLAGS $LIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-L$additional_libdir"
+ fi
+ fi
+ haveit=
+ for x in $LDFLAGS $LTLIBBABELTRACE; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X-L$additional_libdir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ if test -d "$additional_libdir"; then
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-L$additional_libdir"
+ fi
+ fi
+ fi
+ fi
+ ;;
+ -R*)
+ dir=`echo "X$dep" | sed -e 's/^X-R//'`
+ if test "$enable_rpath" != no; then
+ haveit=
+ for x in $rpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ rpathdirs="$rpathdirs $dir"
+ fi
+ haveit=
+ for x in $ltrpathdirs; do
+ if test "X$x" = "X$dir"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ ltrpathdirs="$ltrpathdirs $dir"
+ fi
+ fi
+ ;;
+ -l*)
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's/^X-l//'`
+ ;;
+ *.la)
+ names_next_round="$names_next_round "`echo "X$dep" | sed -e 's,^X.*/,,' -e 's,^lib,,' -e 's,\.la$,,'`
+ ;;
+ *)
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$dep"
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }$dep"
+ ;;
+ esac
+ done
+ fi
+ else
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }-l$name"
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-l$name"
+ fi
+ fi
+ fi
+ done
+ done
+ if test "X$rpathdirs" != "X"; then
+ if test -n "$hardcode_libdir_separator"; then
+ alldirs=
+ for found_dir in $rpathdirs; do
+ alldirs="${alldirs}${alldirs:+$hardcode_libdir_separator}$found_dir"
+ done
+ acl_save_libdir="$libdir"
+ libdir="$alldirs"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$flag"
+ else
+ for found_dir in $rpathdirs; do
+ acl_save_libdir="$libdir"
+ libdir="$found_dir"
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ libdir="$acl_save_libdir"
+ LIBBABELTRACE="${LIBBABELTRACE}${LIBBABELTRACE:+ }$flag"
+ done
+ fi
+ fi
+ if test "X$ltrpathdirs" != "X"; then
+ for found_dir in $ltrpathdirs; do
+ LTLIBBABELTRACE="${LTLIBBABELTRACE}${LTLIBBABELTRACE:+ }-R$found_dir"
+ done
+ fi
+
+
+ ac_save_CPPFLAGS="$CPPFLAGS"
+
+ for element in $INCBABELTRACE; do
+ haveit=
+ for x in $CPPFLAGS; do
+
+ acl_save_prefix="$prefix"
+ prefix="$acl_final_prefix"
+ acl_save_exec_prefix="$exec_prefix"
+ exec_prefix="$acl_final_exec_prefix"
+ eval x=\"$x\"
+ exec_prefix="$acl_save_exec_prefix"
+ prefix="$acl_save_prefix"
+
+ if test "X$x" = "X$element"; then
+ haveit=yes
+ break
+ fi
+ done
+ if test -z "$haveit"; then
+ CPPFLAGS="${CPPFLAGS}${CPPFLAGS:+ }$element"
+ fi
+ done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for libbabeltrace" >&5
+$as_echo_n "checking for libbabeltrace... " >&6; }
+if test "${ac_cv_libbabeltrace+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ac_save_LIBS="$LIBS"
+ LIBS="$LIBS $LIBBABELTRACE"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <babeltrace/babeltrace.h>
+ #include <babeltrace/ctf/events.h>
+ #include <babeltrace/ctf/iterator.h>
+int
+main ()
+{
+struct bt_iter_pos *pos = bt_iter_get_pos (bt_ctf_get_iter (NULL));
+ struct bt_ctf_event *event = NULL;
+ const struct bt_definition *scope;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_STREAM_EVENT_HEADER);
+ bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_libbabeltrace=yes
+else
+ ac_cv_libbabeltrace=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LIBS="$ac_save_LIBS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_libbabeltrace" >&5
+$as_echo "$ac_cv_libbabeltrace" >&6; }
+ if test "$ac_cv_libbabeltrace" = yes; then
+ HAVE_LIBBABELTRACE=yes
+
+$as_echo "#define HAVE_LIBBABELTRACE 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to link with libbabeltrace" >&5
+$as_echo_n "checking how to link with libbabeltrace... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIBBABELTRACE" >&5
+$as_echo "$LIBBABELTRACE" >&6; }
+ else
+ HAVE_LIBBABELTRACE=no
+ CPPFLAGS="$ac_save_CPPFLAGS"
+ LIBBABELTRACE=
+ LTLIBBABELTRACE=
+ fi
+
+
+
+
+
+
+ CFLAGS=$saved_CFLAGS
+
+ if test "$HAVE_LIBBABELTRACE" != yes; then
+ if test "$with_babeltrace" = yes; then
+ as_fn_error "babeltrace is missing or unusable" "$LINENO" 5
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: babeltrace is missing or unusable; GDB is unable to read CTF data." >&5
+$as_echo "$as_me: WARNING: babeltrace is missing or unusable; GDB is unable to read CTF data." >&2;}
+ fi
+ fi
+fi
+
# If nativefile (NAT_FILE) is not set in config/*/*.m[ht] files, we link
# to an empty version.
diff --git a/gdb/configure.ac b/gdb/configure.ac
index c17f587..149ac37 100644
--- a/gdb/configure.ac
+++ b/gdb/configure.ac
@@ -2321,6 +2321,47 @@ if test "$enable_gdbserver" = "yes" -a "$gdbserver_build_enabled" != "yes"; then
AC_MSG_ERROR(Automatic gdbserver build is not supported for this configuration)
fi
+# Check for babeltrace and babeltrace-ctf
+AC_ARG_WITH(babeltrace,
+ AC_HELP_STRING([--with-babeltrace], [include babeltrace support (auto/yes/no)]),
+ [], [with_babeltrace=auto])
+AC_MSG_CHECKING([whether to use babeltrace])
+AC_MSG_RESULT([$with_babeltrace])
+
+if test "x$with_babeltrace" = "xno"; then
+ AC_MSG_WARN([babletrace support disabled; GDB is unable to read CTF data.])
+else
+ # Append -Werror to CFLAGS so that configure can catch the warning
+ # "assignment from incompatible pointer type", which is related to
+ # the babeltrace change from 1.0.3 to 1.1.0. Babeltrace 1.1.0 works
+ # in GDB, while babeltrace 1.0.3 is broken.
+ # AC_LIB_HAVE_LINKFLAGS may modify CPPFLAGS in it, so it should be
+ # safe to save and restore CFLAGS here.
+ saved_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS -Werror"
+ AC_LIB_HAVE_LINKFLAGS([babeltrace], [babeltrace-ctf],
+ [#include <babeltrace/babeltrace.h>
+ #include <babeltrace/ctf/events.h>
+ #include <babeltrace/ctf/iterator.h>],
+ [struct bt_iter_pos *pos = bt_iter_get_pos (bt_ctf_get_iter (NULL));
+ struct bt_ctf_event *event = NULL;
+ const struct bt_definition *scope;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_STREAM_EVENT_HEADER);
+ bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+ ])
+ CFLAGS=$saved_CFLAGS
+
+ if test "$HAVE_LIBBABELTRACE" != yes; then
+ if test "$with_babeltrace" = yes; then
+ AC_MSG_ERROR([babeltrace is missing or unusable])
+ else
+ AC_MSG_WARN([babeltrace is missing or unusable; GDB is unable to read CTF data.])
+ fi
+ fi
+fi
+
# If nativefile (NAT_FILE) is not set in config/*/*.m[ht] files, we link
# to an empty version.
diff --git a/gdb/ctf.c b/gdb/ctf.c
index de54051..0985784 100644
--- a/gdb/ctf.c
+++ b/gdb/ctf.c
@@ -24,6 +24,7 @@
#include "tracepoint.h"
#include "regcache.h"
#include "gdb_stat.h"
+#include "exec.h"
#include <ctype.h>
@@ -34,10 +35,15 @@
1. The length (in bytes) of register cache. Event "register" will
be defined in metadata, which includes the length.
- 2. Trace status. Not implemented yet in CTF writer.
+ 2. Trace status. Event "status" is defined in metadata, which
+ includes all aspects of trace status.
- 3. Uploaded trace variables and tracepoints. Not implemented yet
- in CTF writer.
+ 3. Uploaded trace variables. Event "tsv_def" is defined in
+ metadata, which is about all aspects of a uploaded trace variable.
+ Uploaded tracepoints. Event "tp_def" is defined in meta, which
+ is about all aspects of an uploaded tracepoint. Note that the
+ "sequence" (a CTF type, which is a dynamically-sized array.) is
+ used for "actions" "step_actions" and "cmd_strings".
4. Trace frames. Each trace frame is composed by several blocks
of different types ('R', 'M', 'V'). One trace frame is saved in
@@ -65,6 +71,9 @@
#define CTF_EVENT_ID_TSV 1
#define CTF_EVENT_ID_MEMORY 2
#define CTF_EVENT_ID_FRAME 3
+#define CTF_EVENT_ID_STATUS 4
+#define CTF_EVENT_ID_TSV_DEF 5
+#define CTF_EVENT_ID_TP_DEF 6
/* The state kept while writing the CTF datastream file. */
@@ -119,6 +128,12 @@ ctf_save_write (struct trace_write_handler *handler,
#define ctf_save_write_uint32(HANDLER, U32) \
ctf_save_write (HANDLER, (gdb_byte *) &U32, 4)
+/* Write a signed 32-bit integer to datastream file represented by
+ HANDLER. */
+
+#define ctf_save_write_int32(HANDLER, INT32) \
+ ctf_save_write ((HANDLER), (gdb_byte *) &(INT32), 4)
+
/* Set datastream file position. Update HANDLER->content_size
if WHENCE is SEEK_CUR. */
@@ -217,6 +232,15 @@ ctf_save_metadata_header (struct trace_write_handler *handler)
"typealias integer { size = 64; align = 64;"
"signed = false; base = hex;}"
" := uint64_t;\n");
+ ctf_save_write_metadata (handler,
+ "typealias integer { size = 32; align = 32;"
+ "signed = true; } := int32_t;\n");
+ ctf_save_write_metadata (handler,
+ "typealias integer { size = 64; align = 64;"
+ "signed = true; } := int64_t;\n");
+ ctf_save_write_metadata (handler,
+ "typealias string { encoding = ascii;"
+ " } := chars;\n");
ctf_save_write_metadata (handler, "\n");
/* Get the byte order of the host and write CTF data in this byte
@@ -365,8 +389,50 @@ ctf_write_header (struct trace_file_writer *self)
"\t};\n"
"};\n", CTF_EVENT_ID_FRAME);
+ ctf_save_write_metadata (&writer->tcs, "\n");
+ ctf_save_write_metadata (&writer->tcs,
+ "event {\n\tname = \"tsv_def\";\n"
+ "\tid = %u;\n\tfields := struct { \n"
+ "\t\tint64_t initial_value;\n"
+ "\t\tint32_t number;\n"
+ "\t\tint32_t builtin;\n"
+ "\t\tchars name;\n"
+ "\t};\n"
+ "};\n", CTF_EVENT_ID_TSV_DEF);
+
+ ctf_save_write_metadata (&writer->tcs, "\n");
+ ctf_save_write_metadata (&writer->tcs,
+ "event {\n\tname = \"tp_def\";\n"
+ "\tid = %u;\n\tfields := struct { \n"
+ "\t\tuint64_t addr;\n"
+ "\t\tuint64_t traceframe_usage;\n"
+ "\t\tint32_t number;\n"
+ "\t\tint32_t enabled;\n"
+ "\t\tint32_t step;\n"
+ "\t\tint32_t pass;\n"
+ "\t\tint32_t hit_count;\n"
+ "\t\tint32_t type;\n"
+ "\t\tchars cond;\n"
+
+ "\t\tuint32_t action_num;\n"
+ "\t\tchars actions[action_num];\n"
+
+ "\t\tuint32_t step_action_num;\n"
+ "\t\tchars step_actions[step_action_num];\n"
+
+ "\t\tchars at_string;\n"
+ "\t\tchars cond_string;\n"
+
+ "\t\tuint32_t cmd_num;\n"
+ "\t\tchars cmd_strings[cmd_num];\n"
+ "\t};\n"
+ "};\n", CTF_EVENT_ID_TP_DEF);
+
gdb_assert (writer->tcs.content_size == 0);
gdb_assert (writer->tcs.packet_start == 0);
+
+ /* Create a new packet to contain this event. */
+ self->ops->frame_ops->start (self, 0);
}
/* This is the implementation of trace_file_write_ops method
@@ -397,8 +463,39 @@ static void
ctf_write_status (struct trace_file_writer *self,
struct trace_status *ts)
{
- /* It is not supported yet to write trace status into CTF trace
- data. */
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ uint32_t id;
+ int32_t int32;
+
+ ctf_save_write_metadata (&writer->tcs, "\n");
+ ctf_save_write_metadata (&writer->tcs,
+ "event {\n\tname = \"status\";\n\tid = %u;\n"
+ "\tfields := struct { \n"
+ "\t\tint32_t stop_reason;\n"
+ "\t\tint32_t stopping_tracepoint;\n"
+ "\t\tint32_t traceframe_count;\n"
+ "\t\tint32_t traceframes_created;\n"
+ "\t\tint32_t buffer_free;\n"
+ "\t\tint32_t buffer_size;\n"
+ "\t\tint32_t disconnected_tracing;\n"
+ "\t\tint32_t circular_buffer;\n"
+ "\t};\n"
+ "};\n",
+ CTF_EVENT_ID_STATUS);
+
+ id = CTF_EVENT_ID_STATUS;
+ /* Event Id. */
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &id, 4, 4);
+
+ ctf_save_write_int32 (&writer->tcs, ts->stop_reason);
+ ctf_save_write_int32 (&writer->tcs, ts->stopping_tracepoint);
+ ctf_save_write_int32 (&writer->tcs, ts->traceframe_count);
+ ctf_save_write_int32 (&writer->tcs, ts->traceframes_created);
+ ctf_save_write_int32 (&writer->tcs, ts->buffer_free);
+ ctf_save_write_int32 (&writer->tcs, ts->buffer_size);
+ ctf_save_write_int32 (&writer->tcs, ts->disconnected_tracing);
+ ctf_save_write_int32 (&writer->tcs, ts->circular_buffer);
}
/* This is the implementation of trace_file_write_ops method
@@ -408,8 +505,31 @@ static void
ctf_write_uploaded_tsv (struct trace_file_writer *self,
struct uploaded_tsv *tsv)
{
- /* It is not supported yet to write uploaded trace variables
- into CTF trace data. */
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ int32_t int32;
+ int64_t int64;
+ unsigned int len;
+ const gdb_byte zero = 0;
+
+ /* Event Id. */
+ int32 = CTF_EVENT_ID_TSV_DEF;
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &int32, 4, 4);
+
+ /* initial_value */
+ int64 = tsv->initial_value;
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &int64, 8, 8);
+
+ /* number */
+ ctf_save_write_int32 (&writer->tcs, tsv->number);
+
+ /* builtin */
+ ctf_save_write_int32 (&writer->tcs, tsv->builtin);
+
+ /* name */
+ if (tsv->name != NULL)
+ ctf_save_write (&writer->tcs, tsv->name, strlen (tsv->name));
+ ctf_save_write (&writer->tcs, &zero, 1);
}
/* This is the implementation of trace_file_write_ops method
@@ -419,8 +539,80 @@ static void
ctf_write_uploaded_tp (struct trace_file_writer *self,
struct uploaded_tp *tp)
{
- /* It is not supported yet to write uploaded tracepoints
- into CTF trace data. */
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+ int32_t int32;
+ int64_t int64;
+ uint32_t u32;
+ const gdb_byte zero = 0;
+ int a;
+ char *act;
+
+ /* Event Id. */
+ int32 = CTF_EVENT_ID_TP_DEF;
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &int32, 4, 4);
+
+ /* address */
+ int64 = tp->addr;
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &int64, 8, 8);
+
+ /* traceframe_usage */
+ int64 = tp->traceframe_usage;
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &int64, 8, 8);
+
+ /* number */
+ ctf_save_write_int32 (&writer->tcs, tp->number);
+
+ /* enabled */
+ ctf_save_write_int32 (&writer->tcs, tp->enabled);
+
+ /* step */
+ ctf_save_write_int32 (&writer->tcs, tp->step);
+
+ /* pass */
+ ctf_save_write_int32 (&writer->tcs, tp->pass);
+
+ /* hit_count */
+ ctf_save_write_int32 (&writer->tcs, tp->hit_count);
+
+ /* type */
+ ctf_save_write_int32 (&writer->tcs, tp->type);
+
+ /* condition */
+ if (tp->cond != NULL)
+ ctf_save_write (&writer->tcs, tp->cond, strlen (tp->cond));
+ ctf_save_write (&writer->tcs, &zero, 1);
+
+ /* actions */
+ u32 = VEC_length (char_ptr, tp->actions);
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &u32, 4, 4);
+ for (a = 0; VEC_iterate (char_ptr, tp->actions, a, act); ++a)
+ ctf_save_write (&writer->tcs, act, strlen (act) + 1);
+
+ /* step_actions */
+ u32 = VEC_length (char_ptr, tp->step_actions);
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &u32, 4, 4);
+ for (a = 0; VEC_iterate (char_ptr, tp->step_actions, a, act); ++a)
+ ctf_save_write (&writer->tcs, act, strlen (act) + 1);
+
+ /* at_string */
+ if (tp->at_string != NULL)
+ ctf_save_write (&writer->tcs, tp->at_string,
+ strlen (tp->at_string));
+ ctf_save_write (&writer->tcs, &zero, 1);
+
+ /* cond_string */
+ if (tp->cond_string != NULL)
+ ctf_save_write (&writer->tcs, tp->cond_string,
+ strlen (tp->cond_string));
+ ctf_save_write (&writer->tcs, &zero, 1);
+
+ /* cmd_strings */
+ u32 = VEC_length (char_ptr, tp->cmd_strings);
+ ctf_save_align_write (&writer->tcs, (gdb_byte *) &u32, 4, 4);
+ for (a = 0; VEC_iterate (char_ptr, tp->cmd_strings, a, act); ++a)
+ ctf_save_write (&writer->tcs, act, strlen (act) + 1);
+
}
/* This is the implementation of trace_file_write_ops method
@@ -429,7 +621,10 @@ ctf_write_uploaded_tp (struct trace_file_writer *self,
static void
ctf_write_definition_end (struct trace_file_writer *self)
{
- /* Nothing to do for CTF. */
+ struct ctf_trace_file_writer *writer
+ = (struct ctf_trace_file_writer *) self;
+
+ self->ops->frame_ops->end (self);
}
/* The minimal file size of data stream. It is required by
@@ -670,3 +865,984 @@ ctf_trace_file_writer_new (void)
return (struct trace_file_writer *) writer;
}
+
+#if HAVE_LIBBABELTRACE
+/* Use libbabeltrace to read CTF data. The libbabeltrace provides
+ iterator to iterate over each event in CTF data and APIs to get
+ details of event and packet, so it is very convenient to use
+ libbabeltrace to access events in CTF. */
+
+#include <babeltrace/babeltrace.h>
+#include <babeltrace/ctf/events.h>
+#include <babeltrace/ctf/iterator.h>
+
+/* The struct pointer for current CTF directory. */
+static struct bt_context *ctx = NULL;
+static struct bt_ctf_iter *ctf_iter = NULL;
+/* The position of the first packet containing trace frame. */
+static struct bt_iter_pos *start_pos;
+
+/* The name of CTF directory. */
+static char *trace_dirname;
+
+static struct target_ops ctf_ops;
+
+/* Destroy ctf iterator and context. */
+
+static void
+ctf_destroy (void)
+{
+ if (ctf_iter != NULL)
+ {
+ bt_ctf_iter_destroy (ctf_iter);
+ ctf_iter = NULL;
+ }
+ if (ctx != NULL)
+ {
+ bt_context_put (ctx);
+ ctx = NULL;
+ }
+}
+
+/* Open CTF trace data in DIRNAME. */
+
+static void
+ctf_open_dir (char *dirname)
+{
+ int ret;
+ struct bt_iter_pos begin_pos;
+ struct bt_iter_pos *pos;
+
+ ctx = bt_context_create ();
+ if (ctx == NULL)
+ error (_("Unable to create bt_context"));
+ ret = bt_context_add_trace (ctx, dirname, "ctf", NULL, NULL, NULL);
+ if (ret < 0)
+ {
+ ctf_destroy ();
+ error (_("Unable to use libbabeltrace on directory \"%s\""),
+ dirname);
+ }
+
+ begin_pos.type = BT_SEEK_BEGIN;
+ ctf_iter = bt_ctf_iter_create (ctx, &begin_pos, NULL);
+ if (ctf_iter == NULL)
+ {
+ ctf_destroy ();
+ error (_("Unable to create bt_iterator"));
+ }
+
+ /* Iterate over events, and look for an event for register block
+ to set trace_regblock_size. */
+
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event;
+
+ event = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (name == NULL)
+ break;
+ else if (strcmp (name, "register") == 0)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+
+ trace_regblock_size
+ = bt_ctf_get_array_len (bt_ctf_get_decl_from_def (array));
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+}
+
+#define SET_INT32_FIELD(EVENT, SCOPE, VAR, FIELD) \
+ (VAR)->FIELD = (int) bt_ctf_get_int64 (bt_ctf_get_field ((EVENT), \
+ (SCOPE), \
+ #FIELD))
+
+/* EVENT is the "status" event and TS is filled in. */
+
+static void
+ctf_read_status (struct bt_ctf_event *event, struct trace_status *ts)
+{
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event, BT_EVENT_FIELDS);
+
+ SET_INT32_FIELD (event, scope, ts, stop_reason);
+ SET_INT32_FIELD (event, scope, ts, stopping_tracepoint);
+ SET_INT32_FIELD (event, scope, ts, traceframe_count);
+ SET_INT32_FIELD (event, scope, ts, traceframes_created);
+ SET_INT32_FIELD (event, scope, ts, buffer_free);
+ SET_INT32_FIELD (event, scope, ts, buffer_size);
+ SET_INT32_FIELD (event, scope, ts, disconnected_tracing);
+ SET_INT32_FIELD (event, scope, ts, circular_buffer);
+
+ bt_iter_next (bt_ctf_get_iter (ctf_iter));
+}
+
+/* Read the events "tsv_def" one by one, extract its contents and fill
+ in the list UPLOADED_TSVS. */
+
+static void
+ctf_read_tsv (struct uploaded_tsv **uploaded_tsvs)
+{
+ gdb_assert (ctf_iter != NULL);
+
+ while (1)
+ {
+ struct bt_ctf_event *event;
+ const struct bt_definition *scope;
+ const struct bt_definition *def;
+ uint32_t event_id;
+ struct uploaded_tsv *utsv = NULL;
+
+ event = bt_ctf_iter_read_event (ctf_iter);
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_STREAM_EVENT_HEADER);
+ event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope,
+ "id"));
+ if (event_id != CTF_EVENT_ID_TSV_DEF)
+ break;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+
+ def = bt_ctf_get_field (event, scope, "number");
+ utsv = get_uploaded_tsv ((int32_t) bt_ctf_get_int64 (def),
+ uploaded_tsvs);
+
+ def = bt_ctf_get_field (event, scope, "builtin");
+ utsv->builtin = (int32_t) bt_ctf_get_int64 (def);
+ def = bt_ctf_get_field (event, scope, "initial_value");
+ utsv->initial_value = bt_ctf_get_int64 (def);
+
+ def = bt_ctf_get_field (event, scope, "name");
+ utsv->name = xstrdup (bt_ctf_get_string (def));
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+}
+
+/* Read the value of element whose index is NUM from CTF and write it
+ to the corresponding VAR->ARRAY. */
+
+#define SET_ARRAY_FIELD(EVENT, SCOPE, VAR, NUM, ARRAY) \
+ do \
+ { \
+ uint32_t u32, i; \
+ const struct bt_definition *def; \
+ \
+ u32 = (uint32_t) bt_ctf_get_uint64 (bt_ctf_get_field ((EVENT), \
+ (SCOPE), \
+ #NUM)); \
+ def = bt_ctf_get_field ((EVENT), (SCOPE), #ARRAY); \
+ for (i = 0; i < u32; i++) \
+ { \
+ const struct bt_definition *element \
+ = bt_ctf_get_index ((EVENT), def, i); \
+ \
+ VEC_safe_push (char_ptr, (VAR)->ARRAY, \
+ xstrdup (bt_ctf_get_string (element))); \
+ } \
+ } \
+ while (0)
+
+/* Read a string from CTF and set VAR->FIELD. If the length of string
+ is zero, set VAR->FIELD to NULL. */
+
+#define SET_STRING_FIELD(EVENT, SCOPE, VAR, FIELD) \
+ do \
+ { \
+ const char *p = bt_ctf_get_string (bt_ctf_get_field ((EVENT), \
+ (SCOPE), \
+ #FIELD)); \
+ \
+ if (strlen (p) > 0) \
+ (VAR)->FIELD = xstrdup (p); \
+ else \
+ (VAR)->FIELD = NULL; \
+ } \
+ while (0)
+
+/* Read the events "tp_def" one by one, extract its contents and fill
+ in the list UPLOADED_TPS. */
+
+static void
+ctf_read_tp (struct uploaded_tp **uploaded_tps)
+{
+ gdb_assert (ctf_iter != NULL);
+
+ while (1)
+ {
+ struct bt_ctf_event *event;
+ const struct bt_definition *scope;
+ uint32_t u32;
+ int32_t int32;
+ uint64_t u64;
+ struct uploaded_tp *utp = NULL;
+
+ event = bt_ctf_iter_read_event (ctf_iter);
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_STREAM_EVENT_HEADER);
+ u32 = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope,
+ "id"));
+ if (u32 != CTF_EVENT_ID_TP_DEF)
+ break;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ int32 = (int32_t) bt_ctf_get_int64 (bt_ctf_get_field (event,
+ scope,
+ "number"));
+ u64 = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope,
+ "addr"));
+ utp = get_uploaded_tp (int32, u64, uploaded_tps);
+
+ SET_INT32_FIELD (event, scope, utp, enabled);
+ SET_INT32_FIELD (event, scope, utp, step);
+ SET_INT32_FIELD (event, scope, utp, pass);
+ SET_INT32_FIELD (event, scope, utp, hit_count);
+ SET_INT32_FIELD (event, scope, utp, type);
+
+ /* Read 'cmd_strings'. */
+ SET_ARRAY_FIELD (event, scope, utp, cmd_num, cmd_strings);
+ /* Read 'actions'. */
+ SET_ARRAY_FIELD (event, scope, utp, action_num, actions);
+ /* Read 'step_actions'. */
+ SET_ARRAY_FIELD (event, scope, utp, step_action_num,
+ step_actions);
+
+ SET_STRING_FIELD(event, scope, utp, at_string);
+ SET_STRING_FIELD(event, scope, utp, cond_string);
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+}
+
+/* This is the implementation of target_ops method to_open. Open CTF
+ trace data, read trace status, trace state variables and tracepoint
+ definitions from the first packet. Set the start position at the
+ second packet which contains events on trace blocks. */
+
+static void
+ctf_open (char *dirname, int from_tty)
+{
+ struct bt_ctf_event *event;
+ uint32_t event_id;
+ const struct bt_definition *scope;
+ struct uploaded_tsv *uploaded_tsvs = NULL;
+ struct uploaded_tp *uploaded_tps = NULL;
+
+ if (!dirname)
+ error (_("No CTF directory specified."));
+
+ ctf_open_dir (dirname);
+
+ target_preopen (from_tty);
+
+ /* Skip the first packet which about the trace status. The first
+ event is "frame". */
+ event = bt_ctf_iter_read_event (ctf_iter);
+ scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
+ event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+ if (event_id != CTF_EVENT_ID_FRAME)
+ error (_("Wrong event id of the first event"));
+ /* The second event is "status". */
+ bt_iter_next (bt_ctf_get_iter (ctf_iter));
+ event = bt_ctf_iter_read_event (ctf_iter);
+ scope = bt_ctf_get_top_level_scope (event, BT_STREAM_EVENT_HEADER);
+ event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "id"));
+ if (event_id != CTF_EVENT_ID_STATUS)
+ error (_("Wrong event id of the second event"));
+ ctf_read_status (event, current_trace_status ());
+
+ ctf_read_tsv (&uploaded_tsvs);
+
+ ctf_read_tp (&uploaded_tps);
+
+ event = bt_ctf_iter_read_event (ctf_iter);
+ /* EVENT can be NULL if we've already gone to the end of stream of
+ events. */
+ if (event != NULL)
+ {
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_STREAM_EVENT_HEADER);
+ event_id = bt_ctf_get_uint64 (bt_ctf_get_field (event,
+ scope, "id"));
+ if (event_id != CTF_EVENT_ID_FRAME)
+ error (_("Wrong event id of the first event of the second packet"));
+ }
+
+ start_pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (start_pos->type == BT_SEEK_RESTORE);
+
+ trace_dirname = xstrdup (dirname);
+ push_target (&ctf_ops);
+
+ merge_uploaded_trace_state_variables (&uploaded_tsvs);
+ merge_uploaded_tracepoints (&uploaded_tps);
+}
+
+/* This is the implementation of target_ops method to_close. Destroy
+ CTF iterator and context. */
+
+static void
+ctf_close (void)
+{
+ ctf_destroy ();
+ xfree (trace_dirname);
+ trace_dirname = NULL;
+}
+
+/* This is the implementation of target_ops method to_files_info.
+ Print the directory name of CTF trace data. */
+
+static void
+ctf_files_info (struct target_ops *t)
+{
+ printf_filtered ("\t`%s'\n", trace_dirname);
+}
+
+/* This is the implementation of target_ops method to_fetch_registers.
+ Iterate over events whose name is "register" in current frame,
+ extract contents from events, and set REGCACHE with the contents.
+ If no matched events are found, mark registers unavailable. */
+
+static void
+ctf_fetch_registers (struct target_ops *ops,
+ struct regcache *regcache, int regno)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ int offset, regn, regsize, pc_regno;
+ char *regs = NULL;
+ struct bt_ctf_event *event = NULL;
+ struct bt_iter_pos *pos;
+
+ /* An uninitialized reg size says we're not going to be
+ successful at getting register blocks. */
+ if (trace_regblock_size == 0)
+ return;
+
+ gdb_assert (ctf_iter != NULL);
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event1;
+
+ event1 = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event1);
+
+ if (name == NULL || strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "register") == 0)
+ {
+ event = event1;
+ break;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ if (event != NULL)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+
+ regs = bt_ctf_get_char_array (array);
+ /* Assume the block is laid out in GDB register number order,
+ each register with the size that it has in GDB. */
+ offset = 0;
+ for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+ {
+ regsize = register_size (gdbarch, regn);
+ /* Make sure we stay within block bounds. */
+ if (offset + regsize >= trace_regblock_size)
+ break;
+ if (regcache_register_status (regcache, regn) == REG_UNKNOWN)
+ {
+ if (regno == regn)
+ {
+ regcache_raw_supply (regcache, regno, regs + offset);
+ break;
+ }
+ else if (regno == -1)
+ {
+ regcache_raw_supply (regcache, regn, regs + offset);
+ }
+ }
+ offset += regsize;
+ }
+ return;
+ }
+
+ regs = alloca (trace_regblock_size);
+
+ /* We get here if no register data has been found. Mark registers
+ as unavailable. */
+ for (regn = 0; regn < gdbarch_num_regs (gdbarch); regn++)
+ regcache_raw_supply (regcache, regn, NULL);
+
+ /* We can often usefully guess that the PC is going to be the same
+ as the address of the tracepoint. */
+ pc_regno = gdbarch_pc_regnum (gdbarch);
+ if (pc_regno >= 0 && (regno == -1 || regno == pc_regno))
+ {
+ struct tracepoint *tp = get_tracepoint (get_tracepoint_number ());
+
+ if (tp != NULL && tp->base.loc)
+ {
+ /* But don't try to guess if tracepoint is multi-location... */
+ if (tp->base.loc->next != NULL)
+ {
+ warning (_("Tracepoint %d has multiple "
+ "locations, cannot infer $pc"),
+ tp->base.number);
+ return;
+ }
+ /* ... or does while-stepping. */
+ if (tp->step_count > 0)
+ {
+ warning (_("Tracepoint %d does while-stepping, "
+ "cannot infer $pc"),
+ tp->base.number);
+ return;
+ }
+
+ store_unsigned_integer (regs, register_size (gdbarch, pc_regno),
+ gdbarch_byte_order (gdbarch),
+ tp->base.loc->address);
+ regcache_raw_supply (regcache, pc_regno, regs);
+ }
+ }
+}
+
+/* This is the implementation of target_ops method to_xfer_partial.
+ Iterate over events whose name is "memory" in
+ current frame, extract the address and length from events. If
+ OFFSET is within the range, read the contents from events to
+ READBUF. */
+
+static LONGEST
+ctf_xfer_partial (struct target_ops *ops, enum target_object object,
+ const char *annex, gdb_byte *readbuf,
+ const gdb_byte *writebuf, ULONGEST offset,
+ LONGEST len)
+{
+ /* We're only doing regular memory for now. */
+ if (object != TARGET_OBJECT_MEMORY)
+ return -1;
+
+ if (readbuf == NULL)
+ error (_("ctf_xfer_partial: trace file is read-only"));
+
+ if (get_traceframe_number () != -1)
+ {
+ struct bt_iter_pos *pos;
+ int i = 0;
+
+ gdb_assert (ctf_iter != NULL);
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ /* Iterate through the traceframe's blocks, looking for
+ memory. */
+ while (1)
+ {
+ ULONGEST amt;
+ uint64_t maddr;
+ uint16_t mlen;
+ enum bfd_endian byte_order
+ = gdbarch_byte_order (target_gdbarch ());
+ const struct bt_definition *scope;
+ const struct bt_definition *def;
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+ const char *name = bt_ctf_event_name (event);
+
+ if (strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "memory") != 0)
+ {
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+
+ continue;
+ }
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+
+ def = bt_ctf_get_field (event, scope, "address");
+ maddr = bt_ctf_get_uint64 (def);
+ def = bt_ctf_get_field (event, scope, "length");
+ mlen = (uint16_t) bt_ctf_get_uint64 (def);
+
+ /* If the block includes the first part of the desired
+ range, return as much it has; GDB will re-request the
+ remainder, which might be in a different block of this
+ trace frame. */
+ if (maddr <= offset && offset < (maddr + mlen))
+ {
+ const struct bt_definition *array
+ = bt_ctf_get_field (event, scope, "contents");
+ const struct bt_declaration *decl
+ = bt_ctf_get_decl_from_def (array);
+ gdb_byte *contents;
+ int k;
+
+ contents = xmalloc (mlen);
+
+ for (k = 0; k < mlen; k++)
+ {
+ const struct bt_definition *element
+ = bt_ctf_get_index (event, array, k);
+
+ contents[k] = (gdb_byte) bt_ctf_get_uint64 (element);
+ }
+
+ amt = (maddr + mlen) - offset;
+ if (amt > len)
+ amt = len;
+
+ memcpy (readbuf, &contents[offset - maddr], amt);
+
+ xfree (contents);
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return amt;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+ }
+
+ /* It's unduly pedantic to refuse to look at the executable for
+ read-only pieces; so do the equivalent of readonly regions aka
+ QTro packet. */
+ if (exec_bfd != NULL)
+ {
+ asection *s;
+ bfd_size_type size;
+ bfd_vma vma;
+
+ for (s = exec_bfd->sections; s; s = s->next)
+ {
+ if ((s->flags & SEC_LOAD) == 0
+ || (s->flags & SEC_READONLY) == 0)
+ continue;
+
+ vma = s->vma;
+ size = bfd_get_section_size (s);
+ if (vma <= offset && offset < (vma + size))
+ {
+ ULONGEST amt;
+
+ amt = (vma + size) - offset;
+ if (amt > len)
+ amt = len;
+
+ amt = bfd_get_section_contents (exec_bfd, s,
+ readbuf, offset - vma, amt);
+ return amt;
+ }
+ }
+ }
+
+ /* Indicate failure to find the requested memory block. */
+ return -1;
+}
+
+/* This is the implementation of target_ops method
+ to_get_trace_state_variable_value.
+ Iterate over events whose name is "tsv" in current frame. When the
+ trace variable is found, set the value of it to *VAL and return
+ true, otherwise return false. */
+
+static int
+ctf_get_trace_state_variable_value (int tsvnum, LONGEST *val)
+{
+ struct bt_iter_pos *pos;
+ int found = 0;
+
+ gdb_assert (ctf_iter != NULL);
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ /* Iterate through the traceframe's blocks, looking for 'V'
+ block. */
+ while (1)
+ {
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+ const char *name = bt_ctf_event_name (event);
+
+ if (name == NULL || strcmp (name, "frame") == 0)
+ break;
+ else if (strcmp (name, "tsv") == 0)
+ {
+ const struct bt_definition *scope;
+ const struct bt_definition *def;
+
+ scope = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+
+ def = bt_ctf_get_field (event, scope, "num");
+ if (tsvnum == (int32_t) bt_ctf_get_uint64 (def))
+ {
+ def = bt_ctf_get_field (event, scope, "val");
+ *val = bt_ctf_get_uint64 (def);
+
+ found = 1;
+ }
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return found;
+}
+
+/* Return the tracepoint number in "frame" event. */
+
+static int
+ctf_get_tpnum_from_frame_event (struct bt_ctf_event *event)
+{
+ /* The packet context of events has a field "tpnum". */
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event, BT_STREAM_PACKET_CONTEXT);
+ uint64_t tpnum
+ = bt_ctf_get_uint64 (bt_ctf_get_field (event, scope, "tpnum"));
+
+ return (int) tpnum;
+}
+
+/* Return the address at which the current frame was collected. */
+
+static CORE_ADDR
+ctf_get_traceframe_address (void)
+{
+ struct bt_ctf_event *event = NULL;
+ struct bt_iter_pos *pos;
+ CORE_ADDR addr = 0;
+
+ gdb_assert (ctf_iter != NULL);
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ while (1)
+ {
+ const char *name;
+ struct bt_ctf_event *event1;
+
+ event1 = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event1);
+
+ if (name == NULL)
+ break;
+ else if (strcmp (name, "frame") == 0)
+ {
+ event = event1;
+ break;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ if (event != NULL)
+ {
+ int tpnum = ctf_get_tpnum_from_frame_event (event);
+ struct tracepoint *tp
+ = get_tracepoint_by_number_on_target (tpnum);
+
+ if (tp && tp->base.loc)
+ addr = tp->base.loc->address;
+ }
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return addr;
+}
+
+/* This is the implementation of target_ops method to_trace_find.
+ Iterate the events whose name is "frame", extract the tracepoint
+ number in it. Return traceframe number when matched. */
+
+static int
+ctf_trace_find (enum trace_find_type type, int num,
+ CORE_ADDR addr1, CORE_ADDR addr2, int *tpp)
+{
+ int ret = -1;
+ int tfnum = 0;
+ int found = 0;
+ struct bt_iter_pos pos;
+
+ if (num == -1)
+ {
+ if (tpp != NULL)
+ *tpp = -1;
+ return -1;
+ }
+
+ gdb_assert (ctf_iter != NULL);
+ /* Set iterator back to the start. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), start_pos);
+
+ while (1)
+ {
+ int id;
+ struct bt_ctf_event *event;
+ const char *name;
+
+ event = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (event == NULL || name == NULL)
+ break;
+
+ if (strcmp (name, "frame") == 0)
+ {
+ CORE_ADDR tfaddr;
+
+ if (type == tfind_number)
+ {
+ /* Looking for a specific trace frame. */
+ if (tfnum == num)
+ found = 1;
+ }
+ else
+ {
+ /* Start from the _next_ trace frame. */
+ if (tfnum > get_traceframe_number ())
+ {
+ switch (type)
+ {
+ case tfind_tp:
+ {
+ struct tracepoint *tp = get_tracepoint (num);
+
+ if (tp != NULL
+ && (tp->number_on_target
+ == ctf_get_tpnum_from_frame_event (event)))
+ found = 1;
+ break;
+ }
+ case tfind_pc:
+ tfaddr = ctf_get_traceframe_address ();
+ if (tfaddr == addr1)
+ found = 1;
+ break;
+ case tfind_range:
+ tfaddr = ctf_get_traceframe_address ();
+ if (addr1 <= tfaddr && tfaddr <= addr2)
+ found = 1;
+ break;
+ case tfind_outside:
+ tfaddr = ctf_get_traceframe_address ();
+ if (!(addr1 <= tfaddr && tfaddr <= addr2))
+ found = 1;
+ break;
+ default:
+ internal_error (__FILE__, __LINE__, _("unknown tfind type"));
+ }
+ }
+ }
+ if (found)
+ {
+ if (tpp != NULL)
+ *tpp = ctf_get_tpnum_from_frame_event (event);
+
+ /* Skip the event "frame". */
+ bt_iter_next (bt_ctf_get_iter (ctf_iter));
+
+ return tfnum;
+ }
+ tfnum++;
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+
+ return -1;
+}
+
+/* This is the implementation of target_ops method to_has_stack.
+ The target has a stack when GDB has already selected one trace
+ frame. */
+
+static int
+ctf_has_stack (struct target_ops *ops)
+{
+ return get_traceframe_number () != -1;
+}
+
+/* This is the implementation of target_ops method to_has_registers.
+ The target has registers when GDB has already selected one trace
+ frame. */
+
+static int
+ctf_has_registers (struct target_ops *ops)
+{
+ return get_traceframe_number () != -1;
+}
+
+/* This is the implementation of target_ops method to_traceframe_info.
+ Iterate the events whose name is "memory", in current
+ frame, extract memory range information, and return them in
+ traceframe_info. */
+
+static struct traceframe_info *
+ctf_traceframe_info (void)
+{
+ struct traceframe_info *info = XCNEW (struct traceframe_info);
+ const char *name;
+ struct bt_iter_pos *pos;
+
+ gdb_assert (ctf_iter != NULL);
+ /* Save the current position. */
+ pos = bt_iter_get_pos (bt_ctf_get_iter (ctf_iter));
+ gdb_assert (pos->type == BT_SEEK_RESTORE);
+
+ do
+ {
+ struct bt_ctf_event *event
+ = bt_ctf_iter_read_event (ctf_iter);
+
+ name = bt_ctf_event_name (event);
+
+ if (name == NULL || strcmp (name, "register") == 0
+ || strcmp (name, "frame") == 0)
+ ;
+ else if (strcmp (name, "memory") == 0)
+ {
+ const struct bt_definition *scope
+ = bt_ctf_get_top_level_scope (event,
+ BT_EVENT_FIELDS);
+ const struct bt_definition *def;
+ struct mem_range *r;
+
+ r = VEC_safe_push (mem_range_s, info->memory, NULL);
+ def = bt_ctf_get_field (event, scope, "address");
+ r->start = bt_ctf_get_uint64 (def);
+
+ def = bt_ctf_get_field (event, scope, "length");
+ r->length = (uint16_t) bt_ctf_get_uint64 (def);
+ }
+ else
+ {
+ warning (_("Unhandled trace block type (%s) "
+ "while building trace frame info."),
+ name);
+ }
+
+ if (bt_iter_next (bt_ctf_get_iter (ctf_iter)) < 0)
+ break;
+ }
+ while (name != NULL && strcmp (name, "frame") != 0);
+
+ /* Restore the position. */
+ bt_iter_set_pos (bt_ctf_get_iter (ctf_iter), pos);
+
+ return info;
+}
+
+/* This is the implementation of target_ops method to_get_trace_status.
+ The trace status for a file is that tracing can never be run. */
+
+static int
+ctf_get_trace_status (struct trace_status *ts)
+{
+ /* Other bits of trace status were collected as part of opening the
+ trace files, so nothing to do here. */
+
+ return -1;
+}
+
+static void
+init_ctf_ops (void)
+{
+ memset (&ctf_ops, 0, sizeof (ctf_ops));
+
+ ctf_ops.to_shortname = "ctf";
+ ctf_ops.to_longname = "CTF file";
+ ctf_ops.to_doc = "Use a CTF directory as a target.\n\
+Specify the filename of the CTF directory.";
+ ctf_ops.to_open = ctf_open;
+ ctf_ops.to_close = ctf_close;
+ ctf_ops.to_fetch_registers = ctf_fetch_registers;
+ ctf_ops.to_xfer_partial = ctf_xfer_partial;
+ ctf_ops.to_files_info = ctf_files_info;
+ ctf_ops.to_get_trace_status = ctf_get_trace_status;
+ ctf_ops.to_trace_find = ctf_trace_find;
+ ctf_ops.to_get_trace_state_variable_value
+ = ctf_get_trace_state_variable_value;
+ ctf_ops.to_stratum = process_stratum;
+ ctf_ops.to_has_stack = ctf_has_stack;
+ ctf_ops.to_has_registers = ctf_has_registers;
+ ctf_ops.to_traceframe_info = ctf_traceframe_info;
+ ctf_ops.to_magic = OPS_MAGIC;
+}
+
+#endif
+
+/* -Wmissing-prototypes */
+
+extern initialize_file_ftype _initialize_ctf;
+
+/* module initialization */
+
+void
+_initialize_ctf (void)
+{
+#if HAVE_LIBBABELTRACE
+ init_ctf_ops ();
+
+ add_target (&ctf_ops);
+#endif
+}
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index bf7e25e..6974b5c 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -12307,13 +12307,33 @@ that can be shared by multiple debugging and tracing tools. Please go to
@kindex target tfile
@kindex tfile
+@kindex target ctf
+@kindex ctf
@item target tfile @var{filename}
-Use the file named @var{filename} as a source of trace data. Commands
-that examine data work as they do with a live target, but it is not
-possible to run any new trace experiments. @code{tstatus} will report
-the state of the trace run at the moment the data was saved, as well
-as the current trace frame you are examining. @var{filename} must be
-on a filesystem accessible to the host.
+@itemx target ctf @var{dirname}
+Use the file named @var{filename} or directory named @var{dirname} as
+a source of trace data. Commands that examine data work as they do with
+a live target, but it is not possible to run any new trace experiments.
+@code{tstatus} will report the state of the trace run at the moment
+the data was saved, as well as the current trace frame you are examining.
+@var{filename} or @var{dirname} must be on a filesystem accessible to
+the host.
+
+@smallexample
+(@value{GDBP}) target ctf ctf.ctf
+(@value{GDBP}) tfind
+Found trace frame 0, tracepoint 2
+39 ++a; /* set tracepoint 1 here */
+(@value{GDBP}) tdump
+Data collected at tracepoint 2, trace frame 0:
+i = 0
+a = 0
+b = 1 '\001'
+c = @{"123", "456", "789", "123", "456", "789"@}
+d = @{@{@{a = 1, b = 2@}, @{a = 3, b = 4@}@}, @{@{a = 5, b = 6@}, @{a = 7, b = 8@}@}@}
+(@value{GDBP}) p b
+$1 = 1
+@end smallexample
@end table
diff --git a/gdb/testsuite/gdb.trace/actions.exp b/gdb/testsuite/gdb.trace/actions.exp
index 5fa1b97..be2bb3e 100644
--- a/gdb/testsuite/gdb.trace/actions.exp
+++ b/gdb/testsuite/gdb.trace/actions.exp
@@ -310,6 +310,9 @@ gdb_test_no_output "tstop" ""
set tracefile [standard_output_file ${testfile}]
gdb_test "tsave ${tracefile}.tf" \
"Trace data saved to file '${tracefile}.tf'\.\\r"
+gdb_test "tsave -ctf ${tracefile}.ctf" \
+ "Trace data saved to directory '${tracefile}.ctf'\.\\r" \
+ "save ctf trace file"
# Restart GDB and read the trace data in tfile target.
gdb_exit
@@ -319,3 +322,24 @@ gdb_file_cmd $binfile
gdb_test "target tfile ${tracefile}.tf" ".*" \
"change to tfile target"
check_tracepoint "tfile"
+
+# Try to read ctf data if GDB supports.
+set gdb_can_read_ctf_data 0
+gdb_test_multiple "target ctf" "" {
+ -re "Undefined target command: \"ctf\"\. Try \"help target\"\.\r\n$gdb_prompt $" {
+ set gdb_can_read_ctf_data 0
+ }
+ -re "No CTF directory specified.*\r\n$gdb_prompt $" {
+ set gdb_can_read_ctf_data 1
+ }
+}
+
+if { $gdb_can_read_ctf_data } {
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_file_cmd $binfile
+ gdb_test "target ctf ${tracefile}.ctf" ".*" \
+ "change to ctf target"
+ check_tracepoint "ctf"
+}
diff --git a/gdb/testsuite/gdb.trace/report.exp b/gdb/testsuite/gdb.trace/report.exp
index 3c3025d..8bb71e4 100644
--- a/gdb/testsuite/gdb.trace/report.exp
+++ b/gdb/testsuite/gdb.trace/report.exp
@@ -412,6 +412,11 @@ gdb_test "tsave ${tracefile}.tf" \
"Trace data saved to file '${tracefile}.tf'.*" \
"save tfile trace file"
+# Save trace frames to ctf.
+gdb_test "tsave -ctf ${tracefile}.ctf" \
+ "Trace data saved to directory '${tracefile}.ctf'.*" \
+ "save ctf trace file"
+
# Change target to tfile.
set test "change to tfile target"
gdb_test_multiple "target tfile ${tracefile}.tf" "$test" {
@@ -425,3 +430,12 @@ gdb_test_multiple "target tfile ${tracefile}.tf" "$test" {
}
# Test the collected trace frames from tfile.
use_collected_data "tfile"
+
+# Try to read ctf data if GDB supports.
+gdb_test_multiple "target ctf ${tracefile}.ctf" "" {
+ -re "Undefined target command: \"ctf ${tracefile}.ctf\"\. Try \"help target\"\.\r\n$gdb_prompt $" {
+ }
+ -re ".*\r\n$gdb_prompt $" {
+ use_collected_data "ctf"
+ }
+}
diff --git a/gdb/testsuite/gdb.trace/tstatus.exp b/gdb/testsuite/gdb.trace/tstatus.exp
index 74d0c27..c709ad8 100644
--- a/gdb/testsuite/gdb.trace/tstatus.exp
+++ b/gdb/testsuite/gdb.trace/tstatus.exp
@@ -142,6 +142,10 @@ set tracefile [standard_output_file ${testfile}]
gdb_test "tsave ${tracefile}.tf" \
"Trace data saved to file '${tracefile}.tf'.*" \
"save tfile trace file"
+# Save trace frames to CTF.
+gdb_test "tsave -ctf ${tracefile}.ctf" \
+ "Trace data saved to directory '${tracefile}.ctf'.*" \
+ "save ctf trace file"
# Change target to tfile.
set test "change to tfile target"
@@ -162,3 +166,13 @@ set tstatus_output [string map {\) \\)} $tstatus_output]
# The status should be identical to the status of live inferior.
gdb_test "tstatus" "Using a trace file\.\r\n${tstatus_output}.*" \
"tstatus on tfile target"
+
+# Change target to ctf if GDB supports.
+gdb_test_multiple "target ctf ${tracefile}.ctf" "" {
+ -re "Undefined target command: \"ctf ${tracefile}.ctf\"\. Try \"help target\"\.\r\n$gdb_prompt $" {
+ }
+ -re ".*\r\n$gdb_prompt $" {
+ gdb_test "tstatus" "Using a trace file\.\r\n${tstatus_output}.*" \
+ "tstatus on ctf target"
+ }
+}
diff --git a/gdb/testsuite/gdb.trace/tsv.exp b/gdb/testsuite/gdb.trace/tsv.exp
index 6e88adc..76b8645 100644
--- a/gdb/testsuite/gdb.trace/tsv.exp
+++ b/gdb/testsuite/gdb.trace/tsv.exp
@@ -147,6 +147,10 @@ set tracefile [standard_output_file ${testfile}]
gdb_test "tsave ${tracefile}.tf" \
"Trace data saved to file '${tracefile}.tf'.*" \
"save tfile trace file"
+# Save trace frames to ctf.
+gdb_test "tsave -ctf ${tracefile}.ctf" \
+ "Trace data saved to directory '${tracefile}.ctf'.*" \
+ "save ctf trace file"
proc check_tsv { data_source } {
with_test_prefix "${data_source}" {
@@ -174,4 +178,13 @@ gdb_test_multiple "target tfile ${tracefile}.tf" "$test" {
}
# Check the tsv from tfile.
+
check_tsv "tfile"
+# Try to read ctf data if GDB supports.
+gdb_test_multiple "target ctf ${tracefile}.ctf" "" {
+ -re "Undefined target command: \"ctf ${tracefile}.ctf\"\. Try \"help target\"\.\r\n$gdb_prompt $" {
+ }
+ -re ".*\r\n$gdb_prompt $" {
+ check_tsv "ctf"
+ }
+}
diff --git a/gdb/testsuite/gdb.trace/while-stepping.exp b/gdb/testsuite/gdb.trace/while-stepping.exp
index 0b823a4..da9b14a 100644
--- a/gdb/testsuite/gdb.trace/while-stepping.exp
+++ b/gdb/testsuite/gdb.trace/while-stepping.exp
@@ -136,6 +136,9 @@ set tracefile [standard_output_file ${testfile}]
gdb_test "tsave ${tracefile}.tf" \
"Trace data saved to file '${tracefile}.tf'\.\\r" \
"save tfile trace file"
+gdb_test "tsave -ctf ${tracefile}.ctf" \
+ "Trace data saved to directory '${tracefile}.ctf'\.\\r" \
+ "save ctf trace file"
# Restart GDB and read the trace data in tfile target.
gdb_exit
@@ -145,3 +148,24 @@ gdb_file_cmd $binfile
gdb_test "target tfile ${tracefile}.tf" ".*" \
"change to tfile target"
check_tracepoint "tfile"
+
+# Try to read ctf data if GDB supports.
+set gdb_can_read_ctf_data 0
+gdb_test_multiple "target ctf" "" {
+ -re "Undefined target command: \"ctf\"\. Try \"help target\"\.\r\n$gdb_prompt $" {
+ set gdb_can_read_ctf_data 0
+ }
+ -re "No CTF directory specified.*\r\n$gdb_prompt $" {
+ set gdb_can_read_ctf_data 1
+ }
+}
+
+if { $gdb_can_read_ctf_data } {
+ gdb_exit
+ gdb_start
+ gdb_reinitialize_dir $srcdir/$subdir
+ gdb_file_cmd $binfile
+ gdb_test "target ctf ${tracefile}.ctf" ".*" \
+ "change to ctf target"
+ check_tracepoint "ctf"
+}
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 3d8b131..c9ffc77 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -127,14 +127,6 @@ extern void (*deprecated_readline_end_hook) (void);
typedef struct trace_state_variable tsv_s;
DEF_VEC_O(tsv_s);
-/* An object describing the contents of a traceframe. */
-
-struct traceframe_info
-{
- /* Collected memory. */
- VEC(mem_range_s) *memory;
-};
-
static VEC(tsv_s) *tvariables;
/* The next integer to assign to a variable. */
@@ -3303,8 +3295,6 @@ static const struct trace_file_write_ops tfile_write_ops =
#define TRACE_WRITE_V_BLOCK(writer, num, val) \
writer->ops->frame_ops->write_v_block ((writer), (num), (val))
-extern int trace_regblock_size;
-
/* Save tracepoint data to file named FILENAME through WRITER. WRITER
determines the trace file format. If TARGET_DOES_SAVE is non-zero,
the save is performed on the target, otherwise GDB obtains all trace
@@ -3741,6 +3731,12 @@ get_traceframe_number (void)
return traceframe_number;
}
+int
+get_tracepoint_number (void)
+{
+ return tracepoint_number;
+}
+
/* Make the traceframe NUM be the current trace frame. Does nothing
if NUM is already current. */
@@ -3859,7 +3855,7 @@ free_uploaded_tps (struct uploaded_tp **utpp)
/* Given a number and address, return an uploaded tracepoint with that
number, creating if necessary. */
-static struct uploaded_tsv *
+struct uploaded_tsv *
get_uploaded_tsv (int num, struct uploaded_tsv **utsvp)
{
struct uploaded_tsv *utsv;
diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h
index 8df906f..f88394b 100644
--- a/gdb/tracepoint.h
+++ b/gdb/tracepoint.h
@@ -24,6 +24,14 @@
#include "memrange.h"
#include "gdb_vecs.h"
+/* An object describing the contents of a traceframe. */
+
+struct traceframe_info
+{
+ /* Collected memory. */
+ VEC(mem_range_s) *memory;
+};
+
/* A trace state variable is a value managed by a target being
traced. A trace state variable (or tsv for short) can be accessed
and assigned to by tracepoint actions and conditionals, but is not
@@ -142,6 +150,8 @@ struct trace_status *current_trace_status (void);
extern char *default_collect;
+extern int trace_regblock_size;
+
/* Struct to collect random info about tracepoints on the target. */
struct uploaded_tp
@@ -324,6 +334,9 @@ extern void (*deprecated_trace_start_stop_hook) (int start, int from_tty);
/* Returns the current traceframe number. */
extern int get_traceframe_number (void);
+/* Returns the tracepoint number for current traceframe. */
+extern int get_tracepoint_number (void);
+
/* Make the traceframe NUM be the current GDB trace frame number, and
do nothing more. In particular, this does not flush the
register/frame caches or notify the target about the trace frame
@@ -368,6 +381,8 @@ extern void parse_tsv_definition (char *line, struct uploaded_tsv **utsvp);
extern struct uploaded_tp *get_uploaded_tp (int num, ULONGEST addr,
struct uploaded_tp **utpp);
+extern struct uploaded_tsv *get_uploaded_tsv (int num,
+ struct uploaded_tsv **utsvp);
extern struct tracepoint *create_tracepoint_from_upload (struct uploaded_tp *utp);
extern void merge_uploaded_tracepoints (struct uploaded_tp **utpp);
extern void merge_uploaded_trace_state_variables (struct uploaded_tsv **utsvp);
--
1.7.7.6
^ permalink raw reply [flat|nested] 60+ messages in thread* [patch] Regenerate config.in [Re: [PATCH v3 00/15] CTF Support]
2013-04-10 19:16 ` [PATCH v3 00/15] CTF Support Yao Qi
@ 2013-04-11 22:59 ` Jan Kratochvil
2013-04-12 22:27 ` [commit] " Jan Kratochvil
2014-08-04 18:59 ` Incorrect placement of babeltrace gdb/NEWS item " Jan Kratochvil
1 sibling, 1 reply; 60+ messages in thread
From: Jan Kratochvil @ 2013-04-11 22:59 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches
On Wed, 10 Apr 2013 11:45:10 +0200, Yao Qi wrote:
> --- a/gdb/config.in
> +++ b/gdb/config.in
> @@ -180,6 +180,9 @@
> /* Define if your <locale.h> file defines LC_MESSAGES. */
> #undef HAVE_LC_MESSAGES
>
> +/* Define if libbabeltrace is available */
> +#undef HAVE_LIBBABELTRACE
> +
> /* Define to 1 if you have the `dl' library (-ldl). */
> #undef HAVE_LIBDL
>
When I regenerate it with autoheader from autoconf-2.64 I get a different
output. Just FYI to not to flip it back and forth, I haven't found this
message form in autoconf history.
Jan
gdb/
2013-04-11 Jan Kratochvil <jan.kratochvil@redhat.com>
* config.in: Regenerate.
--- gdb/config.in 10 Apr 2013 09:42:56 -0000 1.152
+++ gdb/config.in 11 Apr 2013 13:56:05 -0000
@@ -180,7 +180,7 @@
/* Define if your <locale.h> file defines LC_MESSAGES. */
#undef HAVE_LC_MESSAGES
-/* Define if libbabeltrace is available */
+/* Define if you have the babeltrace library. */
#undef HAVE_LIBBABELTRACE
/* Define to 1 if you have the `dl' library (-ldl). */
^ permalink raw reply [flat|nested] 60+ messages in thread
* Incorrect placement of babeltrace gdb/NEWS item [Re: [PATCH v3 00/15] CTF Support]
2013-04-10 19:16 ` [PATCH v3 00/15] CTF Support Yao Qi
2013-04-11 22:59 ` [patch] Regenerate config.in [Re: [PATCH v3 00/15] CTF Support] Jan Kratochvil
@ 2014-08-04 18:59 ` Jan Kratochvil
2014-08-06 1:30 ` Yao Qi
1 sibling, 1 reply; 60+ messages in thread
From: Jan Kratochvil @ 2014-08-04 18:59 UTC (permalink / raw)
To: Yao Qi; +Cc: gdb-patches, eliz
On Wed, 10 Apr 2013 11:45:10 +0200, Yao Qi wrote:
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 6f202e2..86716e0 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -135,6 +135,9 @@ Tilera TILE-Gx GNU/Linux tilegx*-*-linux
> Release versions, on the other hand, are built without -lmcheck
> by default. The --enable-libmcheck/--disable-libmcheck configure
> options allow the user to override that default.
> +--with-babeltrace/--with-babeltrace-include/--with-babeltrace-lib
> + This configure option allows the user to build GDB with
> + libbabeltrace using which GDB can read Common Trace Format data.
>
> * New commands (for set/show, see "New options" below)
>
https://sourceware.org/git/?p=binutils-gdb.git;a=blobdiff;f=gdb/NEWS;h=86716e0f866250bed8542bf3af9ca5fdcde02b1e;hp=6f202e2e8c8f1d7387bebe3ffd27331884214b0d;hb=393fd4c3768e4babdc112fded0bde4aedd40925e;hpb=b7a273f8c632d5bc5005fb7ece063a5ed0091bc5
commit 393fd4c3768e4babdc112fded0bde4aedd40925e
Author: Yao Qi <yao@codesourcery.com>
Date: Wed Apr 10 09:42:57 2013 +0000
* configure.ac: Check libbabeltrace is installed.
This addition is in section:
*** Changes in GDB 7.6
while it is a change in gdb-7.7 so it should be moved higher in the NEWS file
I think to the section:
*** Changes in GDB 7.7
Moreover there seems to be missing an empty line delimiter for it.
Jan
^ permalink raw reply [flat|nested] 60+ messages in thread* Re: Incorrect placement of babeltrace gdb/NEWS item [Re: [PATCH v3 00/15] CTF Support]
2014-08-04 18:59 ` Incorrect placement of babeltrace gdb/NEWS item " Jan Kratochvil
@ 2014-08-06 1:30 ` Yao Qi
0 siblings, 0 replies; 60+ messages in thread
From: Yao Qi @ 2014-08-06 1:30 UTC (permalink / raw)
To: Jan Kratochvil; +Cc: gdb-patches, eliz
On 08/05/2014 02:59 AM, Jan Kratochvil wrote:
> This addition is in section:
> *** Changes in GDB 7.6
> while it is a change in gdb-7.7 so it should be moved higher in the NEWS file
> I think to the section:
> *** Changes in GDB 7.7
Er, the news entry was added in the wrong section.
>
> Moreover there seems to be missing an empty line delimiter for it.
Here is the patch to fix it.
--
Yao (é½å°§)
Subject: [PATCH] Move babeltrace change to GDB 7.7
gdb:
2014-08-06 Yao Qi <yao@codesourcery.com>
* NEWS: Move babeltrace change to GDB 7.7 section.
---
gdb/NEWS | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/gdb/NEWS b/gdb/NEWS
index d603cf7..91fda7b 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -465,6 +465,12 @@ qXfer:libraries-svr4:read's annex
The "set remotebaud" and "show remotebaud" commands are still available
to provide backward compatibility with older versions of GDB.
+* New configure options
+
+--with-babeltrace/--with-babeltrace-include/--with-babeltrace-lib
+ This configure option allows the user to build GDB with
+ libbabeltrace using which GDB can read Common Trace Format data.
+
*** Changes in GDB 7.6
* Target record has been renamed to record-full.
@@ -576,9 +582,6 @@ Tilera TILE-Gx GNU/Linux tilegx*-*-linux
Release versions, on the other hand, are built without -lmcheck
by default. The --enable-libmcheck/--disable-libmcheck configure
options allow the user to override that default.
---with-babeltrace/--with-babeltrace-include/--with-babeltrace-lib
- This configure option allows the user to build GDB with
- libbabeltrace using which GDB can read Common Trace Format data.
* New commands (for set/show, see "New options" below)
--
1.9.0
^ permalink raw reply [flat|nested] 60+ messages in thread