Merge remote-tracking branch 'origin/patch'

This commit is contained in:
Ryan Kurtz 2023-05-24 12:49:11 -04:00
commit 3b9263f1b4
31 changed files with 709 additions and 134 deletions

View file

@ -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);
}
}

View file

@ -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);

View file

@ -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();

View file

@ -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);

View file

@ -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;
}
}

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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);
}
}