mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-30 09:05:31 +08:00
GP-6643 Added ability to order Libraries via an ordinal assignment. This ordered list is now used by external symbol resolver analyzer.
This commit is contained in:
+91
-46
@@ -14,14 +14,36 @@
|
||||
<BODY lang="EN-US">
|
||||
<H1><A name="View_External_Program_Names"></A>External Program Names</H1>
|
||||
|
||||
<P>An external reference is a reference to a location in another program. The reference
|
||||
destination includes the name of some program. To use an external reference to navigate, the
|
||||
external program name must be associated with an existing program file in the Ghidra project.
|
||||
<A name="Resolve"></A>If the association has been defined, then the external reference is said
|
||||
to have been <B><I>resolved</I></B>. The <I>External Programs</I> view manages the associations
|
||||
between external program names and program files. The table shows all external program names
|
||||
and their associated links to program files. Use the <I>External Programs</I> view to add
|
||||
external names, delete external names, set associations, and clear associations.</P>
|
||||
<P>An external location identifies an external function or data dependency
|
||||
associated with a named Library (i.e., External Program). One or more external references may refer to
|
||||
a single external location. Thunk functions within a Program may also refer to an external
|
||||
location if it corresponds to a function. Each Library defined within Ghidra can optionally
|
||||
be associated with another Program file within the Ghidra project. </P>
|
||||
|
||||
<P>There is a reserved
|
||||
Library named <B><EXTERNAL></B> which is a holding area for external locations whose
|
||||
associated Library is unknown (commonly used by ELF Imports).
|
||||
The <B>External Symbol Resolver</B> analyzer can be used to search
|
||||
for these external locations among the ordered list of Libraries which have a Program file association.
|
||||
The ordered Library sequence dictates the order that this analyzer searches through them.</P>
|
||||
|
||||
<P>To navigate on an external reference/location, or resolve external locations, the
|
||||
external Library name must be associated with an existing Program file in the same project.
|
||||
<A name="Resolve"></A>If a Library's Program association has been specified, then any related
|
||||
external reference is said to have been <B><I>resolved</I></B>. </P>
|
||||
|
||||
<P>The <I>External Programs</I> view manages the associations
|
||||
between external Library names and Program files as well as the ordered Library sequence.
|
||||
Use the <I>External Programs</I> view to add/delete external Library names,
|
||||
set/clear Program associations and adjust search order using up/down placement actions.
|
||||
Other than the up/down ordering functionality, the
|
||||
<A href="../SymbolTreePlugin/SymbolTree.htm#Externals">Symbol Tree</A> Imports node provides
|
||||
similar actions plus the ability to navigate.</P>
|
||||
|
||||
<P><I><IMG src="help/shared/note.png" border="0"> The term "External Program" within Ghidra
|
||||
is used interchangeably with the term "Library" and represents a dependency. Each defined
|
||||
Library has a corresponding Library Symbol within a program's symbol table and may have related
|
||||
external locations.</P>
|
||||
|
||||
<H2><A name="ExternalNamesDialog"></A>External Programs View</H2>
|
||||
|
||||
@@ -29,26 +51,33 @@
|
||||
</P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>The <I>External Programs</I> view consists of a main scrollable list of external program
|
||||
<P>The <I>External Programs</I> view consists of a main scrollable list of external Library
|
||||
names and their associated Ghidra program files.</P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<H3>Name Column</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>The name of the external program. Many external programs will share the same external
|
||||
program name. Setting or changing the associated Ghidra file will affect all the external
|
||||
references to that name. Double-click on this field to edit the name. After you change
|
||||
the name, hit the <Enter> key.</P>
|
||||
<P>The name of the external Library. Many external function and/or data locations will
|
||||
correspond to the same external Library within a Ghidra program which are considered to
|
||||
be Imports.</P>
|
||||
|
||||
<P>The name used within the current program to identify the Library may be
|
||||
changed. To do this, double-click on the Name to enter edit mode. After you change
|
||||
the name, press <Enter> to commit the change.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3>Ghidra Program Column<BR>
|
||||
</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>The Ghidra file associated with the external program name. This field is blank if
|
||||
external reference has not been resolved. Ghidra will not be able to "follow" an external
|
||||
reference if its external program name does not have an associated Ghidra file.</P>
|
||||
<P>The Ghidra program file associated with the external Library name. This field is blank if
|
||||
the external Library has not been resolved. Ghidra will not be able to "follow" an external
|
||||
location reference into a Library, or search for external symbols within a Library,
|
||||
if a Library does not have a Ghidra program file association.</P>
|
||||
|
||||
<P>See <A href="#ChooseExternalProgram">Set External Path Association</A> for changing the
|
||||
path shown.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Add_External_Program_Name"></A>Add Button</H3>
|
||||
@@ -58,14 +87,48 @@
|
||||
for entering a new external program name.<BR>
|
||||
</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Delete_External_Program_Name"></A>Delete External Name Button</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>The <SPAN style="font-weight: bold;">Delete</SPAN> <IMG alt="" src=
|
||||
"images/edit-delete.png"> button deletes the selected external Library names from the
|
||||
program. If a selected external Library name has associated external locations, it can
|
||||
not be deleted. The <SPAN style="font-weight: bold;">Delete</SPAN> button is enabled
|
||||
whenever one or more rows are selected.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Move_Library_Up"></A>Move Library Up Button</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>The <SPAN style="font-weight: bold;">Up</SPAN> <IMG alt="" src=
|
||||
"images/up.png"> button will shift a selected external Library up
|
||||
within the list of Libraries thus increasing its priority when used to
|
||||
search for external symbols. The <SPAN style="font-weight: bold;">Up</SPAN>
|
||||
button is enabled whenever one external program name is selected and can be moved
|
||||
up within the Library list.</P>
|
||||
<P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Move_Library_Down"></A>Move Library Down Button</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>The <SPAN style="font-weight: bold;">Down</SPAN> <IMG alt="" src=
|
||||
"images/down.png"> button will shift a selected external Library down
|
||||
within the list of Libraries thus reducing its priority when used to
|
||||
search for external symbols. The <SPAN style="font-weight: bold;">Down</SPAN>
|
||||
button is enabled whenever one external program name is selected and can be moved
|
||||
down within the Library list.</P>
|
||||
<P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="ChooseExternalProgram"></A><A name="Set_External_Name_Association"></A>Set
|
||||
External Name Association Button</H3>
|
||||
External Path Association Button</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>The <SPAN style="font-weight: bold;">Set</SPAN> <IMG alt="" src=
|
||||
"images/editbytes.gif"> button brings up a <I>Ghidra program chooser</I> dialog. Choose a
|
||||
Ghidra program file to associate it with the selected external program name. This button
|
||||
Ghidra program file to associate it with the selected external Library name. This button
|
||||
is only enabled when a single external program name is selected.</P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
@@ -77,26 +140,13 @@
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<H3><A name="Clear_External_Name_Association"></A>Clear External Name Association
|
||||
<H3><A name="Clear_External_Name_Association"></A>Clear External Path Association
|
||||
Button</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>This <SPAN style="font-weight: bold;">Clear <IMG alt="" src=
|
||||
"images/edit-delete.png"> </SPAN> button clears the assocated program for all the
|
||||
selected external program names.<BR>
|
||||
</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Delete_External_Program_Name"></A>Delete External Name Button</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P>This <SPAN style="font-weight: bold;">Delete</SPAN> <IMG alt="" src=
|
||||
"images/edit-delete.png"> button deletes the selected external program names from the
|
||||
program. If a selected external program name contains external locations, it can
|
||||
not be deleted. The <SPAN style="font-weight: bold;">Delete</SPAN> button is enabled
|
||||
whenever one or more external program names are selected.</P>
|
||||
|
||||
<P><BR>
|
||||
<P>The <SPAN style="font-weight: bold;">Clear <IMG alt="" src=
|
||||
"Icons.CLEAR_ICON"> </SPAN> button clears the associated program path for all the
|
||||
selected rows.<BR>
|
||||
</P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
@@ -115,17 +165,12 @@
|
||||
|
||||
<LI>Enter the new external program name into the pop-up dialog.</LI>
|
||||
|
||||
<LI style="list-style: none">
|
||||
<>
|
||||
<P><I><IMG src="help/shared/note.png" border="0">Any new External Program added
|
||||
will be placed at the bottom of the list. If relying on external symbol resolution
|
||||
analysis and the library search order is important, the new entry may be moved up
|
||||
in the list using the Up button.
|
||||
</I></P>
|
||||
|
||||
<P><I><IMG src="help/shared/note.png" border="0"> If the table is sorted by Name, then
|
||||
the name you enter will be placed at the correct position in the table to maintain the
|
||||
sort order. The sort icon <IMG src="Icons.SORT_ASCENDING_ICON" border="0"> or <IMG
|
||||
src="Icons.SORT_DESCENDING_ICON" border="0"> indicates the order and what column is
|
||||
being sorted. You can also sort by Ghidra Pathname by clicking on the header for this
|
||||
column. Click on the sort icon to change the order.</I></P>
|
||||
</>
|
||||
</LI>
|
||||
</OL>
|
||||
|
||||
<H3>Resolving an External Name to an existing Ghidra program<BR>
|
||||
@@ -157,7 +202,7 @@
|
||||
|
||||
<LI>Click on the external program name that has an association to be cleared.</LI>
|
||||
|
||||
<LI>Press the <B>Clear</B> <IMG alt="" src="images/erase16.png"> button</LI>
|
||||
<LI>Press the <B>Clear</B> <IMG alt="" src="Icons.CLEAR_ICON"> button</LI>
|
||||
</OL>
|
||||
|
||||
<H3>Removing an External Program Name</H3>
|
||||
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 11 KiB |
+21
-12
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -16,37 +16,46 @@
|
||||
package ghidra.app.cmd.refs;
|
||||
|
||||
import ghidra.framework.cmd.Command;
|
||||
import ghidra.program.model.listing.Library;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.program.model.symbol.ExternalManager;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
* Command to remove an external program name from the reference manager.
|
||||
* Command to clear the external program path associated with an external Library.
|
||||
*
|
||||
*/
|
||||
public class ClearExternalNameCmd implements Command<Program> {
|
||||
public class ClearExternalPathCmd implements Command<Program> {
|
||||
|
||||
private String externalName;
|
||||
private String status;
|
||||
private boolean userDefined = true;
|
||||
|
||||
/**
|
||||
* Constructs a new command removing an external program name.
|
||||
* @param externalName the name of the external program name to be removed.
|
||||
* Constructs a new command for clearing the external program path associated with a
|
||||
* specified external Library.
|
||||
* @param externalName external Library name
|
||||
*/
|
||||
public ClearExternalNameCmd(String externalName) {
|
||||
public ClearExternalPathCmd(String externalName) {
|
||||
this.externalName = externalName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyTo(Program program) {
|
||||
try {
|
||||
program.getExternalManager().setExternalPath(externalName, null, userDefined);
|
||||
// Avoid creating the Library if it does not already exist
|
||||
ExternalManager externalManager = program.getExternalManager();
|
||||
Library lib = externalManager.getExternalLibrary(externalName);
|
||||
if (lib != null) {
|
||||
externalManager.setExternalPath(externalName, null, userDefined);
|
||||
return true;
|
||||
}
|
||||
status = "Library not found: " + externalName;
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
throw new AssertException(e);
|
||||
status = e.getMessage();
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -56,7 +65,7 @@ public class ClearExternalNameCmd implements Command<Program> {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Remove External Program Name";
|
||||
return "Clear External Library Path";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -16,7 +16,11 @@
|
||||
package ghidra.app.cmd.refs;
|
||||
|
||||
import ghidra.framework.cmd.Command;
|
||||
import ghidra.program.model.listing.Library;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.ExternalManager;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
/**
|
||||
@@ -26,29 +30,48 @@ public class SetExternalNameCmd implements Command<Program> {
|
||||
|
||||
private String externalName;
|
||||
private String externalPath;
|
||||
private SourceType source;
|
||||
|
||||
private String status;
|
||||
private boolean userDefined = true;
|
||||
|
||||
/**
|
||||
* Constructs a new command for setting the external program name and path.
|
||||
* @param externalName the name of the link.
|
||||
* @param externalPath the path of the file to associate with this link.
|
||||
* Constructs a new command for creating a Library, if it does not exist, and optionally
|
||||
* setting the associated external program path. If created, a {@link SourceType#USER_DEFINED}
|
||||
* source will be specified.
|
||||
* @param externalName the Library name.
|
||||
* @param externalPath the project file path of the program file to associate with the Library.
|
||||
*/
|
||||
public SetExternalNameCmd(String externalName, String externalPath) {
|
||||
this(externalName, externalPath, SourceType.USER_DEFINED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new command for creating a Library, if it does not exist, and optionally
|
||||
* setting the associated external program path.
|
||||
* @param externalName the Library name.
|
||||
* @param externalPath the project file path of the program file to associate with the Library.
|
||||
* @param source the symbol source type to be applied if the library must be created.
|
||||
*/
|
||||
public SetExternalNameCmd(String externalName, String externalPath, SourceType source) {
|
||||
this.externalName = externalName;
|
||||
this.externalPath = externalPath;
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyTo(Program program) {
|
||||
try {
|
||||
program.getExternalManager().setExternalPath(externalName, externalPath, userDefined);
|
||||
ExternalManager externalManager = program.getExternalManager();
|
||||
Library library = externalManager.getExternalLibrary(externalName);
|
||||
if (library == null) {
|
||||
externalManager.addExternalLibraryName(externalName, source);
|
||||
}
|
||||
library.setAssociatedProgramPath(externalPath);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
status = "Invalid name specified";
|
||||
return false;
|
||||
catch (DuplicateNameException | InvalidInputException e) {
|
||||
status = e.getMessage();
|
||||
}
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -58,7 +81,7 @@ public class SetExternalNameCmd implements Command<Program> {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Set External Program Name";
|
||||
return "Set External Library Name and Path";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+36
-14
@@ -26,8 +26,7 @@ import ghidra.app.merge.*;
|
||||
import ghidra.app.merge.util.ConflictUtility;
|
||||
import ghidra.app.util.HelpTopics;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.listing.ProgramChangeSet;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.util.ProgramMerge;
|
||||
import ghidra.program.util.SimpleDiffUtility;
|
||||
@@ -448,20 +447,36 @@ public class ExternalProgramMerger implements MergeResolver, ListingMergeConstan
|
||||
mergeManager.updateProgress(progress,
|
||||
"Merging external program information for " + name + "...");
|
||||
|
||||
String originalPath =
|
||||
(originalName != null) ? originalExtMgr.getExternalLibraryPath(originalName) : null;
|
||||
String latestPath =
|
||||
(latestName != null) ? latestExtMgr.getExternalLibraryPath(latestName) : null;
|
||||
String myPath = (myName != null) ? myExtMgr.getExternalLibraryPath(myName) : null;
|
||||
if (same(latestName, myName) && same(latestPath, myPath)) {
|
||||
Library originalLib =
|
||||
(originalName != null) ? originalExtMgr.getExternalLibrary(originalName) : null;
|
||||
Library latestLib =
|
||||
(latestName != null) ? latestExtMgr.getExternalLibrary(latestName) : null;
|
||||
Library myLib = (myName != null) ? myExtMgr.getExternalLibrary(myName) : null;
|
||||
|
||||
String originalPath = (originalLib != null) ? originalLib.getAssociatedProgramPath() : null;
|
||||
String latestPath = (latestLib != null) ? latestLib.getAssociatedProgramPath() : null;
|
||||
String myPath = (myLib != null) ? myLib.getAssociatedProgramPath() : null;
|
||||
|
||||
int originalOrdinal =
|
||||
originalLib != null ? originalExtMgr.getLibraryOrdinal(originalName) : -1;
|
||||
int latestOrdinal = latestLib != null ? latestExtMgr.getLibraryOrdinal(latestName) : -1;
|
||||
int myOrdinal = myLib != null ? myExtMgr.getLibraryOrdinal(myName) : -1;
|
||||
|
||||
if (same(latestName, myName) && same(latestPath, myPath) && latestOrdinal == myOrdinal) {
|
||||
return;
|
||||
}
|
||||
boolean changedLatestName = !same(originalName, latestName);
|
||||
boolean changedMyName = !same(originalName, myName);
|
||||
boolean changedLatestPath = !same(originalPath, latestPath);
|
||||
boolean changedMyPath = !same(originalPath, myPath);
|
||||
boolean changedLatest = changedLatestName || changedLatestPath;
|
||||
boolean changedMy = changedMyName || changedMyPath;
|
||||
|
||||
// Temper ordinal changes - don't allow them to drive a conflict but try to preserve my change.
|
||||
// Ordinal changes may be lost during any library change conflict resolution.
|
||||
boolean changedMyOrdinal = myLib != null && myOrdinal != originalOrdinal;
|
||||
|
||||
boolean changedLatest = changedLatestName || changedLatestPath; // ignore ordinal change
|
||||
boolean changedMy = changedMyName || changedMyPath || changedMyOrdinal;
|
||||
|
||||
if (changedLatest) {
|
||||
if (changedMy) {
|
||||
// conflict: Ask to keep latest or my
|
||||
@@ -473,7 +488,7 @@ public class ExternalProgramMerger implements MergeResolver, ListingMergeConstan
|
||||
if (resultID != -1 && resultName == null) {
|
||||
resultName = latestName; // Need to create Library symbol in Result program.
|
||||
}
|
||||
autoMergeWhenOnlyLatestChanged(resultName, latestName, latestPath);
|
||||
autoMergeWhenOnlyLatestChanged(resultName, latestName, latestPath, latestOrdinal);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -491,13 +506,13 @@ public class ExternalProgramMerger implements MergeResolver, ListingMergeConstan
|
||||
symbol.getSymbolType());
|
||||
}
|
||||
}
|
||||
autoMergeWhenOnlyMyChanged(resultName, myName, myPath);
|
||||
autoMergeWhenOnlyMyChanged(resultName, myName, myPath, myOrdinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void autoMergeWhenOnlyLatestChanged(String resultName, String latestName,
|
||||
String latestPath) {
|
||||
String latestPath, int latestOrdinal) {
|
||||
if (resultName == null) {
|
||||
// latestName appears to have been discarded during SymbolMerge.
|
||||
return;
|
||||
@@ -509,6 +524,9 @@ public class ExternalProgramMerger implements MergeResolver, ListingMergeConstan
|
||||
else {
|
||||
resultExtMgr.setExternalPath(resultName, latestPath,
|
||||
isExternalUserDefined(latestPgm, latestName));
|
||||
if (latestOrdinal >= 0) {
|
||||
resultExtMgr.setLibraryOrdinal(resultName, latestOrdinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
@@ -516,7 +534,8 @@ public class ExternalProgramMerger implements MergeResolver, ListingMergeConstan
|
||||
}
|
||||
}
|
||||
|
||||
private void autoMergeWhenOnlyMyChanged(String resultName, String myName, String myPath) {
|
||||
private void autoMergeWhenOnlyMyChanged(String resultName, String myName, String myPath,
|
||||
int myOrdinal) {
|
||||
if (resultName == null) {
|
||||
// myName appears to have been discarded during SymbolMerge.
|
||||
return;
|
||||
@@ -528,6 +547,9 @@ public class ExternalProgramMerger implements MergeResolver, ListingMergeConstan
|
||||
else {
|
||||
resultExtMgr.setExternalPath(resultName, myPath,
|
||||
isExternalUserDefined(myPgm, myName));
|
||||
if (myOrdinal >= 0) {
|
||||
resultExtMgr.setLibraryOrdinal(resultName, myOrdinal);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -2463,6 +2463,8 @@ class SymbolMerger extends AbstractListingMerger {
|
||||
ExternalManager srcExtMgr = srcPgm.getExternalManager();
|
||||
String path = srcExtMgr.getExternalLibraryPath(name);
|
||||
|
||||
// NOTE: No attempt is made to preserve library ordinal
|
||||
|
||||
ExternalManagerDB extMgr = (ExternalManagerDB) resultPgm.getExternalManager();
|
||||
extMgr.setExternalPath(name, path, (source == SourceType.USER_DEFINED));
|
||||
symbol = resultSymTab.getLibrarySymbol(name);
|
||||
|
||||
+65
-25
@@ -27,7 +27,7 @@ import docking.ActionContext;
|
||||
import docking.DefaultActionContext;
|
||||
import docking.action.builder.ActionBuilder;
|
||||
import docking.widgets.dialogs.InputDialog;
|
||||
import docking.widgets.table.AbstractSortedTableModel;
|
||||
import docking.widgets.table.AbstractGTableModel;
|
||||
import generic.theme.GIcon;
|
||||
import ghidra.app.cmd.refs.*;
|
||||
import ghidra.framework.cmd.Command;
|
||||
@@ -51,6 +51,8 @@ import resources.Icons;
|
||||
public class ExternalReferencesProvider extends ComponentProviderAdapter {
|
||||
private static Icon ADD_ICON = Icons.ADD_ICON;
|
||||
private static Icon DELETE_ICON = Icons.DELETE_ICON;
|
||||
private static Icon UP_ICON = Icons.UP_ICON;
|
||||
private static Icon DOWN_ICON = Icons.DOWN_ICON;
|
||||
private static Icon EDIT_ICON = new GIcon("icon.base.edit.bytes");
|
||||
private static Icon CLEAR_ICON = Icons.CLEAR_ICON;
|
||||
|
||||
@@ -98,6 +100,22 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
|
||||
.onAction(ac -> deleteExternalProgram())
|
||||
.buildAndInstallLocal(this);
|
||||
|
||||
new ActionBuilder("Move Library Up", getOwner())
|
||||
.popupMenuPath("Move Library Up")
|
||||
.popupMenuIcon(UP_ICON)
|
||||
.toolBarIcon(UP_ICON)
|
||||
.enabledWhen(ac -> canDecrementSelectedLibraryOrdinal())
|
||||
.onAction(ac -> adjustLibraryOrdinal(true))
|
||||
.buildAndInstallLocal(this);
|
||||
|
||||
new ActionBuilder("Move Library Down", getOwner())
|
||||
.popupMenuPath("Move Library Down")
|
||||
.popupMenuIcon(DOWN_ICON)
|
||||
.toolBarIcon(DOWN_ICON)
|
||||
.enabledWhen(ac -> canIncrementSelectedLibraryOrdinal())
|
||||
.onAction(ac -> adjustLibraryOrdinal(false))
|
||||
.buildAndInstallLocal(this);
|
||||
|
||||
new ActionBuilder("Set External Name Association", getOwner())
|
||||
.popupMenuPath("Set External Name Association")
|
||||
.popupMenuIcon(EDIT_ICON)
|
||||
@@ -238,6 +256,48 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
private void adjustLibraryOrdinal(boolean moveUp) {
|
||||
if ((moveUp && !canDecrementSelectedLibraryOrdinal()) ||
|
||||
(!moveUp && !canIncrementSelectedLibraryOrdinal())) {
|
||||
return;
|
||||
}
|
||||
int ordinalAdjustment = moveUp ? -1 : 1;
|
||||
List<String> selectedExternalNames = getSelectedExternalNames();
|
||||
String externalName = selectedExternalNames.get(0); // must be exactly one for us to be enabled.
|
||||
ExternalManager externalManager = program.getExternalManager();
|
||||
Library externalLibrary = externalManager.getExternalLibrary(externalName);
|
||||
if (externalLibrary != null) {
|
||||
program.withTransaction("Adjust Library Order", () -> {
|
||||
int ordinal = externalManager.getLibraryOrdinal(externalName);
|
||||
if (ordinal < 0) {
|
||||
Msg.showError(this, mainPanel, "Library Ordering Change Error",
|
||||
"Failed to update Library ordinal for: " + externalName);
|
||||
return;
|
||||
}
|
||||
externalManager.setLibraryOrdinal(externalName, ordinal + ordinalAdjustment);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canDecrementSelectedLibraryOrdinal() {
|
||||
int[] selectedRows = table.getSelectedRows();
|
||||
if (selectedRows.length == 1 && selectedRows[0] != 0) {
|
||||
ExternalNamesRow rowBefore = tableModel.getRowObject(selectedRows[0] - 1);
|
||||
return !Library.UNKNOWN.equals(rowBefore.getName()); // cannot displace UNKNOWN Library
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean canIncrementSelectedLibraryOrdinal() {
|
||||
int lastRow = table.getRowCount() - 1;
|
||||
int[] selectedRows = table.getSelectedRows();
|
||||
if (selectedRows.length == 1 && selectedRows[0] != lastRow) {
|
||||
ExternalNamesRow row = tableModel.getRowObject(selectedRows[0]);
|
||||
return !Library.UNKNOWN.equals(row.getName()); // cannot alter UNKNOWN Library ordinal
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setExternalProgramAssociation() {
|
||||
List<String> selectedExternalNames = getSelectedExternalNames();
|
||||
String externalName = selectedExternalNames.get(0); // must be exactly one for us to be enabled.
|
||||
@@ -268,7 +328,7 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
|
||||
private void clearExternalAssociation() {
|
||||
CompoundCmd<Program> cmd = new CompoundCmd<>("Clear External Program Associations");
|
||||
for (String externalName : getSelectedExternalNames()) {
|
||||
cmd.add(new ClearExternalNameCmd(externalName));
|
||||
cmd.add(new ClearExternalPathCmd(externalName));
|
||||
}
|
||||
getTool().execute(cmd, program);
|
||||
}
|
||||
@@ -325,7 +385,7 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
|
||||
|
||||
}
|
||||
|
||||
class ExternalNamesTableModel extends AbstractSortedTableModel<ExternalNamesRow> {
|
||||
class ExternalNamesTableModel extends AbstractGTableModel<ExternalNamesRow> {
|
||||
|
||||
final static int NAME_COL = 0;
|
||||
final static int PATH_COL = 1;
|
||||
@@ -336,18 +396,18 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
|
||||
private List<ExternalNamesRow> paths = new ArrayList<>();
|
||||
|
||||
void updateTableData() {
|
||||
|
||||
paths.clear();
|
||||
|
||||
if (program != null && isVisible()) {
|
||||
ExternalManager extMgr = program.getExternalManager();
|
||||
// NOTE: Keep table in ordinal sequence as provided by external manager
|
||||
String[] programNames = extMgr.getExternalLibraryNames();
|
||||
Arrays.sort(programNames);
|
||||
|
||||
for (String programName : programNames) {
|
||||
if (Library.UNKNOWN.equals(programName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ExternalNamesRow path = new ExternalNamesRow(programName,
|
||||
extMgr.getExternalLibraryPath(programName));
|
||||
paths.add(path);
|
||||
@@ -391,11 +451,6 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
|
||||
return "External Programs Model";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSortable(int columnIndex) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||
if (columnIndex == NAME_COL) {
|
||||
@@ -448,21 +503,6 @@ public class ExternalReferencesProvider extends ComponentProviderAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Comparator<ExternalNamesRow> createSortComparator(int columnIndex) {
|
||||
if (columnIndex == PATH_COL) {
|
||||
// force the path column to have a secondary compare using the name column
|
||||
// to ensure a 'stable' sort. Without this during analysis
|
||||
// the constant updates cause the table to sort randomly when
|
||||
// there are lots of empty path values.
|
||||
Comparator<ExternalNamesRow> c1 =
|
||||
(r1, r2) -> Objects.requireNonNullElse(r1.getPath(), "")
|
||||
.compareTo(Objects.requireNonNullElse(r2.getPath(), ""));
|
||||
return c1.thenComparing((r1, r2) -> r1.getName().compareTo(r2.getName()));
|
||||
}
|
||||
return super.createSortComparator(columnIndex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-2
@@ -645,8 +645,7 @@ public class SymbolTreeProvider extends ComponentProviderAdapter {
|
||||
.each(SYMBOL_REMOVED).call(this::processSymbolRemoved)
|
||||
.each(EXTERNAL_ENTRY_ADDED, EXTERNAL_ENTRY_REMOVED)
|
||||
.call(this::processExternalEntryChanged)
|
||||
.any(EXTERNAL_PATH_CHANGED, EXTERNAL_NAME_ADDED,
|
||||
EXTERNAL_NAME_REMOVED, EXTERNAL_NAME_CHANGED)
|
||||
.any(EXTERNAL_NAME_ADDED, EXTERNAL_NAME_REMOVED, EXTERNAL_NAME_CHANGED)
|
||||
// Rather than try to find each affected symbol, it is easier to just reload
|
||||
// the tree. This is infrequent enough that it should not be disruptive.
|
||||
.call(this::reloadTree)
|
||||
|
||||
+12
@@ -39,6 +39,7 @@ import ghidra.program.model.listing.Library;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.ExternalManager;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.StringUtilities;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -101,6 +102,17 @@ public abstract class AbstractLibrarySupportLoader extends AbstractProgramLoader
|
||||
public static final String LOAD_ONLY_LIBRARIES_OPTION_NAME = "Only Load Libraries"; // hidden
|
||||
static final boolean LOAD_ONLY_LIBRARIES_OPTION_DEFAULT = false;
|
||||
|
||||
/**
|
||||
* Gets a program property name to represent the ordered required library of the given index
|
||||
*
|
||||
* @param libraryIndex The index of the required library
|
||||
* @return A program property name to represent the ordered required library of the given index
|
||||
*/
|
||||
public static String getRequiredLibraryProperty(int libraryIndex) {
|
||||
return String.format("%s %s]", "Required Library [",
|
||||
StringUtilities.pad("" + libraryIndex, ' ', 4));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads bytes in a particular format into the given {@link Program}.
|
||||
*
|
||||
|
||||
@@ -54,7 +54,6 @@ import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.AddressSetPropertyMap;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.program.util.ExternalSymbolResolver;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.datastruct.*;
|
||||
import ghidra.util.exception.*;
|
||||
@@ -458,7 +457,8 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
String[] neededLibs = elf.getDynamicLibraryNames();
|
||||
for (String neededLib : neededLibs) {
|
||||
monitor.checkCancelled();
|
||||
props.setString(ExternalSymbolResolver.getRequiredLibraryProperty(libraryIndex++),
|
||||
props.setString(
|
||||
AbstractLibrarySupportLoader.getRequiredLibraryProperty(libraryIndex++),
|
||||
neededLib);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,6 @@ import ghidra.program.model.reloc.RelocationResult;
|
||||
import ghidra.program.model.reloc.RelocationTable;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.program.util.ExternalSymbolResolver;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -1298,7 +1297,7 @@ public class MachoProgramBuilder {
|
||||
libraryPaths.add(libraryPath);
|
||||
addLibrary(libraryPath);
|
||||
props.setString(
|
||||
ExternalSymbolResolver.getRequiredLibraryProperty(libraryIndex++),
|
||||
AbstractLibrarySupportLoader.getRequiredLibraryProperty(libraryIndex++),
|
||||
libraryPath);
|
||||
}
|
||||
}
|
||||
|
||||
+66
-103
@@ -23,75 +23,18 @@ import java.util.function.Consumer;
|
||||
import db.Transaction;
|
||||
import ghidra.app.util.opinion.Loaded;
|
||||
import ghidra.framework.model.*;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.StringUtilities;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Moves dangling external function symbols found in the {@link Library#UNKNOWN EXTERNAL/UNKNOWN}
|
||||
* namespace into the namespace of the external library that publishes a matching symbol.
|
||||
* <p>
|
||||
* This uses an ordered list of external library names that was attached to the program during
|
||||
* import by the Elf or Macho loader (see {@link #REQUIRED_LIBRARY_PROPERTY_PREFIX}).
|
||||
*
|
||||
*/
|
||||
public class ExternalSymbolResolver implements Closeable {
|
||||
private final static String REQUIRED_LIBRARY_PROPERTY_PREFIX = "Required Library [";
|
||||
|
||||
/**
|
||||
* Gets a program property name to represent the ordered required library of the given index
|
||||
*
|
||||
* @param libraryIndex The index of the required library
|
||||
* @return A program property name to represent the ordered required library of the given index
|
||||
*/
|
||||
public static String getRequiredLibraryProperty(int libraryIndex) {
|
||||
return String.format("%s %s]", REQUIRED_LIBRARY_PROPERTY_PREFIX,
|
||||
StringUtilities.pad("" + libraryIndex, ' ', 4));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ordered list of library names, as specified by the logic/rules of the original
|
||||
* operating system's loader (eg. Elf / MachO dynamic library loading / symbol resolving
|
||||
* rules)
|
||||
*
|
||||
* @param program The {@link Program}
|
||||
* @return list of library names, in original order
|
||||
*/
|
||||
public static List<String> getOrderedRequiredLibraryNames(Program program) {
|
||||
TreeMap<Integer, String> orderLibraryMap = new TreeMap<>();
|
||||
Options options = program.getOptions(Program.PROGRAM_INFO);
|
||||
for (String optionName : options.getOptionNames()) {
|
||||
|
||||
// Legacy programs may have the old "ELF Required Library [" program property, so
|
||||
// we should not assume that the option name starts exactly with
|
||||
// REQUIRED_LIBRARY_PROPERTY_PREFIX. We must deal with a potential substring at the
|
||||
// start of the option name.
|
||||
int prefixIndex = optionName.indexOf(REQUIRED_LIBRARY_PROPERTY_PREFIX);
|
||||
if (prefixIndex == -1 || !optionName.endsWith("]")) {
|
||||
continue;
|
||||
}
|
||||
String libName = options.getString(optionName, null);
|
||||
if (libName == null) {
|
||||
continue;
|
||||
}
|
||||
String indexStr = optionName
|
||||
.substring(prefixIndex + REQUIRED_LIBRARY_PROPERTY_PREFIX.length(),
|
||||
optionName.length() - 1)
|
||||
.trim();
|
||||
try {
|
||||
orderLibraryMap.put(Integer.parseInt(indexStr), libName.trim());
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
Msg.error(ExternalSymbolResolver.class,
|
||||
"Program contains invalid property: " + optionName);
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(orderLibraryMap.values());
|
||||
}
|
||||
|
||||
private final ProjectData projectData;
|
||||
private final TaskMonitor monitor;
|
||||
@@ -236,33 +179,6 @@ public class ExternalSymbolResolver implements Closeable {
|
||||
* Represents a program that needs its external symbols to be fixed.
|
||||
*/
|
||||
private class ProgramSymbolResolver {
|
||||
record ExtLibInfo(String name, Library lib, String programPath, Program program,
|
||||
List<String> resolvedSymbols, Throwable problem) {
|
||||
String getProblemMessage() {
|
||||
if (problem instanceof VersionException ve) {
|
||||
return getVersionError(ve);
|
||||
}
|
||||
return problem != null ? problem.getMessage() : "";
|
||||
}
|
||||
|
||||
String getLibPath() {
|
||||
return programPath != null ? programPath : "missing";
|
||||
}
|
||||
|
||||
String getVersionError(VersionException ve) {
|
||||
String versionType = switch (ve.getVersionIndicator()) {
|
||||
case VersionException.NEWER_VERSION -> " newer";
|
||||
case VersionException.OLDER_VERSION -> "n older";
|
||||
default -> "n unknown";
|
||||
};
|
||||
|
||||
String upgradeMsg = ve.isUpgradable() ? " (upgrade is possible)" : "";
|
||||
|
||||
return "skipped: file was created with a%s version of Ghidra%s"
|
||||
.formatted(versionType, upgradeMsg);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Program program;
|
||||
String programPath;
|
||||
@@ -296,16 +212,19 @@ public class ExternalSymbolResolver implements Closeable {
|
||||
logger.accept("\t%d external symbols resolved, %d remain unresolved"
|
||||
.formatted(getResolvedSymbolCount(), unresolvedExternalFunctionIds.size()));
|
||||
for (ExtLibInfo extLib : extLibs) {
|
||||
String libPath = extLib.getAssociatedProgramPath();
|
||||
String loggedLibPath = libPath != null ? libPath : "missing";
|
||||
if (extLib.problem != null) {
|
||||
logger.accept("\t[%s] -> %s, %s".formatted(extLib.name, extLib.getLibPath(),
|
||||
logger.accept("\t[%s] -> %s, %s".formatted(extLib.getName(), loggedLibPath,
|
||||
extLib.getProblemMessage()));
|
||||
}
|
||||
else if (extLib.programPath != null) {
|
||||
logger.accept("\t[%s] -> %s, %d new symbols resolved".formatted(extLib.name,
|
||||
extLib.getLibPath(), extLib.resolvedSymbols.size()));
|
||||
else if (libPath != null) {
|
||||
logger.accept(
|
||||
"\t[%s] -> %s, %d new symbols resolved".formatted(extLib.getName(),
|
||||
loggedLibPath, extLib.resolvedSymbols.size()));
|
||||
}
|
||||
else {
|
||||
logger.accept("\t[%s] -> %s".formatted(extLib.name, extLib.getLibPath()));
|
||||
logger.accept("\t[%s] -> %s".formatted(extLib.getName(), loggedLibPath));
|
||||
}
|
||||
if (!shortSummary) {
|
||||
for (String symbolName : extLib.resolvedSymbols) {
|
||||
@@ -328,8 +247,8 @@ public class ExternalSymbolResolver implements Closeable {
|
||||
|
||||
private boolean hasSomeLibrariesConfigured() {
|
||||
for (ExtLibInfo extLib : extLibs) {
|
||||
if (extLib.program != null || extLib.problem != null ||
|
||||
extLib.programPath != null) {
|
||||
if (extLib.problem != null ||
|
||||
extLib.getAssociatedProgramPath() != null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -367,19 +286,17 @@ public class ExternalSymbolResolver implements Closeable {
|
||||
private List<ExtLibInfo> getLibsToSearch() throws CancelledException {
|
||||
List<ExtLibInfo> result = new ArrayList<>();
|
||||
ExternalManager externalManager = program.getExternalManager();
|
||||
for (String libName : getOrderedRequiredLibraryNames(program)) {
|
||||
Library lib = externalManager.getExternalLibrary(libName);
|
||||
String libPath = lib != null ? lib.getAssociatedProgramPath() : null;
|
||||
// External manager supplies external Libraries in appropriate search order
|
||||
for (Library lib : externalManager.getLibraries()) {
|
||||
String libPath = lib.getAssociatedProgramPath();
|
||||
Program libProg = libPath != null ? getLibraryProgram(libPath) : null;
|
||||
Throwable problem =
|
||||
libProg == null && libPath != null ? problemLibraries.get(libPath) : null;
|
||||
|
||||
result.add(
|
||||
new ExtLibInfo(libName, lib, libPath, libProg, new ArrayList<>(), problem));
|
||||
result.add(new ExtLibInfo(lib, problem));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Moves unresolved functions from the EXTERNAL/UNKNOWN namespace to the namespace of the
|
||||
* external library if the extLib publishes a symbol with a matching name.
|
||||
@@ -388,10 +305,6 @@ public class ExternalSymbolResolver implements Closeable {
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
private void resolveSymbolsToLibrary(ExtLibInfo extLib) throws CancelledException {
|
||||
if (extLib.program == null) {
|
||||
// can't do anything if the external library doesn't have a valid program associated
|
||||
return;
|
||||
}
|
||||
ExternalManager externalManager = program.getExternalManager();
|
||||
SymbolTable symbolTable = program.getSymbolTable();
|
||||
|
||||
@@ -409,7 +322,7 @@ public class ExternalSymbolResolver implements Closeable {
|
||||
ExternalLocation extLoc = externalManager.getExternalLocation(s);
|
||||
String extLocName =
|
||||
Objects.requireNonNullElse(extLoc.getOriginalImportedName(), extLoc.getLabel());
|
||||
if (isExportedSymbol(extLib.program, extLocName)) {
|
||||
if (isExportedSymbol(program, extLocName)) {
|
||||
try {
|
||||
s.setNamespace(extLib.lib);
|
||||
idIterator.remove();
|
||||
@@ -443,6 +356,56 @@ public class ExternalSymbolResolver implements Closeable {
|
||||
}
|
||||
return symbolIds;
|
||||
}
|
||||
|
||||
private class ExtLibInfo {
|
||||
|
||||
final Library lib;
|
||||
final List<String> resolvedSymbols = new ArrayList<>();
|
||||
final Throwable problem;
|
||||
|
||||
/**
|
||||
* Define external Library dependency associated with {@link ProgramSymbolResolver}
|
||||
* instance.
|
||||
* @param lib external library dependency
|
||||
* @param problem exception which occured while accessing Library
|
||||
*/
|
||||
ExtLibInfo(Library lib, Throwable problem) {
|
||||
if (program != lib.getSymbol().getProgram()) {
|
||||
throw new AssertionError("Program mismatch");
|
||||
}
|
||||
this.lib = lib;
|
||||
this.problem = problem;
|
||||
}
|
||||
|
||||
String getName() {
|
||||
return lib.getName();
|
||||
}
|
||||
|
||||
String getProblemMessage() {
|
||||
if (problem instanceof VersionException ve) {
|
||||
return getVersionError(ve);
|
||||
}
|
||||
return problem != null ? problem.getMessage() : "";
|
||||
}
|
||||
|
||||
String getVersionError(VersionException ve) {
|
||||
String versionType = switch (ve.getVersionIndicator()) {
|
||||
case VersionException.NEWER_VERSION -> " newer";
|
||||
case VersionException.OLDER_VERSION -> "n older";
|
||||
default -> "n unknown";
|
||||
};
|
||||
|
||||
String upgradeMsg = ve.isUpgradable() ? " (upgrade is possible)" : "";
|
||||
|
||||
return "skipped: file was created with a%s version of Ghidra%s"
|
||||
.formatted(versionType, upgradeMsg);
|
||||
}
|
||||
|
||||
String getAssociatedProgramPath() {
|
||||
return lib.getAssociatedProgramPath();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -230,11 +230,20 @@ class SymbolMerge {
|
||||
}
|
||||
else if (type == SymbolType.LIBRARY) {
|
||||
ExternalManager fromExtMgr = fromProgram.getExternalManager();
|
||||
String path = fromExtMgr.getExternalLibraryPath(name);
|
||||
Library fromLib = fromExtMgr.getExternalLibrary(name);
|
||||
|
||||
String path = fromLib != null ? fromLib.getAssociatedProgramPath() : null;
|
||||
int ordinal = fromLib != null ? fromExtMgr.getLibraryOrdinal(name) : -1;
|
||||
|
||||
ExternalManagerDB extMgr = (ExternalManagerDB) toProgram.getExternalManager();
|
||||
extMgr.setExternalPath(name, path, source == SourceType.USER_DEFINED);
|
||||
symbol = toSymbolTable.getLibrarySymbol(name);
|
||||
Library newLib = extMgr.addExternalLibraryName(name, source);
|
||||
symbol = newLib.getSymbol();
|
||||
if (ordinal >= 0) {
|
||||
extMgr.setLibraryOrdinal(name, ordinal);
|
||||
}
|
||||
if (path != null) {
|
||||
extMgr.setExternalPath(name, path, source == SourceType.USER_DEFINED);
|
||||
}
|
||||
}
|
||||
else if (type == SymbolType.FUNCTION) {
|
||||
FunctionManager fromFunctionMgr = fromProgram.getFunctionManager();
|
||||
|
||||
Vendored
+4
-5
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -25,7 +25,6 @@ import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.listing.CircularDependencyException;
|
||||
import ghidra.program.model.listing.Library;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
@@ -47,7 +46,7 @@ public class ExternalManagerDBTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
public void setUp() throws Exception {
|
||||
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY, this);
|
||||
space = program.getAddressFactory().getDefaultAddressSpace();
|
||||
extMgr = (ExternalManagerDB) program.getExternalManager();
|
||||
extMgr = program.getExternalManager();
|
||||
transactionID = program.startTransaction("Test");
|
||||
}
|
||||
|
||||
@@ -336,7 +335,7 @@ public class ExternalManagerDBTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
||||
@Test
|
||||
public void testOriginalImportName()
|
||||
throws InvalidInputException, DuplicateNameException, CircularDependencyException {
|
||||
throws InvalidInputException, DuplicateNameException {
|
||||
ExternalLocation extLoc =
|
||||
extMgr.addExtLocation("ext1", "foo", addr(1000), SourceType.IMPORTED);
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* 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.
|
||||
@@ -16,28 +16,15 @@
|
||||
package sarif.managers;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressFormatException;
|
||||
import ghidra.program.model.address.AddressOverflowException;
|
||||
import ghidra.program.model.listing.GhidraClass;
|
||||
import ghidra.program.model.listing.Library;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.ExternalLocation;
|
||||
import ghidra.program.model.symbol.ExternalManager;
|
||||
import ghidra.program.model.symbol.Namespace;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskLauncher;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
import sarif.SarifProgramOptions;
|
||||
@@ -127,14 +114,21 @@ public class ExternalLibSarifMgr extends SarifMgr {
|
||||
return; // already has a value--don't override it
|
||||
}
|
||||
|
||||
// NB: Can't use "DEFAULT" here or result.get("sourceType") which may be
|
||||
// "DEFAULT"
|
||||
// NB: Can't use "DEFAULT" here or result.get("sourceType") which may be "DEFAULT"
|
||||
String source = (String) result.get("sourceType");
|
||||
SourceType sourceType = getSourceType(source);
|
||||
if (sourceType.equals(SourceType.DEFAULT)) {
|
||||
sourceType = SourceType.IMPORTED;
|
||||
}
|
||||
library = extManager.addExternalLibraryName(progName, sourceType);
|
||||
|
||||
// NOTE: It is assumed that a full export/import will maintain the ordered sequence of Libraries
|
||||
|
||||
// NOTE: Skip setting library location within project which is unlikely to match-up properly
|
||||
// String progPath = (String) result.get("location");
|
||||
// if (progPath != null) {
|
||||
// extManager.setExternalPath(progName, progPath, sourceType == SourceType.USER_DEFINED);
|
||||
// }
|
||||
}
|
||||
|
||||
private void processExternalLocation(Map<String, Object> result) throws IOException {
|
||||
|
||||
Reference in New Issue
Block a user