Update ooo320-m1
[ooovba.git] / basic / source / classes / disas.cxx
blob0e5a376bac2db6e56fd502cb1dd433343942aaa1
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: disas.cxx,v $
10 * $Revision: 1.28 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_basic.hxx"
34 #include <stdio.h>
35 #include <string.h>
36 #include <tools/stream.hxx>
37 #include <basic/sbx.hxx>
38 #include "sb.hxx"
39 #include "iosys.hxx"
40 #include "disas.hxx"
43 static const char* pOp1[] = {
44 "NOP",
46 // Operators
47 // the following operators have the same order as in
48 // enum SbxVarOp
49 "EXP", "MUL", "DIV", "MOD", "PLUS", "MINUS", "NEG",
50 "EQ", "NE", "LT", "GT", "LE", "GE",
51 "IDIV", "AND", "OR", "XOR", "EQV", "IMP", "NOT",
52 "CAT",
53 // End enum SbxVarOp
54 "LIKE", "IS",
55 // Load/Store
56 "ARGC", // Create new Argv
57 "ARGV", // TOS ==> current Argv
58 "INPUT", // Input ==> TOS
59 "LINPUT", // Line Input ==> TOS
60 "GET", // get TOS
61 "SET", // Save Object TOS ==> TOS-1
62 "PUT", // TOS ==> TOS-1
63 "CONST", // TOS ==> TOS-1, then ReadOnly
64 "DIM", // DIM
65 "REDIM", // REDIM
66 "REDIMP", // REDIM PRESERVE
67 "ERASE", // delete TOS
68 // Branch
69 "STOP", // End of program
70 "INITFOR", // FOR-Variable init
71 "NEXT", // FOR-Variable increment
72 "CASE", // Begin CASE
73 "ENDCASE", // End CASE
74 "STDERR", // Default error handling
75 "NOERROR", // No error handling
76 "LEAVE", // leave UP
77 // I/O
78 "CHANNEL", // TOS = Channelnumber
79 "PRINT", // print TOS
80 "PRINTF", // print TOS in field
81 "WRITE", // write TOS
82 "RENAME", // Rename Tos+1 to Tos
83 "PROMPT", // TOS = Prompt for Input
84 "RESTART", // Define restart point
85 "STDIO", // Switch to I/O channel 0
86 // Misc
87 "EMPTY", // Empty statement to stack
88 "ERROR", // TOS = error code
89 "LSET", // Save object TOS ==> TOS-1
90 "RSET", // Save object TOS ==> TOS-1 (TODO: Same as above?)
91 "REDIMP_ERASE",
92 "INITFOREACH",
93 "VBASET",
94 "ERASE_CLEAR",
95 "ARRAYACCESS"
98 static const char* pOp2[] = {
99 "NUMBER", // Load a numeric constant (+ID)
100 "STRING", // Load a string constant (+ID)
101 "CONSTANT", // Immediate Load (+value)
102 "ARGN", // Save named args in argv (+StringID)
103 "PAD", // Pad String to defined length (+length)
104 // Branches
105 "JUMP", // Jump to target (+Target)
106 "JUMP.T", // evaluate TOS, conditional jump (+Target)
107 "JUMP.F", // evaluate TOS, conditional jump (+Target)
108 "ONJUMP", // evaluate TOS, jump into JUMP-table (+MaxVal)
109 "GOSUB", // UP-Call (+Target)
110 "RETURN", // UP-Return (+0 or Target)
111 "TESTFOR", // Test FOR-Variable, increment (+Endlabel)
112 "CASETO", // Tos+1 <= Case <= Tos, 2xremove (+Target)
113 "ERRHDL", // Error-Handler (+Offset)
114 "RESUME", // Resume after errors (+0 or 1 or Label)
115 // I/O
116 "CLOSE", // (+channel/0)
117 "PRCHAR", // (+char)
118 // Objects
119 "SETCLASS", // Test Set + Classname (+StringId)
120 "TESTCLASS", // Check TOS class (+StringId)
121 "LIB", // Set Libname for Declare-Procs (+StringId)
122 // New since Beta 3 (TODO: Which Beta3?)
123 "BASED", // TOS is incremted about BASE, push BASE before
124 "ARGTYP", // Convert last parameter in argv (+Type)
125 "VBASETCLASS",
128 static const char* pOp3[] = {
129 // All opcodes with two operands
130 "RTL", // Load from RTL (+StringID+Typ)
131 "FIND", // Load (+StringID+Typ)
132 "ELEM", // Load element (+StringID+Typ)
133 "PARAM", // Parameter (+Offset+Typ)
135 // Branching
136 "CALL", // Call DECLARE method (+StringID+Typ)
137 "CALL.C", // Call Cdecl-DECLARE method (+StringID+Typ)
138 "CASEIS", // Case-Test (+Test-Opcode+False-Target)
139 "STMNT", // Start of a statement (+Line+Col)
141 // I/O
142 "OPEN", // (+SvStreamFlags+Flags)
144 // Objects and variables
145 "LOCAL", // Local variables (+StringID+Typ)
146 "PUBLIC", // Modul global var (+StringID+Typ)
147 "GLOBAL", // Global var (+StringID+Typ)
148 "CREATE", // Create object (+StringId+StringId)
149 "STATIC", // Create static object (+StringId+StringId)
150 "TCREATE", // Create User defined Object (+StringId+StringId)
151 "DCREATE", // Create User defined Object-Array kreieren (+StringId+StringId)
152 "GLOBAL_P", // Define persistent global var (existing after basic restart)
153 // P=PERSIST (+StringID+Typ)
154 "FIND_G", // Searches for global var with special handling due to _GLOBAL_P
155 "DCREATE_REDIMP", // Change dimensions of a user defined Object-Array (+StringId+StringId)
156 "FIND_CM", // Search inside a class module (CM) to enable global search in time
157 "PUBLIC_P", // Module global Variable (persisted between calls)(+StringID+Typ)
160 static const char** pOps[3] = { pOp1, pOp2, pOp3 };
162 typedef void( SbiDisas::*Func )( String& ); // Processing routines
164 static const Func pOperand2[] = {
165 &SbiDisas::StrOp, // Load a numeric constant (+ID)
166 &SbiDisas::StrOp, // Load a string constant (+ID)
167 &SbiDisas::ImmOp, // Immediate Load (+Wert)
168 &SbiDisas::StrOp, // Save a named argument (+ID)
169 &SbiDisas::ImmOp, // Strip String to fixed size (+length)
171 // Branches
172 &SbiDisas::LblOp, // Jump (+Target)
173 &SbiDisas::LblOp, // eval TOS, conditional jump (+Target)
174 &SbiDisas::LblOp, // eval TOS, conditional jump (+Target)
175 &SbiDisas::OnOp, // eval TOS, jump in JUMP table (+MaxVal)
176 &SbiDisas::LblOp, // UP call (+Target)
177 &SbiDisas::ReturnOp, // UP Return (+0 or Target)
178 &SbiDisas::LblOp, // test FOR-Variable, increment (+Endlabel)
179 &SbiDisas::LblOp, // Tos+1 <= Case <= Tos), 2xremove (+Target)
180 &SbiDisas::LblOp, // Error handler (+Offset)
181 &SbiDisas::ResumeOp, // Resume after errors (+0 or 1 or Label)
183 // I/O
184 &SbiDisas::CloseOp, // (+channel/0)
185 &SbiDisas::CharOp, // (+char)
187 // Objects
188 &SbiDisas::StrOp, // Test classname (+StringId)
189 &SbiDisas::StrOp, // TESTCLASS, Check TOS class (+StringId)
190 &SbiDisas::StrOp, // Set libname for declare procs (+StringId)
191 &SbiDisas::ImmOp, // TOS is incremented about BASE erhoeht, BASE pushed before
192 &SbiDisas::TypeOp, // Convert last parameter to/in(?) argv (+Typ)
193 &SbiDisas::StrOp, // VBASETCLASS (+StringId)
196 static const Func pOperand3[] = {
197 // All opcodes with two operands
198 &SbiDisas::VarOp, // Load from RTL (+StringID+Typ)
199 &SbiDisas::VarOp, // Load (+StringID+Typ)
200 &SbiDisas::VarOp, // Load Element (+StringID+Typ)
201 &SbiDisas::OffOp, // Parameter (+Offset+Typ)
203 // Branch
204 &SbiDisas::VarOp, // Call DECLARE-Method (+StringID+Typ)
205 &SbiDisas::VarOp, // Call CDecl-DECLARE-Methode (+StringID+Typ)
206 &SbiDisas::CaseOp, // Case-Test (+Test-Opcode+False-Target)
207 &SbiDisas::StmntOp, // Statement (+Row+Column)
209 // I/O
210 &SbiDisas::StrmOp, // (+SvStreamFlags+Flags)
212 // Objects
213 &SbiDisas::VarDefOp, // Define local var (+StringID+Typ)
214 &SbiDisas::VarDefOp, // Define Module global var (+StringID+Typ)
215 &SbiDisas::VarDefOp, // Define global var (+StringID+Typ)
216 &SbiDisas::Str2Op, // Create object (+StringId+StringId)
217 &SbiDisas::VarDefOp, // Define static object (+StringID+Typ)
218 &SbiDisas::Str2Op, // Create User defined Object (+StringId+StringId)
219 &SbiDisas::Str2Op, // Create User defined Object-Array (+StringId+StringId)
220 &SbiDisas::VarDefOp, // Define persistent global var P=PERSIST (+StringID+Typ)
221 &SbiDisas::VarOp, // Searches for global var with special handling due to _GLOBAL_P
222 &SbiDisas::Str2Op, // Redimensionate User defined Object-Array (+StringId+StringId)
223 &SbiDisas::VarOp, // FIND_CM
224 &SbiDisas::VarDefOp, // PUBLIC_P
227 // TODO: Why as method? Isn't a simple define sufficient?
228 static const char* _crlf()
230 #if defined (UNX) || defined( PM2 )
231 return "\n";
232 #else
233 return "\r\n";
234 #endif
237 // This method exists because we want to load the file as own segment
238 BOOL SbModule::Disassemble( String& rText )
240 rText.Erase();
241 if( pImage )
243 SbiDisas aDisas( this, pImage );
244 aDisas.Disas( rText );
246 return BOOL( rText.Len() != 0 );
249 SbiDisas::SbiDisas( SbModule* p, const SbiImage* q ) : rImg( *q ), pMod( p )
251 memset( cLabels, 0, 8192 );
252 nLine = 0;
253 nOff = 0;
254 nPC = 0;
255 nOp1 = nOp2 = nParts = 0;
256 eOp = _NOP;
257 // Set Label-Bits
258 nOff = 0;
259 while( Fetch() )
261 switch( eOp )
263 case _RESUME: if( nOp1 <= 1 ) break;
264 case _RETURN: if( !nOp1 ) break;
265 case _JUMP:
266 case _JUMPT:
267 case _JUMPF:
268 case _GOSUB:
269 case _TESTFOR:
270 case _CASEIS:
271 case _CASETO:
272 case _ERRHDL:
273 cLabels[ (nOp1 & 0xffff) >> 3 ] |= ( 1 << ( nOp1 & 7 ) );
274 break;
275 default: break;
278 nOff = 0;
279 // Add the publics
280 for( USHORT i = 0; i < pMod->GetMethods()->Count(); i++ )
282 SbMethod* pMeth = PTR_CAST(SbMethod,pMod->GetMethods()->Get( i ));
283 if( pMeth )
285 USHORT nPos = (USHORT) (pMeth->GetId());
286 cLabels[ nPos >> 3 ] |= ( 1 << ( nPos & 7 ) );
291 // Read current opcode
292 BOOL SbiDisas::Fetch()
294 nPC = nOff;
295 if( nOff >= rImg.GetCodeSize() )
296 return FALSE;
297 const unsigned char* p = (const unsigned char*)( rImg.GetCode() + nOff );
298 eOp = (SbiOpcode) ( *p++ & 0xFF );
299 if( eOp <= SbOP0_END )
301 nOp1 = nOp2 = 0;
302 nParts = 1;
303 nOff++;
304 return TRUE;
306 else if( eOp <= SbOP1_END )
308 nOff += 5;
309 if( nOff > rImg.GetCodeSize() )
310 return FALSE;
311 nOp1 = *p++; nOp1 |= *p++ << 8; nOp1 |= *p++ << 16; nOp1 |= *p++ << 24;
312 nParts = 2;
313 return TRUE;
315 else if( eOp <= SbOP2_END )
317 nOff += 9;
318 if( nOff > rImg.GetCodeSize() )
319 return FALSE;
320 nOp1 = *p++; nOp1 |= *p++ << 8; nOp1 |= *p++ << 16; nOp1 |= *p++ << 24;
321 nOp2 = *p++; nOp2 |= *p++ << 8; nOp2 |= *p++ << 16; nOp2 |= *p++ << 24;
322 nParts = 3;
323 return TRUE;
325 else
326 return FALSE;
329 void SbiDisas::Disas( SvStream& r )
331 String aText;
332 nOff = 0;
333 while( DisasLine( aText ) )
335 ByteString aByteText( aText, gsl_getSystemTextEncoding() );
336 r.WriteLine( aByteText );
340 void SbiDisas::Disas( String& r )
342 r.Erase();
343 String aText;
344 nOff = 0;
345 while( DisasLine( aText ) )
347 r += aText;
348 r.AppendAscii( _crlf() );
350 aText.ConvertLineEnd();
353 BOOL SbiDisas::DisasLine( String& rText )
355 char cBuf[ 100 ];
356 const char* pMask[] = {
357 "%08" SAL_PRIXUINT32 " ",
358 "%08" SAL_PRIXUINT32 " %02X ",
359 "%08" SAL_PRIXUINT32 " %02X %08X ",
360 "%08" SAL_PRIXUINT32 " %02X %08X %08X " };
361 rText.Erase();
362 if( !Fetch() )
363 return FALSE;
364 // New line?
365 if( eOp == _STMNT && nOp1 != nLine )
367 // Find line
368 String aSource = rImg.aOUSource;
369 nLine = nOp1;
370 USHORT n = 0;
371 USHORT l = (USHORT)nLine;
372 while( --l ) {
373 n = aSource.SearchAscii( "\n", n );
374 if( n == STRING_NOTFOUND ) break;
375 else n++;
377 // Show position
378 if( n != STRING_NOTFOUND )
380 USHORT n2 = aSource.SearchAscii( "\n", n );
381 if( n2 == STRING_NOTFOUND ) n2 = aSource.Len() - n;
382 String s( aSource.Copy( n, n2 - n + 1 ) );
383 BOOL bDone;
384 do {
385 bDone = TRUE;
386 n = s.Search( '\r' );
387 if( n != STRING_NOTFOUND ) bDone = FALSE, s.Erase( n, 1 );
388 n = s.Search( '\n' );
389 if( n != STRING_NOTFOUND ) bDone = FALSE, s.Erase( n, 1 );
390 } while( !bDone );
391 // snprintf( cBuf, sizeof(cBuf), pMask[ 0 ], nPC );
392 // rText += cBuf;
393 rText.AppendAscii( "; " );
394 rText += s;
395 rText.AppendAscii( _crlf() );
398 // Label?
399 const char* p = "";
400 if( cLabels[ nPC >> 3 ] & ( 1 << ( nPC & 7 ) ) )
402 // Public?
403 ByteString aByteMethName;
404 for( USHORT i = 0; i < pMod->GetMethods()->Count(); i++ )
406 SbMethod* pMeth = PTR_CAST(SbMethod,pMod->GetMethods()->Get( i ));
407 if( pMeth )
409 aByteMethName = ByteString( pMeth->GetName(), gsl_getSystemTextEncoding() );
410 if( pMeth->GetId() == nPC )
412 p = aByteMethName.GetBuffer();
413 break;
415 if( pMeth->GetId() >= nPC )
416 break;
419 snprintf( cBuf, sizeof(cBuf), pMask[ 0 ], nPC );
420 rText.AppendAscii( cBuf );
421 if( p && *p )
423 rText.AppendAscii( p );
425 else
427 // fix warning (now error) for "Lbl%04lX" format
428 snprintf( cBuf, sizeof(cBuf), "Lbl%08" SAL_PRIXUINT32, nPC );
429 rText.AppendAscii( cBuf );
431 rText += ':';
432 rText.AppendAscii( _crlf() );
434 snprintf( cBuf, sizeof(cBuf), pMask[ nParts ], nPC, (USHORT) eOp, nOp1, nOp2 );
435 rText.AppendAscii( cBuf );
436 int n = eOp;
437 if( eOp >= SbOP2_START )
438 n -= SbOP2_START;
439 else if( eOp >= SbOP1_START )
440 n -= SbOP1_START;
441 rText += '\t';
442 rText.AppendAscii( pOps[ nParts-1 ][ n ] );
443 rText += '\t';
444 switch( nParts )
446 case 2: (this->*( pOperand2[ n ] ) )( rText ); break;
447 case 3: (this->*( pOperand3[ n ] ) )( rText ); break;
449 return TRUE;
452 // Read from StringPool
453 void SbiDisas::StrOp( String& rText )
455 String aStr = rImg.GetString( (USHORT)nOp1 );
456 ByteString aByteString( aStr, RTL_TEXTENCODING_ASCII_US );
457 const char* p = aByteString.GetBuffer();
458 if( p )
460 rText += '"';
461 rText.AppendAscii( p );
462 rText += '"';
464 else
466 rText.AppendAscii( "?String? " );
467 rText += (USHORT)nOp1;
471 void SbiDisas::Str2Op( String& rText )
473 StrOp( rText );
474 rText += ',';
475 String s;
476 nOp1 = nOp2;
477 StrOp( s );
478 rText += s;
481 // Immediate Operand
482 void SbiDisas::ImmOp( String& rText )
484 rText += String::CreateFromInt32(nOp1);
487 // OnGoto Operand
488 void SbiDisas::OnOp( String& rText )
490 rText += String::CreateFromInt32(nOp1 & 0x7FFF);
491 if( nOp1 & 0x800 )
492 rText.AppendAscii( "\t; Gosub" );
495 // Label
496 void SbiDisas::LblOp( String& rText )
498 char cBuf[ 10 ];
499 snprintf( cBuf, sizeof(cBuf), "Lbl%04" SAL_PRIXUINT32, nOp1 );
500 rText.AppendAscii( cBuf );
503 // 0 or Label
504 void SbiDisas::ReturnOp( String& rText )
506 if( nOp1 )
507 LblOp( rText );
510 // 0, 1 or Label
511 void SbiDisas::ResumeOp( String& rText )
513 switch( nOp1 )
515 case 1: rText.AppendAscii( "NEXT" ); break;
516 case 2: LblOp( rText );
520 // print Prompt
521 // FALSE/TRUE
522 void SbiDisas::PromptOp( String& rText )
524 if( nOp1 )
525 rText.AppendAscii( "\"? \"" );
528 // 0 or 1
529 void SbiDisas::CloseOp( String& rText )
531 rText.AppendAscii( nOp1 ? "Channel" : "All" );
534 // Print character
535 void SbiDisas::CharOp( String& rText )
537 const char* p = NULL;
538 switch( nOp1 )
540 case 7: p = "'\\a'"; break;
541 case 9: p = "'\\t'"; break;
542 case 10: p = "'\\n'"; break;
543 case 12: p = "'\\f'"; break;
544 case 13: p = "'\\r'"; break;
546 if( p ) rText.AppendAscii( p );
547 else if( nOp1 >= ' ' )
548 rText += '\'',
549 rText += (char) nOp1,
550 rText += '\'';
551 else
552 rText.AppendAscii( "char " ),
553 rText += (USHORT)nOp1;
556 // Print var: String-ID and type
557 void SbiDisas::VarOp( String& rText )
559 rText += rImg.GetString( (USHORT)(nOp1 & 0x7FFF) );
560 rText.AppendAscii( "\t; " );
561 // The type
562 UINT32 n = nOp1;
563 nOp1 = nOp2;
564 TypeOp( rText );
565 if( n & 0x8000 )
566 rText.AppendAscii( ", Args" );
569 // Define variable: String-ID and type
570 void SbiDisas::VarDefOp( String& rText )
572 rText += rImg.GetString( (USHORT)(nOp1 & 0x7FFF) );
573 rText.AppendAscii( "\t; " );
574 // The Typ
575 nOp1 = nOp2;
576 TypeOp( rText );
579 // Print variable: Offset and Typ
580 void SbiDisas::OffOp( String& rText )
582 rText += String::CreateFromInt32( nOp1 & 0x7FFF );
583 rText.AppendAscii( "\t; " );
584 // The type
585 UINT32 n = nOp1;
586 nOp1 = nOp2;
587 TypeOp( rText );
588 if( n & 0x8000 )
589 rText.AppendAscii( ", Args" );
592 // Data type
593 #ifdef HP9000 // TODO: remove this!
594 static char* SbiDisas_TypeOp_pTypes[13] = {
595 "Empty","Null","Integer","Long","Single","Double",
596 "Currency","Date","String","Object","Error","Boolean",
597 "Variant" };
598 #define pTypes SbiDisas_TypeOp_pTypes
599 #endif
600 void SbiDisas::TypeOp( String& rText )
602 // AB 19.1.96: Typ kann Flag für BYVAL enthalten (StepARGTYP)
603 if( nOp1 & 0x8000 )
605 nOp1 &= 0x7FFF; // Flag wegfiltern
606 rText.AppendAscii( "BYVAL " );
608 if( nOp1 < 13 )
610 #ifndef HP9000
611 static char pTypes[][13] = {
612 "Empty","Null","Integer","Long","Single","Double",
613 "Currency","Date","String","Object","Error","Boolean",
614 "Variant" };
615 #endif
616 rText.AppendAscii( pTypes[ nOp1 ] );
618 else
620 rText.AppendAscii( "type " );
621 rText += (USHORT)nOp1;
624 #ifdef HP9000
625 #undef pTypes
626 #endif
628 // TRUE-Label, condition Opcode
629 void SbiDisas::CaseOp( String& rText )
631 LblOp( rText );
632 rText += ',';
633 rText.AppendAscii( pOp1[ nOp2 - SbxEQ + _EQ ] );
636 // Row, column
637 void SbiDisas::StmntOp( String& rText )
639 rText += String::CreateFromInt32( nOp1 );
640 rText += ',';
641 UINT32 nCol = nOp2 & 0xFF;
642 UINT32 nFor = nOp2 / 0x100;
643 rText += String::CreateFromInt32( nCol );
644 rText.AppendAscii( " (For-Level: " );
645 rText += String::CreateFromInt32( nFor );
646 rText += ')';
649 // open mode, flags
650 void SbiDisas::StrmOp( String& rText )
652 char cBuf[ 10 ];
653 snprintf( cBuf, sizeof(cBuf), "%04" SAL_PRIXUINT32, nOp1 );
654 rText.AppendAscii( cBuf );
655 if( nOp2 & SBSTRM_INPUT )
656 rText.AppendAscii( ", Input" );
657 if( nOp2 & SBSTRM_OUTPUT )
658 rText.AppendAscii( ", Output" );
659 if( nOp2 & SBSTRM_APPEND )
660 rText.AppendAscii( ", Append" );
661 if( nOp2 & SBSTRM_RANDOM )
662 rText.AppendAscii( ", Random" );
663 if( nOp2 & SBSTRM_BINARY )
664 rText.AppendAscii( ", Binary" );