Files
libreoffice/basic/source/classes/disas.cxx
Vladimir Glazounov 367ec43177 INTEGRATION: CWS npower3 (1.19.4); FILE MERGED
2006/09/28 22:28:22 npower 1.19.4.2: RESYNC: (1.19-1.20); FILE MERGED
2006/08/18 14:26:56 npower 1.19.4.1: #i64377# check in forgotten local edits <sigh>
2006-11-01 15:12:48 +00:00

689 lines
20 KiB
C++
Raw Blame History

/*************************************************************************
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: disas.cxx,v $
*
* $Revision: 1.22 $
*
* last change: $Author: vg $ $Date: 2006-11-01 16:12:48 $
*
* The Contents of this file are made available subject to
* the terms of GNU Lesser General Public License Version 2.1.
*
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2005 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
************************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_basic.hxx"
#include <stdio.h>
#include <string.h>
#ifndef _STREAM_HXX //autogen
#include <tools/stream.hxx>
#endif
#include <sbx.hxx>
#include "sb.hxx"
#include "iosys.hxx"
#include "disas.hxx"
static const char* pOp1[] = {
"NOP",
// Operatoren
// die folgenden Operatoren sind genauso angeordnet
// wie der enum SbxVarOp
"EXP", "MUL", "DIV", "MOD", "PLUS", "MINUS", "NEG",
"EQ", "NE", "LT", "GT", "LE", "GE",
"IDIV", "AND", "OR", "XOR", "EQV", "IMP", "NOT",
"CAT",
// Ende enum SbxVarOp
"LIKE", "IS",
// Laden/speichern
"ARGC", // neuen Argv einrichten
"ARGV", // TOS ==> aktueller Argv
"INPUT", // Input ==> TOS
"LINPUT", // Line Input ==> TOS
"GET", // TOS anfassen
"SET", // Speichern Objekt TOS ==> TOS-1
"PUT", // TOS ==> TOS-1
"CONST", // TOS ==> TOS-1, dann ReadOnly
"DIM", // DIM
"REDIM", // REDIM
"REDIMP", // REDIM PRESERVE
"ERASE", // TOS loeschen
// Verzweigen
"STOP", // Programmende
"INITFOR", // FOR-Variable initialisieren
"NEXT", // FOR-Variable inkrementieren
"CASE", // Anfang CASE
"ENDCASE", // Ende CASE
"STDERR", // Standard-Fehlerbehandlung
"NOERROR", // keine Fehlerbehandlung
"LEAVE", // UP verlassen
// E/A
"CHANNEL", // TOS = Kanalnummer
"PRINT", // print TOS
"PRINTF", // print TOS in field
"WRITE", // write TOS
"RENAME", // Rename Tos+1 to Tos
"PROMPT", // TOS = Prompt for Input
"RESTART", // Restartpunkt definieren
"STDIO", // E/A-Kanal 0 einstellen
// Sonstiges
"EMPTY", // Leeren Ausdruck auf Stack
"ERROR", // TOS = Fehlercode
"LSET", // Speichern Objekt TOS ==> TOS-1
"RSET", // Speichern Objekt TOS ==> TOS-1
"REDIMP_ERASE",
"INITFOREACH"
};
static const char* pOp2[] = {
"NUMBER", // Laden einer numerischen Konstanten (+ID)
"STRING", // Laden einer Stringkonstanten (+ID)
"CONSTANT", // Immediate Load (+Wert)
"ARGN", // Speichern eines named Args in Argv (+StringID)
"PAD", // String auf feste Laenge bringen (+Laenge)
// Verzweigungen
"JUMP", // Sprung (+Target)
"JUMP.T", // TOS auswerten, bedingter Sprung (+Target)
"JUMP.F", // TOS auswerten, bedingter Sprung (+Target)
"ONJUMP", // TOS auswerten, Sprung in JUMP-Tabelle (+MaxVal)
"GOSUB", // UP-Aufruf (+Target)
"RETURN", // UP-Return (+0 oder Target)
"TESTFOR", // FOR-Variable testen, inkrementieren (+Endlabel)
"CASETO", // Tos+1 <= Case <= Tos, 2xremove (+Target)
"ERRHDL", // Fehler-Handler (+Offset)
"RESUME", // Resume nach Fehlern (+0 or 1 or Label)
// E/A
"CLOSE", // (+Kanal/0)
"PRCHAR", // (+char)
// Objekte
"SETCLASS", // Set + Klassennamen testen (+StringId)
"TESTCLASS", // Check TOS class (+StringId)
"LIB", // Libnamen fuer Declare-Procs setzen (+StringId)
// Neues ab Beta 3
"BASED", // TOS wird um BASE erhoeht, BASE davor gepusht
"ARGTYP", // Letzten Parameter in Argv konvertieren (+Typ)
};
static const char* pOp3[] = {
// Alle Opcodes mit zwei Operanden
"RTL", // Laden aus RTL (+StringID+Typ)
"FIND", // Laden (+StringID+Typ)
"ELEM", // Laden Element (+StringID+Typ)
"PARAM", // Parameter (+Offset+Typ)
// Verzweigen
"CALL", // DECLARE-Methode rufen (+StringID+Typ)
"CALL.C", // Cdecl-DECLARE-Methode rufen (+StringID+Typ)
"CASEIS", // Case-Test (+Test-Opcode+False-Target)
"STMNT", // Beginn eines Statements (+Line+Col)
// E/A
"OPEN", // (+SvStreamFlags+Flags)
// Objekte und Variable
"LOCAL", // Lokale Variable (+StringID+Typ)
"PUBLIC", // Modulglobale Variable (+StringID+Typ)
"GLOBAL", // Globale Variable (+StringID+Typ)
"CREATE", // Objekt kreieren (+StringId+StringId)
"STATIC", // Objekt kreieren (+StringId+StringId)
"TCREATE", // User defined Objekt kreieren (+StringId+StringId)
"DCREATE", // User defined Objekt-Array kreieren (+StringId+StringId)
"GLOBAL_P", // Globale Variable definieren, die beim Neustart von Basic
// nicht ueberschrieben wird, P=PERSIST (+StringID+Typ)
"FIND_G", // Sucht globale Variable mit Spezialbehandlung wegen _GLOBAL_P
"DCREATE_REDIMP", // User defined Objekt-Array redimensionieren (+StringId+StringId)
"FIND_CM", // Search inside a class module (CM) to enable global search in time
};
static const char** pOps[3] = { pOp1, pOp2, pOp3 };
typedef void( SbiDisas::*Func )( String& ); // Verarbeitungsroutine
static const Func pOperand2[] = {
&SbiDisas::StrOp, // Laden einer numerischen Konstanten (+ID)
&SbiDisas::StrOp, // Laden einer Stringkonstanten (+ID)
&SbiDisas::ImmOp, // Immediate Load (+Wert)
&SbiDisas::StrOp, // Speichern eines benannten Arguments(+ID)
&SbiDisas::ImmOp, // String auf feste Laenge bringen (+Laenge)
// Verzweigungen
&SbiDisas::LblOp, // Sprung (+Target)
&SbiDisas::LblOp, // TOS auswerten), bedingter Sprung (+Target)
&SbiDisas::LblOp, // TOS auswerten), bedingter Sprung (+Target)
&SbiDisas::OnOp, // TOS auswerten), Sprung in JUMP-Tabelle (+MaxVal)
&SbiDisas::LblOp, // UP-Aufruf (+Target)
&SbiDisas::ReturnOp, // UP-Return (+0 oder Target)
&SbiDisas::LblOp, // FOR-Variable testen), inkrementieren (+Endlabel)
&SbiDisas::LblOp, // Tos+1 <= Case <= Tos), 2xremove (+Target)
&SbiDisas::LblOp, // Fehler-Handler (+Offset)
&SbiDisas::ResumeOp, // Resume nach Fehlern (+0 or 1 or Label)
// E/A
&SbiDisas::CloseOp, // (+Kanal/0)
&SbiDisas::CharOp, // (+char)
// Objekte
&SbiDisas::StrOp, // Klassennamen testen (+StringId)
&SbiDisas::StrOp, // TESTCLASS, Check TOS class (+StringId)
&SbiDisas::StrOp, // Libnamen fuer Declare-Procs setzen (+StringId)
&SbiDisas::ImmOp, // TOS wird um BASE erhoeht, BASE davor gepusht
&SbiDisas::TypeOp, // Letzten Parameter in Argv konvertieren (+Typ)
};
static const Func pOperand3[] = {
// Alle Opcodes mit zwei Operanden
&SbiDisas::VarOp, // Laden aus RTL (+StringID+Typ)
&SbiDisas::VarOp, // Laden (+StringID+Typ)
&SbiDisas::VarOp, // Laden Element (+StringID+Typ)
&SbiDisas::OffOp, // Parameter (+Offset+Typ)
// Verzweigen
&SbiDisas::VarOp, // DECLARE-Methode rufen (+StringID+Typ)
&SbiDisas::VarOp, // CDecl-DECLARE-Methode rufen (+StringID+Typ)
&SbiDisas::CaseOp, // Case-Test (+Test-Opcode+False-Target)
&SbiDisas::StmntOp, // Statement (+Zeilen+Spalte)
// E/A
&SbiDisas::StrmOp, // (+SvStreamFlags+Flags)
// Objekte
&SbiDisas::VarDefOp, // Lokale Variable definieren (+StringID+Typ)
&SbiDisas::VarDefOp, // Modulglobale Variable definieren (+StringID+Typ)
&SbiDisas::VarDefOp, // Globale Variable definieren (+StringID+Typ)
&SbiDisas::Str2Op, // Objekt kreieren (+StringId+StringId)
&SbiDisas::VarDefOp, // Statische Variable definieren (+StringID+Typ)
&SbiDisas::Str2Op, // User defined Objekt kreieren (+StringId+StringId)
&SbiDisas::Str2Op, // User defined Objekt-Array kreieren (+StringId+StringId)
&SbiDisas::VarDefOp, // Globale Variable definieren, die beim Neustart von Basic
// nicht ueberschrieben wird, P=PERSIST (+StringID+Typ)
&SbiDisas::VarOp, // Sucht globale Variable mit Spezialbehandlung wegen _GLOBAL_P
&SbiDisas::Str2Op, // User defined Objekt-Array redimensionieren (+StringId+StringId)
&SbiDisas::VarOp, // FIND_CM
};
static const char* _crlf()
{
#if defined (UNX) || defined( PM2 )
return "\n";
#else
return "\r\n";
#endif
}
// Diese Methode ist hier, damit die Datei als eigenes Segment geladen werden
// kann.
BOOL SbModule::Disassemble( String& rText )
{
rText.Erase();
if( pImage )
{
SbiDisas aDisas( this, pImage );
aDisas.Disas( rText );
}
return BOOL( rText.Len() != 0 );
}
SbiDisas::SbiDisas( SbModule* p, const SbiImage* q ) : rImg( *q ), pMod( p )
{
memset( cLabels, 0, 8192 );
nLine = nOff = nPC = nOp1 = nOp2 = nParts = 0;
eOp = _NOP;
// Label-Bits setzen
nOff = 0;
while( Fetch() )
{
switch( eOp )
{
case _RESUME: if( nOp1 <= 1 ) break;
case _RETURN: if( !nOp1 ) break;
case _JUMP:
case _JUMPT:
case _JUMPF:
case _GOSUB:
case _TESTFOR:
case _CASEIS:
case _CASETO:
case _ERRHDL:
cLabels[ nOp1 >> 3 ] |= ( 1 << ( nOp1 & 7 ) );
break;
default: break;
}
}
nOff = 0;
// Die Publics noch dazu
for( USHORT i = 0; i < pMod->GetMethods()->Count(); i++ )
{
SbMethod* pMeth = PTR_CAST(SbMethod,pMod->GetMethods()->Get( i ));
if( pMeth )
{
USHORT nPos = pMeth->GetId();
cLabels[ nPos >> 3 ] |= ( 1 << ( nPos & 7 ) );
}
}
}
// Aktuellen Opcode auslesen
BOOL SbiDisas::Fetch()
{
nPC = nOff;
if( nOff >= rImg.GetCodeSize() )
return FALSE;
const char* p = rImg.GetCode() + nOff;
eOp = (SbiOpcode) ( *p++ & 0xFF );
if( eOp <= SbOP0_END )
{
nOp1 = nOp2 = 0;
nParts = 1;
nOff++;
return TRUE;
}
else if( eOp <= SbOP1_END )
{
nOff += 3;
if( nOff > rImg.GetCodeSize() )
return FALSE;
nOp1 = *p++ & 0xFF; nOp1 |= *p << 8;
nParts = 2;
return TRUE;
}
else if( eOp <= SbOP2_END )
{
nOff += 5;
if( nOff > rImg.GetCodeSize() )
return FALSE;
nOp1 = *p++ & 0xFF; nOp1 |= *p++ << 8;
nOp2 = *p++ & 0xFF; nOp2 |= *p << 8;
nParts = 3;
return TRUE;
}
else
return FALSE;
}
void SbiDisas::Disas( SvStream& r )
{
String aText;
nOff = 0;
while( DisasLine( aText ) )
{
ByteString aByteText( aText, gsl_getSystemTextEncoding() );
r.WriteLine( aByteText );
}
}
void SbiDisas::Disas( String& r )
{
r.Erase();
String aText;
nOff = 0;
while( DisasLine( aText ) )
{
r += aText;
r.AppendAscii( _crlf() );
}
aText.ConvertLineEnd();
}
#ifdef HP9000
const char* SbiDisas_DisasLine_pMask[] = {
"%04X ",
"%04X %02X ",
"%04X %02X %04X ",
"%04X %02X %04X %04X " };
#define pMask SbiDisas_DisasLine_pMask
#endif
BOOL SbiDisas::DisasLine( String& rText )
{
char cBuf[ 30 ];
#ifndef HP9000
const char* pMask[] = {
"%04X ",
"%04X %02X ",
"%04X %02X %04X ",
"%04X %02X %04X %04X " };
#endif
rText.Erase();
if( !Fetch() )
return FALSE;
// Neue Zeile?
if( eOp == _STMNT && (short) nOp1 != nLine )
{
// Zeile raussuchen
String aSource = rImg.aOUSource;
USHORT n = 0, l = nLine = nOp1;
while( --l ) {
n = aSource.SearchAscii( "\n", n );
if( n == STRING_NOTFOUND ) break;
else n++;
}
// Stelle anzeigen
if( n != STRING_NOTFOUND )
{
USHORT n2 = aSource.SearchAscii( "\n", n );
if( n2 == STRING_NOTFOUND ) n2 = aSource.Len() - n;
String s( aSource.Copy( n, n2 - n + 1 ) );
BOOL bDone;
do {
bDone = TRUE;
n = s.Search( '\r' );
if( n != STRING_NOTFOUND ) bDone = FALSE, s.Erase( n, 1 );
n = s.Search( '\n' );
if( n != STRING_NOTFOUND ) bDone = FALSE, s.Erase( n, 1 );
} while( !bDone );
// snprintf( cBuf, sizeof(cBuf), pMask[ 0 ], nPC );
// rText += cBuf;
rText.AppendAscii( "; " );
rText += s;
rText.AppendAscii( _crlf() );
}
}
// Label?
const char* p = "";
if( cLabels[ nPC >> 3 ] & ( 1 << ( nPC & 7 ) ) )
{
// Public?
ByteString aByteMethName;
for( USHORT i = 0; i < pMod->GetMethods()->Count(); i++ )
{
SbMethod* pMeth = PTR_CAST(SbMethod,pMod->GetMethods()->Get( i ));
if( pMeth )
{
aByteMethName = ByteString( pMeth->GetName(), gsl_getSystemTextEncoding() );
if( pMeth->GetId() == nPC )
{
p = aByteMethName.GetBuffer();
break;
}
if( pMeth->GetId() >= nPC )
break;
}
}
snprintf( cBuf, sizeof(cBuf), pMask[ 0 ], nPC );
rText.AppendAscii( cBuf );
if( p && *p )
{
rText.AppendAscii( p );
}
else
{
// fix warning (now error) for "Lbl%04lX" format
// nPC is now a sal_Int32
snprintf( cBuf, sizeof(cBuf), "Lbl%08lX", nPC );
rText.AppendAscii( cBuf );
}
rText += ':';
rText.AppendAscii( _crlf() );
}
snprintf( cBuf, sizeof(cBuf), pMask[ nParts ], nPC, (USHORT) eOp, nOp1, nOp2 );
rText.AppendAscii( cBuf );
int n = eOp;
if( eOp >= SbOP2_START )
n -= SbOP2_START;
else if( eOp >= SbOP1_START )
n -= SbOP1_START;
rText += '\t';
rText.AppendAscii( pOps[ nParts-1 ][ n ] );
rText += '\t';
switch( nParts )
{
case 2: (this->*( pOperand2[ n ] ) )( rText ); break;
case 3: (this->*( pOperand3[ n ] ) )( rText ); break;
}
return TRUE;
}
#ifdef HP9000
#undef pMask
#endif
// Auslesen aus StringPool
void SbiDisas::StrOp( String& rText )
{
String aStr = rImg.GetString( nOp1 );
ByteString aByteString( aStr, RTL_TEXTENCODING_ASCII_US );
const char* p = aByteString.GetBuffer();
if( p )
{
rText += '"';
rText.AppendAscii( p );
rText += '"';
}
else
{
rText.AppendAscii( "?String? " );
rText += nOp1;
}
}
void SbiDisas::Str2Op( String& rText )
{
StrOp( rText );
rText += ',';
String s;
nOp1 = nOp2;
StrOp( s );
rText += s;
}
// Immediate Operand
void SbiDisas::ImmOp( String& rText )
{
rText += String::CreateFromInt32(nOp1);
}
// OnGoto Operand
void SbiDisas::OnOp( String& rText )
{
rText += String::CreateFromInt32(nOp1 & 0x7FFF);
if( nOp1 & 0x800 )
rText.AppendAscii( "\t; Gosub" );
}
// Label
void SbiDisas::LblOp( String& rText )
{
char cBuf[ 10 ];
snprintf( cBuf, sizeof(cBuf), "Lbl%04X", nOp1 );
rText.AppendAscii( cBuf );
}
// 0 oder Label
void SbiDisas::ReturnOp( String& rText )
{
if( nOp1 )
LblOp( rText );
}
// 0, 1 oder Label
void SbiDisas::ResumeOp( String& rText )
{
switch( nOp1 )
{
case 1: rText.AppendAscii( "NEXT" ); break;
case 2: LblOp( rText );
}
}
// Prompt ausgeben
// FALSE/TRUE
void SbiDisas::PromptOp( String& rText )
{
if( nOp1 )
rText.AppendAscii( "\"? \"" );
}
// 0 oder 1
void SbiDisas::CloseOp( String& rText )
{
rText.AppendAscii( nOp1 ? "Channel" : "All" );
}
// Zeichen ausgeben
void SbiDisas::CharOp( String& rText )
{
const char* p = NULL;
switch( nOp1 )
{
case 7: p = "'\\a'"; break;
case 9: p = "'\\t'"; break;
case 10: p = "'\\n'"; break;
case 12: p = "'\\f'"; break;
case 13: p = "'\\r'"; break;
}
if( p ) rText.AppendAscii( p );
else if( nOp1 >= ' ' )
rText += '\'',
rText += (char) nOp1,
rText += '\'';
else
rText.AppendAscii( "char " ),
rText += nOp1;
}
// Variable ausgeben: String-ID und Typ
void SbiDisas::VarOp( String& rText )
{
rText += rImg.GetString( nOp1 & 0x7FFF );
rText.AppendAscii( "\t; " );
// Der Typ
USHORT n = nOp1;
nOp1 = nOp2;
TypeOp( rText );
if( n & 0x8000 )
rText.AppendAscii( ", Args" );
}
// Variable definieren: String-ID und Typ
void SbiDisas::VarDefOp( String& rText )
{
rText += rImg.GetString( nOp1 );
rText.AppendAscii( "\t; " );
// Der Typ
nOp1 = nOp2;
TypeOp( rText );
}
// Variable ausgeben: Offset und Typ
void SbiDisas::OffOp( String& rText )
{
rText += String::CreateFromInt32( nOp1 & 0x7FFF );
rText.AppendAscii( "\t; " );
// Der Typ
USHORT n = nOp1;
nOp1 = nOp2;
TypeOp( rText );
if( n & 0x8000 )
rText.AppendAscii( ", Args" );
}
// Datentyp
#ifdef HP9000
static char* SbiDisas_TypeOp_pTypes[13] = {
"Empty","Null","Integer","Long","Single","Double",
"Currency","Date","String","Object","Error","Boolean",
"Variant" };
#define pTypes SbiDisas_TypeOp_pTypes
#endif
void SbiDisas::TypeOp( String& rText )
{
// AB 19.1.96: Typ kann Flag f<>r BYVAL enthalten (StepARGTYP)
if( nOp1 & 0x8000 )
{
nOp1 &= 0x7FFF; // Flag wegfiltern
rText.AppendAscii( "BYVAL " );
}
if( nOp1 < 13 )
{
#ifndef HP9000
static char pTypes[][13] = {
"Empty","Null","Integer","Long","Single","Double",
"Currency","Date","String","Object","Error","Boolean",
"Variant" };
#endif
rText.AppendAscii( pTypes[ nOp1 ] );
}
else
{
rText.AppendAscii( "type " );
rText += nOp1;
}
}
#ifdef HP9000
#undef pTypes
#endif
// TRUE-Label, Bedingungs-Opcode
void SbiDisas::CaseOp( String& rText )
{
LblOp( rText );
rText += ',';
rText.AppendAscii( pOp1[ nOp2 - SbxEQ + _EQ ] );
}
// Zeile, Spalte
void SbiDisas::StmntOp( String& rText )
{
rText += String::CreateFromInt32( nOp1 );
rText += ',';
USHORT nCol = nOp2 & 0xFF;
USHORT nFor = nOp2 / 0x100;
rText += String::CreateFromInt32( nCol );
rText.AppendAscii( " (For-Level: " );
rText += String::CreateFromInt32( nFor );
rText += ')';
}
// open mode, flags
void SbiDisas::StrmOp( String& rText )
{
char cBuf[ 10 ];
snprintf( cBuf, sizeof(cBuf), "%04X", nOp1 );
rText.AppendAscii( cBuf );
if( nOp2 & SBSTRM_INPUT )
rText.AppendAscii( ", Input" );
if( nOp2 & SBSTRM_OUTPUT )
rText.AppendAscii( ", Output" );
if( nOp2 & SBSTRM_APPEND )
rText.AppendAscii( ", Append" );
if( nOp2 & SBSTRM_RANDOM )
rText.AppendAscii( ", Random" );
if( nOp2 & SBSTRM_BINARY )
rText.AppendAscii( ", Binary" );
}