Disasm.cpp

Go to the documentation of this file.
00001 /*
00002  *      disasm.cc - Disassembler for U8's usecode
00003  *
00004  *  Copyright (C) 2001-2003 Willem Jan Palenstijn and The Pentagram Team
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00019  */
00020 
00021 #include "pent_include.h"
00022 
00023 #include <fstream>
00024 #include <cstdio>
00025 
00026 #include <map>
00027 using   std::map;
00028 
00029 #include <string>
00030 using   std::string;
00031 
00032 #include <algorithm>
00033 #include <cctype>
00034 
00035 #include "Args.h"
00036 #if 0 // FIXME: Add conf/
00037 #include "Configuration.h"
00038 #endif
00039 #include "common_types.h"
00040 
00041 #include "IDataSource.h"
00042 #include "FileSystem.h"
00043 #include "util.h"
00044 
00045 // define to drop debugging output everywhere
00046 //#define DISASM_DEBUG
00047 
00048 #ifdef DISASM_DEBUG
00049 #include <iomanip>
00050 #endif
00051 
00052 /* A temporary opcode class as I slowly transition to returning pure Node* from
00053         the relevant readOp functions */
00054 class TempOp
00055 {
00056         public:
00057                 TempOp(const uint32 offset_=0, const sint32 opcode_=0,
00058                         const uint32 nextoffset_=0,
00059                         const sint32 i0_=0, const sint32 i1_=0, const sint32 i2_=0,
00060                         const sint32 i3_=0, const sint32 i4_=0, const string &str_=string())
00061                         : offset(offset_), nextoffset(nextoffset_), i0(i0_), i1(i1_), i2(i2_),
00062                         i3(i3_), i4(i4_), str(str_),
00063                         sp_size(0), ret_size(0), opcode(opcode_) {};
00064 
00065                 ~TempOp() {};
00066 
00067                 void op(const uint32 opcode_) { opcode = opcode_; };
00068                 uint32 op() const { return opcode; };
00069 
00070                 uint32 offset;
00071                 uint32 nextoffset;
00072                 sint32 i0, i1, i2, i3, i4;
00073                 string str;
00074 
00075                 // added for calli preprocessor
00076                 uint32 sp_size;
00077                 uint32 ret_size;
00078 
00079         protected:
00080                 uint32 opcode;
00081 };
00082 
00083 /* curOffset is the current offset from the start of the current data section
00084    thus the specialised read functions */
00085 
00086 uint32 curOffset;
00087 
00088 inline uint32 read1(IDataSource *ucfile) { curOffset+=1; return ucfile->read1(); };
00089 inline uint32 read2(IDataSource *ucfile) { curOffset+=2; return ucfile->read2(); };
00090 inline uint32 read4(IDataSource *ucfile) { curOffset+=4; return ucfile->read4(); };
00091 /* read string until null terninator */
00092 inline std::string readstr(IDataSource *ucfile)
00093 {
00094         string s;
00095         while(char c = static_cast<char>(read1(ucfile)))
00096                 s += c;
00097 //      for (uint32 i=0; i < 8; ++i)
00098 //                       op.str += static_cast<char>(read1(ucfile));
00099 //                      if(read1(ucfile)!=0) assert(false); // trailing 0
00100         return s;
00101 }
00102 /* read 'n' characters into a string */
00103 inline std::string readnstr(IDataSource *ucfile, uint32 n)
00104 {
00105         string s;
00106         while(n-->0)
00107                 s += static_cast<char>(read1(ucfile));
00108 //      for (uint32 i=0; i < 8; ++i)
00109 //                       op.str += static_cast<char>(read1(ucfile));
00110 //                      if(read1(ucfile)!=0) assert(false); // trailing 0
00111         return s;
00112 }
00113 
00114 std::map<sint32, string> ScriptExpressions;
00115 
00116 map<uint32, uint32> EventMap;
00117 
00118 class UsecodeHeader
00119 {
00120         public:
00121                 UsecodeHeader()
00122                 : routines(0), maxOffset(0), offset(0), externTable(0), fixupTable(0) {};
00123 
00124                 uint32 routines;
00125                 uint32 maxOffset;
00126                 uint32 offset;
00127                 uint32 externTable;
00128                 uint32 fixupTable;
00129 };
00130 
00131 const char * const print_bp(const sint32 offset)
00132 {
00133         static char str[32];
00134         snprintf(str, 32, "[BP%c%02Xh]", offset>0x7F?'-':'+', offset>0x7F?0x100-offset:offset);
00135         return str;
00136 }
00137 
00138 const char * const print_sp(const sint32 offset)
00139 {
00140         static char str[32];
00141         snprintf(str, 32, "[SP%c%02Xh]", offset>0x7F?'-':'+', offset>0x7F?0x100-offset:offset);
00142         return str;
00143 }
00144 
00145 #include "u8/ConvertUsecodeU8.h"
00146 #include "crusader/ConvertUsecodeCrusader.h"
00147 
00148 using std::endl;
00149 using std::pair;
00150 
00151 #ifndef HAVE_SNPRINTF
00152 extern sint32 snprintf(char *, size_t, const char *, /*args*/ ...);
00153 namespace std {
00154 using ::snprintf;
00155 }
00156 #endif
00157 
00158 /* this should be set depending upon what we're converting, but currently
00159         since we really only support u8 properly here, we'll just set it as the
00160         default and worry about it later */
00161 ConvertUsecode *convert = new ConvertUsecodeU8();
00162 
00163 
00164 // Overload Table
00165 void printoverloads(IDataSource *ucfile, uint32 endpos);
00166 
00167 
00168 class GlobalName
00169 {
00170         public:
00171                 GlobalName(const uint32 _offset=0, const uint32 _size=0,
00172                         const string _name=string())
00173                 : offset(_offset), size(_size), name(_name) {};
00174 
00175                 uint32  offset; //the offset into the char[]
00176                 uint32  size; //the number of bytes stored in the global
00177                 string  name; //the name of the global
00178 };
00179 
00180 /* Additional note: The maximum size of the globals array would be 64k. */
00181 map<uint32, GlobalName> GlobalNames;
00182 
00183 map<string, string> FuncNames;
00184 
00185 string  gamelanguage;
00186 string  gametype;
00187 string  outputdir;
00188 bool    print_globals=false;
00189 bool    strings_only=false;
00190 
00191 bool crusader=false;
00192 
00193 void readglobals(IDataSource *ucfile)
00194 {
00195         char buf[60];
00196         char c;
00197         ucfile->seek(0x80);
00198         sint32 offset = read4(ucfile);
00199         sint32 length = read4(ucfile);
00200 
00201         sint32 curoff = 0;
00202 
00203         ucfile->seek(offset);
00204         while (curoff < length-1) {
00205                 sint32 i = 0;
00206                 do {
00207                         c = read1(ucfile);
00208                         ++curoff;
00209                         buf[i++] = c;
00210                 } while (c != 0);
00211                 uint32 i0 = read1(ucfile);
00212                 uint32 i1 = read1(ucfile);
00213                 uint32 i2 = read1(ucfile);
00214                 read1(ucfile);
00215                 curoff+=4;
00216 
00217                 uint32 flag = i0 + (i1<<8);
00218                 GlobalNames[flag] = GlobalName(flag, i2, buf);
00219         }
00220 }
00221 
00222 void printglobals()
00223 {
00224         for(std::map<uint32, GlobalName>::iterator i=GlobalNames.begin(); i!=GlobalNames.end(); ++i)
00225                 con.Printf("[%04X %02X] (%s)\n", i->first, i->second.size, i->second.name.c_str());
00226 }
00227 
00228 /* Yes, this is icky and evil. *grin* But it works without modifying anything. */
00229 #ifdef FOLD
00230         #define con_Printf if(print_disasm && !strings_only) con.Printf
00231         #define con_Printf_s if(print_disasm && strings_only) con.Printf("\n"); if(print_disasm) con.Printf
00232 //      #define con_Printf con.Printf
00233 #else
00234         #define con_Printf if (!strings_only) con.Printf
00235         #define con_Printf_s if (strings_only) con.Printf("\n"); con.Printf
00236 #endif
00237 
00238 
00239 // should be passed to readfunction, except that would make it dependaing upon Fold.cpp
00240 // which is not what I'm intending atm.
00241 #ifdef FOLD
00242 #include "Folder.h"
00243 Folder *folder = new Folder();
00244 #endif
00245 
00246 void just_print(TempOp &op, IDataSource *ucfile);
00247 bool readfunction(IDataSource *ucfile, const char *name, const UsecodeHeader &uch, const uint32 func)
00248 {
00249         std::string str;
00250 
00251         if (curOffset >= uch.maxOffset) return false;
00252 
00253         con_Printf("Func_%X", curOffset);
00254 
00255         std::map<uint32, uint32>::iterator it = EventMap.find(curOffset);
00256         if (it != EventMap.end())
00257         {
00258                 if (it->second < 0x20)
00259                         con_Printf(" (Event %X) %s::%s", it->second, name, convert->event_names()[it->second]);
00260                 else 
00261                         con_Printf(" (Event %X) %s::ordinal%02X", it->second, name, it->second);
00262         }
00263         else 
00264                 con_Printf("  %s::%04X", name, curOffset);
00265 
00266         con_Printf(":\n");
00267 
00268         std::vector<DebugSymbol> debugSymbols;
00269         uint32 dbg_symbol_offset=0;
00270         bool done = false;
00271         
00272         #ifdef FOLD
00273         folder->SelectUnit(func);
00274         #endif
00275         
00276         while (!done)
00277         {
00278                 //if (!ucfile->good())
00279                 if(ucfile->getPos()>=ucfile->getSize())
00280                         return false;
00281 
00282                 TempOp op;
00283                 #ifdef FOLD
00284                 //foldops.push_back(FoldOp(op.offset, op.op(), op.nextoffset, op.i0, op.i1, op.i2, op.i3, op.i4, op.str));
00285                 folder->fold(convert->readOp(ucfile, dbg_symbol_offset, debugSymbols, done));
00286                 #else
00287                 convert->readOp(op, ucfile, dbg_symbol_offset, debugSymbols, done);
00288                 #endif
00289                 just_print(op, ucfile);
00290                 
00291         }
00292         //printbytes(ucfile, 20);
00293         return true;
00294 }
00295 
00296 void just_print(TempOp &op, IDataSource *ucfile)
00297 {
00298                 // point to the location of the opcode we just grabbed
00299                 con_Printf("    %04X:", op.offset);
00300 
00301                 con_Printf(" %02X\t", op.op());
00302 
00303                 switch(op.op()) {
00304 
00305                 // Poping to variables
00306                 case 0x00:
00307                         con_Printf("pop byte\t%s", print_bp(op.i0));
00308                         break;
00309                 case 0x01:
00310                         con_Printf("pop\t\t%s", print_bp(op.i0));
00311                         break;
00312                 case 0x02:
00313                         con_Printf("pop dword\t%s", print_bp(op.i0));
00314                         break;
00315                 case 0x03:
00316                         con_Printf("pop huge\t%s %i", print_bp(op.i0), op.i1);
00317                         break;
00318 
00319                 case 0x08:
00320                         con_Printf("pop res");
00321                         break;
00322                 case 0x09:
00323                         con_Printf("pop element\t%s (%02X) slist==%02X", print_bp(op.i0), op.i1, op.i2);
00324                         break;
00325 
00326                 // Constant pushing
00327                 case 0x0A:
00328                         con_Printf("push byte\t%02Xh", op.i0);
00329                         break;
00330                 case 0x0B:
00331                         con_Printf("push\t\t%04Xh", op.i0);
00332                         break;
00333                 case 0x0C:
00334                         con_Printf("push dword\t%08Xh", op.i0);
00335                         break;
00336                 case 0x0D:
00337                         
00338                         if (strings_only)
00339                         {
00340                                 con_Printf_s("%s\n\n",op.str.c_str());
00341                         }
00342                         else
00343                         {
00344                                 con_Printf("push string\t\"%s\"", op.str.c_str());
00345                         }
00346                         break;
00347                 case 0x0E:
00348                         con_Printf("create list\t%02X (%02X)", op.i1, op.i0);
00349                         break;
00350 
00351                 // Usecode function and intrinsic calls
00352                 case 0x0F:
00353                         con_Printf("calli\t\t%02Xh %04Xh (%s)", op.i0, op.i1, convert->intrinsics()[op.i1]);
00354                         break;
00355                 case 0x11:
00356                         con_Printf("call\t\t%04X:%04X (%s)", op.i0, op.i1,
00357                                 convert->UsecodeFunctionAddressToString(op.i0, op.i1, ucfile, crusader).c_str());
00358                         break;
00359                 case 0x12:
00360                         con_Printf("pop\t\ttemp");
00361                         break;
00362 
00363                 case 0x14:
00364                         con_Printf("add");
00365                         break;
00366                 case 0x15:
00367                         con_Printf("add dword");
00368                         break;
00369                 case 0x16:
00370                         con_Printf("concat");
00371                         break;
00372                 case 0x17:
00373                         con_Printf("append");
00374                         break;
00375                 case 0x19:
00376                         con_Printf("append slist\t(%02X)", op.i0);
00377                         break;
00378                 case 0x1A:
00379                         con_Printf("remove slist\t(%02X)", op.i0);
00380                         break;
00381                 case 0x1B:
00382                         con_Printf("remove list\t(%02X)", op.i0);
00383                         break;
00384                 case 0x1C:
00385                         con_Printf("sub");
00386                         break;
00387                 case 0x1D:
00388                         con_Printf("sub dword");
00389                         break;
00390                 case 0x1E:
00391                         con_Printf("mul");
00392                         break;
00393                 case 0x1F:
00394                         con_Printf("mul dword");
00395                         break;
00396                 case 0x20:
00397                         con_Printf("div");
00398                         break;
00399                 case 0x21:
00400                         con_Printf("div dword");
00401                         break;
00402                 case 0x22:
00403                         con_Printf("mod");
00404                         break;
00405                 case 0x23:
00406                         con_Printf("mod dword");
00407                         assert(false); // Guessed opcode
00408                         break;
00409                 case 0x24:
00410                         con_Printf("cmp");
00411                         break;
00412                 case 0x25:
00413                         con_Printf("cmp dword");
00414                         assert(false); // Guessed opcode
00415                         break;
00416                 case 0x26:
00417                         con_Printf("strcmp");
00418                         break;
00419                 case 0x28:
00420                         con_Printf("lt");
00421                         break;
00422                 case 0x29:
00423                         con_Printf("lt dword");
00424                         break;
00425                 case 0x2A:
00426                         con_Printf("le");
00427                         break;
00428                 case 0x2B:
00429                         con_Printf("le dword");
00430                         break;
00431                 case 0x2C:
00432                         con_Printf("gt");
00433                         break;
00434                 case 0x2D:
00435                         con_Printf("gt dword");
00436                         break;
00437                 case 0x2E:
00438                         con_Printf("ge");
00439                         break;
00440                 case 0x2F:
00441                         con_Printf("ge dword");
00442                         break;
00443                 case 0x30:
00444                         con_Printf("not");
00445                         break;
00446                 case 0x31:
00447                         con_Printf("not dword");
00448                         break;
00449                 case 0x32:
00450                         con_Printf("and");
00451                         break;
00452                 case 0x33:
00453                         con_Printf("and dword");
00454                         break;
00455                 case 0x34:
00456                         con_Printf("or");
00457                         break;
00458                 case 0x35:
00459                         con_Printf("or dword");
00460                         break;
00461                 case 0x36:
00462                         con_Printf("ne");
00463                         break;
00464                 case 0x37:
00465                         con_Printf("ne dword");
00466                         break;
00467 
00468                 case 0x38:
00469                         con_Printf("in list\t\t%02X slist==%02X", op.i0, op.i1);
00470                         break;
00471 
00472                 case 0x39:
00473                         con_Printf("bit_and");
00474                         break;
00475                 case 0x3A:
00476                         con_Printf("bit_or");
00477                         break;
00478                 case 0x3B:
00479                         con_Printf("bit_not");
00480                         break;
00481                 case 0x3C:
00482                         con_Printf("lsh");
00483                         break;
00484                 case 0x3D:
00485                         con_Printf("rsh");
00486                         break;
00487 
00488                 case 0x3E:
00489                         con_Printf("push byte\t%s", print_bp(op.i0));
00490                         break;
00491                 case 0x3F:
00492                         con_Printf("push\t\t%s", print_bp(op.i0));
00493                         break;
00494                 case 0x40:
00495                         con_Printf("push dword\t%s", print_bp(op.i0));
00496                         break;
00497                 case 0x41:
00498                         con_Printf("push string\t%s", print_bp(op.i0));
00499                         break;
00500                 case 0x42:
00501                         con_Printf("push list\t%s (%02X)", print_bp(op.i0), op.i1);
00502                         break;
00503                 case 0x43:
00504                         con_Printf("push slist\t%s", print_bp(op.i0));
00505                         break;
00506                 case 0x44:
00507                         con_Printf("push element\t(%02X) slist==%02X", op.i0, op.i1);
00508                         break;
00509                 case 0x45:
00510                         con_Printf("push huge\t%02X %02X", op.i0, op.i1);
00511                         break;
00512                 case 0x4B:
00513                         con_Printf("push addr\t%s", print_bp(op.i0));
00514                         break;
00515                 case 0x4C:
00516                         con_Printf("push indirect\t%02Xh bytes", op.i0);
00517                         break;
00518                 case 0x4D:
00519                         con_Printf("pop indirect\t%02Xh bytes", op.i0);
00520                         break;
00521 
00522                 case 0x4E:
00523                         con_Printf("push\t\tglobal [%04X %02X] (%s)", op.i0, op.i1,
00524                                 GlobalNames[op.i0].name.c_str());
00525                         break;
00526                 case 0x4F:
00527                         con_Printf("pop\t\tglobal [%04X %02X] (%s)", op.i0, op.i1,
00528                                 GlobalNames[op.i0].name.c_str());
00529                         break;
00530 
00531                 case 0x50:
00532                         con_Printf("ret");
00533                         break;
00534                 case 0x51:
00535                         con_Printf("jne\t\t%04Xh\t(to %04X)", op.i0, op.nextoffset + static_cast<short>(op.i0));
00536                         break;
00537                 case 0x52:
00538                         con_Printf("jmp\t\t%04Xh\t(to %04X)", op.i0, op.nextoffset + static_cast<short>(op.i0));
00539                         break;
00540 
00541                 case 0x53:
00542                         con_Printf("suspend");
00543                         break;
00544 
00545                 case 0x54:
00546                         con_Printf("implies\t\t%02X %02X", op.i0, op.i1);
00547                         break;
00548 
00549                 case 0x57:
00550                         con_Printf("spawn\t\t%02X %02X %04X:%04X (%s)",
00551                                    op.i0, op.i1, op.i2, op.i3, convert->UsecodeFunctionAddressToString(op.i2, op.i3, ucfile, crusader).c_str());
00552                         break;
00553                 case 0x58:
00554                         con_Printf("spawn inline\t%04X:%04X+%04X=%04X %02X %02X (%s+%04X)",
00555                                    op.i0, op.i1, op.i2, op.i1+op.i2, op.i3, op.i4,
00556                                    convert->UsecodeFunctionAddressToString(op.i0, op.i1, ucfile, crusader).c_str(), op.i2);
00557                         break;
00558                 case 0x59:
00559                         con_Printf("push\t\tpid");
00560                         break;
00561 
00562                 case 0x5A:
00563                         con_Printf("init\t\t%02X", op.i0);
00564                         break;
00565 
00566                 case 0x5B:
00567                         con_Printf ("line number\t%i (%04Xh)", op.i0, op.i0);
00568                         break;
00569                 case 0x5C:
00570                         con_Printf("symbol info\toffset %04Xh = \"%s\"", op.i0, op.str.c_str());
00571                         break;
00572 
00573                 case 0x5D:
00574                         con_Printf("push byte\tretval");
00575                         break;
00576                 case 0x5E:
00577                         con_Printf("push\t\tretval");
00578                         break;
00579                 case 0x5F:
00580                         con_Printf("push dword\tretval");
00581                         break;
00582 
00583                 case 0x60:
00584                         con_Printf("word to dword");
00585                         break;
00586                 case 0x61:
00587                         con_Printf("dword to word");
00588                         break;
00589 
00590                 case 0x62:
00591                         con_Printf("free string\t%s", print_bp(op.i0));
00592                         break;
00593                 case 0x63:
00594                         con_Printf("free slist\t%s", print_bp(op.i0));
00595                         break;
00596                 case 0x64:
00597                         con_Printf("free list\t%s", print_bp(op.i0));
00598                         break;
00599                 case 0x65:
00600                         con_Printf("free string\t%s", print_sp(op.i0));
00601                         break;
00602                 case 0x66:
00603                         con_Printf("free list\t%s", print_sp(op.i0));
00604                         break;
00605                 case 0x67:
00606                         con_Printf("free slist\t%s", print_sp(op.i0));
00607                         break;
00608                 case 0x69:
00609                         con_Printf("push strptr\t%s", print_bp(op.i0));
00610                         break;
00611                 case 0x6B:
00612                         con_Printf("str to ptr");
00613                         break;
00614 
00615                 case 0x6C:
00616                         con_Printf("param pid chg\t%s %02X", print_bp(op.i0), op.i1);
00617                         break;
00618 
00619                 case 0x6D:
00620                         con_Printf("push dword\tprocess result");
00621                         break;
00622                 case 0x6E:
00623                         con_Printf("add sp\t\t%s%02Xh", op.i0>0x7F?"-":"", op.i0>0x7F?0x100-op.i0:op.i0);
00624                         break;
00625                 case 0x6F:
00626                         con_Printf("push addr\t%s", print_sp(0x100 - op.i0));
00627                         break;
00628 
00629                 case 0x70:
00630                         con_Printf("loop\t\t%s %02X %02X", print_bp(op.i0), op.i1, op.i2);
00631                         break;
00632                 case 0x73:
00633                         con_Printf("loopnext");
00634                         break;
00635                 case 0x74:
00636                         con_Printf("loopscr\t\t%02X \"%c\" - %s", op.i0, static_cast<char>(op.i0),ScriptExpressions[op.i0].c_str());
00637                         break;
00638 
00639                 case 0x75:
00640                         con_Printf("foreach list\t%s (%02X) %04X", print_bp(op.i0), op.i1, op.i2);
00641                         break;
00642 
00643                 case 0x76:
00644                         con_Printf("foreach slist\t%s (%02X) %04X", print_bp(op.i0), op.i1, op.i2);
00645                         break;
00646 
00647                 case 0x77:
00648                         con_Printf("set info");
00649                         break;
00650 
00651                 case 0x78:
00652                         con_Printf("process exclude");
00653                         break;
00654 
00655                 case 0x79:
00656                         con_Printf("global_address\t%04X", op.i0);
00657                         break;
00658 
00659                 case 0x7A:
00660                         con_Printf("end");
00661 
00662                         if(op.str.size())
00663                         {
00664                                 con_Printf("\tsize of dbg symbols %04X", op.str.size());
00665                         }
00666 
00667                         break;
00668 
00669                 // can't happen.
00670                 default:
00671                         con_Printf("db\t\t%02x", op.op());
00672                         assert(false);
00673                 }
00674                 con_Printf("\n");
00675 }
00676 
00677 
00678 void printfunc(const uint32 func, const uint32 nameoffset, IDataSource *ucfile)
00679 {
00680         ucfile->seek(0x80 + 8*(func+2));
00681         uint32 offset = read4(ucfile);
00682         uint32 length = read4(ucfile);
00683 
00684         if (length == 0) return;
00685 
00686         ucfile->seek(nameoffset + 4 + (13 * func));
00687 
00688         char namebuf[9];
00689         ucfile->read(namebuf, 9);
00690 
00691         ucfile->seek(offset);
00692         
00693         UsecodeHeader uch;
00694         
00695         convert->readheader(ucfile, uch, curOffset);
00696 
00697         con_Printf_s("Usecode class %d (%04X %s)\n", func, func, namebuf);
00698 
00699         convert->readevents(ucfile, uch);
00700 
00701         while (readfunction(ucfile, namebuf, uch, func));
00702 
00703         #ifdef FOLD
00704         folder->FinalUnit();
00705         //fold(func);
00706         //folder->print_unk(pout);
00707         folder->print_asm(con);
00708         folder->print_unk(con);
00709         //delete folder;
00710         //folder = new Folder();
00711         //clearfolding(); // clear in case we need to do another function
00712         #endif
00713 }
00714 #undef con_Printf // undef the evil define
00715 
00716 void readfunctionnames(void)
00717 {
00718 #if 0 // FIXME: conf/
00719         Configuration config;
00720         std::vector<std::string> functionnames;
00721         std::string functionaddress;
00722 
00723         config.read_config_file("usecodemap.cfg");
00724         functionnames = config.listkeys("usecodemap",false);
00725         std::vector<std::string>::iterator it = functionnames.begin();
00726         while (it != functionnames.end())
00727         {
00728                 config.value("usecodemap/" + *it + "/" + gamelanguage, functionaddress, "N/A");
00729                 if (functionaddress == "N/A")
00730                         perr << gamelanguage << " entry point for " << *it << " not found" << std::endl;
00731                 else
00732                 {
00733                         for(std::string::iterator i=functionaddress.begin(); i!=functionaddress.end(); ++i)
00734                                 std::toupper(*i);
00735 //                      std::transform(functionaddress.begin(), functionaddress.end(), functionaddress.begin(), std::toupper);
00736                         FuncNames[functionaddress] = *it;
00737                 }
00738                 it++;
00739         }
00740 #endif
00741 }
00742 
00743 int main(int argc, char **argv)
00744 {
00745         if (argc < 3) {
00746                 perr << "Usage: " << argv[0] << " <file> [<function number>|-a] {--game [u8|crusader]} {--lang [english|german|french|japanese]} {--odir <directory>}" << endl;
00747                 perr << "or" << endl;
00748                 perr << "Usage: " << argv[0] << " <file> -l" << endl;
00749                 perr << "or" << endl;
00750                 perr << "Usage: " << argv[0] << " <file> --globals {--game [u8|crusader]}" << endl;
00751                 // Overload Table
00752                 perr << "or" << endl;
00753                 perr << "Usage: " << argv[0] << " <file> -overload" << endl;
00754                 return 1;
00755         }
00756 
00757         con.DisableWordWrap();
00758         
00759         Args parameters;
00760         
00761         parameters.declare("--lang",    &gamelanguage,  "unknown");
00762         parameters.declare("--game",    &gametype,      "none");
00763         parameters.declare("--odir",    &outputdir,     "");
00764         parameters.declare("--globals", &print_globals, true);
00765         #ifdef FOLD
00766         parameters.declare("--disasm",  &print_disasm,  true);
00767         #endif
00768         parameters.declare("--strings", &strings_only,  true);
00769 
00770         parameters.process(argc, argv);
00771 
00772         // Filename with stripped path
00773         char *stripped_filename = argv[1];
00774 
00775         // Search for last ':', '/' or '\\'
00776         for(uint32 i = 0; argv[1][i]; ++i)
00777                 if (argv[1][i] == '\\' || argv[1][i] == '/' || argv[1][i] == ':') stripped_filename  = argv[1]+i+1;
00778 
00779         if (gamelanguage=="unknown")  // try to determine game language from file name
00780         {
00781                 switch (stripped_filename[0])
00782                 {
00783                         case 'g': case 'G':
00784                                 gamelanguage = "german";
00785                                 break;
00786                         case 'e': case 'E':
00787                                 gamelanguage = "english";
00788                                 break;
00789                         case 'f': case 'F':
00790                                 gamelanguage = "french";
00791                                 break;
00792                         case 'j': case 'J':
00793                                 gamelanguage = "japanese";
00794                                 break;
00795                         default:
00796                                 perr << "Could not determine game language. Defaulting to english." << std::endl;
00797                                 gamelanguage = "english";
00798                 }
00799         }
00800         if ( (gamelanguage != "german") && (gamelanguage != "english") && (gamelanguage != "french") && (gamelanguage != "japanese"))
00801         {
00802                 perr << "Warning: unknown language specified (" << gamelanguage << ")." << std::endl;
00803         }
00804 
00805         // Create filesystem object
00806         FileSystem filesys(true);
00807 
00808         // Load usecode file
00809         IDataSource *ucfile = filesys.ReadFile(argv[1]);
00810 
00811         // Uh oh, couldn't load it
00812         if(ucfile==0)
00813         {
00814                 perr << "Error reading file \"" << argv[1] << "\"" << endl;
00815                 return 1;
00816         }
00817 
00818         // Force crusader mode if we are reading overload.dat
00819         if (!Pentagram::strcasecmp(stripped_filename, "overload.dat"))
00820         {
00821                 pout << "Using \"overload.dat\". Forcing crusader gametype." << std::endl;
00822                 gametype="crusader";
00823         }
00824         // Or if gametype is none, attempt to autodetect game type
00825         else if (gametype=="none")
00826         {
00827                 ucfile->seek(0x80);
00828                 sint32 nameoffset = read4(ucfile);
00829                 sint32 namelength = read4(ucfile);
00830 
00831                 // Looks like Ultima8 (has a global section)
00832                 if (nameoffset && namelength) gametype="u8";
00833                 // Must be crusader (no globals section)
00834                 else gametype="crusader";
00835         }
00836 
00837         // Output the game type and langauge
00838         pout << "Game type: " << gametype << std::endl <<
00839                 "Language: " << gamelanguage << std::endl;
00840 
00841         if(outputdir.size())
00842                 pout << "Output Directory: `" << outputdir << "`" << endl;
00843         
00844         // setup crusader
00845         if (gametype=="crusader")
00846         {
00847                 crusader=true;
00848                 FORGET_OBJECT(convert);
00849                 convert = new ConvertUsecodeCrusader();
00850         }
00851 
00852         // Read function names from cfg file
00853         readfunctionnames();
00854 
00855         // List functions
00856         if (!Pentagram::strcasecmp(argv[2], "-l")) {
00857 
00858                 pout << "Listing classes..." << endl << endl;
00859 
00860                 // Read num entries
00861                 ucfile->seek( 0x54);
00862                 uint32 entries = read4(ucfile)-2;
00863 
00864                 ucfile->seek(0x80 + 8);
00865                 sint32 nameoffset = read4(ucfile);
00866                 /*sint32 namelength =*/ read4(ucfile);
00867 
00868                 pout.setf(std::ios::uppercase);
00869 
00870                 con.Printf("Class         Name     Offset     Routines   MaxOffset  Offset     ExternTab  FixupTab\n");
00871 
00872                 sint32 actual_num = 0;
00873                 for(uint32 func = 0; func < entries; ++func)
00874                 {
00875                         ucfile->seek(0x80 + 8*(func+2));
00876                         sint32 offset = read4(ucfile);
00877                         sint32 length = read4(ucfile);
00878 
00879                         ucfile->seek(nameoffset + 4 + (13 * func));
00880                         char namebuf[9];
00881                         ucfile->read(namebuf, 9);
00882 
00883                         if (length == 0) continue;
00884 
00885                         //cout << "Usecode function " << func << " (0x" << std::hex << func
00886                         //      << std::dec << ") (" << namebuf << ")" << endl;
00887 
00888                         ucfile->seek(offset);
00889                         UsecodeHeader uch;
00890                         convert->readheader(ucfile, uch, curOffset);
00891                         
00892                         con.Printf("%4d (0x%04X) %-8s 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08X 0x%08d\n",
00893                                 func, func, namebuf, offset, uch.routines, uch.maxOffset,
00894                                 uch.offset, uch.externTable, uch.fixupTable, uch.fixupTable - uch.externTable);
00895                         
00896                         ++actual_num;
00897                 }
00898                 pout << endl << actual_num << " Usecode classes" << endl;
00899                 return 0;
00900         }
00901         // Overload Table
00902         else if (!Pentagram::strcasecmp(argv[2], "-overload")) {
00903                 uint32 end;
00904 
00905                 // it's overload.dat
00906                 if (!Pentagram::strcasecmp(stripped_filename, "overload.dat"))
00907                 {
00908                         end = ucfile->getSize();
00909                         ucfile->seek(0);
00910                 }
00911                 // We want usecode entry 1
00912                 else 
00913                 {
00914                         ucfile->seek(0x88);
00915                         uint32 offset = ucfile->read4();
00916                         end = ucfile->read4();
00917                         ucfile->seek(offset);
00918                         end += offset;
00919                 }
00920 
00921                 printoverloads(ucfile, end);
00922                 return 0;
00923         }
00924 
00925         pout.setf(std::ios::uppercase);
00926         pout << std::hex;
00927 
00928         readglobals(ucfile);
00929 
00930         if(print_globals)
00931                 printglobals();
00932         
00933         // Setup script expressions
00934         ScriptExpressions[0] = "false";
00935         ScriptExpressions[1] = "true";
00936         ScriptExpressions['$'] = "end";
00937         ScriptExpressions['%'] = "int";
00938         ScriptExpressions['&'] = "&&";
00939         ScriptExpressions['+'] = "||";
00940         ScriptExpressions['!'] = "!";
00941         ScriptExpressions['?'] = "item->status";
00942         ScriptExpressions['*'] = "item->q";
00943         ScriptExpressions['#'] = "item->npc_num";
00944         ScriptExpressions['='] = "==";
00945         ScriptExpressions['>'] = ">";
00946         ScriptExpressions['<'] = "<";
00947         ScriptExpressions[']'] = ">=";
00948         ScriptExpressions['['] = "<=";
00949         ScriptExpressions[':'] = "item->family";
00950         ScriptExpressions['@'] = "item->shape";
00951         ScriptExpressions['`'] = "item->frame";
00952 
00953         #ifdef FOLD
00954         initfolding();
00955         #endif
00956 
00957         ucfile->seek(0x80 + 8);
00958         uint32 nameoffset = read4(ucfile);
00959         /*uint32 namelength =*/ read4(ucfile);
00960 
00961         if(std::strcmp(argv[2], "-a")==0)
00962         {
00963                 ucfile->seek(0x54); // Seek to the 'start' of the FLEX
00964                 uint32 entries = read4(ucfile)-2;
00965                 
00966                 for(uint32 func=0; func<entries; ++func)
00967                         printfunc(func, nameoffset, ucfile);
00968         }
00969         
00970         uint32 func = std::strtol(argv[2], 0, 0);
00971         
00972         printfunc(func, nameoffset, ucfile);
00973         
00974         return 0;
00975 }
00976 
00977 // Overload Table
00978 void printoverloads(IDataSource *ucfile, uint32 endpos)
00979 {
00980         con.Printf ("Overload Table:\n");
00981 
00982         uint32 f, i = 0;
00983         uint32 all_mask = 0;
00984 
00985         while ((ucfile->getPos()) < endpos) {
00986                 uint32 mask;
00987                 char classname[9];
00988 
00989                 mask = ucfile->read4();
00990                 ucfile->read(classname, 9);
00991 
00992                 if (classname[0]) {
00993                         con.Printf ("%04d: %8s ", i, classname);
00994 
00995                         for (f=0; f<32; f++) con.Printf (" %i",(mask>>f) & 1);
00996 
00997                         con.Printf ("\n");
00998                 }
00999                 all_mask |= mask;
01000                 i++;
01001         }
01002         con.Printf ("\n%i functions ", i);
01003 
01004         con.Printf ("\nAll functions: ");
01005 
01006         for (f=0; f<32; f++) con.Printf (" %i",(all_mask>>f) & 1);
01007 
01008         con.Printf ("\n\nEvents used:\n");
01009         for (f=0; f<32; f++) {
01010                 if ((all_mask>>f) & 1) con.Printf (" %i: %s\n", f, convert->event_names()[f]);
01011         }
01012 }

Generated on Fri Jul 27 22:27:14 2007 for pentagram by  doxygen 1.4.7