diff options
Diffstat (limited to 'gdb/arc-inst-tracing.c')
-rw-r--r-- | gdb/arc-inst-tracing.c | 356 |
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; +} + +/******************************************************************************/ |