ghidra/Ghidra/Features/MicrosoftDmang/src/main/java/mdemangler/object/MDObjectCPP.java

289 lines
8.6 KiB
Java

/* ###
* 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 mdemangler.object;
import ghidra.util.Msg;
import mdemangler.*;
import mdemangler.MDMang.ProcessingMode;
import mdemangler.functiontype.MDFunctionType;
import mdemangler.naming.*;
import mdemangler.typeinfo.MDTypeInfo;
import mdemangler.typeinfo.MDTypeInfoParser;
/**
* This class represents a derivative of an <b><code>MDObject</code></b> which is a C++ object.
*/
public class MDObjectCPP extends MDObject {
protected MDHashedObject hashedObject;
protected MDQualifiedBasicName qualifiedName;
protected MDTypeInfo typeInfo;
protected boolean embeddedObjectFlag;
protected boolean hashedObjectFlag;
public MDObjectCPP(MDMang dmang) {
super(dmang);
}
public MDQualifiedBasicName getQualifiedName() {
return qualifiedName;
}
public MDTypeInfo getTypeInfo() {
return typeInfo;
}
/**
* Returns the embedded object if there is one. Else returns itself.
* @see MDBasicName#getEmbeddedObject()
* @return An MDObjectCPP representing the original or the embedded object.
*/
public MDObjectCPP getEmbeddedObject() {
if (embeddedObjectFlag) {
return qualifiedName.getBasicName().getEmbeddedObject();
}
return this;
}
/**
* Returns the name of the symbol, minus any namespace component.
* @return the name.
*/
public String getName() {
if (hashedObjectFlag) {
return hashedObject.getName();
}
return getQualifiedName().getBasicName().toString();
}
/**
* Returns the {@link MDQualification} component that represents the namespace.
* @return the namespace information.
*/
public MDQualification getQualification() {
if (hashedObjectFlag) {
return hashedObject.getQualification();
}
return getQualifiedName().getQualification();
}
/**
* Returns {@code true} if the symbol's Basic Name is of a {@link MDString} type.
* @return {@code true} if Basic Name is of {@link MDString} type.
*/
public boolean isString() {
if (qualifiedName == null) {
return false;
}
return qualifiedName.isString();
}
/**
* Returns the {@link MDString} from the Basic Name if it is a symbol of that type; else
* returns null.
* @return the {@link MDString} or null if does not exist.
*/
public MDString getMDString() {
if (isString()) {
return qualifiedName.getMDString();
}
return null;
}
@Override
public void insert(StringBuilder builder) {
if (hashedObjectFlag) {
hashedObject.insert(builder);
}
else {
qualifiedName.insert(builder);
if (typeInfo != null) {
typeInfo.insert(builder);
}
}
}
@Override
protected void parseInternal() throws MDException {
if (dmang.peek() != '?') {
throw new MDException("Invalid ObjectCPP");
}
if (!dmang.isProcessingModeActive(ProcessingMode.LLVM)) {
// If not LLVM mode, then the '?' seen above is valid as being part of this MDObjectCPP
// parsing, so we should consume it. If, on the other hand, we are in LLVM mode, then
// this '?' is currently part of the possible nonstandard mangling forms that are
// output by LLVM mangling and they are consumed there.
dmang.increment();
}
if ((dmang.peek(0) == '?') && (dmang.peek(1) == '?')) { //??? prefix
embeddedObjectFlag = true;
}
if ((dmang.peek(0) == '?') && (dmang.peek(1) == '@')) { //??@ prefix
// MDMANG SPECIALIZATION USED.
dmang.processHashedObject(this);
}
else {
qualifiedName = new MDQualifiedBasicName(dmang);
qualifiedName.parse();
if (qualifiedName.isString()) {
return;
}
if (dmang.peek() != MDMang.DONE) {
int RTTINum = qualifiedName.getRTTINumber();
typeInfo = MDTypeInfoParser.parse(dmang, RTTINum);
if (qualifiedName.isTypeCast()) {
typeInfo.setTypeCast();
}
typeInfo.parse();
if (!typeInfo.getNameModifier().isEmpty()) {
qualifiedName.setNameModifier(typeInfo.getNameModifier());
}
if (qualifiedName.isTypeCast()) {
applyFunctionReturnTypeToTypeCastOperatorName();
}
}
}
}
private void applyFunctionReturnTypeToTypeCastOperatorName() {
// Make sure there is a function with a return type
if (!(typeInfo.getMDType() instanceof MDFunctionType)) {
Msg.warn(this, "Cannot get function return type from non-function");
return;
}
MDFunctionType functionType = (MDFunctionType) typeInfo.getMDType();
if (!functionType.hasReturn() || functionType.getReturnType() == null) {
Msg.warn(this, "No return type available to set to cast operator name");
return;
}
qualifiedName.setCastTypeString(functionType.getReturnType().toString());
}
/**
* Processes the hashed object in the normal fashion.
* @throws MDException On parsing error.
*/
public void processHashedObject() throws MDException {
hashedObject = new MDHashedObject(dmang);
hashedObject.parse();
hashedObjectFlag = true;
}
/**
* Always throws an exception, mimicking the MSFT "failure" behavior, which cuts the parsing
* process short... This is one of two choice methods than can be used.
* @throws MDException always.
* @see #processHashedObject()
*/
public void processHashedObjectMSVC() throws MDException {
throw new MDException("cannot parse hashed symbol");
}
/**
* Represents the MD5 hashed representation of the internals of the {@link MDObjectCPP}.
* It takes the place of the {@link MDQualifiedBasicName}. We have included an unused
* (except to be able to return one that is empty) {@link MDQualification} so that the
* {@link MDObjectCPP} has one to return.
* <p>
* Not sure that we will keep this class in the long run or find a way to include it
* inside of the {@link MDObjectCPP} or if this {@link MDHashedObject} should be pulled
* out separately and detected/parsed by the {@link MDMangObjectParser}. If this last
* thing is done, then we would have to find places in the package where we explicitly
* create {@link MDObjectCPP MDObjectCPPs}, such as in {@link MDNestedName}, and check to
* see if we can modify those locations (in all cases) to perform the detecting/parsing
* using the {@link MDMangObjectParser}. This will need more study when more time is
* available.
*/
public class MDHashedObject extends MDParsableItem {
private String hashString = "";
private MDQualification qualification; // We are making this dummy object
/**
* Constructor for {@link MDHashedObject}
* @param dmang The {@link MDMang} for which the work is performed and from from which
* the information is parsed.
*/
public MDHashedObject(MDMang dmang) {
super(dmang);
qualification = new MDQualification(dmang);
}
/**
* Returns the hashed string.
* @return the hashed string.
*/
public String getHashString() {
return hashString;
}
/**
* Returns an empty {@link MDQualification} that represents the namespace of the symbol.
* Note: we have yet to decide whether we should do anything but this.
* @return the namespace information (empty for now).
*/
public MDQualification getQualification() {
return qualification;
}
@Override
protected void parseInternal() throws MDException {
if ((dmang.peek() != '?') && (dmang.peek(1) != '@')) {
throw new MDException("Invalid HashedObject");
}
dmang.increment(2);
StringBuilder builder = new StringBuilder();
char ch;
int start = dmang.getIndex();
while ((ch = dmang.peek()) != MDMang.DONE) {
if (ch == '@') {
break;
}
if (!(Character.isLetter(ch) || Character.isDigit(ch))) {
break;
}
builder.append(ch);
dmang.increment();
}
int end = dmang.getIndex();
if ((end - start) != 32 || ch != '@') {
throw new MDException("Invalid HashedObject");
}
dmang.increment();
hashString = builder.toString();
}
/**
* Returns the name representation
* @return the name
*/
public String getName() {
// We have made up the name representation with the encompassing tick marks (similar
// to other types). Nothing is sacrosanct about this output.
return "`" + hashString + "'";
}
@Override
public void insert(StringBuilder builder) {
builder.append(getName());
}
}
}
/******************************************************************************/
/******************************************************************************/