GP-2966: Consider aliases in debugger register mapping.

This commit is contained in:
Dan 2023-01-19 12:48:01 -05:00
parent 942d60eeac
commit a9c1949742
13 changed files with 276 additions and 55 deletions

View file

@ -15,8 +15,7 @@
*/
package ghidra.trace.database.guest;
import java.util.Collection;
import java.util.List;
import java.util.*;
import ghidra.dbg.target.TargetObject;
import ghidra.dbg.target.TargetRegister;
@ -80,41 +79,58 @@ public interface InternalTracePlatform extends TracePlatform {
return result;
}
default List<String> listRegNames(Register register) {
Set<String> result = new LinkedHashSet<>();
result.add(register.getName());
result.add(register.getName().toUpperCase());
result.add(register.getName().toLowerCase());
for (String alias : register.getAliases()) {
result.add(alias);
result.add(alias.toUpperCase());
result.add(alias.toLowerCase());
}
return List.copyOf(result);
}
@Override
default String getConventionalRegisterObjectName(Register register) {
default Collection<String> getConventionalRegisterObjectNames(Register register) {
Address pmin = mapGuestToHost(register.getAddress());
if (pmin == null) {
return register.getName();
return listRegNames(register);
}
TraceSymbolManager symbolManager = getTrace().getSymbolManager();
TraceNamespaceSymbol nsRegMap = symbolManager.namespaces().getGlobalNamed(regMap(register));
Collection<? extends TraceLabelSymbol> labels = symbolManager.labels()
Collection<String> labels = symbolManager.labels()
.getAt(0, null, pmin, false)
.stream()
.filter(s -> s.getParentNamespace() == nsRegMap)
.map(TraceSymbol::getName)
.toList();
if (labels.isEmpty()) {
return register.getName();
if (!labels.isEmpty()) {
return labels;
}
// primary is listed first, so take it
return labels.iterator().next().getName();
return listRegNames(register);
}
@Override
default PathMatcher getConventionalRegisterPath(TargetObjectSchema schema, List<String> path,
String name) {
Collection<String> names) {
PathMatcher matcher = schema.searchFor(TargetRegister.class, path, true);
if (matcher.isEmpty()) {
return matcher;
}
return matcher.applyKeys(Align.RIGHT, List.of(name));
PathMatcher result = new PathMatcher();
for (String name:names) {
result.addAll(matcher.applyKeys(Align.RIGHT, List.of(name)));
}
return result;
}
@Override
default PathMatcher getConventionalRegisterPath(TargetObjectSchema schema, List<String> path,
Register register) {
return getConventionalRegisterPath(schema, path,
getConventionalRegisterObjectName(register));
getConventionalRegisterObjectNames(register));
}
@Override
@ -156,6 +172,11 @@ public interface InternalTracePlatform extends TracePlatform {
if (nsRegMap == null) {
nsRegMap = namespaces.add(regMap, globals, SourceType.USER_DEFINED);
}
TraceLabelSymbol exists = symbolManager.labels()
.getChildWithNameAt(objectName, getIntKey(), null, hostAddr, nsRegMap);
if (exists != null) {
return exists;
}
return symbolManager.labels()
.create(0, null, hostAddr, objectName, nsRegMap, SourceType.USER_DEFINED);
}

View file

@ -15,6 +15,7 @@
*/
package ghidra.trace.model.guest;
import java.util.Collection;
import java.util.List;
import ghidra.dbg.target.TargetObject;
@ -171,27 +172,29 @@ public interface TracePlatform {
AddressRange getConventionalRegisterRange(AddressSpace overlay, Register register);
/**
* Get the name or index of the register object for the given platform register
* Get the names or indices of the register object for the given platform register
*
* <p>
* This will check for a label in the host physical space, allowing a mapper to specify an
* alternative register object name. See {@link #addRegisterMapOverride(Register, String)}.
* alternative register object name. See {@link #addRegisterMapOverride(Register, String)}. If
* one exists, then only that name is returned. Otherwise, the given register's names and
* aliases are all returned as defined and in all-upper and all-lower case.
*
* @param register the platform register
* @return the mapped name
*/
String getConventionalRegisterObjectName(Register register);
Collection<String> getConventionalRegisterObjectNames(Register register);
/**
* Get the expected path where an object defining the register value would be
*
* @param schema the schema of the register container
* @param path the path to the register container
* @param name the name of the register on the target
* @param names the possible names of the register on the target
* @return the path matcher, possibly empty
*/
PathMatcher getConventionalRegisterPath(TargetObjectSchema schema, List<String> path,
String name);
Collection<String> names);
/**
* Get the expected path where an object defining the register value would be

View file

@ -459,4 +459,23 @@ public class DBTraceObjectRegisterSupportTest extends AbstractGhidraHeadlessInte
assertMatches("Targets[0].Threads[0].Registers.User[r0]",
b.host.getConventionalRegisterPath(overlay, b.reg("r0")));
}
@Test
public void testPlatformGetConventionalRegisterPathAlias() throws Throwable {
AddressSpace registers = b.trace.getBaseAddressFactory().getRegisterSpace();
AddressSpace overlay;
Register r0;
try (UndoableTransaction tid = b.startTransaction()) {
root = manager.createRootObject(ctx.getSchema(new SchemaName("Session"))).getChild();
r0 = b.language.getRegister("r0");
overlay = b.trace.getMemoryManager()
.createOverlayAddressSpace("Targets[0].Threads[0].Registers", registers);
}
PathMatcher matcher = b.host.getConventionalRegisterPath(overlay, r0);
assertMatches("Targets[0].Threads[0].Registers.User[r0]", matcher);
assertMatches("Targets[0].Threads[0].Registers.User[a0]", matcher);
assertMatches("Targets[0].Threads[0].Registers.User[R0]", matcher);
assertMatches("Targets[0].Threads[0].Registers.User[A0]", matcher);
}
}