mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-07-30 07:18:37 -09:00
GP-6976 handle .cold symbols in ELF files
This commit is contained in:
@@ -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.
|
||||
@@ -15,8 +15,7 @@
|
||||
*/
|
||||
package ghidra.app.cmd.analysis;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.app.cmd.disassemble.SetFlowOverrideCmd;
|
||||
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
||||
@@ -24,6 +23,7 @@ import ghidra.framework.cmd.BackgroundCommand;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.AddressSetPropertyMap;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
@@ -72,6 +72,10 @@ public class SharedReturnAnalysisCmd extends BackgroundCommand<Program> {
|
||||
processFunctionJumpReferences(program, entry, monitor);
|
||||
}
|
||||
|
||||
AddressSetPropertyMap coldMap =
|
||||
program.getAddressSetPropertyMap(Program.COLD_ENTRY_MAP_NAME);
|
||||
Set<Address> conditionalJumpTargets = new HashSet<>();
|
||||
Set<Address> onlyUnconditionalJumpTargets = new HashSet<>();
|
||||
if (assumeContiguousFunctions) {
|
||||
// assume if checkAllJumpReferences then set is much more than new function starts
|
||||
|
||||
@@ -116,6 +120,45 @@ public class SharedReturnAnalysisCmd extends BackgroundCommand<Program> {
|
||||
continue; // can't handle flows between different spaces/overlays
|
||||
}
|
||||
|
||||
// skip .cold targets
|
||||
if (coldMap != null) {
|
||||
if (coldMap.contains(destAddr)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!considerConditionalBranches) {
|
||||
if (conditionalJumpTargets.contains(destAddr)) {
|
||||
// destAddr is a conditional jump target, skip
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!onlyUnconditionalJumpTargets.contains(destAddr)) {
|
||||
//haven't checked the types of flow refs to destAddr yet
|
||||
ReferenceIterator refIter =
|
||||
program.getReferenceManager().getReferencesTo(destAddr);
|
||||
boolean conditionalRef = false;
|
||||
while (refIter.hasNext()) {
|
||||
Reference ref = refIter.next();
|
||||
RefType refType = ref.getReferenceType();
|
||||
if (!refType.isFlow()) {
|
||||
continue;
|
||||
}
|
||||
if (refType.isConditional()) {
|
||||
conditionalRef = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (conditionalRef) {
|
||||
// found a conditional jump, record destAddr and skip
|
||||
conditionalJumpTargets.add(destAddr);
|
||||
continue;
|
||||
}
|
||||
// no conditional flow refs to destAddr
|
||||
onlyUnconditionalJumpTargets.add(destAddr);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset cached functions if we transition to a different space/overlay
|
||||
if (functionAfterSrc != null &&
|
||||
functionAfterSrc.getAddressSpace() != srcAddr.getAddressSpace()) {
|
||||
|
||||
@@ -404,7 +404,7 @@ public class EntryPointAnalyzer extends AbstractAnalyzer {
|
||||
}
|
||||
|
||||
private void disassembleCodeMapMarkers(Program program, TaskMonitor monitor) {
|
||||
AddressSetPropertyMap codeProp = program.getAddressSetPropertyMap("CodeMap");
|
||||
AddressSetPropertyMap codeProp = program.getAddressSetPropertyMap(Program.CODE_MAP_NAME);
|
||||
if (codeProp != null) {
|
||||
Set<Address> codeSet = new HashSet<>();
|
||||
AddressIterator aiter = codeProp.getAddresses();
|
||||
|
||||
@@ -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.
|
||||
@@ -33,7 +33,7 @@ import ghidra.util.task.TaskMonitor;
|
||||
* associated branching instruction flow to a CALL-RETURN
|
||||
*/
|
||||
public class SharedReturnAnalyzer extends AbstractAnalyzer {
|
||||
|
||||
|
||||
private static final String NAME = "Shared Return Calls";
|
||||
protected static final String DESCRIPTION =
|
||||
"Converts branches to calls, followed by an immediate return, when the destination is a function. " +
|
||||
@@ -59,7 +59,8 @@ public class SharedReturnAnalyzer extends AbstractAnalyzer {
|
||||
private final static boolean OPTION_DEFAULT_CONSIDER_CONDITIONAL_BRANCHES_ENABLED = false;
|
||||
|
||||
private boolean assumeContiguousFunctions = OPTION_DEFAULT_ASSUME_CONTIGUOUS_FUNCTIONS_ENABLED;
|
||||
private boolean considerConditionalBranches = OPTION_DEFAULT_CONSIDER_CONDITIONAL_BRANCHES_ENABLED;
|
||||
private boolean considerConditionalBranches =
|
||||
OPTION_DEFAULT_CONSIDER_CONDITIONAL_BRANCHES_ENABLED;
|
||||
|
||||
public SharedReturnAnalyzer() {
|
||||
this(NAME, DESCRIPTION, AnalyzerType.FUNCTION_ANALYZER);
|
||||
@@ -91,11 +92,12 @@ public class SharedReturnAnalyzer extends AbstractAnalyzer {
|
||||
if (GoRttiMapper.isGolangProgram(program)) {
|
||||
sharedReturnEnabled = false;
|
||||
}
|
||||
|
||||
|
||||
// If the language (in the .pspec file) overrides this setting, use that value
|
||||
boolean contiguousFunctionsEnabled = language.getPropertyAsBoolean(
|
||||
GhidraLanguagePropertyKeys.ENABLE_ASSUME_CONTIGUOUS_FUNCTIONS_ONLY, assumeContiguousFunctions);
|
||||
|
||||
GhidraLanguagePropertyKeys.ENABLE_ASSUME_CONTIGUOUS_FUNCTIONS_ONLY,
|
||||
assumeContiguousFunctions);
|
||||
|
||||
assumeContiguousFunctions = contiguousFunctionsEnabled;
|
||||
|
||||
return sharedReturnEnabled;
|
||||
@@ -121,7 +123,8 @@ public class SharedReturnAnalyzer extends AbstractAnalyzer {
|
||||
assumeContiguousFunctions = options.getBoolean(OPTION_NAME_ASSUME_CONTIGUOUS_FUNCTIONS,
|
||||
assumeContiguousFunctions);
|
||||
|
||||
considerConditionalBranches = options.getBoolean(OPTION_NAME_CONSIDER_CONDITIONAL_BRANCHES_FUNCTIONS,
|
||||
considerConditionalBranches =
|
||||
options.getBoolean(OPTION_NAME_CONSIDER_CONDITIONAL_BRANCHES_FUNCTIONS,
|
||||
considerConditionalBranches);
|
||||
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ package ghidra.app.plugin.exceptionhandlers.gcc.structures.ehFrame;
|
||||
import ghidra.app.cmd.comments.SetCommentCmd;
|
||||
import ghidra.app.cmd.data.CreateArrayCmd;
|
||||
import ghidra.app.cmd.data.CreateDataCmd;
|
||||
import ghidra.app.cmd.function.CreateFunctionCmd;
|
||||
import ghidra.app.plugin.core.analysis.AutoAnalysisManager;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.*;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.sections.CieSource;
|
||||
import ghidra.app.plugin.exceptionhandlers.gcc.sections.DebugFrameSection;
|
||||
@@ -469,9 +469,12 @@ public class FrameDescriptionEntry extends GccAnalysisClass {
|
||||
region.setIPRange(addrRange);
|
||||
|
||||
try {
|
||||
/* Create a function at the pcBegin Addr address */
|
||||
CreateFunctionCmd createFuncCmd = new CreateFunctionCmd(pcBeginAddr);
|
||||
createFuncCmd.applyTo(program);
|
||||
/* pcBeginAddr is not necessarily a function start, but it is code */
|
||||
/* schedule disassembly if there is not already a function defined there */
|
||||
if (program.getListing().getFunctionAt(pcBeginAddr) == null) {
|
||||
AutoAnalysisManager analysisMgr = AutoAnalysisManager.getAnalysisManager(program);
|
||||
analysisMgr.disassemble(new AddressSet(pcBeginAddr));
|
||||
}
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
throw new ExceptionHandlerFrameException(
|
||||
|
||||
@@ -17,6 +17,7 @@ package ghidra.app.util.bin.format.elf;
|
||||
|
||||
import ghidra.app.util.bin.format.MemoryLoadable;
|
||||
import ghidra.app.util.importer.MessageLog;
|
||||
import ghidra.app.util.opinion.AbstractProgramLoader;
|
||||
import ghidra.app.util.opinion.ElfLoaderOptionsFactory;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
@@ -78,7 +79,10 @@ public interface ElfLoadHelper {
|
||||
* The analyzers will pick this up and disassemble the code.
|
||||
* @param address code memory address to be marked
|
||||
*/
|
||||
void markAsCode(Address address);
|
||||
default void markAsCode(Address address) {
|
||||
Program program = getProgram();
|
||||
AbstractProgramLoader.markProperty(program, address, Program.CODE_MAP_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a one-byte function, so that when the code is analyzed,
|
||||
|
||||
@@ -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.
|
||||
@@ -16,6 +16,8 @@
|
||||
package ghidra.app.util.bin.format.elf;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
@@ -91,6 +93,10 @@ public class ElfSymbol {
|
||||
/**Not preemptible, not exported*/
|
||||
public static final byte STV_PROTECTED = 3;
|
||||
|
||||
/** Pattern for recognized .cold symbol names in ELF files **/
|
||||
private static final Pattern COLD_ELF_SYMBOL_PATTERN =
|
||||
Pattern.compile(".+\\.cold((\\.[0-9]+)?)");
|
||||
|
||||
private ElfSymbolTable symbolTable;
|
||||
private final int symbolTableIndex;
|
||||
|
||||
@@ -317,11 +323,36 @@ public class ElfSymbol {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this symbol defines a function.
|
||||
* @return true if this symbol defines a function
|
||||
* Returns true if this symbol has type {@link ElfSymbol#STT_FUNC}.
|
||||
* <br>
|
||||
* Note: compare to {@link ElfSymbol#isFunction(boolean)}
|
||||
* @return true if symbol type is {@code STT_FUNC}
|
||||
*/
|
||||
public boolean isFunction() {
|
||||
return getType() == STT_FUNC;
|
||||
return isFunction(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* If {@code entryPointsOnly} is false, this method tests whether the symbol's type is
|
||||
* {@link ElfSymbol#STT_FUNC}. If {@code entryPointsOnly} is true, this method tests whether
|
||||
* the symbol's type is {@link ElfSymbol#STT_FUNC} and whether the symbol represents an actual
|
||||
* function entry point (currently by checking whether the symbol name ends in {@code .cold}
|
||||
* or {@code .cold.N})
|
||||
* @param entryPointsOnly if true, restrict to function entry points
|
||||
* @return true if the symbol is a (possibly restricted) function symbol.
|
||||
*/
|
||||
public boolean isFunction(boolean entryPointsOnly) {
|
||||
if (getType() != STT_FUNC) {
|
||||
// not a function symbol
|
||||
return false;
|
||||
}
|
||||
if (!entryPointsOnly) {
|
||||
// only care about whether it is a function symbol
|
||||
return true;
|
||||
}
|
||||
// check the symbol name
|
||||
Matcher matcher = COLD_ELF_SYMBOL_PATTERN.matcher(getNameAsString());
|
||||
return !matcher.matches();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -504,4 +535,14 @@ public class ElfSymbol {
|
||||
Integer.toHexString(Short.toUnsignedInt(st_shndx));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether {@code name} is the name of a "cold" Elf symbol.
|
||||
* @param name string to test
|
||||
* @return true if cold, false otherwise
|
||||
*/
|
||||
public static boolean isColdSymbolName(String name) {
|
||||
Matcher matcher = COLD_ELF_SYMBOL_PATTERN.matcher(name);
|
||||
return matcher.matches();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.AddressSetPropertyMap;
|
||||
import ghidra.program.util.DefaultLanguageService;
|
||||
import ghidra.program.util.GhidraProgramUtilities;
|
||||
import ghidra.util.MD5Utilities;
|
||||
@@ -348,6 +349,27 @@ public abstract class AbstractProgramLoader implements Loader {
|
||||
prog.setExecutableSHA256(sha256);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark an address in the given property map. If the map does not exist it will be created.
|
||||
* @param program program
|
||||
* @param address address to mark
|
||||
* @param propertyMapName name of property map
|
||||
*/
|
||||
public static void markProperty(Program program, Address address, String propertyMapName) {
|
||||
AddressSetPropertyMap codeProp = program.getAddressSetPropertyMap(propertyMapName);
|
||||
if (codeProp == null) {
|
||||
try {
|
||||
codeProp = program.createAddressSetPropertyMap(propertyMapName);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
codeProp = program.getAddressSetPropertyMap(propertyMapName);
|
||||
}
|
||||
}
|
||||
if (codeProp != null) {
|
||||
codeProp.add(address, address);
|
||||
}
|
||||
}
|
||||
|
||||
private String getProgramNameFromSourceData(ByteProvider provider, String domainFileName) {
|
||||
FSRL fsrl = provider.getFSRL();
|
||||
if (fsrl != null) {
|
||||
|
||||
@@ -50,7 +50,6 @@ import ghidra.program.model.reloc.*;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.scalar.Scalar;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.AddressSetPropertyMap;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.datastruct.*;
|
||||
@@ -613,13 +612,13 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
set.delete(startAddr, block.getEnd());
|
||||
}
|
||||
}
|
||||
catch (MemoryBlockException | LockException | NotFoundException e) {
|
||||
catch (MemoryBlockException | LockException e) {
|
||||
throw new AssertException(e); // unexpected
|
||||
}
|
||||
}
|
||||
|
||||
private MemoryBlock setReadOnlyBlockRange(MemoryBlock block, AddressRange range)
|
||||
throws MemoryBlockException, LockException, NotFoundException {
|
||||
throws MemoryBlockException, LockException {
|
||||
if (!block.isWrite()) {
|
||||
return block;
|
||||
}
|
||||
@@ -2102,7 +2101,7 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
}
|
||||
|
||||
try {
|
||||
boolean isPrimary = (elfSymbol.getType() == ElfSymbol.STT_FUNC) ||
|
||||
boolean isPrimary = elfSymbol.isFunction() ||
|
||||
(elfSymbol.getType() == ElfSymbol.STT_OBJECT) || (elfSymbol.getSize() != 0);
|
||||
// don't displace existing primary unless symbol is a function or object symbol
|
||||
if (name.contains("@")) {
|
||||
@@ -2127,8 +2126,8 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
program.getSymbolTable().addExternalEntryPoint(address);
|
||||
}
|
||||
|
||||
if (elfSymbol.getType() == ElfSymbol.STT_FUNC) {
|
||||
Function existingFunction = program.getFunctionManager().getFunctionAt(address);
|
||||
Function existingFunction = program.getFunctionManager().getFunctionAt(address);
|
||||
if (elfSymbol.isFunction(true)) {
|
||||
if (existingFunction == null) {
|
||||
Function f = createOneByteFunction(null, address, false);
|
||||
if (f != null) {
|
||||
@@ -2146,6 +2145,11 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (elfSymbol.isFunction(false) && existingFunction == null) {
|
||||
AbstractProgramLoader.markProperty(program, address, Program.CODE_MAP_NAME);
|
||||
AbstractProgramLoader.markProperty(program, address,
|
||||
Program.COLD_ENTRY_MAP_NAME);
|
||||
}
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
throw new RuntimeException("Unexpected Exception", e);
|
||||
@@ -2153,7 +2157,6 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setElfSymbolAddress(ElfSymbol elfSymbol, Address address) {
|
||||
symbolMap.put(elfSymbol, address);
|
||||
@@ -2164,25 +2167,6 @@ class ElfProgramBuilder extends MemorySectionResolver implements ElfLoadHelper {
|
||||
return symbolMap.get(elfSymbol);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void markAsCode(Address address) {
|
||||
// TODO: this should be in a common place, so all importers can communicate that something
|
||||
// is code or data.
|
||||
AddressSetPropertyMap codeProp = program.getAddressSetPropertyMap("CodeMap");
|
||||
if (codeProp == null) {
|
||||
try {
|
||||
codeProp = program.createAddressSetPropertyMap("CodeMap");
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
codeProp = program.getAddressSetPropertyMap("CodeMap");
|
||||
}
|
||||
}
|
||||
|
||||
if (codeProp != null) {
|
||||
codeProp.add(address, address);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function createOneByteFunction(String name, Address address, boolean isEntry) {
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.reloc.Relocation.Status;
|
||||
import ghidra.program.model.reloc.RelocationTable;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.AddressSetPropertyMap;
|
||||
import ghidra.program.model.util.CodeUnitInsertionException;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.*;
|
||||
@@ -495,32 +494,6 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this location as code in the CodeMap. The analyzers will pick this up and disassemble
|
||||
* the code.
|
||||
*
|
||||
* TODO: this should be in a common place, so all importers can communicate that something is
|
||||
* code or data.
|
||||
*
|
||||
* @param program The program to mark up.
|
||||
* @param address The location.
|
||||
*/
|
||||
private void markAsCode(Program program, Address address) {
|
||||
AddressSetPropertyMap codeProp = program.getAddressSetPropertyMap("CodeMap");
|
||||
if (codeProp == null) {
|
||||
try {
|
||||
codeProp = program.createAddressSetPropertyMap("CodeMap");
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
codeProp = program.getAddressSetPropertyMap("CodeMap");
|
||||
}
|
||||
}
|
||||
|
||||
if (codeProp != null) {
|
||||
codeProp.add(address, address);
|
||||
}
|
||||
}
|
||||
|
||||
private void processExports(OptionalHeader optionalHeader, Program program, TaskMonitor monitor,
|
||||
MessageLog log) {
|
||||
|
||||
@@ -809,7 +782,7 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||
if (entry > 0) {
|
||||
try {
|
||||
symTable.createLabel(entryAddr, "__x86_CIL_", SourceType.IMPORTED);
|
||||
markAsCode(prog, entryAddr);
|
||||
markProperty(prog, entryAddr, Program.CODE_MAP_NAME);
|
||||
symTable.addExternalEntryPoint(entryAddr);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
@@ -825,7 +798,7 @@ public class PeLoader extends AbstractPeDebugLoader {
|
||||
try {
|
||||
// mark up entry (either Native or IL)
|
||||
symTable.createLabel(entryAddr, "entry", SourceType.IMPORTED);
|
||||
markAsCode(prog, entryAddr);
|
||||
markProperty(prog, entryAddr, Program.CODE_MAP_NAME);
|
||||
}
|
||||
catch (InvalidInputException e) {
|
||||
// ignore
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import generic.jar.ResourceFile;
|
||||
import generic.json.Json;
|
||||
import ghidra.app.util.SymbolPathParser;
|
||||
import ghidra.app.util.bin.format.elf.ElfSymbol;
|
||||
import ghidra.app.util.demangler.*;
|
||||
import ghidra.framework.Application;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
@@ -451,8 +452,12 @@ public class GnuDemanglerParser {
|
||||
|
||||
private DemangledObjectBuilder getSpecializedBuilder(String demangled) {
|
||||
|
||||
// first check for .cold clone labels
|
||||
if (ElfSymbol.isColdSymbolName(mangledSource)) {
|
||||
return new ColdLabelHandler(demangled);
|
||||
}
|
||||
//
|
||||
// Note: we check for the 'special handlers' first, since they are more specific than
|
||||
// Note: we check for the 'special handlers' next, since they are more specific than
|
||||
// the other handlers here. Checking for the operator handler first can produce
|
||||
// errors, since some 'special handler' strings actually contain 'operator'
|
||||
// signatures. In those cases, the operator handler will incorrectly match on the
|
||||
@@ -2567,4 +2572,17 @@ public class GnuDemanglerParser {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class ColdLabelHandler extends DemangledObjectBuilder {
|
||||
|
||||
ColdLabelHandler(String demangled) {
|
||||
super(demangled);
|
||||
}
|
||||
|
||||
@Override
|
||||
DemangledObject build() {
|
||||
return new DemangledLabel(mangledSource, demangledSource, demangled);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ package ghidra.app.util.demangler;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
@@ -2386,6 +2387,32 @@ public class GnuDemanglerParserTest extends AbstractGenericTest {
|
||||
signature);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColdLabel1() throws IOException {
|
||||
String mangled = "_Z6calleei.cold";
|
||||
String demangled = process.demangle(mangled);
|
||||
DemangledObject object = parser.parse(mangled, demangled);
|
||||
assertNotNull(object);
|
||||
assertType(object, DemangledLabel.class);
|
||||
assertEquals("callee(int) [clone .cold]", object.getRawDemangled());
|
||||
assertEquals("callee(int)_[clone_.cold]", object.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testColdLabel2() throws IOException {
|
||||
String mangled = "_ZN6ghidra15ContextInternal9FreeArrayaSERKS1_.cold";
|
||||
String demangled = process.demangle(mangled);
|
||||
DemangledObject object = parser.parse(mangled, demangled);
|
||||
assertNotNull(object);
|
||||
assertType(object, DemangledLabel.class);
|
||||
assertEquals(
|
||||
"ghidra::ContextInternal::FreeArray::operator=(ghidra::ContextInternal::FreeArray const&) [clone .cold]",
|
||||
object.getRawDemangled());
|
||||
assertEquals(
|
||||
"ghidra::ContextInternal::FreeArray::operator=(ghidra::ContextInternal::FreeArray_const&)_[clone_.cold]",
|
||||
object.getName());
|
||||
}
|
||||
|
||||
private void assertType(Demangled o, Class<?> c) {
|
||||
assertTrue("Wrong demangled type. \nExpected " + c + "; \nfound " + o.getClass(),
|
||||
c.isInstance(o));
|
||||
|
||||
@@ -82,6 +82,11 @@ public interface Program extends DataTypeManagerDomainObject, ProgramArchitectur
|
||||
/** The maximum number of operands for any assembly language */
|
||||
public final static int MAX_OPERANDS = 16;
|
||||
|
||||
/** Name of code property map **/
|
||||
public static final String CODE_MAP_NAME = "CodeMap";
|
||||
/** Name of cold entry point addresses property map **/
|
||||
public static final String COLD_ENTRY_MAP_NAME = "ColdEntries";
|
||||
|
||||
/**
|
||||
* Get the listing object.
|
||||
* @return the Listing interface to the listing object.
|
||||
|
||||
@@ -126,8 +126,9 @@ public class ARM_ElfExtension extends ElfExtension {
|
||||
}
|
||||
functionAddress = functionAddress.previous(); // align address
|
||||
try {
|
||||
program.getProgramContext().setValue(tmodeRegister, functionAddress,
|
||||
functionAddress, BigInteger.ONE);
|
||||
program.getProgramContext()
|
||||
.setValue(tmodeRegister, functionAddress,
|
||||
functionAddress, BigInteger.ONE);
|
||||
}
|
||||
catch (ContextChangeException e) {
|
||||
// ignore since should not be instructions at time of import
|
||||
@@ -165,8 +166,9 @@ public class ARM_ElfExtension extends ElfExtension {
|
||||
}
|
||||
else if ("$t".equals(symName) || symName.startsWith("$t.")) {
|
||||
// is thumb mode
|
||||
program.getProgramContext().setValue(tmodeRegister, address, address,
|
||||
BigInteger.valueOf(1));
|
||||
program.getProgramContext()
|
||||
.setValue(tmodeRegister, address, address,
|
||||
BigInteger.valueOf(1));
|
||||
elfLoadHelper.markAsCode(address);
|
||||
|
||||
// do not retain $t symbols in program due to potential function/thunk naming interference
|
||||
@@ -175,8 +177,9 @@ public class ARM_ElfExtension extends ElfExtension {
|
||||
}
|
||||
else if ("$a".equals(symName) || symName.startsWith("$a.")) {
|
||||
// is arm mode
|
||||
program.getProgramContext().setValue(tmodeRegister, address, address,
|
||||
BigInteger.valueOf(0));
|
||||
program.getProgramContext()
|
||||
.setValue(tmodeRegister, address, address,
|
||||
BigInteger.valueOf(0));
|
||||
elfLoadHelper.markAsCode(address);
|
||||
|
||||
// do not retain $a symbols in program due to potential function/thunk naming interference
|
||||
@@ -194,12 +197,13 @@ public class ARM_ElfExtension extends ElfExtension {
|
||||
elfLoadHelper.setElfSymbolAddress(elfSymbol, address);
|
||||
return null;
|
||||
}
|
||||
if (elfSymbol.getType() == ElfSymbol.STT_FUNC) {
|
||||
if (elfSymbol.isFunction()) {
|
||||
long symVal = address.getOffset();
|
||||
if ((symVal & 1) != 0 && tmodeRegister != null) {
|
||||
address = address.previous();
|
||||
program.getProgramContext().setValue(tmodeRegister, address, address,
|
||||
BigInteger.valueOf(1));
|
||||
program.getProgramContext()
|
||||
.setValue(tmodeRegister, address, address,
|
||||
BigInteger.valueOf(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,7 +393,7 @@ public class MIPS_ElfExtension extends ElfExtension {
|
||||
return address;
|
||||
}
|
||||
|
||||
if (elfSymbol.getType() == ElfSymbol.STT_FUNC) {
|
||||
if (elfSymbol.isFunction()) {
|
||||
|
||||
Program program = elfLoadHelper.getProgram();
|
||||
|
||||
|
||||
@@ -704,7 +704,7 @@ public class PowerPC64_ElfExtension extends ElfExtension {
|
||||
ElfHeader elfHeader = elfLoadHelper.getElfHeader();
|
||||
|
||||
// Check for V2 ABI
|
||||
if (isExternal || elfSymbol.getType() != ElfSymbol.STT_FUNC ||
|
||||
if (isExternal || !elfSymbol.isFunction() ||
|
||||
getPpc64ElfABIVersion(elfHeader) != 2) {
|
||||
return address;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user