diff --git a/DevGuide.md b/DevGuide.md index 09f21da4d0..d424e55fe7 100644 --- a/DevGuide.md +++ b/DevGuide.md @@ -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/ diff --git a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/ssh/GhidraSshPtyFactory.java b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/ssh/GhidraSshPtyFactory.java index 68fdb1954e..21688cabfe 100644 --- a/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/ssh/GhidraSshPtyFactory.java +++ b/Ghidra/Debug/Debugger-agent-gdb/src/main/java/agent/gdb/pty/ssh/GhidraSshPtyFactory.java @@ -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); } diff --git a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtendedFlatProgramAPI.java b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtendedFlatProgramAPI.java index c2791db137..9f81ee502f 100644 --- a/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtendedFlatProgramAPI.java +++ b/Ghidra/Features/Decompiler/ghidra_scripts/classrecovery/ExtendedFlatProgramAPI.java @@ -1333,7 +1333,7 @@ public class ExtendedFlatProgramAPI extends FlatProgramAPI { commaIndex--; } - String shortenedName = className.substring(0, nextComma) + " ...>"; + String shortenedName = className.substring(0, nextComma) + "...>"; return shortenedName; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc index 9421da8c96..dac7169ccd 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc @@ -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 diff --git a/Ghidra/Features/PDB/developer_scripts/PdbQueryActivator.java b/Ghidra/Features/PDB/developer_scripts/PdbQueryActivator.java new file mode 100644 index 0000000000..3eab2bce1f --- /dev/null +++ b/Ghidra/Features/PDB/developer_scripts/PdbQueryActivator.java @@ -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); + } + +} diff --git a/Ghidra/Features/PDB/developer_scripts/PdbQueryCloseAllScript.java b/Ghidra/Features/PDB/developer_scripts/PdbQueryCloseAllScript.java new file mode 100644 index 0000000000..5d8460b123 --- /dev/null +++ b/Ghidra/Features/PDB/developer_scripts/PdbQueryCloseAllScript.java @@ -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); + } +} diff --git a/Ghidra/Features/PDB/developer_scripts/PdbQueryCloseScript.java b/Ghidra/Features/PDB/developer_scripts/PdbQueryCloseScript.java new file mode 100644 index 0000000000..b1f5431849 --- /dev/null +++ b/Ghidra/Features/PDB/developer_scripts/PdbQueryCloseScript.java @@ -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 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()); + } +} diff --git a/Ghidra/Features/PDB/developer_scripts/PdbQueryDatatypeScript.java b/Ghidra/Features/PDB/developer_scripts/PdbQueryDatatypeScript.java new file mode 100644 index 0000000000..99eeb910e2 --- /dev/null +++ b/Ghidra/Features/PDB/developer_scripts/PdbQueryDatatypeScript.java @@ -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 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); + } + +} diff --git a/Ghidra/Features/PDB/developer_scripts/PdbQueryOpenScript.java b/Ghidra/Features/PDB/developer_scripts/PdbQueryOpenScript.java new file mode 100644 index 0000000000..3be06c4515 --- /dev/null +++ b/Ghidra/Features/PDB/developer_scripts/PdbQueryOpenScript.java @@ -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); + } +} diff --git a/Ghidra/Features/PDB/developer_scripts/PdbQuerySymbolScript.java b/Ghidra/Features/PDB/developer_scripts/PdbQuerySymbolScript.java new file mode 100644 index 0000000000..285ed1fe19 --- /dev/null +++ b/Ghidra/Features/PDB/developer_scripts/PdbQuerySymbolScript.java @@ -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 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); + } +} diff --git a/Ghidra/Features/PDB/developer_scripts/pdbquery/PdbFactory.java b/Ghidra/Features/PDB/developer_scripts/pdbquery/PdbFactory.java new file mode 100644 index 0000000000..8c922c8516 --- /dev/null +++ b/Ghidra/Features/PDB/developer_scripts/pdbquery/PdbFactory.java @@ -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 pdbInfoByFile = new TreeMap<>(); + private static Map, 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> iterator = pdbInfoByFile.entrySet().iterator(); + while (iterator.hasNext()) { + Entry 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 getPdbInfo() { + List 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 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 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; + } + + } +} diff --git a/Ghidra/Features/PDB/developer_scripts/pdbquery/PdbQuery.java b/Ghidra/Features/PDB/developer_scripts/pdbquery/PdbQuery.java new file mode 100644 index 0000000000..5a8adbdc55 --- /dev/null +++ b/Ghidra/Features/PDB/developer_scripts/pdbquery/PdbQuery.java @@ -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 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 symbols = + pdb.getDebugInfo().getModuleSymbolsByOffset(module); + numSymbols += symbols.size(); + for (Map.Entry 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); + } + } + +} diff --git a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java index 1031cf269f..3f682846ee 100644 --- a/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java +++ b/Ghidra/Features/PDB/src/main/java/ghidra/app/util/pdb/pdbapplicator/PdbApplicator.java @@ -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(); diff --git a/GhidraDocs/InstallationGuide.html b/GhidraDocs/InstallationGuide.html index 432c08d994..4a8f6f700a 100644 --- a/GhidraDocs/InstallationGuide.html +++ b/GhidraDocs/InstallationGuide.html @@ -18,7 +18,7 @@

Ghidra Installation Guide

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

@@ -318,7 +318,7 @@ Ghidra release includes native binaries for the following platforms:

system:

  • A supported version of a Java Development Kit
  • -
  • Gradle 6 or 7
  • +
  • Gradle 6.8+ or 7.x
  • make, gcc, and g++ (Linux/macOS-only)
  • Microsoft Visual Studio diff --git a/README.md b/README.md index f23dfb822f..8c8d57c982 100644 --- a/README.md +++ b/README.md @@ -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)