mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-30 16:47:43 +08:00
GP-729 Decode RUNTIME_INFO and UNWIND_INFO structures in the PE .pdata section
This commit is contained in:
@@ -29,7 +29,8 @@ If applicable, please attach any files that caused problems or log files generat
|
|||||||
**Environment (please complete the following information):**
|
**Environment (please complete the following information):**
|
||||||
- OS: [e.g. macOS 10.14.2]
|
- OS: [e.g. macOS 10.14.2]
|
||||||
- Java Version: [e.g. 11.0]
|
- Java Version: [e.g. 11.0]
|
||||||
- Ghidra Version: [e.g. 9.0]
|
- Ghidra Version: [e.g. 9.1.2]
|
||||||
|
- Ghidra Origin: [e.g. official ghidra-sre.org distro, third party distro, locally built]
|
||||||
|
|
||||||
**Additional context**
|
**Additional context**
|
||||||
Add any other context about the problem here.
|
Add any other context about the problem here.
|
||||||
|
|||||||
@@ -6,14 +6,61 @@
|
|||||||
</HEAD>
|
</HEAD>
|
||||||
|
|
||||||
<BODY>
|
<BODY>
|
||||||
|
<H1 align="center">Ghidra 9.2.3 Change History (March 2021)</H1>
|
||||||
|
<blockquote><p><u>Improvements</u></p>
|
||||||
|
<ul>
|
||||||
|
<li><I>Analysis</I>. Added check for vftable entries in <code>.NEP</code> section and relaxed the requirement that the code must have a return. (GP-649)</li>
|
||||||
|
<li><I>Analysis</I>. Corrected flaw in RTTI analyzer determination of size of vftables. (GP-688)</li>
|
||||||
|
<li><I>Basic Infrastructure</I>. Updated TLS protocol preference to use the most preferred/recent version available to both sides of an SSL connection (e.g., TLSv1.3) instead of forcing use of TLSv1.2. (GP-622)</li>
|
||||||
|
<li><I>Build</I>. Corrected build issues which had prevented users from building Ghidra on an Apple M1 (OS X, AARCH64 architecture). (GP-600, Issue #2653)</li>
|
||||||
|
<li><I>Demangler</I>. Increased Gnu Demangler parsing performance by changing some regular expressions. (GP-705)</li>
|
||||||
|
<li><I>Eclipse Integration</I>. Updated SleighEditor to support new endian tag on <B>define token</B> definitions. (GP-721)</li>
|
||||||
|
<li><I>GUI</I>. Updated the Choose Data Type dialog to apply data types in the same manner as dragging types from the Data Types window. This provides users more control when choosing how to overwrite existing types. (GP-521)</li>
|
||||||
|
<li><I>Importer:ELF</I>. Added support for ELF relocation <code>R_X86_64_IRELATIVE</code>. (GP-651, Issue #1189)</li>
|
||||||
|
<li><I>Importer:ELF</I>. Sped up loading of ELF files with large symbol tables. (GP-697)</li>
|
||||||
|
</ul>
|
||||||
|
</blockquote>
|
||||||
|
<blockquote><p><u>Bugs</u></p>
|
||||||
|
<ul>
|
||||||
|
<li><I>Analysis</I>. The RTTI analyzer now runs prior to Reference analysis so that references into vftables are not turned into code or data before the vftables are created. (GP-517)</li>
|
||||||
|
<li><I>API</I>. <code>Funtion.getCalledFunctions(TaskMonitor)</code> and <code>Function.getCallingFunctions(TaskMonitor)</code> now support passing <code>null</code> for the task monitor parameter, which previously would have thrown an exception. (GP-589, Issue #2643)</li>
|
||||||
|
<li><I>Data Types</I>. Corrected segmented 32-bit pointer datatype address generation for 16:16 x86 far pointers. (GP-534, Issue #2548)</li>
|
||||||
|
<li><I>Decompiler</I>. Fixed Decompiler issue where, when a function name extends beyond the line limit, an end-of-line comment could wrap around to additional lines without including additional <code>//</code> comment indicators. (GP-473)</li>
|
||||||
|
<li><I>Decompiler</I>. Corrected an exception that could occur when attempting to edit function signature from the Decompiler. (GP-597, Issue #2601)</li>
|
||||||
|
<li><I>Eclipse Integration</I>. When installing the SleighEditor into Eclipse, the plugin will now show up under the Ghidra category. Previously the <B>Group Items by Category</B> option had to be turned off before the SleighEditor would appear as a visible entry. (GP-564)</li>
|
||||||
|
<li><I>Eclipse Integration</I>. Fixed an issue with Eclipse PyDev breakpoints not catching. (GP-668, Issue #2713)</li>
|
||||||
|
<li><I>Eclipse Integration</I>. Fixed an Eclipse GhidraDev exception that occurred when creating a new Ghidra scripting project if a <B>~/ghidra_scripts</B> directory did not exist. (GP-669)</li>
|
||||||
|
<li><I>Emulator</I>. Replaced Java floating point emulation to fix multiple rounding issues. (GP-357, Issue #2414)</li>
|
||||||
|
<li><I>Graphing</I>. Fixed issue with graph filters not updating satellite view when changing edge filters. (GP-557)</li>
|
||||||
|
<li><I>Graphing</I>. Fixed Function Graph keybindings that did not work when docked in the main Code Browser window. (GP-586, Issue #2641)</li>
|
||||||
|
<li><I>GUI</I>. Fixed NPE due to using <B>Go To</B> action when there was no open program in the Listing. (GP-66)</li>
|
||||||
|
<li><I>GUI</I>. Fixed bug in Reference Code Viewer options that caused an exception. (GP-620, Issue #2672)</li>
|
||||||
|
<li><I>Importer</I>. Fixed exception caused when importing previously exported XML data where the bookmark override option was turned off. (GP-667)</li>
|
||||||
|
<li><I>Importer:ELF</I>. Fixed a NullPointerException caused by importing an ELF with an uninitialized <code>.got</code> section. (GP-360, Issue #2416)</li>
|
||||||
|
<li><I>Importer:ELF</I>. Added Support for ELF <code>R_ARM_MOVW_ABS_NC</code> and <code>R_ARM_MOVT_ABS ELF</code> Relocations for ARM. (GP-555, Issue #2510)</li>
|
||||||
|
<li><I>Importer:ELF</I>. Corrected ELF processing of <code>.init_array</code> and <code>.fini_array</code> which was incorrectly overadjusting entries for an image base change. (GP-699)</li>
|
||||||
|
<li><I>Importer:Mach-O</I>. Corrected Mach-O fat-binary library import issue and resolved error related to unnamed Mach-O segment. (GP-652, Issue #2702)</li>
|
||||||
|
<li><I>Importer:Mach-O</I>. Fixed an issue with DYLD Load Command data structures being created in the wrong locations. (GP-689, Issue #2624)</li>
|
||||||
|
<li><I>Importer:Mach-O</I>. Fixed an exception that occurred when importing Mach-O files that define zero <code>LC_BUILD_VERSION</code> tool entries. (GP-702, Issue #2192)</li>
|
||||||
|
<li><I>PDB</I>. Fixed createPdbXmlFiles.bat to permit spaces in the path name of Ghidra installation folder and the batch argument name. (GP-575, Issue #2167)</li>
|
||||||
|
<li><I>PDB</I>. Fix PDB Universal analyzer to set the run-once flag when finished. (GP-724)</li>
|
||||||
|
<li><I>Processors</I>. Added missing <code>RFE</code> instruction in MIPS up to version R3000. (GP-33, Issue #1766)</li>
|
||||||
|
<li><I>Processors</I>. ARM instruction <code>VMUL</code> now decodes correctly. (GP-627, Issue #2677)</li>
|
||||||
|
<li><I>Processors</I>. Added missing <code>CFINV</code> instruction to AARCH64 processor specification and added definitions for locals in neon instructions. (GP-655, Issue #2710)</li>
|
||||||
|
<li><I>Scripting</I>. Fixed analyzeHeadless <code><B>-scriptPath</B></code> option that didn't work for Python and other non-Java scripts located in non-default directories. (GP-528, Issue #2561)</li>
|
||||||
|
<li><I>Scripting</I>. Fixed concurrency issue with management of scripting bundle paths. (GP-576)</li>
|
||||||
|
<li><I>Scripting</I>. Corrected handling for Ghidra Script files which are symlinks that were broken in Ghidra 9.2. (GP-650, Issue #2698)</li>
|
||||||
|
</ul>
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
<H1 align="center">Ghidra 9.2.2 Change History (December 2020)</H1>
|
<H1 align="center">Ghidra 9.2.2 Change History (December 2020)</H1>
|
||||||
<blockquote><p><u>Bugs</u></p>
|
<blockquote><p><u>Bugs</u></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><I>Graphing</I>. Fixed issue with Graph filters not working and satellite view sometimes not matching graph. (GP-526)</li>
|
<li><I>Graphing</I>. Fixed issue with Graph filters not working and satellite view sometimes not matching graph. (GP-526)</li>
|
||||||
<li><I>Importer:MachO</I>. MachO DYLD cache incorrect offset use has been fixed. (GP-550, Issue ##2560)</li>
|
<li><I>Importer:Mach-O</I>. Mach-O DYLD cache incorrect offset use has been fixed. (GP-550, Issue #2560)</li>
|
||||||
<li><I>Listing</I>. Fixed issue where Edit Label action (L key) did not work on primary function symbols. (GP-537)</li>
|
<li><I>Listing</I>. Fixed issue where <B>Edit Label</B> action (L key) did not work on primary function symbols. (GP-537)</li>
|
||||||
<li><I>Multi-User</I>. Corrected Ghidra Server build issue for version 9.2.1 which had an improperly generated <B>classpath.frag</B> file. Issue caused server to fail startup with a ClassNotFoundException. (GP-542)</li>
|
<li><I>Multi-User</I>. Corrected Ghidra Server build issue for version 9.2.1 which had an improperly generated <B>classpath.frag</B> file. Issue caused server to fail startup with a ClassNotFoundException. (GP-542)</li>
|
||||||
<li><I>Processors</I>. The V850 JMP instruction has been corrected not to use the PC in the address calculation (GP-548, Issue #2570)</li>
|
<li><I>Processors</I>. The V850 <code>JMP</code> instruction has been corrected not to use the PC in the address calculation. (GP-548, Issue #2570)</li>
|
||||||
<li><I>Processors</I>. Removed erroneous VST4 variant, most likely from a copy/paste error. This fixes the ARM Thumb BL instruction disassembly with a negative offset. (GP-549, Issue #2559)</li>
|
<li><I>Processors</I>. Removed erroneous VST4 variant, most likely from a copy/paste error. This fixes the ARM Thumb BL instruction disassembly with a negative offset. (GP-549, Issue #2559)</li>
|
||||||
</ul>
|
</ul>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
@@ -24,6 +71,7 @@
|
|||||||
<li><I>Analysis</I>. Updated RTTI analyzer to find <code>type_info</code> vftable when it cannot be found with its mangled name. This will enable many more Windows programs to have their RTTI structures created that were unable to be parsed in previous Ghidra versions. (GP-141)</li>
|
<li><I>Analysis</I>. Updated RTTI analyzer to find <code>type_info</code> vftable when it cannot be found with its mangled name. This will enable many more Windows programs to have their RTTI structures created that were unable to be parsed in previous Ghidra versions. (GP-141)</li>
|
||||||
<li><I>API</I>. Relaxed memory block naming restrictions and restored ability to have spaces in memory block names. However, if a memory block is flagged as an overlay, the associated overlay space name may be modified to ensure validity and uniqueness. The DuplicateNameException has been removed from all memory block API methods since this was entirely an overlay space concern. Memory block GUI has also been changed eliminate the duplicate block name restriction. (GP-420, Issue #2465)</li>
|
<li><I>API</I>. Relaxed memory block naming restrictions and restored ability to have spaces in memory block names. However, if a memory block is flagged as an overlay, the associated overlay space name may be modified to ensure validity and uniqueness. The DuplicateNameException has been removed from all memory block API methods since this was entirely an overlay space concern. Memory block GUI has also been changed eliminate the duplicate block name restriction. (GP-420, Issue #2465)</li>
|
||||||
<li><I>Build</I>. Eliminated the need for installation of <B>bison</B> and <B>flex</B> when performing source-based <B>gradle</B> build of Ghidra or the Decompiler module. The generated files are now included with source files and maintained in source control. A separate <code><B>gradle Decompiler:generateParsers</B></code> task, which still requires <B>bison</B> and <B>flex</B>, must be used, explicitly, when changes are made to lex/yacc source files. (GP-467)</li>
|
<li><I>Build</I>. Eliminated the need for installation of <B>bison</B> and <B>flex</B> when performing source-based <B>gradle</B> build of Ghidra or the Decompiler module. The generated files are now included with source files and maintained in source control. A separate <code><B>gradle Decompiler:generateParsers</B></code> task, which still requires <B>bison</B> and <B>flex</B>, must be used, explicitly, when changes are made to lex/yacc source files. (GP-467)</li>
|
||||||
|
<li><I>Graphing</I>. Fixed issue with exporting graphs to DOT format due to invalid vertex IDs. (GP-280)</li>
|
||||||
<li><I>Graphing</I>. Improved graphing where it did not navigate when clicking on external function nodes. Now it will navigate to the <B>fake</B> function location in the program, which is the location of the pointer to the external function. (GP-493)</li>
|
<li><I>Graphing</I>. Improved graphing where it did not navigate when clicking on external function nodes. Now it will navigate to the <B>fake</B> function location in the program, which is the location of the pointer to the external function. (GP-493)</li>
|
||||||
<li><I>Listing:Symbols</I>. Removed restriction for naming labels that resemble default label names. (GT-3185, Issue #1057)</li>
|
<li><I>Listing:Symbols</I>. Removed restriction for naming labels that resemble default label names. (GT-3185, Issue #1057)</li>
|
||||||
<li><I>PDB</I>. Crafted PDB type ID records <code>0x1608</code> and <code>0x1609</code> with presumed <B>class</B> and <B>struct</B> types and follow-on application of these types. Also fixed up some fall-back data type logic and improved some warning messages to reflect the <B>cause</B> of the conditions. (GP-474, Issue #2523)</li>
|
<li><I>PDB</I>. Crafted PDB type ID records <code>0x1608</code> and <code>0x1609</code> with presumed <B>class</B> and <B>struct</B> types and follow-on application of these types. Also fixed up some fall-back data type logic and improved some warning messages to reflect the <B>cause</B> of the conditions. (GP-474, Issue #2523)</li>
|
||||||
@@ -37,7 +85,7 @@
|
|||||||
<li><I>Decompiler</I>. Fixed issue with the Auto Create/Fill Structure command that caused it to silently miss some pointer accesses. (GP-344)</li>
|
<li><I>Decompiler</I>. Fixed issue with the Auto Create/Fill Structure command that caused it to silently miss some pointer accesses. (GP-344)</li>
|
||||||
<li><I>Decompiler</I>. Jump table recovery now takes into account encoded bits, like ARM/THUMB mode transition, that may be present in address tables. (GP-387, Issue #2420)</li>
|
<li><I>Decompiler</I>. Jump table recovery now takes into account encoded bits, like ARM/THUMB mode transition, that may be present in address tables. (GP-387, Issue #2420)</li>
|
||||||
<li><I>Decompiler</I>. Fixed a bug in the Decompiler <B>renaming</B> action when applied to function references. (GP-477, Issue #2415)</li>
|
<li><I>Decompiler</I>. Fixed a bug in the Decompiler <B>renaming</B> action when applied to function references. (GP-477, Issue #2415)</li>
|
||||||
<li><I>Decompiler</I>. Corrected 8-byte return value storage specification in compiler-spec affecting longlong and double return values. Endianess ordering of r0/r1 was incorrect. (GP-512, Issue #2547)</li>
|
<li><I>Decompiler</I>. Corrected 8-byte return value storage specification in compiler-spec affecting <code>longlong</code> and <code>double</code> return values. Endianess ordering of <code>r0</code>/<code>r1</code> was incorrect. (GP-512, Issue #2547)</li>
|
||||||
<li><I>Graphing</I>. Fixed the Function Graph's <B>drag-to-select-nodes</B> feature. (GP-430)</li>
|
<li><I>Graphing</I>. Fixed the Function Graph's <B>drag-to-select-nodes</B> feature. (GP-430)</li>
|
||||||
<li><I>Graphing</I>. Fixed issue where the graph in the satellite view is sometimes truncated. (GP-469)</li>
|
<li><I>Graphing</I>. Fixed issue where the graph in the satellite view is sometimes truncated. (GP-469)</li>
|
||||||
<li><I>Graphing</I>. Fixed a stack trace issue caused by reusing a graph display window to show a graph that is larger than is allowed. (GP-492)</li>
|
<li><I>Graphing</I>. Fixed a stack trace issue caused by reusing a graph display window to show a graph that is larger than is allowed. (GP-492)</li>
|
||||||
@@ -126,7 +174,7 @@
|
|||||||
<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 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:ELF</I>. Added ELF import opinion for ARM BE8. (GT-3642, Issue #1187)</li>
|
||||||
<li><I>Importer:ELF</I>. Added support for ELF RELR relocations, such as those produced for Android. (GP-348)</li>
|
<li><I>Importer:ELF</I>. Added support for ELF RELR relocations, such as those produced for Android. (GP-348)</li>
|
||||||
<li><I>Importer:MachO</I>. DYLD Loader can now load x86_64 DYLD from macOS. (GT-3611, Issue #1566)</li>
|
<li><I>Importer:Mach-O</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>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>Jython</I>. Upgraded Jython to version 2.7.2. (GP-109)</li>
|
||||||
<li><I>Listing</I>. In the PCode field of the Listing, accesses of varnodes in the <code>unique</code> space are now always shown with the size of the access. Fixed bug which would cause the PCode emulator to reject valid pcode in rare instances. (GP-196)</li>
|
<li><I>Listing</I>. In the PCode field of the Listing, accesses of varnodes in the <code>unique</code> space are now always shown with the size of the access. Fixed bug which would cause the PCode emulator to reject valid pcode in rare instances. (GP-196)</li>
|
||||||
@@ -282,8 +330,8 @@
|
|||||||
<li><I>Disassembly</I>. Corrected potential infinite loop with disassembler caused by branch to self with invalid delay slot instruction. (GT-3511, Issue #1486)</li>
|
<li><I>Disassembly</I>. Corrected potential infinite loop with disassembler caused by branch to self with invalid delay slot instruction. (GT-3511, Issue #1486)</li>
|
||||||
<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</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>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>Importer:Mach-O</I>. A Mach-O 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>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>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>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 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>. Corrected issue in M68000 with some move instructions not creating correct array assignments. (GT-3429, Issue #1394)</li>
|
||||||
@@ -294,7 +342,7 @@
|
|||||||
<H1 align="center">Ghidra 9.1.1 Change History (December 2019)</H1>
|
<H1 align="center">Ghidra 9.1.1 Change History (December 2019)</H1>
|
||||||
<blockquote><p><u>Improvements</u></p>
|
<blockquote><p><u>Improvements</u></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><I>Importer:MachO</I>. Improved import/load time of DYLD shared cache files. (GT-3261)</li>
|
<li><I>Importer:Mach-O</I>. Improved import/load time of DYLD shared cache files. (GT-3261)</li>
|
||||||
<li><I>Program API</I>. Cached the addresses that correspond to executable memory to improve analysis performance. (GT-3260)</li>
|
<li><I>Program API</I>. Cached the addresses that correspond to executable memory to improve analysis performance. (GT-3260)</li>
|
||||||
</ul>
|
</ul>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
@@ -331,7 +379,7 @@
|
|||||||
<li><I>Eclipse Integration</I>. Added new GhidraSleighEditor Eclipse plugin in the installation directory under Extensions/Eclipse. (GT-113)</li>
|
<li><I>Eclipse Integration</I>. Added new GhidraSleighEditor Eclipse plugin in the installation directory under Extensions/Eclipse. (GT-113)</li>
|
||||||
<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>. 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>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>Importer:Mach-O</I>. Added new importer/loader for DYLD-shared cache files. (GT-2343)</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>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>. 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 SH1/2/2a sleigh processor specification. (GT-3029, Issue #715)</li>
|
||||||
@@ -488,7 +536,7 @@
|
|||||||
<li><I>Listing</I>. Cursor in the listing now stays in the proper column after editing a field. (GT-3045, Issue #702)</li>
|
<li><I>Listing</I>. Cursor in the listing now stays in the proper column after editing a field. (GT-3045, Issue #702)</li>
|
||||||
<li><I>Listing</I>. Fixed a problem with register highlighting that could occur on certain register/sub-register combinations. (GT-3071, Issue #810)</li>
|
<li><I>Listing</I>. Fixed a problem with register highlighting that could occur on certain register/sub-register combinations. (GT-3071, Issue #810)</li>
|
||||||
<li><I>Multi-User</I>. Corrected terminate checkout from viewed checkout list which was always terminating first row range based upon number of selected rows and not the actual selected rows. (GT-2903)</li>
|
<li><I>Multi-User</I>. Corrected terminate checkout from viewed checkout list which was always terminating first row range based upon number of selected rows and not the actual selected rows. (GT-2903)</li>
|
||||||
<li><I>Multi-user</I>. Corrected ability for user to cancel checkin/checkout to Ghidra Server. (GT-3208)</li>
|
<li><I>Multi-User</I>. Corrected ability for user to cancel checkin/checkout to Ghidra Server. (GT-3208)</li>
|
||||||
<li><I>Multi-User:Ghidra Server</I>. Added proper Ghidra Server interface binding with new <code><B>-i</B></code> option. Corrected <code><B>-ip</B></code> option to strictly convey remote access hostname to clients. The updated server will only accept connections from Ghidra 9.1 and later clients due to the registry port now employing TLS. (GT-2685, Issue #101, #645)</li>
|
<li><I>Multi-User:Ghidra Server</I>. Added proper Ghidra Server interface binding with new <code><B>-i</B></code> option. Corrected <code><B>-ip</B></code> option to strictly convey remote access hostname to clients. The updated server will only accept connections from Ghidra 9.1 and later clients due to the registry port now employing TLS. (GT-2685, Issue #101, #645)</li>
|
||||||
<li><I>Multi-User:Ghidra Server</I>. Fixed argument-passing bug in svrAdmin script. (GT-3082, Issue #907)</li>
|
<li><I>Multi-User:Ghidra Server</I>. Fixed argument-passing bug in svrAdmin script. (GT-3082, Issue #907)</li>
|
||||||
<li><I>Multi-User:Merge</I>. Corrected merge problem affecting modified Function Definition datatypes which could result in a NullPointerException. (GT-2922)</li>
|
<li><I>Multi-User:Merge</I>. Corrected merge problem affecting modified Function Definition datatypes which could result in a NullPointerException. (GT-2922)</li>
|
||||||
@@ -518,7 +566,7 @@
|
|||||||
<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 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>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>
|
<li><I>Project Manager</I>. Fixed a problem with creating Ghidra projects in Windows root directories (e.g., Z:\). (GT-2585)</li>
|
||||||
<li><I>Project Manager</I>. Fixed a path traversal vulnerability that could occur when restoring a malicious project archive. (GT-3001, Issue #789)</li>
|
<li><I>Project Manager</I>. Fixed a path-traversal vulnerability that could occur when restoring a malicious project archive. (GT-3001, Issue #789)</li>
|
||||||
<li><I>Scripting</I>. <code>GhidraScript.askDomainFile()</code> now correctly throws a CancelledException when the cancel button is clicked. (GT-2841)</li>
|
<li><I>Scripting</I>. <code>GhidraScript.askDomainFile()</code> now correctly throws a CancelledException when the cancel button is clicked. (GT-2841)</li>
|
||||||
<li><I>Scripting</I>. Removed deprecated scripting methods older than 5 releases. (GT-2949)</li>
|
<li><I>Scripting</I>. Removed deprecated scripting methods older than 5 releases. (GT-2949)</li>
|
||||||
<li><I>Security</I>. Removed use of nonsecure XMLEncoder/XMLDecoder from Ghidra code base. (GT-3198, Issue #1090)</li>
|
<li><I>Security</I>. Removed use of nonsecure XMLEncoder/XMLDecoder from Ghidra code base. (GT-3198, Issue #1090)</li>
|
||||||
@@ -531,128 +579,123 @@
|
|||||||
<H1 align="center">Ghidra 9.0.4 Change History (May 2019)</H1>
|
<H1 align="center">Ghidra 9.0.4 Change History (May 2019)</H1>
|
||||||
<blockquote><p><u>Bugs</u></p>
|
<blockquote><p><u>Bugs</u></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><I>Multi-User:Ghidra Server</I>. Corrected severe script error in svrAdmin.bat introduced with 9.0.3 build.</li>
|
<li><I>Multi-User:Ghidra Server</I>. Corrected severe script error in svrAdmin.bat introduced with 9.0.3 build. (GT-2874)</li>
|
||||||
<li><I>GUI</I>. Restored the default 'p' key binding for creating pointers within the listing display.</li>
|
<li><I>GUI</I>. Restored the default 'p' key binding for creating pointers within the listing display. (GT-2854)</li>
|
||||||
</ul>
|
</ul>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<H1 align="center">Ghidra 9.0.3 Change History (April 2019)</H1>
|
<H1 align="center">Ghidra 9.0.3 Change History (April 2019)</H1>
|
||||||
<blockquote><p><u>New Features</u></p>
|
<blockquote><p><u>New Features</u></p>
|
||||||
<ul>
|
<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. (GT-2114)</li>
|
||||||
</ul>
|
</ul>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<blockquote><p><u>Improvements</u></p>
|
<blockquote><p><u>Improvements</u></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><I>Decompiler</I>. Improved modeling of CFG on Windows 10. (Issue #340)</li>
|
<li><I>Decompiler</I>. Improved modeling of CFG on Windows 10. (GT-2755, 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>Patcher</I>. Renamed patch directory to <install dir>/Ghidra/patch and added README.txt that explains how the patch directory is used. (GT-2734)</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>Search</I>. Updated the Decompiler Data Type Finder to find references inside of nested array access in a line of Decompiler C output. (GT-2756, Issue #416)</li>
|
||||||
<li><I>Sleigh</I>. Improved error reporting for SLEIGH compiler. (Issue #364)</li>
|
<li><I>Sleigh</I>. Improved error reporting for SLEIGH compiler. (GT-2820, Issue #364)</li>
|
||||||
</ul>
|
</ul>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<blockquote><p><u>Bugs</u></p>
|
<blockquote><p><u>Bugs</u></p>
|
||||||
<ul>
|
<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>. Code that checks for thunks no longer throws an exception if the PC is not set for the processor. (GT-2730)</li>
|
||||||
<li><I>Analysis</I>. Made a fix to enable Apply button when changing tool options. (Issue #40)</li>
|
<li><I>Analysis</I>. Made a fix to enable Apply button when changing tool options. (GT-2801, 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>Data Types</I>. Fixed concurrent modification exception when replacing one datatype for another that results in some other datatype being renamed. (GT-2736)</li>
|
||||||
<li><I>Decompiler</I>. Fixed dynamic variables and equates in 16-bit x86 programs. (Issue #336)</li>
|
<li><I>Decompiler</I>. Fixed dynamic variables and equates in 16-bit x86 programs. (GT-2745, Issue #336)</li>
|
||||||
<li><I>Decompiler:Java</I>. Fixed DEX decompilation regression issue. (Issue #350)</li>
|
<li><I>Decompiler:Java</I>. Fixed DEX decompilation regression issue. (Issue #350, GT-2743)</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>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. (GT-2721, 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>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>Importer</I>. Fixed an exception that occurred when batch importing APK files. (GT-2767, Issue #426)</li>
|
||||||
<li><I>Multi-User:Ghidra Server</I>. Restored ability to execute svrAdmin script in development mode. </li>
|
<li><I>Multi-User:Ghidra Server</I>. Restored ability to execute svrAdmin script in development mode. (GT-2740) </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 6502 Zero page indexed addressing has been corrected to only access the Zero page. (GT-2759, 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>Processors</I>. The M68000 BCD arithmetic instructions now have pcode semantics that allow disassembly to continue. (GT-2807, Issue #227)</li>
|
||||||
<li><I>Search</I>. Fixed NullPointerException in Decompiler Data Type Reference Finder. (Issue #407)</li>
|
<li><I>Search</I>. Fixed NullPointerException in Decompiler Data Type Reference Finder. (GT-2754. Issue #407)</li>
|
||||||
</ul>
|
</ul>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<H1 align="center">Ghidra 9.0.2 Change History (April 2019)</H1>
|
<H1 align="center">Ghidra 9.0.2 Change History (April 2019)</H1>
|
||||||
<blockquote><p><u>Bugs</u></p>
|
<blockquote><p><u>Bugs</u></p>
|
||||||
<ul>
|
<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>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. (GT-2723, 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. (GT-2704, Issue #247)</li>
|
||||||
<li><I>Decompiler</I>. Fixed decompiler handling of Function Definition data types. (Issue #247) </li>
|
<li><I>Decompiler</I>. Fixed rendering bug in the Decompiler when the "Find" dialog is closed. (GT-2716, Issue #282)</li>
|
||||||
<li><I>Decompiler</I>. Fixed "Free Varnode" exception in RuleConditionalMove. (Issue #294) </li>
|
<li><I>Decompiler</I>. Fixed "Free Varnode" exception in RuleConditionalMove. (GT-2726, Issue #294)</li>
|
||||||
<li><I>Diff</I>. Fixed exceptions that can occur in the Diff View for programs with overlays. </li>
|
<li><I>Diff</I>. Fixed exceptions that can occur in the Diff View for programs with overlays. (GT-2706)</li>
|
||||||
<li><I>Documentation</I>. Corrected the spelling of "listener" throughout the source code. (Issue #235) </li>
|
<li><I>Documentation</I>. Corrected the spelling of "listener" throughout the source code. (GT-2702, 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>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. (GT-2703, Issue #260)</li>
|
||||||
<li><I>GUI</I>. Fixed exception that occurs after disabling MyProgramChangesDisplayPlugin. </li>
|
<li><I>GUI</I>. Fixed exception that occurs after disabling MyProgramChangesDisplayPlugin. (GT-2712)</li>
|
||||||
<li><I>GUI</I>. Updated the "Open Program" dialog to disallow file drop operations. (Issue #252)
|
<li><I>GUI</I>. Updated the "Open Program" dialog to disallow file drop operations. (GT-2705, Issue #252)</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>Multi-User:Ghidra Server</I>. Corrected bug introduced into ghidraSvr.bat which could prevent Ghidra Server startup. (GT-2717, 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>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. (GT-2722, 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>
|
<li><I>Scripting</I>. MultiInstructionMemReference script has been corrected to consider input and output registers when placing a reference on an instruction. (GT-2723)</li>
|
||||||
</ul>
|
</ul>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<blockquote><p><u>Security</u></p>
|
<blockquote><p><u>Security</u></p>
|
||||||
<ul>
|
<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. (GT-2725, Issue #286)</li>
|
||||||
</ul>
|
</ul>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<H1 align="center">Ghidra 9.0.1 Change History (March 2019)</H1>
|
<H1 align="center">Ghidra 9.0.1 Change History (March 2019)</H1>
|
||||||
<blockquote><p><u>New Features</u></p>
|
<blockquote><p><u>New Features</u></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><I>Scripting</I>. Created a script to show all equates within the current selection. (Issue #111)</li>
|
<li><I>Scripting</I>. Created ShowEquatesInSelectionScript to show all equates within the current selection. (GT-2651, Issue #111)</li>
|
||||||
</ul>
|
</ul>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<blockquote><p><u>Improvements</u></p>
|
<blockquote><p><u>Improvements</u></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><I>Basic Infrastructure</I>. Updated commons-compress library to version 1.18. (Issue #171)</li>
|
<li><I>Basic Infrastructure</I>. Updated commons-compress library to version 1.18. (GT-2657, 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>Eclipse Integration</I>. Ghidra now connects to the Eclipse GhidraDev plugin on 127.0.0.1 rather than localhost. (GT-2691)</li>
|
||||||
<li><I>GUI</I>. Turned on font anti-aliasing by default for Linux. (Issue #212)</li>
|
<li><I>GUI</I>. Turned on font anti-aliasing by default for Linux. (GT-2674, Issue #212)</li>
|
||||||
<li><I>GUI</I>. Fixed Options Dialog slow scrolling speed. (Issue #27)</li>
|
<li><I>GUI</I>. Fixed Options Dialog slow scrolling speed. (GT-2679, Issue #27)</li>
|
||||||
<li><I>Importer:ELF</I>. Corrected bug in ELF loader which can improperly process the GOT, PLT and relocations
|
<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. (GT-2646, Issue #52)</li>
|
||||||
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. (GT-2637)</li>
|
||||||
<li><I>Multi-User:Ghidra Server</I>. Corrected the Ghidra Server service wrapper (YAJSW) configuration for
|
<li><I>Processors</I>. Added ARM/Thumb SRS instruction decodes for undefined modes. (GT-2676, Issue #216)</li>
|
||||||
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>
|
</ul>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<blockquote><p><u>Bugs</u></p>
|
<blockquote><p><u>Bugs</u></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><I>API</I>. Fixed equals method on Varnode class. (Issue #97)</li>
|
<li><I>API</I>. Fixed equals method on Varnode class. (GT-2648, Issue #97)</li>
|
||||||
<li><I>API</I>. Fixed a bug in MaskImpl.comlementMask(). (Issue #187)</li>
|
<li><I>API</I>. Fixed a bug in MaskImpl.complementMask(). (GT-2694, Issue #187)</li>
|
||||||
<li><I>Basic Infrastructure</I>. Fixed special character handling in idaxml.py. (Issue #75)</li>
|
<li><I>Basic Infrastructure</I>. Fixed special character handling in idaxml.py. (GT-2669, 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.
|
<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. (GT-2680, Issue #209)</li>
|
||||||
This fixes certain unexpected exceptions. (Issue #209)</li>
|
<li><I>Diff</I>. Fixed exception occasionally encountered when starting a Diff session. (GT-2672, Issue #211)</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. (GT-2655, Issue #129)</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. (GT-2650, Issue #65)</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. (GT-1516, Issue #41)</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. (GT-2638)</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. (GT-2642, Issue #51)</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. (GT-2647, Issue #2)</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. (GT-2656, Issue #133)</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. (GT-2659, Issue #152)</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. (GT-2689)</li>
|
||||||
<li><I>GUI</I>. Toolbar buttons now respond to fast clicking.</li>
|
<li><I>Importer:Mach-O</I>. The Mach-O loader can now find import libraries found in Universal Binary files. (GT-2663, Issue #136)</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 table entries are more than 4 bytes each. (GT-2671, Issue #220)</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. (GT-2653)</li>
|
||||||
<li><I>Multi-User:Ghidra Server</I>. Removed support for native OS authentication from Ghidra Server (removed modes -a2 and -a3)
|
<li><I>PDB</I>. Corrected NPE error when processing PDB files. (GT-2673, Issues #138, #188)</li>
|
||||||
due to incompatibility with newer OS releases including Windows 10 and Windows Server 2016. Re-introduction of this will be
|
<li><I>Processors</I>. Added missing PowerPC VLE conditional branch instructions: e_bdnz and e_bdz. (GT-2652, Issue #103)</li>
|
||||||
considered for a future release.</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. (GT-2660, Issues #22, #53, #158, #157)</li>
|
||||||
<li><I>PDB</I>. Corrected NPE error when processing PDB files. (Issues #138, #188)</li>
|
<li><I>Processors</I>. The M68000 MOVE instruction now correctly sets the CF and VF flags. (GT-2661, Issue #163)</li>
|
||||||
<li><I>Processors</I>. Added missing PowerPC VLE conditional branch instructions: e_bdnz and e_bdz. (Issue #103)</li>
|
<li><I>Processors</I>. Added four missing MOVEM instruction variants to the M68000 processor. (GT-2675, Issue #219)</li>
|
||||||
<li><I>Processors</I>. Fixed instruction semantics for several instructions and added Control Flow Enforcement, NOP variants, CMP variants, UD1, and
|
<li><I>Processors</I>. An incorrect usage of X instead of Y in indexed mode for the 6502 has been corrected. (GT-2677, Issue #201)</li>
|
||||||
prefixed call instructions to X86 processor specification. (Issues #22, #53, #158, #157)</li>
|
<li><I>Processors</I>. PPC VLE now disassembles base PPC instructions that are valid in VLE mode. (GT-2681, Issue #127)</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 support for ARM Thumb half BL instruction on processor variants prior to v6. (GT-2684, Issue #39)</li>
|
||||||
<li><I>Processors</I>. Added four missing MOVEM instruction variants to the 68000 processor. (Issue #219)</li>
|
<li><I>Scripting</I>. Fixed a bug in ImportSymbolsScript.py that prevented it from running. (GT-2668, Issue #170)</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>
|
</ul>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
<blockquote><p><u>Security</u></p>
|
<blockquote><p><u>Security</u></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><I>Basic Infrastructure</I>. Running Ghidra in debug mode no longer opens remotely accessible ports by default. (Issue #6)</li>
|
<li><I>Basic Infrastructure</I>. Running Ghidra in debug mode no longer opens remotely accessible ports by default. (GT-2641, Issue #6)</li>
|
||||||
<li><I>GUI</I>. The Defined Strings plugin no longer renders HTML in its table. (Issue #45)</li>
|
<li><I>GUI</I>. The Defined Strings plugin no longer renders HTML in its table. (GT-2686, Issue #45)</li>
|
||||||
<li><I>Project Manager</I>. Fixed an XXE vulnerability affecting projects and many other saved components. (Issue #71)</li>
|
<li><I>Project Manager</I>. Fixed an XXE vulnerability affecting projects and many other saved components. (GT-2643, Issue #71)</li>
|
||||||
</ul>
|
</ul>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
|
abort
|
||||||
CxxThrowException
|
CxxThrowException
|
||||||
CxxThrowException@8
|
CxxThrowException@8
|
||||||
CxxFrameHandler3
|
CxxFrameHandler3
|
||||||
crtExitProcess
|
crtExitProcess
|
||||||
ExitProcess
|
ExitProcess
|
||||||
|
ExitThread
|
||||||
exit
|
exit
|
||||||
|
FreeLibraryAndExitThread
|
||||||
|
invalid_parameter_noinfo_noreturn
|
||||||
|
invoke_watson
|
||||||
longjmp
|
longjmp
|
||||||
|
quick_exit
|
||||||
|
RpcRaiseException
|
||||||
|
terminate
|
||||||
|
|||||||
+28
-16
@@ -17,6 +17,7 @@ package ghidra.app.plugin.core.navigation;
|
|||||||
|
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
|
|
||||||
|
import docking.ActionContext;
|
||||||
import docking.action.*;
|
import docking.action.*;
|
||||||
import docking.tool.ToolConstants;
|
import docking.tool.ToolConstants;
|
||||||
import ghidra.GhidraOptions;
|
import ghidra.GhidraOptions;
|
||||||
@@ -29,7 +30,7 @@ import ghidra.app.util.HelpTopics;
|
|||||||
import ghidra.app.util.navigation.GoToAddressLabelDialog;
|
import ghidra.app.util.navigation.GoToAddressLabelDialog;
|
||||||
import ghidra.framework.options.*;
|
import ghidra.framework.options.*;
|
||||||
import ghidra.framework.plugintool.*;
|
import ghidra.framework.plugintool.*;
|
||||||
import ghidra.framework.plugintool.util.*;
|
import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
import ghidra.util.bean.opteditor.OptionsVetoException;
|
import ghidra.util.bean.opteditor.OptionsVetoException;
|
||||||
|
|
||||||
@@ -91,11 +92,21 @@ public class GoToAddressLabelPlugin extends Plugin implements OptionsChangeListe
|
|||||||
public void actionPerformed(NavigatableActionContext context) {
|
public void actionPerformed(NavigatableActionContext context) {
|
||||||
goToDialog.show(context.getNavigatable(), context.getAddress(), tool);
|
goToDialog.show(context.getNavigatable(), context.getAddress(), tool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isEnabledForContext(NavigatableActionContext context) {
|
||||||
|
return context.getProgram() != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAddToPopup(ActionContext context) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
action.setHelpLocation(new HelpLocation(HelpTopics.NAVIGATION, action.getName()));
|
action.setHelpLocation(new HelpLocation(HelpTopics.NAVIGATION, action.getName()));
|
||||||
action.setMenuBarData(new MenuData(
|
action.setMenuBarData(
|
||||||
new String[] { ToolConstants.MENU_NAVIGATION, "Go To..." }, null, "GoTo",
|
new MenuData(new String[] { ToolConstants.MENU_NAVIGATION, "Go To..." }, null, "GoTo",
|
||||||
MenuData.NO_MNEMONIC, "2")); // second item in the menu
|
MenuData.NO_MNEMONIC, "2")); // second item in the menu
|
||||||
|
|
||||||
action.setKeyBindingData(new KeyBindingData(KeyEvent.VK_G, 0));
|
action.setKeyBindingData(new KeyBindingData(KeyEvent.VK_G, 0));
|
||||||
|
|
||||||
@@ -144,10 +155,11 @@ public class GoToAddressLabelPlugin extends Plugin implements OptionsChangeListe
|
|||||||
* @param newValue new value of the option
|
* @param newValue new value of the option
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void optionsChanged(ToolOptions options, String opName, Object oldValue, Object newValue) {
|
public void optionsChanged(ToolOptions options, String opName, Object oldValue,
|
||||||
|
Object newValue) {
|
||||||
if (opName.equals(GhidraOptions.OPTION_MAX_GO_TO_ENTRIES)) {
|
if (opName.equals(GhidraOptions.OPTION_MAX_GO_TO_ENTRIES)) {
|
||||||
maximumGotoEntries =
|
maximumGotoEntries =
|
||||||
options.getInt(GhidraOptions.OPTION_MAX_GO_TO_ENTRIES, DEFAULT_MAX_GOTO_ENTRIES);
|
options.getInt(GhidraOptions.OPTION_MAX_GO_TO_ENTRIES, DEFAULT_MAX_GOTO_ENTRIES);
|
||||||
if (maximumGotoEntries <= 0) {
|
if (maximumGotoEntries <= 0) {
|
||||||
throw new OptionsVetoException("Search limit must be greater than 0");
|
throw new OptionsVetoException("Search limit must be greater than 0");
|
||||||
}
|
}
|
||||||
@@ -155,7 +167,7 @@ public class GoToAddressLabelPlugin extends Plugin implements OptionsChangeListe
|
|||||||
}
|
}
|
||||||
else if (opName.equals(GhidraOptions.OPTION_NUMERIC_FORMATTING)) {
|
else if (opName.equals(GhidraOptions.OPTION_NUMERIC_FORMATTING)) {
|
||||||
cStyleInput =
|
cStyleInput =
|
||||||
options.getBoolean(GhidraOptions.OPTION_NUMERIC_FORMATTING, DEFAULT_C_STYLE);
|
options.getBoolean(GhidraOptions.OPTION_NUMERIC_FORMATTING, DEFAULT_C_STYLE);
|
||||||
goToDialog.setCStyleInput(cStyleInput);
|
goToDialog.setCStyleInput(cStyleInput);
|
||||||
}
|
}
|
||||||
else if (opName.equals(GO_TO_MEMORY)) {
|
else if (opName.equals(GO_TO_MEMORY)) {
|
||||||
@@ -182,20 +194,20 @@ public class GoToAddressLabelPlugin extends Plugin implements OptionsChangeListe
|
|||||||
ToolOptions opt = tool.getOptions(ToolConstants.TOOL_OPTIONS);
|
ToolOptions opt = tool.getOptions(ToolConstants.TOOL_OPTIONS);
|
||||||
// descriptions
|
// descriptions
|
||||||
opt.registerOption(GhidraOptions.OPTION_NUMERIC_FORMATTING, DEFAULT_C_STYLE, null,
|
opt.registerOption(GhidraOptions.OPTION_NUMERIC_FORMATTING, DEFAULT_C_STYLE, null,
|
||||||
"Interpret value entered in the Go To dialog as either hex, "
|
"Interpret value entered in the Go To dialog as either hex, " +
|
||||||
+ "octal, or binary number.");
|
"octal, or binary number.");
|
||||||
opt.registerOption(GhidraOptions.OPTION_MAX_GO_TO_ENTRIES, DEFAULT_MAX_GOTO_ENTRIES, null,
|
opt.registerOption(GhidraOptions.OPTION_MAX_GO_TO_ENTRIES, DEFAULT_MAX_GOTO_ENTRIES, null,
|
||||||
"Max number of entries remembered in the go to list.");
|
"Max number of entries remembered in the go to list.");
|
||||||
opt.registerOption(GO_TO_MEMORY, DEFAULT_MEMORY, null,
|
opt.registerOption(GO_TO_MEMORY, DEFAULT_MEMORY, null,
|
||||||
"Remember the last successful go to input in the "
|
"Remember the last successful go to input in the " +
|
||||||
+ "Go To dialog. If this option is enabled, then the "
|
"Go To dialog. If this option is enabled, then the " +
|
||||||
+ "Go To dialog will leave the last "
|
"Go To dialog will leave the last " +
|
||||||
+ "successful go to input in the combo box of the Go "
|
"successful go to input in the combo box of the Go " +
|
||||||
+ "To dialog and will select the " + "value for easy paste replacement.");
|
"To dialog and will select the " + "value for easy paste replacement.");
|
||||||
|
|
||||||
// options
|
// options
|
||||||
maximumGotoEntries =
|
maximumGotoEntries =
|
||||||
opt.getInt(GhidraOptions.OPTION_MAX_GO_TO_ENTRIES, DEFAULT_MAX_GOTO_ENTRIES);
|
opt.getInt(GhidraOptions.OPTION_MAX_GO_TO_ENTRIES, DEFAULT_MAX_GOTO_ENTRIES);
|
||||||
|
|
||||||
cStyleInput = opt.getBoolean(GhidraOptions.OPTION_NUMERIC_FORMATTING, DEFAULT_C_STYLE);
|
cStyleInput = opt.getBoolean(GhidraOptions.OPTION_NUMERIC_FORMATTING, DEFAULT_C_STYLE);
|
||||||
goToDialog.setCStyleInput(cStyleInput);
|
goToDialog.setCStyleInput(cStyleInput);
|
||||||
|
|||||||
+290
-247
File diff suppressed because it is too large
Load Diff
+486
@@ -0,0 +1,486 @@
|
|||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.util.bin.format.pe;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import ghidra.app.util.bin.StructConverter;
|
||||||
|
import ghidra.app.util.bin.format.FactoryBundledWithBinaryReader;
|
||||||
|
import ghidra.program.model.data.*;
|
||||||
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY {
|
||||||
|
* DWORD BeginAddress;
|
||||||
|
* DWORD EndAddress;
|
||||||
|
* union {
|
||||||
|
* DWORD UnwindInfoAddress;
|
||||||
|
* DWORD UnwindData;
|
||||||
|
* } DUMMYUNIONNAME;
|
||||||
|
* } RUNTIME_FUNCTION, *PRUNTIME_FUNCTION, _IMAGE_RUNTIME_FUNCTION_ENTRY, *_PIMAGE_RUNTIME_FUNCTION_ENTRY;
|
||||||
|
*
|
||||||
|
* #define UNW_FLAG_NHANDLER 0x0
|
||||||
|
* #define UNW_FLAG_EHANDLER 0x1
|
||||||
|
* #define UNW_FLAG_UHANDLER 0x2
|
||||||
|
* #define UNW_FLAG_CHAININFO 0x4
|
||||||
|
*
|
||||||
|
* typedef struct _UNWIND_INFO {
|
||||||
|
* UCHAR Version : 3;
|
||||||
|
* UCHAR Flags : 5;
|
||||||
|
* UCHAR SizeOfProlog;
|
||||||
|
* UCHAR CountOfUnwindCodes;
|
||||||
|
* UCHAR FrameRegister : 4;
|
||||||
|
* UCHAR FrameOffset : 4;
|
||||||
|
* UNWIND_CODE UnwindCode[1];
|
||||||
|
*
|
||||||
|
* //
|
||||||
|
* // The unwind codes are followed by an optional DWORD aligned field that
|
||||||
|
* // contains the exception handler address or the address of chained unwind
|
||||||
|
* // information. If an exception handler address is specified, then it is
|
||||||
|
* // followed by the language specified exception handler data.
|
||||||
|
* //
|
||||||
|
* // union {
|
||||||
|
* // ULONG ExceptionHandler;
|
||||||
|
* // ULONG FunctionEntry;
|
||||||
|
* // };
|
||||||
|
* //
|
||||||
|
* // ULONG ExceptionData[];
|
||||||
|
* //
|
||||||
|
* } UNWIND_INFO, *PUNWIND_INFO;
|
||||||
|
*/
|
||||||
|
public class ImageRuntimeFunctionEntries {
|
||||||
|
private final static int UNWIND_INFO_VERSION_BITMASK = 0x07;
|
||||||
|
private final static int UNWIND_INFO_FLAGS_SHIFT = 0x03;
|
||||||
|
private final static int UNWIND_INFO_FRAME_REGISTER_MASK = 0x0F;
|
||||||
|
private final static int UNWIND_INFO_FRAME_OFFSET_SHIFT = 0x04;
|
||||||
|
private final static int UNWIND_INFO_OPCODE_MASK = 0x0F;
|
||||||
|
private final static int UNWIND_INFO_OPCODE_INFO_SHIFT = 0x04;
|
||||||
|
private final static int UNWIND_INFO_SIZE = 0x0C;
|
||||||
|
|
||||||
|
List<_IMAGE_RUNTIME_FUNCTION_ENTRY> functionEntries = new ArrayList<>();
|
||||||
|
|
||||||
|
static ImageRuntimeFunctionEntries createImageRuntimeFunctionEntries(
|
||||||
|
FactoryBundledWithBinaryReader reader, long index, NTHeader ntHeader)
|
||||||
|
throws IOException {
|
||||||
|
ImageRuntimeFunctionEntries imageRuntimeFunctionEntriesSection =
|
||||||
|
(ImageRuntimeFunctionEntries) reader.getFactory()
|
||||||
|
.create(ImageRuntimeFunctionEntries.class);
|
||||||
|
imageRuntimeFunctionEntriesSection.initImageRuntimeFunctionEntries(reader, index, ntHeader);
|
||||||
|
return imageRuntimeFunctionEntriesSection;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* DO NOT USE THIS CONSTRUCTOR, USE create*(GenericFactory ...) FACTORY METHODS INSTEAD.
|
||||||
|
*/
|
||||||
|
public ImageRuntimeFunctionEntries() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initImageRuntimeFunctionEntries(FactoryBundledWithBinaryReader reader, long index,
|
||||||
|
NTHeader ntHeader) throws IOException {
|
||||||
|
|
||||||
|
int entryCount = 0;
|
||||||
|
|
||||||
|
// Find the exception handler data section. This is an unbounded array of
|
||||||
|
// RUNTIME_INFO structures one after another and there's no count field
|
||||||
|
// to tell us how many there are, so get the maximum number there could be
|
||||||
|
// based on the size of the section.
|
||||||
|
FileHeader fh = ntHeader.getFileHeader();
|
||||||
|
for (SectionHeader section : fh.getSectionHeaders()) {
|
||||||
|
if (section.getName().contentEquals(".pdata")) {
|
||||||
|
entryCount = section.getSizeOfRawData() / UNWIND_INFO_SIZE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entryCount == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long origIndex = reader.getPointerIndex();
|
||||||
|
|
||||||
|
reader.setPointerIndex(index);
|
||||||
|
|
||||||
|
for (int i = 0; i < entryCount; i++) {
|
||||||
|
_IMAGE_RUNTIME_FUNCTION_ENTRY entry = new _IMAGE_RUNTIME_FUNCTION_ENTRY();
|
||||||
|
entry.beginAddress = reader.readNextUnsignedInt();
|
||||||
|
entry.endAddress = reader.readNextUnsignedInt();
|
||||||
|
entry.unwindInfoAddressOrData = reader.readNextUnsignedInt();
|
||||||
|
|
||||||
|
// When the size of the section is bigger than the number of structures
|
||||||
|
// the structure data fields will all be null, signaling the end of the
|
||||||
|
// array of structures. Break out here.
|
||||||
|
if (entry.beginAddress == 0 && entry.endAddress == 0 &&
|
||||||
|
entry.unwindInfoAddressOrData == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read and process the UNWIND_INFO structures the RUNTIME_INFO
|
||||||
|
// structures point to
|
||||||
|
entry.unwindInfo = readUnwindInfo(reader, entry.unwindInfoAddressOrData, ntHeader);
|
||||||
|
|
||||||
|
functionEntries.add(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.setPointerIndex(origIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
private UNWIND_INFO readUnwindInfo(FactoryBundledWithBinaryReader reader, long offset,
|
||||||
|
NTHeader ntHeader) throws IOException {
|
||||||
|
long origIndex = reader.getPointerIndex();
|
||||||
|
|
||||||
|
long pointer = ntHeader.rvaToPointer(offset);
|
||||||
|
UNWIND_INFO unwindInfo = new UNWIND_INFO(pointer);
|
||||||
|
|
||||||
|
if (pointer < 0) {
|
||||||
|
return unwindInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.setPointerIndex(pointer);
|
||||||
|
byte splitByte = reader.readNextByte();
|
||||||
|
unwindInfo.version = (byte) (splitByte & UNWIND_INFO_VERSION_BITMASK);
|
||||||
|
unwindInfo.flags = (byte) (splitByte >> UNWIND_INFO_FLAGS_SHIFT);
|
||||||
|
|
||||||
|
unwindInfo.sizeOfProlog = reader.readNextByte();
|
||||||
|
unwindInfo.countOfUnwindCodes = reader.readNextByte();
|
||||||
|
|
||||||
|
splitByte = reader.readNextByte();
|
||||||
|
unwindInfo.frameRegister = (byte) (splitByte & UNWIND_INFO_FRAME_REGISTER_MASK);
|
||||||
|
unwindInfo.frameOffset = (byte) (splitByte >> UNWIND_INFO_FRAME_OFFSET_SHIFT);
|
||||||
|
|
||||||
|
unwindInfo.unwindCodes = new UNWIND_CODE[unwindInfo.countOfUnwindCodes];
|
||||||
|
for (int i = 0; i < unwindInfo.countOfUnwindCodes; i++) {
|
||||||
|
UNWIND_CODE code = new UNWIND_CODE();
|
||||||
|
code.offsetInProlog = reader.readNextByte();
|
||||||
|
|
||||||
|
int opCodeData = reader.readNextUnsignedByte();
|
||||||
|
code.opCode = UNWIND_CODE_OPCODE.fromInt((opCodeData & UNWIND_INFO_OPCODE_MASK));
|
||||||
|
code.opInfoRegister =
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER.fromInt(opCodeData >> UNWIND_INFO_OPCODE_INFO_SHIFT);
|
||||||
|
|
||||||
|
unwindInfo.unwindCodes[i] = code;
|
||||||
|
}
|
||||||
|
|
||||||
|
// You can have an exception handler and/or an unwind handler, or you
|
||||||
|
// can have chained exception handling info only.
|
||||||
|
if (unwindInfo.hasExceptionHandler() || unwindInfo.hasUnwindHandler()) {
|
||||||
|
if (unwindInfo.hasExceptionHandler()) {
|
||||||
|
unwindInfo.exceptionHandlerFunction = reader.readNextInt();
|
||||||
|
}
|
||||||
|
if (unwindInfo.hasUnwindHandler()) {
|
||||||
|
unwindInfo.unwindHandlerFunction = reader.readNextInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (unwindInfo.hasChainedUnwindInfo()) {
|
||||||
|
unwindInfo.unwindHandlerChainInfo = new _IMAGE_RUNTIME_FUNCTION_ENTRY();
|
||||||
|
unwindInfo.unwindHandlerChainInfo.beginAddress = reader.readNextInt();
|
||||||
|
unwindInfo.unwindHandlerChainInfo.endAddress = reader.readNextInt();
|
||||||
|
unwindInfo.unwindHandlerChainInfo.unwindInfoAddressOrData = reader.readNextInt();
|
||||||
|
|
||||||
|
// Follow the chain to the referenced UNWIND_INFO structure until we
|
||||||
|
// get to the end
|
||||||
|
unwindInfo.unwindHandlerChainInfo.unwindInfo = readUnwindInfo(reader,
|
||||||
|
unwindInfo.unwindHandlerChainInfo.unwindInfoAddressOrData, ntHeader);
|
||||||
|
}
|
||||||
|
|
||||||
|
reader.setPointerIndex(origIndex);
|
||||||
|
|
||||||
|
return unwindInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<_IMAGE_RUNTIME_FUNCTION_ENTRY> getRuntimeFunctionEntries() {
|
||||||
|
return functionEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class _IMAGE_RUNTIME_FUNCTION_ENTRY {
|
||||||
|
public long beginAddress;
|
||||||
|
public long endAddress;
|
||||||
|
public long unwindInfoAddressOrData;
|
||||||
|
public UNWIND_INFO unwindInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum UNWIND_CODE_OPCODE {
|
||||||
|
UWOP_PUSH_NONVOL(0x00),
|
||||||
|
UWOP_ALLOC_LARGE(0x01),
|
||||||
|
UWOP_ALLOC_SMALL(0x02),
|
||||||
|
UWOP_SET_FPREG(0x03),
|
||||||
|
UWOP_SAVE_NONVOL(0x04),
|
||||||
|
UWOP_SAVE_NONVOL_FAR(0x05),
|
||||||
|
UWOP_SAVE_XMM(0x06),
|
||||||
|
UWOP_SAVE_XMM_FAR(0x07),
|
||||||
|
UWOP_SAVE_XMM128(0x08),
|
||||||
|
UWOP_SAVE_XMM128_FAR(0x09),
|
||||||
|
UWOP_PUSH_MACHFRAME(0x0A);
|
||||||
|
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
UNWIND_CODE_OPCODE(int value) {
|
||||||
|
id = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int id() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UNWIND_CODE_OPCODE fromInt(int id) {
|
||||||
|
UNWIND_CODE_OPCODE[] values = UNWIND_CODE_OPCODE.values();
|
||||||
|
for (UNWIND_CODE_OPCODE value : values) {
|
||||||
|
if (value.id == id) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum UNWIND_CODE_OPINFO_REGISTER {
|
||||||
|
UNWIND_OPINFO_REGISTER_RAX(0x00),
|
||||||
|
UNWIND_OPINFO_REGISTER_RCX(0x01),
|
||||||
|
UNWIND_OPINFO_REGISTER_RDX(0x02),
|
||||||
|
UNWIND_OPINFO_REGISTER_RBX(0x03),
|
||||||
|
UNWIND_OPINFO_REGISTER_RSP(0x04),
|
||||||
|
UNWIND_OPINFO_REGISTER_RBP(0x05),
|
||||||
|
UNWIND_OPINFO_REGISTER_RSI(0x06),
|
||||||
|
UNWIND_OPINFO_REGISTER_RDI(0x07),
|
||||||
|
UNWIND_OPINFO_REGISTER_R8(0x08),
|
||||||
|
UNWIND_OPINFO_REGISTER_R9(0x09),
|
||||||
|
UNWIND_OPINFO_REGISTER_R10(0x0A),
|
||||||
|
UNWIND_OPINFO_REGISTER_R11(0x0B),
|
||||||
|
UNWIND_OPINFO_REGISTER_R12(0x0C),
|
||||||
|
UNWIND_OPINFO_REGISTER_R13(0x0D),
|
||||||
|
UNWIND_OPINFO_REGISTER_R14(0x0E),
|
||||||
|
UNWIND_OPINFO_REGISTER_R15(0x0F);
|
||||||
|
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER(int value) {
|
||||||
|
id = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int id() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UNWIND_CODE_OPINFO_REGISTER fromInt(int id) {
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER[] values = UNWIND_CODE_OPINFO_REGISTER.values();
|
||||||
|
for (UNWIND_CODE_OPINFO_REGISTER value : values) {
|
||||||
|
if (value.id == id) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UNWIND_CODE {
|
||||||
|
public byte offsetInProlog;
|
||||||
|
public UNWIND_CODE_OPCODE opCode;
|
||||||
|
public UNWIND_CODE_OPINFO_REGISTER opInfoRegister;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UNWIND_INFO implements StructConverter {
|
||||||
|
private static final String NAME = "UNWIND_INFO";
|
||||||
|
|
||||||
|
private final static int UNW_FLAG_NHANDLER = 0x0;
|
||||||
|
private final static int UNW_FLAG_EHANDLER = 0x1;
|
||||||
|
private final static int UNW_FLAG_UHANDLER = 0x2;
|
||||||
|
private final static int UNW_FLAG_CHAININFO = 0x4;
|
||||||
|
|
||||||
|
private final static int UNWIND_VERSION_FIELD_LENGTH = 0x03;
|
||||||
|
private final static int UNWIND_FLAGS_FIELD_LENGTH = 0x05;
|
||||||
|
private final static int UNWIND_FRAME_REGISTER_LENGTH = 0x04;
|
||||||
|
private final static int UNWIND_OP_FIELD_LENGTH = 0x04;
|
||||||
|
|
||||||
|
byte version;
|
||||||
|
byte flags;
|
||||||
|
byte sizeOfProlog;
|
||||||
|
byte countOfUnwindCodes;
|
||||||
|
byte frameRegister;
|
||||||
|
byte frameOffset;
|
||||||
|
UNWIND_CODE[] unwindCodes;
|
||||||
|
int exceptionHandlerFunction;
|
||||||
|
int unwindHandlerFunction;
|
||||||
|
_IMAGE_RUNTIME_FUNCTION_ENTRY unwindHandlerChainInfo;
|
||||||
|
|
||||||
|
long startOffset;
|
||||||
|
|
||||||
|
public UNWIND_INFO(long offset) {
|
||||||
|
startOffset = offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DataType toDataType() throws DuplicateNameException, IOException {
|
||||||
|
StructureDataType struct = new StructureDataType(NAME + "_" + startOffset, 0);
|
||||||
|
try {
|
||||||
|
StructureDataType vf = new StructureDataType("VersionFlags", 0);
|
||||||
|
vf.insertBitField(0, 1, 0, BYTE, UNWIND_VERSION_FIELD_LENGTH, "Version", null);
|
||||||
|
vf.insertBitField(0, 1, UNWIND_VERSION_FIELD_LENGTH, defineFlagsField(),
|
||||||
|
UNWIND_FLAGS_FIELD_LENGTH, "Flags", null);
|
||||||
|
|
||||||
|
struct.add(vf, "Version + Flags", null);
|
||||||
|
}
|
||||||
|
catch (InvalidDataTypeException e) {
|
||||||
|
struct.add(BYTE, "Version + Flags", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct.add(BYTE, "SizeOfProlog", null);
|
||||||
|
struct.add(BYTE, "CountOfUnwindCodes", null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
StructureDataType fr = new StructureDataType("FrameRegisterAndOffset", 0);
|
||||||
|
fr.insertBitField(0, 1, 0, BYTE, UNWIND_FRAME_REGISTER_LENGTH, "FrameRegister",
|
||||||
|
null);
|
||||||
|
fr.insertBitField(0, 1, UNWIND_FRAME_REGISTER_LENGTH, BYTE,
|
||||||
|
UNWIND_FRAME_REGISTER_LENGTH, "FrameOffset", null);
|
||||||
|
struct.add(fr, "FrameRegister + FrameOffset", null);
|
||||||
|
}
|
||||||
|
catch (InvalidDataTypeException e) {
|
||||||
|
struct.add(BYTE, "FrameRegister + FrameOffset", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < countOfUnwindCodes; i++) {
|
||||||
|
StructureDataType unwindCode = new StructureDataType("UnwindCode", 0);
|
||||||
|
unwindCode.add(BYTE, "OffsetInProlog", null);
|
||||||
|
|
||||||
|
StructureDataType unwindCodeInfo = new StructureDataType("UnwindCodeInfo", 0);
|
||||||
|
try {
|
||||||
|
if (unwindCodes[i].opCode != null) {
|
||||||
|
unwindCodeInfo.insertBitField(0, 1, 0, defineUnwindOpCodeField(),
|
||||||
|
UNWIND_OP_FIELD_LENGTH, "UnwindOpCode", null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unwindCodeInfo.insertBitField(0, 1, 0, BYTE, UNWIND_OP_FIELD_LENGTH,
|
||||||
|
"UnwindOpCode", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unwindCodes[i].opInfoRegister != null) {
|
||||||
|
unwindCodeInfo.insertBitField(0, 1, UNWIND_OP_FIELD_LENGTH,
|
||||||
|
defineUnwindCodeRegisterField(), UNWIND_OP_FIELD_LENGTH, "OpInfo",
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unwindCodeInfo.insertBitField(0, 1, UNWIND_OP_FIELD_LENGTH, BYTE,
|
||||||
|
UNWIND_OP_FIELD_LENGTH, "OpInfo", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (InvalidDataTypeException e) {
|
||||||
|
}
|
||||||
|
unwindCode.add(unwindCodeInfo, "UnwindCodeInfo", null);
|
||||||
|
|
||||||
|
struct.add(unwindCode, "UnwindCode", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasExceptionHandler() || hasUnwindHandler()) {
|
||||||
|
if (hasExceptionHandler()) {
|
||||||
|
struct.add(IBO32, "ExceptionHandler", null);
|
||||||
|
}
|
||||||
|
if (hasUnwindHandler()) {
|
||||||
|
struct.add(IBO32, "UnwindHandler", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (hasChainedUnwindInfo()) {
|
||||||
|
struct.add(IBO32, "FunctionStartAddress", null);
|
||||||
|
struct.add(IBO32, "FunctionEndAddress", null);
|
||||||
|
struct.add(IBO32, "FunctionUnwindInfoAddress", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return struct;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasExceptionHandler() {
|
||||||
|
return (flags & UNW_FLAG_EHANDLER) == UNW_FLAG_EHANDLER;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasUnwindHandler() {
|
||||||
|
return (flags & UNW_FLAG_UHANDLER) == UNW_FLAG_UHANDLER;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasChainedUnwindInfo() {
|
||||||
|
return (flags & UNW_FLAG_CHAININFO) == UNW_FLAG_CHAININFO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EnumDataType defineFlagsField() {
|
||||||
|
EnumDataType flagsField = new EnumDataType("Flags", 5);
|
||||||
|
flagsField.add("UNW_FLAG_NHANDLER", UNW_FLAG_NHANDLER);
|
||||||
|
flagsField.add("UNW_FLAG_EHANDLER", UNW_FLAG_EHANDLER);
|
||||||
|
flagsField.add("UNW_FLAG_UHANDLER", UNW_FLAG_UHANDLER);
|
||||||
|
flagsField.add("UNW_FLAG_CHAININFO", UNW_FLAG_CHAININFO);
|
||||||
|
|
||||||
|
return flagsField;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EnumDataType defineUnwindOpCodeField() {
|
||||||
|
EnumDataType unwindOpCodeField = new EnumDataType("UNWIND_CODE_OPCODE", 4);
|
||||||
|
unwindOpCodeField.add("UWOP_PUSH_NONVOL", UNWIND_CODE_OPCODE.UWOP_PUSH_NONVOL.id);
|
||||||
|
unwindOpCodeField.add("UWOP_ALLOC_LARGE", UNWIND_CODE_OPCODE.UWOP_ALLOC_LARGE.id);
|
||||||
|
unwindOpCodeField.add("UWOP_ALLOC_SMALL", UNWIND_CODE_OPCODE.UWOP_ALLOC_SMALL.id);
|
||||||
|
unwindOpCodeField.add("UWOP_SET_FPREG", UNWIND_CODE_OPCODE.UWOP_SET_FPREG.id);
|
||||||
|
unwindOpCodeField.add("UWOP_SAVE_NONVOL", UNWIND_CODE_OPCODE.UWOP_SAVE_NONVOL.id);
|
||||||
|
unwindOpCodeField.add("UWOP_SAVE_NONVOL_FAR",
|
||||||
|
UNWIND_CODE_OPCODE.UWOP_SAVE_NONVOL_FAR.id);
|
||||||
|
unwindOpCodeField.add("UWOP_SAVE_XMM", UNWIND_CODE_OPCODE.UWOP_SAVE_XMM.id);
|
||||||
|
unwindOpCodeField.add("UWOP_SAVE_XMM_FAR", UNWIND_CODE_OPCODE.UWOP_SAVE_XMM_FAR.id);
|
||||||
|
unwindOpCodeField.add("UWOP_SAVE_XMM128", UNWIND_CODE_OPCODE.UWOP_SAVE_XMM128.id);
|
||||||
|
unwindOpCodeField.add("UWOP_SAVE_XMM128_FAR",
|
||||||
|
UNWIND_CODE_OPCODE.UWOP_SAVE_XMM128_FAR.id);
|
||||||
|
unwindOpCodeField.add("UWOP_PUSH_MACHFRAME", UNWIND_CODE_OPCODE.UWOP_PUSH_MACHFRAME.id);
|
||||||
|
|
||||||
|
return unwindOpCodeField;
|
||||||
|
}
|
||||||
|
|
||||||
|
private EnumDataType defineUnwindCodeRegisterField() {
|
||||||
|
EnumDataType unwindCodeRegisterField =
|
||||||
|
new EnumDataType("UNWIND_CODE_OPINFO_REGISTER", 4);
|
||||||
|
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RAX",
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RAX.id);
|
||||||
|
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RCX",
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RCX.id);
|
||||||
|
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RDX",
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RDX.id);
|
||||||
|
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RBX",
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RBX.id);
|
||||||
|
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RSP",
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RSP.id);
|
||||||
|
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RBP",
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RBP.id);
|
||||||
|
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RSI",
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RSI.id);
|
||||||
|
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_RDI",
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_RDI.id);
|
||||||
|
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R8",
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R8.id);
|
||||||
|
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R9",
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R9.id);
|
||||||
|
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R10",
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R10.id);
|
||||||
|
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R11",
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R11.id);
|
||||||
|
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R12",
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R12.id);
|
||||||
|
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R13",
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R13.id);
|
||||||
|
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R14",
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R14.id);
|
||||||
|
unwindCodeRegisterField.add("UNWIND_OPINFO_REGISTER_R15",
|
||||||
|
UNWIND_CODE_OPINFO_REGISTER.UNWIND_OPINFO_REGISTER_R15.id);
|
||||||
|
|
||||||
|
return unwindCodeRegisterField;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -82,8 +82,8 @@ public class NTHeader implements StructConverter, OffsetValidator {
|
|||||||
public NTHeader() {
|
public NTHeader() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initNTHeader(FactoryBundledWithBinaryReader reader, int index, SectionLayout layout,
|
private void initNTHeader(FactoryBundledWithBinaryReader reader, int index,
|
||||||
boolean advancedProcess, boolean parseCliHeaders)
|
SectionLayout layout, boolean advancedProcess, boolean parseCliHeaders)
|
||||||
throws InvalidNTHeaderException, IOException {
|
throws InvalidNTHeaderException, IOException {
|
||||||
this.reader = reader;
|
this.reader = reader;
|
||||||
this.index = index;
|
this.index = index;
|
||||||
@@ -172,9 +172,9 @@ public class NTHeader implements StructConverter, OffsetValidator {
|
|||||||
//low alignment mode?
|
//low alignment mode?
|
||||||
//
|
//
|
||||||
if (optionalHeader != null) {
|
if (optionalHeader != null) {
|
||||||
if (optionalHeader.getFileAlignment() == optionalHeader.getSectionAlignment()
|
if (optionalHeader.getFileAlignment() == optionalHeader.getSectionAlignment() &&
|
||||||
&& optionalHeader.getSectionAlignment() < 800
|
optionalHeader.getSectionAlignment() < 800 &&
|
||||||
&& optionalHeader.getFileAlignment() > 1) {
|
optionalHeader.getFileAlignment() > 1) {
|
||||||
return rva;
|
return rva;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -270,6 +270,7 @@ public class NTHeader implements StructConverter, OffsetValidator {
|
|||||||
|
|
||||||
fileHeader.processSections(optionalHeader);
|
fileHeader.processSections(optionalHeader);
|
||||||
fileHeader.processSymbols();
|
fileHeader.processSymbols();
|
||||||
|
fileHeader.processImageRuntimeFunctionEntries();
|
||||||
|
|
||||||
if (advancedProcess) {
|
if (advancedProcess) {
|
||||||
optionalHeader.processDataDirectories(TaskMonitorAdapter.DUMMY_MONITOR);
|
optionalHeader.processDataDirectories(TaskMonitorAdapter.DUMMY_MONITOR);
|
||||||
@@ -278,7 +279,7 @@ public class NTHeader implements StructConverter, OffsetValidator {
|
|||||||
|
|
||||||
void writeHeader(RandomAccessFile raf, DataConverter dc) throws IOException {
|
void writeHeader(RandomAccessFile raf, DataConverter dc) throws IOException {
|
||||||
|
|
||||||
raf.seek( index );
|
raf.seek(index);
|
||||||
|
|
||||||
raf.write(dc.getBytes(signature));
|
raf.write(dc.getBytes(signature));
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import ghidra.app.util.bin.ByteProvider;
|
|||||||
import ghidra.app.util.bin.format.mz.DOSHeader;
|
import ghidra.app.util.bin.format.mz.DOSHeader;
|
||||||
import ghidra.app.util.bin.format.pe.*;
|
import ghidra.app.util.bin.format.pe.*;
|
||||||
import ghidra.app.util.bin.format.pe.ImageCor20Header.ImageCor20Flags;
|
import ghidra.app.util.bin.format.pe.ImageCor20Header.ImageCor20Flags;
|
||||||
|
import ghidra.app.util.bin.format.pe.ImageRuntimeFunctionEntries._IMAGE_RUNTIME_FUNCTION_ENTRY;
|
||||||
import ghidra.app.util.bin.format.pe.PortableExecutable.SectionLayout;
|
import ghidra.app.util.bin.format.pe.PortableExecutable.SectionLayout;
|
||||||
import ghidra.app.util.bin.format.pe.debug.DebugCOFFSymbol;
|
import ghidra.app.util.bin.format.pe.debug.DebugCOFFSymbol;
|
||||||
import ghidra.app.util.bin.format.pe.debug.DebugDirectoryParser;
|
import ghidra.app.util.bin.format.pe.debug.DebugDirectoryParser;
|
||||||
@@ -148,6 +149,7 @@ public class PeLoader extends AbstractPeDebugLoader {
|
|||||||
processProperties(optionalHeader, program, monitor);
|
processProperties(optionalHeader, program, monitor);
|
||||||
processComments(program.getListing(), monitor);
|
processComments(program.getListing(), monitor);
|
||||||
processSymbols(fileHeader, sectionToAddress, program, monitor, log);
|
processSymbols(fileHeader, sectionToAddress, program, monitor, log);
|
||||||
|
processImageRuntimeFunctionEntries(fileHeader, program, monitor, log);
|
||||||
|
|
||||||
processEntryPoints(ntHeader, program, monitor);
|
processEntryPoints(ntHeader, program, monitor);
|
||||||
String compiler = CompilerOpinion.getOpinion(pe, provider).toString();
|
String compiler = CompilerOpinion.getOpinion(pe, provider).toString();
|
||||||
@@ -248,24 +250,74 @@ public class PeLoader extends AbstractPeDebugLoader {
|
|||||||
setComment(CodeUnit.EOL_COMMENT, start, section.getName());
|
setComment(CodeUnit.EOL_COMMENT, start, section.getName());
|
||||||
start = start.add(dt.getLength());
|
start = start.add(dt.getLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
// for (int i = 0; i < datadirs.length; ++i) {
|
|
||||||
// if (datadirs[i] == null || datadirs[i].getSize() == 0) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if (datadirs[i].hasParsedCorrectly()) {
|
|
||||||
// start = datadirs[i].getMarkupAddress(program, true);
|
|
||||||
// dt = datadirs[i].toDataType();
|
|
||||||
// DataUtilities.createData(program, start, dt, true, DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
catch (Exception e1) {
|
catch (Exception e1) {
|
||||||
Msg.error(this, "Error laying down header structures " + e1);
|
Msg.error(this, "Error laying down header structures " + e1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void processImageRuntimeFunctionEntries(FileHeader fileHeader, Program program,
|
||||||
|
TaskMonitor monitor, MessageLog log) {
|
||||||
|
|
||||||
|
// Check to see that we have exception data to process
|
||||||
|
SectionHeader irfeHeader = null;
|
||||||
|
for (SectionHeader header : fileHeader.getSectionHeaders()) {
|
||||||
|
if (header.getName().contains(".pdata")) {
|
||||||
|
irfeHeader = header;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (irfeHeader == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Address start = program.getImageBase().add(irfeHeader.getVirtualAddress());
|
||||||
|
|
||||||
|
List<_IMAGE_RUNTIME_FUNCTION_ENTRY> irfes = fileHeader.getImageRuntimeFunctionEntries();
|
||||||
|
if (irfes == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StructureDataType dt = new StructureDataType(".PDATA", 0);
|
||||||
|
dt.setCategoryPath(new CategoryPath("/PE"));
|
||||||
|
|
||||||
|
// Lay an array of RUNTIME_INFO structure out over the data
|
||||||
|
StructureDataType irfeStruct = new StructureDataType("_IMAGE_RUNTIME_FUNCTION_ENTRY", 0);
|
||||||
|
irfeStruct.add(ghidra.app.util.bin.StructConverter.IBO32, "BeginAddress", null);
|
||||||
|
irfeStruct.add(ghidra.app.util.bin.StructConverter.IBO32, "EndAddress", null);
|
||||||
|
irfeStruct.add(ghidra.app.util.bin.StructConverter.IBO32, "UnwindInfoAddressOrData", null);
|
||||||
|
|
||||||
|
ArrayDataType irfeArray =
|
||||||
|
new ArrayDataType(irfeStruct, irfes.size(), irfeStruct.getLength());
|
||||||
|
|
||||||
|
try {
|
||||||
|
DataUtilities.createData(program, start, irfeArray, irfeArray.getLength(), true,
|
||||||
|
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||||
|
}
|
||||||
|
catch (CodeUnitInsertionException e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each RUNTIME_INFO contains an address to an UNWIND_INFO structure
|
||||||
|
// which also needs to be laid out. When they contain chaining data
|
||||||
|
// they're recursive but the toDataType() function handles that.
|
||||||
|
for (_IMAGE_RUNTIME_FUNCTION_ENTRY entry : irfes) {
|
||||||
|
if (entry.unwindInfoAddressOrData > 0) {
|
||||||
|
try {
|
||||||
|
dt = (StructureDataType) entry.unwindInfo.toDataType();
|
||||||
|
start = program.getImageBase().add(entry.unwindInfoAddressOrData);
|
||||||
|
|
||||||
|
DataUtilities.createData(program, start, dt, dt.getLength(), true,
|
||||||
|
DataUtilities.ClearDataMode.CHECK_FOR_SPACE);
|
||||||
|
}
|
||||||
|
catch (CodeUnitInsertionException | DuplicateNameException | IOException e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void processSymbols(FileHeader fileHeader, Map<SectionHeader, Address> sectionToAddress,
|
private void processSymbols(FileHeader fileHeader, Map<SectionHeader, Address> sectionToAddress,
|
||||||
Program program, TaskMonitor monitor, MessageLog log) {
|
Program program, TaskMonitor monitor, MessageLog log) {
|
||||||
List<DebugCOFFSymbol> symbols = fileHeader.getSymbols();
|
List<DebugCOFFSymbol> symbols = fileHeader.getSymbols();
|
||||||
@@ -506,8 +558,7 @@ public class PeLoader extends AbstractPeDebugLoader {
|
|||||||
importInfo.getName(), null, SourceType.IMPORTED, 0, RefType.DATA);
|
importInfo.getName(), null, SourceType.IMPORTED, 0, RefType.DATA);
|
||||||
}
|
}
|
||||||
catch (DuplicateNameException | InvalidInputException e) {
|
catch (DuplicateNameException | InvalidInputException e) {
|
||||||
log.appendMsg(
|
log.appendMsg("Failed to create Delay Load external function at: " + iatAddr);
|
||||||
"Failed to create Delay Load external function at: " + iatAddr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create delay load proxy function
|
// Create delay load proxy function
|
||||||
|
|||||||
+1
-1
@@ -56,7 +56,7 @@ import ghidra.util.timer.GTimer;
|
|||||||
*
|
*
|
||||||
* Refactor fileInfo -> needs dialog to show properties
|
* Refactor fileInfo -> needs dialog to show properties
|
||||||
* Refactor GFile.getInfo() to return Map<> instead of String.
|
* Refactor GFile.getInfo() to return Map<> instead of String.
|
||||||
* Persistant filesystem - when reopen tool, filesystems should auto-reopen.
|
* Persistent filesystem - when reopen tool, filesystems should auto-reopen.
|
||||||
* Unify GhidraFileChooser with GFileSystem.
|
* Unify GhidraFileChooser with GFileSystem.
|
||||||
* Add "Mounted Filesystems" button to show currently opened GFilesystems?
|
* Add "Mounted Filesystems" button to show currently opened GFilesystems?
|
||||||
* Dockable filesystem browser in FrontEnd.
|
* Dockable filesystem browser in FrontEnd.
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -170,7 +169,7 @@ public class VarnodeOperation extends Varnode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPersistant() {
|
public boolean isPersistent() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+27
-1
@@ -205,7 +205,33 @@ public class DataTypeManagerPluginTest extends AbstractGhidraHeadedIntegrationTe
|
|||||||
waitForSwing();
|
waitForSwing();
|
||||||
|
|
||||||
waitForTree();
|
waitForTree();
|
||||||
runSwing(() -> jTree.stopEditing());
|
|
||||||
|
// verify that the tree opens a new node with the default
|
||||||
|
// category name is "New Category"
|
||||||
|
assertEquals(childCount + 1, miscNode.getChildCount());
|
||||||
|
GTreeNode node = miscNode.getChild("New Category");
|
||||||
|
assertNotNull(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateCategory_WhileFiltered() throws Exception {
|
||||||
|
// select a category
|
||||||
|
GTreeNode miscNode = programNode.getChild("MISC");
|
||||||
|
assertNotNull(miscNode);
|
||||||
|
expandNode(miscNode);
|
||||||
|
|
||||||
|
int childCount = miscNode.getChildCount();
|
||||||
|
selectNode(miscNode);
|
||||||
|
|
||||||
|
filterTree(miscNode.getName());
|
||||||
|
|
||||||
|
DockingActionIf action = getAction(plugin, "New Category");
|
||||||
|
assertTrue(action.isEnabledForContext(treeContext));
|
||||||
|
|
||||||
|
// select "New Category" action
|
||||||
|
DataTypeTestUtils.performAction(action, tree, false);
|
||||||
|
|
||||||
|
waitForDialogComponent("Cannot Edit Tree Node");
|
||||||
|
|
||||||
// verify that the tree opens a new node with the default
|
// verify that the tree opens a new node with the default
|
||||||
// category name is "New Category"
|
// category name is "New Category"
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import ghidra.program.model.pcode.*;
|
|||||||
import ghidra.service.graph.*;
|
import ghidra.service.graph.*;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import static ghidra.service.graph.GraphDisplay.*;
|
||||||
|
|
||||||
public class GraphAST extends GhidraScript {
|
public class GraphAST extends GhidraScript {
|
||||||
protected static final String COLOR_ATTRIBUTE = "Color";
|
protected static final String COLOR_ATTRIBUTE = "Color";
|
||||||
@@ -66,11 +67,12 @@ public class GraphAST extends GhidraScript {
|
|||||||
buildGraph();
|
buildGraph();
|
||||||
|
|
||||||
Map<String, String> properties = new HashMap<>();
|
Map<String, String> properties = new HashMap<>();
|
||||||
properties.put("selectedVertexColor", "0xFF1493");
|
properties.put(SELECTED_VERTEX_COLOR, "0xFF1493");
|
||||||
properties.put("selectedEdgeColor", "0xFF1493");
|
properties.put(SELECTED_EDGE_COLOR, "0xFF1493");
|
||||||
properties.put("initialLayoutAlgorithm", "Hierarchical MinCross Coffman Graham");
|
properties.put(INITIAL_LAYOUT_ALGORITHM, "Hierarchical MinCross Coffman Graham");
|
||||||
properties.put("displayVerticesAsIcons", "false");
|
properties.put(DISPLAY_VERTICES_AS_ICONS, "false");
|
||||||
properties.put("vertexLabelPosition", "S");
|
properties.put(VERTEX_LABEL_POSITION, "S");
|
||||||
|
properties.put(ENABLE_EDGE_SELECTION, "true");
|
||||||
GraphDisplay graphDisplay =
|
GraphDisplay graphDisplay =
|
||||||
graphDisplayBroker.getDefaultGraphDisplay(false, properties, monitor);
|
graphDisplayBroker.getDefaultGraphDisplay(false, properties, monitor);
|
||||||
// graphDisplay.defineVertexAttribute(CODE_ATTRIBUTE); //
|
// graphDisplay.defineVertexAttribute(CODE_ATTRIBUTE); //
|
||||||
@@ -137,7 +139,7 @@ public class GraphAST extends GhidraScript {
|
|||||||
else if (vn.isUnique()) {
|
else if (vn.isUnique()) {
|
||||||
colorattrib = "Black";
|
colorattrib = "Black";
|
||||||
}
|
}
|
||||||
else if (vn.isPersistant()) {
|
else if (vn.isPersistent()) {
|
||||||
colorattrib = "DarkOrange";
|
colorattrib = "DarkOrange";
|
||||||
}
|
}
|
||||||
else if (vn.isAddrTied()) {
|
else if (vn.isAddrTied()) {
|
||||||
|
|||||||
@@ -926,7 +926,7 @@ This is a truncation operator that understands the endianess of the
|
|||||||
data. Input1 indicates the number of least significant bytes of input0
|
data. Input1 indicates the number of least significant bytes of input0
|
||||||
to be thrown away. Output is then filled with any remaining bytes of
|
to be thrown away. Output is then filled with any remaining bytes of
|
||||||
input0 <emphasis>up to the size of output</emphasis>. If the size of
|
input0 <emphasis>up to the size of output</emphasis>. If the size of
|
||||||
output is smaller than the size of input0 plus the constant input1,
|
output is smaller than the size of input0 minus the constant input1,
|
||||||
then the additional most significant bytes of input0 will also be
|
then the additional most significant bytes of input0 will also be
|
||||||
truncated.
|
truncated.
|
||||||
</para>
|
</para>
|
||||||
|
|||||||
+6
-3
@@ -34,6 +34,8 @@ import ghidra.util.exception.GraphException;
|
|||||||
import ghidra.util.task.Task;
|
import ghidra.util.task.Task;
|
||||||
import ghidra.util.task.TaskMonitor;
|
import ghidra.util.task.TaskMonitor;
|
||||||
|
|
||||||
|
import static ghidra.service.graph.GraphDisplay.*;
|
||||||
|
|
||||||
public class ASTGraphTask extends Task {
|
public class ASTGraphTask extends Task {
|
||||||
enum GraphType {
|
enum GraphType {
|
||||||
CONTROL_FLOW_GRAPH("AST Control Flow"), DATA_FLOW_GRAPH("AST Data Flow");
|
CONTROL_FLOW_GRAPH("AST Control Flow"), DATA_FLOW_GRAPH("AST Data Flow");
|
||||||
@@ -104,9 +106,10 @@ public class ASTGraphTask extends Task {
|
|||||||
createControlFlowGraph(graph, monitor);
|
createControlFlowGraph(graph, monitor);
|
||||||
}
|
}
|
||||||
Map<String, String> properties = new HashMap<>();
|
Map<String, String> properties = new HashMap<>();
|
||||||
properties.put("selectedVertexColor", "0xFF1493");
|
properties.put(SELECTED_VERTEX_COLOR, "0xFF1493");
|
||||||
properties.put("selectedEdgeColor", "0xFF1493");
|
properties.put(SELECTED_EDGE_COLOR, "0xFF1493");
|
||||||
properties.put("initialLayoutAlgorithm", "Hierarchical MinCross Coffman Graham");
|
properties.put(INITIAL_LAYOUT_ALGORITHM, "Hierarchical MinCross Coffman Graham");
|
||||||
|
properties.put(ENABLE_EDGE_SELECTION, "true");
|
||||||
GraphDisplay display = graphService.getDefaultGraphDisplay(!newGraph, properties, monitor);
|
GraphDisplay display = graphService.getDefaultGraphDisplay(!newGraph, properties, monitor);
|
||||||
ASTGraphDisplayListener displayListener =
|
ASTGraphDisplayListener displayListener =
|
||||||
new ASTGraphDisplayListener(tool, display, hfunction, graphType);
|
new ASTGraphDisplayListener(tool, display, hfunction, graphType);
|
||||||
|
|||||||
+5
-1
@@ -15,9 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.file.formats.sevenzip;
|
package ghidra.file.formats.sevenzip;
|
||||||
|
|
||||||
import java.io.*;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
|
||||||
import org.apache.commons.io.FilenameUtils;
|
import org.apache.commons.io.FilenameUtils;
|
||||||
|
|
||||||
import ghidra.formats.gfilesystem.*;
|
import ghidra.formats.gfilesystem.*;
|
||||||
@@ -261,6 +262,9 @@ public class SevenZipFileSystem implements GFileSystem {
|
|||||||
case UNKNOWN_OPERATION_RESULT: {
|
case UNKNOWN_OPERATION_RESULT: {
|
||||||
throw new IOException("Unexpected: 7-Zip returned unknown operation result");
|
throw new IOException("Unexpected: 7-Zip returned unknown operation result");
|
||||||
}
|
}
|
||||||
|
case WRONG_PASSWORD: {
|
||||||
|
throw new IOException("7-Zip wrong password");
|
||||||
|
}
|
||||||
case OK:
|
case OK:
|
||||||
default: {
|
default: {
|
||||||
// it's all ok!
|
// it's all ok!
|
||||||
|
|||||||
+4
-7
@@ -239,15 +239,12 @@ public class GnuDemanglerParser {
|
|||||||
* Pattern: text for|to text
|
* Pattern: text for|to text
|
||||||
*
|
*
|
||||||
* Parts:
|
* Parts:
|
||||||
* -required text (capture group 2)
|
* -required text (capture group 2) -+
|
||||||
* --note: this uses '++', a possessive quantifier, to help keep the
|
* -'for' or 'to' (capture group 3) | (capture group 1)
|
||||||
* backtracking to a minimum
|
* -a space -+
|
||||||
* -a space
|
|
||||||
* -'for' or 'to' (capture group 3)
|
|
||||||
* -a space
|
|
||||||
* -optional text (capture group 4)
|
* -optional text (capture group 4)
|
||||||
*
|
*
|
||||||
* Note: capture group 1 is the combination of groups 2 and 3
|
* Note: capture group 1 is the combination of groups 2 and 3 with trailing space
|
||||||
*
|
*
|
||||||
* Examples:
|
* Examples:
|
||||||
* construction vtable for
|
* construction vtable for
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
EXCLUDE FROM GHIDRA JAR: true
|
EXCLUDE FROM GHIDRA JAR: true
|
||||||
|
|
||||||
MODULE FILE LICENSE: lib/jungrapht-visualization-1.1.jar BSD
|
MODULE FILE LICENSE: lib/jungrapht-visualization-1.2.jar BSD
|
||||||
MODULE FILE LICENSE: lib/jungrapht-layout-1.1.jar BSD
|
MODULE FILE LICENSE: lib/jungrapht-layout-1.2.jar BSD
|
||||||
MODULE FILE LICENSE: lib/jgrapht-core-1.5.0.jar LGPL 2.1
|
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/jgrapht-io-1.5.0.jar LGPL 2.1
|
||||||
MODULE FILE LICENSE: lib/jheaps-0.13.jar Apache License 2.0
|
MODULE FILE LICENSE: lib/jheaps-0.13.jar Apache License 2.0
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ dependencies {
|
|||||||
compile project(":Base")
|
compile project(":Base")
|
||||||
|
|
||||||
// jungrapht - exclude slf4j which produces a conflict with other uses with Ghidra
|
// jungrapht - exclude slf4j which produces a conflict with other uses with Ghidra
|
||||||
compile ("com.github.tomnelson:jungrapht-visualization:1.1") { exclude group: "org.slf4j", module: "slf4j-api" }
|
compile ("com.github.tomnelson:jungrapht-visualization:1.2") { exclude group: "org.slf4j", module: "slf4j-api" }
|
||||||
compile ("com.github.tomnelson:jungrapht-layout:1.1") { exclude group: "org.slf4j", module: "slf4j-api" }
|
compile ("com.github.tomnelson:jungrapht-layout:1.2") { exclude group: "org.slf4j", module: "slf4j-api" }
|
||||||
|
|
||||||
compile "org.jgrapht:jgrapht-core:1.5.0"
|
compile "org.jgrapht:jgrapht-core:1.5.0"
|
||||||
|
|
||||||
|
|||||||
+70
-26
@@ -103,28 +103,33 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||||||
|
|
||||||
private static final String ACTION_OWNER = "GraphServices";
|
private static final String ACTION_OWNER = "GraphServices";
|
||||||
|
|
||||||
/*
|
|
||||||
A handful of properties that can be set via the constructor
|
|
||||||
*/
|
|
||||||
private static final String SELECTED_VERTEX_COLOR = "selectedVertexColor";
|
|
||||||
private static final String SELECTED_EDGE_COLOR = "selectedEdgeColor";
|
|
||||||
private static final String INITIAL_LAYOUT_ALGORITHM = "initialLayoutAlgorithm";
|
|
||||||
private static final String DISPLAY_VERTICES_AS_ICONS = "displayVerticesAsIcons";
|
|
||||||
private static final String VERTEX_LABEL_POSITION = "vertexLabelPosition";
|
|
||||||
|
|
||||||
private static final int MAX_NODES = Integer.getInteger("maxNodes", 10000);
|
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_VIEW_SIZE = new Dimension(1000, 1000);
|
||||||
private static final Dimension PREFERRED_LAYOUT_SIZE = new Dimension(3000, 3000);
|
private static final Dimension PREFERRED_LAYOUT_SIZE = new Dimension(3000, 3000);
|
||||||
|
|
||||||
private Logger log = Logger.getLogger(DefaultGraphDisplay.class.getName());
|
private Logger log = Logger.getLogger(DefaultGraphDisplay.class.getName());
|
||||||
|
|
||||||
private Map<String, String> displayProperties = new HashMap<>();
|
private Map<String, String> displayProperties;
|
||||||
private Set<DockingActionIf> addedActions = new LinkedHashSet<>();
|
private Set<DockingActionIf> addedActions = new LinkedHashSet<>();
|
||||||
private GraphDisplayListener listener = new DummyGraphDisplayListener();
|
private GraphDisplayListener listener = new DummyGraphDisplayListener();
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
private AttributedGraph graph;
|
private AttributedGraph graph;
|
||||||
|
|
||||||
|
private static String DEFAULT_EDGE_TYPE_PRIORITY_LIST =
|
||||||
|
"Fall-Through,"+
|
||||||
|
"Conditional-Return,"+
|
||||||
|
"Unconditional-Jump,"+
|
||||||
|
"Conditional-Jump,"+
|
||||||
|
"Unconditional-Call,"+
|
||||||
|
"Conditional-Call,"+
|
||||||
|
"Terminator,"+
|
||||||
|
"Computed,"+
|
||||||
|
"Indirection,"+
|
||||||
|
"Entry";
|
||||||
|
|
||||||
|
private static String DEFAULT_FAVORED_EDGES = "Fall-Through";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a unique id for this {@link GraphDisplay}
|
* a unique id for this {@link GraphDisplay}
|
||||||
*/
|
*/
|
||||||
@@ -219,7 +224,9 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||||||
viewer.getComponent().add(satelliteViewer.getComponent());
|
viewer.getComponent().add(satelliteViewer.getComponent());
|
||||||
}
|
}
|
||||||
layoutTransitionManager =
|
layoutTransitionManager =
|
||||||
new LayoutTransitionManager(viewer, this::isRoot);
|
new LayoutTransitionManager(viewer, this::isRoot,
|
||||||
|
getEdgeTypePriorityList(),
|
||||||
|
getFavoredEdgePredicate());
|
||||||
|
|
||||||
viewer.getComponent().addComponentListener(new ComponentAdapter() {
|
viewer.getComponent().addComponentListener(new ComponentAdapter() {
|
||||||
@Override
|
@Override
|
||||||
@@ -252,6 +259,19 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||||||
return Colors.getHexColor(property);
|
return Colors.getHexColor(property);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<String> getEdgeTypePriorityList() {
|
||||||
|
return Arrays.asList(displayProperties
|
||||||
|
.getOrDefault(EDGE_TYPE_PRIORITY_LIST, DEFAULT_EDGE_TYPE_PRIORITY_LIST)
|
||||||
|
.split(","));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Predicate<AttributedEdge> getFavoredEdgePredicate() {
|
||||||
|
String[] favoredEdges = displayProperties.getOrDefault(FAVORED_EDGES, DEFAULT_FAVORED_EDGES)
|
||||||
|
.split(",");
|
||||||
|
return attributedEdge -> Arrays.stream(favoredEdges)
|
||||||
|
.anyMatch(s -> s.equals(attributedEdge.getAttribute("EdgeType")));
|
||||||
|
}
|
||||||
|
|
||||||
JComponent getComponent() {
|
JComponent getComponent() {
|
||||||
JComponent component = viewer.getComponent();
|
JComponent component = viewer.getComponent();
|
||||||
component.setFocusable(true);
|
component.setFocusable(true);
|
||||||
@@ -486,7 +506,7 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||||||
"Extends the current selection by including the target/source vertices " +
|
"Extends the current selection by including the target/source vertices " +
|
||||||
"of all edges whose source/target is selected")
|
"of all edges whose source/target is selected")
|
||||||
.keyBinding("ctrl C")
|
.keyBinding("ctrl C")
|
||||||
.enabledWhen(c -> !isAllSelected(getSourceVerticesFromSelected()) &&
|
.enabledWhen(c -> !isAllSelected(getSourceVerticesFromSelected()) ||
|
||||||
!isAllSelected(getTargetVerticesFromSelected()))
|
!isAllSelected(getTargetVerticesFromSelected()))
|
||||||
.onAction(c -> growSelection(getAllComponentVerticesFromSelected()))
|
.onAction(c -> growSelection(getAllComponentVerticesFromSelected()))
|
||||||
.buildAndInstallLocal(componentProvider);
|
.buildAndInstallLocal(componentProvider);
|
||||||
@@ -610,6 +630,23 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||||||
|
|
||||||
private void growSelection(Set<AttributedVertex> vertices) {
|
private void growSelection(Set<AttributedVertex> vertices) {
|
||||||
viewer.getSelectedVertexState().select(vertices);
|
viewer.getSelectedVertexState().select(vertices);
|
||||||
|
selectEdgesConnecting(vertices);
|
||||||
|
}
|
||||||
|
|
||||||
|
// select all the edges that connect the supplied vertices
|
||||||
|
private void selectEdgesConnecting(Collection<AttributedVertex> vertices) {
|
||||||
|
viewer.getSelectedEdgeState().select(
|
||||||
|
graph.edgeSet()
|
||||||
|
.stream()
|
||||||
|
.filter(
|
||||||
|
e -> {
|
||||||
|
AttributedVertex source = graph.getEdgeSource(e);
|
||||||
|
AttributedVertex target = graph.getEdgeTarget(e);
|
||||||
|
return vertices.contains(source)
|
||||||
|
&& vertices.contains(target);
|
||||||
|
})
|
||||||
|
.collect(Collectors.toSet()));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isAllSelected(Set<AttributedVertex> vertices) {
|
private boolean isAllSelected(Set<AttributedVertex> vertices) {
|
||||||
@@ -617,8 +654,8 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Set<AttributedVertex> getSourceVerticesFromSelected() {
|
private Set<AttributedVertex> getSourceVerticesFromSelected() {
|
||||||
Set<AttributedVertex> sources = new HashSet<>();
|
|
||||||
Set<AttributedVertex> selectedVertices = getSelectedVertices();
|
Set<AttributedVertex> selectedVertices = getSelectedVertices();
|
||||||
|
Set<AttributedVertex> sources = new HashSet<>(selectedVertices);
|
||||||
for (AttributedVertex v : selectedVertices) {
|
for (AttributedVertex v : selectedVertices) {
|
||||||
Set<AttributedEdge> edges = graph.incomingEdgesOf(v);
|
Set<AttributedEdge> edges = graph.incomingEdgesOf(v);
|
||||||
edges.forEach(e -> sources.add(graph.getEdgeSource(e)));
|
edges.forEach(e -> sources.add(graph.getEdgeSource(e)));
|
||||||
@@ -635,8 +672,8 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Set<AttributedVertex> getTargetVerticesFromSelected() {
|
private Set<AttributedVertex> getTargetVerticesFromSelected() {
|
||||||
Set<AttributedVertex> targets = new HashSet<>();
|
|
||||||
Set<AttributedVertex> selectedVertices = getSelectedVertices();
|
Set<AttributedVertex> selectedVertices = getSelectedVertices();
|
||||||
|
Set<AttributedVertex> targets = new HashSet<>(selectedVertices);
|
||||||
for (AttributedVertex v : selectedVertices) {
|
for (AttributedVertex v : selectedVertices) {
|
||||||
Set<AttributedEdge> edges = graph.outgoingEdgesOf(v);
|
Set<AttributedEdge> edges = graph.outgoingEdgesOf(v);
|
||||||
edges.forEach(e -> targets.add(graph.getEdgeTarget(e)));
|
edges.forEach(e -> targets.add(graph.getEdgeTarget(e)));
|
||||||
@@ -674,9 +711,20 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||||||
return upstream;
|
return upstream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gather all source and target vertices until there are no more available.
|
||||||
|
* @return all the vertices in the component(s) of the selected vertices
|
||||||
|
*/
|
||||||
public Set<AttributedVertex> getAllComponentVerticesFromSelected() {
|
public Set<AttributedVertex> getAllComponentVerticesFromSelected() {
|
||||||
Set<AttributedVertex> componentVertices = getAllDownstreamVerticesFromSelected();
|
Set<AttributedVertex> componentVertices = new HashSet<>(viewer.getSelectedVertices());
|
||||||
componentVertices.addAll(getAllUpstreamVerticesFromSelected());
|
Set<AttributedVertex> downstream = getAllDownstreamVerticesFromSelected();
|
||||||
|
Set<AttributedVertex> upstream = getAllUpstreamVerticesFromSelected();
|
||||||
|
while (!downstream.isEmpty() || !upstream.isEmpty()) {
|
||||||
|
componentVertices.addAll(downstream);
|
||||||
|
componentVertices.addAll(upstream);
|
||||||
|
downstream = getAllDownstreamVerticesFromSelected();
|
||||||
|
upstream = getAllUpstreamVerticesFromSelected();
|
||||||
|
}
|
||||||
return componentVertices;
|
return componentVertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -955,13 +1003,14 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if a vertex is a root. For our purpose, a root either has no incoming edges
|
* 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
|
* or if all edges of a vertex are 'loop' edges
|
||||||
* @param vertex the vertex to test if it is a root
|
* @param vertex the vertex to test if it is a root
|
||||||
* @return true if the vertex is a root
|
* @return true if the vertex is a root
|
||||||
*/
|
*/
|
||||||
private boolean isRoot(AttributedVertex vertex) {
|
private boolean isRoot(AttributedVertex vertex) {
|
||||||
Set<AttributedEdge> incomingEdgesOf = graph.incomingEdgesOf(vertex);
|
Set<AttributedEdge> incomingEdgesOf = graph.incomingEdgesOf(vertex);
|
||||||
return incomingEdgesOf.isEmpty();
|
return incomingEdgesOf.isEmpty() ||
|
||||||
|
graph.incomingEdgesOf(vertex).equals(graph.outgoingEdgesOf(vertex));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1230,12 +1279,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||||||
|
|
||||||
setVertexPreferences(vv);
|
setVertexPreferences(vv);
|
||||||
|
|
||||||
// the selectedEdgeState will be controlled by the vertices that are selected.
|
|
||||||
// if both endpoints of an edge are selected, select that edge.
|
|
||||||
vv.setSelectedEdgeState(
|
|
||||||
new VertexEndpointsSelectedEdgeSelectedState<>(vv.getVisualizationModel()::getGraph,
|
|
||||||
vv.getSelectedVertexState()));
|
|
||||||
|
|
||||||
// selected edges will be drawn with a wider stroke
|
// selected edges will be drawn with a wider stroke
|
||||||
renderContext.setEdgeStrokeFunction(
|
renderContext.setEdgeStrokeFunction(
|
||||||
e -> isSelected(e) ? new BasicStroke(20.f)
|
e -> isSelected(e) ? new BasicStroke(20.f)
|
||||||
@@ -1259,7 +1302,6 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||||||
|
|
||||||
// cause the lightweight (optimized) renderer to use the vertex shapes instead
|
// cause the lightweight (optimized) renderer to use the vertex shapes instead
|
||||||
// of using default shapes.
|
// of using default shapes.
|
||||||
|
|
||||||
if (vertexRenderer instanceof LightweightVertexRenderer) {
|
if (vertexRenderer instanceof LightweightVertexRenderer) {
|
||||||
Function<AttributedVertex, Shape> vertexShapeFunction =
|
Function<AttributedVertex, Shape> vertexShapeFunction =
|
||||||
renderContext.getVertexShapeFunction();
|
renderContext.getVertexShapeFunction();
|
||||||
@@ -1282,7 +1324,9 @@ public class DefaultGraphDisplay implements GraphDisplay {
|
|||||||
vv.getComponent().removeMouseListener(mouseListener);
|
vv.getComponent().removeMouseListener(mouseListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
graphMouse = new JgtGraphMouse(this);
|
graphMouse = new JgtGraphMouse(this,
|
||||||
|
Boolean.parseBoolean(displayProperties.getOrDefault(ENABLE_EDGE_SELECTION,
|
||||||
|
"false")));
|
||||||
vv.setGraphMouse(graphMouse);
|
vv.setGraphMouse(graphMouse);
|
||||||
|
|
||||||
return vv;
|
return vv;
|
||||||
|
|||||||
+55
-6
@@ -15,7 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.graph.visualization;
|
package ghidra.graph.visualization;
|
||||||
|
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import org.jungrapht.visualization.layout.algorithms.*;
|
import org.jungrapht.visualization.layout.algorithms.*;
|
||||||
import org.jungrapht.visualization.layout.algorithms.repulsion.BarnesHutFRRepulsion;
|
import org.jungrapht.visualization.layout.algorithms.repulsion.BarnesHutFRRepulsion;
|
||||||
@@ -36,22 +38,38 @@ class LayoutFunction
|
|||||||
|
|
||||||
static final String KAMADA_KAWAI = "Force Balanced";
|
static final String KAMADA_KAWAI = "Force Balanced";
|
||||||
static final String FRUCTERMAN_REINGOLD = "Force Directed";
|
static final String FRUCTERMAN_REINGOLD = "Force Directed";
|
||||||
static final String CIRCLE_MINCROSS = "Circle";
|
static final String CIRCLE = "Circle";
|
||||||
static final String TIDIER_TREE = "Compact Hierarchical";
|
static final String TIDIER_TREE = "Compact Hierarchical";
|
||||||
static final String TIDIER_RADIAL_TREE = "Compact Radial";
|
static final String TIDIER_RADIAL_TREE = "Compact Radial";
|
||||||
static final String MIN_CROSS_TOP_DOWN = "Hierarchical MinCross Top Down";
|
static final String MIN_CROSS_TOP_DOWN = "Hierarchical MinCross Top Down";
|
||||||
static final String MIN_CROSS_LONGEST_PATH = "Hierarchical MinCross Longest Path";
|
static final String MIN_CROSS_LONGEST_PATH = "Hierarchical MinCross Longest Path";
|
||||||
static final String MIN_CROSS_NETWORK_SIMPLEX = "Hierarchical MinCross Network Simplex";
|
static final String MIN_CROSS_NETWORK_SIMPLEX = "Hierarchical MinCross Network Simplex";
|
||||||
static final String MIN_CROSS_COFFMAN_GRAHAM = "Hierarchical MinCross Coffman Graham";
|
static final String MIN_CROSS_COFFMAN_GRAHAM = "Hierarchical MinCross Coffman Graham";
|
||||||
|
static final String EXP_MIN_CROSS_TOP_DOWN = "Experimental Hierarchical MinCross Top Down";
|
||||||
|
static final String EXP_MIN_CROSS_LONGEST_PATH = "Experimental Hierarchical MinCross Longest Path";
|
||||||
|
static final String EXP_MIN_CROSS_NETWORK_SIMPLEX = "Experimental Hierarchical MinCross Network Simplex";
|
||||||
|
static final String EXP_MIN_CROSS_COFFMAN_GRAHAM = "Experimental Hierarchical MinCross Coffman Graham";
|
||||||
static final String TREE = "Hierarchical";
|
static final String TREE = "Hierarchical";
|
||||||
static final String RADIAL = "Radial";
|
static final String RADIAL = "Radial";
|
||||||
static final String BALLOON = "Balloon";
|
static final String BALLOON = "Balloon";
|
||||||
static final String GEM = "Gem (Graph Embedder)";
|
static final String GEM = "Gem (Graph Embedder)";
|
||||||
|
|
||||||
|
Predicate<AttributedEdge> favoredEdgePredicate;
|
||||||
|
Comparator<AttributedEdge> edgeTypeComparator;
|
||||||
|
|
||||||
|
LayoutFunction(Comparator<AttributedEdge> edgeTypeComparator, Predicate<AttributedEdge> favoredEdgePredicate) {
|
||||||
|
this.edgeTypeComparator = edgeTypeComparator;
|
||||||
|
this.favoredEdgePredicate = favoredEdgePredicate;
|
||||||
|
}
|
||||||
|
|
||||||
public String[] getNames() {
|
public String[] getNames() {
|
||||||
return new String[] { TIDIER_TREE, TREE,
|
return new String[] { TIDIER_TREE, TREE,
|
||||||
TIDIER_RADIAL_TREE, MIN_CROSS_TOP_DOWN, MIN_CROSS_LONGEST_PATH,
|
TIDIER_RADIAL_TREE, MIN_CROSS_TOP_DOWN, MIN_CROSS_LONGEST_PATH,
|
||||||
MIN_CROSS_NETWORK_SIMPLEX, MIN_CROSS_COFFMAN_GRAHAM, CIRCLE_MINCROSS,
|
MIN_CROSS_NETWORK_SIMPLEX, MIN_CROSS_COFFMAN_GRAHAM, CIRCLE,
|
||||||
|
EXP_MIN_CROSS_TOP_DOWN,
|
||||||
|
EXP_MIN_CROSS_LONGEST_PATH,
|
||||||
|
EXP_MIN_CROSS_NETWORK_SIMPLEX,
|
||||||
|
EXP_MIN_CROSS_COFFMAN_GRAHAM,
|
||||||
KAMADA_KAWAI, FRUCTERMAN_REINGOLD, RADIAL, BALLOON, GEM
|
KAMADA_KAWAI, FRUCTERMAN_REINGOLD, RADIAL, BALLOON, GEM
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -67,27 +85,56 @@ class LayoutFunction
|
|||||||
case FRUCTERMAN_REINGOLD:
|
case FRUCTERMAN_REINGOLD:
|
||||||
return FRLayoutAlgorithm.<AttributedVertex> builder()
|
return FRLayoutAlgorithm.<AttributedVertex> builder()
|
||||||
.repulsionContractBuilder(BarnesHutFRRepulsion.builder());
|
.repulsionContractBuilder(BarnesHutFRRepulsion.builder());
|
||||||
case CIRCLE_MINCROSS:
|
case CIRCLE:
|
||||||
return CircleLayoutAlgorithm.<AttributedVertex> builder()
|
return CircleLayoutAlgorithm.<AttributedVertex> builder()
|
||||||
.reduceEdgeCrossing(true);
|
.reduceEdgeCrossing(false);
|
||||||
case TIDIER_RADIAL_TREE:
|
case TIDIER_RADIAL_TREE:
|
||||||
return TidierRadialTreeLayoutAlgorithm
|
return TidierRadialTreeLayoutAlgorithm
|
||||||
.<AttributedVertex, AttributedEdge> edgeAwareBuilder();
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator);
|
||||||
case MIN_CROSS_TOP_DOWN:
|
case MIN_CROSS_TOP_DOWN:
|
||||||
return EiglspergerLayoutAlgorithm
|
return EiglspergerLayoutAlgorithm
|
||||||
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator)
|
||||||
.layering(Layering.TOP_DOWN);
|
.layering(Layering.TOP_DOWN);
|
||||||
case MIN_CROSS_LONGEST_PATH:
|
case MIN_CROSS_LONGEST_PATH:
|
||||||
return EiglspergerLayoutAlgorithm
|
return EiglspergerLayoutAlgorithm
|
||||||
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator)
|
||||||
.layering(Layering.LONGEST_PATH);
|
.layering(Layering.LONGEST_PATH);
|
||||||
case MIN_CROSS_NETWORK_SIMPLEX:
|
case MIN_CROSS_NETWORK_SIMPLEX:
|
||||||
return EiglspergerLayoutAlgorithm
|
return EiglspergerLayoutAlgorithm
|
||||||
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator)
|
||||||
.layering(Layering.NETWORK_SIMPLEX);
|
.layering(Layering.NETWORK_SIMPLEX);
|
||||||
case MIN_CROSS_COFFMAN_GRAHAM:
|
case MIN_CROSS_COFFMAN_GRAHAM:
|
||||||
return EiglspergerLayoutAlgorithm
|
return EiglspergerLayoutAlgorithm
|
||||||
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator)
|
||||||
|
.layering(Layering.COFFMAN_GRAHAM);
|
||||||
|
case EXP_MIN_CROSS_TOP_DOWN:
|
||||||
|
return EiglspergerLayoutAlgorithm
|
||||||
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator)
|
||||||
|
.favoredEdgePredicate(favoredEdgePredicate)
|
||||||
|
.layering(Layering.TOP_DOWN);
|
||||||
|
case EXP_MIN_CROSS_LONGEST_PATH:
|
||||||
|
return EiglspergerLayoutAlgorithm
|
||||||
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator)
|
||||||
|
.favoredEdgePredicate(favoredEdgePredicate)
|
||||||
|
.layering(Layering.LONGEST_PATH);
|
||||||
|
case EXP_MIN_CROSS_NETWORK_SIMPLEX:
|
||||||
|
return EiglspergerLayoutAlgorithm
|
||||||
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator)
|
||||||
|
.favoredEdgePredicate(favoredEdgePredicate)
|
||||||
|
.layering(Layering.NETWORK_SIMPLEX);
|
||||||
|
case EXP_MIN_CROSS_COFFMAN_GRAHAM:
|
||||||
|
return EiglspergerLayoutAlgorithm
|
||||||
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator)
|
||||||
|
.favoredEdgePredicate(favoredEdgePredicate)
|
||||||
.layering(Layering.COFFMAN_GRAHAM);
|
.layering(Layering.COFFMAN_GRAHAM);
|
||||||
case RADIAL:
|
case RADIAL:
|
||||||
return RadialTreeLayoutAlgorithm
|
return RadialTreeLayoutAlgorithm
|
||||||
@@ -103,7 +150,9 @@ class LayoutFunction
|
|||||||
case TIDIER_TREE:
|
case TIDIER_TREE:
|
||||||
default:
|
default:
|
||||||
return TidierTreeLayoutAlgorithm
|
return TidierTreeLayoutAlgorithm
|
||||||
.<AttributedVertex, AttributedEdge> edgeAwareBuilder();
|
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
|
||||||
|
.edgeComparator(edgeTypeComparator);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-37
@@ -38,7 +38,7 @@ import ghidra.service.graph.AttributedVertex;
|
|||||||
*/
|
*/
|
||||||
class LayoutTransitionManager {
|
class LayoutTransitionManager {
|
||||||
|
|
||||||
LayoutFunction layoutFunction = new LayoutFunction();
|
LayoutFunction layoutFunction;
|
||||||
/**
|
/**
|
||||||
* the {@link VisualizationServer} used to display graphs using the requested {@link LayoutAlgorithm}
|
* the {@link VisualizationServer} used to display graphs using the requested {@link LayoutAlgorithm}
|
||||||
*/
|
*/
|
||||||
@@ -49,24 +49,6 @@ class LayoutTransitionManager {
|
|||||||
*/
|
*/
|
||||||
Predicate<AttributedVertex> rootPredicate;
|
Predicate<AttributedVertex> rootPredicate;
|
||||||
|
|
||||||
public static final List<String> EDGE_PRIORITY_LIST =
|
|
||||||
List.of(
|
|
||||||
"Fall-Through",
|
|
||||||
"Conditional-Return",
|
|
||||||
"Unconditional-Jump",
|
|
||||||
"Conditional-Jump",
|
|
||||||
"Unconditional-Call",
|
|
||||||
"Conditional-Call",
|
|
||||||
"Terminator",
|
|
||||||
"Computed",
|
|
||||||
"Indirection",
|
|
||||||
"Entry");
|
|
||||||
/**
|
|
||||||
* a {@link Comparator} to sort edges during layout graph traversal
|
|
||||||
* The default uses the {@code EDGE_PRIORTITY_LIST }
|
|
||||||
*/
|
|
||||||
Comparator<AttributedEdge> edgeComparator = new EdgeComparator(EDGE_PRIORITY_LIST);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* a {@link Function} to provide {@link Rectangle} (and thus bounds} for vertices
|
* a {@link Function} to provide {@link Rectangle} (and thus bounds} for vertices
|
||||||
*/
|
*/
|
||||||
@@ -81,47 +63,54 @@ class LayoutTransitionManager {
|
|||||||
|
|
||||||
LayoutPaintable.RadialRings<AttributedVertex> radialLayoutRings;
|
LayoutPaintable.RadialRings<AttributedVertex> radialLayoutRings;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance with passed parameters
|
* Create an instance with passed parameters
|
||||||
* @param visualizationServer displays the graph
|
* @param visualizationServer displays the graph
|
||||||
* @param rootPredicate selects root vertices
|
* @param rootPredicate selects root vertices
|
||||||
|
* @param edgeTypePriorityList a {@code List} of EdgeType names in priority order
|
||||||
|
* @param favoredEdgePredicate q {@code Predicate} that will cause certain EdgeTypes to be favored during layout
|
||||||
*/
|
*/
|
||||||
public LayoutTransitionManager(
|
public LayoutTransitionManager(
|
||||||
VisualizationServer<AttributedVertex, AttributedEdge> visualizationServer,
|
VisualizationServer<AttributedVertex, AttributedEdge> visualizationServer,
|
||||||
Predicate<AttributedVertex> rootPredicate) {
|
Predicate<AttributedVertex> rootPredicate,
|
||||||
|
List<String> edgeTypePriorityList,
|
||||||
|
Predicate<AttributedEdge> favoredEdgePredicate) {
|
||||||
this.visualizationServer = visualizationServer;
|
this.visualizationServer = visualizationServer;
|
||||||
this.rootPredicate = rootPredicate;
|
this.rootPredicate = rootPredicate;
|
||||||
|
|
||||||
this.renderContext = visualizationServer.getRenderContext();
|
this.renderContext = visualizationServer.getRenderContext();
|
||||||
this.vertexBoundsFunction = visualizationServer.getRenderContext().getVertexBoundsFunction();
|
this.vertexBoundsFunction = visualizationServer.getRenderContext().getVertexBoundsFunction();
|
||||||
}
|
this.layoutFunction = new LayoutFunction(new EdgeComparator(edgeTypePriorityList),
|
||||||
|
favoredEdgePredicate);
|
||||||
public void setEdgeComparator(Comparator<AttributedEdge> edgeComparator) {
|
|
||||||
this.edgeComparator = edgeComparator;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set the layout in order to configure the requested {@link LayoutAlgorithm}
|
* set the layout in order to configure the requested {@link LayoutAlgorithm}
|
||||||
* @param layoutName the name of the layout algorithm to use
|
* @param layoutName the name of the layout algorithm to use
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void setLayout(String layoutName) {
|
public void setLayout(String layoutName) {
|
||||||
LayoutAlgorithm.Builder<AttributedVertex, ?, ?> builder = layoutFunction.apply(layoutName);
|
LayoutAlgorithm.Builder<AttributedVertex, ?, ?> builder = layoutFunction.apply(layoutName);
|
||||||
LayoutAlgorithm<AttributedVertex> layoutAlgorithm = builder.build();
|
LayoutAlgorithm<AttributedVertex> layoutAlgorithm = builder.build();
|
||||||
|
// layout algorithm considers the size of vertices
|
||||||
if (layoutAlgorithm instanceof VertexBoundsFunctionConsumer) {
|
if (layoutAlgorithm instanceof VertexBoundsFunctionConsumer) {
|
||||||
((VertexBoundsFunctionConsumer<AttributedVertex>) layoutAlgorithm)
|
((VertexBoundsFunctionConsumer<AttributedVertex>) layoutAlgorithm)
|
||||||
.setVertexBoundsFunction(vertexBoundsFunction);
|
.setVertexBoundsFunction(vertexBoundsFunction);
|
||||||
}
|
}
|
||||||
|
// mincross layouts are 'layered'. put some bounds on the number of
|
||||||
|
// iterations of the level cross function based on the size of the graph
|
||||||
|
// very large graphs do not improve enough to out-weigh the cost of
|
||||||
|
// repeated iterations
|
||||||
if (layoutAlgorithm instanceof Layered) {
|
if (layoutAlgorithm instanceof Layered) {
|
||||||
((Layered<AttributedVertex, AttributedEdge>) layoutAlgorithm)
|
((Layered<AttributedVertex, AttributedEdge>) layoutAlgorithm)
|
||||||
.setMaxLevelCrossFunction(g ->
|
.setMaxLevelCrossFunction(g ->
|
||||||
Math.max(1, Math.min(10, 500 / g.vertexSet().size())));
|
Math.max(1, Math.min(10, 500 / g.vertexSet().size())));
|
||||||
}
|
}
|
||||||
|
// tree layouts need a way to determine which vertices are roots
|
||||||
|
// especially when the graph is not a DAG
|
||||||
if (layoutAlgorithm instanceof TreeLayout) {
|
if (layoutAlgorithm instanceof TreeLayout) {
|
||||||
((TreeLayout<AttributedVertex>) layoutAlgorithm).setRootPredicate(rootPredicate);
|
((TreeLayout<AttributedVertex>) layoutAlgorithm).setRootPredicate(rootPredicate);
|
||||||
}
|
}
|
||||||
// remove any previously added layout paintables
|
// remove any previously added layout paintables
|
||||||
|
// and apply paintables to these 2 algorithms
|
||||||
removePaintable(radialLayoutRings);
|
removePaintable(radialLayoutRings);
|
||||||
removePaintable(balloonLayoutRings);
|
removePaintable(balloonLayoutRings);
|
||||||
if (layoutAlgorithm instanceof BalloonLayoutAlgorithm) {
|
if (layoutAlgorithm instanceof BalloonLayoutAlgorithm) {
|
||||||
@@ -138,9 +127,7 @@ class LayoutTransitionManager {
|
|||||||
visualizationServer.addPreRenderPaintable(radialLayoutRings);
|
visualizationServer.addPreRenderPaintable(radialLayoutRings);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (layoutAlgorithm instanceof EdgeSorting) {
|
// apply the layout algorithm
|
||||||
((EdgeSorting<AttributedEdge>) layoutAlgorithm).setEdgeComparator(edgeComparator);
|
|
||||||
}
|
|
||||||
LayoutAlgorithmTransition.apply(visualizationServer,
|
LayoutAlgorithmTransition.apply(visualizationServer,
|
||||||
layoutAlgorithm);
|
layoutAlgorithm);
|
||||||
}
|
}
|
||||||
@@ -151,7 +138,10 @@ class LayoutTransitionManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
/**
|
||||||
|
* Supplies the {@code LayoutAlgorithm} to be used for the initial @{code Graph} visualization
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public LayoutAlgorithm<AttributedVertex> getInitialLayoutAlgorithm() {
|
public LayoutAlgorithm<AttributedVertex> getInitialLayoutAlgorithm() {
|
||||||
LayoutAlgorithm<AttributedVertex> initialLayoutAlgorithm =
|
LayoutAlgorithm<AttributedVertex> initialLayoutAlgorithm =
|
||||||
layoutFunction.apply(TIDIER_TREE).build();
|
layoutFunction.apply(TIDIER_TREE).build();
|
||||||
@@ -159,12 +149,6 @@ class LayoutTransitionManager {
|
|||||||
if (initialLayoutAlgorithm instanceof TreeLayout) {
|
if (initialLayoutAlgorithm instanceof TreeLayout) {
|
||||||
((TreeLayout<AttributedVertex>) initialLayoutAlgorithm)
|
((TreeLayout<AttributedVertex>) initialLayoutAlgorithm)
|
||||||
.setRootPredicate(rootPredicate);
|
.setRootPredicate(rootPredicate);
|
||||||
((TreeLayout<AttributedVertex>) initialLayoutAlgorithm)
|
|
||||||
.setVertexBoundsFunction(vertexBoundsFunction);
|
|
||||||
}
|
|
||||||
if (initialLayoutAlgorithm instanceof EdgeSorting) {
|
|
||||||
((EdgeSorting<AttributedEdge>) initialLayoutAlgorithm)
|
|
||||||
.setEdgeComparator(edgeComparator);
|
|
||||||
}
|
}
|
||||||
if (initialLayoutAlgorithm instanceof VertexBoundsFunctionConsumer) {
|
if (initialLayoutAlgorithm instanceof VertexBoundsFunctionConsumer) {
|
||||||
((VertexBoundsFunctionConsumer<AttributedVertex>) initialLayoutAlgorithm)
|
((VertexBoundsFunctionConsumer<AttributedVertex>) initialLayoutAlgorithm)
|
||||||
@@ -173,6 +157,10 @@ class LayoutTransitionManager {
|
|||||||
return initialLayoutAlgorithm;
|
return initialLayoutAlgorithm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supplies a {@code String[]} array of the supported layout names
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
public String[] getLayoutNames() {
|
public String[] getLayoutNames() {
|
||||||
return layoutFunction.getNames();
|
return layoutFunction.getNames();
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-3
@@ -29,12 +29,14 @@ import ghidra.service.graph.AttributedVertex;
|
|||||||
public class JgtGraphMouse extends DefaultGraphMouse<AttributedVertex, AttributedEdge> {
|
public class JgtGraphMouse extends DefaultGraphMouse<AttributedVertex, AttributedEdge> {
|
||||||
|
|
||||||
private DefaultGraphDisplay graphDisplay;
|
private DefaultGraphDisplay graphDisplay;
|
||||||
|
private boolean allowEdgeSelection;
|
||||||
|
|
||||||
// TODO we should not need the graph display for any mouse plugins, but the API is net yet
|
// 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
|
// robust enough to communicate fully without it
|
||||||
public JgtGraphMouse(DefaultGraphDisplay graphDisplay) {
|
public JgtGraphMouse(DefaultGraphDisplay graphDisplay, boolean allowEdgeSelection) {
|
||||||
super(DefaultGraphMouse.builder());
|
super(DefaultGraphMouse.builder());
|
||||||
this.graphDisplay = graphDisplay;
|
this.graphDisplay = graphDisplay;
|
||||||
|
this.allowEdgeSelection = allowEdgeSelection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -54,13 +56,13 @@ public class JgtGraphMouse extends DefaultGraphMouse<AttributedVertex, Attribute
|
|||||||
// JUNGRAPHT CHANGE 1,2
|
// JUNGRAPHT CHANGE 1,2
|
||||||
//
|
//
|
||||||
// Note: this code can go away when we can turn off the picking square
|
// Note: this code can go away when we can turn off the picking square
|
||||||
add(new JgtSelectingGraphMousePlugin());
|
add(allowEdgeSelection ? new SelectingGraphMousePlugin() : new VertexSelectingGraphMousePlugin<>());
|
||||||
// add(new SelectingGraphMousePlugin<>());
|
// add(new SelectingGraphMousePlugin<>());
|
||||||
|
|
||||||
add(new RegionSelectingGraphMousePlugin<>());
|
add(new RegionSelectingGraphMousePlugin<>());
|
||||||
|
|
||||||
// the grab/pan feature
|
// the grab/pan feature
|
||||||
add(new TranslatingGraphMousePlugin(InputEvent.BUTTON1_DOWN_MASK));
|
add(TranslatingGraphMousePlugin.builder().translatingMask(InputEvent.BUTTON1_DOWN_MASK).build());
|
||||||
|
|
||||||
// scaling
|
// scaling
|
||||||
add(new ScalingGraphMousePlugin());
|
add(new ScalingGraphMousePlugin());
|
||||||
|
|||||||
+6
-4
@@ -39,19 +39,21 @@ public class JgtSatelliteGraphMouse
|
|||||||
//
|
//
|
||||||
// JUNGRAPHT CHANGE 3
|
// JUNGRAPHT CHANGE 3
|
||||||
//
|
//
|
||||||
|
// disable single selection in satellite view by setting masks to 0
|
||||||
SelectingGraphMousePlugin<AttributedVertex, AttributedEdge> mySelectingPlugin =
|
SelectingGraphMousePlugin<AttributedVertex, AttributedEdge> mySelectingPlugin =
|
||||||
new JgtSelectingGraphMousePlugin(singleSelectionMask, addSingleSelectionMask);
|
new JgtSelectingGraphMousePlugin(0, 0);
|
||||||
mySelectingPlugin.setLocked(true);
|
mySelectingPlugin.setLocked(true);
|
||||||
selectingPlugin = mySelectingPlugin;
|
selectingPlugin = mySelectingPlugin;
|
||||||
|
|
||||||
regionSelectingPlugin =
|
regionSelectingPlugin =
|
||||||
RegionSelectingGraphMousePlugin.builder()
|
RegionSelectingGraphMousePlugin.builder()
|
||||||
.regionSelectionMask(regionSelectionMask)
|
.regionSelectionMask(regionSelectionMask)
|
||||||
.addRegionSelectionMask(addRegionSelectionMask)
|
.toggleRegionSelectionMask(toggleRegionSelectionMask)
|
||||||
.regionSelectionCompleteMask(regionSelectionCompleteMask)
|
.regionSelectionCompleteMask(regionSelectionCompleteMask)
|
||||||
.addRegionSelectionCompleteMask(addRegionSelectionCompleteMask)
|
.toggleRegionSelectionCompleteMask(toggleRegionSelectionCompleteMask)
|
||||||
.build();
|
.build();
|
||||||
translatingPlugin = new SatelliteTranslatingGraphMousePlugin(translatingMask);
|
translatingPlugin = SatelliteTranslatingGraphMousePlugin.builder()
|
||||||
|
.translatingMask(translatingMask).build();
|
||||||
add(selectingPlugin);
|
add(selectingPlugin);
|
||||||
add(regionSelectingPlugin);
|
add(regionSelectingPlugin);
|
||||||
add(translatingPlugin);
|
add(translatingPlugin);
|
||||||
|
|||||||
+4
-6
@@ -54,8 +54,10 @@ public class JgtSelectingGraphMousePlugin
|
|||||||
this.pickFootprintPaintable = dummyPickFootprintPaintable;
|
this.pickFootprintPaintable = dummyPickFootprintPaintable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JgtSelectingGraphMousePlugin(int singleSelectionMask, int addSingleSelectionMask) {
|
public JgtSelectingGraphMousePlugin(int singleSelectionMask, int toggleSingleSelectionMask) {
|
||||||
super(singleSelectionMask, addSingleSelectionMask);
|
super(SelectingGraphMousePlugin.<AttributedVertex, AttributedEdge>builder()
|
||||||
|
.singleSelectionMask(singleSelectionMask)
|
||||||
|
.toggleSingleSelectionMask(toggleSingleSelectionMask));
|
||||||
|
|
||||||
//
|
//
|
||||||
// JUNGRAPHT CHANGE 1
|
// JUNGRAPHT CHANGE 1
|
||||||
@@ -89,7 +91,6 @@ public class JgtSelectingGraphMousePlugin
|
|||||||
selectedVertexState.clear();
|
selectedVertexState.clear();
|
||||||
}
|
}
|
||||||
selectedVertexState.select(vertex);
|
selectedVertexState.select(vertex);
|
||||||
deselectedVertex = null;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// If this vertex is still around in mouseReleased, it will be deselected
|
// If this vertex is still around in mouseReleased, it will be deselected
|
||||||
@@ -99,9 +100,6 @@ public class JgtSelectingGraphMousePlugin
|
|||||||
//
|
//
|
||||||
// JUNGRAPHT CHANGE 2 HERE
|
// JUNGRAPHT CHANGE 2 HERE
|
||||||
//
|
//
|
||||||
if (addToSelection) {
|
|
||||||
deselectedVertex = vertex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
e.consume();
|
e.consume();
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ jungrapht.satelliteBackgroundTransparent=false
|
|||||||
jungrapht.satelliteLensColor= 0xFAFAFA
|
jungrapht.satelliteLensColor= 0xFAFAFA
|
||||||
|
|
||||||
jungrapht.pickedEdgeColor=0xFF0000
|
jungrapht.pickedEdgeColor=0xFF0000
|
||||||
jungrapht.edgeArrowLength=30
|
jungrapht.edgeArrowLength=50
|
||||||
jungrapht.edgeArrowWidth=20
|
jungrapht.edgeArrowWidth=40
|
||||||
|
|
||||||
# default spacing for tree layouts
|
# default spacing for tree layouts
|
||||||
jungrapht.treeLayoutHorizontalSpacing=2
|
jungrapht.treeLayoutHorizontalSpacing=2
|
||||||
@@ -34,7 +34,7 @@ jungrapht.lensStrokeWidth=10.0
|
|||||||
# when scale is < .1, switch to lightweight rendering
|
# when scale is < .1, switch to lightweight rendering
|
||||||
jungrapht.lightweightScaleThreshold=.1
|
jungrapht.lightweightScaleThreshold=.1
|
||||||
# under 50 vertices will use heavyweight rendering all the time
|
# under 50 vertices will use heavyweight rendering all the time
|
||||||
jungrapht.lightweightCountThreshold=50
|
jungrapht.lightweightCountThreshold=80
|
||||||
|
|
||||||
# default pixels spacings for vertices
|
# default pixels spacings for vertices
|
||||||
jungrapht.mincross.horizontalOffset=10
|
jungrapht.mincross.horizontalOffset=10
|
||||||
@@ -69,12 +69,12 @@ jungrapht.edgeSpatialSupport=RTREE
|
|||||||
# the mask for single vertex/edge selection
|
# the mask for single vertex/edge selection
|
||||||
jungrapht.singleSelectionMask=MB1
|
jungrapht.singleSelectionMask=MB1
|
||||||
# the mask to augment the selection with a single vertex/edge
|
# the mask to augment the selection with a single vertex/edge
|
||||||
jungrapht.addSingleSelectionMask=MB1_MENU
|
jungrapht.toggleSingleSelectionMask=MB1_MENU
|
||||||
# the mask to select vertices within a region
|
# the mask to select vertices within a region
|
||||||
jungrapht.regionSelectionMask=MB1_MENU
|
jungrapht.regionSelectionMask=MB1_MENU
|
||||||
# the mask to augment the selection with vertices in a region
|
# the mask to augment the selection with vertices in a region
|
||||||
jungrapht.addRegionSelectionMask=MB1_SHIFT_MENU
|
jungrapht.toggleRegionSelectionMask=MB1_SHIFT_MENU
|
||||||
# the mask to indicate that the selection region is complete/closed and selection may commence
|
# the mask to indicate that the selection region is complete/closed and selection may commence
|
||||||
jungrapht.regionSelectionCompleteMask=MENU
|
jungrapht.regionSelectionCompleteMask=MENU
|
||||||
# the mask to indicate that the selection region for augmentation is complete/closed and selection may commence
|
# the mask to indicate that the selection region for augmentation is complete/closed and selection may commence
|
||||||
jungrapht.addRegionSelectionCompleteMask=SHIFT_MENU
|
jungrapht.toggleRegionSelectionCompleteMask=SHIFT_MENU
|
||||||
|
|||||||
+3
-2
@@ -15,9 +15,10 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.app.util.pdb.pdbapplicator;
|
package ghidra.app.util.pdb.pdbapplicator;
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
|
||||||
import ghidra.app.cmd.label.SetLabelPrimaryCmd;
|
import ghidra.app.cmd.label.SetLabelPrimaryCmd;
|
||||||
import ghidra.app.util.NamespaceUtils;
|
import ghidra.app.util.NamespaceUtils;
|
||||||
import ghidra.app.util.SymbolPath;
|
import ghidra.app.util.SymbolPath;
|
||||||
@@ -204,7 +205,7 @@ public class PdbApplicator {
|
|||||||
throw new PdbException("Invalid Restriction");
|
throw new PdbException("Invalid Restriction");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (program == null) {
|
if (program != null) {
|
||||||
Options options = program.getOptions(Program.PROGRAM_INFO);
|
Options options = program.getOptions(Program.PROGRAM_INFO);
|
||||||
options.setBoolean(PdbParserConstants.PDB_LOADED, true);
|
options.setBoolean(PdbParserConstants.PDB_LOADED, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package docking;
|
package docking;
|
||||||
|
|
||||||
import java.awt.event.MouseEvent;
|
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@@ -134,7 +133,7 @@ public class ActionToGuiMapper {
|
|||||||
return menuGroupMap;
|
return menuGroupMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void showPopupMenu(ComponentPlaceholder componentInfo, MouseEvent e) {
|
public void showPopupMenu(ComponentPlaceholder componentInfo, PopupMenuContext popupContext) {
|
||||||
popupActionManager.popupMenu(componentInfo, e);
|
popupActionManager.popupMenu(componentInfo, popupContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,17 +67,17 @@ public class DockableComponent extends JPanel implements ContainerListener {
|
|||||||
@Override
|
@Override
|
||||||
public void mousePressed(MouseEvent e) {
|
public void mousePressed(MouseEvent e) {
|
||||||
componentSelected((Component) e.getSource());
|
componentSelected((Component) e.getSource());
|
||||||
processPopupMouseEvent(e);
|
showContextMenu(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseReleased(MouseEvent e) {
|
public void mouseReleased(MouseEvent e) {
|
||||||
processPopupMouseEvent(e);
|
showContextMenu(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void mouseClicked(MouseEvent e) {
|
public void mouseClicked(MouseEvent e) {
|
||||||
processPopupMouseEvent(e);
|
showContextMenu(e);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -146,24 +146,27 @@ public class DockableComponent extends JPanel implements ContainerListener {
|
|||||||
return focusedComponent;
|
return focusedComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processPopupMouseEvent(final MouseEvent e) {
|
void showContextMenu(PopupMenuContext popupContext) {
|
||||||
|
actionMgr.showPopupMenu(placeholder, popupContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showContextMenu(MouseEvent e) {
|
||||||
Component component = e.getComponent();
|
Component component = e.getComponent();
|
||||||
if (component == null) {
|
if (component == null) {
|
||||||
return;
|
return; // not sure this can happen
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the bounds to see if the clicked point is over the component
|
// get the bounds to see if the clicked point is over the component
|
||||||
Rectangle bounds = component.getBounds(); // get bounds to get width and height
|
Rectangle bounds = component.getBounds();
|
||||||
|
|
||||||
if (component instanceof JComponent) {
|
if (component instanceof JComponent) {
|
||||||
((JComponent) component).computeVisibleRect(bounds);
|
((JComponent) component).computeVisibleRect(bounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
Point point = e.getPoint();
|
Point point = e.getPoint();
|
||||||
boolean withinBounds = bounds.contains(point);
|
boolean withinBounds = bounds.contains(point);
|
||||||
|
|
||||||
if (e.isPopupTrigger() && withinBounds) {
|
if (e.isPopupTrigger() && withinBounds) {
|
||||||
actionMgr.showPopupMenu(placeholder, e);
|
PopupMenuContext popupContext = new PopupMenuContext(e);
|
||||||
|
actionMgr.showPopupMenu(placeholder, popupContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -476,17 +479,11 @@ public class DockableComponent extends JPanel implements ContainerListener {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see java.awt.event.ContainerListener#componentAdded(java.awt.event.ContainerEvent)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void componentAdded(ContainerEvent e) {
|
public void componentAdded(ContainerEvent e) {
|
||||||
initializeComponents(e.getChild());
|
initializeComponents(e.getChild());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @see java.awt.event.ContainerListener#componentRemoved(java.awt.event.ContainerEvent)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void componentRemoved(ContainerEvent e) {
|
public void componentRemoved(ContainerEvent e) {
|
||||||
deinitializeComponents(e.getChild());
|
deinitializeComponents(e.getChild());
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ package docking;
|
|||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
|
|
||||||
|
import org.apache.commons.text.WordUtils;
|
||||||
|
|
||||||
import docking.widgets.OkDialog;
|
import docking.widgets.OkDialog;
|
||||||
import docking.widgets.OptionDialog;
|
import docking.widgets.OptionDialog;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
@@ -62,23 +64,34 @@ public class DockingErrorDisplay implements ErrorDisplay {
|
|||||||
Component parent, String title, Object message, Throwable throwable) {
|
Component parent, String title, Object message, Throwable throwable) {
|
||||||
|
|
||||||
int dialogType = OptionDialog.PLAIN_MESSAGE;
|
int dialogType = OptionDialog.PLAIN_MESSAGE;
|
||||||
|
|
||||||
String messageString = message != null ? message.toString() : null;
|
String messageString = message != null ? message.toString() : null;
|
||||||
String rawMessage = HTMLUtilities.fromHTML(messageString);
|
if (messageString != null) {
|
||||||
|
// prevent excessive message degenerate cases
|
||||||
|
int maxChars = 1000;
|
||||||
|
String safeMessage = StringUtilities.trimMiddle(messageString, maxChars);
|
||||||
|
|
||||||
|
// wrap any poorly formatted text that gets displayed in the label; 80-100 chars is
|
||||||
|
// a reasonable line length based on historical print margins
|
||||||
|
messageString = WordUtils.wrap(safeMessage, 100, null, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
String unformattedMessage = HTMLUtilities.fromHTML(messageString);
|
||||||
switch (messageType) {
|
switch (messageType) {
|
||||||
case INFO:
|
case INFO:
|
||||||
dialogType = OptionDialog.INFORMATION_MESSAGE;
|
dialogType = OptionDialog.INFORMATION_MESSAGE;
|
||||||
consoleDisplay.displayInfoMessage(errorLogger, originator, parent, title,
|
consoleDisplay.displayInfoMessage(errorLogger, originator, parent, title,
|
||||||
rawMessage);
|
unformattedMessage);
|
||||||
break;
|
break;
|
||||||
case WARNING:
|
case WARNING:
|
||||||
case ALERT:
|
case ALERT:
|
||||||
dialogType = OptionDialog.WARNING_MESSAGE;
|
dialogType = OptionDialog.WARNING_MESSAGE;
|
||||||
consoleDisplay.displayWarningMessage(errorLogger, originator, parent, title,
|
consoleDisplay.displayWarningMessage(errorLogger, originator, parent, title,
|
||||||
rawMessage, throwable);
|
unformattedMessage, throwable);
|
||||||
break;
|
break;
|
||||||
case ERROR:
|
case ERROR:
|
||||||
consoleDisplay.displayErrorMessage(errorLogger, originator, parent, title,
|
consoleDisplay.displayErrorMessage(errorLogger, originator, parent, title,
|
||||||
rawMessage, throwable);
|
unformattedMessage, throwable);
|
||||||
dialogType = OptionDialog.ERROR_MESSAGE;
|
dialogType = OptionDialog.ERROR_MESSAGE;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -93,8 +106,8 @@ public class DockingErrorDisplay implements ErrorDisplay {
|
|||||||
return component;
|
return component;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showDialog(final String title, final Throwable throwable,
|
private void showDialog(final String title, final Throwable throwable, final int dialogType,
|
||||||
final int dialogType, final String messageString, final Component parent) {
|
final String messageString, final Component parent) {
|
||||||
|
|
||||||
Swing.runIfSwingOrRunLater(() -> {
|
Swing.runIfSwingOrRunLater(() -> {
|
||||||
|
|
||||||
@@ -108,8 +121,8 @@ public class DockingErrorDisplay implements ErrorDisplay {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showDialogOnSwing(String title, Throwable throwable,
|
private void showDialogOnSwing(String title, Throwable throwable, int dialogType,
|
||||||
int dialogType, String messageString, Component parent) {
|
String messageString, Component parent) {
|
||||||
|
|
||||||
if (activeDialog != null) {
|
if (activeDialog != null) {
|
||||||
activeDialog.addException(messageString, throwable);
|
activeDialog.addException(messageString, throwable);
|
||||||
|
|||||||
@@ -1765,8 +1765,11 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (bestParent == null) {
|
if (bestParent == null) {
|
||||||
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
bestParent = getJavaActiveWindow();
|
||||||
bestParent = kfm.getActiveWindow();
|
}
|
||||||
|
|
||||||
|
if (bestParent != null && !bestParent.isShowing()) {
|
||||||
|
bestParent = null; // don't let non-showing windows be parents
|
||||||
}
|
}
|
||||||
|
|
||||||
return bestParent;
|
return bestParent;
|
||||||
@@ -1775,8 +1778,7 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||||||
private static Window getBestNonModalParent(DialogComponentProvider newProvider,
|
private static Window getBestNonModalParent(DialogComponentProvider newProvider,
|
||||||
Window bestParent) {
|
Window bestParent) {
|
||||||
|
|
||||||
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
Window activeWindow = getJavaActiveWindow();
|
||||||
Window activeWindow = kfm.getActiveWindow();
|
|
||||||
if (!(activeWindow instanceof DockingDialog)) {
|
if (!(activeWindow instanceof DockingDialog)) {
|
||||||
return bestParent;
|
return bestParent;
|
||||||
}
|
}
|
||||||
@@ -1937,13 +1939,19 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||||||
|
|
||||||
private static Window getJavaActiveWindow() {
|
private static Window getJavaActiveWindow() {
|
||||||
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
||||||
return kfm.getActiveWindow();
|
Window activeWindow = kfm.getActiveWindow();
|
||||||
|
if (activeWindow == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!activeWindow.isShowing()) {
|
||||||
|
return null; // don't let non-showing windows be considered active
|
||||||
|
}
|
||||||
|
return activeWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Window getActiveNonTransientWindow() {
|
private static Window getActiveNonTransientWindow() {
|
||||||
|
|
||||||
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
Window bestWindow = getJavaActiveWindow();
|
||||||
Window bestWindow = kfm.getActiveWindow();
|
|
||||||
if (bestWindow instanceof DockingDialog) {
|
if (bestWindow instanceof DockingDialog) {
|
||||||
// We do not want Task Dialogs becoming parents, as they will get closed when the
|
// We do not want Task Dialogs becoming parents, as they will get closed when the
|
||||||
// task is finished, closing any other child dialogs, which means that dialogs such
|
// task is finished, closing any other child dialogs, which means that dialogs such
|
||||||
@@ -2172,6 +2180,34 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder
|
|||||||
objectUnderMouse = null;
|
objectUnderMouse = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows a popup menu over the given component. If this given component is not part of the
|
||||||
|
* docking windows hierarchy, then no action is taken.
|
||||||
|
*
|
||||||
|
* @param component the component
|
||||||
|
*/
|
||||||
|
public static void showContextMenu(Component component) {
|
||||||
|
|
||||||
|
DockingWindowManager dwm = getInstance(component);
|
||||||
|
if (dwm == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DockableComponent dockableComponent = dwm.getDockableComponent(component);
|
||||||
|
if (dockableComponent == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle bounds = dockableComponent.getBounds();
|
||||||
|
|
||||||
|
bounds.x = 0;
|
||||||
|
bounds.y = 0;
|
||||||
|
int x = (int) bounds.getCenterX();
|
||||||
|
int y = (int) bounds.getCenterY();
|
||||||
|
PopupMenuContext popupContext = new PopupMenuContext(dockableComponent, new Point(x, y));
|
||||||
|
dockableComponent.showContextMenu(popupContext);
|
||||||
|
}
|
||||||
|
|
||||||
public void contextChanged(ComponentProvider provider) {
|
public void contextChanged(ComponentProvider provider) {
|
||||||
|
|
||||||
if (provider == null) {
|
if (provider == null) {
|
||||||
|
|||||||
@@ -149,7 +149,8 @@ public class ErrLogDialog extends AbstractErrDialog {
|
|||||||
introPanel.add(
|
introPanel.add(
|
||||||
new GIconLabel(UIManager.getIcon("OptionPane.errorIcon"), SwingConstants.RIGHT),
|
new GIconLabel(UIManager.getIcon("OptionPane.errorIcon"), SwingConstants.RIGHT),
|
||||||
BorderLayout.WEST);
|
BorderLayout.WEST);
|
||||||
introPanel.add(new GHtmlLabel(HTMLUtilities.toHTML(message)) {
|
String html = HTMLUtilities.toHTML(message);
|
||||||
|
introPanel.add(new GHtmlLabel(html) {
|
||||||
@Override
|
@Override
|
||||||
public Dimension getPreferredSize() {
|
public Dimension getPreferredSize() {
|
||||||
// rendering HTML the label can expand larger than the screen; keep it reasonable
|
// rendering HTML the label can expand larger than the screen; keep it reasonable
|
||||||
@@ -387,6 +388,16 @@ public class ErrLogDialog extends AbstractErrDialog {
|
|||||||
textDetails.scrollToBottom();
|
textDetails.scrollToBottom();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
Dimension size = super.getPreferredSize();
|
||||||
|
|
||||||
|
// Cap preferred width to something reasonable; most displays have more than 1000 width.
|
||||||
|
// Users can still resize as desired
|
||||||
|
size.width = Math.min(size.width, 1000);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
void setError(ErrorEntry e) {
|
void setError(ErrorEntry e) {
|
||||||
error = e;
|
error = e;
|
||||||
setExceptionMessage(e.getDetailsText());
|
setExceptionMessage(e.getDetailsText());
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
package docking;
|
package docking;
|
||||||
|
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
|
import java.awt.Point;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
@@ -67,28 +68,27 @@ public class PopupActionManager implements PropertyChangeListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void popupMenu(ComponentPlaceholder info, MouseEvent e) {
|
void popupMenu(ComponentPlaceholder placeholder, PopupMenuContext popupContext) {
|
||||||
|
|
||||||
if (e.isConsumed()) {
|
MouseEvent event = popupContext.getEvent();
|
||||||
return;
|
ComponentProvider popupProvider = placeholder.getProvider();
|
||||||
}
|
ActionContext actionContext = popupProvider.getActionContext(event);
|
||||||
ComponentProvider popupProvider = info.getProvider();
|
|
||||||
ActionContext actionContext = popupProvider.getActionContext(e);
|
|
||||||
if (actionContext == null) {
|
if (actionContext == null) {
|
||||||
actionContext = new ActionContext();
|
actionContext = new ActionContext();
|
||||||
}
|
}
|
||||||
|
|
||||||
actionContext.setSourceObject(e.getSource());
|
actionContext.setSourceObject(popupContext.getSource());
|
||||||
actionContext.setMouseEvent(e);
|
actionContext.setMouseEvent(event);
|
||||||
|
|
||||||
Iterator<DockingActionIf> localActions = info.getActions();
|
Iterator<DockingActionIf> localActions = placeholder.getActions();
|
||||||
JPopupMenu popupMenu = createPopupMenu(localActions, actionContext);
|
JPopupMenu popupMenu = createPopupMenu(localActions, actionContext);
|
||||||
if (popupMenu == null) {
|
if (popupMenu == null) {
|
||||||
return; // no matching actions
|
return; // no matching actions
|
||||||
}
|
}
|
||||||
|
|
||||||
Component c = (Component) e.getSource();
|
Component c = popupContext.getComponent();
|
||||||
popupMenu.show(c, e.getX(), e.getY());
|
Point p = popupContext.getPoint();
|
||||||
|
popupMenu.show(c, p.x, p.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected JPopupMenu createPopupMenu(Iterator<DockingActionIf> localActions,
|
protected JPopupMenu createPopupMenu(Iterator<DockingActionIf> localActions,
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/* ###
|
||||||
|
* 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 docking;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that holds information used to show a popup menu
|
||||||
|
*/
|
||||||
|
public class PopupMenuContext {
|
||||||
|
|
||||||
|
private Component component;
|
||||||
|
private MouseEvent event;
|
||||||
|
private Point point;
|
||||||
|
|
||||||
|
PopupMenuContext(MouseEvent event) {
|
||||||
|
this.event = event;
|
||||||
|
this.component = Objects.requireNonNull(event.getComponent());
|
||||||
|
this.point = event.getPoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
PopupMenuContext(Component component, Point point) {
|
||||||
|
this.component = Objects.requireNonNull(component);
|
||||||
|
this.point = point;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MouseEvent getEvent() {
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Component getComponent() {
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Point getPoint() {
|
||||||
|
return new Point(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getSource() {
|
||||||
|
if (event != null) {
|
||||||
|
return event.getSource();
|
||||||
|
}
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,8 +17,7 @@ package docking.action;
|
|||||||
|
|
||||||
import java.beans.PropertyChangeEvent;
|
import java.beans.PropertyChangeEvent;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
@@ -61,6 +60,7 @@ public class KeyBindingsManager implements PropertyChangeListener {
|
|||||||
|
|
||||||
public void addReservedAction(DockingActionIf action) {
|
public void addReservedAction(DockingActionIf action) {
|
||||||
KeyStroke keyBinding = action.getKeyBinding();
|
KeyStroke keyBinding = action.getKeyBinding();
|
||||||
|
Objects.requireNonNull(keyBinding);
|
||||||
addReservedKeyBinding(action, keyBinding);
|
addReservedKeyBinding(action, keyBinding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,52 @@
|
|||||||
|
/* ###
|
||||||
|
* 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 docking.action;
|
||||||
|
|
||||||
|
import java.awt.*;
|
||||||
|
|
||||||
|
import javax.swing.KeyStroke;
|
||||||
|
|
||||||
|
import docking.ActionContext;
|
||||||
|
import docking.DockingWindowManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An action to trigger a context menu over the focus owner. This allows context menus to be
|
||||||
|
* triggered from the keyboard.
|
||||||
|
*/
|
||||||
|
public class ShowContextMenuAction extends DockingAction {
|
||||||
|
|
||||||
|
public ShowContextMenuAction(KeyStroke keyStroke) {
|
||||||
|
super("Show Context Menu", DockingWindowManager.DOCKING_WINDOWS_OWNER);
|
||||||
|
setKeyBindingData(new KeyBindingData(keyStroke));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionContext context) {
|
||||||
|
|
||||||
|
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
|
||||||
|
Window window = kfm.getActiveWindow();
|
||||||
|
if (window == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// use the focused component to determine what should get the context menu
|
||||||
|
Component focusOwner = kfm.getFocusOwner();
|
||||||
|
if (focusOwner != null) {
|
||||||
|
DockingWindowManager.showContextMenu(focusOwner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -91,6 +91,10 @@ public class ToolActions implements DockingToolActions, PropertyChangeListener {
|
|||||||
keyBindingsManager.addReservedAction(new HelpAction(false, ReservedKeyBindings.HELP_KEY2));
|
keyBindingsManager.addReservedAction(new HelpAction(false, ReservedKeyBindings.HELP_KEY2));
|
||||||
keyBindingsManager.addReservedAction(
|
keyBindingsManager.addReservedAction(
|
||||||
new HelpAction(true, ReservedKeyBindings.HELP_INFO_KEY));
|
new HelpAction(true, ReservedKeyBindings.HELP_INFO_KEY));
|
||||||
|
keyBindingsManager.addReservedAction(
|
||||||
|
new ShowContextMenuAction(ReservedKeyBindings.CONTEXT_MENU_KEY1));
|
||||||
|
keyBindingsManager.addReservedAction(
|
||||||
|
new ShowContextMenuAction(ReservedKeyBindings.CONTEXT_MENU_KEY2));
|
||||||
|
|
||||||
// these are diagnostic
|
// these are diagnostic
|
||||||
if (SystemUtilities.isInDevelopmentMode()) {
|
if (SystemUtilities.isInDevelopmentMode()) {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -26,9 +25,8 @@ import javax.swing.plaf.MenuItemUI;
|
|||||||
|
|
||||||
public class DockingCheckboxMenuItemUI extends DockingMenuItemUI {
|
public class DockingCheckboxMenuItemUI extends DockingMenuItemUI {
|
||||||
public static ComponentUI createUI(JComponent c) {
|
public static ComponentUI createUI(JComponent c) {
|
||||||
LookAndFeel underlying = UIManager.getLookAndFeel();
|
|
||||||
DockingCheckboxMenuItemUI result = new DockingCheckboxMenuItemUI();
|
DockingCheckboxMenuItemUI result = new DockingCheckboxMenuItemUI();
|
||||||
result.ui = (MenuItemUI) underlying.getDefaults().getUI(c);
|
result.ui = (MenuItemUI) UIManager.getDefaults().getUI(c);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,9 +58,8 @@ public class DockingMenuItemUI extends MenuItemUI {
|
|||||||
protected MenuItemUI ui;
|
protected MenuItemUI ui;
|
||||||
|
|
||||||
public static ComponentUI createUI(JComponent c) {
|
public static ComponentUI createUI(JComponent c) {
|
||||||
LookAndFeel underlying = UIManager.getLookAndFeel();
|
|
||||||
DockingMenuItemUI result = new DockingMenuItemUI();
|
DockingMenuItemUI result = new DockingMenuItemUI();
|
||||||
result.ui = (MenuItemUI) underlying.getDefaults().getUI(c);
|
result.ui = (MenuItemUI) UIManager.getDefaults().getUI(c);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -22,9 +21,8 @@ import javax.swing.plaf.MenuItemUI;
|
|||||||
|
|
||||||
public class DockingMenuUI extends DockingMenuItemUI {
|
public class DockingMenuUI extends DockingMenuItemUI {
|
||||||
public static ComponentUI createUI(JComponent c) {
|
public static ComponentUI createUI(JComponent c) {
|
||||||
LookAndFeel underlying = UIManager.getLookAndFeel();
|
|
||||||
DockingMenuUI result = new DockingMenuUI();
|
DockingMenuUI result = new DockingMenuUI();
|
||||||
result.ui = (MenuItemUI) underlying.getDefaults().getUI(c);
|
result.ui = (MenuItemUI) UIManager.getDefaults().getUI(c);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2017,7 +2017,7 @@ public abstract class AbstractDockingTest extends AbstractGenericTest {
|
|||||||
// ThreadedTableModelUpdateMgr<ROW_OBJECT>
|
// ThreadedTableModelUpdateMgr<ROW_OBJECT>
|
||||||
Object updateManager = getInstanceField("updateManager", model);
|
Object updateManager = getInstanceField("updateManager", model);
|
||||||
SwingUpdateManager sum =
|
SwingUpdateManager sum =
|
||||||
(SwingUpdateManager) getInstanceField("updateManager", updateManager);
|
(SwingUpdateManager) getInstanceField("addRemoveUpdater", updateManager);
|
||||||
Worker worker = (Worker) getInstanceField("worker", model);
|
Worker worker = (Worker) getInstanceField("worker", model);
|
||||||
String workerState = worker == null ? "<no worker>" : Boolean.toString(worker.isBusy());
|
String workerState = worker == null ? "<no worker>" : Boolean.toString(worker.isBusy());
|
||||||
return "Table model busy state - Swing Update Manager? " + sum.isBusy() + "; worker?" +
|
return "Table model busy state - Swing Update Manager? " + sum.isBusy() + "; worker?" +
|
||||||
|
|||||||
+7
-8
@@ -60,16 +60,15 @@ public class GTreeStartEditingTask extends GTreeTask {
|
|||||||
|
|
||||||
private void edit() {
|
private void edit() {
|
||||||
|
|
||||||
|
if (tree.isFiltered()) {
|
||||||
|
Msg.showWarn(getClass(), tree, "Cannot Edit Tree Node",
|
||||||
|
"Can't edit tree node \"" + childName + "\" while tree is filtered.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GTreeNode editNode = parent.getChild(childName);
|
GTreeNode editNode = parent.getChild(childName);
|
||||||
if (editNode == null) {
|
if (editNode == null) {
|
||||||
if (tree.isFiltered()) {
|
Msg.debug(this, "Can't find node \"" + childName + "\" to edit.");
|
||||||
Msg.showWarn(getClass(), tree, "Cannot Edit Tree Node",
|
|
||||||
"Can't edit tree node \"" + childName + "\" while tree is filtered.");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Msg.debug(this,
|
|
||||||
"Can't find node \"" + childName + "\" to edit.");
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-3
@@ -204,7 +204,7 @@ public class DockingWindowsLookAndFeelUtils {
|
|||||||
case NIMBUS_LOOK_AND_FEEL:
|
case NIMBUS_LOOK_AND_FEEL:
|
||||||
// fix scroll bar grabber disappearing. See https://bugs.openjdk.java.net/browse/JDK-8134828
|
// fix scroll bar grabber disappearing. See https://bugs.openjdk.java.net/browse/JDK-8134828
|
||||||
// This fix looks like it should not cause harm even if the bug is fixed on the jdk side.
|
// This fix looks like it should not cause harm even if the bug is fixed on the jdk side.
|
||||||
UIDefaults defaults = lookAndFeel.getDefaults();
|
UIDefaults defaults = UIManager.getDefaults();
|
||||||
defaults.put("ScrollBar.minimumThumbSize", new Dimension(30, 30));
|
defaults.put("ScrollBar.minimumThumbSize", new Dimension(30, 30));
|
||||||
|
|
||||||
// (see NimbusDefaults for key values that can be changed here)
|
// (see NimbusDefaults for key values that can be changed here)
|
||||||
@@ -277,8 +277,7 @@ public class DockingWindowsLookAndFeelUtils {
|
|||||||
|
|
||||||
/** Allows you to globally set the font size (don't use this method!) */
|
/** Allows you to globally set the font size (don't use this method!) */
|
||||||
private static void setGlobalFontSizeOverride(int fontSize) {
|
private static void setGlobalFontSizeOverride(int fontSize) {
|
||||||
LookAndFeel lookAndFeel = UIManager.getLookAndFeel();
|
UIDefaults defaults = UIManager.getDefaults();
|
||||||
UIDefaults defaults = lookAndFeel.getDefaults();
|
|
||||||
|
|
||||||
Set<Entry<Object, Object>> set = defaults.entrySet();
|
Set<Entry<Object, Object>> set = defaults.entrySet();
|
||||||
Iterator<Entry<Object, Object>> iterator = set.iterator();
|
Iterator<Entry<Object, Object>> iterator = set.iterator();
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
/* ###
|
/* ###
|
||||||
* IP: GHIDRA
|
* IP: GHIDRA
|
||||||
* REVIEWED: YES
|
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -34,6 +33,11 @@ public class ReservedKeyBindings {
|
|||||||
public static final KeyStroke HELP_INFO_KEY =
|
public static final KeyStroke HELP_INFO_KEY =
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_F1, DockingUtils.CONTROL_KEY_MODIFIER_MASK);
|
KeyStroke.getKeyStroke(KeyEvent.VK_F1, DockingUtils.CONTROL_KEY_MODIFIER_MASK);
|
||||||
|
|
||||||
|
public static final KeyStroke CONTEXT_MENU_KEY1 =
|
||||||
|
KeyStroke.getKeyStroke(KeyEvent.VK_F10, InputEvent.SHIFT_DOWN_MASK);
|
||||||
|
public static final KeyStroke CONTEXT_MENU_KEY2 =
|
||||||
|
KeyStroke.getKeyStroke(KeyEvent.VK_CONTEXT_MENU, 0);
|
||||||
|
|
||||||
public static final KeyStroke FOCUS_INFO_KEY =
|
public static final KeyStroke FOCUS_INFO_KEY =
|
||||||
KeyStroke.getKeyStroke(KeyEvent.VK_F2, DockingUtils.CONTROL_KEY_MODIFIER_MASK |
|
KeyStroke.getKeyStroke(KeyEvent.VK_F2, DockingUtils.CONTROL_KEY_MODIFIER_MASK |
|
||||||
InputEvent.ALT_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK);
|
InputEvent.ALT_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK);
|
||||||
@@ -50,7 +54,8 @@ public class ReservedKeyBindings {
|
|||||||
code == KeyEvent.VK_CAPS_LOCK || code == KeyEvent.VK_TAB ||
|
code == KeyEvent.VK_CAPS_LOCK || code == KeyEvent.VK_TAB ||
|
||||||
HELP_KEY1.equals(keyStroke) || HELP_KEY2.equals(keyStroke) ||
|
HELP_KEY1.equals(keyStroke) || HELP_KEY2.equals(keyStroke) ||
|
||||||
HELP_INFO_KEY.equals(keyStroke) || UPDATE_KEY_BINDINGS_KEY.equals(keyStroke) ||
|
HELP_INFO_KEY.equals(keyStroke) || UPDATE_KEY_BINDINGS_KEY.equals(keyStroke) ||
|
||||||
FOCUS_INFO_KEY.equals(keyStroke) || FOCUS_CYCLE_INFO_KEY.equals(keyStroke)) {
|
FOCUS_INFO_KEY.equals(keyStroke) || FOCUS_CYCLE_INFO_KEY.equals(keyStroke) ||
|
||||||
|
CONTEXT_MENU_KEY1.equals(keyStroke) || CONTEXT_MENU_KEY2.equals(keyStroke)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ public class TaskMonitorComponent extends JPanel implements TaskMonitor {
|
|||||||
shouldCancelRunnable = () -> {
|
shouldCancelRunnable = () -> {
|
||||||
int currentTaskID = taskID.get();
|
int currentTaskID = taskID.get();
|
||||||
|
|
||||||
boolean userSaysYes = OptionDialog.showYesNoDialog(TaskMonitorComponent.this, "Cancel?",
|
boolean userSaysYes = OptionDialog.showYesNoDialog(null, "Cancel?",
|
||||||
"Do you really want to cancel " + getTaskName() + "?") == OptionDialog.OPTION_ONE;
|
"Do you really want to cancel " + getTaskName() + "?") == OptionDialog.OPTION_ONE;
|
||||||
|
|
||||||
if (userSaysYes && currentTaskID == taskID.get()) {
|
if (userSaysYes && currentTaskID == taskID.get()) {
|
||||||
|
|||||||
+34
-73
@@ -30,71 +30,43 @@ import docking.*;
|
|||||||
import docking.test.AbstractDockingTest;
|
import docking.test.AbstractDockingTest;
|
||||||
import docking.widgets.PasswordDialog;
|
import docking.widgets.PasswordDialog;
|
||||||
import generic.test.category.NightlyCategory;
|
import generic.test.category.NightlyCategory;
|
||||||
import ghidra.util.Msg;
|
|
||||||
|
|
||||||
// The splash screen is sensitive to windows being activated/deactivated, so don't run
|
// The splash screen is sensitive to windows being activated/deactivated, so don't run
|
||||||
// when other test windows may be open
|
// when other test windows may be open
|
||||||
@Category(NightlyCategory.class)
|
@Category(NightlyCategory.class)
|
||||||
public class SplashScreenTest extends AbstractDockingTest {
|
public class SplashScreenTest extends AbstractDockingTest {
|
||||||
|
|
||||||
private AboutDialog aboutDialog;
|
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void tearDown() {
|
public void tearDown() {
|
||||||
Msg.debug(this, "tearDown() - open windows before closing");
|
|
||||||
printOpenWindows();
|
|
||||||
|
|
||||||
runSwing(() -> SplashScreen.disposeSplashScreen());
|
runSwing(() -> SplashScreen.disposeSplashScreen());
|
||||||
|
disposeAllWindows();
|
||||||
closeAllWindows();
|
|
||||||
printOpenWindows();
|
|
||||||
|
|
||||||
Msg.debug(this, "tearDown() - open windows after closing");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
private void disposeAllWindows() {
|
||||||
public void testShowInfoWindow() throws Exception {
|
for (Window window : getAllWindows()) {
|
||||||
// no parent
|
runSwing(window::dispose);
|
||||||
showModalInfoWindow(null);
|
}
|
||||||
|
|
||||||
ensureInfoWindowVisible();
|
|
||||||
hideInfoWindow();
|
|
||||||
|
|
||||||
// not visible parent
|
|
||||||
JFrame parentFrame = new JFrame("InfoWindowTest.testShowInfoWindow Frame");
|
|
||||||
parentFrame.setBounds(-100, -100, 0, 0);
|
|
||||||
showModalInfoWindow(parentFrame);
|
|
||||||
|
|
||||||
ensureInfoWindowVisible();
|
|
||||||
hideInfoWindow();
|
|
||||||
|
|
||||||
// visible parent
|
|
||||||
parentFrame.setVisible(true);
|
|
||||||
showModalInfoWindow(parentFrame);
|
|
||||||
|
|
||||||
ensureInfoWindowVisible();
|
|
||||||
hideInfoWindow();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testShowAndHideSplashScreen() {
|
public void testShowAndHideSplashScreen() {
|
||||||
showSplashScreen(true);
|
showSplashScreen(true);
|
||||||
ensureSpashScreenVisible(true);
|
assertSpashScreenVisible(true);
|
||||||
|
|
||||||
showSplashScreen(false);
|
showSplashScreen(false);
|
||||||
ensureSpashScreenVisible(false);
|
assertSpashScreenVisible(false);
|
||||||
|
|
||||||
showSplashScreen(true);
|
showSplashScreen(true);
|
||||||
ensureSpashScreenVisible(true);
|
assertSpashScreenVisible(true);
|
||||||
|
|
||||||
showSplashScreen(false);
|
showSplashScreen(false);
|
||||||
ensureSpashScreenVisible(false);
|
assertSpashScreenVisible(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateSplashScreenStatus() {
|
public void testUpdateSplashScreenStatus() {
|
||||||
showSplashScreen(true);
|
showSplashScreen(true);
|
||||||
ensureSpashScreenVisible(true);
|
assertSpashScreenVisible(true);
|
||||||
|
|
||||||
JLabel statusLabel = (JLabel) getInstanceField("statusLabel", SplashScreen.class);
|
JLabel statusLabel = (JLabel) getInstanceField("statusLabel", SplashScreen.class);
|
||||||
|
|
||||||
@@ -120,24 +92,24 @@ public class SplashScreenTest extends AbstractDockingTest {
|
|||||||
public void testSplashScreenPasswordModality_SharedParent() throws Exception {
|
public void testSplashScreenPasswordModality_SharedParent() throws Exception {
|
||||||
|
|
||||||
showSplashScreen(true);
|
showSplashScreen(true);
|
||||||
ensureSpashScreenVisible(true);
|
assertSpashScreenVisible(true);
|
||||||
|
|
||||||
// show a modal dialog with no parent (this will use the Splash Screen's parent)
|
// show a modal dialog with no parent (this will use the Splash Screen's parent)
|
||||||
showModalPasswordDialog(null);
|
showModalPasswordDialog(null);
|
||||||
|
|
||||||
// When the splash screen and the dialog share a parent, then the dialog should NOT
|
// When the splash screen and the dialog share a parent, then the dialog should NOT
|
||||||
// cause the splash screen to go away
|
// cause the splash screen to go away
|
||||||
ensureSpashScreenVisible(true);
|
assertSpashScreenVisible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSplashScreenPasswordModality_UnsharedParent() throws Exception {
|
public void testSplashScreenPasswordModality_UnsharedParent() throws Exception {
|
||||||
// show the splash screen
|
// show the splash screen
|
||||||
showSplashScreen(true);
|
showSplashScreen(true);
|
||||||
ensureSpashScreenVisible(true);
|
assertSpashScreenVisible(true);
|
||||||
|
|
||||||
DockingFrame frame = new DockingFrame("Modal Parent Frame");
|
DockingFrame frame = new DockingFrame("Modal Parent Frame");
|
||||||
frame.setVisible(true);
|
show(frame);
|
||||||
showModalPasswordDialog(frame);
|
showModalPasswordDialog(frame);
|
||||||
|
|
||||||
ensureSplashScreenWillClose();
|
ensureSplashScreenWillClose();
|
||||||
@@ -147,6 +119,10 @@ public class SplashScreenTest extends AbstractDockingTest {
|
|||||||
// Private Methods
|
// Private Methods
|
||||||
//==================================================================================================
|
//==================================================================================================
|
||||||
|
|
||||||
|
private void show(JFrame frame) {
|
||||||
|
runSwing(() -> frame.setVisible(true));
|
||||||
|
}
|
||||||
|
|
||||||
private void ensureSplashScreenWillClose() {
|
private void ensureSplashScreenWillClose() {
|
||||||
waitForCondition(() -> {
|
waitForCondition(() -> {
|
||||||
SplashScreen splash = getSplash();
|
SplashScreen splash = getSplash();
|
||||||
@@ -155,42 +131,44 @@ public class SplashScreenTest extends AbstractDockingTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private DockingDialog showModalPasswordDialog(Frame parentFrame) throws Exception {
|
private DockingDialog showModalPasswordDialog(Frame parentFrame) throws Exception {
|
||||||
|
|
||||||
String dialogTitle = "InfoWindowTest.testSplashScreenPasswordModality() Dialog";
|
String dialogTitle = "InfoWindowTest.testSplashScreenPasswordModality() Dialog";
|
||||||
DialogComponentProvider passwordDialog = runSwing(() -> new PasswordDialog(dialogTitle,
|
DialogComponentProvider passwordDialog = runSwing(() -> new PasswordDialog(dialogTitle,
|
||||||
"Server Type", "Server Name", "Prompt", null, null));
|
"Server Type", "Server Name", "Prompt", null, null));
|
||||||
|
|
||||||
|
if (parentFrame == null) {
|
||||||
|
// null means to share the parent
|
||||||
|
Object splashParent = getInstanceField("hiddenFrame", SplashScreen.class);
|
||||||
|
parentFrame = (Frame) splashParent;
|
||||||
|
}
|
||||||
|
|
||||||
|
Frame finalParent = parentFrame;
|
||||||
executeOnSwingWithoutBlocking(
|
executeOnSwingWithoutBlocking(
|
||||||
() -> DockingWindowManager.showDialog(parentFrame, passwordDialog));
|
() -> {
|
||||||
|
DockingDialog dialog =
|
||||||
|
DockingDialog.createDialog(finalParent, passwordDialog, finalParent);
|
||||||
|
dialog.setVisible(true);
|
||||||
|
});
|
||||||
|
|
||||||
JDialog dialog = waitForJDialog(dialogTitle);
|
JDialog dialog = waitForJDialog(dialogTitle);
|
||||||
assertNotNull(dialog);
|
assertNotNull(dialog);
|
||||||
|
|
||||||
Window dialogWindow = SwingUtilities.windowForComponent(dialog);
|
|
||||||
Msg.debug(this, "Created modal dialog with parent: " + getTitleForWindow(dialogWindow) +
|
|
||||||
" - id: " + System.identityHashCode(dialogWindow));
|
|
||||||
|
|
||||||
return (DockingDialog) dialog;
|
return (DockingDialog) dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
// handles showing the modal info window, which must be done from a thread outside of the
|
|
||||||
// test thread
|
|
||||||
private void showModalInfoWindow(final JFrame parentFrame) {
|
|
||||||
// create a thread to show the modal dialog so that the current thread doesn't block
|
|
||||||
aboutDialog = runSwing(() -> new AboutDialog());
|
|
||||||
executeOnSwingWithoutBlocking(() -> DockingWindowManager.showDialog(null, aboutDialog));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showSplashScreen(final boolean makeVisible) {
|
private void showSplashScreen(final boolean makeVisible) {
|
||||||
|
|
||||||
if (makeVisible) {
|
if (makeVisible) {
|
||||||
SplashScreen splash = runSwing(() -> SplashScreen.showSplashScreen());
|
SplashScreen splash = runSwing(() -> SplashScreen.showSplashScreen());
|
||||||
assertNotNull("Failed showing splash screen", splash);
|
assertNotNull("Failed showing splash screen", splash);
|
||||||
|
waitForSwing();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SplashScreen.disposeSplashScreen();
|
SplashScreen.disposeSplashScreen();
|
||||||
|
waitForSwing();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ensureSpashScreenVisible(boolean visible) {
|
private void assertSpashScreenVisible(boolean visible) {
|
||||||
// get the 'splashWindow' and make sure that it is not null and that it is visible
|
// get the 'splashWindow' and make sure that it is not null and that it is visible
|
||||||
SplashScreen splashScreen = getSplash();
|
SplashScreen splashScreen = getSplash();
|
||||||
|
|
||||||
@@ -206,23 +184,6 @@ public class SplashScreenTest extends AbstractDockingTest {
|
|||||||
|
|
||||||
// timing issue debug
|
// timing issue debug
|
||||||
waitForCondition(() -> splashScreen.isVisible());
|
waitForCondition(() -> splashScreen.isVisible());
|
||||||
|
|
||||||
if (!splashScreen.isVisible()) {
|
|
||||||
|
|
||||||
// this can happen if other OS windows trigger the splash window to be hidden
|
|
||||||
printOpenWindows();
|
|
||||||
fail("The splash screen is not visible when expected to be so - " + splashScreen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ensureInfoWindowVisible() {
|
|
||||||
// get the 'infoDialog' and make sure that it is not null and that it is visible
|
|
||||||
assertTrue("The info dialog is not visible after it was supposed to " + "have been shown.",
|
|
||||||
aboutDialog.isVisible());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void hideInfoWindow() throws Exception {
|
|
||||||
runSwing(() -> aboutDialog.close());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private SplashScreen getSplash() {
|
private SplashScreen getSplash() {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package ghidra.graph.viewer.popup;
|
package ghidra.graph.viewer.popup;
|
||||||
|
|
||||||
|
import java.awt.Component;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.awt.event.*;
|
import java.awt.event.*;
|
||||||
|
|
||||||
@@ -129,6 +130,13 @@ public class PopupRegulator<V, E> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Component c = event.getComponent();
|
||||||
|
if (!c.isShowing()) {
|
||||||
|
// This method is called from a a timer. It is possible that the graph has been
|
||||||
|
// closed by the time this method is called.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
ToolTipInfo<?> toolTipInfo = popupSource.getToolTipInfo(event);
|
ToolTipInfo<?> toolTipInfo = popupSource.getToolTipInfo(event);
|
||||||
JComponent toolTipComponent = toolTipInfo.getToolTipComponent();
|
JComponent toolTipComponent = toolTipInfo.getToolTipComponent();
|
||||||
boolean isCustomJavaTooltip = !(toolTipComponent instanceof JToolTip);
|
boolean isCustomJavaTooltip = !(toolTipComponent instanceof JToolTip);
|
||||||
|
|||||||
+1
-1
@@ -61,7 +61,7 @@ public interface PcodeFactory {
|
|||||||
public HighSymbol getSymbol(long symbolId);
|
public HighSymbol getSymbol(long symbolId);
|
||||||
public Varnode setInput(Varnode vn,boolean val);
|
public Varnode setInput(Varnode vn,boolean val);
|
||||||
public void setAddrTied(Varnode vn,boolean val);
|
public void setAddrTied(Varnode vn,boolean val);
|
||||||
public void setPersistant(Varnode vn,boolean val);
|
public void setPersistent(Varnode vn, boolean val);
|
||||||
public void setUnaffected(Varnode vn,boolean val);
|
public void setUnaffected(Varnode vn,boolean val);
|
||||||
public void setMergeGroup(Varnode vn,short val);
|
public void setMergeGroup(Varnode vn,short val);
|
||||||
public void setDataType(Varnode vn,DataType type);
|
public void setDataType(Varnode vn,DataType type);
|
||||||
|
|||||||
+2
-2
@@ -392,9 +392,9 @@ public class PcodeSyntaxTree implements PcodeFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPersistant(Varnode vn, boolean val) {
|
public void setPersistent(Varnode vn, boolean val) {
|
||||||
VarnodeAST vnast = (VarnodeAST) vn;
|
VarnodeAST vnast = (VarnodeAST) vn;
|
||||||
vnast.setPersistant(val);
|
vnast.setPersistent(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+3
-3
@@ -255,9 +255,9 @@ public class Varnode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return is persistant
|
* @return is persistent
|
||||||
*/
|
*/
|
||||||
public boolean isPersistant() {
|
public boolean isPersistent() {
|
||||||
return false; // Not a valid query with a free varnode
|
return false; // Not a valid query with a free varnode
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -476,7 +476,7 @@ public class Varnode {
|
|||||||
}
|
}
|
||||||
attrstring = el.getAttribute("persists");
|
attrstring = el.getAttribute("persists");
|
||||||
if ((attrstring != null) && (SpecXmlUtils.decodeBoolean(attrstring))) {
|
if ((attrstring != null) && (SpecXmlUtils.decodeBoolean(attrstring))) {
|
||||||
factory.setPersistant(vn, true);
|
factory.setPersistent(vn, true);
|
||||||
}
|
}
|
||||||
attrstring = el.getAttribute("addrtied");
|
attrstring = el.getAttribute("addrtied");
|
||||||
if ((attrstring != null) && (SpecXmlUtils.decodeBoolean(attrstring))) {
|
if ((attrstring != null) && (SpecXmlUtils.decodeBoolean(attrstring))) {
|
||||||
|
|||||||
+6
-6
@@ -37,7 +37,7 @@ public class VarnodeAST extends Varnode {
|
|||||||
|
|
||||||
private boolean bInput;
|
private boolean bInput;
|
||||||
private boolean bAddrTied;
|
private boolean bAddrTied;
|
||||||
private boolean bPersistant;
|
private boolean bPersistent;
|
||||||
private boolean bUnaffected;
|
private boolean bUnaffected;
|
||||||
private boolean bFree;
|
private boolean bFree;
|
||||||
private int uniqId; // Unique Id for distinguishing otherwise identical varnodes
|
private int uniqId; // Unique Id for distinguishing otherwise identical varnodes
|
||||||
@@ -50,7 +50,7 @@ public class VarnodeAST extends Varnode {
|
|||||||
super(a, sz);
|
super(a, sz);
|
||||||
bInput = false;
|
bInput = false;
|
||||||
bAddrTied = false;
|
bAddrTied = false;
|
||||||
bPersistant = false;
|
bPersistent = false;
|
||||||
bUnaffected = false;
|
bUnaffected = false;
|
||||||
bFree = true;
|
bFree = true;
|
||||||
uniqId = id;
|
uniqId = id;
|
||||||
@@ -70,8 +70,8 @@ public class VarnodeAST extends Varnode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isPersistant() {
|
public boolean isPersistent() {
|
||||||
return bPersistant;
|
return bPersistent;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -132,8 +132,8 @@ public class VarnodeAST extends Varnode {
|
|||||||
def = null;
|
def = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setPersistant(boolean val) {
|
public void setPersistent(boolean val) {
|
||||||
bPersistant = val;
|
bPersistent = val;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUnaffected(boolean val) {
|
public void setUnaffected(boolean val) {
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user