From b3b9301ef4f284b2f2f3dd276cf63600507fe47a Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Mon, 14 Feb 2011 11:13:12 +0000 Subject: [PATCH] gdb/ * target.h (struct traceframe_info): Forward declare. (enum target_object): Add TARGET_OBJECT_TRACEFRAME_INFO. (struct target_ops) : New field. (target_traceframe_info): New. * target.c (update_current_target): Inherit and default to_traceframe_info. * remote.c (PACKET_qXfer_traceframe_info): New. (remote_protocol_features): Register qXfer:traceframe-info:read. (remote_xfer_partial): Handle TARGET_OBJECT_TRACEFRAME_INFO. (remote_traceframe_info): New. (init_remote_ops): Install it. (_initialize_remote): Install "set/show remote traceframe-info" commands. * tracepoint.h (parse_traceframe_info): Declare. * tracepoint.c (struct mem_range): New. (mem_range_s): New typedef. (struct traceframe_info): New. (traceframe_info): New global. (free_traceframe_info): New function. (clear_traceframe_info): New function. (start_tracing, tfind_1, set_traceframe_number): Clear traceframe info. (build_traceframe_info): New function. (tfile_traceframe_info): New function. (init_tfile_ops): Install tfile_traceframe_info. (traceframe_info_start_memory, free_result): New functions. (memory_attributes, traceframe_info_elements): New globals. (parse_traceframe_info, get_traceframe_info): New functions. * features/traceframe-info.dtd: New file. * Makefile.in (XMLFILES): Add traceframe-info.dtd. gdb/gdbserver/ * server.c (handle_qxfer_traceframe_info): New. (qxfer_packets): Register "traceframe-info". (handle_query): Report support for qXfer:traceframe-info:read+. * tracepoint.c (match_blocktype): New. (traceframe_find_block_type): Rename to ... (traceframe_walk_blocks): ... this. Add callback filter argument, and use it. (traceframe_find_block_type): New, reimplemented on top of traceframe_walk_blocks. (build_traceframe_info_xml): New. (traceframe_read_info): New. * server.h (traceframe_read_info): Declare. gdb/doc/ * gdb.texinfo (Remote Configuration): Mention set/show remote traceframe-info. (Tools/Packages Optional for Building GDB): Mention that expat is used for traceframe info. (Remote Protocol) : Add "Traceframe Info Format". (General Query Packets) : Describe the qXfer:traceframe-info:read feature. (qXfer::read): Describe qXfer:traceframe-info:read. (Traceframe Info Format): New section. --- gdb/ChangeLog | 34 +++++- gdb/Makefile.in | 2 +- gdb/doc/ChangeLog | 12 ++ gdb/doc/gdb.texinfo | 78 +++++++++++++ gdb/gdbserver/ChangeLog | 15 +++ gdb/gdbserver/server.c | 52 +++++++++ gdb/gdbserver/server.h | 2 + gdb/gdbserver/tracepoint.c | 110 ++++++++++++++++++- gdb/remote.c | 33 ++++++ gdb/target.c | 4 + gdb/target.h | 13 ++- gdb/tracepoint.c | 217 +++++++++++++++++++++++++++++++++++++ gdb/tracepoint.h | 2 + 13 files changed, 568 insertions(+), 6 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index aa54988732..d74fc1ef1f 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,8 +1,40 @@ +2011-02-14 Pedro Alves + + * target.h (struct traceframe_info): Forward declare. + (enum target_object): Add TARGET_OBJECT_TRACEFRAME_INFO. + (struct target_ops) : New field. + (target_traceframe_info): New. + * target.c (update_current_target): Inherit and default + to_traceframe_info. + * remote.c (PACKET_qXfer_traceframe_info): New. + (remote_protocol_features): Register qXfer:traceframe-info:read. + (remote_xfer_partial): Handle TARGET_OBJECT_TRACEFRAME_INFO. + (remote_traceframe_info): New. + (init_remote_ops): Install it. + (_initialize_remote): Install "set/show remote traceframe-info" + commands. + * tracepoint.h (parse_traceframe_info): Declare. + * tracepoint.c (struct mem_range): New. + (mem_range_s): New typedef. + (struct traceframe_info): New. + (traceframe_info): New global. + (free_traceframe_info): New function. + (clear_traceframe_info): New function. + (start_tracing, tfind_1, set_traceframe_number): Clear traceframe + info. + (build_traceframe_info): New function. + (tfile_traceframe_info): New function. + (init_tfile_ops): Install tfile_traceframe_info. + (traceframe_info_start_memory, free_result): New functions. + (memory_attributes, traceframe_info_elements): New globals. + (parse_traceframe_info, get_traceframe_info): New functions. + * features/traceframe-info.dtd: New file. + * Makefile.in (XMLFILES): Add traceframe-info.dtd. + 2011-02-14 Pedro Alves Base support for value contents. - gdb/ * value.h (value_bytes_available): Declare. (mark_value_bytes_unavailable): Declare. * value.c (struct range): New struct. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 5f91e351d8..f991cb030a 100644 --- a/gdb/Makefile.in +++ b/gdb/Makefile.in @@ -499,7 +499,7 @@ RUNTESTFLAGS= # XML files to build in to GDB. XMLFILES = $(srcdir)/features/gdb-target.dtd $(srcdir)/features/xinclude.dtd \ $(srcdir)/features/library-list.dtd $(srcdir)/features/osdata.dtd \ - $(srcdir)/features/threads.dtd + $(srcdir)/features/threads.dtd $(srcdir)/features/traceframe-info.dtd # This is ser-unix.o for any system which supports a v7/BSD/SYSV/POSIX # interface to the serial port. Hopefully if get ported to OS/2, VMS, diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index d10f9123f4..1dfda73adb 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,15 @@ +2011-02-14 Pedro Alves + + * gdb.texinfo (Remote Configuration): Mention set/show remote + traceframe-info. + (Tools/Packages Optional for Building GDB): Mention that expat is + used for traceframe info. + (Remote Protocol) : Add "Traceframe Info Format". + (General Query Packets) : Describe the + qXfer:traceframe-info:read feature. + (qXfer::read): Describe qXfer:traceframe-info:read. + (Traceframe Info Format): New section. + 2011-02-04 Pedro Alves * gdbint.texinfo (Formatting): Mention some formatting guidelines diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 6a3c7dee0e..332fdef2c8 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -16698,6 +16698,10 @@ are: @item @code{query-attached} @tab @code{qAttached} @tab Querying remote process attach state. + +@item @code{traceframe-info} +@tab @code{qXfer:traceframe-info:read} +@tab Traceframe info @end multitable @node Remote Stub @@ -30848,6 +30852,8 @@ Target descriptions (@pxref{Target Descriptions}) Remote shared library lists (@pxref{Library List Format}) @item MS-Windows shared libraries (@pxref{Shared Libraries}) +@item +Traceframe info (@pxref{Traceframe Info Format}) @end itemize @item zlib @@ -31670,6 +31676,7 @@ Show the current setting of the target wait timeout. * Library List Format:: * Memory Map Format:: * Thread List Format:: +* Traceframe Info Format:: @end menu @node Overview @@ -33220,6 +33227,11 @@ These are the currently defined stub features and their properties: @tab @samp{-} @tab Yes +@item @samp{qXfer:traceframe-info:read} +@tab No +@tab @samp{-} +@tab Yes + @item @samp{QNonStop} @tab No @@ -33322,6 +33334,10 @@ The remote stub understands the @samp{qXfer:siginfo:write} packet The remote stub understands the @samp{qXfer:threads:read} packet (@pxref{qXfer threads read}). +@item qXfer:traceframe-info:read +The remote stub understands the @samp{qXfer:traceframe-info:read} +packet (@pxref{qXfer traceframe info read}). + @item QNonStop The remote stub understands the @samp{QNonStop} packet (@pxref{QNonStop}). @@ -33560,6 +33576,16 @@ annex part of the generic @samp{qXfer} packet must be empty This packet is not probed by default; the remote stub must request it, by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). +@item qXfer:traceframe-info:read::@var{offset},@var{length} +@anchor{qXfer traceframe info read} + +Return a description of the current traceframe's contents. +@xref{Traceframe Info Format}. The annex part of the generic +@samp{qXfer} packet must be empty (@pxref{qXfer read}). + +This packet is not probed by default; the remote stub must request it, +by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). + @item qXfer:osdata:read::@var{offset},@var{length} @anchor{qXfer osdata read} Access the target's @dfn{operating system information}. @@ -35851,6 +35877,58 @@ identifies the thread (@pxref{thread-id syntax}). The the thread was last executing on. The content of the of @samp{thread} element is interpreted as human-readable auxilliary information. +@node Traceframe Info Format +@section Traceframe Info Format +@cindex traceframe info format + +To be able to know which objects in the inferior can be examined when +inspecting a tracepoint hit, @value{GDBN} needs to obtain the list of +memory ranges, registers and trace state variables that have been +collected in a traceframe. + +This list is obtained using the @samp{qXfer:traceframe-info:read} +(@pxref{qXfer traceframe info read}) packet and is an XML document. + +@value{GDBN} must be linked with the Expat library to support XML +traceframe info discovery. @xref{Expat}. + +The top-level structure of the document is shown below: + +@smallexample + + + + block... + +@end smallexample + +Each traceframe block can be either: + +@itemize + +@item +A region of collected memory starting at @var{addr} and extending for +@var{length} bytes from there: + +@smallexample + +@end smallexample + +@end itemize + +The formal DTD for the traceframe info format is given below: + +@smallexample + + + + + +@end smallexample + @include agentexpr.texi @node Trace File Format diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 470b383e21..682c86f429 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,18 @@ +2011-02-14 Pedro Alves + + * server.c (handle_qxfer_traceframe_info): New. + (qxfer_packets): Register "traceframe-info". + (handle_query): Report support for qXfer:traceframe-info:read+. + * tracepoint.c (match_blocktype): New. + (traceframe_find_block_type): Rename to ... + (traceframe_walk_blocks): ... this. Add callback filter argument, + and use it. + (traceframe_find_block_type): New, reimplemented on top of + traceframe_walk_blocks. + (build_traceframe_info_xml): New. + (traceframe_read_info): New. + * server.h (traceframe_read_info): Declare. + 2011-02-11 Yao Qi * configure.ac: Call AC_PROG_RANLIB. diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 9e19739290..ebfcca4e58 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -1118,6 +1118,56 @@ handle_qxfer_threads (const char *annex, return len; } +/* Handle qXfer:traceframe-info:read. */ + +static int +handle_qxfer_traceframe_info (const char *annex, + gdb_byte *readbuf, const gdb_byte *writebuf, + ULONGEST offset, LONGEST len) +{ + static char *result = 0; + static unsigned int result_length = 0; + + if (writebuf != NULL) + return -2; + + if (!target_running () || annex[0] != '\0' || current_traceframe == -1) + return -1; + + if (offset == 0) + { + struct buffer buffer; + + /* When asked for data at offset 0, generate everything and + store into 'result'. Successive reads will be served off + 'result'. */ + free (result); + + buffer_init (&buffer); + + traceframe_read_info (current_traceframe, &buffer); + + result = buffer_finish (&buffer); + result_length = strlen (result); + buffer_free (&buffer); + } + + if (offset >= result_length) + { + /* We're out of data. */ + free (result); + result = NULL; + result_length = 0; + return 0; + } + + if (len > result_length - offset) + len = result_length - offset; + + memcpy (readbuf, result + offset, len); + return len; +} + static const struct qxfer qxfer_packets[] = { { "auxv", handle_qxfer_auxv }, @@ -1128,6 +1178,7 @@ static const struct qxfer qxfer_packets[] = { "spu", handle_qxfer_spu }, { "statictrace", handle_qxfer_statictrace }, { "threads", handle_qxfer_threads }, + { "traceframe-info", handle_qxfer_traceframe_info }, }; static int @@ -1485,6 +1536,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) strcat (own_buf, ";FastTracepoints+"); strcat (own_buf, ";StaticTracepoints+"); strcat (own_buf, ";qXfer:statictrace:read+"); + strcat (own_buf, ";qXfer:traceframe-info:read+"); } return; diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index c567ccbc9b..53f4e0d17d 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -575,6 +575,8 @@ int traceframe_read_sdata (int tfnum, ULONGEST offset, unsigned char *buf, ULONGEST length, ULONGEST *nbytes); +int traceframe_read_info (int tfnum, struct buffer *buffer); + /* If a thread is determined to be collecting a fast tracepoint, this structure holds the collect status. */ diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c index c5b3f56126..fb5f522ec6 100644 --- a/gdb/gdbserver/tracepoint.c +++ b/gdb/gdbserver/tracepoint.c @@ -4741,9 +4741,34 @@ agent_tsv_read (struct traceframe *tframe, int n) #ifndef IN_PROCESS_AGENT +/* Callback for traceframe_walk_blocks, used to find a given block + type in a traceframe. */ + +static int +match_blocktype (char blocktype, unsigned char *dataptr, void *data) +{ + char *wantedp = data; + + if (*wantedp == blocktype) + return 1; + + return 0; +} + +/* Walk over all traceframe blocks of the traceframe buffer starting + at DATABASE, of DATASIZE bytes long, and call CALLBACK for each + block found, passing in DATA unmodified. If CALLBACK returns true, + this returns a pointer to where the block is found. Returns NULL + if no callback call returned true, indicating that all blocks have + been walked. */ + static unsigned char * -traceframe_find_block_type (unsigned char *database, unsigned int datasize, - int tfnum, char type_wanted) +traceframe_walk_blocks (unsigned char *database, unsigned int datasize, + int tfnum, + int (*callback) (char blocktype, + unsigned char *dataptr, + void *data), + void *data) { unsigned char *dataptr; @@ -4769,9 +4794,10 @@ traceframe_find_block_type (unsigned char *database, unsigned int datasize, datasize = dataptr - database; dataptr = database = trace_buffer_lo; } + blocktype = *dataptr++; - if (type_wanted == blocktype) + if ((*callback) (blocktype, dataptr, data)) return dataptr; switch (blocktype) @@ -4805,6 +4831,18 @@ traceframe_find_block_type (unsigned char *database, unsigned int datasize, return NULL; } +/* Look for the block of type TYPE_WANTED in the trameframe starting + at DATABASE of DATASIZE bytes long. TFNUM is the traceframe + number. */ + +static unsigned char * +traceframe_find_block_type (unsigned char *database, unsigned int datasize, + int tfnum, char type_wanted) +{ + return traceframe_walk_blocks (database, datasize, tfnum, + match_blocktype, &type_wanted); +} + static unsigned char * traceframe_find_regblock (struct traceframe *tframe, int tfnum) { @@ -5044,6 +5082,72 @@ traceframe_read_sdata (int tfnum, ULONGEST offset, return 0; } +/* Callback for traceframe_walk_blocks. Builds a traceframe-info + object. DATA is pointer to a struct buffer holding the + traceframe-info object being built. */ + +static int +build_traceframe_info_xml (char blocktype, unsigned char *dataptr, void *data) +{ + struct buffer *buffer = data; + + switch (blocktype) + { + case 'M': + { + unsigned short mlen; + CORE_ADDR maddr; + + memcpy (&maddr, dataptr, sizeof (maddr)); + dataptr += sizeof (maddr); + memcpy (&mlen, dataptr, sizeof (mlen)); + dataptr += sizeof (mlen); + buffer_xml_printf (buffer, + "\n", + paddress (maddr), phex_nz (mlen, sizeof (mlen))); + break; + } + case 'V': + case 'R': + case 'S': + { + break; + } + default: + warning ("Unhandled trace block type (%d) '%c ' " + "while building trace frame info.", + blocktype, blocktype); + break; + } + + return 0; +} + +/* Build a traceframe-info object for traceframe number TFNUM into + BUFFER. */ + +int +traceframe_read_info (int tfnum, struct buffer *buffer) +{ + struct traceframe *tframe; + + trace_debug ("traceframe_read_info"); + + tframe = find_traceframe (tfnum); + + if (!tframe) + { + trace_debug ("traceframe %d not found", tfnum); + return 1; + } + + buffer_grow_str (buffer, "\n"); + traceframe_walk_blocks (tframe->data, tframe->data_size, + tfnum, build_traceframe_info_xml, buffer); + buffer_grow_str0 (buffer, "\n"); + return 0; +} + /* Return the first fast tracepoint whose jump pad contains PC. */ static struct tracepoint * diff --git a/gdb/remote.c b/gdb/remote.c index c79f6e2eef..da04932c9e 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -1205,6 +1205,7 @@ enum { PACKET_qXfer_osdata, PACKET_qXfer_threads, PACKET_qXfer_statictrace_read, + PACKET_qXfer_traceframe_info, PACKET_qGetTIBAddr, PACKET_qGetTLSAddr, PACKET_qSupported, @@ -3683,6 +3684,8 @@ static struct protocol_feature remote_protocol_features[] = { PACKET_qXfer_osdata }, { "qXfer:threads:read", PACKET_DISABLE, remote_supported_packet, PACKET_qXfer_threads }, + { "qXfer:traceframe-info:read", PACKET_DISABLE, remote_supported_packet, + PACKET_qXfer_traceframe_info }, { "QPassSignals", PACKET_DISABLE, remote_supported_packet, PACKET_QPassSignals }, { "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet, @@ -8211,6 +8214,11 @@ remote_xfer_partial (struct target_ops *ops, enum target_object object, return remote_read_qxfer (ops, "threads", annex, readbuf, offset, len, &remote_protocol_packets[PACKET_qXfer_threads]); + case TARGET_OBJECT_TRACEFRAME_INFO: + gdb_assert (annex == NULL); + return remote_read_qxfer + (ops, "traceframe-info", annex, readbuf, offset, len, + &remote_protocol_packets[PACKET_qXfer_traceframe_info]); default: return -1; } @@ -10157,6 +10165,26 @@ remote_set_circular_trace_buffer (int val) error (_("Bogus reply from target: %s"), reply); } +static struct traceframe_info * +remote_traceframe_info (void) +{ + char *text; + + text = target_read_stralloc (¤t_target, + TARGET_OBJECT_TRACEFRAME_INFO, NULL); + if (text != NULL) + { + struct traceframe_info *info; + struct cleanup *back_to = make_cleanup (xfree, text); + + info = parse_traceframe_info (text); + do_cleanups (back_to); + return info; + } + + return NULL; +} + static void init_remote_ops (void) { @@ -10248,6 +10276,7 @@ Specify the serial device it is connected to\n\ = remote_static_tracepoint_marker_at; remote_ops.to_static_tracepoint_markers_by_strid = remote_static_tracepoint_markers_by_strid; + remote_ops.to_traceframe_info = remote_traceframe_info; } /* Set up the extended remote vector by making a copy of the standard @@ -10670,6 +10699,10 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_siginfo_write], "qXfer:siginfo:write", "write-siginfo-object", 0); + add_packet_config_cmd + (&remote_protocol_packets[PACKET_qXfer_traceframe_info], + "qXfer:trace-frame-info:read", "traceframe-info", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTLSAddr], "qGetTLSAddr", "get-thread-local-storage-address", 0); diff --git a/gdb/target.c b/gdb/target.c index ad695a171b..edf03f150a 100644 --- a/gdb/target.c +++ b/gdb/target.c @@ -681,6 +681,7 @@ update_current_target (void) INHERIT (to_set_permissions, t); INHERIT (to_static_tracepoint_marker_at, t); INHERIT (to_static_tracepoint_markers_by_strid, t); + INHERIT (to_traceframe_info, t); INHERIT (to_magic, t); /* Do not inherit to_memory_map. */ /* Do not inherit to_flash_erase. */ @@ -890,6 +891,9 @@ update_current_target (void) de_fault (to_static_tracepoint_markers_by_strid, (VEC(static_tracepoint_marker_p) * (*) (const char *)) tcomplain); + de_fault (to_traceframe_info, + (struct traceframe_info * (*) (void)) + tcomplain); #undef de_fault /* Finally, position the target-stack beneath the squashed diff --git a/gdb/target.h b/gdb/target.h index 4625d520e5..e856dde8de 100644 --- a/gdb/target.h +++ b/gdb/target.h @@ -36,7 +36,7 @@ struct trace_status; struct uploaded_tsv; struct uploaded_tp; struct static_tracepoint_marker; - +struct traceframe_info; struct expression; /* This include file defines the interface between the main part @@ -275,6 +275,8 @@ enum target_object The size of the data transfered is always 8 bytes (the size of an address on ia64). */ TARGET_OBJECT_HPUX_SOLIB_GOT, + /* Traceframe info, in XML format. */ + TARGET_OBJECT_TRACEFRAME_INFO, /* Possible future objects: TARGET_OBJECT_FILE, ... */ }; @@ -736,6 +738,12 @@ struct target_ops VEC(static_tracepoint_marker_p) *(*to_static_tracepoint_markers_by_strid) (const char *id); + /* Return a traceframe info object describing the current + traceframe's contents. This method should not cache data; + higher layers take care of caching, invalidating, and + re-fetching when necessary. */ + struct traceframe_info *(*to_traceframe_info) (void); + int to_magic; /* Need sub-structure for target machine related rather than comm related? */ @@ -1458,6 +1466,9 @@ extern int target_search_memory (CORE_ADDR start_addr, #define target_static_tracepoint_markers_by_strid(marker_id) \ (*current_target.to_static_tracepoint_markers_by_strid) (marker_id) +#define target_traceframe_info() \ + (*current_target.to_traceframe_info) () + /* Command logging facility. */ #define target_log_command(p) \ diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c index ffc31a9550..8117531431 100644 --- a/gdb/tracepoint.c +++ b/gdb/tracepoint.c @@ -130,6 +130,29 @@ extern void output_command (char *, int); typedef struct trace_state_variable tsv_s; DEF_VEC_O(tsv_s); +/* Defines a [START, START + LENGTH) memory range. */ + +struct mem_range +{ + /* Lowest address in the range. */ + CORE_ADDR start; + + /* Length of the range. */ + int length; +}; + +typedef struct mem_range mem_range_s; + +DEF_VEC_O(mem_range_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. */ @@ -148,6 +171,12 @@ static struct symbol *traceframe_fun; /* Symtab and line for last traceframe collected. */ static struct symtab_and_line traceframe_sal; +/* The traceframe info of the current traceframe. NULL if we haven't + yet attempted to fetch it, or if the target does not support + fetching this object, or if we're not inspecting a traceframe + presently. */ +static struct traceframe_info *traceframe_info; + /* Tracing command lists. */ static struct cmd_list_element *tfindlist; @@ -208,6 +237,29 @@ current_trace_status () return &trace_status; } +/* Destroy INFO. */ + +static void +free_traceframe_info (struct traceframe_info *info) +{ + if (info != NULL) + { + VEC_free (mem_range_s, info->memory); + + xfree (info); + } +} + +/* Free and and clear the traceframe info cache of the current + traceframe. */ + +static void +clear_traceframe_info (void) +{ + free_traceframe_info (traceframe_info); + traceframe_info = NULL; +} + /* Set traceframe number to NUM. */ static void set_traceframe_num (int num) @@ -1597,6 +1649,7 @@ start_tracing (void) set_tracepoint_num (-1); set_traceframe_context (NULL); current_trace_status()->running = 1; + clear_traceframe_info (); } /* tstart command: @@ -1964,6 +2017,7 @@ tfind_1 (enum trace_find_type type, int num, registers_changed (); target_dcache_invalidate (); set_traceframe_num (target_frameno); + clear_traceframe_info (); set_tracepoint_num (tp ? tp->number : target_tracept); if (target_frameno == -1) set_traceframe_context (NULL); @@ -2915,6 +2969,8 @@ set_traceframe_number (int num) /* Changing the traceframe changes our view of registers and of the frame chain. */ registers_changed (); + + clear_traceframe_info (); } /* A cleanup used when switching away and back from tfind mode. */ @@ -4108,6 +4164,56 @@ tfile_has_registers (struct target_ops *ops) return traceframe_number != -1; } +/* Callback for traceframe_walk_blocks. Builds a traceframe_info + object for the tfile target's current traceframe. */ + +static int +build_traceframe_info (char blocktype, void *data) +{ + struct traceframe_info *info = data; + + switch (blocktype) + { + case 'M': + { + struct mem_range *r; + ULONGEST maddr; + unsigned short mlen; + + tfile_read ((gdb_byte *) &maddr, 8); + tfile_read ((gdb_byte *) &mlen, 2); + + r = VEC_safe_push (mem_range_s, info->memory, NULL); + + r->start = maddr; + r->length = mlen; + break; + } + case 'V': + case 'R': + case 'S': + { + break; + } + default: + warning (_("Unhandled trace block type (%d) '%c ' " + "while building trace frame info."), + blocktype, blocktype); + break; + } + + return 0; +} + +static struct traceframe_info * +tfile_traceframe_info (void) +{ + struct traceframe_info *info = XCNEW (struct traceframe_info); + + traceframe_walk_blocks (build_traceframe_info, 0, info); + return info; +} + static void init_tfile_ops (void) { @@ -4129,6 +4235,7 @@ init_tfile_ops (void) tfile_ops.to_has_memory = tfile_has_memory; tfile_ops.to_has_stack = tfile_has_stack; tfile_ops.to_has_registers = tfile_has_registers; + tfile_ops.to_traceframe_info = tfile_traceframe_info; tfile_ops.to_magic = OPS_MAGIC; } @@ -4380,6 +4487,116 @@ sdata_make_value (struct gdbarch *gdbarch, struct internalvar *var) return allocate_value (builtin_type (gdbarch)->builtin_void); } +#if !defined(HAVE_LIBEXPAT) + +struct traceframe_info * +parse_traceframe_info (const char *tframe_info) +{ + static int have_warned; + + if (!have_warned) + { + have_warned = 1; + warning (_("Can not parse XML trace frame info; XML support " + "was disabled at compile time")); + } + + return NULL; +} + +#else /* HAVE_LIBEXPAT */ + +#include "xml-support.h" + +/* Handle the start of a element. */ + +static void +traceframe_info_start_memory (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, VEC(gdb_xml_value_s) *attributes) +{ + struct traceframe_info *info = user_data; + struct mem_range *r = VEC_safe_push (mem_range_s, info->memory, NULL); + ULONGEST *start_p, *length_p; + + start_p = xml_find_attribute (attributes, "start")->value; + length_p = xml_find_attribute (attributes, "length")->value; + + r->start = *start_p; + r->length = *length_p; +} + +/* Discard the constructed trace frame info (if an error occurs). */ + +static void +free_result (void *p) +{ + struct traceframe_info *result = p; + + free_traceframe_info (result); +} + +/* The allowed elements and attributes for an XML memory map. */ + +static const struct gdb_xml_attribute memory_attributes[] = { + { "start", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { "length", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_element traceframe_info_children[] = { + { "memory", memory_attributes, NULL, + GDB_XML_EF_REPEATABLE | GDB_XML_EF_OPTIONAL, + traceframe_info_start_memory, NULL }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_element traceframe_info_elements[] = { + { "traceframe-info", NULL, traceframe_info_children, GDB_XML_EF_NONE, + NULL, NULL }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + +/* Parse a traceframe-info XML document. */ + +struct traceframe_info * +parse_traceframe_info (const char *tframe_info) +{ + struct traceframe_info *result; + struct cleanup *back_to; + + result = XCNEW (struct traceframe_info); + back_to = make_cleanup (free_result, result); + + if (gdb_xml_parse_quick (_("trace frame info"), + "traceframe-info.dtd", traceframe_info_elements, + tframe_info, result) == 0) + { + /* Parsed successfully, keep the result. */ + discard_cleanups (back_to); + + return result; + } + + do_cleanups (back_to); + return NULL; +} + +#endif /* HAVE_LIBEXPAT */ + +/* Returns the traceframe_info object for the current traceframe. + This is where we avoid re-fetching the object from the target if we + already have it cached. */ + +struct traceframe_info * +get_traceframe_info (void) +{ + if (traceframe_info == NULL) + traceframe_info = target_traceframe_info (); + + return traceframe_info; +} + /* module initialization */ void _initialize_tracepoint (void) diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h index 817491807f..276501e517 100644 --- a/gdb/tracepoint.h +++ b/gdb/tracepoint.h @@ -236,4 +236,6 @@ extern void tfind_1 (enum trace_find_type type, int num, extern void trace_save (const char *filename, int target_does_save); +extern struct traceframe_info *parse_traceframe_info (const char *tframe_info); + #endif /* TRACEPOINT_H */ -- 2.34.1