mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-01-09 14:08:03 -05:00
Merge tag 'Ghidra_11.4.3_build' into stable
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 = ":";
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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 " +
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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|
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
20
Ghidra/Processors/x86/data/patterns/x86gcc_prepatterns.xml
Normal file
20
Ghidra/Processors/x86/data/patterns/x86gcc_prepatterns.xml
Normal 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>
|
||||
@@ -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
|
||||
|
||||
@@ -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}")
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user