/* $Id$ */ /* Copyright (c) 2011-2022 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 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 . */ #include #include #include #include #include #include #include #include "Asm.h" #ifndef PROGNAME_DEASM # define PROGNAME_DEASM "deasm" #endif /* deasm */ /* private */ /* prototypes */ static int _deasm(char const * arch, char const * format, char const * filename, int raw); static int _deasm_buffer(char const * arch, char const * buffer, size_t size); static int _deasm_string(char const * arch, char const * format, char const * string); static int _deasm_list(void); static int _usage(void); /* functions */ /* deasm */ static int _deasm_section(AsmCode * code, AsmSection * section); static int _deasm(char const * arch, char const * format, char const * filename, int raw) { int ret = -1; Asm * a; AsmCode * code; AsmSection * sections; size_t sections_cnt; size_t i; if((a = asm_new(arch, format)) == NULL) return -error_print(PROGNAME_DEASM); if((code = asm_open_deassemble(a, filename, raw)) == NULL) error_print(PROGNAME_DEASM); else { ret = 0; printf("%s: %s-%s\n", filename, asm_get_format(a), asm_get_arch(a)); asmcode_get_sections(code, §ions, §ions_cnt); for(i = 0; i < sections_cnt; i++) if((ret = _deasm_section(code, §ions[i])) != 0) break; asm_close(a); } asm_delete(a); return ret; } static int _deasm_section(AsmCode * code, AsmSection * section) { AsmArchDefinition const * definition; size_t size; AsmArchInstructionCall * calls = NULL; size_t calls_cnt = 0; size_t i; printf("\nDisassembly of section %s:\n", section->name); if(asmcode_decode_section(code, section, &calls, &calls_cnt) != 0) { error_print(PROGNAME_DEASM); return -1; } definition = asmcode_get_arch_definition(code); size = (definition != NULL) ? definition->address_size : 32; switch(size) { case 64: printf("\n%016lx:\n", section->base); break; case 20: printf("\n%05lx:\n", section->base); break; case 16: printf("\n%04lx:\n", section->base); break; case 32: default: printf("\n%08lx:\n", section->base); break; } for(i = 0; i < calls_cnt; i++) asmcode_print(code, &calls[i]); free(calls); return 0; } /* deasm_buffer */ static int _deasm_buffer(char const * arch, char const * buffer, size_t size) { Asm * a; AsmCode * code; #ifdef DEBUG fprintf(stderr, "DEBUG: %s()\n", __func__); #endif if((a = asm_new(arch, NULL)) == NULL) return -1; if((code = asm_deassemble(a, buffer, size, NULL, NULL)) == NULL) error_print(PROGNAME_DEASM); else { /* FIXME implement */ } asm_delete(a); return 0; } /* deasm_string */ static int _string_hex2bin(int c); static int _string_ishex(int c); static int _deasm_string(char const * arch, char const * format, char const * string) { int ret; unsigned char * str = (unsigned char *)string; size_t len = strlen(string); char * s; size_t i; size_t j; #ifdef DEBUG fprintf(stderr, "DEBUG: %s(\"%s\", \"%s\", \"%s\")\n", __func__, arch, format, string); #endif if((s = malloc(len + 1)) == NULL) return -error_set_print(PROGNAME_DEASM, 1, "%s", strerror(errno)); for(i = 0, j = 0; i < len; i++) { if(str[i] != '\\') s[j++] = str[i]; else if(str[i + 1] != 'x') /* "\\" */ s[j++] = str[++i]; else if(i + 3 < len && _string_ishex(str[i + 2]) && _string_ishex(str[i + 3])) /* "\xHH" */ { s[j++] = (_string_hex2bin(str[i + 2]) << 4) | _string_hex2bin(str[i + 3]); i += 3; } } s[j] = '\0'; /* not really necessary */ ret = _deasm_buffer(arch, s, j); free(s); return ret; } static int _string_hex2bin(int c) { if(c >= '0' && c <= '9') return c - '0'; if(c >= 'a' && c <= 'f') return c - 'a' + 10; if(c >= 'A' && c <= 'F') return c - 'A' + 10; return -1; } static int _string_ishex(int c) { return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' || c <= 'F'); } /* deasm_list */ static int _deasm_list(void) { int res = 0; #ifdef DEBUG fprintf(stderr, "DEBUG: %s()\n", __func__); #endif if(asm_plugin_list(APT_ARCH, 1) != 0) res = error_print(PROGNAME_DEASM); else putchar('\n'); if(asm_plugin_list(APT_FORMAT, 1) != 0) res = error_print(PROGNAME_DEASM); return (res == 0) ? 0 : 2; } /* usage */ static int _usage(void) { fputs("Usage: " PROGNAME_DEASM " [-a arch][-f format][-D] filename\n" " " PROGNAME_DEASM " [-a arch] -s string\n" " " PROGNAME_DEASM " -l\n" " -a Force the given architecture\n" " -f Force the given file format\n" " -D Disassemble all sections\n" " -l List all the architectures and file formats available\n", stderr); return 1; } /* public */ /* functions */ /* main */ int main(int argc, char * argv[]) { int o; char const * arch = NULL; char const * format = NULL; char const * string = NULL; int raw = 0; while((o = getopt(argc, argv, "a:f:ls:D")) != -1) switch(o) { case 'a': arch = optarg; break; case 'f': format = optarg; break; case 'l': return _deasm_list(); case 's': string = optarg; break; case 'D': raw = 1; break; default: return _usage(); } if(optind == argc && string != NULL) return _deasm_string(arch, format, string); else if(optind + 1 == argc && string == NULL) return (_deasm(arch, format, argv[optind], raw) == 0) ? 0 : 2; return _usage(); }