1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: disas.cxx,v $
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"
36 #include <tools/stream.hxx>
37 #include <basic/sbx.hxx>
43 static const char* pOp1
[] = {
47 // the following operators have the same order as in
49 "EXP", "MUL", "DIV", "MOD", "PLUS", "MINUS", "NEG",
50 "EQ", "NE", "LT", "GT", "LE", "GE",
51 "IDIV", "AND", "OR", "XOR", "EQV", "IMP", "NOT",
56 "ARGC", // Create new Argv
57 "ARGV", // TOS ==> current Argv
58 "INPUT", // Input ==> TOS
59 "LINPUT", // Line Input ==> TOS
61 "SET", // Save Object TOS ==> TOS-1
62 "PUT", // TOS ==> TOS-1
63 "CONST", // TOS ==> TOS-1, then ReadOnly
66 "REDIMP", // REDIM PRESERVE
67 "ERASE", // delete TOS
69 "STOP", // End of program
70 "INITFOR", // FOR-Variable init
71 "NEXT", // FOR-Variable increment
73 "ENDCASE", // End CASE
74 "STDERR", // Default error handling
75 "NOERROR", // No error handling
78 "CHANNEL", // TOS = Channelnumber
80 "PRINTF", // print TOS in field
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
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?)
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)
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)
116 "CLOSE", // (+channel/0)
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)
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)
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)
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)
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)
184 &SbiDisas::CloseOp
, // (+channel/0)
185 &SbiDisas::CharOp
, // (+char)
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)
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)
210 &SbiDisas::StrmOp
, // (+SvStreamFlags+Flags)
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 )
237 // This method exists because we want to load the file as own segment
238 BOOL
SbModule::Disassemble( String
& rText
)
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 );
255 nOp1
= nOp2
= nParts
= 0;
263 case _RESUME
: if( nOp1
<= 1 ) break;
264 case _RETURN
: if( !nOp1
) break;
273 cLabels
[ (nOp1
& 0xffff) >> 3 ] |= ( 1 << ( nOp1
& 7 ) );
280 for( USHORT i
= 0; i
< pMod
->GetMethods()->Count(); i
++ )
282 SbMethod
* pMeth
= PTR_CAST(SbMethod
,pMod
->GetMethods()->Get( i
));
285 USHORT nPos
= (USHORT
) (pMeth
->GetId());
286 cLabels
[ nPos
>> 3 ] |= ( 1 << ( nPos
& 7 ) );
291 // Read current opcode
292 BOOL
SbiDisas::Fetch()
295 if( nOff
>= rImg
.GetCodeSize() )
297 const unsigned char* p
= (const unsigned char*)( rImg
.GetCode() + nOff
);
298 eOp
= (SbiOpcode
) ( *p
++ & 0xFF );
299 if( eOp
<= SbOP0_END
)
306 else if( eOp
<= SbOP1_END
)
309 if( nOff
> rImg
.GetCodeSize() )
311 nOp1
= *p
++; nOp1
|= *p
++ << 8; nOp1
|= *p
++ << 16; nOp1
|= *p
++ << 24;
315 else if( eOp
<= SbOP2_END
)
318 if( nOff
> rImg
.GetCodeSize() )
320 nOp1
= *p
++; nOp1
|= *p
++ << 8; nOp1
|= *p
++ << 16; nOp1
|= *p
++ << 24;
321 nOp2
= *p
++; nOp2
|= *p
++ << 8; nOp2
|= *p
++ << 16; nOp2
|= *p
++ << 24;
329 void SbiDisas::Disas( SvStream
& r
)
333 while( DisasLine( aText
) )
335 ByteString
aByteText( aText
, gsl_getSystemTextEncoding() );
336 r
.WriteLine( aByteText
);
340 void SbiDisas::Disas( String
& r
)
345 while( DisasLine( aText
) )
348 r
.AppendAscii( _crlf() );
350 aText
.ConvertLineEnd();
353 BOOL
SbiDisas::DisasLine( String
& rText
)
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 " };
365 if( eOp
== _STMNT
&& nOp1
!= nLine
)
368 String aSource
= rImg
.aOUSource
;
371 USHORT l
= (USHORT
)nLine
;
373 n
= aSource
.SearchAscii( "\n", n
);
374 if( n
== STRING_NOTFOUND
) break;
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 ) );
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 );
391 // snprintf( cBuf, sizeof(cBuf), pMask[ 0 ], nPC );
393 rText
.AppendAscii( "; " );
395 rText
.AppendAscii( _crlf() );
400 if( cLabels
[ nPC
>> 3 ] & ( 1 << ( nPC
& 7 ) ) )
403 ByteString aByteMethName
;
404 for( USHORT i
= 0; i
< pMod
->GetMethods()->Count(); i
++ )
406 SbMethod
* pMeth
= PTR_CAST(SbMethod
,pMod
->GetMethods()->Get( i
));
409 aByteMethName
= ByteString( pMeth
->GetName(), gsl_getSystemTextEncoding() );
410 if( pMeth
->GetId() == nPC
)
412 p
= aByteMethName
.GetBuffer();
415 if( pMeth
->GetId() >= nPC
)
419 snprintf( cBuf
, sizeof(cBuf
), pMask
[ 0 ], nPC
);
420 rText
.AppendAscii( cBuf
);
423 rText
.AppendAscii( p
);
427 // fix warning (now error) for "Lbl%04lX" format
428 snprintf( cBuf
, sizeof(cBuf
), "Lbl%08" SAL_PRIXUINT32
, nPC
);
429 rText
.AppendAscii( cBuf
);
432 rText
.AppendAscii( _crlf() );
434 snprintf( cBuf
, sizeof(cBuf
), pMask
[ nParts
], nPC
, (USHORT
) eOp
, nOp1
, nOp2
);
435 rText
.AppendAscii( cBuf
);
437 if( eOp
>= SbOP2_START
)
439 else if( eOp
>= SbOP1_START
)
442 rText
.AppendAscii( pOps
[ nParts
-1 ][ n
] );
446 case 2: (this->*( pOperand2
[ n
] ) )( rText
); break;
447 case 3: (this->*( pOperand3
[ n
] ) )( rText
); break;
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();
461 rText
.AppendAscii( p
);
466 rText
.AppendAscii( "?String? " );
467 rText
+= (USHORT
)nOp1
;
471 void SbiDisas::Str2Op( String
& rText
)
482 void SbiDisas::ImmOp( String
& rText
)
484 rText
+= String::CreateFromInt32(nOp1
);
488 void SbiDisas::OnOp( String
& rText
)
490 rText
+= String::CreateFromInt32(nOp1
& 0x7FFF);
492 rText
.AppendAscii( "\t; Gosub" );
496 void SbiDisas::LblOp( String
& rText
)
499 snprintf( cBuf
, sizeof(cBuf
), "Lbl%04" SAL_PRIXUINT32
, nOp1
);
500 rText
.AppendAscii( cBuf
);
504 void SbiDisas::ReturnOp( String
& rText
)
511 void SbiDisas::ResumeOp( String
& rText
)
515 case 1: rText
.AppendAscii( "NEXT" ); break;
516 case 2: LblOp( rText
);
522 void SbiDisas::PromptOp( String
& rText
)
525 rText
.AppendAscii( "\"? \"" );
529 void SbiDisas::CloseOp( String
& rText
)
531 rText
.AppendAscii( nOp1
? "Channel" : "All" );
535 void SbiDisas::CharOp( String
& rText
)
537 const char* p
= NULL
;
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
>= ' ' )
549 rText
+= (char) nOp1
,
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; " );
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; " );
579 // Print variable: Offset and Typ
580 void SbiDisas::OffOp( String
& rText
)
582 rText
+= String::CreateFromInt32( nOp1
& 0x7FFF );
583 rText
.AppendAscii( "\t; " );
589 rText
.AppendAscii( ", Args" );
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",
598 #define pTypes SbiDisas_TypeOp_pTypes
600 void SbiDisas::TypeOp( String
& rText
)
602 // AB 19.1.96: Typ kann Flag für BYVAL enthalten (StepARGTYP)
605 nOp1
&= 0x7FFF; // Flag wegfiltern
606 rText
.AppendAscii( "BYVAL " );
611 static char pTypes
[][13] = {
612 "Empty","Null","Integer","Long","Single","Double",
613 "Currency","Date","String","Object","Error","Boolean",
616 rText
.AppendAscii( pTypes
[ nOp1
] );
620 rText
.AppendAscii( "type " );
621 rText
+= (USHORT
)nOp1
;
628 // TRUE-Label, condition Opcode
629 void SbiDisas::CaseOp( String
& rText
)
633 rText
.AppendAscii( pOp1
[ nOp2
- SbxEQ
+ _EQ
] );
637 void SbiDisas::StmntOp( String
& rText
)
639 rText
+= String::CreateFromInt32( nOp1
);
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
);
650 void SbiDisas::StrmOp( String
& rText
)
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" );