Asm

/* $Id$ */
/* Copyright (c) 2011-2018 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 Lesser 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* TODO:
* - lookup if a symbol is defined for each offset
* - derive functions/labels/etc from symbols (type, id, name, union) */
#include <System.h>
#include <sys/utsname.h>
#include <assert.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include "arch.h"
#include "format.h"
#include "code.h"
#include "../config.h"
/* AsmCode */
/* private */
/* types */
struct _AsmCode
{
AsmArch * arch;
AsmFormat * format;
char * filename;
FILE * fp;
/* elements */
AsmElement * elements[AET_COUNT];
size_t elements_cnt[AET_COUNT];
};
/* prototypes */
/* useful */
/* elements */
static void _asmcode_element_delete_all(AsmCode * code, AsmElementType type);
static AsmElement * _asmcode_element_get_by_id(AsmCode * code,
AsmElementType type, AsmElementId id);
static int _asmcode_element_set(AsmElement * element, AsmElementId id,
unsigned int flags, char const * name, off_t offset,
ssize_t size, off_t base);
/* functions */
static void _asmcode_function_delete_all(AsmCode * code);
static AsmFunction * _asmcode_function_get_by_id(AsmCode * code,
AsmFunctionId id);
static int _asmcode_function_set(AsmFunction * codefunction, AsmFunctionId id,
char const * name, off_t offset, ssize_t size);
static AsmFunction * _asmcode_function_append(AsmCode * code);
/* sections */
static AsmSection * _asmcode_section_get_by_id(AsmCode * code, AsmSectionId id);
static int _asmcode_section_set(AsmSection * section, int id,
unsigned int flags, char const * name,
off_t offset, ssize_t size, off_t base);
static AsmSection * _asmcode_section_append(AsmCode * code);
/* strings */
static void _asmcode_string_delete_all(AsmCode * code);
static AsmString * _asmcode_string_get_by_id(AsmCode * code, AsmStringId id);
static int _asmcode_string_set(AsmCode * code, AsmString * codestring,
int id, char const * name, off_t offset, ssize_t length);
static AsmString * _asmcode_string_append(AsmCode * code);
static int _asmcode_string_read(AsmCode * code, AsmString * codestring);
/* symbols */
static void _asmcode_symbol_delete_all(AsmCode * code);
static AsmSymbol * _asmcode_symbol_get_by_id(AsmCode * code, AsmSymbolId id);
static int _asmcode_symbol_set(AsmCode * code, AsmSymbol * symbol,
int id, char const * name, off_t offset, ssize_t length);
static AsmSymbol * _asmcode_symbol_append(AsmCode * code);
static int _asmcode_symbol_read(AsmCode * code, AsmSymbol * symbol);
/* functions */
/* asmcode_new */
static char const * _new_arch(void);
static char const * _new_arch_from_format(AsmCode * code, char const * format);
AsmCode * asmcode_new(char const * arch, char const * format)
{
AsmCode * code;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\", \"%s\")\n", __func__, arch, format);
#endif
if((code = object_new(sizeof(*code))) == NULL)
return NULL;
memset(code, 0, sizeof(*code));
/* guess the architecture if necessary */
if(arch == NULL)
{
arch = (format != NULL) ? _new_arch_from_format(code, format)
: _new_arch();
if(arch == NULL)
{
asmcode_delete(code);
return NULL;
}
}
code->arch = arch_new(arch);
if(format != NULL && code->format == NULL)
code->format = format_new(format);
if(code->arch == NULL)
{
asmcode_delete(code);
return NULL;
}
return code;
}
static char const * _new_arch(void)
{
static struct utsname uts;
static int cached = 0;
if(cached == 0)
{
if(uname(&uts) != 0)
{
error_set_code(-errno, "%s", strerror(errno));
return NULL;
}
cached = 1;
}
return uts.machine;
}
static char const * _new_arch_from_format(AsmCode * code, char const * format)
{
char const * arch;
if((code->format = format_new(format)) == NULL)
return NULL;
if((arch = _new_arch()) != NULL)
arch = format_guess_arch(code->format, arch);
if(arch == NULL)
arch = format_guess_arch(code->format, NULL);
return arch;
}
/* asmcode_new_file */
AsmCode * asmcode_new_file(char const * arch, char const * format,
char const * filename)
{
AsmCode * code;
FILE * fp;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, filename);
#endif
if((fp = fopen(filename, "r")) == NULL)
{
error_set_code(-errno, "%s: %s", filename, strerror(errno));
return NULL;
}
if((code = object_new(sizeof(*code))) == NULL)
{
fclose(fp);
return NULL;
}
memset(code, 0, sizeof(*code));
if(filename != NULL)
code->filename = string_new(filename);
if(format == NULL)
code->format = format_new_match(filename, fp);
else if((code->format = format_new(format)) != NULL
&& format_init(code->format, NULL, filename, fp) != 0)
{
format_delete(code->format);
code->format = NULL;
}
if(arch == NULL && code->format != NULL)
arch = format_detect_arch(code->format);
if(arch != NULL && (code->arch = arch_new(arch)) != NULL
&& arch_init(code->arch, filename, fp) != 0)
{
arch_delete(code->arch);
code->arch = NULL;
}
if((filename != NULL && code->filename == NULL)
|| code->arch == NULL || code->format == NULL)
{
asmcode_delete(code);
return NULL;
}
return code;
}
/* asmcode_delete */
int asmcode_delete(AsmCode * code)
{
int ret = 0;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif
if(code->format != NULL)
format_delete(code->format);
if(code->arch != NULL)
arch_delete(code->arch);
if(code->fp != NULL && fclose(code->fp) != 0)
ret |= -error_set_code(-errno, "%s%s%s",
(code->filename != NULL) ? code->filename : "",
(code->filename != NULL) ? ": " : "",
strerror(errno));
string_delete(code->filename);
object_delete(code);
return ret;
}
/* accessors */
/* asmcode_get_arch */
char const * asmcode_get_arch(AsmCode * code)
{
return arch_get_name(code->arch);
}
/* asmcode_get_arch_definition */
AsmArchDefinition const * asmcode_get_arch_definition(AsmCode * code)
{
return arch_get_definition(code->arch);
}
/* asmcode_get_arch_description */
char const * asmcode_get_arch_description(AsmCode * code)
{
return arch_get_description(code->arch);
}
/* asmcode_get_arch_instruction_by_name */
AsmArchInstruction const * asmcode_get_arch_instruction_by_name(AsmCode * code,
char const * name)
{
return arch_get_instruction_by_name(code->arch, name);
}
/* asmcode_get_arch_instructions */
AsmArchInstruction const * asmcode_get_arch_instructions(AsmCode * code)
{
return arch_get_instructions(code->arch);
}
/* asmcode_get_arch_prefix_by_name */
AsmArchPrefix const * asmcode_get_arch_prefix_by_name(AsmCode * code,
char const * name)
{
return arch_get_prefix_by_name(code->arch, name);
}
/* asmcode_get_arch_prefixes */
AsmArchPrefix const * asmcode_get_arch_prefixes(AsmCode * code)
{
return arch_get_prefixes(code->arch);
}
/* asmcode_get_arch_registers */
AsmArchRegister const * asmcode_get_arch_registers(AsmCode * code)
{
return arch_get_registers(code->arch);
}
/* asmcode_get_filename */
char const * asmcode_get_filename(AsmCode * code)
{
return code->filename;
}
/* asmcode_get_format */
char const * asmcode_get_format(AsmCode * code)
{
if(code->format == NULL)
return arch_get_format(code->arch);
return format_get_name(code->format);
}
/* asmcode_get_format_description */
char const * asmcode_get_format_description(AsmCode * code)
{
if(code->format == NULL)
return NULL;
return format_get_description(code->format);
}
/* asmcode_get_function_by_id */
AsmFunction * asmcode_get_function_by_id(AsmCode * code, AsmFunctionId id)
{
return _asmcode_element_get_by_id(code, AET_FUNCTION, id);
}
/* asmcode_get_functions */
void asmcode_get_functions(AsmCode * code, AsmFunction ** functions,
size_t * functions_cnt)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif
*functions = code->elements[AET_FUNCTION];
*functions_cnt = code->elements_cnt[AET_FUNCTION];
}
/* asmcode_get_section_by_id */
AsmSection * asmcode_get_section_by_id(AsmCode * code, AsmSectionId id)
{
return _asmcode_element_get_by_id(code, AET_SECTION, id);
}
/* asmcode_get_sections */
void asmcode_get_sections(AsmCode * code, AsmSection ** sections,
size_t * sections_cnt)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif
*sections = code->elements[AET_SECTION];
*sections_cnt = code->elements_cnt[AET_SECTION];
}
/* asmcode_get_string_by_id */
AsmString * asmcode_get_string_by_id(AsmCode * code, AsmStringId id)
{
return _asmcode_element_get_by_id(code, AET_STRING, id);
}
/* asmcode_get_strings */
void asmcode_get_strings(AsmCode * code, AsmString ** strings,
size_t * strings_cnt)
{
*strings = code->elements[AET_STRING];
*strings_cnt = code->elements_cnt[AET_STRING];
}
/* asmcode_set_function */
AsmFunction * asmcode_set_function(AsmCode * code, int id, char const * name,
off_t offset, ssize_t size)
{
AsmFunction * ret = NULL;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%d, \"%s\", %ld, %ld)\n", __func__, id, name,
offset, size);
#endif
if(id >= 0)
ret = _asmcode_function_get_by_id(code, id);
if(ret == NULL)
ret = _asmcode_function_append(code);
if(ret == NULL || _asmcode_function_set(ret, id, name, offset, size)
!= 0)
return NULL;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() => %d\n", __func__, ret->id);
#endif
return ret;
}
/* asmcode_set_section */
AsmSection * asmcode_set_section(AsmCode * code, int id, unsigned int flags,
char const * name, off_t offset, ssize_t size, off_t base)
{
AsmSection * ret = NULL;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%d, \"%s\", %ld, %ld)\n", __func__, id, name,
offset, size);
#endif
if(id >= 0)
ret = _asmcode_section_get_by_id(code, id);
if(ret == NULL)
ret = _asmcode_section_append(code);
if(ret == NULL || _asmcode_section_set(ret, id, flags, name,
offset, size, base) != 0)
return NULL;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() => %d\n", __func__, ret->id);
#endif
return ret;
}
/* asmcode_set_string */
AsmString * asmcode_set_string(AsmCode * code, int id, char const * name,
off_t offset, ssize_t length)
{
AsmString * ret = NULL;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(0x%x)\n", __func__, id);
#endif
if(id >= 0)
ret = _asmcode_string_get_by_id(code, id);
if(ret == NULL)
ret = _asmcode_string_append(code);
if(ret == NULL || _asmcode_string_set(code, ret, id, name, offset,
length) != 0)
return NULL;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s() => %d\n", __func__, ret->id);
#endif
return ret;
}
/* useful */
/* asmcode_close */
int asmcode_close(AsmCode * code)
{
int ret = 0;
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s()\n", __func__);
#endif
ret |= arch_exit(code->arch);
if(code->format != NULL)
ret |= format_exit(code->format);
if(code->fp != NULL && fclose(code->fp) != 0 && ret == 0)
ret |= -error_set_code(-errno, "%s: %s", code->filename,
strerror(errno));
code->fp = NULL;
_asmcode_symbol_delete_all(code);
_asmcode_string_delete_all(code);
_asmcode_function_delete_all(code);
return ret;
}
/* asmcode_decode */
int asmcode_decode(AsmCode * code, int raw)
{
return format_decode(code->format, code, raw);
}
/* asmcode_decode_at */
int asmcode_decode_at(AsmCode * code, off_t offset, size_t size, off_t base,
AsmArchInstructionCall ** calls, size_t * calls_cnt)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(%ld, %lu, %ld)\n", __func__, offset, size,
base);
#endif
if(arch_decode_at(code->arch, code, offset, size, base, calls,
calls_cnt) != 0)
return -1;
return 0;
}
/* asmcode_decode_buffer */
int asmcode_decode_buffer(AsmCode * code, char const * buffer, size_t size,
AsmArchInstructionCall ** calls, size_t * calls_cnt)
{
int ret;
arch_init_buffer(code->arch, buffer, size);
ret = arch_decode(code->arch, code, 0, calls, calls_cnt);
arch_exit(code->arch);
return ret;
}
/* asmcode_decode_section */
int asmcode_decode_section(AsmCode * code, AsmSection * section,
AsmArchInstructionCall ** calls, size_t * calls_cnt)
{
return format_decode_section(code->format, code, section, calls,
calls_cnt);
}
/* asmcode_directive */
int asmcode_directive(AsmCode * code, char const * name, char const ** args,
size_t args_cnt)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, name);
#endif
return format_directive(code->format, name, args, args_cnt);
}
/* asmcode_function */
int asmcode_function(AsmCode * code, char const * name)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, name);
#endif
return format_function(code->format, name);
}
/* asmcode_instruction */
int asmcode_instruction(AsmCode * code, AsmArchInstructionCall * call)
{
AsmArchPrefix const * ap = NULL;
AsmArchInstruction const * ai;
if(call->prefix != NULL
&& (ap = arch_get_prefix_by_call(code->arch,
call)) == NULL)
return -1;
if((ai = arch_get_instruction_by_call(code->arch, call)) == NULL)
return -1;
#ifdef DEBUG
fprintf(stderr, "DEBUG: instruction %s, opcode 0x%x, 1 0x%x, 2 0x%x"
", 3 0x%x\n", call->name, ai->opcode, ai->op1, ai->op2,
ai->op3);
#endif
return arch_encode(code->arch, ap, ai, call);
}
/* asmcode_open */
int asmcode_open(AsmCode * code, char const * filename)
{
int ret;
FILE * fp;
if(code->filename != NULL || code->fp != NULL)
return -error_set_code(1, "A file is already opened");
if((fp = fopen(filename, "w+")) == NULL)
return -error_set_code(-errno, "%s: %s", filename,
strerror(errno));
if((ret = asmcode_open_file(code, filename, fp)) == 0)
return 0;
fclose(fp);
unlink(filename); /* XXX may fail */
return ret;
}
/* asmcode_open_file */
int asmcode_open_file(AsmCode * code, char const * filename, FILE * fp)
{
String * p = NULL;
String const * arch;
String const * format;
if(fp == NULL)
return -error_set_code(-EINVAL, "%s", strerror(EINVAL));
if(code->filename != NULL || code->fp != NULL)
return -error_set_code(1, "%s", "A file is already opened");
if(filename != NULL && (p = string_new(filename)) == NULL)
return -1;
if(arch_init(code->arch, p, fp) == 0)
{
arch = arch_get_name(code->arch);
format = arch_get_format(code->arch);
if(code->format == NULL)
code->format = format_new(format);
if(code->format != NULL
&& format_init(code->format, arch, p, fp) == 0)
{
code->filename = p;
code->fp = fp;
return 0;
}
if(code->format != NULL)
format_exit(code->format);
code->format = NULL;
arch_exit(code->arch);
}
string_delete(p);
return -1;
}
/* asmcode_print */
static void _print_address(AsmArchDefinition const * definition,
unsigned long address);
static void _print_immediate(AsmArchOperand * ao);
int asmcode_print(AsmCode * code, AsmArchInstructionCall * call)
{
AsmArchDefinition const * definition;
char const * sep = " ";
size_t i;
uint8_t u8;
AsmArchOperand * ao;
char const * name;
definition = arch_get_definition(code->arch);
if(arch_seek(code->arch, call->offset, SEEK_SET) < 0)
return -1;
_print_address(definition, call->base);
for(i = 0; i < call->size; i++)
{
if(arch_read(code->arch, &u8, sizeof(u8)) != sizeof(u8))
return -1;
printf(" %02x", u8);
}
/* FIXME print on the following line if it was too long */
for(; i < 8; i++)
fputs(" ", stdout);
i = printf("%s%s %s", (call->prefix != NULL) ? " " : "",
(call->prefix != NULL) ? call->prefix : "", call->name);
for(; call->operands_cnt > 0 && i < 12; i++)
fputs(" ", stdout);
for(i = 0; i < call->operands_cnt; i++)
{
ao = &call->operands[i];
fputs(sep, stdout);
switch(AO_GET_TYPE(ao->definition))
{
case AOT_DREGISTER:
name = ao->value.dregister.name;
if(ao->value.dregister.offset == 0)
{
printf("[%%%s]", name);
break;
}
printf("[%%%s + $0x%lx]", name, (unsigned long)
ao->value.dregister.offset);
break;
case AOT_DREGISTER2:
name = ao->value.dregister2.name;
printf("[%%%s + %%%s]", name,
ao->value.dregister2.name2);
break;
case AOT_IMMEDIATE:
_print_immediate(ao);
break;
case AOT_REGISTER:
name = call->operands[i].value._register.name;
printf("%%%s", name);
break;
}
sep = ", ";
}
putchar('\n');
return 0;
}
static void _print_address(AsmArchDefinition const * definition,
unsigned long address)
{
uint32_t size = (definition != NULL) ? definition->address_size : 32;
char const * format;
/* FIXME use if-else-if and ranges instead */
switch(size)
{
case 64:
format = "%16lx:";
break;
case 20:
format = "%5lx:";
break;
case 32:
default:
format = "%8lx:";
break;
}
printf(format, address);
}
static void _print_immediate(AsmArchOperand * ao)
{
printf("%s$0x%lx", ao->value.immediate.negative ? "-" : "",
(unsigned long)ao->value.immediate.value);
if(AO_GET_VALUE(ao->definition) == AOI_REFERS_STRING)
{
if(ao->value.immediate.name != NULL)
printf(" \"%s\"", ao->value.immediate.name);
else
printf("%s", " (string)");
}
else if(AO_GET_VALUE(ao->definition) == AOI_REFERS_FUNCTION)
{
if(ao->value.immediate.name != NULL)
printf(" (call \"%s\")", ao->value.immediate.name);
else
printf("%s", " (call)");
}
}
/* asmcode_section */
int asmcode_section(AsmCode * code, char const * name)
{
#ifdef DEBUG
fprintf(stderr, "DEBUG: %s(\"%s\")\n", __func__, name);
#endif
return format_section(code->format, name);
}
/* private */
/* useful */
/* elements */
/* asmcode_element_set */
static int _asmcode_element_set(AsmElement * element, AsmElementId id,
unsigned int flags, char const * name,
off_t offset, ssize_t size, off_t base)
{
char * p = NULL;
if(name != NULL && (p = string_new(name)) == NULL)
return -1;
element->id = id;
element->flags = flags;
free(element->name);
element->name = p;
element->offset = offset;
element->size = size;
element->base = base;
return 0;
}
static AsmElement * _asmcode_element_append(AsmCode * code, AsmElementType type)
{
AsmElement * p = code->elements[type];
size_t cnt = code->elements_cnt[type];
if((p = realloc(p, sizeof(*p) * (cnt + 1))) == NULL)
{
error_set_code(-errno, "%s", strerror(errno));
return NULL;
}
code->elements[type] = p;
p = &code->elements[type][cnt];
code->elements_cnt[type]++;
p->id = -1;
p->name = NULL;
p->offset = -1;
p->size = -1;
return p;
}
static void _asmcode_element_delete_all(AsmCode * code, AsmElementType type)
{
size_t i;
for(i = 0; i < code->elements_cnt[type]; i++)
free(code->elements[type][i].name);
code->elements_cnt[type] = 0;
free(code->elements[type]);
code->elements[type] = NULL;
}
static AsmElement * _asmcode_element_get_by_id(AsmCode * code,
AsmElementType type, AsmElementId id)
{
size_t i;
for(i = 0; i < code->elements_cnt[type]; i++)
if(code->elements[type][i].id >= 0
&& code->elements[type][i].id == id)
return &code->elements[type][i];
return NULL;
}
/* functions */
/* asmcode_function_delete_all */
static void _asmcode_function_delete_all(AsmCode * code)
{
_asmcode_element_delete_all(code, AET_FUNCTION);
}
/* asmcode_function_get_by_id */
static AsmFunction * _asmcode_function_get_by_id(AsmCode * code,
AsmFunctionId id)
{
return _asmcode_element_get_by_id(code, AET_FUNCTION, id);
}
/* asmcode_function_set */
static int _asmcode_function_set(AsmFunction * codefunction, AsmFunctionId id,
char const * name, off_t offset, ssize_t size)
{
char * p = NULL;
if(name != NULL && (p = string_new(name)) == NULL)
return -error_set_code(-errno, "%s", strerror(errno));
codefunction->id = id;
free(codefunction->name);
codefunction->name = p;
codefunction->offset = offset;
codefunction->size = size;
return 0;
}
/* asmcode_function_append */
static AsmFunction * _asmcode_function_append(AsmCode * code)
{
return _asmcode_element_append(code, AET_FUNCTION);
}
/* sections */
/* asmcode_section_get_by_id */
static AsmSection * _asmcode_section_get_by_id(AsmCode * code, AsmSectionId id)
{
return _asmcode_element_get_by_id(code, AET_SECTION, id);
}
/* asmcode_section_set */
static int _asmcode_section_set(AsmSection * section, int id,
unsigned int flags, char const * name,
off_t offset, ssize_t size, off_t base)
{
return _asmcode_element_set(section, id, flags, name,
offset, size, base);
}
/* asmcode_section_append */
static AsmSection * _asmcode_section_append(AsmCode * code)
{
return _asmcode_element_append(code, AET_SECTION);
}
/* strings */
/* asmcode_string_delete_all */
static void _asmcode_string_delete_all(AsmCode * code)
{
_asmcode_element_delete_all(code, AET_STRING);
}
/* asmcode_string_get_by_id */
static AsmString * _asmcode_string_get_by_id(AsmCode * code, AsmStringId id)
{
AsmString * ret;
if((ret = _asmcode_element_get_by_id(code, AET_STRING, id)) == NULL)
return NULL;
if(ret->name == NULL && ret->size > 0)
_asmcode_string_read(code, ret);
return ret;
}
/* asmcode_string_set */
static int _asmcode_string_set(AsmCode * code, AsmString * codestring, int id,
char const * name, off_t offset, ssize_t length)
{
if(_asmcode_element_set(codestring, id, 0, name,
offset, length, 0) != 0)
return -1;
if(name == NULL && length > 0)
_asmcode_string_read(code, codestring);
return 0;
}
/* asmcode_string_append */
static AsmString * _asmcode_string_append(AsmCode * code)
{
return _asmcode_element_append(code, AET_STRING);
}
/* asmcode_string_read */
static int _asmcode_string_read(AsmCode * code, AsmString * codestring)
{
off_t offset; /* XXX should not have to be kept */
char * buf;
/* FIXME if offset < 0 read until '\0' */
if(codestring->offset < 0 || codestring->size < 0)
return -error_set_code(1, "%s", "Insufficient information to"
" read string");
if((offset = arch_seek(code->arch, 0, SEEK_CUR)) < 0)
return -1;
if((buf = malloc(codestring->size + 1)) == NULL)
return -error_set_code(-errno, "%s", strerror(errno));
if(arch_seek(code->arch, codestring->offset, SEEK_SET)
!= codestring->offset)
return -1;
if(arch_read(code->arch, buf, codestring->size) != codestring->size)
{
free(buf);
arch_seek(code->arch, offset, SEEK_SET);
return -1;
}
buf[codestring->size] = '\0';
free(codestring->name);
codestring->name = buf;
return arch_seek(code->arch, offset, SEEK_SET);
}
/* symbols */
/* asmcode_symbol_delete_all */
static void _asmcode_symbol_delete_all(AsmCode * code)
{
_asmcode_element_delete_all(code, AET_SYMBOL);
}
/* asmcode_symbol_get_by_id */
static AsmSymbol * _asmcode_symbol_get_by_id(AsmCode * code, AsmSymbolId id)
{
AsmSymbol * ret;
if((ret = _asmcode_element_get_by_id(code, AET_SYMBOL, id)) == NULL)
return NULL;
if(ret->name == NULL && ret->size > 0)
_asmcode_symbol_read(code, ret);
return ret;
}
/* asmcode_symbol_set */
static int _asmcode_symbol_set(AsmCode * code, AsmSymbol * symbol, int id,
char const * name, off_t offset, ssize_t length)
{
if(_asmcode_element_set(symbol, id, 0, name,
offset, length, 0) != 0)
return -1;
if(name == NULL && length > 0)
_asmcode_symbol_read(code, symbol);
return 0;
}
/* asmcode_symbol_append */
static AsmSymbol * _asmcode_symbol_append(AsmCode * code)
{
return _asmcode_element_append(code, AET_SYMBOL);
}
/* asmcode_symbol_read */
static int _asmcode_symbol_read(AsmCode * code, AsmSymbol * symbol)
{
off_t offset; /* XXX should not have to be kept */
char * buf;
/* FIXME if offset < 0 read until '\0' */
if(symbol->offset < 0 || symbol->size < 0)
return -error_set_code(1, "%s", "Insufficient information to"
" read symbol");
if((offset = arch_seek(code->arch, 0, SEEK_CUR)) < 0)
return -1;
if((buf = malloc(symbol->size + 1)) == NULL)
return -error_set_code(-errno, "%s", strerror(errno));
if(arch_seek(code->arch, symbol->offset, SEEK_SET)
!= symbol->offset)
return -1;
if(arch_read(code->arch, buf, symbol->size) != symbol->size)
{
free(buf);
arch_seek(code->arch, offset, SEEK_SET);
return -1;
}
buf[symbol->size] = '\0';
free(symbol->name);
symbol->name = buf;
return arch_seek(code->arch, offset, SEEK_SET);
}