?? htdisasm.cc
字號:
/* * HT Editor * htdisasm.cc * * Copyright (C) 1999-2002 Stefan Weyergraf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * 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, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <cstring>#include "cmds.h"#include "htctrl.h"#include "htdisasm.h"#include "hthist.h"#include "htiobox.h"#include "htmenu.h"#include "httag.h"#include "snprintf.h"#include "x86asm.h"#include "x86dis.h"#include "ppcdis.h"extern "C" {#include "evalx.h"#include "regex.h"}ht_view *htdisasm_init(Bounds *b, File *file, ht_format_group *group){ int t1632;#if 1 Assembler *assembler=new x86asm(X86_OPSIZE32, X86_ADDRSIZE32); x86dis *disassembler=new x86dis(X86_OPSIZE32, X86_ADDRSIZE32);#else Assembler *assembler = NULL; Disassembler *disassembler = new PPCDisassembler(PPC_MODE_32);#endif t1632 = 0; ht_disasm_viewer *v=new ht_disasm_viewer(); v->init(b, DESC_DISASM, VC_EDIT | VC_GOTO | VC_SEARCH, file, group, assembler, disassembler, t1632); ht_disasm_sub *d=new ht_disasm_sub(); d->init(file, 0, file->getSize(), disassembler, false, X86DIS_STYLE_OPTIMIZE_ADDR); v->insertsub(d); return v;}format_viewer_if htdisasm_if = { htdisasm_init, 0};/* * dialog_assemble */ static int opcode_compare(const char *a, const char *b){ int al = strlen(a); int bl = strlen(b); if (al > bl) return 1; else if (al < bl) return -1; else return strcmp(a, b);}void dialog_assemble(ht_format_viewer *f, viewer_pos vaddr, CPU_ADDR cpuaddr, Assembler *a, Disassembler *disasm, const char *default_str, int want_length){ char instr[257] = ""; if (default_str) strcpy(instr, default_str); asm_insn *insn = a->alloc_insn(); asm_code *ac = NULL; while (inputbox(a->get_name(), "~instruction:", instr, 255, HISTATOM_ASSEMBLER)) { if ((a->translate_str(insn, instr)) && (ac = a->encode(insn, 0, cpuaddr))) { break; } else { errorbox("%s: %s", a->get_name(), a->get_error_msg()); } } if (ac) { bool ok=true; asm_code *chosen_ac = ac; if (ac->next) { // choose from list if ambigous Bounds b; b.w = 60; b.h = 15; center_bounds(&b); ht_dialog *dialog = new ht_dialog(); dialog->init(&b, "choose opcode", FS_KILLER | FS_TITLE | FS_MOVE); b.assign(1, 0, 56, 1); ht_listbox_title *text = new ht_listbox_title(); text->init(&b); text->setText(2, "opcode", "disassembly"); dialog->insert(text); b.assign(1, 1, 56, 12); ht_text_listbox *list=new ht_text_listbox(); list->init(&b, 2, 0); list->attachTitle(text); asm_code *ac2 = ac; uint aci = 0; int best = 0; while (ac2) { char s[1024], *tmp = s; for (int i=0; i < ac2->size; i++) { tmp += sprintf(tmp, "%02x ", ac2->data[i]); } if (best == 0 && want_length == ac2->size) { best = aci+1; } const char *tmp2; if (disasm) { dis_insn *o=disasm->decode((byte *)ac2->data, ac2->size, cpuaddr); tmp2 = disasm->strf(o, DIS_STYLE_HEX_NOZEROPAD+DIS_STYLE_HEX_ASMSTYLE, DISASM_STRF_SMALL_FORMAT); } else { tmp2 = "<no disassembler>"; } list->insert_str(aci, s, tmp2); ac2 = ac2->next; aci++; } ht_text_listbox_sort_order so; so.col = 0; so.compare_func = opcode_compare; list->update(); if (best) { list->gotoItemByPosition(best-1); } list->sort(1, &so); if (!best) { list->gotoItemByPosition(0); } dialog->insert(list); int r = dialog->run(0); ok = r; if (r == button_ok) { ht_listbox_data d; ViewDataBuf vdb(list, &d, sizeof d); ht_text_listbox_item *i = (ht_text_listbox_item *)d.data->cursor_ptr; asm_code *ac3 = ac; int ac3i = 0; while (ac3) { if (ac3i == i->id) { chosen_ac = ac3; break; } ac3 = ac3->next; ac3i++; } } dialog->done(); delete dialog; } if (ok) { baseview->sendmsg(cmd_edit_mode_i, f->get_file(), NULL); if (f->get_file() && (f->get_file()->getAccessMode() & IOAM_WRITE)) { f->vwrite(vaddr, chosen_ac->data, chosen_ac->size); } } } free(insn);}/* * CLASS ht_disasm_viewer */void ht_disasm_viewer::init(Bounds *b, const char *desc, int caps, File *file, ht_format_group *format_group, Assembler *a, Disassembler *d, int t){ ht_uformat_viewer::init(b, desc, caps, file, format_group); assem = a; disasm = d; op1632 = t;}void ht_disasm_viewer::done(){ ht_uformat_viewer::done(); delete assem; delete disasm;}int ht_disasm_viewer::get_pindicator_str(char *buf, int max_len){ FileOfs o; if (get_current_offset(&o)) { return ht_snprintf(buf, max_len, " %s 0x%08qx/%qu ", edit() ? "edit" : "view", o, o); } else { return ht_snprintf(buf, max_len, " ? "); }} bool ht_disasm_viewer::get_vscrollbar_pos(int *pstart, int *psize){ FileOfs s=file->getSize(); if (s) { int z = MIN(size.h*16, s-(int)top.line_id.id1); return scrollbar_pos(top.line_id.id1, z, s, pstart, psize); } return false;}void ht_disasm_viewer::handlemsg(htmsg *msg){ switch (msg->msg) { case msg_contextmenuquery: { ht_static_context_menu *m=new ht_static_context_menu(); m->init("~Local-Disasm"); m->insert_entry("~Assemble", "Ctrl+A", cmd_disasm_call_assembler, K_Control_A, 1); // FIXME: wrong implementation m->insert_entry("~Toggle 16/32", NULL, cmd_disasm_toggle1632, 0, 1); msg->msg = msg_retval; msg->data1.ptr = m; return; } case msg_get_scrollinfo: { switch (msg->data1.integer) { case gsi_hscrollbar: { gsi_scrollbar_t *p=(gsi_scrollbar_t*)msg->data2.ptr; if (!get_hscrollbar_pos(&p->pstart, &p->psize)) { p->pstart = 0; p->psize = 100; } clearmsg(msg); return; } case gsi_vscrollbar: { gsi_scrollbar_t *p=(gsi_scrollbar_t*)msg->data2.ptr; if (!get_vscrollbar_pos(&p->pstart, &p->psize)) { p->pstart = 0; p->psize = 100; } clearmsg(msg); return; } } break; } case msg_filesize_changed: { htmsg m; m.msg=msg_filesize_changed; m.type=mt_broadcast; sendsubmsg(&m); // FIXME: hack uf_initialized=false; complete_init(); dirtyview(); return; } case cmd_disasm_call_assembler: { viewer_pos current_pos; get_current_pos(¤t_pos); CPU_ADDR cpuaddr; cpuaddr.addr32.seg = 0; cpuaddr.addr32.offset = current_pos.u.line_id.id1; assem->set_imm_eval_proc(NULL, NULL); byte data[32]; int datalen = vread(current_pos, data, sizeof data); dis_insn *o = disasm->decode(data, datalen, cpuaddr); const char *curinsn = disasm->strf(o, DIS_STYLE_HEX_NOZEROPAD+DIS_STYLE_HEX_ASMSTYLE, DISASM_STRF_SMALL_FORMAT); int want_length = disasm->getSize(o); dialog_assemble(this, current_pos, cpuaddr, assem, disasm, curinsn, want_length); clearmsg(msg); return; } case cmd_disasm_toggle1632: { // FIXME: very beautiful... op1632 ^= 1; if (op1632) { ((x86asm *)assem)->opsize = X86_OPSIZE16; ((x86asm *)assem)->addrsize = X86_ADDRSIZE16; ((x86dis *)disasm)->opsize = X86_OPSIZE16; ((x86dis *)disasm)->addrsize = X86_ADDRSIZE16; } else { ((x86asm *)assem)->opsize = X86_OPSIZE32; ((x86asm *)assem)->addrsize = X86_ADDRSIZE32; ((x86dis *)disasm)->opsize = X86_OPSIZE32; ((x86dis *)disasm)->addrsize = X86_ADDRSIZE32; } dirtyview(); clearmsg(msg); return; } } ht_uformat_viewer::handlemsg(msg);}ht_disasm_sub *ht_disasm_viewer::get_disasm_sub(){ return (ht_disasm_sub*)cursor.sub;}bool ht_disasm_viewer::offset_to_pos(FileOfs ofs, viewer_pos *p){ p->u.sub = get_disasm_sub(); p->u.line_id.id1 = ofs; p->u.line_id.id2 = 0; p->u.tag_idx = 0; return true;}bool ht_disasm_viewer::pos_to_offset(viewer_pos p, FileOfs *ofs){ *ofs = p.u.line_id.id1; return true;}bool ht_disasm_viewer::ref_sel(LINE_ID *id){ return goto_offset(id->id1, true);}bool ht_disasm_viewer::qword_to_pos(uint64 q, viewer_pos *p){ ht_linear_sub *s = get_disasm_sub(); FileOfs ofs = q; clear_viewer_pos(p); p->u.sub = s; p->u.tag_idx = 0; return s->convert_ofs_to_id(ofs, &p->u.line_id);}bool ht_disasm_viewer::symbol_handler(eval_scalar *result, char *name){ if (strcmp(name, "$") == 0) { FileOfs ofs; if (!pos_to_offset(*(viewer_pos*)&cursor, &ofs)) return 0; scalar_create_int_q(result, ofs); return true; } return ht_uformat_viewer::symbol_handler(result, name);}const char *ht_disasm_viewer::func(uint i, bool execute){ switch (i) { // FIXME: wrong implementation case 8: if (execute) sendmsg(cmd_disasm_toggle1632); return op1632 ? (char*)"use32" : (char*)"use16"; } return ht_uformat_viewer::func(i, execute);}/* * CLASS ht_disasm_sub */void ht_disasm_sub::init(File *f, FileOfs ofs, int size, Disassembler *u, bool own_u, int ds){ ht_linear_sub::init(f, ofs, size); disasm = u; own_disasm = own_u; display_style = ds;}void ht_disasm_sub::done(){ if (own_disasm) { delete disasm; } ht_linear_sub::done();}bool ht_disasm_sub::convert_ofs_to_id(const FileOfs offset, LINE_ID *line_id){ if ((offset >= fofs) && (offset < fofs+fsize)) { line_id->id1=offset; line_id->id2=0; return true; } return false;}bool ht_disasm_sub::convert_id_to_ofs(const LINE_ID line_id, FileOfs *offset){ *offset = line_id.id1; return true;}static char *diasm_addr_sym_func(CPU_ADDR Addr, int *symstrlen, void *context){ ht_disasm_sub *sub = (ht_disasm_sub *) context; static char buf[120]; LINE_ID line_id; sub->first_line_id(&line_id); if (Addr.addr32.offset >= line_id.id1) { sub->last_line_id(&line_id); if (Addr.addr32.offset <= line_id.id1) { char buf2[60]; ht_snprintf(buf2, sizeof buf2, "0x%x", Addr.addr32.offset); char *b = tag_make_ref(buf, sizeof buf-1, Addr.addr32.offset, 0, 0, 0, buf2); *b = 0; if (symstrlen) *symstrlen = b-buf; return buf; } } return NULL;}bool ht_disasm_sub::getline(char *line, int maxlen, const LINE_ID line_id){ if (line_id.id2) return false; uint64 ofs = line_id.id1; byte buf[16]; int c = MIN(16, sint64(fofs+fsize-ofs)); if (c <= 0) return false; file->seek(ofs); c = file->read(buf, c); CPU_ADDR caddr; caddr.addr32.seg = 0; caddr.addr32.offset = ofs; const char *s; char *l = line; if (c) { dis_insn *insn = disasm->decode(buf, c, caddr); addr_sym_func_context = this; addr_sym_func = &diasm_addr_sym_func; s = disasm->str(insn, display_style); addr_sym_func = NULL; c = disasm->getSize(insn); } else { s = "db ?"; c = 0; } l += ht_snprintf(l, maxlen, "%08qx ", ofs); for (int i=0; i<15; i++) { if (i<c) { l=tag_make_edit_byte(l, maxlen, ofs+i); } else { *l++=' '; *l++=' '; } } *l++=' '; tag_strcpy(l, maxlen, s); return true;}void ht_disasm_sub::first_line_id(LINE_ID *line_id){ clear_line_id(line_id); line_id->id1 = fofs;}void ht_disasm_sub::last_line_id(LINE_ID *line_id){ clear_line_id(line_id); line_id->id1 = fofs+fsize-1;}int ht_disasm_sub::prev_line_id(LINE_ID *line_id, int n){ if (line_id->id2) return 0; uint32 *ofs=&line_id->id1; int min_length; int max_length; int min_look_ahead; int avg_look_ahead; int addr_align; disasm->getOpcodeMetrics(min_length, max_length, min_look_ahead, avg_look_ahead, addr_align); unsigned char buf[avg_look_ahead*50], *bufp=buf; int offsets[avg_look_ahead*50]; int *of=offsets; int r=n<6 ? 6*avg_look_ahead : n*avg_look_ahead; if (r > (int)sizeof buf) r = sizeof buf; uint32 o=*ofs-r; int c=r, d; int s; if (*ofs<fofs+r) { c-=fofs-o; o=fofs; } if (o+c>fofs+fsize) { c=fofs+fsize-o; } file->seek(o); d=file->read(buf, c); CPU_ADDR caddr; caddr.addr32.seg = 0; caddr.addr32.offset = 0; do { if (d>0) { dis_insn *insn=disasm->decode(bufp, d, caddr); s=disasm->getSize(insn);/* if (s!=4) { insn=disasm->decode(bufp, d, caddr); } assert(s==4);*/ d-=s; } else { s=1; } *(of++)=o; o+=s; bufp+=s; } while (o<=*ofs); if (of-n-1<offsets) { *ofs=*(offsets); return of-offsets-1; } else { *ofs=*(of-n-1); return n; }}int ht_disasm_sub::next_line_id(LINE_ID *line_id, int n){ if (line_id->id2) return 0; uint32 *ofs = &line_id->id1; unsigned char buf[15]; int c=0, s; uint z; CPU_ADDR caddr; caddr.addr32.seg = 0; caddr.addr32.offset = 0; while (n--) { z=MIN(15, (uint)(fofs+fsize-*ofs)); file->seek(*ofs); z=file->read(buf, z); if (z) { dis_insn *insn=disasm->decode(buf, z, caddr); s=disasm->getSize(insn); } else { s=1; } if (*ofs+s>fofs+fsize-1) return c; *ofs+=s; c++; } return c;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -