00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <string.h>
00022
00023 #include "cmds.h"
00024 #include "htctrl.h"
00025 #include "htdisasm.h"
00026 #include "hthist.h"
00027 #include "htiobox.h"
00028 #include "htmenu.h"
00029 #include "httag.h"
00030 #include "x86asm.h"
00031 #include "x86dis.h"
00032 #include "ppcdis.h"
00033
00034 extern "C" {
00035 #include "evalx.h"
00036 #include "regex.h"
00037 }
00038
00039 ht_view *htdisasm_init(bounds *b, ht_streamfile *file, ht_format_group *group)
00040 {
00041 int t1632;
00042 #if 1
00043 Assembler *assembler=new x86asm(X86_OPSIZE32, X86_ADDRSIZE32);
00044 x86dis *disassembler=new x86dis(X86_OPSIZE32, X86_ADDRSIZE32);
00045 #else
00046 Assembler *assembler = NULL;
00047 Disassembler *disassembler = new PPCDisassembler();
00048 #endif
00049 t1632 = 0;
00050
00051 ht_disasm_viewer *v=new ht_disasm_viewer();
00052 v->init(b, DESC_DISASM, VC_EDIT | VC_GOTO | VC_SEARCH, file, group, assembler, disassembler, t1632);
00053
00054 ht_disasm_sub *d=new ht_disasm_sub();
00055 d->init(file, 0, file->get_size(),
00056 disassembler, false, X86DIS_STYLE_OPTIMIZE_ADDR);
00057
00058 v->insertsub(d);
00059 return v;
00060 }
00061
00062 format_viewer_if htdisasm_if = {
00063 htdisasm_init,
00064 0
00065 };
00066
00067
00068
00069
00070
00071 static int opcode_compare(const char *a, const char *b)
00072 {
00073 int al = strlen(a);
00074 int bl = strlen(b);
00075 if (al > bl) return 1; else if (al < bl) return -1; else return strcmp(a, b);
00076 }
00077
00078 void dialog_assemble(ht_format_viewer *f, viewer_pos vaddr, CPU_ADDR cpuaddr, Assembler *a, Disassembler *disasm, const char *default_str, UINT want_length)
00079 {
00080 char instr[257] = "";
00081 if (default_str) strcpy(instr, default_str);
00082 asm_insn *insn = a->alloc_insn();
00083 asm_code *ac = NULL;
00084 while (inputbox(a->get_name(), "~instruction:", instr, 255, HISTATOM_ASSEMBLER)) {
00085 if ((a->translate_str(insn, instr)) && (ac = a->encode(insn, 0, cpuaddr))) {
00086 break;
00087 } else {
00088 errorbox("%s: %s", a->get_name(), a->get_error_msg());
00089 }
00090 }
00091 if (ac) {
00092 bool ok=true;
00093 asm_code *chosen_ac = ac;
00094 if (ac->next) {
00095
00096 bounds b;
00097 b.w = 60;
00098 b.h = 15;
00099 center_bounds(&b);
00100 ht_dialog *dialog = new ht_dialog();
00101 dialog->init(&b, "choose opcode", FS_KILLER | FS_TITLE | FS_MOVE);
00102 BOUNDS_ASSIGN(b, 1, 0, 56, 1);
00103 ht_listbox_title *text = new ht_listbox_title();
00104 text->init(&b);
00105 text->setText(2, "opcode", "disassembly");
00106 dialog->insert(text);
00107 BOUNDS_ASSIGN(b, 1, 1, 56, 12);
00108 ht_text_listbox *list=new ht_text_listbox();
00109 list->init(&b, 2, 0);
00110 list->attachTitle(text);
00111 asm_code *ac2 = ac;
00112 UINT aci = 0;
00113 int best = 0;
00114 while (ac2) {
00115 char s[1024]="", *tmp = s;
00116 for (UINT i=0; i<ac2->size; i++) {
00117 tmp += sprintf(tmp, "%02x ", ac2->data[i]);
00118 }
00119 if ((best == 0) && (want_length == ac2->size)) {
00120 best = aci+1;
00121 }
00122 if (disasm) {
00123 dis_insn *o=disasm->decode((byte *)ac2->data, ac2->size, cpuaddr);
00124 tmp = disasm->strf(o, DIS_STYLE_HEX_NOZEROPAD+DIS_STYLE_HEX_ASMSTYLE, DISASM_STRF_SMALL_FORMAT);
00125 } else {
00126 tmp = "<no disassembler>";
00127 }
00128 list->insert_str(aci, s, tmp);
00129 ac2 = ac2->next;
00130 aci++;
00131 }
00132 ht_text_listbox_sort_order so;
00133 so.col = 0;
00134 so.compare_func = opcode_compare;
00135 list->update();
00136 if (best) {
00137 list->gotoItemByPosition(best-1);
00138 }
00139 list->sort(1, &so);
00140 if (!best) {
00141 list->gotoItemByPosition(0);
00142 }
00143 dialog->insert(list);
00144 int r = dialog->run(0);
00145 ok = r;
00146 if (r == button_ok) {
00147 ht_listbox_data d;
00148 list->databuf_get(&d, sizeof d);
00149 ht_text_listbox_item *i=(ht_text_listbox_item *)d.cursor_ptr;
00150 asm_code *ac3 = ac;
00151 int ac3i=0;
00152 while (ac3) {
00153 if (ac3i==i->id) {
00154 chosen_ac=ac3;
00155 break;
00156 }
00157 ac3=ac3->next;
00158 ac3i++;
00159 }
00160 }
00161 dialog->done();
00162 delete dialog;
00163 }
00164 if (ok) {
00165 baseview->sendmsg(cmd_edit_mode_i, f->get_file(), NULL);
00166 if (f->get_file() && (f->get_file()->get_access_mode() & FAM_WRITE)) {
00167 f->vwrite(vaddr, chosen_ac->data, chosen_ac->size);
00168 }
00169 }
00170 }
00171 free(insn);
00172 }
00173
00174
00175
00176
00177
00178 void ht_disasm_viewer::init(bounds *b, char *desc, int caps, ht_streamfile *file, ht_format_group *format_group, Assembler *a, Disassembler *d, int t)
00179 {
00180 ht_uformat_viewer::init(b, desc, caps, file, format_group);
00181 assem = a;
00182 disasm = d;
00183 op1632 = t;
00184 }
00185
00186 void ht_disasm_viewer::done()
00187 {
00188 ht_uformat_viewer::done();
00189 if (assem) delete assem;
00190 if (disasm) delete disasm;
00191 }
00192
00193 void ht_disasm_viewer::get_pindicator_str(char *buf)
00194 {
00195 FILEOFS o;
00196 if (get_current_offset(&o)) {
00197 sprintf(buf, " %s %08x/%u ", edit() ? "edit" : "view", o, o);
00198 } else {
00199 strcpy(buf, "?");
00200 }
00201 }
00202
00203 bool ht_disasm_viewer::get_vscrollbar_pos(int *pstart, int *psize)
00204 {
00205 int s=file->get_size();
00206 if (s) {
00207 int z=MIN(size.h*16, s-(int)top.line_id.id1);
00208 return scrollbar_pos(top.line_id.id1, z, s, pstart, psize);
00209 }
00210 return false;
00211 }
00212
00213 void ht_disasm_viewer::handlemsg(htmsg *msg)
00214 {
00215 switch (msg->msg) {
00216 case msg_contextmenuquery: {
00217 ht_static_context_menu *m=new ht_static_context_menu();
00218 m->init("~Local-Disasm");
00219 m->insert_entry("~Assemble", "Ctrl+A", cmd_disasm_call_assembler, K_Control_A, 1);
00220
00221 m->insert_entry("~Toggle 16/32", NULL, cmd_disasm_toggle1632, 0, 1);
00222
00223 msg->msg = msg_retval;
00224 msg->data1.ptr = m;
00225 return;
00226 }
00227 case msg_get_scrollinfo: {
00228 switch (msg->data1.integer) {
00229 case gsi_pindicator: {
00230 get_pindicator_str((char*)msg->data2.ptr);
00231 clearmsg(msg);
00232 return;
00233 }
00234 case gsi_hscrollbar: {
00235 gsi_scrollbar_t *p=(gsi_scrollbar_t*)msg->data2.ptr;
00236 if (!get_hscrollbar_pos(&p->pstart, &p->psize)) {
00237 p->pstart = 0;
00238 p->psize = 100;
00239 }
00240 clearmsg(msg);
00241 return;
00242 }
00243 case gsi_vscrollbar: {
00244 gsi_scrollbar_t *p=(gsi_scrollbar_t*)msg->data2.ptr;
00245 if (!get_vscrollbar_pos(&p->pstart, &p->psize)) {
00246 p->pstart = 0;
00247 p->psize = 100;
00248 }
00249 clearmsg(msg);
00250 return;
00251 }
00252 }
00253 break;
00254 }
00255 case msg_filesize_changed: {
00256 htmsg m;
00257 m.msg=msg_filesize_changed;
00258 m.type=mt_broadcast;
00259 sendsubmsg(&m);
00260
00261
00262 uf_initialized=false;
00263 complete_init();
00264
00265 dirtyview();
00266 return;
00267 }
00268 case cmd_disasm_call_assembler: {
00269 viewer_pos current_pos;
00270 get_current_pos(¤t_pos);
00271
00272 CPU_ADDR cpuaddr;
00273 cpuaddr.addr32.seg = 0;
00274 cpuaddr.addr32.offset = current_pos.u.line_id.id1;
00275
00276 assem->set_imm_eval_proc(NULL, NULL);
00277
00278 byte data[32];
00279 int datalen = vread(current_pos, data, sizeof data);
00280 dis_insn *o = disasm->decode(data, datalen, cpuaddr);
00281 char *curinsn = disasm->strf(o, DIS_STYLE_HEX_NOZEROPAD+DIS_STYLE_HEX_ASMSTYLE, DISASM_STRF_SMALL_FORMAT);
00282 int want_length = disasm->getSize(o);
00283
00284 dialog_assemble(this, current_pos, cpuaddr, assem, disasm, curinsn, want_length);
00285
00286 clearmsg(msg);
00287 return;
00288 }
00289 case cmd_disasm_toggle1632: {
00290
00291 op1632 ^= 1;
00292 if (op1632) {
00293 ((x86asm *)assem)->opsize = X86_OPSIZE16;
00294 ((x86asm *)assem)->addrsize = X86_OPSIZE16;
00295 ((x86dis *)disasm)->opsize = X86_OPSIZE16;
00296 ((x86dis *)disasm)->addrsize = X86_OPSIZE16;
00297 } else {
00298 ((x86asm *)assem)->opsize = X86_OPSIZE32;
00299 ((x86asm *)assem)->addrsize = X86_OPSIZE32;
00300 ((x86dis *)disasm)->opsize = X86_OPSIZE32;
00301 ((x86dis *)disasm)->addrsize = X86_OPSIZE32;
00302 }
00303 dirtyview();
00304 clearmsg(msg);
00305 return;
00306 }
00307 }
00308 ht_uformat_viewer::handlemsg(msg);
00309 }
00310
00311 ht_disasm_sub *ht_disasm_viewer::get_disasm_sub()
00312 {
00313 return (ht_disasm_sub*)cursor.sub;
00314 }
00315
00316 bool ht_disasm_viewer::offset_to_pos(FILEOFS ofs, viewer_pos *p)
00317 {
00318 p->u.sub = get_disasm_sub();
00319 p->u.line_id.id1 = ofs;
00320 p->u.line_id.id2 = 0;
00321 p->u.tag_idx = 0;
00322 return true;
00323 }
00324
00325 bool ht_disasm_viewer::pos_to_offset(viewer_pos p, FILEOFS *ofs)
00326 {
00327 *ofs = p.u.line_id.id1;
00328 return true;
00329 }
00330
00331 int ht_disasm_viewer::ref_sel(LINE_ID *id)
00332 {
00333 return goto_offset(id->id1, true);
00334 }
00335
00336 bool ht_disasm_viewer::qword_to_pos(qword q, viewer_pos *p)
00337 {
00338 ht_linear_sub *s = get_disasm_sub();
00339 FILEOFS ofs = QWORD_GET_INT(q);
00340 clear_viewer_pos(p);
00341 p->u.sub = s;
00342 p->u.tag_idx = 0;
00343 return s->convert_ofs_to_id(ofs, &p->u.line_id);
00344 }
00345
00346 int ht_disasm_viewer::symbol_handler(eval_scalar *result, char *name)
00347 {
00348 if (strcmp(name, "$") == 0) {
00349 FILEOFS ofs;
00350 if (!pos_to_offset(*(viewer_pos*)&cursor, &ofs)) return 0;
00351 scalar_create_int_c(result, ofs);
00352 return 1;
00353 }
00354 return ht_uformat_viewer::symbol_handler(result, name);
00355 }
00356
00357 char *ht_disasm_viewer::func(UINT i, bool execute)
00358 {
00359 switch (i) {
00360
00361 case 8:
00362 if (execute) sendmsg(cmd_disasm_toggle1632);
00363 return op1632 ? (char*)"use32" : (char*)"use16";
00364 }
00365 return ht_uformat_viewer::func(i, execute);
00366 }
00367
00368
00369
00370
00371
00372 void ht_disasm_sub::init(ht_streamfile *f, FILEOFS ofs, int size, Disassembler *u, bool own_u, int ds)
00373 {
00374 ht_linear_sub::init(f, ofs, size);
00375 disasm = u;
00376 own_disasm = own_u;
00377 display_style = ds;
00378 }
00379
00380 void ht_disasm_sub::done()
00381 {
00382 if (own_disasm) {
00383 delete disasm;
00384 }
00385 ht_linear_sub::done();
00386 }
00387
00388 bool ht_disasm_sub::convert_ofs_to_id(const FILEOFS offset, LINE_ID *line_id)
00389 {
00390 if ((offset >= fofs) && (offset < fofs+fsize)) {
00391 line_id->id1=offset;
00392 line_id->id2=0;
00393 return true;
00394 }
00395 return false;
00396 }
00397
00398 bool ht_disasm_sub::convert_id_to_ofs(const LINE_ID line_id, FILEOFS *offset)
00399 {
00400 *offset = line_id.id1;
00401 return true;
00402 }
00403
00404 static char *diasm_addr_sym_func(CPU_ADDR Addr, int *symstrlen, void *context)
00405 {
00406 ht_disasm_sub *sub = (ht_disasm_sub *) context;
00407 static char buf[120];
00408 LINE_ID line_id;
00409 sub->first_line_id(&line_id);
00410 if (Addr.addr32.offset >= line_id.id1) {
00411 sub->last_line_id(&line_id);
00412 if (Addr.addr32.offset <= line_id.id1) {
00413 char buf2[60];
00414 sprintf(buf2, "0x%x", Addr.addr32.offset);
00415 char *b = tag_make_ref(buf, Addr.addr32.offset, 0, 0, 0, buf2);
00416 *b=0;
00417 if (symstrlen) *symstrlen = b-buf;
00418 return buf;
00419 }
00420 }
00421 return NULL;
00422 }
00423
00424 bool ht_disasm_sub::getline(char *line, const LINE_ID line_id)
00425 {
00426 if (line_id.id2) return false;
00427 dword ofs = line_id.id1;
00428 byte buf[15];
00429 int c = MIN(16, (int)(fofs+fsize-ofs));
00430 if (c <= 0) return false;
00431 file->seek(ofs);
00432 c = file->read(buf, c);
00433 CPU_ADDR caddr;
00434 caddr.addr32.seg = 0;
00435 caddr.addr32.offset = ofs;
00436 char *s;
00437 char *l = line;
00438 if (c) {
00439 dis_insn *insn = disasm->decode(buf, c, caddr);
00440 addr_sym_func_context = this;
00441 addr_sym_func = &diasm_addr_sym_func;
00442 s = disasm->str(insn, display_style);
00443 addr_sym_func = NULL;
00444 c = disasm->getSize(insn);
00445 } else {
00446 s = "db ?";
00447 c = 0;
00448 }
00449 l=mkhexd(l, ofs);
00450 *l++=' ';
00451 for (int i=0; i<15; i++) {
00452 if (i<c) {
00453 l=tag_make_edit_byte(l, ofs+i);
00454 } else {
00455 *l++=' ';
00456 *l++=' ';
00457 }
00458 }
00459 *l++=' ';
00460 tag_strcpy(l, s);
00461 return true;
00462 }
00463
00464 void ht_disasm_sub::first_line_id(LINE_ID *line_id)
00465 {
00466 clear_line_id(line_id);
00467 line_id->id1 = fofs;
00468 }
00469
00470 void ht_disasm_sub::last_line_id(LINE_ID *line_id)
00471 {
00472 clear_line_id(line_id);
00473 line_id->id1 = fofs+fsize-1;
00474 }
00475
00476 int ht_disasm_sub::prev_line_id(LINE_ID *line_id, int n)
00477 {
00478 if (line_id->id2) return 0;
00479 dword *ofs=&line_id->id1;
00480 int min_length;
00481 int max_length;
00482 int min_look_ahead;
00483 int avg_look_ahead;
00484 int addr_align;
00485 disasm->getOpcodeMetrics(min_length, max_length, min_look_ahead, avg_look_ahead, addr_align);
00486
00487 unsigned char buf[avg_look_ahead*50], *bufp=buf;
00488 int offsets[avg_look_ahead*50];
00489 int *of=offsets;
00490 int r=n<6 ? 6*avg_look_ahead : n*avg_look_ahead;
00491 if (r > (int)sizeof buf) r = sizeof buf;
00492 dword o=*ofs-r;
00493 int c=r, d;
00494 int s;
00495 if (*ofs<fofs+r) {
00496 c-=fofs-o;
00497 o=fofs;
00498 }
00499 if (o+c>fofs+fsize) {
00500 c=fofs+fsize-o;
00501 }
00502 file->seek(o);
00503 d=file->read(buf, c);
00504
00505 CPU_ADDR caddr;
00506 caddr.addr32.seg = 0;
00507 caddr.addr32.offset = 0;
00508 do {
00509 if (d>0) {
00510 dis_insn *insn=disasm->decode(bufp, d, caddr);
00511 s=disasm->getSize(insn);
00512
00513
00514
00515
00516 d-=s;
00517 } else {
00518 s=1;
00519 }
00520 *(of++)=o;
00521 o+=s;
00522 bufp+=s;
00523 } while (o<=*ofs);
00524 if (of-n-1<offsets) {
00525 *ofs=*(offsets);
00526 return of-offsets-1;
00527 } else {
00528 *ofs=*(of-n-1);
00529 return n;
00530 }
00531 }
00532
00533 int ht_disasm_sub::next_line_id(LINE_ID *line_id, int n)
00534 {
00535 if (line_id->id2) return 0;
00536 dword *ofs = &line_id->id1;
00537 unsigned char buf[15];
00538 int c=0, s;
00539 UINT z;
00540 CPU_ADDR caddr;
00541 caddr.addr32.seg = 0;
00542 caddr.addr32.offset = 0;
00543 while (n--) {
00544 z=MIN(15, (UINT)(fofs+fsize-*ofs));
00545 file->seek(*ofs);
00546 z=file->read(buf, z);
00547 if (z) {
00548 dis_insn *insn=disasm->decode(buf, z, caddr);
00549 s=disasm->getSize(insn);
00550 } else {
00551 s=1;
00552 }
00553 if (*ofs+s>fofs+fsize-1) return c;
00554 *ofs+=s;
00555 c++;
00556 }
00557 return c;
00558 }
00559