PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/ht-2.0.18/htdisasm.cc

#
C++ | 555 lines | 472 code | 46 blank | 37 comment | 70 complexity | 9bf5249eed2045797a8a5d3cf22166f1 MD5 | raw file
Possible License(s): GPL-2.0
  1. /*
  2. * HT Editor
  3. * htdisasm.cc
  4. *
  5. * Copyright (C) 1999-2002 Stefan Weyergraf
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License version 2 as
  9. * published by the Free Software Foundation.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20. #include <cstring>
  21. #include "cmds.h"
  22. #include "htctrl.h"
  23. #include "htdisasm.h"
  24. #include "hthist.h"
  25. #include "htiobox.h"
  26. #include "htmenu.h"
  27. #include "httag.h"
  28. #include "snprintf.h"
  29. #include "x86asm.h"
  30. #include "x86dis.h"
  31. #include "ppcdis.h"
  32. extern "C" {
  33. #include "evalx.h"
  34. #include "regex.h"
  35. }
  36. ht_view *htdisasm_init(Bounds *b, File *file, ht_format_group *group)
  37. {
  38. int t1632;
  39. #if 1
  40. Assembler *assembler=new x86asm(X86_OPSIZE32, X86_ADDRSIZE32);
  41. x86dis *disassembler=new x86dis(X86_OPSIZE32, X86_ADDRSIZE32);
  42. #else
  43. Assembler *assembler = NULL;
  44. Disassembler *disassembler = new PPCDisassembler(PPC_MODE_32);
  45. #endif
  46. t1632 = 0;
  47. ht_disasm_viewer *v=new ht_disasm_viewer();
  48. v->init(b, DESC_DISASM, VC_EDIT | VC_GOTO | VC_SEARCH, file, group, assembler, disassembler, t1632);
  49. ht_disasm_sub *d=new ht_disasm_sub();
  50. d->init(file, 0, file->getSize(),
  51. disassembler, false, X86DIS_STYLE_OPTIMIZE_ADDR);
  52. v->insertsub(d);
  53. return v;
  54. }
  55. format_viewer_if htdisasm_if = {
  56. htdisasm_init,
  57. 0
  58. };
  59. /*
  60. * dialog_assemble
  61. */
  62. static int opcode_compare(const char *a, const char *b)
  63. {
  64. int al = strlen(a);
  65. int bl = strlen(b);
  66. if (al > bl) return 1; else if (al < bl) return -1; else return strcmp(a, b);
  67. }
  68. void dialog_assemble(ht_format_viewer *f, viewer_pos vaddr, CPU_ADDR cpuaddr, Assembler *a, Disassembler *disasm, const char *default_str, int want_length)
  69. {
  70. char instr[257] = "";
  71. if (default_str) strcpy(instr, default_str);
  72. asm_insn *insn = a->alloc_insn();
  73. asm_code *ac = NULL;
  74. while (inputbox(a->get_name(), "~instruction:", instr, 255, HISTATOM_ASSEMBLER)) {
  75. if ((a->translate_str(insn, instr)) && (ac = a->encode(insn, 0, cpuaddr))) {
  76. break;
  77. } else {
  78. errorbox("%s: %s", a->get_name(), a->get_error_msg());
  79. }
  80. }
  81. if (ac) {
  82. bool ok=true;
  83. asm_code *chosen_ac = ac;
  84. if (ac->next) {
  85. // choose from list if ambigous
  86. Bounds b;
  87. b.w = 60;
  88. b.h = 15;
  89. center_bounds(&b);
  90. ht_dialog *dialog = new ht_dialog();
  91. dialog->init(&b, "choose opcode", FS_KILLER | FS_TITLE | FS_MOVE);
  92. b.assign(1, 0, 56, 1);
  93. ht_listbox_title *text = new ht_listbox_title();
  94. text->init(&b);
  95. text->setText(2, "opcode", "disassembly");
  96. dialog->insert(text);
  97. b.assign(1, 1, 56, 12);
  98. ht_text_listbox *list=new ht_text_listbox();
  99. list->init(&b, 2, 0);
  100. list->attachTitle(text);
  101. asm_code *ac2 = ac;
  102. uint aci = 0;
  103. int best = 0;
  104. while (ac2) {
  105. char s[1024], *tmp = s;
  106. for (int i=0; i < ac2->size; i++) {
  107. tmp += sprintf(tmp, "%02x ", ac2->data[i]);
  108. }
  109. if (best == 0 && want_length == ac2->size) {
  110. best = aci+1;
  111. }
  112. const char *tmp2;
  113. if (disasm) {
  114. dis_insn *o=disasm->decode((byte *)ac2->data, ac2->size, cpuaddr);
  115. tmp2 = disasm->strf(o, DIS_STYLE_HEX_NOZEROPAD+DIS_STYLE_HEX_ASMSTYLE, DISASM_STRF_SMALL_FORMAT);
  116. } else {
  117. tmp2 = "<no disassembler>";
  118. }
  119. list->insert_str(aci, s, tmp2);
  120. ac2 = ac2->next;
  121. aci++;
  122. }
  123. ht_text_listbox_sort_order so;
  124. so.col = 0;
  125. so.compare_func = opcode_compare;
  126. list->update();
  127. if (best) {
  128. list->gotoItemByPosition(best-1);
  129. }
  130. list->sort(1, &so);
  131. if (!best) {
  132. list->gotoItemByPosition(0);
  133. }
  134. dialog->insert(list);
  135. int r = dialog->run(0);
  136. ok = r;
  137. if (r == button_ok) {
  138. ht_listbox_data d;
  139. ViewDataBuf vdb(list, &d, sizeof d);
  140. ht_text_listbox_item *i = (ht_text_listbox_item *)d.data->cursor_ptr;
  141. asm_code *ac3 = ac;
  142. int ac3i = 0;
  143. while (ac3) {
  144. if (ac3i == i->id) {
  145. chosen_ac = ac3;
  146. break;
  147. }
  148. ac3 = ac3->next;
  149. ac3i++;
  150. }
  151. }
  152. dialog->done();
  153. delete dialog;
  154. }
  155. if (ok) {
  156. baseview->sendmsg(cmd_edit_mode_i, f->get_file(), NULL);
  157. if (f->get_file() && (f->get_file()->getAccessMode() & IOAM_WRITE)) {
  158. f->vwrite(vaddr, chosen_ac->data, chosen_ac->size);
  159. }
  160. }
  161. }
  162. free(insn);
  163. }
  164. /*
  165. * CLASS ht_disasm_viewer
  166. */
  167. 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)
  168. {
  169. ht_uformat_viewer::init(b, desc, caps, file, format_group);
  170. assem = a;
  171. disasm = d;
  172. op1632 = t;
  173. }
  174. void ht_disasm_viewer::done()
  175. {
  176. ht_uformat_viewer::done();
  177. delete assem;
  178. delete disasm;
  179. }
  180. int ht_disasm_viewer::get_pindicator_str(char *buf, int max_len)
  181. {
  182. FileOfs o;
  183. if (get_current_offset(&o)) {
  184. return ht_snprintf(buf, max_len, " %s 0x%08qx/%qu ", edit() ? "edit" : "view", o, o);
  185. } else {
  186. return ht_snprintf(buf, max_len, " ? ");
  187. }
  188. }
  189. bool ht_disasm_viewer::get_vscrollbar_pos(int *pstart, int *psize)
  190. {
  191. FileOfs s=file->getSize();
  192. if (s) {
  193. int z = MIN(size.h*16, s-(int)top.line_id.id1);
  194. return scrollbar_pos(top.line_id.id1, z, s, pstart, psize);
  195. }
  196. return false;
  197. }
  198. void ht_disasm_viewer::handlemsg(htmsg *msg)
  199. {
  200. switch (msg->msg) {
  201. case msg_contextmenuquery: {
  202. ht_static_context_menu *m=new ht_static_context_menu();
  203. m->init("~Local-Disasm");
  204. m->insert_entry("~Assemble", "Ctrl+A", cmd_disasm_call_assembler, K_Control_A, 1);
  205. // FIXME: wrong implementation
  206. m->insert_entry("~Toggle 16/32", NULL, cmd_disasm_toggle1632, 0, 1);
  207. msg->msg = msg_retval;
  208. msg->data1.ptr = m;
  209. return;
  210. }
  211. case msg_get_scrollinfo: {
  212. switch (msg->data1.integer) {
  213. case gsi_hscrollbar: {
  214. gsi_scrollbar_t *p=(gsi_scrollbar_t*)msg->data2.ptr;
  215. if (!get_hscrollbar_pos(&p->pstart, &p->psize)) {
  216. p->pstart = 0;
  217. p->psize = 100;
  218. }
  219. clearmsg(msg);
  220. return;
  221. }
  222. case gsi_vscrollbar: {
  223. gsi_scrollbar_t *p=(gsi_scrollbar_t*)msg->data2.ptr;
  224. if (!get_vscrollbar_pos(&p->pstart, &p->psize)) {
  225. p->pstart = 0;
  226. p->psize = 100;
  227. }
  228. clearmsg(msg);
  229. return;
  230. }
  231. }
  232. break;
  233. }
  234. case msg_filesize_changed: {
  235. htmsg m;
  236. m.msg=msg_filesize_changed;
  237. m.type=mt_broadcast;
  238. sendsubmsg(&m);
  239. // FIXME: hack
  240. uf_initialized=false;
  241. complete_init();
  242. dirtyview();
  243. return;
  244. }
  245. case cmd_disasm_call_assembler: {
  246. viewer_pos current_pos;
  247. get_current_pos(&current_pos);
  248. CPU_ADDR cpuaddr;
  249. cpuaddr.addr32.seg = 0;
  250. cpuaddr.addr32.offset = current_pos.u.line_id.id1;
  251. assem->set_imm_eval_proc(NULL, NULL);
  252. byte data[32];
  253. int datalen = vread(current_pos, data, sizeof data);
  254. dis_insn *o = disasm->decode(data, datalen, cpuaddr);
  255. const char *curinsn = disasm->strf(o, DIS_STYLE_HEX_NOZEROPAD+DIS_STYLE_HEX_ASMSTYLE, DISASM_STRF_SMALL_FORMAT);
  256. int want_length = disasm->getSize(o);
  257. dialog_assemble(this, current_pos, cpuaddr, assem, disasm, curinsn, want_length);
  258. clearmsg(msg);
  259. return;
  260. }
  261. case cmd_disasm_toggle1632: {
  262. // FIXME: very beautiful...
  263. op1632 ^= 1;
  264. if (op1632) {
  265. ((x86asm *)assem)->opsize = X86_OPSIZE16;
  266. ((x86asm *)assem)->addrsize = X86_ADDRSIZE16;
  267. ((x86dis *)disasm)->opsize = X86_OPSIZE16;
  268. ((x86dis *)disasm)->addrsize = X86_ADDRSIZE16;
  269. } else {
  270. ((x86asm *)assem)->opsize = X86_OPSIZE32;
  271. ((x86asm *)assem)->addrsize = X86_ADDRSIZE32;
  272. ((x86dis *)disasm)->opsize = X86_OPSIZE32;
  273. ((x86dis *)disasm)->addrsize = X86_ADDRSIZE32;
  274. }
  275. dirtyview();
  276. clearmsg(msg);
  277. return;
  278. }
  279. }
  280. ht_uformat_viewer::handlemsg(msg);
  281. }
  282. ht_disasm_sub *ht_disasm_viewer::get_disasm_sub()
  283. {
  284. return (ht_disasm_sub*)cursor.sub;
  285. }
  286. bool ht_disasm_viewer::offset_to_pos(FileOfs ofs, viewer_pos *p)
  287. {
  288. p->u.sub = get_disasm_sub();
  289. p->u.line_id.id1 = ofs;
  290. p->u.line_id.id2 = 0;
  291. p->u.tag_idx = 0;
  292. return true;
  293. }
  294. bool ht_disasm_viewer::pos_to_offset(viewer_pos p, FileOfs *ofs)
  295. {
  296. *ofs = p.u.line_id.id1;
  297. return true;
  298. }
  299. bool ht_disasm_viewer::ref_sel(LINE_ID *id)
  300. {
  301. return goto_offset(id->id1, true);
  302. }
  303. bool ht_disasm_viewer::qword_to_pos(uint64 q, viewer_pos *p)
  304. {
  305. ht_linear_sub *s = get_disasm_sub();
  306. FileOfs ofs = q;
  307. clear_viewer_pos(p);
  308. p->u.sub = s;
  309. p->u.tag_idx = 0;
  310. return s->convert_ofs_to_id(ofs, &p->u.line_id);
  311. }
  312. bool ht_disasm_viewer::symbol_handler(eval_scalar *result, char *name)
  313. {
  314. if (strcmp(name, "$") == 0) {
  315. FileOfs ofs;
  316. if (!pos_to_offset(*(viewer_pos*)&cursor, &ofs)) return 0;
  317. scalar_create_int_q(result, ofs);
  318. return true;
  319. }
  320. return ht_uformat_viewer::symbol_handler(result, name);
  321. }
  322. const char *ht_disasm_viewer::func(uint i, bool execute)
  323. {
  324. switch (i) {
  325. // FIXME: wrong implementation
  326. case 8:
  327. if (execute) sendmsg(cmd_disasm_toggle1632);
  328. return op1632 ? (char*)"use32" : (char*)"use16";
  329. }
  330. return ht_uformat_viewer::func(i, execute);
  331. }
  332. /*
  333. * CLASS ht_disasm_sub
  334. */
  335. void ht_disasm_sub::init(File *f, FileOfs ofs, int size, Disassembler *u, bool own_u, int ds)
  336. {
  337. ht_linear_sub::init(f, ofs, size);
  338. disasm = u;
  339. own_disasm = own_u;
  340. display_style = ds;
  341. }
  342. void ht_disasm_sub::done()
  343. {
  344. if (own_disasm) {
  345. delete disasm;
  346. }
  347. ht_linear_sub::done();
  348. }
  349. bool ht_disasm_sub::convert_ofs_to_id(const FileOfs offset, LINE_ID *line_id)
  350. {
  351. if ((offset >= fofs) && (offset < fofs+fsize)) {
  352. line_id->id1=offset;
  353. line_id->id2=0;
  354. return true;
  355. }
  356. return false;
  357. }
  358. bool ht_disasm_sub::convert_id_to_ofs(const LINE_ID line_id, FileOfs *offset)
  359. {
  360. *offset = line_id.id1;
  361. return true;
  362. }
  363. static char *diasm_addr_sym_func(CPU_ADDR Addr, int *symstrlen, void *context)
  364. {
  365. ht_disasm_sub *sub = (ht_disasm_sub *) context;
  366. static char buf[120];
  367. LINE_ID line_id;
  368. sub->first_line_id(&line_id);
  369. if (Addr.addr32.offset >= line_id.id1) {
  370. sub->last_line_id(&line_id);
  371. if (Addr.addr32.offset <= line_id.id1) {
  372. char buf2[60];
  373. ht_snprintf(buf2, sizeof buf2, "0x%x", Addr.addr32.offset);
  374. char *b = tag_make_ref(buf, sizeof buf-1, Addr.addr32.offset, 0, 0, 0, buf2);
  375. *b = 0;
  376. if (symstrlen) *symstrlen = b-buf;
  377. return buf;
  378. }
  379. }
  380. return NULL;
  381. }
  382. bool ht_disasm_sub::getline(char *line, int maxlen, const LINE_ID line_id)
  383. {
  384. if (line_id.id2) return false;
  385. uint64 ofs = line_id.id1;
  386. byte buf[16];
  387. int c = MIN(16, sint64(fofs+fsize-ofs));
  388. if (c <= 0) return false;
  389. file->seek(ofs);
  390. c = file->read(buf, c);
  391. CPU_ADDR caddr;
  392. caddr.addr32.seg = 0;
  393. caddr.addr32.offset = ofs;
  394. const char *s;
  395. char *l = line;
  396. if (c) {
  397. dis_insn *insn = disasm->decode(buf, c, caddr);
  398. addr_sym_func_context = this;
  399. addr_sym_func = &diasm_addr_sym_func;
  400. s = disasm->str(insn, display_style);
  401. addr_sym_func = NULL;
  402. c = disasm->getSize(insn);
  403. } else {
  404. s = "db ?";
  405. c = 0;
  406. }
  407. l += ht_snprintf(l, maxlen, "%08qx ", ofs);
  408. for (int i=0; i<15; i++) {
  409. if (i<c) {
  410. l=tag_make_edit_byte(l, maxlen, ofs+i);
  411. } else {
  412. *l++=' ';
  413. *l++=' ';
  414. }
  415. }
  416. *l++=' ';
  417. tag_strcpy(l, maxlen, s);
  418. return true;
  419. }
  420. void ht_disasm_sub::first_line_id(LINE_ID *line_id)
  421. {
  422. clear_line_id(line_id);
  423. line_id->id1 = fofs;
  424. }
  425. void ht_disasm_sub::last_line_id(LINE_ID *line_id)
  426. {
  427. clear_line_id(line_id);
  428. line_id->id1 = fofs+fsize-1;
  429. }
  430. int ht_disasm_sub::prev_line_id(LINE_ID *line_id, int n)
  431. {
  432. if (line_id->id2) return 0;
  433. uint32 *ofs=&line_id->id1;
  434. int min_length;
  435. int max_length;
  436. int min_look_ahead;
  437. int avg_look_ahead;
  438. int addr_align;
  439. disasm->getOpcodeMetrics(min_length, max_length, min_look_ahead, avg_look_ahead, addr_align);
  440. unsigned char buf[avg_look_ahead*50], *bufp=buf;
  441. int offsets[avg_look_ahead*50];
  442. int *of=offsets;
  443. int r=n<6 ? 6*avg_look_ahead : n*avg_look_ahead;
  444. if (r > (int)sizeof buf) r = sizeof buf;
  445. uint32 o=*ofs-r;
  446. int c=r, d;
  447. int s;
  448. if (*ofs<fofs+r) {
  449. c-=fofs-o;
  450. o=fofs;
  451. }
  452. if (o+c>fofs+fsize) {
  453. c=fofs+fsize-o;
  454. }
  455. file->seek(o);
  456. d=file->read(buf, c);
  457. CPU_ADDR caddr;
  458. caddr.addr32.seg = 0;
  459. caddr.addr32.offset = 0;
  460. do {
  461. if (d>0) {
  462. dis_insn *insn=disasm->decode(bufp, d, caddr);
  463. s=disasm->getSize(insn);
  464. /* if (s!=4) {
  465. insn=disasm->decode(bufp, d, caddr);
  466. }
  467. assert(s==4);*/
  468. d-=s;
  469. } else {
  470. s=1;
  471. }
  472. *(of++)=o;
  473. o+=s;
  474. bufp+=s;
  475. } while (o<=*ofs);
  476. if (of-n-1<offsets) {
  477. *ofs=*(offsets);
  478. return of-offsets-1;
  479. } else {
  480. *ofs=*(of-n-1);
  481. return n;
  482. }
  483. }
  484. int ht_disasm_sub::next_line_id(LINE_ID *line_id, int n)
  485. {
  486. if (line_id->id2) return 0;
  487. uint32 *ofs = &line_id->id1;
  488. unsigned char buf[15];
  489. int c=0, s;
  490. uint z;
  491. CPU_ADDR caddr;
  492. caddr.addr32.seg = 0;
  493. caddr.addr32.offset = 0;
  494. while (n--) {
  495. z=MIN(15, (uint)(fofs+fsize-*ofs));
  496. file->seek(*ofs);
  497. z=file->read(buf, z);
  498. if (z) {
  499. dis_insn *insn=disasm->decode(buf, z, caddr);
  500. s=disasm->getSize(insn);
  501. } else {
  502. s=1;
  503. }
  504. if (*ofs+s>fofs+fsize-1) return c;
  505. *ofs+=s;
  506. c++;
  507. }
  508. return c;
  509. }