Merge tag 'Ghidra_11.4.3_build' into stable

This commit is contained in:
ghidra1
2025-12-03 16:31:13 -05:00
33 changed files with 541 additions and 221 deletions

View File

@@ -1,3 +1,18 @@
# Ghidra 11.4.3 Change History (December 2025)
### Improvements
* _Analysis_. Added the ability to restrict function start pattern matches per named section and added a pattern for thunks in the `.plt` so that they are marked up very early. (GP-5526)
* _Analysis_. Added several known PE-related, non-returning, named functions. (GP-5985)
* _Decompiler_. Restored the Decompiler's middle-mouse highlight functionality for if/else keywords. (GP-5951, Issue #8419)
* _Multi-User_. Updated `ghidraSvr` script and `server.conf` with improvements to restrict service wrapper memory consumption. (GP-6067)
* _Processors_. Added support for x86 SSE4a instructions. (GP-5906, Issue #8335)
### Bugs
* _Exporter_. Fixed missing reference type in the ASCII and HTML exporters. (GP-5957, Issue #8468)
* _PDB_. Fixed a `NullPointerException` that occurred during PDB load/analysis that was caused by a function null container class. (GP-6100, Issue #8596)
* _ProgramDB_. Corrected dynamic label bug which produced a stack overflow exception when a pointer reference loop existed. (GP-5995, Issue #8510)
* _Scripting_. Fixed OSGi-related errors that occurred when script-related directories were not readable. (GP-5965, Issue #8466)
# Ghidra 11.4.2 Change History (August 2025)
### Improvements

View File

@@ -18,3 +18,11 @@ longjmp
quick_exit
RpcRaiseException
terminate
___raise_securityfailure
___report_rangecheckfailure
?_Xregex_error@std@@YAXW4error_type@regex_constant@1@@Z
?_Xbad_alloc@std@@YAXXZ
?_Xlength_error@std@@YAXPBD@Z
?_Xout_of_range@std@@YAXPBD@Z
?_Xbad_function_call@std@@YAXXZ
?terminate@@YAXXZ

View File

@@ -563,6 +563,13 @@ public class CreateThunkFunctionCmd extends BackgroundCommand<Program> {
Listing listing = program.getListing();
Instruction instr = listing.getInstructionAt(entry);
// if there is no pcode, go to the next instruction
// assume fallthrough (ie. x86 instruction ENDBR64)
// TODO: at some point, might need to do a NOP detection
if (instr != null && instr.getPcode().length == 0) {
instr = listing.getInstructionAfter(entry);
}
if (instr == null) {
return null;
}

View File

@@ -324,14 +324,16 @@ public class GhidraSourceBundle extends GhidraBundle {
private static void findPackageDirs(List<String> packages, ResourceFile dir) {
boolean added = false;
ResourceFile[] files = dir.listFiles(f -> f.isDirectory() || f.getName().endsWith(".java"));
for (ResourceFile file : files) {
if (!file.getName().matches("internal|private")) {
if (file.isDirectory()) {
findPackageDirs(packages, file);
}
else if (!added) {
added = true;
packages.add(dir.getAbsolutePath());
if (files != null) {
for (ResourceFile file : files) {
if (!file.getName().matches("internal|private")) {
if (file.isDirectory()) {
findPackageDirs(packages, file);
}
else if (!added) {
added = true;
packages.add(dir.getAbsolutePath());
}
}
}
}
@@ -699,14 +701,17 @@ public class GhidraSourceBundle extends GhidraBundle {
ClassMapper mapper = new ClassMapper(binarySubdir);
// for each source file, lookup class files by class name
for (ResourceFile sourceFile : sourceSubdir.listFiles()) {
if (sourceFile.isDirectory()) {
stack.push(sourceFile);
}
else {
List<Path> classFiles = mapper.findAndRemove(sourceFile);
if (classFiles != null) {
discrepancy.found(sourceFile, classFiles);
ResourceFile[] sourceSubdirs = sourceSubdir.listFiles();
if (sourceSubdirs != null) {
for (ResourceFile sourceFile : sourceSubdirs) {
if (sourceFile.isDirectory()) {
stack.push(sourceFile);
}
else {
List<Path> classFiles = mapper.findAndRemove(sourceFile);
if (classFiles != null) {
discrepancy.found(sourceFile, classFiles);
}
}
}
}

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -1606,14 +1606,13 @@ public class ElfHeader implements StructConverter {
* @return the section header that contains the address
*/
public ElfSectionHeader getSectionLoadHeaderContaining(long address) {
// FIXME: verify
for (ElfSectionHeader sectionHeader : sectionHeaders) {
if (!sectionHeader.isAlloc()) {
continue;
}
long start = sectionHeader.getAddress();
long end = start + sectionHeader.getSize();
if (start <= address && address <= end) {
if (start <= address && address < end) {
return sectionHeader;
}
}

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -57,13 +57,13 @@ class ProgramTextOptions {
private final static int DEFAULT_OPERAND_WIDTH = 40;
private final static int DEFAULT_EOL_WIDTH = 40;
private final static int DEFAULT_REF_HEADER_WIDTH = 13;
private final static int DEFAULT_REF_WIDTH = 40;
private final static int DEFAULT_REF_WIDTH = 50; // about 4 refs per line
private final static int DEFAULT_STACK_VAR_PRENAME_WIDTH = 10;
private final static int DEFAULT_STACK_VAR_NAME_WIDTH = 15;
private final static int DEFAULT_STACK_VAR_DATATYPE_WIDTH = 15;
private final static int DEFAULT_STACK_VAR_OFFSET_WIDTH = 8;
private final static int DEFAULT_STACK_VAR_COMMENT_WIDTH = 20;
private final static int DEFAULT_STACK_VAR_XREF_WIDTH = 50;
private final static int DEFAULT_STACK_VAR_XREF_WIDTH = 60; // about 5 refs per line
private final static int DEFAULT_DATA_FIELD_NAME_WIDTH = 12;
private final static String DEFAULT_LABEL_SUFFIX = ":";

View File

@@ -25,7 +25,6 @@ import ghidra.program.model.symbol.*;
class ReferenceLineDispenser extends AbstractLineDispenser {
private static final Address[] EMPTY_ADDR_ARR = new Address[0];
private final static String XREFS_DELIM = ",";
private int headerWidth;
@@ -33,6 +32,7 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
private String header;
private Memory memory;
private ReferenceManager referenceManager;
private boolean forwardRefs;
private List<String> lines = new ArrayList<>();
@@ -51,10 +51,10 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
this.fillAmount =
options.getAddrWidth() + options.getBytesWidth() + options.getLabelWidth();
this.isHTML = options.isHTML();
this.forwardRefs = forwardRefs;
Address[] refs = (forwardRefs ? getForwardRefs(cu) : getXRefList(cu));
Address[] offcuts = (forwardRefs ? EMPTY_ADDR_ARR : getOffcutXRefList(cu));
List<Reference> refs = (forwardRefs ? getForwardRefs(cu) : getXRefList(cu));
List<Reference> offcuts = (forwardRefs ? List.of() : getOffcutXRefList(cu));
processRefs(cu.getMinAddress(), refs, offcuts);
}
@@ -70,24 +70,19 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
options.getStackVarDataTypeWidth() + options.getStackVarOffsetWidth() +
options.getStackVarCommentWidth();
this.isHTML = options.isHTML();
this.forwardRefs = false;
List<Reference> xrefs = new ArrayList<>();
List<Reference> offcuts = new ArrayList<>();
XReferenceUtils.getVariableRefs(var, xrefs, offcuts);
Address[] xrefAddr = extractFromAddr(xrefs);
Address[] offcutsAddr = extractFromAddr(offcuts);
processRefs(var.getFunction().getEntryPoint(),
xrefAddr, offcutsAddr);
}
Comparator<? super Reference> comparator = (r1, r2) -> {
return r1.getFromAddress().compareTo(r2.getFromAddress());
};
xrefs.sort(comparator);
offcuts.sort(comparator);
private Address[] extractFromAddr(List<Reference> refs) {
Address[] addrs = new Address[refs.size()];
for (int i = 0; i < addrs.length; i++) {
addrs[i] = refs.get(i).getFromAddress();
}
Arrays.sort(addrs);
return addrs;
processRefs(var.getFunction().getEntryPoint(), xrefs, offcuts);
}
@Override
@@ -110,7 +105,7 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
////////////////////////////////////////////////////////////////////
private Address[] getForwardRefs(CodeUnit cu) {
private List<Reference> getForwardRefs(CodeUnit cu) {
boolean showRefs = false;
Address cuAddr = cu.getMinAddress();
@@ -130,123 +125,138 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
}
if (!showRefs) {
return EMPTY_ADDR_ARR;
return List.of();
}
Reference[] mRefs = cu.getReferencesFrom();
Address[] refs = new Address[mRefs.length];
for (int i = 0; i < mRefs.length; ++i) {
refs[i] = mRefs[i].getToAddress();
}
Arrays.sort(refs);
List<Reference> refs = Arrays.asList(cu.getReferencesFrom());
refs.sort((r1, r2) -> {
return r1.getToAddress().compareTo(r2.getToAddress());
});
return refs;
}
////////////////////////////////////////////////////////////////////
private void processRefs(Address addr, List<Reference> refs,
List<Reference> offcuts) {
private void processRefs(Address addr, Address[] refs, Address[] offcuts) {
if (width < 1) {
return;
}
if (refs.length == 0 && offcuts.length == 0) {
if (refs.isEmpty() && offcuts.isEmpty()) {
return;
}
StringBuffer buf = new StringBuffer();
Address[] all = new Address[refs.length + offcuts.length];
System.arraycopy(refs, 0, all, 0, refs.length);
System.arraycopy(offcuts, 0, all, refs.length, offcuts.length);
StringBuilder buf = new StringBuilder();
List<Reference> all = new ArrayList<>();
all.addAll(refs);
all.addAll(offcuts);
if (displayRefHeader) {
if (refs.length > 0 || offcuts.length > 0) {
StringBuffer tmp = new StringBuffer();
tmp.append(header);
tmp.append("[");
tmp.append(refs.length);
tmp.append(",");
tmp.append(offcuts.length);
tmp.append("]: ");
if (!refs.isEmpty() || !offcuts.isEmpty()) {
buf.append(clip(tmp.toString(), headerWidth));
String text;
if (!offcuts.isEmpty()) {
text = "%s[%d,%d]: ".formatted(header, refs.size(), offcuts.size());
}
else {
text = "%s[%d]: ".formatted(header, refs.size());
}
buf.append(clip(text, headerWidth));
}
}
else {
buf.append(getFill(headerWidth));
buf.append(prefix);
}
int refsPerLine = width / (all[0].toString().length() + XREFS_DELIM.length());
int refsInCurrLine = 0;
int currentXrefWidth = 0;
for (int i = 0; i < all.size(); ++i) {
for (int i = 0; i < all.length; ++i) {
//if we are not displaying the xref header,
//then we need to append the comment prefix
if (i == 0 && !displayRefHeader) {
// does memory contain this address? if so, then hyperlink it
Reference ref = all.get(i);
XrefItem xrefItem = new XrefItem(ref);
int nextWidth = currentXrefWidth + xrefItem.getDisplayableWidth();
if (nextWidth > width) {
// line is too long for the current xref, break
lines.add(prefix + buf.toString());
buf.delete(0, buf.length());
// since we already have the next xref, add the next line's prefix
buf.append(getFill(headerWidth));
buf.append(prefix);
currentXrefWidth = 0;
}
//if we have started a new line, then
//we need to append the comment prefix
if (refsInCurrLine == 0 && i != 0) {
buf.append(getFill(headerWidth));
if (!displayRefHeader) {
buf.append(prefix);
}
}
//if we already appended a ref to the line
//and we are about to append one more,
//then we need the delim
if (refsInCurrLine > 0) {
currentXrefWidth += xrefItem.getDisplayableWidth();
buf.append(xrefItem.getRawText());
if (i < all.size() - 1) {
buf.append(XREFS_DELIM);
}
//does memory contain this address? if so, then hyperlink it
boolean isInMem = memory.contains(all[i]);
if (isHTML && isInMem) {
buf.append("<A HREF=\"#" + getUniqueAddressString(all[i]) + "\">");
}
buf.append(all[i].toString());
if (isHTML && isInMem) {
buf.append("</A>");
}
refsInCurrLine++;
if (refsInCurrLine == refsPerLine) {
lines.add((displayRefHeader ? prefix : "") + buf.toString());
buf.delete(0, buf.length());
refsInCurrLine = 0;
}
}
if (refsInCurrLine > 0) {
lines.add((displayRefHeader ? prefix : "") + buf.toString());
buf.delete(0, buf.length());
// add the last xref line
if (buf.length() != 0) {
lines.add(prefix + buf.toString());
}
}
public static Address[] getXRefList(CodeUnit cu) {
Program prog = cu.getProgram();
if (prog == null) {
return new Address[0];
// copied from XRefFieldFactory
private String getRefTypeDisplayString(Reference reference) {
if (reference.getReferenceType().isRead() && reference.getReferenceType().isWrite()) {
return "(RW)";
}
List<Address> xrefList = new ArrayList<>();
//lookup the direct xrefs to the current code unit
//
ReferenceIterator iter = prog.getReferenceManager().getReferencesTo(cu.getMinAddress());
while (iter.hasNext()) {
Reference ref = iter.next();
xrefList.add(ref.getFromAddress());
RefType refType = reference.getReferenceType();
if (reference instanceof ThunkReference) {
return "(T)";
}
Address[] arr = new Address[xrefList.size()];
xrefList.toArray(arr);
Arrays.sort(arr);
return arr;
if (refType instanceof DataRefType) {
if (refType.isRead() || refType.isIndirect()) {
return "(R)";
}
else if (refType.isWrite()) {
return "(W)";
}
else if (refType.isData()) {
return "(*)";
}
}
if (refType.isCall()) {
return "(c)";
}
else if (refType.isJump()) {
return "(j)";
}
return "";
}
private static Address[] getOffcutXRefList(CodeUnit cu) {
public static List<Reference> getXRefList(CodeUnit cu) {
Program prog = cu.getProgram();
if (prog == null) {
return new Address[0];
return List.of();
}
List<Address> offcutList = new ArrayList<>();
// default value taken from XRefFieldFactory
int maxXrefs = 20;
List<Reference> refs = XReferenceUtils.getXReferences(cu, maxXrefs + 1);
int maxOffcuts = Math.max(0, maxXrefs - refs.size());
List<Reference> offcuts = XReferenceUtils.getOffcutXReferences(cu, maxOffcuts);
refs.addAll(offcuts);
refs.sort((r1, r2) -> {
return r1.getFromAddress().compareTo(r2.getFromAddress());
});
return refs;
}
private static List<Reference> getOffcutXRefList(CodeUnit cu) {
Program prog = cu.getProgram();
if (prog == null) {
return List.of();
}
List<Reference> offcutList = new ArrayList<>();
// Lookup the offcut xrefs...
//
if (cu.getLength() > 1) {
@@ -259,13 +269,39 @@ class ReferenceLineDispenser extends AbstractLineDispenser {
ReferenceIterator refIter = refMgr.getReferencesTo(addr);
while (refIter.hasNext()) {
Reference ref = refIter.next();
offcutList.add(ref.getFromAddress());
offcutList.add(ref);
}
}
}
Address[] arr = new Address[offcutList.size()];
offcutList.toArray(arr);
Arrays.sort(arr);
return arr;
offcutList.sort((r1, r2) -> {
return r1.getFromAddress().compareTo(r2.getFromAddress());
});
return offcutList;
}
private class XrefItem {
private Address address;
private String displayableString;
XrefItem(Reference ref) {
address = forwardRefs ? ref.getToAddress() : ref.getFromAddress();
String refType = getRefTypeDisplayString(ref);
this.displayableString = address.toString() + refType;
}
int getDisplayableWidth() {
return displayableString.length();
}
String getRawText() {
boolean isInMem = memory.contains(address);
if (isHTML && isInMem) {
String href = getUniqueAddressString(address);
return "<A HREF=\"#%s\">%s</A>".formatted(href, displayableString);
}
return displayableString;
}
}
}

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -24,10 +24,11 @@ import ghidra.util.Msg;
public class StringComparer {
public static void compareLines(List<String> expectedList, File actualFile) throws Exception {
FilePrinter filePrinter = new FilePrinter(actualFile);
int index = 0;
boolean hasFailure = false;
try (BufferedReader reader = new BufferedReader(new FileReader(actualFile))) {
int excess = 0;
while (true) {
@@ -51,17 +52,21 @@ public class StringComparer {
hasFailure |= !match;
if (!match) {
Msg.debug(StringComparer.class, "Expected line does not match actual line (" + index +
"): \nExpected: " + expectedLine + "\nActual: " + actualLine);
filePrinter.print();
Msg.debug(StringComparer.class,
"Expected line does not match actual line (" + index +
"): \nExpected: " + expectedLine + "\nActual: " + actualLine);
}
}
if (excess > 0) {
filePrinter.print();
String message = "Actual file contains " + excess + " more lines than expected";
Msg.debug(StringComparer.class, message);
Assert.fail(message);
}
else if (!hasFailure && index < expectedList.size()) {
filePrinter.print();
int fewer = expectedList.size() - index;
String message = "Actual file contains " + fewer +
" fewer lines than expected";
@@ -74,4 +79,20 @@ public class StringComparer {
}
}
}
private static class FilePrinter {
private File f;
private boolean printed;
FilePrinter(File f) {
this.f = f;
}
void print() {
if (!printed) {
Msg.debug(this, "Test file: " + f);
printed = true;
}
}
}
}

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -28,7 +28,8 @@ import ghidra.app.util.viewer.proxy.ProxyObj;
import ghidra.framework.options.Options;
import ghidra.framework.options.ToolOptions;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.*;
import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Data;
import ghidra.program.model.symbol.Reference;
import ghidra.program.util.ProgramLocation;
import ghidra.program.util.XRefHeaderFieldLocation;
@@ -132,8 +133,9 @@ public class XRefHeaderFieldFactory extends XRefFieldFactory {
if (cu == null) {
return null;
}
Program prog = cu.getProgram();
int xrefCount = prog.getReferenceManager().getReferenceCountTo(cu.getMinAddress());
List<Reference> xrefs = XReferenceUtils.getXReferences(cu, maxXRefs);
int xrefCount = xrefs.size();
List<Reference> offcuts = XReferenceUtils.getOffcutXReferences(cu, maxXRefs);
int offcutCount = offcuts.size();

View File

@@ -505,8 +505,8 @@ public class SymbolTreePlugin1Test extends AbstractGhidraHeadedIntegrationTest {
DefaultTreeCellEditor cellEditor = (DefaultTreeCellEditor) tree.getCellEditor();
JTree jTree = (JTree) AbstractGenericTest.getInstanceField("tree", tree);
Container container = (Container) cellEditor.getTreeCellEditorComponent(jTree, newNsNode,
true, true, true, row);
Container container = (Container) runSwing(
() -> cellEditor.getTreeCellEditorComponent(jTree, newNsNode, true, true, true, row));
JTextField textField = (JTextField) container.getComponent(0);
assertEquals("NewNamespace", textField.getText());
}

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -138,18 +138,18 @@ public class XrefViewerTest extends AbstractGhidraHeadedIntegrationTest {
/*
Direct References
01001009 ?? LAB_01001007 READ
01001050 thunk_FUN_01001005 ?? FUN_01001005 UNCONDITIONAL_CALL
01001050 thunk_FUN_01001005 ?? FUN_01001005 THUNK
References to the Thunk Function
01001046 ?? thunk_FUN_01001005 UNCONDITIONAL_CALL thunk
*/
doubleClickXRef(baseFunctionAddress, "XREF[1]: ");
doubleClickXRef(baseFunctionAddress, "XREF[2]: ");
ComponentProvider comp = waitForComponentProvider(TableComponentProvider.class);
TableComponentProvider<?> tableProvider = (TableComponentProvider<?>) comp;
GhidraProgramTableModel<?> model = tableProvider.getModel();
@@ -176,12 +176,12 @@ public class XrefViewerTest extends AbstractGhidraHeadedIntegrationTest {
/*
Direct References
01001046 ?? thunk_FUN_01001005 UNCONDITIONAL_CALL thunk
References to the thunk and the end thunked function
01001046 ?? thunk_FUN_01001005 UNCONDITIONAL_CALL thunk
01001009 ?? LAB_01001007 READ
01001050 thunk_FUN_01001005 ?? FUN_01001005 UNCONDITIONAL_CALL

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -130,6 +130,56 @@ public class SymbolUtilities2Test extends AbstractGhidraHeadedIntegrationTest {
assertEquals("s__CODE_0200", symbol.getName());
}
@Test
public void testDynamicPTRLabel() throws Exception {
// 50 -> 100(pointer) -> 200(pointer) -> 300(pointer) -> 400(byte)XYZ
listing.createData(addr(0x100), PointerDataType.dataType);
listing.createData(addr(0x200), PointerDataType.dataType);
listing.createData(addr(0x300), PointerDataType.dataType);
listing.createData(addr(0x400), ByteDataType.dataType);
symbolTable.createLabel(addr(0x400), "XYZ", SourceType.USER_DEFINED);
refMgr.addMemoryReference(addr(0x50), addr(0x100), RefType.DATA, SourceType.USER_DEFINED,
0);
refMgr.addMemoryReference(addr(0x100), addr(0x200), RefType.DATA, SourceType.USER_DEFINED,
0);
refMgr.addMemoryReference(addr(0x200), addr(0x300), RefType.DATA, SourceType.USER_DEFINED,
0);
refMgr.addMemoryReference(addr(0x300), addr(0x400), RefType.DATA, SourceType.USER_DEFINED,
0);
Symbol symbol = symbolTable.getPrimarySymbol(addr(0x100));
assertEquals("PTR_PTR_CODE_0100", symbol.getName());
symbol = symbolTable.getPrimarySymbol(addr(0x200));
assertEquals("PTR_PTR_CODE_0200", symbol.getName());
symbol = symbolTable.getPrimarySymbol(addr(0x300));
assertEquals("PTR_XYZ_CODE_0300", symbol.getName());
}
@Test
public void testDynamicPTRLOOP1Label() throws Exception {
// 100(pointer) -> 100(pointer)
listing.createData(addr(0x100), PointerDataType.dataType);
refMgr.addMemoryReference(addr(0x100), addr(0x100), RefType.READ, SourceType.USER_DEFINED,
0);
Symbol symbol = symbolTable.getPrimarySymbol(addr(0x100));
assertEquals("PTR_LOOP_CODE_0100", symbol.getName());
}
@Test
public void testDynamicPTRLOOP2Label() throws Exception {
// 100(pointer) -> 200(pointer) -> 100(pointer)
listing.createData(addr(0x100), PointerDataType.dataType);
listing.createData(addr(0x200), PointerDataType.dataType);
refMgr.addMemoryReference(addr(0x100), addr(0x200), RefType.READ, SourceType.USER_DEFINED,
0);
refMgr.addMemoryReference(addr(0x200), addr(0x100), RefType.READ, SourceType.USER_DEFINED,
0);
Symbol symbol = symbolTable.getPrimarySymbol(addr(0x100));
assertEquals("PTR_LOOP_CODE_0100", symbol.getName());
symbol = symbolTable.getPrimarySymbol(addr(0x200));
assertEquals("PTR_LOOP_CODE_0200", symbol.getName());
}
@Test
public void testParseDynamicName() {
assertEquals(addr(0x100),

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -17,6 +17,7 @@ package ghidra.app.analyzers;
import java.math.BigInteger;
import java.util.*;
import java.util.regex.Matcher;
import generic.jar.ResourceFile;
import ghidra.app.cmd.function.CreateFunctionCmd;
@@ -207,9 +208,10 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa
private int validCodeMin = NO_VALID_INSTRUCTIONS_REQUIRED;
private int validCodeMax = VALID_INSTRUCTIONS_NO_MAX;
private String label = null;
private boolean isThunk = false; // true if this function should be turned into a thunk
private boolean noreturn = false; // true to set function non-returning
boolean validFunction = false; // must be defined at a function
private boolean isThunk = false; // true if this function should be turned into a thunk
private boolean noreturn = false; // true to set function non-returning
private java.util.regex.Pattern sectionNamePattern = null; // required section name as a regex pattern
boolean validFunction = false; // must be defined at a function
private boolean contiguous = true; // require validcode instructions be contiguous
@Override
@@ -225,6 +227,18 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa
}
protected boolean checkPreRequisites(Program program, Address addr) {
// check required section name
if (sectionNamePattern != null) {
MemoryBlock block = program.getMemory().getBlock(addr);
if (block == null) {
return false;
}
Matcher m = sectionNamePattern.matcher(block.getName());
if (!m.matches()) {
return false;
}
}
/**
* If the match's mark point occurs in undefined data, schedule disassembly
* and a function start at that address. If the match's mark point occurs at an instruction, but that
@@ -641,6 +655,10 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa
isThunk = true;
break;
case "section":
sectionNamePattern = java.util.regex.Pattern.compile(attrValue);
break;
case "noreturn":
noreturn = true;
break;
@@ -816,7 +834,14 @@ public class FunctionStartAnalyzer extends AbstractAnalyzer implements PatternFa
AutoAnalysisManager analysisManager = AutoAnalysisManager.getAnalysisManager(program);
if (!disassemResult.isEmpty()) {
analysisManager.disassemble(disassemResult, AnalysisPriority.DISASSEMBLY);
// disassemble known function starts now
AddressSet doNowDisassembly = disassemResult.intersect(funcResult);
// this will disassemble at this analyzers priority
analysisManager.disassemble(doNowDisassembly);
// delay disassemble of possible function starts
AddressSet delayedDisassembly = disassemResult.subtract(funcResult);
analysisManager.disassemble(delayedDisassembly, AnalysisPriority.DISASSEMBLY);
}
analysisManager.setProtectedLocations(codeLocations);

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -44,7 +44,7 @@ public class FunctionStartPreFuncAnalyzer extends FunctionStartAnalyzer {
public FunctionStartPreFuncAnalyzer() {
super(FUNCTION_START_PRE_SEARCH, DESCRIPTION, AnalyzerType.BYTE_ANALYZER);
setPriority(AnalysisPriority.BLOCK_ANALYSIS.after());
setPriority(AnalysisPriority.BLOCK_ANALYSIS.before());
setDefaultEnablement(true);
setSupportsOneTimeAnalysis();
}

View File

@@ -90,6 +90,7 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
}
});
private Set<String> ignoredMiddleMouseTokens = Set.of("{", "}", ";");
private ActiveMiddleMouse activeMiddleMouse;
private int middleMouseHighlightButton;
private Color middleMouseHighlightColor;
@@ -264,7 +265,10 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
}
// exclude tokens that users do not want to highlight
if (token instanceof ClangSyntaxToken || token instanceof ClangOpToken) {
if (shouldIgnoreOpToken(token)) {
return;
}
if (shouldIgnoreSyntaxTokenHighlight(token)) {
return;
}
@@ -273,6 +277,26 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
activeMiddleMouse = newMiddleMouse;
}
private boolean shouldIgnoreOpToken(ClangToken token) {
if (!(token instanceof ClangOpToken)) {
return false;
}
// users would like to be able to highlight return statements
String text = token.toString();
return !text.equals("return");
}
private boolean shouldIgnoreSyntaxTokenHighlight(ClangToken token) {
if (!(token instanceof ClangSyntaxToken syntaxToken)) {
return false;
}
String string = syntaxToken.toString();
return ignoredMiddleMouseTokens.contains(string);
}
void addHighlighterHighlights(ClangDecompilerHighlighter highlighter,
Supplier<? extends Collection<ClangToken>> tokens, ColorProvider colorProvider) {
highlightController.addHighlighterHighlights(highlighter, tokens, colorProvider);
@@ -745,7 +769,6 @@ public class DecompilerPanel extends JPanel implements FieldMouseListener, Field
int clickCount = ev.getClickCount();
int buttonState = ev.getButton();
if (buttonState == MouseEvent.BUTTON1) {
if (DockingUtils.isControlModifier(ev) && clickCount == 2) {
tryToGoto(location, field, ev, true);

View File

@@ -19,6 +19,7 @@ import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.util.*;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.lang3.StringUtils;
@@ -38,7 +39,7 @@ class DtrfDbg {
private static List<String> clientFilters = new ArrayList<>();
private static Map<Function, List<String>> linesByFunction = new HashMap<>();
private static Map<Function, List<String>> linesByFunction = new ConcurrentHashMap<>();
DtrfDbg() {
// static class

View File

@@ -2228,6 +2228,9 @@ public class DefaultPdbApplicator implements PdbApplicator {
//==============================================================================================
void predefineClass(SymbolPath classPath) {
if (classPath == null) {
return;
}
isClassByNamespace.put(classPath, true);
for (SymbolPath path = classPath.getParent(); path != null; path = path.getParent()) {
if (!isClassByNamespace.containsKey(path)) {

View File

@@ -89,14 +89,9 @@ public class AutoVersionTrackingTask extends Task {
/**
* Constructor for a modal/blocking AutoVersionTrackingTask
*
* @param session The Version Tracking session containing the source, destination, correlator
* and match information needed for this command.
* @param toolOptions the options used when applying matches
* @param minCombinedReferenceCorrelatorScore The minimum score used to limit matches created by
* the Combined Reference Correlator.
* @param minCombinedReferenceCorrelatorConfidence The minimum confidence used to limit matches
* created by the Combined Reference Correlator.
*/
public AutoVersionTrackingTask(VTSession session, ToolOptions toolOptions) {
super(NAME, true, true, true);
@@ -378,12 +373,10 @@ public class AutoVersionTrackingTask extends Task {
}
/**
* Method to create implied matches for the existing applied matches in the current session
* @param applyGoodMatches if true, create applied matches for "good" implied matches based on
* votes/conflict information. For all the applied implied matches, rerun the creation of
* applied matches until no new ones found.
* Method to create implied matches for the existing applied matches in the current session
* @param applyGoodMatches if true, apply matches if minVotes met and maxConflicts not exceeded
* for particular match, if false, don't apply any matches
* for particular match, if false, don't apply any matches. For all the applied implied matches,
* rerun the creation of applied matches until no new ones found.
* @param minVotes minimum votes needed to apply a match
* @param maxConflicts maximum conflicts allowed to apply a match
* @param monitor the task monitor
@@ -646,7 +639,7 @@ public class AutoVersionTrackingTask extends Task {
continue;
}
if (hasAcceptedRelatedAssociation(association, monitor)) {
if (hasAcceptedRelatedAssociation(association)) {
Msg.warn(AutoVersionTrackingTask.class,
"This association has a related association with an accepted match so cannot " +
"make this association accepted which would try to block the already accepted " +
@@ -702,12 +695,11 @@ public class AutoVersionTrackingTask extends Task {
* Method to test whether any related associations (ie associations with either the same source
* or the same destination address) have already been accepted
* @param association the given association (src/dest match pair)
* @param taskMonitor the task monitor
* @return true if any related associations have already been accepted, false otherwise
* @throws CancelledException if cancelled
*/
private boolean hasAcceptedRelatedAssociation(VTAssociation association,
TaskMonitor taskMonitor) throws CancelledException {
private boolean hasAcceptedRelatedAssociation(VTAssociation association)
throws CancelledException {
VTAssociationManager vtAssocManager = session.getAssociationManager();
@@ -745,7 +737,7 @@ public class AutoVersionTrackingTask extends Task {
* function pair association or it would have been identified as a unique match by the exact
* unique function instruction correltor. This method attempts to find unique matches from
* within the related subsets by comparing operand information.
* @param matches The set of matches from the duplicate function instruction correlator
* @param matchSet The set of matches from the duplicate function instruction correlator
* @param monitor Allows user to cancel
* @return true if there are any markup errors, false if no markup errors
* @throws CancelledException if cancelled
@@ -1169,7 +1161,8 @@ public class AutoVersionTrackingTask extends Task {
* Method to check to see if both addresses have functions at them or the same data type at them
* @param addr1 the first Address
* @param addr2 the second Address
* @return
* @return true if same operand type (ie both functions, both same data type, same internal
* function reference
*/
private boolean isSameOperandType(Address addr1, Address addr2) {
@@ -1179,9 +1172,22 @@ public class AutoVersionTrackingTask extends Task {
if (function2 != null) {
return true;
}
else {
return false;
return false;
}
// are both references to same offset in the mapped functions
function1 = sourceProgram.getFunctionManager().getFunctionContaining(addr1);
if (function1 != null) {
Function function2 =
destinationProgram.getFunctionManager().getFunctionContaining(addr2);
if (function2 != null) {
long offsetInFunction1 = getOffsetInFunction(function1, addr1);
long offsetInFunction2 = getOffsetInFunction(function2, addr2);
if (offsetInFunction1 == offsetInFunction2) {
return true;
}
}
return false;
}
Data data1 = sourceProgram.getListing().getDataAt(addr1);
@@ -1275,9 +1281,7 @@ public class AutoVersionTrackingTask extends Task {
// get offset from top of function to use in function to operandMap map
// can be positive or negative offset (positive means instruction address is after
// the entry address, negative means instruction address is before entry address)
Long entryOffset = function.getEntryPoint().getOffset();
Long instOffset = inst.getAddress().getOffset();
Long offset = instOffset - entryOffset;
long offset = getOffsetInFunction(function, inst.getAddress());
offsetToOperandsMap.put(offset, map);
}
@@ -1289,6 +1293,15 @@ public class AutoVersionTrackingTask extends Task {
return offsetToOperandsMap;
}
private long getOffsetInFunction(Function function, Address addressInFunction) {
long entryOffset = function.getEntryPoint().getOffset();
long addrOffset = addressInFunction.getOffset();
long offset = addrOffset - entryOffset;
return offset;
}
/**
* Method to create offset/operand mapping for each function in match set
* if more than one identical offset/operand mapping in src or dest piles then remove
@@ -1343,7 +1356,7 @@ public class AutoVersionTrackingTask extends Task {
// skip already accepted or blocked matches
if (association.getStatus() == VTAssociationStatus.AVAILABLE) {
if (hasAcceptedRelatedAssociation(association, monitor)) {
if (hasAcceptedRelatedAssociation(association)) {
Msg.warn(AutoVersionTrackingTask.class,
"This association has a related association with an accepted match so cannot " +
"make this association accepted which would try to block the already accepted " +

View File

@@ -15,8 +15,7 @@
*/
package ghidra.asm.wild;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.*;
@@ -41,6 +40,7 @@ import ghidra.program.model.lang.LanguageID;
import ghidra.program.model.listing.Program;
import ghidra.test.AbstractGhidraHeadlessIntegrationTest;
import ghidra.test.ClassicSampleX86ProgramBuilder;
import ghidra.util.Msg;
import ghidra.util.NumericUtilities;
public class WildSleighAssemblerTest extends AbstractGhidraHeadlessIntegrationTest {
@@ -136,10 +136,11 @@ public class WildSleighAssemblerTest extends AbstractGhidraHeadlessIntegrationTe
}
protected void dumpResults(AssemblyResolutionResults results) {
System.err.println("results:" + results);
Msg.trace(this, "results:" + results);
for (AssemblyResolution res : results) {
if (res instanceof WildAssemblyResolvedPatterns pats) {
System.err.println(pats.getInstruction());
Msg.trace(this, pats.getInstruction());
for (WildOperandInfo info : pats.getOperandInfo()) {
var choice_str = "?";
var choice = info.choice();
@@ -147,7 +148,7 @@ public class WildSleighAssemblerTest extends AbstractGhidraHeadlessIntegrationTe
choice_str = choice.toString();
}
System.err.println(info.location() + ": " + info.wildcard() + " = " +
Msg.trace(this, info.location() + ": " + info.wildcard() + " = " +
info.expression() + "(" + info.path() + ") == " + choice_str.toString());
}
}
@@ -317,7 +318,7 @@ public class WildSleighAssemblerTest extends AbstractGhidraHeadlessIntegrationTe
toy();
Collection<AssemblyParseResult> parses = asmToy.parseLine("add `Q1/r.`, #6");
AssemblyParseResult one = Unique.assertOne(parses.stream().filter(p -> !p.isError()));
System.err.println("parse: " + one);
//System.err.println("parse: " + one);
Address addr0 = toy.getAddressFactory().getDefaultAddressSpace().getAddress(0);
AssemblyResolutionResults results = asmToy.resolveTree(one, addr0);
@@ -334,7 +335,7 @@ public class WildSleighAssemblerTest extends AbstractGhidraHeadlessIntegrationTe
toy();
Collection<AssemblyParseResult> parses = asmToy.parseLine("add r0, #`Q2[0,2..4]`");
AssemblyParseResult one = Unique.assertOne(parses.stream().filter(p -> !p.isError()));
System.err.println("parse: " + one);
//System.err.println("parse: " + one);
Address addr0 = toy.getAddressFactory().getDefaultAddressSpace().getAddress(0);
AssemblyResolutionResults results = asmToy.resolveTree(one, addr0);
@@ -353,7 +354,7 @@ public class WildSleighAssemblerTest extends AbstractGhidraHeadlessIntegrationTe
Address addr0 = toy.getAddressFactory().getDefaultAddressSpace().getAddress(0);
var allValidPatterns = new HashSet<AssemblyPatternBlock>();
for (AssemblyParseResult p : parses) {
System.err.println("parse: " + p);
//System.err.println("parse: " + p);
AssemblyResolutionResults results = asmToy.resolveTree(p, addr0);
dumpResults(results);
allValidPatterns.addAll(getInstructionPatterns(results));
@@ -375,7 +376,7 @@ public class WildSleighAssemblerTest extends AbstractGhidraHeadlessIntegrationTe
Address addr0 = toy.getAddressFactory().getDefaultAddressSpace().getAddress(0);
var allValidPatterns = new HashSet<AssemblyPatternBlock>();
for (AssemblyParseResult p : parses) {
System.err.println("parse: " + p);
//System.err.println("parse: " + p);
AssemblyResolutionResults results = asmToy.resolveTree(p, addr0);
dumpResults(results);
allValidPatterns.addAll(getInstructionPatterns(results));

View File

@@ -35,10 +35,9 @@ public class IncrementalLoadJob<ROW_OBJECT> extends Job implements ThreadedTable
/**
* Used to signal that the updateManager has finished loading the final contents gathered
* by this job. By default, the value is 0, which means there is nothing to wait for. If we
* flush, this will be set to 1.
* by this job. This is also updated if this job is cancelled.
*/
private volatile CountDownLatch completedCallbackLatch = new CountDownLatch(0);
private volatile CountDownLatch completedCallbackLatch = new CountDownLatch(1);
private volatile boolean isCancelled = false;
private volatile IncrementalUpdatingAccumulator incrementalAccumulator;
@@ -140,14 +139,19 @@ public class IncrementalLoadJob<ROW_OBJECT> extends Job implements ThreadedTable
// -We release the lock
// -A block on jobDone() can now complete as we release the lock
// -jobDone() will notify listeners in an invokeLater(), which puts it behind ours
//
completedCallbackLatch = new CountDownLatch(1);
//
Swing.runLater(() -> updateManager.addThreadedTableListener(IncrementalLoadJob.this));
}
waitForThreadedTableUpdateManagerToFinish();
}
/**
* Waits for the final flushed data to be added to the table. We will get called when the data
* is finished loading or cancelled. The latch will also be released if the cancel method of
* this job is called. This can happen if the work queue is told to cancel all jobs, which can
* happen if a new reload job is requested.
*/
private void waitForThreadedTableUpdateManagerToFinish() {
try {
completedCallbackLatch.await();
@@ -179,6 +183,7 @@ public class IncrementalLoadJob<ROW_OBJECT> extends Job implements ThreadedTable
super.cancel();
isCancelled = true;
incrementalAccumulator.cancel();
completedCallbackLatch.countDown();
// Note: cannot do this here, since the cancel() call may happen asynchronously and after
// a call to reload() on the table model. Assume that the model itself has already

View File

@@ -203,7 +203,7 @@ public abstract class ThreadedTableModel<ROW_OBJECT, DATA_SOURCE>
}
private void cancelCurrentWorkerJob() {
if (worker != null && worker.isBusy()) {
if (worker != null) {
worker.clearAllJobsWithInterrupt_IKnowTheRisks();
}
}

View File

@@ -37,6 +37,7 @@
<logger name="docking" level="DEBUG"/>
<logger name="ghidra" level="DEBUG" />
<logger name="ghidra.feature.fid" level="INFO" />
<logger name="ghidra.framework" level="DEBUG"/>
<logger name="ghidra.graph" level="DEBUG" />

View File

@@ -35,6 +35,7 @@
<logger name="docking" level="DEBUG"/>
<logger name="ghidra" level="DEBUG" />
<logger name="ghidra.feature.fid" level="INFO" />
<logger name="ghidra.framework" level="DEBUG"/>
<logger name="ghidra.graph" level="DEBUG" />

View File

@@ -4,9 +4,9 @@
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -140,7 +140,7 @@ public class ToolUtils {
File[] toolFiles = USER_TOOLS_DIR.listFiles(filter);
if (toolFiles != null) {
for (File toolFile : toolFiles) {
ToolTemplate template = ToolUtils.readToolTemplate(toolFile);
ToolTemplate template = readToolTemplate(toolFile);
if (template != null) {
map.put(template.getName(), template);
}
@@ -202,9 +202,9 @@ public class ToolUtils {
}
public static void renameToolTemplate(ToolTemplate toolTemplate, String newName) {
ToolUtils.deleteTool(toolTemplate);
deleteTool(toolTemplate);
toolTemplate.setName(newName);
ToolUtils.writeToolTemplate(toolTemplate);
writeToolTemplate(toolTemplate);
}
public static boolean writeToolTemplate(ToolTemplate template) {
@@ -232,6 +232,8 @@ public class ToolUtils {
}
public static ToolTemplate readToolTemplate(File toolFile) {
LOGGER.trace("Loading tool file {}", toolFile);
GhidraToolTemplate toolTemplate = null;
try (FileInputStream is = new FileInputStream(toolFile)) {
@@ -331,7 +333,7 @@ public class ToolUtils {
public static String getUniqueToolName(ToolTemplate template) {
String name = template.getName();
int n = 1;
while (ToolUtils.getToolFile(name).exists()) {
while (getToolFile(name).exists()) {
name = name + "_" + n++;
}
return name;

View File

@@ -259,7 +259,7 @@ public class PointerDataType extends BuiltIn implements Pointer {
while (ref != null && ref.isMemoryReference()) {
Address toAddr = ref.getToAddress();
if (!refAddrs.add(toAddr)) {
break;
return PointerReferenceClassification.LOOP;
}
if (++depth > 2) {
return PointerReferenceClassification.DEEP;

View File

@@ -92,5 +92,6 @@ data/patterns/x86-64gcc_patterns.xml||GHIDRA||||END|
data/patterns/x86-64win_patterns.xml||GHIDRA||||END|
data/patterns/x86delphi_patterns.xml||GHIDRA||||END|
data/patterns/x86gcc_patterns.xml||GHIDRA||||END|
data/patterns/x86gcc_prepatterns.xml||GHIDRA||||END|
data/patterns/x86win_patterns.xml||GHIDRA||||END|
data/patterns/x86win_prepatterns.xml||GHIDRA||||END|

View File

@@ -4894,13 +4894,13 @@ define pcodeop verw;
# of this instruction is always 64-bits and is always in memory". Is it an error that the "Instruction" entry in the
# box giving the definition does not specify m64?
:VMPTRST m64 is vexMode=0 & byte=0x0f; byte=0xc7; ( mod != 0b11 & reg_opcode=7 ) ... & m64 { vmptrst(m64); }
:VMREAD rm32, Reg32 is vexMode=0 & opsize=1 & byte=0x0f; byte=0x78; rm32 & check_rm32_dest ... & Reg32 ... { rm32 = vmread(Reg32); build check_rm32_dest; }
:VMREAD rm32, Reg32 is $(PRE_NO) & vexMode=0 & opsize=1 & byte=0x0f; byte=0x78; rm32 & check_rm32_dest ... & Reg32 ... { rm32 = vmread(Reg32); build check_rm32_dest; }
@ifdef IA64
:VMREAD rm64, Reg64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0x0f; byte=0x78; rm64 & Reg64 ... { rm64 = vmread(Reg64); }
:VMREAD rm64, Reg64 is $(LONGMODE_ON) & $(PRE_NO) & vexMode=0 & opsize=2 & byte=0x0f; byte=0x78; rm64 & Reg64 ... { rm64 = vmread(Reg64); }
@endif
:VMWRITE Reg32, rm32 is vexMode=0 & opsize=1 & byte=0x0f; byte=0x79; rm32 & Reg32 ... & check_Reg32_dest ... { vmwrite(rm32,Reg32); build check_Reg32_dest; }
:VMWRITE Reg32, rm32 is $(PRE_NO) & vexMode=0 & opsize=1 & byte=0x0f; byte=0x79; rm32 & Reg32 ... & check_Reg32_dest ... { vmwrite(rm32,Reg32); build check_Reg32_dest; }
@ifdef IA64
:VMWRITE Reg64, rm64 is $(LONGMODE_ON) & vexMode=0 & opsize=2 & byte=0x0f; byte=0x79; rm64 & Reg64 ... { vmwrite(rm64,Reg64); }
:VMWRITE Reg64, rm64 is $(LONGMODE_ON) & $(PRE_NO) & vexMode=0 & opsize=2 & byte=0x0f; byte=0x79; rm64 & Reg64 ... { vmwrite(rm64,Reg64); }
@endif
:VMXOFF is vexMode=0 & byte=0x0f; byte=0x01; byte=0xc4 { vmxoff(); }
# NB: this opcode is incorrect in the 2005 edition of the Intel manual. Opcode below is taken from the 2008 version.
@@ -10457,4 +10457,46 @@ define pcodeop PackedSwapDWords;
define pcodeop MaskedMoveQWord;
:MASKMOVQ mmxreg1, mmxreg2 is vexMode=0 & mandover=0 & byte=0x0F; byte=0xF7; mmxmod = 3 & mmxreg1 & mmxreg2 { mmxreg1 = MaskedMoveQWord(mmxreg1, mmxreg2); }
####
#### SSE4a instructions
####
bitLen: val is imm8 [ val=imm8 & 0x3f; ] { export *[const]:1 val; }
lsbOffset: val is imm8 [ val=imm8 & 0x3f; ] { export *[const]:1 val; }
:EXTRQ XmmReg2, bitLen, lsbOffset is vexMode=0 & $(PRE_66) & byte=0x0F; byte=0x78; reg_opcode=0 & XmmReg2; bitLen; lsbOffset {
local mask:16 = ((1 << bitLen) - 1) << lsbOffset;
local val:16 = (XmmReg2 & mask) >> lsbOffset;
XmmReg2 = val;
}
:EXTRQ XmmReg1, XmmReg2 is vexMode=0 & $(PRE_66) & byte=0x0F; byte=0x79; XmmReg1 & XmmReg2 {
local len = XmmReg2[0,6];
local offs = XmmReg2[6,6];
local mask = ((1 << len) - 1) << offs;
local val = (XmmReg1 & mask) >> offs;
XmmReg1 = val;
}
:INSERTQ XmmReg1, XmmReg2, bitLen, lsbOffset is vexMode=0 & $(PRE_F2) & byte=0x0F; byte=0x78; XmmReg1 & XmmReg2; bitLen; lsbOffset {
local mask:16 = ((1 << bitLen) - 1) << lsbOffset;
local val:16 = (zext(XmmReg2[0,64]) & ((1 << bitLen) - 1));
XmmReg1 = (XmmReg1 & ~zext(mask)) | (zext(val) << lsbOffset);
}
:INSERTQ XmmReg1, XmmReg2 is vexMode=0 & $(PRE_F2) & byte=0x0F; byte=0x79; XmmReg1 & XmmReg2 {
local len = XmmReg2[64,6];
local offs = XmmReg2[72,6];
local mask:16 = ((1 << len) - 1) << offs;
local val:16 = (zext(XmmReg2[0,64]) & ((1 << len) - 1));
XmmReg1 = (XmmReg1 & ~zext(mask)) | (zext(val) << offs);
}
:MOVNTSD m64, XmmReg1 is vexMode=0 & $(PRE_F2) & byte=0x0F; byte=0x2B; XmmReg1 ... & m64 {
m64 = XmmReg1[0,64];
}
:MOVNTSS m32, XmmReg1 is vexMode=0 & $(PRE_F3) & byte=0x0F; byte=0x2B; XmmReg1 ... & m32 {
m32 = XmmReg1[0,32];
}
} # end with : lockprefx=0

View File

@@ -7,6 +7,15 @@
<compiler id="borlandcpp">
<patternfile>x86win_prepatterns.xml</patternfile>
</compiler>
<compiler id="gcc">
<patternfile>x86gcc_prepatterns.xml</patternfile>
</compiler>
</language>
<language id="x86:LE:64:default">
<compiler id="gcc">
<patternfile>x86gcc_prepatterns.xml</patternfile>
</compiler>
</language>
</patternconstraints>

View File

@@ -0,0 +1,20 @@
<patternlist>
<pattern>
<data>
0xff25........ <!-- jmp -->
0x68......00 <!-- push -->
0xe9......ff <!-- jmp -addr -->
</data> <!-- .plt thunk -->
<funcstart thunk="true" section="(?i)(\.plt)"/>
</pattern>
<pattern>
<data>
0xf3 0x0f 0x1e 0xfa <!-- ENDBR64 -->
0xf2 0xff 0x25 <!-- jmp qword ptr [0xxxx] -->
</data> <!-- .plt thunk -->
<funcstart thunk="true" section="(?i)(\.plt(\.sec)?)"/>
</pattern>
</patternlist>

View File

@@ -1,6 +1,15 @@
#********************************************************************
#**************************************************************************
# Service Wrapper Properties
#********************************************************************
#
# NOTE: It is important to know that the Ghidra Server consists of both
# a controlling wrapper process and its wrapped child process. The
# properties within this file may affect each differently - specifically
# JVM options and how they are specified. The service wrapper relies on
# wrapper.ntservice.additional.N properties within this file, while the
# wrapped Ghidra Server child process relies on wrapper.java.additional.N
# properties. Any changes to ntservice properties require reinstallation
# of the service for them to have any affect.
#**************************************************************************
# Initial Working Directory (i.e., absolute installation directory path)
wrapper.working.dir=${ghidra_home}
@@ -107,11 +116,13 @@ wrapper.java.monitor.deadlock = true
# Main server application class
wrapper.java.app.mainclass=ghidra.server.remote.GhidraServer
# Initial Java Heap Size (in MB)
# Initial Java Heap Size (in MB) - this has the same affect as JVM option -Xms
# NOTE: See ntservice options at bottom of this file for installed service wrapper control
wrapper.java.initmemory=396
# Maximum Java Heap Size (in MB)
# Maximum Java Heap Size (in MB) - this has the same affect as JVM option -Xmx
# See svrREADME.txt file for advice (Server Memory Considerations)
# NOTE: See ntservice options at bottom of this file for installed service wrapper control
wrapper.java.maxmemory=768
# Specify the directory used to store repositories. This directory must be dedicated to this
@@ -259,3 +270,16 @@ wrapper.ntservice.interactive=false
# Restart failed service after 1 minute delay
wrapper.ntservice.failure_actions.actions=RESTART
wrapper.ntservice.failure_actions.actions_delay=60000
# Specify JVM arguments to be used by installed service wrapper process.
# Maximum Java Heap Size for installed service wrapper.
# NOTE: See also -Xmx option specification with ghidraSvr script which relates to other
# uses of the YAJSW wrapper (e.g., console mode).
wrapper.ntservice.additional.1=-Xmx512M
# Uncomment to enable detailed memory tracking capability for the installed service wrapper process.
# This will allow command such as the following to dump memory use information:
# jcmd <PID> VM.native_memory summary
# jcmd <PID> VM.native_memory detail
#wrapper.ntservice.additional.2=-XX:NativeMemoryTracking=detail

View File

@@ -171,7 +171,10 @@ else
JAVA_CMD="${LS_JAVA_HOME}/bin/java"
fi
# Specify JVM arguments for direct invocations of YAJSW wrapper, including specification
# of maximum heap size (-Xmx) option.
VMARGS=()
VMARGS+=("-Xmx512M")
VMARGS+=("-Djna_tmpdir=${WRAPPER_TMPDIR}")
VMARGS+=("-Djava.io.tmpdir=${WRAPPER_TMPDIR}")

View File

@@ -185,7 +185,10 @@ set "java=%LS_JAVA_HOME%\bin\java.exe"
:: execute command OPTION
:lab3
set VMARGS=-Djava.io.tmpdir="%WRAPPER_TMPDIR%"
:: Specify JVM arguments for direct invocations of YAJSW wrapper, including specification
:: of maximum heap size (-Xmx) option.
set VMARGS=-Xmx512M
set VMARGS=%VMARGS% -Djava.io.tmpdir="%WRAPPER_TMPDIR%"
set VMARGS=%VMARGS% -Djna_tmpdir="%WRAPPER_TMPDIR%"
:: set DEBUG=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:18888

View File

@@ -1,5 +1,5 @@
application.name=Ghidra
application.version=11.4.2
application.version=11.4.3
application.release.name=DEV
application.layout.version=3
application.gradle.min=8.5