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

macho_analy.cc

Go to the documentation of this file.
00001 /* 
00002  *      HT Editor
00003  *      macho_analy.cc
00004  *
00005  *      Copyright (C) 1999-2002 Sebastian Biallas (sb@web-productions.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 "analy.h"
00022 #include "analy_names.h"
00023 #include "analy_ppc.h"
00024 #include "analy_register.h"
00025 #include "analy_x86.h"
00026 #include "global.h"
00027 #include "macho_analy.h"
00028 
00029 #include "htctrl.h"
00030 #include "htdebug.h"
00031 #include "htiobox.h"
00032 #include "htmacho.h"
00033 #include "htstring.h"
00034 #include "pestruct.h"
00035 #include "snprintf.h"
00036 //#include "x86asm.h"
00037 
00038 extern "C" {
00039 #include "demangle.h"
00040 }
00041 
00042 #include <stdio.h>
00043 #include <stdlib.h>
00044 #include <string.h>
00045 
00046 /*
00047  *
00048  */
00049  
00050 void MachoAnalyser::init(ht_macho_shared_data *Macho_shared, ht_streamfile *File)
00051 {
00052         macho_shared = Macho_shared;
00053         file = File;
00054 
00055         validarea = new Area();
00056         validarea->init();
00057 
00058         Analyser::init();
00059 }
00060 
00061 void MachoAnalyser::beginAnalysis()
00062 {
00063         setLocationTreeOptimizeThreshold(100);
00064         setSymbolTreeOptimizeThreshold(100);
00065 
00066         MACHO_COMMAND_U **pp;
00067         /*
00068          *      entrypoints
00069          */
00070         UINT entrypoint_count = 0;
00071         pp = macho_shared->cmds.cmds;
00072         for (UINT i=0; i < macho_shared->cmds.count; i++) {
00073                 if (((*pp)->cmd.cmd == LC_UNIXTHREAD) || ((*pp)->cmd.cmd == LC_THREAD)) {
00074                         MACHO_THREAD_COMMAND *s = (MACHO_THREAD_COMMAND*)*pp;
00075                         Address *entry;
00076                         switch (macho_shared->header.cputype) {
00077                         case MACHO_CPU_TYPE_POWERPC:
00078                                 entry = createAddress32(s->state.state_ppc.srr0);
00079                                 break;
00080                         case MACHO_CPU_TYPE_I386:
00081                                 entry = createAddress32(s->state.state_i386.eip);
00082                                 break;
00083                         default: assert(0);
00084                         }
00085                         char desc[128];
00086                         sprintf(desc, "entrypoint%d", entrypoint_count++);
00087                         pushAddress(entry, entry);
00088                         assignSymbol(entry, desc, label_func);
00089                         addComment(entry, 0, "");
00090                         addComment(entry, 0, ";****************************");
00091                         addComment(entry, 0, "; thread entrypoint");
00092                         addComment(entry, 0, ";****************************");
00093                         delete entry;
00094                 }
00095                 pp++;
00096         }
00097         
00098         /*
00099          *      give all sections a descriptive comment:
00100          */
00101 
00102         char blub[100];
00103         pp = macho_shared->cmds.cmds;
00104         for (UINT i=0; i < macho_shared->cmds.count; i++) {
00105                 if ((*pp)->cmd.cmd == LC_SEGMENT) {
00106                 MACHO_SEGMENT_COMMAND *s = (MACHO_SEGMENT_COMMAND*)*pp;
00107 
00108                 Address *secaddr;
00109 
00110                 secaddr = createAddress32(s->vmaddr);
00111                 if (validAddress(secaddr, scvalid)) {
00112                         ht_snprintf(blub, sizeof blub, ";  section %d <%s>", i+1, getSegmentNameByAddress(secaddr));
00113                         addComment(secaddr, 0, "");
00114                         addComment(secaddr, 0, ";******************************************************************");
00115                         addComment(secaddr, 0, blub);
00116                         ht_snprintf(blub, sizeof blub, ";  virtual address  %08x  virtual size   %08x", s->vmaddr, s->vmsize);
00117                         addComment(secaddr, 0, blub);
00118                         ht_snprintf(blub, sizeof blub, ";  file offset      %08x  file size      %08x", s->fileoff, s->filesize);
00119                         addComment(secaddr, 0, blub);
00120                         addComment(secaddr, 0, ";******************************************************************");
00121 
00122                         // mark end of sections
00123                         ht_snprintf(blub, sizeof blub, ";  end of section <%s>", getSegmentNameByAddress(secaddr));
00124                         Address *secend_addr = (Address *)secaddr->duplicate();
00125 
00126                         secend_addr->add(s->vmsize);
00127                         newLocation(secend_addr)->flags |= AF_FUNCTION_END;
00128                         addComment(secend_addr, 0, "");
00129                         addComment(secend_addr, 0, ";******************************************************************");
00130                         addComment(secend_addr, 0, blub);
00131                         addComment(secend_addr, 0, ";******************************************************************");
00132 
00133                         validarea->add(secaddr, secend_addr);
00134 
00135                         delete secend_addr;
00136                 }
00137                 delete secaddr;
00138                 }
00139                 pp++;
00140         }
00141 
00142 
00143         /* symbols */
00144         pp = macho_shared->cmds.cmds;
00145         for (UINT i=0; i < macho_shared->cmds.count; i++) {
00146                 if ((*pp)->cmd.cmd == LC_SYMTAB) {
00147                         MACHO_SYMTAB_COMMAND *s = (MACHO_SYMTAB_COMMAND*)*pp;
00148                         int *entropy = random_permutation(s->nsyms);
00149                         for (UINT j=0; j<s->nsyms; j++) {
00150                                 file->seek(s->symoff+entropy[j]*sizeof (MACHO_SYMTAB_NLIST));
00151                                 MACHO_SYMTAB_NLIST nlist;
00152                                 if (file->read(&nlist, sizeof nlist) != sizeof nlist) break;
00153                                 create_host_struct(&nlist, MACHO_SYMTAB_NLIST_struct, macho_shared->image_endianess);
00154                                 if (nlist.strx && (nlist.type & MACHO_SYMBOL_N_TYPE == MACHO_SYMBOL_TYPE_N_SECT)) {
00155                                         char macho_buffer[1024];
00156                                         file->seek(s->stroff+nlist.strx);
00157                                         char *label = fgetstrz(file);
00158 //                                      fprintf(stderr, "symbol '%s' addr %08x\n", label, nlist.value);
00159                                         Address *address = createAddress32(nlist.value);
00160                                         if (validAddress(address, scvalid)) {
00161                                                 char *demangled = NULL/*cplus_demangle(label, DMGL_PARAMS | DMGL_ANSI)*/;
00162                                                 make_valid_name(label, label);
00163                                                 ht_snprintf(macho_buffer, sizeof macho_buffer, "; function %s", (demangled) ? demangled : label);
00164                                                 if (demangled) free(demangled);
00165                                                 addComment(address, 0, "");
00166                                                 addComment(address, 0, ";********************************************************");
00167                                                 addComment(address, 0, macho_buffer);
00168                                                 addComment(address, 0, ";********************************************************");
00169                                                 pushAddress(address, address);
00170                                                 assignSymbol(address, label, label_func);
00171                                         } else {
00172 //                                              fprintf(stderr, "'%s' has invalid addr %08x\n", label, nlist.value);
00173                                         }
00174                                         delete address;
00175                                         free(label);
00176                                 }
00177                         }
00178                         free(entropy);
00179                 }
00180                 pp++;
00181         }
00182         setLocationTreeOptimizeThreshold(1000);
00183         setSymbolTreeOptimizeThreshold(1000);
00184         
00185         Analyser::beginAnalysis();
00186 }
00187 
00188 /*
00189  *
00190  */
00191 void MachoAnalyser::initInsertSymbols(int shidx)
00192 {
00193 }
00194 
00195 /*
00196  *
00197  */
00198 int MachoAnalyser::load(ht_object_stream *f)
00199 {
00200         GET_OBJECT(f, validarea);
00201         return Analyser::load(f);
00202 }
00203 
00204 /*
00205  *
00206  */
00207 void MachoAnalyser::done()
00208 {
00209         validarea->done();
00210         delete validarea;
00211         Analyser::done();
00212 }
00213 
00214 OBJECT_ID MachoAnalyser::object_id() const
00215 {
00216         return ATOM_MACHO_ANALYSER;
00217 }
00218 
00219 /*
00220  *
00221  */
00222 UINT MachoAnalyser::bufPtr(Address *Addr, byte *buf, int size)
00223 {
00224         FILEOFS ofs = addressToFileofs(Addr);
00225 /*     if (ofs == INVALID_FILE_OFS) {
00226                 int as = 1;
00227         }*/
00228         assert(ofs != INVALID_FILE_OFS);
00229         file->seek(ofs);
00230         return file->read(buf, size);;
00231 }
00232 
00233 bool MachoAnalyser::convertAddressToMACHOAddress(Address *addr, MACHOAddress *r)
00234 {
00235 /*      if (addr->object_id()==ATOM_ADDRESS_FLAT_32) {
00236                 r->a32 = ((AddressFlat32*)addr)->addr;
00237                 return true;
00238         } else if (addr->object_id()==ATOM_ADDRESS_X86_FLAT_32) {
00239                 r->a32 = ((AddressX86Flat32*)addr)->addr;
00240                 return true;
00241         } else if (addr->object_id()==ATOM_ADDRESS_FLAT_64) {
00242                 r->a64.lo = ((AddressFlat64*)addr)->addr.lo;
00243                 r->a64.hi = ((AddressFlat64*)addr)->addr.hi;
00244                 return true;*/
00245         if (addr->object_id() == ATOM_ADDRESS_FLAT_32) {
00246                 *r = ((AddressFlat32*)addr)->addr;
00247                 return true;
00248         } else if (addr->object_id() == ATOM_ADDRESS_X86_FLAT_32) {
00249                 *r = ((AddressX86Flat32*)addr)->addr;
00250                 return true;
00251         }
00252         return false;
00253 }
00254 
00255 Address *MachoAnalyser::createAddress()
00256 {
00257         switch (macho_shared->header.cputype) {
00258                         case MACHO_CPU_TYPE_I386: {
00259                                 return new AddressX86Flat32();
00260                         }
00261                         case MACHO_CPU_TYPE_POWERPC: {
00262                                 return new AddressFlat32();
00263                         }
00264         }
00265         assert(0);
00266         return NULL;
00267 }
00268 
00269 Address *MachoAnalyser::createAddress32(dword addr)
00270 {
00271         switch (macho_shared->header.cputype) {
00272                         case MACHO_CPU_TYPE_I386: {
00273                                 return new AddressX86Flat32(addr);
00274                         }
00275                         case MACHO_CPU_TYPE_POWERPC: {
00276                                 return new AddressFlat32(addr);
00277                         }
00278         }
00279         assert(0);
00280         return NULL;
00281 }
00282 
00283 /*
00284  *
00285  */
00286 Assembler *MachoAnalyser::createAssembler()
00287 {
00288 /*      switch (macho_shared->header32.e_machine) {
00289                 case MACHO_EM_386:
00290                         Assembler *a = new x86asm(X86_OPSIZE32, X86_ADDRSIZE32);
00291                         a->init();
00292                         return a;
00293         }*/
00294         return NULL;
00295 }
00296 
00297 /*
00298  *
00299  */
00300 FILEOFS MachoAnalyser::addressToFileofs(Address *Addr)
00301 {
00302         if (validAddress(Addr, scinitialized)) {
00303                 uint32 ofs;
00304                 MACHOAddress ea;
00305                 if (!convertAddressToMACHOAddress(Addr, &ea)) return INVALID_FILE_OFS;
00306                 if (!macho_addr_to_ofs(&macho_shared->sections, 0, ea, &ofs)) return INVALID_FILE_OFS;
00307                 return ofs;
00308         } else {
00309                 return INVALID_FILE_OFS;
00310         }
00311 }
00312 
00313 /*
00314  *
00315  */
00316 char *MachoAnalyser::getSegmentNameByAddress(Address *Addr)
00317 {
00318         static char macho_sectionname[33];
00319         macho_sections *sections = &macho_shared->sections;
00320         int i;
00321         MACHOAddress ea;
00322         if (!convertAddressToMACHOAddress(Addr, &ea)) return NULL;
00323         if (!macho_addr_to_section(sections, 0, ea, &i)) return NULL;
00324         strncpy(macho_sectionname, (char*)sections->sections[i].sectname, 16);
00325         macho_sectionname[16] = 0;
00326         return macho_sectionname;
00327 }
00328 
00329 /*
00330  *
00331  */
00332 const char *MachoAnalyser::getName()
00333 {
00334         return file->get_desc();
00335 }
00336 
00337 /*
00338  *
00339  */
00340 const char *MachoAnalyser::getType()
00341 {
00342         return "Mach-O/Analyser";
00343 }
00344 
00345 /*
00346  *
00347  */
00348 void MachoAnalyser::initCodeAnalyser()
00349 {
00350         Analyser::initCodeAnalyser();
00351 }
00352 
00353 /*
00354  *
00355  */
00356 void MachoAnalyser::initUnasm()
00357 {
00358         DPRINTF("macho_analy: ");
00359         UINT machine = macho_shared->header.cputype;
00360         bool macho64 = false;
00361         switch (machine) {
00362                 case MACHO_CPU_TYPE_I386: // Intel x86
00363                         DPRINTF("initing analy_x86_disassembler\n");
00364                         analy_disasm = new AnalyX86Disassembler();
00365                         ((AnalyX86Disassembler*)analy_disasm)->init(this, macho64 ? ANALYX86DISASSEMBLER_FLAGS_FLAT64 : 0);
00366                         break;
00367                 case MACHO_CPU_TYPE_POWERPC:    // PowerPC
00368                         DPRINTF("initing analy_ppc_disassembler\n");
00369                         analy_disasm = new AnalyPPCDisassembler();
00370                         ((AnalyPPCDisassembler*)analy_disasm)->init(this);
00371                         break;
00372                 default:
00373                         DPRINTF("no apropriate disassembler for machine %04x\n", machine);
00374                         warnbox("No disassembler for unknown machine type %04x!", machine);
00375         }
00376 }
00377 
00378 /*
00379  *
00380  */
00381 void MachoAnalyser::log(const char *msg)
00382 {
00383         /*
00384          *      log() does to much traffic so dont log
00385          *   perhaps we reactivate this later
00386          *
00387          */
00388 /*      LOG(msg);*/
00389 }
00390 
00391 /*
00392  *
00393  */
00394 Address *MachoAnalyser::nextValid(Address *Addr)
00395 {
00396         return (Address *)validarea->findNext(Addr);
00397 }
00398 
00399 /*
00400  *
00401  */
00402 void MachoAnalyser::store(ht_object_stream *f)
00403 {
00404         PUT_OBJECT(f, validarea);
00405         Analyser::store(f);
00406 }
00407 
00408 /*
00409  *
00410  */
00411 int MachoAnalyser::queryConfig(int mode)
00412 {
00413         switch (mode) {
00414                 case Q_DO_ANALYSIS:
00415                 case Q_ENGAGE_CODE_ANALYSER:
00416                 case Q_ENGAGE_DATA_ANALYSER:
00417                         return true;
00418                 default:
00419                         return 0;
00420         }
00421 }
00422 
00423 /*
00424  *
00425  */
00426 Address *MachoAnalyser::fileofsToAddress(FILEOFS fileofs)
00427 {
00428         MACHOAddress ea;
00429         if (macho_ofs_to_addr(&macho_shared->sections, 0, fileofs, &ea)) {
00430 /*              switch (macho_shared->ident.e_ident[MACHO_EI_CLASS]) {          
00431                         case MACHOCLASS32: return createAddress32(ea.a32);
00432                         case MACHOCLASS64: return createAddress64(ea.a64);
00433                 }
00434                 return new InvalidAddress();*/
00435                 return createAddress32(ea);
00436         } else {
00437                 return new InvalidAddress();
00438         }
00439 }
00440 
00441 /*
00442  *
00443  */
00444 bool MachoAnalyser::validAddress(Address *Addr, tsectype action)
00445 {
00446         macho_sections *sections = &macho_shared->sections;
00447         int sec;
00448         byte cls = 0/*macho_shared->ident.e_ident[MACHO_EI_CLASS]*/;
00449         MACHOAddress ea;
00450         if (!convertAddressToMACHOAddress(Addr, &ea)) return false;
00451         if (!macho_addr_to_section(sections, cls, ea, &sec)) return false;
00452 /*      switch (cls) {
00453                 case MACHOCLASS32: {*/
00454                         MACHO_SECTION *s = &sections->sections[sec];
00455                         switch (action) {
00456                                 case scvalid:
00457                                         return true;
00458                                 case scread:
00459                                         return true;
00460                                 case scwrite:
00461                                 case screadwrite: {
00462                                         bool writable =
00463                                                 ((s->flags & MACHO_SECTION_TYPE) != MACHO_S_CSTRING_LITERALS) &&
00464                                                 ((s->flags & MACHO_SECTION_TYPE) != MACHO_S_4BYTE_LITERALS) &&
00465                                                 ((s->flags & MACHO_SECTION_TYPE) != MACHO_S_8BYTE_LITERALS)
00466                                         ;
00467                                         return writable;
00468                                 }
00469                                 case sccode:
00470                                         return ((s->flags & MACHO_SECTION_TYPE) == MACHO_S_REGULAR);
00471                                 case scinitialized:
00472                                         return ((s->flags & MACHO_SECTION_TYPE) != MACHO_S_ZEROFILL);
00473                         }
00474                         return false;
00475 /*              }
00476                 case MACHOCLASS64: {
00477                         MACHO_SECTION_HEADER64 *s=sections->sheaders64+sec;
00478                         switch (action) {
00479                                 case scvalid:
00480                                         return true;
00481                                 case scread:
00482                                         return true;
00483                                 case scwrite:
00484                                 case screadwrite:
00485                                         return s->sh_flags.lo & MACHO_SHF_WRITE;
00486                                 case sccode:
00487                                         return (s->sh_flags.lo & MACHO_SHF_EXECINSTR) && (s->sh_type==MACHO_SHT_PROGBITS);
00488                                 case scinitialized:
00489                                         return s->sh_type==MACHO_SHT_PROGBITS;
00490                         }
00491                         return false;
00492                 }
00493         }*/
00494         return false;
00495 }
00496 
00497 

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