Merge remote-tracking branch 'origin/master' into debugger

This commit is contained in:
Dan 2021-02-16 10:22:19 -05:00
commit 3093e2dd2a
32 changed files with 283 additions and 645 deletions

View file

@ -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.

View file

@ -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="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;sourceLookupDirector&gt;&#10; &lt;sourceContainers duplicates=&quot;false&quot;&gt;&#10; &lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;classpathContainer path=&amp;quot;org.eclipse.jdt.launching.JRE_CONTAINER&amp;quot;/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.jdt.launching.sourceContainer.classpathContainer&quot;/&gt;&#10; &lt;container memento=&quot;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; standalone=&amp;quot;no&amp;quot;?&amp;gt;&amp;#10;&amp;lt;default/&amp;gt;&amp;#10;&quot; typeId=&quot;org.eclipse.debug.core.containerType.default&quot;/&gt;&#10; &lt;/sourceContainers&gt;&#10;&lt;/sourceLookupDirector&gt;&#10;"/>
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">

View file

@ -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;
}
}
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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>

View file

@ -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>

View file

@ -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));
}
}

View file

@ -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);
}

View file

@ -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
*/

View file

@ -183,6 +183,9 @@ public class ElfDefaultGotPltMarkup {
monitor.checkCanceled();
Data data = createPointer(gotStart, true);
if (data == null) {
break;
}
try {
gotStart = data.getMaxAddress().add(1);

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -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

View file

@ -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;
}
}
}

View file

@ -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

View file

@ -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 '" +

View file

@ -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;

View file

@ -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();

View file

@ -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;
}

View file

@ -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);
}
}
}
//==============================================================================================
//==============================================================================================
//==============================================================================================

View file

@ -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) {

View file

@ -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.";

View 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="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry path=&quot;5&quot; projectName=&quot;Framework Utility&quot; type=&quot;1&quot;/&gt;&#10;"/>
</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="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; standalone=&quot;no&quot;?&gt;&#10;&lt;runtimeClasspathEntry containerPath=&quot;org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11&quot; path=&quot;4&quot; type=&quot;4&quot;/&gt;&#10;"/>
</listAttribute>
<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="ghidra.pcodeCPort.slgh_compile.SleighCompileLauncher -DBaseDir=&quot;${project_loc}/../../../../&quot; -i &quot;${project_loc}/build/tmp/sleighArgs.txt&quot; -a &quot;${project_loc}/data/languages&quot;"/>
<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=&quot;Sleigh&quot; -Dvisualvm.display.name=Sleigh"/>
</launchConfiguration>

View file

@ -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();
}

View file

@ -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) {

View file

@ -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"/>

View file

@ -2,7 +2,7 @@
<feature
id="ghidra.ghidradev"
label="GhidraDev"
version="2.1.1.qualifier"
version="2.1.2.qualifier"
provider-name="Ghidra">
<description>

View file

@ -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>

View file

@ -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",

View file

@ -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()));