mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
GT-3481 - Gnu Demangler - Checkpoint 2 - Most docs and tests done;
analyzer test remains
This commit is contained in:
parent
b774ecb2d6
commit
b4ce3012d7
55 changed files with 854 additions and 1283 deletions
|
@ -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; }
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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|
|
||||||
|
|
|
@ -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 |
|
@ -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"><GHIDRA_INSTALL_DIR>/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,99 @@
|
||||||
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 sing the <CODE>--help</CODE> switch.
|
||||||
|
</P>
|
||||||
|
<P>
|
||||||
|
The GNU demanglers can be found at:
|
||||||
|
<CODE CLASS="path">
|
||||||
|
<GHIDRA_INSTALL_DIR>/GPL/DemanglerGnu/build/os/<OS>/
|
||||||
|
</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 which have been mitigated in
|
||||||
|
the version created for Ghidra.
|
||||||
|
</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>
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -25,7 +25,20 @@ import ghidra.program.model.symbol.*;
|
||||||
import ghidra.util.exception.CancelledException;
|
import ghidra.util.exception.CancelledException;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
// TODO docme
|
/**
|
||||||
|
* 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 abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
public AbstractDemanglerAnalyzer(String name, String description) {
|
public AbstractDemanglerAnalyzer(String name, String description) {
|
||||||
|
@ -35,7 +48,7 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canAnalyze(Program program) {
|
public boolean canAnalyze(Program program) {
|
||||||
// override this to be enable for a binary containing symbols you wisht to process
|
// override this to control program-specific enablement
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,13 +91,38 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO callback before demangling begins...
|
/**
|
||||||
|
* 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) {
|
protected boolean validateOptions(DemanglerOptions options, MessageLog log) {
|
||||||
// override to validate custom options for a particular demangler
|
// override to validate custom options for a particular demangler
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean skipSymbol(Symbol symbol) {
|
/**
|
||||||
|
* 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) {
|
if (symbol.getSource() == SourceType.DEFAULT) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -111,9 +149,13 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract DemangledObject doDemangle(String mangled, DemanglerOptions options,
|
/**
|
||||||
MessageLog log) throws DemangledException;
|
* 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() {
|
protected DemanglerOptions getOptions() {
|
||||||
// note: these can be stored in the analyzer subclass and updated when the
|
// note: these can be stored in the analyzer subclass and updated when the
|
||||||
// analysis options change
|
// analysis options change
|
||||||
|
@ -124,6 +166,15 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
|
||||||
return options;
|
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,
|
protected DemangledObject demangle(String mangled, DemanglerOptions options,
|
||||||
MessageLog log) {
|
MessageLog log) {
|
||||||
|
|
||||||
|
@ -148,6 +199,16 @@ public abstract class AbstractDemanglerAnalyzer extends AbstractAnalyzer {
|
||||||
return demangled;
|
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,
|
protected void apply(Program program, Address address, DemangledObject demangled,
|
||||||
DemanglerOptions options, MessageLog log, TaskMonitor monitor) {
|
DemanglerOptions options, MessageLog log, TaskMonitor monitor) {
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ public class AnalysisOptionsDialog extends DialogComponentProvider implements
|
||||||
AnalysisOptionsDialog(Program program) {
|
AnalysisOptionsDialog(Program program) {
|
||||||
this(List.of(program));
|
this(List.of(program));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*
|
*
|
||||||
|
@ -53,20 +53,20 @@ public class AnalysisOptionsDialog extends DialogComponentProvider implements
|
||||||
super("Analysis Options");
|
super("Analysis Options");
|
||||||
setHelpLocation(new HelpLocation("AutoAnalysisPlugin", "AnalysisOptions"));
|
setHelpLocation(new HelpLocation("AutoAnalysisPlugin", "AnalysisOptions"));
|
||||||
panel = buildComponent(programs);
|
panel = buildComponent(programs);
|
||||||
|
|
||||||
addWorkPanel(panel);
|
addWorkPanel(panel);
|
||||||
addOKButton();
|
addOKButton();
|
||||||
addCancelButton();
|
addCancelButton();
|
||||||
setOkButtonText("Analyze");
|
setOkButtonText("Analyze");
|
||||||
okButton.setMnemonic('A');
|
okButton.setMnemonic('A');
|
||||||
setOkEnabled(true);
|
setOkEnabled(true);
|
||||||
setPreferredSize(800, 400);
|
setPreferredSize(1000, 600);
|
||||||
setRememberSize(true);
|
setRememberSize(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void propertyChange(PropertyChangeEvent evt) {
|
public void propertyChange(PropertyChangeEvent evt) {
|
||||||
|
|
||||||
// On any analyzer status change, update the options for all programs
|
// On any analyzer status change, update the options for all programs
|
||||||
// being analyzed. This is necessary to keep options consistent across all
|
// being analyzed. This is necessary to keep options consistent across all
|
||||||
// programs being analyzed.
|
// programs being analyzed.
|
||||||
|
@ -75,9 +75,9 @@ 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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void okCallback() {
|
public void okCallback() {
|
||||||
|
@ -94,7 +94,7 @@ public class AnalysisOptionsDialog extends DialogComponentProvider implements
|
||||||
boolean wasAnalyzeButtonSelected() {
|
boolean wasAnalyzeButtonSelected() {
|
||||||
return doAnalysis;
|
return doAnalysis;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@link AnalysisPanel}
|
* Constructs a new {@link AnalysisPanel}
|
||||||
*
|
*
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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,14 +60,14 @@ 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;
|
||||||
|
|
||||||
private boolean createBookmarksEnabled = OPTION_DEFAULT_CREATE_BOOKMARKS_ENABLED;
|
private boolean createBookmarksEnabled = OPTION_DEFAULT_CREATE_BOOKMARKS_ENABLED;
|
||||||
|
@ -105,16 +105,16 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
||||||
this.reasonList = new ArrayList<>();
|
this.reasonList = new ArrayList<>();
|
||||||
|
|
||||||
monitor.setMessage("NoReturn - Finding non-returning functions");
|
monitor.setMessage("NoReturn - Finding non-returning functions");
|
||||||
|
|
||||||
AddressSet noReturnSet = new AddressSet();
|
AddressSet noReturnSet = new AddressSet();
|
||||||
|
|
||||||
boolean hadOtherSuspiciousFunctions = detectNoReturn(program, noReturnSet, set);
|
boolean hadOtherSuspiciousFunctions = detectNoReturn(program, noReturnSet, set);
|
||||||
|
|
||||||
// run again with the new known noReturnSet
|
// run again with the new known noReturnSet
|
||||||
if (hadOtherSuspiciousFunctions) {
|
if (hadOtherSuspiciousFunctions) {
|
||||||
detectNoReturn(program, noReturnSet, set);
|
detectNoReturn(program, noReturnSet, set);
|
||||||
}
|
}
|
||||||
|
|
||||||
// mark all detected non-returning functions
|
// mark all detected non-returning functions
|
||||||
AddressIterator noreturns = noReturnSet.getAddresses(true);
|
AddressIterator noreturns = noReturnSet.getAddresses(true);
|
||||||
for (Address address : noreturns) {
|
for (Address address : noreturns) {
|
||||||
|
@ -130,12 +130,12 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// repair the damage for all non-returning functions
|
// repair the damage for all non-returning functions
|
||||||
if (repairDamageEnabled) {
|
if (repairDamageEnabled) {
|
||||||
AddressSet clearInstSet = new AddressSet();
|
AddressSet clearInstSet = new AddressSet();
|
||||||
noreturns = noReturnSet.getAddresses(true);
|
noreturns = noReturnSet.getAddresses(true);
|
||||||
for (Address address : noreturns) {
|
for (Address address : noreturns) {
|
||||||
clearInstSet.add(findPotentialDamagedLocations(program, address));
|
clearInstSet.add(findPotentialDamagedLocations(program, address));
|
||||||
}
|
}
|
||||||
repairDamagedLocations(monitor, clearInstSet);
|
repairDamagedLocations(monitor, clearInstSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,7 +214,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* find locations of potential damage from calls to non-returning functions
|
* find locations of potential damage from calls to non-returning functions
|
||||||
*
|
*
|
||||||
|
@ -278,7 +279,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
||||||
if (fallthruAddr == null) {
|
if (fallthruAddr == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if location right below is an entry point, don't clear it
|
// if location right below is an entry point, don't clear it
|
||||||
Address checkAddr = skipNOPS(fallthruAddr);
|
Address checkAddr = skipNOPS(fallthruAddr);
|
||||||
if (program.getSymbolTable().isExternalEntryPoint(checkAddr) ||
|
if (program.getSymbolTable().isExternalEntryPoint(checkAddr) ||
|
||||||
|
@ -301,7 +302,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
||||||
// entries that are data should not be cleared, only possible bookmarks
|
// entries that are data should not be cleared, only possible bookmarks
|
||||||
ClearFlowAndRepairCmd.clearBadBookmarks(program, clearDataSet, monitor);
|
ClearFlowAndRepairCmd.clearBadBookmarks(program, clearDataSet, monitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
return clearInstSet;
|
return clearInstSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,9 +314,9 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
||||||
AddressSet checkedSet = new AddressSet();
|
AddressSet checkedSet = new AddressSet();
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
|
@ -344,7 +345,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
||||||
// detected a calling issue, check other instructions calling the same place
|
// detected a calling issue, check other instructions calling the same place
|
||||||
Address[] flows = inst.getFlows();
|
Address[] flows = inst.getFlows();
|
||||||
for (Address target : flows) {
|
for (Address target : flows) {
|
||||||
|
|
||||||
int count = 1;
|
int count = 1;
|
||||||
ReferenceIterator refsTo = cp.getReferenceManager().getReferencesTo(target);
|
ReferenceIterator refsTo = cp.getReferenceManager().getReferencesTo(target);
|
||||||
for (Reference reference : refsTo) {
|
for (Reference reference : refsTo) {
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -375,7 +377,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// was suspicious, but evidence didn't pass threshold
|
// was suspicious, but evidence didn't pass threshold
|
||||||
if (count < evidenceThresholdFunctions) {
|
if (count < evidenceThresholdFunctions) {
|
||||||
// if function only calls non-returning functions
|
// if function only calls non-returning functions
|
||||||
|
@ -393,41 +395,42 @@ 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);
|
||||||
|
|
||||||
// follow the flow of the instructions
|
// follow the flow of the instructions
|
||||||
// if hit return, then no good
|
// if hit return, then no good
|
||||||
// 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;
|
||||||
|
|
||||||
while (!todo.isEmpty()) {
|
while (!todo.isEmpty()) {
|
||||||
Address blockAddr = todo.pop();
|
Address blockAddr = todo.pop();
|
||||||
CodeBlock block = model.getCodeBlockAt(blockAddr, monitor);
|
CodeBlock block = model.getCodeBlockAt(blockAddr, monitor);
|
||||||
|
|
||||||
if (block == null) {
|
if (block == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (visited.contains(blockAddr)) {
|
if (visited.contains(blockAddr)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
visited.add(blockAddr);
|
visited.add(blockAddr);
|
||||||
|
|
||||||
FlowType flowType = block.getFlowType();
|
FlowType flowType = block.getFlowType();
|
||||||
if (flowType.isTerminal()) {
|
if (flowType.isTerminal()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if target has a call to it, then can't tell, but suspect...
|
// if target has a call to it, then can't tell, but suspect...
|
||||||
// add all destinations to todo
|
// add all destinations to todo
|
||||||
CodeBlockReferenceIterator destinations = block.getDestinations(monitor);
|
CodeBlockReferenceIterator destinations = block.getDestinations(monitor);
|
||||||
|
|
||||||
// no destinations
|
// no destinations
|
||||||
if (!destinations.hasNext()) {
|
if (!destinations.hasNext()) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -457,7 +460,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
||||||
todo.push(destAddr);
|
todo.push(destAddr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return hitNoReturn;
|
return hitNoReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,11 +490,11 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
||||||
if (flows != null && flows.length > 0) {
|
if (flows != null && flows.length > 0) {
|
||||||
target = flows[0];
|
target = flows[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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();
|
||||||
}
|
}
|
||||||
|
@ -514,11 +517,12 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
||||||
reasonList.add(location);
|
reasonList.add(location);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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();
|
||||||
|
|
||||||
|
@ -666,19 +671,19 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
||||||
if (!instructionAt.getFlowType().isFallthrough()) {
|
if (!instructionAt.getFlowType().isFallthrough()) {
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// instruction has PCODE, might not be a NOP
|
// instruction has PCODE, might not be a NOP
|
||||||
PcodeOp[] pcode = instructionAt.getPcode();
|
PcodeOp[] pcode = instructionAt.getPcode();
|
||||||
if (pcode != null && pcode.length != 0) {
|
if (pcode != null && pcode.length != 0) {
|
||||||
// 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()) {
|
||||||
|
@ -686,7 +691,7 @@ public class FindNoReturnFunctionsAnalyzer extends AbstractAnalyzer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addr = instructionAt.getFallThrough();
|
addr = instructionAt.getFallThrough();
|
||||||
// this shouldn't happen, to have no fallthru, you should have flow, but could be override
|
// this shouldn't happen, to have no fallthru, you should have flow, but could be override
|
||||||
if (addr == null) {
|
if (addr == null) {
|
||||||
|
@ -710,15 +715,15 @@ 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,8 +736,8 @@ 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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
@ -179,7 +145,7 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
|
||||||
pointerEnabled = false;
|
pointerEnabled = false;
|
||||||
addressTablesEnabled = false;
|
addressTablesEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// only analyze programs with address spaces > 16 bits
|
// only analyze programs with address spaces > 16 bits
|
||||||
int bitSize = defaultAddressSpace.getSize();
|
int bitSize = defaultAddressSpace.getSize();
|
||||||
return bitSize > 16;
|
return bitSize > 16;
|
||||||
|
@ -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);
|
||||||
|
|
|
@ -43,7 +43,7 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
|
||||||
|
|
||||||
private final static String NAME = "Disassemble Entry Points";
|
private final static String NAME = "Disassemble Entry Points";
|
||||||
private static final String DESCRIPTION = "Disassembles entry points in newly added memory.";
|
private static final String DESCRIPTION = "Disassembles entry points in newly added memory.";
|
||||||
|
|
||||||
private final static String OPTION_NAME_RESPECT_EXECUTE_FLAG = "Respect Execute Flag";
|
private final static String OPTION_NAME_RESPECT_EXECUTE_FLAG = "Respect Execute Flag";
|
||||||
|
|
||||||
private static final String OPTION_DESCRIPTION_RESPECT_EXECUTE_FLAG =
|
private static final String OPTION_DESCRIPTION_RESPECT_EXECUTE_FLAG =
|
||||||
|
@ -52,7 +52,7 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
|
||||||
private final static boolean OPTION_DEFAULT_RESPECT_EXECUTE_ENABLED = true;
|
private final static boolean OPTION_DEFAULT_RESPECT_EXECUTE_ENABLED = true;
|
||||||
|
|
||||||
private boolean respectExecuteFlags = OPTION_DEFAULT_RESPECT_EXECUTE_ENABLED;
|
private boolean respectExecuteFlags = OPTION_DEFAULT_RESPECT_EXECUTE_ENABLED;
|
||||||
|
|
||||||
private AddressSetView executeSet;
|
private AddressSetView executeSet;
|
||||||
|
|
||||||
public EntryPointAnalyzer() {
|
public EntryPointAnalyzer() {
|
||||||
|
@ -60,12 +60,11 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
|
||||||
setPriority(AnalysisPriority.BLOCK_ANALYSIS);
|
setPriority(AnalysisPriority.BLOCK_ANALYSIS);
|
||||||
setDefaultEnablement(true);
|
setDefaultEnablement(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@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
|
||||||
|
@ -150,14 +150,15 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
|
||||||
if (doLaterSet.isEmpty()) {
|
if (doLaterSet.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Put off the do-later until later if doing block analysis...
|
// Put off the do-later until later if doing block analysis...
|
||||||
if (this.getPriority() == AnalysisPriority.BLOCK_ANALYSIS) {
|
if (this.getPriority() == AnalysisPriority.BLOCK_ANALYSIS) {
|
||||||
AutoAnalysisManager analysisManager = AutoAnalysisManager.getAnalysisManager(program);
|
AutoAnalysisManager analysisManager = AutoAnalysisManager.getAnalysisManager(program);
|
||||||
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());
|
||||||
}
|
}
|
||||||
|
@ -246,7 +249,7 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
|
||||||
recreateFunctionSet.add(func.getEntryPoint());
|
recreateFunctionSet.add(func.getEntryPoint());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
recreateFunctionSet.add(entry);
|
recreateFunctionSet.add(entry);
|
||||||
// Never clear functions that are already created
|
// Never clear functions that are already created
|
||||||
// program.getFunctionManager().removeFunction(entry);
|
// program.getFunctionManager().removeFunction(entry);
|
||||||
|
@ -274,7 +277,7 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
|
||||||
laterIter.remove();
|
laterIter.remove();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// relocation at this place, don't trust it
|
// relocation at this place, don't trust it
|
||||||
if (program.getRelocationTable().getRelocation(entry) != null) {
|
if (program.getRelocationTable().getRelocation(entry) != null) {
|
||||||
laterIter.remove();
|
laterIter.remove();
|
||||||
|
@ -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());
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 " +
|
||||||
|
|
|
@ -26,15 +26,48 @@ public interface Demangler extends ExtensionPoint {
|
||||||
|
|
||||||
public boolean canDemangle(Program program);
|
public boolean canDemangle(Program program);
|
||||||
|
|
||||||
// TODO deprecate
|
/**
|
||||||
@Deprecated
|
* 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;
|
||||||
|
|
||||||
// TODO docme
|
/**
|
||||||
|
* 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)
|
public DemangledObject demangle(String mangled, DemanglerOptions options)
|
||||||
throws DemangledException;
|
throws DemangledException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates default options for this particular demangler
|
||||||
|
* @return the options
|
||||||
|
*/
|
||||||
public default DemanglerOptions createDefaultOptions() {
|
public default DemanglerOptions createDefaultOptions() {
|
||||||
return new DemanglerOptions();
|
return new DemanglerOptions();
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,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;
|
||||||
}
|
}
|
||||||
|
@ -82,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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -24,13 +24,13 @@
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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
|
||||||
way it had been done in the beginning). The net effect is that the text is indented. In
|
way it had been done in the beginning). The net effect is that the text is indented. In
|
||||||
|
@ -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; }
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -19,17 +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.GnuDemanglerNativeProcess;
|
import ghidra.app.util.demangler.gnu.GnuDemanglerOptions;
|
||||||
import ghidra.app.util.demangler.gnu.GnuDemanglerParser;
|
|
||||||
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 {
|
||||||
|
@ -37,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;
|
||||||
|
@ -55,81 +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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO change to GnuDemanglerOptions
|
println("Succesfully demangled " + mangled + " to " + demangledObject);
|
||||||
DemanglerOptions options = new DemanglerOptions();
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// TODO this is here because we did not support program arguments. replace this code
|
|
||||||
private Process createProcess(String executableName) throws Exception {
|
|
||||||
|
|
||||||
String demanglerName = GnuDemanglerNativeProcess.DEMANGLER_GNU;
|
|
||||||
OperatingSystem OS = Platform.CURRENT_PLATFORM.getOperatingSystem();
|
|
||||||
String demanglerExe =
|
|
||||||
(OS == OperatingSystem.WINDOWS) ? demanglerName + ".exe" : demanglerName;
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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()) {
|
||||||
|
|
|
@ -22,11 +22,13 @@ import org.apache.commons.lang3.StringUtils;
|
||||||
import ghidra.app.util.demangler.*;
|
import ghidra.app.util.demangler.*;
|
||||||
import ghidra.app.util.demangler.gnu.*;
|
import ghidra.app.util.demangler.gnu.*;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.framework.options.*;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.Msg;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A version of the demangler analyzer to handle GNU GCC symbols
|
||||||
|
*/
|
||||||
public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
||||||
|
|
||||||
private static final String NAME = "Demangler GNU";
|
private static final String NAME = "Demangler GNU";
|
||||||
|
@ -35,7 +37,7 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
||||||
"the name and apply datatypes to parameters.";
|
"the name and apply datatypes to parameters.";
|
||||||
|
|
||||||
private static final String OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS =
|
private static final String OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS =
|
||||||
"Only Demangle Known Mangled Symbols";
|
"Demangle Only Known Mangled Symbols";
|
||||||
private static final String OPTION_DESCRIPTION_USE_KNOWN_PATTERNS =
|
private static final String OPTION_DESCRIPTION_USE_KNOWN_PATTERNS =
|
||||||
"Only demangle symbols that follow known compiler mangling patterns. " +
|
"Only demangle symbols that follow known compiler mangling patterns. " +
|
||||||
"Leaving this option off may cause non-mangled symbols to get demangled.";
|
"Leaving this option off may cause non-mangled symbols to get demangled.";
|
||||||
|
@ -44,14 +46,20 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
||||||
private static final String OPTION_DESCRIPTION_APPLY_SIGNATURE =
|
private static final String OPTION_DESCRIPTION_APPLY_SIGNATURE =
|
||||||
"Apply any recovered function signature, in addition to the function name";
|
"Apply any recovered function signature, in addition to the function name";
|
||||||
|
|
||||||
// note: we use 'Z' as a trick to be below the other options
|
static final String OPTION_NAME_USE_DEPRECATED_DEMANGLER = "Use Deprecated Demangler";
|
||||||
private static final String OPTION_NAME_GNU_DEMANGLER = "Z GNU Demangler";
|
private static final String OPTION_DESCRIPTION_DEPRECATED_DEMANGLER =
|
||||||
|
"Signals to use the deprecated demangler when the modern demangler cannot demangle a " +
|
||||||
|
"given string";
|
||||||
|
|
||||||
|
private 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 doSignatureEnabled = true;
|
||||||
private boolean demangleOnlyKnownPatterns = false;
|
private boolean demangleOnlyKnownPatterns = false;
|
||||||
private GnuDemanglerOptionsPropertyEditor gnuOptionsEditor =
|
private boolean useDeprecatedDemangler = false;
|
||||||
new GnuDemanglerOptionsPropertyEditor();
|
private String demanglerParameters = "";
|
||||||
private GnuDemanglerWrappedOption gnuWrappedOptions;
|
|
||||||
|
|
||||||
private GnuDemangler demangler = new GnuDemangler();
|
private GnuDemangler demangler = new GnuDemangler();
|
||||||
|
|
||||||
|
@ -67,28 +75,20 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void registerOptions(Options options, Program program) {
|
public void registerOptions(Options options, Program program) {
|
||||||
options.registerOption(OPTION_NAME_APPLY_SIGNATURE, doSignatureEnabled, null,
|
|
||||||
OPTION_DESCRIPTION_APPLY_SIGNATURE);
|
|
||||||
|
|
||||||
options.registerOption(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, false, null,
|
|
||||||
OPTION_DESCRIPTION_USE_KNOWN_PATTERNS);
|
|
||||||
|
|
||||||
options.registerOptionsEditor(null);
|
|
||||||
|
|
||||||
HelpLocation help = new HelpLocation("AutoAnalysisPlugin", "Demangler_Analyzer");
|
HelpLocation help = new HelpLocation("AutoAnalysisPlugin", "Demangler_Analyzer");
|
||||||
options.registerOption(OPTION_NAME_GNU_DEMANGLER, OptionType.CUSTOM_TYPE,
|
options.registerOption(OPTION_NAME_APPLY_SIGNATURE, doSignatureEnabled, help,
|
||||||
new GnuDemanglerWrappedOption(), help, "Advanced GNU demangler options",
|
OPTION_DESCRIPTION_APPLY_SIGNATURE);
|
||||||
gnuOptionsEditor);
|
|
||||||
|
|
||||||
CustomOption customOption = options.getCustomOption(OPTION_NAME_GNU_DEMANGLER,
|
options.registerOption(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns,
|
||||||
new GnuDemanglerWrappedOption());
|
help,
|
||||||
if (!(customOption instanceof GnuDemanglerWrappedOption)) {
|
OPTION_DESCRIPTION_USE_KNOWN_PATTERNS);
|
||||||
customOption = new GnuDemanglerWrappedOption();
|
|
||||||
Msg.debug(this, "Unexpected custom option type for GNU Demangler: " +
|
|
||||||
customOption.getClass());
|
|
||||||
}
|
|
||||||
gnuWrappedOptions = (GnuDemanglerWrappedOption) customOption;
|
|
||||||
|
|
||||||
|
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
|
@Override
|
||||||
|
@ -97,9 +97,11 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
||||||
demangleOnlyKnownPatterns =
|
demangleOnlyKnownPatterns =
|
||||||
options.getBoolean(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns);
|
options.getBoolean(OPTION_NAME_DEMANGLE_USE_KNOWN_PATTERNS, demangleOnlyKnownPatterns);
|
||||||
|
|
||||||
gnuWrappedOptions =
|
useDeprecatedDemangler =
|
||||||
(GnuDemanglerWrappedOption) options.getCustomOption(OPTION_NAME_GNU_DEMANGLER,
|
options.getBoolean(OPTION_NAME_USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler);
|
||||||
new GnuDemanglerWrappedOption());
|
|
||||||
|
demanglerParameters =
|
||||||
|
options.getString(OPTION_NAME_DEMANGLER_PARAMETERS, demanglerParameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -109,15 +111,7 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
||||||
options.setDoDisassembly(true);
|
options.setDoDisassembly(true);
|
||||||
options.setApplySignature(doSignatureEnabled);
|
options.setApplySignature(doSignatureEnabled);
|
||||||
options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns);
|
options.setDemangleOnlyKnownPatterns(demangleOnlyKnownPatterns);
|
||||||
|
options.setDemanglerApplicationArguments(demanglerParameters);
|
||||||
options.setUseDeprecatedDemangler(gnuWrappedOptions.useDeprecatedDemangler());
|
|
||||||
|
|
||||||
String text = null;
|
|
||||||
if (gnuWrappedOptions.useDemanglerParameters()) {
|
|
||||||
text = gnuWrappedOptions.getDemanglerParametersText();
|
|
||||||
}
|
|
||||||
options.setDemanglerApplicationArguments(text);
|
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,7 +138,7 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
||||||
log.appendException(e);
|
log.appendException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.useDeprecatedDemangler()) {
|
if (useDeprecatedDemangler) {
|
||||||
// see if the options work in the deprecated demangler
|
// see if the options work in the deprecated demangler
|
||||||
GnuDemanglerOptions deprecatedOptions = options.withDeprecatedDemangler();
|
GnuDemanglerOptions deprecatedOptions = options.withDeprecatedDemangler();
|
||||||
String deprecatedName = deprecatedOptions.getDemanglerName();
|
String deprecatedName = deprecatedOptions.getDemanglerName();
|
||||||
|
@ -176,7 +170,7 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
||||||
demangled = demangler.demangle(mangled, options);
|
demangled = demangler.demangle(mangled, options);
|
||||||
}
|
}
|
||||||
catch (DemangledException e) {
|
catch (DemangledException e) {
|
||||||
if (!options.useDeprecatedDemangler()) {
|
if (!useDeprecatedDemangler) {
|
||||||
throw e; // let our parent handle this
|
throw e; // let our parent handle this
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -185,7 +179,7 @@ public class GnuDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
||||||
return demangled;
|
return demangled;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.useDeprecatedDemangler()) {
|
if (useDeprecatedDemangler) {
|
||||||
GnuDemanglerOptions newOptions = options.withDeprecatedDemangler();
|
GnuDemanglerOptions newOptions = options.withDeprecatedDemangler();
|
||||||
demangled = demangler.demangle(mangled, newOptions);
|
demangled = demangler.demangle(mangled, newOptions);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,179 +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 java.awt.Component;
|
|
||||||
import java.awt.Container;
|
|
||||||
import java.beans.PropertyEditorSupport;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import javax.swing.*;
|
|
||||||
import javax.swing.event.DocumentEvent;
|
|
||||||
import javax.swing.event.DocumentListener;
|
|
||||||
|
|
||||||
import docking.widgets.checkbox.GCheckBox;
|
|
||||||
import ghidra.framework.options.CustomOptionsEditor;
|
|
||||||
import ghidra.util.layout.HorizontalLayout;
|
|
||||||
import ghidra.util.layout.VerticalLayout;
|
|
||||||
|
|
||||||
public class GnuDemanglerOptionsPropertyEditor extends PropertyEditorSupport
|
|
||||||
implements CustomOptionsEditor {
|
|
||||||
|
|
||||||
private static final String USE_DEPRECATED_DEMANGLER = "Use Deprecated Demangler";
|
|
||||||
private static final String USE_DEMANGLER_PARAMETERS = "Use Demangler Program Parameters";
|
|
||||||
|
|
||||||
private static final String USE_DEPRECATED_DEMANGLER_TOOLTIP =
|
|
||||||
"Signals to use the deprecated demangler when the modern demangler cannot demangle a " +
|
|
||||||
"given string";
|
|
||||||
private static final String USE_DEMANGLER_PARAMETERS_TOOLTIP =
|
|
||||||
"Signals to use pass the given parameters to the demangler program";
|
|
||||||
|
|
||||||
private static final String[] NAMES =
|
|
||||||
{ USE_DEPRECATED_DEMANGLER, USE_DEMANGLER_PARAMETERS };
|
|
||||||
|
|
||||||
private static final String[] DESCRIPTIONS = { USE_DEPRECATED_DEMANGLER_TOOLTIP,
|
|
||||||
USE_DEMANGLER_PARAMETERS_TOOLTIP };
|
|
||||||
|
|
||||||
private GnuDemanglerWrappedOption wrappedOption;
|
|
||||||
|
|
||||||
private Component editorComponent;
|
|
||||||
|
|
||||||
private GCheckBox useDeprecatedDemanglerBox;
|
|
||||||
private GCheckBox useDemanglerParametersBox;
|
|
||||||
private JTextField demanglerParametersTextField;
|
|
||||||
|
|
||||||
public GnuDemanglerOptionsPropertyEditor() {
|
|
||||||
editorComponent = buildEditor();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Component buildEditor() {
|
|
||||||
|
|
||||||
// we want to have a panel with our options so that we may group them together
|
|
||||||
JPanel panel = new JPanel(new VerticalLayout(3));
|
|
||||||
|
|
||||||
useDeprecatedDemanglerBox = new GCheckBox(USE_DEPRECATED_DEMANGLER);
|
|
||||||
useDeprecatedDemanglerBox.setSelected(false);
|
|
||||||
useDeprecatedDemanglerBox.setToolTipText(USE_DEPRECATED_DEMANGLER_TOOLTIP);
|
|
||||||
useDeprecatedDemanglerBox.addItemListener(e -> firePropertyChange());
|
|
||||||
panel.add(useDeprecatedDemanglerBox);
|
|
||||||
|
|
||||||
createParameterComponent(panel);
|
|
||||||
|
|
||||||
return panel;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createParameterComponent(Container parent) {
|
|
||||||
|
|
||||||
JPanel textFieldPanel = new JPanel(new HorizontalLayout(0));
|
|
||||||
JTextField textField = new JTextField(15);
|
|
||||||
useDemanglerParametersBox = new GCheckBox(USE_DEMANGLER_PARAMETERS);
|
|
||||||
useDemanglerParametersBox.setToolTipText(USE_DEMANGLER_PARAMETERS_TOOLTIP);
|
|
||||||
useDemanglerParametersBox.addItemListener(e -> {
|
|
||||||
textField.setEnabled(useDemanglerParametersBox.isSelected());
|
|
||||||
firePropertyChange();
|
|
||||||
});
|
|
||||||
|
|
||||||
textField.getDocument().addDocumentListener(new DocumentListener() {
|
|
||||||
@Override
|
|
||||||
public void changedUpdate(DocumentEvent e) {
|
|
||||||
firePropertyChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void insertUpdate(DocumentEvent e) {
|
|
||||||
firePropertyChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void removeUpdate(DocumentEvent e) {
|
|
||||||
firePropertyChange();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
textField.setEnabled(false);
|
|
||||||
|
|
||||||
textFieldPanel.add(useDemanglerParametersBox);
|
|
||||||
textFieldPanel.add(Box.createHorizontalStrut(10));
|
|
||||||
textFieldPanel.add(textField);
|
|
||||||
|
|
||||||
parent.add(textFieldPanel);
|
|
||||||
|
|
||||||
demanglerParametersTextField = textField;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setValue(Object value) {
|
|
||||||
|
|
||||||
if (!(value instanceof GnuDemanglerWrappedOption)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
wrappedOption = (GnuDemanglerWrappedOption) value;
|
|
||||||
setLocalValues(wrappedOption);
|
|
||||||
firePropertyChange();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setLocalValues(GnuDemanglerWrappedOption newOption) {
|
|
||||||
|
|
||||||
if (newOption.useDeprecatedDemangler() != useDeprecatedDemanglerBox.isSelected()) {
|
|
||||||
useDeprecatedDemanglerBox.setSelected(newOption.useDeprecatedDemangler());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newOption.useDemanglerParameters() != useDemanglerParametersBox.isSelected()) {
|
|
||||||
useDemanglerParametersBox.setSelected(newOption.useDemanglerParameters());
|
|
||||||
}
|
|
||||||
|
|
||||||
String newText = newOption.getDemanglerParametersText();
|
|
||||||
String currentText = demanglerParametersTextField.getText();
|
|
||||||
if (!Objects.equals(newText, currentText)) {
|
|
||||||
demanglerParametersTextField.setText(newText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object getValue() {
|
|
||||||
return cloneNamespaceValues();
|
|
||||||
}
|
|
||||||
|
|
||||||
private GnuDemanglerWrappedOption cloneNamespaceValues() {
|
|
||||||
|
|
||||||
GnuDemanglerWrappedOption newOption = new GnuDemanglerWrappedOption();
|
|
||||||
newOption.setUseDeprecatedDemangler(useDeprecatedDemanglerBox.isSelected());
|
|
||||||
newOption.setUseDemanglerParameters(useDemanglerParametersBox.isSelected());
|
|
||||||
newOption.setDemanglerParametersText(demanglerParametersTextField.getText());
|
|
||||||
return newOption;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getOptionNames() {
|
|
||||||
return NAMES;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String[] getOptionDescriptions() {
|
|
||||||
return DESCRIPTIONS;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Component getCustomEditor() {
|
|
||||||
return editorComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean supportsCustomEditor() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,125 +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 java.util.Objects;
|
|
||||||
|
|
||||||
import ghidra.framework.options.CustomOption;
|
|
||||||
import ghidra.framework.options.SaveState;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A simple java bean adapted to the {@link CustomOption} interface. The public
|
|
||||||
* getters and setters are self-documenting.
|
|
||||||
*/
|
|
||||||
public class GnuDemanglerWrappedOption implements CustomOption {
|
|
||||||
|
|
||||||
private static final String USE_DEPRECATED_DEMANGLER = "USE_DEPRECATED_DEMANGLER";
|
|
||||||
private static final String USE_DEMANGLER_PARAMETERS = "USE_DEMANGLER_PARAMETERS";
|
|
||||||
private static final String DEMANGLER_PARAMETERS = "DEMANGLER_PARAMETERS";
|
|
||||||
|
|
||||||
private boolean useDeprecatedDemangler = false;
|
|
||||||
private boolean useDemanglerParameters = false;
|
|
||||||
private String demanglerParametersText = null;
|
|
||||||
|
|
||||||
public void setUseDeprecatedDemangler(boolean doUse) {
|
|
||||||
this.useDeprecatedDemangler = doUse;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean useDeprecatedDemangler() {
|
|
||||||
return useDeprecatedDemangler;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setDemanglerParametersText(String text) {
|
|
||||||
this.demanglerParametersText = text;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDemanglerParametersText() {
|
|
||||||
return demanglerParametersText;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setUseDemanglerParameters(boolean doUse) {
|
|
||||||
this.useDemanglerParameters = doUse;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean useDemanglerParameters() {
|
|
||||||
return useDemanglerParameters;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void readState(SaveState state) {
|
|
||||||
useDeprecatedDemangler =
|
|
||||||
state.getBoolean(USE_DEPRECATED_DEMANGLER, useDemanglerParameters);
|
|
||||||
useDemanglerParameters =
|
|
||||||
state.getBoolean(USE_DEPRECATED_DEMANGLER, useDemanglerParameters);
|
|
||||||
demanglerParametersText =
|
|
||||||
state.getString(DEMANGLER_PARAMETERS, demanglerParametersText);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void writeState(SaveState state) {
|
|
||||||
state.putBoolean(USE_DEPRECATED_DEMANGLER, useDeprecatedDemangler);
|
|
||||||
state.putBoolean(USE_DEMANGLER_PARAMETERS, useDemanglerParameters);
|
|
||||||
state.putString(USE_DEMANGLER_PARAMETERS, demanglerParametersText);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
final int prime = 31;
|
|
||||||
int result = 1;
|
|
||||||
result = prime * result +
|
|
||||||
((demanglerParametersText == null) ? 0 : demanglerParametersText.hashCode());
|
|
||||||
result = prime * result + (useDemanglerParameters ? 1231 : 1237);
|
|
||||||
result = prime * result + (useDeprecatedDemangler ? 1231 : 1237);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object obj) {
|
|
||||||
if (this == obj) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (obj == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (getClass() != obj.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GnuDemanglerWrappedOption other = (GnuDemanglerWrappedOption) obj;
|
|
||||||
if (!Objects.equals(demanglerParametersText, other.demanglerParametersText)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useDemanglerParameters != other.useDemanglerParameters) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (useDeprecatedDemangler != other.useDeprecatedDemangler) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
//@formatter:off
|
|
||||||
return "{\n" +
|
|
||||||
"\tuseDeprecatedDemangler: " + useDeprecatedDemangler + ",\n" +
|
|
||||||
"\tuseDemanglerParameters: " + useDemanglerParameters + ",\n" +
|
|
||||||
"\tdemanglerParametersText: " + demanglerParametersText + ",\n" +
|
|
||||||
"}";
|
|
||||||
//@formatter:on
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -60,6 +60,7 @@ public class GnuDemangler 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 {
|
||||||
GnuDemanglerOptions options = new GnuDemanglerOptions();
|
GnuDemanglerOptions options = new GnuDemanglerOptions();
|
||||||
|
|
|
@ -27,6 +27,11 @@ 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 {
|
||||||
public static final String DEMANGLER_GNU = GnuDemanglerOptions.GNU_DEMANGLER_DEFAULT;
|
public static final String DEMANGLER_GNU = GnuDemanglerOptions.GNU_DEMANGLER_DEFAULT;
|
||||||
|
|
||||||
|
@ -42,21 +47,35 @@ public class GnuDemanglerNativeProcess {
|
||||||
private BufferedReader reader;
|
private BufferedReader reader;
|
||||||
private PrintWriter writer;
|
private PrintWriter writer;
|
||||||
|
|
||||||
// TODO docme
|
/**
|
||||||
|
* 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 {
|
||||||
return getDemanglerNativeProcess(DEMANGLER_GNU);
|
return getDemanglerNativeProcess(DEMANGLER_GNU);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO docme
|
/**
|
||||||
|
* 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)
|
public static synchronized GnuDemanglerNativeProcess getDemanglerNativeProcess(String name)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
return getDemanglerNativeProcess(name, DEFAULT_NATIVE_OPTIONS);
|
return getDemanglerNativeProcess(name, DEFAULT_NATIVE_OPTIONS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO docme
|
/**
|
||||||
// TODO we should probably age-off all demanglers by access time
|
* 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,
|
public static synchronized GnuDemanglerNativeProcess getDemanglerNativeProcess(String name,
|
||||||
String nativeOptions)
|
String nativeOptions)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
@ -66,15 +85,18 @@ public class GnuDemanglerNativeProcess {
|
||||||
options = DEFAULT_NATIVE_OPTIONS;
|
options = DEFAULT_NATIVE_OPTIONS;
|
||||||
}
|
}
|
||||||
|
|
||||||
String key = name + nativeOptions;
|
String key = getKey(name, options);
|
||||||
GnuDemanglerNativeProcess nativeProcess = processesByName.get(key);
|
GnuDemanglerNativeProcess nativeProcess = processesByName.get(key);
|
||||||
if (nativeProcess == null) {
|
if (nativeProcess == null) {
|
||||||
nativeProcess = new GnuDemanglerNativeProcess(name, options);
|
nativeProcess = new GnuDemanglerNativeProcess(name, options);
|
||||||
processesByName.put(key, nativeProcess);
|
|
||||||
}
|
}
|
||||||
return nativeProcess;
|
return nativeProcess;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String getKey(String name, String options) {
|
||||||
|
return name + ' ' + options;
|
||||||
|
}
|
||||||
|
|
||||||
private GnuDemanglerNativeProcess(String applicationName, String options) throws IOException {
|
private GnuDemanglerNativeProcess(String applicationName, String options) throws IOException {
|
||||||
this.applicationName = applicationName;
|
this.applicationName = applicationName;
|
||||||
this.options = options;
|
this.options = options;
|
||||||
|
@ -95,7 +117,6 @@ public class GnuDemanglerNativeProcess {
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
dispose();
|
dispose();
|
||||||
if (!restart) {
|
if (!restart) {
|
||||||
processesByName.remove(applicationName);
|
|
||||||
throw new IOException("Demangler process is not running.", e);
|
throw new IOException("Demangler process is not running.", e);
|
||||||
}
|
}
|
||||||
createProcess();
|
createProcess();
|
||||||
|
@ -109,7 +130,11 @@ public class GnuDemanglerNativeProcess {
|
||||||
return reader.readLine();
|
return reader.readLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void dispose() {
|
public void dispose() {
|
||||||
|
|
||||||
|
String key = getKey(applicationName, options);
|
||||||
|
processesByName.remove(key);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (process != null) {
|
if (process != null) {
|
||||||
process.destroy();
|
process.destroy();
|
||||||
|
@ -139,6 +164,8 @@ public class GnuDemanglerNativeProcess {
|
||||||
checkForError(command);
|
checkForError(command);
|
||||||
|
|
||||||
isDisposed = false;
|
isDisposed = false;
|
||||||
|
String key = getKey(applicationName, options);
|
||||||
|
processesByName.put(key, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] buildCommand() throws FileNotFoundException {
|
private String[] buildCommand() throws FileNotFoundException {
|
||||||
|
|
|
@ -15,12 +15,19 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.util.demangler.gnu;
|
package ghidra.app.util.demangler.gnu;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
|
|
||||||
import ghidra.app.util.demangler.DemanglerOptions;
|
import ghidra.app.util.demangler.DemanglerOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GNU demangler options
|
||||||
|
*/
|
||||||
public class GnuDemanglerOptions extends DemanglerOptions {
|
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.
|
* Version 2.24 of the GNU demangler. This version supports older formats and older bugs.
|
||||||
*/
|
*/
|
||||||
|
@ -38,7 +45,6 @@ public class GnuDemanglerOptions extends DemanglerOptions {
|
||||||
|
|
||||||
private String demanglerName = GNU_DEMANGLER_DEFAULT;
|
private String demanglerName = GNU_DEMANGLER_DEFAULT;
|
||||||
private String demanglerApplicationArguments;
|
private String demanglerApplicationArguments;
|
||||||
private boolean useDeprecatedDemangler;
|
|
||||||
|
|
||||||
public GnuDemanglerOptions() {
|
public GnuDemanglerOptions() {
|
||||||
// use default values
|
// use default values
|
||||||
|
@ -51,48 +57,47 @@ public class GnuDemanglerOptions extends DemanglerOptions {
|
||||||
GnuDemanglerOptions gCopy = (GnuDemanglerOptions) copy;
|
GnuDemanglerOptions gCopy = (GnuDemanglerOptions) copy;
|
||||||
demanglerName = gCopy.demanglerName;
|
demanglerName = gCopy.demanglerName;
|
||||||
demanglerApplicationArguments = gCopy.demanglerApplicationArguments;
|
demanglerApplicationArguments = gCopy.demanglerApplicationArguments;
|
||||||
useDeprecatedDemangler = gCopy.useDeprecatedDemangler;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO docme
|
/**
|
||||||
|
* 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() {
|
public String getDemanglerName() {
|
||||||
return demanglerName;
|
return demanglerName;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO docme
|
/**
|
||||||
// TODO should we validate and or log a message it the name is unknown?
|
* Sets the external demangler executable name to be used for demangling
|
||||||
|
* @param name the name
|
||||||
|
*/
|
||||||
public void setDemanglerName(String name) {
|
public void setDemanglerName(String name) {
|
||||||
this.demanglerName = name;
|
this.demanglerName = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO docme
|
/**
|
||||||
|
* Returns the current arguments to be passed to the external demangler executable
|
||||||
|
* @return the arguments
|
||||||
|
*/
|
||||||
public String getDemanglerApplicationArguments() {
|
public String getDemanglerApplicationArguments() {
|
||||||
return demanglerApplicationArguments;
|
return demanglerApplicationArguments;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO docme
|
/**
|
||||||
|
* Sets the arguments to be passed to the external demangler executable
|
||||||
|
* @param args the arguments
|
||||||
|
*/
|
||||||
public void setDemanglerApplicationArguments(String args) {
|
public void setDemanglerApplicationArguments(String args) {
|
||||||
this.demanglerApplicationArguments = args;
|
this.demanglerApplicationArguments = args;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO docme
|
/**
|
||||||
// TODO mabye rename to hasNativeApplicationOptions()
|
* A convenience method to copy the state of this options object, changing the
|
||||||
public boolean hasDemanglerApplicationArguments() {
|
* demangler executable name to the deprecated demangler
|
||||||
return !StringUtils.isBlank(demanglerApplicationArguments);
|
* @return the new options
|
||||||
}
|
*/
|
||||||
|
|
||||||
// TODO docme
|
|
||||||
public void setUseDeprecatedDemangler(boolean doUse) {
|
|
||||||
this.useDeprecatedDemangler = doUse;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO docme
|
|
||||||
public boolean useDeprecatedDemangler() {
|
|
||||||
return useDeprecatedDemangler;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO docme
|
|
||||||
public GnuDemanglerOptions withDeprecatedDemangler() {
|
public GnuDemanglerOptions withDeprecatedDemangler() {
|
||||||
GnuDemanglerOptions newOptions = new GnuDemanglerOptions(this);
|
GnuDemanglerOptions newOptions = new GnuDemanglerOptions(this);
|
||||||
newOptions.setDemanglerName(GNU_DEMANGLER_V2_24);
|
newOptions.setDemanglerName(GNU_DEMANGLER_V2_24);
|
||||||
|
@ -107,7 +112,6 @@ public class GnuDemanglerOptions extends DemanglerOptions {
|
||||||
"\tapplySignature: " + applySignature() + ",\n" +
|
"\tapplySignature: " + applySignature() + ",\n" +
|
||||||
"\tdemangleOnlyKnownPatterns: " + demangleOnlyKnownPatterns() + ",\n" +
|
"\tdemangleOnlyKnownPatterns: " + demangleOnlyKnownPatterns() + ",\n" +
|
||||||
"\tdemanglerName: " + demanglerName + ",\n" +
|
"\tdemanglerName: " + demanglerName + ",\n" +
|
||||||
"\tuseDeprecatedDemangler: " + useDeprecatedDemangler + ",\n" +
|
|
||||||
"\tdemanglerApplicationArguments: " + demanglerApplicationArguments + ",\n" +
|
"\tdemanglerApplicationArguments: " + demanglerApplicationArguments + ",\n" +
|
||||||
"}";
|
"}";
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
/* ###
|
||||||
|
* 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 org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import ghidra.app.cmd.label.AddLabelCmd;
|
||||||
|
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.SourceType;
|
||||||
|
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||||
|
import ghidra.test.ToyProgramBuilder;
|
||||||
|
import ghidra.util.Msg;
|
||||||
|
import ghidra.util.exception.RollbackException;
|
||||||
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
public class GnuDemanglerAnalyzerTest extends AbstractGhidraHeadlessIntegrationTest {
|
||||||
|
|
||||||
|
private GnuDemanglerAnalyzer analyzer = new GnuDemanglerAnalyzer();
|
||||||
|
private ProgramDB program;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
|
||||||
|
ProgramBuilder builder = new ToyProgramBuilder("test", true);
|
||||||
|
builder.createMemory(".text", "0x0100", 0x100);
|
||||||
|
program = builder.getProgram();
|
||||||
|
registerOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeprectedDemangledString() 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);
|
||||||
|
|
||||||
|
MessageLog log = new MessageLog();
|
||||||
|
analyzer.added(program, program.getMemory(), TaskMonitor.DUMMY, log);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setOption(String optionNameUseDeprecatedDemangler, boolean b) {
|
||||||
|
|
||||||
|
Options options = program.getOptions("Analyzers");
|
||||||
|
|
||||||
|
for (String name : options.getOptionNames()) {
|
||||||
|
|
||||||
|
if (name.contains("Demangler GNU")) {
|
||||||
|
Msg.out("found it: " + name);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Msg.out("no it: " + name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createSymbol(Address addr, String mangled) {
|
||||||
|
|
||||||
|
AddLabelCmd cmd = new AddLabelCmd(addr, mangled, SourceType.ANALYSIS);
|
||||||
|
int txId = program.startTransaction(cmd.getName());
|
||||||
|
boolean commit = true;
|
||||||
|
try {
|
||||||
|
boolean status = cmd.applyTo(program);
|
||||||
|
program.flushEvents();
|
||||||
|
|
||||||
|
if (!status) {
|
||||||
|
fail("Could not apply command: " + cmd.getStatusMsg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (RollbackException e) {
|
||||||
|
commit = false;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
program.endTransaction(txId, commit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeprectedDemangledString_WithArguments_Valid() {
|
||||||
|
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeprectedDemangledString_WithArguments_Invalid() {
|
||||||
|
|
||||||
|
fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1130,7 +1130,7 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,8 @@ import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import generic.test.AbstractGenericTest;
|
import generic.test.AbstractGenericTest;
|
||||||
import ghidra.app.util.demangler.*;
|
import ghidra.app.util.demangler.DemangledException;
|
||||||
|
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;
|
||||||
|
@ -54,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
|
||||||
|
@ -65,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) {
|
||||||
|
@ -82,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);
|
||||||
}
|
}
|
||||||
|
@ -99,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);
|
||||||
|
@ -132,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);
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,9 @@ import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A version of the demangler analyzer to handle microsoft symbols
|
||||||
|
*/
|
||||||
public class MicrosoftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
public class MicrosoftDemanglerAnalyzer extends AbstractDemanglerAnalyzer {
|
||||||
|
|
||||||
private static final String NAME = "Demangler Microsoft";
|
private static final String NAME = "Demangler Microsoft";
|
||||||
|
|
|
@ -39,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 {
|
||||||
|
@ -82,36 +83,4 @@ public class MicrosoftDemangler implements Demangler {
|
||||||
throw gde;
|
throw gde;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * 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]");
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,8 @@ import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import ghidra.app.cmd.label.DemanglerCmd;
|
import ghidra.app.cmd.label.DemanglerCmd;
|
||||||
import ghidra.app.util.demangler.*;
|
import ghidra.app.util.demangler.DemangledException;
|
||||||
|
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.test.AbstractGhidraHeadlessIntegrationTest;
|
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
|
||||||
|
@ -58,13 +59,13 @@ public class GnuDemanglerIntegrationTest extends AbstractGhidraHeadlessIntegrati
|
||||||
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);
|
||||||
|
DemangledObject result = demangler.demangle(mangled, options);
|
||||||
assertNotNull(result);
|
assertNotNull(result);
|
||||||
assertEquals("undefined MyNamespace::MyFunction($ParamNamespace::paramName *)",
|
assertEquals("undefined MyNamespace::MyFunction($ParamNamespace::paramName *)",
|
||||||
result.getSignature(false));
|
result.getSignature(false));
|
||||||
|
|
||||||
DemanglerOptions options = new DemanglerOptions();
|
|
||||||
options.setDemangleOnlyKnownPatterns(false);
|
|
||||||
DemanglerCmd cmd = new DemanglerCmd(addr("01001000"), mangled, options);
|
DemanglerCmd cmd = new DemanglerCmd(addr("01001000"), mangled, options);
|
||||||
|
|
||||||
// this used to trigger an exception
|
// this used to trigger an exception
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -24,13 +24,13 @@
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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
|
||||||
way it had been done in the beginning). The net effect is that the text is indented. In
|
way it had been done in the beginning). The net effect is that the text is indented. In
|
||||||
|
@ -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; }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue