From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 32589 invoked by alias); 28 Feb 2013 11:01:37 -0000 Received: (qmail 32580 invoked by uid 22791); 28 Feb 2013 11:01:35 -0000 X-SWARE-Spam-Status: No, hits=-4.5 required=5.0 tests=AWL,BAYES_00,KHOP_RCVD_UNTRUST,KHOP_THREADED,RCVD_IN_HOSTKARMA_W,RCVD_IN_HOSTKARMA_WL,TW_RV,TW_TR X-Spam-Check-By: sourceware.org Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Thu, 28 Feb 2013 11:01:21 +0000 Received: from svr-orw-fem-01.mgc.mentorg.com ([147.34.98.93]) by relay1.mentorg.com with esmtp id 1UB1En-0003y7-7j from Yao_Qi@mentor.com for gdb-patches@sourceware.org; Thu, 28 Feb 2013 03:01:21 -0800 Received: from SVR-ORW-FEM-03.mgc.mentorg.com ([147.34.97.39]) by svr-orw-fem-01.mgc.mentorg.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675); Thu, 28 Feb 2013 03:01:21 -0800 Received: from qiyao.dyndns.org (147.34.91.1) by svr-orw-fem-03.mgc.mentorg.com (147.34.97.39) with Microsoft SMTP Server id 14.1.289.1; Thu, 28 Feb 2013 03:01:29 -0800 Message-ID: <512F38CE.5030802@codesourcery.com> Date: Thu, 28 Feb 2013 13:17:00 -0000 From: Yao Qi User-Agent: Mozilla/5.0 (X11; Linux i686; rv:17.0) Gecko/17.0 Thunderbird/17.0 MIME-Version: 1.0 To: Subject: Re: [PATCH 2/5] Save trace into CTF format References: <1361931459-3953-1-git-send-email-yao@codesourcery.com> <1361931459-3953-3-git-send-email-yao@codesourcery.com> In-Reply-To: <1361931459-3953-3-git-send-email-yao@codesourcery.com> Content-Type: text/plain; charset="UTF-8"; format=flowed Content-Transfer-Encoding: 8bit X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2013-02/txt/msg00733.txt.bz2 On 02/27/2013 10:17 AM, Yao Qi wrote: > +static void > +ctf_write_frame_v_block (struct trace_file_writer *self, > + int num, LONGEST val) > +{ > + struct ctf_writer_data *data = self->data; > + int one = 1; > + > + /* Event Id. */ > + ctf_save_align_write (&data->tcs, (void *) &one, 4, 4); "&one" should be cast to "gdb_byte *" instead of "void *". > + > +static void > +ctf_write_frame_end (struct trace_file_writer *self) > +{ > + struct ctf_writer_data *data = self->data; > + uint32_t u32; > + uint32_t t; > + > + /* Write the content size to packet header. */ > + ctf_save_fseek (&data->tcs, data->tcs.packet_start + 4, SEEK_SET); > + u32 = data->tcs.content_size * TARGET_CHAR_BIT; > + > + t = data->tcs.content_size; > + ctf_save_write (&data->tcs, (gdb_byte *) &u32, 4); Writing a unsigned 32-bit integer is popular in this patch, so I add a new function "ctf_save_write_uint32" to avoid many casts in the code. Here is the updated patch to address them. -- Yao (齐尧) gdb: 2013-02-28 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. --- gdb/Makefile.in | 6 +- gdb/ctf.c | 690 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/ctf.h | 24 ++ gdb/mi/mi-main.c | 11 +- gdb/tracepoint.c | 36 +++- gdb/tracepoint.h | 2 + 6 files changed, 760 insertions(+), 9 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..58acf4c --- /dev/null +++ b/gdb/ctf.c @@ -0,0 +1,690 @@ +/* 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 'R' and 'V' are saved in event "register" and "tsv" + respectively. They are fixed in length, so there is only one event + type for each of them. + 4.3: The block 'M' is variable on length. Each event type is + defined for a specific length of block 'M', so there are multiple + event types "memory_$LENGTH" in metadata file. $LENGTH is a + decimal. + 4.4: 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_FRAME 2 +#define CTF_EVENT_ID_LAST 3 + +/* Handler of writing trace of CTF format. */ + +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 contents in BUF to file FD. SIZE is the size of BUF. */ + +static void +ctf_save_fwrite (FILE *fd, const gdb_byte *buf, size_t size) +{ + if (fwrite (buf, size, 1, fd) != 1) + error (_("Unable to write file for saving trace data (%s)"), + safe_strerror (errno)); +} + +static void +ctf_save_fwrite_format_1 (FILE *fd, const char *format, va_list args) +{ + char *linebuffer; + struct cleanup *old_cleanups; + + linebuffer = xstrvprintf (format, args); + old_cleanups = make_cleanup (xfree, linebuffer); + ctf_save_fwrite (fd, linebuffer, strlen (linebuffer)); + do_cleanups (old_cleanups); +} + +/* Write data in FORMAT to FD. */ + +static void +ctf_save_fwrite_format (FILE *fd, const char *format, ...) +{ + va_list args; + + va_start (args, format); + ctf_save_fwrite_format_1 (fd, format, args); + 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) +{ + ctf_save_fwrite (handler->datastream_fd, buf, size); + + handler->content_size += size; + + return 0; +} + +/* Write a unsigned 32-bit integer to datastream file represented by + HANDLER. */ + +static int +ctf_save_write_uint32 (struct trace_write_handler *handler, + uint32_t u32) +{ + return 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) +{ + 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; +} + +/* Move to next 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_fwrite_format (handler->metadata_fd, "/* CTF %d.%d */\n", + CTF_SAVE_MAJOR, CTF_SAVE_MINOR); + ctf_save_fwrite_format (handler->metadata_fd, + "typealias integer { size = 8; align = 8; " + "signed = false; encoding = ascii; }" + " := uint8_t;\n"); + ctf_save_fwrite_format (handler->metadata_fd, + "typealias integer { size = 16; align = 16;" + "signed = false; } := uint16_t;\n"); + ctf_save_fwrite_format (handler->metadata_fd, + "typealias integer { size = 32; align = 32;" + "signed = false; } := uint32_t;\n"); + ctf_save_fwrite_format (handler->metadata_fd, + "typealias integer { size = 64; align = 64;" + "signed = false; base = hex;}" + " := uint64_t;\n"); + ctf_save_fwrite_format (handler->metadata_fd, "\n"); + + ctf_save_fwrite_format (handler->metadata_fd, metadata_fmt, + CTF_SAVE_MAJOR, CTF_SAVE_MINOR, + BYTE_ORDER == LITTLE_ENDIAN ? "le" : "be"); + ctf_save_fwrite_format (handler->metadata_fd, "\n"); +} + +/* Cleanup function. */ + +static void +ctf_save_cleanup (void *p) +{ + struct trace_write_handler *handler = p; + + if (handler->metadata_fd) + fclose (handler->metadata_fd); + + if (handler->datastream_fd) + fclose (handler->datastream_fd); +} + +/* Data specific to CTF trace writer. */ + +struct ctf_writer_data +{ + struct trace_write_handler tcs; + + /* Event id 0 1 and 2 are reserved: + - 0 for register block + - 1 for trace variable block. + - 2 for frame start marker. */ + unsigned int event_id; + + /* The value of element of index I is the size of 'M' block, whose + event id is I. */ + unsigned int *m_block_size; + /* Length of M_BLOCK_SIZE. */ + unsigned int length; + + struct cleanup *cleanup; +}; + +/* This is the implementation of trace_file_write_ops method + can_target_save. */ + +static int +ctf_can_target_save (struct trace_file_writer *self, + const char *filename) +{ + /* 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_writer_data *data = self->data; + int i; + + data->event_id = CTF_EVENT_ID_LAST; + data->length = 8; + data->m_block_size = xmalloc (data->length * sizeof (int)); + memset (data->m_block_size, 0, data->length * sizeof (int)); + + /* Create DIRNAME. */ + file_name = alloca (strlen (dirname) + 1 + + strlen (CTF_DATASTREAM_NAME) + 1); + 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 (&data->tcs, '\0', sizeof (data->tcs)); + + file_name = xstrprintf ("%s/%s", dirname, CTF_METADATA_NAME); + old_chain = make_cleanup (xfree, file_name); + + data->tcs.metadata_fd = fopen (file_name, "w"); + if (!data->tcs.metadata_fd) + error (_("Unable to open file '%s' for saving trace data (%s)"), + file_name, safe_strerror (errno)); + do_cleanups (old_chain); + + ctf_save_metadata_header (&data->tcs); + + file_name = xstrprintf ("%s/%s", dirname, CTF_DATASTREAM_NAME); + old_chain = make_cleanup (xfree, file_name); + data->tcs.datastream_fd = fopen (file_name, "w"); + if (!data->tcs.datastream_fd) + error (_("Unable to open file '%s' for saving trace data (%s)"), + file_name, safe_strerror (errno)); + do_cleanups (old_chain); + + data->cleanup = make_cleanup (ctf_save_cleanup, &data->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_writer_data *data = self->data; + + ctf_save_fwrite_format (data->tcs.metadata_fd, "\n"); + ctf_save_fwrite_format (data->tcs.metadata_fd, + "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_fwrite_format (data->tcs.metadata_fd, "\n"); + ctf_save_fwrite_format (data->tcs.metadata_fd, + "event {\n\tname = \"frame\";\n\tid = %u;\n" + "\tfields := struct { \n" + "\t};\n" + "};\n", CTF_EVENT_ID_FRAME); + + gdb_assert (data->tcs.content_size == 0); + gdb_assert (data->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_writer_data *data = self->data; + + ctf_save_fwrite_format (data->tcs.metadata_fd, "\n"); + + ctf_save_fwrite_format (data->tcs.metadata_fd, + "event {\n\tname = \"register\";\n\tid = %u;\n" + "\tfields := struct { \n" + "\t\tuint8_t 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_writer_data *data = self->data; + + gdb_assert (data->tcs.content_size == 0); + /* The babeltrace requires or assumes that the datastream file + is larger than 4096. If we don't generate enough packets and + events, create a fake packet which has zero event, to use up + the space. */ + if (data->tcs.packet_start < CTF_FILE_MIN_SIZE) + { + uint32_t u32; + + /* magic. */ + u32 = CTF_MAGIC; + ctf_save_write_uint32 (&data->tcs, u32); + + /* content_size. */ + u32 = 0; + ctf_save_write_uint32 (&data->tcs, u32); + + /* packet_size. */ + u32 = 12; + if (data->tcs.packet_start + u32 < 4096) + u32 = CTF_FILE_MIN_SIZE - data->tcs.packet_start; + + u32 *= TARGET_CHAR_BIT; + ctf_save_write_uint32 (&data->tcs, u32); + + /* tpnum. */ + u32 = 0; + ctf_save_write (&data->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 + > (data->tcs.packet_start + data->tcs.content_size)) + { + gdb_byte b = 0; + + ctf_save_fseek (&data->tcs, CTF_FILE_MIN_SIZE - 1, + SEEK_SET); + ctf_save_write (&data->tcs, &b, 1); + } + } + + do_cleanups (data->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_writer_data *data = self->data; + int two = 2; + uint32_t u32; + + /* Step 1: Write packet context. */ + /* magic. */ + u32 = CTF_MAGIC; + ctf_save_write_uint32 (&data->tcs, u32); + /* content_size and packet_size.. We still don't know the value, + write it later. */ + ctf_save_fseek (&data->tcs, 4, SEEK_CUR); + ctf_save_fseek (&data->tcs, 4, SEEK_CUR); + /* Tracepoint number. */ + ctf_save_write (&data->tcs, (gdb_byte *) &tpnum, 2); + + /* Step 2: Write event "frame". */ + /* Event Id. */ + ctf_save_align_write (&data->tcs, (gdb_byte *) &two, 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, int size) +{ + struct ctf_writer_data *data = self->data; + int zero = 0; + + /* Event Id. */ + ctf_save_align_write (&data->tcs, (gdb_byte *) &zero, 4, 4); + + /* array contents. */ + ctf_save_align_write (&data->tcs, buf, size, 1); +} + +/* This is the implementation of trace_frame_write_ops method + write_m_block. */ + +static void +ctf_write_frame_m_block (struct trace_file_writer *self, + ULONGEST addr, gdb_byte *buf, + uint16_t length) +{ + struct ctf_writer_data *data = self->data; + int i; + int event_id = 0; + + /* Check we've seen the 'M' block of length LENGTH before. */ + for (i = 0; i < data->length; i++) + { + if (length == data->m_block_size[i]) + { + event_id = i + CTF_EVENT_ID_LAST; + break; + } + } + + /* Record it. */ + if (event_id == 0) + { + event_id = data->event_id++; + + if (event_id - CTF_EVENT_ID_LAST >= data->length) + { + data->m_block_size + = xrealloc (data->m_block_size, + sizeof (int) * data->length * 2); + memset (&data->m_block_size[data->length], 0, + data->length * sizeof (int)); + data->length *= 2; + } + + data->m_block_size[event_id - CTF_EVENT_ID_LAST] = length; + + /* Save the type of 'M' block into metadata. */ + ctf_save_fwrite_format (data->tcs.metadata_fd, "\n"); + ctf_save_fwrite_format (data->tcs.metadata_fd, + "event {\n\tname = \"memory_%d\";\n\tid = %u;\n" + "\tfields := struct { \n" + "\t\tuint64_t address;\n" + "\t\tuint16_t length;\n" + "\t\tuint8_t contents[%d];\n" + "\t};\n" + "};\n", + length, event_id, length); + } + + /* Save 'M' block into datastream. */ + /* Event Id. */ + ctf_save_align_write (&data->tcs, (gdb_byte *) &event_id, 4, 4); + + /* Address. */ + ctf_save_align_write (&data->tcs, (gdb_byte *) &addr, 8, 8); + + /* Length. */ + ctf_save_align_write (&data->tcs, (gdb_byte *) &length, 2, 2); + + /* Contents. */ + ctf_save_align_write (&data->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, + int num, LONGEST val) +{ + struct ctf_writer_data *data = self->data; + int one = 1; + + /* Event Id. */ + ctf_save_align_write (&data->tcs, (gdb_byte *) &one, 4, 4); + + /* val. */ + ctf_save_align_write (&data->tcs, (gdb_byte *) &val, 8, 8); + /* num. */ + ctf_save_align_write (&data->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_writer_data *data = self->data; + uint32_t u32; + uint32_t t; + + /* Write the content size to packet header. */ + ctf_save_fseek (&data->tcs, data->tcs.packet_start + 4, SEEK_SET); + u32 = data->tcs.content_size * TARGET_CHAR_BIT; + + t = data->tcs.content_size; + ctf_save_write_uint32 (&data->tcs, u32); + + /* Write the packet size. */ + u32 += 4 * TARGET_CHAR_BIT; + ctf_save_write_uint32 (&data->tcs, u32); + + data->tcs.content_size = t; + + /* Write zero at the end of the packet. */ + ctf_save_fseek (&data->tcs, data->tcs.packet_start + t, SEEK_SET); + u32 = 0; + ctf_save_write_uint32 (&data->tcs, u32); + data->tcs.content_size = t; + + ctf_save_next_packet (&data->tcs); +} + +/* Operations to write various types of trace frames into CTF + format. */ + +static struct trace_frame_write_ops ctf_write_frame_ops = +{ + ctf_write_frame_start, + ctf_write_frame_r_block, + ctf_write_frame_m_block, + ctf_write_frame_v_block, + ctf_write_frame_end, +}; + +/* Operations to write trace buffers into CTF format. */ + +static struct trace_file_write_ops ctf_write_ops = +{ + ctf_can_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 (void) +{ + struct trace_file_writer *writer + = xmalloc (sizeof (struct trace_file_writer)); + + writer->ops = &ctf_write_ops; + writer->data = xmalloc (sizeof (struct ctf_writer_data)); + + return writer; +} diff --git a/gdb/ctf.h b/gdb/ctf.h new file mode 100644 index 0000000..d2fccaf --- /dev/null +++ b/gdb/ctf.h @@ -0,0 +1,24 @@ +/* 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 (void); +#endif diff --git a/gdb/mi/mi-main.c b/gdb/mi/mi-main.c index 206b626..a950b34 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,16 +2478,19 @@ void mi_cmd_trace_save (char *command, char **argv, int argc) { int target_saves = 0; + int generate_ctf = 0; char *filename; if (argc != 1 && argc != 2) - error (_("Usage: -trace-save [-r] filename")); + error (_("Usage: -trace-save [-r] [-ctf] filename")); if (argc == 2) { filename = argv[1]; if (strcmp (argv[0], "-r") == 0) target_saves = 1; + if (strcmp (argv[0], "-ctf") == 0) + generate_ctf = 1; else error (_("Invalid option: %s"), argv[0]); } @@ -2495,7 +2499,10 @@ mi_cmd_trace_save (char *command, char **argv, int argc) filename = argv[0]; } - 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 390f779..c2720e8 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" @@ -3451,6 +3452,7 @@ static void trace_save_command (char *args, int from_tty) { int target_does_save = 0; + int generate_ctf = 0; char **argv; char *filename = NULL; struct cleanup *back_to; @@ -3466,6 +3468,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 @@ -3475,15 +3479,22 @@ trace_save_command (char *args, int from_tty) if (!filename) error_no_arg (_("file in which to save trace data")); - writer = xmalloc (sizeof (struct trace_file_writer)); - writer->ops = &tfile_write_ops; - writer->data = xmalloc (sizeof (struct tfile_writer_data)); + if (generate_ctf) + writer = ctf_trace_file_writer (); + else + { + writer = xmalloc (sizeof (struct trace_file_writer)); + writer->ops = &tfile_write_ops; + writer->data = xmalloc (sizeof (struct tfile_writer_data)); + } + 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); } @@ -3499,6 +3510,22 @@ trace_save_tfile (const char *filename, int target_does_save) writer->ops = &tfile_write_ops; writer->data = xmalloc (sizeof (struct tfile_writer_data)); + trace_save (filename, writer, target_does_save); + + back_to = make_cleanup (trace_file_writer_xfree, writer); + do_cleanups (back_to); +} + +/* Save the trace data to dir DIRENAME 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 (); + trace_save (dirname, writer, target_does_save); back_to = make_cleanup (trace_file_writer_xfree, writer); do_cleanups (back_to); } @@ -5552,6 +5579,7 @@ _initialize_tracepoint (void) add_com ("tsave", class_trace, trace_save_command, _("\ Save the trace data to a file.\n\ Use the '-r' option to direct the target to save directly to the file,\n\ +Use the '-ctf' option to save the data to CTF format,\n\ using its own filesystem.")); c = add_com ("tvariable", class_trace, trace_variable_command,_("\ diff --git a/gdb/tracepoint.h b/gdb/tracepoint.h index 1db6b69..44ff2de 100644 --- a/gdb/tracepoint.h +++ b/gdb/tracepoint.h @@ -372,6 +372,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