Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

htdisasm.cc

Go to the documentation of this file.
00001 /*
00002  *      HT Editor
00003  *      htdisasm.cc
00004  *
00005  *      Copyright (C) 1999-2002 Stefan Weyergraf (stefan@weyergraf.de)
00006  *
00007  *      This program is free software; you can redistribute it and/or modify
00008  *      it under the terms of the GNU General Public License version 2 as
00009  *      published by the Free Software Foundation.
00010  *
00011  *      This program is distributed in the hope that it will be useful,
00012  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *      GNU General Public License for more details.
00015  *
00016  *      You should have received a copy of the GNU General Public License
00017  *      along with this program; if not, write to the Free Software
00018  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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  *      dialog_assemble
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                         // choose from list if ambigous
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  *      CLASS ht_disasm_viewer
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                         // FIXME: wrong implementation
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 // FIXME: hack
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(&current_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 // FIXME: very beautiful...
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 // FIXME: wrong implementation
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  *      CLASS ht_disasm_sub
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 /*                      if (s!=4) {
00513                                 insn=disasm->decode(bufp, d, caddr);
00514                         }
00515                         assert(s==4);*/
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 

Generated on Fri May 7 21:15:33 2004 by doxygen 1.3.5