Merge remote-tracking branch

'origin/GT-3481-dragonmacher-gnu-demangler-update'

Fixes #1195, fixes #1308, fixes #1454, fixes #1451
This commit is contained in:
ghidorahrex 2020-02-18 10:53:58 -05:00
commit cd7a6e2235
105 changed files with 17388 additions and 1217 deletions

View file

@ -12,6 +12,12 @@ apply plugin: 'eclipse'
eclipse.project.name = 'GPL DemanglerGnu' eclipse.project.name = 'GPL DemanglerGnu'
def v33_1 = "demangler_gnu_v2_33_1"
def v24 = "demangler_gnu_v2_24"
def srcVersion33_1 = "src/demangler_gnu_v2_33_1"
def srcVersion24 = "src/demangler_gnu_v2_24"
/**************************************************************************** /****************************************************************************
* Defines the platforms we have to support in Ghidra. This model is used * Defines the platforms we have to support in Ghidra. This model is used
* for all native builds and should be extended by each module as-needed. * for all native builds and should be extended by each module as-needed.
@ -54,64 +60,126 @@ task zipBuildableSource(type:Zip) {
baseName project.name + "-src-for-build" baseName project.name + "-src-for-build"
extension 'zip' extension 'zip'
from (project.projectDir.toString() + "/src/demangler_gnu/c") { //
into "/src/demangler_gnu" // Version 2.33.1
//
from (project.projectDir.toString() + "/" + srcVersion33_1 + "c") {
into "/" + srcVersion33_1
} }
from (project.projectDir.toString() + "/src/demangler_gnu/headers") { from (project.projectDir.toString() + "/" + srcVersion33_1 + "/headers") {
into "/src/demangler_gnu" into "/" + srcVersion33_1
} }
from (project.projectDir.toString() + "/src/demangler_gnu/build") { from (project.projectDir.toString() + "/" + srcVersion33_1 + "/build") {
into "/src/demangler_gnu" into "/" + srcVersion33_1
} }
from (project.projectDir.toString() + "/src/demangler_gnu/README.txt") from (project.projectDir.toString() + "/" + srcVersion33_1 + "/README.txt")
//
// Version 2.24
//
from (project.projectDir.toString() + "/" + srcVersion24 + "c") {
into "/" + srcVersion24
}
from (project.projectDir.toString() + "/" + srcVersion24 + "/headers") {
into "/" + srcVersion24
}
from (project.projectDir.toString() + "/" + srcVersion24 + "/build") {
into "/" + srcVersion24
}
from (project.projectDir.toString() + "/" + srcVersion24 + "/README.txt")
} }
model { model {
//
// Version 2.33.1
//
components { components {
demangler_gnu(NativeExecutableSpec) { demangler_gnu_v2_33_1(NativeExecutableSpec) {
targetPlatform "win64" targetPlatform "win64"
targetPlatform "linux64" targetPlatform "linux64"
targetPlatform "osx64" targetPlatform "osx64"
sources { sources {
c { c {
source { source {
srcDir "src/demangler_gnu/c" srcDir srcVersion33_1 + "/c"
} }
exportedHeaders { exportedHeaders {
srcDir "src/demangler_gnu/headers" srcDir srcVersion33_1 + "/headers"
} }
} }
} }
}
//
// Version 2.24
//
demangler_gnu_v2_24(NativeExecutableSpec) {
targetPlatform "win64"
targetPlatform "linux64"
targetPlatform "osx64"
sources {
c {
source {
srcDir srcVersion24 + "/c"
}
exportedHeaders {
srcDir srcVersion24 + "/headers"
}
}
}
} }
} }
} }
model { model {
binaries { binaries {
/*
Note: 'all' will pass all binary output, which is each platform for each version
*/
all{ b -> all{ b ->
if (toolChain in Gcc) {
cCompiler.args "-DMAIN_CPLUS_DEM" def version = b.getApplication().getName()
cCompiler.args "-DHAVE_STDLIB_H" println "have binary: " + b
cCompiler.args "-DHAVE_STRING_H"
if (targetPlatform.operatingSystem.linux) { if (version.equals(v33_1)) {
// linker.args "-static" if (toolChain in Gcc) {
//cCompiler.args "-DCP_DEMANGLE_DEBUG"
cCompiler.args "-DHAVE_STDLIB_H"
cCompiler.args "-DHAVE_STRING_H"
}
else if (toolChain in VisualCpp) {
cCompiler.args "/D_CONSOLE"
cCompiler.args "-DHAVE_STDLIB_H"
cCompiler.args "-DHAVE_STRING_H"
}
else if (toolChain in Clang) {
cCompiler.args "-DHAVE_STDLIB_H"
cCompiler.args "-DHAVE_STRING_H"
} }
} }
else if (toolChain in VisualCpp) { else if (version.equals(v24)) {
cCompiler.args "/D_CONSOLE" if (toolChain in Gcc) {
cCompiler.args "/DMAIN_CPLUS_DEM" cCompiler.args "-DMAIN_CPLUS_DEM"
cCompiler.args "-DHAVE_STDLIB_H" cCompiler.args "-DHAVE_STDLIB_H"
cCompiler.args "-DHAVE_STRING_H" cCompiler.args "-DHAVE_STRING_H"
} }
else if (toolChain in Clang) { else if (toolChain in VisualCpp) {
cCompiler.args "-DMAIN_CPLUS_DEM" cCompiler.args "/D_CONSOLE"
cCompiler.args "-DHAVE_STDLIB_H" cCompiler.args "/DMAIN_CPLUS_DEM"
cCompiler.args "-DHAVE_STRING_H" cCompiler.args "-DHAVE_STDLIB_H"
if (targetPlatform.operatingSystem.linux) { cCompiler.args "-DHAVE_STRING_H"
// linker.args "-static" }
else if (toolChain in Clang) {
cCompiler.args "-DMAIN_CPLUS_DEM"
cCompiler.args "-DHAVE_STDLIB_H"
cCompiler.args "-DHAVE_STRING_H"
} }
} }
} }
} }
} }

View file

@ -7,4 +7,5 @@
Module.manifest||Public Domain||||END| Module.manifest||Public Domain||||END|
build.gradle||Public Domain||||END| build.gradle||Public Domain||||END|
settings.gradle||Public Domain||||END| settings.gradle||Public Domain||||END|
src/demangler_gnu/README.txt||Public Domain||||END| src/demangler_gnu_v2_24/README.txt||Public Domain||||END|
src/demangler_gnu_v2_33_1/README.txt||Public Domain||||END|

View file

@ -1,5 +1,5 @@
/* ### /* ###
* IP: GPL 3 Linking Permitted * IP: LGPL 2.1
*/ */
/* Demangler for g++ V3 ABI. /* Demangler for g++ V3 ABI.
Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
@ -33,10 +33,9 @@
CHANGE NOTICE: CHANGE NOTICE:
This file was changed on July 1st, 2014. This file was changed on July 22nd, 2020
This file was changed on Jan 22, 2020
CHANGE NOTICE: - Added a method to wrap calls to d_print_comp() in order to track too much recursion
This file was changed on July 4th, 2019.
*/ */
/* This code implements a demangler for the g++ V3 ABI. The ABI is /* This code implements a demangler for the g++ V3 ABI. The ABI is
@ -312,6 +311,11 @@ struct d_print_info
int pack_index; int pack_index;
/* Number of d_print_flush calls so far. */ /* Number of d_print_flush calls so far. */
unsigned long int flush_count; unsigned long int flush_count;
// Changed Jan 22, 2020 - Added a method to wrap calls to d_print_comp() in
// order to track too much recursion
int recursion_level;
}; };
#ifdef CP_DEMANGLE_DEBUG #ifdef CP_DEMANGLE_DEBUG
@ -470,6 +474,12 @@ static inline char d_last_char (struct d_print_info *);
static void static void
d_print_comp (struct d_print_info *, int, const struct demangle_component *); d_print_comp (struct d_print_info *, int, const struct demangle_component *);
// Changed Jan 22, 2020 - Added a method to wrap calls to d_print_comp() in
// order to track too much recursion
static void
d_print_comp_delegate (struct d_print_info *, int, const struct demangle_component *);
static void static void
d_print_java_identifier (struct d_print_info *, const char *, int); d_print_java_identifier (struct d_print_info *, const char *, int);
@ -3670,6 +3680,7 @@ static void
d_print_init (struct d_print_info *dpi, demangle_callbackref callback, d_print_init (struct d_print_info *dpi, demangle_callbackref callback,
void *opaque) void *opaque)
{ {
dpi->len = 0; dpi->len = 0;
dpi->last_char = '\0'; dpi->last_char = '\0';
dpi->templates = NULL; dpi->templates = NULL;
@ -3681,6 +3692,10 @@ d_print_init (struct d_print_info *dpi, demangle_callbackref callback,
dpi->opaque = opaque; dpi->opaque = opaque;
dpi->demangle_failure = 0; dpi->demangle_failure = 0;
// Changed Jan 22, 2020 - Added a method to wrap calls to d_print_comp() in
// order to track too much recursion
dpi->recursion_level = 0;
} }
/* Indicate that an error occurred during printing, and test for error. */ /* Indicate that an error occurred during printing, and test for error. */
@ -3931,10 +3946,28 @@ d_print_subexpr (struct d_print_info *dpi, int options,
/* Subroutine to handle components. */ /* Subroutine to handle components. */
// Changed Jan 22, 2020 - Added a method to wrap calls to d_print_comp() in
// order to track too much recursion
static void static void
d_print_comp (struct d_print_info *dpi, int options, d_print_comp (struct d_print_info *dpi, int options,
const struct demangle_component *dc) const struct demangle_component *dc)
{ {
if (dpi->recursion_level > DEMANGLE_RECURSION_LIMIT) {
d_print_error (dpi);
return;
}
dpi->recursion_level++;
d_print_comp_delegate(dpi, options, dc);
dpi->recursion_level--;
}
static void
d_print_comp_delegate (struct d_print_info *dpi, int options,
const struct demangle_component *dc)
{
/* Magic variable to let reference smashing skip over the next modifier /* Magic variable to let reference smashing skip over the next modifier
without needing to modify *dc. */ without needing to modify *dc. */
const struct demangle_component *mod_inner = NULL; const struct demangle_component *mod_inner = NULL;

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: LGPL 3.0 * IP: LGPL 3.0
* REVIEWED: YES
*/ */
/* Defs for interface to demanglers. /* Defs for interface to demanglers.
Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002, Copyright 1992, 1993, 1994, 1995, 1996, 1997, 1998, 2000, 2001, 2002,
@ -71,6 +70,9 @@ extern "C" {
/* If none of these are set, use 'current_demangling_style' as the default. */ /* If none of these are set, use 'current_demangling_style' as the default. */
#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT) #define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU|DMGL_LUCID|DMGL_ARM|DMGL_HP|DMGL_EDG|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT)
// Changed Jan 22, 2020 - Added constant to allow us to limit degenerate recursive calls
#define DEMANGLE_RECURSION_LIMIT 10000
/* Enumeration of possible demangling styles. /* Enumeration of possible demangling styles.
Lucid and ARM styles are still kept logically distinct, even though Lucid and ARM styles are still kept logically distinct, even though

View file

@ -0,0 +1,81 @@
PURPOSE
This is a readme file to note the changes made to the binutils-2.33.1 source
code in to build its GNU demangler. The files in this directory are used to create a demangling
utility during the full build process.
COPIED SOURCE CODE / BUILDING RESTRICTIONS
Most of the files used to build the Ghidra GNU demangler are copied from binutils and have
not been changed. Further, the files in this directory are a small subset of the files used to
build the binutils suite. By copying specific files we are able to use Make and Visual Studio
to build a stand alone demangler without having to perform the more complicated build needed
to build binutils. Specifically, we do not have to run the configure utility that is
provided by binutils. This is critical, as we are using Visual Studio to build on Windows,
which does not have the configure utility support. If we ever wished to build the entire
binutils suite on Windows, then we would most likely need to use a GNU environment made for
Windows, such as MinGW.
CHANGES TO BINUTILS SOURCE
cp-demangle.c
This file contains a small, one-line change to flush to the standard output stream. Without
this change, the program, when called repeatedly from Java would hang as it attempts to read
characters that are buffered on the native side.
UPDATING
If we ever wish to update to a newer version of binutils, then we will need to re-copy the files
in this directory. That is, unless at least one of the following changes happens:
1) building a stand alone c++filt is simple enough that we can do it on each platform, or
2) we decide to build the entire binutils suite and use the full c++filt binary.
SOURCE FILES
binutils/libiberty/alloca.c
binutils/libiberty/argv.c
binutils/libiberty/cp-demangle.c
binutils/libiberty/cplus-dem.c
binutils/libiberty/d-demangle.c
binutils/libiberty/dyn-string.c
binutils/libiberty/getopt.c
binutils/libiberty/getopt1.c
binutils/libiberty/rust-demangle.c
binutils/libiberty/safe-ctype.c
binutils/libiberty/xexit.c
binutils/libiberty/xstrdup.c
binutils/include/ansidecl.h
binutils/libiberty/cp-demangle.h
binutils/include/demangle.h
binutils/include/dyn-string.h
binutils/include/getopt.h
binutils/include/libiberty.h
binutils/libiberty/rust-demangle.h
binutils/include/safe-ctype.h
This file is created to add minor missing dependencies.
missing.c
LICENSE
The files listed above are licensed by using the file header or the COPYING or COPYING.LIB file
listed in the original source directory of binutils.

View file

@ -0,0 +1,487 @@
/* ###
* IP: LGPL 2.1
* NOTE: license is not in file, but in the directory from whence it came: binutils-2.24/libiberty/COPYING.LIB
*/
/* alloca.c -- allocate automatically reclaimed memory
(Mostly) portable public-domain implementation -- D A Gwyn
This implementation of the PWB library alloca function,
which is used to allocate space off the run-time stack so
that it is automatically reclaimed upon procedure exit,
was inspired by discussions with J. Q. Johnson of Cornell.
J.Otto Tennant <jot@cray.com> contributed the Cray support.
There are some preprocessor constants that can
be defined when compiling for your specific system, for
improved efficiency; however, the defaults should be okay.
The general concept of this implementation is to keep
track of all alloca-allocated blocks, and reclaim any
that are found to be deeper in the stack than the current
invocation. This heuristic does not reclaim storage as
soon as it becomes invalid, but it will do so eventually.
As a special case, alloca(0) reclaims storage without
allocating any. It is a good idea to use alloca(0) in
your main control loop, etc. to force garbage collection. */
/*
@deftypefn Replacement void* alloca (size_t @var{size})
This function allocates memory which will be automatically reclaimed
after the procedure exits. The @libib{} implementation does not free
the memory immediately but will do so eventually during subsequent
calls to this function. Memory is allocated using @code{xmalloc} under
normal circumstances.
The header file @file{alloca-conf.h} can be used in conjunction with the
GNU Autoconf test @code{AC_FUNC_ALLOCA} to test for and properly make
available this function. The @code{AC_FUNC_ALLOCA} test requires that
client code use a block of preprocessor code to be safe (see the Autoconf
manual for more); this header incorporates that logic and more, including
the possibility of a GCC built-in function.
@end deftypefn
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <libiberty.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
/* These variables are used by the ASTRDUP implementation that relies
on C_alloca. */
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
const char *libiberty_optr;
char *libiberty_nptr;
unsigned long libiberty_len;
#ifdef __cplusplus
}
#endif /* __cplusplus */
/* If your stack is a linked list of frames, you have to
provide an "address metric" ADDRESS_FUNCTION macro. */
#if defined (CRAY) && defined (CRAY_STACKSEG_END)
static long i00afunc ();
#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
#else
#define ADDRESS_FUNCTION(arg) &(arg)
#endif
#ifndef NULL
#define NULL 0
#endif
/* Define STACK_DIRECTION if you know the direction of stack
growth for your system; otherwise it will be automatically
deduced at run-time.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown */
#ifndef STACK_DIRECTION
#define STACK_DIRECTION 0 /* Direction unknown. */
#endif
#if STACK_DIRECTION != 0
#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
#else /* STACK_DIRECTION == 0; need run-time code. */
static int stack_dir; /* 1 or -1 once known. */
#define STACK_DIR stack_dir
static void
find_stack_direction (void)
{
static char *addr = NULL; /* Address of first `dummy', once known. */
auto char dummy; /* To get stack address. */
if (addr == NULL)
{ /* Initial entry. */
addr = ADDRESS_FUNCTION (dummy);
find_stack_direction (); /* Recurse once. */
}
else
{
/* Second entry. */
if (ADDRESS_FUNCTION (dummy) > addr)
stack_dir = 1; /* Stack grew upward. */
else
stack_dir = -1; /* Stack grew downward. */
}
}
#endif /* STACK_DIRECTION == 0 */
/* An "alloca header" is used to:
(a) chain together all alloca'ed blocks;
(b) keep track of stack depth.
It is very important that sizeof(header) agree with malloc
alignment chunk size. The following default should work okay. */
#ifndef ALIGN_SIZE
#define ALIGN_SIZE sizeof(double)
#endif
typedef union hdr
{
char align[ALIGN_SIZE]; /* To force sizeof(header). */
struct
{
union hdr *next; /* For chaining headers. */
char *deep; /* For stack depth measure. */
} h;
} header;
static header *last_alloca_header = NULL; /* -> last alloca header. */
/* Return a pointer to at least SIZE bytes of storage,
which will be automatically reclaimed upon exit from
the procedure that called alloca. Originally, this space
was supposed to be taken from the current stack frame of the
caller, but that method cannot be made to work for some
implementations of C, for example under Gould's UTX/32. */
/* @undocumented C_alloca */
PTR
C_alloca (size_t size)
{
auto char probe; /* Probes stack depth: */
register char *depth = ADDRESS_FUNCTION (probe);
#if STACK_DIRECTION == 0
if (STACK_DIR == 0) /* Unknown growth direction. */
find_stack_direction ();
#endif
/* Reclaim garbage, defined as all alloca'd storage that
was allocated from deeper in the stack than currently. */
{
register header *hp; /* Traverses linked list. */
for (hp = last_alloca_header; hp != NULL;)
if ((STACK_DIR > 0 && hp->h.deep > depth)
|| (STACK_DIR < 0 && hp->h.deep < depth))
{
register header *np = hp->h.next;
free ((PTR) hp); /* Collect garbage. */
hp = np; /* -> next header. */
}
else
break; /* Rest are not deeper. */
last_alloca_header = hp; /* -> last valid storage. */
}
if (size == 0)
return NULL; /* No allocation required. */
/* Allocate combined header + user data storage. */
{
register void *new_storage = XNEWVEC (char, sizeof (header) + size);
/* Address of header. */
if (new_storage == 0)
abort();
((header *) new_storage)->h.next = last_alloca_header;
((header *) new_storage)->h.deep = depth;
last_alloca_header = (header *) new_storage;
/* User storage begins just after header. */
return (PTR) ((char *) new_storage + sizeof (header));
}
}
#if defined (CRAY) && defined (CRAY_STACKSEG_END)
#ifdef DEBUG_I00AFUNC
#include <stdio.h>
#endif
#ifndef CRAY_STACK
#define CRAY_STACK
#ifndef CRAY2
/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
struct stack_control_header
{
long shgrow:32; /* Number of times stack has grown. */
long shaseg:32; /* Size of increments to stack. */
long shhwm:32; /* High water mark of stack. */
long shsize:32; /* Current size of stack (all segments). */
};
/* The stack segment linkage control information occurs at
the high-address end of a stack segment. (The stack
grows from low addresses to high addresses.) The initial
part of the stack segment linkage control information is
0200 (octal) words. This provides for register storage
for the routine which overflows the stack. */
struct stack_segment_linkage
{
long ss[0200]; /* 0200 overflow words. */
long sssize:32; /* Number of words in this segment. */
long ssbase:32; /* Offset to stack base. */
long:32;
long sspseg:32; /* Offset to linkage control of previous
segment of stack. */
long:32;
long sstcpt:32; /* Pointer to task common address block. */
long sscsnm; /* Private control structure number for
microtasking. */
long ssusr1; /* Reserved for user. */
long ssusr2; /* Reserved for user. */
long sstpid; /* Process ID for pid based multi-tasking. */
long ssgvup; /* Pointer to multitasking thread giveup. */
long sscray[7]; /* Reserved for Cray Research. */
long ssa0;
long ssa1;
long ssa2;
long ssa3;
long ssa4;
long ssa5;
long ssa6;
long ssa7;
long sss0;
long sss1;
long sss2;
long sss3;
long sss4;
long sss5;
long sss6;
long sss7;
};
#else /* CRAY2 */
/* The following structure defines the vector of words
returned by the STKSTAT library routine. */
struct stk_stat
{
long now; /* Current total stack size. */
long maxc; /* Amount of contiguous space which would
be required to satisfy the maximum
stack demand to date. */
long high_water; /* Stack high-water mark. */
long overflows; /* Number of stack overflow ($STKOFEN) calls. */
long hits; /* Number of internal buffer hits. */
long extends; /* Number of block extensions. */
long stko_mallocs; /* Block allocations by $STKOFEN. */
long underflows; /* Number of stack underflow calls ($STKRETN). */
long stko_free; /* Number of deallocations by $STKRETN. */
long stkm_free; /* Number of deallocations by $STKMRET. */
long segments; /* Current number of stack segments. */
long maxs; /* Maximum number of stack segments so far. */
long pad_size; /* Stack pad size. */
long current_address; /* Current stack segment address. */
long current_size; /* Current stack segment size. This
number is actually corrupted by STKSTAT to
include the fifteen word trailer area. */
long initial_address; /* Address of initial segment. */
long initial_size; /* Size of initial segment. */
};
/* The following structure describes the data structure which trails
any stack segment. I think that the description in 'asdef' is
out of date. I only describe the parts that I am sure about. */
struct stk_trailer
{
long this_address; /* Address of this block. */
long this_size; /* Size of this block (does not include
this trailer). */
long unknown2;
long unknown3;
long link; /* Address of trailer block of previous
segment. */
long unknown5;
long unknown6;
long unknown7;
long unknown8;
long unknown9;
long unknown10;
long unknown11;
long unknown12;
long unknown13;
long unknown14;
};
#endif /* CRAY2 */
#endif /* not CRAY_STACK */
#ifdef CRAY2
/* Determine a "stack measure" for an arbitrary ADDRESS.
I doubt that "lint" will like this much. */
static long
i00afunc (long *address)
{
struct stk_stat status;
struct stk_trailer *trailer;
long *block, size;
long result = 0;
/* We want to iterate through all of the segments. The first
step is to get the stack status structure. We could do this
more quickly and more directly, perhaps, by referencing the
$LM00 common block, but I know that this works. */
STKSTAT (&status);
/* Set up the iteration. */
trailer = (struct stk_trailer *) (status.current_address
+ status.current_size
- 15);
/* There must be at least one stack segment. Therefore it is
a fatal error if "trailer" is null. */
if (trailer == 0)
abort ();
/* Discard segments that do not contain our argument address. */
while (trailer != 0)
{
block = (long *) trailer->this_address;
size = trailer->this_size;
if (block == 0 || size == 0)
abort ();
trailer = (struct stk_trailer *) trailer->link;
if ((block <= address) && (address < (block + size)))
break;
}
/* Set the result to the offset in this segment and add the sizes
of all predecessor segments. */
result = address - block;
if (trailer == 0)
{
return result;
}
do
{
if (trailer->this_size <= 0)
abort ();
result += trailer->this_size;
trailer = (struct stk_trailer *) trailer->link;
}
while (trailer != 0);
/* We are done. Note that if you present a bogus address (one
not in any segment), you will get a different number back, formed
from subtracting the address of the first block. This is probably
not what you want. */
return (result);
}
#else /* not CRAY2 */
/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
Determine the number of the cell within the stack,
given the address of the cell. The purpose of this
routine is to linearize, in some sense, stack addresses
for alloca. */
static long
i00afunc (long address)
{
long stkl = 0;
long size, pseg, this_segment, stack;
long result = 0;
struct stack_segment_linkage *ssptr;
/* Register B67 contains the address of the end of the
current stack segment. If you (as a subprogram) store
your registers on the stack and find that you are past
the contents of B67, you have overflowed the segment.
B67 also points to the stack segment linkage control
area, which is what we are really interested in. */
stkl = CRAY_STACKSEG_END ();
ssptr = (struct stack_segment_linkage *) stkl;
/* If one subtracts 'size' from the end of the segment,
one has the address of the first word of the segment.
If this is not the first segment, 'pseg' will be
nonzero. */
pseg = ssptr->sspseg;
size = ssptr->sssize;
this_segment = stkl - size;
/* It is possible that calling this routine itself caused
a stack overflow. Discard stack segments which do not
contain the target address. */
while (!(this_segment <= address && address <= stkl))
{
#ifdef DEBUG_I00AFUNC
fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
#endif
if (pseg == 0)
break;
stkl = stkl - pseg;
ssptr = (struct stack_segment_linkage *) stkl;
size = ssptr->sssize;
pseg = ssptr->sspseg;
this_segment = stkl - size;
}
result = address - this_segment;
/* If you subtract pseg from the current end of the stack,
you get the address of the previous stack segment's end.
This seems a little convoluted to me, but I'll bet you save
a cycle somewhere. */
while (pseg != 0)
{
#ifdef DEBUG_I00AFUNC
fprintf (stderr, "%011o %011o\n", pseg, size);
#endif
stkl = stkl - pseg;
ssptr = (struct stack_segment_linkage *) stkl;
size = ssptr->sssize;
pseg = ssptr->sspseg;
result += size;
}
return (result);
}
#endif /* not CRAY2 */
#endif /* CRAY */

View file

@ -0,0 +1,561 @@
/* ###
* IP: LGPL 2.1
* NOTE: See binutils/libiberty/COPYING.LIB
*/
/* Create and destroy argument vectors (argv's)
Copyright (C) 1992-2019 Free Software Foundation, Inc.
Written by Fred Fish @ Cygnus Support
This file is part of the libiberty library.
Libiberty is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
Libiberty 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with libiberty; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
/* Create and destroy argument vectors. An argument vector is simply an
array of string pointers, terminated by a NULL pointer. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "ansidecl.h"
#include "libiberty.h"
#include "safe-ctype.h"
/* Routines imported from standard C runtime libraries. */
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifndef NULL
#define NULL 0
#endif
#ifndef EOS
#define EOS '\0'
#endif
#define INITIAL_MAXARGC 8 /* Number of args + NULL in initial argv */
/*
@deftypefn Extension char** dupargv (char * const *@var{vector})
Duplicate an argument vector. Simply scans through @var{vector},
duplicating each argument until the terminating @code{NULL} is found.
Returns a pointer to the argument vector if successful. Returns
@code{NULL} if there is insufficient memory to complete building the
argument vector.
@end deftypefn
*/
char **
dupargv (char * const *argv)
{
int argc;
char **copy;
if (argv == NULL)
return NULL;
/* the vector */
for (argc = 0; argv[argc] != NULL; argc++);
copy = (char **) xmalloc ((argc + 1) * sizeof (char *));
/* the strings */
for (argc = 0; argv[argc] != NULL; argc++)
copy[argc] = xstrdup (argv[argc]);
copy[argc] = NULL;
return copy;
}
/*
@deftypefn Extension void freeargv (char **@var{vector})
Free an argument vector that was built using @code{buildargv}. Simply
scans through @var{vector}, freeing the memory for each argument until
the terminating @code{NULL} is found, and then frees @var{vector}
itself.
@end deftypefn
*/
void freeargv (char **vector)
{
register char **scan;
if (vector != NULL)
{
for (scan = vector; *scan != NULL; scan++)
{
free (*scan);
}
free (vector);
}
}
static void
consume_whitespace (const char **input)
{
while (ISSPACE (**input))
{
(*input)++;
}
}
static int
only_whitespace (const char* input)
{
while (*input != EOS && ISSPACE (*input))
input++;
return (*input == EOS);
}
/*
@deftypefn Extension char** buildargv (char *@var{sp})
Given a pointer to a string, parse the string extracting fields
separated by whitespace and optionally enclosed within either single
or double quotes (which are stripped off), and build a vector of
pointers to copies of the string for each field. The input string
remains unchanged. The last element of the vector is followed by a
@code{NULL} element.
All of the memory for the pointer array and copies of the string
is obtained from @code{xmalloc}. All of the memory can be returned to the
system with the single function call @code{freeargv}, which takes the
returned result of @code{buildargv}, as it's argument.
Returns a pointer to the argument vector if successful. Returns
@code{NULL} if @var{sp} is @code{NULL} or if there is insufficient
memory to complete building the argument vector.
If the input is a null string (as opposed to a @code{NULL} pointer),
then buildarg returns an argument vector that has one arg, a null
string.
@end deftypefn
The memory for the argv array is dynamically expanded as necessary.
In order to provide a working buffer for extracting arguments into,
with appropriate stripping of quotes and translation of backslash
sequences, we allocate a working buffer at least as long as the input
string. This ensures that we always have enough space in which to
work, since the extracted arg is never larger than the input string.
The argument vector is always kept terminated with a @code{NULL} arg
pointer, so it can be passed to @code{freeargv} at any time, or
returned, as appropriate.
*/
char **buildargv (const char *input)
{
char *arg;
char *copybuf;
int squote = 0;
int dquote = 0;
int bsquote = 0;
int argc = 0;
int maxargc = 0;
char **argv = NULL;
char **nargv;
if (input != NULL)
{
copybuf = (char *) xmalloc (strlen (input) + 1);
/* Is a do{}while to always execute the loop once. Always return an
argv, even for null strings. See NOTES above, test case below. */
do
{
/* Pick off argv[argc] */
consume_whitespace (&input);
if ((maxargc == 0) || (argc >= (maxargc - 1)))
{
/* argv needs initialization, or expansion */
if (argv == NULL)
{
maxargc = INITIAL_MAXARGC;
nargv = (char **) xmalloc (maxargc * sizeof (char *));
}
else
{
maxargc *= 2;
nargv = (char **) xrealloc (argv, maxargc * sizeof (char *));
}
argv = nargv;
argv[argc] = NULL;
}
/* Begin scanning arg */
arg = copybuf;
while (*input != EOS)
{
if (ISSPACE (*input) && !squote && !dquote && !bsquote)
{
break;
}
else
{
if (bsquote)
{
bsquote = 0;
*arg++ = *input;
}
else if (*input == '\\')
{
bsquote = 1;
}
else if (squote)
{
if (*input == '\'')
{
squote = 0;
}
else
{
*arg++ = *input;
}
}
else if (dquote)
{
if (*input == '"')
{
dquote = 0;
}
else
{
*arg++ = *input;
}
}
else
{
if (*input == '\'')
{
squote = 1;
}
else if (*input == '"')
{
dquote = 1;
}
else
{
*arg++ = *input;
}
}
input++;
}
}
*arg = EOS;
argv[argc] = xstrdup (copybuf);
argc++;
argv[argc] = NULL;
consume_whitespace (&input);
}
while (*input != EOS);
free (copybuf);
}
return (argv);
}
/*
@deftypefn Extension int writeargv (char * const *@var{argv}, FILE *@var{file})
Write each member of ARGV, handling all necessary quoting, to the file
named by FILE, separated by whitespace. Return 0 on success, non-zero
if an error occurred while writing to FILE.
@end deftypefn
*/
int
writeargv (char * const *argv, FILE *f)
{
int status = 0;
if (f == NULL)
return 1;
while (*argv != NULL)
{
const char *arg = *argv;
while (*arg != EOS)
{
char c = *arg;
if (ISSPACE(c) || c == '\\' || c == '\'' || c == '"')
if (EOF == fputc ('\\', f))
{
status = 1;
goto done;
}
if (EOF == fputc (c, f))
{
status = 1;
goto done;
}
arg++;
}
if (EOF == fputc ('\n', f))
{
status = 1;
goto done;
}
argv++;
}
done:
return status;
}
/*
@deftypefn Extension void expandargv (int *@var{argcp}, char ***@var{argvp})
The @var{argcp} and @code{argvp} arguments are pointers to the usual
@code{argc} and @code{argv} arguments to @code{main}. This function
looks for arguments that begin with the character @samp{@@}. Any such
arguments are interpreted as ``response files''. The contents of the
response file are interpreted as additional command line options. In
particular, the file is separated into whitespace-separated strings;
each such string is taken as a command-line option. The new options
are inserted in place of the option naming the response file, and
@code{*argcp} and @code{*argvp} will be updated. If the value of
@code{*argvp} is modified by this function, then the new value has
been dynamically allocated and can be deallocated by the caller with
@code{freeargv}. However, most callers will simply call
@code{expandargv} near the beginning of @code{main} and allow the
operating system to free the memory when the program exits.
@end deftypefn
*/
void
expandargv (int *argcp, char ***argvp)
{
/* The argument we are currently processing. */
int i = 0;
/* To check if ***argvp has been dynamically allocated. */
char ** const original_argv = *argvp;
/* Limit the number of response files that we parse in order
to prevent infinite recursion. */
unsigned int iteration_limit = 2000;
/* Loop over the arguments, handling response files. We always skip
ARGVP[0], as that is the name of the program being run. */
while (++i < *argcp)
{
/* The name of the response file. */
const char *filename;
/* The response file. */
FILE *f;
/* An upper bound on the number of characters in the response
file. */
long pos;
/* The number of characters in the response file, when actually
read. */
size_t len;
/* A dynamically allocated buffer used to hold options read from a
response file. */
char *buffer;
/* Dynamically allocated storage for the options read from the
response file. */
char **file_argv;
/* The number of options read from the response file, if any. */
size_t file_argc;
#ifdef S_ISDIR
struct stat sb;
#endif
/* We are only interested in options of the form "@file". */
filename = (*argvp)[i];
if (filename[0] != '@')
continue;
/* If we have iterated too many times then stop. */
if (-- iteration_limit == 0)
{
fprintf (stderr, "%s: error: too many @-files encountered\n", (*argvp)[0]);
xexit (1);
}
#ifdef S_ISDIR
if (stat (filename+1, &sb) < 0)
continue;
if (S_ISDIR(sb.st_mode))
{
fprintf (stderr, "%s: error: @-file refers to a directory\n", (*argvp)[0]);
xexit (1);
}
#endif
/* Read the contents of the file. */
f = fopen (++filename, "r");
if (!f)
continue;
if (fseek (f, 0L, SEEK_END) == -1)
goto error;
pos = ftell (f);
if (pos == -1)
goto error;
if (fseek (f, 0L, SEEK_SET) == -1)
goto error;
buffer = (char *) xmalloc (pos * sizeof (char) + 1);
len = fread (buffer, sizeof (char), pos, f);
if (len != (size_t) pos
/* On Windows, fread may return a value smaller than POS,
due to CR/LF->CR translation when reading text files.
That does not in-and-of itself indicate failure. */
&& ferror (f))
goto error;
/* Add a NUL terminator. */
buffer[len] = '\0';
/* If the file is empty or contains only whitespace, buildargv would
return a single empty argument. In this context we want no arguments,
instead. */
if (only_whitespace (buffer))
{
file_argv = (char **) xmalloc (sizeof (char *));
file_argv[0] = NULL;
}
else
/* Parse the string. */
file_argv = buildargv (buffer);
/* If *ARGVP is not already dynamically allocated, copy it. */
if (*argvp == original_argv)
*argvp = dupargv (*argvp);
/* Count the number of arguments. */
file_argc = 0;
while (file_argv[file_argc])
++file_argc;
/* Free the original option's memory. */
free ((*argvp)[i]);
/* Now, insert FILE_ARGV into ARGV. The "+1" below handles the
NULL terminator at the end of ARGV. */
*argvp = ((char **)
xrealloc (*argvp,
(*argcp + file_argc + 1) * sizeof (char *)));
memmove (*argvp + i + file_argc, *argvp + i + 1,
(*argcp - i) * sizeof (char *));
memcpy (*argvp + i, file_argv, file_argc * sizeof (char *));
/* The original option has been replaced by all the new
options. */
*argcp += file_argc - 1;
/* Free up memory allocated to process the response file. We do
not use freeargv because the individual options in FILE_ARGV
are now in the main ARGV. */
free (file_argv);
free (buffer);
/* Rescan all of the arguments just read to support response
files that include other response files. */
--i;
error:
/* We're all done with the file now. */
fclose (f);
}
}
/*
@deftypefn Extension int countargv (char * const *@var{argv})
Return the number of elements in @var{argv}.
Returns zero if @var{argv} is NULL.
@end deftypefn
*/
int
countargv (char * const *argv)
{
int argc;
if (argv == NULL)
return 0;
for (argc = 0; argv[argc] != NULL; argc++)
continue;
return argc;
}
#ifdef MAIN
/* Simple little test driver. */
static const char *const tests[] =
{
"a simple command line",
"arg 'foo' is single quoted",
"arg \"bar\" is double quoted",
"arg \"foo bar\" has embedded whitespace",
"arg 'Jack said \\'hi\\'' has single quotes",
"arg 'Jack said \\\"hi\\\"' has double quotes",
"a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4 5 6 7 8 9",
/* This should be expanded into only one argument. */
"trailing-whitespace ",
"",
NULL
};
int
main (void)
{
char **argv;
const char *const *test;
char **targs;
for (test = tests; *test != NULL; test++)
{
printf ("buildargv(\"%s\")\n", *test);
if ((argv = buildargv (*test)) == NULL)
{
printf ("failed!\n\n");
}
else
{
for (targs = argv; *targs != NULL; targs++)
{
printf ("\t\"%s\"\n", *targs);
}
printf ("\n");
}
freeargv (argv);
}
return 0;
}
#endif /* MAIN */

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,495 @@
/* ###
* IP: LGPL 2.1
* NOTE: See binutils/libiberty/COPYING.LIB
*/
/* Demangler for GNU C++
Copyright (C) 1989-2019 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.uucp)
Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
Modified by Satish Pai (pai@apollo.hp.com) for HP demangling
This file is part of the libiberty library.
Libiberty is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
In addition to the permissions in the GNU Library General Public
License, the Free Software Foundation gives you unlimited permission
to link the compiled version of this file into combinations with other
programs, and to distribute those combinations without any restriction
coming from the use of this file. (The Library Public License
restrictions do apply in other respects; for example, they cover
modification of the file, and distribution when not linked into a
combined executable.)
Libiberty 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with libiberty; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
/* This file lives in both GCC and libiberty. When making changes, please
try not to break either. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "safe-ctype.h"
#include <string.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#else
void * malloc ();
void * realloc ();
#endif
#include <demangle.h>
#undef CURRENT_DEMANGLING_STYLE
#define CURRENT_DEMANGLING_STYLE options
#include "libiberty.h"
#include "rust-demangle.h"
enum demangling_styles current_demangling_style = auto_demangling;
const struct demangler_engine libiberty_demanglers[] =
{
{
NO_DEMANGLING_STYLE_STRING,
no_demangling,
"Demangling disabled"
}
,
{
AUTO_DEMANGLING_STYLE_STRING,
auto_demangling,
"Automatic selection based on executable"
}
,
{
GNU_V3_DEMANGLING_STYLE_STRING,
gnu_v3_demangling,
"GNU (g++) V3 (Itanium C++ ABI) style demangling"
}
,
{
JAVA_DEMANGLING_STYLE_STRING,
java_demangling,
"Java style demangling"
}
,
{
GNAT_DEMANGLING_STYLE_STRING,
gnat_demangling,
"GNAT style demangling"
}
,
{
DLANG_DEMANGLING_STYLE_STRING,
dlang_demangling,
"DLANG style demangling"
}
,
{
RUST_DEMANGLING_STYLE_STRING,
rust_demangling,
"Rust style demangling"
}
,
{
NULL, unknown_demangling, NULL
}
};
/* Add a routine to set the demangling style to be sure it is valid and
allow for any demangler initialization that maybe necessary. */
enum demangling_styles
cplus_demangle_set_style (enum demangling_styles style)
{
const struct demangler_engine *demangler = libiberty_demanglers;
for (; demangler->demangling_style != unknown_demangling; ++demangler)
if (style == demangler->demangling_style)
{
current_demangling_style = style;
return current_demangling_style;
}
return unknown_demangling;
}
/* Do string name to style translation */
enum demangling_styles
cplus_demangle_name_to_style (const char *name)
{
const struct demangler_engine *demangler = libiberty_demanglers;
for (; demangler->demangling_style != unknown_demangling; ++demangler)
if (strcmp (name, demangler->demangling_style_name) == 0)
return demangler->demangling_style;
return unknown_demangling;
}
/* char *cplus_demangle (const char *mangled, int options)
If MANGLED is a mangled function name produced by GNU C++, then
a pointer to a @code{malloc}ed string giving a C++ representation
of the name will be returned; otherwise NULL will be returned.
It is the caller's responsibility to free the string which
is returned.
Note that any leading underscores, or other such characters prepended by
the compilation system, are presumed to have already been stripped from
MANGLED. */
char *
cplus_demangle (const char *mangled, int options)
{
char *ret;
if (current_demangling_style == no_demangling)
return xstrdup (mangled);
if ((options & DMGL_STYLE_MASK) == 0)
options |= (int) current_demangling_style & DMGL_STYLE_MASK;
/* The V3 ABI demangling is implemented elsewhere. */
if (GNU_V3_DEMANGLING || RUST_DEMANGLING || AUTO_DEMANGLING)
{
ret = cplus_demangle_v3 (mangled, options);
if (GNU_V3_DEMANGLING)
return ret;
if (ret)
{
/* Rust symbols are GNU_V3 mangled plus some extra subtitutions.
The subtitutions are always smaller, so do in place changes. */
if (rust_is_mangled (ret))
rust_demangle_sym (ret);
else if (RUST_DEMANGLING)
{
free (ret);
ret = NULL;
}
}
if (ret || RUST_DEMANGLING)
return ret;
}
if (JAVA_DEMANGLING)
{
ret = java_demangle_v3 (mangled);
if (ret)
return ret;
}
if (GNAT_DEMANGLING)
return ada_demangle (mangled, options);
if (DLANG_DEMANGLING)
{
ret = dlang_demangle (mangled, options);
if (ret)
return ret;
}
return (ret);
}
char *
rust_demangle (const char *mangled, int options)
{
/* Rust symbols are GNU_V3 mangled plus some extra subtitutions. */
char *ret = cplus_demangle_v3 (mangled, options);
/* The Rust subtitutions are always smaller, so do in place changes. */
if (ret != NULL)
{
if (rust_is_mangled (ret))
rust_demangle_sym (ret);
else
{
free (ret);
ret = NULL;
}
}
return ret;
}
/* Demangle ada names. The encoding is documented in gcc/ada/exp_dbug.ads. */
char *
ada_demangle (const char *mangled, int option ATTRIBUTE_UNUSED)
{
int len0;
const char* p;
char *d;
char *demangled = NULL;
/* Discard leading _ada_, which is used for library level subprograms. */
if (strncmp (mangled, "_ada_", 5) == 0)
mangled += 5;
/* All ada unit names are lower-case. */
if (!ISLOWER (mangled[0]))
goto unknown;
/* Most of the demangling will trivially remove chars. Operator names
may add one char but because they are always preceeded by '__' which is
replaced by '.', they eventually never expand the size.
A few special names such as '___elabs' add a few chars (at most 7), but
they occur only once. */
len0 = strlen (mangled) + 7 + 1;
demangled = XNEWVEC (char, len0);
d = demangled;
p = mangled;
while (1)
{
/* An entity names is expected. */
if (ISLOWER (*p))
{
/* An identifier, which is always lower case. */
do
*d++ = *p++;
while (ISLOWER(*p) || ISDIGIT (*p)
|| (p[0] == '_' && (ISLOWER (p[1]) || ISDIGIT (p[1]))));
}
else if (p[0] == 'O')
{
/* An operator name. */
static const char * const operators[][2] =
{{"Oabs", "abs"}, {"Oand", "and"}, {"Omod", "mod"},
{"Onot", "not"}, {"Oor", "or"}, {"Orem", "rem"},
{"Oxor", "xor"}, {"Oeq", "="}, {"One", "/="},
{"Olt", "<"}, {"Ole", "<="}, {"Ogt", ">"},
{"Oge", ">="}, {"Oadd", "+"}, {"Osubtract", "-"},
{"Oconcat", "&"}, {"Omultiply", "*"}, {"Odivide", "/"},
{"Oexpon", "**"}, {NULL, NULL}};
int k;
for (k = 0; operators[k][0] != NULL; k++)
{
size_t slen = strlen (operators[k][0]);
if (strncmp (p, operators[k][0], slen) == 0)
{
p += slen;
slen = strlen (operators[k][1]);
*d++ = '"';
memcpy (d, operators[k][1], slen);
d += slen;
*d++ = '"';
break;
}
}
/* Operator not found. */
if (operators[k][0] == NULL)
goto unknown;
}
else
{
/* Not a GNAT encoding. */
goto unknown;
}
/* The name can be directly followed by some uppercase letters. */
if (p[0] == 'T' && p[1] == 'K')
{
/* Task stuff. */
if (p[2] == 'B' && p[3] == 0)
{
/* Subprogram for task body. */
break;
}
else if (p[2] == '_' && p[3] == '_')
{
/* Inner declarations in a task. */
p += 4;
*d++ = '.';
continue;
}
else
goto unknown;
}
if (p[0] == 'E' && p[1] == 0)
{
/* Exception name. */
goto unknown;
}
if ((p[0] == 'P' || p[0] == 'N') && p[1] == 0)
{
/* Protected type subprogram. */
break;
}
if ((*p == 'N' || *p == 'S') && p[1] == 0)
{
/* Enumerated type name table. */
goto unknown;
}
if (p[0] == 'X')
{
/* Body nested. */
p++;
while (p[0] == 'n' || p[0] == 'b')
p++;
}
if (p[0] == 'S' && p[1] != 0 && (p[2] == '_' || p[2] == 0))
{
/* Stream operations. */
const char *name;
switch (p[1])
{
case 'R':
name = "'Read";
break;
case 'W':
name = "'Write";
break;
case 'I':
name = "'Input";
break;
case 'O':
name = "'Output";
break;
default:
goto unknown;
}
p += 2;
strcpy (d, name);
d += strlen (name);
}
else if (p[0] == 'D')
{
/* Controlled type operation. */
const char *name;
switch (p[1])
{
case 'F':
name = ".Finalize";
break;
case 'A':
name = ".Adjust";
break;
default:
goto unknown;
}
strcpy (d, name);
d += strlen (name);
break;
}
if (p[0] == '_')
{
/* Separator. */
if (p[1] == '_')
{
/* Standard separator. Handled first. */
p += 2;
if (ISDIGIT (*p))
{
/* Overloading number. */
do
p++;
while (ISDIGIT (*p) || (p[0] == '_' && ISDIGIT (p[1])));
if (*p == 'X')
{
p++;
while (p[0] == 'n' || p[0] == 'b')
p++;
}
}
else if (p[0] == '_' && p[1] != '_')
{
/* Special names. */
static const char * const special[][2] = {
{ "_elabb", "'Elab_Body" },
{ "_elabs", "'Elab_Spec" },
{ "_size", "'Size" },
{ "_alignment", "'Alignment" },
{ "_assign", ".\":=\"" },
{ NULL, NULL }
};
int k;
for (k = 0; special[k][0] != NULL; k++)
{
size_t slen = strlen (special[k][0]);
if (strncmp (p, special[k][0], slen) == 0)
{
p += slen;
slen = strlen (special[k][1]);
memcpy (d, special[k][1], slen);
d += slen;
break;
}
}
if (special[k][0] != NULL)
break;
else
goto unknown;
}
else
{
*d++ = '.';
continue;
}
}
else if (p[1] == 'B' || p[1] == 'E')
{
/* Entry Body or barrier Evaluation. */
p += 2;
while (ISDIGIT (*p))
p++;
if (p[0] == 's' && p[1] == 0)
break;
else
goto unknown;
}
else
goto unknown;
}
if (p[0] == '.' && ISDIGIT (p[1]))
{
/* Nested subprogram. */
p += 2;
while (ISDIGIT (*p))
p++;
}
if (*p == 0)
{
/* End of mangled name. */
break;
}
else
goto unknown;
}
*d = 0;
return demangled;
unknown:
XDELETEVEC (demangled);
len0 = strlen (mangled);
demangled = XNEWVEC (char, len0 + 3);
if (mangled[0] == '<')
strcpy (demangled, mangled);
else
sprintf (demangled, "<%s>", mangled);
return demangled;
}

View file

@ -0,0 +1,272 @@
/* ###
* IP: GPL 3
*/
/* Demangler for GNU C++ - main program
Copyright (C) 1989-2019 Free Software Foundation, Inc.
Written by James Clark (jjc@jclark.uucp)
Rewritten by Fred Fish (fnf@cygnus.com) for ARM and Lucid demangling
Modified by Satish Pai (pai@apollo.hp.com) for HP demangling
This file is part of GNU Binutils.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or (at
your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA.
CHANGE NOTICE:
This file was changed on July 22nd, 2020.
*/
#include "libiberty.h"
#include "demangle.h"
#include "getopt.h"
#include "safe-ctype.h"
static int flags = DMGL_PARAMS | DMGL_ANSI | DMGL_VERBOSE;
static int strip_underscore = 0; // TARGET_PREPENDS_UNDERSCORE; // Changed Jan 22, 2020
static const char *program_name; // Changed Jan 22, 2020
static const struct option long_options[] =
{
{"strip-underscore", no_argument, NULL, '_'},
{"format", required_argument, NULL, 's'},
{"help", no_argument, NULL, 'h'},
{"no-params", no_argument, NULL, 'p'},
{"no-strip-underscores", no_argument, NULL, 'n'},
{"no-verbose", no_argument, NULL, 'i'},
{"types", no_argument, NULL, 't'},
{"version", no_argument, NULL, 'v'},
{"recurse-limit", no_argument, NULL, 'R'},
{"recursion-limit", no_argument, NULL, 'R'},
{"no-recurse-limit", no_argument, NULL, 'r'},
{"no-recursion-limit", no_argument, NULL, 'r'},
{NULL, no_argument, NULL, 0}
};
static void
demangle_it (char *mangled_name)
{
char *result;
unsigned int skip_first = 0;
/* _ and $ are sometimes found at the start of function names
in assembler sources in order to distinguish them from other
names (eg register names). So skip them here. */
if (mangled_name[0] == '.' || mangled_name[0] == '$')
++skip_first;
if (strip_underscore && mangled_name[skip_first] == '_')
++skip_first;
result = cplus_demangle (mangled_name + skip_first, flags);
if (result == NULL)
printf ("%s", mangled_name);
else
{
if (mangled_name[0] == '.')
putchar ('.');
printf ("%s", result);
free (result);
}
}
static void
print_demangler_list (FILE *stream)
{
const struct demangler_engine *demangler;
fprintf (stream, "{%s", libiberty_demanglers->demangling_style_name);
for (demangler = libiberty_demanglers + 1;
demangler->demangling_style != unknown_demangling;
++demangler)
fprintf (stream, ",%s", demangler->demangling_style_name);
fprintf (stream, "}");
}
ATTRIBUTE_NORETURN static void
usage (FILE *stream, int status)
{
fprintf (stream, "\
Usage: %s [options] [mangled names]\n", program_name);
fprintf (stream, "\
Options are:\n\
[-_|--strip-underscore] Ignore first leading underscore%s\n",
strip_underscore ? " (default)" : ""); // Changed Jan 22, 2020
fprintf (stream, "\
[-n|--no-strip-underscore] Do not ignore a leading underscore%s\n",
strip_underscore ? "" : " (default)"); // Changed Jan 22, 2020
fprintf (stream, "\
[-p|--no-params] Do not display function arguments\n\
[-i|--no-verbose] Do not show implementation details (if any)\n\
[-R|--recurse-limit] Enable a limit on recursion whilst demangling. [Default]\n\
]-r|--no-recurse-limit] Disable a limit on recursion whilst demangling\n\
[-t|--types] Also attempt to demangle type encodings\n\
[-s|--format ");
print_demangler_list (stream);
fprintf (stream, "]\n");
fprintf (stream, "\
[@<file>] Read extra options from <file>\n\
[-h|--help] Display this information\n\
[-v|--version] Show the version information\n\
Demangled names are displayed to stdout.\n\
If a name cannot be demangled it is just echoed to stdout.\n\
If no names are provided on the command line, stdin is read.\n");
/* Changed Jan 22, 2020
if (REPORT_BUGS_TO[0] && status == 0)
fprintf (stream, _("Report bugs to %s.\n"), REPORT_BUGS_TO);
*/
exit (status);
}
/* Return the string of non-alnum characters that may occur
as a valid symbol component, in the standard assembler symbol
syntax. */
static const char *
standard_symbol_characters (void)
{
return "_$.";
}
extern int main (int, char **);
int
main (int argc, char **argv)
{
int c;
const char *valid_symbols;
enum demangling_styles style = auto_demangling;
program_name = argv[0];
// xmalloc_set_program_name (program_name); // Changed Jan 22, 2020
// bfd_set_error_program_name (program_name); // Changed Jan 22, 2020
expandargv (&argc, &argv);
while ((c = getopt_long (argc, argv, "_hinprRs:tv", long_options, (int *) 0)) != EOF)
{
switch (c)
{
case '?':
usage (stderr, 1);
break;
case 'h':
usage (stdout, 0);
case 'n':
strip_underscore = 0;
break;
case 'p':
flags &= ~ DMGL_PARAMS;
break;
case 'r':
flags |= DMGL_NO_RECURSE_LIMIT;
break;
case 'R':
flags &= ~ DMGL_NO_RECURSE_LIMIT;
break;
case 't':
flags |= DMGL_TYPES;
break;
case 'i':
flags &= ~ DMGL_VERBOSE;
break;
case 'v':
printf ("(GNU Binutils) c++filt 2.33.1\n"); // Changed Jan 22, 2020
return 0;
case '_':
strip_underscore = 1;
break;
case 's':
style = cplus_demangle_name_to_style (optarg);
if (style == unknown_demangling)
{
fprintf (stderr, "%s: unknown demangling style `%s'\n",
program_name, optarg);
return 1;
}
cplus_demangle_set_style (style);
break;
}
}
if (optind < argc)
{
for ( ; optind < argc; optind++)
{
demangle_it (argv[optind]);
putchar ('\n');
}
return 0;
}
switch (current_demangling_style)
{
case auto_demangling:
case gnu_v3_demangling:
case java_demangling:
case gnat_demangling:
case dlang_demangling:
case rust_demangling:
valid_symbols = standard_symbol_characters ();
break;
default: {
/* Folks should explicitly indicate the appropriate alphabet for
each demangling. Providing a default would allow the
question to go unconsidered. */
fprintf (stderr, "Internal error: no symbol alphabet for current style\n"); // Changed Jan 22, 2020
exit (1); // Changed Jan 22, 2020
}
}
for (;;)
{
static char mbuffer[32767];
unsigned i = 0;
c = getchar ();
/* Try to read a mangled name. */
while (c != EOF && (ISALNUM (c) || strchr (valid_symbols, c)))
{
if (i >= sizeof (mbuffer) - 1)
break;
mbuffer[i++] = c;
c = getchar ();
}
if (i > 0)
{
mbuffer[i] = 0;
demangle_it (mbuffer);
}
if (c == EOF)
break;
/* Echo the whitespace characters so that the output looks
like the input, only with the mangled names demangled. */
putchar (c);
if (c == '\n')
fflush (stdout);
}
fflush (stdout);
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,401 @@
/* ###
* IP: GPL 3 Linking Permitted
* NOTE: See binutils/include/COPYING3
*/
/* An abstract string datatype.
Copyright (C) 1998-2019 Free Software Foundation, Inc.
Contributed by Mark Mitchell (mark@markmitchell.com).
This file is part of GNU CC.
GNU CC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
In addition to the permissions in the GNU General Public License, the
Free Software Foundation gives you unlimited permission to link the
compiled version of this file into combinations with other programs,
and to distribute those combinations without any restriction coming
from the use of this file. (The General Public License restrictions
do apply in other respects; for example, they cover modification of
the file, and distribution when not linked into a combined
executable.)
GNU CC 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to
the Free Software Foundation, 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "libiberty.h"
#include "dyn-string.h"
/* Performs in-place initialization of a dyn_string struct. This
function can be used with a dyn_string struct on the stack or
embedded in another object. The contents of of the string itself
are still dynamically allocated. The string initially is capable
of holding at least SPACE characeters, including the terminating
NUL. If SPACE is 0, it will silently be increated to 1.
If RETURN_ON_ALLOCATION_FAILURE is defined and memory allocation
fails, returns 0. Otherwise returns 1. */
int
dyn_string_init (struct dyn_string *ds_struct_ptr, int space)
{
/* We need at least one byte in which to store the terminating NUL. */
if (space == 0)
space = 1;
#ifdef RETURN_ON_ALLOCATION_FAILURE
ds_struct_ptr->s = (char *) malloc (space);
if (ds_struct_ptr->s == NULL)
return 0;
#else
ds_struct_ptr->s = XNEWVEC (char, space);
#endif
ds_struct_ptr->allocated = space;
ds_struct_ptr->length = 0;
ds_struct_ptr->s[0] = '\0';
return 1;
}
/* Create a new dynamic string capable of holding at least SPACE
characters, including the terminating NUL. If SPACE is 0, it will
be silently increased to 1. If RETURN_ON_ALLOCATION_FAILURE is
defined and memory allocation fails, returns NULL. Otherwise
returns the newly allocated string. */
dyn_string_t
dyn_string_new (int space)
{
dyn_string_t result;
#ifdef RETURN_ON_ALLOCATION_FAILURE
result = (dyn_string_t) malloc (sizeof (struct dyn_string));
if (result == NULL)
return NULL;
if (!dyn_string_init (result, space))
{
free (result);
return NULL;
}
#else
result = XNEW (struct dyn_string);
dyn_string_init (result, space);
#endif
return result;
}
/* Free the memory used by DS. */
void
dyn_string_delete (dyn_string_t ds)
{
free (ds->s);
free (ds);
}
/* Returns the contents of DS in a buffer allocated with malloc. It
is the caller's responsibility to deallocate the buffer using free.
DS is then set to the empty string. Deletes DS itself. */
char*
dyn_string_release (dyn_string_t ds)
{
/* Store the old buffer. */
char* result = ds->s;
/* The buffer is no longer owned by DS. */
ds->s = NULL;
/* Delete DS. */
free (ds);
/* Return the old buffer. */
return result;
}
/* Increase the capacity of DS so it can hold at least SPACE
characters, plus the terminating NUL. This function will not (at
present) reduce the capacity of DS. Returns DS on success.
If RETURN_ON_ALLOCATION_FAILURE is defined and a memory allocation
operation fails, deletes DS and returns NULL. */
dyn_string_t
dyn_string_resize (dyn_string_t ds, int space)
{
int new_allocated = ds->allocated;
/* Increase SPACE to hold the NUL termination. */
++space;
/* Increase allocation by factors of two. */
while (space > new_allocated)
new_allocated *= 2;
if (new_allocated != ds->allocated)
{
ds->allocated = new_allocated;
/* We actually need more space. */
#ifdef RETURN_ON_ALLOCATION_FAILURE
ds->s = (char *) realloc (ds->s, ds->allocated);
if (ds->s == NULL)
{
free (ds);
return NULL;
}
#else
ds->s = XRESIZEVEC (char, ds->s, ds->allocated);
#endif
}
return ds;
}
/* Sets the contents of DS to the empty string. */
void
dyn_string_clear (dyn_string_t ds)
{
/* A dyn_string always has room for at least the NUL terminator. */
ds->s[0] = '\0';
ds->length = 0;
}
/* Makes the contents of DEST the same as the contents of SRC. DEST
and SRC must be distinct. Returns 1 on success. On failure, if
RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
int
dyn_string_copy (dyn_string_t dest, dyn_string_t src)
{
if (dest == src)
abort ();
/* Make room in DEST. */
if (dyn_string_resize (dest, src->length) == NULL)
return 0;
/* Copy DEST into SRC. */
strcpy (dest->s, src->s);
/* Update the size of DEST. */
dest->length = src->length;
return 1;
}
/* Copies SRC, a NUL-terminated string, into DEST. Returns 1 on
success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
and returns 0. */
int
dyn_string_copy_cstr (dyn_string_t dest, const char *src)
{
int length = strlen (src);
/* Make room in DEST. */
if (dyn_string_resize (dest, length) == NULL)
return 0;
/* Copy DEST into SRC. */
strcpy (dest->s, src);
/* Update the size of DEST. */
dest->length = length;
return 1;
}
/* Inserts SRC at the beginning of DEST. DEST is expanded as
necessary. SRC and DEST must be distinct. Returns 1 on success.
On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
returns 0. */
int
dyn_string_prepend (dyn_string_t dest, dyn_string_t src)
{
return dyn_string_insert (dest, 0, src);
}
/* Inserts SRC, a NUL-terminated string, at the beginning of DEST.
DEST is expanded as necessary. Returns 1 on success. On failure,
if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
int
dyn_string_prepend_cstr (dyn_string_t dest, const char *src)
{
return dyn_string_insert_cstr (dest, 0, src);
}
/* Inserts SRC into DEST starting at position POS. DEST is expanded
as necessary. SRC and DEST must be distinct. Returns 1 on
success. On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST
and returns 0. */
int
dyn_string_insert (dyn_string_t dest, int pos, dyn_string_t src)
{
int i;
if (src == dest)
abort ();
if (dyn_string_resize (dest, dest->length + src->length) == NULL)
return 0;
/* Make room for the insertion. Be sure to copy the NUL. */
for (i = dest->length; i >= pos; --i)
dest->s[i + src->length] = dest->s[i];
/* Splice in the new stuff. */
strncpy (dest->s + pos, src->s, src->length);
/* Compute the new length. */
dest->length += src->length;
return 1;
}
/* Inserts SRC, a NUL-terminated string, into DEST starting at
position POS. DEST is expanded as necessary. Returns 1 on
success. On failure, RETURN_ON_ALLOCATION_FAILURE, deletes DEST
and returns 0. */
int
dyn_string_insert_cstr (dyn_string_t dest, int pos, const char *src)
{
int i;
int length = strlen (src);
if (dyn_string_resize (dest, dest->length + length) == NULL)
return 0;
/* Make room for the insertion. Be sure to copy the NUL. */
for (i = dest->length; i >= pos; --i)
dest->s[i + length] = dest->s[i];
/* Splice in the new stuff. */
strncpy (dest->s + pos, src, length);
/* Compute the new length. */
dest->length += length;
return 1;
}
/* Inserts character C into DEST starting at position POS. DEST is
expanded as necessary. Returns 1 on success. On failure,
RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
int
dyn_string_insert_char (dyn_string_t dest, int pos, int c)
{
int i;
if (dyn_string_resize (dest, dest->length + 1) == NULL)
return 0;
/* Make room for the insertion. Be sure to copy the NUL. */
for (i = dest->length; i >= pos; --i)
dest->s[i + 1] = dest->s[i];
/* Add the new character. */
dest->s[pos] = c;
/* Compute the new length. */
++dest->length;
return 1;
}
/* Append S to DS, resizing DS if necessary. Returns 1 on success.
On failure, if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and
returns 0. */
int
dyn_string_append (dyn_string_t dest, dyn_string_t s)
{
if (dyn_string_resize (dest, dest->length + s->length) == 0)
return 0;
strcpy (dest->s + dest->length, s->s);
dest->length += s->length;
return 1;
}
/* Append the NUL-terminated string S to DS, resizing DS if necessary.
Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE,
deletes DEST and returns 0. */
int
dyn_string_append_cstr (dyn_string_t dest, const char *s)
{
int len = strlen (s);
/* The new length is the old length plus the size of our string, plus
one for the null at the end. */
if (dyn_string_resize (dest, dest->length + len) == NULL)
return 0;
strcpy (dest->s + dest->length, s);
dest->length += len;
return 1;
}
/* Appends C to the end of DEST. Returns 1 on success. On failure,
if RETURN_ON_ALLOCATION_FAILURE, deletes DEST and returns 0. */
int
dyn_string_append_char (dyn_string_t dest, int c)
{
/* Make room for the extra character. */
if (dyn_string_resize (dest, dest->length + 1) == NULL)
return 0;
/* Append the character; it will overwrite the old NUL. */
dest->s[dest->length] = c;
/* Add a new NUL at the end. */
dest->s[dest->length + 1] = '\0';
/* Update the length. */
++(dest->length);
return 1;
}
/* Sets the contents of DEST to the substring of SRC starting at START
and ending before END. START must be less than or equal to END,
and both must be between zero and the length of SRC, inclusive.
Returns 1 on success. On failure, if RETURN_ON_ALLOCATION_FAILURE,
deletes DEST and returns 0. */
int
dyn_string_substring (dyn_string_t dest, dyn_string_t src,
int start, int end)
{
int i;
int length = end - start;
if (start > end || start > src->length || end > src->length)
abort ();
/* Make room for the substring. */
if (dyn_string_resize (dest, length) == NULL)
return 0;
/* Copy the characters in the substring, */
for (i = length; --i >= 0; )
dest->s[i] = src->s[start + i];
/* NUL-terimate the result. */
dest->s[length] = '\0';
/* Record the length of the substring. */
dest->length = length;
return 1;
}
/* Returns non-zero if DS1 and DS2 have the same contents. */
int
dyn_string_eq (dyn_string_t ds1, dyn_string_t ds2)
{
/* If DS1 and DS2 have different lengths, they must not be the same. */
if (ds1->length != ds2->length)
return 0;
else
return !strcmp (ds1->s, ds2->s);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,183 @@
/* ###
* IP: GPL 3
* NOTE: See binutils/include/COPYING3
*/
/* getopt_long and getopt_long_only entry points for GNU getopt.
Copyright (C) 1987-2019 Free Software Foundation, Inc.
NOTE: This source is derived from an old version taken from the GNU C
Library (glibc).
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
USA. */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#if !defined __STDC__ || !__STDC__
/* This is a separate conditional since some stdc systems
reject `defined (const)'. */
#ifndef const
#define const
#endif
#endif
#include <stdio.h>
#include "getopt.h"
/* Comment out all this code if we are using the GNU C Library, and are not
actually compiling the library itself. This code is part of the GNU C
Library, but also included in many other GNU distributions. Compiling
and linking in this code is a waste when using the GNU C library
(especially if it is a shared library). Rather than having every GNU
program understand `configure --with-gnu-libc' and omit the object files,
it is simpler to just do this in the source for each such file. */
#define GETOPT_INTERFACE_VERSION 2
#if !defined _LIBC && defined __GLIBC__ && __GLIBC__ >= 2
#include <gnu-versions.h>
#if _GNU_GETOPT_INTERFACE_VERSION == GETOPT_INTERFACE_VERSION
#define ELIDE_CODE
#endif
#endif
#ifndef ELIDE_CODE
/* This needs to come after some library #include
to get __GNU_LIBRARY__ defined. */
#ifdef __GNU_LIBRARY__
#include <stdlib.h>
#endif
#ifndef NULL
#define NULL 0
#endif
int
getopt_long (int argc, char *const *argv, const char *options,
const struct option *long_options, int *opt_index)
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
}
/* Like getopt_long, but '-' as well as '--' can indicate a long option.
If an option that starts with '-' (not '--') doesn't match a long option,
but does match a short option, it is parsed as a short option
instead. */
int
getopt_long_only (int argc, char *const *argv, const char *options,
const struct option *long_options, int *opt_index)
{
return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
}
#endif /* Not ELIDE_CODE. */
#ifdef TEST
#include <stdio.h>
int
main (int argc, char **argv)
{
int c;
int digit_optind = 0;
while (1)
{
int this_option_optind = optind ? optind : 1;
int option_index = 0;
static struct option long_options[] =
{
{"add", 1, 0, 0},
{"append", 0, 0, 0},
{"delete", 1, 0, 0},
{"verbose", 0, 0, 0},
{"create", 0, 0, 0},
{"file", 1, 0, 0},
{0, 0, 0, 0}
};
c = getopt_long (argc, argv, "abc:d:0123456789",
long_options, &option_index);
if (c == -1)
break;
switch (c)
{
case 0:
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (digit_optind != 0 && digit_optind != this_option_optind)
printf ("digits occur in two different argv-elements.\n");
digit_optind = this_option_optind;
printf ("option %c\n", c);
break;
case 'a':
printf ("option a\n");
break;
case 'b':
printf ("option b\n");
break;
case 'c':
printf ("option c with value `%s'\n", optarg);
break;
case 'd':
printf ("option d with value `%s'\n", optarg);
break;
case '?':
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
printf ("\n");
}
exit (0);
}
#endif /* TEST */

View file

@ -0,0 +1,75 @@
/* ###
* IP: LGPL 2.1
* NOTE: Code copied from older version of cplus-dem.c that Ghidra had modified
*/
/*
Copyright (C) 2003-2019 Free Software Foundation, Inc.
This file exists to provide code missing from sibling files in this directory.
In addition to the permissions in the GNU Library General Public
License, the Free Software Foundation gives you unlimited permission
to link the compiled version of this file into combinations with other
programs, and to distribute those combinations without any restriction
coming from the use of this file. (The Library Public License
restrictions do apply in other respects; for example, they cover
modification of the file, and distribution when not linked into a
combined executable.)
Libiberty 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with libiberty; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA.
CHANGE NOTICE:
This file was created on January 22nd, 2020:
-This code was copied and modified from a previous version of libiberty
*/
#include <sys/types.h>
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#else
void * malloc ();
void * realloc ();
#endif
static void
fatal (str)
const char *str;
{
fprintf (stderr, "%s\n", str);
exit (1);
}
void *
xmalloc (size)
size_t size;
{
register void * value = malloc (size);
if (value == 0)
fatal ("virtual memory exhausted");
return value;
}
void *
xrealloc (ptr, size)
size_t size;
{
register void * value = realloc (ptr, size);
if (value == 0)
fatal ("virtual memory exhausted");
return value;
}

View file

@ -0,0 +1,353 @@
/* ###
* IP: LGPL 2.1
* NOTE: See binutils/libiberty/COPYING.LIB
*/
/* Demangler for the Rust programming language
Copyright (C) 2016-2019 Free Software Foundation, Inc.
Written by David Tolnay (dtolnay@gmail.com).
This file is part of the libiberty library.
Libiberty is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
In addition to the permissions in the GNU Library General Public
License, the Free Software Foundation gives you unlimited permission
to link the compiled version of this file into combinations with other
programs, and to distribute those combinations without any restriction
coming from the use of this file. (The Library Public License
restrictions do apply in other respects; for example, they cover
modification of the file, and distribution when not linked into a
combined executable.)
Libiberty 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with libiberty; see the file COPYING.LIB.
If not, see <http://www.gnu.org/licenses/>. */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "safe-ctype.h"
#include <sys/types.h>
#include <string.h>
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#else
extern size_t strlen(const char *s);
extern int strncmp(const char *s1, const char *s2, size_t n);
extern void *memset(void *s, int c, size_t n);
#endif
#include <demangle.h>
#include "libiberty.h"
#include "rust-demangle.h"
/* Mangled Rust symbols look like this:
_$LT$std..sys..fd..FileDesc$u20$as$u20$core..ops..Drop$GT$::drop::hc68340e1baa4987a
The original symbol is:
<std::sys::fd::FileDesc as core::ops::Drop>::drop
The last component of the path is a 64-bit hash in lowercase hex,
prefixed with "h". Rust does not have a global namespace between
crates, an illusion which Rust maintains by using the hash to
distinguish things that would otherwise have the same symbol.
Any path component not starting with a XID_Start character is
prefixed with "_".
The following escape sequences are used:
"," => $C$
"@" => $SP$
"*" => $BP$
"&" => $RF$
"<" => $LT$
">" => $GT$
"(" => $LP$
")" => $RP$
" " => $u20$
"\"" => $u22$
"'" => $u27$
"+" => $u2b$
";" => $u3b$
"[" => $u5b$
"]" => $u5d$
"{" => $u7b$
"}" => $u7d$
"~" => $u7e$
A double ".." means "::" and a single "." means "-".
The only characters allowed in the mangled symbol are a-zA-Z0-9 and _.:$ */
static const char *hash_prefix = "::h";
static const size_t hash_prefix_len = 3;
static const size_t hash_len = 16;
static int is_prefixed_hash (const char *start);
static int looks_like_rust (const char *sym, size_t len);
static int unescape (const char **in, char **out, const char *seq, char value);
/* INPUT: sym: symbol that has been through C++ (gnu v3) demangling
This function looks for the following indicators:
1. The hash must consist of "h" followed by 16 lowercase hex digits.
2. As a sanity check, the hash must use between 5 and 15 of the 16
possible hex digits. This is true of 99.9998% of hashes so once
in your life you may see a false negative. The point is to
notice path components that could be Rust hashes but are
probably not, like "haaaaaaaaaaaaaaaa". In this case a false
positive (non-Rust symbol has an important path component
removed because it looks like a Rust hash) is worse than a false
negative (the rare Rust symbol is not demangled) so this sets
the balance in favor of false negatives.
3. There must be no characters other than a-zA-Z0-9 and _.:$
4. There must be no unrecognized $-sign sequences.
5. There must be no sequence of three or more dots in a row ("..."). */
int
rust_is_mangled (const char *sym)
{
size_t len, len_without_hash;
if (!sym)
return 0;
len = strlen (sym);
if (len <= hash_prefix_len + hash_len)
/* Not long enough to contain "::h" + hash + something else */
return 0;
len_without_hash = len - (hash_prefix_len + hash_len);
if (!is_prefixed_hash (sym + len_without_hash))
return 0;
return looks_like_rust (sym, len_without_hash);
}
/* A hash is the prefix "::h" followed by 16 lowercase hex digits. The
hex digits must comprise between 5 and 15 (inclusive) distinct
digits. */
static int
is_prefixed_hash (const char *str)
{
const char *end;
char seen[16];
size_t i;
int count;
if (strncmp (str, hash_prefix, hash_prefix_len))
return 0;
str += hash_prefix_len;
memset (seen, 0, sizeof(seen));
for (end = str + hash_len; str < end; str++)
if (*str >= '0' && *str <= '9')
seen[*str - '0'] = 1;
else if (*str >= 'a' && *str <= 'f')
seen[*str - 'a' + 10] = 1;
else
return 0;
/* Count how many distinct digits seen */
count = 0;
for (i = 0; i < 16; i++)
if (seen[i])
count++;
return count >= 5 && count <= 15;
}
static int
looks_like_rust (const char *str, size_t len)
{
const char *end = str + len;
while (str < end)
switch (*str)
{
case '$':
if (!strncmp (str, "$C$", 3))
str += 3;
else if (!strncmp (str, "$SP$", 4)
|| !strncmp (str, "$BP$", 4)
|| !strncmp (str, "$RF$", 4)
|| !strncmp (str, "$LT$", 4)
|| !strncmp (str, "$GT$", 4)
|| !strncmp (str, "$LP$", 4)
|| !strncmp (str, "$RP$", 4))
str += 4;
else if (!strncmp (str, "$u20$", 5)
|| !strncmp (str, "$u22$", 5)
|| !strncmp (str, "$u27$", 5)
|| !strncmp (str, "$u2b$", 5)
|| !strncmp (str, "$u3b$", 5)
|| !strncmp (str, "$u5b$", 5)
|| !strncmp (str, "$u5d$", 5)
|| !strncmp (str, "$u7b$", 5)
|| !strncmp (str, "$u7d$", 5)
|| !strncmp (str, "$u7e$", 5))
str += 5;
else
return 0;
break;
case '.':
/* Do not allow three or more consecutive dots */
if (!strncmp (str, "...", 3))
return 0;
/* Fall through */
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
case '0': case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
case '_':
case ':':
str++;
break;
default:
return 0;
}
return 1;
}
/*
INPUT: sym: symbol for which rust_is_mangled(sym) returned 1.
The input is demangled in-place because the mangled name is always
longer than the demangled one. */
void
rust_demangle_sym (char *sym)
{
const char *in;
char *out;
const char *end;
if (!sym)
return;
in = sym;
out = sym;
end = sym + strlen (sym) - (hash_prefix_len + hash_len);
while (in < end)
switch (*in)
{
case '$':
if (!(unescape (&in, &out, "$C$", ',')
|| unescape (&in, &out, "$SP$", '@')
|| unescape (&in, &out, "$BP$", '*')
|| unescape (&in, &out, "$RF$", '&')
|| unescape (&in, &out, "$LT$", '<')
|| unescape (&in, &out, "$GT$", '>')
|| unescape (&in, &out, "$LP$", '(')
|| unescape (&in, &out, "$RP$", ')')
|| unescape (&in, &out, "$u20$", ' ')
|| unescape (&in, &out, "$u22$", '\"')
|| unescape (&in, &out, "$u27$", '\'')
|| unescape (&in, &out, "$u2b$", '+')
|| unescape (&in, &out, "$u3b$", ';')
|| unescape (&in, &out, "$u5b$", '[')
|| unescape (&in, &out, "$u5d$", ']')
|| unescape (&in, &out, "$u7b$", '{')
|| unescape (&in, &out, "$u7d$", '}')
|| unescape (&in, &out, "$u7e$", '~'))) {
/* unexpected escape sequence, not looks_like_rust. */
goto fail;
}
break;
case '_':
/* If this is the start of a path component and the next
character is an escape sequence, ignore the underscore. The
mangler inserts an underscore to make sure the path
component begins with a XID_Start character. */
if ((in == sym || in[-1] == ':') && in[1] == '$')
in++;
else
*out++ = *in++;
break;
case '.':
if (in[1] == '.')
{
/* ".." becomes "::" */
*out++ = ':';
*out++ = ':';
in += 2;
}
else
{
/* "." becomes "-" */
*out++ = '-';
in++;
}
break;
case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
case 's': case 't': case 'u': case 'v': case 'w': case 'x':
case 'y': case 'z':
case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
case 'Y': case 'Z':
case '0': case '1': case '2': case '3': case '4': case '5':
case '6': case '7': case '8': case '9':
case ':':
*out++ = *in++;
break;
default:
/* unexpected character in symbol, not looks_like_rust. */
goto fail;
}
goto done;
fail:
*out++ = '?'; /* This is pretty lame, but it's hard to do better. */
done:
*out = '\0';
}
static int
unescape (const char **in, char **out, const char *seq, char value)
{
size_t len = strlen (seq);
if (strncmp (*in, seq, len))
return 0;
**out = value;
*in += len;
*out += 1;
return 1;
}

View file

@ -0,0 +1,258 @@
/* ###
* IP: LGPL 2.1
* NOTE: See binutils/include/COPYING
*/
/* <ctype.h> replacement macros.
Copyright (C) 2000-2019 Free Software Foundation, Inc.
Contributed by Zack Weinberg <zackw@stanford.edu>.
This file is part of the libiberty library.
Libiberty is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
Libiberty 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with libiberty; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
/*
@defvr Extension HOST_CHARSET
This macro indicates the basic character set and encoding used by the
host: more precisely, the encoding used for character constants in
preprocessor @samp{#if} statements (the C "execution character set").
It is defined by @file{safe-ctype.h}, and will be an integer constant
with one of the following values:
@ftable @code
@item HOST_CHARSET_UNKNOWN
The host character set is unknown - that is, not one of the next two
possibilities.
@item HOST_CHARSET_ASCII
The host character set is ASCII.
@item HOST_CHARSET_EBCDIC
The host character set is some variant of EBCDIC. (Only one of the
nineteen EBCDIC varying characters is tested; exercise caution.)
@end ftable
@end defvr
@deffn Extension ISALPHA (@var{c})
@deffnx Extension ISALNUM (@var{c})
@deffnx Extension ISBLANK (@var{c})
@deffnx Extension ISCNTRL (@var{c})
@deffnx Extension ISDIGIT (@var{c})
@deffnx Extension ISGRAPH (@var{c})
@deffnx Extension ISLOWER (@var{c})
@deffnx Extension ISPRINT (@var{c})
@deffnx Extension ISPUNCT (@var{c})
@deffnx Extension ISSPACE (@var{c})
@deffnx Extension ISUPPER (@var{c})
@deffnx Extension ISXDIGIT (@var{c})
These twelve macros are defined by @file{safe-ctype.h}. Each has the
same meaning as the corresponding macro (with name in lowercase)
defined by the standard header @file{ctype.h}. For example,
@code{ISALPHA} returns true for alphabetic characters and false for
others. However, there are two differences between these macros and
those provided by @file{ctype.h}:
@itemize @bullet
@item These macros are guaranteed to have well-defined behavior for all
values representable by @code{signed char} and @code{unsigned char}, and
for @code{EOF}.
@item These macros ignore the current locale; they are true for these
fixed sets of characters:
@multitable {@code{XDIGIT}} {yada yada yada yada yada yada yada yada}
@item @code{ALPHA} @tab @kbd{A-Za-z}
@item @code{ALNUM} @tab @kbd{A-Za-z0-9}
@item @code{BLANK} @tab @kbd{space tab}
@item @code{CNTRL} @tab @code{!PRINT}
@item @code{DIGIT} @tab @kbd{0-9}
@item @code{GRAPH} @tab @code{ALNUM || PUNCT}
@item @code{LOWER} @tab @kbd{a-z}
@item @code{PRINT} @tab @code{GRAPH ||} @kbd{space}
@item @code{PUNCT} @tab @kbd{`~!@@#$%^&*()_-=+[@{]@}\|;:'",<.>/?}
@item @code{SPACE} @tab @kbd{space tab \n \r \f \v}
@item @code{UPPER} @tab @kbd{A-Z}
@item @code{XDIGIT} @tab @kbd{0-9A-Fa-f}
@end multitable
Note that, if the host character set is ASCII or a superset thereof,
all these macros will return false for all values of @code{char} outside
the range of 7-bit ASCII. In particular, both ISPRINT and ISCNTRL return
false for characters with numeric values from 128 to 255.
@end itemize
@end deffn
@deffn Extension ISIDNUM (@var{c})
@deffnx Extension ISIDST (@var{c})
@deffnx Extension IS_VSPACE (@var{c})
@deffnx Extension IS_NVSPACE (@var{c})
@deffnx Extension IS_SPACE_OR_NUL (@var{c})
@deffnx Extension IS_ISOBASIC (@var{c})
These six macros are defined by @file{safe-ctype.h} and provide
additional character classes which are useful when doing lexical
analysis of C or similar languages. They are true for the following
sets of characters:
@multitable {@code{SPACE_OR_NUL}} {yada yada yada yada yada yada yada yada}
@item @code{IDNUM} @tab @kbd{A-Za-z0-9_}
@item @code{IDST} @tab @kbd{A-Za-z_}
@item @code{VSPACE} @tab @kbd{\r \n}
@item @code{NVSPACE} @tab @kbd{space tab \f \v \0}
@item @code{SPACE_OR_NUL} @tab @code{VSPACE || NVSPACE}
@item @code{ISOBASIC} @tab @code{VSPACE || NVSPACE || PRINT}
@end multitable
@end deffn
*/
#include "ansidecl.h"
#include <safe-ctype.h>
#include <stdio.h> /* for EOF */
#if EOF != -1
#error "<safe-ctype.h> requires EOF == -1"
#endif
/* Shorthand */
#define bl _sch_isblank
#define cn _sch_iscntrl
#define di _sch_isdigit
#define is _sch_isidst
#define lo _sch_islower
#define nv _sch_isnvsp
#define pn _sch_ispunct
#define pr _sch_isprint
#define sp _sch_isspace
#define up _sch_isupper
#define vs _sch_isvsp
#define xd _sch_isxdigit
/* Masks. */
#define L (const unsigned short) (lo|is |pr) /* lower case letter */
#define XL (const unsigned short) (lo|is|xd|pr) /* lowercase hex digit */
#define U (const unsigned short) (up|is |pr) /* upper case letter */
#define XU (const unsigned short) (up|is|xd|pr) /* uppercase hex digit */
#define D (const unsigned short) (di |xd|pr) /* decimal digit */
#define P (const unsigned short) (pn |pr) /* punctuation */
#define _ (const unsigned short) (pn|is |pr) /* underscore */
#define C (const unsigned short) ( cn) /* control character */
#define Z (const unsigned short) (nv |cn) /* NUL */
#define M (const unsigned short) (nv|sp |cn) /* cursor movement: \f \v */
#define V (const unsigned short) (vs|sp |cn) /* vertical space: \r \n */
#define T (const unsigned short) (nv|sp|bl|cn) /* tab */
#define S (const unsigned short) (nv|sp|bl|pr) /* space */
/* Are we ASCII? */
#if HOST_CHARSET == HOST_CHARSET_ASCII
const unsigned short _sch_istable[256] =
{
Z, C, C, C, C, C, C, C, /* NUL SOH STX ETX EOT ENQ ACK BEL */
C, T, V, M, M, V, C, C, /* BS HT LF VT FF CR SO SI */
C, C, C, C, C, C, C, C, /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
C, C, C, C, C, C, C, C, /* CAN EM SUB ESC FS GS RS US */
S, P, P, P, P, P, P, P, /* SP ! " # $ % & ' */
P, P, P, P, P, P, P, P, /* ( ) * + , - . / */
D, D, D, D, D, D, D, D, /* 0 1 2 3 4 5 6 7 */
D, D, P, P, P, P, P, P, /* 8 9 : ; < = > ? */
P, XU, XU, XU, XU, XU, XU, U, /* @ A B C D E F G */
U, U, U, U, U, U, U, U, /* H I J K L M N O */
U, U, U, U, U, U, U, U, /* P Q R S T U V W */
U, U, U, P, P, P, P, _, /* X Y Z [ \ ] ^ _ */
P, XL, XL, XL, XL, XL, XL, L, /* ` a b c d e f g */
L, L, L, L, L, L, L, L, /* h i j k l m n o */
L, L, L, L, L, L, L, L, /* p q r s t u v w */
L, L, L, P, P, P, P, C, /* x y z { | } ~ DEL */
/* high half of unsigned char is locale-specific, so all tests are
false in "C" locale */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
};
const unsigned char _sch_tolower[256] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64,
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
91, 92, 93, 94, 95, 96,
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
123,124,125,126,127,
128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143,
144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159,
160,161,162,163, 164,165,166,167, 168,169,170,171, 172,173,174,175,
176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,190,191,
192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207,
208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223,
224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239,
240,241,242,243, 244,245,246,247, 248,249,250,251, 252,253,254,255,
};
const unsigned char _sch_toupper[256] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64,
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
91, 92, 93, 94, 95, 96,
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
123,124,125,126,127,
128,129,130,131, 132,133,134,135, 136,137,138,139, 140,141,142,143,
144,145,146,147, 148,149,150,151, 152,153,154,155, 156,157,158,159,
160,161,162,163, 164,165,166,167, 168,169,170,171, 172,173,174,175,
176,177,178,179, 180,181,182,183, 184,185,186,187, 188,189,190,191,
192,193,194,195, 196,197,198,199, 200,201,202,203, 204,205,206,207,
208,209,210,211, 212,213,214,215, 216,217,218,219, 220,221,222,223,
224,225,226,227, 228,229,230,231, 232,233,234,235, 236,237,238,239,
240,241,242,243, 244,245,246,247, 248,249,250,251, 252,253,254,255,
};
#else
# if HOST_CHARSET == HOST_CHARSET_EBCDIC
#error "FIXME: write tables for EBCDIC"
# else
#error "Unrecognized host character set"
# endif
#endif

View file

@ -0,0 +1,56 @@
/* ###
* IP: LGPL 2.1
* NOTE: See binutils/libiberty/COPYING.LIB
*/
/* xexit.c -- Run any exit handlers, then exit.
Copyright (C) 1994-2019 Free Software Foundation, Inc.
This file is part of the libiberty library.
Libiberty is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
Libiberty 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with libiberty; see the file COPYING.LIB. If not, write
to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
/*
@deftypefn Replacement void xexit (int @var{code})
Terminates the program. If any functions have been registered with
the @code{xatexit} replacement function, they will be called first.
Termination is handled via the system's normal @code{exit} call.
@end deftypefn
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include "libiberty.h"
/* This variable is set by xatexit if it is called. This way, xmalloc
doesn't drag xatexit into the link. */
void (*_xexit_cleanup) (void);
void
xexit (int code)
{
if (_xexit_cleanup != NULL)
(*_xexit_cleanup) ();
exit (code);
}

View file

@ -0,0 +1,39 @@
/* ###
* IP: Public Domain
*/
/* xstrdup.c -- Duplicate a string in memory, using xmalloc.
This trivial function is in the public domain.
Ian Lance Taylor, Cygnus Support, December 1995. */
/*
@deftypefn Replacement char* xstrdup (const char *@var{s})
Duplicates a character string without fail, using @code{xmalloc} to
obtain memory.
@end deftypefn
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#ifdef HAVE_STRING_H
#include <string.h>
#else
# ifdef HAVE_STRINGS_H
# include <strings.h>
# endif
#endif
#include "ansidecl.h"
#include "libiberty.h"
char *
xstrdup (const char *s)
{
register size_t len = strlen (s) + 1;
register char *ret = XNEWVEC (char, len);
return (char *) memcpy (ret, s, len);
}

View file

@ -0,0 +1,406 @@
/* ###
* IP: LGPL 2.1
* NOTE: See binutils/include/COPYING
*/
/* ANSI and traditional C compatability macros
Copyright (C) 1991-2019 Free Software Foundation, Inc.
This file is part of the GNU C Library.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
/* ANSI and traditional C compatibility macros
ANSI C is assumed if __STDC__ is #defined.
Macro ANSI C definition Traditional C definition
----- ---- - ---------- ----------- - ----------
PTR `void *' `char *'
const not defined `'
volatile not defined `'
signed not defined `'
For ease of writing code which uses GCC extensions but needs to be
portable to other compilers, we provide the GCC_VERSION macro that
simplifies testing __GNUC__ and __GNUC_MINOR__ together, and various
wrappers around __attribute__. Also, __extension__ will be #defined
to nothing if it doesn't work. See below. */
#ifndef _ANSIDECL_H
#define _ANSIDECL_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* Every source file includes this file,
so they will all get the switch for lint. */
/* LINTLIBRARY */
/* Using MACRO(x,y) in cpp #if conditionals does not work with some
older preprocessors. Thus we can't define something like this:
#define HAVE_GCC_VERSION(MAJOR, MINOR) \
(__GNUC__ > (MAJOR) || (__GNUC__ == (MAJOR) && __GNUC_MINOR__ >= (MINOR)))
and then test "#if HAVE_GCC_VERSION(2,7)".
So instead we use the macro below and test it against specific values. */
/* This macro simplifies testing whether we are using gcc, and if it
is of a particular minimum version. (Both major & minor numbers are
significant.) This macro will evaluate to 0 if we are not using
gcc at all. */
#ifndef GCC_VERSION
#define GCC_VERSION (__GNUC__ * 1000 + __GNUC_MINOR__)
#endif /* GCC_VERSION */
#if defined (__STDC__) || defined(__cplusplus) || defined (_AIX) || (defined (__mips) && defined (_SYSTYPE_SVR4)) || defined(_WIN32)
/* All known AIX compilers implement these things (but don't always
define __STDC__). The RISC/OS MIPS compiler defines these things
in SVR4 mode, but does not define __STDC__. */
/* eraxxon@alumni.rice.edu: The Compaq C++ compiler, unlike many other
C++ compilers, does not define __STDC__, though it acts as if this
was so. (Verified versions: 5.7, 6.2, 6.3, 6.5) */
#define PTR void *
#undef const
#undef volatile
#undef signed
/* inline requires special treatment; it's in C99, and GCC >=2.7 supports
it too, but it's not in C89. */
#undef inline
#if __STDC_VERSION__ >= 199901L || defined(__cplusplus) || (defined(__SUNPRO_C) && defined(__C99FEATURES__))
/* it's a keyword */
#else
# if GCC_VERSION >= 2007
# define inline __inline__ /* __inline__ prevents -pedantic warnings */
# else
# define inline /* nothing */
# endif
#endif
#else /* Not ANSI C. */
#define PTR char *
/* some systems define these in header files for non-ansi mode */
#undef const
#undef volatile
#undef signed
#undef inline
#define const
#define volatile
#define signed
#define inline
#endif /* ANSI C. */
/* Define macros for some gcc attributes. This permits us to use the
macros freely, and know that they will come into play for the
version of gcc in which they are supported. */
#if (GCC_VERSION < 2007)
# define __attribute__(x)
#endif
/* Attribute __malloc__ on functions was valid as of gcc 2.96. */
#ifndef ATTRIBUTE_MALLOC
# if (GCC_VERSION >= 2096)
# define ATTRIBUTE_MALLOC __attribute__ ((__malloc__))
# else
# define ATTRIBUTE_MALLOC
# endif /* GNUC >= 2.96 */
#endif /* ATTRIBUTE_MALLOC */
/* Attributes on labels were valid as of gcc 2.93 and g++ 4.5. For
g++ an attribute on a label must be followed by a semicolon. */
#ifndef ATTRIBUTE_UNUSED_LABEL
# ifndef __cplusplus
# if GCC_VERSION >= 2093
# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED
# else
# define ATTRIBUTE_UNUSED_LABEL
# endif
# else
# if GCC_VERSION >= 4005
# define ATTRIBUTE_UNUSED_LABEL ATTRIBUTE_UNUSED ;
# else
# define ATTRIBUTE_UNUSED_LABEL
# endif
# endif
#endif
/* Similarly to ARG_UNUSED below. Prior to GCC 3.4, the C++ frontend
couldn't parse attributes placed after the identifier name, and now
the entire compiler is built with C++. */
#ifndef ATTRIBUTE_UNUSED
#if GCC_VERSION >= 3004
# define ATTRIBUTE_UNUSED __attribute__ ((__unused__))
#else
#define ATTRIBUTE_UNUSED
#endif
#endif /* ATTRIBUTE_UNUSED */
/* Before GCC 3.4, the C++ frontend couldn't parse attributes placed after the
identifier name. */
#if ! defined(__cplusplus) || (GCC_VERSION >= 3004)
# define ARG_UNUSED(NAME) NAME ATTRIBUTE_UNUSED
#else /* !__cplusplus || GNUC >= 3.4 */
# define ARG_UNUSED(NAME) NAME
#endif /* !__cplusplus || GNUC >= 3.4 */
#ifndef ATTRIBUTE_NORETURN
#define ATTRIBUTE_NORETURN __attribute__ ((__noreturn__))
#endif /* ATTRIBUTE_NORETURN */
/* Attribute `nonnull' was valid as of gcc 3.3. */
#ifndef ATTRIBUTE_NONNULL
# if (GCC_VERSION >= 3003)
# define ATTRIBUTE_NONNULL(m) __attribute__ ((__nonnull__ (m)))
# else
# define ATTRIBUTE_NONNULL(m)
# endif /* GNUC >= 3.3 */
#endif /* ATTRIBUTE_NONNULL */
/* Attribute `returns_nonnull' was valid as of gcc 4.9. */
#ifndef ATTRIBUTE_RETURNS_NONNULL
# if (GCC_VERSION >= 4009)
# define ATTRIBUTE_RETURNS_NONNULL __attribute__ ((__returns_nonnull__))
# else
# define ATTRIBUTE_RETURNS_NONNULL
# endif /* GNUC >= 4.9 */
#endif /* ATTRIBUTE_RETURNS_NONNULL */
/* Attribute `pure' was valid as of gcc 3.0. */
#ifndef ATTRIBUTE_PURE
# if (GCC_VERSION >= 3000)
# define ATTRIBUTE_PURE __attribute__ ((__pure__))
# else
# define ATTRIBUTE_PURE
# endif /* GNUC >= 3.0 */
#endif /* ATTRIBUTE_PURE */
/* Use ATTRIBUTE_PRINTF when the format specifier must not be NULL.
This was the case for the `printf' format attribute by itself
before GCC 3.3, but as of 3.3 we need to add the `nonnull'
attribute to retain this behavior. */
#ifndef ATTRIBUTE_PRINTF
#define ATTRIBUTE_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n))) ATTRIBUTE_NONNULL(m)
#define ATTRIBUTE_PRINTF_1 ATTRIBUTE_PRINTF(1, 2)
#define ATTRIBUTE_PRINTF_2 ATTRIBUTE_PRINTF(2, 3)
#define ATTRIBUTE_PRINTF_3 ATTRIBUTE_PRINTF(3, 4)
#define ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF(4, 5)
#define ATTRIBUTE_PRINTF_5 ATTRIBUTE_PRINTF(5, 6)
#endif /* ATTRIBUTE_PRINTF */
/* Use ATTRIBUTE_FPTR_PRINTF when the format attribute is to be set on
a function pointer. Format attributes were allowed on function
pointers as of gcc 3.1. */
#ifndef ATTRIBUTE_FPTR_PRINTF
# if (GCC_VERSION >= 3001)
# define ATTRIBUTE_FPTR_PRINTF(m, n) ATTRIBUTE_PRINTF(m, n)
# else
# define ATTRIBUTE_FPTR_PRINTF(m, n)
# endif /* GNUC >= 3.1 */
# define ATTRIBUTE_FPTR_PRINTF_1 ATTRIBUTE_FPTR_PRINTF(1, 2)
# define ATTRIBUTE_FPTR_PRINTF_2 ATTRIBUTE_FPTR_PRINTF(2, 3)
# define ATTRIBUTE_FPTR_PRINTF_3 ATTRIBUTE_FPTR_PRINTF(3, 4)
# define ATTRIBUTE_FPTR_PRINTF_4 ATTRIBUTE_FPTR_PRINTF(4, 5)
# define ATTRIBUTE_FPTR_PRINTF_5 ATTRIBUTE_FPTR_PRINTF(5, 6)
#endif /* ATTRIBUTE_FPTR_PRINTF */
/* Use ATTRIBUTE_NULL_PRINTF when the format specifier may be NULL. A
NULL format specifier was allowed as of gcc 3.3. */
#ifndef ATTRIBUTE_NULL_PRINTF
# if (GCC_VERSION >= 3003)
# define ATTRIBUTE_NULL_PRINTF(m, n) __attribute__ ((__format__ (__printf__, m, n)))
# else
# define ATTRIBUTE_NULL_PRINTF(m, n)
# endif /* GNUC >= 3.3 */
# define ATTRIBUTE_NULL_PRINTF_1 ATTRIBUTE_NULL_PRINTF(1, 2)
# define ATTRIBUTE_NULL_PRINTF_2 ATTRIBUTE_NULL_PRINTF(2, 3)
# define ATTRIBUTE_NULL_PRINTF_3 ATTRIBUTE_NULL_PRINTF(3, 4)
# define ATTRIBUTE_NULL_PRINTF_4 ATTRIBUTE_NULL_PRINTF(4, 5)
# define ATTRIBUTE_NULL_PRINTF_5 ATTRIBUTE_NULL_PRINTF(5, 6)
#endif /* ATTRIBUTE_NULL_PRINTF */
/* Attribute `sentinel' was valid as of gcc 3.5. */
#ifndef ATTRIBUTE_SENTINEL
# if (GCC_VERSION >= 3005)
# define ATTRIBUTE_SENTINEL __attribute__ ((__sentinel__))
# else
# define ATTRIBUTE_SENTINEL
# endif /* GNUC >= 3.5 */
#endif /* ATTRIBUTE_SENTINEL */
#ifndef ATTRIBUTE_ALIGNED_ALIGNOF
# if (GCC_VERSION >= 3000)
# define ATTRIBUTE_ALIGNED_ALIGNOF(m) __attribute__ ((__aligned__ (__alignof__ (m))))
# else
# define ATTRIBUTE_ALIGNED_ALIGNOF(m)
# endif /* GNUC >= 3.0 */
#endif /* ATTRIBUTE_ALIGNED_ALIGNOF */
/* Useful for structures whose layout must match some binary specification
regardless of the alignment and padding qualities of the compiler. */
#ifndef ATTRIBUTE_PACKED
# define ATTRIBUTE_PACKED __attribute__ ((packed))
#endif
/* Attribute `hot' and `cold' was valid as of gcc 4.3. */
#ifndef ATTRIBUTE_COLD
# if (GCC_VERSION >= 4003)
# define ATTRIBUTE_COLD __attribute__ ((__cold__))
# else
# define ATTRIBUTE_COLD
# endif /* GNUC >= 4.3 */
#endif /* ATTRIBUTE_COLD */
#ifndef ATTRIBUTE_HOT
# if (GCC_VERSION >= 4003)
# define ATTRIBUTE_HOT __attribute__ ((__hot__))
# else
# define ATTRIBUTE_HOT
# endif /* GNUC >= 4.3 */
#endif /* ATTRIBUTE_HOT */
/* Attribute 'no_sanitize_undefined' was valid as of gcc 4.9. */
#ifndef ATTRIBUTE_NO_SANITIZE_UNDEFINED
# if (GCC_VERSION >= 4009)
# define ATTRIBUTE_NO_SANITIZE_UNDEFINED __attribute__ ((no_sanitize_undefined))
# else
# define ATTRIBUTE_NO_SANITIZE_UNDEFINED
# endif /* GNUC >= 4.9 */
#endif /* ATTRIBUTE_NO_SANITIZE_UNDEFINED */
/* Attribute 'nonstring' was valid as of gcc 8. */
#ifndef ATTRIBUTE_NONSTRING
# if GCC_VERSION >= 8000
# define ATTRIBUTE_NONSTRING __attribute__ ((__nonstring__))
# else
# define ATTRIBUTE_NONSTRING
# endif
#endif
/* We use __extension__ in some places to suppress -pedantic warnings
about GCC extensions. This feature didn't work properly before
gcc 2.8. */
#if GCC_VERSION < 2008
#define __extension__
#endif
/* This is used to declare a const variable which should be visible
outside of the current compilation unit. Use it as
EXPORTED_CONST int i = 1;
This is because the semantics of const are different in C and C++.
"extern const" is permitted in C but it looks strange, and gcc
warns about it when -Wc++-compat is not used. */
#ifdef __cplusplus
#define EXPORTED_CONST extern const
#else
#define EXPORTED_CONST const
#endif
/* Be conservative and only use enum bitfields with C++ or GCC.
FIXME: provide a complete autoconf test for buggy enum bitfields. */
#ifdef __cplusplus
#define ENUM_BITFIELD(TYPE) enum TYPE
#elif (GCC_VERSION > 2000)
#define ENUM_BITFIELD(TYPE) __extension__ enum TYPE
#else
#define ENUM_BITFIELD(TYPE) unsigned int
#endif
#if __cpp_constexpr >= 200704
#define CONSTEXPR constexpr
#else
#define CONSTEXPR
#endif
/* C++11 adds the ability to add "override" after an implementation of a
virtual function in a subclass, to:
(A) document that this is an override of a virtual function
(B) allow the compiler to issue a warning if it isn't (e.g. a mismatch
of the type signature).
Similarly, it allows us to add a "final" to indicate that no subclass
may subsequently override the vfunc.
Provide OVERRIDE and FINAL as macros, allowing us to get these benefits
when compiling with C++11 support, but without requiring C++11.
For gcc, use "-std=c++11" to enable C++11 support; gcc 6 onwards enables
this by default (actually GNU++14). */
#if defined __cplusplus
# if __cplusplus >= 201103
/* C++11 claims to be available: use it. Final/override were only
implemented in 4.7, though. */
# if GCC_VERSION < 4007
# define OVERRIDE
# define FINAL
# else
# define OVERRIDE override
# define FINAL final
# endif
# elif GCC_VERSION >= 4007
/* G++ 4.7 supports __final in C++98. */
# define OVERRIDE
# define FINAL __final
# else
/* No C++11 support; leave the macros empty. */
# define OVERRIDE
# define FINAL
# endif
#else
/* No C++11 support; leave the macros empty. */
# define OVERRIDE
# define FINAL
#endif
/* A macro to disable the copy constructor and assignment operator.
When building with C++11 and above, the methods are explicitly
deleted, causing a compile-time error if something tries to copy.
For C++03, this just declares the methods, causing a link-time
error if the methods end up called (assuming you don't
define them). For C++03, for best results, place the macro
under the private: access specifier, like this,
class name_lookup
{
private:
DISABLE_COPY_AND_ASSIGN (name_lookup);
};
so that most attempts at copy are caught at compile-time. */
#if __cplusplus >= 201103
#define DISABLE_COPY_AND_ASSIGN(TYPE) \
TYPE (const TYPE&) = delete; \
void operator= (const TYPE &) = delete
#else
#define DISABLE_COPY_AND_ASSIGN(TYPE) \
TYPE (const TYPE&); \
void operator= (const TYPE &)
#endif /* __cplusplus >= 201103 */
#ifdef __cplusplus
}
#endif
#endif /* ansidecl.h */

View file

@ -0,0 +1,201 @@
/* ###
* IP: GPL 3 Linking Permitted
* NOTE: See binutils/libiberty/COPYING.LIB; Used GPL 3 from this file's header
*/
/* Internal demangler interface for g++ V3 ABI.
Copyright (C) 2003-2019 Free Software Foundation, Inc.
Written by Ian Lance Taylor <ian@wasabisystems.com>.
This file is part of the libiberty library, which is part of GCC.
This file is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
In addition to the permissions in the GNU General Public License, the
Free Software Foundation gives you unlimited permission to link the
compiled version of this file into combinations with other programs,
and to distribute those combinations without any restriction coming
from the use of this file. (The General Public License restrictions
do apply in other respects; for example, they cover modification of
the file, and distribution when not linked into a combined
executable.)
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
*/
/* This file provides some definitions shared by cp-demangle.c and
cp-demint.c. It should not be included by any other files. */
/* Information we keep for operators. */
struct demangle_operator_info
{
/* Mangled name. */
const char *code;
/* Real name. */
const char *name;
/* Length of real name. */
int len;
/* Number of arguments. */
int args;
};
/* How to print the value of a builtin type. */
enum d_builtin_type_print
{
/* Print as (type)val. */
D_PRINT_DEFAULT,
/* Print as integer. */
D_PRINT_INT,
/* Print as unsigned integer, with trailing "u". */
D_PRINT_UNSIGNED,
/* Print as long, with trailing "l". */
D_PRINT_LONG,
/* Print as unsigned long, with trailing "ul". */
D_PRINT_UNSIGNED_LONG,
/* Print as long long, with trailing "ll". */
D_PRINT_LONG_LONG,
/* Print as unsigned long long, with trailing "ull". */
D_PRINT_UNSIGNED_LONG_LONG,
/* Print as bool. */
D_PRINT_BOOL,
/* Print as float--put value in square brackets. */
D_PRINT_FLOAT,
/* Print in usual way, but here to detect void. */
D_PRINT_VOID
};
/* Information we keep for a builtin type. */
struct demangle_builtin_type_info
{
/* Type name. */
const char *name;
/* Length of type name. */
int len;
/* Type name when using Java. */
const char *java_name;
/* Length of java name. */
int java_len;
/* How to print a value of this type. */
enum d_builtin_type_print print;
};
/* The information structure we pass around. */
struct d_info
{
/* The string we are demangling. */
const char *s;
/* The end of the string we are demangling. */
const char *send;
/* The options passed to the demangler. */
int options;
/* The next character in the string to consider. */
const char *n;
/* The array of components. */
struct demangle_component *comps;
/* The index of the next available component. */
int next_comp;
/* The number of available component structures. */
int num_comps;
/* The array of substitutions. */
struct demangle_component **subs;
/* The index of the next substitution. */
int next_sub;
/* The number of available entries in the subs array. */
int num_subs;
/* The last name we saw, for constructors and destructors. */
struct demangle_component *last_name;
/* A running total of the length of large expansions from the
mangled name to the demangled name, such as standard
substitutions and builtin types. */
int expansion;
/* Non-zero if we are parsing an expression. */
int is_expression;
/* Non-zero if we are parsing the type operand of a conversion
operator, but not when in an expression. */
int is_conversion;
/* If DMGL_NO_RECURSE_LIMIT is not active then this is set to
the current recursion level. */
unsigned int recursion_level;
};
/* To avoid running past the ending '\0', don't:
- call d_peek_next_char if d_peek_char returned '\0'
- call d_advance with an 'i' that is too large
- call d_check_char(di, '\0')
Everything else is safe. */
#define d_peek_char(di) (*((di)->n))
#ifndef CHECK_DEMANGLER
# define d_peek_next_char(di) ((di)->n[1])
# define d_advance(di, i) ((di)->n += (i))
#endif
#define d_check_char(di, c) (d_peek_char(di) == c ? ((di)->n++, 1) : 0)
#define d_next_char(di) (d_peek_char(di) == '\0' ? '\0' : *((di)->n++))
#define d_str(di) ((di)->n)
#ifdef CHECK_DEMANGLER
static inline char
d_peek_next_char (const struct d_info *di)
{
if (!di->n[0])
abort ();
return di->n[1];
}
static inline void
d_advance (struct d_info *di, int i)
{
if (i < 0)
abort ();
while (i--)
{
if (!di->n[0])
abort ();
di->n++;
}
}
#endif
/* Functions and arrays in cp-demangle.c which are referenced by
functions in cp-demint.c. */
#ifdef IN_GLIBCPP_V3
#define CP_STATIC_IF_GLIBCPP_V3 static
#else
#define CP_STATIC_IF_GLIBCPP_V3 extern
#endif
#ifndef IN_GLIBCPP_V3
extern const struct demangle_operator_info cplus_demangle_operators[];
#endif
#define D_BUILTIN_TYPE_COUNT (34)
CP_STATIC_IF_GLIBCPP_V3
const struct demangle_builtin_type_info
cplus_demangle_builtin_types[D_BUILTIN_TYPE_COUNT];
CP_STATIC_IF_GLIBCPP_V3
struct demangle_component *
cplus_demangle_mangled_name (struct d_info *, int);
CP_STATIC_IF_GLIBCPP_V3
struct demangle_component *
cplus_demangle_type (struct d_info *);
extern void
cplus_demangle_init_info (const char *, int, size_t, struct d_info *);
/* cp-demangle.c needs to define this a little differently */
#undef CP_STATIC_IF_GLIBCPP_V3

View file

@ -0,0 +1,710 @@
/* ###
* IP: LGPL 2.1
* NOTE: See binutils/include/COPYING
*/
/* Defs for interface to demanglers.
Copyright (C) 1992-2019 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License
as published by the Free Software Foundation; either version 2, or
(at your option) any later version.
In addition to the permissions in the GNU Library General Public
License, the Free Software Foundation gives you unlimited
permission to link the compiled version of this file into
combinations with other programs, and to distribute those
combinations without any restriction coming from the use of this
file. (The Library Public License restrictions do apply in other
respects; for example, they cover modification of the file, and
distribution when not linked into a combined executable.)
This program 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
02110-1301, USA. */
#if !defined (DEMANGLE_H)
#define DEMANGLE_H
#include "libiberty.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Options passed to cplus_demangle (in 2nd parameter). */
#define DMGL_NO_OPTS 0 /* For readability... */
#define DMGL_PARAMS (1 << 0) /* Include function args */
#define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */
#define DMGL_JAVA (1 << 2) /* Demangle as Java rather than C++. */
#define DMGL_VERBOSE (1 << 3) /* Include implementation details. */
#define DMGL_TYPES (1 << 4) /* Also try to demangle type encodings. */
#define DMGL_RET_POSTFIX (1 << 5) /* Print function return types (when
present) after function signature.
It applies only to the toplevel
function type. */
#define DMGL_RET_DROP (1 << 6) /* Suppress printing function return
types, even if present. It applies
only to the toplevel function type.
*/
#define DMGL_AUTO (1 << 8)
#define DMGL_GNU_V3 (1 << 14)
#define DMGL_GNAT (1 << 15)
#define DMGL_DLANG (1 << 16)
#define DMGL_RUST (1 << 17) /* Rust wraps GNU_V3 style mangling. */
/* If none of these are set, use 'current_demangling_style' as the default. */
#define DMGL_STYLE_MASK (DMGL_AUTO|DMGL_GNU_V3|DMGL_JAVA|DMGL_GNAT|DMGL_DLANG|DMGL_RUST)
/* Disable a limit on the depth of recursion in mangled strings.
Note if this limit is disabled then stack exhaustion is possible when
demangling pathologically complicated strings. Bug reports about stack
exhaustion when the option is enabled will be rejected. */
#define DMGL_NO_RECURSE_LIMIT (1 << 18)
/* If DMGL_NO_RECURSE_LIMIT is not enabled, then this is the value used as
the maximum depth of recursion allowed. It should be enough for any
real-world mangled name. */
#define DEMANGLE_RECURSION_LIMIT 2048
/* Enumeration of possible demangling styles.
Lucid and ARM styles are still kept logically distinct, even though
they now both behave identically. The resulting style is actual the
union of both. I.E. either style recognizes both "__pt__" and "__rf__"
for operator "->", even though the first is lucid style and the second
is ARM style. (FIXME?) */
extern enum demangling_styles
{
no_demangling = -1,
unknown_demangling = 0,
auto_demangling = DMGL_AUTO,
gnu_v3_demangling = DMGL_GNU_V3,
java_demangling = DMGL_JAVA,
gnat_demangling = DMGL_GNAT,
dlang_demangling = DMGL_DLANG,
rust_demangling = DMGL_RUST
} current_demangling_style;
/* Define string names for the various demangling styles. */
#define NO_DEMANGLING_STYLE_STRING "none"
#define AUTO_DEMANGLING_STYLE_STRING "auto"
#define GNU_V3_DEMANGLING_STYLE_STRING "gnu-v3"
#define JAVA_DEMANGLING_STYLE_STRING "java"
#define GNAT_DEMANGLING_STYLE_STRING "gnat"
#define DLANG_DEMANGLING_STYLE_STRING "dlang"
#define RUST_DEMANGLING_STYLE_STRING "rust"
/* Some macros to test what demangling style is active. */
#define CURRENT_DEMANGLING_STYLE current_demangling_style
#define AUTO_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_AUTO)
#define GNU_V3_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNU_V3)
#define JAVA_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_JAVA)
#define GNAT_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_GNAT)
#define DLANG_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_DLANG)
#define RUST_DEMANGLING (((int) CURRENT_DEMANGLING_STYLE) & DMGL_RUST)
/* Provide information about the available demangle styles. This code is
pulled from gdb into libiberty because it is useful to binutils also. */
extern const struct demangler_engine
{
const char *const demangling_style_name;
const enum demangling_styles demangling_style;
const char *const demangling_style_doc;
} libiberty_demanglers[];
extern char *
cplus_demangle (const char *mangled, int options);
/* Note: This sets global state. FIXME if you care about multi-threading. */
extern enum demangling_styles
cplus_demangle_set_style (enum demangling_styles style);
extern enum demangling_styles
cplus_demangle_name_to_style (const char *name);
/* Callback typedef for allocation-less demangler interfaces. */
typedef void (*demangle_callbackref) (const char *, size_t, void *);
/* V3 ABI demangling entry points, defined in cp-demangle.c. Callback
variants return non-zero on success, zero on error. char* variants
return a string allocated by malloc on success, NULL on error. */
extern int
cplus_demangle_v3_callback (const char *mangled, int options,
demangle_callbackref callback, void *opaque);
extern char*
cplus_demangle_v3 (const char *mangled, int options);
extern int
java_demangle_v3_callback (const char *mangled,
demangle_callbackref callback, void *opaque);
extern char*
java_demangle_v3 (const char *mangled);
char *
ada_demangle (const char *mangled, int options);
extern char *
dlang_demangle (const char *mangled, int options);
/* Returns non-zero iff MANGLED is a rust mangled symbol. MANGLED must
already have been demangled through cplus_demangle_v3. If this function
returns non-zero then MANGLED can be demangled (in-place) using
RUST_DEMANGLE_SYM. */
extern int
rust_is_mangled (const char *mangled);
/* Demangles SYM (in-place) if RUST_IS_MANGLED returned non-zero for SYM.
If RUST_IS_MANGLED returned zero for SYM then RUST_DEMANGLE_SYM might
replace characters that cannot be demangled with '?' and might truncate
SYM. After calling RUST_DEMANGLE_SYM SYM might be shorter, but never
larger. */
extern void
rust_demangle_sym (char *sym);
/* Demangles MANGLED if it was GNU_V3 and then RUST mangled, otherwise
returns NULL. Uses CPLUS_DEMANGLE_V3, RUST_IS_MANGLED and
RUST_DEMANGLE_SYM. Returns a new string that is owned by the caller. */
extern char *
rust_demangle (const char *mangled, int options);
enum gnu_v3_ctor_kinds {
gnu_v3_complete_object_ctor = 1,
gnu_v3_base_object_ctor,
gnu_v3_complete_object_allocating_ctor,
/* These are not part of the V3 ABI. Unified constructors are generated
as a speed-for-space optimization when the -fdeclone-ctor-dtor option
is used, and are always internal symbols. */
gnu_v3_unified_ctor,
gnu_v3_object_ctor_group
};
/* Return non-zero iff NAME is the mangled form of a constructor name
in the G++ V3 ABI demangling style. Specifically, return an `enum
gnu_v3_ctor_kinds' value indicating what kind of constructor
it is. */
extern enum gnu_v3_ctor_kinds
is_gnu_v3_mangled_ctor (const char *name);
enum gnu_v3_dtor_kinds {
gnu_v3_deleting_dtor = 1,
gnu_v3_complete_object_dtor,
gnu_v3_base_object_dtor,
/* These are not part of the V3 ABI. Unified destructors are generated
as a speed-for-space optimization when the -fdeclone-ctor-dtor option
is used, and are always internal symbols. */
gnu_v3_unified_dtor,
gnu_v3_object_dtor_group
};
/* Return non-zero iff NAME is the mangled form of a destructor name
in the G++ V3 ABI demangling style. Specifically, return an `enum
gnu_v3_dtor_kinds' value, indicating what kind of destructor
it is. */
extern enum gnu_v3_dtor_kinds
is_gnu_v3_mangled_dtor (const char *name);
/* The V3 demangler works in two passes. The first pass builds a tree
representation of the mangled name, and the second pass turns the
tree representation into a demangled string. Here we define an
interface to permit a caller to build their own tree
representation, which they can pass to the demangler to get a
demangled string. This can be used to canonicalize user input into
something which the demangler might output. It could also be used
by other demanglers in the future. */
/* These are the component types which may be found in the tree. Many
component types have one or two subtrees, referred to as left and
right (a component type with only one subtree puts it in the left
subtree). */
enum demangle_component_type
{
/* A name, with a length and a pointer to a string. */
DEMANGLE_COMPONENT_NAME,
/* A qualified name. The left subtree is a class or namespace or
some such thing, and the right subtree is a name qualified by
that class. */
DEMANGLE_COMPONENT_QUAL_NAME,
/* A local name. The left subtree describes a function, and the
right subtree is a name which is local to that function. */
DEMANGLE_COMPONENT_LOCAL_NAME,
/* A typed name. The left subtree is a name, and the right subtree
describes that name as a function. */
DEMANGLE_COMPONENT_TYPED_NAME,
/* A template. The left subtree is a template name, and the right
subtree is a template argument list. */
DEMANGLE_COMPONENT_TEMPLATE,
/* A template parameter. This holds a number, which is the template
parameter index. */
DEMANGLE_COMPONENT_TEMPLATE_PARAM,
/* A function parameter. This holds a number, which is the index. */
DEMANGLE_COMPONENT_FUNCTION_PARAM,
/* A constructor. This holds a name and the kind of
constructor. */
DEMANGLE_COMPONENT_CTOR,
/* A destructor. This holds a name and the kind of destructor. */
DEMANGLE_COMPONENT_DTOR,
/* A vtable. This has one subtree, the type for which this is a
vtable. */
DEMANGLE_COMPONENT_VTABLE,
/* A VTT structure. This has one subtree, the type for which this
is a VTT. */
DEMANGLE_COMPONENT_VTT,
/* A construction vtable. The left subtree is the type for which
this is a vtable, and the right subtree is the derived type for
which this vtable is built. */
DEMANGLE_COMPONENT_CONSTRUCTION_VTABLE,
/* A typeinfo structure. This has one subtree, the type for which
this is the tpeinfo structure. */
DEMANGLE_COMPONENT_TYPEINFO,
/* A typeinfo name. This has one subtree, the type for which this
is the typeinfo name. */
DEMANGLE_COMPONENT_TYPEINFO_NAME,
/* A typeinfo function. This has one subtree, the type for which
this is the tpyeinfo function. */
DEMANGLE_COMPONENT_TYPEINFO_FN,
/* A thunk. This has one subtree, the name for which this is a
thunk. */
DEMANGLE_COMPONENT_THUNK,
/* A virtual thunk. This has one subtree, the name for which this
is a virtual thunk. */
DEMANGLE_COMPONENT_VIRTUAL_THUNK,
/* A covariant thunk. This has one subtree, the name for which this
is a covariant thunk. */
DEMANGLE_COMPONENT_COVARIANT_THUNK,
/* A Java class. This has one subtree, the type. */
DEMANGLE_COMPONENT_JAVA_CLASS,
/* A guard variable. This has one subtree, the name for which this
is a guard variable. */
DEMANGLE_COMPONENT_GUARD,
/* The init and wrapper functions for C++11 thread_local variables. */
DEMANGLE_COMPONENT_TLS_INIT,
DEMANGLE_COMPONENT_TLS_WRAPPER,
/* A reference temporary. This has one subtree, the name for which
this is a temporary. */
DEMANGLE_COMPONENT_REFTEMP,
/* A hidden alias. This has one subtree, the encoding for which it
is providing alternative linkage. */
DEMANGLE_COMPONENT_HIDDEN_ALIAS,
/* A standard substitution. This holds the name of the
substitution. */
DEMANGLE_COMPONENT_SUB_STD,
/* The restrict qualifier. The one subtree is the type which is
being qualified. */
DEMANGLE_COMPONENT_RESTRICT,
/* The volatile qualifier. The one subtree is the type which is
being qualified. */
DEMANGLE_COMPONENT_VOLATILE,
/* The const qualifier. The one subtree is the type which is being
qualified. */
DEMANGLE_COMPONENT_CONST,
/* The restrict qualifier modifying a member function. The one
subtree is the type which is being qualified. */
DEMANGLE_COMPONENT_RESTRICT_THIS,
/* The volatile qualifier modifying a member function. The one
subtree is the type which is being qualified. */
DEMANGLE_COMPONENT_VOLATILE_THIS,
/* The const qualifier modifying a member function. The one subtree
is the type which is being qualified. */
DEMANGLE_COMPONENT_CONST_THIS,
/* C++11 A reference modifying a member function. The one subtree is the
type which is being referenced. */
DEMANGLE_COMPONENT_REFERENCE_THIS,
/* C++11: An rvalue reference modifying a member function. The one
subtree is the type which is being referenced. */
DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS,
/* A vendor qualifier. The left subtree is the type which is being
qualified, and the right subtree is the name of the
qualifier. */
DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL,
/* A pointer. The one subtree is the type which is being pointed
to. */
DEMANGLE_COMPONENT_POINTER,
/* A reference. The one subtree is the type which is being
referenced. */
DEMANGLE_COMPONENT_REFERENCE,
/* C++0x: An rvalue reference. The one subtree is the type which is
being referenced. */
DEMANGLE_COMPONENT_RVALUE_REFERENCE,
/* A complex type. The one subtree is the base type. */
DEMANGLE_COMPONENT_COMPLEX,
/* An imaginary type. The one subtree is the base type. */
DEMANGLE_COMPONENT_IMAGINARY,
/* A builtin type. This holds the builtin type information. */
DEMANGLE_COMPONENT_BUILTIN_TYPE,
/* A vendor's builtin type. This holds the name of the type. */
DEMANGLE_COMPONENT_VENDOR_TYPE,
/* A function type. The left subtree is the return type. The right
subtree is a list of ARGLIST nodes. Either or both may be
NULL. */
DEMANGLE_COMPONENT_FUNCTION_TYPE,
/* An array type. The left subtree is the dimension, which may be
NULL, or a string (represented as DEMANGLE_COMPONENT_NAME), or an
expression. The right subtree is the element type. */
DEMANGLE_COMPONENT_ARRAY_TYPE,
/* A pointer to member type. The left subtree is the class type,
and the right subtree is the member type. CV-qualifiers appear
on the latter. */
DEMANGLE_COMPONENT_PTRMEM_TYPE,
/* A fixed-point type. */
DEMANGLE_COMPONENT_FIXED_TYPE,
/* A vector type. The left subtree is the number of elements,
the right subtree is the element type. */
DEMANGLE_COMPONENT_VECTOR_TYPE,
/* An argument list. The left subtree is the current argument, and
the right subtree is either NULL or another ARGLIST node. */
DEMANGLE_COMPONENT_ARGLIST,
/* A template argument list. The left subtree is the current
template argument, and the right subtree is either NULL or
another TEMPLATE_ARGLIST node. */
DEMANGLE_COMPONENT_TEMPLATE_ARGLIST,
/* A template parameter object (C++20). The left subtree is the
corresponding template argument. */
DEMANGLE_COMPONENT_TPARM_OBJ,
/* An initializer list. The left subtree is either an explicit type or
NULL, and the right subtree is a DEMANGLE_COMPONENT_ARGLIST. */
DEMANGLE_COMPONENT_INITIALIZER_LIST,
/* An operator. This holds information about a standard
operator. */
DEMANGLE_COMPONENT_OPERATOR,
/* An extended operator. This holds the number of arguments, and
the name of the extended operator. */
DEMANGLE_COMPONENT_EXTENDED_OPERATOR,
/* A typecast, represented as a unary operator. The one subtree is
the type to which the argument should be cast. */
DEMANGLE_COMPONENT_CAST,
/* A conversion operator, represented as a unary operator. The one
subtree is the type to which the argument should be converted
to. */
DEMANGLE_COMPONENT_CONVERSION,
/* A nullary expression. The left subtree is the operator. */
DEMANGLE_COMPONENT_NULLARY,
/* A unary expression. The left subtree is the operator, and the
right subtree is the single argument. */
DEMANGLE_COMPONENT_UNARY,
/* A binary expression. The left subtree is the operator, and the
right subtree is a BINARY_ARGS. */
DEMANGLE_COMPONENT_BINARY,
/* Arguments to a binary expression. The left subtree is the first
argument, and the right subtree is the second argument. */
DEMANGLE_COMPONENT_BINARY_ARGS,
/* A trinary expression. The left subtree is the operator, and the
right subtree is a TRINARY_ARG1. */
DEMANGLE_COMPONENT_TRINARY,
/* Arguments to a trinary expression. The left subtree is the first
argument, and the right subtree is a TRINARY_ARG2. */
DEMANGLE_COMPONENT_TRINARY_ARG1,
/* More arguments to a trinary expression. The left subtree is the
second argument, and the right subtree is the third argument. */
DEMANGLE_COMPONENT_TRINARY_ARG2,
/* A literal. The left subtree is the type, and the right subtree
is the value, represented as a DEMANGLE_COMPONENT_NAME. */
DEMANGLE_COMPONENT_LITERAL,
/* A negative literal. Like LITERAL, but the value is negated.
This is a minor hack: the NAME used for LITERAL points directly
to the mangled string, but since negative numbers are mangled
using 'n' instead of '-', we want a way to indicate a negative
number which involves neither modifying the mangled string nor
allocating a new copy of the literal in memory. */
DEMANGLE_COMPONENT_LITERAL_NEG,
/* A libgcj compiled resource. The left subtree is the name of the
resource. */
DEMANGLE_COMPONENT_JAVA_RESOURCE,
/* A name formed by the concatenation of two parts. The left
subtree is the first part and the right subtree the second. */
DEMANGLE_COMPONENT_COMPOUND_NAME,
/* A name formed by a single character. */
DEMANGLE_COMPONENT_CHARACTER,
/* A number. */
DEMANGLE_COMPONENT_NUMBER,
/* A decltype type. */
DEMANGLE_COMPONENT_DECLTYPE,
/* Global constructors keyed to name. */
DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS,
/* Global destructors keyed to name. */
DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS,
/* A lambda closure type. */
DEMANGLE_COMPONENT_LAMBDA,
/* A default argument scope. */
DEMANGLE_COMPONENT_DEFAULT_ARG,
/* An unnamed type. */
DEMANGLE_COMPONENT_UNNAMED_TYPE,
/* A transactional clone. This has one subtree, the encoding for
which it is providing alternative linkage. */
DEMANGLE_COMPONENT_TRANSACTION_CLONE,
/* A non-transactional clone entry point. In the i386/x86_64 abi,
the unmangled symbol of a tm_callable becomes a thunk and the
non-transactional function version is mangled thus. */
DEMANGLE_COMPONENT_NONTRANSACTION_CLONE,
/* A pack expansion. */
DEMANGLE_COMPONENT_PACK_EXPANSION,
/* A name with an ABI tag. */
DEMANGLE_COMPONENT_TAGGED_NAME,
/* A transaction-safe function type. */
DEMANGLE_COMPONENT_TRANSACTION_SAFE,
/* A cloned function. */
DEMANGLE_COMPONENT_CLONE,
DEMANGLE_COMPONENT_NOEXCEPT,
DEMANGLE_COMPONENT_THROW_SPEC
};
/* Types which are only used internally. */
struct demangle_operator_info;
struct demangle_builtin_type_info;
/* A node in the tree representation is an instance of a struct
demangle_component. Note that the field names of the struct are
not well protected against macros defined by the file including
this one. We can fix this if it ever becomes a problem. */
struct demangle_component
{
/* The type of this component. */
enum demangle_component_type type;
/* Guard against recursive component printing.
Initialize to zero. Private to d_print_comp.
All other fields are final after initialization. */
int d_printing;
union
{
/* For DEMANGLE_COMPONENT_NAME. */
struct
{
/* A pointer to the name (which need not NULL terminated) and
its length. */
const char *s;
int len;
} s_name;
/* For DEMANGLE_COMPONENT_OPERATOR. */
struct
{
/* Operator. */
const struct demangle_operator_info *op;
} s_operator;
/* For DEMANGLE_COMPONENT_EXTENDED_OPERATOR. */
struct
{
/* Number of arguments. */
int args;
/* Name. */
struct demangle_component *name;
} s_extended_operator;
/* For DEMANGLE_COMPONENT_FIXED_TYPE. */
struct
{
/* The length, indicated by a C integer type name. */
struct demangle_component *length;
/* _Accum or _Fract? */
short accum;
/* Saturating or not? */
short sat;
} s_fixed;
/* For DEMANGLE_COMPONENT_CTOR. */
struct
{
/* Kind of constructor. */
enum gnu_v3_ctor_kinds kind;
/* Name. */
struct demangle_component *name;
} s_ctor;
/* For DEMANGLE_COMPONENT_DTOR. */
struct
{
/* Kind of destructor. */
enum gnu_v3_dtor_kinds kind;
/* Name. */
struct demangle_component *name;
} s_dtor;
/* For DEMANGLE_COMPONENT_BUILTIN_TYPE. */
struct
{
/* Builtin type. */
const struct demangle_builtin_type_info *type;
} s_builtin;
/* For DEMANGLE_COMPONENT_SUB_STD. */
struct
{
/* Standard substitution string. */
const char* string;
/* Length of string. */
int len;
} s_string;
/* For DEMANGLE_COMPONENT_*_PARAM. */
struct
{
/* Parameter index. */
long number;
} s_number;
/* For DEMANGLE_COMPONENT_CHARACTER. */
struct
{
int character;
} s_character;
/* For other types. */
struct
{
/* Left (or only) subtree. */
struct demangle_component *left;
/* Right subtree. */
struct demangle_component *right;
} s_binary;
struct
{
/* subtree, same place as d_left. */
struct demangle_component *sub;
/* integer. */
int num;
} s_unary_num;
} u;
};
/* People building mangled trees are expected to allocate instances of
struct demangle_component themselves. They can then call one of
the following functions to fill them in. */
/* Fill in most component types with a left subtree and a right
subtree. Returns non-zero on success, zero on failure, such as an
unrecognized or inappropriate component type. */
extern int
cplus_demangle_fill_component (struct demangle_component *fill,
enum demangle_component_type,
struct demangle_component *left,
struct demangle_component *right);
/* Fill in a DEMANGLE_COMPONENT_NAME. Returns non-zero on success,
zero for bad arguments. */
extern int
cplus_demangle_fill_name (struct demangle_component *fill,
const char *, int);
/* Fill in a DEMANGLE_COMPONENT_BUILTIN_TYPE, using the name of the
builtin type (e.g., "int", etc.). Returns non-zero on success,
zero if the type is not recognized. */
extern int
cplus_demangle_fill_builtin_type (struct demangle_component *fill,
const char *type_name);
/* Fill in a DEMANGLE_COMPONENT_OPERATOR, using the name of the
operator and the number of arguments which it takes (the latter is
used to disambiguate operators which can be both binary and unary,
such as '-'). Returns non-zero on success, zero if the operator is
not recognized. */
extern int
cplus_demangle_fill_operator (struct demangle_component *fill,
const char *opname, int args);
/* Fill in a DEMANGLE_COMPONENT_EXTENDED_OPERATOR, providing the
number of arguments and the name. Returns non-zero on success,
zero for bad arguments. */
extern int
cplus_demangle_fill_extended_operator (struct demangle_component *fill,
int numargs,
struct demangle_component *nm);
/* Fill in a DEMANGLE_COMPONENT_CTOR. Returns non-zero on success,
zero for bad arguments. */
extern int
cplus_demangle_fill_ctor (struct demangle_component *fill,
enum gnu_v3_ctor_kinds kind,
struct demangle_component *name);
/* Fill in a DEMANGLE_COMPONENT_DTOR. Returns non-zero on success,
zero for bad arguments. */
extern int
cplus_demangle_fill_dtor (struct demangle_component *fill,
enum gnu_v3_dtor_kinds kind,
struct demangle_component *name);
/* This function translates a mangled name into a struct
demangle_component tree. The first argument is the mangled name.
The second argument is DMGL_* options. This returns a pointer to a
tree on success, or NULL on failure. On success, the third
argument is set to a block of memory allocated by malloc. This
block should be passed to free when the tree is no longer
needed. */
extern struct demangle_component *
cplus_demangle_v3_components (const char *mangled, int options, void **mem);
/* This function takes a struct demangle_component tree and returns
the corresponding demangled string. The first argument is DMGL_*
options. The second is the tree to demangle. The third is a guess
at the length of the demangled string, used to initially allocate
the return buffer. The fourth is a pointer to a size_t. On
success, this function returns a buffer allocated by malloc(), and
sets the size_t pointed to by the fourth argument to the size of
the allocated buffer (not the length of the returned string). On
failure, this function returns NULL, and sets the size_t pointed to
by the fourth argument to 0 for an invalid tree, or to 1 for a
memory allocation error. */
extern char *
cplus_demangle_print (int options,
struct demangle_component *tree,
int estimated_length,
size_t *p_allocated_size);
/* This function takes a struct demangle_component tree and passes back
a demangled string in one or more calls to a callback function.
The first argument is DMGL_* options. The second is the tree to
demangle. The third is a pointer to a callback function; on each call
this receives an element of the demangled string, its length, and an
opaque value. The fourth is the opaque value passed to the callback.
The callback is called once or more to return the full demangled
string. The demangled element string is always nul-terminated, though
its length is also provided for convenience. In contrast to
cplus_demangle_print(), this function does not allocate heap memory
to grow output strings (except perhaps where alloca() is implemented
by malloc()), and so is normally safe for use where the heap has been
corrupted. On success, this function returns 1; on failure, 0. */
extern int
cplus_demangle_print_callback (int options,
struct demangle_component *tree,
demangle_callbackref callback, void *opaque);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* DEMANGLE_H */

View file

@ -0,0 +1,76 @@
/* ###
* IP: GPL 3
* NOTE: See binutils/include/COPYING3
*/
/* An abstract string datatype.
Copyright (C) 1998-2019 Free Software Foundation, Inc.
Contributed by Mark Mitchell (mark@markmitchell.com).
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
GCC 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to
the Free Software Foundation, 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
#ifndef DYN_STRING_H
#define DYN_STRING_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct dyn_string
{
int allocated; /* The amount of space allocated for the string. */
int length; /* The actual length of the string. */
char *s; /* The string itself, NUL-terminated. */
}* dyn_string_t;
/* The length STR, in bytes, not including the terminating NUL. */
#define dyn_string_length(STR) \
((STR)->length)
/* The NTBS in which the contents of STR are stored. */
#define dyn_string_buf(STR) \
((STR)->s)
/* Compare DS1 to DS2 with strcmp. */
#define dyn_string_compare(DS1, DS2) \
(strcmp ((DS1)->s, (DS2)->s))
extern int dyn_string_init (struct dyn_string *, int);
extern dyn_string_t dyn_string_new (int);
extern void dyn_string_delete (dyn_string_t);
extern char *dyn_string_release (dyn_string_t);
extern dyn_string_t dyn_string_resize (dyn_string_t, int);
extern void dyn_string_clear (dyn_string_t);
extern int dyn_string_copy (dyn_string_t, dyn_string_t);
extern int dyn_string_copy_cstr (dyn_string_t, const char *);
extern int dyn_string_prepend (dyn_string_t, dyn_string_t);
extern int dyn_string_prepend_cstr (dyn_string_t, const char *);
extern int dyn_string_insert (dyn_string_t, int, dyn_string_t);
extern int dyn_string_insert_cstr (dyn_string_t, int, const char *);
extern int dyn_string_insert_char (dyn_string_t, int, int);
extern int dyn_string_append (dyn_string_t, dyn_string_t);
extern int dyn_string_append_cstr (dyn_string_t, const char *);
extern int dyn_string_append_char (dyn_string_t, int);
extern int dyn_string_substring (dyn_string_t, dyn_string_t, int, int);
extern int dyn_string_eq (dyn_string_t, dyn_string_t);
#ifdef __cplusplus
}
#endif
#endif /* !defined (DYN_STRING_H) */

View file

@ -0,0 +1,147 @@
/* ###
* IP: GPL 3
* NOTE: See binutils/include/COPYING3
*/
/* Declarations for getopt.
Copyright (C) 1989-2019 Free Software Foundation, Inc.
NOTE: The canonical source of this file is maintained with the GNU C Library.
Bugs can be reported to bug-glibc@gnu.org.
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2, or (at your option) any
later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
USA. */
#ifndef _GETOPT_H
#define _GETOPT_H 1
#ifdef __cplusplus
extern "C" {
#endif
/* For communication from `getopt' to the caller.
When `getopt' finds an option that takes an argument,
the argument value is returned here.
Also, when `ordering' is RETURN_IN_ORDER,
each non-option ARGV-element is returned here. */
extern char *optarg;
/* Index in ARGV of the next element to be scanned.
This is used for communication to and from the caller
and for communication between successive calls to `getopt'.
On entry to `getopt', zero means this is the first call; initialize.
When `getopt' returns -1, this is the index of the first of the
non-option elements that the caller should itself scan.
Otherwise, `optind' communicates from one call to the next
how much of ARGV has been scanned so far. */
extern int optind;
/* Callers store zero here to inhibit the error message `getopt' prints
for unrecognized options. */
extern int opterr;
/* Set to an option character which was unrecognized. */
extern int optopt;
/* Describe the long-named options requested by the application.
The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
of `struct option' terminated by an element containing a name which is
zero.
The field `has_arg' is:
no_argument (or 0) if the option does not take an argument,
required_argument (or 1) if the option requires an argument,
optional_argument (or 2) if the option takes an optional argument.
If the field `flag' is not NULL, it points to a variable that is set
to the value given in the field `val' when the option is found, but
left unchanged if the option is not found.
To have a long-named option do something other than set an `int' to
a compiled-in constant, such as set a value from `optarg', set the
option's `flag' field to zero and its `val' field to a nonzero
value (the equivalent single-letter option character, if there is
one). For long options that have a zero `flag' field, `getopt'
returns the contents of the `val' field. */
struct option
{
#if defined (__STDC__) && __STDC__
const char *name;
#else
char *name;
#endif
/* has_arg can't be an enum because some compilers complain about
type mismatches in all the code that assumes it is an int. */
int has_arg;
int *flag;
int val;
};
/* Names for the values of the `has_arg' field of `struct option'. */
#define no_argument 0
#define required_argument 1
#define optional_argument 2
#if defined (__STDC__) && __STDC__
/* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is
undefined, we haven't run the autoconf check so provide the
declaration without arguments. If it is 0, we checked and failed
to find the declaration so provide a fully prototyped one. If it
is 1, we found it so don't provide any declaration at all. */
#if !HAVE_DECL_GETOPT
#if defined (__GNU_LIBRARY__) || defined (HAVE_DECL_GETOPT)
/* Many other libraries have conflicting prototypes for getopt, with
differences in the consts, in unistd.h. To avoid compilation
errors, only prototype getopt for the GNU C library. */
extern int getopt (int argc, char *const *argv, const char *shortopts);
#else
#ifndef __cplusplus
extern int getopt ();
#endif /* __cplusplus */
#endif
#endif /* !HAVE_DECL_GETOPT */
extern int getopt_long (int argc, char *const *argv, const char *shortopts,
const struct option *longopts, int *longind);
extern int getopt_long_only (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind);
/* Internal only. Users should not call this directly. */
extern int _getopt_internal (int argc, char *const *argv,
const char *shortopts,
const struct option *longopts, int *longind,
int long_only);
#else /* not __STDC__ */
extern int getopt ();
extern int getopt_long ();
extern int getopt_long_only ();
extern int _getopt_internal ();
#endif /* __STDC__ */
#ifdef __cplusplus
}
#endif
#endif /* getopt.h */

View file

@ -0,0 +1,759 @@
/* ###
* IP: GPL 3
* NOTE: See binutils/include/COPYING3
*/
/* Function declarations for libiberty.
Copyright (C) 1997-2019 Free Software Foundation, Inc.
Note - certain prototypes declared in this header file are for
functions whoes implementation copyright does not belong to the
FSF. Those prototypes are present in this file for reference
purposes only and their presence in this file should not construed
as an indication of ownership by the FSF of the implementation of
those functions in any way or form whatsoever.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA.
Written by Cygnus Support, 1994.
The libiberty library provides a number of functions which are
missing on some operating systems. We do not declare those here,
to avoid conflicts with the system header files on operating
systems that do support those functions. In this file we only
declare those functions which are specific to libiberty. */
#ifndef LIBIBERTY_H
#define LIBIBERTY_H
#ifdef __cplusplus
extern "C" {
#endif
#include "ansidecl.h"
/* Get a definition for size_t. */
#include <stddef.h>
/* Get a definition for va_list. */
#include <stdarg.h>
#include <stdio.h>
/* If the OS supports it, ensure that the supplied stream is setup to
avoid any multi-threaded locking. Otherwise leave the FILE pointer
unchanged. If the stream is NULL do nothing. */
extern void unlock_stream (FILE *);
/* If the OS supports it, ensure that the standard I/O streams, stdin,
stdout and stderr are setup to avoid any multi-threaded locking.
Otherwise do nothing. */
extern void unlock_std_streams (void);
/* Open and return a FILE pointer. If the OS supports it, ensure that
the stream is setup to avoid any multi-threaded locking. Otherwise
return the FILE pointer unchanged. */
extern FILE *fopen_unlocked (const char *, const char *);
extern FILE *fdopen_unlocked (int, const char *);
extern FILE *freopen_unlocked (const char *, const char *, FILE *);
/* Build an argument vector from a string. Allocates memory using
malloc. Use freeargv to free the vector. */
extern char **buildargv (const char *) ATTRIBUTE_MALLOC;
/* Free a vector returned by buildargv. */
extern void freeargv (char **);
/* Duplicate an argument vector. Allocates memory using malloc. Use
freeargv to free the vector. */
extern char **dupargv (char * const *) ATTRIBUTE_MALLOC;
/* Expand "@file" arguments in argv. */
extern void expandargv (int *, char ***);
/* Write argv to an @-file, inserting necessary quoting. */
extern int writeargv (char * const *, FILE *);
/* Return the number of elements in argv. */
extern int countargv (char * const *);
/* Return the last component of a path name. Note that we can't use a
prototype here because the parameter is declared inconsistently
across different systems, sometimes as "char *" and sometimes as
"const char *" */
/* HAVE_DECL_* is a three-state macro: undefined, 0 or 1. If it is
undefined, we haven't run the autoconf check so provide the
declaration without arguments. If it is 0, we checked and failed
to find the declaration so provide a fully prototyped one. If it
is 1, we found it so don't provide any declaration at all. */
#if !HAVE_DECL_BASENAME
#if defined (__GNU_LIBRARY__ ) || defined (__linux__) \
|| defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__) \
|| defined (__CYGWIN__) || defined (__CYGWIN32__) || defined (__MINGW32__) \
|| defined (__DragonFly__) || defined (HAVE_DECL_BASENAME)
extern char *basename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1);
#else
/* Do not allow basename to be used if there is no prototype seen. We
either need to use the above prototype or have one from
autoconf which would result in HAVE_DECL_BASENAME being set. */
#define basename basename_cannot_be_used_without_a_prototype
#endif
#endif
/* A well-defined basename () that is always compiled in. */
extern const char *lbasename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1);
/* Same, but assumes DOS semantics (drive name, backslash is also a
dir separator) regardless of host. */
extern const char *dos_lbasename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1);
/* Same, but assumes Unix semantics (absolute paths always start with
a slash, only forward slash is accepted as dir separator)
regardless of host. */
extern const char *unix_lbasename (const char *) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1);
/* A well-defined realpath () that is always compiled in. */
extern char *lrealpath (const char *);
/* Concatenate an arbitrary number of strings. You must pass NULL as
the last argument of this function, to terminate the list of
strings. Allocates memory using xmalloc. */
extern char *concat (const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_SENTINEL;
/* Concatenate an arbitrary number of strings. You must pass NULL as
the last argument of this function, to terminate the list of
strings. Allocates memory using xmalloc. The first argument is
not one of the strings to be concatenated, but if not NULL is a
pointer to be freed after the new string is created, similar to the
way xrealloc works. */
extern char *reconcat (char *, const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_SENTINEL;
/* Determine the length of concatenating an arbitrary number of
strings. You must pass NULL as the last argument of this function,
to terminate the list of strings. */
extern unsigned long concat_length (const char *, ...) ATTRIBUTE_SENTINEL;
/* Concatenate an arbitrary number of strings into a SUPPLIED area of
memory. You must pass NULL as the last argument of this function,
to terminate the list of strings. The supplied memory is assumed
to be large enough. */
extern char *concat_copy (char *, const char *, ...) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL;
/* Concatenate an arbitrary number of strings into a GLOBAL area of
memory. You must pass NULL as the last argument of this function,
to terminate the list of strings. The supplied memory is assumed
to be large enough. */
extern char *concat_copy2 (const char *, ...) ATTRIBUTE_RETURNS_NONNULL ATTRIBUTE_SENTINEL;
/* This is the global area used by concat_copy2. */
extern char *libiberty_concat_ptr;
/* Concatenate an arbitrary number of strings. You must pass NULL as
the last argument of this function, to terminate the list of
strings. Allocates memory using alloca. The arguments are
evaluated twice! */
#define ACONCAT(ACONCAT_PARAMS) \
(libiberty_concat_ptr = (char *) alloca (concat_length ACONCAT_PARAMS + 1), \
concat_copy2 ACONCAT_PARAMS)
/* Check whether two file descriptors refer to the same file. */
extern int fdmatch (int fd1, int fd2);
/* Return the position of the first bit set in the argument. */
/* Prototypes vary from system to system, so we only provide a
prototype on systems where we know that we need it. */
#if defined (HAVE_DECL_FFS) && !HAVE_DECL_FFS
extern int ffs(int);
#endif
/* Get the working directory. The result is cached, so don't call
chdir() between calls to getpwd(). */
extern char * getpwd (void);
/* Get the current time. */
/* Prototypes vary from system to system, so we only provide a
prototype on systems where we know that we need it. */
#ifdef __MINGW32__
/* Forward declaration to avoid #include <sys/time.h>. */
struct timeval;
extern int gettimeofday (struct timeval *, void *);
#endif
/* Get the amount of time the process has run, in microseconds. */
extern long get_run_time (void);
/* Generate a relocated path to some installation directory. Allocates
return value using malloc. */
extern char *make_relative_prefix (const char *, const char *,
const char *) ATTRIBUTE_MALLOC;
/* Generate a relocated path to some installation directory without
attempting to follow any soft links. Allocates
return value using malloc. */
extern char *make_relative_prefix_ignore_links (const char *, const char *,
const char *) ATTRIBUTE_MALLOC;
/* Returns a pointer to a directory path suitable for creating temporary
files in. */
extern const char *choose_tmpdir (void) ATTRIBUTE_RETURNS_NONNULL;
/* Choose a temporary directory to use for scratch files. */
extern char *choose_temp_base (void) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
/* Return a temporary file name or NULL if unable to create one. */
extern char *make_temp_file (const char *) ATTRIBUTE_MALLOC;
/* Return a temporary file name with given PREFIX and SUFFIX
or NULL if unable to create one. */
extern char *make_temp_file_with_prefix (const char *, const char *) ATTRIBUTE_MALLOC;
/* Remove a link to a file unless it is special. */
extern int unlink_if_ordinary (const char *);
/* Allocate memory filled with spaces. Allocates using malloc. */
extern const char *spaces (int count);
/* Return the maximum error number for which strerror will return a
string. */
extern int errno_max (void);
/* Return the name of an errno value (e.g., strerrno (EINVAL) returns
"EINVAL"). */
extern const char *strerrno (int);
/* Given the name of an errno value, return the value. */
extern int strtoerrno (const char *);
/* ANSI's strerror(), but more robust. */
extern char *xstrerror (int) ATTRIBUTE_RETURNS_NONNULL;
/* Return the maximum signal number for which strsignal will return a
string. */
extern int signo_max (void);
/* Return a signal message string for a signal number
(e.g., strsignal (SIGHUP) returns something like "Hangup"). */
/* This is commented out as it can conflict with one in system headers.
We still document its existence though. */
/*extern const char *strsignal (int);*/
/* Return the name of a signal number (e.g., strsigno (SIGHUP) returns
"SIGHUP"). */
extern const char *strsigno (int);
/* Given the name of a signal, return its number. */
extern int strtosigno (const char *);
/* Register a function to be run by xexit. Returns 0 on success. */
extern int xatexit (void (*fn) (void));
/* Exit, calling all the functions registered with xatexit. */
extern void xexit (int status) ATTRIBUTE_NORETURN;
/* Set the program name used by xmalloc. */
extern void xmalloc_set_program_name (const char *);
/* Report an allocation failure. */
extern void xmalloc_failed (size_t) ATTRIBUTE_NORETURN;
/* Allocate memory without fail. If malloc fails, this will print a
message to stderr (using the name set by xmalloc_set_program_name,
if any) and then call xexit. */
extern void *xmalloc (size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
/* Reallocate memory without fail. This works like xmalloc. Note,
realloc type functions are not suitable for attribute malloc since
they may return the same address across multiple calls. */
extern void *xrealloc (void *, size_t) ATTRIBUTE_RETURNS_NONNULL;
/* Allocate memory without fail and set it to zero. This works like
xmalloc. */
extern void *xcalloc (size_t, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
/* Copy a string into a memory buffer without fail. */
extern char *xstrdup (const char *) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
/* Copy at most N characters from string into a buffer without fail. */
extern char *xstrndup (const char *, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
/* Copy an existing memory buffer to a new memory buffer without fail. */
extern void *xmemdup (const void *, size_t, size_t) ATTRIBUTE_MALLOC ATTRIBUTE_RETURNS_NONNULL;
/* Physical memory routines. Return values are in BYTES. */
extern double physmem_total (void);
extern double physmem_available (void);
/* Compute the 32-bit CRC of a block of memory. */
extern unsigned int xcrc32 (const unsigned char *, int, unsigned int);
/* These macros provide a K&R/C89/C++-friendly way of allocating structures
with nice encapsulation. The XDELETE*() macros are technically
superfluous, but provided here for symmetry. Using them consistently
makes it easier to update client code to use different allocators such
as new/delete and new[]/delete[]. */
/* Scalar allocators. */
#define XALLOCA(T) ((T *) alloca (sizeof (T)))
#define XNEW(T) ((T *) xmalloc (sizeof (T)))
#define XCNEW(T) ((T *) xcalloc (1, sizeof (T)))
#define XDUP(T, P) ((T *) xmemdup ((P), sizeof (T), sizeof (T)))
#define XDELETE(P) free ((void*) (P))
/* Array allocators. */
#define XALLOCAVEC(T, N) ((T *) alloca (sizeof (T) * (N)))
#define XNEWVEC(T, N) ((T *) xmalloc (sizeof (T) * (N)))
#define XCNEWVEC(T, N) ((T *) xcalloc ((N), sizeof (T)))
#define XDUPVEC(T, P, N) ((T *) xmemdup ((P), sizeof (T) * (N), sizeof (T) * (N)))
#define XRESIZEVEC(T, P, N) ((T *) xrealloc ((void *) (P), sizeof (T) * (N)))
#define XDELETEVEC(P) free ((void*) (P))
/* Allocators for variable-sized structures and raw buffers. */
#define XALLOCAVAR(T, S) ((T *) alloca ((S)))
#define XNEWVAR(T, S) ((T *) xmalloc ((S)))
#define XCNEWVAR(T, S) ((T *) xcalloc (1, (S)))
#define XDUPVAR(T, P, S1, S2) ((T *) xmemdup ((P), (S1), (S2)))
#define XRESIZEVAR(T, P, S) ((T *) xrealloc ((P), (S)))
/* Type-safe obstack allocator. */
#define XOBNEW(O, T) ((T *) obstack_alloc ((O), sizeof (T)))
#define XOBNEWVEC(O, T, N) ((T *) obstack_alloc ((O), sizeof (T) * (N)))
#define XOBNEWVAR(O, T, S) ((T *) obstack_alloc ((O), (S)))
#define XOBFINISH(O, T) ((T) obstack_finish ((O)))
/* hex character manipulation routines */
#define _hex_array_size 256
#define _hex_bad 99
extern const unsigned char _hex_value[_hex_array_size];
extern void hex_init (void);
#define hex_p(c) (hex_value (c) != _hex_bad)
/* If you change this, note well: Some code relies on side effects in
the argument being performed exactly once. */
#define hex_value(c) ((unsigned int) _hex_value[(unsigned char) (c)])
/* Flags for pex_init. These are bits to be or'ed together. */
/* Record subprocess times, if possible. */
#define PEX_RECORD_TIMES 0x1
/* Use pipes for communication between processes, if possible. */
#define PEX_USE_PIPES 0x2
/* Save files used for communication between processes. */
#define PEX_SAVE_TEMPS 0x4
/* Max number of alloca bytes per call before we must switch to malloc.
?? Swiped from gnulib's regex_internal.h header. Is this actually
the case? This number seems arbitrary, though sane.
The OS usually guarantees only one guard page at the bottom of the stack,
and a page size can be as small as 4096 bytes. So we cannot safely
allocate anything larger than 4096 bytes. Also care for the possibility
of a few compiler-allocated temporary stack slots. */
#define MAX_ALLOCA_SIZE 4032
/* Prepare to execute one or more programs, with standard output of
each program fed to standard input of the next.
FLAGS As above.
PNAME The name of the program to report in error messages.
TEMPBASE A base name to use for temporary files; may be NULL to
use a random name.
Returns NULL on error. */
extern struct pex_obj *pex_init (int flags, const char *pname,
const char *tempbase) ATTRIBUTE_RETURNS_NONNULL;
/* Flags for pex_run. These are bits to be or'ed together. */
/* Last program in pipeline. Standard output of program goes to
OUTNAME, or, if OUTNAME is NULL, to standard output of caller. Do
not set this if you want to call pex_read_output. After this is
set, pex_run may no longer be called with the same struct
pex_obj. */
#define PEX_LAST 0x1
/* Search for program in executable search path. */
#define PEX_SEARCH 0x2
/* OUTNAME is a suffix. */
#define PEX_SUFFIX 0x4
/* Send program's standard error to standard output. */
#define PEX_STDERR_TO_STDOUT 0x8
/* Input file should be opened in binary mode. This flag is ignored
on Unix. */
#define PEX_BINARY_INPUT 0x10
/* Output file should be opened in binary mode. This flag is ignored
on Unix. For proper behaviour PEX_BINARY_INPUT and
PEX_BINARY_OUTPUT have to match appropriately--i.e., a call using
PEX_BINARY_OUTPUT should be followed by a call using
PEX_BINARY_INPUT. */
#define PEX_BINARY_OUTPUT 0x20
/* Capture stderr to a pipe. The output can be read by
calling pex_read_err and reading from the returned
FILE object. This flag may be specified only for
the last program in a pipeline.
This flag is supported only on Unix and Windows. */
#define PEX_STDERR_TO_PIPE 0x40
/* Capture stderr in binary mode. This flag is ignored
on Unix. */
#define PEX_BINARY_ERROR 0x80
/* Append stdout to existing file instead of truncating it. */
#define PEX_STDOUT_APPEND 0x100
/* Thes same as PEX_STDOUT_APPEND, but for STDERR. */
#define PEX_STDERR_APPEND 0x200
/* Execute one program. Returns NULL on success. On error returns an
error string (typically just the name of a system call); the error
string is statically allocated.
OBJ Returned by pex_init.
FLAGS As above.
EXECUTABLE The program to execute.
ARGV NULL terminated array of arguments to pass to the program.
OUTNAME Sets the output file name as follows:
PEX_SUFFIX set (OUTNAME may not be NULL):
TEMPBASE parameter to pex_init not NULL:
Output file name is the concatenation of TEMPBASE
and OUTNAME.
TEMPBASE is NULL:
Output file name is a random file name ending in
OUTNAME.
PEX_SUFFIX not set:
OUTNAME not NULL:
Output file name is OUTNAME.
OUTNAME NULL, TEMPBASE not NULL:
Output file name is randomly chosen using
TEMPBASE.
OUTNAME NULL, TEMPBASE NULL:
Output file name is randomly chosen.
If PEX_LAST is not set, the output file name is the
name to use for a temporary file holding stdout, if
any (there will not be a file if PEX_USE_PIPES is set
and the system supports pipes). If a file is used, it
will be removed when no longer needed unless
PEX_SAVE_TEMPS is set.
If PEX_LAST is set, and OUTNAME is not NULL, standard
output is written to the output file name. The file
will not be removed. If PEX_LAST and PEX_SUFFIX are
both set, TEMPBASE may not be NULL.
ERRNAME If not NULL, this is the name of a file to which
standard error is written. If NULL, standard error of
the program is standard error of the caller.
ERR On an error return, *ERR is set to an errno value, or
to 0 if there is no relevant errno.
*/
extern const char *pex_run (struct pex_obj *obj, int flags,
const char *executable, char * const *argv,
const char *outname, const char *errname,
int *err);
/* As for pex_run (), but takes an extra parameter to enable the
environment for the child process to be specified.
ENV The environment for the child process, specified as
an array of character pointers. Each element of the
array should point to a string of the form VAR=VALUE,
with the exception of the last element which must be
a null pointer.
*/
extern const char *pex_run_in_environment (struct pex_obj *obj, int flags,
const char *executable,
char * const *argv,
char * const *env,
const char *outname,
const char *errname, int *err);
/* Return a stream for a temporary file to pass to the first program
in the pipeline as input. The file name is chosen as for pex_run.
pex_run closes the file automatically; don't close it yourself. */
extern FILE *pex_input_file (struct pex_obj *obj, int flags,
const char *in_name);
/* Return a stream for a pipe connected to the standard input of the
first program in the pipeline. You must have passed
`PEX_USE_PIPES' to `pex_init'. Close the returned stream
yourself. */
extern FILE *pex_input_pipe (struct pex_obj *obj, int binary);
/* Read the standard output of the last program to be executed.
pex_run cannot be called after this. BINARY should be non-zero if
the file should be opened in binary mode; this is ignored on Unix.
Returns NULL on error. Don't call fclose on the returned FILE; it
will be closed by pex_free. */
extern FILE *pex_read_output (struct pex_obj *, int binary);
/* Read the standard error of the last program to be executed.
pex_run cannot be called after this. BINARY should be non-zero if
the file should be opened in binary mode; this is ignored on Unix.
Returns NULL on error. Don't call fclose on the returned FILE; it
will be closed by pex_free. */
extern FILE *pex_read_err (struct pex_obj *, int binary);
/* Return exit status of all programs in VECTOR. COUNT indicates the
size of VECTOR. The status codes in the vector are in the order of
the calls to pex_run. Returns 0 on error, 1 on success. */
extern int pex_get_status (struct pex_obj *, int count, int *vector);
/* Return times of all programs in VECTOR. COUNT indicates the size
of VECTOR. struct pex_time is really just struct timeval, but that
is not portable to all systems. Returns 0 on error, 1 on
success. */
struct pex_time
{
unsigned long user_seconds;
unsigned long user_microseconds;
unsigned long system_seconds;
unsigned long system_microseconds;
};
extern int pex_get_times (struct pex_obj *, int count,
struct pex_time *vector);
/* Clean up a pex_obj. If you have not called pex_get_times or
pex_get_status, this will try to kill the subprocesses. */
extern void pex_free (struct pex_obj *);
/* Just execute one program. Return value is as for pex_run.
FLAGS Combination of PEX_SEARCH and PEX_STDERR_TO_STDOUT.
EXECUTABLE As for pex_run.
ARGV As for pex_run.
PNAME As for pex_init.
OUTNAME As for pex_run when PEX_LAST is set.
ERRNAME As for pex_run.
STATUS Set to exit status on success.
ERR As for pex_run.
*/
extern const char *pex_one (int flags, const char *executable,
char * const *argv, const char *pname,
const char *outname, const char *errname,
int *status, int *err);
/* pexecute and pwait are the old pexecute interface, still here for
backward compatibility. Don't use these for new code. Instead,
use pex_init/pex_run/pex_get_status/pex_free, or pex_one. */
/* Definitions used by the pexecute routine. */
#define PEXECUTE_FIRST 1
#define PEXECUTE_LAST 2
#define PEXECUTE_ONE (PEXECUTE_FIRST + PEXECUTE_LAST)
#define PEXECUTE_SEARCH 4
#define PEXECUTE_VERBOSE 8
/* Execute a program. */
extern int pexecute (const char *, char * const *, const char *,
const char *, char **, char **, int);
/* Wait for pexecute to finish. */
extern int pwait (int, int *, int);
#if defined(HAVE_DECL_ASPRINTF) && !HAVE_DECL_ASPRINTF
/* Like sprintf but provides a pointer to malloc'd storage, which must
be freed by the caller. */
extern int asprintf (char **, const char *, ...) ATTRIBUTE_PRINTF_2;
#endif
/* Like asprintf but allocates memory without fail. This works like
xmalloc. */
extern char *xasprintf (const char *, ...) ATTRIBUTE_MALLOC ATTRIBUTE_PRINTF_1;
#if !HAVE_DECL_VASPRINTF
/* Like vsprintf but provides a pointer to malloc'd storage, which
must be freed by the caller. */
extern int vasprintf (char **, const char *, va_list) ATTRIBUTE_PRINTF(2,0);
#endif
/* Like vasprintf but allocates memory without fail. This works like
xmalloc. */
extern char *xvasprintf (const char *, va_list) ATTRIBUTE_MALLOC ATTRIBUTE_PRINTF(1,0);
#if defined(HAVE_DECL_SNPRINTF) && !HAVE_DECL_SNPRINTF
/* Like sprintf but prints at most N characters. */
extern int snprintf (char *, size_t, const char *, ...) ATTRIBUTE_PRINTF_3;
#endif
#if defined(HAVE_DECL_VSNPRINTF) && !HAVE_DECL_VSNPRINTF
/* Like vsprintf but prints at most N characters. */
extern int vsnprintf (char *, size_t, const char *, va_list) ATTRIBUTE_PRINTF(3,0);
#endif
#if defined (HAVE_DECL_STRNLEN) && !HAVE_DECL_STRNLEN
extern size_t strnlen (const char *, size_t);
#endif
#if defined(HAVE_DECL_STRVERSCMP) && !HAVE_DECL_STRVERSCMP
/* Compare version strings. */
extern int strverscmp (const char *, const char *);
#endif
#if defined(HAVE_DECL_STRTOL) && !HAVE_DECL_STRTOL
extern long int strtol (const char *nptr,
char **endptr, int base);
#endif
#if defined(HAVE_DECL_STRTOUL) && !HAVE_DECL_STRTOUL
extern unsigned long int strtoul (const char *nptr,
char **endptr, int base);
#endif
#if defined(HAVE_LONG_LONG) && defined(HAVE_DECL_STRTOLL) && !HAVE_DECL_STRTOLL
__extension__
extern long long int strtoll (const char *nptr,
char **endptr, int base);
#endif
#if defined(HAVE_LONG_LONG) && defined(HAVE_DECL_STRTOULL) && !HAVE_DECL_STRTOULL
__extension__
extern unsigned long long int strtoull (const char *nptr,
char **endptr, int base);
#endif
#if defined(HAVE_DECL_STRVERSCMP) && !HAVE_DECL_STRVERSCMP
/* Compare version strings. */
extern int strverscmp (const char *, const char *);
#endif
/* Set the title of a process */
extern void setproctitle (const char *name, ...);
/* Increase stack limit if possible. */
extern void stack_limit_increase (unsigned long);
#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0]))
/* Drastically simplified alloca configurator. If we're using GCC,
we use __builtin_alloca; otherwise we use the C alloca. The C
alloca is always available. You can override GCC by defining
USE_C_ALLOCA yourself. The canonical autoconf macro C_ALLOCA is
also set/unset as it is often used to indicate whether code needs
to call alloca(0). */
extern void *C_alloca (size_t) ATTRIBUTE_MALLOC;
#undef alloca
#if GCC_VERSION >= 2000 && !defined USE_C_ALLOCA
# define alloca(x) __builtin_alloca(x)
# undef C_ALLOCA
# define ASTRDUP(X) \
(__extension__ ({ const char *const libiberty_optr = (X); \
const unsigned long libiberty_len = strlen (libiberty_optr) + 1; \
char *const libiberty_nptr = (char *) alloca (libiberty_len); \
(char *) memcpy (libiberty_nptr, libiberty_optr, libiberty_len); }))
#else
# define alloca(x) C_alloca(x)
# undef USE_C_ALLOCA
# define USE_C_ALLOCA 1
# undef C_ALLOCA
# define C_ALLOCA 1
extern const char *libiberty_optr;
extern char *libiberty_nptr;
extern unsigned long libiberty_len;
# define ASTRDUP(X) \
(libiberty_optr = (X), \
libiberty_len = strlen (libiberty_optr) + 1, \
libiberty_nptr = (char *) alloca (libiberty_len), \
(char *) memcpy (libiberty_nptr, libiberty_optr, libiberty_len))
#endif
#ifdef __cplusplus
}
#endif
#endif /* ! defined (LIBIBERTY_H) */

View file

@ -0,0 +1,49 @@
/* ###
* IP: LGPL 2.1
* NOTE: See binutils/libiberty/COPYING.LIB
*/
/* Internal demangler interface for the Rust programming language.
Copyright (C) 2016-2019 Free Software Foundation, Inc.
Written by David Tolnay (dtolnay@gmail.com).
This file is part of the libiberty library.
Libiberty is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
In addition to the permissions in the GNU Library General Public
License, the Free Software Foundation gives you unlimited permission
to link the compiled version of this file into combinations with other
programs, and to distribute those combinations without any restriction
coming from the use of this file. (The Library Public License
restrictions do apply in other respects; for example, they cover
modification of the file, and distribution when not linked into a
combined executable.)
Libiberty 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with libiberty; see the file COPYING.LIB.
If not, see <http://www.gnu.org/licenses/>. */
/* This file provides some definitions shared by cplus-dem.c and
rust-demangle.c. It should not be included by any other files. */
/* Returns non-zero iff MANGLED is a rust mangled symbol. MANGLED must
already have been demangled through cplus_demangle_v3. If this function
returns non-zero then MANGLED can be demangled (in-place) using
RUST_DEMANGLE_SYM. */
extern int
rust_is_mangled (const char *mangled);
/* Demangles SYM (in-place) if RUST_IS_MANGLED returned non-zero for SYM.
If RUST_IS_MANGLED returned zero for SYM then RUST_DEMANGLE_SYM might
replace characters that cannot be demangled with '?' and might truncate
SYM. After calling RUST_DEMANGLE_SYM SYM might be shorter, but never
larger. */
extern void
rust_demangle_sym (char *sym);

View file

@ -0,0 +1,154 @@
/* ###
* IP: LGPL 2.1
* NOTE: See binutils/include/COPYING
*/
/* <ctype.h> replacement macros.
Copyright (C) 2000-2019 Free Software Foundation, Inc.
Contributed by Zack Weinberg <zackw@stanford.edu>.
This file is part of the libiberty library.
Libiberty is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
Libiberty 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with libiberty; see the file COPYING.LIB. If
not, write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
Boston, MA 02110-1301, USA. */
/* This is a compatible replacement of the standard C library's <ctype.h>
with the following properties:
- Implements all isxxx() macros required by C99.
- Also implements some character classes useful when
parsing C-like languages.
- Does not change behavior depending on the current locale.
- Behaves properly for all values in the range of a signed or
unsigned char.
To avoid conflicts, this header defines the isxxx functions in upper
case, e.g. ISALPHA not isalpha. */
#ifndef SAFE_CTYPE_H
#define SAFE_CTYPE_H
/* Determine host character set. */
#define HOST_CHARSET_UNKNOWN 0
#define HOST_CHARSET_ASCII 1
#define HOST_CHARSET_EBCDIC 2
#if '\n' == 0x0A && ' ' == 0x20 && '0' == 0x30 \
&& 'A' == 0x41 && 'a' == 0x61 && '!' == 0x21
# define HOST_CHARSET HOST_CHARSET_ASCII
#else
# if '\n' == 0x15 && ' ' == 0x40 && '0' == 0xF0 \
&& 'A' == 0xC1 && 'a' == 0x81 && '!' == 0x5A
# define HOST_CHARSET HOST_CHARSET_EBCDIC
# else
# define HOST_CHARSET HOST_CHARSET_UNKNOWN
# endif
#endif
/* Categories. */
enum {
/* In C99 */
_sch_isblank = 0x0001, /* space \t */
_sch_iscntrl = 0x0002, /* nonprinting characters */
_sch_isdigit = 0x0004, /* 0-9 */
_sch_islower = 0x0008, /* a-z */
_sch_isprint = 0x0010, /* any printing character including ' ' */
_sch_ispunct = 0x0020, /* all punctuation */
_sch_isspace = 0x0040, /* space \t \n \r \f \v */
_sch_isupper = 0x0080, /* A-Z */
_sch_isxdigit = 0x0100, /* 0-9A-Fa-f */
/* Extra categories useful to cpplib. */
_sch_isidst = 0x0200, /* A-Za-z_ */
_sch_isvsp = 0x0400, /* \n \r */
_sch_isnvsp = 0x0800, /* space \t \f \v \0 */
/* Combinations of the above. */
_sch_isalpha = _sch_isupper|_sch_islower, /* A-Za-z */
_sch_isalnum = _sch_isalpha|_sch_isdigit, /* A-Za-z0-9 */
_sch_isidnum = _sch_isidst|_sch_isdigit, /* A-Za-z0-9_ */
_sch_isgraph = _sch_isalnum|_sch_ispunct, /* isprint and not space */
_sch_iscppsp = _sch_isvsp|_sch_isnvsp, /* isspace + \0 */
_sch_isbasic = _sch_isprint|_sch_iscppsp /* basic charset of ISO C
(plus ` and @) */
};
/* Character classification. */
extern const unsigned short _sch_istable[256];
#define _sch_test(c, bit) (_sch_istable[(c) & 0xff] & (unsigned short)(bit))
#define ISALPHA(c) _sch_test(c, _sch_isalpha)
#define ISALNUM(c) _sch_test(c, _sch_isalnum)
#define ISBLANK(c) _sch_test(c, _sch_isblank)
#define ISCNTRL(c) _sch_test(c, _sch_iscntrl)
#define ISDIGIT(c) _sch_test(c, _sch_isdigit)
#define ISGRAPH(c) _sch_test(c, _sch_isgraph)
#define ISLOWER(c) _sch_test(c, _sch_islower)
#define ISPRINT(c) _sch_test(c, _sch_isprint)
#define ISPUNCT(c) _sch_test(c, _sch_ispunct)
#define ISSPACE(c) _sch_test(c, _sch_isspace)
#define ISUPPER(c) _sch_test(c, _sch_isupper)
#define ISXDIGIT(c) _sch_test(c, _sch_isxdigit)
#define ISIDNUM(c) _sch_test(c, _sch_isidnum)
#define ISIDST(c) _sch_test(c, _sch_isidst)
#define IS_ISOBASIC(c) _sch_test(c, _sch_isbasic)
#define IS_VSPACE(c) _sch_test(c, _sch_isvsp)
#define IS_NVSPACE(c) _sch_test(c, _sch_isnvsp)
#define IS_SPACE_OR_NUL(c) _sch_test(c, _sch_iscppsp)
/* Character transformation. */
extern const unsigned char _sch_toupper[256];
extern const unsigned char _sch_tolower[256];
#define TOUPPER(c) _sch_toupper[(c) & 0xff]
#define TOLOWER(c) _sch_tolower[(c) & 0xff]
/* Prevent the users of safe-ctype.h from accidently using the routines
from ctype.h. Initially, the approach was to produce an error when
detecting that ctype.h has been included. But this was causing
trouble as ctype.h might get indirectly included as a result of
including another system header (for instance gnulib's stdint.h).
So we include ctype.h here and then immediately redefine its macros. */
#include <ctype.h>
#undef isalpha
#define isalpha(c) do_not_use_isalpha_with_safe_ctype
#undef isalnum
#define isalnum(c) do_not_use_isalnum_with_safe_ctype
#undef iscntrl
#define iscntrl(c) do_not_use_iscntrl_with_safe_ctype
#undef isdigit
#define isdigit(c) do_not_use_isdigit_with_safe_ctype
#undef isgraph
#define isgraph(c) do_not_use_isgraph_with_safe_ctype
#undef islower
#define islower(c) do_not_use_islower_with_safe_ctype
#undef isprint
#define isprint(c) do_not_use_isprint_with_safe_ctype
#undef ispunct
#define ispunct(c) do_not_use_ispunct_with_safe_ctype
#undef isspace
#define isspace(c) do_not_use_isspace_with_safe_ctype
#undef isupper
#define isupper(c) do_not_use_isupper_with_safe_ctype
#undef isxdigit
#define isxdigit(c) do_not_use_isxdigit_with_safe_ctype
#undef toupper
#define toupper(c) do_not_use_toupper_with_safe_ctype
#undef tolower
#define tolower(c) do_not_use_tolower_with_safe_ctype
#endif /* SAFE_CTYPE_H */

View file

@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
li { font-family:times new roman; font-size:14pt; } li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/* /*
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
td { font-family:times new roman; font-size:14pt; vertical-align: top; } td { font-family:times new roman; font-size:14pt; vertical-align: top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; } th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
code { color: black; font-family: courier new; font-size: 14pt; } /*
Code-like formatting for things such as file system paths and proper names of classes,
methods, etc. To apply this to a file path, use this syntax:
<CODE CLASS="path">...</CODE>
*/
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }

View file

@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
li { font-family:times new roman; font-size:14pt; } li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/* /*
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
td { font-family:times new roman; font-size:14pt; vertical-align: top; } td { font-family:times new roman; font-size:14pt; vertical-align: top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; } th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
code { color: black; font-family: courier new; font-size: 14pt; } /*
Code-like formatting for things such as file system paths and proper names of classes,
methods, etc. To apply this to a file path, use this syntax:
<CODE CLASS="path">...</CODE>
*/
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }

View file

@ -82,7 +82,6 @@ ghidra_scripts/world.png||FAMFAMFAM Icons - CC 2.5|||famfamfam silk icon set|END
src/main/help/help/TOC_Source.xml||GHIDRA||||END| src/main/help/help/TOC_Source.xml||GHIDRA||||END|
src/main/help/help/shared/arrow.gif||GHIDRA||||END| src/main/help/help/shared/arrow.gif||GHIDRA||||END|
src/main/help/help/shared/close16.gif||GHIDRA||||END| src/main/help/help/shared/close16.gif||GHIDRA||||END|
src/main/help/help/shared/helpWarning.png||Oxygen Icons - LGPL 3.0|||Oxygen icon theme (dual license; LGPL or CC-SA-3.0)|END|
src/main/help/help/shared/menu16.gif||GHIDRA||||END| src/main/help/help/shared/menu16.gif||GHIDRA||||END|
src/main/help/help/shared/note-red.png||Oxygen Icons - LGPL 3.0|||renamed from flag-red.png|END| src/main/help/help/shared/note-red.png||Oxygen Icons - LGPL 3.0|||renamed from flag-red.png|END|
src/main/help/help/shared/note.png||Oxygen Icons - LGPL 3.0|||renamed from flag-green.png|END| src/main/help/help/shared/note.png||Oxygen Icons - LGPL 3.0|||renamed from flag-green.png|END|

View file

@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
li { font-family:times new roman; font-size:14pt; } li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/* /*
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
td { font-family:times new roman; font-size:14pt; vertical-align: top; } td { font-family:times new roman; font-size:14pt; vertical-align: top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; } th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
code { color: black; font-family: courier new; font-size: 14pt; } /*
Code-like formatting for things such as file system paths and proper names of classes,
methods, etc. To apply this to a file path, use this syntax:
<CODE CLASS="path">...</CODE>
*/
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -5,7 +5,7 @@
<META name="generator" content= <META name="generator" content=
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net"> "HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
<TITLE>Auto-analysis</TITLE> <TITLE>Auto Analysis</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=windows-1252"> <META http-equiv="Content-Type" content="text/html; charset=windows-1252">
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css"> <LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
</HEAD> </HEAD>
@ -24,7 +24,7 @@
<BLOCKQUOTE> <BLOCKQUOTE>
<OL> <OL>
<LI>User Disassembles</LI> <LI>The user triggers disassembly</LI>
<LI>Function Analyzer - looks at all calls and creates Functions</LI> <LI>Function Analyzer - looks at all calls and creates Functions</LI>
@ -34,9 +34,8 @@
<LI>Operand Analyzer - looks at scalar operands for possible address references</LI> <LI>Operand Analyzer - looks at scalar operands for possible address references</LI>
<LI>Data Reference Analyzer - looks at references for possible strings or pointers to <LI>Data Reference Analyzer - looks at references for possible strings or pointers to
code.<BR> code. References to code are disassembled.<BR>
References to code are disassembled.<BR> .....The cycle repeats with 2) as additional code is disassembled.</LI>
..... Cycle repeats with 2) as additional code is disassembled.</LI>
</OL> </OL>
<P>One program change might cause several Analyzers to become active, however only one <P>One program change might cause several Analyzers to become active, however only one
@ -210,46 +209,46 @@
<H4><B>Options</B></H4> <H4><B>Options</B></H4>
<UL> <UL>
<LI><B>Create strings containing existing strings</B> - if checked, strings will be <LI><B>Create Strings Containing Existing Strings</B> - if checked, strings will be
created even if they contain existing substrings (existing strings will be cleared). The created even if they contain existing substrings (existing strings will be cleared). The
string will be created only if existing strings (a) are wholly contained within the string will be created only if existing strings (a) are wholly contained within the
potential string, (b) do not share the same starting address as the potential string, (c) potential string, (b) do not share the same starting address as the potential string, (c)
share the same ending address as the potential string, and (d) are the same datatype as share the same ending address as the potential string, and (d) are the same datatype as
the potential string to be created).</LI> the potential string to be created).</LI>
<LI><B>Create strings containing references</B> - if checked, strings that contain, but <LI><B>Create Strings Containing References</B> - if checked, strings that contain, but
do not start with, one or more references will be created.</LI> do not start with, one or more references will be created.</LI>
<LI><B>Force model reload</B> - if checked, forces the model to be reloaded every time <LI><B>Force Model Reload</B> - if checked, forces the model to be reloaded every time
the analyzer is run (in cases where the user wishes to see the effect of changing a model the analyzer is run (in cases where the user wishes to see the effect of changing a model
without restarting Ghidra).</LI> without restarting Ghidra).</LI>
<LI><B>Minimum string length</B> - specifies the smallest number of characters in a <LI><B>Minimum String Length</B> - specifies the smallest number of characters in a
string for it to be considered a valid string. For this analyzer, null termination string for it to be considered a valid string. For this analyzer, null termination
characters are ignored for the purposes of counting characters. Note that smaller numbers characters are ignored for the purposes of counting characters. Note that smaller numbers
will result in a larger number of false positives. String length must be at least 4.</LI> will result in a larger number of false positives. String length must be at least 4.</LI>
<LI><B>Model file</B> - Specifies the model file built using the BuildStringModels class <LI><B>Model File</B> - Specifies the model file built using the BuildStringModels class
(default is 'StringModel.sng'). Note that the location of the model file does not need to (default is 'StringModel.sng'). Note that the location of the model file does not need to
be specified, as models should always be placed in the be specified, as models should always be placed in the
'Ghidra/Features/Base/data/stringngrams' directory.</LI> <CODE CLASS="path">&lt;GHIDRA_INSTALL_DIR&gt;/Ghidra/Features/Base/data/stringngrams/</CODE> directory.</LI>
<LI><B>Require null termination for string</B> - if checked, only null-terminated strings <LI><B>Require Null Termination for String</B> - if checked, only null-terminated strings
are created.</LI> are created.</LI>
<LI><B>Search only in accessible memory blocks</B> - if checked, searches only in memory <LI><B>Search Only in Accessible Memory Blocks</B> - if checked, searches only in memory
blocks that have at least one of the Read (R), Write (W), or Execute (X) permissions set blocks that have at least one of the Read (R), Write (W), or Execute (X) permissions set
to true. Enabling this option ensures strings are not created in areas such as overlays to true. Enabling this option ensures strings are not created in areas such as overlays
or debug sections.</LI> or debug sections.</LI>
<LI><B>String end alignment</B> - specifies the byte alignment requirement for the end of <LI><B>String End Alignment</B> - specifies the byte alignment requirement for the end of
the string. An alignment of 1 means the string can end at any address. Alignments greater the string. An alignment of 1 means the string can end at any address. Alignments greater
than 1 require that (a) the 'require null termination' option be enabled, and (b) if the than 1 require that (a) the 'require null termination' option be enabled, and (b) if the
null-terminated string does not end at an aligned boundary, that there exist enough null-terminated string does not end at an aligned boundary, that there exist enough
trailing '0' bytes following the string to allow alignment. If neither (a) nor (b) apply, trailing '0' bytes following the string to allow alignment. If neither (a) nor (b) apply,
end alignment is not enforced.</LI> end alignment is not enforced.</LI>
<LI><B>String start alignment</B> - specifies the byte alignment requirement for the <LI><B>String Start Alignment</B> - specifies the byte alignment requirement for the
start of the string. An alignment of 1 means that strings can start at any address. An start of the string. An alignment of 1 means that strings can start at any address. An
alignment of 2 means that strings must start on an even address. An alignment of 4 means alignment of 2 means that strings must start on an even address. An alignment of 4 means
that strings must start on an address that is a multiple of 4.</LI> that strings must start on an address that is a multiple of 4.</LI>
@ -344,7 +343,100 @@
name and create a new primary symbol for the demangled name. It will also assign the name and create a new primary symbol for the demangled name. It will also assign the
appropriate datatypes to the parameters and return type.</P> appropriate datatypes to the parameters and return type.</P>
<P><U>Started By:</U> New defined functions</P> <P>
The default demangler options are:
<TABLE BORDER="1">
<TR>
<TH WIDTH="25%">Name</TH>
<TH WIDTH="75%">Description</TH>
</TR>
<TR>
<TD>Apply Function Signatures
</TD>
<TD>
Apply any recovered function signature type information
in addition to the function name
</TD>
</TR>
<TR>
<TD>Only Demangle Known Mangled Symbols
</TD>
<TD>
Only demangle symbols that follow known compiler mangling patterns.
Leaving this option off may cause non-mangled symbols to get demangled.
</TD>
</TR>
</TABLE>
</P>
<P><A name="Gnu_Demangler_Options">
<BR>
<BR>
<B>The GNU Demangler</B> adds the following analysis options:
<BLOCKQUOTE>
<P>
<U><B>Use Deprecated Demangler</B></U> -
By default, GCC symbols will be demangled using the most up-to-date demangler
that Ghidra contains (<B>version 2.33.1</B> as of this writing). Turning this
option on will also invoke the now deprecated previous version of the demangler
(<B>version 2.24</B>) if the preferred demangler cannot demangle a given symbol.
</P>
<P>
Support for older demangling styles was removed in <CODE>c++filt (v2.32)</CODE>.
Specifically, the following formats are no longer supported:
<CODE>Lucid, ARM, HP, and EDG</CODE>. To use these formats, you must enable
usage of the deprecated demangler, which is <B>version 2.24</B>. Further, you
may have to pass the required external demangler options using the Ghidra
option below.
</P>
<P>
<U><B>Use External Demangler Options</B></U> -
This allows users to pass settings to the demangler. As an example, you can enter
in this Ghidra option text field the following text to use the <CODE>rust</CODE>
format: <CODE>-s rust</CODE>. This is not needed for
normal operation. To see a full list of supported options, query each demangler
directly using the <CODE>--help</CODE> switch.
</P>
<P>
The GNU demanglers can be found at:
<CODE CLASS="path">
&lt;GHIDRA_INSTALL_DIR&gt;/GPL/DemanglerGnu/build/os/&lt;OS&gt;/
</CODE><BR>
</P>
<BLOCKQUOTE>
<P>
The available programs are:
<UL>
<LI><CODE>demangler_gnu_v2_33_1</CODE></LI>
<LI><CODE>demangler_gnu_v2_24</CODE></LI>
</UL>
</P>
<P style="background-color: #FFF0E0;">
<IMG SRC="../../shared/warning.png" />When using an external GNU demangler,
please understand the risks associated with using that version of the
software. The <CODE>demangler_gnu_v2_24</CODE> version of the
demangler is a modified version of GNU's <CODE>c++filt (v2.24)</CODE>. The
original version has known vulnerabilities, some of which have been
mitigated in the version created for Ghidra. Use caution when enabling this
feature.
</P>
</BLOCKQUOTE>
<P>
<IMG SRC="../../shared/tip.png" />The Demangler Analyzer is designed to be extensible.
You can extend <CODE>ghidra.app.plugin.core.analysis.AbstractDemanglerAnalyzer</CODE>
to add your demangler analyzer callback. This allows you to precisely control
which demanglers get called, as well as which options are used.
</P>
</BLOCKQUOTE>
<P STYLE="margin-top: 30px;"><U>Started By:</U> New defined functions</P>
</BLOCKQUOTE> </BLOCKQUOTE>
<H3><A name="Auto_Analysis_Option_Byte"></A>Entry Point Analyzer</H3> <H3><A name="Auto_Analysis_Option_Byte"></A>Entry Point Analyzer</H3>

View file

@ -72,7 +72,7 @@ public class DemanglerCmd extends BackgroundCommand {
private boolean doDemangle(Demangler demangler, Program program, TaskMonitor monitor) { private boolean doDemangle(Demangler demangler, Program program, TaskMonitor monitor) {
try { try {
demangledObject = demangler.demangle(mangled, options.demangleOnlyKnownPatterns()); demangledObject = demangler.demangle(mangled, options);
} }
catch (DemangledException e) { catch (DemangledException e) {
if (e.isInvalidMangledName()) { if (e.isInvalidMangledName()) {

View file

@ -0,0 +1,243 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.analysis;
import ghidra.app.services.*;
import ghidra.app.util.demangler.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
/**
* The base demangler analyzer. Implementations of this analyzer will attempt to demangle
* symbols in the binary being analyzed.
*
* <P>Default implementations of this class exist for Microsoft and GNU. These two analyzers will
* only be enabled when the program being analyzed has an architecture that fits each respective
* analyzer. Users can subclass this analyzer to easily control the demangling behavior from
* the analyzer UI.
*
* <P>This analyzer will call each implementation's
* {@link #doDemangle(String, DemanglerOptions, MessageLog)} method for each symbol.
* See the various protected methods of this class for points at which behavior can be overridden.
*
*/
public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
public AbstractDemanglerAnalyzer(String name, String description) {
super(name, description, AnalyzerType.BYTE_ANALYZER);
setPriority(AnalysisPriority.DATA_TYPE_PROPOGATION.before().before().before());
}
@Override
public boolean canAnalyze(Program program) {
// override this to control program-specific enablement
return true;
}
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
DemanglerOptions options = getOptions();
if (!validateOptions(options, log)) {
log.error(getName(), "Invalid demangler options--cannot demangle");
return false;
}
monitor.initialize(100);
SymbolTable symbolTable = program.getSymbolTable();
SymbolIterator it = symbolTable.getPrimarySymbolIterator(set, true);
while (it.hasNext()) {
monitor.checkCanceled();
Symbol symbol = it.next();
if (skipSymbol(symbol)) {
continue;
}
Address address = symbol.getAddress();
String mangled = cleanSymbol(address, symbol.getName());
DemangledObject demangled = demangle(mangled, options, log);
if (demangled != null) {
apply(program, address, demangled, options, log, monitor);
}
Address min = set.getMinAddress();
Address max = set.getMaxAddress();
int distance = (int) (address.getOffset() - min.getOffset());
int percent = (int) ((distance / max.getOffset()) * 100);
monitor.setProgress(percent);
}
return true;
}
/**
* The implementation-specific demangling callback
*
* @param mangled the mangled string
* @param options the demangler options
* @param log the error log
* @return the demangled object; null if demangling was unsuccessful
* @throws DemangledException if there is a problem demangling or building the result
*/
protected abstract DemangledObject doDemangle(String mangled, DemanglerOptions options,
MessageLog log) throws DemangledException;
/**
* Called before each analysis request to ensure that the current options (which may have
* user-defined input) will work with the current demangler
*
* @param options the current options in use
* @param log the error log into which error message can be written
* @return true if valid
*/
protected boolean validateOptions(DemanglerOptions options, MessageLog log) {
// override to validate custom options for a particular demangler
return true;
}
/**
* True if this analyzer should <b>not</b> attempt to demangle the given symbol
*
* @param symbol the symbol
* @return true to skip the symbol
*/
protected boolean skipSymbol(Symbol symbol) {
if (symbol.getSource() == SourceType.DEFAULT) {
return true;
}
// Only demangle global or external symbols when directly parented to a Library namespace
Namespace parentNamespace = symbol.getParentNamespace();
if (symbol.isExternal()) {
if (!(parentNamespace instanceof Library)) {
return true;
}
}
else if (!parentNamespace.isGlobal()) {
return true;
}
// Someone has already added arguments or return to the function signature
if (symbol.getSymbolType() == SymbolType.FUNCTION) {
Function function = (Function) symbol.getObject();
if (function.getSignatureSource() != SourceType.DEFAULT) {
return true;
}
}
return false;
}
/**
* Creates the options for the demangler used by implementations of this analyzer. This will
* be called before each {@link #added(Program, AddressSetView, TaskMonitor, MessageLog)}
* call processes symbols.
*
* @return the options
*/
protected DemanglerOptions getOptions() {
// note: these can be stored in the analyzer subclass and updated when the
// analysis options change
DemanglerOptions options = new DemanglerOptions();
options.setApplySignature(true);
options.setDoDisassembly(true);
options.setDemangleOnlyKnownPatterns(false);
return options;
}
/**
* This calss's default demangle method. This may be overridden to change how errors are
* handled.
*
* @param mangled the mangled string
* @param options the demangler options
* @param log the error log
* @return the demangled object; null if unsuccessful
*/
protected DemangledObject demangle(String mangled, DemanglerOptions options,
MessageLog log) {
DemangledObject demangled = null;
try {
demangled = doDemangle(mangled, options, log);
}
catch (Throwable e) {
if (e instanceof DemangledException) {
if (((DemangledException) e).isInvalidMangledName()) {
//ignore invalid names, consider as not an error
return null;
}
}
log.appendMsg(getName(),
"Unable to demangle symbol: " + mangled + ". Message: " + e.getMessage());
return null;
}
return demangled;
}
/**
* Applies the given demangled object to the program
*
* @param program the program
* @param address the apply address
* @param demangled the demangled object
* @param options the options used during the apply
* @param log the error log
* @param monitor the task monitor
*/
protected void apply(Program program, Address address, DemangledObject demangled,
DemanglerOptions options, MessageLog log, TaskMonitor monitor) {
String errorMessage = null;
try {
if (demangled.applyTo(program, address, options, monitor)) {
return;
}
}
catch (Exception e) {
String message = e.getMessage();
if (message == null) {
message = "";
}
errorMessage = "\n" + e.getClass().getSimpleName() + ' ' + message;
}
String failMessage = " (" + getName() + "/" + demangled.getClass().getName() + ")";
if (errorMessage != null) {
failMessage += errorMessage;
}
log.appendMsg(getName(),
"Failed to apply mangled symbol at " + address + "; name: " +
demangled.getMangledName() + failMessage);
}
protected String cleanSymbol(Address address, String name) {
return SymbolUtilities.getCleanSymbolName(name, address);
}
}

View file

@ -60,7 +60,7 @@ public class AnalysisOptionsDialog extends DialogComponentProvider implements
setOkButtonText("Analyze"); setOkButtonText("Analyze");
okButton.setMnemonic('A'); okButton.setMnemonic('A');
setOkEnabled(true); setOkEnabled(true);
setPreferredSize(800, 400); setPreferredSize(1000, 600);
setRememberSize(true); setRememberSize(true);
} }
@ -75,7 +75,7 @@ public class AnalysisOptionsDialog extends DialogComponentProvider implements
// analysis panel has finished being constructed, so protect against // analysis panel has finished being constructed, so protect against
// that before calling the update method. // that before calling the update method.
if (panel != null) { if (panel != null) {
panel.updateOptionForAllPrograms(evt.getPropertyName(), (Boolean)evt.getNewValue()); panel.updateOptionForAllPrograms(evt.getPropertyName(), (Boolean) evt.getNewValue());
} }
} }

View file

@ -16,20 +16,18 @@
package ghidra.app.plugin.core.analysis; package ghidra.app.plugin.core.analysis;
import java.awt.*; import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.*; import java.beans.*;
import java.util.*; import java.util.*;
import java.util.List; import java.util.List;
import javax.swing.*; import javax.swing.*;
import javax.swing.border.Border; import javax.swing.border.Border;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.*; import javax.swing.table.*;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import docking.help.Help;
import docking.help.HelpService;
import docking.options.editor.GenericOptionsComponent; import docking.options.editor.GenericOptionsComponent;
import docking.widgets.OptionDialog; import docking.widgets.OptionDialog;
import docking.widgets.label.GLabel; import docking.widgets.label.GLabel;
@ -39,11 +37,11 @@ import ghidra.app.services.Analyzer;
import ghidra.framework.options.*; import ghidra.framework.options.*;
import ghidra.program.model.listing.Program; import ghidra.program.model.listing.Program;
import ghidra.util.ColorUtils; import ghidra.util.ColorUtils;
import ghidra.util.HelpLocation;
import ghidra.util.exception.AssertException; import ghidra.util.exception.AssertException;
import ghidra.util.layout.VerticalLayout; import ghidra.util.layout.VerticalLayout;
class AnalysisPanel extends JPanel implements PropertyChangeListener { class AnalysisPanel extends JPanel implements PropertyChangeListener {
private static final long serialVersionUID = 1L;
public static final String PROTOTYPE = " (Prototype)"; public static final String PROTOTYPE = " (Prototype)";
@ -132,12 +130,7 @@ class AnalysisPanel extends JPanel implements PropertyChangeListener {
AutoAnalysisManager manager = AutoAnalysisManager.getAnalysisManager(programs.get(0)); AutoAnalysisManager manager = AutoAnalysisManager.getAnalysisManager(programs.get(0));
List<String> propertyNames = analysisOptions.getOptionNames(); List<String> propertyNames = analysisOptions.getOptionNames();
Collections.sort(propertyNames, new Comparator<String>() { Collections.sort(propertyNames, (o1, o2) -> o1.compareToIgnoreCase(o2));
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
});
for (String analyzerName : propertyNames) { for (String analyzerName : propertyNames) {
if (analyzerName.indexOf('.') == -1) { if (analyzerName.indexOf('.') == -1) {
if (analysisOptions.getType(analyzerName) != OptionType.BOOLEAN_TYPE) { if (analysisOptions.getType(analyzerName) != OptionType.BOOLEAN_TYPE) {
@ -217,26 +210,11 @@ class AnalysisPanel extends JPanel implements PropertyChangeListener {
private JPanel buildButtonPanel() { private JPanel buildButtonPanel() {
JButton selectAllButton = new JButton("Select All"); JButton selectAllButton = new JButton("Select All");
selectAllButton.addActionListener(new ActionListener() { selectAllButton.addActionListener(e -> selectAll());
@Override
public void actionPerformed(ActionEvent e) {
selectAll();
}
});
JButton deselectAllButton = new JButton("Deselect All"); JButton deselectAllButton = new JButton("Deselect All");
deselectAllButton.addActionListener(new ActionListener() { deselectAllButton.addActionListener(e -> deselectAll());
@Override
public void actionPerformed(ActionEvent e) {
deselectAll();
}
});
JButton restoreDefaultsButton = new JButton("Restore Defaults"); JButton restoreDefaultsButton = new JButton("Restore Defaults");
restoreDefaultsButton.addActionListener(new ActionListener() { restoreDefaultsButton.addActionListener(e -> restoreDefaults());
@Override
public void actionPerformed(ActionEvent e) {
restoreDefaults();
}
});
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT)); JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
buttonPanel.add(selectAllButton); buttonPanel.add(selectAllButton);
buttonPanel.add(deselectAllButton); buttonPanel.add(deselectAllButton);
@ -343,25 +321,22 @@ class AnalysisPanel extends JPanel implements PropertyChangeListener {
private void buildTable() { private void buildTable() {
table = new GTable(model); table = new GTable(model);
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
table.getSelectionModel().addListSelectionListener(new ListSelectionListener() { table.getSelectionModel().addListSelectionListener(e -> {
@Override if (e.getValueIsAdjusting()) {
public void valueChanged(ListSelectionEvent e) { return;
if (e.getValueIsAdjusting()) {
return;
}
ListSelectionModel lsm = (ListSelectionModel) e.getSource();
int selectedRow = lsm.getMinSelectionIndex();
if (selectedRow == -1) {//TODO
analyzerOptionsPanel.removeAll();
analyzerOptionsPanel.validate();
analyzerOptionsPanel.repaint();
descriptionComponent.setText("");
return;
}
String analyzerName = analyzerNames.get(selectedRow);
setAnalyzerSelected(analyzerName);
} }
ListSelectionModel lsm = (ListSelectionModel) e.getSource();
int selectedRow = lsm.getMinSelectionIndex();
if (selectedRow == -1) {//TODO
analyzerOptionsPanel.removeAll();
analyzerOptionsPanel.validate();
analyzerOptionsPanel.repaint();
descriptionComponent.setText("");
return;
}
String analyzerName = analyzerNames.get(selectedRow);
setAnalyzerSelected(analyzerName);
}); });
} }
@ -532,6 +507,8 @@ class AnalysisPanel extends JPanel implements PropertyChangeListener {
noOptionsPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5)); noOptionsPanel.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 5));
noOptionsPanel.add(new GLabel("No options available.")); noOptionsPanel.add(new GLabel("No options available."));
HelpService help = Help.getHelpService();
for (Options optionsGroup : optionGroups) { for (Options optionsGroup : optionGroups) {
String analyzerName = optionsGroup.getName(); String analyzerName = optionsGroup.getName();
@ -550,10 +527,18 @@ class AnalysisPanel extends JPanel implements PropertyChangeListener {
List<GenericOptionsComponent> optionComponents = new ArrayList<>(); List<GenericOptionsComponent> optionComponents = new ArrayList<>();
for (String childOptionName : optionNames) { for (String childOptionName : optionNames) {
EditorState childState = EditorState childState =
editorStateFactory.getEditorState(optionsGroup, childOptionName, this); editorStateFactory.getEditorState(optionsGroup, childOptionName, this);
GenericOptionsComponent comp = GenericOptionsComponent comp =
GenericOptionsComponent.createOptionComponent(childState); GenericOptionsComponent.createOptionComponent(childState);
HelpLocation helpLoc = analysisOptions
.getHelpLocation(analyzerName + Options.DELIMITER_STRING + childOptionName);
if (helpLoc != null) {
help.registerHelp(comp, helpLoc);
}
optionsContainer.add(comp); optionsContainer.add(comp);
optionComponents.add(comp); optionComponents.add(comp);
analyzerManagedComponentsMap.get(analyzerName).add(comp); analyzerManagedComponentsMap.get(analyzerName).add(comp);

View file

@ -1,138 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.analysis;
import ghidra.app.cmd.label.DemanglerCmd;
import ghidra.app.services.*;
import ghidra.app.util.demangler.DemanglerOptions;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.*;
import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor;
public class DemanglerAnalyzer extends AbstractAnalyzer {
private static final String NAME = "Demangler";
private static final String DESCRIPTION =
"After a function is created, this analyzer will attempt to demangle " +
"the name and apply datatypes to parameters.";
private static final String OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS =
"Only Demangle Known Mangled Symbols";
private static final String OPTION_DESCRIPTION_USE_KNOWN_PATTERNS =
"Only demangle " + "symbols that follow known compiler mangling patterns. " +
"Leaving this option off may cause non-mangled symbols to get demangled.";
private final static String OPTION_NAME_COMMIT_SIGNATURE = "Commit Function Signatures";
private static final String OPTION_DESCRIPTION_COMMIT_SIGNATURE =
"Apply any recovered function signature, in addition to the function name";
private boolean doSignatureEnabled = true;
private boolean demangleAllSymbols = false;
public DemanglerAnalyzer() {
super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER);
setPriority(AnalysisPriority.DATA_TYPE_PROPOGATION.before().before().before());
setDefaultEnablement(true);
}
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException {
SymbolTable symbolTable = program.getSymbolTable();
int progress = 0;
monitor.initialize(symbolTable.getNumSymbols());
monitor.setShowProgressValue(false);
SymbolIterator symiter = symbolTable.getPrimarySymbolIterator(set, true);
while (symiter.hasNext()) {
monitor.checkCanceled();
Symbol symbol = symiter.next();
Address address = symbol.getAddress();
if (address.compareTo(set.getMaxAddress()) > 0) {
break;
}
if (symbol.getSource() == SourceType.DEFAULT) {
continue;
}
// Only demangle global memory symbols or external
// symbols directly parented to a Library namespace
Namespace parentNamespace = symbol.getParentNamespace();
if (symbol.isExternal()) {
if (!(parentNamespace instanceof Library)) {
continue;
}
}
else if (!parentNamespace.isGlobal()) {
continue;
}
// Someone has already added arguments or return to the function
// signature.
if (symbol.getSymbolType() == SymbolType.FUNCTION) {
Function function = (Function) symbol.getObject();
if (function.getSignatureSource() != SourceType.DEFAULT) {
continue;
}
}
// retrieve symbol count each time, as the number of symbols changes while we are working
int count = symbolTable.getNumSymbols();
monitor.setMaximum(count);
monitor.setProgress((int) ((progress++ / (double) count) * count));
DemanglerOptions options = new DemanglerOptions();
options.setDoDisassembly(true);
options.setApplySignature(doSignatureEnabled);
options.setDemangleOnlyKnownPatterns(demangleAllSymbols);
DemanglerCmd cmd = new DemanglerCmd(address, symbol.getName(), options);
if (!cmd.applyTo(program)) {
String message = cmd.getStatusMsg();
if (message != null) {
log.appendMsg(cmd.getName(), message);
log.setStatus(message);
}
}
}
monitor.setShowProgressValue(true);
return true;
}
@Override
public void registerOptions(Options options, Program program) {
options.registerOption(OPTION_NAME_COMMIT_SIGNATURE, doSignatureEnabled, null,
OPTION_DESCRIPTION_COMMIT_SIGNATURE);
options.registerOption(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, false, null,
OPTION_DESCRIPTION_USE_KNOWN_PATTERNS);
}
@Override
public void optionsChanged(Options options, Program program) {
doSignatureEnabled = options.getBoolean(OPTION_NAME_COMMIT_SIGNATURE, doSignatureEnabled);
demangleAllSymbols =
options.getBoolean(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleAllSymbols);
}
}

View file

@ -49,7 +49,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
"analyzer was disabled or not present."; "analyzer was disabled or not present.";
private final static String OPTION_FUNCTION_NONRETURN_THRESHOLD = private final static String OPTION_FUNCTION_NONRETURN_THRESHOLD =
"Function non-return threshold"; "Function Non-return Threshold";
private static final String OPTION_DESCRIPTION_FUNCTION_NONRETURN_THRESHOLD = private static final String OPTION_DESCRIPTION_FUNCTION_NONRETURN_THRESHOLD =
"Enter the number of indications for a given function before it is considered non-returning."; "Enter the number of indications for a given function before it is considered non-returning.";
@ -60,12 +60,12 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
private static final String OPTION_NAME_REPAIR_DAMAGE = "Repair Flow Damage"; private static final String OPTION_NAME_REPAIR_DAMAGE = "Repair Flow Damage";
private static final String OPTION_DESCRIPTION_REPAIR_DAMAGE = private static final String OPTION_DESCRIPTION_REPAIR_DAMAGE =
"If checked, repair any flow after a call to found non-returning functions."; "Signals to repair any flow after a call to found non-returning functions.";
private static final boolean OPTION_DEFAULT_REPAIR_DAMAGE_ENABLED = true; private static final boolean OPTION_DEFAULT_REPAIR_DAMAGE_ENABLED = true;
private static final String OPTION_NAME_CREATE_BOOKMARKS = "Create Analysis Bookmarks"; private static final String OPTION_NAME_CREATE_BOOKMARKS = "Create Analysis Bookmarks";
private static final String OPTION_DESCRIPTION_CREATE_BOOKMARKS = private static final String OPTION_DESCRIPTION_CREATE_BOOKMARKS =
"If checked, an analysis bookmark will created on each function marked as non-returning."; "Signals to create an analysis bookmark on each function marked as non-returning.";
private static final boolean OPTION_DEFAULT_CREATE_BOOKMARKS_ENABLED = true; private static final boolean OPTION_DEFAULT_CREATE_BOOKMARKS_ENABLED = true;
private boolean repairDamageEnabled = OPTION_DEFAULT_REPAIR_DAMAGE_ENABLED; private boolean repairDamageEnabled = OPTION_DEFAULT_REPAIR_DAMAGE_ENABLED;
@ -164,7 +164,8 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
// entries including data flow referenced from instructions will be repaired // entries including data flow referenced from instructions will be repaired
ClearFlowAndRepairCmd cmd = new ClearFlowAndRepairCmd(clearInstSet, protectedSet, true, false, true); ClearFlowAndRepairCmd cmd =
new ClearFlowAndRepairCmd(clearInstSet, protectedSet, true, false, true);
cmd.applyTo(program, monitor); cmd.applyTo(program, monitor);
} }
@ -315,7 +316,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
boolean hadSuspiciousFunctions = false; boolean hadSuspiciousFunctions = false;
AddressIterator refIter = AddressIterator refIter =
cp.getReferenceManager().getReferenceSourceIterator(checkSet, true); cp.getReferenceManager().getReferenceSourceIterator(checkSet, true);
for (Address address : refIter) { for (Address address : refIter) {
monitor.checkCanceled(); monitor.checkCanceled();
@ -364,7 +365,8 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
continue; continue;
} }
Instruction oinst = cp.getListing().getInstructionAt(fromAddress); Instruction oinst = cp.getListing().getInstructionAt(fromAddress);
if ( oinst == null || !checkNonReturningIndicators(oinst, noReturnSet, blockModel)) { if (oinst == null ||
!checkNonReturningIndicators(oinst, noReturnSet, blockModel)) {
continue; continue;
} }
@ -393,7 +395,8 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
return hadSuspiciousFunctions; return hadSuspiciousFunctions;
} }
private boolean targetOnlyCallsNoReturn(Program cp, Address target, AddressSet noReturnSet) throws CancelledException { private boolean targetOnlyCallsNoReturn(Program cp, Address target, AddressSet noReturnSet)
throws CancelledException {
SimpleBlockModel model = new SimpleBlockModel(cp); SimpleBlockModel model = new SimpleBlockModel(cp);
@ -402,7 +405,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
// if hit call, check noReturn, if is stop following // if hit call, check noReturn, if is stop following
// if hit place that is called, then stop, and return no-good // if hit place that is called, then stop, and return no-good
Stack<Address> todo = new Stack<Address>(); Stack<Address> todo = new Stack<>();
todo.push(target); todo.push(target);
AddressSet visited = new AddressSet(); AddressSet visited = new AddressSet();
boolean hitNoReturn = false; boolean hitNoReturn = false;
@ -491,7 +494,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
// get the address of the next function after this instruction // get the address of the next function after this instruction
Address nextFuncAddr = null; Address nextFuncAddr = null;
if (fallThru != null) { if (fallThru != null) {
FunctionIterator functions = program.getFunctionManager().getFunctions(fallThru,true); FunctionIterator functions = program.getFunctionManager().getFunctions(fallThru, true);
if (functions.hasNext()) { if (functions.hasNext()) {
nextFuncAddr = functions.next().getEntryPoint(); nextFuncAddr = functions.next().getEntryPoint();
} }
@ -518,7 +521,8 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
/* check for codeblock containing a function */ /* check for codeblock containing a function */
if (nextFuncAddr != null && block.contains(nextFuncAddr)) { if (nextFuncAddr != null && block.contains(nextFuncAddr)) {
NoReturnLocations location = NoReturnLocations location =
new NoReturnLocations(target, fallThru, "Function defined in instruction after call"); new NoReturnLocations(target, fallThru,
"Function defined in instruction after call");
reasonList.add(location); reasonList.add(location);
return true; return true;
} }
@ -598,8 +602,9 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
protected void fixCallingFunctionBody(Program cp, Address entry) throws CancelledException { protected void fixCallingFunctionBody(Program cp, Address entry) throws CancelledException {
if (createBookmarksEnabled) { if (createBookmarksEnabled) {
cp.getBookmarkManager().setBookmark(entry, BookmarkType.ANALYSIS, cp.getBookmarkManager()
"Non-Returning Function", "Non-Returning Function Found"); .setBookmark(entry, BookmarkType.ANALYSIS,
"Non-Returning Function", "Non-Returning Function Found");
} }
AddressSet fixedSet = new AddressSet(); AddressSet fixedSet = new AddressSet();
@ -673,12 +678,12 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
// must do an operation, or assign to non-unique // must do an operation, or assign to non-unique
for (PcodeOp pCode : pcode) { for (PcodeOp pCode : pcode) {
int opcode = pCode.getOpcode(); int opcode = pCode.getOpcode();
switch(opcode) { switch (opcode) {
case PcodeOp.LOAD: case PcodeOp.LOAD:
case PcodeOp.STORE: case PcodeOp.STORE:
case PcodeOp.CALLOTHER: case PcodeOp.CALLOTHER:
case PcodeOp.SEGMENTOP: case PcodeOp.SEGMENTOP:
return addr; return addr;
} }
Varnode output = pCode.getOutput(); Varnode output = pCode.getOutput();
if (output != null && !output.isUnique()) { if (output != null && !output.isUnique()) {
@ -710,14 +715,14 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
@Override @Override
public void registerOptions(Options options, Program prog) { public void registerOptions(Options options, Program prog) {
HelpLocation helpLocation = new HelpLocation("AutoAnalysisPlugin", HelpLocation helpLocation = new HelpLocation("AutoAnalysisPlugin",
"Auto_Analysis_Option_Instruction" + getAnalysisType()); "Auto_Analysis_Option_Instructions");
options.registerOption(OPTION_FUNCTION_NONRETURN_THRESHOLD, options.registerOption(OPTION_FUNCTION_NONRETURN_THRESHOLD,
OPTION_DEFAULT_EVIDENCE_THRESHOLD, helpLocation, OPTION_DEFAULT_EVIDENCE_THRESHOLD, helpLocation,
OPTION_DESCRIPTION_FUNCTION_NONRETURN_THRESHOLD); OPTION_DESCRIPTION_FUNCTION_NONRETURN_THRESHOLD);
options.registerOption(OPTION_NAME_REPAIR_DAMAGE, repairDamageEnabled, null, options.registerOption(OPTION_NAME_REPAIR_DAMAGE, repairDamageEnabled, null,
OPTION_DESCRIPTION_REPAIR_DAMAGE); OPTION_DESCRIPTION_REPAIR_DAMAGE);
options.registerOption(OPTION_NAME_CREATE_BOOKMARKS, createBookmarksEnabled, null, options.registerOption(OPTION_NAME_CREATE_BOOKMARKS, createBookmarksEnabled, null,
OPTION_DESCRIPTION_CREATE_BOOKMARKS); OPTION_DESCRIPTION_CREATE_BOOKMARKS);
@ -731,7 +736,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
options.getInt(OPTION_FUNCTION_NONRETURN_THRESHOLD, OPTION_DEFAULT_EVIDENCE_THRESHOLD); options.getInt(OPTION_FUNCTION_NONRETURN_THRESHOLD, OPTION_DEFAULT_EVIDENCE_THRESHOLD);
repairDamageEnabled = repairDamageEnabled =
options.getBoolean(OPTION_NAME_REPAIR_DAMAGE, repairDamageEnabled); options.getBoolean(OPTION_NAME_REPAIR_DAMAGE, repairDamageEnabled);
createBookmarksEnabled = createBookmarksEnabled =
options.getBoolean(OPTION_NAME_CREATE_BOOKMARKS, createBookmarksEnabled); options.getBoolean(OPTION_NAME_CREATE_BOOKMARKS, createBookmarksEnabled);

View file

@ -27,57 +27,23 @@ import ghidra.app.cmd.function.CreateFunctionCmd;
import ghidra.app.cmd.function.CreateThunkFunctionCmd; import ghidra.app.cmd.function.CreateThunkFunctionCmd;
import ghidra.app.plugin.core.disassembler.AddressTable; import ghidra.app.plugin.core.disassembler.AddressTable;
import ghidra.app.plugin.core.function.FunctionAnalyzer; import ghidra.app.plugin.core.function.FunctionAnalyzer;
import ghidra.app.services.AbstractAnalyzer; import ghidra.app.services.*;
import ghidra.app.services.AnalysisPriority;
import ghidra.app.services.AnalyzerType;
import ghidra.app.util.PseudoDisassembler; import ghidra.app.util.PseudoDisassembler;
import ghidra.app.util.importer.MessageLog; import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.PeLoader; import ghidra.app.util.opinion.PeLoader;
import ghidra.framework.cmd.BackgroundCommand; import ghidra.framework.cmd.*;
import ghidra.framework.cmd.Command;
import ghidra.framework.cmd.CompoundBackgroundCommand;
import ghidra.framework.options.Options; import ghidra.framework.options.Options;
import ghidra.program.disassemble.Disassembler; import ghidra.program.disassemble.Disassembler;
import ghidra.program.model.address.Address; import ghidra.program.model.address.*;
import ghidra.program.model.address.AddressIterator; import ghidra.program.model.data.*;
import ghidra.program.model.address.AddressOutOfBoundsException;
import ghidra.program.model.address.AddressOverflowException;
import ghidra.program.model.address.AddressSet;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.address.SegmentedAddressSpace;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.FunctionDefinition;
import ghidra.program.model.data.Pointer;
import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.data.StringDataType;
import ghidra.program.model.data.Undefined;
import ghidra.program.model.lang.RegisterValue; import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.BookmarkType; import ghidra.program.model.listing.*;
import ghidra.program.model.listing.CodeUnit; import ghidra.program.model.mem.*;
import ghidra.program.model.listing.CodeUnitIterator;
import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.FlowOverride;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.FunctionManager;
import ghidra.program.model.listing.Instruction;
import ghidra.program.model.listing.Listing;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.DumbMemBufferImpl;
import ghidra.program.model.mem.Memory;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.pcode.PcodeOp; import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.Varnode; import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.reloc.RelocationTable; import ghidra.program.model.reloc.RelocationTable;
import ghidra.program.model.scalar.Scalar; import ghidra.program.model.scalar.Scalar;
import ghidra.program.model.symbol.FlowType; import ghidra.program.model.symbol.*;
import ghidra.program.model.symbol.OffsetReference;
import ghidra.program.model.symbol.RefType;
import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.ReferenceIterator;
import ghidra.program.model.symbol.SourceType;
import ghidra.program.model.symbol.Symbol;
import ghidra.util.HelpLocation; import ghidra.util.HelpLocation;
import ghidra.util.exception.CancelledException; import ghidra.util.exception.CancelledException;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
@ -328,7 +294,8 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
// New information from the thunked function (noreturn, callfixup, etc...) // New information from the thunked function (noreturn, callfixup, etc...)
// may affect callers to the function, so tell analyzers about it. // may affect callers to the function, so tell analyzers about it.
// TODO: this should be done by the Auto Thunking mechanisms... // TODO: this should be done by the Auto Thunking mechanisms...
if ((!func.isThunk() && CreateThunkFunctionCmd.isThunk(program, func))) { if ((!func.isThunk() &&
CreateThunkFunctionCmd.isThunk(program, func))) {
CreateFunctionCmd createFunctionCmd = new CreateFunctionCmd(null, CreateFunctionCmd createFunctionCmd = new CreateFunctionCmd(null,
func.getEntryPoint(), null, SourceType.ANALYSIS, false, true); func.getEntryPoint(), null, SourceType.ANALYSIS, false, true);
if (createFunctionCmd.applyTo(program)) { if (createFunctionCmd.applyTo(program)) {
@ -533,8 +500,9 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
AddressIterator foundIter = foundCodeBookmarkLocations.getAddresses(true); AddressIterator foundIter = foundCodeBookmarkLocations.getAddresses(true);
while (foundIter.hasNext()) { while (foundIter.hasNext()) {
Address target = foundIter.next(); Address target = foundIter.next();
program.getBookmarkManager().setBookmark(target, BookmarkType.ANALYSIS, program.getBookmarkManager()
"Found Code", "Found code from operand reference"); .setBookmark(target, BookmarkType.ANALYSIS,
"Found Code", "Found code from operand reference");
} }
} }
@ -622,8 +590,9 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
instr.setFlowOverride(FlowOverride.CALL_RETURN); instr.setFlowOverride(FlowOverride.CALL_RETURN);
// Get rid of any bad disassembly bookmark // Get rid of any bad disassembly bookmark
AddressSet set = new AddressSet(toAddr); AddressSet set = new AddressSet(toAddr);
program.getBookmarkManager().removeBookmarks(set, BookmarkType.ERROR, program.getBookmarkManager()
Disassembler.ERROR_BOOKMARK_CATEGORY, monitor); .removeBookmarks(set, BookmarkType.ERROR,
Disassembler.ERROR_BOOKMARK_CATEGORY, monitor);
} }
// make sure function created at destination // make sure function created at destination
@ -808,9 +777,10 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
if (lastGoodTable != null) { if (lastGoodTable != null) {
instr.removeOperandReference(opIndex, target); instr.removeOperandReference(opIndex, target);
program.getReferenceManager().addOffsetMemReference(instr.getMinAddress(), program.getReferenceManager()
lastGoodTable.getTopAddress(), -((i + 3) * entryLen), RefType.DATA, .addOffsetMemReference(instr.getMinAddress(),
SourceType.ANALYSIS, opIndex); lastGoodTable.getTopAddress(), -((i + 3) * entryLen), RefType.DATA,
SourceType.ANALYSIS, opIndex);
} }
return lastGoodTable; return lastGoodTable;
@ -1266,7 +1236,7 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
@Override @Override
public void registerOptions(Options options, Program program) { public void registerOptions(Options options, Program program) {
HelpLocation helpLocation = new HelpLocation("AutoAnalysisPlugin", HelpLocation helpLocation = new HelpLocation("AutoAnalysisPlugin",
"Auto_Analysis_Option_Instruction" + getAnalysisType()); "Auto_Analysis_Option_Instructions");
if (minimumAddressTableSize == -1) { if (minimumAddressTableSize == -1) {
calculateMinimumAddressTableSize(program); calculateMinimumAddressTableSize(program);

View file

@ -64,8 +64,7 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
@Override @Override
public void registerOptions(Options options, Program program) { public void registerOptions(Options options, Program program) {
HelpLocation helpLocation = HelpLocation helpLocation =
new HelpLocation("AutoAnalysisPlugin", "Auto_Analysis_Option_Instruction" + new HelpLocation("AutoAnalysisPlugin", "Auto_Analysis_Option_Instructions");
getAnalysisType());
options.registerOption(OPTION_NAME_RESPECT_EXECUTE_FLAG, respectExecuteFlags, helpLocation, options.registerOption(OPTION_NAME_RESPECT_EXECUTE_FLAG, respectExecuteFlags, helpLocation,
OPTION_DESCRIPTION_RESPECT_EXECUTE_FLAG); OPTION_DESCRIPTION_RESPECT_EXECUTE_FLAG);
@ -73,7 +72,8 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
@Override @Override
public void optionsChanged(Options options, Program program) { public void optionsChanged(Options options, Program program) {
respectExecuteFlags = options.getBoolean(OPTION_NAME_RESPECT_EXECUTE_FLAG, respectExecuteFlags); respectExecuteFlags =
options.getBoolean(OPTION_NAME_RESPECT_EXECUTE_FLAG, respectExecuteFlags);
} }
@Override @Override
@ -83,8 +83,8 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
monitor.initialize(addressSet.getNumAddresses()); monitor.initialize(addressSet.getNumAddresses());
Set<Address> doNowSet = new HashSet<Address>(); Set<Address> doNowSet = new HashSet<>();
Set<Address> doLaterSet = new HashSet<Address>(); Set<Address> doLaterSet = new HashSet<>();
executeSet = program.getMemory().getExecuteSet(); executeSet = program.getMemory().getExecuteSet();
@ -100,8 +100,8 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
// Someone created them as a placeholder // Someone created them as a placeholder
// Disassemble them // Disassemble them
// Remember them so the function body can be fixed later // Remember them so the function body can be fixed later
Set<Address> dummyFunctionSet = new HashSet<Address>(); Set<Address> dummyFunctionSet = new HashSet<>();
Set<Address> redoFunctionSet = new HashSet<Address>(); Set<Address> redoFunctionSet = new HashSet<>();
findDummyFunctions(program, addressSet, dummyFunctionSet, redoFunctionSet); findDummyFunctions(program, addressSet, dummyFunctionSet, redoFunctionSet);
// disassemble dummy functions now, re-create the function bodies later // disassemble dummy functions now, re-create the function bodies later
@ -157,7 +157,8 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
EntryPointAnalyzer entryPointAnalyzer = new EntryPointAnalyzer(); EntryPointAnalyzer entryPointAnalyzer = new EntryPointAnalyzer();
entryPointAnalyzer.setPriority(AnalysisPriority.REFERENCE_ANALYSIS.before()); entryPointAnalyzer.setPriority(AnalysisPriority.REFERENCE_ANALYSIS.before());
analysisManager.scheduleOneTimeAnalysis(entryPointAnalyzer, toAddressSet(doLaterSet)); analysisManager.scheduleOneTimeAnalysis(entryPointAnalyzer, toAddressSet(doLaterSet));
} else { }
else {
// came back in, just do it now // came back in, just do it now
doDisassembly(program, monitor, doLaterSet); doDisassembly(program, monitor, doLaterSet);
} }
@ -195,7 +196,7 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
private void fixDummyFunctionBodies(Program program, TaskMonitor monitor, private void fixDummyFunctionBodies(Program program, TaskMonitor monitor,
Set<Address> redoFunctionSet) throws CancelledException { Set<Address> redoFunctionSet) throws CancelledException {
Set<Address> recreateFunctionSet = new HashSet<Address>(); Set<Address> recreateFunctionSet = new HashSet<>();
for (Address entry : redoFunctionSet) { for (Address entry : redoFunctionSet) {
Function function = program.getFunctionManager().getFunctionAt(entry); Function function = program.getFunctionManager().getFunctionAt(entry);
if (function == null) { if (function == null) {
@ -219,7 +220,8 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
if (!foundNonJumpRef) { if (!foundNonJumpRef) {
// check if we have been thunked // check if we have been thunked
Address[] functionThunkAddresses = function.getFunctionThunkAddresses(); Address[] functionThunkAddresses = function.getFunctionThunkAddresses();
foundNonJumpRef = functionThunkAddresses != null && functionThunkAddresses.length != 0; foundNonJumpRef =
functionThunkAddresses != null && functionThunkAddresses.length != 0;
} }
// if found non-jump ref, or is external // if found non-jump ref, or is external
@ -232,8 +234,9 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
while (referencesTo.hasNext()) { while (referencesTo.hasNext()) {
Reference reference = referencesTo.next(); Reference reference = referencesTo.next();
Function func = Function func =
program.getFunctionManager().getFunctionContaining( program.getFunctionManager()
reference.getFromAddress()); .getFunctionContaining(
reference.getFromAddress());
if (func != null) { if (func != null) {
recreateFunctionSet.add(func.getEntryPoint()); recreateFunctionSet.add(func.getEntryPoint());
} }
@ -340,8 +343,9 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
int defaultPointerSize = program.getDefaultPointerSize(); int defaultPointerSize = program.getDefaultPointerSize();
try { try {
Data data = Data data =
program.getListing().createData(entry, program.getListing()
PointerDataType.getPointer(null, defaultPointerSize)); .createData(entry,
PointerDataType.getPointer(null, defaultPointerSize));
Object value = data.getValue(); Object value = data.getValue();
if (value instanceof Address) { if (value instanceof Address) {
Address codeLoc = (Address) value; Address codeLoc = (Address) value;
@ -401,7 +405,7 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
private void disassembleCodeMapMarkers(Program program, TaskMonitor monitor) { private void disassembleCodeMapMarkers(Program program, TaskMonitor monitor) {
AddressSetPropertyMap codeProp = program.getAddressSetPropertyMap("CodeMap"); AddressSetPropertyMap codeProp = program.getAddressSetPropertyMap("CodeMap");
if (codeProp != null) { if (codeProp != null) {
Set<Address> codeSet = new HashSet<Address>(); Set<Address> codeSet = new HashSet<>();
AddressIterator aiter = codeProp.getAddresses(); AddressIterator aiter = codeProp.getAddresses();
while (aiter.hasNext()) { while (aiter.hasNext()) {
codeSet.add(aiter.next()); codeSet.add(aiter.next());

View file

@ -41,17 +41,17 @@ public class SharedReturnAnalyzer extends AbstractAnalyzer {
"analyzer was disabled or not present."; "analyzer was disabled or not present.";
private final static String OPTION_NAME_ASSUME_CONTIGUOUS_FUNCTIONS = private final static String OPTION_NAME_ASSUME_CONTIGUOUS_FUNCTIONS =
"Assume contiguous functions only"; "Assume Contiguous Functions oOnly";
private final static String OPTION_NAME_CONSIDER_CONDITIONAL_BRANCHES_FUNCTIONS = private final static String OPTION_NAME_CONSIDER_CONDITIONAL_BRANCHES_FUNCTIONS =
"Allow conditional Jumps"; "Allow Conditional Jumps";
private static final String OPTION_DESCRIPTION_ASSUME_CONTIGUOUS_FUNCTIONS = private static final String OPTION_DESCRIPTION_ASSUME_CONTIGUOUS_FUNCTIONS =
"Select this check box to assume all function bodies are contiguous " + "Signals to assume all function bodies are contiguous " +
"and all jumps across other functions should be treated as a call-return."; "and all jumps across other functions should be treated as a call-return.";
private static final String OPTION_DESCRIPTION_CONSIDER_CONDITIONAL_BRANCHES_FUNCTIONS = private static final String OPTION_DESCRIPTION_CONSIDER_CONDITIONAL_BRANCHES_FUNCTIONS =
"Select this check box to allow conditional jumps to be consider for " + "Signals to allow conditional jumps to be consider for " +
"shared return jumps to other functions."; "shared return jumps to other functions.";
private final static boolean OPTION_DEFAULT_ASSUME_CONTIGUOUS_FUNCTIONS_ENABLED = false; private final static boolean OPTION_DEFAULT_ASSUME_CONTIGUOUS_FUNCTIONS_ENABLED = false;
@ -71,11 +71,7 @@ public class SharedReturnAnalyzer extends AbstractAnalyzer {
setSupportsOneTimeAnalysis(); setSupportsOneTimeAnalysis();
} }
/** @Override
* Called when a function has been added. Looks at address for call
* reference
* @throws CancelledException
*/
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws CancelledException { throws CancelledException {
@ -86,6 +82,7 @@ public class SharedReturnAnalyzer extends AbstractAnalyzer {
return true; return true;
} }
@Override
public boolean getDefaultEnablement(Program program) { public boolean getDefaultEnablement(Program program) {
Language language = program.getLanguage(); Language language = program.getLanguage();
@ -98,7 +95,7 @@ public class SharedReturnAnalyzer extends AbstractAnalyzer {
@Override @Override
public void registerOptions(Options options, Program program) { public void registerOptions(Options options, Program program) {
HelpLocation helpLocation = new HelpLocation("AutoAnalysisPlugin", HelpLocation helpLocation = new HelpLocation("AutoAnalysisPlugin",
"Auto_Analysis_Option_Instruction" + getAnalysisType()); "Auto_Analysis_Option_Instructions");
options.registerOption(OPTION_NAME_ASSUME_CONTIGUOUS_FUNCTIONS, options.registerOption(OPTION_NAME_ASSUME_CONTIGUOUS_FUNCTIONS,
OPTION_DEFAULT_ASSUME_CONTIGUOUS_FUNCTIONS_ENABLED, helpLocation, OPTION_DEFAULT_ASSUME_CONTIGUOUS_FUNCTIONS_ENABLED, helpLocation,

View file

@ -38,37 +38,37 @@ public class StringsAnalyzer extends AbstractAnalyzer {
"This analyzer searches for valid ASCII strings and automatically creates them in the binary."; "This analyzer searches for valid ASCII strings and automatically creates them in the binary.";
// Option Names // Option Names
private static final String MODELFILE_OPTION_NAME = "Model file"; private static final String MODELFILE_OPTION_NAME = "Model File";
private static final String MODELFILE_OPTION_DESCRIPTION = private static final String MODELFILE_OPTION_DESCRIPTION =
"Model file built using Ghidra's BuildStringModels class. Any model files for this analyzer " + "Model file built using Ghidra's BuildStringModels class. Any model files for this analyzer " +
"should be located in the Ghidra/Features/Base/data/stringngrams directory and " + "should be located in the Ghidra/Features/Base/data/stringngrams directory and " +
"end in \".sng\"."; "end in \".sng\".";
private static final String FORCE_MODEL_RELOAD_OPTION_NAME = "Force model reload"; private static final String FORCE_MODEL_RELOAD_OPTION_NAME = "Force Model Reload";
private static final String FORCE_MODEL_RELOAD_OPTION_DESCRIPTION = private static final String FORCE_MODEL_RELOAD_OPTION_DESCRIPTION =
"When checked, forces reload of model files every time the analyzer is run. When unchecked, " + "When checked, forces reload of model files every time the analyzer is run. When unchecked, " +
"model files will only be reloaded when Ghidra is restarted or when model file option " + "model files will only be reloaded when Ghidra is restarted or when model file option " +
"name is changed."; "name is changed.";
private static final String MINIMUM_STRING_LENGTH_OPTION_NAME = "Minimum string length"; private static final String MINIMUM_STRING_LENGTH_OPTION_NAME = "Minimum String Length";
private static final String MINIMUM_STRING_LENGTH_OPTION_DESCRIPTION = private static final String MINIMUM_STRING_LENGTH_OPTION_DESCRIPTION =
"The smallest number of characters in a string to be considered a valid string. " + "The smallest number of characters in a string to be considered a valid string. " +
"(Smaller numbers will give more false positives). String length must be 4 " + "(Smaller numbers will give more false positives). String length must be 4 " +
"or greater."; "or greater.";
private static final String REQUIRE_NULL_TERMINATION_OPTION_NAME = private static final String REQUIRE_NULL_TERMINATION_OPTION_NAME =
"Require null termination for string"; "Require Null Termination for String";
private static final String REQUIRE_NULL_TERMINATION_OPTION_DESCRIPTION = private static final String REQUIRE_NULL_TERMINATION_OPTION_DESCRIPTION =
"If set to true, requires all strings to end in null."; "If set to true, requires all strings to end in null.";
private static final String ALLOW_STRING_CREATION_WITH_MIDDLE_REF_NAME = private static final String ALLOW_STRING_CREATION_WITH_MIDDLE_REF_NAME =
"Create strings containing references"; "Create Strings Containing References";
private static final String ALLOW_STRING_CREATION_WITH_MIDDLE_REF_DESCRIPTION = private static final String ALLOW_STRING_CREATION_WITH_MIDDLE_REF_DESCRIPTION =
"If checked, allows a string that contains, but does not start with, one or more references" + "If checked, allows a string that contains, but does not start with, one or more references" +
" to be created."; " to be created.";
private static final String ALLOW_STRING_CREATION_WITH_EXISTING_SUBSTR_NAME = private static final String ALLOW_STRING_CREATION_WITH_EXISTING_SUBSTR_NAME =
"Create strings containing existing strings"; "Create Strings Containing Existing Strings";
private static final String ALLOW_STRING_CREATION_WITH_EXISTING_SUBSTR_DESCRIPTION = private static final String ALLOW_STRING_CREATION_WITH_EXISTING_SUBSTR_DESCRIPTION =
"If checked, allows a string to be created even if it contains existing strings (existing " + "If checked, allows a string to be created even if it contains existing strings (existing " +
"strings will be cleared). The string will be created only if existing strings (a) " + "strings will be cleared). The string will be created only if existing strings (a) " +
@ -76,7 +76,7 @@ public class StringsAnalyzer extends AbstractAnalyzer {
"address as the potential string, (c) share the same ending address as the potential " + "address as the potential string, (c) share the same ending address as the potential " +
"string, and (d) are the same datatype as the potential string."; "string, and (d) are the same datatype as the potential string.";
private static final String START_ALIGNMENT_OPTION_NAME = "String start alignment"; private static final String START_ALIGNMENT_OPTION_NAME = "String Start Alignment";
private static final String START_ALIGNMENT_OPTION_DESCRIPTION = private static final String START_ALIGNMENT_OPTION_DESCRIPTION =
"Specifies an alignment requirement for the start of the string. An alignment of 1 " + "Specifies an alignment requirement for the start of the string. An alignment of 1 " +
"means the string can start at any address. An alignment of 2 means the string " + "means the string can start at any address. An alignment of 2 means the string " +
@ -92,7 +92,7 @@ public class StringsAnalyzer extends AbstractAnalyzer {
"alignment is not enforced."; "alignment is not enforced.";
private static final String SEARCH_ONLY_ACCESSIBLE_MEM_BLOCKS_NAME = private static final String SEARCH_ONLY_ACCESSIBLE_MEM_BLOCKS_NAME =
"Search only in accessible memory blocks"; "Search Only in Accessible Memory Blocks";
private static final String SEARCH_ONLY_ACCESSIBLE_MEM_BLOCKS_DESCRIPTION = private static final String SEARCH_ONLY_ACCESSIBLE_MEM_BLOCKS_DESCRIPTION =
"If checked, this " + "If checked, this " +
"analyzer only searches in memory blocks that have at least one of the Read (R), Write " + "analyzer only searches in memory blocks that have at least one of the Read (R), Write " +

View file

@ -115,6 +115,14 @@ public abstract class DemangledObject {
return demangledName; return demangledName;
} }
/**
* Returns the original mangled name
* @return the name
*/
public String getMangledName() {
return originalMangled;
}
/** /**
* Returns the demangled name of this object. * Returns the demangled name of this object.
* NOTE: unsupported symbol characters, like whitespace, will be * NOTE: unsupported symbol characters, like whitespace, will be
@ -495,8 +503,11 @@ public abstract class DemangledObject {
List<Symbol> symbols = symbolTable.getSymbols(namespaceName, namespace); List<Symbol> symbols = symbolTable.getSymbols(namespaceName, namespace);
Symbol namespaceSymbol = Symbol namespaceSymbol =
symbols.stream().filter(s -> (s.getSymbolType() == SymbolType.NAMESPACE || symbols.stream()
s.getSymbolType() == SymbolType.CLASS)).findFirst().orElse(null); .filter(s -> (s.getSymbolType() == SymbolType.NAMESPACE ||
s.getSymbolType() == SymbolType.CLASS))
.findFirst()
.orElse(null);
if (namespaceSymbol == null) { if (namespaceSymbol == null) {
try { try {
namespace = namespace =

View file

@ -23,8 +23,52 @@ import ghidra.util.classfinder.ExtensionPoint;
* the ClassSearcher will not find them. * the ClassSearcher will not find them.
*/ */
public interface Demangler extends ExtensionPoint { public interface Demangler extends ExtensionPoint {
public boolean canDemangle(Program program); public boolean canDemangle(Program program);
/**
* Deprecated. Use {@link #demangle(String)} or
* {@link #demangle(String, DemanglerOptions)}.
*
* @param mangled the mangled string
* @param demangleOnlyKnownPatterns true signals to avoid demangling strings that do
* not fit known demangled patterns for this demangler
* @return the result
* @throws DemangledException if the string cannot be demangled
* @deprecated see above
*/
@Deprecated(since = "9.2", forRemoval = true)
public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns) public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns)
throws DemangledException; throws DemangledException;
/**
* Attempts to demangle the given string using the default options
* ({@link #createDefaultOptions()}
*
* @param mangled the mangled string
* @return the result
* @throws DemangledException if the string cannot be demangled
*/
public default DemangledObject demangle(String mangled) throws DemangledException {
return demangle(mangled, createDefaultOptions());
}
/**
* Attempts to demangle the given string using the given options
*
* @param mangled the mangled string
* @param options the options
* @return the result
* @throws DemangledException if the string cannot be demangled
*/
public DemangledObject demangle(String mangled, DemanglerOptions options)
throws DemangledException;
/**
* Creates default options for this particular demangler
* @return the options
*/
public default DemanglerOptions createDefaultOptions() {
return new DemanglerOptions();
}
} }

View file

@ -92,4 +92,14 @@ public class DemanglerOptions {
this.demangleOnlyKnownPatterns = demangleOnlyKnownPatterns; this.demangleOnlyKnownPatterns = demangleOnlyKnownPatterns;
} }
@Override
public String toString() {
//@formatter:off
return "{\n" +
"\tdoDisassembly: " + doDisassembly + ",\n" +
"\tapplySignature: " + applySignature + ",\n" +
"\tdemangleOnlyKnownPatterns: " + demangleOnlyKnownPatterns + ",\n" +
"}";
//@formatter:on
}
} }

View file

@ -1,30 +0,0 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler;
public interface DemanglerParser {
/**
* Parses the output of the demangler process and converts
* it into a demangled object.
* @param mangled the original mangled string - e.g., "_ZdaPv"
* @param demangled the demangled string - e.g., "operator_delete[](void*)"
* @return a demangled object
*/
public DemangledObject parse(String mangled, String demangled);
}

View file

@ -32,7 +32,13 @@ public class DemanglerUtil {
private static final Pattern TRAILING_PARAMETER_SPACE_PATTERN = Pattern.compile("([\\(\\,]) "); private static final Pattern TRAILING_PARAMETER_SPACE_PATTERN = Pattern.compile("([\\(\\,]) ");
/** /**
* Locates all available demanglers, then it attempts to demangle. * Locates all available demanglers, then it attempts to demangle. This method will
* query all demanglers regardless of architecture.
*
* <p>This method will use only the default options for demangling. If you need to
* specify options, then you will have to call each specific demangler directly, creating
* the options specifically needed for each demangler. See
* {@link Demangler#createDefaultOptions()}.
* *
* @param mangled the mangled name * @param mangled the mangled name
* @return the demangled object or null * @return the demangled object or null
@ -41,9 +47,7 @@ public class DemanglerUtil {
List<Demangler> demanglers = getDemanglers(); List<Demangler> demanglers = getDemanglers();
for (Demangler demangler : demanglers) { for (Demangler demangler : demanglers) {
try { try {
// not sure if we should be doing all symbols, but this is what it used to do DemangledObject demangledObject = demangler.demangle(mangled);
boolean onlyKnownTypes = false;
DemangledObject demangledObject = demangler.demangle(mangled, onlyKnownTypes);
if (demangledObject != null) { if (demangledObject != null) {
return demangledObject; return demangledObject;
} }
@ -59,6 +63,11 @@ public class DemanglerUtil {
* Locates all available demanglers and checks to see if the supplied program is * Locates all available demanglers and checks to see if the supplied program is
* supported, then it attempts to demangle. * supported, then it attempts to demangle.
* *
* <p>This method will use only the default options for demangling. If you need to
* specify options, then you will have to call each specific demangler directly, creating
* the options specifically needed for each demangler. See
* {@link Demangler#createDefaultOptions()}.
*
* @param program the program containing the mangled name * @param program the program containing the mangled name
* @param mangled the mangled name * @param mangled the mangled name
* @return the demangled object or null * @return the demangled object or null
@ -71,9 +80,7 @@ public class DemanglerUtil {
continue; continue;
} }
// not sure if we should be doing all symbols, but this is what it used to do DemangledObject demangledObject = demangler.demangle(mangled);
boolean onlyKnownTypes = false;
DemangledObject demangledObject = demangler.demangle(mangled, onlyKnownTypes);
if (demangledObject != null) { if (demangledObject != null) {
return demangledObject; return demangledObject;
} }
@ -95,12 +102,14 @@ public class DemanglerUtil {
} }
/** /**
* Converts the list of names into a namespace linked list. * Converts the list of names into a namespace demangled type.
* Given names = { "A", "B", "C" }, which represents "A::B::C". * Given names = { "A", "B", "C" }, which represents "A::B::C".
* The following will be created {@literal "Namespace{A}->Namespace{B}->Namespace{C}"} * The following will be created {@literal "Namespace{A}->Namespace{B}->Namespace{C}"}
* and Namespace{C} will be returned. * and Namespace{C} will be returned.
* *
* NOTE: the list will be empty after the call. * NOTE: the list will be empty after the call.
* @param names the names to convert
* @return the newly created type
*/ */
public static DemangledType convertToNamespaces(List<String> names) { public static DemangledType convertToNamespaces(List<String> names) {
if (names.size() == 0) { if (names.size() == 0) {
@ -129,13 +138,13 @@ public class DemanglerUtil {
private static String replace(String str, Pattern spaceCleanerPattern) { private static String replace(String str, Pattern spaceCleanerPattern) {
Matcher matcher = spaceCleanerPattern.matcher(str); Matcher matcher = spaceCleanerPattern.matcher(str);
StringBuffer buf = new StringBuffer(); StringBuilder buffy = new StringBuilder();
while (matcher.find()) { while (matcher.find()) {
String captureGroup = matcher.group(1); String captureGroup = matcher.group(1);
matcher.appendReplacement(buf, captureGroup); matcher.appendReplacement(buffy, captureGroup);
} }
matcher.appendTail(buf); matcher.appendTail(buffy);
return buf.toString(); return buffy.toString();
} }
public static void setNamespace(DemangledType dt, DemangledType namespace) { public static void setNamespace(DemangledType dt, DemangledType namespace) {

View file

@ -83,11 +83,11 @@ public class NamespacePropertyEditor extends PropertyEditorSupport implements Cu
showLibraryInNamespaceCheckBox = new GCheckBox(DISPLAY_LIBRARY_IN_NAMESPACE_LABEL); showLibraryInNamespaceCheckBox = new GCheckBox(DISPLAY_LIBRARY_IN_NAMESPACE_LABEL);
showLibraryInNamespaceCheckBox.setSelected(true); showLibraryInNamespaceCheckBox.setSelected(true);
showLocalCheckBox.setToolTipText(SHOW_LIBRARY_IN_NAMESPACE_TOOLTIP); showLibraryInNamespaceCheckBox.setToolTipText(SHOW_LIBRARY_IN_NAMESPACE_TOOLTIP);
panel.add(showNonLocalCheckBox); panel.add(showNonLocalCheckBox);
panel.add(showLocalCheckBox);
panel.add(showLibraryInNamespaceCheckBox); panel.add(showLibraryInNamespaceCheckBox);
panel.add(showLocalCheckBox);
localPrefixField = localPrefixField =
createLocalPrefixTextField(LOCAL_NAMESPACE_PREFIX_LABEL, LOCAL_PREFIX_TOOLTIP, panel); createLocalPrefixTextField(LOCAL_NAMESPACE_PREFIX_LABEL, LOCAL_PREFIX_TOOLTIP, panel);
@ -169,7 +169,8 @@ public class NamespacePropertyEditor extends PropertyEditorSupport implements Cu
if (namespaceOption.isShowLocalNamespace() != showLocalCheckBox.isSelected()) { if (namespaceOption.isShowLocalNamespace() != showLocalCheckBox.isSelected()) {
showLocalCheckBox.setSelected(namespaceOption.isShowLocalNamespace()); showLocalCheckBox.setSelected(namespaceOption.isShowLocalNamespace());
} }
if (namespaceOption.isShowLibraryInNamespace() != showLibraryInNamespaceCheckBox.isSelected()) { if (namespaceOption.isShowLibraryInNamespace() != showLibraryInNamespaceCheckBox
.isSelected()) {
showLibraryInNamespaceCheckBox.setSelected(namespaceOption.isShowLibraryInNamespace()); showLibraryInNamespaceCheckBox.setSelected(namespaceOption.isShowLibraryInNamespace());
} }
if (namespaceOption.isUseLocalPrefixOverride() != useLocalPrefixCheckBox.isSelected()) { if (namespaceOption.isUseLocalPrefixOverride() != useLocalPrefixCheckBox.isSelected()) {

View file

@ -1,72 +0,0 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//@category CodeAnalysis
import ghidra.app.analyzers.LibHashDB;
import ghidra.app.script.GhidraScript;
import ghidra.framework.Application;
import ghidra.xml.NonThreadedXmlPullParserImpl;
import ghidra.xml.XmlPullParser;
import java.io.*;
import org.xml.sax.*;
public class BuildFuncDB extends GhidraScript {
@Override
protected void run() throws Exception {
//If the file is already there, it adds more function records to it. If not, it creates and populates the file.
File dbFile =
Application.getModuleDataSubDirectory("BytePatterns", "lib/db.xml").getFile(true);
LibHashDB db = new LibHashDB();
if (dbFile.exists()) {
db.restoreXml(getParser(dbFile));
}
LibHashDB dbCurrent = new LibHashDB(this.currentProgram);
db.mergeWith(dbCurrent);
FileWriter fwrite = new FileWriter(dbFile);
db.saveXml(fwrite);
fwrite.close();
return;
}
private static XmlPullParser getParser(File xmlfile) throws SAXException, IOException {
ErrorHandler handler = new ErrorHandler() {
@Override
public void warning(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void error(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}
};
XmlPullParser parser;
parser = new NonThreadedXmlPullParserImpl(xmlfile, handler, false);
return parser;
}
}

View file

@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
li { font-family:times new roman; font-size:14pt; } li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/* /*
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
td { font-family:times new roman; font-size:14pt; vertical-align: top; } td { font-family:times new roman; font-size:14pt; vertical-align: top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; } th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
code { color: black; font-family: courier new; font-size: 14pt; } /*
Code-like formatting for things such as file system paths and proper names of classes,
methods, etc. To apply this to a file path, use this syntax:
<CODE CLASS="path">...</CODE>
*/
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }

View file

@ -1,111 +0,0 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.analyzers;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
import ghidra.util.exception.CancelledException;
import ghidra.xml.XmlPullParser;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.TreeSet;
public class LibHashDB {
private TreeSet<LibraryRecord> libraries;
//Empty Constructor
public LibHashDB() {
this.libraries = new TreeSet<LibraryRecord>();
}
//Construct a DB from the current program, with a record for every function.
public LibHashDB(Program prgm) throws CancelledException {
this.libraries = new TreeSet<LibraryRecord>();
this.libraries.add(new LibraryRecord(prgm));
}
//Merge another DB into this one.
public void mergeWith(LibHashDB toMergeIn) {
this.libraries.addAll(toMergeIn.libraries);
}
//Add a library to the database.
public void addLibrary(LibraryRecord libRec) {
this.libraries.add(libRec);
return;
}
public TreeSet<FuncRecord> getRecords() {
TreeSet<FuncRecord> results = new TreeSet<FuncRecord>();
for (LibraryRecord lib : this.libraries) {
results.addAll(lib.getRecords());
}
return results;
}
//Find an entry of the database based on actual underlying function.
public ArrayList<FuncRecord> query(Function func) throws CancelledException {
FuncRecord queryHash = new FuncRecord(func);
ArrayList<FuncRecord> result = this.query(queryHash.hashValue); //Use the hash query method instead.
for (FuncRecord entry : result) {
if (entry.func == func) {
ArrayList<FuncRecord> newResult = new ArrayList<FuncRecord>();
newResult.add(entry);
return newResult;
}
}
return result; //Return all matches.
}
//Find an entry of the database based on hash. Returns all records with that hash.
public ArrayList<FuncRecord> query(Long hash) {
ArrayList<FuncRecord> result = new ArrayList<FuncRecord>(); //Set up the result.
FuncRecord temp = new FuncRecord();
temp.hashValue = hash;
for (LibraryRecord libRec : this.libraries) { //Search each library for a record matching the hash.
result.addAll(libRec.query(hash));
}
return result;
}
//DB is made up of libraries. To get a DB from a file/parser, look for the "funcDB" tag, and then pass the buck to the LibraryRecord class.
public void restoreXml(XmlPullParser parser) {
parser.start("funcDB"); //The XML tag for an entire DB.
while (parser.peek().isStart()) {
LibraryRecord libRec = new LibraryRecord();
libRec.restoreXml(parser); //Pass the buck.
this.addLibrary(libRec); //DB is a collection of library records.
}
parser.end();
return;
}
//Save DB to an XML file.
public void saveXml(Writer fwrite) throws IOException {
StringBuffer buf = new StringBuffer();
buf.append("<funcDB>\n"); //The XML tag for the entire DB.
fwrite.append(buf.toString());
for (LibraryRecord libRec : this.libraries) {
libRec.saveXml(fwrite); //Write out each library in XML.
}
fwrite.append("</funcDB>\n"); //Finish up.
return;
}
}

View file

@ -1,271 +0,0 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.analyzers;
import java.io.*;
import java.util.*;
import org.xml.sax.*;
import ghidra.app.cmd.label.*;
import ghidra.app.services.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.Application;
import ghidra.framework.cmd.Command;
import ghidra.framework.options.Options;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.listing.*;
import ghidra.program.model.symbol.*;
import ghidra.util.Msg;
import ghidra.util.task.TaskMonitor;
import ghidra.xml.NonThreadedXmlPullParserImpl;
import ghidra.xml.XmlPullParser;
public class LibraryHashAnalyzer extends AbstractAnalyzer {
private static final String NAME = "Library Hash Identification";
private static final String DESCRIPTION =
"Analyzes program for statically linked library functions (e.g., printf, scanf, etc.).";
private final static String OPTION_NAME_MEM_SEARCH = "Analyze undefined bytes";
private final static String OPTION_NAME_DISASSEMBLE = "Disassemble matches in undefined bytes";
private static final String OPTION_DESCRIPTION_MEM_SEARCH =
"Search for known library signatures in undefined bytes.";
private static final String OPTION_DESCRIPTION_DISASSEMBLE =
"Disassemble any library functions found while searching undefined bytes.";
private final static boolean OPTION_DEFAULT_MEM_SEARCH = true;
private final static boolean OPTION_DEFAULT_DISASSEMBLE = true;
private boolean memSearchOption = OPTION_DEFAULT_MEM_SEARCH;
private boolean disassembleOption = OPTION_DEFAULT_DISASSEMBLE;
public LibraryHashAnalyzer() {
super(NAME, DESCRIPTION, AnalyzerType.BYTE_ANALYZER);
setPrototype();
setPriority(AnalysisPriority.DATA_TYPE_PROPOGATION.before());
setSupportsOneTimeAnalysis();
}
@Override
public boolean canAnalyze(Program program) {
// TODO: for now, this can't analyze anything!
// WARNING: this will cause this analyzer not to show up for anything!
return false;
}
@Override
public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) {
this.identifyLibraryFunctions(set, program, monitor);
return true;
}
@Override
public void registerOptions(Options options, Program program) {
options.registerOption(OPTION_NAME_MEM_SEARCH, memSearchOption, null,
OPTION_DESCRIPTION_MEM_SEARCH);
options.registerOption(OPTION_NAME_DISASSEMBLE, disassembleOption, null,
OPTION_DESCRIPTION_DISASSEMBLE);
}
/**
* @see ghidra.app.services.Analyzer#optionsChanged(ghidra.framework.options.Options, Program)
*/
@Override
public void optionsChanged(Options options, Program program) {
memSearchOption = options.getBoolean(OPTION_NAME_MEM_SEARCH, memSearchOption);
disassembleOption = options.getBoolean(OPTION_NAME_DISASSEMBLE, disassembleOption);
}
private void identifyLibraryFunctions(AddressSetView set, Program p, TaskMonitor monitor) {
//Get the library from the xml database file.
File libraryFile;
try {
libraryFile = Application.getModuleDataFile("lib/db.xml").getFile(true);
}
catch (FileNotFoundException e1) {
Msg.error(this, "Cannot find db.xml file--not hashing functions", e1);
return;
}
LibHashDB db = new LibHashDB();
//Handler is for the XML parser.
ErrorHandler handler = new ErrorHandler() {
@Override
public void warning(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void error(SAXParseException exception) throws SAXException {
throw exception;
}
@Override
public void fatalError(SAXParseException exception) throws SAXException {
throw exception;
}
};
try {
InputStream hstream = new FileInputStream(libraryFile);
//Create the parser.
XmlPullParser parser = new NonThreadedXmlPullParserImpl(hstream,
"Function Database parser", handler, false);
hstream.close();
//Create the database.
db.restoreXml(parser);
HashMap<FuncRecord, FuncRecord> pinning = new HashMap<FuncRecord, FuncRecord>(); //Matching between query and library functions.
LibHashDB qdb = new LibHashDB(p);
FunctionIterator funcIter = p.getListing().getFunctions(true);
//If a signature is unique in the libraries and in the query, we may as well match them.
while (funcIter.hasNext()) {
Function func = funcIter.next();
ArrayList<FuncRecord> libResponse = db.query(func);
if (libResponse.size() != 1) { //Check uniqueness in libraries.
continue;
}
FuncRecord libVal = libResponse.get(0);
ArrayList<FuncRecord> queResponse = qdb.query(libVal.hashValue);
if (queResponse.size() != 1) { //Check uniqueness in query.
continue;
}
FuncRecord queVal = queResponse.get(0);
pinning.put(queVal, libVal);
}
PriorityQueue<FuncRecord> q = new PriorityQueue<FuncRecord>(pinning.keySet());
HashSet<FuncRecord> seen = new HashSet<FuncRecord>();
while (q.size() > 0) {
FuncRecord current = q.remove(); //A query record which is already matched.
seen.add(current);
Iterator<FuncRecord> qit = current.children.iterator();
FuncRecord partner = pinning.get(current);
Iterator<FuncRecord> lit = partner.children.iterator();
while (qit.hasNext()) {
FuncRecord qKid = qit.next(); //Child on the query side.
if (!lit.hasNext()) {
break;
}
FuncRecord lKid = lit.next(); //Child to match on the library side.
//Should we add a second seen set for the lKids?
if (qKid.hashValue != lKid.hashValue || seen.contains(qKid)) {
continue;
}
//Match 'em and put 'em in the queue.
//This little check is unnecessary, except that calls can be incorrectly disassembled.
if (qKid.children.size() != lKid.children.size()) {
continue;
}
pinning.put(qKid, lKid);
this.addSymbol(p, qKid.func.getEntryPoint(), lKid.funcName, false);
q.add(qKid);
}
}
/*
File outFile = new File(dataDir, "testy.txt");
File outFile2 = new File(dataDir, "testy2.txt");
FileWriter writer = new FileWriter(outFile);
FileWriter writer2 = new FileWriter(outFile2);
writer.write("Matched: " + pinning.size() + "\n");
writer2.write("Unmatched:\n");
for(FuncRecord key : qdb.getRecords()){
if(pinning.containsKey(key)){
writer.write(key.toString() + "\n");
}
else{
writer2.write(key.toString() + "\n");
}
}
writer.close();
writer2.close();
*/
}
catch (Exception e) {
e.printStackTrace();
}
return;
}
@Override
public void analysisEnded(Program program) {
// don't care
}
private void addSymbol(Program program, Address addr, String name, boolean localscope) {
SymbolTable st = program.getSymbolTable();
Symbol existSym = st.getPrimarySymbol(addr);
Command cmd = null;
if (existSym == null) { //Symbol didn't exist
cmd = new AddLabelCmd(addr, name, localscope, SourceType.IMPORTED); //So we prepare to add it.
}
else if (!existSym.getName().equals(name)) { //There is a symbol there with the wrong name.
if (existSym.getSource() == SourceType.DEFAULT || //It's got a non-smart name.
(existSym.getSource() == SourceType.ANALYSIS &&
existSym.getSymbolType().equals(SymbolType.FUNCTION))) {
cmd = new RenameLabelCmd(addr, existSym.getName(), name, //Prepare to rename it.
existSym.getParentNamespace(), SourceType.IMPORTED);
}
else {
cmd = new AddLabelCmd(addr, name, localscope, SourceType.IMPORTED); //Our name is better?
}
}
if (cmd != null && cmd.applyTo(program)) { //Apply the name, make sure it worked.
Msg.debug(this, "Created symbol for library function " + name + " at address " + addr);
Namespace space = st.getNamespace(addr);
if (!localscope) {
space = null;
}
cmd = new SetLabelPrimaryCmd(addr, name, space);
cmd.applyTo(program);
cmd = new DemanglerCmd(addr, name);
if (cmd.applyTo(program)) {
Msg.debug(this, "Demangled library function " + name);
}
//resolved.add(addr);
}
/*
program.getBookmarkManager().setBookmark(addr, "Analysis",
LibraryIdentificationConstants.LIB_BOOKMARK_CATEGORY, "Library function");
if (disassembleOption) {
PseudoDisassembler pdis = new PseudoDisassembler(program);
// make sure it is a disassembly
if (pdis.isValidSubroutine(addr, false)) {
disassembleSet.addRange(addr, addr);
}
}
*/
return;
}
}

View file

@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
li { font-family:times new roman; font-size:14pt; } li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/* /*
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
td { font-family:times new roman; font-size:14pt; vertical-align: top; } td { font-family:times new roman; font-size:14pt; vertical-align: top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; } th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
code { color: black; font-family: courier new; font-size: 14pt; } /*
Code-like formatting for things such as file system paths and proper names of classes,
methods, etc. To apply this to a file path, use this syntax:
<CODE CLASS="path">...</CODE>
*/
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }

View file

@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
li { font-family:times new roman; font-size:14pt; } li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/* /*
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
td { font-family:times new roman; font-size:14pt; vertical-align: top; } td { font-family:times new roman; font-size:14pt; vertical-align: top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; } th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
code { color: black; font-family: courier new; font-size: 14pt; } /*
Code-like formatting for things such as file system paths and proper names of classes,
methods, etc. To apply this to a file path, use this syntax:
<CODE CLASS="path">...</CODE>
*/
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }

View file

@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
li { font-family:times new roman; font-size:14pt; } li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/* /*
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
td { font-family:times new roman; font-size:14pt; vertical-align: top; } td { font-family:times new roman; font-size:14pt; vertical-align: top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; } th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
code { color: black; font-family: courier new; font-size: 14pt; } /*
Code-like formatting for things such as file system paths and proper names of classes,
methods, etc. To apply this to a file path, use this syntax:
<CODE CLASS="path">...</CODE>
*/
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }

View file

@ -110,7 +110,7 @@ public class DecompilerFunctionAnalyzer extends AbstractAnalyzer {
@Override @Override
public void registerOptions(Options options, Program program) { public void registerOptions(Options options, Program program) {
HelpLocation helpLocation = new HelpLocation("AutoAnalysisPlugin", HelpLocation helpLocation = new HelpLocation("AutoAnalysisPlugin",
"Auto_Analysis_Option_Instruction" + getAnalysisType()); "Decompiler_Parameter_ID_Analyzer");
options.registerOption(OPTION_NAME_CLEAR_LEVEL, SourceType.ANALYSIS, helpLocation, options.registerOption(OPTION_NAME_CLEAR_LEVEL, SourceType.ANALYSIS, helpLocation,
OPTION_DESCRIPTION_CLEAR_LEVEL); OPTION_DESCRIPTION_CLEAR_LEVEL);

View file

@ -24,12 +24,12 @@
*/ */
body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px;} /* some padding to improve readability */ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 10px; } /* some padding to improve readability */
li { font-family:times new roman; font-size:14pt; } li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; font-family:times new roman; font-size:14pt; font-style:italic; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/* /*
P tag code. Most of the help files nest P tags inside of blockquote tags (the was the P tag code. Most of the help files nest P tags inside of blockquote tags (the was the
@ -40,12 +40,25 @@ h4 { margin-left: 10px; font-family:times new roman; font-size:14pt; font-style:
*/ */
p { margin-left: 40px; font-family:times new roman; font-size:14pt; } p { margin-left: 40px; font-family:times new roman; font-size:14pt; }
blockquote p { margin-left: 10px; } blockquote p { margin-left: 10px; }
p.providedbyplugin { color:#7f7f7f; margin-left: 10px; font-size:14pt; margin-top:100px } p.providedbyplugin { color:#7f7f7f; margin-left: 10px; font-size:14pt; margin-top:100px }
p.ProvidedByPlugin { color:#7f7f7f; margin-left: 10px; font-size:14pt; margin-top:100px } p.ProvidedByPlugin { color:#7f7f7f; margin-left: 10px; font-size:14pt; margin-top:100px }
p.relatedtopic { color:#800080; margin-left: 10px; font-size:14pt; } p.relatedtopic { color:#800080; margin-left: 10px; font-size:14pt; }
p.RelatedTopic { color:#800080; margin-left: 10px; font-size:14pt; } p.RelatedTopic { color:#800080; margin-left: 10px; font-size:14pt; }
/*
We wish for a tables to have space between it and the preceding element, so that text
is not too close to the top of the table. Also, nest the table a bit so that it is clear
the table relates to the preceding text.
*/
table { margin-left: 20px; margin-top: 10px; width: 80%;}
td { font-family:times new roman; font-size:14pt; vertical-align: top; } td { font-family:times new roman; font-size:14pt; vertical-align: top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; } th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
code { color: black; font-family: courier new; font-size: 14pt; }
/*
Code-like formatting for things such as file system paths and proper names of classes,
methods, etc. To apply this to a file path, use this syntax:
<CODE CLASS="path">...</CODE>
*/
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }

View file

@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
li { font-family:times new roman; font-size:14pt; } li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/* /*
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
td { font-family:times new roman; font-size:14pt; vertical-align: top; } td { font-family:times new roman; font-size:14pt; vertical-align: top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; } th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
code { color: black; font-family: courier new; font-size: 14pt; } /*
Code-like formatting for things such as file system paths and proper names of classes,
methods, etc. To apply this to a file path, use this syntax:
<CODE CLASS="path">...</CODE>
*/
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }

View file

@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
li { font-family:times new roman; font-size:14pt; } li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/* /*
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
td { font-family:times new roman; font-size:14pt; vertical-align: top; } td { font-family:times new roman; font-size:14pt; vertical-align: top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; } th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
code { color: black; font-family: courier new; font-size: 14pt; } /*
Code-like formatting for things such as file system paths and proper names of classes,
methods, etc. To apply this to a file path, use this syntax:
<CODE CLASS="path">...</CODE>
*/
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }

View file

@ -19,16 +19,10 @@
// //
//@category Examples.Demangler //@category Examples.Demangler
import java.io.*;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.app.util.demangler.DemangledObject; import ghidra.app.util.demangler.DemangledObject;
import ghidra.app.util.demangler.DemanglerOptions; import ghidra.app.util.demangler.gnu.GnuDemangler;
import ghidra.app.util.demangler.gnu.GnuDemanglerParser; import ghidra.app.util.demangler.gnu.GnuDemanglerOptions;
import ghidra.app.util.opinion.ElfLoader;
import ghidra.app.util.opinion.MachoLoader;
import ghidra.framework.*;
import ghidra.program.model.lang.CompilerSpec;
import ghidra.program.model.symbol.Symbol; import ghidra.program.model.symbol.Symbol;
public class DemangleElfWithOptionScript extends GhidraScript { public class DemangleElfWithOptionScript extends GhidraScript {
@ -36,8 +30,9 @@ public class DemangleElfWithOptionScript extends GhidraScript {
@Override @Override
protected void run() throws Exception { protected void run() throws Exception {
String executableFormat = currentProgram.getExecutableFormat(); GnuDemangler demangler = new GnuDemangler();
if (!canDemangle(executableFormat)) { if (!demangler.canDemangle(currentProgram)) {
String executableFormat = currentProgram.getExecutableFormat();
println("Cannot use the elf demangling options for executable format: " + println("Cannot use the elf demangling options for executable format: " +
executableFormat); executableFormat);
return; return;
@ -54,75 +49,22 @@ public class DemangleElfWithOptionScript extends GhidraScript {
String mangled = symbol.getName(); String mangled = symbol.getName();
Process process = createProcess(executableFormat); GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDoDisassembly(false);
options.setDemanglerApplicationArguments("-s auto");
InputStream in = process.getInputStream(); /*
OutputStream out = process.getOutputStream(); // for older formats use the deprecated demangler
options.setDemanglerName(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
options.setDemanglerApplicationArguments("-s arm");
*/
BufferedReader input = new BufferedReader(new InputStreamReader(in)); DemangledObject demangledObject = demangler.demangle(mangled, options);
PrintWriter output = new PrintWriter(out);
output.println(mangled);
output.flush();
String demangled = input.readLine();
println("demangled: " + demangled);
GnuDemanglerParser parser = new GnuDemanglerParser(null);
DemangledObject demangledObject = parser.parse(mangled, demangled);
if (demangledObject == null) { if (demangledObject == null) {
println("Could not demangle: " + mangled); println("Could not demangle: " + mangled);
return; return;
} }
DemanglerOptions options = new DemanglerOptions(); println("Succesfully demangled " + mangled + " to " + demangledObject);
options.setDoDisassembly(false);
options.setApplySignature(true);
options.setDemangleOnlyKnownPatterns(true);
if (!demangledObject.applyTo(currentProgram, currentAddress, options, monitor)) {
println("Failed to apply demangled data for " + mangled);
}
println("Succesfully demangled " + mangled + " to " + demangled);
}
private boolean canDemangle(String executableFormat) {
//check if language is GCC - this is not altogether correct !
// Objective-C and other non-GCC based symbols may be handled improperly
if (isELF(executableFormat) || isMacho(executableFormat)) {
return true;
}
CompilerSpec compilerSpec = currentProgram.getCompilerSpec();
if (compilerSpec.getCompilerSpecID().getIdAsString().toLowerCase().indexOf("windows") == -1) {
return true;
}
return false;
}
private boolean isELF(String executableFormat) {
return executableFormat != null && executableFormat.indexOf(ElfLoader.ELF_NAME) != -1;
}
private boolean isMacho(String executableFormat) {
return executableFormat != null && executableFormat.indexOf(MachoLoader.MACH_O_NAME) != -1;
}
private Process createProcess(String executableName) throws Exception {
OperatingSystem OS = Platform.CURRENT_PLATFORM.getOperatingSystem();
String demanglerExe =
(OS == OperatingSystem.WINDOWS) ? "demangler_gnu.exe" : "demangler_gnu";
File commandPath = Application.getOSFile("GnuDemangler", demanglerExe);
//
// This is where special options are to be passed. Put your own here as necessary.
//
String[] command = new String[] { commandPath.getAbsolutePath(), "-s", "arm" };
Process process = Runtime.getRuntime().exec(command);
return process;
} }
} }

View file

@ -95,8 +95,9 @@ public class VxWorksSymTab_5_4 extends GhidraScript {
Address vxSymTbl = vxNumSymEntriesAddr.subtract(vxNumSymEntries * SYM_ENTRY_SIZE); Address vxSymTbl = vxNumSymEntriesAddr.subtract(vxNumSymEntries * SYM_ENTRY_SIZE);
for (int i = 0; i < vxNumSymEntries; i++) { for (int i = 0; i < vxNumSymEntries; i++) {
if (monitor.isCancelled()) if (monitor.isCancelled()) {
return; // check for cancel button return; // check for cancel button
}
println("i=" + i); // visual counter println("i=" + i); // visual counter
// Extract symbol table entry values // Extract symbol table entry values
@ -112,15 +113,19 @@ public class VxWorksSymTab_5_4 extends GhidraScript {
Address a; Address a;
String symName; String symName;
for (a = symNameAddr; mem.getByte(a) != 0; a = a.add(1)) { for (a = symNameAddr; mem.getByte(a) != 0; a = a.add(1)) {
if (getDataAt(a) != null) if (getDataAt(a) != null) {
removeDataAt(a); removeDataAt(a);
if (getInstructionAt(a) != null) }
if (getInstructionAt(a) != null) {
removeInstructionAt(a); removeInstructionAt(a);
}
} }
if (getDataAt(a) != null) if (getDataAt(a) != null) {
removeDataAt(a); removeDataAt(a);
if (getInstructionAt(a) != null) }
if (getInstructionAt(a) != null) {
removeInstructionAt(a); removeInstructionAt(a);
}
// Turn *symNameAddr into a string and store it in symName // Turn *symNameAddr into a string and store it in symName
try { try {
@ -137,7 +142,7 @@ public class VxWorksSymTab_5_4 extends GhidraScript {
String symDemangledName = null; String symDemangledName = null;
try { try {
// if successful, symDemangledName will be non-NULL // if successful, symDemangledName will be non-NULL
symDemangledName = demangler.demangle(symName, true).getSignature(false); symDemangledName = demangler.demangle(symName).getSignature(false);
} }
catch (DemangledException e) { catch (DemangledException e) {
// if symName wasn't a mangled name, silently continue // if symName wasn't a mangled name, silently continue

View file

@ -138,7 +138,7 @@ public class VxWorksSymTab_6_1 extends GhidraScript {
String symDemangledName = null; String symDemangledName = null;
try { try {
// if successful, symDemangledName will be non-NULL // if successful, symDemangledName will be non-NULL
symDemangledName = demangler.demangle(symName, true).getSignature(false); symDemangledName = demangler.demangle(symName).getSignature(false);
} }
catch (DemangledException e) { catch (DemangledException e) {
// if symName wasn't a mangled name, silently continue // if symName wasn't a mangled name, silently continue

View file

@ -50,13 +50,7 @@ import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.gnu.GnuDemangler; import ghidra.app.util.demangler.gnu.GnuDemangler;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet; import ghidra.program.model.address.AddressSet;
import ghidra.program.model.data.ArrayDataType; import ghidra.program.model.data.*;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.DataTypeComponent;
import ghidra.program.model.data.DataTypeConflictHandler;
import ghidra.program.model.data.DataTypeManager;
import ghidra.program.model.data.PointerDataType;
import ghidra.program.model.data.StructureDataType;
import ghidra.program.model.listing.Data; import ghidra.program.model.listing.Data;
import ghidra.program.model.listing.Instruction; import ghidra.program.model.listing.Instruction;
import ghidra.program.model.mem.MemoryBlock; import ghidra.program.model.mem.MemoryBlock;
@ -143,8 +137,9 @@ public class VxWorksSymTab_Finder extends GhidraScript {
// Add SYMBOL data type to Program DataTypeManager // Add SYMBOL data type to Program DataTypeManager
// (if data type already exists, replace it) // (if data type already exists, replace it)
public void createGhidraType() { public void createGhidraType() {
currentProgram.getDataTypeManager().addDataType(dt, currentProgram.getDataTypeManager()
DataTypeConflictHandler.REPLACE_HANDLER); .addDataType(dt,
DataTypeConflictHandler.REPLACE_HANDLER);
} }
} }
@ -351,8 +346,7 @@ public class VxWorksSymTab_Finder extends GhidraScript {
} }
} }
if (_byte == 0x00) if (_byte == 0x00) {
{
return true; // Scan stopped at null. return true; // Scan stopped at null.
} }
return false; // Scan stopped at invalid char. return false; // Scan stopped at invalid char.
@ -657,8 +651,9 @@ public class VxWorksSymTab_Finder extends GhidraScript {
if (demangled != null) { if (demangled != null) {
new DemanglerCmd(addr, mangled).applyTo(currentProgram, monitor); new DemanglerCmd(addr, mangled).applyTo(currentProgram, monitor);
currentProgram.getSymbolTable().removeSymbolSpecial( currentProgram.getSymbolTable()
getSymbol(mangled, currentProgram.getGlobalNamespace())); .removeSymbolSpecial(
getSymbol(mangled, currentProgram.getGlobalNamespace()));
} }
return; return;
@ -772,7 +767,7 @@ public class VxWorksSymTab_Finder extends GhidraScript {
// Demangle symName // Demangle symName
String symDemangledName = null; String symDemangledName = null;
try { try {
symDemangledName = demangler.demangle(symName, true).getSignature(false); symDemangledName = demangler.demangle(symName).getSignature(false);
} }
catch (DemangledException e) { // report demangling error catch (DemangledException e) { // report demangling error
if (!e.isInvalidMangledName()) { if (!e.isInvalidMangledName()) {

View file

@ -0,0 +1,189 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.analysis;
import java.io.IOException;
import org.apache.commons.lang3.StringUtils;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.gnu.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.program.model.listing.Program;
import ghidra.util.HelpLocation;
/**
* A version of the demangler analyzer to handle GNU GCC symbols
*/
public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
private static final String NAME = "Demangler GNU";
private static final String DESCRIPTION =
"After a function is created, this analyzer will attempt to demangle " +
"the name and apply datatypes to parameters.";
private static final String OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS =
"Demangle Only Known Mangled Symbols";
private static final String OPTION_DESCRIPTION_USE_KNOWN_PATTERNS =
"Only demangle symbols that follow known compiler mangling patterns. " +
"Leaving this option off may cause non-mangled symbols to get demangled.";
private static final String OPTION_NAME_APPLY_SIGNATURE = "Apply Function Signatures";
private static final String OPTION_DESCRIPTION_APPLY_SIGNATURE =
"Apply any recovered function signature, in addition to the function name";
static final String OPTION_NAME_USE_DEPRECATED_DEMANGLER = "Use Deprecated Demangler";
private static final String OPTION_DESCRIPTION_DEPRECATED_DEMANGLER =
"Signals to use the deprecated demangler when the modern demangler cannot demangle a " +
"given string";
static final String OPTION_NAME_DEMANGLER_PARAMETERS =
"Use External Demangler Options";
private static final String OPTION_DESCRIPTION_DEMANGLER_PARAMETERS =
"Signals to use pass the given parameters to the demangler program";
private boolean doSignatureEnabled = true;
private boolean demangleOnlyKnownPatterns = false;
private boolean useDeprecatedDemangler = false;
private String demanglerParameters = "";
private GnuDemangler demangler = new GnuDemangler();
public GnuDemanglerAnalyzer() {
super(NAME, DESCRIPTION);
setDefaultEnablement(true);
}
@Override
public boolean canAnalyze(Program program) {
return demangler.canDemangle(program);
}
@Override
public void registerOptions(Options options, Program program) {
HelpLocation help = new HelpLocation("AutoAnalysisPlugin", "Demangler_Analyzer");
options.registerOption(OPTION_NAME_APPLY_SIGNATURE, doSignatureEnabled, help,
OPTION_DESCRIPTION_APPLY_SIGNATURE);
options.registerOption(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns,
help,
OPTION_DESCRIPTION_USE_KNOWN_PATTERNS);
options.registerOption(OPTION_NAME_USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler, help,
OPTION_DESCRIPTION_DEPRECATED_DEMANGLER);
options.registerOption(OPTION_NAME_DEMANGLER_PARAMETERS, demanglerParameters, help,
OPTION_DESCRIPTION_DEMANGLER_PARAMETERS);
}
@Override
public void optionsChanged(Options options, Program program) {
doSignatureEnabled = options.getBoolean(OPTION_NAME_APPLY_SIGNATURE, doSignatureEnabled);
demangleOnlyKnownPatterns =
options.getBoolean(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns);
useDeprecatedDemangler =
options.getBoolean(OPTION_NAME_USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler);
demanglerParameters =
options.getString(OPTION_NAME_DEMANGLER_PARAMETERS, demanglerParameters);
}
@Override
protected DemanglerOptions getOptions() {
GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDoDisassembly(true);
options.setApplySignature(doSignatureEnabled);
options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns);
options.setDemanglerApplicationArguments(demanglerParameters);
return options;
}
@Override
protected boolean validateOptions(DemanglerOptions demanglerOtions, MessageLog log) {
GnuDemanglerOptions options = (GnuDemanglerOptions) demanglerOtions;
String applicationArguments = options.getDemanglerApplicationArguments();
if (StringUtils.isBlank(applicationArguments)) {
return true;
}
// Check that the supplied arguments will work with at least one of the requested
// demanglers. (Different versions of the GNU demangler support different arguments.)
String demanglerName = options.getDemanglerName();
try {
GnuDemanglerNativeProcess.getDemanglerNativeProcess(demanglerName,
applicationArguments);
return true;
}
catch (IOException e) {
log.error(getName(), "Invalid options for GNU dangler '" + demanglerName +
"': " + applicationArguments);
log.appendException(e);
}
if (useDeprecatedDemangler) {
// see if the options work in the deprecated demangler
GnuDemanglerOptions deprecatedOptions = options.withDeprecatedDemangler();
String deprecatedName = deprecatedOptions.getDemanglerName();
try {
GnuDemanglerNativeProcess.getDemanglerNativeProcess(deprecatedName,
applicationArguments);
return true;
}
catch (IOException e) {
log.error(getName(),
"Invalid options for GNU dangler '" + deprecatedName + "': " +
applicationArguments);
log.appendException(e);
}
}
return false;
}
@Override
protected DemangledObject doDemangle(String mangled, DemanglerOptions demanglerOtions,
MessageLog log)
throws DemangledException {
GnuDemanglerOptions options = (GnuDemanglerOptions) demanglerOtions;
DemangledObject demangled = null;
try {
demangled = demangler.demangle(mangled, options);
}
catch (DemangledException e) {
if (!useDeprecatedDemangler) {
throw e; // let our parent handle this
}
}
if (demangled != null) {
return demangled;
}
if (useDeprecatedDemangler) {
GnuDemanglerOptions newOptions = options.withDeprecatedDemangler();
demangled = demangler.demangle(mangled, newOptions);
}
return demangled;
}
}

View file

@ -38,32 +38,46 @@ public class GnuDemangler implements Demangler {
// needed to instantiate dynamically // needed to instantiate dynamically
} }
@Override
public DemanglerOptions createDefaultOptions() {
return new GnuDemanglerOptions();
}
@Override @Override
public boolean canDemangle(Program program) { public boolean canDemangle(Program program) {
String executableFormat = program.getExecutableFormat(); String executableFormat = program.getExecutableFormat();
if (isELF(executableFormat) || isMacho(executableFormat)) { if (isELF(executableFormat) || isMacho(executableFormat)) {
return true; return true;
} }
//check if language is GCC CompilerSpec spec = program.getCompilerSpec();
CompilerSpec compilerSpec = program.getCompilerSpec(); String specId = spec.getCompilerSpecID().getIdAsString();
if (compilerSpec.getCompilerSpecID().getIdAsString().toLowerCase().indexOf( if (!specId.toLowerCase().contains("windows")) {
"windows") == -1) {
return true; return true;
} }
return false; return false;
} }
@Override @Override
@Deprecated(since = "9.2", forRemoval = true)
public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns) public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns)
throws DemangledException { throws DemangledException {
GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns);
return demangle(mangled, options);
}
if (skip(mangled, demangleOnlyKnownPatterns)) { @Override
public DemangledObject demangle(String mangled, DemanglerOptions demanglerOtions)
throws DemangledException {
if (skip(mangled, demanglerOtions)) {
return null; return null;
} }
GnuDemanglerOptions options = getGnuOptions(demanglerOtions);
String originalMangled = mangled; String originalMangled = mangled;
String globalPrefix = null; String globalPrefix = null;
if (mangled.startsWith(GLOBAL_PREFIX)) { if (mangled.startsWith(GLOBAL_PREFIX)) {
int index = mangled.indexOf("_Z"); int index = mangled.indexOf("_Z");
@ -84,15 +98,16 @@ public class GnuDemangler implements Demangler {
} }
try { try {
GnuDemanglerNativeProcess process = GnuDemanglerNativeProcess.getDemanglerNativeProcess();
String demangled = process.demangle(mangled).trim();
GnuDemanglerNativeProcess process = getNativeProcess(options);
String demangled = process.demangle(mangled).trim();
if (mangled.equals(demangled) || demangled.length() == 0) { if (mangled.equals(demangled) || demangled.length() == 0) {
throw new DemangledException(true); throw new DemangledException(true);
} }
boolean onlyKnownPatterns = options.demangleOnlyKnownPatterns();
DemangledObject demangledObject = DemangledObject demangledObject =
parse(mangled, process, demangled, demangleOnlyKnownPatterns); parse(mangled, process, demangled, onlyKnownPatterns);
if (demangledObject == null) { if (demangledObject == null) {
return demangledObject; return demangledObject;
} }
@ -107,6 +122,7 @@ public class GnuDemangler implements Demangler {
else { else {
demangledObject.setSignature(demangled); demangledObject.setSignature(demangled);
} }
demangledObject.setOriginalMangled(originalMangled); demangledObject.setOriginalMangled(originalMangled);
if (isDwarf) { if (isDwarf) {
@ -121,7 +137,7 @@ public class GnuDemangler implements Demangler {
return demangledObject; return demangledObject;
} }
catch (IOException e) { catch (IOException e) {
if (e.getMessage().endsWith("14001")) {//missing runtime dlls, prolly if (e.getMessage().endsWith("14001")) {
ResourceFile installationDir = Application.getInstallationDirectory(); ResourceFile installationDir = Application.getInstallationDirectory();
throw new DemangledException("Missing runtime libraries. " + "Please install " + throw new DemangledException("Missing runtime libraries. " + "Please install " +
installationDir + File.separatorChar + "support" + File.separatorChar + installationDir + File.separatorChar + "support" + File.separatorChar +
@ -131,7 +147,25 @@ public class GnuDemangler implements Demangler {
} }
} }
private boolean skip(String mangled, boolean demangleOnlyKnownPatterns) { private GnuDemanglerOptions getGnuOptions(DemanglerOptions options) {
if (options instanceof GnuDemanglerOptions) {
return (GnuDemanglerOptions) options;
}
return new GnuDemanglerOptions(options);
}
private GnuDemanglerNativeProcess getNativeProcess(GnuDemanglerOptions options)
throws IOException {
String demanglerName = options.getDemanglerName();
String applicationOptions = options.getDemanglerApplicationArguments();
return GnuDemanglerNativeProcess.getDemanglerNativeProcess(demanglerName,
applicationOptions);
}
private boolean skip(String mangled, DemanglerOptions options) {
// Ignore versioned symbols which are generally duplicated at the same address // Ignore versioned symbols which are generally duplicated at the same address
if (mangled.indexOf("@") > 0) { // do not demangle versioned symbols if (mangled.indexOf("@") > 0) { // do not demangle versioned symbols
@ -143,7 +177,7 @@ public class GnuDemangler implements Demangler {
return true; return true;
} }
if (!demangleOnlyKnownPatterns) { if (!options.demangleOnlyKnownPatterns()) {
return false; // let it go through return false; // let it go through
} }
@ -167,24 +201,20 @@ public class GnuDemangler implements Demangler {
return true; return true;
} }
private DemangledObject parse(String mangled, GnuDemanglerNativeProcess process, String demangled, private DemangledObject parse(String mangled, GnuDemanglerNativeProcess process,
String demangled,
boolean demangleOnlyKnownPatterns) { boolean demangleOnlyKnownPatterns) {
if (demangleOnlyKnownPatterns && !isMangledString(mangled, demangled)) { if (demangleOnlyKnownPatterns && !isKnownMangledString(mangled, demangled)) {
return null; return null;
} }
try { GnuDemanglerParser parser = new GnuDemanglerParser(process);
GnuDemanglerParser parser = new GnuDemanglerParser(process); DemangledObject demangledObject = parser.parse(mangled, demangled);
DemangledObject demangledObject = parser.parse(mangled, demangled); return demangledObject;
return demangledObject;
}
catch (Exception e) {
throw e;
}
} }
private boolean isMangledString(String mangled, String demangled) { private boolean isKnownMangledString(String mangled, String demangled) {
// //
// We get requests to demangle strings that are not mangled. For newer mangled strings // We get requests to demangle strings that are not mangled. For newer mangled strings
// we know how to avoid that. However, older mangled strings can be of many forms. To // we know how to avoid that. However, older mangled strings can be of many forms. To

View file

@ -16,29 +16,90 @@
package ghidra.app.util.demangler.gnu; package ghidra.app.util.demangler.gnu;
import java.io.*; import java.io.*;
import java.nio.charset.Charset;
import java.util.*;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import ghidra.framework.Application; import ghidra.framework.Application;
import ghidra.framework.Platform; import ghidra.framework.Platform;
/**
* A class that allows for the reuse of native demangler executable processes. This class will
* cache the process by name and by any arguments passed to the process when started. Once
* successfully started, the process will persist
*/
public class GnuDemanglerNativeProcess { public class GnuDemanglerNativeProcess {
private static final String DEMANGLER_GNU = "demangler_gnu"; public static final String DEMANGLER_GNU = GnuDemanglerOptions.GNU_DEMANGLER_DEFAULT;
private static GnuDemanglerNativeProcess demanglerNativeProcess; private static final String DEFAULT_NATIVE_OPTIONS = "";
private static final Map<String, GnuDemanglerNativeProcess> processesByName =
new HashMap<>();
private String applicationName;
private String options;
private boolean isDisposed; private boolean isDisposed;
private Process process; private Process process;
private BufferedReader reader; private BufferedReader reader;
private PrintWriter writer; private PrintWriter writer;
/**
* Gets the default GNU demangler native process
* @return the process
* @throws IOException if the process cannot be started
*/
public static synchronized GnuDemanglerNativeProcess getDemanglerNativeProcess() public static synchronized GnuDemanglerNativeProcess getDemanglerNativeProcess()
throws IOException { throws IOException {
if (demanglerNativeProcess == null) { return getDemanglerNativeProcess(DEMANGLER_GNU);
demanglerNativeProcess = new GnuDemanglerNativeProcess();
}
return demanglerNativeProcess;
} }
private GnuDemanglerNativeProcess() throws IOException { /**
* Gets the default GNU demangler native process
* @param name the specific executable name to launch
* @return the process
* @throws IOException if the process cannot be started
*/
public static synchronized GnuDemanglerNativeProcess getDemanglerNativeProcess(String name)
throws IOException {
return getDemanglerNativeProcess(name, DEFAULT_NATIVE_OPTIONS);
}
/**
* Gets the default GNU demangler native process
* @param name the specific executable name to launch
* @param nativeOptions the arguments string to pass to the native demangler
* @return the process
* @throws IOException if the process cannot be started
*/
public static synchronized GnuDemanglerNativeProcess getDemanglerNativeProcess(String name,
String nativeOptions)
throws IOException {
String options = nativeOptions;
if (StringUtils.isBlank(options)) {
options = DEFAULT_NATIVE_OPTIONS;
}
String key = getKey(name, options);
GnuDemanglerNativeProcess nativeProcess = processesByName.get(key);
if (nativeProcess == null) {
nativeProcess = new GnuDemanglerNativeProcess(name, options);
}
return nativeProcess;
}
private static String getKey(String name, String options) {
return name + ' ' + options;
}
private GnuDemanglerNativeProcess(String applicationName, String options) throws IOException {
this.applicationName = applicationName;
this.options = options;
createProcess(); createProcess();
} }
@ -51,23 +112,29 @@ public class GnuDemanglerNativeProcess {
private String demangle(String mangled, boolean restart) throws IOException { private String demangle(String mangled, boolean restart) throws IOException {
try { try {
writer.println(mangled); return doDemangle(mangled);
writer.flush();
return reader.readLine();
} }
catch (IOException e) { catch (IOException e) {
dispose(); dispose();
if (!restart) { if (!restart) {
demanglerNativeProcess = null; throw new IOException("Demangler process is not running.", e);
throw new IOException("Demangler process is not running.");
} }
createProcess(); createProcess();
return demangle(mangled, false); return demangle(mangled, false);
} }
} }
private void dispose() { private String doDemangle(String mangled) throws IOException {
writer.println(mangled);
writer.flush();
return reader.readLine();
}
public void dispose() {
String key = getKey(applicationName, options);
processesByName.remove(key);
try { try {
if (process != null) { if (process != null) {
process.destroy(); process.destroy();
@ -86,19 +153,68 @@ public class GnuDemanglerNativeProcess {
private void createProcess() throws IOException { private void createProcess() throws IOException {
String executableName = DEMANGLER_GNU + Platform.CURRENT_PLATFORM.getExecutableExtension(); String[] command = buildCommand();
File commandPath = Application.getOSFile(executableName);
String[] command = new String[] { commandPath.getAbsolutePath() };
process = Runtime.getRuntime().exec(command); process = Runtime.getRuntime().exec(command);
InputStream in = process.getInputStream(); InputStream in = process.getInputStream();
OutputStream out = process.getOutputStream(); OutputStream out = process.getOutputStream();
reader = new BufferedReader(new InputStreamReader(in)); reader = new BufferedReader(new InputStreamReader(in));
writer = new PrintWriter(out); writer = new PrintWriter(out);
checkForError(command);
isDisposed = false; isDisposed = false;
String key = getKey(applicationName, options);
processesByName.put(key, this);
}
private String[] buildCommand() throws FileNotFoundException {
String executableName =
applicationName + Platform.CURRENT_PLATFORM.getExecutableExtension();
File commandPath = Application.getOSFile(executableName);
String[] command = new String[] { commandPath.getAbsolutePath() };
if (!StringUtils.isBlank(options)) {
String[] optionsArray = options.split("\\s");
command = ArrayUtils.addAll(command, optionsArray);
}
return command;
}
private void checkForError(String[] command) throws IOException {
//
// We do not want to read the error stream in the happy path case, as that will block.
// Send a test string over and read the result. If the test string is blank, then
// there was an error.
//
String testResult = doDemangle("test");
if (!StringUtils.isBlank(testResult)) {
return;
}
InputStream err = process.getErrorStream();
String error = null;
try {
List<String> errorLines = IOUtils.readLines(err, Charset.defaultCharset());
error = StringUtils.join(errorLines, '\n');
}
catch (IOException e) {
throw new IOException("Unable to read process error stream: ", e);
}
if (StringUtils.isBlank(error)) {
return;
}
String executable = command[0];
String baseName = FilenameUtils.getBaseName(executable);
command[0] = baseName;
// cleanup full path, as it is ugly in the error message
error = error.replace(executable, "");
throw new IOException("Error starting demangler with command: '" +
Arrays.toString(command) + "' " + error);
} }
} }

View file

@ -0,0 +1,119 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.demangler.gnu;
import ghidra.app.util.demangler.DemanglerOptions;
/**
* GNU demangler options
*/
public class GnuDemanglerOptions extends DemanglerOptions {
/*
Note!
If you update the demangler versions, then you also must update the help (search the
html files for the old version strings).
*/
/**
* Version 2.24 of the GNU demangler. This version supports older formats and older bugs.
*/
public static final String GNU_DEMANGLER_V2_24 = "demangler_gnu_v2_24";
/**
* Version 2.33.1 of the GNU demangler. This version supports less formats than older versions.
*/
public static final String GNU_DEMANGLER_V2_33_1 = "demangler_gnu_v2_33_1";
/**
* The default version to use of the GNU demangler
*/
public static final String GNU_DEMANGLER_DEFAULT = GNU_DEMANGLER_V2_33_1;
private String demanglerName = GNU_DEMANGLER_DEFAULT;
private String demanglerApplicationArguments;
public GnuDemanglerOptions() {
// use default values
}
public GnuDemanglerOptions(DemanglerOptions copy) {
super(copy);
if (copy instanceof GnuDemanglerOptions) {
GnuDemanglerOptions gCopy = (GnuDemanglerOptions) copy;
demanglerName = gCopy.demanglerName;
demanglerApplicationArguments = gCopy.demanglerApplicationArguments;
}
}
/**
* Returns the external demangler executable name to be used for demangling. The
* default value is {@link #GNU_DEMANGLER_DEFAULT}.
* @return the name
*/
public String getDemanglerName() {
return demanglerName;
}
/**
* Sets the external demangler executable name to be used for demangling
* @param name the name
*/
public void setDemanglerName(String name) {
this.demanglerName = name;
}
/**
* Returns the current arguments to be passed to the external demangler executable
* @return the arguments
*/
public String getDemanglerApplicationArguments() {
return demanglerApplicationArguments;
}
/**
* Sets the arguments to be passed to the external demangler executable
* @param args the arguments
*/
public void setDemanglerApplicationArguments(String args) {
this.demanglerApplicationArguments = args;
}
/**
* A convenience method to copy the state of this options object, changing the
* demangler executable name to the deprecated demangler
* @return the new options
*/
public GnuDemanglerOptions withDeprecatedDemangler() {
GnuDemanglerOptions newOptions = new GnuDemanglerOptions(this);
newOptions.setDemanglerName(GNU_DEMANGLER_V2_24);
return newOptions;
}
@Override
public String toString() {
//@formatter:off
return "{\n" +
"\tdoDisassembly: " + doDisassembly() + ",\n" +
"\tapplySignature: " + applySignature() + ",\n" +
"\tdemangleOnlyKnownPatterns: " + demangleOnlyKnownPatterns() + ",\n" +
"\tdemanglerName: " + demanglerName + ",\n" +
"\tdemanglerApplicationArguments: " + demanglerApplicationArguments + ",\n" +
"}";
//@formatter:on
}
}

View file

@ -27,7 +27,7 @@ import ghidra.app.util.demangler.*;
import ghidra.program.model.lang.CompilerSpec; import ghidra.program.model.lang.CompilerSpec;
import ghidra.util.StringUtilities; import ghidra.util.StringUtilities;
public class GnuDemanglerParser implements DemanglerParser { public class GnuDemanglerParser {
private static final String CONSTRUCTION_VTABLE_FOR = "construction vtable for "; private static final String CONSTRUCTION_VTABLE_FOR = "construction vtable for ";
private static final String VTT_FOR = "VTT for "; private static final String VTT_FOR = "VTT for ";
@ -154,7 +154,6 @@ public class GnuDemanglerParser implements DemanglerParser {
this.process = process; this.process = process;
} }
@Override
public DemangledObject parse(String mangled, String demangled) { public DemangledObject parse(String mangled, String demangled) {
try { try {
return doParse(mangled, demangled); return doParse(mangled, demangled);

View file

@ -0,0 +1,323 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.analysis;
import static org.junit.Assert.*;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
import ghidra.app.cmd.label.AddLabelCmd;
import ghidra.app.util.demangler.gnu.GnuDemanglerOptions;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.*;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
import ghidra.test.ToyProgramBuilder;
import ghidra.util.Msg;
import ghidra.util.StringUtilities;
import ghidra.util.task.TaskMonitor;
public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationTest {
private ProgramDB program;
private GnuDemanglerAnalyzer analyzer = new GnuDemanglerAnalyzer();
// overridden to prevent stack traces from appearing in the console
private MessageLog log = new MessageLog() {
@Override
public void appendException(Throwable t) {
appendMsg(t.toString());
}
};
@Before
public void setUp() throws Exception {
ProgramBuilder builder = new ToyProgramBuilder("test", true);
builder.createMemory(".text", "0x0100", 0x100);
program = builder.getProgram();
registerOptions();
}
@Override
protected void testFailed(Throwable e) {
Msg.error(this, "Test failed - analysis log:\n" + log);
}
@Test
public void testDeprectedMangledString_WithoutDeprecatedDemangler() throws Exception {
//
// The below demangles to MsoDAL::VertFrame::__dt( (void))
// note the (void) syntax
//
// from program Microsoft Entourage
//
String mangled = "__dt__Q26MsoDAL9VertFrameFv";
Address addr = addr("0x110");
createSymbol(addr, mangled);
setOption(GnuDemanglerAnalyzer.OPTION_NAME_USE_DEPRECATED_DEMANGLER, false);
analyze();
assertNotDemangled(addr, "__dt");
}
@Test
public void testDeprectedMangledString_WithDeprecatedDemangler() throws Exception {
//
// The below demangles to MsoDAL::VertFrame::__dt( (void))
// note the (void) syntax
//
// from program Microsoft Entourage
//
String mangled = "__dt__Q26MsoDAL9VertFrameFv";
Address addr = addr("0x110");
createSymbol(addr, mangled);
setOption(GnuDemanglerAnalyzer.OPTION_NAME_USE_DEPRECATED_DEMANGLER, true);
analyze();
assertDemangled(addr, "__dt");
}
@Test
public void testMangledString_WithArguments_Valid() {
//
// The below demangles to std::io::Read::read_to_end
//
String mangled = "_ZN3std2io4Read11read_to_end17hb85a0f6802e14499E";
Address addr = addr("0x110");
createSymbol(addr, mangled);
setOption(GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_PARAMETERS, "-s rust");
analyze();
assertDemangled(addr, "read_to_end");
}
@Test
public void testMangledString_WithArguments_ValidButWrongFormat() {
//
// The below demangles to std::io::Read::read_to_end
//
String mangled = "_ZN3std2io4Read11read_to_end17hb85a0f6802e14499E";
Address addr = addr("0x110");
createSymbol(addr, mangled);
setOption(GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_PARAMETERS, "-s dlang");
analyze();
assertNotDemangled(addr, "read_to_end");
}
@Test
public void testMangledString_WithArguments_Invalid() {
//
// The below demangles to std::io::Read::read_to_end
//
String mangled = "_ZN3std2io4Read11read_to_end17hb85a0f6802e14499E";
Address addr = addr("0x110");
createSymbol(addr, mangled);
setOption(GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_PARAMETERS, "-s badformatname");
analyze();
assertNotDemangled(addr, "read_to_end");
assertMessageLogLine("java.io.IOException: Error starting demangler with command");
assertMessageLogLine("Invalid options", GnuDemanglerOptions.GNU_DEMANGLER_V2_33_1);
}
@Test
public void testDeprecatedMangledString_WithArguments_Invalid() {
//
// The below demangles to std::io::Read::read_to_end
//
String mangled = "_ZN3std2io4Read11read_to_end17hb85a0f6802e14499E";
Address addr = addr("0x110");
createSymbol(addr, mangled);
setOption(GnuDemanglerAnalyzer.OPTION_NAME_USE_DEPRECATED_DEMANGLER, true);
setOption(GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_PARAMETERS, "-s badformatname");
analyze();
assertNotDemangled(addr, "read_to_end");
assertMessageLogLine("java.io.IOException: Error starting demangler with command");
assertMessageLogLine("Invalid options", GnuDemanglerOptions.GNU_DEMANGLER_V2_33_1);
assertMessageLogLine("Invalid options", GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
}
@Test
public void testDeprecatedMangledString_WithArguments_InvalidModernArguments_ValidDeprecatedArguments() {
//
// The below demangles to std::io::Read::read_to_end
//
String mangled = "_ZN3std2io4Read11read_to_end17hb85a0f6802e14499E";
Address addr = addr("0x110");
createSymbol(addr, mangled);
setOption(GnuDemanglerAnalyzer.OPTION_NAME_USE_DEPRECATED_DEMANGLER, true);
setOption(GnuDemanglerAnalyzer.OPTION_NAME_DEMANGLER_PARAMETERS, "-s arm");
analyze();
assertNotDemangled(addr, "read_to_end");
assertMessageLogLine("java.io.IOException: Error starting demangler with command");
assertMessageLogLine("Invalid options", GnuDemanglerOptions.GNU_DEMANGLER_V2_33_1);
assertMessageNotInLogLine("Invalid options", GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
}
// things missed:
// -demangle error case in base class...this is OK
// -error case in applyTo method in base class
// -use deprecated demangler case in validateOptions
//==================================================================================================
// Private Methods
//==================================================================================================
private void assertMessageLogLine(String... expected) {
String allMessages = log.toString();
String[] logLines = allMessages.split("\n");
for (String line : logLines) {
if (StringUtilities.containsAllIgnoreCase(line, expected)) {
return;
}
}
fail("The folllowing source text did not have a line containing:\n" +
Arrays.toString(expected) + "\n\nActual Text:\n" + allMessages);
}
private void assertMessageNotInLogLine(String... expected) {
String allMessages = log.toString();
String[] logLines = allMessages.split("\n");
for (String line : logLines) {
if (StringUtilities.containsAllIgnoreCase(line, expected)) {
fail("The folllowing source text unexpectedly has a line containing:\n" +
Arrays.toString(expected) + "\n\nActual Text:\n" + allMessages);
}
}
}
private void analyze() {
tx(program, () -> analyzer.added(program, program.getMemory(), TaskMonitor.DUMMY, log));
}
private void assertNotDemangled(Address addr, String name) {
SymbolTable st = program.getSymbolTable();
Symbol[] symbols = st.getSymbols(addr);
for (Symbol s : symbols) {
if (s.getName().equals(name)) {
fail("Symbol should not have been demangled '" + name + "'");
}
}
}
private void assertDemangled(Address addr, String name) {
SymbolTable st = program.getSymbolTable();
Symbol[] symbols = st.getSymbols(addr);
for (Symbol s : symbols) {
if (s.getName().equals(name)) {
return;
}
}
fail("Unable to find demangled symbol '" + name + "'");
}
private void setOption(String optionName, boolean doUse) {
String fullOptionName = analyzer.getName() + Options.DELIMITER_STRING + optionName;
Options options = program.getOptions("Analyzers");
for (String name : options.getOptionNames()) {
if (name.equals(fullOptionName)) {
tx(program, () -> options.setBoolean(optionName, doUse));
// we must call this manually, since we are not using a tool
analyzer.optionsChanged(options, program);
return;
}
}
fail("Could not find option '" + optionName + "'");
}
private void setOption(String optionName, String value) {
String fullOptionName = analyzer.getName() + Options.DELIMITER_STRING + optionName;
Options options = program.getOptions("Analyzers");
for (String name : options.getOptionNames()) {
if (name.equals(fullOptionName)) {
tx(program, () -> options.setString(optionName, value));
// we must call this manually, since we are not using a tool
analyzer.optionsChanged(options, program);
return;
}
}
fail("Could not find option '" + optionName + "'");
}
private void createSymbol(Address addr, String mangled) {
AddLabelCmd cmd = new AddLabelCmd(addr, mangled, SourceType.ANALYSIS);
applyCmd(program, cmd);
}
private Address addr(String addr) {
return program.getAddressFactory().getAddress(addr);
}
private void registerOptions() {
Options options = program.getOptions(Program.ANALYSIS_PROPERTIES);
Options analyzerOptions = options.getOptions(analyzer.getName());
analyzer.registerOptions(analyzerOptions, program);
}
}

View file

@ -33,7 +33,8 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
process = GnuDemanglerNativeProcess.getDemanglerNativeProcess(); process = GnuDemanglerNativeProcess
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_33_1);
parser = new GnuDemanglerParser(process); parser = new GnuDemanglerParser(process);
} }
@ -41,38 +42,37 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void test() throws Exception { public void test() throws Exception {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
demangle(process, parser, "_ZTVN6Magick21DrawableTextAntialiasE"); demangle("_ZTVN6Magick21DrawableTextAntialiasE");
demangle(process, parser, "_ZGVZN10KDirLister11emitChangesEvE3dot");//guard variables demangle("_ZGVZN10KDirLister11emitChangesEvE3dot");//guard variables
demangle(process, parser, "_ZZ18__gthread_active_pvE20__gthread_active_ptr"); demangle("_ZZ18__gthread_active_pvE20__gthread_active_ptr");
demangle(process, parser, "_ZNSt10_List_baseIN6Magick5VPathESaIS1_EE5clearEv"); demangle("_ZNSt10_List_baseIN6Magick5VPathESaIS1_EE5clearEv");
demangle(process, parser, "_ZTISt14unary_functionIPN9MagickLib12_DrawContextEvE"); demangle("_ZTISt14unary_functionIPN9MagickLib12_DrawContextEvE");
demangle(process, parser, "_ZTSSt14unary_functionIPN9MagickLib12_DrawContextEvE"); demangle("_ZTSSt14unary_functionIPN9MagickLib12_DrawContextEvE");
demangle(process, parser, "_ZTCN4Arts17StdoutWriter_implE68_NS_11Object_skelE"); demangle("_ZTCN4Arts17StdoutWriter_implE68_NS_11Object_skelE");
demangle(process, parser, "_ZN6Magick5ImageD1Ev"); demangle("_ZN6Magick5ImageD1Ev");
demangle(process, parser, demangle(
"_ZN6Magick19matteFloodfillImageC2ERKNS_5ColorEjiiN9MagickLib11PaintMethodE"); "_ZN6Magick19matteFloodfillImageC2ERKNS_5ColorEjiiN9MagickLib11PaintMethodE");
demangle(process, parser, "_ZThn8_N14nsPrintSession6AddRefEv");// non-virtual thunk demangle("_ZThn8_N14nsPrintSession6AddRefEv");// non-virtual thunk
demangle(process, parser, demangle(
"_ZTv0_n24_NSt19basic_ostringstreamIcSt11char_traitsIcE14pool_allocatorIcEED0Ev");// virtual thunk "_ZTv0_n24_NSt19basic_ostringstreamIcSt11char_traitsIcE14pool_allocatorIcEED0Ev");// virtual thunk
demangle(process, parser, "_ZTch0_h16_NK8KHotKeys13WindowTrigger4copyEPNS_10ActionDataE");// covariant return thunk demangle("_ZTch0_h16_NK8KHotKeys13WindowTrigger4copyEPNS_10ActionDataE");// covariant return thunk
demangle(process, parser, "_ZNK2cc14ScrollSnapTypeneERKS0_"); demangle("_ZNK2cc14ScrollSnapTypeneERKS0_");
List<String> list = loadTextResource(GnuDemanglerParserTest.class, "libMagick.symbols.txt"); List<String> list = loadTextResource(GnuDemanglerParserTest.class, "libMagick.symbols.txt");
for (String mangled : list) { for (String mangled : list) {
if (mangled == null) { if (mangled == null) {
break; break;
} }
demangle(process, parser, mangled); demangle(mangled);
} }
System.out.println("Elapsed Time: " + (System.currentTimeMillis() - start)); System.out.println("Elapsed Time: " + (System.currentTimeMillis() - start));
} }
private void demangle(GnuDemanglerNativeProcess process, GnuDemanglerParser parser, private void demangle(String mangled) throws IOException {
String mangled) throws IOException {
String demangled = process.demangle(mangled); String demangled = process.demangle(mangled);
assertNotNull(demangled); assertNotNull(demangled);
assertNotEquals(mangled, demangled); assertNotEquals(mangled, demangled);
@ -81,14 +81,12 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
} }
@Test @Test
public void testParsingBug() { public void testOverloadedShiftOperatorParsingBug() {
// std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char> >(std::basic_istream<char, std::char_traits<char> >&, char&) parser = new GnuDemanglerParser(null);
// _ZStrsIcSt11char_traitsIcEERSt13basic_istreamIT_T0_ES6_RS3_
// _ZStrsIcSt11char_traitsIcESaIcEERSt13basic_istreamIT_T0_ES7_RSbIS4_S5_T1_E
GnuDemanglerParser parser = new GnuDemanglerParser(null);
DemangledObject object = parser.parse(null, DemangledObject object = parser.parse(null,
"std::basic_istream<char, std::char_traits<char> >& std::operator>><char, std::char_traits<char> >(std::basic_istream<char, std::char_traits<char> >&, char&)"); "std::basic_istream<char, std::char_traits<char> >& " +
"std::operator>><char, std::char_traits<char> >" +
"(std::basic_istream<char, std::char_traits<char> >&, char&)");
String name = object.getName(); String name = object.getName();
assertEquals("operator>><char,std--char_traits<char>>", name); assertEquals("operator>><char,std--char_traits<char>>", name);
} }
@ -210,6 +208,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
public void testFunctionPointers() throws Exception { public void testFunctionPointers() throws Exception {
String mangled = "__t6XpsMap2ZlZP14CORBA_TypeCodePFRCl_UlUlUlf"; String mangled = "__t6XpsMap2ZlZP14CORBA_TypeCodePFRCl_UlUlUlf";
process = GnuDemanglerNativeProcess
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled); String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled); DemangledObject object = parser.parse(mangled, demangled);
@ -431,6 +432,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// //
String mangled = "CalcPortExposedRect__13LScrollerViewCFR4Rectb"; String mangled = "CalcPortExposedRect__13LScrollerViewCFR4Rectb";
process = GnuDemanglerNativeProcess
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled); String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled); DemangledObject object = parser.parse(mangled, demangled);
@ -452,6 +456,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// //
String mangled = "__dt__Q26MsoDAL9VertFrameFv"; String mangled = "__dt__Q26MsoDAL9VertFrameFv";
process = GnuDemanglerNativeProcess
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled); String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled); DemangledObject object = parser.parse(mangled, demangled);
@ -491,6 +498,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// //
String mangled = "GetColWidths__13CDataRendererCFRA7_s"; String mangled = "GetColWidths__13CDataRendererCFRA7_s";
process = GnuDemanglerNativeProcess
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled); String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled); DemangledObject object = parser.parse(mangled, demangled);
@ -512,6 +522,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// //
String mangled = "GetColWidths__13CDataRendererCFPA7_s"; String mangled = "GetColWidths__13CDataRendererCFPA7_s";
process = GnuDemanglerNativeProcess
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled); String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled); DemangledObject object = parser.parse(mangled, demangled);
@ -567,6 +580,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// //
String mangled = "_gmStage2__FP12SECTION_INFOPiPA12_iiPCs"; String mangled = "_gmStage2__FP12SECTION_INFOPiPA12_iiPCs";
process = GnuDemanglerNativeProcess
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled); String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled); DemangledObject object = parser.parse(mangled, demangled);
@ -598,6 +614,9 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// //
String mangled = "__ct__Q24CStr6BufferFR4CStrUl"; String mangled = "__ct__Q24CStr6BufferFR4CStrUl";
process = GnuDemanglerNativeProcess
.getDemanglerNativeProcess(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
String demangled = process.demangle(mangled); String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled); DemangledObject object = parser.parse(mangled, demangled);
@ -1016,7 +1035,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
} }
@Test @Test
public void testBob() throws Exception { public void testTemplatesThatContainFunctionSignatures() throws Exception {
// //
// Mangled: _ZNSt6vectorIN5boost8functionIFvvEEESaIS3_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS3_S5_EERKS3_ // Mangled: _ZNSt6vectorIN5boost8functionIFvvEEESaIS3_EE13_M_insert_auxEN9__gnu_cxx17__normal_iteratorIPS3_S5_EERKS3_
// //
@ -1085,6 +1104,7 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
// Mangled: _ZN12uavcan_stm329CanDriverC1ILj64EEERA2_AT__NS_9CanRxItemE // Mangled: _ZN12uavcan_stm329CanDriverC1ILj64EEERA2_AT__NS_9CanRxItemE
// //
// Demangled: uavcan_stm32::CanDriver::CanDriver<64u>(uavcan_stm32::CanRxItem (&) [2][64u]) // Demangled: uavcan_stm32::CanDriver::CanDriver<64u>(uavcan_stm32::CanRxItem (&) [2][64u])
//
String mangled = "_ZN12uavcan_stm329CanDriverC1ILj64EEERA2_AT__NS_9CanRxItemE"; String mangled = "_ZN12uavcan_stm329CanDriverC1ILj64EEERA2_AT__NS_9CanRxItemE";
@ -1110,7 +1130,28 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
String mangled = "uv__dup"; String mangled = "uv__dup";
GnuDemangler demangler = new GnuDemangler(); GnuDemangler demangler = new GnuDemangler();
DemangledObject res = demangler.demangle(mangled, true); DemangledObject res = demangler.demangle(mangled);
assertNull(res); assertNull(res);
} }
// @Test TODO upcoming fix for GT-3545
public void testFunctionWithLambda_WrappingAnotherFunctionCall() throws Exception {
//
// Mangled: _Z11wrap_360_cdIiEDTcl8wrap_360fp_Lf42c80000EEET_
//
// Demangled: (wrap_360({parm#1}, (float)[42c80000])) wrap_360_cd<int>(int)
//
String mangled = "_Z11wrap_360_cdIiEDTcl8wrap_360fp_Lf42c80000EEET_";
String demangled = process.demangle(mangled);
DemangledObject object = parser.parse(mangled, demangled);
assertNotNull(object);
assertTrue(object instanceof DemangledFunction);
// TODO maybe put full output in setUtilDemangled()
String signature = object.getSignature(false);
assertEquals("undefined wrap_360_cd<int>(int)", signature);
}
} }

View file

@ -17,12 +17,14 @@ package ghidra.app.util.demangler.gnu;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.io.IOException;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import generic.test.AbstractGenericTest; import generic.test.AbstractGenericTest;
import ghidra.app.cmd.label.DemanglerCmd; import ghidra.app.util.demangler.DemangledException;
import ghidra.app.util.demangler.*; import ghidra.app.util.demangler.DemangledObject;
import ghidra.program.database.ProgramDB; import ghidra.program.database.ProgramDB;
import ghidra.program.model.address.Address; import ghidra.program.model.address.Address;
import ghidra.program.model.data.TerminatedStringDataType; import ghidra.program.model.data.TerminatedStringDataType;
@ -30,6 +32,7 @@ import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Data; import ghidra.program.model.listing.Data;
import ghidra.program.model.symbol.*; import ghidra.program.model.symbol.*;
import ghidra.test.ToyProgramBuilder; import ghidra.test.ToyProgramBuilder;
import ghidra.util.Msg;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class GnuDemanglerTest extends AbstractGenericTest { public class GnuDemanglerTest extends AbstractGenericTest {
@ -52,7 +55,7 @@ public class GnuDemanglerTest extends AbstractGenericTest {
demangler.canDemangle(program);// this perform initialization demangler.canDemangle(program);// this perform initialization
// this throws an exception with the bug in place // this throws an exception with the bug in place
demangler.demangle(mangled, true); demangler.demangle(mangled);
} }
@Test @Test
@ -63,8 +66,10 @@ public class GnuDemanglerTest extends AbstractGenericTest {
GnuDemangler demangler = new GnuDemangler(); GnuDemangler demangler = new GnuDemangler();
demangler.canDemangle(program);// this perform initialization demangler.canDemangle(program);// this perform initialization
GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDemangleOnlyKnownPatterns(false);
try { try {
demangler.demangle(mangled, false); demangler.demangle(mangled, options);
fail("Demangle should have failed attempting to demangle a non-mangled string"); fail("Demangle should have failed attempting to demangle a non-mangled string");
} }
catch (DemangledException e) { catch (DemangledException e) {
@ -80,7 +85,7 @@ public class GnuDemanglerTest extends AbstractGenericTest {
GnuDemangler demangler = new GnuDemangler(); GnuDemangler demangler = new GnuDemangler();
demangler.canDemangle(program);// this perform initialization demangler.canDemangle(program);// this perform initialization
DemangledObject result = demangler.demangle(mangled, true); DemangledObject result = demangler.demangle(mangled);
assertNull("Demangle did not skip a name that does not match a known mangled pattern", assertNull("Demangle did not skip a name that does not match a known mangled pattern",
result); result);
} }
@ -97,13 +102,13 @@ public class GnuDemanglerTest extends AbstractGenericTest {
symbolTable.createLabel(addr("01001000"), mangled, SourceType.IMPORTED); symbolTable.createLabel(addr("01001000"), mangled, SourceType.IMPORTED);
GnuDemangler demangler = new GnuDemangler(); GnuDemangler demangler = new GnuDemangler();
DemangledObject obj = demangler.demangle(mangled, true); DemangledObject obj = demangler.demangle(mangled);
assertNotNull(obj); assertNotNull(obj);
//assertEquals("typeinfo for AP_HAL::HAL::Callbacks", obj.getSignature(false)); //assertEquals("typeinfo for AP_HAL::HAL::Callbacks", obj.getSignature(false));
assertTrue( assertTrue(
obj.applyTo(program, addr("01001000"), new DemanglerOptions(), TaskMonitor.DUMMY)); obj.applyTo(program, addr("01001000"), new GnuDemanglerOptions(), TaskMonitor.DUMMY));
Symbol s = symbolTable.getPrimarySymbol(addr("01001000")); Symbol s = symbolTable.getPrimarySymbol(addr("01001000"));
assertNotNull(s); assertNotNull(s);
@ -130,13 +135,13 @@ public class GnuDemanglerTest extends AbstractGenericTest {
symbolTable.createLabel(addr("01001000"), mangled, SourceType.IMPORTED); symbolTable.createLabel(addr("01001000"), mangled, SourceType.IMPORTED);
GnuDemangler demangler = new GnuDemangler(); GnuDemangler demangler = new GnuDemangler();
DemangledObject obj = demangler.demangle(mangled, true); DemangledObject obj = demangler.demangle(mangled);
assertNotNull(obj); assertNotNull(obj);
assertEquals("typeinfo name for AP_HAL::HAL::Callbacks", obj.getSignature(false)); assertEquals("typeinfo name for AP_HAL::HAL::Callbacks", obj.getSignature(false));
assertTrue( assertTrue(
obj.applyTo(program, addr("01001000"), new DemanglerOptions(), TaskMonitor.DUMMY)); obj.applyTo(program, addr("01001000"), new GnuDemanglerOptions(), TaskMonitor.DUMMY));
Symbol s = symbolTable.getPrimarySymbol(addr("01001000")); Symbol s = symbolTable.getPrimarySymbol(addr("01001000"));
assertNotNull(s); assertNotNull(s);
@ -161,7 +166,10 @@ public class GnuDemanglerTest extends AbstractGenericTest {
GnuDemangler demangler = new GnuDemangler(); GnuDemangler demangler = new GnuDemangler();
demangler.canDemangle(program);// this perform initialization demangler.canDemangle(program);// this perform initialization
DemangledObject result = demangler.demangle(mangled, false); GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDemangleOnlyKnownPatterns(false);
options.setDemanglerName(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
DemangledObject result = demangler.demangle(mangled, options);
assertNotNull(result); assertNotNull(result);
assertEquals("undefined MyFunction::~MyFunction(void)", result.getSignature(false)); assertEquals("undefined MyFunction::~MyFunction(void)", result.getSignature(false));
} }
@ -184,10 +192,63 @@ public class GnuDemanglerTest extends AbstractGenericTest {
GnuDemangler demangler = new GnuDemangler(); GnuDemangler demangler = new GnuDemangler();
demangler.canDemangle(program);// this perform initialization demangler.canDemangle(program);// this perform initialization
DemangledObject result = demangler.demangle(mangled, true); GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDemangleOnlyKnownPatterns(true); // do not try
options.setDemanglerName(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
DemangledObject result = demangler.demangle(mangled, options);
assertNull(result); assertNull(result);
} }
@Test
public void testDemangler_Format_CodeWarrior_MacOS8or9() throws DemangledException {
// .scroll__10TTextPanelFUcsi
String mangled = ".scroll__10TTextPanelFUcsi";
GnuDemangler demangler = new GnuDemangler();
demangler.canDemangle(program);// this perform initialization
GnuDemanglerOptions options = new GnuDemanglerOptions();
options.setDemangleOnlyKnownPatterns(false);
options.setDemanglerName(GnuDemanglerOptions.GNU_DEMANGLER_V2_24);
DemangledObject result = demangler.demangle(mangled, options);
assertNotNull(result);
assertEquals("undefined TTextPanel::scroll(unsigned char,short,int)",
result.getSignature(false));
}
@Test
public void testGnuNativeProcessWithValidArguments() {
String demanglerName = GnuDemanglerOptions.GNU_DEMANGLER_DEFAULT;
String applicationArguments = "-s auto";
try {
GnuDemanglerNativeProcess.getDemanglerNativeProcess(demanglerName,
applicationArguments);
}
catch (IOException e) {
fail("Expected an exception when passing unknown arguments to the native demangler");
}
}
@Test
public void testGnuNativeProcessWithUnknownArguments() {
String demanglerName = GnuDemanglerOptions.GNU_DEMANGLER_DEFAULT;
String applicationArguments = "-s MrBob";
try {
GnuDemanglerNativeProcess.getDemanglerNativeProcess(demanglerName,
applicationArguments);
fail("Expected an exception when passing unknown arguments to the native demangler");
}
catch (IOException e) {
// expected
Msg.error(this, "Test error", e);
}
}
private Address addr(String address) { private Address addr(String address) {
return program.getAddressFactory().getAddress(address); return program.getAddressFactory().getAddress(address);
} }

View file

@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
li { font-family:times new roman; font-size:14pt; } li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/* /*
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
td { font-family:times new roman; font-size:14pt; vertical-align: top; } td { font-family:times new roman; font-size:14pt; vertical-align: top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; } th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
code { color: black; font-family: courier new; font-size: 14pt; } /*
Code-like formatting for things such as file system paths and proper names of classes,
methods, etc. To apply this to a file path, use this syntax:
<CODE CLASS="path">...</CODE>
*/
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }

View file

@ -94,7 +94,7 @@ public class MicrosoftDemanglerScript extends GhidraScript {
} }
private void demangle(String mangled) throws Exception { private void demangle(String mangled) throws Exception {
DemangledObject demangled = demangler.demangle(mangled, true); DemangledObject demangled = demangler.demangle(mangled);
printf("magled %s\ndemangled %s", mangled, demangled); printf("magled %s\ndemangled %s", mangled, demangled);
} }
} }

View file

@ -0,0 +1,68 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.plugin.core.analysis;
import ghidra.app.util.demangler.*;
import ghidra.app.util.demangler.microsoft.MicrosoftDemangler;
import ghidra.app.util.importer.MessageLog;
import ghidra.framework.options.Options;
import ghidra.program.model.listing.Program;
/**
* A version of the demangler analyzer to handle microsoft symbols
*/
public class MicrosoftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
private static final String NAME = "Demangler Microsoft";
private static final String DESCRIPTION =
"After a function is created, this analyzer will attempt to demangle " +
"the name and apply datatypes to parameters.";
private final static String OPTION_NAME_APPLY_SIGNATURE = "Apply Function Signatures";
private static final String OPTION_DESCRIPTION_APPLY_SIGNATURE =
"Apply any recovered function signature, in addition to the function name";
private boolean applyFunctionSignature = true;
private MicrosoftDemangler demangler = new MicrosoftDemangler();
public MicrosoftDemanglerAnalyzer() {
super(NAME, DESCRIPTION);
setDefaultEnablement(true);
}
@Override
public boolean canAnalyze(Program program) {
return demangler.canDemangle(program);
}
@Override
public void registerOptions(Options options, Program program) {
options.registerOption(OPTION_NAME_APPLY_SIGNATURE, applyFunctionSignature, null,
OPTION_DESCRIPTION_APPLY_SIGNATURE);
}
@Override
public void optionsChanged(Options options, Program program) {
applyFunctionSignature =
options.getBoolean(OPTION_NAME_APPLY_SIGNATURE, applyFunctionSignature);
}
@Override
protected DemangledObject doDemangle(String mangled, DemanglerOptions options, MessageLog log)
throws DemangledException {
DemangledObject demangled = demangler.demangle(mangled, options);
return demangled;
}
}

View file

@ -15,8 +15,6 @@
*/ */
package ghidra.app.util.demangler.microsoft; package ghidra.app.util.demangler.microsoft;
import java.util.regex.Pattern;
import ghidra.app.util.demangler.*; import ghidra.app.util.demangler.*;
import ghidra.app.util.opinion.MSCoffLoader; import ghidra.app.util.opinion.MSCoffLoader;
import ghidra.app.util.opinion.PeLoader; import ghidra.app.util.opinion.PeLoader;
@ -30,15 +28,6 @@ import util.demangler.GenericDemangledException;
*/ */
public class MicrosoftDemangler implements Demangler { public class MicrosoftDemangler implements Demangler {
/**
* This represents an odd symbol that looks mangled, but we don't know what to do with. It
* is of the form:
* ?BobsStuffIO@344text__@@U_text@@?W
*
* where the last character is preceded by a special character, such as ?, *, -, etc
*/
private static Pattern INVALID_TRAILING_CHARS_PATTERN = Pattern.compile(".*@@[?*`%~+/-][A-Z]");
public MicrosoftDemangler() { public MicrosoftDemangler() {
} }
@ -50,6 +39,7 @@ public class MicrosoftDemangler implements Demangler {
} }
@Override @Override
@Deprecated(since = "9.2", forRemoval = true)
public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns) public DemangledObject demangle(String mangled, boolean demangleOnlyKnownPatterns)
throws DemangledException { throws DemangledException {
try { try {
@ -61,6 +51,19 @@ public class MicrosoftDemangler implements Demangler {
} }
} }
@Override
public DemangledObject demangle(String mangled, DemanglerOptions options)
throws DemangledException {
try {
DemangledObject demangled = demangleMS(mangled, options.demangleOnlyKnownPatterns());
return demangled;
}
catch (GenericDemangledException e) {
throw new DemangledException(true);
}
}
private DemangledObject demangleMS(String mangled, boolean demangleOnlyKnownPatterns) private DemangledObject demangleMS(String mangled, boolean demangleOnlyKnownPatterns)
throws GenericDemangledException { throws GenericDemangledException {
if (mangled == null || mangled.length() == 0) { if (mangled == null || mangled.length() == 0) {
@ -69,7 +72,7 @@ public class MicrosoftDemangler implements Demangler {
MDMangGhidra demangler = new MDMangGhidra(); MDMangGhidra demangler = new MDMangGhidra();
try { try {
demangler.demangle(mangled, demangleOnlyKnownPatterns); //not using return type here. demangler.demangle(mangled, demangleOnlyKnownPatterns);
DemangledObject object = demangler.getObject(); DemangledObject object = demangler.getObject();
return object; return object;
} }
@ -80,27 +83,4 @@ public class MicrosoftDemangler implements Demangler {
throw gde; throw gde;
} }
} }
// private boolean isMangled(String mangled) {
// int atpos = mangled.indexOf("@");
// boolean isMangled = mangled.charAt(0) == '?' && atpos != -1;
//
// if (!isMangled) {
// return false;
// }
//
// if (mangled.endsWith("~")) {
// return false;
// }
//
// //
// // Now check for some odd things that we've seen.
// //
// Matcher matcher = INVALID_TRAILING_CHARS_PATTERN.matcher(mangled);
// if (matcher.matches()) {
// return false;
// }
//
// return true;
// }
} }

View file

@ -33,10 +33,6 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
private ProgramDB program; private ProgramDB program;
public MicrosoftDemanglerTest() {
super();
}
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
ToyProgramBuilder builder = new ToyProgramBuilder("test", true); ToyProgramBuilder builder = new ToyProgramBuilder("test", true);
@ -49,7 +45,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
String mangled = "?Te@NS1@BobsStuff@@0QAY0BAA@$$CBIA"; String mangled = "?Te@NS1@BobsStuff@@0QAY0BAA@$$CBIA";
MicrosoftDemangler demangler = new MicrosoftDemangler(); MicrosoftDemangler demangler = new MicrosoftDemangler();
DemangledObject demangledObject = demangler.demangle(mangled, true); DemangledObject demangledObject = demangler.demangle(mangled);
int txID = program.startTransaction("Test"); int txID = program.startTransaction("Test");
@ -67,7 +63,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
String mangled = "??0_LocaleUpdate@@QAE@PAUlocaleinfo_struct@@@Z"; String mangled = "??0_LocaleUpdate@@QAE@PAUlocaleinfo_struct@@@Z";
MicrosoftDemangler demangler = new MicrosoftDemangler(); MicrosoftDemangler demangler = new MicrosoftDemangler();
DemangledObject demangledObj = demangler.demangle(mangled, true); DemangledObject demangledObj = demangler.demangle(mangled);
assertNotNull(demangledObj); assertNotNull(demangledObj);
} }
@ -78,7 +74,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
MicrosoftDemangler demangler = new MicrosoftDemangler(); MicrosoftDemangler demangler = new MicrosoftDemangler();
DemangledObject demangledObj = null; DemangledObject demangledObj = null;
try { try {
demangledObj = demangler.demangle(mangled, true); demangledObj = demangler.demangle(mangled);
} }
catch (DemangledException e) { catch (DemangledException e) {
// Expected // Expected
@ -94,7 +90,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
MicrosoftDemangler demangler = new MicrosoftDemangler(); MicrosoftDemangler demangler = new MicrosoftDemangler();
DemangledObject demangledObj = null; DemangledObject demangledObj = null;
try { try {
demangledObj = demangler.demangle(mangled, true); demangledObj = demangler.demangle(mangled);
} }
catch (DemangledException e) { catch (DemangledException e) {
// Expected // Expected
@ -110,7 +106,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
MicrosoftDemangler demangler = new MicrosoftDemangler(); MicrosoftDemangler demangler = new MicrosoftDemangler();
DemangledObject demangledObj = null; DemangledObject demangledObj = null;
try { try {
demangledObj = demangler.demangle(mangled, true); demangledObj = demangler.demangle(mangled);
} }
catch (DemangledException e) { catch (DemangledException e) {
// Expected // Expected
@ -126,7 +122,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
MicrosoftDemangler demangler = new MicrosoftDemangler(); MicrosoftDemangler demangler = new MicrosoftDemangler();
DemangledObject demangledObj = null; DemangledObject demangledObj = null;
try { try {
demangledObj = demangler.demangle(mangled, true); demangledObj = demangler.demangle(mangled);
} }
catch (DemangledException e) { catch (DemangledException e) {
// Expected // Expected
@ -142,7 +138,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
MicrosoftDemangler demangler = new MicrosoftDemangler(); MicrosoftDemangler demangler = new MicrosoftDemangler();
DemangledObject demangledObj = null; DemangledObject demangledObj = null;
try { try {
demangledObj = demangler.demangle(mangled, true); demangledObj = demangler.demangle(mangled);
} }
catch (DemangledException e) { catch (DemangledException e) {
// Expected // Expected
@ -158,7 +154,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
MicrosoftDemangler demangler = new MicrosoftDemangler(); MicrosoftDemangler demangler = new MicrosoftDemangler();
DemangledObject demangledObj = null; DemangledObject demangledObj = null;
try { try {
demangledObj = demangler.demangle(mangled, true); demangledObj = demangler.demangle(mangled);
} }
catch (DemangledException e) { catch (DemangledException e) {
// Expected // Expected
@ -174,7 +170,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
MicrosoftDemangler demangler = new MicrosoftDemangler(); MicrosoftDemangler demangler = new MicrosoftDemangler();
DemangledObject demangledObj = null; DemangledObject demangledObj = null;
try { try {
demangledObj = demangler.demangle(mangled, true); demangledObj = demangler.demangle(mangled);
} }
catch (DemangledException e) { catch (DemangledException e) {
// Expected // Expected
@ -190,7 +186,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
MicrosoftDemangler demangler = new MicrosoftDemangler(); MicrosoftDemangler demangler = new MicrosoftDemangler();
DemangledObject demangledObj = null; DemangledObject demangledObj = null;
try { try {
demangledObj = demangler.demangle(mangled, true); demangledObj = demangler.demangle(mangled);
} }
catch (DemangledException e) { catch (DemangledException e) {
// Expected // Expected
@ -206,7 +202,7 @@ public class MicrosoftDemanglerTest extends AbstractGenericTest {
MicrosoftDemangler demangler = new MicrosoftDemangler(); MicrosoftDemangler demangler = new MicrosoftDemangler();
DemangledObject demangledObj = null; DemangledObject demangledObj = null;
try { try {
demangledObj = demangler.demangle(mangled, true); demangledObj = demangler.demangle(mangled);
} }
catch (DemangledException e) { catch (DemangledException e) {
// Expected // Expected

View file

@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
li { font-family:times new roman; font-size:14pt; } li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/* /*
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
td { font-family:times new roman; font-size:14pt; vertical-align: top; } td { font-family:times new roman; font-size:14pt; vertical-align: top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; } th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
code { color: black; font-family: courier new; font-size: 14pt; } /*
Code-like formatting for things such as file system paths and proper names of classes,
methods, etc. To apply this to a file path, use this syntax:
<CODE CLASS="path">...</CODE>
*/
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }

View file

@ -82,8 +82,9 @@ class LoadPdbTask extends Task {
} }
try { try {
AutoAnalysisManager.getAnalysisManager(program).scheduleWorker(worker, null, true, AutoAnalysisManager.getAnalysisManager(program)
monitor); .scheduleWorker(worker, null, true,
monitor);
} }
catch (InterruptedException | CancelledException e1) { catch (InterruptedException | CancelledException e1) {
// ignore // ignore
@ -117,7 +118,7 @@ class LoadPdbTask extends Task {
private void analyzeSymbols(TaskMonitor monitor, MessageLog log) { private void analyzeSymbols(TaskMonitor monitor, MessageLog log) {
DemanglerAnalyzer demanglerAnalyzer = new DemanglerAnalyzer(); MicrosoftDemanglerAnalyzer demanglerAnalyzer = new MicrosoftDemanglerAnalyzer();
String analyzerName = demanglerAnalyzer.getName(); String analyzerName = demanglerAnalyzer.getName();
Options analysisProperties = program.getOptions(Program.ANALYSIS_PROPERTIES); Options analysisProperties = program.getOptions(Program.ANALYSIS_PROPERTIES);

View file

@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
li { font-family:times new roman; font-size:14pt; } li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/* /*
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
td { font-family:times new roman; font-size:14pt; vertical-align: top; } td { font-family:times new roman; font-size:14pt; vertical-align: top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; } th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
code { color: black; font-family: courier new; font-size: 14pt; } /*
Code-like formatting for things such as file system paths and proper names of classes,
methods, etc. To apply this to a file path, use this syntax:
<CODE CLASS="path">...</CODE>
*/
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }

View file

@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
li { font-family:times new roman; font-size:14pt; } li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/* /*
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
td { font-family:times new roman; font-size:14pt; vertical-align: top; } td { font-family:times new roman; font-size:14pt; vertical-align: top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; } th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
code { color: black; font-family: courier new; font-size: 14pt; } /*
Code-like formatting for things such as file system paths and proper names of classes,
methods, etc. To apply this to a file path, use this syntax:
<CODE CLASS="path">...</CODE>
*/
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }

View file

@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
li { font-family:times new roman; font-size:14pt; } li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/* /*
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
td { font-family:times new roman; font-size:14pt; vertical-align: top; } td { font-family:times new roman; font-size:14pt; vertical-align: top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; } th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
code { color: black; font-family: courier new; font-size: 14pt; } /*
Code-like formatting for things such as file system paths and proper names of classes,
methods, etc. To apply this to a file path, use this syntax:
<CODE CLASS="path">...</CODE>
*/
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }

View file

@ -28,7 +28,7 @@ body { margin-bottom: 50px; margin-left: 10px; margin-right: 10px; margin-top: 1
li { font-family:times new roman; font-size:14pt; } li { font-family:times new roman; font-size:14pt; }
h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; } h1 { color:#000080; font-family:times new roman; font-size:36pt; font-style:italic; font-weight:bold; text-align:center; }
h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; } h2 { margin: 10px; margin-top: 20px; color:#984c4c; font-family:times new roman; font-size:18pt; font-weight:bold; }
h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; font-size:14pt; font-weight:bold; } h3 { margin-left: 10px; margin-top: 20px; color:#0000ff; font-family:times new roman; `font-size:14pt; font-weight:bold; }
h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; } h4 { margin-left: 10px; margin-top: 20px; font-family:times new roman; font-size:14pt; font-style:italic; }
/* /*
@ -55,4 +55,10 @@ table { margin-left: 20px; margin-top: 10px; width: 80%;}
td { font-family:times new roman; font-size:14pt; vertical-align: top; } td { font-family:times new roman; font-size:14pt; vertical-align: top; }
th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; } th { font-family:times new roman; font-size:14pt; font-weight:bold; background-color: #EDF3FE; }
code { color: black; font-family: courier new; font-size: 14pt; } /*
Code-like formatting for things such as file system paths and proper names of classes,
methods, etc. To apply this to a file path, use this syntax:
<CODE CLASS="path">...</CODE>
*/
code { color: black; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }
code.path { color: #4682B4; font-weight: bold; font-family: courier new, monospace; font-size: 14pt; white-space: nowrap; }

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,25 +15,29 @@
*/ */
package docking.options.editor; package docking.options.editor;
import ghidra.framework.options.EditorState;
import java.awt.Dimension; import java.awt.Dimension;
import ghidra.framework.options.EditorState;
import ghidra.util.layout.HorizontalLayout;
/** /**
* A custom OptionComponent that controls it's own display using the editor component of the * A custom OptionComponent that controls it's own display using the editor component of the
* given EditorState. * given EditorState.
*/ */
public class CustomOptionComponent extends GenericOptionsComponent { public class CustomOptionComponent extends GenericOptionsComponent {
protected CustomOptionComponent( EditorState editorState ) { protected CustomOptionComponent(EditorState editorState) {
super( editorState ); super(editorState);
// this class is designed to let the editor component handle the display and editing // this layout allows us to easily left-align the single component in this container
add( editorState.getEditorComponent() ); setLayout(new HorizontalLayout(0));
}
@Override // this class is designed to let the editor component handle the display and editing
protected Dimension getPreferredAlignmentSize() { add(editorState.getEditorComponent());
return new Dimension( 0, 0 ); }
}
@Override
protected Dimension getPreferredAlignmentSize() {
return new Dimension(0, 0);
}
} }

Some files were not shown because too many files have changed in this diff Show more