mame/src/emu/cpu/x86log.c
Aaron Giles ad4910a8a8 Bulk change alert.
This update changes the way we handle memory allocation. Rather
than allocating in terms of bytes, allocations are now done in
terms of objects. This is done via new set of macros that replace
the malloc_or_die() macro:

  alloc_or_die(t) - allocate memory for an object of type 't'
  alloc_array_or_die(t,c) - allocate memory for an array of 'c' objects of type 't'
  alloc_clear_or_die(t) - same as alloc_or_die but memset's the memory to 0
  alloc_array_clear_or_die(t,c) - same as alloc_array_or_die but memset's the memory to 0

All original callers of malloc_or_die have been updated to call these
new macros. If you just need an array of bytes, you can use
alloc_array_or_die(UINT8, numbytes).

Made a similar change to the auto_* allocation macros. In addition,
added 'machine' as a required parameter to the auto-allocation macros,
as the resource pools will eventually be owned by the machine object.
The new macros are:

  auto_alloc(m,t) - allocate memory for an object of type 't'
  auto_alloc_array(m,t,c) - allocate memory for an array of 'c' objects of type 't'
  auto_alloc_clear(m,t) - allocate and memset
  auto_alloc_array_clear(m,t,c) - allocate and memset

All original calls or auto_malloc have been updated to use the new
macros. In addition, auto_realloc(), auto_strdup(), auto_astring_alloc(),
and auto_bitmap_alloc() have been updated to take a machine parameter.

Changed validity check allocations to not rely on auto_alloc* anymore
because they are not done in the context of a machine.

One final change that is included is the removal of SMH_BANKn macros.
Just use SMH_BANK(n) instead, which is what the previous macros mapped
to anyhow.
2009-04-26 23:54:37 +00:00

318 lines
8.6 KiB
C

/***************************************************************************
x86log.c
x86/x64 code logging helpers.
Copyright Aaron Giles
Released for general use under the MAME license
Visit http://mamedev.org for licensing and usage restrictions.
***************************************************************************/
#include "x86log.h"
#include "mame.h"
#include <stddef.h>
/***************************************************************************
CONSTANTS
***************************************************************************/
/* comment parameters */
#define MAX_COMMENTS 4000
#define MAX_DATA_RANGES 1000
#define COMMENT_POOL_SIZE (MAX_COMMENTS * 40)
/***************************************************************************
TYPE DEFINITIONS
***************************************************************************/
/* code logging info */
typedef struct _log_comment log_comment;
struct _log_comment
{
x86code * base;
const char * string;
};
/* data ranges */
typedef struct _data_range_t data_range_t;
struct _data_range_t
{
x86code * base;
x86code * end;
int size;
};
/* the code logging context */
struct _x86log_context
{
astring * filename; /* name of the file */
FILE * file; /* file we are logging to */
data_range_t data_range[MAX_DATA_RANGES]; /* list of data ranges */
int data_range_count; /* number of data ranges */
log_comment comment_list[MAX_COMMENTS]; /* list of comments */
int comment_count; /* number of live comments */
char comment_pool[COMMENT_POOL_SIZE];/* string pool to hold comments */
char * comment_pool_next; /* pointer to next string pool location */
};
/***************************************************************************
FUNCTION PROTOTYPES
***************************************************************************/
static void reset_log(x86log_context *log);
static int x86log_i386_dasm_one_ex(char *buffer, UINT64 eip, const UINT8 *oprom, int mode);
/***************************************************************************
EXTERNAL INTERFACES
***************************************************************************/
/*-------------------------------------------------
x86log_create_context - create a new context
-------------------------------------------------*/
x86log_context *x86log_create_context(const char *filename)
{
x86log_context *log;
/* allocate the log */
log = alloc_clear_or_die(x86log_context);
/* allocate the filename */
log->filename = astring_dupc(filename);
/* reset things */
reset_log(log);
return log;
}
/*-------------------------------------------------
x86log_free_context - release a context
-------------------------------------------------*/
void x86log_free_context(x86log_context *log)
{
/* close any open files */
if (log->file != NULL)
fclose(log->file);
/* free the structure */
astring_free(log->filename);
free(log);
}
/*-------------------------------------------------
x86log_add_comment - add a comment associated
with a given code pointer
-------------------------------------------------*/
void x86log_add_comment(x86log_context *log, x86code *base, const char *format, ...)
{
char *string = log->comment_pool_next;
log_comment *comment;
va_list va;
assert(log->comment_count < MAX_COMMENTS);
assert(log->comment_pool_next + strlen(format) + 256 < log->comment_pool + COMMENT_POOL_SIZE);
/* we assume comments are registered in order; enforce this */
assert(log->comment_count == 0 || base >= log->comment_list[log->comment_count - 1].base);
/* if we exceed the maxima, skip it */
if (log->comment_count >= MAX_COMMENTS)
return;
if (log->comment_pool_next + strlen(format) + 256 >= log->comment_pool + COMMENT_POOL_SIZE)
return;
/* do the printf to the string pool */
va_start(va, format);
log->comment_pool_next += vsprintf(log->comment_pool_next, format, va) + 1;
va_end(va);
/* fill in the new comment */
comment = &log->comment_list[log->comment_count++];
comment->base = base;
comment->string = string;
}
/*-------------------------------------------------
x86log_mark_as_data - mark a given range as
data for logging purposes
-------------------------------------------------*/
void x86log_mark_as_data(x86log_context *log, x86code *base, x86code *end, int size)
{
data_range_t *data;
assert(log->data_range_count < MAX_DATA_RANGES);
assert(end >= base);
assert(size == 1 || size == 2 || size == 4 || size == 8);
/* we assume data ranges are registered in order; enforce this */
assert(log->data_range_count == 0 || base > log->data_range[log->data_range_count - 1].end);
/* if we exceed the maxima, skip it */
if (log->data_range_count >= MAX_DATA_RANGES)
return;
/* fill in the new range */
data = &log->data_range[log->data_range_count++];
data->base = base;
data->end = end;
data->size = size;
}
/*-------------------------------------------------
x86log_disasm_code_range - disassemble a range
of code and reset accumulated information
-------------------------------------------------*/
void x86log_disasm_code_range(x86log_context *log, const char *label, x86code *start, x86code *stop)
{
const log_comment *lastcomment = &log->comment_list[log->comment_count];
const log_comment *curcomment = &log->comment_list[0];
const data_range_t *lastdata = &log->data_range[log->data_range_count];
const data_range_t *curdata = &log->data_range[0];
x86code *cur = start;
/* print the optional label */
if (label != NULL)
x86log_printf(log, "\n%s\n", label);
/* loop from the start until the cache top */
while (cur < stop)
{
char buffer[100];
int bytes;
/* skip past any past data ranges */
while (curdata < lastdata && cur > curdata->end)
curdata++;
/* skip past any past comments */
while (curcomment < lastcomment && cur > curcomment->base)
curcomment++;
/* if we're in a data range, output the next chunk and continue */
if (cur >= curdata->base && cur <= curdata->end)
{
bytes = curdata->size;
switch (curdata->size)
{
default:
case 1: sprintf(buffer, "db %02X", *cur); break;
case 2: sprintf(buffer, "dw %04X", *(UINT16 *)cur); break;
case 4: sprintf(buffer, "dd %08X", *(UINT32 *)cur); break;
case 8: sprintf(buffer, "dq %08X%08X", ((UINT32 *)cur)[1], ((UINT32 *)cur)[0]); break;
}
}
/* if we're not in the data range, skip filler opcodes */
else if (*cur == 0xcc)
{
cur++;
continue;
}
/* otherwise, do a disassembly of the current instruction */
else
{
#ifdef PTR64
bytes = x86log_i386_dasm_one_ex(buffer, (FPTR)cur, cur, 64) & DASMFLAG_LENGTHMASK;
#else
bytes = x86log_i386_dasm_one_ex(buffer, (FPTR)cur, cur, 32) & DASMFLAG_LENGTHMASK;
#endif
}
/* if we have a matching comment, output it */
if (curcomment < lastcomment && cur == curcomment->base)
{
/* if we have additional matching comments at the same address, output them first */
for ( ; curcomment + 1 < lastcomment && cur == curcomment[1].base; curcomment++)
x86log_printf(log, "%p: %-50s; %s\n", cur, "", curcomment->string);
x86log_printf(log, "%p: %-50s; %s\n", cur, buffer, curcomment->string);
}
/* if we don't, just print the disassembly and move on */
else
x86log_printf(log, "%p: %s\n", cur, buffer);
/* advance past this instruction */
cur += bytes;
}
/* reset our state */
reset_log(log);
}
/*-------------------------------------------------
x86log_printf - manually printf information to
the log file
-------------------------------------------------*/
void x86log_printf(x86log_context *log, const char *format, ...)
{
va_list va;
/* open the file, creating it if necessary */
if (log->file == NULL)
log->file = fopen(astring_c(log->filename), "w");
if (log->file == NULL)
return;
/* do the printf */
va_start(va, format);
vfprintf(log->file, format, va);
va_end(va);
/* flush the file */
fflush(log->file);
}
/***************************************************************************
LOCAL FUNCTIONS
***************************************************************************/
/*-------------------------------------------------
reset_log - reset the state of the log
-------------------------------------------------*/
static void reset_log(x86log_context *log)
{
log->data_range_count = 0;
log->comment_count = 0;
log->comment_pool_next = log->comment_pool;
}
/***************************************************************************
DISASSEMBLERS
***************************************************************************/
#define i386_dasm_one x86log_i386_dasm_one
#define i386_dasm_one_ex x86log_i386_dasm_one_ex
#include "cpu/i386/i386dasm.c"