From d0353e76919f8bd8cfdd0e9da13fa16ab95df2d3 Mon Sep 17 00:00:00 2001 From: Yao Qi Date: Thu, 14 Mar 2013 09:02:30 +0000 Subject: [PATCH] gdb/ 2013-03-14 Hui Zhu Yao Qi * 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. * NEWS: Mention these changes. gdb/doc/ 2013-03-14 Hui Zhu Yao Qi * gdb.texinfo (Trace Files): Add "tsave -ctf". --- gdb/ChangeLog | 19 ++ gdb/Makefile.in | 7 +- gdb/NEWS | 8 + gdb/ctf.c | 647 ++++++++++++++++++++++++++++++++++++++++++++ gdb/ctf.h | 25 ++ gdb/doc/ChangeLog | 5 + gdb/doc/gdb.texinfo | 6 + gdb/mi/mi-main.c | 47 +++- gdb/tracepoint.c | 28 +- gdb/tracepoint.h | 2 + 10 files changed, 776 insertions(+), 18 deletions(-) create mode 100644 gdb/ctf.c create mode 100644 gdb/ctf.h diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 42829fbae39..e5ab65e177c 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,22 @@ +2013-03-14 Hui Zhu + Yao Qi + + * 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. + * NEWS: Mention these changes. + 2013-03-14 Yao Qi * tracepoint.c (trace_file_writer_xfree): New. diff --git a/gdb/Makefile.in b/gdb/Makefile.in index 5366d9ead76..9bab01cfef8 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/NEWS b/gdb/NEWS index 4e68fce796e..b759adf5350 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -3,6 +3,14 @@ *** Changes since GDB 7.6 +* The command 'tsave' can now support new option '-ctf' to save trace + buffer in Common Trace Format. + +* MI changes + + ** The -trace-save MI command can optionally save trace buffer in Common + Trace Format now. + *** Changes in GDB 7.6 * Target record has been renamed to record-full. diff --git a/gdb/ctf.c b/gdb/ctf.c new file mode 100644 index 00000000000..d2ff862dd37 --- /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 + Contributed by Yao Qi + + 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 . */ + +#include "defs.h" +#include "ctf.h" +#include "tracepoint.h" +#include "regcache.h" + +#include + +/* 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 00000000000..6a61cf39fd6 --- /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 . */ + +#ifndef CTF_H +#define CTF_H + +extern struct trace_file_writer *ctf_trace_file_writer_new (void); + +#endif diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index d45c4b8496f..4830331a56a 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,8 @@ +2013-03-14 Hui Zhu + Yao Qi + + * gdb.texinfo (Trace Files): Add "tsave -ctf". + 2013-03-13 Keith Seitz * gdb.texinfo (Maintenance Commands): Add missing ')' for diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 0822bd28ea6..4ac28bb8bb8 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -12286,6 +12286,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 @@ -12294,6 +12295,11 @@ 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 diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index 085439bb82e..94fda8f63b2 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 2bfa500b846..d579fb43183 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" @@ -3544,6 +3545,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) @@ -3556,6 +3558,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 @@ -3565,14 +3569,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); } @@ -3591,6 +3599,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. */ @@ -5657,6 +5680,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 a5d3d42d048..2a809c7ee10 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); -- 2.39.5