2015-11-30 10:02:20 +01:00
# include <sys/types.h>
# include <stdio.h>
# include <string.h>
# include "util.h"
# include "debug.h"
# include "symbol.h"
# include "demangle-java.h"
2017-04-17 16:10:49 -03:00
# include "sane_ctype.h"
2015-11-30 10:02:20 +01:00
enum {
MODE_PREFIX = 0 ,
MODE_CLASS = 1 ,
MODE_FUNC = 2 ,
MODE_TYPE = 3 ,
MODE_CTYPE = 3 , /* class arg */
} ;
# define BASE_ENT(c, n) [c - 'A']=n
static const char * base_types [ ' Z ' - ' A ' + 1 ] = {
BASE_ENT ( ' B ' , " byte " ) ,
BASE_ENT ( ' C ' , " char " ) ,
BASE_ENT ( ' D ' , " double " ) ,
BASE_ENT ( ' F ' , " float " ) ,
BASE_ENT ( ' I ' , " int " ) ,
BASE_ENT ( ' J ' , " long " ) ,
BASE_ENT ( ' S ' , " short " ) ,
BASE_ENT ( ' Z ' , " bool " ) ,
} ;
/*
* demangle Java symbol between str and end positions and stores
* up to maxlen characters into buf . The parser starts in mode .
*
* Use MODE_PREFIX to process entire prototype till end position
* Use MODE_TYPE to process return type if str starts on return type char
*
* Return :
* success : buf
* error : NULL
*/
static char *
__demangle_java_sym ( const char * str , const char * end , char * buf , int maxlen , int mode )
{
int rlen = 0 ;
int array = 0 ;
int narg = 0 ;
const char * q ;
if ( ! end )
end = str + strlen ( str ) ;
for ( q = str ; q ! = end ; q + + ) {
if ( rlen = = ( maxlen - 1 ) )
break ;
switch ( * q ) {
case ' L ' :
if ( mode = = MODE_PREFIX | | mode = = MODE_CTYPE ) {
if ( mode = = MODE_CTYPE ) {
if ( narg )
rlen + = scnprintf ( buf + rlen , maxlen - rlen , " , " ) ;
narg + + ;
}
rlen + = scnprintf ( buf + rlen , maxlen - rlen , " class " ) ;
if ( mode = = MODE_PREFIX )
mode = MODE_CLASS ;
} else
buf [ rlen + + ] = * q ;
break ;
case ' B ' :
case ' C ' :
case ' D ' :
case ' F ' :
case ' I ' :
case ' J ' :
case ' S ' :
case ' Z ' :
if ( mode = = MODE_TYPE ) {
if ( narg )
rlen + = scnprintf ( buf + rlen , maxlen - rlen , " , " ) ;
rlen + = scnprintf ( buf + rlen , maxlen - rlen , " %s " , base_types [ * q - ' A ' ] ) ;
while ( array - - )
rlen + = scnprintf ( buf + rlen , maxlen - rlen , " [] " ) ;
array = 0 ;
narg + + ;
} else
buf [ rlen + + ] = * q ;
break ;
case ' V ' :
if ( mode = = MODE_TYPE ) {
rlen + = scnprintf ( buf + rlen , maxlen - rlen , " void " ) ;
while ( array - - )
rlen + = scnprintf ( buf + rlen , maxlen - rlen , " [] " ) ;
array = 0 ;
} else
buf [ rlen + + ] = * q ;
break ;
case ' [ ' :
if ( mode ! = MODE_TYPE )
goto error ;
array + + ;
break ;
case ' ( ' :
if ( mode ! = MODE_FUNC )
goto error ;
buf [ rlen + + ] = * q ;
mode = MODE_TYPE ;
break ;
case ' ) ' :
if ( mode ! = MODE_TYPE )
goto error ;
buf [ rlen + + ] = * q ;
narg = 0 ;
break ;
case ' ; ' :
if ( mode ! = MODE_CLASS & & mode ! = MODE_CTYPE )
goto error ;
/* safe because at least one other char to process */
if ( isalpha ( * ( q + 1 ) ) )
rlen + = scnprintf ( buf + rlen , maxlen - rlen , " . " ) ;
if ( mode = = MODE_CLASS )
mode = MODE_FUNC ;
else if ( mode = = MODE_CTYPE )
mode = MODE_TYPE ;
break ;
case ' / ' :
if ( mode ! = MODE_CLASS & & mode ! = MODE_CTYPE )
goto error ;
rlen + = scnprintf ( buf + rlen , maxlen - rlen , " . " ) ;
break ;
default :
buf [ rlen + + ] = * q ;
}
}
buf [ rlen ] = ' \0 ' ;
return buf ;
error :
return NULL ;
}
/*
* Demangle Java function signature ( openJDK , not GCJ )
* input :
* str : string to parse . String is not modified
* flags : comobination of JAVA_DEMANGLE_ * flags to modify demangling
* return :
* if input can be demangled , then a newly allocated string is returned .
* if input cannot be demangled , then NULL is returned
*
* Note : caller is responsible for freeing demangled string
*/
char *
java_demangle_sym ( const char * str , int flags )
{
char * buf , * ptr ;
char * p ;
size_t len , l1 = 0 ;
if ( ! str )
return NULL ;
/* find start of retunr type */
p = strrchr ( str , ' ) ' ) ;
if ( ! p )
return NULL ;
/*
* expansion factor estimated to 3 x
*/
len = strlen ( str ) * 3 + 1 ;
buf = malloc ( len ) ;
if ( ! buf )
return NULL ;
buf [ 0 ] = ' \0 ' ;
if ( ! ( flags & JAVA_DEMANGLE_NORET ) ) {
/*
* get return type first
*/
ptr = __demangle_java_sym ( p + 1 , NULL , buf , len , MODE_TYPE ) ;
if ( ! ptr )
goto error ;
/* add space between return type and function prototype */
l1 = strlen ( buf ) ;
buf [ l1 + + ] = ' ' ;
}
/* process function up to return type */
ptr = __demangle_java_sym ( str , p + 1 , buf + l1 , len - l1 , MODE_PREFIX ) ;
if ( ! ptr )
goto error ;
return buf ;
error :
free ( buf ) ;
return NULL ;
}