mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-09-20 09:31:47 +00:00
Merge remote-tracking branch 'origin/master' into debugger
This commit is contained in:
commit
3093e2dd2a
29
DevGuide.md
29
DevGuide.md
|
@ -28,26 +28,29 @@
|
|||
The following is a list of dependencies, in no particular order.
|
||||
This guide includes instructions for obtaining many of these at the relevant step(s).
|
||||
You may not need all of these, depending on which portions you are building or developing.
|
||||
|
||||
#### At minimum you will need all of the following
|
||||
* Java JDK 11 (64-bit) - Free long term support (LTS) versions of JDK 11 are provided by:
|
||||
- AdoptOpenJDK
|
||||
- https://adoptopenjdk.net/releases.html?variant=openjdk11&jvmVariant=hotspot
|
||||
- Amazon Corretto
|
||||
- https://docs.aws.amazon.com/corretto/latest/corretto-11-ug/downloads-list.html
|
||||
* Eclipse - It must support JDK 11. Eclipse 2018-12 or later should work. Other IDEs may work, but we have not tested them.
|
||||
- https://www.eclipse.org/downloads/
|
||||
* Gradle 5.0 or later - We use version 5.0, and tested with up to 5.6.3.
|
||||
- https://gradle.org/next-steps/?version=5.0&format=bin
|
||||
* A C/C++ compiler - We use GCC on Linux, Xcode (Clang) on macOS, and Visual Studio (2017 or later) on Windows.
|
||||
- https://gcc.gnu.org/
|
||||
- https://developer.apple.com/xcode/
|
||||
- https://visualstudio.microsoft.com/downloads/
|
||||
* Git - We use the official installer on Windows. Most Linux distros have git in their repos. Xcode provides git on macOS.
|
||||
#### Optional for Development
|
||||
* Eclipse - It must support JDK 11. Eclipse 2018-12 or later should work. Other IDEs may work, but we have not tested them.
|
||||
- https://www.eclipse.org/downloads/
|
||||
#### Necessary unless a download zip snapshot of the ghidra repository is used
|
||||
* Git - We use the official installer on Windows. For windows you can also use the github CLI or git from with (Windows Subsystem for Linux - WSL). Most Linux distros have git in their repos. Xcode provides git on macOS. You can skip Git if you download a .zip file of the ghidra repository.
|
||||
- https://git-scm.com/downloads
|
||||
* Bash - This is moot on Linux and macOS. On Windows, we use MinGW. This may be distributed with Git for Windows.
|
||||
- https://cli.github.com/
|
||||
#### Optional unless following [Manual download instructions](#manual-download-instructions)
|
||||
* Bash - This is moot on Linux and macOS. On Windows, we use MinGW. This may be distributed with Git for Windows. This can be skipped if using the automatic build.
|
||||
- https://osdn.net/projects/mingw/releases/
|
||||
* Bison and Flex - We use win-flex-bison v2.5.17. These packages may also be available in MSYS (MinGW). Most Linux distros have these in their repos. Xcode provides these for macOS.
|
||||
- https://sourceforge.net/projects/winflexbison/
|
||||
#### Necessary for the development and building of Ghidra, these and more will be downloaded during the [Automatic](#automatic-script-instructions) or the [Manual](#manual-download-instructions) instructions
|
||||
* dex2jar. We use version 2.0.
|
||||
- https://github.com/pxb1988/dex2jar/releases
|
||||
* AXMLPrinter2
|
||||
|
@ -69,10 +72,8 @@ If you need these offline, a reasonable course of action is to set up a developm
|
|||
|
||||
## Install Development and Build Tools
|
||||
|
||||
If you're on Windows, install Git, MinGW, Bison, and Flex.
|
||||
Many of the commands given below must be executed in Bash (Use git-bash or MSYS from MinGW).
|
||||
**IMPORTANT**: The bison and flex executables may be named `win-bison.exe` and `win-flex.exe`.
|
||||
Our build cannot currently cope with that, so you should rename them to `bison.exe` and `flex.exe`.
|
||||
If you're on Windows, install Git unless you will download a .zip clone of the ghidra repository. If you go the manual route
|
||||
many of the commands given below must be executed in Bash (Windows Subsystem for Linux (WSL), or Use git-bash or MSYS from MinGW).
|
||||
|
||||
Install OpenJDK 11 and make sure it's the default java.
|
||||
|
||||
|
@ -84,7 +85,7 @@ Install Gradle, add it to your `PATH`, and ensure it is launched using JDK 11.
|
|||
|
||||
## Setup Source Repository
|
||||
|
||||
You may choose any directory for your working copy, but these instructions will assume you have cloned the source to `~/git/ghidra`.
|
||||
You may choose any directory for your working copy, however these instructions will assume you have cloned the source to `~/git/ghidra`.
|
||||
Be sure to adjust the commands to match your chosen working directory if different than suggested:
|
||||
|
||||
```bash
|
||||
|
@ -92,6 +93,7 @@ mkdir ~/git
|
|||
cd ~/git
|
||||
git clone git@github.com:NationalSecurityAgency/ghidra.git
|
||||
```
|
||||
or unzip a snapshot .zip of the ghidra repository
|
||||
|
||||
## Setup Build Dependency Repository
|
||||
|
||||
|
@ -264,7 +266,6 @@ Some of Ghidra's components are built for the native platform.
|
|||
We currently support Linux, macOS, and Windows 64-bit x86 systems.
|
||||
Others should be possible, but we do not test on them.
|
||||
|
||||
Ensure bison and flex are installed and in your `PATH`.
|
||||
Now build using Gradle:
|
||||
|
||||
On Linux:
|
||||
|
@ -365,7 +366,7 @@ The result can be added to an installation or source tree by copying it to `~/gi
|
|||
This task is often done manually from the Ghidra GUI, and the archives included in our official build require a fair bit of fine tuning.
|
||||
You will first need to import the relevant libraries from which you'd like to produce a FID database.
|
||||
This is often a set of libraries from an SDK.
|
||||
We include a variety of Visual Studio platforms in the official build.
|
||||
We include a variety of Visual Studio platforms in the official build. The official .fidb files can be found in the ghidra-data repository here https://github.com/NationalSecurityAgency/ghidra-data/tree/master/FunctionID
|
||||
|
||||
From a CodeBrowser window, select __File -> Configure__.
|
||||
Enable the "Function ID" plugins, and close the dialog.
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="1"/>
|
||||
</listAttribute>
|
||||
<mapAttribute key="org.eclipse.debug.core.preferred_launchers">
|
||||
<mapEntry key="[debug]" value="org.eclipse.jdt.launching.localJavaApplication"/>
|
||||
<mapEntry key="[run]" value="org.eclipse.jdt.launching.localJavaApplication"/>
|
||||
</mapAttribute>
|
||||
<stringAttribute key="org.eclipse.debug.core.source_locator_id" value="org.eclipse.jdt.launching.sourceLocator.JavaSourceLookupDirector"/>
|
||||
<stringAttribute key="org.eclipse.debug.core.source_locator_memento" value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <sourceLookupDirector> <sourceContainers duplicates="false"> <container memento="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;classpathContainer path=&quot;org.eclipse.jdt.launching.JRE_CONTAINER&quot;/&gt;&#10;" typeId="org.eclipse.jdt.launching.sourceContainer.classpathContainer"/> <container memento="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;default/&gt;&#10;" typeId="org.eclipse.debug.core.containerType.default"/> </sourceContainers> </sourceLookupDirector> "/>
|
||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
||||
|
|
|
@ -1,409 +0,0 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// New Table Stuff
|
||||
//@category Search
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.tablechooser.*;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.mem.MemoryAccessException;
|
||||
|
||||
public class FindRunsOfPointersWithTableScript extends GhidraScript {
|
||||
private List<PossiblePtrs> resultsArray = new ArrayList<PossiblePtrs>();
|
||||
public static final int LITTLE_ENDIAN = 0;
|
||||
public static final int BIG_ENDIAN = 1;
|
||||
|
||||
@Override
|
||||
public void run() throws Exception {
|
||||
|
||||
int size = currentProgram.getAddressFactory().getDefaultAddressSpace().getSize();
|
||||
if (size != 32) {
|
||||
println("This script only works on 32-bit programs.");
|
||||
return;
|
||||
}
|
||||
|
||||
TableChooserExecutor executor = createTableExecutor();
|
||||
TableChooserDialog tableDialog = createTableChooserDialog("Runs of Pointers", executor);
|
||||
configureTableColumns(tableDialog);
|
||||
tableDialog.show();
|
||||
tableDialog.setMessage("Searching...");
|
||||
Memory memory = currentProgram.getMemory();
|
||||
long distance;
|
||||
// TODO add option to work only on selection
|
||||
AddressIterator addrIter = memory.getAddresses(true);
|
||||
//println("Memory range: " + memory.getMinAddress() + " - " + memory.getMaxAddress());
|
||||
Address prevAddress = null;
|
||||
while (addrIter.hasNext() && !monitor.isCancelled()) {
|
||||
Address addr = addrIter.next();
|
||||
try {
|
||||
// get the value in address form of the bytes at address a
|
||||
int addrInt = memory.getInt(addr);
|
||||
long addrLong = addrInt & 0xffffffffL;
|
||||
Address testAddr = addr.getNewAddress(addrLong);
|
||||
|
||||
if ((addrLong != 0) && (memory.contains(testAddr))) {
|
||||
if (prevAddress != null) {
|
||||
distance = addr.subtract(prevAddress);
|
||||
}
|
||||
else {
|
||||
distance = 0;
|
||||
}
|
||||
|
||||
PossiblePtrs pp = new PossiblePtrs(addr, testAddr, distance);
|
||||
resultsArray.add(pp);
|
||||
//println(addr.toString() + " " + testAddr.toString() + " " + distance);
|
||||
prevAddress = addr;
|
||||
}
|
||||
}
|
||||
catch (MemoryAccessException e) {
|
||||
break;
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// go through the list of pointers and only print out the ones with a run of the same distance between them
|
||||
// keep the one before the run and include the last one with the same distance
|
||||
//println("tableAddress distance tableSize");
|
||||
if (resultsArray.size() == 0) {
|
||||
tableDialog.setMessage("Done! Found no hits");
|
||||
return;
|
||||
}
|
||||
|
||||
long dist = resultsArray.get(0).getDistanceFromLast();
|
||||
int tableSize = 0;
|
||||
Address topAddress = null;
|
||||
int i = 1;
|
||||
while (i < resultsArray.size() && !monitor.isCancelled()) {
|
||||
// for(int i=1;i<resultsArray.size();i++){
|
||||
long thisDist = resultsArray.get(i).getDistanceFromLast();
|
||||
if (thisDist == dist) {
|
||||
if (tableSize == 0) {
|
||||
topAddress = resultsArray.get(i - 2).getAddrOfPtr();
|
||||
tableSize = 1;
|
||||
}
|
||||
tableSize++;
|
||||
}
|
||||
else {
|
||||
if (tableSize >= 3) {
|
||||
tableSize++;
|
||||
|
||||
Address ref = findRef(topAddress, dist);
|
||||
//println(topAddress.toString() + " " + dist + " " + tableSize);
|
||||
Table pointerTable = new Table(topAddress, dist, tableSize, ref);
|
||||
tableDialog.add(pointerTable);
|
||||
}
|
||||
tableSize = 0;
|
||||
dist = thisDist;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
tableDialog.setMessage("Done! Found " + tableDialog.getRowCount() + " hits");
|
||||
|
||||
// print out results
|
||||
// println("Table address Dist bet ptrs Num ptrs Ref found");
|
||||
// for(int j=0;j<tableArray.size();j++){
|
||||
// Table ptrTable = tableArray.get(j);
|
||||
// String refString = new String();
|
||||
// if(ptrTable.getRef() != null){
|
||||
// refString = " at " + ptrTable.getRef().toString();
|
||||
// println(" " + ptrTable.getTopAddr().toString() + " " + ptrTable.getDistance() + " " + ptrTable.getNumPointers() + " " + refString);
|
||||
// }
|
||||
// else if(searchNonRefd){
|
||||
// refString = "No";
|
||||
// println(" " + ptrTable.getTopAddr().toString() + " " + ptrTable.getDistance() + " " + ptrTable.getNumPointers() + " " + refString);
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
private void configureTableColumns(TableChooserDialog tableDialog) {
|
||||
StringColumnDisplay distanceColumn = new StringColumnDisplay() {
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return "Dist bet ptrs";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnValue(AddressableRowObject rowObject) {
|
||||
Table table = (Table) rowObject;
|
||||
return Long.toString(table.getDistance());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(AddressableRowObject o1, AddressableRowObject o2) {
|
||||
Table table1 = (Table) o1;
|
||||
Table table2 = (Table) o2;
|
||||
return (int) (table1.getDistance() - table2.getDistance());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
StringColumnDisplay numberOfPointersColumn = new StringColumnDisplay() {
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return "Num ptrs";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnValue(AddressableRowObject rowObject) {
|
||||
Table table = (Table) rowObject;
|
||||
return Long.toString(table.getNumPointers());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compare(AddressableRowObject o1, AddressableRowObject o2) {
|
||||
Table table1 = (Table) o1;
|
||||
Table table2 = (Table) o2;
|
||||
return table1.getNumPointers() - table2.getNumPointers();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
StringColumnDisplay referenceFoundColumn = new StringColumnDisplay() {
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return "Ref found";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getColumnValue(AddressableRowObject rowObject) {
|
||||
Table table = (Table) rowObject;
|
||||
if (table.getRef() != null) {
|
||||
return " at " + table.getRef();
|
||||
}
|
||||
return "No";
|
||||
}
|
||||
};
|
||||
|
||||
ColumnDisplay<Address> secondAddressColumn =
|
||||
new AbstractComparableColumnDisplay<Address>() {
|
||||
@Override
|
||||
public String getColumnName() {
|
||||
return "Offset Address";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getColumnValue(AddressableRowObject rowObject) {
|
||||
Table table = (Table) rowObject;
|
||||
return table.getAddress().add(100);
|
||||
}
|
||||
};
|
||||
|
||||
tableDialog.addCustomColumn(distanceColumn);
|
||||
tableDialog.addCustomColumn(secondAddressColumn);
|
||||
tableDialog.addCustomColumn(numberOfPointersColumn);
|
||||
tableDialog.addCustomColumn(referenceFoundColumn);
|
||||
}
|
||||
|
||||
private TableChooserExecutor createTableExecutor() {
|
||||
TableChooserExecutor executor = new TableChooserExecutor() {
|
||||
@Override
|
||||
public String getButtonName() {
|
||||
return "Hit Me";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(AddressableRowObject rowObject) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
return executor;
|
||||
}
|
||||
|
||||
// find the first ref starting at topAddr and working back dist - pointersize
|
||||
// once a ref is found, stop - it doesn't make much sense that there would be more than one.
|
||||
Address findRef(Address topAddress, long dist) {
|
||||
|
||||
Memory memory = currentProgram.getMemory();
|
||||
Address ref = null;
|
||||
|
||||
//change later to handle 64 bits too
|
||||
byte[] maskBytes = new byte[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
maskBytes[i] = (byte) 0xff;
|
||||
}
|
||||
|
||||
// search memory for the byte patterns within the range of topAddr and topAddr - dist
|
||||
// make a structure of found bytes/topAddr offset????
|
||||
boolean noRefFound = true;
|
||||
boolean tryPrevAddr = true;
|
||||
long longIndex = 0;
|
||||
while (noRefFound && tryPrevAddr) {
|
||||
Address testAddr = topAddress.subtract(longIndex);
|
||||
byte[] addressBytes = turnAddressIntoBytes(testAddr);
|
||||
|
||||
//println("TestAddr = " + testAddr.toString());
|
||||
Address found = memory.findBytes(currentProgram.getMinAddress(), addressBytes,
|
||||
maskBytes, true, monitor);
|
||||
if (found != null) {
|
||||
ref = found;
|
||||
// println("Found ref at " + found.toString());
|
||||
noRefFound = false;
|
||||
}
|
||||
else {
|
||||
longIndex++;
|
||||
// check to see if we are at the top of the range of possible refs
|
||||
if (longIndex > (dist - 4)) {// change the four to pointer size when I add 64bit
|
||||
tryPrevAddr = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
byte[] turnAddressIntoBytes(Address addr) {
|
||||
// turn addresses into bytes
|
||||
|
||||
byte[] addressBytes = new byte[4]; // only 32-bit for now - change later to add 64 bit
|
||||
// This is the correct way to do turn a long into an address
|
||||
long addrLong = addr.getOffset();
|
||||
|
||||
int endian = getEndian();
|
||||
|
||||
if (endian == BIG_ENDIAN) {
|
||||
// put bytes in forward order
|
||||
addressBytes = bytesForward(addrLong);
|
||||
}
|
||||
else if (endian == LITTLE_ENDIAN) {
|
||||
// put bytes in reverse order
|
||||
addressBytes = bytesReversed(addrLong);
|
||||
}
|
||||
else {
|
||||
println("Unknown endian - cannot find references.");
|
||||
return null;
|
||||
}
|
||||
|
||||
return addressBytes;
|
||||
}
|
||||
|
||||
byte[] bytesForward(long addr) {
|
||||
byte[] bytes = new byte[4]; // only works for 32-bit for now-later add 64
|
||||
for (int i = 0; i < 4; i++) {
|
||||
bytes[i] = (byte) ((addr >> (24 - (i * 8))) & 0xff);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
byte[] bytesReversed(long addr) {
|
||||
byte[] bytes = new byte[4]; // only works for 32-bit for now-later add 64
|
||||
for (int i = 3; i >= 0; i--) {
|
||||
bytes[3 - i] = (byte) ((addr >> (24 - (i * 8))) & 0xff);
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
// find references to the possible table
|
||||
// start looking at the top of the array and work back the distance between the pointers in
|
||||
// the table
|
||||
// Address [] findReferenceToTable(Address topAddress, long dist){
|
||||
//
|
||||
// ArrayList<Address> foundAddrs = new ArrayList<Address>();
|
||||
// long counter = 0;
|
||||
// while((foundAddrs.size() == 0) || (counter == (dist-1))){
|
||||
// List<Address> newList = findReferences(topAddress.subtract(dist-counter));
|
||||
// for(int i=0;i<newList.size();i++){
|
||||
// Address a = (Address)newList.get(i);
|
||||
// foundAddrs.add(a);
|
||||
// }
|
||||
// counter++;
|
||||
// }
|
||||
//
|
||||
// return (Address[]) foundAddrs.toArray();
|
||||
// }
|
||||
|
||||
//public List<Address> findReferences(Address addr){
|
||||
// FindPossibleReferences fpr = new FindPossibleReferences(currentProgram,getEndian());
|
||||
// return fpr.findReferences(addr);
|
||||
//}
|
||||
|
||||
public int getEndian() {
|
||||
|
||||
if (currentProgram.getLanguage().isBigEndian()) {
|
||||
return 1; // BIG_ENDIAN
|
||||
}
|
||||
return 0; // LITTLE_ENDIAN
|
||||
}
|
||||
|
||||
// info about the pushed parameter that gets applied to the calling functions params and locals and referenced data
|
||||
class PossiblePtrs {
|
||||
|
||||
private Address addrOfPtr;
|
||||
private Address possiblePtr;
|
||||
private long distanceFromLast;
|
||||
|
||||
PossiblePtrs(Address addrOfPtr, Address possiblePtr, long distanceFromLast) {
|
||||
|
||||
this.addrOfPtr = addrOfPtr;
|
||||
this.possiblePtr = possiblePtr;
|
||||
this.distanceFromLast = distanceFromLast;
|
||||
}
|
||||
|
||||
public Address getAddrOfPtr() {
|
||||
return addrOfPtr;
|
||||
}
|
||||
|
||||
public Address getPossiblePointer() {
|
||||
return possiblePtr;
|
||||
}
|
||||
|
||||
public long getDistanceFromLast() {
|
||||
return distanceFromLast;
|
||||
}
|
||||
}
|
||||
|
||||
class Table implements AddressableRowObject {
|
||||
private Address topAddr;
|
||||
private long distance;
|
||||
private int numPointers;
|
||||
Address ref;
|
||||
|
||||
Table(Address topAddr, long distance, int numPointers, Address ref) {
|
||||
this.topAddr = topAddr;
|
||||
this.distance = distance;
|
||||
this.numPointers = numPointers;
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getAddress() {
|
||||
return getTopAddr();
|
||||
}
|
||||
|
||||
public Address getTopAddr() {
|
||||
return topAddr;
|
||||
}
|
||||
|
||||
public long getDistance() {
|
||||
return distance;
|
||||
}
|
||||
|
||||
public int getNumPointers() {
|
||||
return numPointers;
|
||||
}
|
||||
|
||||
public Address getRef() {
|
||||
return ref;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -75,8 +75,10 @@ public class FindSharedReturnFunctionsScript extends GhidraScript {
|
|||
@Override
|
||||
public String getColumnValue(AddressableRowObject rowObject) {
|
||||
SharedReturnLocations entry = (SharedReturnLocations) rowObject;
|
||||
Function func = entry.getProgram().getFunctionManager().getFunctionContaining(
|
||||
entry.getWhyAddr());
|
||||
Function func = entry.getProgram()
|
||||
.getFunctionManager()
|
||||
.getFunctionContaining(
|
||||
entry.getWhyAddr());
|
||||
if (func == null) {
|
||||
return "";
|
||||
}
|
||||
|
@ -93,8 +95,10 @@ public class FindSharedReturnFunctionsScript extends GhidraScript {
|
|||
@Override
|
||||
public String getColumnValue(AddressableRowObject rowObject) {
|
||||
SharedReturnLocations entry = (SharedReturnLocations) rowObject;
|
||||
Function func = entry.getProgram().getFunctionManager().getFunctionContaining(
|
||||
entry.getAddress());
|
||||
Function func = entry.getProgram()
|
||||
.getFunctionManager()
|
||||
.getFunctionContaining(
|
||||
entry.getAddress());
|
||||
if (func == null) {
|
||||
return "";
|
||||
}
|
||||
|
@ -151,26 +155,18 @@ public class FindSharedReturnFunctionsScript extends GhidraScript {
|
|||
@Override
|
||||
public boolean execute(AddressableRowObject rowObject) {
|
||||
SharedReturnLocations sharedRetLoc = (SharedReturnLocations) rowObject;
|
||||
System.out.println("Fixup Shared Return Jump at : " + rowObject.getAddress());
|
||||
println("Fixup Shared Return Jump at : " + rowObject.getAddress());
|
||||
|
||||
Program cp = sharedRetLoc.getProgram();
|
||||
Address entry = sharedRetLoc.getAddress();
|
||||
|
||||
// gonna change something, have to open a transaction
|
||||
int trans = cp.startTransaction("Fixup Shared Return Jump at " + entry);
|
||||
try {
|
||||
addBookMark(cp, entry, "Shared Return Jump");
|
||||
addBookMark(cp, entry, "Shared Return Jump");
|
||||
|
||||
if (!sharedRetLoc.getStatus().equals("fixed")) {
|
||||
fixSharedReturnLocation(cp, entry);
|
||||
}
|
||||
|
||||
addBookMark(cp, sharedRetLoc.getWhyAddr(), sharedRetLoc.getExplanation());
|
||||
}
|
||||
finally {
|
||||
cp.endTransaction(trans, true);
|
||||
if (!sharedRetLoc.getStatus().equals("fixed")) {
|
||||
fixSharedReturnLocation(cp, entry);
|
||||
}
|
||||
|
||||
addBookMark(cp, sharedRetLoc.getWhyAddr(), sharedRetLoc.getExplanation());
|
||||
return false; // don't remove row
|
||||
}
|
||||
|
||||
|
|
|
@ -112,8 +112,10 @@ public class FixupNoReturnFunctionsScript extends GhidraScript {
|
|||
@Override
|
||||
public String getColumnValue(AddressableRowObject rowObject) {
|
||||
NoReturnLocations entry = (NoReturnLocations) rowObject;
|
||||
Function func = entry.getProgram().getFunctionManager().getFunctionContaining(
|
||||
entry.getAddress());
|
||||
Function func = entry.getProgram()
|
||||
.getFunctionManager()
|
||||
.getFunctionContaining(
|
||||
entry.getAddress());
|
||||
if (func == null) {
|
||||
return "";
|
||||
}
|
||||
|
@ -283,20 +285,13 @@ public class FixupNoReturnFunctionsScript extends GhidraScript {
|
|||
return false;
|
||||
}
|
||||
|
||||
// gonna change something, have to open a transaction
|
||||
int trans = cp.startTransaction("Fixup No Return at " + entry);
|
||||
try {
|
||||
addBookMark(cp, entry, "Non Returning Function");
|
||||
addBookMark(cp, entry, "Non Returning Function");
|
||||
|
||||
if (!noRetLoc.isFixed()) {
|
||||
repairDamage(cp, func, entry);
|
||||
}
|
||||
if (!noRetLoc.isFixed()) {
|
||||
repairDamage(cp, func, entry);
|
||||
}
|
||||
|
||||
addBookMark(cp, noRetLoc.getWhyAddr(), noRetLoc.getExplanation());
|
||||
}
|
||||
finally {
|
||||
cp.endTransaction(trans, true);
|
||||
}
|
||||
addBookMark(cp, noRetLoc.getWhyAddr(), noRetLoc.getExplanation());
|
||||
|
||||
return false; // don't remove row
|
||||
}
|
||||
|
|
|
@ -463,7 +463,7 @@
|
|||
<P>This analyzer detects variadic function calls in the bodies of each function that intersect
|
||||
the current selection. It then parses their format string arguments to infer the correct function
|
||||
call signatures. Currently, this analyzer only supports printf, scanf, and their variants (e.g., snprintf, fscanf).
|
||||
If the current selection is emtpy, it searches through every function within the binary. Once
|
||||
If the current selection is empty, it searches through every function within the binary. Once
|
||||
the signatures are inferred, they are overridden.</P>
|
||||
|
||||
<P><U>Started By:</U> Importing or adding to a program, Auto Analyze command</P>
|
||||
|
|
|
@ -33,7 +33,7 @@ The list of extensions is populated when the dialog is launched. To build the li
|
|||
<ul>
|
||||
<li>Extension Installation Directories: Contains any extensions that have been installed. The directories are located at:</li>
|
||||
<ul>
|
||||
<li><i>[user dir]/.ghidra/.ghidra-[version]/Extensions</i> - Installed/uninstalled from this dialog</li>
|
||||
<li><i>[user dir]/.ghidra/.ghidra_[version]/Extensions</i> - Installed/uninstalled from this dialog</li>
|
||||
<li><i>[installation dir]/Ghidra/Extensions/</i> - Installed/uninstalled from filesystem manually</li>
|
||||
</ul>
|
||||
<li>Extensions Archive Directory: This is where all archive files (zips) are stored. It is located at <i>[installation dir]/Extensions/Ghidra/</i></li>
|
||||
|
|
|
@ -84,23 +84,30 @@ class CommentTableModel extends AddressBasedTableModel<CommentRowObject> {
|
|||
listing.getCommentAddressIterator(getProgram().getMemory(), true);
|
||||
while (commentIterator.hasNext()) {
|
||||
Address commentAddr = commentIterator.next();
|
||||
CodeUnit cu = listing.getCodeUnitAt(commentAddr);
|
||||
if (cu != null) {
|
||||
if (cu.getComment(CodeUnit.PRE_COMMENT) != null) {
|
||||
accumulator.add(new CommentRowObject(commentAddr, CodeUnit.PRE_COMMENT));
|
||||
}
|
||||
if (cu.getComment(CodeUnit.POST_COMMENT) != null) {
|
||||
accumulator.add(new CommentRowObject(commentAddr, CodeUnit.POST_COMMENT));
|
||||
}
|
||||
if (cu.getComment(CodeUnit.EOL_COMMENT) != null) {
|
||||
accumulator.add(new CommentRowObject(commentAddr, CodeUnit.EOL_COMMENT));
|
||||
}
|
||||
if (cu.getComment(CodeUnit.PLATE_COMMENT) != null) {
|
||||
accumulator.add(new CommentRowObject(commentAddr, CodeUnit.PLATE_COMMENT));
|
||||
}
|
||||
if (cu.getComment(CodeUnit.REPEATABLE_COMMENT) != null) {
|
||||
accumulator.add(new CommentRowObject(commentAddr, CodeUnit.REPEATABLE_COMMENT));
|
||||
}
|
||||
CodeUnit cu = listing.getCodeUnitContaining(commentAddr);
|
||||
if (!(cu instanceof Data)) {
|
||||
// avoid too many comments in the table by not showing offcut instruction comments
|
||||
cu = listing.getCodeUnitAt(commentAddr);
|
||||
}
|
||||
|
||||
if (cu == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cu.getComment(CodeUnit.PRE_COMMENT) != null) {
|
||||
accumulator.add(new CommentRowObject(commentAddr, CodeUnit.PRE_COMMENT));
|
||||
}
|
||||
if (cu.getComment(CodeUnit.POST_COMMENT) != null) {
|
||||
accumulator.add(new CommentRowObject(commentAddr, CodeUnit.POST_COMMENT));
|
||||
}
|
||||
if (cu.getComment(CodeUnit.EOL_COMMENT) != null) {
|
||||
accumulator.add(new CommentRowObject(commentAddr, CodeUnit.EOL_COMMENT));
|
||||
}
|
||||
if (cu.getComment(CodeUnit.PLATE_COMMENT) != null) {
|
||||
accumulator.add(new CommentRowObject(commentAddr, CodeUnit.PLATE_COMMENT));
|
||||
}
|
||||
if (cu.getComment(CodeUnit.REPEATABLE_COMMENT) != null) {
|
||||
accumulator.add(new CommentRowObject(commentAddr, CodeUnit.REPEATABLE_COMMENT));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -112,8 +112,9 @@ public class TableChooserDialog extends DialogComponentProvider
|
|||
navigatable.addNavigatableListener(this);
|
||||
table.installNavigation(goToService, navigatable);
|
||||
}
|
||||
table.getSelectionModel().addListSelectionListener(
|
||||
e -> setOkEnabled(table.getSelectedRowCount() > 0));
|
||||
table.getSelectionModel()
|
||||
.addListSelectionListener(
|
||||
e -> setOkEnabled(table.getSelectedRowCount() > 0));
|
||||
|
||||
GhidraTableFilterPanel<AddressableRowObject> filterPanel =
|
||||
new GhidraTableFilterPanel<>(table, model);
|
||||
|
@ -241,7 +242,8 @@ public class TableChooserDialog extends DialogComponentProvider
|
|||
monitor.initialize(rowObjects.size());
|
||||
|
||||
try {
|
||||
List<AddressableRowObject> deleted = doProcessRowObjects(rowObjects, monitor);
|
||||
List<AddressableRowObject> deleted = doProcessRowsInTransaction(rowObjects, monitor);
|
||||
|
||||
for (AddressableRowObject rowObject : deleted) {
|
||||
model.removeObject(rowObject);
|
||||
}
|
||||
|
@ -254,8 +256,9 @@ public class TableChooserDialog extends DialogComponentProvider
|
|||
}
|
||||
}
|
||||
|
||||
private List<AddressableRowObject> doProcessRowObjects(List<AddressableRowObject> rowObjects,
|
||||
private List<AddressableRowObject> doProcessRows(List<AddressableRowObject> rowObjects,
|
||||
TaskMonitor monitor) {
|
||||
|
||||
List<AddressableRowObject> deleted = new ArrayList<>();
|
||||
for (AddressableRowObject rowObject : rowObjects) {
|
||||
if (monitor.isCancelled()) {
|
||||
|
@ -280,6 +283,18 @@ public class TableChooserDialog extends DialogComponentProvider
|
|||
return deleted;
|
||||
}
|
||||
|
||||
private List<AddressableRowObject> doProcessRowsInTransaction(
|
||||
List<AddressableRowObject> rowObjects, TaskMonitor monitor) {
|
||||
|
||||
int tx = program.startTransaction("Table Chooser: " + getTitle());
|
||||
try {
|
||||
return doProcessRows(rowObjects, monitor);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(tx, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void addCustomColumn(ColumnDisplay<?> columnDisplay) {
|
||||
model.addCustomColumn(columnDisplay);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,11 @@
|
|||
*/
|
||||
package ghidra.app.tablechooser;
|
||||
|
||||
/**
|
||||
* The interface clients must implement to use the {@link TableChooserDialog}. This class is the
|
||||
* callback that is used to process items from the dialog's table as users select one or more
|
||||
* rows in the table and then press the table's "apply" button.
|
||||
*/
|
||||
public interface TableChooserExecutor {
|
||||
|
||||
/**
|
||||
|
@ -29,6 +34,9 @@ public interface TableChooserExecutor {
|
|||
* Applies this executors action to the given rowObject. Return true if the given object
|
||||
* should be removed from the table.
|
||||
*
|
||||
* <P>This method call will be wrapped in a transaction so the client does not have to do so.
|
||||
* Multiple selected rows will all be processed in a single transaction.
|
||||
*
|
||||
* @param rowObject the AddressRowObject to be executed upon
|
||||
* @return true if the rowObject should be removed from the table, false otherwise
|
||||
*/
|
||||
|
|
|
@ -183,6 +183,9 @@ public class ElfDefaultGotPltMarkup {
|
|||
monitor.checkCanceled();
|
||||
|
||||
Data data = createPointer(gotStart, true);
|
||||
if (data == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
try {
|
||||
gotStart = data.getMaxAddress().add(1);
|
||||
|
|
|
@ -191,4 +191,14 @@ public class ElfSectionHeaderConstants {
|
|||
public static final short SHN_XINDEX = (short) 0xffff;
|
||||
/**upper bound on range of reserved indexes*/
|
||||
public static final short SHN_HIRESERVE = (short) 0xffff;
|
||||
|
||||
/**
|
||||
* @param symbolSectionIndex symbol section index (st_shndx)
|
||||
* @return true if specified symbol section index corresponds to a processor
|
||||
* specific value in the range SHN_LOPROC..SHN_HIPROC, else false
|
||||
*/
|
||||
public static boolean isProcessorSpecificSymbolSectionIndex(short symbolSectionIndex) {
|
||||
return symbolSectionIndex >= ElfSectionHeaderConstants.SHN_LOPROC &&
|
||||
symbolSectionIndex <= ElfSectionHeaderConstants.SHN_HIPROC;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -312,6 +312,22 @@ public class ElfLoadAdapter {
|
|||
return functionAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method allows an extension to override the default address calculation for loading
|
||||
* a symbol. This is generally only neccessary when symbol requires handling of processor-specific
|
||||
* flags or section index. This method should return null when default symbol processing
|
||||
* is sufficient. {@link Address#NO_ADDRESS} should be returned if the symbol is external
|
||||
* and is not handled by default processing.
|
||||
* @param elfLoadHelper load helper object
|
||||
* @param elfSymbol elf symbol
|
||||
* @return symbol memory address or null to defer to default implementation
|
||||
* @throws NoValueException if error logged and address calculation failed
|
||||
*/
|
||||
public Address calculateSymbolAddress(ElfLoadHelper elfLoadHelper, ElfSymbol elfSymbol)
|
||||
throws NoValueException {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* During symbol processing this method will be invoked to permit an extension to
|
||||
* adjust the address and/or apply context to the intended symbol location.
|
||||
|
@ -487,4 +503,5 @@ public class ElfLoadAdapter {
|
|||
public Class<? extends ElfRelocation> getRelocationClass(ElfHeader elfHeader) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ import java.io.InputStream;
|
|||
import java.math.BigInteger;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import ghidra.app.cmd.label.SetLabelPrimaryCmd;
|
||||
import ghidra.app.util.MemoryBlockUtils;
|
||||
|
@ -1232,7 +1231,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
|||
monitor.checkCanceled();
|
||||
try {
|
||||
|
||||
Address address = calculateSymbolAddress(elfSymbol, msg -> log(msg));
|
||||
Address address = calculateSymbolAddress(elfSymbol);
|
||||
if (address == null) {
|
||||
continue;
|
||||
}
|
||||
|
@ -1280,11 +1279,10 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
|||
/**
|
||||
* Calculate the load address associated with a specified elfSymbol.
|
||||
* @param elfSymbol ELF symbol
|
||||
* @param errorConsumer error consumer
|
||||
* @return symbol address or null if symbol not supported and address not determined,
|
||||
* or NO_ADDRESS if symbol is external and should be allocated to the EXTERNAL block.
|
||||
* or {@link Address#NO_ADDRESS} if symbol is external and should be allocated to the EXTERNAL block.
|
||||
*/
|
||||
private Address calculateSymbolAddress(ElfSymbol elfSymbol, Consumer<String> errorConsumer) {
|
||||
private Address calculateSymbolAddress(ElfSymbol elfSymbol) {
|
||||
|
||||
if (elfSymbol.getSymbolTableIndex() == 0) {
|
||||
return null; // always skip the first symbol, it is NULL
|
||||
|
@ -1296,13 +1294,23 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
|||
|
||||
if (elfSymbol.isTLS()) {
|
||||
// TODO: Investigate support for TLS symbols
|
||||
errorConsumer.accept(
|
||||
"Unsupported Thread-Local Symbol not loaded: " + elfSymbol.getNameAsString());
|
||||
log("Unsupported Thread-Local Symbol not loaded: " + elfSymbol.getNameAsString());
|
||||
return null;
|
||||
}
|
||||
|
||||
ElfLoadAdapter loadAdapter = elf.getLoadAdapter();
|
||||
|
||||
// Allow extension to have first shot at calculating symbol address
|
||||
try {
|
||||
Address address = elf.getLoadAdapter().calculateSymbolAddress(this, elfSymbol);
|
||||
if (address != null) {
|
||||
return address;
|
||||
}
|
||||
}
|
||||
catch (NoValueException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ElfSectionHeader[] elfSections = elf.getSections();
|
||||
short sectionIndex = elfSymbol.getSectionHeaderIndex();
|
||||
Address symSectionBase = null;
|
||||
|
@ -1316,7 +1324,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
|||
ElfSectionHeader symSection = elf.getSections()[sectionIndex];
|
||||
symSectionBase = findLoadAddress(symSection, 0);
|
||||
if (symSectionBase == null) {
|
||||
errorConsumer.accept("Unable to place symbol due to non-loaded section: " +
|
||||
log("Unable to place symbol due to non-loaded section: " +
|
||||
elfSymbol.getNameAsString() + " - value=0x" +
|
||||
Long.toHexString(elfSymbol.getValue()) + ", section=" +
|
||||
symSection.getNameAsString());
|
||||
|
@ -1366,7 +1374,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
|||
// SHN_COMMON 0xfff2
|
||||
// SHN_HIRESERVE 0xffff
|
||||
|
||||
errorConsumer.accept("Unable to place symbol: " + elfSymbol.getNameAsString() +
|
||||
log("Unable to place symbol: " + elfSymbol.getNameAsString() +
|
||||
" - value=0x" + Long.toHexString(elfSymbol.getValue()) + ", section-index=0x" +
|
||||
Integer.toHexString(sectionIndex & 0xffff));
|
||||
return null;
|
||||
|
@ -1389,12 +1397,12 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
|||
}
|
||||
else if (elf.isRelocatable()) {
|
||||
if (sectionIndex < 0 || sectionIndex >= elfSections.length) {
|
||||
errorConsumer.accept("Error creating symbol: " + elfSymbol.getNameAsString() +
|
||||
log("Error creating symbol: " + elfSymbol.getNameAsString() +
|
||||
" - 0x" + Long.toHexString(elfSymbol.getValue()));
|
||||
return Address.NO_ADDRESS;
|
||||
}
|
||||
else if (symSectionBase == null) {
|
||||
errorConsumer.accept("No Memory for symbol: " + elfSymbol.getNameAsString() +
|
||||
log("No Memory for symbol: " + elfSymbol.getNameAsString() +
|
||||
" - 0x" + Long.toHexString(elfSymbol.getValue()));
|
||||
return Address.NO_ADDRESS;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import ghidra.app.util.HighlightProvider;
|
|||
import ghidra.app.util.viewer.format.FieldFormatModel;
|
||||
import ghidra.app.util.viewer.listingpanel.ListingModel;
|
||||
import ghidra.app.util.viewer.options.OptionsGui;
|
||||
import ghidra.app.util.viewer.proxy.DataProxy;
|
||||
import ghidra.app.util.viewer.proxy.ProxyObj;
|
||||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.options.ToolOptions;
|
||||
|
@ -126,10 +127,10 @@ public class PlateFieldFactory extends FieldFactory {
|
|||
nLinesBeforeLabels = fieldOptions.getInt(LINES_BEFORE_LABELS_OPTION, 1);
|
||||
nLinesBeforePlates = fieldOptions.getInt(LINES_BEFORE_PLATES_OPTION, 0);
|
||||
|
||||
showExternalFunctionPointerPlates = fieldOptions.getBoolean(
|
||||
ListingModel.DISPLAY_EXTERNAL_FUNCTION_POINTER_OPTION_NAME, true);
|
||||
showNonExternalFunctionPointerPlates = fieldOptions.getBoolean(
|
||||
ListingModel.DISPLAY_NONEXTERNAL_FUNCTION_POINTER_OPTION_NAME, false);
|
||||
showExternalFunctionPointerPlates = fieldOptions
|
||||
.getBoolean(ListingModel.DISPLAY_EXTERNAL_FUNCTION_POINTER_OPTION_NAME, true);
|
||||
showNonExternalFunctionPointerPlates = fieldOptions
|
||||
.getBoolean(ListingModel.DISPLAY_NONEXTERNAL_FUNCTION_POINTER_OPTION_NAME, false);
|
||||
|
||||
}
|
||||
|
||||
|
@ -160,11 +161,32 @@ public class PlateFieldFactory extends FieldFactory {
|
|||
FieldElement[] fields = new FieldElement[elementList.size()];
|
||||
elementList.toArray(fields);
|
||||
|
||||
if (isNestedDataAtSameAddressAsParent(proxy)) {
|
||||
// This is data at the same address as the parent, which happens with the first
|
||||
// element in a structure. We do not want to the plate comment here, but only at the
|
||||
// parent topmost address.
|
||||
return null;
|
||||
}
|
||||
|
||||
PlateFieldTextField textField =
|
||||
new PlateFieldTextField(fields, this, proxy, startX, width, commentText, isClipped);
|
||||
return new PlateListingTextField(proxy, textField);
|
||||
}
|
||||
|
||||
private boolean isNestedDataAtSameAddressAsParent(ProxyObj<?> proxy) {
|
||||
if (proxy instanceof DataProxy) {
|
||||
DataProxy dp = (DataProxy) proxy;
|
||||
Data data = dp.getObject();
|
||||
int[] cpath = data.getComponentPath();
|
||||
if (cpath.length > 0) {
|
||||
if (cpath[cpath.length - 1] == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private String getCommentText(CodeUnit cu) {
|
||||
String[] comments = cu.getCommentAsArray(CodeUnit.PLATE_COMMENT);
|
||||
if (comments == null) {
|
||||
|
@ -199,8 +221,8 @@ public class PlateFieldFactory extends FieldFactory {
|
|||
AttributedString prototype = new AttributedString(EMPTY_STRING, color, getMetrics());
|
||||
|
||||
for (int i = 0; i < comments.length; i++) {
|
||||
elementList.add(
|
||||
CommentUtils.parseTextForAnnotations(comments[i], program, prototype, i));
|
||||
elementList
|
||||
.add(CommentUtils.parseTextForAnnotations(comments[i], program, prototype, i));
|
||||
}
|
||||
|
||||
if (isWordWrap) {
|
||||
|
@ -499,7 +521,10 @@ public class PlateFieldFactory extends FieldFactory {
|
|||
if (!CodeUnit.class.isAssignableFrom(proxyObjectClass)) {
|
||||
return false;
|
||||
}
|
||||
return (category == FieldFormatModel.PLATE);
|
||||
|
||||
// some users like the look of plate comments and would like them in many places
|
||||
return (category == FieldFormatModel.PLATE || category == FieldFormatModel.OPEN_DATA ||
|
||||
category == FieldFormatModel.INSTRUCTION_OR_DATA);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -120,16 +120,14 @@ public class PreCommentFieldFactory extends FieldFactory {
|
|||
|
||||
private String[] getDefinedPreComments(CodeUnit cu) {
|
||||
|
||||
// If this code unit is the outside of a data
|
||||
// container, then do not display any comments.
|
||||
// If this was allowed, then the comment would appear
|
||||
// on the outside data container and on the 1st
|
||||
// internal member
|
||||
//
|
||||
// Do not show comments for nested components that share the same address as their parent
|
||||
if (cu instanceof Data) {
|
||||
Data data = (Data) cu;
|
||||
if (data.getNumComponents() > 0) {
|
||||
return null;
|
||||
int[] cpath = data.getComponentPath();
|
||||
if (cpath.length > 0) {
|
||||
if (cpath[cpath.length - 1] == 0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ import java.util.regex.Pattern;
|
|||
import docking.widgets.fieldpanel.field.AttributedString;
|
||||
import ghidra.app.nav.Navigatable;
|
||||
import ghidra.app.services.GoToService;
|
||||
import ghidra.app.services.QueryData;
|
||||
import ghidra.app.util.NamespaceUtils;
|
||||
import ghidra.framework.plugintool.ServiceProvider;
|
||||
import ghidra.program.model.address.Address;
|
||||
|
@ -142,8 +141,8 @@ public class SymbolAnnotatedStringHandler implements AnnotatedStringHandler {
|
|||
|
||||
// try going to the symbol first
|
||||
if (!symbols.isEmpty()) {
|
||||
QueryData data = new QueryData(symbols.get(0).getName(), true);
|
||||
return goToService.goToQuery(sourceNavigatable, null, data, null, null);
|
||||
Symbol s = symbols.get(0);
|
||||
return goToService.goTo(s.getProgramLocation());
|
||||
}
|
||||
|
||||
// try going to the address
|
||||
|
|
|
@ -40,8 +40,7 @@ import ghidra.program.model.pcode.*;
|
|||
import ghidra.program.model.symbol.Reference;
|
||||
import ghidra.program.model.symbol.ReferenceIterator;
|
||||
import ghidra.program.util.*;
|
||||
import ghidra.util.SystemUtilities;
|
||||
import ghidra.util.UndefinedFunction;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.InvalidInputException;
|
||||
|
||||
|
@ -157,10 +156,9 @@ public class ShowConstantUse extends GhidraScript {
|
|||
}
|
||||
|
||||
/**
|
||||
* Builds the configurable columns for the TableDialog. More columns could
|
||||
* be added.
|
||||
* Builds the configurable columns for the TableDialog. More columns could be added.
|
||||
*
|
||||
* @param tableChooserDialog
|
||||
* @param tableChooserDialog the dialog
|
||||
*/
|
||||
private void configureTableColumns(TableChooserDialog tableChooserDialog) {
|
||||
// First column added is the Constant value that is found.
|
||||
|
@ -254,8 +252,10 @@ public class ShowConstantUse extends GhidraScript {
|
|||
@Override
|
||||
public String getColumnValue(AddressableRowObject rowObject) {
|
||||
ConstUseLocation entry = (ConstUseLocation) rowObject;
|
||||
Function func = entry.getProgram().getFunctionManager().getFunctionContaining(
|
||||
entry.getAddress());
|
||||
Function func = entry.getProgram()
|
||||
.getFunctionManager()
|
||||
.getFunctionContaining(
|
||||
entry.getAddress());
|
||||
if (func == null) {
|
||||
return "";
|
||||
}
|
||||
|
@ -299,7 +299,7 @@ public class ShowConstantUse extends GhidraScript {
|
|||
* script by creating an artificial ScriptState. This is a useful technique
|
||||
* for other scripts as well.
|
||||
*
|
||||
* @return
|
||||
* @return the executor
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
private TableChooserExecutor createTableExecutor() {
|
||||
|
@ -314,23 +314,14 @@ public class ShowConstantUse extends GhidraScript {
|
|||
@Override
|
||||
public boolean execute(AddressableRowObject rowObject) {
|
||||
ConstUseLocation constLoc = (ConstUseLocation) rowObject;
|
||||
System.out.println("Follow Structure : " + rowObject.getAddress());
|
||||
println("Follow Structure : " + rowObject.getAddress());
|
||||
|
||||
Program cp = constLoc.getProgram();
|
||||
Address entry = constLoc.getAddress();
|
||||
|
||||
// If we will change something in program, have to open a
|
||||
// transaction
|
||||
int trans = cp.startTransaction("Run Script" + entry);
|
||||
try {
|
||||
System.out.println("Create Structure at " + entry);
|
||||
|
||||
runScript("CreateStructure.java", cp, entry);
|
||||
}
|
||||
finally {
|
||||
cp.endTransaction(trans, true);
|
||||
}
|
||||
println("Create Structure at " + entry);
|
||||
|
||||
runScript("CreateStructure.java", cp, entry);
|
||||
return false; // don't remove row from display table
|
||||
}
|
||||
|
||||
|
@ -347,7 +338,7 @@ public class ShowConstantUse extends GhidraScript {
|
|||
}
|
||||
}
|
||||
catch (Exception exc) {
|
||||
exc.printStackTrace();
|
||||
Msg.error(this, "Exception running script", exc);
|
||||
}
|
||||
throw new IllegalArgumentException("Script does not exist: " + name);
|
||||
}
|
||||
|
@ -393,7 +384,7 @@ public class ShowConstantUse extends GhidraScript {
|
|||
* decompiler. In the decompiler this could be a local/parameter at any
|
||||
* point in the decompiler. In the listing, it must be a parameter variable.
|
||||
*
|
||||
* @return
|
||||
* @return the varnode
|
||||
*/
|
||||
private Varnode getVarnodeLocation() {
|
||||
Varnode var = null;
|
||||
|
@ -559,7 +550,7 @@ public class ShowConstantUse extends GhidraScript {
|
|||
* - accumulate entries. Don't like passing it, but this way the
|
||||
* user gets immediate feedback as locations are found
|
||||
* @return a map of Addresses->constants (constants could be NULL)
|
||||
* @throws CancelledException
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
private HashMap<Address, Long> backtrackToConstant(Varnode var,
|
||||
TableChooserDialog tableChooserDialog) throws CancelledException {
|
||||
|
@ -587,15 +578,12 @@ public class ShowConstantUse extends GhidraScript {
|
|||
* Backtrack to a constant given a start position of a parameter of a given
|
||||
* function Useful if you want to start from a function paramter.
|
||||
*
|
||||
* @param f
|
||||
* - function to start in
|
||||
* @param paramIndex
|
||||
* - parameter index to backtrack from
|
||||
* @param tableChooserDialog
|
||||
* - accumulate entries. Don't like passing it, but this way the
|
||||
* user gets immediate feedback as locations are found
|
||||
* @return a map of Addresses->constants (constants could be NULL)
|
||||
* @throws CancelledException
|
||||
* @param f function to start in
|
||||
* @param paramIndex parameter index to backtrack from
|
||||
* @param tableChooserDialog accumulate entries. Don't like passing it, but this way the
|
||||
* user gets immediate feedback as locations are found
|
||||
* @return a map of Addresses to constants (constants could be NULL)
|
||||
* @throws CancelledException if cancelled
|
||||
*/
|
||||
private HashMap<Address, Long> backtrackParamToConstant(Function f, int paramIndex,
|
||||
TableChooserDialog tableChooserDialog) throws CancelledException {
|
||||
|
@ -699,14 +687,7 @@ public class ShowConstantUse extends GhidraScript {
|
|||
this.addConstantProblem(tableDialog, address, problem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyze a functions references
|
||||
*
|
||||
* @param constUse
|
||||
* @param funcVarUse
|
||||
* @param funcList
|
||||
*/
|
||||
public void analyzeFunction(HashMap<Address, Long> constUse, DecompInterface decompInterface,
|
||||
private void analyzeFunction(HashMap<Address, Long> constUse, DecompInterface decompInterface,
|
||||
Program prog, Function f, Address refAddr, FunctionParamUse funcVarUse, int paramIndex,
|
||||
ArrayList<PcodeOp> defUseList, ArrayList<FunctionParamUse> funcList) {
|
||||
if (f == null) {
|
||||
|
@ -722,12 +703,9 @@ public class ShowConstantUse extends GhidraScript {
|
|||
Iterator<PcodeOpAST> ops = hfunction.getPcodeOps(refAddr.getPhysicalAddress());
|
||||
while (ops.hasNext() && !monitor.isCancelled()) {
|
||||
PcodeOpAST pcodeOpAST = ops.next();
|
||||
// System.out.println(pcodeOpAST);
|
||||
if (pcodeOpAST.getOpcode() == PcodeOp.CALL) {
|
||||
// get the second parameter
|
||||
Varnode parm = pcodeOpAST.getInput(paramIndex + 1); // 1st param
|
||||
// is the
|
||||
// call dest
|
||||
Varnode parm = pcodeOpAST.getInput(paramIndex + 1); // 1st param is the call dest
|
||||
if (parm == null) {
|
||||
constUse.put(instr.getAddress(), null);
|
||||
String problem = " *** Warning, it appears that function '" +
|
||||
|
|
|
@ -42,9 +42,9 @@ public class FormatStringAnalyzer extends AbstractAnalyzer {
|
|||
private static final String[] VARIADIC_SUBSTRINGS = { "printf", "scanf" };
|
||||
private static final String NAME = "Variadic Function Signature Override";
|
||||
private static final String DESCRIPTION =
|
||||
"Detects variadic function calls in the bodies of each function that intersect the" +
|
||||
"Detects variadic function calls in the bodies of each function that intersect the " +
|
||||
"current selection and parses their format string arguments to infer the correct " +
|
||||
"signatures. Currently, this analyzer only supports printf, scanf, and thier variants " +
|
||||
"signatures. Currently, this analyzer only supports printf, scanf, and their variants " +
|
||||
"(e.g., snprintf, fscanf). If the current selection is empty, it searches through " +
|
||||
"every function. Once the correct signatures are inferred, they are overridden.";
|
||||
private final static boolean OPTION_DEFAULT_CREATE_BOOKMARKS_ENABLED = false;
|
||||
|
|
|
@ -58,7 +58,7 @@ public class RttiAnalyzer extends AbstractAnalyzer {
|
|||
setSupportsOneTimeAnalysis();
|
||||
// Set priority of RTTI analyzer to run after Demangler so can see if better
|
||||
// plate comment or label already exists from Demangler.
|
||||
setPriority(AnalysisPriority.DATA_TYPE_PROPOGATION.before().before());
|
||||
setPriority(AnalysisPriority.REFERENCE_ANALYSIS.before());
|
||||
setDefaultEnablement(true);
|
||||
validationOptions = new DataValidationOptions();
|
||||
applyOptions = new DataApplyOptions();
|
||||
|
|
|
@ -19,7 +19,6 @@ import java.util.*;
|
|||
|
||||
import ghidra.app.cmd.disassemble.DisassembleCommand;
|
||||
import ghidra.app.cmd.function.*;
|
||||
import ghidra.app.util.SymbolPath;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbException;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.RecordNumber;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.*;
|
||||
|
@ -301,9 +300,6 @@ public class FunctionSymbolApplier extends MsSymbolApplier {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
applicator.addFunctionUse(procedureSymbol, new SymbolPath(function.getSymbol()));
|
||||
|
||||
DataType dataType = applier.getDataType();
|
||||
// Since we know the applier is an AbstractionFunctionTypeApplier, then dataType is either
|
||||
// FunctionDefinition or no type (typedef).
|
||||
|
@ -317,7 +313,6 @@ public class FunctionSymbolApplier extends MsSymbolApplier {
|
|||
" due to " + sigCmd.getStatusMsg() + "; dataType: " + def.getName());
|
||||
return false;
|
||||
}
|
||||
// TODO: Move datatype to correct category
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,6 @@ import ghidra.program.model.data.*;
|
|||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.CancelOnlyWrappingTaskMonitor;
|
||||
|
@ -65,7 +64,6 @@ import ghidra.util.task.TaskMonitor;
|
|||
public class PdbApplicator {
|
||||
|
||||
private static final String THUNK_NAME_PREFIX = "[thunk]:";
|
||||
private static final SymbolPath DUMMY_SYMBOL_PATH = new SymbolPath("/");
|
||||
|
||||
//==============================================================================================
|
||||
/**
|
||||
|
@ -145,13 +143,6 @@ public class PdbApplicator {
|
|||
*/
|
||||
private Map<SymbolPath, Boolean> isClassByNamespace;
|
||||
|
||||
/**
|
||||
* Map for tracking use of procedure type records by function symbols.
|
||||
* If a type record is used more than once it will get mapped to the
|
||||
* {@link #DUMMY_SYMBOL_PATH} to indicate non-unique use.
|
||||
*/
|
||||
private Map<RecordNumber, SymbolPath> procedureSymbolNameMap;
|
||||
|
||||
//==============================================================================================
|
||||
private SymbolApplierFactory symbolApplierParser;
|
||||
|
||||
|
@ -208,7 +199,6 @@ public class PdbApplicator {
|
|||
case NONE:
|
||||
processTypes();
|
||||
processSymbols();
|
||||
renameAnonymousFunctions();
|
||||
break;
|
||||
default:
|
||||
throw new PdbException("Invalid Restriction");
|
||||
|
@ -326,7 +316,6 @@ public class PdbApplicator {
|
|||
complexApplierMapper = new ComplexTypeApplierMapper(this);
|
||||
applierDependencyGraph = new JungDirectedGraph<>();
|
||||
isClassByNamespace = new TreeMap<>();
|
||||
procedureSymbolNameMap = new HashMap<>();
|
||||
if (program != null) {
|
||||
// Currently, this must happen after symbolGroups are created.
|
||||
PdbVbtManager pdbVbtManager = new PdbVbtManager(this);
|
||||
|
@ -1246,74 +1235,6 @@ public class PdbApplicator {
|
|||
}
|
||||
}
|
||||
|
||||
void addFunctionUse(AbstractProcedureMsSymbol procedureSymbol, SymbolPath symbolPath) {
|
||||
RecordNumber rn = procedureSymbol.getTypeRecordNumber();
|
||||
SymbolPath n = procedureSymbolNameMap.get(rn);
|
||||
if (n == null) {
|
||||
procedureSymbolNameMap.put(rn, symbolPath);
|
||||
}
|
||||
else if (!symbolPath.equals(n)) {
|
||||
procedureSymbolNameMap.put(rn, DUMMY_SYMBOL_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
private void renameAnonymousFunctions() throws CancelledException {
|
||||
|
||||
monitor.setMessage("Renaming function definitions...");
|
||||
monitor.setProgress(0);
|
||||
monitor.setMaximum(procedureSymbolNameMap.size());
|
||||
int cnt = 0;
|
||||
int renamedCnt = 0;
|
||||
|
||||
for (RecordNumber rn : procedureSymbolNameMap.keySet()) {
|
||||
monitor.checkCanceled();
|
||||
monitor.setProgress(++cnt);
|
||||
SymbolPath symbolPath = procedureSymbolNameMap.get(rn);
|
||||
if (symbolPath != DUMMY_SYMBOL_PATH) {
|
||||
// unique name exists for function definition (single use)
|
||||
MsTypeApplier typeApplier = getTypeApplier(rn);
|
||||
DataType dt = typeApplier.getDataType();
|
||||
CategoryPath category = categoryUtils.getCategory(symbolPath.getParent());
|
||||
Category newCategory = dataTypeManager.createCategory(category);
|
||||
String newName = symbolPath.getName();
|
||||
|
||||
try {
|
||||
if (newCategory.getDataType(newName) == null) {
|
||||
// fast approach should generally work
|
||||
dt.setName(newName);
|
||||
dt.setCategoryPath(category);
|
||||
}
|
||||
else {
|
||||
// use slow approach if conflict exists
|
||||
DataType newDt = dt.copy(dataTypeManager);
|
||||
newDt.setName(symbolPath.getName());
|
||||
newDt.setCategoryPath(category);
|
||||
newDt = resolve(newDt);
|
||||
dataTypeManager.replaceDataType(dt, newDt, false);
|
||||
typeApplier.resolvedDataType = newDt;
|
||||
}
|
||||
++renamedCnt;
|
||||
}
|
||||
catch (InvalidNameException | DuplicateNameException
|
||||
| DataTypeDependencyException e) {
|
||||
// unexpected - skip
|
||||
Msg.error(this, "PDB Function definition rename failed: " + dt.getName() +
|
||||
" -> " + symbolPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (renamedCnt != 0) {
|
||||
Msg.debug(this, "PDB Renamed " + renamedCnt + " of " + cnt + " function definitions");
|
||||
Category anonymousCategory =
|
||||
dataTypeManager.getCategory(getAnonymousFunctionsCategory());
|
||||
if (anonymousCategory != null) {
|
||||
Msg.debug(this, "PDB Remaining anonymous function definition count: " +
|
||||
anonymousCategory.getDataTypes().length);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//==============================================================================================
|
||||
//==============================================================================================
|
||||
//==============================================================================================
|
||||
|
|
|
@ -218,8 +218,12 @@ public class GhidraPythonInterpreter extends InteractiveInterpreter {
|
|||
InetAddress localhost = InetAddress.getLocalHost();
|
||||
new Socket(localhost, PyDevUtils.PYDEV_REMOTE_DEBUGGER_PORT).close();
|
||||
Msg.info(this, "Python debugger found");
|
||||
exec("import pydevd; pydevd.settrace(host=\"" + localhost.getHostName() +
|
||||
StringBuilder dbgCmds = new StringBuilder();
|
||||
dbgCmds.append("import pydevd;");
|
||||
dbgCmds.append("pydevd.threadingCurrentThread().__pydevd_main_thread = True;");
|
||||
dbgCmds.append("pydevd.settrace(host=\"" + localhost.getHostName() +
|
||||
"\", port=" + PyDevUtils.PYDEV_REMOTE_DEBUGGER_PORT + ", suspend=False);");
|
||||
exec(dbgCmds.toString());
|
||||
Msg.info(this, "Connected to a python debugger.");
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
|
|
@ -454,7 +454,7 @@ public class GraphComponent<V extends VisualVertex, E extends VisualEdge<V>, G e
|
|||
mainStalePanel.setOpaque(false);
|
||||
|
||||
String tooltip = HTMLUtilities.toWrappedHTML("The block model of the function " +
|
||||
"for this graph has changed. Press the relyout button to refresh the layout." +
|
||||
"for this graph has changed. Press the relayout button to refresh the layout." +
|
||||
"\n\n") + "<b>Note: </b>You can edit the graph " +
|
||||
"options to have the graph update automatically.";
|
||||
|
||||
|
|
31
Ghidra/Framework/SoftwareModeling/Sleigh.launch
Normal file
31
Ghidra/Framework/SoftwareModeling/Sleigh.launch
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<launchConfiguration type="org.eclipse.jdt.launching.localJavaApplication">
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
|
||||
<listEntry value="/Framework Utility/src/main/java/ghidra/GhidraLauncher.java"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="1"/>
|
||||
</listAttribute>
|
||||
<mapAttribute key="org.eclipse.debug.core.preferred_launchers">
|
||||
<mapEntry key="[debug]" value="org.eclipse.jdt.launching.localJavaApplication"/>
|
||||
<mapEntry key="[run]" value="org.eclipse.jdt.launching.localJavaApplication"/>
|
||||
</mapAttribute>
|
||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
||||
</listAttribute>
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_CLASSPATH_ONLY_JAR" value="false"/>
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.ATTR_USE_START_ON_FIRST_THREAD" value="true"/>
|
||||
<listAttribute key="org.eclipse.jdt.launching.CLASSPATH">
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry path="5" projectName="Framework Utility" type="1"/> "/>
|
||||
</listAttribute>
|
||||
<booleanAttribute key="org.eclipse.jdt.launching.DEFAULT_CLASSPATH" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="ghidra.GhidraLauncher"/>
|
||||
<listAttribute key="org.eclipse.jdt.launching.MODULEPATH">
|
||||
<listEntry value="<?xml version="1.0" encoding="UTF-8" standalone="no"?> <runtimeClasspathEntry containerPath="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11" path="4" type="4"/> "/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="ghidra.pcodeCPort.slgh_compile.SleighCompileLauncher -DBaseDir="${project_loc}/../../../../" -i "${project_loc}/build/tmp/sleighArgs.txt" -a "${project_loc}/data/languages""/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Framework Utility"/>
|
||||
<stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-Djava.awt.headless=true -Xmx1048M -XX:+IgnoreUnrecognizedVMOptions -Djava.system.class.loader=ghidra.GhidraClassLoader -Dfile.encoding=UTF-8 -Duser.country=US -Duser.language=en -Duser.variant -Xdock:name="Sleigh" -Dvisualvm.display.name=Sleigh"/>
|
||||
</launchConfiguration>
|
|
@ -239,7 +239,7 @@ public class VariableStorage implements Comparable<VariableStorage> {
|
|||
}
|
||||
if (i < (varnodes.length - 1) && !isRegister) {
|
||||
throw new InvalidInputException(
|
||||
"Compound storage must use registers accept for last varnode");
|
||||
"Compound storage must use registers except for last varnode");
|
||||
}
|
||||
size += varnode.getSize();
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ import ghidra.util.exception.*;
|
|||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class MIPS_ElfExtension extends ElfExtension {
|
||||
|
||||
|
||||
private static final String MIPS_STUBS_SECTION_NAME = ".MIPS.stubs";
|
||||
|
||||
// GP value reflected by symbol address
|
||||
|
@ -287,9 +287,13 @@ public class MIPS_ElfExtension extends ElfExtension {
|
|||
public static final byte ODK_IDENT = 10;
|
||||
public static final byte ODK_PAGESIZE = 11;
|
||||
|
||||
// MIPS-specific SHN values
|
||||
public static final short SHN_MIPS_ACOMMON = (short) 0xff00;
|
||||
public static final short SHN_MIPS_TEXT = (short) 0xff01;
|
||||
public static final short SHN_MIPS_DATA = (short) 0xff02;
|
||||
|
||||
@Override
|
||||
public boolean canHandle(ElfHeader elf) {
|
||||
// TODO: Verify 64-bit MIPS support
|
||||
return elf.e_machine() == ElfConstants.EM_MIPS;
|
||||
}
|
||||
|
||||
|
@ -328,6 +332,25 @@ public class MIPS_ElfExtension extends ElfExtension {
|
|||
return functionAddress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address calculateSymbolAddress(ElfLoadHelper elfLoadHelper, ElfSymbol elfSymbol)
|
||||
throws NoValueException {
|
||||
|
||||
short sectionIndex = elfSymbol.getSectionHeaderIndex();
|
||||
if (!ElfSectionHeaderConstants.isProcessorSpecificSymbolSectionIndex(sectionIndex)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (sectionIndex == SHN_MIPS_ACOMMON || sectionIndex == SHN_MIPS_TEXT || sectionIndex == SHN_MIPS_DATA) {
|
||||
// NOTE: logic assumes no memory conflict occured during section loading
|
||||
AddressSpace defaultSpace = elfLoadHelper.getProgram().getAddressFactory().getDefaultAddressSpace();
|
||||
return defaultSpace.getAddress(elfSymbol.getValue() + elfLoadHelper.getImageBaseWordAdjustmentOffset());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Address evaluateElfSymbol(ElfLoadHelper elfLoadHelper, ElfSymbol elfSymbol,
|
||||
Address address, boolean isExternal) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<site>
|
||||
<feature url="features/ghidra.ghidradev_2.1.1.qualifier.jar" id="ghidra.ghidradev" version="2.1.1.qualifier">
|
||||
<feature id="ghidra.ghidradev">
|
||||
<category name="ghidra.ghidradev"/>
|
||||
</feature>
|
||||
<category-def name="ghidra.ghidradev" label="Ghidra"/>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<feature
|
||||
id="ghidra.ghidradev"
|
||||
label="GhidraDev"
|
||||
version="2.1.1.qualifier"
|
||||
version="2.1.2.qualifier"
|
||||
provider-name="Ghidra">
|
||||
|
||||
<description>
|
||||
|
|
|
@ -53,6 +53,8 @@ change with future releases.</p>
|
|||
</ul>
|
||||
|
||||
<h2><a name="ChangeHistory"></a>Change History</h2>
|
||||
<p><u><b>2.1.2</b>:</u> Fixed exception that occurred when creating a new Ghidra scripting project
|
||||
if a <i>~/ghidra_scripts</i> directory does not exist.</p>
|
||||
<p><u><b>2.1.1</b>:</u>
|
||||
<ul>
|
||||
<li>
|
||||
|
|
|
@ -3,7 +3,7 @@ Manifest-Version: 1.0
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: GhidraDev
|
||||
Bundle-SymbolicName: ghidra.ghidradev;singleton:=true
|
||||
Bundle-Version: 2.1.1.qualifier
|
||||
Bundle-Version: 2.1.2.qualifier
|
||||
Bundle-Activator: ghidradev.Activator
|
||||
Require-Bundle: org.eclipse.ant.core;bundle-version="3.5.200",
|
||||
org.eclipse.buildship.core;bundle-version="3.0.0",
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.eclipse.jdt.core.*;
|
|||
|
||||
import ghidra.GhidraApplicationLayout;
|
||||
import ghidra.framework.GModule;
|
||||
import ghidradev.Activator;
|
||||
|
||||
/**
|
||||
* Utility methods for working with Ghidra scripts in Eclipse.
|
||||
|
@ -87,6 +88,12 @@ public class GhidraScriptUtils {
|
|||
|
||||
// Link in the user's personal ghidra_scripts directory
|
||||
if (linkUserScripts) {
|
||||
if (!userScriptsDir.isDirectory()) {
|
||||
if (!userScriptsDir.mkdirs()) {
|
||||
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
|
||||
IStatus.ERROR, "Failed to create " + userScriptsDir, null));
|
||||
}
|
||||
}
|
||||
IFolder link = javaProject.getProject().getFolder("Home scripts");
|
||||
link.createLink(new Path(userScriptsDir.getAbsolutePath()), IResource.NONE, monitor);
|
||||
classpathEntries.add(JavaCore.newSourceEntry(link.getFullPath()));
|
||||
|
|
Loading…
Reference in New Issue
Block a user