blob: c22ddb732ec1958d6f096683353922e684f0727f [file] [log] [blame]
/* 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;
}
/******************************************************************************/