aboutsummaryrefslogtreecommitdiff
path: root/gdb/arc-inst-tracing.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/arc-inst-tracing.c')
-rw-r--r--gdb/arc-inst-tracing.c356
1 files changed, 356 insertions, 0 deletions
diff --git a/gdb/arc-inst-tracing.c b/gdb/arc-inst-tracing.c
new file mode 100644
index 0000000..c22ddb7
--- /dev/null
+++ b/gdb/arc-inst-tracing.c
@@ -0,0 +1,356 @@
+/* Target dependent code for ARC processor family, for GDB, the GNU debugger.
+
+ Copyright 2009 Free Software Foundation, Inc.
+
+ Contributed by ARC International (www.arc.com)
+
+ Authors:
+ Richard Stuckey <richard.stuckey@arc.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/>. */
+
+/******************************************************************************/
+/* */
+/* Outline: */
+/* This module implements operations for recording an instruction trace */
+/* of successive PC values in a compressed binary format in a file. */
+/* */
+/* The file is regarded as a linear sequence of bits, of the form: */
+/* */
+/* <64-bit first instruction count> */
+/* <64-bit last instruction count> */
+/* { <3-bit-code> [ <16-bit-data> | <31-bit-data> ] } */
+/* [ <zero-pad-bits> ] */
+/* */
+/******************************************************************************/
+
+/* system header files */
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <errno.h>
+
+/* gdb header files */
+#include "defs.h"
+
+/* ARC header files */
+#include "arc-inst-tracing.h"
+#include "arc-tdep.h"
+
+
+/* -------------------------------------------------------------------------- */
+/* local data */
+/* -------------------------------------------------------------------------- */
+
+#define MAX_ORDINAL 0xFFFFFFFFFFFFFFFFULL
+
+/* The file that is currently open for read or write. */
+static FILE *file;
+
+/* The byte of data that has been read from, or is about to be written to, the
+ currently open file; and the number of bits in that byte that have been used
+ (i.e. been consumed on input, or produced on output). */
+static unsigned char byte;
+static unsigned int bits_used;
+
+/* Set to TRUE if EOF occurs whilst trying to read from the file. */
+static Boolean EOF_detected;
+
+
+/* -------------------------------------------------------------------------- */
+/* local functions */
+/* -------------------------------------------------------------------------- */
+
+/* Write the N least-significant bits of the given value to the file. */
+
+static void
+output_bits (unsigned int N, unsigned int value)
+{
+ unsigned int i;
+
+ for (i = 0; i < N; i++)
+ {
+ if (bits_used == BITS_IN_BYTE)
+ {
+ (void) putc((int) byte, file);
+ byte = 0;
+ bits_used = 0;
+// printf("byte = %02X\n", byte);
+ }
+
+ byte <<= 1;
+ byte |= (value >> (N - i - 1)) & 0x1;
+ bits_used++;
+ }
+}
+
+
+/* Read N bits from the file and return them as the least-significant bits of a value. */
+
+static unsigned int
+input_bits (unsigned int N)
+{
+ unsigned int value = 0;
+ unsigned int i;
+
+ for (i = 0; i < N; i++)
+ {
+ unsigned int bit;
+
+ /* If all the bits in the current input byte have been used. */
+ if (bits_used == BITS_IN_BYTE)
+ {
+ /* Read the next byte from the file. */
+ int input = getc(file);
+
+ if (input == EOF)
+ {
+ EOF_detected = TRUE;
+ return 0;
+ }
+
+ byte = (unsigned char) input;
+ bits_used = 0;
+// printf("byte = %02X\n", byte);
+ }
+
+ bit = (unsigned int) ((byte & 0x80) >> 7);
+ value <<= 1;
+ value |= bit;
+ byte <<= 1;
+ bits_used++;
+ }
+
+ return value;
+}
+
+
+/* Write a 64-bit value to the file. */
+
+static void
+output_ordinal (Ordinal value)
+{
+ output_bits(32, (unsigned int) (value >> 32));
+ output_bits(32, (unsigned int) (value & 0xFFFFFFFF));
+}
+
+
+/* Read a 64-bit value from the file. */
+
+static Ordinal
+input_ordinal (void)
+{
+ unsigned int high = input_bits(32);
+ unsigned int low = input_bits(32);
+
+ return ((Ordinal) high) << 32 | (Ordinal) low;
+}
+
+
+/* Open the named file with the given access mode. */
+
+static Boolean
+open_file (const char *filename, const char *mode)
+{
+ file = fopen(filename, mode);
+
+ if (file == NULL)
+ {
+ fprintf(stderr, "Can not open file %s: %s\n", filename, strerror(errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/* -------------------------------------------------------------------------- */
+/* externally visible functions */
+/* -------------------------------------------------------------------------- */
+
+/* Start encoding trace data into the named file. */
+
+Boolean
+arc_start_encoding (const char *filename,
+ Ordinal first_instr_count)
+{
+ ENTERARGS("filename = %s, first = %llu", filename, first_instr_count);
+
+ byte = 0;
+ bits_used = 0;
+
+ if (open_file(filename, "wb"))
+ {
+ /* The second value will be fixed up later. */
+ output_ordinal(first_instr_count);
+ output_ordinal(MAX_ORDINAL);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/* Stop encoding trace data into the file. */
+
+void
+arc_stop_encoding (Ordinal last_instr_count)
+{
+ ENTERARGS("last = %llu", last_instr_count);
+
+ if (file)
+ {
+ /* Make sure the last partial byte output is flushed to the file,
+ padded with 0 bits as necessary. */
+ if (bits_used > 0)
+ output_bits(BITS_IN_BYTE, 0);
+
+ /* N.B. this is necessary! */
+ (void) fflush(file);
+
+ /* Now fix up the second 8-byte value in tjhe file. */
+
+ if (lseek(fileno(file), (off_t) sizeof(Ordinal), SEEK_SET) == -1)
+ warning(_("can not seek in file: %s"), strerror(errno));
+ else
+ {
+ bits_used = 0;
+ byte = 0;
+ output_ordinal(last_instr_count);
+
+ /* Make sure the last byte is flushed. */
+ output_bits(1, 0);
+ }
+
+ (void) fclose(file);
+ file = NULL;
+ }
+}
+
+
+/* Start decoding trace data from the named file.
+ Retrieve the first and last instruction ordinal positions. */
+
+Boolean
+arc_start_decoding (const char *filename,
+ Ordinal *first_instr_count,
+ Ordinal *last_instr_count)
+{
+ ENTERARGS("filename = %s", filename);
+
+ /* The first attempt to input a bit will result in a read from the file. */
+ bits_used = BITS_IN_BYTE;
+ EOF_detected = FALSE;
+
+ if (open_file(filename, "r"))
+ {
+ *first_instr_count = input_ordinal();
+ *last_instr_count = input_ordinal();
+
+ DEBUG("first = %llu, last = %llu\n", *first_instr_count, *last_instr_count);
+
+ return !EOF_detected;
+ }
+
+ return FALSE;
+}
+
+
+/* Stop decoding trace data from the file. */
+
+void
+arc_stop_decoding (void)
+{
+ if (file)
+ {
+ if (bits_used < BITS_IN_BYTE)
+ fprintf(stderr, "all data not processed!\n");
+
+ (void) fclose(file);
+ file = NULL;
+ }
+}
+
+
+/* Write a PC value into the file with the specified encoding. */
+
+void
+arc_encode_PC (ARC_ProgramCounterEncoding encoding, unsigned int value)
+{
+// printf("%d:%x\n", encoding, value);
+
+ output_bits(3, (unsigned int) encoding);
+
+ switch (encoding)
+ {
+ case NO_CHANGE:
+ case PLUS_16_BITS:
+ case PLUS_32_BITS:
+ case PLUS_48_BITS:
+ case PLUS_64_BITS:
+ break;
+ case DELTA_16_BIT_POSITIVE:
+ case DELTA_16_BIT_NEGATIVE:
+ output_bits(16, value);
+ break;
+ case ABSOLUTE_31_BITS:
+ output_bits(31, value);
+ break;
+ }
+}
+
+
+/* Read a PC value and its encoding from the file.
+ Return TRUE if a value could be read, FALSE otherwise. */
+
+Boolean
+arc_decode_PC (ARC_ProgramCounterEncoding *encoding, unsigned int *value)
+{
+ unsigned int code = input_bits(3);
+
+ if (EOF_detected)
+ return FALSE;
+
+ *encoding = (ARC_ProgramCounterEncoding) code;
+
+ switch (*encoding)
+ {
+ case NO_CHANGE:
+ case PLUS_16_BITS:
+ case PLUS_32_BITS:
+ case PLUS_48_BITS:
+ case PLUS_64_BITS:
+ *value = 0;
+ break;
+ case DELTA_16_BIT_POSITIVE:
+ case DELTA_16_BIT_NEGATIVE:
+ *value = input_bits(16);
+ break;
+ case ABSOLUTE_31_BITS:
+ *value = input_bits(31);
+ break;
+ }
+
+ if (EOF_detected)
+ return FALSE;
+
+// printf("%d:%x\n", *encoding, *value);
+
+ return TRUE;
+}
+
+/******************************************************************************/