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

htne.cc

Go to the documentation of this file.
00001 /*
00002  *      HT Editor
00003  *      htne.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 "log.h"
00022 #include "htendian.h"
00023 #include "htiobox.h"
00024 #include "htne.h"
00025 #include "htneent.h"
00026 #include "htnehead.h"
00027 #include "htneimp.h"
00028 #include "htnenms.h"
00029 #include "htneobj.h"
00030 #include "htneimg.h"
00031 #include "htnewexe.h"
00032 #include "nestruct.h"
00033 #include "tools.h"
00034 
00035 #include <stdlib.h>
00036 #include <string.h>
00037 
00038 static format_viewer_if *htne_ifs[] = {
00039         &htneheader_if,
00040         &htnesegments_if,
00041         &htneimports_if,
00042         &htneentrypoints_if,
00043         &htnenames_if,
00044         &htneimage_if,
00045         0
00046 };
00047 
00048 static int compare_keys_ne_import_rec(Object *key_a, Object *key_b)
00049 {
00050         ne_import_rec *a=(ne_import_rec*)key_a;
00051         ne_import_rec *b=(ne_import_rec*)key_b;
00052         if (a->module == b->module) {
00053                 if (a->byname == b->byname) {
00054                         if (a->byname) {
00055                                 return a->name_ofs - b->name_ofs;
00056                         } else {
00057                                 return a->ord - b->ord;
00058                         }
00059                 }
00060                 return a->byname - b->byname;
00061         }
00062         return a->module - b->module;
00063 }
00064 
00065 static ht_view *htne_init(bounds *b, ht_streamfile *file, ht_format_group *format_group)
00066 {
00067         byte nemagic[2];
00068         FILEOFS h = get_newexe_header_ofs(file);
00069         file->seek(h);
00070         file->read(nemagic, 2);
00071         if ((nemagic[0]!=NE_MAGIC0) || (nemagic[1]!=NE_MAGIC1))
00072                 return 0;
00073 
00074         ht_ne *g=new ht_ne();
00075         g->init(b, file, htne_ifs, format_group, h);
00076         return g;
00077 }
00078 
00079 format_viewer_if htne_if = {
00080         htne_init,
00081         0
00082 };
00083 
00084 void ht_ne::init(bounds *b, ht_streamfile *f, format_viewer_if **ifs, ht_format_group *format_group, FILEOFS h)
00085 {
00086         ht_format_group::init(b, VO_BROWSABLE | VO_SELECTABLE | VO_RESIZE, DESC_NE, f, false, true, 0, format_group);
00087         VIEW_DEBUG_NAME("ht_ne");
00088 
00089         LOG("%s: NE: found header at %08x", file->get_filename(), h);
00090 
00091         ht_ne_shared_data *ne_shared = (ht_ne_shared_data*)malloc(sizeof (ht_ne_shared_data));
00092         shared_data = ne_shared;
00093 
00094         ne_shared->fake_segment = 0;
00095         ne_shared->hdr_ofs = h;
00096         ne_shared->entrypoints = NULL;
00097         ne_shared->imports = NULL;
00098         ne_shared->v_image = NULL;
00099 
00100         file->seek(h);
00101         file->read(&ne_shared->hdr, sizeof ne_shared->hdr);
00102         create_host_struct(&ne_shared->hdr, NE_HEADER_struct, little_endian);
00103 
00104 /* read segment descriptors */
00105         ne_shared->segments.segment_count = ne_shared->hdr.cseg;
00106         ne_shared->segments.segments = (NE_SEGMENT *)malloc(sizeof (NE_SEGMENT) * ne_shared->segments.segment_count);
00107 
00108         bool reloc_needed = false;
00109         NE_SEGMENT *s = ne_shared->segments.segments;
00110         file->seek(h+ne_shared->hdr.segtab);
00111         for (dword i = 0; i < ne_shared->segments.segment_count; i++) {
00112                 file->read(s, sizeof *s);
00113                 create_host_struct(s, NE_SEGMENT_struct, little_endian);
00114                 if (s->flags & NE_HASRELOC) reloc_needed = true;
00115                 s++;
00116         }
00117 /* read entrypoint descriptors */
00118         FILEOFS o = h + ne_shared->hdr.enttab;
00119         NE_ENTRYPOINT_HEADER e;
00120         file->seek(o);
00121         file->read(&e, sizeof e);
00122         create_host_struct(&e, NE_ENTRYPOINT_HEADER_struct, little_endian);
00123         o += sizeof e;
00124 
00125         ht_clist *ep = new ht_clist();
00126         ep->init();
00127 
00128         dword index = 1;
00129         while (o<h+ne_shared->hdr.enttab+ne_shared->hdr.cbenttab) {
00130                 for (int i=0; i<e.entry_count; i++) {
00131                         if (e.seg_index==0) {
00132                         } else if (e.seg_index==0xff) {
00133                                 o+=sizeof (NE_ENTRYPOINT_MOVABLE);
00134                                 
00135                                 NE_ENTRYPOINT_MOVABLE me;
00136                                 file->read(&me, sizeof me);
00137                                 create_host_struct(&me, NE_ENTRYPOINT_MOVABLE_struct, little_endian);
00138 
00139                                 ep->set(index, new ht_ne_entrypoint(index, me.seg, me.offset, 0));
00140                         } else {
00141                                 o+=sizeof (NE_ENTRYPOINT_FIXED);
00142                                 
00143                                 NE_ENTRYPOINT_FIXED fe;
00144                                 file->seek(o);
00145                                 file->read(&fe, sizeof fe);
00146                                 create_host_struct(&fe, NE_ENTRYPOINT_FIXED_struct, little_endian);
00147                                 ep->set(index, new ht_ne_entrypoint(index, e.seg_index, fe.offset, 0));
00148                         }
00149                         index++;
00150                 }
00151                 file->seek(o);
00152                 file->read(&e, sizeof e);
00153                 create_host_struct(&e, NE_ENTRYPOINT_HEADER_struct, little_endian);
00154                 o += sizeof e;
00155         }
00156 
00157         ne_shared->entrypoints = ep;
00158 
00159 /* read module names */
00160         o = h + ne_shared->hdr.modtab;
00161         FILEOFS no = h + ne_shared->hdr.imptab;
00162         file->seek(o);
00163         ne_shared->modnames_count = ne_shared->hdr.cmod;
00164         ne_shared->modnames = (char**)malloc(sizeof *ne_shared->modnames * ne_shared->modnames_count);
00165         for (UINT i=0; i<ne_shared->hdr.cmod; i++) {
00166                 char buf[2];
00167                 file->seek(o+i*2);
00168                 if (file->read(buf, 2) != 2) break;
00169                 int w = create_host_int(buf, 2, little_endian);
00170                 file->seek(no+w);
00171                 ne_shared->modnames[i] = getstrp(file);
00172         }
00173 
00174 /* do relocations */
00175         if (reloc_needed) {
00176                 ht_ne_reloc_file *rf = new ht_ne_reloc_file();
00177                 rf->init(file, false, (ht_ne_shared_data*)shared_data);
00178 
00179                 if (relocate(rf)) {
00180                         rf->finalize();
00181                         file = rf;
00182                         own_file = true;
00183                         LOG("%s: NE: relocations present, relocation simulation layer enabled", file->get_filename());
00184                 } else {
00185                         LOG_EX(LOG_WARN, "%s: NE relocations seem to be corrupted.", file->get_filename());
00186                         errorbox("%s: NE relocations seem to be corrupted.", file->get_filename());
00187                         rf->done();
00188                         delete rf;
00189                 }
00190         }
00191 
00192         ht_format_group::init_ifs(ifs);
00193 }
00194 
00195 void ht_ne::done()
00196 {
00197         ht_format_group::done();
00198 
00199         ht_ne_shared_data *ne_shared = (ht_ne_shared_data*)shared_data;
00200 
00201         if (ne_shared->segments.segments) {
00202                 free(ne_shared->segments.segments);
00203         }
00204         
00205         if (ne_shared->modnames) {
00206                 for (UINT i=0; i<ne_shared->modnames_count; i++) {
00207                         free(ne_shared->modnames[i]);
00208                 }
00209                 free(ne_shared->modnames);
00210         }
00211         
00212         if (ne_shared->entrypoints) {
00213                 ne_shared->entrypoints->destroy();
00214                 delete ne_shared->entrypoints;
00215         }
00216         
00217         if (ne_shared->imports) {
00218                 ne_shared->imports->destroy();
00219                 delete ne_shared->imports;
00220         }
00221         free(shared_data);
00222 }
00223 
00224 void ht_ne::loc_enum_start()
00225 {
00226 //      loc_enum=true;
00227 }
00228 
00229 bool ht_ne::loc_enum_next(ht_format_loc *loc)
00230 {
00231 #if 0
00232         ht_ne_shared_data *sh=(ht_ne_shared_data*)shared_data;
00233         if (loc_enum) {
00234                 loc->name="ne";
00235                 loc->start=sh->hdr_ofs;
00236                 loc->length=file->get_size()-loc->start;        /* FIXME: ENOTOK */
00237                 
00238                 loc_enum=false;
00239                 return true;
00240         }
00241 #endif
00242         return false;
00243 }
00244 
00245 bool ht_ne::create_fake_segment()
00246 {
00247         ht_ne_shared_data *ne_shared = (ht_ne_shared_data*)shared_data;
00248         UINT i = ne_shared->hdr.cseg;
00249         NE_SEGMENT *newsegs = (NE_SEGMENT*)malloc(sizeof *newsegs * (ne_shared->segments.segment_count+1));
00250         memcpy(newsegs, ne_shared->segments.segments, sizeof *newsegs * ne_shared->segments.segment_count);
00251         ne_shared->segments.segment_count++;
00252         free(ne_shared->segments.segments);
00253         ne_shared->segments.segments = newsegs;
00254         newsegs[i].offset = 0;
00255         newsegs[i].size = 0;
00256         newsegs[i].flags = NE_DATA;
00257         newsegs[i].minalloc = 0;                // = 64k
00258         ne_shared->fake_segment = i;
00259         return true;
00260 }
00261 
00262 bool ht_ne::relocate(ht_reloc_file *rf)
00263 {
00264         ht_ne_shared_data *ne_shared = (ht_ne_shared_data*)shared_data;
00265         if (!create_fake_segment()) return false;
00266 
00267         ht_stree *imports = new ht_stree();
00268         imports->init(compare_keys_ne_import_rec);
00269 
00270         int fake_entry_count = 0;
00271         /* if selfload only relocate first segment. Is this "The Right Thing" ? */
00272         /* Works for me though. */
00273         UINT c = (ne_shared->hdr.flags & NE_FLAGS_SELFLOAD) ? 1 : ne_shared->segments.segment_count;
00274         for (dword i = 0; i < c; i++) {
00275                 if (ne_shared->segments.segments[i].flags & NE_HASRELOC) {
00276                         FILEOFS seg_ofs = NE_get_seg_ofs(ne_shared, i);
00277                         FILEOFS f = seg_ofs + NE_get_seg_psize(ne_shared, i);
00278                         char buf[2];
00279                         file->seek(f);
00280                         file->read(buf, 2);
00281                         f += 2;
00282                         int c = create_host_int(buf, 2, little_endian);
00283                         for (int j = 0; j < c; j++) {
00284                                 NE_RELOC_HEADER reloc;
00285                                 file->seek(f);
00286                                 file->read(&reloc, sizeof reloc);
00287                                 create_host_struct(&reloc, NE_RELOC_HEADER_struct, little_endian);
00288                                 f += sizeof reloc;
00289                                 switch (reloc.flags & NE_RF_RT_MASK) {
00290                                         case NE_RF_INTERNAL: {
00291                                                 NE_RELOC_INTERNAL sreloc;
00292                                                 file->read(&sreloc, sizeof sreloc);
00293                                                 create_host_struct(&sreloc, NE_RELOC_INTERNAL_struct, little_endian);
00294                                                 f += sizeof sreloc;
00295                                                 if (sreloc.seg == 0xff) {
00296 //                                      ne_shared->entrypoint->;
00297                                                         if (!relocate_single(rf, i, seg_ofs + reloc.src_ofs, reloc.type, reloc.flags, 0xf1, 0)) return false;
00298                                                 } else {
00299                                                         if (!relocate_single(rf, i, seg_ofs + reloc.src_ofs, reloc.type, reloc.flags, sreloc.seg, sreloc.ofs)) return false;
00300                                                 }
00301                                                 break;
00302                                         }
00303                                         case NE_RF_IMPORT_ORD: {
00304                                                 NE_RELOC_IMPORT sreloc;
00305                                                 file->read(&sreloc, sizeof sreloc);
00306                                                 create_host_struct(&sreloc, NE_RELOC_IMPORT_struct, little_endian);
00307                                                 f += sizeof sreloc;
00308                                                 if (imports->insert(new ne_import_rec(fake_entry_count, sreloc.module, false, sreloc.ord), NULL)) {
00309 //                                                      if (!relocate_single(rf, i, seg_ofs + reloc.src_ofs, reloc.type, reloc.flags, 0xf2, sreloc.ord)) return false;
00310                                                         if (!relocate_single(rf, i, seg_ofs + reloc.src_ofs, reloc.type, reloc.flags, ne_shared->fake_segment+1, fake_entry_count)) return false;
00311                                                         fake_entry_count++;
00312                                                 }
00313                                                 break;
00314                                         }
00315                                         case NE_RF_IMPORT_NAME: {
00316                                                 NE_RELOC_IMPORT sreloc;
00317                                                 file->read(&sreloc, sizeof sreloc);
00318                                                 create_host_struct(&sreloc, NE_RELOC_IMPORT_struct, little_endian);
00319                                                 f += sizeof sreloc;
00320                                                 if (imports->insert(new ne_import_rec(fake_entry_count, sreloc.module, true, sreloc.name_ofs), NULL)) {
00321 //                                                      if (!relocate_single(rf, i, seg_ofs + reloc.src_ofs, reloc.type, reloc.flags, 0xf3, sreloc.name_ofs)) return false;
00322                                                         if (!relocate_single(rf, i, seg_ofs + reloc.src_ofs, reloc.type, reloc.flags, ne_shared->fake_segment+1, fake_entry_count)) return false;
00323                                                         fake_entry_count++;
00324                                                 }
00325                                                 break;
00326                                         }
00327                                         case NE_RF_OSFIXUP: {
00328                                                 NE_RELOC_FIXUP sreloc;
00329                                                 file->read(&sreloc, sizeof sreloc);
00330                                                 create_host_struct(&sreloc, NE_RELOC_FIXUP_struct, little_endian);
00331                                                 f += sizeof sreloc;
00332                                                 if (!relocate_single(rf, i, seg_ofs + reloc.src_ofs, reloc.type, reloc.flags, 0xdead, 0xcafebabe)) return false;
00333                                                 break;
00334                                         }
00335                                 }
00336                         }
00337                 }
00338         }
00339         ne_shared->imports = imports;
00340         return true;
00341 }
00342 
00343 bool ht_ne::relocate_single(ht_reloc_file *rf, UINT seg, FILEOFS ofs, UINT type, UINT flags, word value_seg, word value_ofs)
00344 {
00345         ht_ne_shared_data *ne_shared = (ht_ne_shared_data*)shared_data;
00346         while (1) {
00347                 if (flags & NE_RF_ADD) break;
00348                 switch (type & NE_RT_MASK) {
00349                         case NE_RT_SEG16:
00350                         case NE_RT_PTR32:
00351                         case NE_RT_OFS16:
00352                         case NE_RT_PTR48:
00353                         case NE_RT_OFS32:
00354                                 break;
00355                         case NE_RT_OFS8:
00356                         /* FIXME: we want to read a word (offset) out of the file,
00357                            but we can't because there's only one relocated
00358                            byte. Maybe I dont understand NE relocs completely. */
00359                         default:
00360                         /* unknown relocation record */
00361                                 return false;
00362                 }
00363                 rf->insert_reloc(ofs, new ht_ne_reloc_entry(type, flags & NE_RF_ADD, value_seg, value_ofs));
00364                 char buf[2];
00365                 file->seek(ofs);
00366                 file->read(buf, 2);
00367                 word r = create_host_int(buf, 2, little_endian);
00368                 if (r == 0xffff) break;
00369                 NEAddress a = NE_MAKE_ADDR(seg+1, r);
00370                 if (!NE_addr_to_ofs(ne_shared, a, &ofs)) {
00371                         return false;
00372                 }
00373         }
00374         return true;
00375 }
00376 
00377 /*
00378  *      CLASS ht_ne_entrypoint
00379  */
00380 
00381 ht_ne_entrypoint::ht_ne_entrypoint(UINT Ordinal, UINT Seg, UINT Offset, UINT Flags)
00382 {
00383         ordinal = Ordinal;
00384         seg = Seg;
00385         offset = Offset;
00386         flags = Flags;
00387         name = NULL;
00388 }
00389 
00390 ht_ne_entrypoint::~ht_ne_entrypoint()
00391 {
00392            if (name) free(name);
00393 }
00394 
00395 /*
00396  *      CLASS ht_ne_reloc_entry
00397  */
00398 
00399 ht_ne_reloc_entry::ht_ne_reloc_entry(UINT Mode, bool Add, word Seg, word Ofs)
00400 {
00401         mode = Mode;
00402         add = Add;
00403         seg = Seg;
00404         ofs = Ofs;
00405 }
00406 
00407 /*
00408  *      CLASS ht_ne_reloc_file
00409  */
00410 
00411 void ht_ne_reloc_file::init(ht_streamfile *s, bool os, ht_ne_shared_data *d)
00412 {
00413         ht_reloc_file::init(s, os);
00414         data = d;
00415 }
00416 
00417 void ht_ne_reloc_file::reloc_apply(Object *reloc, byte *data)
00418 {
00419         ht_ne_reloc_entry *e = (ht_ne_reloc_entry*)reloc;
00420 
00421         switch (e->mode & NE_RT_MASK) {
00422                 case NE_RT_OFS8:
00423                         create_foreign_int(data, e->ofs, 1, little_endian);
00424                         break;
00425                 case NE_RT_SEG16:
00426                         create_foreign_int(data, e->seg, 2, little_endian);
00427                         break;
00428                 case NE_RT_OFS16:
00429                         create_foreign_int(data, e->ofs, 2, little_endian);
00430                         break;
00431                 case NE_RT_PTR32:
00432                         create_foreign_int(data, e->ofs, 2, little_endian);
00433                         create_foreign_int(data+2, e->seg, 2, little_endian);
00434                         break;
00435                 case NE_RT_OFS32:
00436                         create_foreign_int(data, e->ofs, 4, little_endian);
00437                         break;
00438                 case NE_RT_PTR48:
00439                         create_foreign_int(data, e->ofs, 4, little_endian);
00440                         create_foreign_int(data+4, e->seg, 2, little_endian);
00441                         break;
00442         }
00443 }
00444 
00445 bool ht_ne_reloc_file::reloc_unapply(Object *reloc, byte *data)
00446 {
00447         return false;
00448 //      ht_ne_reloc_entry *e = (ht_ne_reloc_entry*)reloc;
00449 }
00450 
00451 /*
00452  *
00453  */
00454 
00455 FILEOFS NE_get_seg_ofs(ht_ne_shared_data *NE_shared, UINT i)
00456 {
00457                 return (NE_shared->segments.segments[i].offset << NE_shared->hdr.align);
00458 }
00459 
00460 NEAddress NE_get_seg_addr(ht_ne_shared_data *NE_shared, UINT i)
00461 {
00462                 return NE_MAKE_ADDR(i+1, 0);
00463 }
00464 
00465 UINT NE_get_seg_psize(ht_ne_shared_data *NE_shared, UINT i)
00466 {
00467                 return (NE_shared->segments.segments[i].size || !NE_shared->segments.segments[i].offset)
00468                            ? NE_shared->segments.segments[i].size : 0x10000;
00469 //              return NE_shared->segments.segments[i].size;
00470 }
00471 
00472 UINT NE_get_seg_vsize(ht_ne_shared_data *NE_shared, UINT i)
00473 {
00474                 return NE_shared->segments.segments[i].minalloc ? NE_shared->segments.segments[i].minalloc : 0x10000;
00475 //              return NE_shared->segments.segments[i].minalloc;
00476 }
00477 
00478 bool NE_addr_to_segment(ht_ne_shared_data *NE_shared, NEAddress Addr, int *segment)
00479 {
00480         for (UINT i = 0; i < NE_shared->segments.segment_count; i++) {
00481                 NEAddress base = NE_get_seg_addr(NE_shared, i);
00482                 UINT evsize = MAX(NE_get_seg_vsize(NE_shared, i), NE_get_seg_psize(NE_shared, i));
00483                 if ((Addr >= base) && (Addr < base + evsize)) {
00484                         *segment = i;
00485                         return true;
00486                 }
00487         }
00488         return false;
00489 }
00490 
00491 bool NE_addr_is_physical(ht_ne_shared_data *NE_shared, NEAddress Addr)
00492 {
00493         for (UINT i = 0; i < NE_shared->segments.segment_count; i++) {
00494                 NEAddress base = NE_get_seg_addr(NE_shared, i);
00495                 UINT epsize = MIN(NE_get_seg_vsize(NE_shared, i), NE_get_seg_psize(NE_shared, i));
00496                 if ((Addr >= base) && (Addr < base + epsize)) return true;
00497         }
00498         return false;
00499 }
00500 
00501 bool NE_addr_to_ofs(ht_ne_shared_data *NE_shared, NEAddress Addr, FILEOFS *ofs)
00502 {
00503         for (UINT i = 0; i < NE_shared->segments.segment_count; i++) {
00504                 NEAddress base = NE_get_seg_addr(NE_shared, i);
00505                 UINT epsize = MIN(NE_get_seg_vsize(NE_shared, i), NE_get_seg_psize(NE_shared, i));
00506                 if ((Addr >= base) && (Addr < base + epsize)) {
00507                         *ofs = NE_get_seg_ofs(NE_shared, i) + (Addr - base);
00508                         return true;
00509                 }
00510         }
00511         return false;
00512 }
00513 
00514 bool NE_ofs_to_addr(ht_ne_shared_data *NE_shared, FILEOFS ofs, NEAddress *Addr)
00515 {
00516         for (UINT i = 0; i < NE_shared->segments.segment_count; i++) {
00517                 FILEOFS sofs = NE_get_seg_ofs(NE_shared, i);
00518                 if ((ofs >= sofs) && (ofs < sofs + NE_get_seg_psize(NE_shared, i))) {
00519                         *Addr = NE_get_seg_addr(NE_shared, i) + (ofs - sofs);
00520                         return true;
00521                 }
00522         }
00523         return false;
00524 }

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