Asm/src/format.c

287 lines
7.0 KiB
C

/* $Id$ */
/* Copyright (c) 2011 Pierre Pronchery <khorben@defora.org> */
/* This file is part of DeforaOS Devel asm */
/* 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, version 3 of the License.
*
* 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/>. */
#include <System.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "Asm/format.h"
#include "format.h"
#include "../config.h"
/* Format */
/* private */
/* types */
struct _Format
{
char * arch;
FormatPluginHelper helper;
Plugin * handle;
FormatPlugin * plugin;
/* internal */
/* file */
char const * filename;
FILE * fp;
/* deassembly */
Code * code;
};
/* prototypes */
/* callbacks */
static char const * _format_get_filename(Format * format);
static ssize_t _format_read(Format * format, void * buf, size_t size);
static off_t _format_seek(Format * format, off_t offset, int whence);
static ssize_t _format_write(Format * format, void const * buf, size_t size);
/* public */
/* functions */
/* format_new */
Format * format_new(char const * format, char const * arch)
{
Format * f;
Plugin * handle;
FormatPlugin * plugin;
if(format == NULL)
{
error_set_code(1, "%s", strerror(EINVAL));
return NULL;
}
if((handle = plugin_new(LIBDIR, PACKAGE, "format", format)) == NULL)
return NULL;
if((plugin = plugin_lookup(handle, "format_plugin")) == NULL
|| (f = object_new(sizeof(*f))) == NULL)
{
plugin_delete(handle);
return NULL;
}
f->arch = string_new(arch);
memset(&f->helper, 0, sizeof(f->helper));
f->plugin = plugin;
f->handle = handle;
if(f->arch == NULL)
{
format_delete(f);
return NULL;
}
return f;
}
/* format_delete */
void format_delete(Format * format)
{
plugin_delete(format->handle);
string_delete(format->arch);
object_delete(format);
}
/* accessors */
/* format_get_name */
char const * format_get_name(Format * format)
{
return format->plugin->name;
}
/* useful */
/* format_decode */
static int _decode_callback(Format * format, char const * section,
off_t offset, size_t size, off_t base);
static AsmString * _get_string_by_id_callback(Format * format, AsmId id);
static int _set_function_callback(Format * format, int id, char const * name,
off_t offset, ssize_t size);
static int _set_string_callback(Format * format, int id, char const * name,
off_t offset, ssize_t size);
int format_decode(Format * format, Code * code)
{
int ret;
if(format->plugin->decode == NULL)
return error_set_code(1, "%s: %s", format_get_name(format),
"Disassembly is not supported");
format->helper.decode = _decode_callback;
format->helper.get_string_by_id = _get_string_by_id_callback;
format->helper.set_function = _set_string_callback;
format->helper.set_string = _set_string_callback;
format->code = code;
ret = format->plugin->decode(format->plugin);
format->code = NULL;
format->helper.set_string = NULL;
format->helper.set_function = NULL;
format->helper.get_string_by_id = NULL;
format->helper.decode = NULL;
return ret;
}
static int _decode_callback(Format * format, char const * section,
off_t offset, size_t size, off_t base)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\", 0x%lx, 0x%lx, 0x%lx)\n", __func__,
section, offset, size, base);
#endif
return code_decode_at(format->code, section, offset, size, base);
}
static AsmString * _get_string_by_id_callback(Format * format, AsmId id)
{
return code_get_string_by_id(format->code, id);
}
static int _set_function_callback(Format * format, int id, char const * name,
off_t offset, ssize_t size)
{
return code_set_function(format->code, id, name, offset, size);
}
static int _set_string_callback(Format * format, int id, char const * name,
off_t offset, ssize_t size)
{
return code_set_string(format->code, id, name, offset, size);
}
/* format_exit */
int format_exit(Format * format)
{
int ret = 0;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif
if(format->plugin->exit != NULL)
ret = format->plugin->exit(format->plugin);
format->helper.format = NULL;
format->helper.decode = NULL;
format->helper.read = NULL;
format->helper.seek = NULL;
format->plugin->helper = NULL;
format->fp = NULL;
format->filename = NULL;
return ret;
}
/* format_function */
int format_function(Format * format, char const * function)
{
if(format->plugin->function == NULL)
return 0;
return format->plugin->function(format->plugin, function);
}
/* format_init */
int format_init(Format * format, char const * filename, FILE * fp)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\", %p)\n", __func__, filename,
(void *)fp);
#endif
format->filename = filename;
format->fp = fp;
format->helper.format = format;
format->helper.decode = NULL;
format->helper.get_filename = _format_get_filename;
format->helper.read = _format_read;
format->helper.seek = _format_seek;
format->helper.write = _format_write;
format->plugin->helper = &format->helper;
if(format->plugin->init != NULL)
return format->plugin->init(format->plugin, format->arch);
return 0;
}
/* format_section */
int format_section(Format * format, char const * section)
{
if(format->plugin->section == NULL)
return 0;
return format->plugin->section(format->plugin, section);
}
/* private */
/* functions */
/* format_get_filename */
static char const * _format_get_filename(Format * format)
{
return format->filename;
}
/* format_read */
static ssize_t _format_read(Format * format, void * buf, size_t size)
{
if(fread(buf, size, 1, format->fp) == 1)
return size;
if(ferror(format->fp))
return -error_set_code(1, "%s: %s", format->filename,
strerror(errno));
if(feof(format->fp))
return -error_set_code(1, "%s: %s", format->filename,
"End of file reached");
return -error_set_code(1, "%s: %s", format->filename, "Read error");
}
/* format_seek */
static off_t _format_seek(Format * format, off_t offset, int whence)
{
if(whence == SEEK_SET)
{
if(fseek(format->fp, offset, whence) == 0)
return offset;
}
else if(whence == SEEK_CUR || whence == SEEK_END)
{
if(fseek(format->fp, offset, whence) == 0)
return ftello(format->fp);
}
else
return -error_set_code(1, "%s: %s", format->filename,
"Invalid argument for seeking");
return -error_set_code(1, "%s: %s", format->filename, strerror(errno));
}
/* format_write */
static ssize_t _format_write(Format * format, void const * buf, size_t size)
{
if(fwrite(buf, size, 1, format->fp) == 1)
return size;
if(ferror(format->fp))
return -error_set_code(1, "%s: %s", format->filename,
strerror(errno));
if(feof(format->fp))
return -error_set_code(1, "%s: %s", format->filename,
"End of file reached");
return -error_set_code(1, "%s: %s", format->filename, "Write error");
}