/* $Id$ */ /* Copyright (c) 2011-2018 Pierre Pronchery */ /* 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 . */ /* TODO: * - lookup if a symbol is defined for each offset * - derive functions/labels/etc from symbols (type, id, name, union) */ #include #include #include #include #include #include #include #include #include #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); }