Merge remote-tracking branch 'origin/patch'

This commit is contained in:
ghidra1 2021-03-23 13:55:44 -04:00
commit 19f9d3cecf
10 changed files with 221 additions and 20 deletions

View file

@ -148,4 +148,31 @@ public abstract class GhidraScriptProvider
return scriptName; return scriptName;
} }
/**
* Return the start of certification header line if this file type is
* subject to certification.
* @return start of certification header or null if not supported
*/
protected String getCertifyHeaderStart() {
return null;
}
/**
* Return the prefix for each certification header bofy line if
* this file is subject to certification
* @return certification heaber body prefix or null if not supported
*/
protected String getCertificationBodyPrefix() {
return null;
}
/**
* Return the end of certification header line if this file type is
* subject to certification.
* @return end of certification header or null if not supported
*/
protected String getCertifyHeaderEnd() {
return null;
}
} }

View file

@ -164,6 +164,16 @@ public class JavaScriptProvider extends GhidraScriptProvider {
return "//"; return "//";
} }
@Override
protected String getCertifyHeaderStart() {
return "/* ###";
}
@Override
protected String getCertifyHeaderEnd() {
return "*/";
}
/** /**
* *
* Fix script name for search in script directories, such as Java package parts in the name and inner class names. * Fix script name for search in script directories, such as Java package parts in the name and inner class names.

View file

@ -20,7 +20,6 @@ import static ghidra.util.HTMLUtilities.*;
import java.io.*; import java.io.*;
import java.util.List; import java.util.List;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import java.util.regex.Pattern;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
import javax.swing.KeyStroke; import javax.swing.KeyStroke;
@ -47,9 +46,6 @@ public class ScriptInfo {
static final String AT_MENUPATH = "@menupath"; static final String AT_MENUPATH = "@menupath";
static final String AT_TOOLBAR = "@toolbar"; static final String AT_TOOLBAR = "@toolbar";
private static final Pattern DOCUMENTATION_START = Pattern.compile("/\\*");
private static final Pattern DOCUMENTATION_END = Pattern.compile("\\*/");
// omit from METADATA to avoid pre-populating in new scripts // omit from METADATA to avoid pre-populating in new scripts
private static final String AT_IMPORTPACKAGE = "@importpackage"; private static final String AT_IMPORTPACKAGE = "@importpackage";
@ -186,6 +182,16 @@ public class ScriptInfo {
init(); init();
String commentPrefix = provider.getCommentCharacter();
// Note that skipping certification header presumes that the header
// is intact with an appropriate start and end
String certifyHeaderStart = provider.getCertifyHeaderStart();
String certifyHeaderEnd = provider.getCertifyHeaderEnd();
String certifyHeaderBodyPrefix = provider.getCertificationBodyPrefix();
boolean allowCertifyHeader = (certifyHeaderStart != null);
boolean skipCertifyHeader = false;
BufferedReader reader = null; BufferedReader reader = null;
try { try {
StringBuffer buffer = new StringBuffer(); StringBuffer buffer = new StringBuffer();
@ -197,16 +203,34 @@ public class ScriptInfo {
break; break;
} }
if (DOCUMENTATION_START.matcher(line).find()) { if (allowCertifyHeader) {
while (line != null && !DOCUMENTATION_END.matcher(line).find()) { // Skip past certification header if found
line = reader.readLine(); if (skipCertifyHeader) {
String trimLine = line.trim();
if (trimLine.startsWith(certifyHeaderEnd)) {
allowCertifyHeader = false;
skipCertifyHeader = false;
continue;
}
if (certifyHeaderBodyPrefix == null ||
trimLine.startsWith(certifyHeaderBodyPrefix)) {
continue; // skip certification header body
}
// broken certification header - unexpected line
Msg.error(this,
"Script contains invalid certification header: " + getName());
allowCertifyHeader = false;
skipCertifyHeader = false;
}
else if (line.startsWith(certifyHeaderStart)) {
skipCertifyHeader = true;
continue;
} }
continue;
} }
String commentPrefix = provider.getCommentCharacter();
if (line.startsWith(commentPrefix)) { if (line.startsWith(commentPrefix)) {
allowCertifyHeader = false;
line = line.substring(commentPrefix.length()).trim(); line = line.substring(commentPrefix.length()).trim();
if (line.startsWith("@")) { if (line.startsWith("@")) {

View file

@ -15,9 +15,10 @@
*/ */
package ghidra.app.util.bin.format.dwarf4; package ghidra.app.util.bin.format.dwarf4;
import java.io.IOException;
import java.util.*; import java.util.*;
import java.io.IOException;
import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.ArrayUtils;
import ghidra.app.util.bin.BinaryReader; import ghidra.app.util.bin.BinaryReader;
@ -884,6 +885,30 @@ public class DIEAggregate {
throw new IOException("Bad/unsupported DW_AT_high_pc attribute value or type"); throw new IOException("Bad/unsupported DW_AT_high_pc attribute value or type");
} }
/**
* Returns true if the raw lowPc and highPc values are the same.
* <p>
* This indicates an empty range, in which case the caller may want to take
* special steps to avoid issues with Ghidra ranges.
* <p>
* Only seen in extremely old gcc versions. Typically the low & high
* pc values are omitted if the CU is empty.
*
* @return boolean true if the LowPC and HighPC values are present and equal
*/
public boolean isLowPCEqualHighPC() {
AttrInfo low = findAttribute(DWARFAttribute.DW_AT_low_pc);
AttrInfo high = findAttribute(DWARFAttribute.DW_AT_high_pc);
if (low != null && high != null && low.form == high.form &&
low.attr instanceof DWARFNumericAttribute &&
high.attr instanceof DWARFNumericAttribute) {
DWARFNumericAttribute lowVal = (DWARFNumericAttribute) low.attr;
DWARFNumericAttribute highVal = (DWARFNumericAttribute) high.attr;
return lowVal.getValue() == highVal.getValue();
}
return false;
}
/** /**
* A simple class used by findAttribute() to return the found attribute, along with * A simple class used by findAttribute() to return the found attribute, along with
* the DIE it was found in, and the DWARFForm type of the raw attribute. * the DIE it was found in, and the DWARFForm type of the raw attribute.

View file

@ -49,11 +49,14 @@ public class DWARFCompileUnit {
String comp_dir = diea.getString(DWARFAttribute.DW_AT_comp_dir, null); String comp_dir = diea.getString(DWARFAttribute.DW_AT_comp_dir, null);
Number high_pc = null, low_pc = null, language = null, stmt_list = null; Number high_pc = null, low_pc = null, language = null, stmt_list = null;
if (diea.hasAttribute(DWARFAttribute.DW_AT_low_pc)) { if (diea.hasAttribute(DWARFAttribute.DW_AT_low_pc)) {
low_pc = diea.getLowPC(0); low_pc = diea.getLowPC(0);
} }
if (diea.hasAttribute(DWARFAttribute.DW_AT_high_pc)) { // if lowPC and highPC values are the same, don't read the high value
// because Ghidra can't express an empty range.
if (diea.hasAttribute(DWARFAttribute.DW_AT_high_pc) && !diea.isLowPCEqualHighPC()) {
high_pc = diea.getHighPC(); high_pc = diea.getHighPC();
} }

View file

@ -0,0 +1,54 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.app.util.bin.format.dwarf4.next;
import static ghidra.app.util.bin.format.dwarf4.encoding.DWARFAttribute.*;
import static org.junit.Assert.*;
import java.io.IOException;
import org.junit.Test;
import ghidra.app.util.bin.format.dwarf4.*;
import ghidra.app.util.bin.format.dwarf4.encoding.DWARFTag;
import ghidra.app.util.bin.format.dwarf4.expression.DWARFExpressionOpCodes;
import ghidra.program.model.data.IntegerDataType;
import ghidra.program.model.listing.CodeUnit;
import ghidra.program.model.listing.Data;
import ghidra.util.exception.CancelledException;
public class DWARFStaticVarImporterTest extends DWARFTestBase {
@Test
public void testIntStaticVar() throws CancelledException, IOException, DWARFException {
DebugInfoEntry intDIE = addInt(cu);
new DIECreator(DWARFTag.DW_TAG_variable)
.addString(DW_AT_name, "static_var1")
.addRef(DW_AT_type, intDIE)
.addBlock(DW_AT_location, DWARFExpressionOpCodes.DW_OP_addr, 0x10, 0x4, 0, 0, 0, 0,
0, 0)
.create(cu);
importFunctions();
CodeUnit cu = program.getListing().getCodeUnitAt(addr(0x410));
assertNotNull(cu);
assertEquals("static_var1", cu.getLabel());
assertEquals(4, cu.getLength());
assertTrue(((Data) cu).getDataType() instanceof IntegerDataType);
}
}

View file

@ -87,6 +87,16 @@ public class DIECreator {
return this; return this;
} }
public DIECreator addBlock(int attribute, int... intBytes) {
byte[] bytes = new byte[intBytes.length];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) intBytes[i];
}
attributes.put(attribute,
new AttrInfo(attribute, DWARFForm.DW_FORM_block1, new DWARFBlobAttribute(bytes)));
return this;
}
DWARFAbbreviation createAbbreviation(MockDWARFCompilationUnit cu) { DWARFAbbreviation createAbbreviation(MockDWARFCompilationUnit cu) {
DWARFAttributeSpecification[] attrSpecs = DWARFAttributeSpecification[] attrSpecs =
new DWARFAttributeSpecification[attributes.size()]; new DWARFAttributeSpecification[attributes.size()];
@ -121,13 +131,15 @@ public class DIECreator {
die.addChild(childDIE); die.addChild(childDIE);
} }
cu.addMockEntry(die); if (parent == null) {
parent = cu.getCompileUnitDIE();
}
if (parent != null) { if (parent != null) {
die.setParent(parent);
Assert.assertTrue(parent.getCompilationUnit() == cu); Assert.assertTrue(parent.getCompilationUnit() == cu);
parent.addChild(die); parent.addChild(die);
die.setParent(parent);
} }
cu.addMockEntry(die);
return die; return die;
} }

View file

@ -32,6 +32,8 @@ import ghidra.app.util.bin.format.dwarf4.next.sectionprovider.NullSectionProvide
import ghidra.program.database.ProgramBuilder; import ghidra.program.database.ProgramBuilder;
import ghidra.program.database.ProgramDB; import ghidra.program.database.ProgramDB;
import ghidra.program.database.data.DataTypeManagerDB; import ghidra.program.database.data.DataTypeManagerDB;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.data.CategoryPath; import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.DataTypeManager; import ghidra.program.model.data.DataTypeManager;
import ghidra.test.AbstractGhidraHeadedIntegrationTest; import ghidra.test.AbstractGhidraHeadedIntegrationTest;
@ -44,7 +46,10 @@ import ghidra.util.task.TaskMonitor;
*/ */
public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest { public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest {
protected static final long BaseAddress = 0x400;
protected ProgramDB program; protected ProgramDB program;
protected AddressSpace space;
protected DataTypeManagerDB dataMgr; protected DataTypeManagerDB dataMgr;
protected DataTypeManager builtInDTM; protected DataTypeManager builtInDTM;
protected int transactionID; protected int transactionID;
@ -62,10 +67,16 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest {
*/ */
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._TOY, this); program = createDefaultProgram(testName.getMethodName(), ProgramBuilder._X64, this);
space = program.getAddressFactory().getDefaultAddressSpace();
dataMgr = program.getDataTypeManager(); dataMgr = program.getDataTypeManager();
startTransaction(); startTransaction();
program.getMemory()
.createInitializedBlock("test", addr(BaseAddress), 500, (byte) 0, TaskMonitor.DUMMY,
false);
AutoAnalysisManager mgr = AutoAnalysisManager.getAnalysisManager(program); AutoAnalysisManager mgr = AutoAnalysisManager.getAnalysisManager(program);
DataTypeManagerService dtms = mgr.getDataTypeManagerService(); DataTypeManagerService dtms = mgr.getDataTypeManagerService();
builtInDTM = dtms.getBuiltInDataTypesManager(); builtInDTM = dtms.getBuiltInDataTypesManager();
@ -113,6 +124,16 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest {
dwarfDTM.importAllDataTypes(monitor); dwarfDTM.importAllDataTypes(monitor);
} }
protected void importFunctions() throws CancelledException, IOException, DWARFException {
dwarfProg.checkPreconditions(monitor);
dwarfDTM.importAllDataTypes(monitor);
DWARFImportSummary importSummary = new DWARFImportSummary();
DWARFFunctionImporter dfi =
new DWARFFunctionImporter(dwarfProg, dwarfDTM, importOptions, importSummary, monitor);
dfi.importFunctions();
}
protected DIEAggregate getAggregate(DebugInfoEntry die) protected DIEAggregate getAggregate(DebugInfoEntry die)
throws CancelledException, IOException, DWARFException { throws CancelledException, IOException, DWARFException {
dwarfProg.setCurrentCompilationUnit(die.getCompilationUnit(), monitor); dwarfProg.setCurrentCompilationUnit(die.getCompilationUnit(), monitor);
@ -278,4 +299,7 @@ public class DWARFTestBase extends AbstractGhidraHeadedIntegrationTest {
return arrayType; return arrayType;
} }
protected Address addr(long l) {
return space.getAddress(l);
}
} }

View file

@ -18,13 +18,14 @@ package ghidra.app.util.bin.format.dwarf4;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import ghidra.app.util.bin.format.dwarf4.encoding.DWARFIdentifierCase; import ghidra.app.util.bin.format.dwarf4.encoding.*;
import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram; import ghidra.app.util.bin.format.dwarf4.next.DWARFProgram;
import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitor;
public class MockDWARFCompilationUnit extends DWARFCompilationUnit { public class MockDWARFCompilationUnit extends DWARFCompilationUnit {
private List<DebugInfoEntry> mockEntries = new ArrayList<>(); private List<DebugInfoEntry> mockEntries = new ArrayList<>();
private DebugInfoEntry compUnitDIE;
public MockDWARFCompilationUnit(DWARFProgram dwarfProgram, long startOffset, long endOffset, public MockDWARFCompilationUnit(DWARFProgram dwarfProgram, long startOffset, long endOffset,
long length, int format, short version, long abbreviationOffset, byte pointerSize, long length, int format, short version, long abbreviationOffset, byte pointerSize,
@ -35,6 +36,9 @@ public class MockDWARFCompilationUnit extends DWARFCompilationUnit {
setCompileUnit( setCompileUnit(
new DWARFCompileUnit("Mock Comp Unit", "Mock Comp Unit Producer", "Mock Comp Unit Dir", new DWARFCompileUnit("Mock Comp Unit", "Mock Comp Unit Producer", "Mock Comp Unit Dir",
0, 0, 0, 0, DWARFIdentifierCase.DW_ID_case_insensitive, false, null)); 0, 0, 0, 0, DWARFIdentifierCase.DW_ID_case_insensitive, false, null));
compUnitDIE = new DIECreator(DWARFTag.DW_TAG_compile_unit)
.addString(DWARFAttribute.DW_AT_name, "MockCompUnit" + compUnitNumber)
.create(this);
} }
@Override @Override
@ -42,6 +46,10 @@ public class MockDWARFCompilationUnit extends DWARFCompilationUnit {
dies.addAll(mockEntries); dies.addAll(mockEntries);
} }
public DebugInfoEntry getCompileUnitDIE() {
return compUnitDIE;
}
public void addMockEntry(DebugInfoEntry die) { public void addMockEntry(DebugInfoEntry die) {
mockEntries.add(die); mockEntries.add(die);
} }

View file

@ -1,6 +1,5 @@
/* ### /* ###
* IP: GHIDRA * IP: GHIDRA
* REVIEWED: YES
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,12 +15,12 @@
*/ */
package ghidra.python; package ghidra.python;
import java.io.*;
import generic.jar.ResourceFile; import generic.jar.ResourceFile;
import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScript;
import ghidra.app.script.GhidraScriptProvider; import ghidra.app.script.GhidraScriptProvider;
import java.io.*;
public class PythonScriptProvider extends GhidraScriptProvider { public class PythonScriptProvider extends GhidraScriptProvider {
@Override @Override
@ -39,6 +38,21 @@ public class PythonScriptProvider extends GhidraScriptProvider {
return "#"; return "#";
} }
@Override
protected String getCertifyHeaderStart() {
return "## ###";
}
@Override
protected String getCertifyHeaderEnd() {
return "##";
}
@Override
protected String getCertificationBodyPrefix() {
return "#";
}
@Override @Override
public String getDescription() { public String getDescription() {
return "Python"; return "Python";