mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-06 12:00:04 +02:00
Merge remote-tracking branch 'origin/Ghidra_9.2'
This commit is contained in:
commit
b88c949c6b
116 changed files with 12869 additions and 39864 deletions
|
@ -142,7 +142,6 @@ model {
|
|||
all{ b ->
|
||||
|
||||
def version = b.getApplication().getName()
|
||||
println "have binary: " + b
|
||||
|
||||
if (version.equals(v33_1)) {
|
||||
if (toolChain in Gcc) {
|
||||
|
|
|
@ -6,6 +6,219 @@
|
|||
</HEAD>
|
||||
|
||||
<BODY>
|
||||
<H1 align="center">Ghidra 9.2 Change History (November 2020)</H1>
|
||||
<blockquote><p><u>New Features</u></p>
|
||||
<ul>
|
||||
<li><I>Graphing</I>. A new graph service and implementation was created. The graph service provides basic graphing capabilities. It was also used to generate several different types of graphs including code block graphs, call graphs, and AST graphs. In addition, an export graph service was created that supports various formats. (GP-211)</li>
|
||||
<li><I>PDB</I>. Added a new, prototype, platform-independent PDB analyzer that processes and applies data types and symbols to a program from a raw (non-XML-converted) PDB file, allowing users to more easily take advantage of PDB information. (GT-3112)</li>
|
||||
<li><I>Processors</I>. Added M8C SLEIGH processor specification. (GT-3052)</li>
|
||||
<li><I>Processors</I>. Added support for the RISC-V processor. (GT-3389, Issue #932)</li>
|
||||
<li><I>Processors</I>. Added support for the Motorola 6809 processor. (GT-3390, Issue #1201)</li>
|
||||
<li><I>Processors</I>. Added CP1600-series processor support. (GT-3426, Issue #1383)</li>
|
||||
<li><I>Processors</I>. Added V850 processor module. (GT-3523, Issue #1430)</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
<blockquote><p><u>Improvements</u></p>
|
||||
<ul>
|
||||
<li><I>Analysis</I>. Increased the speed of the Embedded Media Analyzer, which was especially poor for large programs, by doing better checking and reducing the number of passes over the program. (GT-3258)</li>
|
||||
<li><I>Analysis</I>. Improved the performance of the RTTI analyzer. (GT-3341, Issue #10)</li>
|
||||
<li><I>Analysis</I>. Updated Auto-analysis to preserve work when encountering recoverable exceptions. (GT-3599)</li>
|
||||
<li><I>Analysis</I>. Improved efficiency when creating or checking for functions and namespaces which overlap. (GP-21)</li>
|
||||
<li><I>Analysis</I>. Added partial support of Clang for Windows. (GP-64)</li>
|
||||
<li><I>Analysis</I>. RTTI structure processing speed has been improved with a faster technique for finding the root RTTI type descriptor. (GP-168, Issue #2075)</li>
|
||||
<li><I>API</I>. The performance of adding large numbers of data types to the same category has been improved. (GT-3535)</li>
|
||||
<li><I>API</I>. Added the BigIntegerNumberInputDialog that allows users to enter integer values larger than <code>Integer.MAX_VALUE</code> (2147483647). (GT-3607)</li>
|
||||
<li><I>API</I>. Made JSON more available using GSON. (GP-89, Issue #1982)</li>
|
||||
<li><I>Basic Infrastructure</I>. Introduced an extension point <code>priority</code> annotation so users can control extension point ordering. (GT-3350, Issue #1260)</li>
|
||||
<li><I>Basic Infrastructure</I>. Changed file names in <B>launch.bat</B> to always run executables from System32. (GT-3614, Issue #1599)</li>
|
||||
<li><I>Basic Infrastructure</I>. Unknown platforms now default to 64-bit. (GT-3615, Issue #1499)</li>
|
||||
<li><I>Build</I>. Ghidra's native Windows binaries can now be built using Visual Studio 2019. (GT-3277, Issue #999)</li>
|
||||
<li><I>Build</I>. Extension builds now exclude gradlew artifacts from zip file. (GT-3631, Issue #1763)</li>
|
||||
<li><I>Build</I>. Reduced the number of duplicated help files among the build jar files. (GP-57, Issue #2144)</li>
|
||||
<li><I>Build</I>. Git commit hash has been added to <B>application.properties</B> file for every build (not just releases). (GP-67)</li>
|
||||
<li><I>Contrib</I>. Extensions are now installed to the user's settings directory, not the Ghidra installation directory. (GT-3639, Issue #1960)</li>
|
||||
<li><I>Data Types</I>. Added mutability data settings (constant, volatile) for Enum datatype. (GT-3415)</li>
|
||||
<li><I>Data Types</I>. Improved Structure Editor's <B>Edit Component</B> action to work on array pointers. (GP-205, Issue #1633)</li>
|
||||
<li><I>Decompiler</I>. Added Secondary Highlights to the Decompiler. This feature allows the user to create a highlight for a token to show all occurrences of that token. Further, multiple secondary highlights are allowed at the same time, each using a unique color. See the Decompiler help for more information. (GT-3292, Issue #784)</li>
|
||||
<li><I>Decompiler</I>. Added heuristics to the Decompiler to better distinguish whether a constant pointer refers to something in the CODE or DATA address space, for Harvard architectures. (GT-3468)</li>
|
||||
<li><I>Decompiler</I>. Improved Decompiler analysis of local variables with small data types, eliminating unnecessary casts and mask operations. (GT-3525)</li>
|
||||
<li><I>Decompiler</I>. Documentation for the Decompiler, accessible from within the Code Browser, has been rewritten and extended. (GP-166)</li>
|
||||
<li><I>Decompiler</I>. The Decompiler can now display the namespace path (or part of it) of symbols it renders. With the default display configuration, the minimal number of path elements necessary are printed to fully resolve the symbol within the current scope. (GP-236)</li>
|
||||
<li><I>Decompiler</I>. The Decompiler now respects the <B>Charset</B> and <B>Translate</B> settings for string literals it displays. (GP-237)</li>
|
||||
<li><I>Decompiler</I>. The Decompiler's analysis of array accesses is much improved. It can detect more and varied access patterns produced by optimized code, even if the base offset is not contained in the array. Multi-dimensional arrays are detected as well. (GP-238, Issue #461, #1348)</li>
|
||||
<li><I>Decompiler</I>. Extended the Decompiler's support for analyzing class methods. The class data type is propagated through the <B>this</B> pointer even in cases where the full prototype of the method is not known. The methods <code>isThisPointer()</code> and <code>isHiddenReturn()</code> are now populated in HighSymbol objects and are accessible in Ghidra scripts. (GP-239, Issue #2151)</li>
|
||||
<li><I>Decompiler</I>. The Decompiler will now infer a string pointer from a constant that addresses the interior of a string, not just the beginning. (GP-240, Issue #1502)</li>
|
||||
<li><I>Decompiler</I>. The Decompiler now always prints the full precision of floating-point values, using the minimal number of characters in either fixed point or scientific notation. (GP-241, Issue #778)</li>
|
||||
<li><I>Decompiler</I>. The Decompiler's <B>Auto Create Structure</B> command now incorporates into new structures data-type information from function prototypes. The <B>Auto Fill in Structure</B> variant of the command will override <B>undefined</B> and other more general data-types with discovered data-types if they are more specific. (GP-242)</li>
|
||||
<li><I>Demangler</I>. Modified Microsoft Demangler (MDMang) to handle symbols represented by MD5 hash codes when their normal mangled length exceeds 4096. (GT-3409, Issue #1344)</li>
|
||||
<li><I>Demangler</I>. Upgraded the GNU Demangler to version 2.33.1. Added support for the now-deprecated GNU Demangler version 2.24 to be used as a fallback option for demangling. (GT-3481, Issue #1195, #1308, #1451, #1454)</li>
|
||||
<li><I>Demangler</I>. The Demangler now more carefully applies information if generic changes have been made. Previously if the function signature had changed in any way from default, the demangler would not attempt to apply any information including the function name. (GP-12)</li>
|
||||
<li><I>Demangler</I>. Changed MDMang so cast operator names are complete within the qualified function name, effecting what is available from internal API. (GP-13)</li>
|
||||
<li><I>Demangler</I>. Added additional MDMang Extended Types such as <code>char8_t</code>, <code>char16_t</code>, and <code>char32_t</code>. (GP-14)</li>
|
||||
<li><I>Documentation</I>. Removed Eclipse BuildShip instructions from the DevGuide. (GT-3634, Issue #1735)</li>
|
||||
<li><I>FID</I>. Regenerated FunctionID databases. Added support for Visual Studio versions 2017 and 2019. (GP-170)</li>
|
||||
<li><I>Function Diff</I>. Users may now add functions ad-hoc to existing function comparison panels. (GT-2229)</li>
|
||||
<li><I>Function Graph</I>. Added <B>Navigation History</B> Tool option for Function Graph to signal it to produce fewer navigation history entries. (GT-3233, Issue #1115)</li>
|
||||
<li><I>GUI</I>. Users can now view the Function Tag window to see all functions associated with a tag, without having to inspect the Listing. (GT-3054)</li>
|
||||
<li><I>GUI</I>. Updated the <B>Copy Special</B> action to work on the current address when there is no selection. (GT-3155, Issue #1000)</li>
|
||||
<li><I>GUI</I>. Significantly improved the performance of filtering trees in the Ghidra GUI. (GT-3225)</li>
|
||||
<li><I>GUI</I>. Added many optimizations to increase the speed of table sorting and filtering. (GT-3226, Issue #500)</li>
|
||||
<li><I>GUI</I>. Improved performance of bit view component recently introduced to Structure Editor. (GT-3244, Issue #1141)</li>
|
||||
<li><I>GUI</I>. Updated usage of timestamps in the UI to be consistent. (GT-3286)</li>
|
||||
<li><I>GUI</I>. Added tool actions for navigating to the next/previous functions in the navigation history. (GT-3291, Issue #475)</li>
|
||||
<li><I>GUI</I>. Filtering now works on all tables in the Function Tag window. (GT-3329)</li>
|
||||
<li><I>GUI</I>. Updated the Ghidra File Chooser so that users can type text into the list and table views in order to quickly jump to a desired file. (GT-3396)</li>
|
||||
<li><I>GUI</I>. Improved the performance of the Defined Strings table. (GT-3414, Issue #1259)</li>
|
||||
<li><I>GUI</I>. Updated Ghidra to allow users to set a key binding to perform an equivalent operation to double-clicking the <code>XREF</code> field in the Listing. See the <B>Show Xrefs</B> action in the <B>Tool Options... Key Bindings</B> section. (GT-3446)</li>
|
||||
<li><I>GUI</I>. Improved mouse wheel scrolling in Listing and Byte Viewers. (GT-3473)</li>
|
||||
<li><I>GUI</I>. Ghidra's action context mechanism was changed so that actions that modify the program are not accidentally invoked in the wrong context, thus possibly modifying the program in ways the user did not want or without the user knowing that it happened. This also fixed an issue where the navigation history drop-down menu did not represent the locations that would be used if the next/previous buttons were pressed. (GT-3485)</li>
|
||||
<li><I>GUI</I>. Updated Ghidra tables to defer updating while analysis is running. (GT-3604)</li>
|
||||
<li><I>GUI</I>. Updated Font Size options to allow the user to set any font size. (GT-3606, Issue #160, #1541)</li>
|
||||
<li><I>GUI</I>. Added ability to overlay text on an icon. (GP-41)</li>
|
||||
<li><I>GUI</I>. Updated Ghidra options to allow users to clear default key binding values. (GP-61, Issue #1681)</li>
|
||||
<li><I>GUI</I>. ToggleDirectionAction button now shows in snapshot windows. (GP-93)</li>
|
||||
<li><I>GUI</I>. Added a new action to the Symbol Tree to allow users to convert a Namespace to a Class. (GP-225, Issue #2301)</li>
|
||||
<li><I>Importer</I>. Updated the XML Loader to parse symbol names for namespaces. (GT-3293)</li>
|
||||
<li><I>Importer:ELF</I>. Added support for processing Android packed ELF Relocation Tables. (GT-3320, Issue #1192)</li>
|
||||
<li><I>Importer:ELF</I>. Added ELF import opinion for ARM BE8. (GT-3642, Issue #1187)</li>
|
||||
<li><I>Importer:MachO</I>. DYLD Loader can now load x86_64 DYLD from macOS. (GT-3611, Issue #1566)</li>
|
||||
<li><I>Importer:PE</I>. Improved parsing of Microsoft ordinal map files produced with <code>DUMPBIN /EXPORTS</code> (see <B>Ghidra/Features/Base/data/symbols/README.txt</B>). (GT-3235)</li>
|
||||
<li><I>Jython</I>. Upgraded Jython to version 2.7.2. (GP-109)</li>
|
||||
<li><I>Listing:Data</I>. Improved handling and display of character sequences embedded in operands or integer values. (GT-3347, Issue #1241)</li>
|
||||
<li><I>Multi-User:Ghidra Server</I>. Added ability to specify initial Ghidra Server user password (<code><B>-a0</B></code> mode only) for the svrAdmin <B>add</B> and <B>reset</B> commands. (GT-3640, Issue #321)</li>
|
||||
<li><I>Processors</I>. Implemented semantics for <code>vstmia/db</code> <code>vldmia/db</code>, added missing instructions, and fixed shift value for several instructions for the ARM/Thumb NEON instruction set. (GT-2567)</li>
|
||||
<li><I>Processors</I>. Added the XMEGA variant of the AVR8 processor with general purpose registers moved to a non-memory-mapped register space. (GT-2909)</li>
|
||||
<li><I>Processors</I>. Added support for x86 <code>SALC</code> instruction. (GT-3367, Issue #1303)</li>
|
||||
<li><I>Processors</I>. Implemented pcode for 6502 <code>BRK</code> instruction. (GT-3375, Issue #1049)</li>
|
||||
<li><I>Processors</I>. Implemented x86 <code>PTEST</code> instruction. (GT-3380, Issue #1295)</li>
|
||||
<li><I>Processors</I>. Added missing instructions to ARM language module. (GT-3394)</li>
|
||||
<li><I>Processors</I>. Added support for <code>RDRAND</code> and <code>RDSEED</code> instructions to x86-32. (GT-3413)</li>
|
||||
<li><I>Processors</I>. Improved x86 breakpoint disassembly. (GT-3421, Issue #872)</li>
|
||||
<li><I>Processors</I>. Added manual index file for the M6809 processor. (GT-3449, Issue #1414)</li>
|
||||
<li><I>Processors</I>. Corrected issues related to retained instruction context during a language upgrade. In some rare cases this retained context could interfere with the instruction re-disassembly. This context-clearing mechanism is controlled by a new pspec property: <code>resetContextOnUpgrade</code>. (GT-3531)</li>
|
||||
<li><I>Processors</I>. Updated PIC24/PIC30 index file to match latest manual. Added support for dsPIC33C. (GT-3562)</li>
|
||||
<li><I>Processors</I>. Updated AVR8 ATmega256 processor model to reflect correct memory layout specification. (GT-933)</li>
|
||||
<li><I>Processors</I>. Added missing call-fixup to handle call side-effects for 32 bit gcc programs for <code>get_pc_thunk.ax/si</code>. (GP-10)</li>
|
||||
<li><I>Processors</I>. Added <code>ExitProcess</code> to PEFunctionsThatDoNotReturn. (GP-35)</li>
|
||||
<li><I>Processors</I>. <B>External Disassembly</B> field in the Listing now shows Thumb disassembly when appropriate TMode context has been established on a memory location. (GP-49)</li>
|
||||
<li><I>Processors</I>. Changed RISC-V jump instructions to the more appropriate <code>goto</code> instead of <code>call</code>. (GP-54, Issue #2120)</li>
|
||||
<li><I>Processors</I>. Updated AARCH64 to v8.5, including new MTE instructions. (GP-124)</li>
|
||||
<li><I>Processors</I>. Added support for floating point params and return for SH4 processor calling conventions. (GP-183, Issue #2218)</li>
|
||||
<li><I>Processors</I>. Added semantic support for many AARCH64 neon instructions. Addresses for register lanes are now precalculated, reducing the amount of p-code generated. (GP-343)</li>
|
||||
<li><I>Program API</I>. Improved multi-threaded ProgramDB access performance. (GT-3262)</li>
|
||||
<li><I>Scripting</I>. Improved <B>ImportSymbolScript.py</B> to import functions in addition to generic labels. (GT-3249, Issue #946)</li>
|
||||
<li><I>Scripting</I>. Python scripts can now call protected methods from the GhidraScript API. (GT-3334, Issue #1250)</li>
|
||||
<li><I>Scripting</I>. Updated scripting feature with better change detection, external jar dependencies, and modularity. (GP-4)</li>
|
||||
<li><I>Scripting</I>. Updated the GhidraDev plugin (v2.1.1) to support Python Debugging when PyDev is installed via the Eclipse <B>dropins</B> directory. (GP-186, Issue #1922)</li>
|
||||
<li><I>Sleigh</I>. Error messages produced by the SLEIGH compiler have been reformatted to be more consistent in layout as well as more descriptive and more consistent in providing line number information. (GT-3174)</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
<blockquote><p><u>Bugs</u></p>
|
||||
<ul>
|
||||
<li><I>Analysis</I>. Fixed an issue where stored context is initializing the set of registers constantly. (GP-25)</li>
|
||||
<li><I>Analysis</I>. Fixed an RTTI Analyzer regression when analyzing RTTI0 structures with no RTTI4 references to them. (GP-62, Issue #2153)</li>
|
||||
<li><I>Analysis</I>. Fixed an issue where the RTTI analyzer was not filling out RTTI3 structures in some cases. (GP-111)</li>
|
||||
<li><I>API</I>. Fixed NullPointerException when attempting to delete all bookmarks from a script. (GT-3405)</li>
|
||||
<li><I>API</I>. Updated the Class Searcher so that Extension Points found in the <B>Ghidra/patch</B> directory get loaded. (GT-3547, Issue #1515)</li>
|
||||
<li><I>Build</I>. Updated dependency fetch script to use HTTPS when downloading CDT. (GP-69, Issue #2173)</li>
|
||||
<li><I>Build</I>. Fixed resource leak in Ghidra jar builder. (GP-342)</li>
|
||||
<li><I>Byte Viewer</I>. Fixed Byte Viewer to correctly load the middle-mouse highlight color options change. (GT-3471, Issue #1464, #1465)</li>
|
||||
<li><I>Data Types</I>. Fixed decoding of static strings that have a character set with a smaller character size than the platform's character size. (GT-3333, Issue #1255)</li>
|
||||
<li><I>Data Types</I>. Correctly handle Java character sets that do not support the encoding operation. (GT-3407, Issue #1358)</li>
|
||||
<li><I>Data Types</I>. Fixed bug that caused Data Type Manager Editor key bindings to get deleted. (GT-3411, Issue #1355)</li>
|
||||
<li><I>Data Types</I>. Updated the DataTypeParser to handle data type names containing templates. (GT-3493, Issue #1417)</li>
|
||||
<li><I>Data Types</I>. Corrected pointer data type <code>isEquivalent()</code> method to properly check the equivalence of the base data type. The old implementation could cause a pointer to be replaced by a conflicting pointer with the same name whose base datatype is not equivalent. This change has a negative performance impact associated with it and can cause additional conflict datatypes due to the rigid datatype relationships. (GT-3557)</li>
|
||||
<li><I>Data Types</I>. Improved composite conflict resolution performance and corrected composite merge issues when composite bitfields and/or flexible arrays are present. (GT-3571)</li>
|
||||
<li><I>Data Types</I>. Corrected size of <code><B>long</B></code> for AARCH64 per LP64 standard. (GP-175)</li>
|
||||
<li><I>Decompiler</I>. Fixed bug causing the Decompiler to miss symbol references when they are stored to the heap. (GT-3267)</li>
|
||||
<li><I>Decompiler</I>. Fixed bug in the Decompiler that caused <code>Deleting op with descendants</code> exception. (GT-3506)</li>
|
||||
<li><I>Decompiler</I>. Decompiler now correctly compensates for integer promotion on shift, division, and remainder operations. (GT-3572)</li>
|
||||
<li><I>Decompiler</I>. Fixed handling of 64-bit implementations of alloca_probe in the Decompiler. (GT-3576)</li>
|
||||
<li><I>Decompiler</I>. Default Decompiler options now minimize the risk of losing code when renaming or retyping variables. (GT-3577)</li>
|
||||
<li><I>Decompiler</I>. The Decompiler no longer inherits a variable name from a subfunction if that variable incorporates additional data-flow unrelated to the subfunction. (GT-3580)</li>
|
||||
<li><I>Decompiler</I>. Fixed the Decompiler <B>Override Signature</B> action to be enabled on the entire C-code statement. (GT-3636, Issue #1589)</li>
|
||||
<li><I>Decompiler</I>. Fixed frequent ClassCast and IllegalArgument exceptions when performing <B>Auto Create Structure</B> or <B>Auto Create Class</B> actions in the Decompiler. (GP-119)</li>
|
||||
<li><I>Decompiler</I>. Fixed a bug in the Decompiler that caused different variables to be assigned the same name in rare instances. (GP-243, Issue #1995)</li>
|
||||
<li><I>Decompiler</I>. Fixed a bug in the Decompiler that caused <code>PTRSUB off of non-pointer type</code> exceptions. (GP-244, Issue #1826)</li>
|
||||
<li><I>Decompiler</I>. Fixed a bug in the Decompiler that caused load operations from volatile memory to be removed as dead code. (GP-245, Issue #393, #1832)</li>
|
||||
<li><I>Decompiler</I>. Fixed a bug causing the Decompiler to miss a stack alias if its offset was, itself, stored on the stack. (GP-246)</li>
|
||||
<li><I>Decompiler</I>. Fixed a bug causing the Decompiler to lose Equate references to constants passed to functions that were called indirectly. (GP-247)</li>
|
||||
<li><I>Decompiler</I>. Addressed various situations where the Decompiler unexpectedly removes active instructions as dead code after renaming or retyping a stack location. If the location was really an array element or structure field, renaming forced the Decompiler to treat the location as a distinct variable. Subsequently, the Decompiler thought that indirect references based before the location could not alias any following stack locations, which could then by considered dead. As of the 9.2 release, the Decompiler's renaming action no longer switches an annotation to <code>forcing</code> if it wasn't already. A retyping action, although it is <code>forcing</code>, won't trigger alias blocking for atomic data-types (this is configurable). (GP-248, Issue #524, #873)</li>
|
||||
<li><I>Decompiler</I>. Fixed decompiler memory issues reported by a community security researcher. (GP-267)</li>
|
||||
<li><I>Demangler</I>. Fixed the GnuDemangler to parse the full namespace for <code>operator</code> symbols. (GT-3474, Issue #1441, #1448)</li>
|
||||
<li><I>Demangler</I>. Fixed numerous GNU Demangler parsing issues. Most notable is the added support for C++ Lambda functions. (GT-3545, Issue #1457, #1569)</li>
|
||||
<li><I>Demangler</I>. Updated the GNU Demangler to correctly parse and apply C++ strings using the <code>unnamed type</code> syntax. (GT-3645)</li>
|
||||
<li><I>Demangler</I>. Fixed duplicate namespace entry returned from <code>getNamespaceString()</code> on DemangledVariable. (GT-3646, Issue #1729)</li>
|
||||
<li><I>Demangler</I>. Fixed a GnuDemangler ClassCastException when parsing a <code>typeinfo</code> string containing <code>operator</code> text. (GP-160, Issue #1870, #2267)</li>
|
||||
<li><I>Demangler</I>. Added <B>stdlib.h</B> include to the GNU Demangler to fix a build issue on some systems. (GP-187, Issue #2294)</li>
|
||||
<li><I>DWARF</I>. Corrected DWARF relocation handling where the address image base adjustment was factored in twice. (GT-3330)</li>
|
||||
<li><I>File Formats</I>. Fixed a potential divide-by-zero exception in the EXT4 file system. (GT-3400, Issue #1342)</li>
|
||||
<li><I>File Formats</I>. Fixed date and time parsing of dates in cdrom <code>iso9660</code> image files. (GT-3451, Issue #1403)</li>
|
||||
<li><I>Graphing</I>. Fixed a ClassCastException sometimes encountered when performing <B>Select -> Scoped Flow -> Forward Scoped Flow</B>. (GP-180)</li>
|
||||
<li><I>GUI</I>. Fixed inconsistent behavior with the interactive python interpreter's key bindings. (GT-3282)</li>
|
||||
<li><I>GUI</I>. Fixed Structure Editor bug that prevented the <B>F2 Edit</B> action from editing the correct table cell after using the arrow keys. (GT-3308, Issue #703)</li>
|
||||
<li><I>GUI</I>. Updated the Structure Editor so the <B>Delete</B> action is put into a background task to prevent the UI from locking. (GT-3352)</li>
|
||||
<li><I>GUI</I>. Fixed IndexOutOfBoundsException when invoking column filter on Key Bindings table. (GT-3445)</li>
|
||||
<li><I>GUI</I>. Fixed the analysis log dialog to not consume all available screen space. (GT-3610)</li>
|
||||
<li><I>GUI</I>. Fixed issue where <B>Location</B> column, when used in the column filters, resulted in extraneous dialogs popping up. (GT-3623)</li>
|
||||
<li><I>GUI</I>. Fixed Data Type Preview <B>copy</B> action so that newlines are preserved; updated table export to CSV to escape quotes and commas. (GT-3624)</li>
|
||||
<li><I>GUI</I>. Fixed tables in Ghidra to copy the text that is rendered. Some tables mistakenly copied the wrong value, such as the Functions Table's Function Signature Column. (GT-3629, Issue #1628)</li>
|
||||
<li><I>GUI</I>. Structure editor name now updates in title bar and tab when structure is renamed. (GP-19)</li>
|
||||
<li><I>GUI</I>. Fixed an issue where drag-and-drop import locks the Windows File Explorer source window until the import dialog is closed by the user. (GP-27)</li>
|
||||
<li><I>GUI</I>. Fixed an issue in GTreeModel where fireNodeChanged had no effect. This could result in stale node information and truncation of the text associated with a node in a GTree. (GP-30)</li>
|
||||
<li><I>GUI</I>. Fixed an issue where the file chooser directory list truncated filenames with ellipses on HiDPI Windows. (GP-31)</li>
|
||||
<li><I>GUI</I>. Fixed an uncaught exception when double-clicking on <code>UndefinedFunction_</code> in Decompiler window. (GP-40)</li>
|
||||
<li><I>GUI</I>. Updated error handling to only show one dialog when a flurry of errors is encountered. (GP-65, Issue #2185)</li>
|
||||
<li><I>GUI</I>. Fixed an issue where Docking Windows are restored incorrectly if a snapshot is present. (GP-92)</li>
|
||||
<li><I>GUI</I>. Fixed a File Chooser bug causing a NullPointerException for some users. (GP-171, Issue #1706)</li>
|
||||
<li><I>GUI</I>. Fixed an issue that caused the script progress bar to appear intermittently. (GP-179, Issue #1819)</li>
|
||||
<li><I>GUI</I>. Fixed a bug that caused Call Tree nodes to go missing when showing more than one function with the same name. (GP-213, Issue #1682)</li>
|
||||
<li><I>GUI:Project Window</I>. Fixed Front End <B>copy</B> action to allow for the copy of program names so that users can paste those names into external applications. (GT-3403, Issue #1257)</li>
|
||||
<li><I>Headless</I>. Headless Ghidra now properly honors the <code><B>-processor</B></code> flag, even if the specified processor is not a valid <B>opinion</B>. (GT-3376, Issue #1311)</li>
|
||||
<li><I>Importer</I>. Corrected an NeLoader flags parsing error. (GT-3381, Issue #1312)</li>
|
||||
<li><I>Importer</I>. Fixed the <B>File -> Add to Program...</B> action to not show a memory conflict error when the user is creating an overlay. (GT-3491, Issue #1376)</li>
|
||||
<li><I>Importer</I>. Updated the XML Importer to apply repeatable comments. (GT-3492, Issue #1423)</li>
|
||||
<li><I>Importer</I>. Fixed issue in Batch Import where only one item of a selection was removed when attempting to remove a selection of items. (GP-138)</li>
|
||||
<li><I>Importer</I>. Corrected various issues with processing crushed PNG images. (GP-146, Issue #1854, #1874, #1875, #2252)</li>
|
||||
<li><I>Importer</I>. Fixed RuntimeException occurrence when trying to load NE programs with unknown resources. (GP-182, Issue #1596, #1713, #2012)</li>
|
||||
<li><I>Importer</I>. Fixed batch import to handle IllegalArgumentExceptions thrown by loaders. (GP-227, Issue #2328)</li>
|
||||
<li><I>Importer:ELF</I>. Corrected ELF relocation processing for ARM BE8 (mixed-endian). (GT-3527, Issue #1494)</li>
|
||||
<li><I>Importer:ELF</I>. Corrected ELF import processing of <code>DT_JMPREL</code> relocations and markup of associated PLT entries. (GP-252, Issue #2334)</li>
|
||||
<li><I>Importer:PE</I>. Fixed an IndexOutOfBoundsException in the PeLoader that occurred when the size of a section extends past the end of the file. (GT-3433, Issue #1371)</li>
|
||||
<li><I>Listing:Comments</I>. Fixed bug in Comment field that prevented navigation when clicking on an address or symbol where tabs were present in the comment. (GT-3440)</li>
|
||||
<li><I>Memory</I>. Fixed bug where sometimes random bytes are inserted instead of <code>0x00</code> when expanding a memory block. (GT-3465)</li>
|
||||
<li><I>Processors</I>. Corrected the offset in SuperH instructions generated by sign-extending a 20-bit immediate value composed of two sub-fields. (GT-3251, Issue #1161)</li>
|
||||
<li><I>Processors</I>. Fixed AVR8 addition/subtraction flag macros. (GT-3276)</li>
|
||||
<li><I>Processors</I>. Corrected <code>XGATE</code> <code>ROR</code> instruction semantics. (GT-3278)</li>
|
||||
<li><I>Processors</I>. Corrected semantics for SuperH <code>movi20</code> and <code>movi20s</code> instructions. (GT-3337, Issue #1264)</li>
|
||||
<li><I>Processors</I>. Corrected SuperH floating point instruction token definition. (GT-3340, Issue #1265)</li>
|
||||
<li><I>Processors</I>. Corrected SuperH <code>movu.b</code> and <code>movu.w</code> instruction semantics. (GT-3345, Issue #1271)</li>
|
||||
<li><I>Processors</I>. Corrected AVR8 <code>lpm</code> and <code>elpm</code> instruction semantics. (GT-3346, Issue #631)</li>
|
||||
<li><I>Processors</I>. Corrected pcode for the 6805 <code>BSET</code> instruction. (GT-3366, Issue #1307)</li>
|
||||
<li><I>Processors</I>. Corrected ARM constructors for instructions <code>vnmla</code>, <code>vnmls</code>, and <code>vnmul</code>. (GT-3368, Issue #1277)</li>
|
||||
<li><I>Processors</I>. Corrected bit-pattern for ARM <code>vcvt</code> instruction. (GT-3369, Issue #1278)</li>
|
||||
<li><I>Processors</I>. Corrected TriCore <code>abs</code> instructions. (GT-3379, Issue #1286)</li>
|
||||
<li><I>Processors</I>. Corrected x86 <code>BT</code> instruction semantics. (GT-3423, Issue #1370)</li>
|
||||
<li><I>Processors</I>. Fixed issue where CRC16C <code>LOAD</code>/<code>STOR</code> with <code>abs20</code> were not mapped correctly. (GT-3529, Issue #1518)</li>
|
||||
<li><I>Processors</I>. Fixed M68000 <code>MOVE USP,x</code> and <code>MOVE x,USP</code> opcodes. (GT-3594, Issue #1593)</li>
|
||||
<li><I>Processors</I>. Fixed the ARM/Thumb <code>TEQ</code> instruction pcode to be an XOR. (GP-23, Issue #1802)</li>
|
||||
<li><I>Processors</I>. Emulation was broken by a regression in version 9.1.2. Emulation and Sleigh Pcodetests now work correctly. (GP-24, Issue #1579)</li>
|
||||
<li><I>Processors</I>. Fixed carry flag issue for 6502 <code>CMP</code>, <code>CPX</code>, and <code>CPY</code> instructions. (GP-34)</li>
|
||||
<li><I>Processors</I>. Corrected the SuperH high-order bit calculation for the <code>rotr</code> instruction. (GP-47)</li>
|
||||
<li><I>Processors</I>. Corrected ELF ARM relocation processing for type 3 (<code>R_ARM_REL32</code>) and added support for type 42 (<code>R_ARM_PREL31</code>). (GP-164, Issue #2261, #2276)</li>
|
||||
<li><I>Scripting</I>. Moved Jython cache directory out of <B>tmp</B>. (GP-36)</li>
|
||||
<li><I>Scripting</I>. Fixed a NoClassDefFoundError when compiling GhidraScript under JDK14. (GP-59, Issue #2152)</li>
|
||||
<li><I>Scripting</I>. Fixed issues with null result when searching for the script directory. (GP-103, Issue #2187)</li>
|
||||
<li><I>Scripting</I>. Fixed scripting issue where, if there were non-ASCII characters in the user path, Jython would not work. (GP-204, Issue #1890)</li>
|
||||
<li><I>Sleigh</I>. Corrected IndexOutOfBoundsException in SLEIGH when doing simple assignment in disassembly actions block. (GT-3382, Issue #745)</li>
|
||||
<li><I>Symbol Tree</I>. Fixed the Symbol Tree so that clicking an already-selected symbol node will still trigger a Listing navigation. (GT-3436, Issue #453)</li>
|
||||
<li><I>Symbol Tree</I>. Fixed the Symbol Tree to not continuously rebuild while performing Auto-analysis. (GT-3542)</li>
|
||||
<li><I>Version Tracking</I>. Fixed Version Tracking <B>Create Manual Match</B> action. (GT-3305, Issue #2215)</li>
|
||||
<li><I>Version Tracking</I>. Fixed a NullPointerException encountered when changing the Version Tracking options for the <B>Listing Code Comparison</B> when no data was loaded. (GT-3437, Issue #1143)</li>
|
||||
<li><I>Version Tracking</I>. Fixed Version Tracking exception triggered in the <B>Exact Functions Instructions Match</B> correlator encountered when the two functions being compared differed in their number of instructions. (GT-3438, Issue #1352)</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<H1 align="center">Ghidra 9.1.2 Change History (February 2020)</H1>
|
||||
<blockquote><p><u>Bugs</u></p>
|
||||
<ul>
|
||||
|
@ -16,11 +229,11 @@
|
|||
<li><I>GUI</I>. Corrected processor manual display for Microsoft Windows users, which was not displaying processor manual and was, instead, rendering a blank page in web browser. (GT-3444)</li>
|
||||
<li><I>GUI:Bitfield Editor</I>. Added field comment support to composite bitfield editor. (GT-3410)</li>
|
||||
<li><I>Importer:MachO</I>. A MachO loader regression, in Ghidra 9.1.1, when laying down symbols at the correct location, has been fixed. (GT-3487, Issue #1446)</li>
|
||||
<li><I>Languages</I>. Corrected mnemonic for ARM thumb <code>RSB.w</code> instruction. (GT-3420, Issue #1365)</li>
|
||||
<li><I>Languages</I>. Corrected issue in M68000 with some move instructions not creating correct array assignments. (GT-3429, Issue #1394)</li>
|
||||
<li><I>Languages</I>. Updated x86 processor manual index file with latest Intel and AMD manuals. (GT-3489, Issue #1078)</li>
|
||||
<li><I>Multi-User:Ghidra Server</I>. Corrected Ghidra Server remote interface errors that occur when running with Java 11.0.6 (and later) release, which would throw RemoteException <code>"Method is not Remote"</code> errors. (GT-3521, Issue #1440)</li>
|
||||
<li><I>PDB</I>. Corrected PDB XML generation for zero-length classes and structures and resolved various datatype dependency issues encountered during PDB Analysis. Changed line numbers from hex to decimal. (GT-3462, Issue #1410)</li>
|
||||
<li><I>Processors</I>. Corrected mnemonic for ARM thumb <code>RSB.w</code> instruction. (GT-3420, Issue #1365)</li>
|
||||
<li><I>Processors</I>. Corrected issue in M68000 with some move instructions not creating correct array assignments. (GT-3429, Issue #1394)</li>
|
||||
<li><I>Processors</I>. Updated x86 processor manual index file with latest Intel and AMD manuals. (GT-3489, Issue #1078)</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
|
@ -31,6 +244,7 @@
|
|||
<li><I>Program API</I>. Cached the addresses that correspond to executable memory to improve analysis performance. (GT-3260)</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<blockquote><p><u>Bugs</u></p>
|
||||
<ul>
|
||||
<li><I>Analysis</I>. Fixed a symbol name error that occurred in the Objective-C analyzer. (GT-3321, Issue #1200)</li>
|
||||
|
@ -42,17 +256,17 @@
|
|||
<li><I>Decompiler</I>. Fixed issue with enum name strings causing <code>Low-level Error: XML error: syntax error</code> in the decompiler. (GT-3387, Issue #1329)</li>
|
||||
<li><I>GUI</I>. Fixed a potential ConcurrentModificationException in the interactive python interpreter. (GT-3280)</li>
|
||||
<li><I>Importer:PE</I>. Fixed an exception in the PeLoader that occurred when the size of the memory block for the headers is larger than the file size. (GT-3344, Issue #1266)</li>
|
||||
<li><I>Languages</I>. Corrected Sparc floating point instruction pcode implementation. (GT-3202)</li>
|
||||
<li><I>Languages</I>. Corrected the semantics of the PowerPC <code>e_cmpi</code> instruction. (GT-3228, Issue #1127)</li>
|
||||
<li><I>Languages</I>. Corrected bit generation for PowerPC instructions <code>se_bclri</code>, <code>se_bgeni</code>, <code>se_bseti</code>, and <code>se_btsti</code>. (GT-3232, Issue #967)</li>
|
||||
<li><I>Languages</I>. Corrected register definitions for x86 <code>RDRAND</code> instruction. (GT-3253, Issue #1169)</li>
|
||||
<li><I>Languages</I>. Corrected signed immediate calculation for some powerPC VLE offsets being incorrect. (GT-3254, Issue #1160)</li>
|
||||
<li><I>Languages</I>. Resolved issue with x86 escape opcodes preventing certain instruction patterns from decoding. (GT-3256)</li>
|
||||
<li><I>Languages</I>. Corrected bug in <code>XGATE</code> <code>LDH</code> instruction shifting out high bits. (GT-3268)</li>
|
||||
<li><I>Languages</I>. Corrected processing of <code>R_MIPS_REL32</code>, <code>R_X86_64_RELATIVE</code>, and <code>R_X86_64_RELATIVE64</code> ELF relocations affecting relocatable binaries which have non-zero section/segment load addresses. (GT-3349)</li>
|
||||
<li><I>Listing</I>. Fixed missing scroll bar in listing. (GT-3290)</li>
|
||||
<li><I>Listing</I>. Fixed issue that was causing a stack trace to be generated when contiguous addresses were cleared for a range greater than <code>Integer.MAX</code>. (GT-3357)</li>
|
||||
<li><I>Listing:References</I>. Corrected <B>Create Default Reference</B> action bug which did not handle composite/array data components properly. (GT-3371)</li>
|
||||
<li><I>Processors</I>. Corrected Sparc floating point instruction pcode implementation. (GT-3202)</li>
|
||||
<li><I>Processors</I>. Corrected the semantics of the PowerPC <code>e_cmpi</code> instruction. (GT-3228, Issue #1127)</li>
|
||||
<li><I>Processors</I>. Corrected bit generation for PowerPC instructions <code>se_bclri</code>, <code>se_bgeni</code>, <code>se_bseti</code>, and <code>se_btsti</code>. (GT-3232, Issue #967)</li>
|
||||
<li><I>Processors</I>. Corrected register definitions for x86 <code>RDRAND</code> instruction. (GT-3253, Issue #1169)</li>
|
||||
<li><I>Processors</I>. Corrected signed immediate calculation for some powerPC VLE offsets being incorrect. (GT-3254, Issue #1160)</li>
|
||||
<li><I>Processors</I>. Resolved issue with x86 escape opcodes preventing certain instruction patterns from decoding. (GT-3256)</li>
|
||||
<li><I>Processors</I>. Corrected bug in <code>XGATE</code> <code>LDH</code> instruction shifting out high bits. (GT-3268)</li>
|
||||
<li><I>Processors</I>. Corrected processing of <code>R_MIPS_REL32</code>, <code>R_X86_64_RELATIVE</code>, and <code>R_X86_64_RELATIVE64</code> ELF relocations affecting relocatable binaries which have non-zero section/segment load addresses. (GT-3349)</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
|
@ -64,21 +278,20 @@
|
|||
<li><I>GUI</I>. Added method for turning off table sorting by control-clicking the only sorted table column. (GT-2763, Issue #87)</li>
|
||||
<li><I>GUI</I>. Hovering on an address will now show where the byte at that address came from in the imported file. (GT-3016, Issue #154)</li>
|
||||
<li><I>Importer:MachO</I>. Added new importer/loader for DYLD-shared cache files. (GT-2343)</li>
|
||||
<li><I>Languages</I>. Implemented Intel MCS-96 processor module. (GT-2350)</li>
|
||||
<li><I>Languages</I>. Added SH1/2/2a sleigh processor specification. (GT-3029, Issue #715)</li>
|
||||
<li><I>Languages</I>. Added Tricore processor specification. (GT-3041, Issue #567)</li>
|
||||
<li><I>Languages</I>. Added HCS12X processor specification. (GT-3049)</li>
|
||||
<li><I>Languages</I>. Added HCS05 and HCS08 sleigh processor specifications. (GT-3050)</li>
|
||||
<li><I>Languages</I>. Added SH4 sleigh processor specification. (GT-3051, Issue #37)</li>
|
||||
<li><I>Languages</I>. Added MCS-48 processor specification. (GT-3058, Issue #638)</li>
|
||||
<li><I>Memory</I>. Added new API to preserve imported program's original bytes and how they map to memory blocks. (GT-2845)</li>
|
||||
<li><I>Processors</I>. Implemented Intel MCS-96 processor module. (GT-2350)</li>
|
||||
<li><I>Processors</I>. Added SH1/2/2a sleigh processor specification. (GT-3029, Issue #715)</li>
|
||||
<li><I>Processors</I>. Added Tricore processor specification. (GT-3041, Issue #567)</li>
|
||||
<li><I>Processors</I>. Added HCS12X processor specification. (GT-3049)</li>
|
||||
<li><I>Processors</I>. Added HCS05 and HCS08 sleigh processor specifications. (GT-3050)</li>
|
||||
<li><I>Processors</I>. Added SH4 sleigh processor specification. (GT-3051, Issue #37)</li>
|
||||
<li><I>Processors</I>. Added MCS-48 processor specification. (GT-3058, Issue #638)</li>
|
||||
<li><I>Program API</I>. Added Bit-field support for structures and unions.
|
||||
<B>Warning:</B> Version upgrade will be forced on all modified programs and data type archives that are open for update. (GT-557)</li>
|
||||
<li><I>Sleigh</I>. Added two new extension modules (SleighDevTools and GnuDisassembler) in support of processor module development. Added support for pcode junit tests which utilize emulation of cross-compiled C test code to verify sleigh pcode (i.e., instruction semantics). The SleighDevTools extension provides the pcode test C source and associated build scripts, as well as external disassembler support for aiding in the validation of disassembled instruction syntax. (GT-3067)</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
|
||||
<blockquote><p><u>Improvements</u></p>
|
||||
<ul>
|
||||
<li><I>Analysis</I>. Added example script, ResolveX86orX64LinuxSyscallsScript.java, for decompiling Linux system calls in x86 and x64. Added syscall-related exercises to <B>Advanced</B> class. (GT-3113)</li>
|
||||
|
@ -123,18 +336,6 @@
|
|||
<li><I>Importer:PE</I>. PeLoader better accounts for section alignment when laying out memory blocks, allowing additional bytes from the file to be loaded into memory. (GT-2827, Issue #327, #418)</li>
|
||||
<li><I>Importer:PE</I>. Removed out-of-place call to demangler and laying down of types from PeLoader. This fix enables demangling and other analyzers to be applied correctly and in the proper order. (GT-2849)</li>
|
||||
<li><I>Importer:PE</I>. PeLoader now adds TLS callback functions as entry points. (GT-2898, Issue #102)</li>
|
||||
<li><I>Languages</I>. Added new Task Monitor service to better handle user experience when there are delays in building languages. (GT-2376)</li>
|
||||
<li><I>Languages</I>. Corrected ARM/Thumb instruction parsing for Thumb <code>bl</code> and <code>add</code> instructions. (GT-2744, Issue #362)</li>
|
||||
<li><I>Languages</I>. Added AVR8 manual index file. (GT-2828, Issue #346)</li>
|
||||
<li><I>Languages</I>. Improved support for ARM on Windows. (GT-2880)</li>
|
||||
<li><I>Languages</I>. M68000 <code>LSL.W</code>, <code>ASL.B</code>, <code>LSL.B</code>, and <code>ASL.W</code> instructions now correctly set the <code>CF</code> flag. (GT-2907, Issue #619)</li>
|
||||
<li><I>Languages</I>. Updated x86 manual index files. (GT-2943, Issue #366)</li>
|
||||
<li><I>Languages</I>. Improved macro label-related error reporting in slaspec files. (GT-2995, Issue #522)</li>
|
||||
<li><I>Languages</I>. Added MIPS special <code>0x1f</code> patterns. (GT-3005, Issue #709)</li>
|
||||
<li><I>Languages</I>. Added proper updating of the <code>X</code> condition flag register for the M68000 processor <code>lsl</code> and <code>lsr</code> instructions. (GT-3137, Issue #983)</li>
|
||||
<li><I>Languages</I>. Implemented PowerPc VLE Interrupt Handler Efficiency Instructions. (GT-3143, Issue #935)</li>
|
||||
<li><I>Languages</I>. Ghidra now correctly models SPARC 64-bit <B>stack bias</B>. (GT-3201)</li>
|
||||
<li><I>Languages</I>. Updated AVR32 instruction manual index to latest version. (GT-712)</li>
|
||||
<li><I>Listing</I>. Updated Listing to support horizontal scrolling by holding the <B>Shift</B> key when using the mouse wheel. (GT-3105, Issue #451)</li>
|
||||
<li><I>Listing:References</I>. Created new <B>overriding</B> reference types, which improve and extend the ability to override calls, jumps, and callothers. (GT-2885)</li>
|
||||
<li><I>Multi-User</I>. Added a script to allow repository admins the ability to terminate multiple file checkouts belonging to an individual user on a shared project. (GT-2893)</li>
|
||||
|
@ -143,6 +344,18 @@
|
|||
<li><I>PDB</I>. Now using HTTPS for Microsoft symbol server URL. (GT-2819, Issue #369)</li>
|
||||
<li><I>PDB</I>. PDB processing can now store data types that contain forward slashes under a CategoryPath. (GT-2974, Issue #94, #182)</li>
|
||||
<li><I>PDB</I>. PDB Analyzer no longer automatically includes the PDB path specified in the program's PE header when searching for the PDB. However, the filename in this path is considered during the search. The analyzer's <B>Unsafe: Include PE PDB Path in PDB Search</B> option allows the user to revert to the original PDB search algorithm. (GT-3076, Issue #277)</li>
|
||||
<li><I>Processors</I>. Added new Task Monitor service to better handle user experience when there are delays in building languages. (GT-2376)</li>
|
||||
<li><I>Processors</I>. Corrected ARM/Thumb instruction parsing for Thumb <code>bl</code> and <code>add</code> instructions. (GT-2744, Issue #362)</li>
|
||||
<li><I>Processors</I>. Added AVR8 manual index file. (GT-2828, Issue #346)</li>
|
||||
<li><I>Processors</I>. Improved support for ARM on Windows. (GT-2880)</li>
|
||||
<li><I>Processors</I>. M68000 <code>LSL.W</code>, <code>ASL.B</code>, <code>LSL.B</code>, and <code>ASL.W</code> instructions now correctly set the <code>CF</code> flag. (GT-2907, Issue #619)</li>
|
||||
<li><I>Processors</I>. Updated x86 manual index files. (GT-2943, Issue #366)</li>
|
||||
<li><I>Processors</I>. Improved macro label-related error reporting in slaspec files. (GT-2995, Issue #522)</li>
|
||||
<li><I>Processors</I>. Added MIPS special <code>0x1f</code> patterns. (GT-3005, Issue #709)</li>
|
||||
<li><I>Processors</I>. Added proper updating of the <code>X</code> condition flag register for the M68000 processor <code>lsl</code> and <code>lsr</code> instructions. (GT-3137, Issue #983)</li>
|
||||
<li><I>Processors</I>. Implemented PowerPc VLE Interrupt Handler Efficiency Instructions. (GT-3143, Issue #935)</li>
|
||||
<li><I>Processors</I>. Ghidra now correctly models SPARC 64-bit <B>stack bias</B>. (GT-3201)</li>
|
||||
<li><I>Processors</I>. Updated AVR32 instruction manual index to latest version. (GT-712)</li>
|
||||
<li><I>Program API</I>. Added SHA256 hash to Program metadata and API. (GT-2753, Issue #331)</li>
|
||||
<li><I>Scripting</I>. Updated Script Table Chooser Dialog: to fix bug with tracking work items, to add new API methods for item removal and dialog closed notification, and to prevent the same item from being worked on more than once. (GT-2724, Issue #307)</li>
|
||||
<li><I>Scripting</I>. Fixed MultiInstructionMemReference Ghidra script to place the reference correctly on instructions with a delay slot. (GT-2906)</li>
|
||||
|
@ -216,25 +429,6 @@
|
|||
<li><I>Importer:ELF</I>. Improved ELF MIPS support for GP-relative relocations encountered in PIC compiled binaries. Also added support for <code>R_MIPS_RPREL32</code> relocation. (GT-3026, Issue #764)</li>
|
||||
<li><I>Importer:ELF</I>. ELF x86-64 relocations <code>R_X86_64_GOT32</code>, <code>R_X86_64_PLT32</code>, <code>R_X86_64_SIZE32</code>, <code>R_X86_64_SIZE64</code>, and <code>R_X86_64_GOTPC32</code> have been fixed to relocate correctly. Additional ELF x86-64 relocations, found mostly in unlinked <B>.o</B> files, have been added. (GT-3089, Issue #910)</li>
|
||||
<li><I>Importer:PE</I>. Fixed a problem in the PeLoader that would result in section names being incorrectly used as primary symbols. This could result in function names being wrong. (GT-3195, Issue #761, #1051)</li>
|
||||
<li><I>Languages</I>. Utilized <code>FLOAT_NEG</code> pcodeop to simplify PowerPC <code>fneg</code> instructions. (GT-2781, Issue #387)</li>
|
||||
<li><I>Languages</I>. Added 6502 <code>I</code> status bit save and restore. (GT-2826, Issue #469)</li>
|
||||
<li><I>Languages</I>. Corrected alternate register definitions in z80 processor. (GT-2876, Issue #520)</li>
|
||||
<li><I>Languages</I>. Reviewed all processor modules for GhidraSleighEditor syntax errors. (GT-2902)</li>
|
||||
<li><I>Languages</I>. Added support for <code>RD</code>, <code>WR</code>, <code>FS</code>, and <code>GSBASE</code> instructions in x86. (GT-2940, Issue #554, #555)</li>
|
||||
<li><I>Languages</I>. Added fixes for sign extension of <code>ADD</code>, <code>AND</code>, <code>CMP</code>, and <code>SUB</code> instructions on x86-64bit. (GT-2955, Issue #881)</li>
|
||||
<li><I>Languages</I>. Updated PIC-30 division pcode to correct decompilation issue. (GT-3008)</li>
|
||||
<li><I>Languages</I>. Fixed x86 <code>AAM</code> instruction. (GT-3015)</li>
|
||||
<li><I>Languages</I>. Corrected x86 decode of <code>MOVBE</code> instruction. (GT-3039, Issue #822)</li>
|
||||
<li><I>Languages</I>. Corrected M68000 <code>mov3q</code> instruction decode and semantics. (GT-3080, Issue #905)</li>
|
||||
<li><I>Languages</I>. The JVM instruction <code>I2D</code> now correctly pushes an 8-byte double on the stack. (GT-3081)</li>
|
||||
<li><I>Languages</I>. Fixed problem displaying processor manuals in Windows Firefox. (GT-3084)</li>
|
||||
<li><I>Languages</I>. Encoding of <code>MOV</code> into debug registers has been relaxed. (GT-3117)</li>
|
||||
<li><I>Languages</I>. Corrected behavior of PowerPC <code>vectorPermute</code> pcodeop for emulation. (GT-3148)</li>
|
||||
<li><I>Languages</I>. Corrected MIPS relocation computation for <code>R_MIPS_26</code>, <code>R_MIPS16_26</code>, and <code>R_MICROMIPS_26_S1</code>. (GT-3154, Issue #1001)</li>
|
||||
<li><I>Languages</I>. Corrected the bit patterns for PowerPC VLE <code>rlwimi</code> and <code>rlwinm</code> instructions. (GT-3159, Issue #752)</li>
|
||||
<li><I>Languages</I>. Corrected instruction semantics for AARCH64 <code>BLR</code> instruction. (GT-3191)</li>
|
||||
<li><I>Languages</I>. Corrected fall-through override semantics for cases where pcode simply drops into the next address. (GT-3196, Issue #1083)</li>
|
||||
<li><I>Languages</I>. Corrected the semantics of the PowerPC <code>se_bmaski</code> instruction. (GT-3230, Issue #1123)</li>
|
||||
<li><I>Listing</I>. Fixed potential infinite loop when editing long comments. (GT-2824, Issue #437)</li>
|
||||
<li><I>Listing</I>. Fixed potential ClassCastException in Listing comments. (GT-3023)</li>
|
||||
<li><I>Listing</I>. Cursor in the listing now stays in the proper column after editing a field. (GT-3045, Issue #702)</li>
|
||||
|
@ -248,6 +442,25 @@
|
|||
<li><I>PDB</I>. Addressed memory leaks and string handling issues in <B>pdb.exe</B>. (GT-2975, Issue #674, #597, #598, #599, #600)</li>
|
||||
<li><I>PDB</I>. Can now recover stack variables from more recent Visual Studio version PDBs. (GT-3014)</li>
|
||||
<li><I>PDB</I>. Fixed PDB validation logic, which caused a more severe error message to be created, masking the real issue. (GT-3209, Issue #198, #1024)</li>
|
||||
<li><I>Processors</I>. Utilized <code>FLOAT_NEG</code> pcodeop to simplify PowerPC <code>fneg</code> instructions. (GT-2781, Issue #387)</li>
|
||||
<li><I>Processors</I>. Added 6502 <code>I</code> status bit save and restore. (GT-2826, Issue #469)</li>
|
||||
<li><I>Processors</I>. Corrected alternate register definitions in z80 processor. (GT-2876, Issue #520)</li>
|
||||
<li><I>Processors</I>. Reviewed all processor modules for GhidraSleighEditor syntax errors. (GT-2902)</li>
|
||||
<li><I>Processors</I>. Added support for <code>RD</code>, <code>WR</code>, <code>FS</code>, and <code>GSBASE</code> instructions in x86. (GT-2940, Issue #554, #555)</li>
|
||||
<li><I>Processors</I>. Added fixes for sign extension of <code>ADD</code>, <code>AND</code>, <code>CMP</code>, and <code>SUB</code> instructions on x86-64bit. (GT-2955, Issue #881)</li>
|
||||
<li><I>Processors</I>. Updated PIC-30 division pcode to correct decompilation issue. (GT-3008)</li>
|
||||
<li><I>Processors</I>. Fixed x86 <code>AAM</code> instruction. (GT-3015)</li>
|
||||
<li><I>Processors</I>. Corrected x86 decode of <code>MOVBE</code> instruction. (GT-3039, Issue #822)</li>
|
||||
<li><I>Processors</I>. Corrected M68000 <code>mov3q</code> instruction decode and semantics. (GT-3080, Issue #905)</li>
|
||||
<li><I>Processors</I>. The JVM instruction <code>I2D</code> now correctly pushes an 8-byte double on the stack. (GT-3081)</li>
|
||||
<li><I>Processors</I>. Fixed problem displaying processor manuals in Windows Firefox. (GT-3084)</li>
|
||||
<li><I>Processors</I>. Encoding of <code>MOV</code> into debug registers has been relaxed. (GT-3117)</li>
|
||||
<li><I>Processors</I>. Corrected behavior of PowerPC <code>vectorPermute</code> pcodeop for emulation. (GT-3148)</li>
|
||||
<li><I>Processors</I>. Corrected MIPS relocation computation for <code>R_MIPS_26</code>, <code>R_MIPS16_26</code>, and <code>R_MICROMIPS_26_S1</code>. (GT-3154, Issue #1001)</li>
|
||||
<li><I>Processors</I>. Corrected the bit patterns for PowerPC VLE <code>rlwimi</code> and <code>rlwinm</code> instructions. (GT-3159, Issue #752)</li>
|
||||
<li><I>Processors</I>. Corrected instruction semantics for AARCH64 <code>BLR</code> instruction. (GT-3191)</li>
|
||||
<li><I>Processors</I>. Corrected fall-through override semantics for cases where pcode simply drops into the next address. (GT-3196, Issue #1083)</li>
|
||||
<li><I>Processors</I>. Corrected the semantics of the PowerPC <code>se_bmaski</code> instruction. (GT-3230, Issue #1123)</li>
|
||||
<li><I>Program API</I>. Corrected parameter storage which failed to properly refresh after undo/redo. (GT-3130, Issue #960)</li>
|
||||
<li><I>Program API</I>. Corrected function parameter ordinal numbering when more than one auto-parameter is present. (GT-3214)</li>
|
||||
<li><I>Project Manager</I>. Fixed a problem with creating Ghidra projects in Windows root directories (e.g., Z:\). (GT-2585)</li>
|
||||
|
@ -262,164 +475,130 @@
|
|||
</blockquote>
|
||||
|
||||
<H1 align="center">Ghidra 9.0.4 Change History (May 2019)</H1>
|
||||
|
||||
<blockquote><p><u>Bugs</u></p></blockquote>
|
||||
<blockquote>
|
||||
<blockquote><p><u>Bugs</u></p>
|
||||
<ul>
|
||||
|
||||
<li><I>Multi-User:Ghidra Server.</I> Corrected severe script error in svrAdmin.bat introduced with 9.0.3 build.</li>
|
||||
<li><I>GUI.</I> Restored the default 'p' key binding for creating pointers within the listing display.</li>
|
||||
|
||||
<li><I>Multi-User:Ghidra Server</I>. Corrected severe script error in svrAdmin.bat introduced with 9.0.3 build.</li>
|
||||
<li><I>GUI</I>. Restored the default 'p' key binding for creating pointers within the listing display.</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<H1 align="center">Ghidra 9.0.3 Change History (April 2019)</H1>
|
||||
|
||||
<blockquote><p><u>New Feature</u></p></blockquote>
|
||||
<blockquote>
|
||||
<blockquote><p><u>New Features</u></p>
|
||||
<ul>
|
||||
|
||||
<li><I>GUI.</I> Function tags are now viewable from Functions Window table using new column.</li>
|
||||
|
||||
<li><I>GUI</I>. Function tags are now viewable from Functions Window table using new column.</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<blockquote><p><u>Improvements</u></p></blockquote>
|
||||
<blockquote>
|
||||
<blockquote><p><u>Improvements</u></p>
|
||||
<ul>
|
||||
|
||||
<li><I>Decompiler.</I> Improved modeling of CFG on Windows 10. (Issue #340)</li>
|
||||
<li><I>Patcher.</I> Renamed patch directory to /Ghidra/patch and added README.txt that explains how the patch directory is used.</li>
|
||||
<li><I>Search.</I> Updated the Decompiler Data Type Finder to find references to inside of nested array access in a line of Decompiler C output. (Issue #416)</li>
|
||||
<li><I>Sleigh.</I> Improved error reporting for SLEIGH compiler. (Issue #364)</li>
|
||||
|
||||
<li><I>Decompiler</I>. Improved modeling of CFG on Windows 10. (Issue #340)</li>
|
||||
<li><I>Patcher</I>. Renamed patch directory to /Ghidra/patch and added README.txt that explains how the patch directory is used.</li>
|
||||
<li><I>Search</I>. Updated the Decompiler Data Type Finder to find references to inside of nested array access in a line of Decompiler C output. (Issue #416)</li>
|
||||
<li><I>Sleigh</I>. Improved error reporting for SLEIGH compiler. (Issue #364)</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<blockquote><p><u>Bugs</u></p></blockquote>
|
||||
<blockquote>
|
||||
<blockquote><p><u>Bugs</u></p>
|
||||
<ul>
|
||||
|
||||
<li><I>Analysis.</I> Code that checks for thunks no longer throws an exception if the PC is not set for the processor.</li>
|
||||
<li><I>Analysis.</I> Made a fix to enable Apply button when changing tool options. (Issue #40)</li>
|
||||
<li><I>Data Types.</I> Fixed concurrent modification exception when replacing one datatype for another that results in some other datatype being renamed. </li>
|
||||
<li><I>Decompiler.</I> Fixed dynamic variables and equates in 16-bit x86 programs. (Issue #336)</li>
|
||||
<li><I>Decompiler:Java.</I> Fixed DEX decompilation regression issue. (Issue #350)</li>
|
||||
<li><I>Eclipse Integration.</I> Fixed exception in Eclipse GhidraDev plugin that occurred when performing certain actions on a Ghidra project that was imported from a previously exported Archive File. (Issues #283, #383)</li>
|
||||
<li><I>GUI.</I> Improved documentation on how to deal with HiDPI monitor issues in Linux. In the <I><ghidra_installation></I>/support/launch.properties file, change VMARGS=-Dsun.java2d.xrender from false to true.</li>
|
||||
<li><I>Importer.</I> Fixed an exception that occurred when batch importing APK files. (Issue #426)</li>
|
||||
<li><I>Languages.</I> The 6502 Zero page indexed addressing has been corrected to only access the Zero page. (Issue #201)</li>
|
||||
<li><I>Languages.</I> The 68000 BCD arithmetic instructions now have pcode semantics that allow disassembly to continue. (Issue #227)</li>
|
||||
<li><I>Multi-User:Ghidra Server.</I> Restored ability to execute svrAdmin script in development mode. </li>
|
||||
<li><I>Search.</I> Fixed NullPointerException in Decompiler Data Type Reference Finder. (Issue #407)</li>
|
||||
|
||||
<li><I>Analysis</I>. Code that checks for thunks no longer throws an exception if the PC is not set for the processor.</li>
|
||||
<li><I>Analysis</I>. Made a fix to enable Apply button when changing tool options. (Issue #40)</li>
|
||||
<li><I>Data Types</I>. Fixed concurrent modification exception when replacing one datatype for another that results in some other datatype being renamed. </li>
|
||||
<li><I>Decompiler</I>. Fixed dynamic variables and equates in 16-bit x86 programs. (Issue #336)</li>
|
||||
<li><I>Decompiler:Java</I>. Fixed DEX decompilation regression issue. (Issue #350)</li>
|
||||
<li><I>Eclipse Integration</I>. Fixed exception in Eclipse GhidraDev plugin that occurred when performing certain actions on a Ghidra project that was imported from a previously exported Archive File. (Issues #283, #383)</li>
|
||||
<li><I>GUI</I>. Improved documentation on how to deal with HiDPI monitor issues in Linux. In the <I><ghidra_installation></I>/support/launch.properties file, change VMARGS=-Dsun.java2d.xrender from false to true.</li>
|
||||
<li><I>Importer</I>. Fixed an exception that occurred when batch importing APK files. (Issue #426)</li>
|
||||
<li><I>Multi-User:Ghidra Server</I>. Restored ability to execute svrAdmin script in development mode. </li>
|
||||
<li><I>Processors</I>. The 6502 Zero page indexed addressing has been corrected to only access the Zero page. (Issue #201)</li>
|
||||
<li><I>Processors</I>. The 68000 BCD arithmetic instructions now have pcode semantics that allow disassembly to continue. (Issue #227)</li>
|
||||
<li><I>Search</I>. Fixed NullPointerException in Decompiler Data Type Reference Finder. (Issue #407)</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<H1 align="center">Ghidra 9.0.2 Change History (April 2019)</H1>
|
||||
|
||||
<blockquote><p><u>Bugs</u></p></blockquote>
|
||||
<blockquote>
|
||||
<blockquote><p><u>Bugs</u></p>
|
||||
<ul>
|
||||
|
||||
<li><I>Analysis.</I> Constant reference analysis boundary controls for speculative references has been fixed. Speculative references are references created from computed constants passed as parameters, stored to a location, or from indexed offsets from a register. (Issue #228)</li>
|
||||
|
||||
<li><I>Decompiler. </I> Fixed rendering bug in the Decompiler when the "Find" dialog is closed. (Issue #282) </li>
|
||||
<li><I>Decompiler. </I> Fixed decompiler handling of Function Definition data types. (Issue #247) </li>
|
||||
|
||||
<li><I>Decompiler. </I> Fixed "Free Varnode" exception in RuleConditionalMove. (Issue #294) </li>
|
||||
|
||||
<li><I>Diff. </I> Fixed exceptions that can occur in the Diff View for programs with overlays. </li>
|
||||
|
||||
<li><I>Documentation. </I> Corrected the spelling of "listener" throughout the source code. (Issue #235) </li>
|
||||
<li><I>Exporter. </I> Exporting a selection as Intel Hex will now allow a selection of any length. Previously this was restricted to multiples of 16 bytes. (Issue #260) </li>
|
||||
<li><I>GUI. </I> Fixed exception that occurs after disabling MyProgramChangesDisplayPlugin. </li>
|
||||
|
||||
<li><I>GUI.</I> Updated the "Open Program" dialog to disallow file drop operations. (Issue #252)
|
||||
|
||||
<li><I>Languages. </I> The ARM Thumb CMP.W and LSL isntructions have been changed to correctly decode. There are still issues to work out with Unpredictable execution when Rd is the PC. (Issue #280) </li>
|
||||
<li><I>Multi-User:Ghidra Server. </I> Corrected bug introduced into ghidraSvr.bat which could prevent Ghidra Server startup (Issue #279) </li>
|
||||
|
||||
<li><I>Scripting.</I> MultiInstructionMemReference script has been corrected to consider input and output registers when placing a reference on an instruction.</li>
|
||||
|
||||
<li><I>Analysis</I>. Constant reference analysis boundary controls for speculative references has been fixed. Speculative references are references created from computed constants passed as parameters, stored to a location, or from indexed offsets from a register. (Issue #228)</li>
|
||||
<li><I>Decompiler</I>. Fixed rendering bug in the Decompiler when the "Find" dialog is closed. (Issue #282) </li>
|
||||
<li><I>Decompiler</I>. Fixed decompiler handling of Function Definition data types. (Issue #247) </li>
|
||||
<li><I>Decompiler</I>. Fixed "Free Varnode" exception in RuleConditionalMove. (Issue #294) </li>
|
||||
<li><I>Diff</I>. Fixed exceptions that can occur in the Diff View for programs with overlays. </li>
|
||||
<li><I>Documentation</I>. Corrected the spelling of "listener" throughout the source code. (Issue #235) </li>
|
||||
<li><I>Exporter</I>. Exporting a selection as Intel Hex will now allow a selection of any length. Previously this was restricted to multiples of 16 bytes. (Issue #260) </li>
|
||||
<li><I>GUI</I>. Fixed exception that occurs after disabling MyProgramChangesDisplayPlugin. </li>
|
||||
<li><I>GUI</I>. Updated the "Open Program" dialog to disallow file drop operations. (Issue #252)
|
||||
<li><I>Multi-User:Ghidra Server</I>. Corrected bug introduced into ghidraSvr.bat which could prevent Ghidra Server startup (Issue #279) </li>
|
||||
<li><I>Processors</I>. The ARM Thumb CMP.W and LSL instructions have been changed to correctly decode. There are still issues to work out with Unpredictable execution when Rd is the PC. (Issue #280) </li>
|
||||
<li><I>Scripting</I>. MultiInstructionMemReference script has been corrected to consider input and output registers when placing a reference on an instruction.</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<blockquote><p><u>Security</u></p></blockquote>
|
||||
<blockquote>
|
||||
<blockquote><p><u>Security</u></p>
|
||||
<ul>
|
||||
|
||||
<li><I>Basic Infrastructure. </I> Added a property to support/launch.properties to prevent log4j from using jansi.dll on Windows. (Issue #286) </li>
|
||||
|
||||
<li><I>Basic Infrastructure</I>. Added a property to support/launch.properties to prevent log4j from using jansi.dll on Windows. (Issue #286) </li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<H1 align="center">Ghidra 9.0.1 Change History (March 2019)</H1>
|
||||
|
||||
<blockquote><p><u>New Features</u></p></blockquote>
|
||||
<blockquote>
|
||||
<blockquote><p><u>New Features</u></p>
|
||||
<ul>
|
||||
<li><I>Scripting</I>. Created a script to show all equates within the current selection. (Issue #111)</li>
|
||||
<li><I>Scripting</I>. Created a script to show all equates within the current selection. (Issue #111)</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<blockquote><p><u>Improvements</u></p></blockquote>
|
||||
<blockquote>
|
||||
<blockquote><p><u>Improvements</u></p>
|
||||
<ul>
|
||||
<li><I>Basic Infrastructure</I>. Updated commons-compress library to version 1.18. (Issue #171)</li>
|
||||
<li><I>Eclipse Integration</I>. Ghidra now connects to the Eclipse GhidraDev plugin on 127.0.0.1 rather than localhost.</li>
|
||||
<li><I>GUI</I>. Turned on font anti-aliasing by default for Linux. (Issue #212)</li>
|
||||
<li><I>GUI</I>. Fixed Options Dialog slow scrolling speed. (Issue #27)</li>
|
||||
<li><I>Importer:ELF</I>. Corrected bug in ELF loader which can improperly process the GOT, PLT and relocations
|
||||
when multiple symbol tables exist within the ELF binary. (Issue #52)</li>
|
||||
<li><I>Languages</I>. Added ARM/Thumb SRS instruction decodes for undefined modes. (Issue #216)</li>
|
||||
<li><I>Multi-User:Ghidra Server</I>. Corrected the Ghidra Server service wrapper (YAJSW) configuration for
|
||||
Mac OS X to prevent a startup timeout condition which could occur.</li>
|
||||
<li><I>Basic Infrastructure</I>. Updated commons-compress library to version 1.18. (Issue #171)</li>
|
||||
<li><I>Eclipse Integration</I>. Ghidra now connects to the Eclipse GhidraDev plugin on 127.0.0.1 rather than localhost.</li>
|
||||
<li><I>GUI</I>. Turned on font anti-aliasing by default for Linux. (Issue #212)</li>
|
||||
<li><I>GUI</I>. Fixed Options Dialog slow scrolling speed. (Issue #27)</li>
|
||||
<li><I>Importer:ELF</I>. Corrected bug in ELF loader which can improperly process the GOT, PLT and relocations
|
||||
when multiple symbol tables exist within the ELF binary. (Issue #52)</li>
|
||||
<li><I>Multi-User:Ghidra Server</I>. Corrected the Ghidra Server service wrapper (YAJSW) configuration for
|
||||
Mac OS X to prevent a startup timeout condition which could occur.</li>
|
||||
<li><I>Processors</I>. Added ARM/Thumb SRS instruction decodes for undefined modes. (Issue #216)</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<blockquote><p><u>Bugs</u></p></blockquote>
|
||||
<blockquote>
|
||||
<blockquote><p><u>Bugs</u></p>
|
||||
<ul>
|
||||
<li><I>API</I>. Fixed equals method on Varnode class. (Issue #97)</li>
|
||||
<li><I>API</I>. Fixed a bug in MaskImpl.comlementMask(). (Issue #187)</li>
|
||||
<li><I>Basic Infrasturcture</I>. Fixed special character handling in idaxml.py. (Issue #75)</li>
|
||||
<li><I>Basic Infrastructure</I>. Ghidra now forces the locale to en_US by default. Only the en_US is currently supported.
|
||||
This fixes certain unexpected exceptions. (Issue #209)</li>
|
||||
<li><I>Diff</I>. Fixed exceptions occasionally encountered when starting a Diff session. (Issue #211)</li>
|
||||
<li><I>Documentation</I>. Fixed javadoc search box redirecting to broken links. (Issue #129)</li>
|
||||
<li><I>Function Graph</I>. Fixed Function Graph exception when generating tooltip. (Issue #65)</li>
|
||||
<li><I>GUI</I>. Updted window placement to keep windows on screen. (Issue #41)</li>
|
||||
<li><I>GUI</I>. Add/Edit References dialog now restricts users to creating refs in valid memory address spaces.</li>
|
||||
<li><I>GUI</I>. Fixed exception when exiting Ghidra while a table is being edited. (Issue #51)</li>
|
||||
<li><I>GUI</I>. Fixed some touchpad scrolling issues. (Issue #2)</li>
|
||||
<li><I>GUI</I>. Fixed stack trace in the Data Type Manager's tooltip generation. (Issue #133)</li>
|
||||
<li><I>GUI</I>. User key binding settings for the Recently Used and Define Pointer actions no longer lost after re-launching tool. (Issue #152)</li>
|
||||
<li><I>GUI</I>. Toolbar buttons now respond to fast clicking.</li>
|
||||
<li><I>Importer:MachO</I>. The MachoLoader can now find import libraries found in Universal Binary files. (Issue #136)</li>
|
||||
<li><I>Importer:PE</I>. The PeLoader now correctly parses the GuardCFFunctionTable when entries are more than 4 bytes each. (Issue #220)</li>
|
||||
<li><I>Languages</I>. Added missing PowerPC VLE conditional branch instructions: e_bdnz and e_bdz. (Issue #103)</li>
|
||||
<li><I>Languages</I>. Fixed instruction semantics for several instructions and added Control Flow Enforcement, NOP variants, CMP variants, UD1, and
|
||||
prefixed call instructions to X86 processor specification. (Issues #22, #53, #158, #157)</li>
|
||||
<li><I>Languages</I>. The 68000 MOVE instruction now correctly sets the CF and VF flags. (Issue #163)</li>
|
||||
<li><I>Languages</I>. Added four missing MOVEM instruction variants to the 68000 processor. (Issue #219)</li>
|
||||
<li><I>Languages</I>. An incorrect usage of X instead of Y in indexed mode for the 6502 has been corrected.(Issue #201)</li>
|
||||
<li><I>Languages</I>. Added support for ARM Thumb half BL instruction on processor variants prior to v6. (Issue #39)</li>
|
||||
<li><I>Multi-User:Ghidra Server</I>. Removed support for native OS authentication from Ghidra Server (removed modes -a2 and -a3)
|
||||
due to incompatibility with newer OS releases including Windows 10 and Windows Server 2016. Re-introduction of this will be
|
||||
considered for a future release.</li>
|
||||
<li><I>PDB</I>. Corrected NPE error when processing PDB files. (Issues #138, #188)</li>
|
||||
<li><I>Scripting</I>. Fixed a bug in ImportSymbolsScript.py that prevented it from running. (Issue #170)</li>
|
||||
<li><I>API</I>. Fixed equals method on Varnode class. (Issue #97)</li>
|
||||
<li><I>API</I>. Fixed a bug in MaskImpl.comlementMask(). (Issue #187)</li>
|
||||
<li><I>Basic Infrastructure</I>. Fixed special character handling in idaxml.py. (Issue #75)</li>
|
||||
<li><I>Basic Infrastructure</I>. Ghidra now forces the locale to en_US by default. Only the en_US is currently supported.
|
||||
This fixes certain unexpected exceptions. (Issue #209)</li>
|
||||
<li><I>Diff</I>. Fixed exceptions occasionally encountered when starting a Diff session. (Issue #211)</li>
|
||||
<li><I>Documentation</I>. Fixed javadoc search box redirecting to broken links. (Issue #129)</li>
|
||||
<li><I>Function Graph</I>. Fixed Function Graph exception when generating tooltip. (Issue #65)</li>
|
||||
<li><I>GUI</I>. Updated window placement to keep windows on screen. (Issue #41)</li>
|
||||
<li><I>GUI</I>. Add/Edit References dialog now restricts users to creating refs in valid memory address spaces.</li>
|
||||
<li><I>GUI</I>. Fixed exception when exiting Ghidra while a table is being edited. (Issue #51)</li>
|
||||
<li><I>GUI</I>. Fixed some touchpad scrolling issues. (Issue #2)</li>
|
||||
<li><I>GUI</I>. Fixed stack trace in the Data Type Manager's tooltip generation. (Issue #133)</li>
|
||||
<li><I>GUI</I>. User key binding settings for the Recently Used and Define Pointer actions no longer lost after re-launching tool. (Issue #152)</li>
|
||||
<li><I>GUI</I>. Toolbar buttons now respond to fast clicking.</li>
|
||||
<li><I>Importer:MachO</I>. The MachoLoader can now find import libraries found in Universal Binary files. (Issue #136)</li>
|
||||
<li><I>Importer:PE</I>. The PeLoader now correctly parses the GuardCFFunctionTable when entries are more than 4 bytes each. (Issue #220)</li>
|
||||
<li><I>Multi-User:Ghidra Server</I>. Removed support for native OS authentication from Ghidra Server (removed modes -a2 and -a3)
|
||||
due to incompatibility with newer OS releases including Windows 10 and Windows Server 2016. Re-introduction of this will be
|
||||
considered for a future release.</li>
|
||||
<li><I>PDB</I>. Corrected NPE error when processing PDB files. (Issues #138, #188)</li>
|
||||
<li><I>Processors</I>. Added missing PowerPC VLE conditional branch instructions: e_bdnz and e_bdz. (Issue #103)</li>
|
||||
<li><I>Processors</I>. Fixed instruction semantics for several instructions and added Control Flow Enforcement, NOP variants, CMP variants, UD1, and
|
||||
prefixed call instructions to X86 processor specification. (Issues #22, #53, #158, #157)</li>
|
||||
<li><I>Processors</I>. The 68000 MOVE instruction now correctly sets the CF and VF flags. (Issue #163)</li>
|
||||
<li><I>Processors</I>. Added four missing MOVEM instruction variants to the 68000 processor. (Issue #219)</li>
|
||||
<li><I>Processors</I>. An incorrect usage of X instead of Y in indexed mode for the 6502 has been corrected.(Issue #201)</li>
|
||||
<li><I>Processors</I>. Added support for ARM Thumb half BL instruction on processor variants prior to v6. (Issue #39)</li>
|
||||
<li><I>Scripting</I>. Fixed a bug in ImportSymbolsScript.py that prevented it from running. (Issue #170)</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
<blockquote><p><u>Security</u></p></blockquote>
|
||||
<blockquote>
|
||||
<blockquote><p><u>Security</u></p>
|
||||
<ul>
|
||||
<li><I>Basic Infrastructure</I>. Running Ghidra in debug mode no longer opens remotely accessible ports by default. (Issue #6)</li>
|
||||
<li><I>GUI</I>. The Defined Strings plugin no longer renders HTML in its table. (Issue #45)</li>
|
||||
<li><I>Project Manager</I>. Fixed an XXE vulnerability affeting projects and many other saved components. (Issue #71)</li>
|
||||
</li>
|
||||
<li><I>Basic Infrastructure</I>. Running Ghidra in debug mode no longer opens remotely accessible ports by default. (Issue #6)</li>
|
||||
<li><I>GUI</I>. The Defined Strings plugin no longer renders HTML in its table. (Issue #45)</li>
|
||||
<li><I>Project Manager</I>. Fixed an XXE vulnerability affecting projects and many other saved components. (Issue #71)</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
|
||||
|
|
|
@ -443,6 +443,8 @@ src/main/help/help/topics/GhidraServer/GhidraServer.htm||GHIDRA||||END|
|
|||
src/main/help/help/topics/Glossary/glossary.htm||GHIDRA||||END|
|
||||
src/main/help/help/topics/Glossary/images/BigEndian.png||GHIDRA||reviewed||END|
|
||||
src/main/help/help/topics/Glossary/images/LittleEndian.png||GHIDRA||reviewed||END|
|
||||
src/main/help/help/topics/Graph/GraphIntro.html||GHIDRA||||END|
|
||||
src/main/help/help/topics/Graph/GraphServicesIntro.html||GHIDRA||||END|
|
||||
src/main/help/help/topics/HeadlessAnalyzer/HeadlessAnalyzer.htm||GHIDRA||||END|
|
||||
src/main/help/help/topics/ImporterPlugin/images/About_pdb.png||GHIDRA||reviewed||END|
|
||||
src/main/help/help/topics/ImporterPlugin/images/BatchImportDialog.png||GHIDRA||||END|
|
||||
|
|
|
@ -150,7 +150,9 @@
|
|||
|
||||
<tocdef id="FileSystem Browser" text="FileSystem Browser" target="help/topics/FileSystemBrowserPlugin/FileSystemBrowserPlugin.html" />
|
||||
|
||||
<tocdef id="Graphing" text="Graphing" />
|
||||
<tocdef id="Graphing" text="Graphing" target="help/topics/Graph/GraphIntro.html">
|
||||
<tocdef id="Graph Services" text="Graph Services" target="help/topics/Graph/GraphServicesIntro.html"/>
|
||||
</tocdef>
|
||||
|
||||
<tocdef id="Program Tree" text="Program Tree" target="help/topics/ProgramTreePlugin/program_tree.htm" >
|
||||
<tocdef id="Folders and Fragments" sortgroup="a" text="Folders and Fragments" target="help/topics/ProgramTreePlugin/program_tree.htm#FoldersAndFragments" />
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<!DOCTYPE doctype PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN">
|
||||
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Graphing</TITLE>
|
||||
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
|
||||
</HEAD>
|
||||
|
||||
<BODY lang="EN-US">
|
||||
|
||||
|
||||
<H1>Graphing</H1>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>
|
||||
This section contains all help related to the creation and display of Graphs. Content will
|
||||
appear inside of this section as plugins are added. To see the available graph features,
|
||||
see the <B>Graph</b> menu on the toolbar.
|
||||
</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
|
@ -0,0 +1,25 @@
|
|||
<!DOCTYPE doctype PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN">
|
||||
|
||||
<HTML>
|
||||
<HEAD>
|
||||
<TITLE>Graph Services</TITLE>
|
||||
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
|
||||
</HEAD>
|
||||
|
||||
<BODY lang="EN-US">
|
||||
|
||||
|
||||
<H1>Graph Services</H1>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>
|
||||
This section contains all help related to the graph services that provide capabilities for
|
||||
generated graphs, such as displaying and exporting. Content will appear inside of this '
|
||||
section as plugins are added. To see the available graph features,
|
||||
see the <B>Graph</b> menu on the toolbar.
|
||||
</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
|
@ -120,6 +120,10 @@ public abstract class AddressBasedGraphDisplayListener
|
|||
return null;
|
||||
}
|
||||
String id = getVertexId(address);
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return graphDisplay.getGraph().getVertex(id);
|
||||
}
|
||||
|
||||
|
@ -202,6 +206,9 @@ public abstract class AddressBasedGraphDisplayListener
|
|||
|
||||
private void handleSymbolAddedOrRenamed(Address address, Symbol symbol) {
|
||||
AttributedVertex vertex = getVertex(address);
|
||||
if (vertex == null) {
|
||||
return;
|
||||
}
|
||||
graphDisplay.updateVertexName(vertex, symbol.getName());
|
||||
}
|
||||
|
||||
|
|
|
@ -147,6 +147,7 @@ public class FdeTable {
|
|||
|
||||
// this is an indirect reference to code from the table,
|
||||
// so tag reference as an indirect code flow
|
||||
// TODO: This should be a CODE flow, leaving as INDIRECTION until refactor
|
||||
prog.getReferenceManager().addMemoryReference(locComponentAddr, locAddr,
|
||||
RefType.INDIRECTION,
|
||||
SourceType.ANALYSIS, 0);
|
||||
|
|
|
@ -71,6 +71,7 @@ public final class ObjectiveC1_TypeEncodings {
|
|||
public final static char _C_BYCOPY = 'O';
|
||||
public final static char _C_BYREF = 'R';
|
||||
public final static char _C_ONEWAY = 'V';
|
||||
public final static char _C_ATOMIC = 'A';
|
||||
|
||||
private final static String ANONYMOUS_PREFIX = "Anonymous";
|
||||
|
||||
|
@ -410,8 +411,13 @@ public final class ObjectiveC1_TypeEncodings {
|
|||
DataType dt = parseDataType(buffer);
|
||||
return new TypedefDataType("ONEWAY " + dt.getDisplayName(), dt);
|
||||
}
|
||||
case _C_ATOMIC: {
|
||||
buffer.deleteCharAt(0);
|
||||
DataType dt = parseDataType(buffer);
|
||||
return new TypedefDataType("ATOMIC " + dt.getDisplayName(), dt);
|
||||
}
|
||||
}
|
||||
throw new UnsupportedOperationException("unrecognized format type: " + buffer.charAt(0));
|
||||
throw new UnsupportedOperationException("Unsupported Objective C type encoding: " + buffer.charAt(0));
|
||||
}
|
||||
|
||||
private Union parseBitFields(StringBuffer buffer) {
|
||||
|
|
|
@ -202,8 +202,7 @@ public class PcodeFormatter {
|
|||
formatVarnodeTpl(program, opcode, -1, output, lineList);
|
||||
lineList.add(EQUALS);
|
||||
}
|
||||
Color color =
|
||||
(opcode == PcodeOp.UNIMPLEMENTED) ? Color.RED : Color.BLUE.darker();
|
||||
Color color = (opcode == PcodeOp.UNIMPLEMENTED) ? Color.RED : Color.BLUE.darker();
|
||||
lineList.add(new AttributedString(PcodeOp.getMnemonic(opcode), color, metrics));
|
||||
VarnodeTpl[] inputs = op.getInput();
|
||||
for (int i = 0; i < inputs.length; i++) {
|
||||
|
@ -262,7 +261,7 @@ public class PcodeFormatter {
|
|||
formatConstant(offset, size, lineList);
|
||||
}
|
||||
else if (space.isUniqueSpace()) {
|
||||
formatUnique(offset, size, opIndex < 0, lineList);
|
||||
formatUnique(offset, size, lineList);
|
||||
}
|
||||
else {
|
||||
formatAddress(program, space.getSpaceId(), offset, size, lineList);
|
||||
|
@ -284,25 +283,21 @@ public class PcodeFormatter {
|
|||
private void formatRaw(AddressSpace space, ConstTpl offset, ConstTpl size,
|
||||
List<AttributedString> lineList) {
|
||||
// same format as the Varnode.toString
|
||||
String str =
|
||||
"(" + space.getName() + ", 0x" + Long.toHexString(offset.getReal()) + ", " +
|
||||
size.getReal() + ")";
|
||||
String str = "(" + space.getName() + ", 0x" + Long.toHexString(offset.getReal()) + ", " +
|
||||
size.getReal() + ")";
|
||||
lineList.add(new AttributedString(str, Color.BLUE, metrics));
|
||||
}
|
||||
|
||||
private void formatUnique(ConstTpl offset, ConstTpl size, boolean isOutput,
|
||||
List<AttributedString> lineList) {
|
||||
private void formatUnique(ConstTpl offset, ConstTpl size, List<AttributedString> lineList) {
|
||||
if (offset.getType() != ConstTpl.REAL) {
|
||||
throw new RuntimeException("Unsupported unique offset type: " + offset.getType());
|
||||
}
|
||||
if (size.getType() != ConstTpl.REAL) {
|
||||
throw new RuntimeException("Unsupported unique size type: " + size.getType());
|
||||
}
|
||||
lineList.add(new AttributedString("$U" + Long.toHexString(offset.getReal()), localColor,
|
||||
metrics));
|
||||
if (isOutput) {
|
||||
formatSize(size, lineList);
|
||||
}
|
||||
lineList.add(
|
||||
new AttributedString("$U" + Long.toHexString(offset.getReal()), localColor, metrics));
|
||||
formatSize(size, lineList);
|
||||
}
|
||||
|
||||
private void formatAddress(Program program, AddressSpace addrSpace, ConstTpl offset,
|
||||
|
@ -314,8 +309,8 @@ public class PcodeFormatter {
|
|||
long offsetValue = offset.getReal();
|
||||
if (addrSpace == null) {
|
||||
lineList.add(STAR);
|
||||
lineList.add(new AttributedString("0x" + Long.toHexString(offsetValue), addressColor,
|
||||
metrics));
|
||||
lineList.add(
|
||||
new AttributedString("0x" + Long.toHexString(offsetValue), addressColor, metrics));
|
||||
if (size.getType() != ConstTpl.J_CURSPACE_SIZE) {
|
||||
formatSize(size, lineList);
|
||||
}
|
||||
|
@ -328,7 +323,8 @@ public class PcodeFormatter {
|
|||
lineList.add(new AttributedString(reg.getName(), registerColor, metrics));
|
||||
if (reg.getMinimumByteSize() > sizeValue) {
|
||||
lineList.add(COLON);
|
||||
lineList.add(new AttributedString(Integer.toString(sizeValue), this.scalarColor, metrics));
|
||||
lineList.add(
|
||||
new AttributedString(Integer.toString(sizeValue), this.scalarColor, metrics));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -336,7 +332,7 @@ public class PcodeFormatter {
|
|||
lineList.add(LEFT_BRACKET);
|
||||
lineList.add(new AttributedString(addrSpace.getName(), Color.BLUE, metrics));
|
||||
lineList.add(RIGHT_BRACKET);
|
||||
|
||||
|
||||
long wordOffset = offsetValue / addrSpace.getAddressableUnitSize();
|
||||
long offcut = offsetValue % addrSpace.getAddressableUnitSize();
|
||||
String str = "0x" + Long.toHexString(wordOffset);
|
||||
|
@ -396,7 +392,8 @@ public class PcodeFormatter {
|
|||
}
|
||||
|
||||
private boolean formatLabelInput(VarnodeTpl input0, List<AttributedString> lineList) {
|
||||
if (input0.getSpace().isConstSpace() && input0.getOffset().getType() == ConstTpl.J_RELATIVE) {
|
||||
if (input0.getSpace().isConstSpace() &&
|
||||
input0.getOffset().getType() == ConstTpl.J_RELATIVE) {
|
||||
String label = "<" + input0.getOffset().getReal() + ">";
|
||||
lineList.add(new AttributedString(label, Color.BLUE, metrics));
|
||||
return true;
|
||||
|
|
|
@ -15,14 +15,14 @@
|
|||
*/
|
||||
package ghidra.test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ToyProgramBuilder extends ProgramBuilder {
|
||||
|
||||
private static final String TOY_LANGUAGE_ID_BE = "Toy:BE:32:builder";
|
||||
|
@ -106,7 +106,7 @@ public class ToyProgramBuilder extends ProgramBuilder {
|
|||
/**
|
||||
* Get address in default ram space
|
||||
* @param offset address offset
|
||||
* @return address
|
||||
* @return the address
|
||||
*/
|
||||
public Address getAddress(long offset) {
|
||||
return defaultSpace.getAddress(offset);
|
||||
|
|
|
@ -170,17 +170,23 @@ public class UndefinedFunction implements Function {
|
|||
while (iterator.hasNext() && !monitor.isCancelled()) {
|
||||
CodeBlockReference blockReference = iterator.next();
|
||||
FlowType flowType = blockReference.getFlowType();
|
||||
if (flowType.isCall())
|
||||
continue; // Don't follow call edges for within-function analysis
|
||||
count += 1; // Count the existence of source that is NOT a call
|
||||
if (flowType.isCall()) {
|
||||
continue; // Don't follow call edges for within-function analysis
|
||||
}
|
||||
if (flowType.isIndirect()) {
|
||||
continue; // Don't follow improper use of Indirect reference
|
||||
}
|
||||
count += 1; // Count the existence of source that is NOT a call
|
||||
Address sourceAddr = blockReference.getSourceAddress();
|
||||
if (visitedAddresses.contains(sourceAddr))
|
||||
continue; // Already visited this block
|
||||
if (visitedAddresses.contains(sourceAddr)) {
|
||||
continue; // Already visited this block
|
||||
}
|
||||
visitedAddresses.addRange(sourceAddr, sourceAddr);
|
||||
worklist.add(blockReference.getSourceBlock());
|
||||
}
|
||||
if (count == 0) // We found a block with no incoming edges, a likely function start
|
||||
if (count == 0) {
|
||||
return curblock;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -469,8 +475,9 @@ public class UndefinedFunction implements Function {
|
|||
|
||||
@Override
|
||||
public void setReturnType(DataType type, SourceType source) {
|
||||
if (type == DataType.DEFAULT)
|
||||
if (type == DataType.DEFAULT) {
|
||||
return;
|
||||
}
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
|
|
@ -94,6 +94,7 @@ class Funcdata {
|
|||
void splitUses(Varnode *vn); ///< Make all reads of the given Varnode unique
|
||||
Varnode *cloneVarnode(const Varnode *vn); ///< Clone a Varnode (between copies of the function)
|
||||
void destroyVarnode(Varnode *vn); ///< Delete the given Varnode from \b this function
|
||||
void coverVarnodes(SymbolEntry *entry,vector<Varnode *> &list);
|
||||
// Low level op functions
|
||||
void opZeroMulti(PcodeOp *op); ///< Transform trivial CPUI_MULTIEQUAL to CPUI_COPY
|
||||
// Low level block functions
|
||||
|
|
|
@ -1376,6 +1376,35 @@ Address Funcdata::findDisjointCover(Varnode *vn,int4 &sz)
|
|||
return addr;
|
||||
}
|
||||
|
||||
/// \brief Make sure every Varnode in the given list has a Symbol it will link to
|
||||
///
|
||||
/// This is used when Varnodes overlap a locked Symbol but extend beyond it.
|
||||
/// An existing Symbol is passed in with a list of possibly overextending Varnodes.
|
||||
/// The list is in Address order. We check that each Varnode has a Symbol that
|
||||
/// overlaps its first byte (to guarantee a link). If one doesn't exist it is created.
|
||||
/// \param entry is the existing Symbol entry
|
||||
/// \param list is the list of Varnodes
|
||||
void Funcdata::coverVarnodes(SymbolEntry *entry,vector<Varnode *> &list)
|
||||
|
||||
{
|
||||
Scope *scope = entry->getSymbol()->getScope();
|
||||
for(int4 i=0;i<list.size();++i) {
|
||||
Varnode *vn = list[i];
|
||||
// We only need to check once for all Varnodes at the same Address
|
||||
// Of these, pick the biggest Varnode
|
||||
if (i+1<list.size() && list[i+1]->getAddr() == vn->getAddr())
|
||||
continue;
|
||||
Address usepoint = vn->getUsePoint(*this);
|
||||
SymbolEntry *overlapEntry = scope->findContainer(vn->getAddr(), vn->getSize(), usepoint);
|
||||
if (overlapEntry == (SymbolEntry *)0) {
|
||||
int4 diff = (int4)(vn->getOffset() - entry->getAddr().getOffset());
|
||||
ostringstream s;
|
||||
s << entry->getSymbol()->getName() << '_' << diff;
|
||||
scope->addSymbol(s.str(),vn->getHigh()->getType(),vn->getAddr(),usepoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Search for \e addrtied Varnodes whose storage falls in the global Scope, then
|
||||
/// build a new global Symbol if one didn't exist before.
|
||||
void Funcdata::mapGlobals(void)
|
||||
|
@ -1386,6 +1415,7 @@ void Funcdata::mapGlobals(void)
|
|||
Varnode *vn,*maxvn;
|
||||
Datatype *ct;
|
||||
uint4 flags;
|
||||
vector<Varnode *> uncoveredVarnodes;
|
||||
bool inconsistentuse = false;
|
||||
|
||||
iter = vbank.beginLoc(); // Go through all varnodes for this space
|
||||
|
@ -1398,10 +1428,16 @@ void Funcdata::mapGlobals(void)
|
|||
maxvn = vn;
|
||||
Address addr = vn->getAddr();
|
||||
Address endaddr = addr + vn->getSize();
|
||||
uncoveredVarnodes.clear();
|
||||
while(iter != enditer) {
|
||||
vn = *iter;
|
||||
if (!vn->isPersist()) break;
|
||||
if (vn->getAddr() < endaddr) {
|
||||
// Varnodes at the same base address will get linked to the Symbol at that address
|
||||
// even if the size doesn't match, but we check for internal Varnodes that
|
||||
// do not have an attached Symbol as these won't get linked to anything
|
||||
if (vn->getAddr() != addr && vn->getSymbolEntry() == (SymbolEntry *)0)
|
||||
uncoveredVarnodes.push_back(vn);
|
||||
endaddr = vn->getAddr() + vn->getSize();
|
||||
if (vn->getSize() > maxvn->getSize())
|
||||
maxvn = vn;
|
||||
|
@ -1429,8 +1465,11 @@ void Funcdata::mapGlobals(void)
|
|||
Varnode::addrtied|Varnode::persist);
|
||||
discover->addSymbol(symbolname,ct,addr,usepoint);
|
||||
}
|
||||
else if ((addr.getOffset()+ct->getSize())-1 > (entry->getAddr().getOffset()+entry->getSize()) -1)
|
||||
else if ((addr.getOffset()+ct->getSize())-1 > (entry->getAddr().getOffset()+entry->getSize()) -1) {
|
||||
inconsistentuse = true;
|
||||
if (!uncoveredVarnodes.empty()) // Provide Symbols for any uncovered internal Varnodes
|
||||
coverVarnodes(entry, uncoveredVarnodes);
|
||||
}
|
||||
}
|
||||
if (inconsistentuse)
|
||||
warningHeader("Globals starting with '_' overlap smaller symbols at the same address");
|
||||
|
|
|
@ -1987,7 +1987,7 @@ bool SleighCompile::undefinePreprocValue(const string &nm)
|
|||
|
||||
// Functions needed by the parser
|
||||
|
||||
TokenSymbol *SleighCompile::defineToken(string *name,uintb *sz)
|
||||
TokenSymbol *SleighCompile::defineToken(string *name,uintb *sz,int4 endian)
|
||||
|
||||
{
|
||||
uint4 size = *sz;
|
||||
|
@ -1998,7 +1998,12 @@ TokenSymbol *SleighCompile::defineToken(string *name,uintb *sz)
|
|||
}
|
||||
else
|
||||
size = size/8;
|
||||
Token *newtoken = new Token(*name,size,isBigEndian(),tokentable.size());
|
||||
bool isBig;
|
||||
if (endian ==0)
|
||||
isBig = isBigEndian();
|
||||
else
|
||||
isBig = (endian > 0);
|
||||
Token *newtoken = new Token(*name,size,isBig,tokentable.size());
|
||||
tokentable.push_back(newtoken);
|
||||
delete name;
|
||||
TokenSymbol *res = new TokenSymbol(newtoken);
|
||||
|
|
|
@ -261,7 +261,7 @@ public:
|
|||
bool undefinePreprocValue(const string &nm);
|
||||
|
||||
// Parser functions
|
||||
TokenSymbol *defineToken(string *name,uintb *sz);
|
||||
TokenSymbol *defineToken(string *name,uintb *sz,int4 endian);
|
||||
void addTokenField(TokenSymbol *sym,FieldQuality *qual);
|
||||
bool addContextField(VarnodeSymbol *sym,FieldQuality *qual);
|
||||
void newSpace(SpaceQuality *qual);
|
||||
|
|
|
@ -181,7 +181,9 @@ aligndef: DEFINE_KEY ALIGN_KEY '=' INTEGER ';' { slgh->setAlignment(*$4); delete
|
|||
;
|
||||
tokendef: tokenprop ';' {}
|
||||
;
|
||||
tokenprop: DEFINE_KEY TOKEN_KEY STRING '(' INTEGER ')' { $$ = slgh->defineToken($3,$5); }
|
||||
tokenprop: DEFINE_KEY TOKEN_KEY STRING '(' INTEGER ')' { $$ = slgh->defineToken($3,$5,0); }
|
||||
| DEFINE_KEY TOKEN_KEY STRING '(' INTEGER ')' ENDIAN_KEY '=' LITTLE_KEY { $$ = slgh->defineToken($3,$5,-1); }
|
||||
| DEFINE_KEY TOKEN_KEY STRING '(' INTEGER ')' ENDIAN_KEY '=' BIG_KEY { $$ = slgh->defineToken($3,$5,1); }
|
||||
| tokenprop fielddef { $$ = $1; slgh->addTokenField($1,$2); }
|
||||
| DEFINE_KEY TOKEN_KEY anysymbol { string errmsg=$3->getName()+": redefined as a token"; yyerror(errmsg.c_str()); YYERROR; }
|
||||
;
|
||||
|
|
|
@ -494,7 +494,7 @@ int4 scan_number(char *numtext,YYSTYPE *lval,bool signednum)
|
|||
[(),\-] { yylval.ch = yytext[0]; return yytext[0]; }
|
||||
\: { BEGIN(print); slgh->calcContextLayout(); yylval.ch = yytext[0]; return yytext[0]; }
|
||||
\{ { BEGIN(sem); yylval.ch = yytext[0]; return yytext[0]; }
|
||||
#.*$
|
||||
#.*
|
||||
[\r\ \t\v]+
|
||||
\n { slgh->nextLine(); }
|
||||
macro { BEGIN(macroblock); return MACRO_KEY; }
|
||||
|
@ -540,7 +540,7 @@ with { BEGIN(pattern); withsection = 1; slgh->calcContextLayout(); return WITH
|
|||
<defblock>values { return VALUES_KEY; }
|
||||
<defblock>variables { return VARIABLES_KEY; }
|
||||
<defblock>pcodeop { return PCODEOP_KEY; }
|
||||
<defblock>#.*$
|
||||
<defblock>#.*
|
||||
<defblock>[a-zA-Z_.][a-zA-Z0-9_.]* { return find_symbol(); }
|
||||
<defblock>[0-9]|[1-9][0-9]+ { return scan_number(yytext,&yylval,false); }
|
||||
<defblock>0x[0-9a-fA-F]+ { return scan_number(yytext,&yylval,false); }
|
||||
|
@ -582,7 +582,7 @@ with { BEGIN(pattern); withsection = 1; slgh->calcContextLayout(); return WITH
|
|||
<pattern>\| { yylval.ch = yytext[0]; return (actionon==0) ? yytext[0] : OP_OR; }
|
||||
<pattern>\^ { return OP_XOR; }
|
||||
<pattern>[=(),:;+\-*/~<>] { yylval.ch = yytext[0]; return yytext[0]; }
|
||||
<pattern>#.*$
|
||||
<pattern>#.*
|
||||
<pattern>[a-zA-Z_.][a-zA-Z0-9_.]* { return find_symbol(); }
|
||||
<pattern>[0-9]|[1-9][0-9]+ { return scan_number(yytext,&yylval,true); }
|
||||
<pattern>0x[0-9a-fA-F]+ { return scan_number(yytext,&yylval,true); }
|
||||
|
@ -648,7 +648,7 @@ with { BEGIN(pattern); withsection = 1; slgh->calcContextLayout(); return WITH
|
|||
<sem>build { return BUILD_KEY; }
|
||||
<sem>local { return LOCAL_KEY; }
|
||||
<sem>[=(),:\[\];!&|^+\-*/%~<>] { yylval.ch = yytext[0]; return yytext[0]; }
|
||||
<sem>#.*$
|
||||
<sem>#.*
|
||||
<sem>[a-zA-Z_.][a-zA-Z0-9_.]* { return find_symbol(); }
|
||||
<sem>[0-9]|[1-9][0-9]+ { return scan_number(yytext,&yylval,false); }
|
||||
<sem>0x[0-9a-fA-F]+ { return scan_number(yytext,&yylval,false); }
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<title>SLEIGH</title>
|
||||
<subtitle>A Language for Rapid Processor Specification</subtitle>
|
||||
<pubdate>Originally published December 16, 2005</pubdate>
|
||||
<releaseinfo>Last updated September 5, 2019</releaseinfo>
|
||||
<releaseinfo>Last updated October 28, 2020</releaseinfo>
|
||||
</info>
|
||||
<simplesect>
|
||||
<info>
|
||||
|
@ -573,13 +573,14 @@ define endian=little;
|
|||
</programlisting>
|
||||
</informalexample>
|
||||
This defines how the processor interprets contiguous sequences of
|
||||
bytes as integers. It effects how integer fields within an instruction
|
||||
are interpreted (see <xref linkend="sleigh_defining_tokens"/>), and
|
||||
it also effects the details of how the processor is supposed to
|
||||
implement atomic operations like integer addition and integer
|
||||
compare. The specification designer should only need to worry about
|
||||
these details when labeling instruction fields, otherwise the
|
||||
specification language will hide endianess issues.
|
||||
bytes as integers or other values and globally affects values across
|
||||
all address spaces. It also affects how integer fields
|
||||
within an instruction are interpreted, (see <xref linkend="sleigh_defining_tokens"/>),
|
||||
although it is possible to override this setting in the rare case that endianess is
|
||||
different for data versus instruction encoding.
|
||||
The specification designer generally only needs to worry about
|
||||
endianess when labeling instruction fields and when defining overlapping registers,
|
||||
otherwise the specification language hides endianess issues.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2>
|
||||
|
@ -966,7 +967,7 @@ individual <emphasis>constructor</emphasis> (defined in <xref linkend="sleigh_co
|
|||
defines a local scope for operand names. As with most languages, a
|
||||
local symbol with the same name as a global
|
||||
symbol <emphasis>hides</emphasis> the global symbol while that scope
|
||||
is in affect.
|
||||
is in effect.
|
||||
</para>
|
||||
</sect2>
|
||||
<sect2 id="sleigh_predefined_symbols">
|
||||
|
@ -1057,8 +1058,22 @@ there are one or more field declarations specifying the name of the
|
|||
field and the range of bits within the token making up the field. The
|
||||
size of a field does <emphasis>not</emphasis> need to be a multiple of
|
||||
8. The range is inclusive where the least significant bit in the token
|
||||
is labeled 0. The endianess of the processor will effect this labeling
|
||||
when defining tokens that are bigger than 1 byte. After each field
|
||||
is labeled 0. When defining tokens that are bigger than 1 byte, the
|
||||
global endianess setting (See <xref linkend="sleigh_endianess_definition"/>)
|
||||
will affect this labeling. Although it is rarely required, it is possible to override
|
||||
the global endianess setting for a specific token by appending either the qualifier
|
||||
<emphasis role="bold">endian=little</emphasis> or <emphasis role="bold">endian=big</emphasis>
|
||||
immediately after the token name and size. For instance:
|
||||
<informalexample>
|
||||
<programlisting>
|
||||
define token instr ( 32 ) endian=little op0=(0,15) <emphasis role="weak">...</emphasis>
|
||||
</programlisting>
|
||||
</informalexample>
|
||||
The token <emphasis>instr</emphasis> is overridden to be little endian.
|
||||
This override applies to all fields defined for the token but affects no other tokens.
|
||||
</para>
|
||||
<para>
|
||||
After each field
|
||||
declaration, there can be zero or more of the following attribute
|
||||
keywords:
|
||||
<informalexample>
|
||||
|
@ -2023,7 +2038,7 @@ assignment to such a variable changes the context in which the current
|
|||
instruction is being disassembled and can potentially have a drastic
|
||||
effect on how the rest of the instruction is disassembled. An
|
||||
assignment of this form is considered local to the instruction and
|
||||
will not effect how other instructions are parsed. The context
|
||||
will not affect how other instructions are parsed. The context
|
||||
variable is reset to its original value before parsing other
|
||||
instructions. The disassembly action may also contain one or
|
||||
more <emphasis role="bold">globalset</emphasis> directives, which
|
||||
|
@ -2547,7 +2562,7 @@ the table symbol <emphasis>mode</emphasis>. When this constructor is
|
|||
matched, as part of a more complicated instruction, the
|
||||
symbol <emphasis>mode</emphasis> will represent the original semantic
|
||||
value of <emphasis>reg</emphasis> but with the standard post-increment
|
||||
side effect.
|
||||
side-effect.
|
||||
</para>
|
||||
<para>
|
||||
The table symbol associated with the constructor becomes
|
||||
|
@ -3724,7 +3739,7 @@ blr is opcode=35 & reg=15 & LRset=1 { return [lr]; }
|
|||
An alternative to the <emphasis role="bold">noflow</emphasis> attribute is to simply issue
|
||||
multiple directives within a single constructor, so an explicit end to a context change
|
||||
can be given. The value of the variable exported to the global state
|
||||
is the one in affect at the point where the directive is issued. Thus,
|
||||
is the one in effect at the point where the directive is issued. Thus,
|
||||
after one <emphasis role="bold">globalset</emphasis>, the same context
|
||||
variable can be assigned a different value, followed by
|
||||
another <emphasis role="bold">globalset</emphasis> for a different
|
||||
|
@ -3735,7 +3750,7 @@ Because context in SLEIGH is controlled by a disassembly process,
|
|||
there are some basic caveats to the use of
|
||||
the <emphasis role="bold">globalset</emphasis> directive. With
|
||||
<emphasis>flowing</emphasis> context changes,
|
||||
there is no guarantee of what global state will be in affect at a
|
||||
there is no guarantee of what global state will be in effect at a
|
||||
particular address. During disassembly, at any given
|
||||
point, the process may not have uncovered all the relevant directives,
|
||||
and the known directives may not necessarily be consistent. In
|
||||
|
|
|
@ -526,6 +526,9 @@ public class DecompileCallback {
|
|||
|
||||
private Namespace getNameSpaceByID(long id) {
|
||||
Symbol namespaceSym = program.getSymbolTable().getSymbol(id);
|
||||
if (namespaceSym == null) {
|
||||
return null;
|
||||
}
|
||||
Object namespace = namespaceSym.getObject();
|
||||
if (namespace instanceof Namespace) {
|
||||
return (Namespace) namespace;
|
||||
|
|
|
@ -123,13 +123,7 @@ public class ASTGraphTask extends Task {
|
|||
graphType == GraphType.DATA_FLOW_GRAPH ? "AST Data Flow" : "AST Control Flow";
|
||||
description = description + " for " + hfunction.getFunction().getName();
|
||||
display.setGraph(graph, description, false, monitor);
|
||||
// set the graph location
|
||||
if (location != null) {
|
||||
AttributedVertex vertex = displayListener.getVertex(location);
|
||||
// update graph location, but don't have it send out event
|
||||
display.setFocusedVertex(vertex, EventTrigger.INTERNAL_ONLY);
|
||||
}
|
||||
|
||||
setGraphLocation(display, displayListener);
|
||||
}
|
||||
catch (GraphException e) {
|
||||
Msg.showError(this, null, "Graph Error", e.getMessage());
|
||||
|
@ -140,6 +134,20 @@ public class ASTGraphTask extends Task {
|
|||
|
||||
}
|
||||
|
||||
private void setGraphLocation(GraphDisplay display, ASTGraphDisplayListener displayListener) {
|
||||
if (location == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
AttributedVertex vertex = displayListener.getVertex(location);
|
||||
if (vertex == null) {
|
||||
return; // location not in graph
|
||||
}
|
||||
|
||||
// update graph location, but don't have it send out event
|
||||
display.setFocusedVertex(vertex, EventTrigger.INTERNAL_ONLY);
|
||||
}
|
||||
|
||||
protected void createDataFlowGraph(AttributedGraph graph, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
Iterator<PcodeOpAST> opIter = hfunction.getPcodeOps();
|
||||
|
|
|
@ -1091,8 +1091,9 @@ class FGActionManager {
|
|||
AddressSet subtraction = provider.getCurrentProgramSelection().subtract(functionBody);
|
||||
|
||||
ProgramSelection programSelectionWithoutGraphBody = new ProgramSelection(subtraction);
|
||||
plugin.getTool().firePluginEvent(new ProgramSelectionPluginEvent("Spoof!",
|
||||
programSelectionWithoutGraphBody, provider.getCurrentProgram()));
|
||||
plugin.getTool()
|
||||
.firePluginEvent(new ProgramSelectionPluginEvent("Spoof!",
|
||||
programSelectionWithoutGraphBody, provider.getCurrentProgram()));
|
||||
}
|
||||
|
||||
private Set<FGVertex> getAllVertices() {
|
||||
|
@ -1161,8 +1162,10 @@ class FGActionManager {
|
|||
|
||||
private void makeSelectionFromAddresses(AddressSet addresses) {
|
||||
ProgramSelection selection = new ProgramSelection(addresses);
|
||||
plugin.getTool().firePluginEvent(
|
||||
new ProgramSelectionPluginEvent("Spoof!", selection, provider.getCurrentProgram()));
|
||||
plugin.getTool()
|
||||
.firePluginEvent(
|
||||
new ProgramSelectionPluginEvent("Spoof!", selection,
|
||||
provider.getCurrentProgram()));
|
||||
}
|
||||
|
||||
private void ungroupVertices(Set<GroupedFunctionGraphVertex> groupVertices) {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
EXCLUDE FROM GHIDRA JAR: true
|
||||
|
||||
MODULE FILE LICENSE: lib/jungrapht-visualization-1.0-RC9.jar BSD
|
||||
MODULE FILE LICENSE: lib/jungrapht-layout-1.0-RC9.jar BSD
|
||||
MODULE FILE LICENSE: lib/jungrapht-visualization-1.0.jar BSD
|
||||
MODULE FILE LICENSE: lib/jungrapht-layout-1.0.jar BSD
|
||||
MODULE FILE LICENSE: lib/jgrapht-core-1.5.0.jar LGPL 2.1
|
||||
MODULE FILE LICENSE: lib/jgrapht-io-1.5.0.jar LGPL 2.1
|
||||
MODULE FILE LICENSE: lib/jheaps-0.13.jar Apache License 2.0
|
||||
|
|
|
@ -11,10 +11,8 @@ eclipse.project.name = 'Features Graph Services'
|
|||
dependencies {
|
||||
compile project(":Base")
|
||||
|
||||
// compile "com.github.tomnelson:jungrapht-visualization:1.0-SNAPSHOT"
|
||||
// compile "com.github.tomnelson:jungrapht-layout:1.0-SNAPSHOT"
|
||||
compile "com.github.tomnelson:jungrapht-visualization:1.0-RC9"
|
||||
compile "com.github.tomnelson:jungrapht-layout:1.0-RC9"
|
||||
compile "com.github.tomnelson:jungrapht-visualization:1.0"
|
||||
compile "com.github.tomnelson:jungrapht-layout:1.0"
|
||||
compile "org.jgrapht:jgrapht-core:1.5.0"
|
||||
|
||||
// not using jgrapht-io code that depends on antlr, so exclude antlr
|
||||
|
|
|
@ -50,11 +50,9 @@
|
|||
|
||||
<tocroot>
|
||||
|
||||
<tocref id="Graphing">
|
||||
<tocdef id="Graph Services" text="Graph Services">
|
||||
<tocdef id="Default Graph Display" text="Default Graph Display" target="help/topics/GraphServices/GraphDisplay.htm" />
|
||||
<tocdef id="Exporting a Graph" text="Exporting a Graph" target="help/topics/GraphServices/GraphExport.htm" />
|
||||
</tocdef>
|
||||
<tocref id="Graph Services">
|
||||
<tocdef id="Default Graph Display" text="Default Graph Display" target="help/topics/GraphServices/GraphDisplay.htm" />
|
||||
<tocdef id="Exporting a Graph" text="Exporting a Graph" target="help/topics/GraphServices/GraphExport.htm" />
|
||||
</tocref>
|
||||
|
||||
</tocroot>
|
||||
|
|
|
@ -5,103 +5,245 @@
|
|||
<META name="generator" content=
|
||||
"HTML Tidy for Java (vers. 2009-12-01), see jtidy.sourceforge.net">
|
||||
|
||||
<TITLE>Graphing</TITLE>
|
||||
<TITLE>Graph Display</TITLE>
|
||||
<META http-equiv="Content-Type" content="text/html; charset=windows-1252">
|
||||
<LINK rel="stylesheet" type="text/css" href="../../shared/Frontpage.css">
|
||||
</HEAD>
|
||||
|
||||
<BODY lang="EN-US">
|
||||
<A name="Default_Graph_Display"/>
|
||||
<A name="Default_Graph_Display">
|
||||
|
||||
|
||||
<H1>Default Graph Display</H1>
|
||||
<H2>Visualization of a Graph</H2>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>The visualization display will show the graph in a new window or in a new tab of a previously created graph window.</P>
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P align="left"><IMG src="images/DefaultGraphDisplay.png" border="1"></P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
<H2>Manipulating the Graph:</H2>
|
||||
<ul>
|
||||
<li>MouseButton1+drag will translate the display in the x and y axis</li>
|
||||
<li>Mouse Wheel will zoom in and out</li>
|
||||
<li>CTRL+Mouse Wheel will zoom in and out in the X-Axis only</li>
|
||||
<li>ALT+Mouse Wheel will zoom in and out in the Y-Axis only</li>
|
||||
<li>Ctrl+MouseButton1 will select a vertex or edge</li>
|
||||
<ul>
|
||||
<li>Shift+Ctrl+MouseButton1 over an unselected vertex will add that vertex to the selection</li>
|
||||
<li>Shift+Ctrl+MouseButton1 over a previously selected vertex will remove that vertex from the selection</li>
|
||||
</ul>
|
||||
<li>Ctrl+MouseButton1+drag on an empty area will create a rectangular area and select enclosed vertices</li>
|
||||
<li>Ctrl+MouseButton1+drag over a vertex will reposition all selected vertices</li>
|
||||
</ul>
|
||||
<H2>Toolbar Buttons</H2>
|
||||
<P><A name="Scroll_To_Selection"/> The <IMG src="images/locationIn.gif"> toggle button, when 'set' will cause a focused vertex (red arrow) to be scrolled to the center of the view</P>
|
||||
<P><A name="Free_Form_Selection"/>The <IMG src="images/Lasso.png" width="16" height="16"> toggle button, when 'set' will allow the user to draw a free-form shape that encloses the vertices they wish to select.</P>
|
||||
<P><A name="SatelliteView"/>The <IMG src="images/sat2.png" width="16" height="16"> toggle button, when 'set' will open a satellite mini view of the graph in the lower right corner. The mini-view can be manipulated with the mouse to affect the main view</P>
|
||||
<P><A name="Reset_View"/>The <IMG src="images/reload3.png"> button will reset any visual transformations on the graph and center it at a best-effort size</P>
|
||||
<P><A name="View_Magnifier"/>The <IMG src="images/magnifier.png"> toggle button, when 'set' will open a rectangular magnification lens in the graph view</P>
|
||||
<BLOCKQUOTE><BLOCKQUOTE>
|
||||
<ul>
|
||||
<li>MouseButton1 click-drag on the lens center circle to move the magnifier lens</li>
|
||||
<li>MouseButton1 click-draw on a lens edge diamond to resize the magnifier lens </li>
|
||||
<li>MouseButton1 click on the upper-right circle-cross to dispose of the magnifier lens</li>
|
||||
<li>MouseWheel will change the magnification of the lens</li>
|
||||
</ul>
|
||||
</BLOCKQUOTE></BLOCKQUOTE>
|
||||
|
||||
<P><A name="Show_Filters"/>The <IMG src="images/filter_on.png"> button will open a Filter dialog. Select buttons in the dialog to hide specific vertices or edges in the display.
|
||||
The Filter dialog buttons are created by examining the graph vertex/edge properties to discover candidates for filtering.</P></BLOCKQUOTE></BLOCKQUOTE>
|
||||
|
||||
<P><A name="Arrangement"/>The <IMG src="images/katomic.png" width="16" height="16"> Arrangement menu is used to select one of several graph layout algorithms.</P>
|
||||
<BLOCKQUOTE><BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P>The visualization display will show the graph in a new window or in a new tab of a
|
||||
previously created graph window.</P>
|
||||
|
||||
<ul>
|
||||
<li><A name="Compact_Hierarchical"/><B>Compact Hierarchical</B> is the <b>TidierTree Layout Algorithm</b>. It builds a tree structure and attempts to reduce horizontal space.</li>
|
||||
<li><A name="Hierarchical"/><B>Hierarchical</B> is a basic Tree algorithm. It prioritizes 'important' edges while constructing the tree.</li>
|
||||
<li><A name="Compact Radial"/><B>Compact Radial</B> is the <b>TidierTree Layout Algorithm</b> with the root(s) at the center and child vertices radiating outwards.</li>
|
||||
<li><B>Hierarchical MinCross</B> is the <b>Sugiyama Layout Algorithm</b>. It attempts to route edges around vertices in order to reduce crossing.There are four layering algorithms:</li>
|
||||
<ul>
|
||||
<li><A name="Hierarchical_MinCross_Top_Down"/><B>Top Down</B> - biases the vertices to the top</li>
|
||||
<li><A name="Hierarchical_MinCross_Longest_Path"/><B>Longest Path</B> - biases the vertices to the bottom</li>
|
||||
<li><A name="Hierarchical_MinCross_Network_Simplex"/><B>Network Simplex</B> - layers after finding an 'optimal tree'</li>
|
||||
<li><A name="Hierarchical_MinCross_Coffman_Graham"/><B>Coffman Graham</B> - biases the vertices using a scheduling algorithm to minimize length</li>
|
||||
</ul>
|
||||
|
||||
<li><A name="Circle"/><B>Circle</B> will arrange vertices in a Circle. If there are not too many edges (less than specified in the jungrapht.circle.reduceEdgeCrossingMaxEdges property with a default of 200), it will attempt to reduce edge crossing by rearranging the vertices.</li>
|
||||
<li><A name="Force_Balanced"/><B>Force Balanced</B> is a <b>Force Directed Layout Algorithm</b> using the the <b>Kamada Kawai</b> approach. It attempts to balance the graph by considering vertices and edge connections.</li>
|
||||
<li><A name="Force_Directed"/><B>Force Directed</B> is a <b>Force Directed Layout Algorithm</b> using the <b>Fructermann Reingold</b> approach. It pushes unconnected vertices apart and draws connected vertices together.</li>
|
||||
<li><A name="Radial"/><B>Radial</B> is a Tree structure with the root(s) at the center and child vertices radiating outwards.</li>
|
||||
<li><A name="Balloon"/><B>Balloon</B> is a Tree structure with the root(s) at the centers of circles in a radial pattern</li>
|
||||
<li><A name="Gem__Graph_Embedder_"/><B>GEM</B> is a Force Directed layout with locally separated components </li>
|
||||
</ul>
|
||||
</BLOCKQUOTE></BLOCKQUOTE>
|
||||
<H2>Popup Actions</H2>
|
||||
<BLOCKQUOTE>
|
||||
<H3> Standard Popup Actions</H3>
|
||||
<ul>
|
||||
<li><A name="Hide Selected"/><B>Hide Selected</B> - Causes the display to not show selected vertices. </li>
|
||||
<li><A name="Hide Unselected"/><B>Hide Unselected</B> - Causes the display to not show unselected vertices.</li>
|
||||
<li><A name="Invert Selection"/><B>Invert Selection</B> - Unselects all selected nodes and selects all unselected nodes.</li>
|
||||
<li><A name="Grow Selection From Sources"/><B>Grow Selection From Sources</B> - Adds to the selection all vertices that have outgoing edges to the current selection.</li>
|
||||
<li><A name="Grow Selection To Targets"/><B>Grow Selection To Targets</B> - Adds to the selection all vertices that have incoming edges from the current selection.</li>
|
||||
<li><A name="Create Subgraph"/><B>Display Selected As New Graph</B> - Creates a new graph and display from the currently selected vertices.</li>
|
||||
</ul>
|
||||
<H3> Vertex Popup Actions</H3>
|
||||
<ul>
|
||||
<li><A name="Select Vertex"/><B>Select Vertex</B> - Selects the vertex that this action was invoked on.</li>
|
||||
<li><A name="Deselect Vertex"/><B>Deselect Vertex</B> - Deselects the vertex that this action was invoked on.</li>
|
||||
</ul>
|
||||
|
||||
<H3> Edge Popup Actions</H3>
|
||||
<ul>
|
||||
<li><A name="Edge Source"/><B>Go To Edge Source</B> - Makes this edge's source vertex be the focused vertex.</li>
|
||||
<li><A name="Edge Target"/><B>Go To Edge Target</B> - Makes this edge's destination vertex be the focused vertex.</li>
|
||||
<li><A name="Select Edge"/><B>Select Edge</B> - Add this edge and its associated vertices to the selection</li>
|
||||
<li><A name="Deselect Edge"/><B>Deselect Edge</B> - Removes this edge and its associated vertices from the selection </li>
|
||||
</ul>
|
||||
<CENTER>
|
||||
<TABLE border="0" width="100%">
|
||||
<TR>
|
||||
<TD width="100%" align="center"><IMG alt="" border="1" src=
|
||||
"images/DefaultGraphDisplay.png"></TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</CENTER>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H2>Manipulating the Graph</H2>
|
||||
|
||||
<UL>
|
||||
<LI>Dragging in the graph or on any unselected vertices will pan the graph (translate the
|
||||
display in the x and y axis)</LI>
|
||||
|
||||
<LI>Dragging a selected vertex will reposition all selected vertices</LI>
|
||||
|
||||
<LI>Using the <CODE>Mouse Wheel</CODE> will zoom the graph in and out</LI>
|
||||
|
||||
<LI><CODE>Control+Mouse Wheel</CODE> will zoom the graph in and out on the X-Axis only</LI>
|
||||
|
||||
<LI><CODE>ALT+Mouse Wheel</CODE> will zoom the graph in and out in the Y-Axis only</LI>
|
||||
|
||||
<LI><CODE>Ctrl+Click</CODE> will select a vertex
|
||||
<UL>
|
||||
<LI><CODE>Ctrl+Click</CODE> over an unselected vertex will add that vertex to the
|
||||
selection</LI>
|
||||
|
||||
<LI><CODE>Ctrl+Click</CODE> over a previously selected vertex will remove that vertex
|
||||
from the selection</LI>
|
||||
</UL>
|
||||
</LI>
|
||||
|
||||
<LI><CODE>Ctrl+drag</CODE> on an empty area will create a rectangular area and select
|
||||
enclosed vertices</LI>
|
||||
|
||||
|
||||
</UL>
|
||||
|
||||
<H2>Toolbar Buttons</H2>
|
||||
|
||||
<P><A name="Scroll_To_Selection">
|
||||
The <IMG alt="" src="images/locationIn.gif"> toggle button, when 'set' will cause a focused
|
||||
vertex (the vertex with the red arrow) to be moved to the center of the view</P>
|
||||
|
||||
<P><A name="Free_Form_Selection">
|
||||
The <IMG alt="" src="images/Lasso.png" width="16" height="16"> toggle button, when 'set' will
|
||||
allow the user to draw a free-form shape that encloses the vertices they wish to select.</P>
|
||||
|
||||
<P><A name="SatelliteView">
|
||||
The <IMG alt="" src="images/network-wireless-16.png" width="16" height="16"> toggle button,
|
||||
when 'set' will open a satellite mini view of the graph in the lower right corner. The
|
||||
mini-view can be manipulated with the mouse to affect the main view</P>
|
||||
|
||||
<P><A name="Reset_View">
|
||||
The <IMG alt="" src="images/reload3.png"> button will reset any visual transformations on the
|
||||
graph and center it at a best-effort size</P>
|
||||
|
||||
<P><A name="View_Magnifier">
|
||||
The <IMG alt="" src="images/magnifier.png"> toggle button, when 'set' will open a rectangular
|
||||
magnification lens in the graph view</P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<UL>
|
||||
<LI>MouseButton1 click-drag on the lens center circle to move the magnifier lens</LI>
|
||||
|
||||
<LI>MouseButton1 click-draw on a lens edge diamond to resize the magnifier lens</LI>
|
||||
|
||||
<LI>MouseButton1 click on the upper-right circle-cross to dispose of the magnifier
|
||||
lens</LI>
|
||||
|
||||
<LI>MouseWheel will change the magnification of the lens</LI>
|
||||
</UL>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P><A name="Show_Filters">
|
||||
The <IMG alt="" src="Icons.CONFIGURE_FILTER_ICON"> button will open a Filter dialog. Select
|
||||
buttons in the dialog to hide specific vertices or edges in the display. The Filter dialog
|
||||
buttons are created by examining the graph vertex/edge properties to discover candidates for
|
||||
filtering.</P>
|
||||
|
||||
<P><A name="Arrangement">
|
||||
The <IMG alt="" src="images/katomic.png" width="16" height="16"> Arrangement menu is used to
|
||||
select one of several graph layout algorithms.</P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<UL>
|
||||
<LI><A name="Compact_Hierarchical">
|
||||
<B>Compact Hierarchical</B> is the <B>TidierTree Layout Algorithm</B>. It builds a tree
|
||||
structure and attempts to reduce horizontal space.</LI>
|
||||
|
||||
<LI><A name="Hierarchical">
|
||||
<B>Hierarchical</B> is a basic Tree algorithm. It prioritizes 'important' edges while
|
||||
constructing the tree.</LI>
|
||||
|
||||
<LI><A name="Compact Radial">
|
||||
<B>Compact Radial</B> is the <B>TidierTree Layout Algorithm</B> with the root(s) at the
|
||||
center and child vertices radiating outwards.</LI>
|
||||
|
||||
<LI><B>Hierarchical MinCross</B> is the <B>Sugiyama Layout Algorithm</B>. It attempts to
|
||||
route edges around vertices in order to reduce crossing.There are four layering
|
||||
algorithms:</LI>
|
||||
|
||||
<LI style="list-style: none">
|
||||
<UL>
|
||||
<LI><A name="Hierarchical_MinCross_Top_Down">
|
||||
<B>Top Down</B> - biases the vertices to the top</LI>
|
||||
|
||||
<LI><A name="Hierarchical_MinCross_Longest_Path">
|
||||
<B>Longest Path</B> - biases the vertices to the bottom</LI>
|
||||
|
||||
<LI><A name="Hierarchical_MinCross_Network_Simplex">
|
||||
<B>Network Simplex</B> - layers after finding an 'optimal tree'</LI>
|
||||
|
||||
<LI><A name="Hierarchical_MinCross_Coffman_Graham">
|
||||
<B>Coffman Graham</B> - biases the vertices using a scheduling algorithm to minimize
|
||||
length</LI>
|
||||
</UL>
|
||||
</LI>
|
||||
|
||||
<LI><A name="Circle">
|
||||
<B>Circle</B> will arrange vertices in a Circle. If there are not too many edges (less
|
||||
than specified in the jungrapht.circle.reduceEdgeCrossingMaxEdges property with a default
|
||||
of 200), it will attempt to reduce edge crossing by rearranging the vertices.</LI>
|
||||
|
||||
<LI><A name="Force_Balanced">
|
||||
<B>Force Balanced</B> is a <B>Force Directed Layout Algorithm</B> using the the <B>Kamada
|
||||
Kawai</B> approach. It attempts to balance the graph by considering vertices and edge
|
||||
connections.</LI>
|
||||
|
||||
<LI><A name="Force_Directed">
|
||||
<B>Force Directed</B> is a <B>Force Directed Layout Algorithm</B> using the
|
||||
<B>Fructermann Reingold</B> approach. It pushes unconnected vertices apart and draws
|
||||
connected vertices together.</LI>
|
||||
|
||||
<LI><A name="Radial">
|
||||
<B>Radial</B> is a Tree structure with the root(s) at the center and child vertices
|
||||
radiating outwards.</LI>
|
||||
|
||||
<LI><A name="Balloon">
|
||||
<B>Balloon</B> is a Tree structure with the root(s) at the centers of circles in a radial
|
||||
pattern</LI>
|
||||
|
||||
<LI><A name="Gem__Graph_Embedder_">
|
||||
<B>GEM</B> is a Force Directed layout with locally separated components</LI>
|
||||
</UL>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H2>Popup Actions</H2>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<H3>Standard Popup Actions</H3>
|
||||
|
||||
<UL>
|
||||
<LI><A name="Hide_Selected">
|
||||
<B>Hide Selected</B> - Causes the display to not show selected vertices.</LI>
|
||||
|
||||
<LI><A name="Hide_Unselected">
|
||||
<B>Hide Unselected</B> - Causes the display to not show unselected vertices.</LI>
|
||||
|
||||
<LI><A name="Invert_Selection">
|
||||
<B>Invert Selection</B> - Unselects all selected nodes and selects all unselected
|
||||
nodes.</LI>
|
||||
|
||||
<LI><A name="Grow_Selection From Sources">
|
||||
<B>Grow Selection From Sources</B> - Adds to the selection all vertices that have outgoing
|
||||
edges to the current selection.</LI>
|
||||
|
||||
<LI><A name="Grow_Selection To Targets">
|
||||
<B>Grow Selection To Targets</B> - Adds to the selection all vertices that have incoming
|
||||
edges from the current selection.</LI>
|
||||
|
||||
<LI><A name="Clear_Selection">
|
||||
<B>Clear Selection</B> - Clears all edge and vertex selection.</LI>
|
||||
|
||||
<LI><A name="Create_Subgraph">
|
||||
<B>Display Selected As New Graph</B> - Creates a new graph and display from the currently
|
||||
selected vertices.</LI>
|
||||
|
||||
<LI><A name="Display_Popup_Windows">
|
||||
<B>Display Popup Windows</B> - When toggled off no tooltip popups will be displayed.</LI>
|
||||
|
||||
</UL>
|
||||
|
||||
<H3>Vertex Popup Actions</H3>
|
||||
|
||||
<UL>
|
||||
<LI><A name="Select_Vertex">
|
||||
<B>Select Vertex</B> - Selects the vertex that this action was invoked on.</LI>
|
||||
|
||||
<LI><A name="Deselect_Vertex">
|
||||
<B>Deselect Vertex</B> - Deselects the vertex that this action was invoked on.</LI>
|
||||
</UL>
|
||||
|
||||
<H3>Edge Popup Actions</H3>
|
||||
|
||||
<UL>
|
||||
<LI><A name="Edge_Source">
|
||||
<B>Go To Edge Source</B> - Makes this edge's source vertex be the focused vertex.</LI>
|
||||
|
||||
<LI><A name="Edge_Target">
|
||||
<B>Go To Edge Target</B> - Makes this edge's destination vertex be the focused vertex.</LI>
|
||||
|
||||
<LI><A name="Select_Edge">
|
||||
<B>Select Edge</B> - Add this edge and its associated vertices to the selection</LI>
|
||||
|
||||
<LI><A name="Deselect_Edge">
|
||||
<B>Deselect Edge</B> - Removes this edge and its associated vertices from the
|
||||
selection</LI>
|
||||
</UL>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P class="providedbyplugin">Provided By: <I>GraphDisplayBrokerPlugin</I></P>
|
||||
|
||||
<P class="relatedtopic">Related Topics:</P>
|
||||
|
||||
<UL>
|
||||
<LI><A href="help/topics/GraphServices/GraphExport.htm">Graph Export</A></LI>
|
||||
</UL><BR>
|
||||
<BR>
|
||||
</BODY>
|
||||
</HTML>
|
||||
</HTML>
|
||||
|
|
|
@ -11,19 +11,22 @@
|
|||
</HEAD>
|
||||
|
||||
<BODY lang="EN-US">
|
||||
<A name="Default Graph Exporter"/>
|
||||
<A NAME="Graph_Exporter"/>
|
||||
<H1>Graph Export Service</H1>
|
||||
|
||||
<H2> Export Dialog </H2>
|
||||
<P> Whenever a graph is generated and the graph output is set to <B>Graph Export</B>, then the
|
||||
following graph export dialog is displayed: </P>
|
||||
<BR>
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
|
||||
<P align="left"><IMG src="images/ExportDialog.png"></P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
<CENTER>
|
||||
<TABLE border="0" width="100%">
|
||||
<TR>
|
||||
<TD width="100%" align="center"><IMG alt="" border="1" src=
|
||||
"images/ExportDialog.png"></TD>
|
||||
</TR>
|
||||
</TABLE>
|
||||
</CENTER>
|
||||
<BR>
|
||||
<BLOCKQUOTE>
|
||||
<P>The Export Graph dialog offers a choice of the following graph formats:</P>
|
||||
|
@ -49,5 +52,16 @@
|
|||
<p>The <b>Ok</b> button will marshal the graph to the selected file in the selected format and close the dialog.</p>
|
||||
<p>The <b>Cancel</b> button will close the dialog and perform no other action.</p>
|
||||
|
||||
|
||||
|
||||
<P class="providedbyplugin">Provided By: <I>GraphDisplayBrokerPlugin</I></P>
|
||||
|
||||
<P class="relatedtopic">Related Topics:</P>
|
||||
<UL>
|
||||
<LI><A href="help/topics/GraphServices/GraphDisplay.htm">Default Graph Display</A></LI>
|
||||
</UL>
|
||||
<BR>
|
||||
<BR>
|
||||
|
||||
</BODY>
|
||||
</HTML>
|
Binary file not shown.
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 14 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 8.5 KiB |
|
@ -73,6 +73,6 @@ public class ExportAttributedGraphDisplayProvider implements GraphDisplayProvide
|
|||
|
||||
@Override
|
||||
public HelpLocation getHelpLocation() {
|
||||
return new HelpLocation("GraphServices", "Default_Graph_Exporter");
|
||||
return new HelpLocation("GraphServices", "Graph_Exporter");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ public class GraphExporterDialog extends DialogComponentProvider {
|
|||
addWorkPanel(buildWorkPanel());
|
||||
addOKButton();
|
||||
addCancelButton();
|
||||
setHelpLocation(new HelpLocation("ExporterPlugin", "Exporter_Dialog"));
|
||||
setHelpLocation(new HelpLocation("GraphServices", "Graph_Exporter"));
|
||||
validate();
|
||||
}
|
||||
|
||||
|
|
|
@ -27,10 +27,10 @@ final class DefaultDisplayGraphIcons {
|
|||
private DefaultDisplayGraphIcons() {
|
||||
}
|
||||
|
||||
public static final Icon SATELLITE_VIEW_ICON = Icons.get("images/sat2.png");
|
||||
public static final Icon SATELLITE_VIEW_ICON = Icons.get("images/network-wireless-16.png");
|
||||
public static final Icon VIEW_MAGNIFIER_ICON = Icons.get("images/magnifier.png");
|
||||
public static final Icon PROGRAM_GRAPH_ICON = Icons.get("images/redspheregraph.png");
|
||||
public static final Icon LAYOUT_ALGORITHM_ICON = Icons.get("images/katomic.png");
|
||||
public static final Icon LASSO_ICON = Icons.get("images/Lasso.png");
|
||||
public static final Icon FILTER_ICON = Icons.get("images/filter_on.png");
|
||||
public static final Icon FILTER_ICON = Icons.CONFIGURE_FILTER_ICON;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ import java.awt.event.*;
|
|||
import java.awt.geom.Point2D;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -32,6 +31,7 @@ import javax.swing.*;
|
|||
import javax.swing.event.AncestorEvent;
|
||||
import javax.swing.event.AncestorListener;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.jgrapht.Graph;
|
||||
import org.jgrapht.graph.AsSubgraph;
|
||||
import org.jungrapht.visualization.*;
|
||||
|
@ -58,9 +58,13 @@ import docking.action.ToggleDockingAction;
|
|||
import docking.action.builder.*;
|
||||
import docking.menu.ActionState;
|
||||
import docking.widgets.EventTrigger;
|
||||
import generic.util.WindowUtilities;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.graph.AttributeFilters;
|
||||
import ghidra.graph.job.GraphJobRunner;
|
||||
import ghidra.graph.viewer.popup.*;
|
||||
import ghidra.graph.visualization.mouse.JgtPluggableGraphMouse;
|
||||
import ghidra.graph.visualization.mouse.JgtUtils;
|
||||
import ghidra.service.graph.*;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
@ -73,19 +77,18 @@ import resources.Icons;
|
|||
*/
|
||||
public class DefaultGraphDisplay implements GraphDisplay {
|
||||
|
||||
public static final String FAVORED_EDGE = "Fall-Through";
|
||||
private static final int MAX_NODES = Integer.getInteger("maxNodes", 10000);
|
||||
public static final Dimension PREFERRED_VIEW_SIZE = new Dimension(1000, 1000);
|
||||
public static final Dimension PREFERRED_LAYOUT_SIZE = new Dimension(3000, 3000);
|
||||
private static final String ACTION_OWNER = "GraphServices";
|
||||
|
||||
Logger log = Logger.getLogger(DefaultGraphDisplay.class.getName());
|
||||
private static final String FAVORED_EDGE = "Fall-Through";
|
||||
private static final int MAX_NODES = Integer.getInteger("maxNodes", 10000);
|
||||
private static final Dimension PREFERRED_VIEW_SIZE = new Dimension(1000, 1000);
|
||||
private static final Dimension PREFERRED_LAYOUT_SIZE = new Dimension(3000, 3000);
|
||||
|
||||
private Logger log = Logger.getLogger(DefaultGraphDisplay.class.getName());
|
||||
|
||||
private GraphDisplayListener listener = new DummyGraphDisplayListener();
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* the {@link Graph} to visualize
|
||||
*/
|
||||
private AttributedGraph graph;
|
||||
|
||||
/**
|
||||
|
@ -94,99 +97,71 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
private final int displayId;
|
||||
|
||||
/**
|
||||
* the delegate viewer to display the ProgramGraph
|
||||
* The delegate viewer to display the ProgramGraph
|
||||
*/
|
||||
private final VisualizationViewer<AttributedVertex, AttributedEdge> viewer;
|
||||
|
||||
/**
|
||||
* the {@link PluginTool}
|
||||
* The {@link PluginTool}
|
||||
*/
|
||||
private final PluginTool pluginTool;
|
||||
|
||||
/**
|
||||
* the "owner name" for action - mainly affects default help location
|
||||
*/
|
||||
private final String actionOwnerName = "GraphServices";
|
||||
|
||||
/**
|
||||
* provides the component for the {@link GraphDisplay}
|
||||
*/
|
||||
private final DefaultGraphDisplayComponentProvider componentProvider;
|
||||
|
||||
/**
|
||||
* whether to ensure the focused vertex is visible, scrolling if necessary
|
||||
* Whether to ensure the focused vertex is visible, scrolling if necessary
|
||||
* the visualization in order to center the selected vertex
|
||||
* or the center of the set of selected vertices
|
||||
*/
|
||||
private boolean ensureVertexIsVisible = false;
|
||||
|
||||
/**
|
||||
* allows selection of various {@link LayoutAlgorithm} ('arrangements')
|
||||
* Allows selection of various {@link LayoutAlgorithm} ('arrangements')
|
||||
*/
|
||||
private final LayoutTransitionManager layoutTransitionManager;
|
||||
|
||||
/**
|
||||
* provides graph displays for supplied graphs
|
||||
* Provides graph displays for supplied graphs
|
||||
*/
|
||||
private final DefaultGraphDisplayProvider graphDisplayProvider;
|
||||
/**
|
||||
* the vertex that has been nominated to be 'focused' in the graph display and listing
|
||||
*/
|
||||
private AttributedVertex focusedVertex;
|
||||
|
||||
/**
|
||||
* Runs animation jobs for updating the display
|
||||
*/
|
||||
private final GraphJobRunner jobRunner = new GraphJobRunner();
|
||||
|
||||
/**
|
||||
* a satellite view that shows in the lower left corner as a birds-eye view of the graph display
|
||||
*/
|
||||
private final SatelliteVisualizationViewer<AttributedVertex, AttributedEdge> satelliteViewer;
|
||||
/**
|
||||
* generated filters on edges
|
||||
*/
|
||||
private AttributeFilters edgeFilters;
|
||||
/**
|
||||
* generated filters on vertices
|
||||
*/
|
||||
private AttributeFilters vertexFilters;
|
||||
/**
|
||||
* a dialog populated with generated vertex/edge filters
|
||||
*/
|
||||
|
||||
private FilterDialog filterDialog;
|
||||
/**
|
||||
* holds the vertex icons (instead of recomputing them)
|
||||
*/
|
||||
private AttributeFilters edgeFilters;
|
||||
private AttributeFilters vertexFilters;
|
||||
|
||||
private GhidraIconCache iconCache;
|
||||
|
||||
/**
|
||||
* multi-selection is done in a free-form traced shape instead of a rectangle
|
||||
* Multi-selection is done in a free-form traced shape instead of a rectangle
|
||||
*/
|
||||
private boolean freeFormSelection;
|
||||
|
||||
/**
|
||||
* Handles the popup
|
||||
* Handles all mouse interaction
|
||||
*/
|
||||
private GhidraGraphMouse graphMouse;
|
||||
private JgtPluggableGraphMouse graphMouse;
|
||||
|
||||
/**
|
||||
* Will accept a {@link Graph} and use it to create a new graph display in
|
||||
* a new tab or new window
|
||||
*/
|
||||
Consumer<Graph<AttributedVertex, AttributedEdge>> subgraphConsumer = g -> {
|
||||
try {
|
||||
AttributedGraph attributedGraph = new AttributedGraph();
|
||||
g.vertexSet().forEach(attributedGraph::addVertex);
|
||||
g.edgeSet().forEach(e -> {
|
||||
AttributedVertex source = g.getEdgeSource(e);
|
||||
AttributedVertex target = g.getEdgeTarget(e);
|
||||
attributedGraph.addEdge(source, target, e);
|
||||
});
|
||||
displaySubGraph(attributedGraph);
|
||||
}
|
||||
catch (CancelledException e) {
|
||||
// noop
|
||||
}
|
||||
};
|
||||
private ToggleDockingAction hideSelectedAction;
|
||||
private ToggleDockingAction hideUnselectedAction;
|
||||
private SwitchableSelectionItemListener switchableSelectionListener;
|
||||
|
||||
private ToggleDockingAction togglePopupsAction;
|
||||
private PopupRegulator<AttributedVertex, AttributedEdge> popupRegulator;
|
||||
|
||||
/**
|
||||
* Create the initial display, the graph-less visualization viewer, and its controls
|
||||
* @param displayProvider provides a {@link PluginTool} for Docking features
|
||||
|
@ -202,6 +177,9 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
componentProvider = new DefaultGraphDisplayComponentProvider(this, pluginTool);
|
||||
componentProvider.addToTool();
|
||||
satelliteViewer = createSatelliteViewer(viewer);
|
||||
if (graphDisplayProvider.getDefaultSatelliteState()) {
|
||||
viewer.getComponent().add(satelliteViewer.getComponent());
|
||||
}
|
||||
layoutTransitionManager =
|
||||
new LayoutTransitionManager(viewer, this::isRoot);
|
||||
|
||||
|
@ -221,7 +199,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
.builder(viewer.getRenderContext().getVertexBoundsFunction())
|
||||
.build());
|
||||
|
||||
graphMouse = new GhidraGraphMouse(componentProvider, viewer);
|
||||
graphMouse = new JgtPluggableGraphMouse(this);
|
||||
|
||||
createToolbarActions();
|
||||
createPopupActions();
|
||||
|
@ -297,7 +275,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
private void createToolbarActions() {
|
||||
|
||||
// create a toggle for 'scroll to selected vertex'
|
||||
new ToggleActionBuilder("Scroll To Selection", actionOwnerName)
|
||||
new ToggleActionBuilder("Scroll To Selection", ACTION_OWNER)
|
||||
.toolBarIcon(Icons.NAVIGATE_ON_INCOMING_EVENT_ICON)
|
||||
.description("Ensure that the 'focused' vertex is visible")
|
||||
.selected(true)
|
||||
|
@ -309,7 +287,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
|
||||
// create a toggle for enabling 'free-form' selection: selection is
|
||||
// inside of a traced shape instead of a rectangle
|
||||
new ToggleActionBuilder("Free-Form Selection", actionOwnerName)
|
||||
new ToggleActionBuilder("Free-Form Selection", ACTION_OWNER)
|
||||
.toolBarIcon(DefaultDisplayGraphIcons.LASSO_ICON)
|
||||
.description("Trace Free-Form Shape to select multiple vertices (CTRL-click-drag)")
|
||||
.selected(false)
|
||||
|
@ -318,13 +296,14 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
.buildAndInstallLocal(componentProvider);
|
||||
|
||||
// create an icon button to display the satellite view
|
||||
new ToggleActionBuilder("SatelliteView", actionOwnerName).description("Show Satellite View")
|
||||
new ToggleActionBuilder("SatelliteView", ACTION_OWNER).description("Show Satellite View")
|
||||
.toolBarIcon(DefaultDisplayGraphIcons.SATELLITE_VIEW_ICON)
|
||||
.onAction(this::toggleSatellite)
|
||||
.selected(graphDisplayProvider.getDefaultSatelliteState())
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
|
||||
// create an icon button to reset the view transformations to identity (scaled to layout)
|
||||
new ActionBuilder("Reset View", actionOwnerName)
|
||||
new ActionBuilder("Reset View", ACTION_OWNER)
|
||||
.description("Reset all view transforms to center graph in display")
|
||||
.toolBarIcon(Icons.REFRESH_ICON)
|
||||
.onAction(context -> viewer.scaleToLayout())
|
||||
|
@ -332,7 +311,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
|
||||
// create a button to show the view magnify lens
|
||||
LensSupport<LensGraphMouse> magnifyViewSupport = createMagnifier();
|
||||
ToggleDockingAction lensToggle = new ToggleActionBuilder("View Magnifier", actionOwnerName)
|
||||
ToggleDockingAction lensToggle = new ToggleActionBuilder("View Magnifier", ACTION_OWNER)
|
||||
.description("Show View Magnifier")
|
||||
.toolBarIcon(DefaultDisplayGraphIcons.VIEW_MAGNIFIER_ICON)
|
||||
.onAction(context -> magnifyViewSupport.activate(
|
||||
|
@ -343,90 +322,91 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
componentProvider.addLocalAction(lensToggle);
|
||||
|
||||
// create an action button to show a dialog with generated filters
|
||||
new ActionBuilder("Show Filters", actionOwnerName).description("Show Graph Filters")
|
||||
new ActionBuilder("Show Filters", ACTION_OWNER).description("Show Graph Filters")
|
||||
.toolBarIcon(DefaultDisplayGraphIcons.FILTER_ICON)
|
||||
.onAction(context -> showFilterDialog())
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
|
||||
// create a menu with graph layout algorithm selections
|
||||
new MultiStateActionBuilder<String>("Arrangement", actionOwnerName)
|
||||
.description("Select Layout Arrangement Algorithm")
|
||||
List<ActionState<String>> layoutActionStates = getLayoutActionStates();
|
||||
new MultiStateActionBuilder<String>("Arrangement", ACTION_OWNER)
|
||||
.description("Arrangement: " + layoutActionStates.get(0).getName())
|
||||
.toolBarIcon(DefaultDisplayGraphIcons.LAYOUT_ALGORITHM_ICON)
|
||||
.fireFirstAction(false)
|
||||
.onActionStateChanged((s, t) -> layoutChanged(s.getName()))
|
||||
.addStates(getLayoutActionStates())
|
||||
.addStates(layoutActionStates)
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
}
|
||||
|
||||
private void createPopupActions() {
|
||||
new ActionBuilder("Select Vertex", actionOwnerName)
|
||||
new ActionBuilder("Select Vertex", ACTION_OWNER)
|
||||
.popupMenuPath("Select Vertex")
|
||||
.popupMenuGroup("selection", "1")
|
||||
.withContext(VertexGraphActionContext.class)
|
||||
.enabledWhen(c -> !viewer.getSelectedVertexState().isSelected(c.getClickedVertex()))
|
||||
.enabledWhen(c -> !isSelected(c.getClickedVertex()))
|
||||
.onAction(c -> viewer.getSelectedVertexState().select(c.getClickedVertex()))
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
|
||||
new ActionBuilder("Deselect Vertex", actionOwnerName)
|
||||
new ActionBuilder("Deselect Vertex", ACTION_OWNER)
|
||||
.popupMenuPath("Deselect Vertex")
|
||||
.popupMenuGroup("selection", "2")
|
||||
.withContext(VertexGraphActionContext.class)
|
||||
.enabledWhen(c -> viewer.getSelectedVertexState().isSelected(c.getClickedVertex()))
|
||||
.enabledWhen(c -> isSelected(c.getClickedVertex()))
|
||||
.onAction(c -> viewer.getSelectedVertexState().deselect(c.getClickedVertex()))
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
|
||||
new ActionBuilder("Select Edge", actionOwnerName)
|
||||
new ActionBuilder("Select Edge", ACTION_OWNER)
|
||||
.popupMenuPath("Select Edge")
|
||||
.popupMenuGroup("selection", "1")
|
||||
.withContext(EdgeGraphActionContext.class)
|
||||
.enabledWhen(c -> !viewer.getSelectedEdgeState().isSelected(c.getClickedEdge()))
|
||||
.enabledWhen(c -> !isSelected(c.getClickedEdge()))
|
||||
.onAction(c -> selectEdge(c.getClickedEdge()))
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
|
||||
new ActionBuilder("Deselect Edge", actionOwnerName)
|
||||
new ActionBuilder("Deselect Edge", ACTION_OWNER)
|
||||
.popupMenuPath("Deselect Edge")
|
||||
.popupMenuGroup("selection", "2")
|
||||
.withContext(EdgeGraphActionContext.class)
|
||||
.enabledWhen(c -> viewer.getSelectedEdgeState().isSelected(c.getClickedEdge()))
|
||||
.enabledWhen(c -> isSelected(c.getClickedEdge()))
|
||||
.onAction(c -> deselectEdge(c.getClickedEdge()))
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
|
||||
new ActionBuilder("Edge Source", actionOwnerName)
|
||||
new ActionBuilder("Edge Source", ACTION_OWNER)
|
||||
.popupMenuPath("Go To Edge Source")
|
||||
.popupMenuGroup("Go To")
|
||||
.withContext(EdgeGraphActionContext.class)
|
||||
.onAction(c -> setFocusedVertex(graph.getEdgeSource(c.getClickedEdge())))
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
|
||||
new ActionBuilder("Edge Target", actionOwnerName)
|
||||
new ActionBuilder("Edge Target", ACTION_OWNER)
|
||||
.popupMenuPath("Go To Edge Target")
|
||||
.popupMenuGroup("Go To")
|
||||
.withContext(EdgeGraphActionContext.class)
|
||||
.onAction(c -> setFocusedVertex(graph.getEdgeTarget(c.getClickedEdge())))
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
|
||||
hideSelectedAction = new ToggleActionBuilder("Hide Selected", actionOwnerName)
|
||||
hideSelectedAction = new ToggleActionBuilder("Hide Selected", ACTION_OWNER)
|
||||
.popupMenuPath("Hide Selected")
|
||||
.popupMenuGroup("z", "1")
|
||||
.description("Toggles whether or not to show selected vertices and edges")
|
||||
.onAction(c -> manageVertexDisplay())
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
|
||||
hideUnselectedAction = new ToggleActionBuilder("Hide Unselected", actionOwnerName)
|
||||
hideUnselectedAction = new ToggleActionBuilder("Hide Unselected", ACTION_OWNER)
|
||||
.popupMenuPath("Hide Unselected")
|
||||
.popupMenuGroup("z", "2")
|
||||
.description("Toggles whether or not to show selected vertices and edges")
|
||||
.onAction(c -> manageVertexDisplay())
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
|
||||
new ActionBuilder("Invert Selection", actionOwnerName)
|
||||
new ActionBuilder("Invert Selection", ACTION_OWNER)
|
||||
.popupMenuPath("Invert Selection")
|
||||
.popupMenuGroup("z", "3")
|
||||
.description("Inverts the current selection")
|
||||
.onAction(c -> invertSelection())
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
|
||||
new ActionBuilder("Grow Selection To Targets", actionOwnerName)
|
||||
new ActionBuilder("Grow Selection To Targets", ACTION_OWNER)
|
||||
.popupMenuPath("Grow Selection To Targets")
|
||||
.popupMenuGroup("z", "4")
|
||||
.description("Extends the current selection by including the target vertex " +
|
||||
|
@ -436,7 +416,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
.onAction(c -> growSelection(getTargetVerticesFromSelected()))
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
|
||||
new ActionBuilder("Grow Selection From Sources", actionOwnerName)
|
||||
new ActionBuilder("Grow Selection From Sources", ACTION_OWNER)
|
||||
.popupMenuPath("Grow Selection From Sources")
|
||||
.popupMenuGroup("z", "4")
|
||||
.description("Extends the current selection by including the target vertex " +
|
||||
|
@ -446,13 +426,49 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
.onAction(c -> growSelection(getSourceVerticesFromSelected()))
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
|
||||
new ActionBuilder("Create Subgraph", actionOwnerName)
|
||||
.popupMenuPath("Display Selected as New Graph")
|
||||
new ActionBuilder("Clear Selection", ACTION_OWNER)
|
||||
.popupMenuPath("Clear Selection")
|
||||
.popupMenuGroup("z", "5")
|
||||
.keyBinding("escape")
|
||||
.enabledWhen(c -> hasSelection())
|
||||
.onAction(c -> clearSelection())
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
|
||||
new ActionBuilder("Create Subgraph", ACTION_OWNER)
|
||||
.popupMenuPath("Display Selected as New Graph")
|
||||
.popupMenuGroup("zz", "5")
|
||||
.description("Creates a subgraph from the selected nodes")
|
||||
.enabledWhen(c -> !viewer.getSelectedVertexState().getSelected().isEmpty())
|
||||
.onAction(c -> createAndDisplaySubGraph())
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
|
||||
togglePopupsAction = new ToggleActionBuilder("Display Popup Windows", ACTION_OWNER)
|
||||
.popupMenuPath("Display Popup Windows")
|
||||
.popupMenuGroup("zz", "1")
|
||||
.description("Toggles whether or not to show popup windows, such as tool tips")
|
||||
.selected(true)
|
||||
.onAction(c -> popupRegulator.setPopupsVisible(togglePopupsAction.isSelected()))
|
||||
.buildAndInstallLocal(componentProvider);
|
||||
popupRegulator.setPopupsVisible(togglePopupsAction.isSelected());
|
||||
|
||||
}
|
||||
|
||||
private void clearSelection() {
|
||||
viewer.getSelectedVertexState().clear();
|
||||
viewer.getSelectedEdgeState().clear();
|
||||
}
|
||||
|
||||
private boolean hasSelection() {
|
||||
return !(viewer.getSelectedVertexState().getSelected().isEmpty() &&
|
||||
viewer.getSelectedEdgeState().getSelected().isEmpty());
|
||||
}
|
||||
|
||||
private boolean isSelected(AttributedVertex v) {
|
||||
return viewer.getSelectedVertexState().isSelected(v);
|
||||
}
|
||||
|
||||
private boolean isSelected(AttributedEdge e) {
|
||||
return viewer.getSelectedEdgeState().isSelected(e);
|
||||
}
|
||||
|
||||
private void createAndDisplaySubGraph() {
|
||||
|
@ -540,7 +556,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
for (String layoutName : names) {
|
||||
ActionState<String> state = new ActionState<>(layoutName,
|
||||
DefaultDisplayGraphIcons.LAYOUT_ALGORITHM_ICON, layoutName);
|
||||
state.setHelpLocation(new HelpLocation(actionOwnerName, layoutName));
|
||||
state.setHelpLocation(new HelpLocation(ACTION_OWNER, layoutName));
|
||||
actionStates.add(state);
|
||||
}
|
||||
return actionStates;
|
||||
|
@ -576,7 +592,9 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
* @param context information about the event
|
||||
*/
|
||||
private void toggleSatellite(ActionContext context) {
|
||||
if (((AbstractButton) context.getSourceObject()).isSelected()) {
|
||||
boolean selected = ((AbstractButton) context.getSourceObject()).isSelected();
|
||||
graphDisplayProvider.setDefaultSatelliteState(selected);
|
||||
if (selected) {
|
||||
viewer.getComponent().add(satelliteViewer.getComponent());
|
||||
}
|
||||
else {
|
||||
|
@ -585,18 +603,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
viewer.repaint();
|
||||
}
|
||||
|
||||
private void displaySubGraph(Graph<AttributedVertex, AttributedEdge> subGraph)
|
||||
throws CancelledException {
|
||||
GraphDisplay graphDisplay = graphDisplayProvider.getGraphDisplay(false, TaskMonitor.DUMMY);
|
||||
graphDisplay.setGraph((AttributedGraph) subGraph, "SubGraph", false, TaskMonitor.DUMMY);
|
||||
graphDisplay.setGraphDisplayListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* create a SatelliteViewer for the Visualization
|
||||
* @param parentViewer the main visualization 'parent' of the satellite view
|
||||
* @return a new SatelliteVisualizationViewer
|
||||
*/
|
||||
private SatelliteVisualizationViewer<AttributedVertex, AttributedEdge> createSatelliteViewer(
|
||||
VisualizationViewer<AttributedVertex, AttributedEdge> parentViewer) {
|
||||
Dimension viewerSize = parentViewer.getSize();
|
||||
|
@ -625,9 +631,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
return satellite;
|
||||
}
|
||||
|
||||
/**
|
||||
* close this graph display
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
graphDisplayProvider.remove(this);
|
||||
|
@ -638,10 +641,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
componentProvider.closeComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* accept a {@code GraphDisplayListener}
|
||||
* @param listener the listener to be notified
|
||||
*/
|
||||
@Override
|
||||
public void setGraphDisplayListener(GraphDisplayListener listener) {
|
||||
if (this.listener != null) {
|
||||
|
@ -673,7 +672,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
viewer.getSelectedVertexState().addItemListener(switchableSelectionListener);
|
||||
}
|
||||
|
||||
protected void setFocusedVertex(AttributedVertex vertex) {
|
||||
public void setFocusedVertex(AttributedVertex vertex) {
|
||||
setFocusedVertex(vertex, EventTrigger.API_CALL);
|
||||
}
|
||||
|
||||
|
@ -709,15 +708,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* transform the supplied {@code AttributedVertex}s to a List of their ids
|
||||
* @param selectedVertices the collections of vertices.
|
||||
* @return a list of vertex ids
|
||||
*/
|
||||
private List<String> toVertexIds(Collection<AttributedVertex> selectedVertices) {
|
||||
return selectedVertices.stream().map(AttributedVertex::getId).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Collection<AttributedVertex> getVertices(Object item) {
|
||||
if (item instanceof Collection) {
|
||||
|
@ -770,7 +760,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* set the {@link AttributedGraph} for visualization
|
||||
* @param attributedGraph the {@link AttributedGraph} to visualize
|
||||
|
@ -784,7 +773,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
configureViewerPreferredSize();
|
||||
|
||||
Swing.runNow(() -> {
|
||||
// set the graph but defer the layoutalgorithm setting
|
||||
// set the graph but defer the layout algorithm setting
|
||||
viewer.getVisualizationModel().setGraph(graph, false);
|
||||
configureFilters();
|
||||
LayoutAlgorithm<AttributedVertex> initialLayoutAlgorithm =
|
||||
|
@ -795,8 +784,8 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
}
|
||||
|
||||
/**
|
||||
* Determines if a vertex is a root. For our purpose, a root either has no incomming edges
|
||||
* or has at least one outgoing "favored" edge and no incomming "favored" edge
|
||||
* Determines if a vertex is a root. For our purpose, a root either has no incoming edges
|
||||
* or has at least one outgoing "favored" edge and no incoming "favored" edge
|
||||
* @param vertex the vertex to test if it is a root
|
||||
* @return true if the vertex is a root
|
||||
*/
|
||||
|
@ -994,8 +983,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
return new Point2D.Double(p.x, p.y);
|
||||
}
|
||||
|
||||
// they did not pick a vertex to center, so
|
||||
// just center the graph
|
||||
// they did not pick a vertex to center, so just center the graph
|
||||
Point2D center = viewer.getCenter();
|
||||
Point p = Point.of(center.getX(), center.getY());
|
||||
return new Point2D.Double(p.x, p.y);
|
||||
|
@ -1057,9 +1045,16 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
}
|
||||
});
|
||||
|
||||
// We control tooltips with the PopupRegulator. Use null values to disable the default
|
||||
// tool tip mechanism
|
||||
vv.setVertexToolTipFunction(v -> null);
|
||||
vv.setEdgeToolTipFunction(e -> null);
|
||||
vv.setToolTipText(null);
|
||||
|
||||
PopupSource<AttributedVertex, AttributedEdge> popupSource = new GraphDisplayPopupSource(vv);
|
||||
popupRegulator = new PopupRegulator<>(popupSource);
|
||||
|
||||
this.iconCache = new GhidraIconCache();
|
||||
vv.setVertexToolTipFunction(AttributedVertex::getHtmlString);
|
||||
vv.setEdgeToolTipFunction(AttributedEdge::getHtmlString);
|
||||
RenderContext<AttributedVertex, AttributedEdge> renderContext = vv.getRenderContext();
|
||||
|
||||
// set up the shape and color functions
|
||||
|
@ -1098,7 +1093,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
renderContext.setArrowFillPaintFunction(
|
||||
e -> renderContext.getSelectedEdgeState().isSelected(e) ? Color.red
|
||||
: Colors.getColor(e));
|
||||
vv.setToolTipText("");
|
||||
|
||||
// assign the shapes to the modal renderer
|
||||
ModalRenderer<AttributedVertex, AttributedEdge> modalRenderer = vv.getRenderer();
|
||||
|
@ -1191,13 +1185,13 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
|
||||
public ActionContext getActionContext(MouseEvent e) {
|
||||
|
||||
AttributedVertex pickedVertex = graphMouse.getPickedVertex(e);
|
||||
AttributedVertex pickedVertex = JgtUtils.getVertex(e, viewer);
|
||||
if (pickedVertex != null) {
|
||||
return new VertexGraphActionContext(componentProvider, graph, getSelectedVertices(),
|
||||
focusedVertex, pickedVertex);
|
||||
}
|
||||
|
||||
AttributedEdge pickedEdge = graphMouse.getPickedEdge(e);
|
||||
AttributedEdge pickedEdge = JgtUtils.getEdge(e, viewer);
|
||||
if (pickedEdge != null) {
|
||||
return new EdgeGraphActionContext(componentProvider, graph, getSelectedVertices(),
|
||||
focusedVertex, pickedEdge);
|
||||
|
@ -1208,7 +1202,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Use the hide selected action states to determine what vertices are shown:
|
||||
* <ul>
|
||||
|
@ -1261,4 +1254,135 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||
});
|
||||
}
|
||||
|
||||
// class passed to the PopupRegulator to help construct info popups for the graph
|
||||
private class GraphDisplayPopupSource implements PopupSource<AttributedVertex, AttributedEdge> {
|
||||
|
||||
private VisualizationViewer<AttributedVertex, AttributedEdge> vv;
|
||||
|
||||
public GraphDisplayPopupSource(VisualizationViewer<AttributedVertex, AttributedEdge> vv) {
|
||||
this.vv = vv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ToolTipInfo<?> getToolTipInfo(MouseEvent event) {
|
||||
|
||||
// check for a vertex hit first, otherwise, we get edge hits when we are hovering
|
||||
// over a vertex, due to how edges are interpreted as existing all the way to the
|
||||
// center point of a vertex
|
||||
AttributedVertex vertex = getVertex(event);
|
||||
if (vertex != null) {
|
||||
return new VertexToolTipInfo(vertex, event);
|
||||
}
|
||||
|
||||
AttributedEdge edge = getEdge(event);
|
||||
if (edge != null) {
|
||||
return new EdgeToolTipInfo(edge, event);
|
||||
}
|
||||
|
||||
// no vertex or edge hit; just create a basic info that is essentially a null-object
|
||||
// placeholder to prevent NPEs
|
||||
return new VertexToolTipInfo(vertex, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributedVertex getVertex(MouseEvent event) {
|
||||
|
||||
LayoutModel<AttributedVertex> layoutModel =
|
||||
vv.getVisualizationModel().getLayoutModel();
|
||||
Point2D p = vv.getTransformSupport().inverseTransform(vv, event.getPoint());
|
||||
AttributedVertex vertex =
|
||||
vv.getPickSupport().getVertex(layoutModel, p.getX(), p.getY());
|
||||
return vertex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributedEdge getEdge(MouseEvent event) {
|
||||
LayoutModel<AttributedVertex> layoutModel =
|
||||
vv.getVisualizationModel().getLayoutModel();
|
||||
Point2D p = vv.getTransformSupport().inverseTransform(vv, event.getPoint());
|
||||
AttributedEdge edge = vv.getPickSupport().getEdge(layoutModel, p.getX(), p.getY());
|
||||
return edge;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMouseMotionListener(MouseMotionListener l) {
|
||||
vv.getComponent().addMouseMotionListener(l);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void repaint() {
|
||||
vv.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Window getPopupParent() {
|
||||
return WindowUtilities.windowForComponent(vv.getComponent());
|
||||
}
|
||||
}
|
||||
|
||||
private class VertexToolTipInfo extends ToolTipInfo<AttributedVertex> {
|
||||
|
||||
VertexToolTipInfo(AttributedVertex vertex, MouseEvent event) {
|
||||
super(event, vertex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JComponent createToolTipComponent() {
|
||||
if (graphObject == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String toolTip = graphObject.getHtmlString();
|
||||
if (StringUtils.isBlank(toolTip)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JToolTip jToolTip = new JToolTip();
|
||||
jToolTip.setTipText(toolTip);
|
||||
return jToolTip;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void emphasize() {
|
||||
// this graph display does not have a notion of emphasizing
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deEmphasize() {
|
||||
// this graph display does not have a notion of emphasizing
|
||||
}
|
||||
}
|
||||
|
||||
private class EdgeToolTipInfo extends ToolTipInfo<AttributedEdge> {
|
||||
|
||||
EdgeToolTipInfo(AttributedEdge edge, MouseEvent event) {
|
||||
super(event, edge);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createToolTipComponent() {
|
||||
if (graphObject == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String toolTip = graphObject.getHtmlString();
|
||||
if (StringUtils.isBlank(toolTip)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JToolTip jToolTip = new JToolTip();
|
||||
jToolTip.setTipText(toolTip);
|
||||
return jToolTip;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void emphasize() {
|
||||
// this graph display does not have a notion of emphasizing
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deEmphasize() {
|
||||
// this graph display does not have a notion of emphasizing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.options.PreferenceState;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.service.graph.GraphDisplay;
|
||||
import ghidra.service.graph.GraphDisplayProvider;
|
||||
|
@ -28,10 +29,14 @@ import ghidra.util.task.TaskMonitor;
|
|||
|
||||
public class DefaultGraphDisplayProvider implements GraphDisplayProvider {
|
||||
|
||||
private static final String PREFERENCES_KEY = "GRAPH_DISPLAY_SERVICE";
|
||||
private static final String DEFAULT_SATELLITE_STATE = "DEFAULT_SATELLITE_STATE";
|
||||
private final Set<DefaultGraphDisplay> displays = new HashSet<>();
|
||||
private PluginTool pluginTool;
|
||||
private Options options;
|
||||
private int displayCounter = 1;
|
||||
private boolean defaultSatelliteState;
|
||||
private PreferenceState preferences;
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
|
@ -66,6 +71,12 @@ public class DefaultGraphDisplayProvider implements GraphDisplayProvider {
|
|||
public void initialize(PluginTool tool, Options graphOptions) {
|
||||
this.pluginTool = tool;
|
||||
this.options = graphOptions;
|
||||
preferences = pluginTool.getWindowManager().getPreferenceState(PREFERENCES_KEY);
|
||||
if (preferences == null) {
|
||||
preferences = new PreferenceState();
|
||||
pluginTool.getWindowManager().putPreferenceState(PREFERENCES_KEY, preferences);
|
||||
}
|
||||
defaultSatelliteState = preferences.getBoolean(DEFAULT_SATELLITE_STATE, false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,4 +116,14 @@ public class DefaultGraphDisplayProvider implements GraphDisplayProvider {
|
|||
displays.remove(defaultGraphDisplay);
|
||||
}
|
||||
|
||||
boolean getDefaultSatelliteState() {
|
||||
return defaultSatelliteState;
|
||||
}
|
||||
|
||||
void setDefaultSatelliteState(boolean b) {
|
||||
defaultSatelliteState = b;
|
||||
preferences.putBoolean(DEFAULT_SATELLITE_STATE, b);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,311 @@
|
|||
/* ###
|
||||
* 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.graph.visualization.mouse;
|
||||
|
||||
import java.awt.Cursor;
|
||||
import java.awt.event.*;
|
||||
|
||||
import org.jungrapht.visualization.SatelliteVisualizationViewer;
|
||||
import org.jungrapht.visualization.VisualizationViewer;
|
||||
import org.jungrapht.visualization.control.AbstractGraphMousePlugin;
|
||||
import org.jungrapht.visualization.selection.MutableSelectedState;
|
||||
|
||||
/**
|
||||
* Graph mouse plugin base class.
|
||||
*
|
||||
* Usage Notes:
|
||||
* <ul>
|
||||
* <li>We clear state on mouseReleased() and mouseExited(), since we will get
|
||||
* at least one of those calls</li>
|
||||
* </ul>
|
||||
* @param <V> the vertex type
|
||||
* @param <E> the edge type
|
||||
*/
|
||||
//@formatter:off
|
||||
public abstract class AbstractJgtGraphMousePlugin<V, E>
|
||||
extends AbstractGraphMousePlugin
|
||||
implements MouseListener, MouseMotionListener {
|
||||
//@formatter:on
|
||||
|
||||
protected boolean isHandlingMouseEvents;
|
||||
|
||||
protected V selectedVertex;
|
||||
protected E selectedEdge;
|
||||
|
||||
public AbstractJgtGraphMousePlugin() {
|
||||
this(InputEvent.BUTTON1_DOWN_MASK);
|
||||
}
|
||||
|
||||
public AbstractJgtGraphMousePlugin(int selectionModifiers) {
|
||||
super(selectionModifiers);
|
||||
}
|
||||
|
||||
public VisualizationViewer<V, E> getViewer(MouseEvent e) {
|
||||
VisualizationViewer<V, E> viewer = getGraphViewer(e);
|
||||
return viewer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <b>primary/master</b> graph viewer.
|
||||
*
|
||||
* @param e the mouse event from which to get the viewer
|
||||
* @return the viewer
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public VisualizationViewer<V, E> getGraphViewer(MouseEvent e) {
|
||||
VisualizationViewer<V, E> viewer = (VisualizationViewer<V, E>) e.getSource();
|
||||
|
||||
// is this the satellite viewer?
|
||||
if (viewer instanceof SatelliteVisualizationViewer) {
|
||||
return ((SatelliteVisualizationViewer<V, E>) viewer).getMaster();
|
||||
}
|
||||
|
||||
return viewer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the satellite graph viewer. This assumes that the mouse event originated from
|
||||
* the satellite viewer.
|
||||
*
|
||||
* @param e the mouse event from which to get the viewer
|
||||
* @return the viewer
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public SatelliteVisualizationViewer<V, E> getSatelliteGraphViewer(MouseEvent e) {
|
||||
|
||||
VisualizationViewer<V, E> viewer = (VisualizationViewer<V, E>) e.getSource();
|
||||
|
||||
// is this the satellite viewer?
|
||||
if (viewer instanceof SatelliteVisualizationViewer) {
|
||||
return (SatelliteVisualizationViewer<V, E>) viewer;
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Do not have a satellite GraphViewer");
|
||||
}
|
||||
|
||||
/**
|
||||
* Signals to perform any cleanup when this plugin is going away
|
||||
*/
|
||||
public void dispose() {
|
||||
// stub
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given mouse event to see if it is a valid event for selecting a vertex at the
|
||||
* mouse location. If so, then the vertex is selected in this mouse handler and the event
|
||||
* is consumed.
|
||||
* @param e the event
|
||||
* @return true if a vertex was selected
|
||||
*/
|
||||
protected boolean checkForVertex(MouseEvent e) {
|
||||
if (!checkModifiers(e)) {
|
||||
selectedVertex = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
VisualizationViewer<V, E> vv = getViewer(e);
|
||||
selectedVertex = JgtUtils.getVertex(e, vv);
|
||||
if (selectedVertex == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
e.consume();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the given mouse event to see if it is a valid event for selecting an edge at the
|
||||
* mouse location. If so, then the edge is selected in this mouse handler and the event
|
||||
* is consumed.
|
||||
* @param e the event
|
||||
* @return true if an edge was selected
|
||||
*/
|
||||
protected boolean checkForEdge(MouseEvent e) {
|
||||
if (!checkModifiers(e) || isOverVertex(e)) {
|
||||
selectedEdge = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
VisualizationViewer<V, E> vv = getViewer(e);
|
||||
selectedEdge = JgtUtils.getEdge(e, vv);
|
||||
if (selectedEdge == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
e.consume();
|
||||
isHandlingMouseEvents = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the given vertex
|
||||
* @param vertex the vertex
|
||||
* @param viewer the graph viewer
|
||||
* @return true if the vertex is selected
|
||||
*/
|
||||
protected boolean selectVertex(V vertex, VisualizationViewer<V, E> viewer) {
|
||||
MutableSelectedState<V> selectedVertexState = viewer.getSelectedVertexState();
|
||||
if (selectedVertexState == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
selectedVertexState.isSelected(vertex);
|
||||
|
||||
if (selectedVertexState.isSelected(vertex) == false) {
|
||||
selectedVertexState.clear();
|
||||
selectedVertexState.select(vertex, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the given edge
|
||||
* @param edge the edge
|
||||
* @param viewer the graph viewer
|
||||
* @return true if the edge is selected
|
||||
*/
|
||||
protected boolean selectEdge(E edge, VisualizationViewer<V, E> viewer) {
|
||||
|
||||
MutableSelectedState<E> selectedVertexState = viewer.getSelectedEdgeState();
|
||||
if (selectedVertexState == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
selectedVertexState.isSelected(edge);
|
||||
|
||||
if (selectedVertexState.isSelected(edge) == false) {
|
||||
selectedVertexState.clear();
|
||||
selectedVertexState.select(edge, true);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the location of the mouse event is over a vertex
|
||||
* @param e the event
|
||||
* @return true if the location of the mouse event is over a vertex
|
||||
*/
|
||||
protected boolean isOverVertex(MouseEvent e) {
|
||||
return getVertex(e) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the vertex if the mouse event is over a vertex
|
||||
* @param e the event
|
||||
* @return a vertex or null
|
||||
*/
|
||||
protected V getVertex(MouseEvent e) {
|
||||
VisualizationViewer<V, E> viewer = getViewer(e);
|
||||
return JgtUtils.getVertex(e, viewer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the location of the mouse event is over a edge
|
||||
* @param e the event
|
||||
* @return true if the location of the mouse event is over a edge
|
||||
*/
|
||||
protected boolean isOverEdge(MouseEvent e) {
|
||||
VisualizationViewer<V, E> viewer = getViewer(e);
|
||||
E edge = JgtUtils.getEdge(e, viewer);
|
||||
if (edge == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !isOverVertex(e);
|
||||
}
|
||||
|
||||
protected void installCursor(Cursor newCursor, MouseEvent e) {
|
||||
VisualizationViewer<V, E> viewer = getViewer(e);
|
||||
viewer.setCursor(newCursor);
|
||||
}
|
||||
|
||||
protected boolean shouldShowCursor(MouseEvent e) {
|
||||
return isOverVertex(e); // to showing cursor over vertices
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (!checkModifiers(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// override this method to do stuff
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (!isHandlingMouseEvents) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.consume();
|
||||
resetState();
|
||||
}
|
||||
|
||||
protected void resetState() {
|
||||
isHandlingMouseEvents = false;
|
||||
selectedVertex = null;
|
||||
selectedEdge = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
if (!isHandlingMouseEvents) {
|
||||
return;
|
||||
}
|
||||
|
||||
e.consume();
|
||||
resetState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
if (isHandlingMouseEvents) {
|
||||
e.consume();
|
||||
}
|
||||
|
||||
// only "turn on" the cursor; resetting is handled elsewhere (in the mouse driver)
|
||||
if (shouldShowCursor(e)) {
|
||||
installCursor(cursor, e);
|
||||
e.consume();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
if (isHandlingMouseEvents) {
|
||||
e.consume();
|
||||
}
|
||||
|
||||
if (shouldShowCursor(e)) {
|
||||
installCursor(cursor, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
if (shouldShowCursor(e)) {
|
||||
installCursor(cursor, e);
|
||||
e.consume();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {
|
||||
installCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR), e);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/* ###
|
||||
* 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.graph.visualization.mouse;
|
||||
|
||||
import java.awt.Cursor;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
|
||||
import org.jungrapht.visualization.VisualizationViewer;
|
||||
import org.jungrapht.visualization.control.AbstractGraphMousePlugin;
|
||||
|
||||
/**
|
||||
* Restores the cursor after other graph mouse operations.
|
||||
*
|
||||
* Future: this is copied from the Visual Graph counterpart--consolidate these
|
||||
*
|
||||
* @param <V> the vertex type
|
||||
* @param <E> the edge type
|
||||
*/
|
||||
public class JgtCursorRestoringPlugin<V, E> extends AbstractGraphMousePlugin
|
||||
implements MouseMotionListener {
|
||||
|
||||
public JgtCursorRestoringPlugin() {
|
||||
super(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
// don't care
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
installCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR), e);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void installCursor(Cursor newCursor, MouseEvent e) {
|
||||
VisualizationViewer<V, E> viewer = (VisualizationViewer<V, E>) e.getSource();
|
||||
viewer.setCursor(newCursor);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,113 @@
|
|||
/* ###
|
||||
* 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.graph.visualization.mouse;
|
||||
|
||||
import java.awt.Cursor;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
import org.jgrapht.Graph;
|
||||
import org.jungrapht.visualization.VisualizationViewer;
|
||||
import org.jungrapht.visualization.layout.model.Point;
|
||||
import org.jungrapht.visualization.selection.MutableSelectedState;
|
||||
|
||||
import ghidra.graph.visualization.CenterAnimationJob;
|
||||
|
||||
/**
|
||||
* Mouse plugin to allow for edge navigation
|
||||
*
|
||||
* @param <V> the vertex type
|
||||
* @param <E> the edge type
|
||||
*/
|
||||
public class JgtEdgeNavigationPlugin<V, E> extends AbstractJgtGraphMousePlugin<V, E> {
|
||||
|
||||
public JgtEdgeNavigationPlugin() {
|
||||
this.cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (!checkModifiers(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.getClickCount() != 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkForEdge(e); // this will select an edge if we can and store off the edge
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (!isHandlingMouseEvents) {
|
||||
return;
|
||||
}
|
||||
|
||||
E edge = selectedEdge; // save off before we reset
|
||||
e.consume();
|
||||
resetState();
|
||||
|
||||
// on double-clicks we go to the vertex in the current edge direction unless that vertex
|
||||
// is already selected, then we go to the other vertex
|
||||
VisualizationViewer<V, E> viewer = getViewer(e);
|
||||
MutableSelectedState<V> selectedState = viewer.getSelectedVertexState();
|
||||
|
||||
Graph<V, E> graph = viewer.getVisualizationModel().getGraph();
|
||||
V end = graph.getEdgeTarget(edge);
|
||||
if (!selectedState.isSelected(end)) {
|
||||
pickAndShowVertex(end, selectedState, viewer);
|
||||
return;
|
||||
}
|
||||
|
||||
// the destination was picked, go the other direction
|
||||
V source = graph.getEdgeSource(edge);
|
||||
pickAndShowVertex(source, selectedState, viewer);
|
||||
}
|
||||
|
||||
private void pickAndShowVertex(V vertex, MutableSelectedState<V> selectedVertexState,
|
||||
VisualizationViewer<V, E> viewer) {
|
||||
|
||||
// TODO animate; this requires a single view updater
|
||||
Point2D existingCenter = viewer.getRenderContext()
|
||||
.getMultiLayerTransformer()
|
||||
.inverseTransform(viewer.getCenter());
|
||||
Point vp = viewer.getVisualizationModel().getLayoutModel().get(vertex);
|
||||
Point2D newCenter = new Point2D.Double(vp.x, vp.y);
|
||||
CenterAnimationJob job = new CenterAnimationJob(viewer, existingCenter, newCenter);
|
||||
job.finished();
|
||||
|
||||
selectedVertexState.clear();
|
||||
selectedVertexState.select(vertex);
|
||||
|
||||
/*
|
||||
VisualGraphViewUpdater<V, E> updater = viewer.getViewUpdater();
|
||||
updater.moveVertexToCenterWithAnimation(vertex, isBusy -> {
|
||||
|
||||
// pick the vertex after the animation has run
|
||||
if (!isBusy) {
|
||||
GPickedState<V> pickedStateWrapper = (GPickedState<V>) selectedVertexState;
|
||||
pickedStateWrapper.pickToActivate(vertex);
|
||||
}
|
||||
});
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean shouldShowCursor(MouseEvent e) {
|
||||
return isOverEdge(e);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/* ###
|
||||
* 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.graph.visualization.mouse;
|
||||
|
||||
import java.awt.event.InputEvent;
|
||||
|
||||
import org.jungrapht.visualization.control.*;
|
||||
|
||||
import docking.DockingUtils;
|
||||
import ghidra.graph.visualization.DefaultGraphDisplay;
|
||||
import ghidra.service.graph.AttributedEdge;
|
||||
import ghidra.service.graph.AttributedVertex;
|
||||
|
||||
/**
|
||||
* Pluggable graph mouse for jungrapht
|
||||
*/
|
||||
public class JgtPluggableGraphMouse extends DefaultGraphMouse<AttributedVertex, AttributedEdge> {
|
||||
|
||||
private DefaultGraphDisplay graphDisplay;
|
||||
|
||||
// TODO we should not need the graph display for any mouse plugins, but the API is net yet
|
||||
// robust enough to communicate fully without it
|
||||
public JgtPluggableGraphMouse(DefaultGraphDisplay graphDisplay) {
|
||||
super(DefaultGraphMouse.<AttributedVertex, AttributedEdge> builder());
|
||||
this.graphDisplay = graphDisplay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadPlugins() {
|
||||
|
||||
//
|
||||
// Note: the order of these additions matters, as an event will flow to each plugin until
|
||||
// it is handled.
|
||||
//
|
||||
|
||||
// edge
|
||||
add(new JgtEdgeNavigationPlugin<AttributedVertex, AttributedEdge>());
|
||||
|
||||
add(new JgtVertexFocusingPlugin<AttributedVertex, AttributedEdge>(graphDisplay));
|
||||
|
||||
// scaling
|
||||
add(new ScalingGraphMousePlugin(new CrossoverScalingControl(), 0, in, out));
|
||||
|
||||
// the grab/pan feature
|
||||
add(new JgtTranslatingPlugin<AttributedVertex, AttributedEdge>());
|
||||
|
||||
add(new SelectingGraphMousePlugin<AttributedVertex, AttributedEdge>(
|
||||
InputEvent.BUTTON1_DOWN_MASK,
|
||||
0,
|
||||
DockingUtils.CONTROL_KEY_MODIFIER_MASK));
|
||||
|
||||
// cursor cleanup
|
||||
add(new JgtCursorRestoringPlugin<AttributedVertex, AttributedEdge>());
|
||||
|
||||
setPluginsLoaded();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
/* ###
|
||||
* 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.graph.visualization.mouse;
|
||||
|
||||
import java.awt.Cursor;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
import org.jungrapht.visualization.*;
|
||||
import org.jungrapht.visualization.MultiLayerTransformer.Layer;
|
||||
import org.jungrapht.visualization.control.TranslatingGraphMousePlugin;
|
||||
import org.jungrapht.visualization.transform.MutableTransformer;
|
||||
|
||||
/**
|
||||
* Note: this class is based on {@link TranslatingGraphMousePlugin}.
|
||||
* <p>
|
||||
* TranslatingGraphMousePlugin uses a MouseButtonOne press and drag gesture to translate
|
||||
* the graph display in the x and y direction. The default MouseButtonOne modifier can be overridden
|
||||
* to cause a different mouse gesture to translate the display.
|
||||
*
|
||||
* @param <V> the vertex type
|
||||
* @param <E> the edge type
|
||||
*/
|
||||
public class JgtTranslatingPlugin<V, E>
|
||||
extends AbstractJgtGraphMousePlugin<V, E> {
|
||||
|
||||
private boolean panning;
|
||||
private boolean isHandlingEvent;
|
||||
|
||||
public JgtTranslatingPlugin() {
|
||||
this(InputEvent.BUTTON1_DOWN_MASK);
|
||||
}
|
||||
|
||||
public JgtTranslatingPlugin(int modifiers) {
|
||||
super(modifiers);
|
||||
this.cursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
boolean accepted = checkModifiers(e) && isInDraggingArea(e);
|
||||
if (!accepted) {
|
||||
return;
|
||||
}
|
||||
|
||||
down = e.getPoint();
|
||||
VisualizationViewer<V, E> viewer = getGraphViewer(e);
|
||||
viewer.setCursor(cursor);
|
||||
isHandlingEvent = true;
|
||||
e.consume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
boolean wasHandlingEvent = isHandlingEvent;
|
||||
isHandlingEvent = false;
|
||||
down = null;
|
||||
installCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR), e);
|
||||
|
||||
// NOTE: we are only consuming the event here if we actually did pan...this allows follow-on
|
||||
// mouse handlers to process the mouseReleased() event. This is a bit odd and not the
|
||||
// normal event processing (which is to consume all related events).
|
||||
if (wasHandlingEvent && panning) {
|
||||
e.consume();
|
||||
}
|
||||
|
||||
panning = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
boolean accepted = checkModifiers(e);
|
||||
if (!accepted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isHandlingEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
panning = true;
|
||||
|
||||
VisualizationViewer<V, E> viewer = getGraphViewer(e);
|
||||
RenderContext<V, E> context = viewer.getRenderContext();
|
||||
MultiLayerTransformer multiLayerTransformer = context.getMultiLayerTransformer();
|
||||
MutableTransformer layoutTransformer = multiLayerTransformer.getTransformer(Layer.LAYOUT);
|
||||
viewer.setCursor(cursor);
|
||||
Point2D downPoint = multiLayerTransformer.inverseTransform(down);
|
||||
Point2D p = multiLayerTransformer.inverseTransform(e.getPoint());
|
||||
float dx = (float) (p.getX() - downPoint.getX());
|
||||
float dy = (float) (p.getY() - downPoint.getY());
|
||||
|
||||
layoutTransformer.translate(dx, dy);
|
||||
down.x = e.getX();
|
||||
down.y = e.getY();
|
||||
e.consume();
|
||||
viewer.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
// don't care
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
if (isHandlingEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isInDraggingArea(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!checkModifiersForCursor(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
installCursor(cursor, e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {
|
||||
installCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR), e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
if (!checkModifiersForCursor(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isHandlingEvent) {
|
||||
e.consume();
|
||||
}
|
||||
|
||||
if (isInDraggingArea(e)) {
|
||||
installCursor(cursor, e);
|
||||
e.consume();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkModifiersForCursor(MouseEvent e) {
|
||||
if (e.getModifiersEx() == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Private methods
|
||||
//==================================================================================================
|
||||
|
||||
private boolean isInDraggingArea(MouseEvent e) {
|
||||
return !(isOverVertex(e) || isOverEdge(e));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installCursor(Cursor newCursor, MouseEvent e) {
|
||||
VisualizationViewer<V, E> viewer = getViewer(e);
|
||||
viewer.setCursor(newCursor);
|
||||
}
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package ghidra.graph.visualization;
|
||||
package ghidra.graph.visualization.mouse;
|
||||
|
||||
import static org.jungrapht.visualization.VisualizationServer.*;
|
||||
|
||||
|
@ -22,42 +22,86 @@ import java.awt.geom.Point2D;
|
|||
import java.awt.geom.Rectangle2D;
|
||||
|
||||
import org.jungrapht.visualization.VisualizationViewer;
|
||||
import org.jungrapht.visualization.control.*;
|
||||
import org.jungrapht.visualization.control.GraphElementAccessor;
|
||||
import org.jungrapht.visualization.control.TransformSupport;
|
||||
import org.jungrapht.visualization.layout.model.LayoutModel;
|
||||
import org.jungrapht.visualization.selection.ShapePickSupport;
|
||||
|
||||
import docking.ComponentProvider;
|
||||
import ghidra.service.graph.AttributedEdge;
|
||||
import ghidra.service.graph.AttributedVertex;
|
||||
|
||||
/**
|
||||
* An extension of the jungrapht DefaultGraphMouse. This class has references to
|
||||
* <ul>
|
||||
* <li>a {@link VisualizationViewer} (to access the Graph and LayoutModel)
|
||||
*
|
||||
* Keeper of shared logic for jungrapht handling
|
||||
*/
|
||||
public class GhidraGraphMouse extends DefaultGraphMouse<AttributedVertex, AttributedEdge> {
|
||||
public class JgtUtils {
|
||||
|
||||
private static final String PICK_AREA_SIZE_PROPERTY = PREFIX + "pickAreaSize";
|
||||
|
||||
private VisualizationViewer<AttributedVertex, AttributedEdge> viewer;
|
||||
|
||||
private int pickSize;
|
||||
|
||||
/**
|
||||
* create an instance with default values
|
||||
* @param componentProvider the graph component provider
|
||||
* @param viewer the graph viewer component
|
||||
* Returns the edge under the given mouse event
|
||||
*
|
||||
* @param <V> the vertex type
|
||||
* @param <E> the edge type
|
||||
* @param e the event
|
||||
* @param viewer the graph viewer
|
||||
* @return the edge
|
||||
*/
|
||||
GhidraGraphMouse(ComponentProvider componentProvider,
|
||||
VisualizationViewer<AttributedVertex, AttributedEdge> viewer) {
|
||||
public static <V, E> E getEdge(MouseEvent e, VisualizationViewer<V, E> viewer) {
|
||||
if (e == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
super(DefaultGraphMouse.<AttributedVertex, AttributedEdge> builder());
|
||||
this.viewer = viewer;
|
||||
pickSize = Integer.getInteger(GhidraGraphMouse.PICK_AREA_SIZE_PROPERTY, 4);
|
||||
Rectangle2D footprintRectangle = getFootprint(e);
|
||||
LayoutModel<V> layoutModel = viewer.getVisualizationModel().getLayoutModel();
|
||||
GraphElementAccessor<V, E> pickSupport = viewer.getPickSupport();
|
||||
if (pickSupport == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (pickSupport instanceof ShapePickSupport) {
|
||||
ShapePickSupport<V, E> shapePickSupport =
|
||||
(ShapePickSupport<V, E>) pickSupport;
|
||||
return shapePickSupport.getEdge(layoutModel, footprintRectangle);
|
||||
}
|
||||
|
||||
TransformSupport<V, E> transformSupport =
|
||||
viewer.getTransformSupport();
|
||||
Point2D layoutPoint = transformSupport.inverseTransform(viewer, e.getPoint());
|
||||
return pickSupport.getEdge(layoutModel, layoutPoint.getX(), layoutPoint.getY());
|
||||
}
|
||||
|
||||
private Rectangle2D getFootprint(MouseEvent e) {
|
||||
/**
|
||||
* Returns the vertex under the given mouse event
|
||||
*
|
||||
* @param <V> the vertex type
|
||||
* @param <E> the edge type
|
||||
* @param e the event
|
||||
* @param viewer the graph viewer
|
||||
* @return the vertex
|
||||
*/
|
||||
public static <V, E> V getVertex(MouseEvent e, VisualizationViewer<V, E> viewer) {
|
||||
if (e == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Rectangle2D footprintRectangle = getFootprint(e);
|
||||
LayoutModel<V> layoutModel = viewer.getVisualizationModel().getLayoutModel();
|
||||
GraphElementAccessor<V, E> pickSupport = viewer.getPickSupport();
|
||||
if (pickSupport == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (pickSupport instanceof ShapePickSupport) {
|
||||
ShapePickSupport<V, E> shapePickSupport =
|
||||
(ShapePickSupport<V, E>) pickSupport;
|
||||
return shapePickSupport.getVertex(layoutModel, footprintRectangle);
|
||||
}
|
||||
|
||||
TransformSupport<V, E> transformSupport =
|
||||
viewer.getTransformSupport();
|
||||
Point2D layoutPoint = transformSupport.inverseTransform(viewer, e.getPoint());
|
||||
return pickSupport.getVertex(layoutModel, layoutPoint.getX(), layoutPoint.getY());
|
||||
}
|
||||
|
||||
private static Rectangle2D getFootprint(MouseEvent e) {
|
||||
int pickSize = Integer.getInteger(PICK_AREA_SIZE_PROPERTY, 4);
|
||||
return new Rectangle2D.Float(
|
||||
e.getPoint().x - pickSize / 2f,
|
||||
e.getPoint().y - pickSize / 2f,
|
||||
|
@ -65,44 +109,4 @@ public class GhidraGraphMouse extends DefaultGraphMouse<AttributedVertex, Attrib
|
|||
pickSize);
|
||||
}
|
||||
|
||||
AttributedEdge getPickedEdge(MouseEvent e) {
|
||||
if (e == null) {
|
||||
return null;
|
||||
}
|
||||
Rectangle2D footprintRectangle = getFootprint(e);
|
||||
LayoutModel<AttributedVertex> layoutModel = viewer.getVisualizationModel().getLayoutModel();
|
||||
GraphElementAccessor<AttributedVertex, AttributedEdge> pickSupport =
|
||||
viewer.getPickSupport();
|
||||
if (pickSupport instanceof ShapePickSupport) {
|
||||
ShapePickSupport<AttributedVertex, AttributedEdge> shapePickSupport =
|
||||
(ShapePickSupport<AttributedVertex, AttributedEdge>) pickSupport;
|
||||
return shapePickSupport.getEdge(layoutModel, footprintRectangle);
|
||||
}
|
||||
|
||||
TransformSupport<AttributedVertex, AttributedEdge> transformSupport =
|
||||
viewer.getTransformSupport();
|
||||
Point2D layoutPoint = transformSupport.inverseTransform(viewer, e.getPoint());
|
||||
return pickSupport.getEdge(layoutModel, layoutPoint.getX(), layoutPoint.getY());
|
||||
}
|
||||
|
||||
AttributedVertex getPickedVertex(MouseEvent e) {
|
||||
if (e == null) {
|
||||
return null;
|
||||
}
|
||||
Rectangle2D footprintRectangle = getFootprint(e);
|
||||
LayoutModel<AttributedVertex> layoutModel = viewer.getVisualizationModel().getLayoutModel();
|
||||
GraphElementAccessor<AttributedVertex, AttributedEdge> pickSupport =
|
||||
viewer.getPickSupport();
|
||||
if (pickSupport instanceof ShapePickSupport) {
|
||||
ShapePickSupport<AttributedVertex, AttributedEdge> shapePickSupport =
|
||||
(ShapePickSupport<AttributedVertex, AttributedEdge>) pickSupport;
|
||||
return shapePickSupport.getVertex(layoutModel, footprintRectangle);
|
||||
}
|
||||
|
||||
TransformSupport<AttributedVertex, AttributedEdge> transformSupport =
|
||||
viewer.getTransformSupport();
|
||||
Point2D layoutPoint = transformSupport.inverseTransform(viewer, e.getPoint());
|
||||
return pickSupport.getVertex(layoutModel, layoutPoint.getX(), layoutPoint.getY());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
/* ###
|
||||
* 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.graph.visualization.mouse;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
import ghidra.graph.visualization.DefaultGraphDisplay;
|
||||
import ghidra.service.graph.AttributedVertex;
|
||||
|
||||
/**
|
||||
* A mouse plugin to focus a vertex when clicked
|
||||
*
|
||||
* @param <V> the vertex type
|
||||
* @param <E> the edge type
|
||||
*/
|
||||
public class JgtVertexFocusingPlugin<V, E> extends AbstractJgtGraphMousePlugin<V, E> {
|
||||
|
||||
private DefaultGraphDisplay graphDisplay;
|
||||
|
||||
public JgtVertexFocusingPlugin(DefaultGraphDisplay graphDisplay) {
|
||||
this.graphDisplay = graphDisplay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (!checkModifiers(e)) {
|
||||
return;
|
||||
}
|
||||
|
||||
selectedVertex = getVertex(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
if (selectedVertex == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
graphDisplay.setFocusedVertex((AttributedVertex) selectedVertex);
|
||||
|
||||
// Note: do not consume the event. We will just focus our vertex, regardless of further
|
||||
// mouse event processing.
|
||||
}
|
||||
}
|
|
@ -62,3 +62,10 @@ jungrapht.initialDimensionVertexDensity=0.3f
|
|||
|
||||
jungrapht.minScale=0.001
|
||||
jungrapht.maxScale=1.0
|
||||
|
||||
|
||||
11:45 AM
|
||||
|
||||
# not using spatial data structures for edges (fixed in versions after 1.0)
|
||||
jungrapht.edgeSpatialSupport=NONE
|
||||
jungrapht.vertexSpatialSupport=NONE
|
||||
|
|
|
@ -26,7 +26,6 @@ import ghidra.app.util.opinion.PeLoader;
|
|||
import ghidra.app.util.pdb.PdbLocator;
|
||||
import ghidra.framework.options.OptionType;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.preferences.Preferences;
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.Msg;
|
||||
|
@ -208,15 +207,8 @@ public class PdbAnalyzer extends AbstractAnalyzer {
|
|||
@Override
|
||||
public void registerOptions(Options options, Program program) {
|
||||
|
||||
String pdbStorageLocation =
|
||||
Preferences.getProperty(PdbParser.PDB_STORAGE_PROPERTY, null, true);
|
||||
symbolsRepositoryDir = PdbLocator.getDefaultPdbSymbolsDir();
|
||||
|
||||
if (pdbStorageLocation != null) {
|
||||
File pdbDirectory = new File(pdbStorageLocation);
|
||||
if (pdbDirectory.isDirectory()) {
|
||||
symbolsRepositoryDir = pdbDirectory;
|
||||
}
|
||||
}
|
||||
options.registerOption(SYMBOLPATH_OPTION_NAME, OptionType.FILE_TYPE, symbolsRepositoryDir,
|
||||
null, SYMBOLPATH_OPTION_DESCRIPTION);
|
||||
|
||||
|
@ -227,12 +219,11 @@ public class PdbAnalyzer extends AbstractAnalyzer {
|
|||
@Override
|
||||
public void optionsChanged(Options options, Program program) {
|
||||
|
||||
symbolsRepositoryDir =
|
||||
options.getFile(SYMBOLPATH_OPTION_NAME, PdbLocator.DEFAULT_SYMBOLS_DIR);
|
||||
|
||||
Preferences.setProperty(PdbParser.PDB_STORAGE_PROPERTY,
|
||||
symbolsRepositoryDir != null ? symbolsRepositoryDir.getAbsolutePath() : null);
|
||||
Preferences.store();
|
||||
File symbolsDir = options.getFile(SYMBOLPATH_OPTION_NAME, symbolsRepositoryDir);
|
||||
if (!symbolsDir.equals(symbolsRepositoryDir)) {
|
||||
symbolsRepositoryDir = symbolsDir;
|
||||
PdbLocator.setDefaultPdbSymbolsDir(symbolsDir);
|
||||
}
|
||||
|
||||
includePeSpecifiedPdbPath =
|
||||
options.getBoolean(OPTION_NAME_INCLUDE_PE_PDB_PATH, includePeSpecifiedPdbPath);
|
||||
|
|
|
@ -22,6 +22,7 @@ import java.util.Date;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.app.services.*;
|
||||
//import ghidra.app.util.bin.format.pdb.PdbParser;
|
||||
import ghidra.app.util.bin.format.pdb.PdbParserConstants;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
|
@ -84,7 +85,6 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
|||
private static final String OPTION_NAME_SYMBOLPATH = "Symbol Repository Path";
|
||||
private static final String OPTION_DESCRIPTION_SYMBOLPATH =
|
||||
"Directory path to root of Microsoft Symbol Repository Directory";
|
||||
private File DEFAULT_SYMBOLS_DIR = PdbLocator.DEFAULT_SYMBOLS_DIR;
|
||||
private File symbolsRepositoryDir;
|
||||
|
||||
// Include the PE-Header-Specified PDB path for searching for appropriate PDB file.
|
||||
|
@ -356,14 +356,18 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
|||
|
||||
@Override
|
||||
public void registerOptions(Options options, Program program) {
|
||||
|
||||
symbolsRepositoryDir = PdbLocator.getDefaultPdbSymbolsDir();
|
||||
|
||||
// PDB file location information
|
||||
options.registerOption(OPTION_NAME_DO_FORCELOAD, Boolean.FALSE, null,
|
||||
OPTION_DESCRIPTION_DO_FORCELOAD);
|
||||
options.registerOption(OPTION_NAME_FORCELOAD_FILE, OptionType.FILE_TYPE,
|
||||
DEFAULT_FORCE_LOAD_FILE,
|
||||
null, OPTION_DESCRIPTION_FORCELOAD_FILE);
|
||||
options.registerOption(OPTION_NAME_SYMBOLPATH, OptionType.FILE_TYPE, DEFAULT_SYMBOLS_DIR,
|
||||
null, OPTION_DESCRIPTION_SYMBOLPATH);
|
||||
if (developerMode) {
|
||||
options.registerOption(OPTION_NAME_DO_FORCELOAD, Boolean.FALSE, null,
|
||||
OPTION_DESCRIPTION_DO_FORCELOAD);
|
||||
options.registerOption(OPTION_NAME_FORCELOAD_FILE, OptionType.FILE_TYPE,
|
||||
DEFAULT_FORCE_LOAD_FILE, null, OPTION_DESCRIPTION_FORCELOAD_FILE);
|
||||
}
|
||||
options.registerOption(OPTION_NAME_SYMBOLPATH, OptionType.FILE_TYPE,
|
||||
symbolsRepositoryDir, null, OPTION_DESCRIPTION_SYMBOLPATH);
|
||||
options.registerOption(OPTION_NAME_INCLUDE_PE_PDB_PATH, includePeSpecifiedPdbPath, null,
|
||||
OPTION_DESCRIPTION_INCLUDE_PE_PDB_PATH);
|
||||
|
||||
|
@ -380,9 +384,9 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
|||
|
||||
// PdbApplicatorOptions
|
||||
getPdbApplicatorOptions();
|
||||
options.registerOption(OPTION_NAME_PROCESSING_RESTRICTIONS, restrictions, null,
|
||||
OPTION_DESCRIPTION_PROCESSING_RESTRICTIONS);
|
||||
if (developerMode) {
|
||||
options.registerOption(OPTION_NAME_PROCESSING_RESTRICTIONS, restrictions, null,
|
||||
OPTION_DESCRIPTION_PROCESSING_RESTRICTIONS);
|
||||
options.registerOption(OPTION_NAME_APPLY_CODE_SCOPE_BLOCK_COMMENTS,
|
||||
applyCodeScopeBlockComments, null,
|
||||
OPTION_DESCRIPTION_APPLY_CODE_SCOPE_BLOCK_COMMENTS);
|
||||
|
@ -414,11 +418,16 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
|||
@Override
|
||||
public void optionsChanged(Options options, Program program) {
|
||||
|
||||
doForceLoad = options.getBoolean(OPTION_NAME_DO_FORCELOAD, doForceLoad);
|
||||
if (developerMode) {
|
||||
doForceLoad = options.getBoolean(OPTION_NAME_DO_FORCELOAD, doForceLoad);
|
||||
forceLoadFile = options.getFile(OPTION_NAME_FORCELOAD_FILE, forceLoadFile);
|
||||
}
|
||||
|
||||
forceLoadFile = options.getFile(OPTION_NAME_FORCELOAD_FILE, forceLoadFile);
|
||||
|
||||
symbolsRepositoryDir = options.getFile(OPTION_NAME_SYMBOLPATH, DEFAULT_SYMBOLS_DIR);
|
||||
File symbolsDir = options.getFile(OPTION_NAME_SYMBOLPATH, symbolsRepositoryDir);
|
||||
if (!symbolsDir.equals(symbolsRepositoryDir)) {
|
||||
symbolsRepositoryDir = symbolsDir;
|
||||
PdbLocator.setDefaultPdbSymbolsDir(symbolsDir);
|
||||
}
|
||||
|
||||
includePeSpecifiedPdbPath =
|
||||
options.getBoolean(OPTION_NAME_INCLUDE_PE_PDB_PATH, includePeSpecifiedPdbPath);
|
||||
|
@ -434,8 +443,8 @@ public class PdbUniversalAnalyzer extends AbstractAnalyzer {
|
|||
setPdbReaderOptions();
|
||||
|
||||
// PdbApplicatorOptions
|
||||
restrictions = options.getEnum(OPTION_NAME_PROCESSING_RESTRICTIONS, restrictions);
|
||||
if (developerMode) {
|
||||
restrictions = options.getEnum(OPTION_NAME_PROCESSING_RESTRICTIONS, restrictions);
|
||||
applyCodeScopeBlockComments = options.getBoolean(
|
||||
OPTION_NAME_APPLY_CODE_SCOPE_BLOCK_COMMENTS, applyCodeScopeBlockComments);
|
||||
// Mechanism to apply instruction labels is not yet implemented-> does nothing
|
||||
|
|
|
@ -54,8 +54,6 @@ public class PdbParser {
|
|||
private static final String README_FILENAME =
|
||||
Application.getInstallationDirectory() + "\\docs\\README_PDB.html";
|
||||
|
||||
public final static String PDB_STORAGE_PROPERTY = "PDB Storage Directory";
|
||||
|
||||
static final String STRUCTURE_KIND = "Structure";
|
||||
static final String UNION_KIND = "Union";
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ import ghidra.app.util.importer.LibrarySearchPathManager;
|
|||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.framework.OperatingSystem;
|
||||
import ghidra.framework.Platform;
|
||||
import ghidra.framework.preferences.Preferences;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.SystemUtilities;
|
||||
|
@ -79,6 +80,8 @@ public class PdbLocator {
|
|||
public final static File WINDOWS_SYMBOLS_DIR =
|
||||
onWindows ? new File("C:/WINDOWS/Symbols") : null;
|
||||
|
||||
public final static String PDB_SYMBOLS_DIR_PREFERENCE = "PDB Storage Directory";
|
||||
|
||||
private File symbolsRepositoryDir;
|
||||
/**
|
||||
* Only holds identifies in PDBs up until a matching one was found--nothing beyond that.
|
||||
|
@ -677,4 +680,21 @@ public class PdbLocator {
|
|||
return true;
|
||||
}
|
||||
|
||||
public static File getDefaultPdbSymbolsDir() {
|
||||
String pdbStorageLocation = Preferences.getProperty(PDB_SYMBOLS_DIR_PREFERENCE, null, true);
|
||||
File defaultSymbolsDir = DEFAULT_SYMBOLS_DIR;
|
||||
if (pdbStorageLocation != null) {
|
||||
File pdbDirectory = new File(pdbStorageLocation);
|
||||
if (pdbDirectory.isDirectory()) {
|
||||
defaultSymbolsDir = pdbDirectory;
|
||||
}
|
||||
}
|
||||
return defaultSymbolsDir;
|
||||
}
|
||||
|
||||
public static void setDefaultPdbSymbolsDir(File symbolsDir) {
|
||||
Preferences.setProperty(PDB_SYMBOLS_DIR_PREFERENCE, symbolsDir.getAbsolutePath());
|
||||
Preferences.store();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -59,6 +59,10 @@ public abstract class AbstractComplexTypeApplier extends MsTypeApplier {
|
|||
return ((AbstractComplexMsType) msType).getMsProperty().isForwardReference();
|
||||
}
|
||||
|
||||
boolean isNested() {
|
||||
return ((AbstractComplexMsType) msType).getMsProperty().isNestedClass();
|
||||
}
|
||||
|
||||
boolean isFinal() {
|
||||
return ((AbstractComplexMsType) msType).getMsProperty().isSealed();
|
||||
}
|
||||
|
|
|
@ -135,7 +135,15 @@ public class CompositeTypeApplier extends AbstractComplexTypeApplier {
|
|||
|
||||
@Override
|
||||
void resolve() {
|
||||
if (!isForwardReference()) {
|
||||
|
||||
// NOTE: Until we know better we do not want to explicitly
|
||||
// apply nested composite datatypes and allow them to be
|
||||
// created as-needed (e.g., function definition). This is
|
||||
// done to minimize duplication of anonymous/unnamed nested
|
||||
// composites since the parent composite reconsruction performed
|
||||
// by DefaultCompositeMember will generate such nested composites.
|
||||
|
||||
if (!isForwardReference() && !isNested()) {
|
||||
super.resolve();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -112,9 +112,9 @@ public class TypeApplierFactory {
|
|||
applier =
|
||||
new MemberFunctionTypeApplier(applicator, (MemberFunction16MsType) type);
|
||||
break;
|
||||
case VtShapeMsType.PDB_ID:
|
||||
applier = new VtShapeTypeApplier(applicator, (VtShapeMsType) type);
|
||||
break;
|
||||
// case VtShapeMsType.PDB_ID:
|
||||
// applier = new VtShapeTypeApplier(applicator, (VtShapeMsType) type);
|
||||
// break;
|
||||
// case Cobol016MsType.PDB_ID:
|
||||
// // Not evaluated/implemented yet.
|
||||
// break;
|
||||
|
|
|
@ -35,6 +35,7 @@ import ghidra.app.services.DataTypeManagerService;
|
|||
import ghidra.app.util.bin.format.pdb.PdbException;
|
||||
import ghidra.app.util.bin.format.pdb.PdbParser;
|
||||
import ghidra.app.util.bin.format.pdb.PdbParser.PdbFileType;
|
||||
import ghidra.app.util.pdb.PdbLocator;
|
||||
import ghidra.app.util.pdb.PdbProgramAttributes;
|
||||
import ghidra.app.util.pdb.pdbapplicator.PdbApplicatorRestrictions;
|
||||
import ghidra.framework.Application;
|
||||
|
@ -399,16 +400,7 @@ public class PdbSymbolServerPlugin extends Plugin {
|
|||
testDirectory = localDir;
|
||||
}
|
||||
else {
|
||||
String userHome = System.getProperty("user.home");
|
||||
|
||||
String storedLocalDir =
|
||||
Preferences.getProperty(PdbParser.PDB_STORAGE_PROPERTY, userHome, true);
|
||||
|
||||
testDirectory = new File(storedLocalDir);
|
||||
|
||||
if (!testDirectory.exists()) {
|
||||
testDirectory = new File(userHome);
|
||||
}
|
||||
testDirectory = PdbLocator.getDefaultPdbSymbolsDir();
|
||||
}
|
||||
|
||||
final File storedDirectory = testDirectory;
|
||||
|
@ -444,7 +436,7 @@ public class PdbSymbolServerPlugin extends Plugin {
|
|||
throw new CancelledException();
|
||||
}
|
||||
|
||||
Preferences.setProperty(PdbParser.PDB_STORAGE_PROPERTY, chosenDir[0].getAbsolutePath());
|
||||
PdbLocator.setDefaultPdbSymbolsDir(chosenDir[0]);
|
||||
|
||||
return chosenDir[0];
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<BODY lang="EN-US">
|
||||
<H1>Graphing the Program</H1>
|
||||
|
||||
<H3>Graph Output</H3>
|
||||
<H2>Graph Output</H2>
|
||||
|
||||
<P>To display or export a graph, Ghidra supports multiple graph services. Ghidra has two
|
||||
built-in graph services; one to display a graph and one to export a graph. Before invoking
|
||||
|
@ -21,7 +21,7 @@
|
|||
will direct the output of the graph function to the active graph service. To select a graph
|
||||
service, use the <B>Graph<IMG src="../../shared/arrow.gif">Graph Output</B></LI> menu.
|
||||
|
||||
<H3>Graph types</H3>
|
||||
<H2>Graph types</H2>
|
||||
<P>Program control flow Graphs can be created and then shown using an appropriate graph service.
|
||||
A control flow graph is a representation of the flow from one portion of the code to
|
||||
another. The nodes of the graph represent blocks of code and the edges represent flow between
|
||||
|
@ -49,7 +49,7 @@
|
|||
<P>Selection and Location events are synchronized between each
|
||||
graph and the other windows in the tool.
|
||||
|
||||
<H3>Selection</H3>
|
||||
<H2>Selection</H2>
|
||||
|
||||
<P>The current selection within the graph display is represented by a red box around selected
|
||||
nodes as shown below on the node labeled "00408133". A node is selected if any addresses it represents are contained within the
|
||||
|
@ -74,7 +74,7 @@
|
|||
from the basic blocks found within the selected subroutine.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3>Location</H3>
|
||||
<H2>Location</H2>
|
||||
|
||||
<P>The node containing the current address location is marked with a large red arrow as shown
|
||||
below on the graph node labeled "00408133".</P>
|
||||
|
@ -95,7 +95,7 @@
|
|||
current address location within Ghidra to change to the minimum address represented by the
|
||||
graph node.</P>
|
||||
|
||||
<H3>Graph Representation</H3>
|
||||
<H2>Graph Representation</H2>
|
||||
|
||||
<P>By Default, the graphs use the following icons and colors to represent the nodes and edges.</P>
|
||||
|
||||
|
@ -220,99 +220,7 @@
|
|||
</DIV>
|
||||
</CENTER>
|
||||
|
||||
<H2><A name="Graph_Block_Flow"></A>Block Flow Graph</H2>
|
||||
|
||||
<P>A Block Flow Graph consists of nodes that represent Basic blocks of contiguous instructions.
|
||||
Basic blocks are broken up by any instruction that causes a change in execution flow. All Jump,
|
||||
Call, Branch, and Return instructions can cause the execution flow to change. Arithmetic and
|
||||
store/load instructions do not break a Basic block because they do not change the execution
|
||||
flow. A labeled instruction will always start a block regardless of the instruction type.</P>
|
||||
|
||||
<P>For example:</P>
|
||||
|
||||
<P align="center"><IMG src="images/BasicBlockExampleCode.png"></P>
|
||||
|
||||
<P>Would generate the following graph:</P>
|
||||
|
||||
<P align="center"><IMG src="images/BasicBlockGraph.png">
|
||||
</P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P><IMG src="../../shared/note.png"> If there is a current selection, the nodes and edges
|
||||
will be restricted to blocks of code that fall within the selection.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P>To Graph Block Flow Using the default model,</P>
|
||||
|
||||
<OL>
|
||||
<LI>Select <B>Graph<IMG src="../../shared/arrow.gif"> Block Flow</B></LI>
|
||||
|
||||
<LI>A new graph window is created</LI>
|
||||
</OL>
|
||||
|
||||
<H2><A name="Graph_Code_Flow"></A>Graph Code Flow</H2>
|
||||
|
||||
<P align="left">A Code Flow Graph is an extension of a <A href="#Graph_Block_Flow">Block Flow
|
||||
Graph</A> in which each graph node (i.e., vertex) contains the list of instructions contained
|
||||
within the associated block. The list of instructions are passed to the graph as the vertex
|
||||
label.</P>
|
||||
|
||||
<P align="center"><BR>
|
||||
<BR>
|
||||
<IMG src="images/CodeBlockGraph.png"></P>
|
||||
|
||||
<H2><A name="Graph_Calls_Using_Default_Model"></A>Graph Calls</H2>
|
||||
|
||||
<P>A graph of the call instruction flow from one subroutine to another can be created with
|
||||
<B>Graph<IMG src="../../shared/arrow.gif"> Calls</B>. The graph is created using the default
|
||||
Call Model. Several Subroutine Models are available. Each model provides a slightly
|
||||
different perspective on what constitutes a subroutine.</P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P><IMG src="../../shared/note.png"> If there is a current selection, the nodes and edges
|
||||
will be restricted to blocks of code that fall within the selection.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P>To Graph Calls Using the default model,</P>
|
||||
|
||||
<OL>
|
||||
<LI>Select <B>Graph<IMG src="../../shared/arrow.gif"> Calls</B></LI>
|
||||
|
||||
<LI>A new graph window is created</LI>
|
||||
</OL>
|
||||
|
||||
<P><A name="Graph_Calls_Using_Model"></A>To Graph Calls Using a specific model*,</P>
|
||||
|
||||
<OL>
|
||||
<LI>Select <B>Graph<IMG src="../../shared/arrow.gif"> Calls Using Model<IMG src=
|
||||
"../../shared/arrow.gif"></B> <<I><B>a Call Model</B></I>></LI>
|
||||
|
||||
<LI>
|
||||
Select one of
|
||||
|
||||
<UL>
|
||||
<LI>Isolated Entry Model</LI>
|
||||
|
||||
<LI>Multiple Entry Model</LI>
|
||||
|
||||
<LI>Overlapped Code Model</LI>
|
||||
|
||||
<LI>Partitioned Code Model</LI>
|
||||
</UL>
|
||||
</LI>
|
||||
|
||||
<LI>A new graph window is created</LI>
|
||||
</OL>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P><IMG src="../../shared/note.png"> *For a more thorough description of each Call Block
|
||||
Model (i.e., Subroutine Model), see <A href="help/topics/BlockModel/Block_Model.htm">Block
|
||||
Models</A>. The specific list of models presented to the user may vary depending upon the
|
||||
set of block models configured into the tool.</P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H2><A name="Reuse_Graph"></A>Reuse Graph</H2>
|
||||
|
||||
<P>When <I>Reuse Graph</I> is turned on, creating any new graphs will re-use the active graph
|
||||
|
@ -378,6 +286,123 @@
|
|||
|
||||
<P>When Show Location is turned <U><I>off</I></U>, the graph view will not change as the
|
||||
current address location changes.</P>
|
||||
|
||||
|
||||
<BR>
|
||||
<BR>
|
||||
<BR>
|
||||
<BR>
|
||||
<BR>
|
||||
<BR>
|
||||
<BR>
|
||||
<BR>
|
||||
<HR WIDTH="90%">
|
||||
<BR>
|
||||
<BR>
|
||||
|
||||
<H2><A name="Graph_Block_Flow"></A>Block Flow Graph</H2>
|
||||
|
||||
<P>A Block Flow Graph consists of nodes that represent Basic blocks of contiguous instructions.
|
||||
Basic blocks are broken up by any instruction that causes a change in execution flow. All Jump,
|
||||
Call, Branch, and Return instructions can cause the execution flow to change. Arithmetic and
|
||||
store/load instructions do not break a Basic block because they do not change the execution
|
||||
flow. A labeled instruction will always start a block regardless of the instruction type.</P>
|
||||
|
||||
<P>For example:</P>
|
||||
|
||||
<P align="center"><IMG src="images/BasicBlockExampleCode.png"></P>
|
||||
|
||||
<P>Would generate the following graph:</P>
|
||||
|
||||
<P align="center"><IMG src="images/BasicBlockGraph.png">
|
||||
</P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P><IMG src="../../shared/note.png"> If there is a current selection, the nodes and edges
|
||||
will be restricted to blocks of code that fall within the selection.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P>To Graph Block Flow Using the default model,</P>
|
||||
|
||||
<OL>
|
||||
<LI>Select <B>Graph<IMG src="../../shared/arrow.gif"> Block Flow</B></LI>
|
||||
|
||||
<LI>A new graph window is created</LI>
|
||||
</OL>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
|
||||
<H3><A NAME="Rename_Vertex"></A>Rename Vertex</H3>
|
||||
<BLOCKQUOTE>
|
||||
<P>Allows the user to rename the symbol represented by the given vertex.
|
||||
</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
||||
<H2><A name="Graph_Code_Flow"></A>Graph Code Flow</H2>
|
||||
|
||||
<P align="left">A Code Flow Graph is an extension of a <A href="#Graph_Block_Flow">Block Flow
|
||||
Graph</A> in which each graph node (i.e., vertex) contains the list of instructions contained
|
||||
within the associated block. The list of instructions are passed to the graph as the vertex
|
||||
label.</P>
|
||||
|
||||
<P align="center"><BR>
|
||||
<BR>
|
||||
<IMG src="images/CodeBlockGraph.png"></P>
|
||||
|
||||
<H2><A name="Graph_Calls_Using_Default_Model"></A>Graph Calls</H2>
|
||||
|
||||
<P>A graph of the call instruction flow from one subroutine to another can be created with
|
||||
<B>Graph<IMG src="../../shared/arrow.gif"> Calls</B>. The graph is created using the default
|
||||
Call Model. Several Subroutine Models are available. Each model provides a slightly
|
||||
different perspective on what constitutes a subroutine.</P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P><IMG src="../../shared/note.png"> If there is a current selection, the nodes and edges
|
||||
will be restricted to blocks of code that fall within the selection.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P>To Graph Calls Using the default model,</P>
|
||||
|
||||
<OL>
|
||||
<LI>Select <B>Graph<IMG src="../../shared/arrow.gif"> Calls</B></LI>
|
||||
|
||||
<LI>A new graph window is created</LI>
|
||||
</OL>
|
||||
|
||||
<P><A name="Graph_Calls_Using_Model"></A>To Graph Calls Using a specific model*,</P>
|
||||
|
||||
<OL>
|
||||
<LI>Select <B>Graph<IMG src="../../shared/arrow.gif"> Calls Using Model<IMG src=
|
||||
"../../shared/arrow.gif"></B> <<I><B>a Call Model</B></I>></LI>
|
||||
|
||||
<LI>
|
||||
Select one of
|
||||
|
||||
<UL>
|
||||
<LI>Isolated Entry Model</LI>
|
||||
|
||||
<LI>Multiple Entry Model</LI>
|
||||
|
||||
<LI>Overlapped Code Model</LI>
|
||||
|
||||
<LI>Partitioned Code Model</LI>
|
||||
</UL>
|
||||
</LI>
|
||||
|
||||
<LI>A new graph window is created</LI>
|
||||
</OL>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P><IMG src="../../shared/note.png"> *For a more thorough description of each Call Block
|
||||
Model (i.e., Subroutine Model), see <A href="help/topics/BlockModel/Block_Model.htm">Block
|
||||
Models</A>. The specific list of models presented to the user may vary depending upon the
|
||||
set of block models configured into the tool.</P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
|
||||
<BR>
|
||||
|
|
|
@ -106,7 +106,7 @@ public class BlockGraphTask extends Task {
|
|||
private CodeBlockModel blockModel;
|
||||
private AddressSetView selection;
|
||||
private ProgramLocation location;
|
||||
private GraphDisplayProvider graphService;
|
||||
private GraphDisplayProvider graphProvider;
|
||||
private boolean reuseGraph;
|
||||
private boolean appendGraph;
|
||||
private PluginTool tool;
|
||||
|
@ -116,7 +116,7 @@ public class BlockGraphTask extends Task {
|
|||
public BlockGraphTask(String actionName, boolean graphEntryPointNexus, boolean showCode,
|
||||
boolean reuseGraph, boolean appendGraph, PluginTool tool, ProgramSelection selection,
|
||||
ProgramLocation location, CodeBlockModel blockModel,
|
||||
GraphDisplayProvider graphService) {
|
||||
GraphDisplayProvider graphProvider) {
|
||||
|
||||
super("Graph Program", true, false, true);
|
||||
this.actionName = actionName;
|
||||
|
@ -127,7 +127,7 @@ public class BlockGraphTask extends Task {
|
|||
this.appendGraph = appendGraph;
|
||||
this.tool = tool;
|
||||
this.blockModel = blockModel;
|
||||
this.graphService = graphService;
|
||||
this.graphProvider = graphProvider;
|
||||
this.colorizingService = tool.getService(ColorizingService.class);
|
||||
this.selection = selection;
|
||||
this.location = location;
|
||||
|
@ -142,7 +142,7 @@ public class BlockGraphTask extends Task {
|
|||
AttributedGraph graph = createGraph();
|
||||
monitor.setMessage("Generating Graph...");
|
||||
try {
|
||||
GraphDisplay display = graphService.getGraphDisplay(reuseGraph, monitor);
|
||||
GraphDisplay display = graphProvider.getGraphDisplay(reuseGraph, monitor);
|
||||
BlockModelGraphDisplayListener listener =
|
||||
new BlockModelGraphDisplayListener(tool, blockModel, display);
|
||||
display.setGraphDisplayListener(listener);
|
||||
|
|
|
@ -26,6 +26,7 @@ import ghidra.program.model.block.*;
|
|||
import ghidra.program.model.symbol.Symbol;
|
||||
import ghidra.program.model.symbol.SymbolTable;
|
||||
import ghidra.service.graph.*;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
|
@ -47,6 +48,7 @@ public class BlockModelGraphDisplayListener extends AddressBasedGraphDisplayList
|
|||
display.addAction(new ActionBuilder("Rename Vertex", "Block Graph")
|
||||
.popupMenuPath("Rename Vertex")
|
||||
.withContext(VertexGraphActionContext.class)
|
||||
.helpLocation(new HelpLocation("ProgramGraphPlugin", "Rename Vertex"))
|
||||
// only enable action when vertex corresponds to an address
|
||||
.enabledWhen(c -> getAddress(c.getClickedVertex().getId()) != null)
|
||||
.onAction(this::updateVertexName)
|
||||
|
|
|
@ -30,6 +30,10 @@ import ghidra.program.model.mem.MemoryAccessException;
|
|||
import ghidra.test.*;
|
||||
|
||||
public class AbstractBlockGraphTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
protected static final String CALLER_FUNCTION_ADDRESS = "01002200";
|
||||
protected static final String SIMPLE_FUNCTION_ADDRESS = "01002239";
|
||||
|
||||
protected PluginTool tool;
|
||||
protected ProgramDB program;
|
||||
protected TestEnv env;
|
||||
|
@ -37,10 +41,6 @@ public class AbstractBlockGraphTest extends AbstractGhidraHeadedIntegrationTest
|
|||
private ToyProgramBuilder builder;
|
||||
protected CodeBrowserPlugin codeBrowser;
|
||||
|
||||
protected Address addr(long addr) {
|
||||
return builder.getAddress(addr);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
|
@ -50,7 +50,6 @@ public class AbstractBlockGraphTest extends AbstractGhidraHeadedIntegrationTest
|
|||
tool = env.getTool();
|
||||
|
||||
initializeTool();
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -80,14 +79,15 @@ public class AbstractBlockGraphTest extends AbstractGhidraHeadedIntegrationTest
|
|||
builder = new ToyProgramBuilder("sample", true);
|
||||
builder.createMemory("caller", "0x01002200", 8);
|
||||
builder.createMemory("simple", "0x01002239", 8);
|
||||
builder.createMemory("not_graphed", "0x01002300", 8);
|
||||
|
||||
buildCallerFunction(builder);
|
||||
buildSimpleFunction(builder);
|
||||
buildCallerFunction();
|
||||
buildSimpleFunction();
|
||||
|
||||
program = builder.getProgram();
|
||||
}
|
||||
|
||||
private void buildCallerFunction(ToyProgramBuilder builder) throws MemoryAccessException {
|
||||
private void buildCallerFunction() throws MemoryAccessException {
|
||||
// just a function that calls another
|
||||
builder.addBytesNOP("0x01002200", 1);
|
||||
builder.addBytesCall("0x01002201", "0x01002239");// jump to C
|
||||
|
@ -98,7 +98,7 @@ public class AbstractBlockGraphTest extends AbstractGhidraHeadedIntegrationTest
|
|||
builder.createLabel("0x01002200", "entry");// function label
|
||||
}
|
||||
|
||||
private void buildSimpleFunction(ToyProgramBuilder builder) throws MemoryAccessException {
|
||||
private void buildSimpleFunction() throws MemoryAccessException {
|
||||
// just a function to render in the graph so that we can clear out settings/cache
|
||||
// 01002239
|
||||
|
||||
|
@ -128,4 +128,12 @@ public class AbstractBlockGraphTest extends AbstractGhidraHeadedIntegrationTest
|
|||
builder.createLabel("0x01002239", "simple");// function label
|
||||
}
|
||||
|
||||
protected Address addr(long addr) {
|
||||
return builder.getAddress(addr);
|
||||
}
|
||||
|
||||
protected Address addr(String addressString) {
|
||||
return builder.addr(addressString);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,17 +34,16 @@
|
|||
<SPLIT_NODE WIDTH="1475" HEIGHT="596" DIVIDER_LOCATION="632" ORIENTATION="HORIZONTAL">
|
||||
<SPLIT_NODE WIDTH="950" HEIGHT="985" DIVIDER_LOCATION="894" ORIENTATION="HORIZONTAL">
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Listing" OWNER="CodeBrowserPlugin" TITLE="Listing: notepad.exe.2" ACTIVE="true" GROUP="" INSTANCE_ID="2777482860928188961" />
|
||||
<COMPONENT_INFO NAME="Test Listing" OWNER="Test Listing" TITLE="Test Listing" ACTIVE="false" GROUP="" INSTANCE_ID="2733632016422332683" />
|
||||
<COMPONENT_INFO NAME="Listing" OWNER="CodeBrowserPlugin" TITLE="Listing:" ACTIVE="true" GROUP="Core" INSTANCE_ID="2777482860928188961" />
|
||||
</COMPONENT_NODE>
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Listing" OWNER="CodeBrowserPlugin" TITLE="[Listing: notepad.exe]" ACTIVE="false" GROUP="disconnected" INSTANCE_ID="2738354194536315852" />
|
||||
<COMPONENT_INFO NAME="Listing" OWNER="CodeBrowserPlugin" TITLE="Listing:" ACTIVE="false" GROUP="disconnected" INSTANCE_ID="2738354194536315852" />
|
||||
</COMPONENT_NODE>
|
||||
</SPLIT_NODE>
|
||||
<SPLIT_NODE WIDTH="355" HEIGHT="1097" DIVIDER_LOCATION="542" ORIENTATION="VERTICAL">
|
||||
<SPLIT_NODE WIDTH="541" HEIGHT="596" DIVIDER_LOCATION="546" ORIENTATION="VERTICAL">
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Decompiler" OWNER="DecompilePlugin" TITLE="Decompiler" ACTIVE="true" GROUP="" INSTANCE_ID="2777482860928188962" />
|
||||
<COMPONENT_INFO NAME="Decompiler" OWNER="DecompilePlugin" TITLE="Decompile" ACTIVE="true" GROUP="" INSTANCE_ID="2777482860928188962" />
|
||||
</COMPONENT_NODE>
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Version Tracking Matches for Destination" OWNER="VTPlugin" TITLE="Version Tracking Matches for Destination" ACTIVE="true" GROUP="VTResults" INSTANCE_ID="2777482861815284257" />
|
||||
|
@ -56,8 +55,7 @@
|
|||
</SPLIT_NODE>
|
||||
</SPLIT_NODE>
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Decompiler" OWNER="Decompiler" TITLE="Decompile" ACTIVE="false" GROUP="" INSTANCE_ID="0" />
|
||||
<COMPONENT_INFO NAME="References from " OWNER="ReferencesPlugin" TITLE="References from notepad.exe@01001004" ACTIVE="false" GROUP="" INSTANCE_ID="0" />
|
||||
<COMPONENT_INFO NAME="References from " OWNER="ReferencesPlugin" TITLE="References from" ACTIVE="false" GROUP="" INSTANCE_ID="0" />
|
||||
<COMPONENT_INFO NAME="Label References Provider" OWNER="LocationReferencesPlugin" TITLE="References to s__0100a000" ACTIVE="false" GROUP="" INSTANCE_ID="2738698427373098901" />
|
||||
</COMPONENT_NODE>
|
||||
</SPLIT_NODE>
|
||||
|
@ -186,7 +184,7 @@
|
|||
</WINDOW_NODE>
|
||||
<WINDOW_NODE X_POS="454" Y_POS="326" WIDTH="464" HEIGHT="513">
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="References Editor " OWNER="ReferencesPlugin" TITLE="References Editor @ 0100566d (notepad.exe)" ACTIVE="false" GROUP="" INSTANCE_ID="2738698427373098900" />
|
||||
<COMPONENT_INFO NAME="References Editor " OWNER="ReferencesPlugin" TITLE="References Editor" ACTIVE="false" GROUP="" INSTANCE_ID="2738698427373098900" />
|
||||
</COMPONENT_NODE>
|
||||
</WINDOW_NODE>
|
||||
<WINDOW_NODE X_POS="0" Y_POS="0" WIDTH="0" HEIGHT="0">
|
||||
|
@ -196,7 +194,7 @@
|
|||
</WINDOW_NODE>
|
||||
<WINDOW_NODE X_POS="397" Y_POS="209" WIDTH="597" HEIGHT="433">
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Structure Editor" OWNER="DataTypeManagerPlugin" TITLE="Structure Editor: IMAGE_RESOURCE_DIRECTORY_ENTRY_NameStruct.conflict (notepad.exe)" ACTIVE="false" GROUP="" INSTANCE_ID="2739607423924196364" />
|
||||
<COMPONENT_INFO NAME="Structure Editor" OWNER="DataTypeManagerPlugin" TITLE="Structure Editor: " ACTIVE="false" GROUP="" INSTANCE_ID="2739607423924196364" />
|
||||
</COMPONENT_NODE>
|
||||
</WINDOW_NODE>
|
||||
<WINDOW_NODE X_POS="171" Y_POS="155" WIDTH="940" HEIGHT="642">
|
||||
|
@ -211,17 +209,17 @@
|
|||
</WINDOW_NODE>
|
||||
<WINDOW_NODE X_POS="-1287" Y_POS="271" WIDTH="1069" HEIGHT="677">
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Enum Editor" OWNER="DataTypeManagerPlugin" TITLE="enum (notepad.exe)" ACTIVE="false" GROUP="" INSTANCE_ID="2736721927148945968" />
|
||||
<COMPONENT_INFO NAME="Enum Editor" OWNER="DataTypeManagerPlugin" TITLE="enum " ACTIVE="false" GROUP="" INSTANCE_ID="2736721927148945968" />
|
||||
</COMPONENT_NODE>
|
||||
</WINDOW_NODE>
|
||||
<WINDOW_NODE X_POS="385" Y_POS="260" WIDTH="488" HEIGHT="350">
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Union Editor" OWNER="DataTypeManagerPlugin" TITLE="Union Editor: union (calc.exe)" ACTIVE="false" GROUP="" INSTANCE_ID="2650648146038267899" />
|
||||
<COMPONENT_INFO NAME="Union Editor" OWNER="DataTypeManagerPlugin" TITLE="Union Editor: union (x.exe)" ACTIVE="false" GROUP="" INSTANCE_ID="2650648146038267899" />
|
||||
</COMPONENT_NODE>
|
||||
</WINDOW_NODE>
|
||||
<WINDOW_NODE X_POS="-752" Y_POS="237" WIDTH="753" HEIGHT="554">
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Bytes" OWNER="ByteViewerPlugin" TITLE="Bytes : notepad.exe.2" ACTIVE="false" GROUP="" INSTANCE_ID="2777482860928188968" />
|
||||
<COMPONENT_INFO NAME="Bytes" OWNER="ByteViewerPlugin" TITLE="Bytes : " ACTIVE="false" GROUP="" INSTANCE_ID="2777482860928188968" />
|
||||
</COMPONENT_NODE>
|
||||
</WINDOW_NODE>
|
||||
<WINDOW_NODE X_POS="443" Y_POS="383" WIDTH="477" HEIGHT="374">
|
||||
|
|
|
@ -34,18 +34,18 @@
|
|||
<SPLIT_NODE WIDTH="1475" HEIGHT="551" DIVIDER_LOCATION="632" ORIENTATION="HORIZONTAL">
|
||||
<SPLIT_NODE WIDTH="950" HEIGHT="985" DIVIDER_LOCATION="894" ORIENTATION="HORIZONTAL">
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Listing" OWNER="CodeBrowserPlugin" TITLE="Listing: WallaceSrc" ACTIVE="true" GROUP="" INSTANCE_ID="2769903913093334120" />
|
||||
<COMPONENT_INFO NAME="Listing" OWNER="CodeBrowserPlugin" TITLE="Listing" ACTIVE="true" GROUP="Core" INSTANCE_ID="2769903913093334120" />
|
||||
<COMPONENT_INFO NAME="Test Listing" OWNER="Test Listing" TITLE="Test Listing" ACTIVE="false" GROUP="" INSTANCE_ID="2733632016422332683" />
|
||||
</COMPONENT_NODE>
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Listing" OWNER="CodeBrowserPlugin" TITLE="[Listing: notepad.exe]" ACTIVE="false" GROUP="disconnected" INSTANCE_ID="2738354194536315852" />
|
||||
<COMPONENT_INFO NAME="Listing" OWNER="CodeBrowserPlugin" TITLE="Listing" ACTIVE="false" GROUP="disconnected" INSTANCE_ID="2738354194536315852" />
|
||||
</COMPONENT_NODE>
|
||||
</SPLIT_NODE>
|
||||
<SPLIT_NODE WIDTH="355" HEIGHT="1097" DIVIDER_LOCATION="542" ORIENTATION="VERTICAL">
|
||||
<SPLIT_NODE WIDTH="541" HEIGHT="551" DIVIDER_LOCATION="546" ORIENTATION="VERTICAL">
|
||||
<SPLIT_NODE WIDTH="541" HEIGHT="551" DIVIDER_LOCATION="546" ORIENTATION="VERTICAL">
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Decompiler" OWNER="DecompilePlugin" TITLE="Decompile: Gadget" ACTIVE="true" GROUP="" INSTANCE_ID="2769903892362986615" />
|
||||
<COMPONENT_INFO NAME="Decompiler" OWNER="DecompilePlugin" TITLE="Decompile" ACTIVE="true" GROUP="" INSTANCE_ID="2769903892362986615" />
|
||||
</COMPONENT_NODE>
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Version Tracking Matches for Source" OWNER="VTPlugin" TITLE="Version Tracking Matches for Source" ACTIVE="true" GROUP="VTResults" INSTANCE_ID="2769903913525347441" />
|
||||
|
@ -61,8 +61,7 @@
|
|||
</SPLIT_NODE>
|
||||
</SPLIT_NODE>
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Decompiler" OWNER="Decompiler" TITLE="Decompile" ACTIVE="false" GROUP="" INSTANCE_ID="0" />
|
||||
<COMPONENT_INFO NAME="References from " OWNER="ReferencesPlugin" TITLE="References from notepad.exe@01001004" ACTIVE="false" GROUP="" INSTANCE_ID="0" />
|
||||
<COMPONENT_INFO NAME="References from " OWNER="ReferencesPlugin" TITLE="References" ACTIVE="false" GROUP="" INSTANCE_ID="0" />
|
||||
<COMPONENT_INFO NAME="Label References Provider" OWNER="LocationReferencesPlugin" TITLE="References to s__0100a000" ACTIVE="false" GROUP="" INSTANCE_ID="2738698427373098901" />
|
||||
</COMPONENT_NODE>
|
||||
</SPLIT_NODE>
|
||||
|
@ -191,7 +190,7 @@
|
|||
</WINDOW_NODE>
|
||||
<WINDOW_NODE X_POS="454" Y_POS="326" WIDTH="464" HEIGHT="513">
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="References Editor " OWNER="ReferencesPlugin" TITLE="References Editor @ 0100566d (notepad.exe)" ACTIVE="false" GROUP="" INSTANCE_ID="2738698427373098900" />
|
||||
<COMPONENT_INFO NAME="References Editor " OWNER="ReferencesPlugin" TITLE="References Editor" ACTIVE="false" GROUP="" INSTANCE_ID="2738698427373098900" />
|
||||
</COMPONENT_NODE>
|
||||
</WINDOW_NODE>
|
||||
<WINDOW_NODE X_POS="0" Y_POS="0" WIDTH="0" HEIGHT="0">
|
||||
|
@ -201,7 +200,7 @@
|
|||
</WINDOW_NODE>
|
||||
<WINDOW_NODE X_POS="397" Y_POS="209" WIDTH="597" HEIGHT="433">
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Structure Editor" OWNER="DataTypeManagerPlugin" TITLE="Structure Editor: IMAGE_RESOURCE_DIRECTORY_ENTRY_NameStruct.conflict (notepad.exe)" ACTIVE="false" GROUP="" INSTANCE_ID="2739607423924196364" />
|
||||
<COMPONENT_INFO NAME="Structure Editor" OWNER="DataTypeManagerPlugin" TITLE="Structure Editor" ACTIVE="false" GROUP="" INSTANCE_ID="2739607423924196364" />
|
||||
</COMPONENT_NODE>
|
||||
</WINDOW_NODE>
|
||||
<WINDOW_NODE X_POS="171" Y_POS="155" WIDTH="940" HEIGHT="642">
|
||||
|
@ -216,17 +215,17 @@
|
|||
</WINDOW_NODE>
|
||||
<WINDOW_NODE X_POS="-1287" Y_POS="271" WIDTH="1069" HEIGHT="677">
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Enum Editor" OWNER="DataTypeManagerPlugin" TITLE="enum (notepad.exe)" ACTIVE="false" GROUP="" INSTANCE_ID="2736721927148945968" />
|
||||
<COMPONENT_INFO NAME="Enum Editor" OWNER="DataTypeManagerPlugin" TITLE="enum " ACTIVE="false" GROUP="" INSTANCE_ID="2736721927148945968" />
|
||||
</COMPONENT_NODE>
|
||||
</WINDOW_NODE>
|
||||
<WINDOW_NODE X_POS="385" Y_POS="260" WIDTH="488" HEIGHT="350">
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Union Editor" OWNER="DataTypeManagerPlugin" TITLE="Union Editor: union (calc.exe)" ACTIVE="false" GROUP="" INSTANCE_ID="2650648146038267899" />
|
||||
<COMPONENT_INFO NAME="Union Editor" OWNER="DataTypeManagerPlugin" TITLE="Union Editor: union" ACTIVE="false" GROUP="" INSTANCE_ID="2650648146038267899" />
|
||||
</COMPONENT_NODE>
|
||||
</WINDOW_NODE>
|
||||
<WINDOW_NODE X_POS="-752" Y_POS="237" WIDTH="753" HEIGHT="554">
|
||||
<COMPONENT_NODE TOP_INFO="0">
|
||||
<COMPONENT_INFO NAME="Bytes" OWNER="ByteViewerPlugin" TITLE="Bytes : WallaceSrc" ACTIVE="false" GROUP="" INSTANCE_ID="2769903913093334115" />
|
||||
<COMPONENT_INFO NAME="Bytes" OWNER="ByteViewerPlugin" TITLE="Bytes" ACTIVE="false" GROUP="" INSTANCE_ID="2769903913093334115" />
|
||||
</COMPONENT_NODE>
|
||||
</WINDOW_NODE>
|
||||
<WINDOW_NODE X_POS="443" Y_POS="383" WIDTH="477" HEIGHT="374">
|
||||
|
|
|
@ -931,17 +931,19 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
* @param rootXMLElement JDOM element from which to extract the state information.
|
||||
*/
|
||||
public void restoreFromXML(Element rootXMLElement) {
|
||||
Element rootNodeElement = rootXMLElement.getChild(RootNode.ROOT_NODE_ELEMENT_NAME);
|
||||
restoreWindowDataFromXml(rootNodeElement);
|
||||
// load the tool preferences
|
||||
restoreWindowDataFromXml(rootXMLElement);
|
||||
restorePreferencesFromXML(rootXMLElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore to the docking window manager the layout and positioning information from XML.
|
||||
* @param windowData The XML element containing the above information.
|
||||
* @param rootXMLElement JDOM element from which to extract the state information.
|
||||
*/
|
||||
public void restoreWindowDataFromXml(Element windowData) {
|
||||
public void restoreWindowDataFromXml(Element rootXMLElement) {
|
||||
Element windowData = rootXMLElement.getChild(RootNode.ROOT_NODE_ELEMENT_NAME);
|
||||
if (windowData == null) {
|
||||
return;
|
||||
}
|
||||
//
|
||||
// Clear our focus history, as we are changing placeholders' providers, so the old focus
|
||||
// is no longer relevant.
|
||||
|
@ -1576,7 +1578,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||
return toolPreferencesElement;
|
||||
}
|
||||
|
||||
private void restorePreferencesFromXML(Element rootElement) {
|
||||
public void restorePreferencesFromXML(Element rootElement) {
|
||||
Element toolPreferencesElement = rootElement.getChild(TOOL_PREFERENCES_XML_NAME);
|
||||
if (toolPreferencesElement == null) {
|
||||
return;
|
||||
|
|
|
@ -1128,9 +1128,13 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
|||
|
||||
private V selectedVertex;
|
||||
|
||||
@SuppressWarnings("deprecation") // deprecated until we fix the checkModifiers() code
|
||||
public VertexClickMousePlugin() {
|
||||
super(InputEvent.BUTTON1_MASK);
|
||||
super(InputEvent.BUTTON1_DOWN_MASK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkModifiers(MouseEvent e) {
|
||||
return e.getModifiersEx() == modifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1203,6 +1207,5 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
|||
public void mouseExited(MouseEvent e) {
|
||||
// stub
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
package ghidra.graph.viewer;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.widgets.PopupWindow;
|
||||
import edu.uci.ics.jung.algorithms.layout.Layout;
|
||||
import edu.uci.ics.jung.visualization.VisualizationViewer;
|
||||
import edu.uci.ics.jung.visualization.picking.MultiPickedState;
|
||||
|
@ -35,6 +35,7 @@ import ghidra.graph.viewer.event.mouse.*;
|
|||
import ghidra.graph.viewer.event.picking.GPickedState;
|
||||
import ghidra.graph.viewer.layout.VisualGraphLayout;
|
||||
import ghidra.graph.viewer.options.VisualGraphOptions;
|
||||
import ghidra.graph.viewer.popup.*;
|
||||
import ghidra.graph.viewer.renderer.VisualGraphRenderer;
|
||||
import ghidra.util.layout.PairLayout;
|
||||
|
||||
|
@ -62,9 +63,7 @@ public class GraphViewer<V extends VisualVertex, E extends VisualEdge<V>>
|
|||
|
||||
private Consumer<GraphViewer<V, E>> initializedListener;
|
||||
|
||||
private PopupRegulator popupRegulator = new PopupRegulator();
|
||||
private PopupWindow popupWindow;
|
||||
private boolean showPopups = true;
|
||||
private PopupRegulator<V, E> popupRegulator;
|
||||
private VertexTooltipProvider<V, E> vertexTooltipProvider = new DummyTooltipProvider();
|
||||
|
||||
protected VisualGraphOptions options;
|
||||
|
@ -88,6 +87,8 @@ public class GraphViewer<V extends VisualVertex, E extends VisualEdge<V>>
|
|||
PickedState<V> pickedState = getPickedVertexState();
|
||||
gPickedState = new GPickedState<>((MultiPickedState<V>) pickedState);
|
||||
setPickedVertexState(gPickedState);
|
||||
|
||||
popupRegulator = new PopupRegulator<V, E>(new GraphViewerPopupSource());
|
||||
}
|
||||
|
||||
private void buildUpdater() {
|
||||
|
@ -271,23 +272,16 @@ public class GraphViewer<V extends VisualVertex, E extends VisualEdge<V>>
|
|||
// Popups and Tooltips
|
||||
//==================================================================================================
|
||||
|
||||
/*package*/ void setPopupDelay(int delayMs) {
|
||||
popupRegulator.setPopupDelay(delayMs);
|
||||
}
|
||||
|
||||
public void setPopupsVisible(boolean visible) {
|
||||
this.showPopups = visible;
|
||||
if (!showPopups) {
|
||||
hidePopupTooltips();
|
||||
}
|
||||
popupRegulator.setPopupsVisible(visible);
|
||||
}
|
||||
|
||||
/*package*/ boolean isPopupShowing() {
|
||||
return popupWindow != null && popupWindow.isShowing();
|
||||
}
|
||||
|
||||
private void hidePopupTooltips() {
|
||||
if (popupWindow != null && popupWindow.isShowing()) {
|
||||
popupWindow.hide();
|
||||
// don't call dispose, or we don't get our componentHidden() callback
|
||||
// popupWindow.dispose();
|
||||
}
|
||||
return popupRegulator.isPopupShowing();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -317,49 +311,11 @@ public class GraphViewer<V extends VisualVertex, E extends VisualEdge<V>>
|
|||
return new VertexToolTipInfo(vertex, event);
|
||||
}
|
||||
|
||||
private void showTooltip(ToolTipInfo<?> info) {
|
||||
JComponent tipComponent = info.getToolTipComponent();
|
||||
if (tipComponent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
MouseEvent event = info.getMouseEvent();
|
||||
showPopupWindow(event, tipComponent);
|
||||
}
|
||||
|
||||
private void showPopupWindow(MouseEvent event, JComponent component) {
|
||||
MenuSelectionManager menuManager = MenuSelectionManager.defaultManager();
|
||||
if (menuManager.getSelectedPath().length != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Window parentWindow = WindowUtilities.windowForComponent(this);
|
||||
popupWindow = new PopupWindow(parentWindow, component);
|
||||
|
||||
popupWindow.addComponentListener(new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentShown(ComponentEvent e) {
|
||||
popupRegulator.popupShown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentHidden(ComponentEvent e) {
|
||||
popupRegulator.popupHidden();
|
||||
}
|
||||
});
|
||||
|
||||
popupWindow.showPopup(event);
|
||||
}
|
||||
|
||||
public VertexMouseInfo<V, E> createVertexMouseInfo(MouseEvent e, V v,
|
||||
Point2D vertexBasedClickPoint) {
|
||||
return new VertexMouseInfo<>(e, v, vertexBasedClickPoint, this);
|
||||
}
|
||||
|
||||
/*package*/ void setPopupDelay(int delayMs) {
|
||||
popupRegulator.setPopupDelay(delayMs);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
|
||||
viewUpdater.dispose();
|
||||
|
@ -369,168 +325,50 @@ public class GraphViewer<V extends VisualVertex, E extends VisualEdge<V>>
|
|||
removeAll();
|
||||
}
|
||||
|
||||
private GraphViewer<V, E> viewer() {
|
||||
return GraphViewer.this;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
// Inner Classes
|
||||
//==================================================================================================
|
||||
|
||||
private class PopupRegulator {
|
||||
private int popupDelay = 1000;
|
||||
private class GraphViewerPopupSource implements PopupSource<V, E> {
|
||||
|
||||
/**
|
||||
* We need this timer because the default mechanism for triggering popups doesn't
|
||||
* always work. We use this timer in conjunction with a mouse motion listener to
|
||||
* get the results we want.
|
||||
*/
|
||||
private Timer popupTimer;
|
||||
private MouseEvent popupMouseEvent;
|
||||
|
||||
/** the current target (vertex or edge) of a popup window */
|
||||
private Object nextPopupTarget;
|
||||
|
||||
/**
|
||||
* This value is not null when the user moves the cursor over a target for which a
|
||||
* popup is already showing. We use this value to prevent showing a popup multiple times
|
||||
* while over a single node.
|
||||
*/
|
||||
private Object lastShownPopupTarget;
|
||||
|
||||
/** The tooltip info used when showing the popup */
|
||||
private ToolTipInfo<?> currentToolTipInfo;
|
||||
|
||||
PopupRegulator() {
|
||||
popupTimer = new Timer(popupDelay, e -> {
|
||||
if (isPopupShowing()) {
|
||||
return; // don't show any new popups while the user is perusing
|
||||
}
|
||||
showPopupForMouseEvent(popupMouseEvent);
|
||||
});
|
||||
|
||||
popupTimer.setRepeats(false);
|
||||
|
||||
addMouseMotionListener(new MouseMotionListener() {
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
hidePopupTooltips();
|
||||
popupTimer.stop();
|
||||
popupMouseEvent = null; // clear any queued popups
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
popupMouseEvent = e;
|
||||
|
||||
// this clears out the current last popup shown so that the user can
|
||||
// move off and on a node to re-show the popup
|
||||
savePopupTarget(e);
|
||||
|
||||
// make sure the popup gets triggered eventually
|
||||
popupTimer.restart();
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public ToolTipInfo<?> getToolTipInfo(MouseEvent event) {
|
||||
return viewer().getToolTipInfo(event);
|
||||
}
|
||||
|
||||
void setPopupDelay(int delayMs) {
|
||||
popupTimer.stop();
|
||||
popupTimer.setDelay(delayMs);
|
||||
popupTimer.setInitialDelay(delayMs);
|
||||
popupDelay = delayMs;
|
||||
}
|
||||
|
||||
private void showPopupForMouseEvent(MouseEvent event) {
|
||||
if (!showPopups) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ToolTipInfo<?> toolTipInfo = getToolTipInfo(event);
|
||||
JComponent toolTipComponent = toolTipInfo.getToolTipComponent();
|
||||
boolean isCustomJavaTooltip = !(toolTipComponent instanceof JToolTip);
|
||||
if (lastShownPopupTarget == nextPopupTarget && isCustomJavaTooltip) {
|
||||
//
|
||||
// Kinda Hacky:
|
||||
// We don't show repeated popups for the same item (the user has to move away
|
||||
// and then come back to re-show the popup). However, one caveat to this is that
|
||||
// we do want to allow the user to see popups for the toolbar actions always. So,
|
||||
// only return here if we have already shown a popup for the item *and* we are
|
||||
// using a custom tooltip (which is used to show a vertex tooltip or an edge
|
||||
// tooltip)
|
||||
return;
|
||||
}
|
||||
|
||||
currentToolTipInfo = toolTipInfo;
|
||||
showTooltip(currentToolTipInfo);
|
||||
}
|
||||
|
||||
void popupShown() {
|
||||
lastShownPopupTarget = nextPopupTarget;
|
||||
currentToolTipInfo.emphasize();
|
||||
repaint();
|
||||
}
|
||||
|
||||
void popupHidden() {
|
||||
currentToolTipInfo.deEmphasize();
|
||||
repaint();
|
||||
}
|
||||
|
||||
private void savePopupTarget(MouseEvent event) {
|
||||
nextPopupTarget = null;
|
||||
V vertex = getVertexForEvent(event);
|
||||
if (vertex != null) {
|
||||
nextPopupTarget = vertex;
|
||||
}
|
||||
else {
|
||||
E edge = getEdgeForEvent(event);
|
||||
nextPopupTarget = edge;
|
||||
}
|
||||
|
||||
if (nextPopupTarget == null) {
|
||||
// We've moved off of a target. We will clear that last target so the user can
|
||||
// mouse off of a vertex and back on in order to trigger a new popup
|
||||
lastShownPopupTarget = null;
|
||||
}
|
||||
}
|
||||
|
||||
private V getVertexForEvent(MouseEvent event) {
|
||||
@Override
|
||||
public V getVertex(MouseEvent event) {
|
||||
Layout<V, E> viewerLayout = getGraphLayout();
|
||||
Point p = event.getPoint();
|
||||
return getPickSupport().getVertex(viewerLayout, p.getX(), p.getY());
|
||||
}
|
||||
|
||||
private E getEdgeForEvent(MouseEvent event) {
|
||||
@Override
|
||||
public E getEdge(MouseEvent event) {
|
||||
Layout<V, E> viewerLayout = getGraphLayout();
|
||||
Point p = event.getPoint();
|
||||
return getPickSupport().getEdge(viewerLayout, p.getX(), p.getY());
|
||||
}
|
||||
}
|
||||
|
||||
/** Basic container object that knows how to generate tooltips */
|
||||
private abstract class ToolTipInfo<T> {
|
||||
protected final MouseEvent event;
|
||||
protected final T graphObject;
|
||||
private JComponent tooltipComponent;
|
||||
|
||||
ToolTipInfo(MouseEvent event, T t) {
|
||||
this.event = event;
|
||||
this.graphObject = t;
|
||||
tooltipComponent = createToolTipComponent(t);
|
||||
@Override
|
||||
public void addMouseMotionListener(MouseMotionListener l) {
|
||||
viewer().addMouseMotionListener(l);
|
||||
}
|
||||
|
||||
protected abstract JComponent createToolTipComponent(T t);
|
||||
|
||||
protected abstract void emphasize();
|
||||
|
||||
protected abstract void deEmphasize();
|
||||
|
||||
MouseEvent getMouseEvent() {
|
||||
return event;
|
||||
@Override
|
||||
public void repaint() {
|
||||
viewer().repaint();
|
||||
}
|
||||
|
||||
JComponent getToolTipComponent() {
|
||||
return tooltipComponent;
|
||||
@Override
|
||||
public Window getPopupParent() {
|
||||
return WindowUtilities.windowForComponent(viewer());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class VertexToolTipInfo extends ToolTipInfo<V> {
|
||||
|
@ -540,19 +378,20 @@ public class GraphViewer<V extends VisualVertex, E extends VisualEdge<V>>
|
|||
}
|
||||
|
||||
@Override
|
||||
public JComponent createToolTipComponent(V vertex) {
|
||||
if (vertex == null) {
|
||||
public JComponent createToolTipComponent() {
|
||||
if (graphObject == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isScaledPastInteractionThreshold()) {
|
||||
return vertexTooltipProvider.getTooltip(vertex);
|
||||
return vertexTooltipProvider.getTooltip(graphObject);
|
||||
}
|
||||
|
||||
VertexMouseInfo<V, E> mouseInfo =
|
||||
GraphViewerUtils.convertMouseEventToVertexMouseEvent(GraphViewer.this, event);
|
||||
MouseEvent translatedMouseEvent = mouseInfo.getTranslatedMouseEvent();
|
||||
String toolTip = vertexTooltipProvider.getTooltipText(vertex, translatedMouseEvent);
|
||||
String toolTip =
|
||||
vertexTooltipProvider.getTooltipText(graphObject, translatedMouseEvent);
|
||||
if (toolTip == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -591,15 +430,15 @@ public class GraphViewer<V extends VisualVertex, E extends VisualEdge<V>>
|
|||
}
|
||||
|
||||
@Override
|
||||
public JComponent createToolTipComponent(E edge) {
|
||||
if (edge == null) {
|
||||
public JComponent createToolTipComponent() {
|
||||
if (graphObject == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
V start = edge.getStart();
|
||||
V end = edge.getEnd();
|
||||
V start = graphObject.getStart();
|
||||
V end = graphObject.getEnd();
|
||||
|
||||
JComponent startComponent = vertexTooltipProvider.getTooltip(start, edge);
|
||||
JComponent startComponent = vertexTooltipProvider.getTooltip(start, graphObject);
|
||||
if (startComponent == null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -611,7 +450,7 @@ public class GraphViewer<V extends VisualVertex, E extends VisualEdge<V>>
|
|||
return component;
|
||||
}
|
||||
|
||||
JComponent endComponent = vertexTooltipProvider.getTooltip(end, edge);
|
||||
JComponent endComponent = vertexTooltipProvider.getTooltip(end, graphObject);
|
||||
if (endComponent == null) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,9 @@ import ghidra.graph.viewer.*;
|
|||
* <li>We clear state on mouseReleased() and mouseExited(), since we will get
|
||||
* at least one of those calls</li>
|
||||
* </ul>
|
||||
*
|
||||
* @param <V> the vertex type
|
||||
* @param <E> the edge type
|
||||
*/
|
||||
//@formatter:off
|
||||
public abstract class VisualGraphAbstractGraphMousePlugin<V extends VisualVertex,
|
||||
|
@ -46,13 +49,18 @@ public abstract class VisualGraphAbstractGraphMousePlugin<V extends VisualVertex
|
|||
protected E selectedEdge;
|
||||
|
||||
public VisualGraphAbstractGraphMousePlugin() {
|
||||
this(InputEvent.BUTTON1_MASK);
|
||||
this(InputEvent.BUTTON1_DOWN_MASK);
|
||||
}
|
||||
|
||||
public VisualGraphAbstractGraphMousePlugin(int selectionModifiers) {
|
||||
super(selectionModifiers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkModifiers(MouseEvent e) {
|
||||
return e.getModifiersEx() == modifiers;
|
||||
}
|
||||
|
||||
protected boolean checkForVertex(MouseEvent e) {
|
||||
if (!checkModifiers(e)) {
|
||||
selectedVertex = null;
|
||||
|
|
|
@ -24,7 +24,10 @@ import edu.uci.ics.jung.visualization.control.AnimatedPickingGraphMousePlugin;
|
|||
import ghidra.graph.viewer.*;
|
||||
|
||||
/**
|
||||
* A mouse handler to center a vertex when the header is double-clicked.
|
||||
* A mouse handler to center a vertex when the header is double-clicked
|
||||
*
|
||||
* @param <V> the vertex type
|
||||
* @param <E> the edge type
|
||||
*/
|
||||
public class VisualGraphAnimatedPickingGraphMousePlugin<V extends VisualVertex, E extends VisualEdge<V>>
|
||||
extends AnimatedPickingGraphMousePlugin<V, E> implements VisualGraphMousePlugin<V, E> {
|
||||
|
@ -32,7 +35,7 @@ public class VisualGraphAnimatedPickingGraphMousePlugin<V extends VisualVertex,
|
|||
private boolean isHandlingMouseEvents;
|
||||
|
||||
public VisualGraphAnimatedPickingGraphMousePlugin() {
|
||||
super(InputEvent.BUTTON1_MASK);
|
||||
super(InputEvent.BUTTON1_DOWN_MASK);
|
||||
this.cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
|
||||
}
|
||||
|
||||
|
|
|
@ -29,10 +29,17 @@ public class VisualGraphCursorRestoringGraphMousePlugin<V, E> extends AbstractGr
|
|||
super(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkModifiers(MouseEvent e) {
|
||||
return e.getModifiersEx() == modifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
// don't care
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
installCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR), e);
|
||||
}
|
||||
|
|
|
@ -38,9 +38,9 @@ public class VisualGraphEventForwardingGraphMousePlugin<V extends VisualVertex,
|
|||
|
||||
private boolean isHandlingEvent = false;
|
||||
|
||||
// TODO for deprecated usage note, see the VisualGraphMousePlugin interface
|
||||
public VisualGraphEventForwardingGraphMousePlugin() {
|
||||
this(InputEvent.BUTTON1_MASK | InputEvent.BUTTON2_MASK | InputEvent.BUTTON3_MASK);
|
||||
this(InputEvent.BUTTON1_DOWN_MASK | InputEvent.BUTTON2_DOWN_MASK |
|
||||
InputEvent.BUTTON3_DOWN_MASK);
|
||||
}
|
||||
|
||||
public VisualGraphEventForwardingGraphMousePlugin(int modifiers) {
|
||||
|
@ -50,18 +50,18 @@ public class VisualGraphEventForwardingGraphMousePlugin<V extends VisualVertex,
|
|||
|
||||
@Override
|
||||
public boolean checkModifiers(MouseEvent e) {
|
||||
int eventModifiers = e.getModifiers();
|
||||
int eventModifiers = e.getModifiersEx();
|
||||
eventModifiers = turnOffControlKey(eventModifiers);
|
||||
return ((eventModifiers & getModifiers()) == eventModifiers);
|
||||
}
|
||||
|
||||
private int turnOffControlKey(int eventModifiers) {
|
||||
return eventModifiers & (~DockingUtils.CONTROL_KEY_MODIFIER_MASK_DEPRECATED);
|
||||
return eventModifiers & (~DockingUtils.CONTROL_KEY_MODIFIER_MASK);
|
||||
}
|
||||
|
||||
private boolean isControlClick(MouseEvent e) {
|
||||
int allModifiers = e.getModifiers();
|
||||
int osSpecificMask = DockingUtils.CONTROL_KEY_MODIFIER_MASK_DEPRECATED;
|
||||
int allModifiers = e.getModifiersEx();
|
||||
int osSpecificMask = DockingUtils.CONTROL_KEY_MODIFIER_MASK;
|
||||
return (allModifiers & osSpecificMask) == osSpecificMask;
|
||||
|
||||
// can't use this until we fix the old modifiers usage
|
||||
|
|
|
@ -61,6 +61,11 @@ public class VisualGraphHoverMousePlugin<V extends VisualVertex, E extends Visua
|
|||
this.otherViewer = otherViewer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkModifiers(MouseEvent e) {
|
||||
return e.getModifiersEx() == modifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
lastMouseEvent = e;
|
||||
|
|
|
@ -28,7 +28,6 @@ import edu.uci.ics.jung.visualization.transform.MutableTransformer;
|
|||
import ghidra.graph.viewer.*;
|
||||
import ghidra.graph.viewer.renderer.*;
|
||||
|
||||
|
||||
/**
|
||||
* A simple plugin that allows clients to be notified of mouse events before any of the other
|
||||
* mouse plugins.
|
||||
|
@ -52,14 +51,15 @@ public class VisualGraphMouseTrackingGraphMousePlugin<V extends VisualVertex,
|
|||
private int mouseMovedCount;
|
||||
|
||||
public VisualGraphMouseTrackingGraphMousePlugin(GraphViewer<V, E> viewer) {
|
||||
super(InputEvent.BUTTON1_MASK | InputEvent.BUTTON2_MASK | InputEvent.BUTTON3_MASK);
|
||||
super(InputEvent.BUTTON1_DOWN_MASK | InputEvent.BUTTON2_DOWN_MASK |
|
||||
InputEvent.BUTTON3_DOWN_MASK);
|
||||
this.viewer = Objects.requireNonNull(viewer);
|
||||
viewer.addPostRenderPaintable(paintable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkModifiers(MouseEvent e) {
|
||||
int eventModifiers = e.getModifiers();
|
||||
int eventModifiers = e.getModifiersEx();
|
||||
eventModifiers = turnOffControlKey(eventModifiers);
|
||||
return ((eventModifiers & getModifiers()) == eventModifiers);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* 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.
|
||||
|
@ -39,18 +38,17 @@ public class VisualGraphPickingGraphMousePlugin<V extends VisualVertex, E extend
|
|||
// ALERT: -this class was created because mouseDragged() has a bug that generates a NPE
|
||||
// -also, mousePressed() has a bug in that it does not check the modifiers when the method is entered
|
||||
|
||||
// TODO for deprecated usage note, see the VisualGraphMousePlugin interface
|
||||
public VisualGraphPickingGraphMousePlugin() {
|
||||
super(InputEvent.BUTTON1_MASK,
|
||||
InputEvent.BUTTON1_MASK | DockingUtils.CONTROL_KEY_MODIFIER_MASK_DEPRECATED);
|
||||
super(InputEvent.BUTTON1_DOWN_MASK,
|
||||
InputEvent.BUTTON1_DOWN_MASK | DockingUtils.CONTROL_KEY_MODIFIER_MASK);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkModifiers(MouseEvent e) {
|
||||
if (e.getModifiers() == addToSelectionModifiers) {
|
||||
if (e.getModifiersEx() == addToSelectionModifiers) {
|
||||
return true;
|
||||
}
|
||||
return super.checkModifiers(e);
|
||||
return e.getModifiersEx() == modifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -80,7 +78,7 @@ public class VisualGraphPickingGraphMousePlugin<V extends VisualVertex, E extend
|
|||
|
||||
private void increaseDragRectangle(MouseEvent e) {
|
||||
Point2D out = e.getPoint();
|
||||
int theModifiers = e.getModifiers();
|
||||
int theModifiers = e.getModifiersEx();
|
||||
if (theModifiers == addToSelectionModifiers || theModifiers == modifiers) {
|
||||
if (down != null) {
|
||||
rect.setFrameFromDiagonal(down, out);
|
||||
|
|
|
@ -29,7 +29,7 @@ public abstract class VisualGraphSatelliteAbstractGraphMousePlugin<V extends Vis
|
|||
extends VisualGraphAbstractGraphMousePlugin<V, E> {
|
||||
|
||||
public VisualGraphSatelliteAbstractGraphMousePlugin() {
|
||||
this(InputEvent.BUTTON1_MASK);
|
||||
this(InputEvent.BUTTON1_DOWN_MASK);
|
||||
}
|
||||
|
||||
public VisualGraphSatelliteAbstractGraphMousePlugin(int selectionModifiers) {
|
||||
|
|
|
@ -1,25 +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.graph.viewer.event.mouse;
|
||||
|
||||
import ghidra.graph.viewer.VisualEdge;
|
||||
import ghidra.graph.viewer.VisualVertex;
|
||||
|
||||
public class VisualGraphSatelliteAnimatedPickingGraphMousePlugin<V extends VisualVertex, E extends VisualEdge<V>>
|
||||
extends VisualGraphAnimatedPickingGraphMousePlugin<V, E> {
|
||||
|
||||
// TODO - delete this class--it should not longer be needed
|
||||
}
|
|
@ -1,25 +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.graph.viewer.event.mouse;
|
||||
|
||||
import ghidra.graph.viewer.VisualEdge;
|
||||
import ghidra.graph.viewer.VisualVertex;
|
||||
|
||||
public class VisualGraphSatelliteEdgeSelectionGraphMousePlugin<V extends VisualVertex, E extends VisualEdge<V>>
|
||||
extends VisualGraphEdgeSelectionGraphMousePlugin<V, E> {
|
||||
|
||||
// TODO this class probably can be deleted now
|
||||
}
|
|
@ -25,7 +25,7 @@ public class VisualGraphSatelliteNavigationGraphMousePlugin<V extends VisualVert
|
|||
extends VisualGraphSatelliteAbstractGraphMousePlugin<V, E> {
|
||||
|
||||
public VisualGraphSatelliteNavigationGraphMousePlugin() {
|
||||
super(InputEvent.BUTTON1_MASK);
|
||||
super(InputEvent.BUTTON1_DOWN_MASK);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -46,7 +46,7 @@ public class VisualGraphSatelliteScalingGraphMousePlugin<V extends VisualVertex,
|
|||
VisualGraphOptions options = viewer.getOptions();
|
||||
boolean scrollWheelPans = options.getScrollWheelPans();
|
||||
int scrollWheelModifierToggle = DockingUtils.CONTROL_KEY_MODIFIER_MASK;
|
||||
int eventModifiers = e.getModifiers();
|
||||
int eventModifiers = e.getModifiersEx();
|
||||
if (scrollWheelPans) {
|
||||
// scrolling will zoom if modified (unmodified in this case means to pan)
|
||||
return (scrollWheelModifierToggle & eventModifiers) == scrollWheelModifierToggle;
|
||||
|
|
|
@ -35,7 +35,7 @@ public class VisualGraphSatelliteTranslatingGraphMousePlugin<V extends VisualVer
|
|||
|
||||
// Note: for ideas on resizing instead of moving, see LensTranslatingGraphMousePlugin
|
||||
public VisualGraphSatelliteTranslatingGraphMousePlugin() {
|
||||
super(InputEvent.BUTTON1_MASK);
|
||||
super(InputEvent.BUTTON1_DOWN_MASK);
|
||||
this.cursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,9 @@ import ghidra.graph.viewer.options.VisualGraphOptions;
|
|||
/**
|
||||
* Overridden implementation that allows us to change scaling behavior through options. This
|
||||
* class works on the opposite modifier setup as FunctionGraphScrollWheelPanningPlugin.
|
||||
*
|
||||
* @param <V> the vertex type
|
||||
* @param <E> the edge type
|
||||
*/
|
||||
public class VisualGraphScalingGraphMousePlugin<V extends VisualVertex, E extends VisualEdge<V>>
|
||||
extends ScalingGraphMousePlugin implements VisualGraphMousePlugin<V, E> {
|
||||
|
@ -51,8 +54,8 @@ public class VisualGraphScalingGraphMousePlugin<V extends VisualVertex, E extend
|
|||
// TODO for deprecated usage note, see the VisualGraphMousePlugin interface
|
||||
VisualGraphOptions options = viewer.getOptions();
|
||||
boolean scrollWheelPans = options.getScrollWheelPans();
|
||||
int scrollWheelModifierToggle = DockingUtils.CONTROL_KEY_MODIFIER_MASK_DEPRECATED;
|
||||
int eventModifiers = e.getModifiers();
|
||||
int scrollWheelModifierToggle = DockingUtils.CONTROL_KEY_MODIFIER_MASK;
|
||||
int eventModifiers = e.getModifiersEx();
|
||||
if (scrollWheelPans) {
|
||||
// scrolling will zoom if modified (unmodified in this case means to pan)
|
||||
return (scrollWheelModifierToggle & eventModifiers) == scrollWheelModifierToggle;
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
package ghidra.graph.viewer.event.mouse;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.event.MouseWheelListener;
|
||||
import java.awt.event.*;
|
||||
|
||||
import docking.DockingUtils;
|
||||
import edu.uci.ics.jung.visualization.control.AbstractGraphMousePlugin;
|
||||
|
@ -31,9 +30,14 @@ public class VisualGraphScreenPositioningPlugin<V extends VisualVertex, E extend
|
|||
super(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkModifiers(MouseEvent e) {
|
||||
return e.getModifiersEx() == modifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseWheelMoved(MouseWheelEvent e) {
|
||||
int eventModifiers = e.getModifiers();
|
||||
int eventModifiers = e.getModifiersEx();
|
||||
boolean controlKeyDown = (eventModifiers & DockingUtils.CONTROL_KEY_MODIFIER_MASK) != 0;
|
||||
if (!controlKeyDown) {
|
||||
return;
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
package ghidra.graph.viewer.event.mouse;
|
||||
|
||||
import java.awt.Point;
|
||||
import java.awt.event.MouseWheelEvent;
|
||||
import java.awt.event.MouseWheelListener;
|
||||
import java.awt.event.*;
|
||||
|
||||
import docking.DockingUtils;
|
||||
import edu.uci.ics.jung.visualization.control.AbstractGraphMousePlugin;
|
||||
|
@ -35,6 +34,11 @@ public class VisualGraphScrollWheelPanningPlugin<V extends VisualVertex,
|
|||
super(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkModifiers(MouseEvent e) {
|
||||
return e.getModifiersEx() == modifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseWheelMoved(MouseWheelEvent e) {
|
||||
if (!isScrollModifiers(e)) {
|
||||
|
@ -91,7 +95,7 @@ public class VisualGraphScrollWheelPanningPlugin<V extends VisualVertex,
|
|||
VisualGraphOptions options = viewer.getOptions();
|
||||
boolean scrollWheelPans = options.getScrollWheelPans();
|
||||
int scrollWheelModifierToggle = DockingUtils.CONTROL_KEY_MODIFIER_MASK;
|
||||
int eventModifiers = e.getModifiers();
|
||||
int eventModifiers = e.getModifiersEx();
|
||||
if (scrollWheelPans) {
|
||||
// scrolling will pan if *not* modified (modified in this case means to zoom)
|
||||
return !((scrollWheelModifierToggle & eventModifiers) == scrollWheelModifierToggle);
|
||||
|
|
|
@ -33,8 +33,8 @@ import ghidra.graph.viewer.*;
|
|||
* the graph display in the x and y direction. The default MouseButtonOne modifier can be overridden
|
||||
* to cause a different mouse gesture to translate the display.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @param <V> the vertex type
|
||||
* @param <E> the edge type
|
||||
*/
|
||||
public class VisualGraphTranslatingGraphMousePlugin<V extends VisualVertex, E extends VisualEdge<V>>
|
||||
extends AbstractGraphMousePlugin
|
||||
|
@ -43,9 +43,8 @@ public class VisualGraphTranslatingGraphMousePlugin<V extends VisualVertex, E ex
|
|||
private boolean panning;
|
||||
private boolean isHandlingEvent;
|
||||
|
||||
// TODO for deprecated usage note, see the VisualGraphMousePlugin interface
|
||||
public VisualGraphTranslatingGraphMousePlugin() {
|
||||
this(InputEvent.BUTTON1_MASK);
|
||||
this(InputEvent.BUTTON1_DOWN_MASK);
|
||||
}
|
||||
|
||||
public VisualGraphTranslatingGraphMousePlugin(int modifiers) {
|
||||
|
@ -53,6 +52,11 @@ public class VisualGraphTranslatingGraphMousePlugin<V extends VisualVertex, E ex
|
|||
this.cursor = Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkModifiers(MouseEvent e) {
|
||||
return e.getModifiersEx() == modifiers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
GraphViewer<V, E> viewer = getGraphViewer(e);
|
||||
|
@ -158,7 +162,7 @@ public class VisualGraphTranslatingGraphMousePlugin<V extends VisualVertex, E ex
|
|||
}
|
||||
|
||||
private boolean checkModifiersForCursor(MouseEvent e) {
|
||||
if (e.getModifiers() == 0) {
|
||||
if (e.getModifiersEx() == 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -24,13 +24,15 @@ import ghidra.graph.viewer.*;
|
|||
/**
|
||||
* A handler to zoom nodes when double-clicked. If the vertex is zoomed out, then we will zoom
|
||||
* in and center. If the vertex is zoomed to full size, then we will zoom out and center.
|
||||
*
|
||||
* @param <V> the vertex type
|
||||
* @param <E> the edge type
|
||||
*/
|
||||
public class VisualGraphZoomingPickingGraphMousePlugin<V extends VisualVertex, E extends VisualEdge<V>>
|
||||
extends VisualGraphAbstractGraphMousePlugin<V, E> {
|
||||
|
||||
// TODO for deprecated usage note, see the VisualGraphMousePlugin interface
|
||||
public VisualGraphZoomingPickingGraphMousePlugin() {
|
||||
super(InputEvent.BUTTON1_MASK);
|
||||
super(InputEvent.BUTTON1_DOWN_MASK);
|
||||
this.cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
/* ###
|
||||
* 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.graph.viewer.popup;
|
||||
|
||||
import java.awt.Window;
|
||||
import java.awt.event.*;
|
||||
|
||||
import javax.swing.*;
|
||||
|
||||
import docking.widgets.PopupWindow;
|
||||
|
||||
/**
|
||||
* A class to control popups for graph clients, bypassing Java's default tool tip mechanism
|
||||
*
|
||||
* @param <V> the vertex type
|
||||
* @param <E> the edge type
|
||||
*/
|
||||
public class PopupRegulator<V, E> {
|
||||
|
||||
private int popupDelay = 1000;
|
||||
|
||||
/**
|
||||
* We need this timer because the default mechanism for triggering popups doesn't
|
||||
* always work. We use this timer in conjunction with a mouse motion listener to
|
||||
* get the results we want.
|
||||
*/
|
||||
private Timer popupTimer;
|
||||
private MouseEvent popupMouseEvent;
|
||||
|
||||
/** the current target (vertex or edge) of a popup window */
|
||||
private Object nextPopupTarget;
|
||||
|
||||
/**
|
||||
* This value is not null when the user moves the cursor over a target for which a
|
||||
* popup is already showing. We use this value to prevent showing a popup multiple times
|
||||
* while over a single node.
|
||||
*/
|
||||
private Object lastShownPopupTarget;
|
||||
|
||||
/** The tooltip info used when showing the popup */
|
||||
private ToolTipInfo<?> currentToolTipInfo;
|
||||
|
||||
private PopupSource<V, E> popupSource;
|
||||
private PopupWindow popupWindow;
|
||||
private boolean showPopups = true;
|
||||
|
||||
public PopupRegulator(PopupSource<V, E> popupSupplier) {
|
||||
this.popupSource = popupSupplier;
|
||||
popupTimer = new Timer(popupDelay, e -> {
|
||||
if (isPopupShowing()) {
|
||||
return; // don't show any new popups while the user is perusing
|
||||
}
|
||||
showPopupForMouseEvent(popupMouseEvent);
|
||||
});
|
||||
|
||||
popupTimer.setRepeats(false);
|
||||
|
||||
popupSupplier.addMouseMotionListener(new MouseMotionListener() {
|
||||
@Override
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
hidePopupTooltips();
|
||||
popupTimer.stop();
|
||||
popupMouseEvent = null; // clear any queued popups
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
popupMouseEvent = e;
|
||||
|
||||
// this clears out the current last popup shown so that the user can
|
||||
// move off and on a node to re-show the popup
|
||||
savePopupTarget(e);
|
||||
|
||||
// make sure the popup gets triggered eventually
|
||||
popupTimer.restart();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this class's popup is showing
|
||||
* @return true if this class's popup is showing
|
||||
*/
|
||||
public boolean isPopupShowing() {
|
||||
return popupWindow != null && popupWindow.isShowing();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time between mouse movements to wait before showing this class's popup
|
||||
* @param delayMs the delay
|
||||
*/
|
||||
public void setPopupDelay(int delayMs) {
|
||||
popupTimer.stop();
|
||||
popupTimer.setDelay(delayMs);
|
||||
popupTimer.setInitialDelay(delayMs);
|
||||
popupDelay = delayMs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the enablement of this class's popup
|
||||
* @param visible true to have popups enabled
|
||||
*/
|
||||
public void setPopupsVisible(boolean visible) {
|
||||
this.showPopups = visible;
|
||||
if (!showPopups) {
|
||||
hidePopupTooltips();
|
||||
}
|
||||
}
|
||||
|
||||
private void showPopupForMouseEvent(MouseEvent event) {
|
||||
if (!showPopups) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ToolTipInfo<?> toolTipInfo = popupSource.getToolTipInfo(event);
|
||||
JComponent toolTipComponent = toolTipInfo.getToolTipComponent();
|
||||
boolean isCustomJavaTooltip = !(toolTipComponent instanceof JToolTip);
|
||||
if (lastShownPopupTarget == nextPopupTarget && isCustomJavaTooltip) {
|
||||
//
|
||||
// Kinda Hacky:
|
||||
// We don't show repeated popups for the same item (the user has to move away
|
||||
// and then come back to re-show the popup). However, one caveat to this is that
|
||||
// we do want to allow the user to see popups for the toolbar actions always. So,
|
||||
// only return here if we have already shown a popup for the item *and* we are
|
||||
// using a custom tooltip (which is used to show a vertex tooltip or an edge
|
||||
// tooltip)
|
||||
return;
|
||||
}
|
||||
|
||||
currentToolTipInfo = toolTipInfo;
|
||||
showTooltip(currentToolTipInfo);
|
||||
}
|
||||
|
||||
private void popupShown() {
|
||||
lastShownPopupTarget = nextPopupTarget;
|
||||
currentToolTipInfo.emphasize();
|
||||
popupSource.repaint();
|
||||
}
|
||||
|
||||
private void popupHidden() {
|
||||
currentToolTipInfo.deEmphasize();
|
||||
popupSource.repaint();
|
||||
}
|
||||
|
||||
private void savePopupTarget(MouseEvent event) {
|
||||
nextPopupTarget = null;
|
||||
V vertex = popupSource.getVertex(event);
|
||||
if (vertex != null) {
|
||||
nextPopupTarget = vertex;
|
||||
}
|
||||
else {
|
||||
E edge = popupSource.getEdge(event);
|
||||
nextPopupTarget = edge;
|
||||
}
|
||||
|
||||
if (nextPopupTarget == null) {
|
||||
// We've moved off of a target. We will clear that last target so the user can
|
||||
// mouse off of a vertex and back on in order to trigger a new popup
|
||||
lastShownPopupTarget = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void hidePopupTooltips() {
|
||||
if (popupWindow != null && popupWindow.isShowing()) {
|
||||
popupWindow.hide();
|
||||
// don't call dispose, or we don't get our componentHidden() callback
|
||||
// popupWindow.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void showTooltip(ToolTipInfo<?> info) {
|
||||
JComponent tipComponent = info.getToolTipComponent();
|
||||
if (tipComponent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
MouseEvent event = info.getMouseEvent();
|
||||
showPopupWindow(event, tipComponent);
|
||||
}
|
||||
|
||||
private void showPopupWindow(MouseEvent event, JComponent component) {
|
||||
MenuSelectionManager menuManager = MenuSelectionManager.defaultManager();
|
||||
if (menuManager.getSelectedPath().length != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Window parentWindow = popupSource.getPopupParent();
|
||||
popupWindow = new PopupWindow(parentWindow, component);
|
||||
|
||||
popupWindow.addComponentListener(new ComponentAdapter() {
|
||||
@Override
|
||||
public void componentShown(ComponentEvent e) {
|
||||
popupShown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void componentHidden(ComponentEvent e) {
|
||||
popupHidden();
|
||||
}
|
||||
});
|
||||
|
||||
popupWindow.showPopup(event);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/* ###
|
||||
* 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.graph.viewer.popup;
|
||||
|
||||
import java.awt.Window;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseMotionListener;
|
||||
|
||||
/**
|
||||
* An interface that provides graph and component information to the {@link PopupRegulator}
|
||||
*
|
||||
* @param <V> the vertex type
|
||||
* @param <E> the edge type
|
||||
*/
|
||||
public interface PopupSource<V, E> {
|
||||
|
||||
/**
|
||||
* Returns the tool tip info object for the given mouse event. Implementations will use the
|
||||
* event to determine whether a popup should be created for a vertex, edge, the graph or
|
||||
* not at all.
|
||||
*
|
||||
* @param event the event
|
||||
* @return the info; null for no popup
|
||||
*/
|
||||
public ToolTipInfo<?> getToolTipInfo(MouseEvent event);
|
||||
|
||||
/**
|
||||
* Returns a vertex for the given event
|
||||
* @param event the event
|
||||
* @return the vertex or null
|
||||
*/
|
||||
public V getVertex(MouseEvent event);
|
||||
|
||||
/**
|
||||
* Returns an edge for the given event
|
||||
* @param event the event
|
||||
* @return the edge or null
|
||||
*/
|
||||
public E getEdge(MouseEvent event);
|
||||
|
||||
/**
|
||||
* Adds the given mouse motion listener to the graph component. This allows the popup
|
||||
* regulator to decided when to show and hide popups.
|
||||
*
|
||||
* @param l the listener
|
||||
*/
|
||||
public void addMouseMotionListener(MouseMotionListener l);
|
||||
|
||||
/**
|
||||
* Signals that the graph needs to repaint
|
||||
*/
|
||||
public void repaint();
|
||||
|
||||
/**
|
||||
* Returns a suitable window parent for the popup window
|
||||
* @return the window parent
|
||||
*/
|
||||
public Window getPopupParent();
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/* ###
|
||||
* 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.graph.viewer.popup;
|
||||
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
|
||||
/**
|
||||
* Basic container object that knows how to generate tooltips
|
||||
*
|
||||
* @param <T> the type of object for which to create a tooltip
|
||||
*/
|
||||
public abstract class ToolTipInfo<T> {
|
||||
|
||||
protected final MouseEvent event;
|
||||
protected final T graphObject;
|
||||
private JComponent tooltipComponent;
|
||||
|
||||
public ToolTipInfo(MouseEvent event, T t) {
|
||||
this.event = event;
|
||||
this.graphObject = t;
|
||||
tooltipComponent = createToolTipComponent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a tool tip component
|
||||
* @return the tool tip component
|
||||
*/
|
||||
protected abstract JComponent createToolTipComponent();
|
||||
|
||||
/**
|
||||
* Signals for the implementation to emphasis the original graph object passed to this info
|
||||
*/
|
||||
protected abstract void emphasize();
|
||||
|
||||
/**
|
||||
* Signals for the implementation to turn off emphasis
|
||||
*/
|
||||
protected abstract void deEmphasize();
|
||||
|
||||
/**
|
||||
* Returns the mouse event from this tool tip info
|
||||
* @return the mouse event from this tool tip info
|
||||
*/
|
||||
MouseEvent getMouseEvent() {
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tool tip component created by this info
|
||||
* @return the tool tip component created by this info
|
||||
*/
|
||||
JComponent getToolTipComponent() {
|
||||
return tooltipComponent;
|
||||
}
|
||||
}
|
|
@ -16,14 +16,19 @@
|
|||
package ghidra.service.graph;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
|
||||
/**
|
||||
* Generic directed graph edge implementation
|
||||
*/
|
||||
public class AttributedEdge extends Attributed {
|
||||
private final String id;
|
||||
|
||||
/**
|
||||
* cache of the edge label parsed as html
|
||||
* Cache of the edge label parsed as html
|
||||
*/
|
||||
private String htmlString;
|
||||
|
||||
|
@ -41,20 +46,27 @@ public class AttributedEdge extends Attributed {
|
|||
}
|
||||
|
||||
/**
|
||||
* create (once) the html representation of the key/values for this edge
|
||||
* The html representation of the key/values for this edge
|
||||
* @return html formatted label for the edge
|
||||
*/
|
||||
public String getHtmlString() {
|
||||
if (htmlString == null) {
|
||||
StringBuilder buf = new StringBuilder("<html>");
|
||||
for (Map.Entry<String, String> entry : entrySet()) {
|
||||
buf.append(entry.getKey());
|
||||
buf.append(":");
|
||||
buf.append(entry.getValue());
|
||||
buf.append("<br>");
|
||||
}
|
||||
htmlString = buf.toString();
|
||||
if (htmlString != null) {
|
||||
return htmlString;
|
||||
}
|
||||
|
||||
Set<Entry<String, String>> entries = entrySet();
|
||||
if (entries.isEmpty()) {
|
||||
return ""; // empty so tooltip clients can handle empty data
|
||||
}
|
||||
|
||||
StringBuilder buf = new StringBuilder("<html>");
|
||||
for (Map.Entry<String, String> entry : entries) {
|
||||
buf.append(entry.getKey());
|
||||
buf.append(":");
|
||||
buf.append(StringEscapeUtils.escapeHtml4(entry.getValue()));
|
||||
buf.append("<br>");
|
||||
}
|
||||
htmlString = buf.toString();
|
||||
return htmlString;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
*/
|
||||
package ghidra.service.graph;
|
||||
|
||||
import org.apache.commons.text.StringEscapeUtils;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Graph vertex with attributes
|
||||
|
@ -85,16 +85,24 @@ public class AttributedVertex extends Attributed {
|
|||
* @return the html string
|
||||
*/
|
||||
public String getHtmlString() {
|
||||
if (htmlString == null) {
|
||||
StringBuilder buf = new StringBuilder("<html>");
|
||||
for (Map.Entry<String, String> entry : entrySet()) {
|
||||
buf.append(entry.getKey());
|
||||
buf.append(":");
|
||||
buf.append(StringEscapeUtils.escapeHtml4(entry.getValue()));
|
||||
buf.append("<br>");
|
||||
}
|
||||
htmlString = buf.toString();
|
||||
|
||||
if (htmlString != null) {
|
||||
return htmlString;
|
||||
}
|
||||
|
||||
Set<Entry<String, String>> entries = entrySet();
|
||||
if (entries.isEmpty()) {
|
||||
return ""; // empty so tooltip clients can handle empty data
|
||||
}
|
||||
|
||||
StringBuilder buf = new StringBuilder("<html>");
|
||||
for (Map.Entry<String, String> entry : entries) {
|
||||
buf.append(entry.getKey());
|
||||
buf.append(":");
|
||||
buf.append(entry.getValue());
|
||||
buf.append("<br>");
|
||||
}
|
||||
htmlString = buf.toString();
|
||||
return htmlString;
|
||||
}
|
||||
|
||||
|
|
|
@ -404,7 +404,7 @@ public abstract class PluginTool extends AbstractDockingTool {
|
|||
"You cannot persist generic tools: " + getClass().getName());
|
||||
}
|
||||
|
||||
public void restoreWindowingDataFromXml(Element windowData) {
|
||||
public void restoreWindowingDataFromXml(Element element) {
|
||||
throw new UnsupportedOperationException(
|
||||
"You cannot persist generic tools: " + getClass().getName());
|
||||
}
|
||||
|
@ -553,6 +553,7 @@ public abstract class PluginTool extends AbstractDockingTool {
|
|||
}
|
||||
|
||||
restoreOptionsFromXml(root);
|
||||
winMgr.restorePreferencesFromXML(root);
|
||||
setDefaultOptionValues();
|
||||
boolean hasErrors = false;
|
||||
try {
|
||||
|
@ -563,7 +564,7 @@ public abstract class PluginTool extends AbstractDockingTool {
|
|||
Msg.showError(this, getToolFrame(), "Error Restoring Plugins", e.getMessage());
|
||||
}
|
||||
|
||||
winMgr.restoreFromXML(root);
|
||||
winMgr.restoreWindowDataFromXml(root);
|
||||
winMgr.setToolName(fullName);
|
||||
return hasErrors;
|
||||
}
|
||||
|
|
|
@ -125,8 +125,8 @@ public class GhidraTool extends PluginTool {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void restoreWindowingDataFromXml(Element windowData) {
|
||||
winMgr.restoreWindowDataFromXml(windowData);
|
||||
public void restoreWindowingDataFromXml(Element rootElement) {
|
||||
winMgr.restoreWindowDataFromXml(rootElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -166,8 +166,8 @@ class WorkspaceImpl implements Workspace {
|
|||
|
||||
Iterator<?> iter = root.getChildren("RUNNING_TOOL").iterator();
|
||||
while (iter.hasNext()) {
|
||||
Element elememnt = (Element) iter.next();
|
||||
String toolName = elememnt.getAttributeValue(ToolTemplate.TOOL_NAME_XML_NAME);
|
||||
Element element = (Element) iter.next();
|
||||
String toolName = element.getAttributeValue(ToolTemplate.TOOL_NAME_XML_NAME);
|
||||
if (toolName == null) {
|
||||
continue;
|
||||
}
|
||||
|
@ -182,12 +182,9 @@ class WorkspaceImpl implements Workspace {
|
|||
}
|
||||
|
||||
boolean hadChanges = tool.hasConfigChanged();
|
||||
Element windowData = elememnt.getChild("ROOT_NODE");
|
||||
if (windowData != null) { // backward compatibility
|
||||
tool.restoreWindowingDataFromXml(windowData);
|
||||
}
|
||||
tool.restoreWindowingDataFromXml(element);
|
||||
|
||||
Element toolDataElem = elememnt.getChild("DATA_STATE");
|
||||
Element toolDataElem = element.getChild("DATA_STATE");
|
||||
tool.restoreDataStateFromXml(toolDataElem);
|
||||
if (hadChanges) {
|
||||
// restore the dirty state, which is cleared by the restoreDataState call
|
||||
|
|
|
@ -52,10 +52,24 @@ generateGrammarSource {
|
|||
include "ghidra/sleigh/grammar/SleighCompiler.g"
|
||||
|
||||
// README: See src/main/antlr/ghidra/sleigh/grammar/README.txt for an explanation of this.
|
||||
|
||||
doFirst {
|
||||
// Ensure that SleighLexar.tokens is rebuilt by removing it if any of the
|
||||
// contributing grammar files have changed. Antlr plugin does not know
|
||||
// about the SleighLexar.tokens dependency on changes to BaseLexer.g,
|
||||
// DisplayLexer.g or SemanticLexer.g
|
||||
delete file("$buildDir/${genSrcDir}/ghidra/sleigh/grammar/SleighLexer.tokens")
|
||||
}
|
||||
|
||||
doLast {
|
||||
// SleighLexar.g is only needed to produce SleighLexar.tokens.
|
||||
// Remove its generated java artifacts which may conflict
|
||||
delete fileTree("$buildDir/${genSrcDir}/ghidra/sleigh/grammar") {
|
||||
include "SleighLexer*.java"
|
||||
}
|
||||
// antlr src directories cause generated java files to output
|
||||
// into the correct package directories, however we need to add
|
||||
// the appropriate java package statement which is missing.
|
||||
fileTree("$buildDir/${genSrcDir}/ghidra/sleigh/grammar") {
|
||||
include "*.java"
|
||||
}.each { File src ->
|
||||
|
|
|
@ -119,6 +119,7 @@ tokens {
|
|||
OP_SUBTABLE;
|
||||
OP_TABLE;
|
||||
OP_TOKEN;
|
||||
OP_TOKEN_ENDIAN;
|
||||
OP_TRUNCATION_SIZE;
|
||||
OP_TYPE;
|
||||
OP_UNIMPL;
|
||||
|
|
|
@ -183,10 +183,20 @@ tokendef
|
|||
if (sym != null) {
|
||||
redefinedError(sym, n, "token");
|
||||
} else {
|
||||
$tokendef::tokenSymbol = sc.defineToken(find(n), $n.value.getText(), $i.value.intValue());
|
||||
$tokendef::tokenSymbol = sc.defineToken(find(n), $n.value.getText(), $i.value.intValue(), 0);
|
||||
}
|
||||
}
|
||||
} fielddefs)
|
||||
| ^(OP_TOKEN_ENDIAN n=specific_identifier["token definition"] i=integer s=endian {
|
||||
if (n != null) {
|
||||
SleighSymbol sym = sc.findSymbol($n.value.getText());
|
||||
if (sym != null) {
|
||||
redefinedError(sym, n, "token");
|
||||
} else {
|
||||
$tokendef::tokenSymbol = sc.defineToken(find(n), $n.value.getText(), $i.value.intValue(), $s.value ==0 ? -1 : 1);
|
||||
}
|
||||
}
|
||||
} fielddefs)
|
||||
;
|
||||
|
||||
fielddefs
|
||||
|
|
|
@ -60,6 +60,7 @@ aligndef
|
|||
|
||||
tokendef
|
||||
: ^(OP_TOKEN n=identifier i=integer { out("define token " + $n.value + "(" + $i.value + ")"); } fielddefs)
|
||||
| ^(OP_TOKEN_ENDIAN n=identifier i=integer s=endian { out("define token endian" + $n.value + "(" + $i.value + ")"); } fielddefs)
|
||||
;
|
||||
|
||||
fielddefs
|
||||
|
|
|
@ -74,6 +74,7 @@ aligndef
|
|||
|
||||
tokendef
|
||||
: lc=KEY_DEFINE KEY_TOKEN identifier LPAREN integer rp=RPAREN fielddefs[$rp] -> ^(OP_TOKEN[$lc, "define token"] identifier integer fielddefs)
|
||||
| lc=KEY_DEFINE KEY_TOKEN identifier LPAREN integer RPAREN rp=KEY_ENDIAN ASSIGN endian fielddefs[$rp] -> ^(OP_TOKEN_ENDIAN[$lc, "define token"] identifier integer endian fielddefs)
|
||||
;
|
||||
|
||||
fielddefs[Token lc]
|
||||
|
|
|
@ -888,11 +888,13 @@ public class SleighLanguage implements Language {
|
|||
throw new SleighException(".sla file for " + getLanguageID() + " has the wrong format");
|
||||
}
|
||||
boolean isBigEndian = SpecXmlUtils.decodeBoolean(el.getAttribute("bigendian"));
|
||||
// check the instruction endianess, not the program data endianess
|
||||
if (isBigEndian ^ description.getInstructionEndian().isBigEndian()) {
|
||||
throw new SleighException(
|
||||
".ldefs says " + getLanguageID() + " is " + description.getInstructionEndian() +
|
||||
" but .sla says " + el.getAttribute("bigendian"));
|
||||
if (isBigEndian ^ description.getEndian().isBigEndian()) {
|
||||
if (description.getInstructionEndian().isBigEndian() == description.getEndian()
|
||||
.isBigEndian()) {
|
||||
throw new SleighException(
|
||||
".ldefs says " + getLanguageID() + " is " + description.getEndian() +
|
||||
" but .sla says " + el.getAttribute("bigendian"));
|
||||
}
|
||||
}
|
||||
uniqueBase = SpecXmlUtils.decodeLong(el.getAttribute("uniqbase"));
|
||||
alignment = SpecXmlUtils.decodeInt(el.getAttribute("align"));
|
||||
|
|
|
@ -310,10 +310,12 @@ public class Emulate {
|
|||
else {
|
||||
takeBranch = memstate.getValue(condVar) != 0;
|
||||
}
|
||||
if (takeBranch)
|
||||
if (takeBranch) {
|
||||
executeBranch(op);
|
||||
else
|
||||
}
|
||||
else {
|
||||
fallthruOp();
|
||||
}
|
||||
}
|
||||
|
||||
/// Since the full instruction is cached, we can do relative branches properly
|
||||
|
@ -324,10 +326,12 @@ public class Emulate {
|
|||
long id = destaddr.getOffset();
|
||||
id = id + current_op;
|
||||
current_op = (int) id;
|
||||
if (current_op == pcode.length)
|
||||
if (current_op == pcode.length) {
|
||||
fallthruOp();
|
||||
else if ((current_op < 0) || (current_op >= pcode.length))
|
||||
}
|
||||
else if ((current_op < 0) || (current_op >= pcode.length)) {
|
||||
throw new LowlevelError("Bad intra-instruction branch");
|
||||
}
|
||||
}
|
||||
else {
|
||||
setCurrentAddress(destaddr);
|
||||
|
@ -451,18 +455,18 @@ public class Emulate {
|
|||
"Unsupported pcode op (opcode=" + op.getOpcode() + ", seq=" + op.getSeqnum() + ")");
|
||||
}
|
||||
if (behave instanceof UnaryOpBehavior) {
|
||||
UnaryOpBehavior uniaryBehave = (UnaryOpBehavior) behave;
|
||||
UnaryOpBehavior unaryBehave = (UnaryOpBehavior) behave;
|
||||
Varnode in1var = op.getInput(0);
|
||||
Varnode outvar = op.getOutput();
|
||||
if (in1var.getSize() > 8 || outvar.getSize() > 8) {
|
||||
BigInteger in1 = memstate.getBigInteger(op.getInput(0), false);
|
||||
BigInteger out = uniaryBehave.evaluateUnary(op.getOutput().getSize(),
|
||||
BigInteger out = unaryBehave.evaluateUnary(op.getOutput().getSize(),
|
||||
op.getInput(0).getSize(), in1);
|
||||
memstate.setValue(op.getOutput(), out);
|
||||
}
|
||||
else {
|
||||
long in1 = memstate.getValue(op.getInput(0));
|
||||
long out = uniaryBehave.evaluateUnary(op.getOutput().getSize(),
|
||||
long out = unaryBehave.evaluateUnary(op.getOutput().getSize(),
|
||||
op.getInput(0).getSize(), in1);
|
||||
memstate.setValue(op.getOutput(), out);
|
||||
}
|
||||
|
|
|
@ -20,9 +20,28 @@ import generic.stl.MapSTL;
|
|||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
|
||||
/**
|
||||
* An subclass of {@link MemoryBank} intended for modeling the "unique" memory
|
||||
* space. The space is byte-addressable and paging is not supported.
|
||||
*/
|
||||
public class UniqueMemoryBank extends MemoryBank {
|
||||
|
||||
protected MapSTL<Long, byte[]> map = new ComparableMapSTL<Long, byte[]>();
|
||||
/**A map from {@link Long} offsets to byte values would require many lookups.
|
||||
* As an optimization, this map is defined from {@link Long} values to
|
||||
* {@link WordInfo} objects, each of which represents an eight-byte word
|
||||
* of memory. Each key in this map must be 0 mod 8.
|
||||
*/
|
||||
protected MapSTL<Long, WordInfo> map = new ComparableMapSTL<Long, WordInfo>();
|
||||
|
||||
private static final long ALIGNMENT_MASK = 0xfffffffffffffff8L;
|
||||
|
||||
//note that WordInfo use the bits in a byte to record whether
|
||||
//or not a given byte has been written to, so you can't just
|
||||
//change WORD_SIZE to another value and without also changing
|
||||
//the implementation of WordInfo
|
||||
private static final int WORD_SIZE = 8;
|
||||
|
||||
private byte[] buffer = new byte[WORD_SIZE];
|
||||
|
||||
public UniqueMemoryBank(AddressSpace spc, boolean isBigEndian) {
|
||||
super(spc, isBigEndian, 0, null);
|
||||
|
@ -45,24 +64,93 @@ public class UniqueMemoryBank extends MemoryBank {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int getChunk(long addrOffset, int size, byte[] res, boolean ignoreFault) {
|
||||
byte[] value = map.get(addrOffset);
|
||||
if (value == null) {
|
||||
throw new LowlevelError("Unique value read before written: 0x" +
|
||||
Long.toHexString(addrOffset));
|
||||
public int getChunk(long offset, int size, byte[] dest, boolean stopOnUninitialized) {
|
||||
int bytesRead = 0;
|
||||
if (size == 0) {
|
||||
return bytesRead;
|
||||
}
|
||||
if (value.length != size) {
|
||||
throw new LowlevelError("Unique value size mismatch: 0x" + Long.toHexString(addrOffset));
|
||||
try {
|
||||
//align if necessary
|
||||
int adjustment = (int) offset % WORD_SIZE;
|
||||
if (adjustment != 0) {
|
||||
WordInfo word = map.get(offset & ALIGNMENT_MASK);
|
||||
if (word == null) {
|
||||
throw new LowlevelError("Attempted to read uninitialized word in unique space");
|
||||
}
|
||||
for (int i = adjustment; i < WORD_SIZE && bytesRead < size; ++i) {
|
||||
dest[bytesRead++] = word.getByte(i);
|
||||
offset += 1;
|
||||
}
|
||||
}
|
||||
//copy a word at a time
|
||||
while (size - bytesRead > 0) {
|
||||
WordInfo word = map.get(offset & ALIGNMENT_MASK);
|
||||
if (word == null) {
|
||||
throw new LowlevelError("Attempted to read uninitialized word in unique space");
|
||||
}
|
||||
offset += WORD_SIZE;
|
||||
//whole word is initialized, copy it (or the appropriate
|
||||
//initial segment) all at once
|
||||
int bytesToRead = Math.min(WORD_SIZE, size - bytesRead);
|
||||
if (word.isEntireWordInitialized()) {
|
||||
word.getWord(buffer);
|
||||
System.arraycopy(buffer, 0, dest, bytesRead,
|
||||
Math.min(WORD_SIZE, size - bytesRead));
|
||||
bytesRead += bytesToRead;
|
||||
continue;
|
||||
}
|
||||
//not entirely initialized, copy one byte at a time until
|
||||
//all requested bytes read (or word.getByte throws an exception)
|
||||
int base = bytesRead;
|
||||
for (int i = 0; i < bytesToRead; ++i) {
|
||||
dest[base + i] = word.getByte(i);
|
||||
bytesRead += 1;
|
||||
}
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
catch (LowlevelError e) {
|
||||
if (stopOnUninitialized) {
|
||||
return bytesRead;
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
System.arraycopy(value, 0, res, 0, size);
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setChunk(long offset, int size, byte[] val) {
|
||||
byte[] value = new byte[size];
|
||||
System.arraycopy(val, 0, value, 0, size);
|
||||
map.put(offset, value);
|
||||
public void setChunk(long offset, int size, byte[] src) {
|
||||
if (size == 0 || src.length == 0) {
|
||||
return;
|
||||
}
|
||||
int currentPosition = 0;
|
||||
//align if necessary
|
||||
int adjustment = (int) offset % WORD_SIZE;
|
||||
if (adjustment != 0) {
|
||||
WordInfo word = map.get(offset & ALIGNMENT_MASK);
|
||||
if (word == null) {
|
||||
word = new WordInfo();
|
||||
map.put(offset & ALIGNMENT_MASK, word);
|
||||
}
|
||||
for (int i = adjustment; i < WORD_SIZE; ++i) {
|
||||
word.setByte(src[currentPosition], i);
|
||||
offset += 1;
|
||||
currentPosition += 1;
|
||||
}
|
||||
}
|
||||
while (size > currentPosition) {
|
||||
WordInfo word = map.get(offset & ALIGNMENT_MASK);
|
||||
if (word == null) {
|
||||
word = new WordInfo();
|
||||
map.put(offset & ALIGNMENT_MASK, word);
|
||||
}
|
||||
int bytesToWrite = Math.min(WORD_SIZE, size - currentPosition);
|
||||
for (int i = 0; i < bytesToWrite; i++) {
|
||||
word.setByte(src[currentPosition + i], i);
|
||||
}
|
||||
offset += bytesToWrite;
|
||||
currentPosition += bytesToWrite;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -72,4 +160,95 @@ public class UniqueMemoryBank extends MemoryBank {
|
|||
map.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple class representing a byte-addressable word of memory. Each
|
||||
* byte can be either initialized to a byte value or uninitialized.
|
||||
* It is an error to attempt to read an uninitialized byte.
|
||||
*/
|
||||
public static class WordInfo {
|
||||
public byte initialized;
|
||||
public long word;
|
||||
|
||||
/**
|
||||
* Constructs a {@link WordInfo} object with all bytes uninitialized.
|
||||
*/
|
||||
public WordInfo() {
|
||||
initialized = 0;
|
||||
word = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the byte at {@code index} and sets its value to
|
||||
* {@code val}
|
||||
* @param val new value
|
||||
* @param index index
|
||||
* @throws LowlevelError if the index is invalid
|
||||
*/
|
||||
public void setByte(byte val, int index) {
|
||||
validateIndex(index);
|
||||
word &= ~(0xffL << (WORD_SIZE * index));
|
||||
long shifted = ((long) val) << (WORD_SIZE * index);
|
||||
word |= shifted;
|
||||
initialized |= (1 << index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the byte at the given index
|
||||
* @param index index
|
||||
* @return corresponding byte value
|
||||
* @throws LowlevelError if the index is invalid or the requested byte
|
||||
* is not initialized.
|
||||
*/
|
||||
public byte getByte(int index) {
|
||||
validateIndex(index);
|
||||
checkInitialized(index);
|
||||
long selected = word & (0xffL << (WORD_SIZE * index));
|
||||
long adjusted = selected >> (WORD_SIZE * index);
|
||||
return (byte) adjusted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an entire word into {@code buffer}
|
||||
* @param buffer buffer to write a single word to. Must have
|
||||
* length 8.
|
||||
* @throws LowlevelError if the entire word is not initialized
|
||||
*/
|
||||
public void getWord(byte[] buffer) {
|
||||
if (initialized != ((byte) (0xff))) {
|
||||
throw new LowlevelError("Attempted to read uninitialized word in unique space");
|
||||
}
|
||||
if (buffer.length != WORD_SIZE) {
|
||||
throw new IllegalArgumentException("Buffer must have length 8");
|
||||
}
|
||||
for (int i = 0; i < WORD_SIZE; ++i) {
|
||||
buffer[i] = (byte) ((word & (0xffL << (WORD_SIZE * i))) >> (WORD_SIZE * i));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true precisely when the entire word is initialized.
|
||||
* @return true if entire work initialized
|
||||
*/
|
||||
protected boolean isEntireWordInitialized() {
|
||||
return initialized == (byte) 0xff;
|
||||
}
|
||||
|
||||
//assumes 0 <= index <= 7
|
||||
private void checkInitialized(int index) {
|
||||
if ((initialized & (1 << (index))) == 0) {
|
||||
throw new LowlevelError(
|
||||
"Attempted to read uninitialized memory in the unique space.");
|
||||
}
|
||||
}
|
||||
|
||||
//ensure that the provided index is valid
|
||||
private void validateIndex(int index) {
|
||||
if (index < 0 || index > 7) {
|
||||
throw new LowlevelError("Invalid index: " + Integer.toString(index));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -529,8 +529,8 @@ public class SleighCompile extends SleighBase {
|
|||
static int findCollision(Map<Long, Integer> local2Operand, ArrayList<Long> locals,
|
||||
int operand) {
|
||||
Integer boxOperand = Integer.valueOf(operand);
|
||||
for (int i = 0; i < locals.size(); ++i) {
|
||||
Integer previous = local2Operand.putIfAbsent(locals.get(i), boxOperand);
|
||||
for (Long local : locals) {
|
||||
Integer previous = local2Operand.putIfAbsent(local, boxOperand);
|
||||
if (previous != null) {
|
||||
if (previous.intValue() != operand) {
|
||||
return previous.intValue();
|
||||
|
@ -842,7 +842,7 @@ public class SleighCompile extends SleighBase {
|
|||
}
|
||||
|
||||
// Parser functions
|
||||
public TokenSymbol defineToken(Location location, String name, long sz) {
|
||||
public TokenSymbol defineToken(Location location, String name, long sz, int endian) {
|
||||
entry("defineToken", location, name, sz);
|
||||
int size = (int) sz;
|
||||
if ((size & 7) != 0) {
|
||||
|
@ -853,8 +853,15 @@ public class SleighCompile extends SleighBase {
|
|||
else {
|
||||
size = size / 8;
|
||||
}
|
||||
boolean isBig;
|
||||
if (endian == 0) {
|
||||
isBig = isBigEndian();
|
||||
}
|
||||
else {
|
||||
isBig = (endian > 0);
|
||||
}
|
||||
ghidra.pcodeCPort.context.Token newtoken =
|
||||
new ghidra.pcodeCPort.context.Token(name, size, isBigEndian(), tokentable.size());
|
||||
new ghidra.pcodeCPort.context.Token(name, size, isBig, tokentable.size());
|
||||
tokentable.push_back(newtoken);
|
||||
TokenSymbol res = new TokenSymbol(location, newtoken);
|
||||
addSymbol(res);
|
||||
|
|
|
@ -83,7 +83,12 @@ public class ParameterDefinitionImpl implements ParameterDefinition {
|
|||
throw new IllegalArgumentException(kind +
|
||||
" type must be specified with fixed-length data type: " + dataType.getName());
|
||||
}
|
||||
if (dataType instanceof VoidDataType) {
|
||||
DataType baseType = dataType;
|
||||
if(baseType instanceof TypedefDataType) {
|
||||
baseType = ((TypedefDataType)baseType).getBaseDataType();
|
||||
}
|
||||
|
||||
if (baseType instanceof VoidDataType) {
|
||||
if (!isReturn) {
|
||||
throw new IllegalArgumentException(
|
||||
"Parameter type may not specify the void datatype - empty parameter list should be used");
|
||||
|
|
|
@ -0,0 +1,253 @@
|
|||
/* ###
|
||||
* 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.pcode.memstate;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import generic.test.AbstractGenericTest;
|
||||
import ghidra.pcode.error.LowlevelError;
|
||||
import ghidra.pcode.memstate.UniqueMemoryBank.WordInfo;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.address.GenericAddressSpace;
|
||||
|
||||
public class UniqueMemoryBankTest extends AbstractGenericTest {
|
||||
|
||||
private AddressSpace uniqueSpace;
|
||||
private UniqueMemoryBank uniqueBank;
|
||||
private byte[] eightTestBytes = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 };
|
||||
private byte[] eightZeroBytes = new byte[8];
|
||||
private byte[] sixteenTestBytes = new byte[] { 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9,
|
||||
0xa, 0xb, 0xc, 0xd, 0xe, 0xf };
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
uniqueSpace = new GenericAddressSpace("unique", 64, AddressSpace.TYPE_UNIQUE, 0);
|
||||
uniqueBank = new UniqueMemoryBank(uniqueSpace, false);
|
||||
}
|
||||
|
||||
public UniqueMemoryBankTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void WordInfoBasicTest() {
|
||||
WordInfo info = new WordInfo();
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x0, 0);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x1, 1);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x2, 2);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x3, 3);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x4, 4);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x5, 5);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x6, 6);
|
||||
assertFalse(info.isEntireWordInitialized());
|
||||
info.setByte((byte) 0x7, 7);
|
||||
assertTrue(info.isEntireWordInitialized());
|
||||
for (int i = 0; i < 8; ++i) {
|
||||
assertEquals((byte) i, info.getByte(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = LowlevelError.class)
|
||||
public void testGetUnitializedByte() {
|
||||
WordInfo info = new WordInfo();
|
||||
info.setByte((byte) 0, 0);
|
||||
info.setByte((byte) 1, 1);
|
||||
info.setByte((byte) 3, 3);
|
||||
info.setByte((byte) 4, 4);
|
||||
info.setByte((byte) 5, 5);
|
||||
info.setByte((byte) 6, 6);
|
||||
info.setByte((byte) 7, 7);
|
||||
@SuppressWarnings("unused")
|
||||
byte val = info.getByte(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleRead() {
|
||||
uniqueBank.setChunk(0x1000, 8, eightTestBytes);
|
||||
byte[] dest = new byte[8];
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 8, dest, true);
|
||||
assertEquals(8, numBytes);
|
||||
assertTrue(Arrays.equals(dest, eightTestBytes));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDifferentlySizedReads() {
|
||||
uniqueBank.setChunk(0x1000, 8, eightTestBytes);
|
||||
byte[] dest = new byte[4];
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 4, dest, true);
|
||||
assertEquals(4, numBytes);
|
||||
assertTrue(Arrays.equals(dest, new byte[] { 0x0, 0x1, 0x2, 0x3 }));
|
||||
numBytes = uniqueBank.getChunk(0x1004, 4, dest, true);
|
||||
assertEquals(4, numBytes);
|
||||
assertTrue(Arrays.equals(dest, new byte[] { 0x4, 0x5, 0x6, 0x7 }));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLargeReadWrite() {
|
||||
uniqueBank.setChunk(0x1004, 16, sixteenTestBytes);
|
||||
byte[] dest = new byte[16];
|
||||
int numBytes = uniqueBank.getChunk(0x1004, 16, dest, true);
|
||||
assertEquals(16, numBytes);
|
||||
assertTrue(Arrays.equals(dest, sixteenTestBytes));
|
||||
|
||||
byte[] largeSrc = new byte[64];
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
largeSrc[i] = (byte) (i + 1);
|
||||
}
|
||||
uniqueBank.setChunk(0x1007, 64, largeSrc);
|
||||
dest = new byte[64];
|
||||
numBytes = uniqueBank.getChunk(0x1007, 64, dest, true);
|
||||
assertEquals(64, numBytes);
|
||||
assertTrue(Arrays.equals(dest, largeSrc));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadAcrossUndefined() {
|
||||
byte[] fourBytes = new byte[] { 0x11, 0x22, 0x33, 0x44 };
|
||||
uniqueBank.setChunk(0x1007, 4, fourBytes);
|
||||
uniqueBank.setChunk(0x100c, 4, fourBytes);
|
||||
byte[] dest = new byte[9];
|
||||
int numBytes = uniqueBank.getChunk(0x1007, 9, dest, true);
|
||||
assertEquals(4, numBytes);
|
||||
assertEquals(0x11, dest[0]);
|
||||
assertEquals(0x22, dest[1]);
|
||||
assertEquals(0x33, dest[2]);
|
||||
assertEquals(0x44, dest[3]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNonAlignedReadWrite() {
|
||||
byte[] fourBytes = new byte[] { 0x11, 0x22, 0x33, 0x44 };
|
||||
uniqueBank.setChunk(0x1004, 4, fourBytes);
|
||||
byte[] dest = new byte[4];
|
||||
int numBytes = uniqueBank.getChunk(0x1004, 4, dest, true);
|
||||
assertEquals(4, numBytes);
|
||||
assertTrue(Arrays.equals(fourBytes, dest));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverlappingReadWrite() {
|
||||
uniqueBank.setChunk(0x1000, 16, sixteenTestBytes);
|
||||
uniqueBank.setChunk(0x1004, 8, eightZeroBytes);
|
||||
byte[] dest = new byte[16];
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 16, dest, true);
|
||||
assertEquals(16, numBytes);
|
||||
for (int i = 0; i < 16; ++i) {
|
||||
if (i > 3 && i < 12) {
|
||||
assertEquals(0, dest[i]);
|
||||
}
|
||||
else {
|
||||
assertEquals(i, dest[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOneByteRead() {
|
||||
byte[] one = new byte[] { (byte) 0x7f };
|
||||
uniqueBank.setChunk(0x1000, 1, one);
|
||||
byte[] dest = new byte[16];
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 1, dest, false);
|
||||
assertEquals(1, numBytes);
|
||||
assertEquals(dest[0], (byte) 0x7f);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClear() {
|
||||
uniqueBank.setChunk(0x1000, 8, eightTestBytes);
|
||||
byte[] dest = new byte[8];
|
||||
uniqueBank.clear();
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 8, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 7, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 6, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 5, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 4, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 3, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 2, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 1, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 0, dest, true);
|
||||
assertEquals(0, numBytes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleOverwrite() {
|
||||
uniqueBank.setChunk(0x1000, 8, eightTestBytes);
|
||||
byte[] dest = new byte[8];
|
||||
int numBytes = uniqueBank.getChunk(0x1000, 8, dest, true);
|
||||
assertEquals(8, numBytes);
|
||||
assertTrue(Arrays.equals(dest, eightTestBytes));
|
||||
uniqueBank.setChunk(0x1000, 8, eightZeroBytes);
|
||||
numBytes = uniqueBank.getChunk(0x1000, 8, dest, true);
|
||||
assertEquals(8, numBytes);
|
||||
assertTrue(Arrays.equals(dest, eightZeroBytes));
|
||||
}
|
||||
|
||||
@Test(expected = LowlevelError.class)
|
||||
public void testUnitializedReadStop() {
|
||||
byte[] dest = new byte[16];
|
||||
uniqueBank.getChunk(0x1000, 0x10, dest, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnitializedReadContinue() {
|
||||
byte[] dest = new byte[16];
|
||||
int bytesRead = uniqueBank.getChunk(0x1000, 0x10, dest, true);
|
||||
assertEquals(0, bytesRead);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testGetPageException() {
|
||||
MemoryPage page = uniqueBank.getPage(0);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testSetPageException() {
|
||||
uniqueBank.setPage(0, new byte[0], 0, 4096, 0);
|
||||
}
|
||||
|
||||
@Test(expected = UnsupportedOperationException.class)
|
||||
public void testSetPageInitializedException() {
|
||||
uniqueBank.setPageInitialized(0, true, 0, 4096, 0);
|
||||
}
|
||||
|
||||
//possibly add:
|
||||
//zero-byte read/write
|
||||
//try to write more bytes than the array has
|
||||
//try to read more bytes into the array than it has
|
||||
|
||||
}
|
|
@ -253,7 +253,7 @@ public class DummyTool extends PluginTool {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void restoreWindowingDataFromXml(Element windowData) {
|
||||
public void restoreWindowingDataFromXml(Element element) {
|
||||
//do nothing
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,11 @@
|
|||
# and the destination is not the upper half of the register (ie, bit 30 q=0)
|
||||
# then the unused remaining upper bits must be set to 0.
|
||||
|
||||
@if DATA_ENDIAN == "little"
|
||||
define endian=little;
|
||||
@else
|
||||
define endian=big;
|
||||
@endif
|
||||
define alignment=4;
|
||||
|
||||
# Unlike the above, these are preprocessor macros. Use them with e.g. $(TAG_GRANULE) in SLEIGH statements.
|
||||
|
@ -1008,7 +1012,7 @@ define context contextreg
|
|||
ShowMemTag = (24,24) noflow
|
||||
;
|
||||
|
||||
define token instrAARCH64 (32)
|
||||
define token instrAARCH64 (32) endian = little
|
||||
|
||||
Rm = (16,20)
|
||||
Rn = (5,9)
|
||||
|
@ -2644,27 +2648,86 @@ vIndexHLM: val is b_2223=0 & b_2121 & b_1111 & b_2020 [ val = b_1111 << 2 | b_21
|
|||
vIndexHL: val is b_2223=0b01 & b_21 & b_11 [ val = b_11 << 1 | b_21; ] { export *[const]:8 val; }
|
||||
vIndexHL: b_11 is b_2223=0b10 & b_11 { export *[const]:8 b_11; }
|
||||
|
||||
Re_VPR128.B.vIndex: Re_VPR128.B^"["^vIndex^"]" is Re_VPR128.B & vIndex { }
|
||||
Re_VPR128.S.vIndex: Re_VPR128.S^"["^vIndex^"]" is Re_VPR128.S & vIndex { }
|
||||
Re_VPR128.D.vIndex: Re_VPR128.D^"["^vIndex^"]" is Re_VPR128.D & vIndex { }
|
||||
@if DATA_ENDIAN == "little"
|
||||
Re_VPR128.B.sel: Re_VPR128, val is Re_VPR128 & b_2222=0 & b_2121 & b_1111 [ val = 0x5000 + 32*Re_VPR128 + b_1111 * 2 + b_2121; ] { export *[register]:1 val; }
|
||||
Re_VPR128.B.sel: Re_VPR128, val is Re_VPR128 & b_2222=1 & b_2121=0 & b_1111 [ val = 0x5000 + 32*Re_VPR128 + b_1111; ] { export *[register]:1 val; }
|
||||
Re_VPR128.S.sel: Re_VPR128, val is Re_VPR128 & b_2222=0 & b_2121 & b_1111 [ val = 0x5000 + 32*Re_VPR128 + (b_1111 * 2 + b_2121) * 4; ] { export *[register]:4 val; }
|
||||
Re_VPR128.S.sel: Re_VPR128, val is Re_VPR128 & b_2222=1 & b_2121=0 & b_1111 [ val = 0x5000 + 32*Re_VPR128 + b_1111 * 4; ] { export *[register]:4 val; }
|
||||
Re_VPR128.D.sel: Re_VPR128, val is Re_VPR128 & b_2222=0 & b_2121 & b_1111 [ val = 0x5000 + 32*Re_VPR128 + (b_1111 * 2 + b_2121) * 8; ] { export *[register]:8 val; }
|
||||
Re_VPR128.D.sel: Re_VPR128, val is Re_VPR128 & b_2222=1 & b_2121=0 & b_1111 [ val = 0x5000 + 32*Re_VPR128 + b_1111 * 8; ] { export *[register]:8 val; }
|
||||
@else
|
||||
Re_VPR128.B.sel: Re_VPR128, val is Re_VPR128 & b_2222=0 & b_2121 & b_1111 [ val = 0x501f + 32*Re_VPR128 - b_1111 * 2 - b_2121; ] { export *[register]:1 val; }
|
||||
Re_VPR128.B.sel: Re_VPR128, val is Re_VPR128 & b_2222=1 & b_2121=0 & b_1111 [ val = 0x501f + 32*Re_VPR128 - b_1111; ] { export *[register]:1 val; }
|
||||
Re_VPR128.S.sel: Re_VPR128, val is Re_VPR128 & b_2222=0 & b_2121 & b_1111 [ val = 0x501c + 32*Re_VPR128 - (b_1111 * 2 + b_2121) * 4; ] { export *[register]:4 val; }
|
||||
Re_VPR128.S.sel: Re_VPR128, val is Re_VPR128 & b_2222=1 & b_2121=0 & b_1111 [ val = 0x501c + 32*Re_VPR128 - b_1111 * 4; ] { export *[register]:4 val; }
|
||||
Re_VPR128.D.sel: Re_VPR128, val is Re_VPR128 & b_2222=0 & b_2121 & b_1111 [ val = 0x5018 + 32*Re_VPR128 - (b_1111 * 2 + b_2121) * 8; ] { export *[register]:8 val; }
|
||||
Re_VPR128.D.sel: Re_VPR128, val is Re_VPR128 & b_2222=1 & b_2121=0 & b_1111 [ val = 0x5018 + 32*Re_VPR128 - b_1111 * 8; ] { export *[register]:8 val; }
|
||||
@endif
|
||||
|
||||
Rd_VPR128.B.imm_neon_uimm4: Rd_VPR128.B^"["^imm_neon_uimm4^"]" is Rd_VPR128.B & imm_neon_uimm4 { export Rd_VPR128.B; }
|
||||
Rd_VPR128.H.imm_neon_uimm3: Rd_VPR128.H^"["^imm_neon_uimm3^"]" is Rd_VPR128.H & imm_neon_uimm3 { export Rd_VPR128.H; }
|
||||
Rd_VPR128.S.imm_neon_uimm2: Rd_VPR128.S^"["^imm_neon_uimm2^"]" is Rd_VPR128.S & imm_neon_uimm2 { export Rd_VPR128.S; }
|
||||
Rd_VPR128.D.imm_neon_uimm1: Rd_VPR128.D^"["^imm_neon_uimm1^"]" is Rd_VPR128.D & imm_neon_uimm1 { export Rd_VPR128.D; }
|
||||
Re_VPR128.B.vIndex: Re_VPR128.B^"["^vIndex^"]" is Re_VPR128.B & vIndex & Re_VPR128.B.sel { export Re_VPR128.B.sel; }
|
||||
Re_VPR128.S.vIndex: Re_VPR128.S^"["^vIndex^"]" is Re_VPR128.S & vIndex & Re_VPR128.S.sel { export Re_VPR128.S.sel; }
|
||||
Re_VPR128.D.vIndex: Re_VPR128.D^"["^vIndex^"]" is Re_VPR128.D & vIndex & Re_VPR128.D.sel { export Re_VPR128.D.sel; }
|
||||
|
||||
Rn_VPR128.B.immN_neon_uimm4: Rn_VPR128.B^"["^immN_neon_uimm4^"]" is Rn_VPR128.B & immN_neon_uimm4 { export Rn_VPR128.B; }
|
||||
Rn_VPR128.H.immN_neon_uimm3: Rn_VPR128.H^"["^immN_neon_uimm3^"]" is Rn_VPR128.H & immN_neon_uimm3 { export Rn_VPR128.H; }
|
||||
Rn_VPR128.S.immN_neon_uimm2: Rn_VPR128.S^"["^immN_neon_uimm2^"]" is Rn_VPR128.S & immN_neon_uimm2 { export Rn_VPR128.S; }
|
||||
Rn_VPR128.D.immN_neon_uimm1: Rn_VPR128.D^"["^immN_neon_uimm1^"]" is Rn_VPR128.D & immN_neon_uimm1 { export Rn_VPR128.D; }
|
||||
@if DATA_ENDIAN == "little"
|
||||
Rd_VPR128.B.sel: Rd_VPR128, val is Rd_VPR128 & imm_neon_uimm4 [ val = 0x5000 + 32*Rd_VPR128 + imm_neon_uimm4; ] { export *[register]:1 val; }
|
||||
Rd_VPR128.H.sel: Rd_VPR128, val is Rd_VPR128 & imm_neon_uimm3 [ val = 0x5000 + 32*Rd_VPR128 + 2*imm_neon_uimm3; ] { export *[register]:2 val; }
|
||||
Rd_VPR128.S.sel: Rd_VPR128, val is Rd_VPR128 & imm_neon_uimm2 [ val = 0x5000 + 32*Rd_VPR128 + 4*imm_neon_uimm2; ] { export *[register]:4 val; }
|
||||
Rd_VPR128.D.sel: Rd_VPR128, val is Rd_VPR128 & imm_neon_uimm1 [ val = 0x5000 + 32*Rd_VPR128 + 8*imm_neon_uimm1; ] { export *[register]:8 val; }
|
||||
@else
|
||||
Rd_VPR128.B.sel: Rd_VPR128, val is Rd_VPR128 & imm_neon_uimm4 [ val = 0x501f + 32*Rd_VPR128 - imm_neon_uimm4; ] { export *[register]:1 val; }
|
||||
Rd_VPR128.H.sel: Rd_VPR128, val is Rd_VPR128 & imm_neon_uimm3 [ val = 0x501e + 32*Rd_VPR128 - 2*imm_neon_uimm3; ] { export *[register]:2 val; }
|
||||
Rd_VPR128.S.sel: Rd_VPR128, val is Rd_VPR128 & imm_neon_uimm2 [ val = 0x501c + 32*Rd_VPR128 - 4*imm_neon_uimm2; ] { export *[register]:4 val; }
|
||||
Rd_VPR128.D.sel: Rd_VPR128, val is Rd_VPR128 & imm_neon_uimm1 [ val = 0x5018 + 32*Rd_VPR128 - 8*imm_neon_uimm1; ] { export *[register]:8 val; }
|
||||
@endif
|
||||
Rd_VPR128.B.imm_neon_uimm4: Rd_VPR128.B^"["^imm_neon_uimm4^"]" is Rd_VPR128.B & imm_neon_uimm4 & Rd_VPR128.B.sel { export Rd_VPR128.B.sel; }
|
||||
Rd_VPR128.H.imm_neon_uimm3: Rd_VPR128.H^"["^imm_neon_uimm3^"]" is Rd_VPR128.H & imm_neon_uimm3 & Rd_VPR128.H.sel { export Rd_VPR128.H.sel; }
|
||||
Rd_VPR128.S.imm_neon_uimm2: Rd_VPR128.S^"["^imm_neon_uimm2^"]" is Rd_VPR128.S & imm_neon_uimm2 & Rd_VPR128.S.sel { export Rd_VPR128.S.sel; }
|
||||
Rd_VPR128.D.imm_neon_uimm1: Rd_VPR128.D^"["^imm_neon_uimm1^"]" is Rd_VPR128.D & imm_neon_uimm1 & Rd_VPR128.D.sel { export Rd_VPR128.D.sel; }
|
||||
|
||||
Rn_VPR128.B.imm_neon_uimm4: Rn_VPR128.B^"["^imm_neon_uimm4^"]" is Rn_VPR128.B & imm_neon_uimm4 { export Rn_VPR128.B; }
|
||||
Rn_VPR128.H.imm_neon_uimm3: Rn_VPR128.H^"["^imm_neon_uimm3^"]" is Rn_VPR128.H & imm_neon_uimm3 { export Rn_VPR128.H; }
|
||||
Rn_VPR128.S.imm_neon_uimm2: Rn_VPR128.S^"["^imm_neon_uimm2^"]" is Rn_VPR128.S & imm_neon_uimm2 { export Rn_VPR128.S; }
|
||||
Rn_VPR128.D.imm_neon_uimm1: Rn_VPR128.D^"["^imm_neon_uimm1^"]" is Rn_VPR128.D & imm_neon_uimm1 { export Rn_VPR128.D; }
|
||||
@if DATA_ENDIAN == "little"
|
||||
Rn_VPR128.B.selN: Rn_VPR128, val is Rn_VPR128 & immN_neon_uimm4 [ val = 0x5000 + 32*Rn_VPR128 + immN_neon_uimm4; ] { export *[register]:1 val; }
|
||||
Rn_VPR128.H.selN: Rn_VPR128, val is Rn_VPR128 & immN_neon_uimm3 [ val = 0x5000 + 32*Rn_VPR128 + 2*immN_neon_uimm3; ] { export *[register]:2 val; }
|
||||
Rn_VPR128.S.selN: Rn_VPR128, val is Rn_VPR128 & immN_neon_uimm2 [ val = 0x5000 + 32*Rn_VPR128 + 4*immN_neon_uimm2; ] { export *[register]:4 val; }
|
||||
Rn_VPR128.D.selN: Rn_VPR128, val is Rn_VPR128 & immN_neon_uimm1 [ val = 0x5000 + 32*Rn_VPR128 + 8*immN_neon_uimm1; ] { export *[register]:8 val; }
|
||||
@else
|
||||
Rn_VPR128.B.selN: Rn_VPR128, val is Rn_VPR128 & immN_neon_uimm4 [ val = 0x501f + 32*Rn_VPR128 - immN_neon_uimm4; ] { export *[register]:1 val; }
|
||||
Rn_VPR128.H.selN: Rn_VPR128, val is Rn_VPR128 & immN_neon_uimm3 [ val = 0x501e + 32*Rn_VPR128 - 2*immN_neon_uimm3; ] { export *[register]:2 val; }
|
||||
Rn_VPR128.S.selN: Rn_VPR128, val is Rn_VPR128 & immN_neon_uimm2 [ val = 0x501c + 32*Rn_VPR128 - 4*immN_neon_uimm2; ] { export *[register]:4 val; }
|
||||
Rn_VPR128.D.selN: Rn_VPR128, val is Rn_VPR128 & immN_neon_uimm1 [ val = 0x5018 + 32*Rn_VPR128 - 8*immN_neon_uimm1; ] { export *[register]:8 val; }
|
||||
@endif
|
||||
Rn_VPR128.B.immN_neon_uimm4: Rn_VPR128.B^"["^immN_neon_uimm4^"]" is Rn_VPR128.B & immN_neon_uimm4 & Rn_VPR128.B.selN { export Rn_VPR128.B.selN; }
|
||||
Rn_VPR128.H.immN_neon_uimm3: Rn_VPR128.H^"["^immN_neon_uimm3^"]" is Rn_VPR128.H & immN_neon_uimm3 & Rn_VPR128.H.selN { export Rn_VPR128.H.selN; }
|
||||
Rn_VPR128.S.immN_neon_uimm2: Rn_VPR128.S^"["^immN_neon_uimm2^"]" is Rn_VPR128.S & immN_neon_uimm2 & Rn_VPR128.S.selN { export Rn_VPR128.S.selN; }
|
||||
Rn_VPR128.D.immN_neon_uimm1: Rn_VPR128.D^"["^immN_neon_uimm1^"]" is Rn_VPR128.D & immN_neon_uimm1 & Rn_VPR128.D.selN { export Rn_VPR128.D.selN; }
|
||||
|
||||
@if DATA_ENDIAN == "little"
|
||||
Rn_VPR128.B.sel: Rn_VPR128, val is Rn_VPR128 & imm_neon_uimm4 [ val = 0x5000 + 32*Rn_VPR128 + imm_neon_uimm4; ] { export *[register]:1 val; }
|
||||
Rn_VPR128.H.sel: Rn_VPR128, val is Rn_VPR128 & imm_neon_uimm3 [ val = 0x5000 + 32*Rn_VPR128 + 2*imm_neon_uimm3; ] { export *[register]:2 val; }
|
||||
Rn_VPR128.S.sel: Rn_VPR128, val is Rn_VPR128 & imm_neon_uimm2 [ val = 0x5000 + 32*Rn_VPR128 + 4*imm_neon_uimm2; ] { export *[register]:4 val; }
|
||||
Rn_VPR128.D.sel: Rn_VPR128, val is Rn_VPR128 & imm_neon_uimm1 [ val = 0x5000 + 32*Rn_VPR128 + 8*imm_neon_uimm1; ] { export *[register]:8 val; }
|
||||
@else
|
||||
Rn_VPR128.B.sel: Rn_VPR128, val is Rn_VPR128 & imm_neon_uimm4 [ val = 0x501f + 32*Rn_VPR128 - imm_neon_uimm4; ] { export *[register]:1 val; }
|
||||
Rn_VPR128.H.sel: Rn_VPR128, val is Rn_VPR128 & imm_neon_uimm3 [ val = 0x501e + 32*Rn_VPR128 - 2*imm_neon_uimm3; ] { export *[register]:2 val; }
|
||||
Rn_VPR128.S.sel: Rn_VPR128, val is Rn_VPR128 & imm_neon_uimm2 [ val = 0x501c + 32*Rn_VPR128 - 4*imm_neon_uimm2; ] { export *[register]:4 val; }
|
||||
Rn_VPR128.D.sel: Rn_VPR128, val is Rn_VPR128 & imm_neon_uimm1 [ val = 0x5018 + 32*Rn_VPR128 - 8*imm_neon_uimm1; ] { export *[register]:8 val; }
|
||||
@endif
|
||||
Rn_VPR128.B.imm_neon_uimm4: Rn_VPR128.B^"["^imm_neon_uimm4^"]" is Rn_VPR128.B & imm_neon_uimm4 & Rn_VPR128.B.sel { export Rn_VPR128.B.sel; }
|
||||
Rn_VPR128.H.imm_neon_uimm3: Rn_VPR128.H^"["^imm_neon_uimm3^"]" is Rn_VPR128.H & imm_neon_uimm3 & Rn_VPR128.H.sel { export Rn_VPR128.H.sel; }
|
||||
Rn_VPR128.S.imm_neon_uimm2: Rn_VPR128.S^"["^imm_neon_uimm2^"]" is Rn_VPR128.S & imm_neon_uimm2 & Rn_VPR128.S.sel { export Rn_VPR128.S.sel; }
|
||||
Rn_VPR128.D.imm_neon_uimm1: Rn_VPR128.D^"["^imm_neon_uimm1^"]" is Rn_VPR128.D & imm_neon_uimm1 & Rn_VPR128.D.sel { export Rn_VPR128.D.sel; }
|
||||
|
||||
Re_VPR128.H.vIndexHL: Re_VPR128.H^"["^vIndexHL^"]" is Re_VPR128.H & vIndexHL { }
|
||||
Re_VPR128Lo.H.vIndexHLM: Re_VPR128Lo.H^"["^vIndexHLM^"]" is Re_VPR128Lo.H & vIndexHLM { }
|
||||
|
||||
@if DATA_ENDIAN == "little"
|
||||
Re_VPR128Lo.H.sel: Re_VPR128, val is Re_VPR128 & b_2223=2 & b_2121 & b_1111 [ val = 0x5000 + 32*Re_VPR128 + (b_1111 * 2 + b_2121)*2; ] { export *[register]:2 val; }
|
||||
Re_VPR128Lo.H.sel: Re_VPR128, val is Re_VPR128 & b_2223=1 & b_2121 & b_1111 & b_2020 [ val = 0x5000 + 32*Re_VPR128 + (b_1111*4 + b_2121*2 + b_2020)*2; ] { export *[register]:2 val; }
|
||||
Re_VPR128Lo.H.sel: Re_VPR128, val is Re_VPR128 & b_2223=0 & b_2121 & b_1111 & b_2020 [ val = 0x5000 + 32*Re_VPR128 + (b_1111*4 + b_2121*2 + b_2020)*2; ] { export *[register]:2 val; }
|
||||
@else
|
||||
Re_VPR128Lo.H.sel: Re_VPR128, val is Re_VPR128 & b_2223=2 & b_2121 & b_1111 [ val = 0x501e + 32*Re_VPR128 - (b_1111 * 2 + b_2121)*2; ] { export *[register]:2 val; }
|
||||
Re_VPR128Lo.H.sel: Re_VPR128, val is Re_VPR128 & b_2223=1 & b_2121 & b_1111 & b_2020 [ val = 0x501e + 32*Re_VPR128 - (b_1111*4 + b_2121*2 + b_2020)*2; ] { export *[register]:2 val; }
|
||||
Re_VPR128Lo.H.sel: Re_VPR128, val is Re_VPR128 & b_2223=0 & b_2121 & b_1111 & b_2020 [ val = 0x501e + 32*Re_VPR128 - (b_1111*4 + b_2121*2 + b_2020)*2; ] { export *[register]:2 val; }
|
||||
@endif
|
||||
Re_VPR128Lo.H.vIndexHLM: Re_VPR128Lo.H^"["^vIndexHLM^"]" is Re_VPR128Lo.H & vIndexHLM & Re_VPR128Lo.H.sel { export Re_VPR128Lo.H.sel; }
|
||||
|
||||
FBitsOp: "#"^fbits is Scale [ fbits = 64 - Scale; ] { export *[const]:2 fbits; }
|
||||
|
||||
|
@ -3193,55 +3256,17 @@ PACIXSP_BTITARGETS: is ShowBTI=0 { }
|
|||
|
||||
# These pseudo ops are used in neon
|
||||
|
||||
define pcodeop SIMD_COPY;
|
||||
define pcodeop SIMD_FLOAT;
|
||||
define pcodeop SIMD_FLOAT2FLOAT;
|
||||
define pcodeop SIMD_FLOAT_ABS;
|
||||
define pcodeop SIMD_FLOAT_ADD;
|
||||
define pcodeop SIMD_FLOAT_DIV;
|
||||
define pcodeop SIMD_FLOAT_MULT;
|
||||
define pcodeop SIMD_FLOAT_NEG;
|
||||
define pcodeop SIMD_FLOAT_SUB;
|
||||
define pcodeop SIMD_INT;
|
||||
define pcodeop SIMD_INT_2COMP;
|
||||
define pcodeop SIMD_INT_ABS;
|
||||
define pcodeop SIMD_INT_ADD;
|
||||
define pcodeop SIMD_INT_AND;
|
||||
define pcodeop SIMD_INT_LEFT;
|
||||
define pcodeop SIMD_INT_LESS;
|
||||
define pcodeop SIMD_INT_MULT;
|
||||
define pcodeop SIMD_INT_NEGATE;
|
||||
define pcodeop SIMD_INT_OR;
|
||||
define pcodeop SIMD_INT_RIGHT;
|
||||
define pcodeop SIMD_INT_SEXT;
|
||||
define pcodeop SIMD_INT_SLESS;
|
||||
define pcodeop SIMD_INT_SRIGHT;
|
||||
define pcodeop SIMD_INT_SUB;
|
||||
define pcodeop SIMD_INT_XOR;
|
||||
define pcodeop SIMD_INT_ZEXT;
|
||||
define pcodeop SIMD_PIECE;
|
||||
define pcodeop SIMD_TRUNC;
|
||||
|
||||
define pcodeop NEON_abs;
|
||||
define pcodeop NEON_add;
|
||||
define pcodeop NEON_addhn;
|
||||
define pcodeop NEON_addhn2;
|
||||
define pcodeop NEON_addp;
|
||||
define pcodeop NEON_addv;
|
||||
define pcodeop NEON_aesd;
|
||||
define pcodeop NEON_aese;
|
||||
define pcodeop NEON_aesimc;
|
||||
define pcodeop NEON_aesmc;
|
||||
define pcodeop NEON_and;
|
||||
define pcodeop NEON_bcax;
|
||||
define pcodeop NEON_bfcvt;
|
||||
define pcodeop NEON_bfcvtn;
|
||||
define pcodeop NEON_bfcvtn2;
|
||||
define pcodeop NEON_bfdot;
|
||||
define pcodeop NEON_bfmlalb;
|
||||
define pcodeop NEON_bfmlalt;
|
||||
define pcodeop NEON_bfmmla;
|
||||
define pcodeop NEON_bic;
|
||||
define pcodeop NEON_bif;
|
||||
define pcodeop NEON_bit;
|
||||
define pcodeop NEON_bsl;
|
||||
|
@ -3256,40 +3281,18 @@ define pcodeop NEON_cmle;
|
|||
define pcodeop NEON_cmlt;
|
||||
define pcodeop NEON_cmtst;
|
||||
define pcodeop NEON_cnt;
|
||||
define pcodeop NEON_dup;
|
||||
define pcodeop NEON_eor;
|
||||
define pcodeop NEON_eor3;
|
||||
define pcodeop NEON_ext;
|
||||
define pcodeop NEON_fabd;
|
||||
define pcodeop NEON_fabs;
|
||||
define pcodeop NEON_facge;
|
||||
define pcodeop NEON_facgt;
|
||||
define pcodeop NEON_fadd;
|
||||
define pcodeop NEON_faddp;
|
||||
define pcodeop NEON_fcadd;
|
||||
define pcodeop NEON_fccmp;
|
||||
define pcodeop NEON_fccmpe;
|
||||
define pcodeop NEON_fcmeq;
|
||||
define pcodeop NEON_fcmge;
|
||||
define pcodeop NEON_fcmgt;
|
||||
define pcodeop NEON_fcmla;
|
||||
define pcodeop NEON_fcmle;
|
||||
define pcodeop NEON_fcmlt;
|
||||
define pcodeop NEON_fcmp;
|
||||
define pcodeop NEON_fcmpe;
|
||||
define pcodeop NEON_fcsel;
|
||||
define pcodeop NEON_fcvt;
|
||||
define pcodeop NEON_fcvt_amnpz_su;
|
||||
define pcodeop NEON_fcvtl;
|
||||
define pcodeop NEON_fcvtl2;
|
||||
define pcodeop NEON_fcvtn;
|
||||
define pcodeop NEON_fcvtn2;
|
||||
define pcodeop NEON_fcvtxn;
|
||||
define pcodeop NEON_fcvtxn2;
|
||||
define pcodeop NEON_fcvtzs;
|
||||
define pcodeop NEON_fcvtzu;
|
||||
define pcodeop NEON_fdiv;
|
||||
define pcodeop NEON_fjcvtzs;
|
||||
define pcodeop NEON_fmadd;
|
||||
define pcodeop NEON_fmax;
|
||||
define pcodeop NEON_fmaxnm;
|
||||
|
@ -3303,50 +3306,22 @@ define pcodeop NEON_fminnmp;
|
|||
define pcodeop NEON_fminnmv;
|
||||
define pcodeop NEON_fminp;
|
||||
define pcodeop NEON_fminv;
|
||||
define pcodeop NEON_fmla;
|
||||
define pcodeop NEON_fmlal;
|
||||
define pcodeop NEON_fmlal2;
|
||||
define pcodeop NEON_fmls;
|
||||
define pcodeop NEON_fmlsl;
|
||||
define pcodeop NEON_fmlsl2;
|
||||
define pcodeop NEON_fmov;
|
||||
define pcodeop NEON_fmsub;
|
||||
define pcodeop NEON_fmul;
|
||||
define pcodeop NEON_fmulx;
|
||||
define pcodeop NEON_fneg;
|
||||
define pcodeop NEON_fnmadd;
|
||||
define pcodeop NEON_fnmsub;
|
||||
define pcodeop NEON_fnmul;
|
||||
define pcodeop NEON_frecpe;
|
||||
define pcodeop NEON_frecps;
|
||||
define pcodeop NEON_frecpx;
|
||||
define pcodeop NEON_frint_aimnpxz;
|
||||
define pcodeop NEON_frsqrte;
|
||||
define pcodeop NEON_frsqrts;
|
||||
define pcodeop NEON_fsqrt;
|
||||
define pcodeop NEON_fsub;
|
||||
define pcodeop NEON_ldnp1;
|
||||
define pcodeop NEON_ldnp2;
|
||||
define pcodeop NEON_ldp1;
|
||||
define pcodeop NEON_ldp2;
|
||||
define pcodeop NEON_ldr;
|
||||
define pcodeop NEON_ldur;
|
||||
define pcodeop NEON_mla;
|
||||
define pcodeop NEON_mls;
|
||||
define pcodeop NEON_mov;
|
||||
define pcodeop NEON_movi;
|
||||
define pcodeop NEON_mul;
|
||||
define pcodeop NEON_mvn;
|
||||
define pcodeop NEON_mvni;
|
||||
define pcodeop NEON_neg;
|
||||
define pcodeop NEON_orn;
|
||||
define pcodeop NEON_orr;
|
||||
define pcodeop NEON_pmul;
|
||||
define pcodeop NEON_pmull;
|
||||
define pcodeop NEON_pmull2;
|
||||
define pcodeop NEON_raddhn;
|
||||
define pcodeop NEON_raddhn2;
|
||||
define pcodeop NEON_rax1;
|
||||
define pcodeop NEON_rbit;
|
||||
define pcodeop NEON_rev16;
|
||||
define pcodeop NEON_rev32;
|
||||
|
@ -3356,22 +3331,11 @@ define pcodeop NEON_rshrn2;
|
|||
define pcodeop NEON_rsubhn;
|
||||
define pcodeop NEON_rsubhn2;
|
||||
define pcodeop NEON_saba;
|
||||
define pcodeop NEON_sabal;
|
||||
define pcodeop NEON_sabal2;
|
||||
define pcodeop NEON_sabd;
|
||||
define pcodeop NEON_sabdl;
|
||||
define pcodeop NEON_sabdl2;
|
||||
define pcodeop NEON_sadalp;
|
||||
define pcodeop NEON_saddl;
|
||||
define pcodeop NEON_saddl2;
|
||||
define pcodeop NEON_saddlp;
|
||||
define pcodeop NEON_saddlv;
|
||||
define pcodeop NEON_saddw;
|
||||
define pcodeop NEON_saddw2;
|
||||
define pcodeop NEON_scvtf;
|
||||
define pcodeop NEON_sdot;
|
||||
define pcodeop NEON_sha1c;
|
||||
define pcodeop NEON_sha1h;
|
||||
define pcodeop NEON_sha1m;
|
||||
define pcodeop NEON_sha1p;
|
||||
define pcodeop NEON_sha1su0;
|
||||
|
@ -3386,10 +3350,6 @@ define pcodeop NEON_sha512su0;
|
|||
define pcodeop NEON_sha512su1;
|
||||
define pcodeop NEON_shadd;
|
||||
define pcodeop NEON_shl;
|
||||
define pcodeop NEON_shll;
|
||||
define pcodeop NEON_shll2;
|
||||
define pcodeop NEON_shrn;
|
||||
define pcodeop NEON_shrn2;
|
||||
define pcodeop NEON_shsub;
|
||||
define pcodeop NEON_sli;
|
||||
define pcodeop NEON_sm3partw1;
|
||||
|
@ -3407,24 +3367,10 @@ define pcodeop NEON_smaxv;
|
|||
define pcodeop NEON_smin;
|
||||
define pcodeop NEON_sminp;
|
||||
define pcodeop NEON_sminv;
|
||||
define pcodeop NEON_smlal;
|
||||
define pcodeop NEON_smlal2;
|
||||
define pcodeop NEON_smlsl;
|
||||
define pcodeop NEON_smlsl2;
|
||||
define pcodeop NEON_smov;
|
||||
define pcodeop NEON_smmla;
|
||||
define pcodeop NEON_smull;
|
||||
define pcodeop NEON_smull2;
|
||||
define pcodeop NEON_sqabs;
|
||||
define pcodeop NEON_sqadd;
|
||||
define pcodeop NEON_sqdmlal;
|
||||
define pcodeop NEON_sqdmlal2;
|
||||
define pcodeop NEON_sqdmlsl;
|
||||
define pcodeop NEON_sqdmlsl2;
|
||||
define pcodeop NEON_sqdmulh;
|
||||
define pcodeop NEON_sqdmull;
|
||||
define pcodeop NEON_sqdmull2;
|
||||
define pcodeop NEON_sqneg;
|
||||
define pcodeop NEON_sqrdml_as_h;
|
||||
define pcodeop NEON_sqrdmulh;
|
||||
define pcodeop NEON_sqrshl;
|
||||
|
@ -3447,45 +3393,12 @@ define pcodeop NEON_srhadd;
|
|||
define pcodeop NEON_sri;
|
||||
define pcodeop NEON_srshl;
|
||||
define pcodeop NEON_srshr;
|
||||
define pcodeop NEON_srsra;
|
||||
define pcodeop NEON_sshl;
|
||||
define pcodeop NEON_sshll;
|
||||
define pcodeop NEON_sshll2;
|
||||
define pcodeop NEON_sshr;
|
||||
define pcodeop NEON_ssra;
|
||||
define pcodeop NEON_ssubl;
|
||||
define pcodeop NEON_ssubl2;
|
||||
define pcodeop NEON_ssubw;
|
||||
define pcodeop NEON_ssubw2;
|
||||
define pcodeop NEON_stnp1;
|
||||
define pcodeop NEON_stnp2;
|
||||
define pcodeop NEON_stp1;
|
||||
define pcodeop NEON_stp2;
|
||||
define pcodeop NEON_str;
|
||||
define pcodeop NEON_stur;
|
||||
define pcodeop NEON_sub;
|
||||
define pcodeop NEON_subhn;
|
||||
define pcodeop NEON_subhn2;
|
||||
define pcodeop NEON_sudot;
|
||||
define pcodeop NEON_suqadd;
|
||||
define pcodeop NEON_sxtl;
|
||||
define pcodeop NEON_sxtl2;
|
||||
define pcodeop NEON_tblx;
|
||||
define pcodeop NEON_trn1;
|
||||
define pcodeop NEON_trn2;
|
||||
define pcodeop NEON_uaba;
|
||||
define pcodeop NEON_uabal;
|
||||
define pcodeop NEON_uabal2;
|
||||
define pcodeop NEON_uabd;
|
||||
define pcodeop NEON_uabdl;
|
||||
define pcodeop NEON_uabdl2;
|
||||
define pcodeop NEON_uadalp;
|
||||
define pcodeop NEON_uaddl;
|
||||
define pcodeop NEON_uaddl2;
|
||||
define pcodeop NEON_uaddlp;
|
||||
define pcodeop NEON_uaddlv;
|
||||
define pcodeop NEON_uaddw;
|
||||
define pcodeop NEON_uaddw2;
|
||||
define pcodeop NEON_ucvtf;
|
||||
define pcodeop NEON_udot;
|
||||
define pcodeop NEON_uhadd;
|
||||
|
@ -3496,14 +3409,8 @@ define pcodeop NEON_umaxv;
|
|||
define pcodeop NEON_umin;
|
||||
define pcodeop NEON_uminp;
|
||||
define pcodeop NEON_uminv;
|
||||
define pcodeop NEON_umlal;
|
||||
define pcodeop NEON_umlal2;
|
||||
define pcodeop NEON_umlsl;
|
||||
define pcodeop NEON_umlsl2;
|
||||
define pcodeop NEON_ummla;
|
||||
define pcodeop NEON_umov;
|
||||
define pcodeop NEON_umull;
|
||||
define pcodeop NEON_umull2;
|
||||
define pcodeop NEON_uqadd;
|
||||
define pcodeop NEON_uqrshl;
|
||||
define pcodeop NEON_uqrshrn;
|
||||
|
@ -3519,28 +3426,10 @@ define pcodeop NEON_urhadd;
|
|||
define pcodeop NEON_urshl;
|
||||
define pcodeop NEON_urshr;
|
||||
define pcodeop NEON_ursqrte;
|
||||
define pcodeop NEON_ursra;
|
||||
define pcodeop NEON_usdot;
|
||||
define pcodeop NEON_ushl;
|
||||
define pcodeop NEON_ushll;
|
||||
define pcodeop NEON_ushll2;
|
||||
define pcodeop NEON_ushr;
|
||||
define pcodeop NEON_usmmla;
|
||||
define pcodeop NEON_usqadd;
|
||||
define pcodeop NEON_usra;
|
||||
define pcodeop NEON_usubl;
|
||||
define pcodeop NEON_usubl2;
|
||||
define pcodeop NEON_usubw;
|
||||
define pcodeop NEON_usubw2;
|
||||
define pcodeop NEON_uxtl;
|
||||
define pcodeop NEON_uxtl2;
|
||||
define pcodeop NEON_uzp1;
|
||||
define pcodeop NEON_uzp2;
|
||||
define pcodeop NEON_xar;
|
||||
define pcodeop NEON_xtn;
|
||||
define pcodeop NEON_xtn2;
|
||||
define pcodeop NEON_zip1;
|
||||
define pcodeop NEON_zip2;
|
||||
|
||||
# These pseudo ops are automatically generated
|
||||
|
||||
|
@ -4013,112 +3902,59 @@ macro set_NZCV(value, condMask)
|
|||
|
||||
# Macro to access simd lanes
|
||||
|
||||
macro simd_address_at(dest, reg, elem, esize, vsize)
|
||||
{
|
||||
@if DATA_ENDIAN == "little"
|
||||
dest = ® + elem * esize;
|
||||
@else
|
||||
dest = ® + vsize - esize - elem * esize;
|
||||
@endif
|
||||
}
|
||||
|
||||
# Macros to zero the high bits of the Z or Q registers
|
||||
# These are friendlier to the decompiler
|
||||
|
||||
macro zext_zb(reg)
|
||||
{
|
||||
@if DATA_ENDIAN == "little"
|
||||
reg[8,56] = 0;
|
||||
reg[64,64] = 0;
|
||||
reg[128,64] = 0;
|
||||
reg[192,64] = 0;
|
||||
@else
|
||||
reg[192,56] = 0;
|
||||
reg[128,64] = 0;
|
||||
reg[64,64] = 0;
|
||||
reg[0,64] = 0;
|
||||
@endif
|
||||
}
|
||||
|
||||
macro zext_zh(reg)
|
||||
{
|
||||
@if DATA_ENDIAN == "little"
|
||||
reg[16,48] = 0;
|
||||
reg[64,64] = 0;
|
||||
reg[128,64] = 0;
|
||||
reg[192,64] = 0;
|
||||
@else
|
||||
reg[192,48] = 0;
|
||||
reg[128,64] = 0;
|
||||
reg[64,64] = 0;
|
||||
reg[0,64] = 0;
|
||||
@endif
|
||||
}
|
||||
|
||||
macro zext_zs(reg)
|
||||
{
|
||||
@if DATA_ENDIAN == "little"
|
||||
reg[32,32] = 0;
|
||||
reg[64,64] = 0;
|
||||
reg[128,64] = 0;
|
||||
reg[192,64] = 0;
|
||||
@else
|
||||
reg[192,32] = 0;
|
||||
reg[128,64] = 0;
|
||||
reg[64,64] = 0;
|
||||
reg[0,64] = 0;
|
||||
@endif
|
||||
}
|
||||
|
||||
macro zext_zd(reg)
|
||||
{
|
||||
@if DATA_ENDIAN == "little"
|
||||
reg[64,64] = 0;
|
||||
reg[128,64] = 0;
|
||||
reg[192,64] = 0;
|
||||
@else
|
||||
reg[0,64] = 0;
|
||||
reg[64,64] = 0;
|
||||
reg[128,64] = 0;
|
||||
@endif
|
||||
}
|
||||
|
||||
macro zext_zq(reg)
|
||||
{
|
||||
@if DATA_ENDIAN == "little"
|
||||
reg[128,64] = 0;
|
||||
reg[192,64] = 0;
|
||||
@else
|
||||
reg[0,64] = 0;
|
||||
reg[64,64] = 0;
|
||||
@endif
|
||||
}
|
||||
|
||||
macro zext_rb(reg)
|
||||
{
|
||||
@if DATA_ENDIAN == "little"
|
||||
reg[8,56] = 0;
|
||||
@else
|
||||
reg[0,56] = 0;
|
||||
@endif
|
||||
}
|
||||
|
||||
macro zext_rh(reg)
|
||||
{
|
||||
@if DATA_ENDIAN == "little"
|
||||
reg[16,48] = 0;
|
||||
@else
|
||||
reg[0,48] = 0;
|
||||
@endif
|
||||
}
|
||||
|
||||
macro zext_rs(reg)
|
||||
{
|
||||
@if DATA_ENDIAN == "little"
|
||||
reg[32,32] = 0;
|
||||
@else
|
||||
reg[0,32] = 0;
|
||||
@endif
|
||||
}
|
||||
|
||||
# SECTION instructions
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue