Convert.h

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) 2002-2003 The Pentagram Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018 
00019 #ifndef CONVERT_H
00020 #define CONVERT_H
00021 
00022 #include "IDataSource.h"
00023 #include "common_types.h"
00024 #include "Console.h"
00025 #include <vector>
00026 #include <string>
00027 #include "GenericNodes.h"
00028 #include "LoopScriptNodes.h"
00029 
00030 class DebugSymbol
00031 {
00032         public:
00033                 uint32 number;
00034                 uint32 unknown1;
00035                 uint32 type;
00036                 uint32 unknown2;
00037                 uint32 unknown3;
00038                 std::string name;
00039                 
00040 };
00041 
00042 class ConvertUsecode
00043 {
00044         // just an 'empty' base class
00045         public:
00046                 ConvertUsecode() {};
00047                 virtual ~ConvertUsecode() {};
00048                 
00049                 virtual const char* const *intrinsics()=0;
00050                 virtual const char* const *event_names()=0;
00051                 virtual void readheader(IDataSource *ucfile, UsecodeHeader &uch, uint32 &curOffset)=0;
00052                 virtual void readevents(IDataSource *ucfile, const UsecodeHeader &uch)=0;
00053                 virtual void readOp(TempOp &op, IDataSource *ucfile, uint32 &dbg_symbol_offset, std::vector<DebugSymbol> &debugSymbols, bool &done)=0;
00054                 virtual Node *readOp(IDataSource *ucfile, uint32 &dbg_symbol_offset, std::vector<DebugSymbol> &debugSymbols, bool &done)=0;
00055 
00056                 void readDbgSymbols(IDataSource *ucfile, std::vector<DebugSymbol> &debugSymbols);
00057                 void readOpGeneric(TempOp &op, IDataSource *ucfile, uint32 &dbg_symbol_offset, std::vector<DebugSymbol> &debugSymbols,
00058                         bool &done, const bool crusader);
00059                 Node *readOpGeneric(IDataSource *ucfile, uint32 &dbg_symbol_offset, std::vector<DebugSymbol> &debugSymbols,
00060                         bool &done, const bool crusader);
00061                 void printDbgSymbols(std::vector<DebugSymbol> &debugSymbols);
00062                 
00063                 std::string UsecodeFunctionAddressToString(const sint32 uclass, const sint32 coffset, IDataSource *ucfile, const bool crusader);
00064         
00065         private:
00066                 static const uint32 MAX_UCFUNC_NAMELEN = 256; // max usecode function name length
00067 };
00068 
00069 /* This needs to go into Convert*Crusader only too */
00070 void ConvertUsecode::readDbgSymbols(IDataSource *ucfile, std::vector<DebugSymbol> &debugSymbols)
00071 {
00072         uint32 count=read1(ucfile);
00073 
00074         for(uint32 i=0; i<count; ++i)
00075         {
00076                 DebugSymbol ds;
00077                 
00078                 ds.number   = i;
00079                 ds.unknown1 = read1(ucfile);
00080                 ds.type     = read1(ucfile);
00081                 ds.unknown2 = read1(ucfile);
00082                 ds.unknown3 = read1(ucfile);
00083                 uint32 tchar;
00084                 while ((tchar = read1(ucfile)))
00085                         ds.name += static_cast<char>(tchar);
00086                 
00087                 debugSymbols.push_back(ds);
00088         }
00089 }
00090 
00091 void ConvertUsecode::printDbgSymbols(std::vector<DebugSymbol> &debugSymbols)
00092 {
00093         for(uint32 i=0; i<debugSymbols.size(); ++i)
00094         {
00095                 DebugSymbol &ds = debugSymbols[i];
00096                 
00097                 con.Printf("%02X: %02X type=%02X (%c) %s (%02X) %02X %s\n",
00098                         ds.number, ds.unknown1, ds.type, ds.type, print_bp(ds.unknown2), ds.unknown2, ds.unknown3, ds.name.c_str());
00099         }
00100 };
00101 
00102 void printbytes(IDataSource *f, uint32 num)
00103 {
00104         //uint32 loff=0;
00105         while(num>0)
00106         {
00107                 uint8 c = f->read1();
00108                 con.Printf("%02X %c ", c, std::isprint(c) ? c : '.');
00109                 --num;
00110         }
00111 }
00112 
00113 /* This needs to be shuffled into two different readOp() functions, one in Convert*Crusader, and
00114         the other in Convert*U8 */
00115 void ConvertUsecode::readOpGeneric(TempOp &op, IDataSource *ucfile, uint32 &dbg_symbol_offset, std::vector<DebugSymbol> &debugSymbols,
00116         bool &done, const bool crusader)
00117 {
00118                 if(dbg_symbol_offset==curOffset)
00119                 {
00120                         readDbgSymbols(ucfile, debugSymbols);
00121                         op.op(read1(ucfile));
00122                         assert(op.op()==0x7a);
00123                 }
00124                 else
00125                         op.op(read1(ucfile));
00126 
00127                 op.offset = curOffset-1;
00128 
00129                 /*
00130                   Guesses of opcodes. I'm reasonably sure about most of them,
00131                   but they're still guesses...
00132                   (Questionmarks generally indicate uncertainty)
00133                 */
00134 
00135                 switch(op.op()) {
00136 
00137                 // Poping to variables
00138                 case 0x00:
00139                         // 00 xx
00140                         // pop 8 bit int into bp+xx
00141                         op.i0 = read1(ucfile);
00142                         break;
00143                 case 0x01:
00144                         // 01 xx
00145                         // pop 16 bit int into bp+xx
00146                         op.i0 = read1(ucfile);
00147                         break;
00148                 case 0x02:
00149                         // 02 xx
00150                         // pop 32 bit int into bp+xx
00151                         op.i0 = read1(ucfile);
00152                         break;
00153                 case 0x03:
00154                         // 03 xx yy
00155                         // pop yy bytes into bp+xx
00156                         op.i0 = read1(ucfile); op.i1 = read1(ucfile);
00157                         break;
00158 
00159                 case 0x08:
00160                         // 08
00161                         // pop 32bits into result register
00162                         break;
00163                 case 0x09:
00164                         // 09 xx yy zz
00165                         // pop yy bytes into an element of list bp+xx (or slist if zz is set).
00166                         op.i0 = read1(ucfile); op.i1 = read1(ucfile); op.i2 = read1(ucfile);
00167                         break;
00168 
00169                 // Constant pushing
00170                 case 0x0A:
00171                         // 0A xx
00172                         // push signed extended 8 bit xx onto the stack
00173                         op.i0 = read1(ucfile);
00174                         break;
00175                 case 0x0B:
00176                         // 0B xx xx
00177                         // push 16 bit xxxx onto the stack
00178                         op.i0 = read2(ucfile);
00179                         break;
00180                 case 0x0C:
00181                         // 0C xx xx xx xx
00182                         // push 32 bit xxxxxxxx onto the stack
00183                         op.i0 = read4(ucfile);
00184                         break;
00185                 case 0x0D:
00186                         // 0D xx xx yy ... yy 00
00187                         // push string (yy ... yy) of length xx xx onto the stack
00188                         op.i0 = read2(ucfile);
00189                         op.str = "";
00190                         while ((op.i1 = read1(ucfile))) op.str += static_cast<char>(op.i1);
00191                         break;
00192                 case 0x0E:
00193                         // 0E xx yy
00194                         // pop yy values of size xx from the stack and push the resulting list
00195                         op.i0 = read1(ucfile);
00196                         op.i1 = read1(ucfile);
00197                         break;
00198 
00199                 // Usecode function and intrinsic calls
00200                 case 0x0F:
00201                         // 0F xx yyyy
00202                         // intrinsic call. xx is number of arguement bytes (includes this pointer)
00203                         op.i0 = read1(ucfile);
00204                         op.i1 = read2(ucfile);
00205                         break;
00206                 case 0x11:
00207                         // 11 xx xx yy yy
00208                         // call the function at offset yy yy of class xx xx
00209                         op.i0 = read2(ucfile);
00210                         op.i1 = read2(ucfile);
00211                         break;
00212                 case 0x12:
00213                         // 12
00214                         // pop 16bits into temp register
00215                         break;
00216 
00217                 case 0x14:
00218                         // 14
00219                         // pop two values from the stack and push the sum
00220                         break;
00221                 case 0x15:
00222                         // 15
00223                         // add two longs
00224                         break;
00225                 case 0x16:
00226                         // 16
00227                         // pop two strings from the stack and push the concatenation
00228                         break;
00229                 case 0x17:
00230                         // 17
00231                         // pop two lists from the stack and push the 'sum' of the lists
00232                         break;
00233                 case 0x19:
00234                         // 19 02
00235                         // add two stringlists
00236                         op.i0 = read1(ucfile);
00237                         break;
00238                 case 0x1A:
00239                         // 1A
00240                         // pop two string lists from the stack and remove the 2nd from the 1st
00241                         op.i0 = read1(ucfile);
00242                         break;
00243                 case 0x1B:
00244                         // 1B
00245                         // pop two lists from the stack and remove the 2nd from the 1st
00246                         op.i0 = read1(ucfile);
00247                         break;
00248                 case 0x1C:
00249                         // 1C
00250                         // subtract two integers
00251                         break;
00252                 case 0x1D:
00253                         // 1D
00254                         // subtract two dwords
00255                         break;
00256                 case 0x1E:
00257                         // 1E
00258                         // multiply two integers
00259                         break;
00260                 case 0x1F:
00261                         // 1F
00262                         // multiply two dwords
00263                         break;
00264                 case 0x20:
00265                         // 20
00266                         // divide two integers
00267                         break;
00268                 case 0x21:
00269                         // 21
00270                         // divide two dwords
00271                         break;
00272                 case 0x22:
00273                         // 22
00274                         // mod
00275                         break;
00276                 case 0x23:
00277                         // 23
00278                         // mod long
00279                         assert(false); // Guessed opcode
00280                         break;
00281                 case 0x24:
00282                         // 24
00283                         // compare two integers
00284                         break;
00285                 case 0x25:
00286                         // 24
00287                         // compare two dwords
00288                         assert(false); // Guessed opcode
00289                         break;
00290                 case 0x26:
00291                         // 26
00292                         // compare two strings
00293                         break;
00294                 case 0x28:
00295                         // 28
00296                         // less than
00297                         break;
00298                 case 0x29:
00299                         // 29
00300                         // less than 32 bit
00301                         break;
00302                 case 0x2A:
00303                         // 2A
00304                         // less than or equal to
00305                         break;
00306                 case 0x2B:
00307                         // 2B
00308                         // less than or equal to 32 bit
00309                         break;
00310                 case 0x2C:
00311                         // 2C
00312                         // greater than
00313                         break;
00314                 case 0x2D:
00315                         // 2D
00316                         // greater than 32 bit
00317                         break;
00318                 case 0x2E:
00319                         // 2E
00320                         // 'greater than or equal to'
00321                         break;
00322                 case 0x2F:
00323                         // 2F
00324                         // 'greater than or equal to' (longs)
00325                         break;
00326                 case 0x30:
00327                         // 30
00328                         // pops a boolean from the stack and pushes the boolean not
00329                         break;
00330                 case 0x31:
00331                         // 31
00332                         // pops a boolean from the stack and pushes the boolean not
00333                         break;
00334                 case 0x32:
00335                         // 32
00336                         // pops two booleans from the stack and pushes the boolean and
00337                         break;
00338                 case 0x33:
00339                         // 33
00340                         // pops two booleans from the stack and pushes the boolean and
00341                         break;
00342                 case 0x34:
00343                         // 34
00344                         // boolean or
00345                         break;
00346                 case 0x35:
00347                         // 35
00348                         // boolean or
00349                         break;
00350                 case 0x36:
00351                         // 36
00352                         // are two integers not equal?
00353                         break;
00354                 case 0x37:
00355                         // 37
00356                         // are two dwords not equal?
00357                         break;
00358 
00359                 case 0x38:
00360                         // 38 xx yy
00361                         // pops a list (or slist if yy==true) from the stack, then pops
00362                         // a value from the stack that it needs to test if it's in the
00363                         // list, pushing 'true' if it is, 'false' if it isn't. 'xx' is
00364                         // the 'size' of each list element, as is true for most list
00365                         // opcodes.
00366                         op.i0 = read1(ucfile); op.i1 = read1(ucfile);
00367                         break;
00368 
00369                 case 0x39:
00370                         // 39
00371                         // bitwise and
00372                         break;
00373                 case 0x3A:
00374                         // 3A
00375                         // bitwise or
00376                         break;
00377                 case 0x3B:
00378                         // 3B
00379                         // bitwise not
00380                         break;
00381                 case 0x3C:
00382                         // 3C
00383                 // left shift
00384                         break;
00385                 case 0x3D:
00386                         // 3D
00387                         // right shift
00388                         break;
00389 
00390                 case 0x3E:
00391                         // 3E xx
00392                         // push the value of the 8 bit local var xx ??
00393                         op.i0 = read1(ucfile);
00394                         break;
00395                 case 0x3F:
00396                         // 3F xx
00397                         // push the value of the 16 bit local var xx
00398                         op.i0 = read1(ucfile);
00399                         break;
00400                 case 0x40:
00401                         // 40 xx
00402                         // push the value of the 32 bit local var xx ??
00403                         op.i0 = read1(ucfile);
00404                         break;
00405                 case 0x41:
00406                         // 41 xx
00407                         // push the string local var at BP+xx
00408                         op.i0 = read1(ucfile);
00409                         break;
00410                 case 0x42:
00411                         // 42 xx yy
00412                         // push the list (with yy size elements) at BP+xx
00413                         op.i0 = read1(ucfile); op.i1 = read1(ucfile);
00414                         break;
00415                 case 0x43:
00416                         // 43 xx
00417                         // push the stringlist local var at BP+xx
00418                         op.i0 = read1(ucfile);
00419                         break;
00420                 case 0x44:
00421                         // 44 xx yy
00422                         // push element from the second last var pushed onto the stack
00423                         // (a list/slist), indexed by the last element pushed onto the list
00424                         // (a byte/word). XX is the size of the types contained in the list
00425                         // YY is true if it's a slist (for garbage collection)
00426                         op.i0 = read1(ucfile); op.i1 = read1(ucfile);
00427                         break;
00428                 case 0x45:
00429                         // 45
00430                         // push huge
00431                         op.i0 = read1(ucfile); op.i1 = read1(ucfile);
00432                         break;
00433                 case 0x4B:
00434                         // 4B xx
00435                         // push 32 pointer address of BP+XX
00436                         op.i0 = read1(ucfile);
00437                         break;
00438                 case 0x4C:
00439                         // 4C xx
00440                         // indirect push,
00441                         // pops a 32 bit pointer off the stack and pushes xx bytes
00442                         // from the location referenced by the pointer
00443                         op.i0 = read1(ucfile);
00444                         break;
00445                 case 0x4D:
00446                         // 4D xx
00447                         // indirect pop,
00448                         // pops a 32 bit pointer off the stack and then pops xx bytes
00449                         // into the location referenced by the pointer
00450                         op.i0 = read1(ucfile);
00451                         break;
00452 
00453                 case 0x4E:
00454                         // 4E xx xx yy
00455                         // push global xx xx size yy
00456                         op.i0 = read2(ucfile); op.i1 = read1(ucfile);
00457                         break;
00458                 case 0x4F:
00459                         // 4F xx xx yy
00460                         // pop value into global xx xx size yy
00461                         op.i0 = read2(ucfile); op.i1 = read1(ucfile);
00462                         break;
00463 
00464                 case 0x50:
00465                         // 50
00466                         // return from function
00467                         break;
00468                 case 0x51:
00469                         // 51 xx xx
00470                         // relative jump to xxxx if false
00471                         op.i0 = read2(ucfile);
00472                         break;
00473                 case 0x52:
00474                         // 52 xx xx
00475                         // relative jump to xxxx
00476                         op.i0 = read2(ucfile);
00477                         break;
00478 
00479                 case 0x53:
00480                         // 50
00481                         // suspend function
00482                         break;
00483 
00484                 case 0x54:
00485                         // 54 xx yy
00486                         // implies
00487                         // this seems to link two processes, 'implying' that if one terminates,
00488                         // the other does also, but it's mostly a guess. *grin*
00489                         op.i0 = read1(ucfile); op.i1 = read1(ucfile);
00490                         break;
00491 
00492                 case 0x57:
00493                         // 57 aa tt xx xx yy yy
00494                         // spawn process function yyyy in class xxxx
00495                         // aa = number of arg bytes pushed
00496                         //      (not including this pointer which is 4 bytes)
00497                         // tt = sizeof this pointer object
00498                         op.i0 = read1(ucfile); op.i1 = read1(ucfile);
00499                         op.i2 = read2(ucfile); op.i3 = read2(ucfile);
00500                         break;
00501                 case 0x58:
00502                         // 58 xx xx yy yy zz zz tt uu
00503                         // spawn inline process function yyyy in class xxxx at offset zzzz
00504                         // tt = size of this pointer
00505                         // uu = unknown
00506                         op.i0 = read2(ucfile); op.i1 = read2(ucfile);
00507                         op.i2 = read2(ucfile);
00508                         op.i3 = read1(ucfile); op.i4 = read1(ucfile);
00509                         break;
00510                 case 0x59:
00511                         // 59
00512                         // push process id of current process
00513                         break;
00514 
00515                 case 0x5A:
00516                         // 5A xx
00517                         // init function. xx = local var size
00518                         // sets xx bytes on stack to 0, and moves sp by xx
00519                         op.i0 = read1(ucfile);
00520                         break;
00521 
00522                 case 0x5B:
00523                         // 5B xx xx
00524                         // the current sourcecode line number
00525                         op.i0 = read2(ucfile);
00526                         break;
00527                 case 0x5C:
00528                         {
00529                                 // 5C xx xx yy yy yy yy yy yy yy yy 00
00530                                 // debugging symbol information
00531                                 // xxxx is the offset to one past the last 'ret' in the function, which
00532                                 // will be pointing to an 0x7a opcode if there is no debug info, else
00533                                 // to the first byte of the debug info.
00534                                 // yy .. yy is the class' name
00535                                 op.i0 = read2(ucfile);
00536                                 //assert(curOffset + (static_cast<short>(op.i0))==op.offset + 3 + (static_cast<short>(op.i0)));
00537                                 op.i0 = curOffset + (static_cast<short>(op.i0));
00538                                 op.str = "";
00539                                 for (uint32 i=0; i < 8; ++i)
00540                                  op.str += static_cast<char>(read1(ucfile));
00541                                 if(read1(ucfile)!=0) assert(false); // trailing 0
00542                                 dbg_symbol_offset = op.i0; // the offset to the raw symbol data.
00543                                         // nothing between it and the 0x7a opcode is opcodes
00544                                 break;
00545                         }
00546 
00547                 case 0x5D:
00548                         // 5D
00549                         // push 8 bit value returned from function call
00550                         break;
00551                 case 0x5E:
00552                         // 5E
00553                         // push 16 bit value returned from function call
00554                         break;
00555                 case 0x5F:
00556                         // 5F
00557                         // push 32 bit value returned from function call?
00558                         break;
00559 
00560                 case 0x60:
00561                         // 60
00562                         // word to dword (sign extend)
00563                         break;
00564                 case 0x61:
00565                         // 61
00566                         // dword to word
00567                         break;
00568 
00569                 case 0x62:
00570                         // 62 xx
00571                         // free the string in var BP+xx
00572                         op.i0 = read1(ucfile);
00573                         break;
00574                 case 0x63:
00575                         // 63 xx
00576                         // free the list in var BP+xx
00577                         // (This one seems to be similar to 0x64 but only used for lists
00578                         //  of strings?)
00579                         op.i0 = read1(ucfile);
00580                         break;
00581                 case 0x64:
00582                         // 64 xx
00583                         // free the list in var BP+xx
00584                         op.i0 = read1(ucfile);
00585                         break;
00586                 case 0x65:
00587                         // 65 xx
00588                         // free string at SP+xx
00589                         op.i0 = read1(ucfile);
00590                         break;
00591                 case 0x66:
00592                         // 66 xx
00593                         // free the list at SP+xx
00594                         op.i0 = read1(ucfile);
00595                         break;
00596                 case 0x67:
00597                         // 66 xx
00598                         // free the string list at SP+xx
00599                         op.i0 = read1(ucfile);
00600                         break;
00601                 case 0x69:
00602                         // 69 xx
00603                         // push the string in var BP+xx as 32 bit pointer
00604                         op.i0 = read1(ucfile);
00605                         break;
00606                 case 0x6B:
00607                         // 6B
00608                         // pop a string and push 32 bit pointer to string
00609                         break;
00610 
00611 // Just my ramblings on 0x6C. It's a bit of a mess since it's taken from an irc log
00612 // but it's the best documentation we have on it at the moment. *grin*
00613 
00614 /* Anyway, the number at the end (01 in the above example) means the type of
00615 pointer the offset points to. 01==string ptr, 02==string list ptr, 03==list
00616 ptr. 01 and 03 are verified, 02 is an educated guess, and I'm pretty sure it's
00617 a BP+xxh value too from looking at the usecode.
00618  *lightbulb* It looks like it may have been used for pointer/reference
00619 stuff. For example:
00620  When a 'string' type is created, the actual string is stored in a Yamm
00621 class instantiation local to the current thread, only the reference to it is
00622 stored on the stack.
00623  When a pointer to this string is passed to another newly created thread,
00624 the data pointed to in the original thread's Yamm needs to be copied to the
00625 newly constructed thread, incase the original thread terminates, (or the
00626 function just returns destroying the data), before the spawned thread uses it.
00627  This is where Mr 0x6C comes in. He takes a pointer to the
00628 oritinal variable, copies the data from the Parent Yamm to it's (the Child's)
00629 Yamm.
00630  Eg: The call in Class 007C:
00631      371F: 59    push            pid
00632      3720: 42    push list       [BP-0Ah] (02)
00633      3723: 42    push list       [BP-0Ch] (02)
00634      3726: 42    push list       [BP-0Eh] (02)
00635      3729: 41    push string     [BP-02h]
00636      372B: 40    push dword      [BP+06h]
00637      372D: 57    spawn           08 02 007C:3757 (unknown)
00638      3734: 66    free list       [SP+06h]
00639      3736: 66    free list       [SP+04h]
00640      3738: 66    free list       [SP+02h]
00641      373A: 65    free string     [SP+00h]
00642      373C: 6E    add sp          -08h
00643      373E: 5E    push            retval
00644  Then the start of the newly spawned function:
00645  Func_3757:
00646      3757: 5A    init            0D
00647      3759: 6C    6C              [BP+0Ah] 01
00648      375C: 6C    6C              [BP+0Ch] 03
00649      375F: 6C    6C              [BP+0Eh] 03
00650      3762: 6C    6C              [BP+10h] 03
00651      3765: 0A    push byte       01h
00652  The type value (01/02/03) at the end tells the opcode what type of data
00653 it's copying or reconstructing. And if you look closely, you'll note there's a
00654 'tiny' flaw in this opcode. In all the other list (not string list) related
00655 opcodes another value is passed, the size of the datatype stored in the array.
00656 This opcode lacks that value, and thus assumes that all datatypes for 03
00657 (list) are 2 bytes wide.
00658  Of course, this also tells us something about how the processes were
00659 executed and/or queued. Either:
00660  1) When a new thread is created by a spawn, it is immediately executed
00661 until it hits the first opcode that 'sleeps' it until the next cycle, and that
00662 the 'init' and 0x6C opcodes are not 'sleep' inducing opcodes.
00663  Or 2) The 'spawn' is a 'sleep' inducing opcode, and the new process is
00664 scheduled to be executed before the 'current' thread in the queue (whether it
00665 just be inserted before, or first, who knows *grin*). That way upon the next
00666 awakening of all the threads, the spawned thread gets the chance to copy all
00667 the relevant data from it's parent thread, before it's parent has a chance to
00668 terminate.
00669  Also in the second case, as in the first case, the 'init' and
00670 '0x6C' opcodes aren't 'sleep' inducing.
00671 
00672 The general consensus is that the new threads are executed instantly upon creation,
00673 and that the child threads are indeed placed infront of the parent thread.
00674 */
00675                 case 0x6C:
00676                         // 6C xx yy
00677                         // looks to be a BP+XX function... maybe not
00678                         op.i0 = read1(ucfile); op.i1 = read1(ucfile);
00679                         break;
00680 
00681                 case 0x6D:
00682                         // 6D
00683                         // push result of process
00684                         break;
00685                 case 0x6E:
00686                         // 6E xx
00687                         // add xx to stack pointer
00688                         op.i0 = read1(ucfile);
00689                         break;
00690                 case 0x6F:
00691                         // 6F xx
00692                         // push 32 pointer address of SP-xx
00693                         op.i0 = read1(ucfile);
00694                         break;
00695 
00696                 // loop-related opcodes
00697                 // Theory: put a 'container object' on the stack, and this will
00698                 // loop over the objects in there. The 'loopscript' determines
00699                 // which objects are selected. (By a simple 'shape == x, frame == y'
00700                 // thing, it seems)
00701                 // See the abacus code (function 375) for a simple example
00702 
00703                 case 0x70:
00704                         // 70 xx yy zz
00705                         // loop something. Stores 'current object' in var xx
00706                         // yy == num bytes in string
00707                         // zz == type
00708                         op.i0 = read1(ucfile); op.i1 = read1(ucfile); op.i2 = read1(ucfile);
00709                         break;
00710                 case 0x73:
00711                         // 73
00712                         // next loop object? pushes false if end reached
00713                         break;
00714                 case 0x74:
00715                         // 74 xx
00716                         // add xx to the current 'loopscript'
00717                         op.i0 = read1(ucfile);
00718                         break;
00719 
00720                 // 75 appears to have something to do with lists, looks like an enum/next from u7...
00721                 case 0x75:
00722                         // 75 xx yy zz zz
00723                         // xx appears to be the location to store 'current' value from the
00724                         //   list (BP+xx)
00725                         // yy is the 'datasize' of the list, identical to the second parameter
00726                         //   of the create list/slist opcodes
00727                         // zzzz appears to be the offset to jump to after it's finished the
00728                         //   iteration, the opcode before is a 'jmp' to the original position
00729                         //   of the opcode.
00730                         // (all guesses from Remorse1.21 usecode, _may_ be different in u8,
00731                         //   unlikely though)
00732                         // the way it appears to operate is it pops a 'word' off the stack
00733                         //   (maximum number of items to iterate through? No idea, I've only
00734                         //   seen 0xFFFF pushed before it (in Remorse1.21)), then pops
00735                         //   the 'list' off to iterate through
00736                         op.i0 = read1(ucfile); op.i1 = read1(ucfile); op.i2 = read2(ucfile);
00737                         break;
00738 
00739                 /* 76 appears to be identical to 0x75, except it operates on slists */
00740                 case 0x76:
00741                         // 75 xx yy zz zz
00742                         op.i0 = read1(ucfile); op.i1 = read1(ucfile); op.i2 = read2(ucfile);
00743                         break;
00744 
00745                 case 0x77:
00746                         // 77
00747                         // set info
00748                         // assigns item number and ProcessType, both values popped from the stack
00749                         break;
00750 
00751                 case 0x78:
00752                         // 78
00753                         // process exclude
00754                         // sets a flag on the object target of the 'current' function call that
00755                         // said function call has exclusive use of the object until the call
00756                         // returns.
00757                         break;
00758 
00759 /*
00760 <Darke> Add global_address to the list of Things That Are Evil About U8Usecode.
00761 <Colourless> why? what's *it's* problem?
00762 <Darke> It makes no sense. *grin*
00763 <Colourless> hehe
00764 <Darke> None! None what so ever!
00765 <Darke> AFAICT, it's only use it to push the address of the global variable to the stack.
00766         Said global variable appears to hold a 'this' pointer to something.
00767 <Darke> There is, afaict, no difference between doing a 'global_address 003C' and doing a
00768         `push global [003C 04]; push addr [SP-00h];`
00769 <Darke> Ok, fine, it _is_ used 667 times in remorse1.21, but I can't see how there could be
00770         an incredible speedup replacing two simple opcodes with a single opcode.
00771 <Colourless> so that's what it does
00772 <Darke> And it's always followed by either a calli or a spawn. So that means that it's
00773         'always' a 4 byte 'this' pointer stored in it.
00774 <Darke> Same in no regret.
00775 <Darke> So it's 'obviously' _never_ modified (which was the only possible problem with the
00776         push/push addr I could see, you'd need to have an appropriate 'un-addr' then pop after
00777         it)... I really can't see the point. *shrug*
00778 */
00779                 case 0x79:
00780                         // 79
00781                         // end of function
00782                         // 79 xx xx
00783                         // global_address
00784                         // push the address of the global xxxx onto the stack
00785                         if (crusader) // it's not eof for crusader...
00786                         {
00787                                 op.i0 = read2(ucfile);
00788                         }
00789                         else // but it is for U8
00790                         {
00791                                 op.op(0x7A); // we'll translate it to the crusader's end to simplify things
00792                                 done = true;
00793                         }
00794                         break;
00795 
00796                         case 0x7A:
00797                         // end of function (79 = u8, 7a = crusader)
00798                         printDbgSymbols(debugSymbols);
00799                         done = true;
00800                         break;
00801 
00802                 // can't happen.
00803                 default:
00804                         con.Printf("db\t\t%02X", op.op());
00805                         assert(false);
00806                 }
00807 
00808                 op.nextoffset=curOffset;
00809 }
00810 
00811 #include "FuncNodes.h"
00812 #include "VarNodes.h"
00813 #include "CallNodes.h"
00814 #include "OperatorNodes.h"
00815 #include "IfNode.h"
00816 
00817 /* This needs to be shuffled into two different readOp() functions, one in Convert*Crusader, and
00818         the other in Convert*U8 */
00819 Node *ConvertUsecode::readOpGeneric(IDataSource *ucfile, uint32 &dbg_symbol_offset, std::vector<DebugSymbol> &debugSymbols,
00820         bool &done, const bool crusader)
00821 {
00822         Node *n=0;
00823         uint32 opcode=0;
00824         static std::string tstring;
00825         
00826         if(dbg_symbol_offset==curOffset)
00827         {
00828                 readDbgSymbols(ucfile, debugSymbols);
00829                 opcode = read1(ucfile);
00830                 assert(opcode==0x7a);
00831         }
00832         else
00833                 opcode = read1(ucfile);
00834         
00835         uint32 offset = curOffset-1;
00836         
00837         switch(opcode) {
00838                 case 0x01: // pop a word into a local var
00839                         n = new PopVarNode(opcode, offset, read1(ucfile));
00840                         break;
00841                 case 0x0A: // pushing a byte (1 byte)
00842                         n = new PushVarNode(opcode, offset, read1(ucfile));
00843                         break;
00844                 case 0x0B: // pushing a word (2 bytes)
00845                         n = new PushVarNode(opcode, offset, read2(ucfile));
00846                         break;
00847                 case 0x0C: // pushing a dword (4 bytes)
00848                         n = new PushVarNode(opcode, offset, read4(ucfile));
00849                         break;
00850                 case 0x0D: // push string (xxxx bytes)
00851                         {
00852                                 uint32 tint = read2(ucfile);
00853                                 tstring.clear();
00854                                 while (char c = static_cast<char>(read1(ucfile))) tstring += c;
00855                                 n = new PushVarNode(opcode, offset, tint, tstring);
00856                         }
00857                         break;
00858                 case 0x0F: // calli
00859                         {
00860                                 uint32 tint=read1(ucfile);
00861                                 n = new DCCallNode(opcode, offset, tint, read2(ucfile));
00862                         }
00863                         break;
00864                 case 0x11: // call
00865                         {
00866                                 uint32 tint=read2(ucfile);
00867                                 n = new DCCallNode(opcode, offset, tint, read2(ucfile));
00868                         }
00869                         break;
00870                 case 0x12: // pop temp
00871                         n = new PopVarNode(opcode, offset);
00872                         break;
00873                 case 0x14: // add
00874                 case 0x1C: // sub
00875                 case 0x1E: // mul
00876                 case 0x24: // cmp
00877                 case 0x28: // lt
00878                 case 0x2A: // le
00879                 case 0x2C: // gt
00880                         n = new BinOperatorNode(opcode, offset);
00881                         break;
00882                 case 0x30: // not
00883                         n = new UniOperatorNode(opcode, offset);
00884                         break;
00885                 case 0x32: // and
00886                         n = new BinOperatorNode(opcode, offset);
00887                         break;
00888                 case 0x34: // or
00889                         n = new BinOperatorNode(opcode, offset);
00890                         break;
00891                 case 0x36: // ne
00892                         n = new BinOperatorNode(opcode, offset);
00893                         break;
00894                 case 0x3F: // pushing a word var (2 bytes)
00895                         n = new PushVarNode(opcode, offset, read1(ucfile));
00896                         break;
00897                 case 0x40: // pushing a dword var (4 bytes)
00898                         n = new PushVarNode(opcode, offset, read1(ucfile));
00899                         break;
00900                 case 0x4B: // pushing an address (4 bytes)
00901                         n = new PushVarNode(opcode, offset, read1(ucfile));
00902                         break;
00903                 case 0x4C: // push indirect
00904                         n = new DCCallMutatorNode(opcode, offset, read1(ucfile));
00905                         break;
00906                 case 0x4E: // push global
00907                         {
00908                                 uint32 tint = read2(ucfile);
00909                                 n = new PushVarNode(opcode, offset, tint, read1(ucfile));
00910                         }
00911                         break;
00912                 case 0x50: // ret
00913                         n = new FuncMutatorNode(opcode, offset);
00914                         break;
00915                 case 0x51: // jne
00916                         n = new IfNode(opcode, offset, offset + 3 + static_cast<uint16>(read2(ucfile)));
00917                         break;
00918                 case 0x52: // jmp
00919                         n = new EndNode(opcode, offset, offset + 3 + static_cast<uint16>(read2(ucfile)));
00920                         break;
00921                 case 0x53: // suspend
00922                         n = new FuncMutatorNode(opcode, offset);
00923                         break;
00924                 case 0x54: // implies
00925                         { // we'll read and ignore the two parameters to implies, since they're always 01 01
00926                                 uint32 tint1 = read1(ucfile);
00927                                 uint32 tint2 = read1(ucfile);
00928                                 assert(tint1==1 && tint2==1);
00929                                 n = new BinOperatorNode(opcode, offset);
00930                         }
00931                         break;
00932                 case 0x57: // spawn
00933                         {
00934                                 uint32 tint1 = read1(ucfile);
00935                                 uint32 tint2 = read1(ucfile);
00936                                 uint32 tint3 = read2(ucfile);
00937                                 n = new DCCallNode(opcode, offset, tint1, tint2, tint3, read2(ucfile));
00938                         }
00939                         break;
00940                 case 0x59: // push pid
00941                         n = new PushVarNode(opcode, offset);
00942                         break;
00943                 case 0x5A: // init
00944                         n = new FuncMutatorNode(opcode, offset, read1(ucfile));
00945                         break;
00946                 case 0x5B: // line number
00947                         n = new FuncMutatorNode(opcode, offset, read2(ucfile));
00948                         break;
00949                 case 0x5C: // symbol info
00950                         {
00951                                 uint32 tint = offset + 3 + static_cast<sint16>(read2(ucfile));
00952                                 dbg_symbol_offset = tint;
00953                                 n = new FuncMutatorNode(opcode, offset, tint, readnstr(ucfile, 9));
00954                         }
00955                         break;
00956                 case 0x5D: // push byte retval
00957                 case 0x5E: // push retval
00958                         n = new DCCallPostfixNode(opcode, offset);
00959                         break;
00960                 case 0x65: // free string
00961                         n = new DCCallPostfixNode(opcode, offset, read1(ucfile));
00962                         break;
00963                 case 0x6B: // str to ptr
00964                         n = new UniOperatorNode(opcode, offset);
00965                         break;
00966                 case 0x6E: // add sp
00967                         n = new DCCallPostfixNode(opcode, offset, read1(ucfile));
00968                         break;
00969                 case 0x70: // loop
00970                         {
00971                                 uint32 currobj = read1(ucfile);
00972                                 uint32 strsize = read1(ucfile);
00973                                 uint32 type = read1(ucfile);
00974                                 n = new LoopNode(opcode, offset, currobj, strsize, type);
00975                         }
00976                         break;
00977                 //case 0x73: // loopnext
00978                 //      n = new LoopNextNode(opcode, offset);
00979                 //      break;
00980                 case 0x74: // loopscr
00981                         n = new LoopScriptNode(opcode, offset, read1(ucfile));
00982                         break;
00983                 case 0x77: // set info
00984                         n = new DCCallMutatorNode(opcode, offset);
00985                         break;
00986                 case 0x78: // process exclude
00987                         n = new DCCallMutatorNode(opcode, offset);
00988                         break;
00989                 case 0x79: // end of function / global_address
00990                         if (crusader) // it's not eof for crusader...
00991                         {
00992                                 assert(false); //TODO: Implement!: op.i0 = read2(ucfile);
00993                         }
00994                         else // but it is for U8
00995                         {
00996                                 n = new FuncMutatorNode(0x7A, offset); // we'll translate it to the crusader's end to simplify things
00997                                 done = true;
00998                         }
00999                         break;
01000                 case 0x7A: // end
01001                         n = new FuncMutatorNode(opcode, offset);
01002                         done = true;
01003                         break;
01004                 
01005                 // can't happen.
01006                 default:
01007                         con.Printf("\n*** ERROR?:");
01008                         con.Printf("\n*** potential opcode:\t%02X", opcode);
01009                         con.Printf("\n*** next four bytes:\t");
01010                         printbytes(ucfile, 4);
01011                         con.Putchar('\n');
01012                         return 0;
01013         }
01014         
01015         return n;
01016 }
01017 /* This looks _real_ dubious. Instead of loading all the offsets from the
01018    files and converting them to pair<uint32, uint32>, we're storing them in
01019    memory as strings, then having to convert the class:offset pair into a
01020    string, and strcmping against them. So instead of having a 2*O(N) operation
01021    at read, and a 2*O(1)*O(logN) at search. We've got a O(N) operation at read,
01022    and a O(N)*O(logN) for _each_ search. */
01023 std::string ConvertUsecode::UsecodeFunctionAddressToString(const sint32 uclass, const sint32 coffset, IDataSource *ucfile, const bool crusader)
01024 {
01025         char buf[MAX_UCFUNC_NAMELEN];
01026         
01027         #if 0 // FuncName stuff doesn't seem to be used anymore...
01028         std::map<string, string>::iterator funcoffset = FuncNames.find(buf);
01029 
01030         snprintf(buf, MAX_UCFUNC_NAMELEN, "%04X:%04X", uclass, coffset);
01031         funcoffset = FuncNames.find(buf);
01032         if (funcoffset != FuncNames.end())
01033                 return funcoffset->second;
01034         #endif
01035         
01036         // Attempt to grab function name of the requested func
01037 
01038         // Save the original pos
01039         uint32 origpos = ucfile->getPos();
01040 
01041         // Seek to index table entry 1
01042         ucfile->seek(0x80 + 8);
01043 
01044         // Get details
01045         sint32 offset = ucfile->read4();
01046         /*sint32 length =*/ ucfile->read4();
01047 
01048         // Seek to name entry
01049         ucfile->seek(offset + uclass*13 + 4);
01050 
01051         // Read name
01052         buf[0]='\0';
01053         ucfile->read(buf, 9);
01054 
01055         // Return to the pos
01056         ucfile->seek(origpos);
01057 
01058         // Couldn't get name, just use number
01059         if (!buf[0]) snprintf(buf, MAX_UCFUNC_NAMELEN, "%04X", uclass);
01060 
01061         // String to return
01062         std::string str = buf;
01063 
01064         // This will only work in crusader
01065         if (crusader)
01066         {
01067                 if (coffset < 0x20)
01068                 {
01069                         return str + "::" + event_names()[coffset];
01070                 }
01071                 else
01072                 {
01073                         snprintf(buf, MAX_UCFUNC_NAMELEN, "%02X", coffset);
01074                         return str + "::ordinal" + buf;
01075                 }
01076         }
01077         // For Ultima 8
01078         else
01079         {
01080                 snprintf(buf, MAX_UCFUNC_NAMELEN, "%04X", coffset);
01081                 return str + "::" + buf;
01082         }
01083         
01084         CANT_HAPPEN();
01085         // Shouldn't ever get here
01086         return "unknown";
01087 }
01088 
01089 #endif

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