mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Merge remote-tracking branch 'origin/patch'
This commit is contained in:
commit
3b9263f1b4
31 changed files with 709 additions and 134 deletions
|
@ -430,7 +430,12 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
if (id != 0) {
|
||||
encoder.writeUnsignedInteger(ATTRIB_ID, id);
|
||||
}
|
||||
encoder.writeString(ATTRIB_NAME, func.getName());
|
||||
String funcName = func.getName();
|
||||
encoder.writeString(ATTRIB_NAME, funcName);
|
||||
String altName = getDataTypeManager().getNameTransformer().simplify(funcName);
|
||||
if (!altName.equals(funcName)) {
|
||||
encoder.writeString(ATTRIB_LABEL, altName);
|
||||
}
|
||||
encoder.writeSignedInteger(ATTRIB_SIZE, size);
|
||||
if (func.isInline()) {
|
||||
encoder.writeBool(ATTRIB_INLINE, true);
|
||||
|
@ -444,7 +449,7 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
else {
|
||||
AddressXML.encode(encoder, entryPoint); // Address is forced on XML
|
||||
}
|
||||
localSymbols.encodeLocalDb(encoder, namespace);
|
||||
localSymbols.encodeLocalDb(encoder, namespace, getDataTypeManager().getNameTransformer());
|
||||
proto.encodePrototype(encoder, getDataTypeManager());
|
||||
if ((jumpTables != null) && (jumpTables.size() > 0)) {
|
||||
encoder.openElement(ELEM_JUMPTABLELIST);
|
||||
|
@ -575,9 +580,11 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
* from the root (global) namespace up to the given namespace
|
||||
* @param encoder is the stream encoder
|
||||
* @param namespace is the namespace being described
|
||||
* @param transformer is used to computer the displayed version of each namespace
|
||||
* @throws IOException for errors in the underlying stream
|
||||
*/
|
||||
static public void encodeNamespace(Encoder encoder, Namespace namespace) throws IOException {
|
||||
static public void encodeNamespace(Encoder encoder, Namespace namespace,
|
||||
NameTransformer transformer) throws IOException {
|
||||
encoder.openElement(ELEM_PARENT);
|
||||
if (namespace != null) {
|
||||
ArrayList<Namespace> arr = new ArrayList<>();
|
||||
|
@ -595,7 +602,12 @@ public class HighFunction extends PcodeSyntaxTree {
|
|||
Namespace curScope = arr.get(i);
|
||||
encoder.openElement(ELEM_VAL);
|
||||
encoder.writeUnsignedInteger(ATTRIB_ID, curScope.getID());
|
||||
encoder.writeString(ATTRIB_CONTENT, curScope.getName());
|
||||
String nm = curScope.getName();
|
||||
String altName = transformer.simplify(nm);
|
||||
if (!nm.equals(altName)) {
|
||||
encoder.writeString(ATTRIB_LABEL, altName);
|
||||
}
|
||||
encoder.writeString(ATTRIB_CONTENT, nm);
|
||||
encoder.closeElement(ELEM_VAL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,10 @@ public class HighFunctionShellSymbol extends HighSymbol {
|
|||
encoder.openElement(ELEM_FUNCTION);
|
||||
encoder.writeUnsignedInteger(ATTRIB_ID, getId());
|
||||
encoder.writeString(ATTRIB_NAME, name);
|
||||
String altName = dtmanage.getNameTransformer().simplify(name);
|
||||
if (!name.equals(altName)) {
|
||||
encoder.writeString(ATTRIB_LABEL, altName);
|
||||
}
|
||||
encoder.writeSignedInteger(ATTRIB_SIZE, 1);
|
||||
AddressXML.encode(encoder, getStorage().getMinAddress());
|
||||
encoder.closeElement(ELEM_FUNCTION);
|
||||
|
|
|
@ -330,14 +330,21 @@ public class LocalSymbolMap {
|
|||
* Encode all the variables in this local variable map to the stream
|
||||
* @param encoder is the stream encoder
|
||||
* @param namespace if the namespace of the function
|
||||
* @param transformer is used to compute a simplified version of the namespace name
|
||||
* @throws IOException for errors in the underlying stream
|
||||
*/
|
||||
public void encodeLocalDb(Encoder encoder, Namespace namespace) throws IOException {
|
||||
public void encodeLocalDb(Encoder encoder, Namespace namespace, NameTransformer transformer)
|
||||
throws IOException {
|
||||
encoder.openElement(ELEM_LOCALDB);
|
||||
encoder.writeBool(ATTRIB_LOCK, false);
|
||||
encoder.writeSpace(ATTRIB_MAIN, localSpace);
|
||||
encoder.openElement(ELEM_SCOPE);
|
||||
encoder.writeString(ATTRIB_NAME, func.getFunction().getName());
|
||||
String nm = func.getFunction().getName();
|
||||
encoder.writeString(ATTRIB_NAME, nm);
|
||||
String altName = transformer.simplify(nm);
|
||||
if (!nm.equals(altName)) {
|
||||
encoder.writeString(ATTRIB_LABEL, altName);
|
||||
}
|
||||
encoder.openElement(ELEM_PARENT);
|
||||
long parentid = Namespace.GLOBAL_NAMESPACE_ID;
|
||||
if (!HighFunction.collapseToGlobal(namespace)) {
|
||||
|
@ -345,7 +352,7 @@ public class LocalSymbolMap {
|
|||
}
|
||||
encoder.writeUnsignedInteger(ATTRIB_ID, parentid);
|
||||
encoder.closeElement(ELEM_PARENT);
|
||||
encoder.openElement(ELEM_RANGELIST); // Emptry address range
|
||||
encoder.openElement(ELEM_RANGELIST); // Empty address range
|
||||
encoder.closeElement(ELEM_RANGELIST);
|
||||
encoder.openElement(ELEM_SYMBOLLIST);
|
||||
Iterator<HighSymbol> iter = symbolMap.values().iterator();
|
||||
|
|
|
@ -31,6 +31,7 @@ import ghidra.program.model.data.Enum;
|
|||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.program.model.lang.DecompilerLanguage;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.NameTransformer;
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -98,6 +99,7 @@ public class PcodeDataTypeManager {
|
|||
private DataTypeManager progDataTypes; // DataTypes from a particular program
|
||||
private DataTypeManager builtInDataTypes = BuiltInDataTypeManager.getDataTypeManager();
|
||||
private DataOrganization dataOrganization;
|
||||
private NameTransformer nameTransformer;
|
||||
private DecompilerLanguage displayLanguage;
|
||||
private boolean voidInputIsVarargs; // true if we should consider void parameter lists as varargs
|
||||
// Some C header conventions use an empty prototype to mean a
|
||||
|
@ -107,11 +109,12 @@ public class PcodeDataTypeManager {
|
|||
private VoidDataType voidDt;
|
||||
private int pointerWordSize; // Wordsize to assign to all pointer datatypes
|
||||
|
||||
public PcodeDataTypeManager(Program prog) {
|
||||
public PcodeDataTypeManager(Program prog, NameTransformer simplifier) {
|
||||
|
||||
program = prog;
|
||||
progDataTypes = prog.getDataTypeManager();
|
||||
dataOrganization = progDataTypes.getDataOrganization();
|
||||
nameTransformer = simplifier;
|
||||
voidInputIsVarargs = true; // By default, do not lock-in void parameter lists
|
||||
displayLanguage = prog.getCompilerSpec().getDecompilerOutputLanguage();
|
||||
if (displayLanguage != DecompilerLanguage.C_LANGUAGE) {
|
||||
|
@ -126,6 +129,14 @@ public class PcodeDataTypeManager {
|
|||
return program;
|
||||
}
|
||||
|
||||
public NameTransformer getNameTransformer() {
|
||||
return nameTransformer;
|
||||
}
|
||||
|
||||
public void setNameTransformer(NameTransformer newTransformer) {
|
||||
nameTransformer = newTransformer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a base/built-in data-type with the given name and/or id. If an id is provided and
|
||||
* a corresponding data-type exists, this data-type is returned. Otherwise the first
|
||||
|
@ -954,7 +965,12 @@ public class PcodeDataTypeManager {
|
|||
((BuiltIn) type).getDecompilerDisplayName(displayLanguage));
|
||||
}
|
||||
else {
|
||||
String name = type.getName();
|
||||
String displayName = nameTransformer.simplify(name);
|
||||
encoder.writeString(ATTRIB_NAME, type.getName());
|
||||
if (!name.equals(displayName)) {
|
||||
encoder.writeString(ATTRIB_LABEL, displayName);
|
||||
}
|
||||
long id = progDataTypes.getID(type);
|
||||
if (id > 0) {
|
||||
encoder.writeUnsignedInteger(ATTRIB_ID, id);
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/* ###
|
||||
* 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.program.model.symbol;
|
||||
|
||||
/**
|
||||
* A transformer that never alters its input
|
||||
*/
|
||||
public class IdentityNameTransformer implements NameTransformer {
|
||||
|
||||
@Override
|
||||
public String simplify(String input) {
|
||||
return input;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
/* ###
|
||||
* 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.program.model.symbol;
|
||||
|
||||
/**
|
||||
* Replace illegal characters in the given name with '_'. The transformer treats the name as a
|
||||
* C++ symbol. Letters and digits are generally legal. '~' is allowed at the start of the symbol.
|
||||
* Template parameters, surrounded by '<' and '>', allow additional special characters. Certain
|
||||
* special characters are allowed after the keyword "operator".
|
||||
*/
|
||||
public class IllegalCharCppTransformer implements NameTransformer {
|
||||
|
||||
private static int[] legalChars = null;
|
||||
private static final int AFTER_FIRST_CHAR = 1; // Legal after the first character
|
||||
private static final int TEMPLATE = 2; // Legal as part of template parameters
|
||||
private static final int OPERATOR = 4; // Legal after the "operator" keyword
|
||||
private static final int FIRST_CHAR = 8; // Legal as the first character
|
||||
|
||||
public IllegalCharCppTransformer() {
|
||||
if (legalChars == null) {
|
||||
legalChars = new int[128];
|
||||
for (int i = 0; i < legalChars.length; ++i) {
|
||||
legalChars[i] = 0;
|
||||
}
|
||||
legalChars['_'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR | FIRST_CHAR;
|
||||
legalChars['0'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||
legalChars['1'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||
legalChars['2'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||
legalChars['3'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||
legalChars['4'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||
legalChars['5'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||
legalChars['6'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||
legalChars['7'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||
legalChars['8'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||
legalChars['9'] = AFTER_FIRST_CHAR | TEMPLATE | OPERATOR;
|
||||
legalChars['*'] = TEMPLATE | OPERATOR;
|
||||
legalChars[':'] = TEMPLATE;
|
||||
legalChars['('] = TEMPLATE | OPERATOR;
|
||||
legalChars[')'] = TEMPLATE | OPERATOR;
|
||||
legalChars['['] = TEMPLATE | OPERATOR;
|
||||
legalChars[']'] = TEMPLATE | OPERATOR;
|
||||
legalChars[','] = TEMPLATE;
|
||||
legalChars['&'] = TEMPLATE | OPERATOR;
|
||||
legalChars['+'] = OPERATOR;
|
||||
legalChars['-'] = OPERATOR;
|
||||
legalChars['|'] = OPERATOR;
|
||||
legalChars['='] = OPERATOR;
|
||||
legalChars['!'] = OPERATOR;
|
||||
legalChars['/'] = OPERATOR;
|
||||
legalChars['%'] = OPERATOR;
|
||||
legalChars['^'] = OPERATOR;
|
||||
legalChars['~'] = TEMPLATE | OPERATOR | FIRST_CHAR;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String simplify(String input) {
|
||||
int templateDepth = 0;
|
||||
char[] transform = null;
|
||||
for (int i = 0; i < input.length(); ++i) {
|
||||
char c = input.charAt(i);
|
||||
if (Character.isLetter(c)) {
|
||||
continue;
|
||||
}
|
||||
else if (c == '<') {
|
||||
templateDepth += 1;
|
||||
continue;
|
||||
}
|
||||
else if (c == '>') {
|
||||
templateDepth -= 1;
|
||||
if (templateDepth < 0) {
|
||||
templateDepth = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (c < 128) {
|
||||
int val = legalChars[c];
|
||||
if (val != 0) {
|
||||
if (((val & AFTER_FIRST_CHAR) != 0) && i > 0) {
|
||||
continue; // Legal after first character
|
||||
}
|
||||
if (((val & FIRST_CHAR) != 0) && i == 0) {
|
||||
continue; // Legal as first character
|
||||
}
|
||||
if (((val & TEMPLATE) != 0) && templateDepth > 0) {
|
||||
continue; // Legal as template parameter
|
||||
}
|
||||
if (((val & OPERATOR) != 0) && i >= 8 && i <= 10) {
|
||||
if (input.startsWith("operator")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If we reach here, the character is deemed illegal
|
||||
if (transform == null) {
|
||||
transform = new char[input.length()];
|
||||
input.getChars(0, input.length(), transform, 0);
|
||||
}
|
||||
transform[i] = '_';
|
||||
}
|
||||
if (transform == null) {
|
||||
return input;
|
||||
}
|
||||
return new String(transform);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/* ###
|
||||
* 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.program.model.symbol;
|
||||
|
||||
/**
|
||||
* Interface to transform (shorten, simplify) names of data-types, functions, and name spaces
|
||||
* for display.
|
||||
*/
|
||||
public interface NameTransformer {
|
||||
|
||||
/**
|
||||
* Return a transformed version of the given input. If no change is made, the original
|
||||
* String object is returned.
|
||||
* @param input is the name to transform
|
||||
* @return the transformed version
|
||||
*/
|
||||
public String simplify(String input);
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/* ###
|
||||
* 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.program.model.symbol;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import generic.test.AbstractGenericTest;
|
||||
|
||||
public class IllegalCharCppTransformerTest extends AbstractGenericTest {
|
||||
|
||||
private IllegalCharCppTransformer transformer = new IllegalCharCppTransformer();
|
||||
|
||||
@Test
|
||||
public void testTemplateChars() {
|
||||
assertEquals("foo<bar>", simplify("foo<bar>"));
|
||||
assertEquals("foo<std::bar>", simplify("foo<std::bar>"));
|
||||
assertEquals("map<int,char*>", simplify("map<int,char*>"));
|
||||
assertEquals("pair<vec1,(*)(char[12]),const&val>",
|
||||
simplify("pair<vec1,(*)(char[12]),const&val>"));
|
||||
assertEquals("_basic_string<char,std::char_traits<char>>",
|
||||
simplify("_basic.string<char,std::char_traits<char>>"));
|
||||
assertEquals("_________baz", simplify("*()~[]&:,baz"));
|
||||
assertEquals("foo12___<std::space__::vec>___bar__operator",
|
||||
simplify("foo12 ??<std::space??::vec>_*~bar::operator"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOperatorChars() {
|
||||
assertEquals("operator<<", simplify("operator<<"));
|
||||
assertEquals("operator>>=", simplify("operator>>="));
|
||||
assertEquals("operator++", simplify("operator++"));
|
||||
assertEquals("operator/=", simplify("operator/="));
|
||||
assertEquals("operator%", simplify("operator%"));
|
||||
assertEquals("operator&&", simplify("operator&&"));
|
||||
assertEquals("operator!=", simplify("operator!="));
|
||||
assertEquals("operator__", simplify("operator.?"));
|
||||
assertEquals("operator~", simplify("operator~"));
|
||||
assertEquals("operator^", simplify("operator^"));
|
||||
assertEquals("myoperator__", simplify("myoperator!="));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadChars() {
|
||||
assertEquals("~destructor_main", simplify("~destructor.main"));
|
||||
assertEquals("~Vector_7", simplify("~Vector~7"));
|
||||
assertEquals("_2foo", simplify("12foo"));
|
||||
assertEquals("std__foo", simplify("std::foo"));
|
||||
assertEquals("bar__1", simplify("bar??1"));
|
||||
assertEquals("_resource_352_", simplify("[resource.352]"));
|
||||
assertEquals("_val_", simplify("!val%"));
|
||||
// Foreign language identifiers
|
||||
assertEquals("\u041d\u0415\u0422", simplify("\u041d\u0415\u0422"));
|
||||
}
|
||||
|
||||
private String simplify(String in) {
|
||||
return transformer.simplify(in);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue