mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-21 11:31:43 +00:00
Merge remote-tracking branch 'origin/GP-1659_SwitchWithInject' into
patch
This commit is contained in:
commit
e5080cd9b1
@ -34,7 +34,7 @@ You may not need all of these, depending on which portions you are building or d
|
||||
- https://adoptium.net/releases.html?variant=openjdk11&jvmVariant=hotspot
|
||||
- Amazon Corretto
|
||||
- https://docs.aws.amazon.com/corretto/latest/corretto-11-ug/downloads-list.html
|
||||
* Gradle 6.4+ or 7.x
|
||||
* Gradle 6.8+ or 7.x
|
||||
- https://gradle.org/releases/
|
||||
* 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/
|
||||
|
@ -17,6 +17,7 @@ package agent.gdb.pty.ssh;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CancellationException;
|
||||
|
||||
import javax.swing.JOptionPane;
|
||||
|
||||
@ -28,7 +29,8 @@ import com.jcraft.jsch.ConfigRepository.Config;
|
||||
import agent.gdb.pty.PtyFactory;
|
||||
import docking.DockingWindowManager;
|
||||
import docking.widgets.PasswordDialog;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.StringUtilities;
|
||||
|
||||
public class GhidraSshPtyFactory implements PtyFactory {
|
||||
private static final String TITLE = "GDB via SSH";
|
||||
@ -209,6 +211,10 @@ public class GhidraSshPtyFactory implements PtyFactory {
|
||||
return session;
|
||||
}
|
||||
catch (JSchException e) {
|
||||
if (e.getMessage().equals("Auth cancel")) {
|
||||
Msg.error(this, "SSH connection canceled");
|
||||
throw new CancellationException("SSH connection canceled");
|
||||
}
|
||||
Msg.error(this, "SSH connection error");
|
||||
throw new IOException("SSH connection error", e);
|
||||
}
|
||||
|
@ -1333,7 +1333,7 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI {
|
||||
commaIndex--;
|
||||
}
|
||||
|
||||
String shortenedName = className.substring(0, nextComma) + " ...>";
|
||||
String shortenedName = className.substring(0, nextComma) + "...>";
|
||||
return shortenedName;
|
||||
}
|
||||
|
||||
|
@ -755,6 +755,8 @@ void FlowInfo::generateOps(void)
|
||||
addrlist.push_back(data.getAddress());
|
||||
while(!addrlist.empty()) // Recovering as much as possible except jumptables
|
||||
fallthru();
|
||||
if (hasInject())
|
||||
injectPcode();
|
||||
do {
|
||||
bool collapsed_jumptable = false;
|
||||
while(!tablelist.empty()) { // For each jumptable found
|
||||
|
35
Ghidra/Features/PDB/developer_scripts/PdbQueryActivator.java
Normal file
35
Ghidra/Features/PDB/developer_scripts/PdbQueryActivator.java
Normal file
@ -0,0 +1,35 @@
|
||||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
import org.osgi.framework.BundleContext;
|
||||
|
||||
import ghidra.app.plugin.core.osgi.GhidraBundleActivator;
|
||||
import pdbquery.PdbFactory;
|
||||
|
||||
/**
|
||||
* Activator class for the PdbQuery bundle of scripts. On "stop," calls method to close all PDBs.
|
||||
*/
|
||||
public class PdbQueryActivator extends GhidraBundleActivator {
|
||||
@Override
|
||||
protected void start(BundleContext bc, Object api) {
|
||||
// purposefully empty
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void stop(BundleContext bc, Object api) {
|
||||
PdbFactory.closeAllPdbs(null);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
// Closes all PDBs opened in the PdbQuery package.
|
||||
//
|
||||
//@category PDB
|
||||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import pdbquery.PdbFactory;
|
||||
|
||||
public class PdbQueryCloseAllScript extends GhidraScript {
|
||||
|
||||
@Override
|
||||
protected void run() throws Exception {
|
||||
PdbFactory.closeAllPdbs(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
// Closes a user-selected PDB that was opened in the PdbQuery package.
|
||||
//
|
||||
//@category PDB
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import pdbquery.PdbFactory;
|
||||
import pdbquery.PdbFactory.PdbInfo;
|
||||
|
||||
public class PdbQueryCloseScript extends GhidraScript {
|
||||
|
||||
@Override
|
||||
protected void run() throws Exception {
|
||||
|
||||
List<PdbInfo> orderedPdbInfo = PdbFactory.getPdbInfo();
|
||||
if (orderedPdbInfo.isEmpty()) {
|
||||
println("There are no open PDBs. Run " + PdbQueryOpenScript.class.getSimpleName() +
|
||||
" to open a PDB.");
|
||||
return;
|
||||
}
|
||||
PdbInfo lastPdbInfo = PdbFactory.getLastPdbInfoByScriptClass(getClass());
|
||||
|
||||
PdbInfo choice = askChoice("Choose PDB to Close", "PDB Info", orderedPdbInfo, lastPdbInfo);
|
||||
|
||||
PdbFactory.closePdb(this, choice.getFilename());
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
// Queries a PDB in PdbQuery package for data and item type records that contain the search string.
|
||||
//
|
||||
//@category PDB
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractPdb;
|
||||
import pdbquery.PdbFactory;
|
||||
import pdbquery.PdbFactory.PdbInfo;
|
||||
import pdbquery.PdbQuery;
|
||||
|
||||
public class PdbQueryDatatypeScript extends GhidraScript {
|
||||
|
||||
@Override
|
||||
protected void run() throws Exception {
|
||||
|
||||
List<PdbInfo> orderedPdbInfo = PdbFactory.getPdbInfo();
|
||||
if (orderedPdbInfo.isEmpty()) {
|
||||
println("There are no open PDBs. Run " + PdbQueryOpenScript.class.getSimpleName() +
|
||||
" to open a PDB.");
|
||||
return;
|
||||
}
|
||||
PdbInfo lastPdbInfo = PdbFactory.getLastPdbInfoByScriptClass(getClass());
|
||||
PdbInfo choice = askChoice("Choose PDB to query", "PDB Info", orderedPdbInfo, lastPdbInfo);
|
||||
|
||||
AbstractPdb pdb = choice.getPdb();
|
||||
|
||||
String searchString = askString("Enter Search String", "String");
|
||||
println("Searching " + choice.getFilename() + " for: " + searchString);
|
||||
|
||||
PdbQuery.searchDataTypes(this, pdb, searchString);
|
||||
PdbQuery.searchItemTypes(this, pdb, searchString);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
// Opens a PDB for the PdbQuery package.
|
||||
//
|
||||
//@category PDB
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.PdbIdentifiers;
|
||||
import pdb.PdbUtils;
|
||||
import pdbquery.PdbFactory;
|
||||
|
||||
public class PdbQueryOpenScript extends GhidraScript {
|
||||
|
||||
@Override
|
||||
protected void run() throws Exception {
|
||||
File pdbFile = askFile("Choose a PDB file", "OK");
|
||||
if (pdbFile == null) {
|
||||
println("Aborting: no file chosen.");
|
||||
return;
|
||||
}
|
||||
|
||||
String pdbFilename = pdbFile.getAbsolutePath();
|
||||
|
||||
if (!pdbFile.exists()) {
|
||||
println("Aborting: " + pdbFilename + " is not a valid file.");
|
||||
return;
|
||||
}
|
||||
if (!StringUtils.endsWithIgnoreCase(pdbFilename, ".pdb")) {
|
||||
println("Aborting: filename missing .pdb extension: " + pdbFilename);
|
||||
return;
|
||||
}
|
||||
|
||||
PdbIdentifiers identifiers = PdbUtils.getPdbIdentifiers(pdbFile, monitor);
|
||||
|
||||
String fileAndIdentifiers =
|
||||
pdbFilename + ", " + identifiers + " (File, GUID/Signature, Age, Version, Processor)";
|
||||
if (!askYesNo("Confirm Load", fileAndIdentifiers)) {
|
||||
println("Aborting: " + pdbFilename + " not confirmed.");
|
||||
return;
|
||||
}
|
||||
|
||||
PdbFactory.openPdb(this, pdbFilename, monitor);
|
||||
println("PDB Opened: " + fileAndIdentifiers);
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
// Queries a PDB in PdbQuery package for Symbol records that contain the search string.
|
||||
//
|
||||
//@category PDB
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.AbstractPdb;
|
||||
import pdbquery.PdbFactory;
|
||||
import pdbquery.PdbFactory.PdbInfo;
|
||||
import pdbquery.PdbQuery;
|
||||
|
||||
public class PdbQuerySymbolScript extends GhidraScript {
|
||||
|
||||
@Override
|
||||
protected void run() throws Exception {
|
||||
|
||||
List<PdbInfo> orderedPdbInfo = PdbFactory.getPdbInfo();
|
||||
if (orderedPdbInfo.isEmpty()) {
|
||||
println("There are no open PDBs. Run " + PdbQueryOpenScript.class.getSimpleName() +
|
||||
" to open a PDB.");
|
||||
return;
|
||||
}
|
||||
PdbInfo lastPdbInfo = PdbFactory.getLastPdbInfoByScriptClass(getClass());
|
||||
PdbInfo choice = askChoice("Choose PDB to query", "PDB Info", orderedPdbInfo, lastPdbInfo);
|
||||
|
||||
AbstractPdb pdb = choice.getPdb();
|
||||
|
||||
String searchString = askString("Enter Search String", "String");
|
||||
println("Searching " + choice.getFilename() + " for: " + searchString);
|
||||
|
||||
PdbQuery.searchSymbols(this, pdb, searchString);
|
||||
}
|
||||
}
|
242
Ghidra/Features/PDB/developer_scripts/pdbquery/PdbFactory.java
Normal file
242
Ghidra/Features/PDB/developer_scripts/pdbquery/PdbFactory.java
Normal file
@ -0,0 +1,242 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package pdbquery;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Helper class for the PdbQuery set of scripts that allows the PdbQuery scripts to manage the
|
||||
* opening, holding open (caching), and closing of PDB files so that multiple user queries can
|
||||
* be run against the PDBs. Without this notion, if a user wanted to query a PDB with multiple
|
||||
* runs of a query scripts, each run would have to, once again, open and parse the PDB file
|
||||
* that is desired, which could take minutes or longer.
|
||||
*/
|
||||
public class PdbFactory {
|
||||
|
||||
private static TreeMap<String, PdbInfo> pdbInfoByFile = new TreeMap<>();
|
||||
private static Map<Class<? extends GhidraScript>, PdbInfo> pdbInfoByScriptClass =
|
||||
new HashMap<>();
|
||||
|
||||
/**
|
||||
* Opens and retains reference to the PDB file specified. Must call
|
||||
* {@link #closePdb(GhidraScript, String)} to close the PDB and remove it from the map; can
|
||||
* alternatively use {@link #closeAllPdbs(GhidraScript)} to close all PDBs in the map.
|
||||
* @param script script for which we are working
|
||||
* @param filename name of PDB file to open and load into map
|
||||
* @param monitor task monitor
|
||||
* @return PDB associated with the filename
|
||||
* @throws CancelledException upon user cancellation
|
||||
* @throws PdbException upon issues parsing the PDB
|
||||
*/
|
||||
public static PdbInfo openPdb(GhidraScript script, String filename, TaskMonitor monitor)
|
||||
throws CancelledException, PdbException {
|
||||
PdbInfo pdbInfo = pdbInfoByFile.get(filename);
|
||||
if (pdbInfo != null) {
|
||||
return pdbInfo;
|
||||
}
|
||||
|
||||
println(script, "Opening PDB: " + filename);
|
||||
|
||||
try {
|
||||
AbstractPdb pdb = PdbParser.parse(filename, new PdbReaderOptions(), monitor);
|
||||
PdbIdentifiers identifiers = pdb.getIdentifiers();
|
||||
pdb.deserialize(monitor);
|
||||
PdbReaderMetrics metrics = pdb.getPdbReaderMetrics();
|
||||
pdbInfo = new PdbInfo(filename, identifiers, pdb, metrics);
|
||||
pdbInfoByFile.put(filename, pdbInfo);
|
||||
println(script, "\n" + metrics.getPostProcessingReport());
|
||||
return pdbInfo;
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
println(script, ioe.getMessage());
|
||||
Msg.debug(null, ioe.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes and unloads the PDB file from the map. Not removed from map if IOException.
|
||||
* @param script script for which we are working
|
||||
* @param filename filename of the PDB file
|
||||
* @return true if successfully closed and removed from the map; false if not found in the map
|
||||
* or if problem closing the PDB.
|
||||
*/
|
||||
public static boolean closePdb(GhidraScript script, String filename) {
|
||||
boolean success = closePdbInternal(script, filename);
|
||||
if (success) {
|
||||
pdbInfoByFile.remove(filename);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes and unloads the PDB file from the map. Not removed from map if IOException.
|
||||
* @param script script for which we are working
|
||||
* @return true if all PDBs were successfully closed and unloaded from the map
|
||||
*/
|
||||
public static boolean closeAllPdbs(GhidraScript script) {
|
||||
boolean allUnloaded = true;
|
||||
Iterator<Entry<String, PdbInfo>> iterator = pdbInfoByFile.entrySet().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Entry<String, PdbInfo> entry = iterator.next();
|
||||
String filename = entry.getKey();
|
||||
boolean success = closePdbInternal(script, filename);
|
||||
if (success) {
|
||||
iterator.remove();
|
||||
}
|
||||
allUnloaded &= success;
|
||||
}
|
||||
return allUnloaded;
|
||||
}
|
||||
|
||||
private static boolean closePdbInternal(GhidraScript script, String filename) {
|
||||
PdbInfo pdbInfo = pdbInfoByFile.get(filename);
|
||||
AbstractPdb pdb = pdbInfo.getPdb();
|
||||
if (pdb != null) {
|
||||
try {
|
||||
pdb.close();
|
||||
String message = "PDB Closed: " + filename;
|
||||
println(script, message);
|
||||
}
|
||||
catch (IOException ioe) {
|
||||
println(script, ioe.getMessage());
|
||||
Msg.info(null, ioe.getMessage());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of PDB information in alphabetical order by filename.
|
||||
* @return the list
|
||||
*/
|
||||
public static List<PdbInfo> getPdbInfo() {
|
||||
List<PdbInfo> orderedPdbInfo = new ArrayList<>();
|
||||
for (String name : pdbInfoByFile.navigableKeySet()) {
|
||||
orderedPdbInfo.add(pdbInfoByFile.get(name));
|
||||
}
|
||||
return orderedPdbInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache PdbInfo value for the class argument
|
||||
* @param clazz the class for which to cache the value
|
||||
* @param pdbInfo the PdbInfo value to cache.
|
||||
*/
|
||||
public static void setLastPdbInfoByScriptClass(Class<? extends GhidraScript> clazz,
|
||||
PdbInfo pdbInfo) {
|
||||
pdbInfoByScriptClass.put(clazz, pdbInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PdbInfo cached for the class argument.
|
||||
* @param clazz the class of the script used to look up the cached value for return
|
||||
* @return the PdbInfo
|
||||
*/
|
||||
public static PdbInfo getLastPdbInfoByScriptClass(Class<? extends GhidraScript> clazz) {
|
||||
return pdbInfoByScriptClass.get(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for outputting a message to the console (if script is not null); otherwise outputs
|
||||
* the message to Msg.info().
|
||||
* @param script the script
|
||||
* @param message the message to output to the console
|
||||
*/
|
||||
private static void println(GhidraScript script, String message) {
|
||||
if (script != null) {
|
||||
script.println(message);
|
||||
}
|
||||
else {
|
||||
Msg.info(PdbFactory.class, message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about a PDB used for specifying and uniquely identifying a PDB along with the
|
||||
* parsed PDB itself and the PDB parsing metrics generated during the parse.
|
||||
*/
|
||||
public static class PdbInfo {
|
||||
private String filename; // absolute pathname
|
||||
private PdbIdentifiers identifiers;
|
||||
private AbstractPdb pdb;
|
||||
private PdbReaderMetrics metrics;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* @param filename PDB filename in absolute pathname format
|
||||
* @param identifiers identifiers used to help identify versions of the PDB
|
||||
* @param pdb the parsed PDB
|
||||
* @param metrics the PDB metrics generated when the PDB was opened and parsed
|
||||
*/
|
||||
PdbInfo(String filename, PdbIdentifiers identifiers, AbstractPdb pdb,
|
||||
PdbReaderMetrics metrics) {
|
||||
this.filename = filename;
|
||||
this.identifiers = identifiers;
|
||||
this.pdb = pdb;
|
||||
this.metrics = metrics;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the PDB filename in absolute path format
|
||||
* @return the filename
|
||||
*/
|
||||
public String getFilename() {
|
||||
return filename;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the parsed PDB
|
||||
* @return the parsed PDB
|
||||
*/
|
||||
public AbstractPdb getPdb() {
|
||||
return pdb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns PDB identifiers that help specify its version
|
||||
* @return the identifiers
|
||||
*/
|
||||
public PdbIdentifiers getIdentifiers() {
|
||||
return identifiers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the metrics generated during PDB parsing
|
||||
* @return the metrics
|
||||
*/
|
||||
public PdbReaderMetrics getPdbReaderMetrics() {
|
||||
return metrics;
|
||||
}
|
||||
|
||||
@Override
|
||||
// The PDB and parsing metrics are purposefully not included in this output.
|
||||
public String toString() {
|
||||
return filename + "; " + identifiers;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
251
Ghidra/Features/PDB/developer_scripts/pdbquery/PdbQuery.java
Normal file
251
Ghidra/Features/PDB/developer_scripts/pdbquery/PdbQuery.java
Normal file
@ -0,0 +1,251 @@
|
||||
/* ###
|
||||
* IP: GHIDRA
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package pdbquery;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import ghidra.app.script.GhidraScript;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.*;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.symbol.AbstractMsSymbol;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.AbstractMsType;
|
||||
import ghidra.app.util.bin.format.pdb2.pdbreader.type.PrimitiveMsType;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Helper class with static query methods available to PdbQuery set of scripts. The methods
|
||||
* in this class allow the user to query particular components inside of a PDB.
|
||||
*/
|
||||
public class PdbQuery {
|
||||
|
||||
/**
|
||||
* Returns the specified PDB data type record.
|
||||
* @param script the script for which we are working
|
||||
* @param pdb the PDB containing the record
|
||||
* @param number the data type record number
|
||||
* @return the data type record
|
||||
*/
|
||||
public static AbstractMsType getDataTypeRecord(GhidraScript script, AbstractPdb pdb,
|
||||
int number) {
|
||||
AbstractTypeProgramInterface tpi = pdb.getTypeProgramInterface();
|
||||
if (tpi == null) {
|
||||
println(script, "PDB does not contain a TPI... aborting search.");
|
||||
return null;
|
||||
}
|
||||
if (number < 0 || number >= tpi.getTypeIndexMaxExclusive()) {
|
||||
println(script, "Record number (" + number + ") out of range (" + 0 + " - " +
|
||||
tpi.getTypeIndexMaxExclusive() + ")");
|
||||
return null;
|
||||
}
|
||||
if (number < tpi.getTypeIndexMin()) {
|
||||
// Created on the fly and is not cached. Moreover, it can add yet-unseen records to
|
||||
// the PDB... so this might not be desired... Also... the record number could represent
|
||||
// what is typically a "type" or an "item" and that cannot be distingushed here...
|
||||
// there is not conflict between primitive type and primitive items... they come from
|
||||
// the same pool, but we might return what is an item record in the request for a type
|
||||
// record or vice versa. TODO: investigate all of these issues this further; might
|
||||
// need to eliminate this report or add a lot more code.
|
||||
return new PrimitiveMsType(pdb, number);
|
||||
}
|
||||
RecordNumber recordNumber = RecordNumber.typeRecordNumber(number);
|
||||
AbstractMsType typeRecord = pdb.getTypeRecord(recordNumber);
|
||||
return typeRecord;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the specified PDB item record.
|
||||
* @param script the script for which we are working
|
||||
* @param pdb the PDB containing the record
|
||||
* @param number the item record number
|
||||
* @return the item record
|
||||
*/
|
||||
public static AbstractMsType getItemTypeRecord(GhidraScript script, AbstractPdb pdb,
|
||||
int number) {
|
||||
AbstractTypeProgramInterface ipi = pdb.getItemProgramInterface();
|
||||
if (ipi == null) {
|
||||
println(script, "PDB does not contain an IPI... aborting search.");
|
||||
return null;
|
||||
}
|
||||
if (number < 0 || number >= ipi.getTypeIndexMaxExclusive()) {
|
||||
println(script, "Record number (" + number + ") out of range (" + 0 + " - " +
|
||||
ipi.getTypeIndexMaxExclusive() + ")");
|
||||
return null;
|
||||
}
|
||||
if (number < ipi.getTypeIndexMin()) {
|
||||
// Created on the fly and is not cached. Moreover, it can add yet-unseen records to
|
||||
// the PDB... so this might not be desired... Also... the record number could represent
|
||||
// what is typically a "type" or an "item" and that cannot be distingushed here...
|
||||
// there is not conflict between primitive type and primitive items... they come from
|
||||
// the same pool, but we might return what is an item record in the request for a type
|
||||
// record or vice versa. TODO: investigate all of these issues this further; might
|
||||
// need to eliminate this report or add a lot more code.
|
||||
return new PrimitiveMsType(pdb, number);
|
||||
}
|
||||
RecordNumber recordNumber = RecordNumber.itemRecordNumber(number);
|
||||
AbstractMsType typeRecord = pdb.getTypeRecord(recordNumber);
|
||||
return typeRecord;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches PDB data type records that contain the search string. Outputs results to the
|
||||
* console.
|
||||
* @param script the script for which we are working
|
||||
* @param pdb the PDB to search
|
||||
* @param searchString the search string
|
||||
* @throws CancelledException upon user cancellation
|
||||
*/
|
||||
public static void searchDataTypes(GhidraScript script, AbstractPdb pdb, String searchString)
|
||||
throws CancelledException {
|
||||
AbstractTypeProgramInterface tpi = pdb.getTypeProgramInterface();
|
||||
if (tpi == null) {
|
||||
println(script, "PDB does not contain a TPI... aborting search.");
|
||||
}
|
||||
|
||||
StringBuilder results = new StringBuilder();
|
||||
results.append('\n');
|
||||
|
||||
int num = tpi.getTypeIndexMaxExclusive() - tpi.getTypeIndexMin();
|
||||
TaskMonitor monitor = script.getMonitor();
|
||||
monitor.initialize(num);
|
||||
println(script, "Searching " + num + " PDB data type components...");
|
||||
for (int indexNumber =
|
||||
tpi.getTypeIndexMin(); indexNumber < tpi.getTypeIndexMaxExclusive(); indexNumber++) {
|
||||
monitor.checkCanceled();
|
||||
RecordNumber recordNumber = RecordNumber.typeRecordNumber(indexNumber);
|
||||
AbstractMsType typeRecord = pdb.getTypeRecord(recordNumber);
|
||||
String recordString = typeRecord.toString();
|
||||
if (recordString.contains(searchString)) {
|
||||
results.append("Data number " + indexNumber + ":\n");
|
||||
results.append(recordString);
|
||||
results.append('\n');
|
||||
}
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
println(script, results.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches PDB item records that contain the search string. Outputs results to the
|
||||
* console.
|
||||
* @param script the script for which we are working
|
||||
* @param pdb the PDB to search
|
||||
* @param searchString the search string
|
||||
* @throws CancelledException upon user cancellation
|
||||
*/
|
||||
public static void searchItemTypes(GhidraScript script, AbstractPdb pdb, String searchString)
|
||||
throws CancelledException {
|
||||
AbstractTypeProgramInterface ipi = pdb.getItemProgramInterface();
|
||||
if (ipi == null) {
|
||||
println(script, "PDB does not contain an IPI... aborting search.");
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder results = new StringBuilder();
|
||||
results.append('\n');
|
||||
|
||||
int num = ipi.getTypeIndexMaxExclusive() - ipi.getTypeIndexMin();
|
||||
TaskMonitor monitor = script.getMonitor();
|
||||
monitor.initialize(num);
|
||||
println(script, "Searching " + num + " PDB item type components...");
|
||||
for (int indexNumber =
|
||||
ipi.getTypeIndexMin(); indexNumber < ipi.getTypeIndexMaxExclusive(); indexNumber++) {
|
||||
monitor.checkCanceled();
|
||||
RecordNumber recordNumber = RecordNumber.itemRecordNumber(indexNumber);
|
||||
AbstractMsType typeRecord = pdb.getTypeRecord(recordNumber);
|
||||
String recordString = typeRecord.toString();
|
||||
if (recordString.contains(searchString)) {
|
||||
results.append("Item number " + indexNumber + ":\n");
|
||||
results.append(recordString);
|
||||
results.append('\n');
|
||||
}
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
println(script, results.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches PDB symbol records that contain the search string. Outputs results to the
|
||||
* console.
|
||||
* @param script the script for which we are working
|
||||
* @param pdb the PDB to search
|
||||
* @param searchString the search string
|
||||
* @throws CancelledException upon user cancellation
|
||||
*/
|
||||
public static void searchSymbols(GhidraScript script, AbstractPdb pdb, String searchString)
|
||||
throws CancelledException {
|
||||
|
||||
StringBuilder results = new StringBuilder();
|
||||
results.append('\n');
|
||||
|
||||
int numModules = pdb.getDebugInfo().getNumModules();
|
||||
TaskMonitor monitor = script.getMonitor();
|
||||
int numSymbols = 0;
|
||||
for (int module = 0; module <= numModules; module++) {
|
||||
monitor.checkCanceled();
|
||||
try {
|
||||
Map<Long, AbstractMsSymbol> symbols =
|
||||
pdb.getDebugInfo().getModuleSymbolsByOffset(module);
|
||||
numSymbols += symbols.size();
|
||||
}
|
||||
catch (PdbException e) {
|
||||
// just skip the module... logging this in the next loop.
|
||||
}
|
||||
}
|
||||
|
||||
monitor.initialize(numSymbols);
|
||||
println(script, "Searching " + numSymbols + " PDB symbol components...");
|
||||
for (int module = 0; module <= numModules; module++) {
|
||||
monitor.checkCanceled();
|
||||
try {
|
||||
Map<Long, AbstractMsSymbol> symbols =
|
||||
pdb.getDebugInfo().getModuleSymbolsByOffset(module);
|
||||
numSymbols += symbols.size();
|
||||
for (Map.Entry<Long, AbstractMsSymbol> entry : symbols.entrySet()) {
|
||||
monitor.checkCanceled();
|
||||
AbstractMsSymbol symbol = entry.getValue();
|
||||
String symbolString = symbol.toString();
|
||||
if (symbolString.contains(searchString)) {
|
||||
results.append("Module " + module + ", Offset " + entry.getKey() + ":\n");
|
||||
results.append(symbolString);
|
||||
results.append('\n');
|
||||
}
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
catch (PdbException e) {
|
||||
Msg.debug(PdbQuery.class, "Skipping module " + module + " due to exception.");
|
||||
}
|
||||
}
|
||||
println(script, results.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Method for outputting a message to the console (if script is not null); otherwise outputs
|
||||
* the message to Msg.info().
|
||||
* @param script the script
|
||||
* @param message the message to output to the console
|
||||
*/
|
||||
private static void println(GhidraScript script, String message) {
|
||||
if (script != null) {
|
||||
script.println(message);
|
||||
}
|
||||
else {
|
||||
Msg.info(PdbQuery.class, message);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -739,7 +739,8 @@ public class PdbApplicator {
|
||||
int num = ipi.getTypeIndexMaxExclusive() - ipi.getTypeIndexMin();
|
||||
monitor.initialize(num);
|
||||
setMonitorMessage("PDB: Processing " + num + " item type components...");
|
||||
for (int indexNumber = ipi.getTypeIndexMin(); indexNumber < num; indexNumber++) {
|
||||
for (int indexNumber =
|
||||
ipi.getTypeIndexMin(); indexNumber < ipi.getTypeIndexMaxExclusive(); indexNumber++) {
|
||||
monitor.checkCanceled();
|
||||
MsTypeApplier applier = getTypeApplier(RecordNumber.itemRecordNumber(indexNumber));
|
||||
applier.apply();
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
<h1>Ghidra Installation Guide</h1>
|
||||
<p>
|
||||
The installation information provided is effective as of Ghidra 10.1 and is subject to change with
|
||||
The installation information provided is effective as of Ghidra 10.1.2 and is subject to change with
|
||||
future releases.
|
||||
</p>
|
||||
|
||||
@ -318,7 +318,7 @@ Ghidra release includes native binaries for the following platforms:</p>
|
||||
system:</p>
|
||||
<ul>
|
||||
<li>A <a href="#Requirements">supported</a> version of a Java Development Kit</li>
|
||||
<li><a href="https://gradle.org/releases/">Gradle 6 or 7</a></li>
|
||||
<li><a href="https://gradle.org/releases/">Gradle 6.8+ or 7.x</a></li>
|
||||
<li>make, gcc, and g++ (Linux/macOS-only)</li>
|
||||
<li>
|
||||
<a href="https://visualstudio.microsoft.com/vs/community/">Microsoft Visual Studio</a>
|
||||
|
@ -44,7 +44,7 @@ To create the latest development build for your platform from this source reposi
|
||||
|
||||
##### Install build tools:
|
||||
* [JDK 11 64-bit][jdk11]
|
||||
* [Gradle 6.4+ or 7.x][gradle]
|
||||
* [Gradle 6.8+ or 7.x][gradle]
|
||||
* make, gcc, and g++ (Linux/macOS-only)
|
||||
* [Microsoft Visual Studio][vs] (Windows-only)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user