Merge remote-tracking branch 'origin/GP-3887_Dan_traceRmiTutorial--SQUASHED'

This commit is contained in:
Dan 2024-04-22 15:56:04 -04:00
commit 6389d9630c
79 changed files with 2235 additions and 1663 deletions

View File

@ -1224,6 +1224,7 @@ def put_regions():
regobj.set_value('_executable', r.perms == None or 'x' in r.perms)
regobj.set_value('_offset', r.offset)
regobj.set_value('_objfile', r.objfile)
regobj.set_value('_display', f'{r.objfile} (0x{r.start:x}-0x{r.end:x})')
regobj.insert()
STATE.trace.proxy_object_path(
MEMORY_PATTERN.format(infnum=inf.num)).retain_values(keys)

View File

@ -57,6 +57,7 @@ GNU_DEBUGDATA_PREFIX = ".gnu_debugdata for "
class Module(namedtuple('BaseModule', ['name', 'base', 'max', 'sections'])):
pass
class Index:
def __init__(self, regions):
self.regions = {}
@ -64,6 +65,7 @@ class Index:
for r in regions:
self.regions[r.start] = r
self.bases.append(r.start)
def compute_base(self, address):
index = bisect.bisect_right(self.bases, address) - 1
if index == -1:
@ -78,6 +80,7 @@ class Index:
else:
return region.start
class Section(namedtuple('BaseSection', ['name', 'start', 'end', 'offset', 'attrs'])):
def better(self, other):
start = self.start if self.start != 0 else other.start
@ -103,8 +106,6 @@ class ModuleInfoReader(object):
if mat is None:
return None
n = mat['name']
if n.startswith(GNU_DEBUGDATA_PREFIX):
return None
return None if mat is None else mat['name']
def section_from_line(self, line):
@ -135,7 +136,7 @@ class ModuleInfoReader(object):
for line in out.split('\n'):
n = self.name_from_line(line)
if n is not None:
if name is not None:
if name is not None and not name.startswith(GNU_DEBUGDATA_PREFIX):
modules[name] = self.finish_module(name, sections, index)
name = n
sections = {}
@ -148,7 +149,7 @@ class ModuleInfoReader(object):
if s.name in sections:
s = s.better(sections[s.name])
sections[s.name] = s
if name is not None:
if name is not None and not name.startswith(GNU_DEBUGDATA_PREFIX):
modules[name] = self.finish_module(name, sections, index)
return modules
@ -292,8 +293,9 @@ class BreakpointLocationInfoReaderV8(object):
inf = gdb.selected_inferior()
thread_groups = [inf.num]
if breakpoint.location is not None and breakpoint.location.startswith("*0x"):
address = int(breakpoint.location[1:],16)
loc = BreakpointLocation(address, breakpoint.enabled, thread_groups)
address = int(breakpoint.location[1:], 16)
loc = BreakpointLocation(
address, breakpoint.enabled, thread_groups)
return [loc]
return []
@ -312,7 +314,8 @@ class BreakpointLocationInfoReaderV9(object):
return []
try:
address = gdb.parse_and_eval(breakpoint.location).address
loc = BreakpointLocation(address, breakpoint.enabled, thread_groups)
loc = BreakpointLocation(
address, breakpoint.enabled, thread_groups)
return [loc]
except Exception as e:
print(f"Error parsing bpt location = {breakpoint.location}")
@ -338,6 +341,7 @@ def _choose_breakpoint_location_info_reader():
BREAKPOINT_LOCATION_INFO_READER = _choose_breakpoint_location_info_reader()
def set_bool_param_by_api(name, value):
gdb.set_parameter(name, value)
@ -353,6 +357,7 @@ def choose_set_parameter():
else:
return set_bool_param_by_cmd
set_bool_param = choose_set_parameter()
@ -360,7 +365,7 @@ def get_level(frame):
if hasattr(frame, "level"):
return frame.level()
else:
level = -1;
level = -1
f = frame
while f is not None:
level += 1
@ -371,16 +376,16 @@ def get_level(frame):
class RegisterDesc(namedtuple('BaseRegisterDesc', ['name'])):
pass
def get_register_descs(arch, group='all'):
if hasattr(arch, "registers"):
return arch.registers(group)
else:
descs = []
regset = gdb.execute(f"info registers {group}", to_string=True).strip().split('\n')
regset = gdb.execute(
f"info registers {group}", to_string=True).strip().split('\n')
for line in regset:
if not line.startswith(" "):
tokens = line.strip().split()
descs.append(RegisterDesc(tokens[0]))
descs.append(RegisterDesc(tokens[0]))
return descs

View File

@ -15,6 +15,8 @@
*/
package ghidra.app.plugin.core.debug.gui.tracermi.launcher;
import static ghidra.app.plugin.core.debug.gui.tracermi.launcher.TraceRmiLauncherServicePlugin.getProgramName;
import java.util.*;
import java.util.stream.Stream;
@ -52,7 +54,7 @@ public class LaunchAction extends MultiActionDockingAction {
Program program = plugin.currentProgram;
String title = program == null
? "Configure and Launch ..."
: "Configure and Launch %s using...".formatted(program.getName());
: "Configure and Launch %s using...".formatted(getProgramName(program));
return Stream.concat(Stream.of(title), menuPath.stream()).toArray(String[]::new);
}
@ -77,12 +79,12 @@ public class LaunchAction extends MultiActionDockingAction {
Long last = saved.get(offer.getConfigName());
if (last == null) {
// NB. If program == null, this will always happen.
// Thus, no worries about program.getName() below.
// Thus, no worries about getProgramName(program) below.
continue;
}
String title = program == null
? "Re-launch " + offer.getTitle()
: "Re-launch %s using %s".formatted(program.getName(), offer.getTitle());
: "Re-launch %s using %s".formatted(getProgramName(program), offer.getTitle());
actions.add(new ActionBuilder(offer.getConfigName(), plugin.getName())
.popupMenuPath(title)
.popupMenuGroup("0", "%016x".formatted(Long.MAX_VALUE - last))
@ -158,11 +160,11 @@ public class LaunchAction extends MultiActionDockingAction {
return "Configure and launch";
}
if (offer == null) {
return "Configure and launch " + program.getName();
return "Configure and launch " + getProgramName(program);
}
if (program == null) {
return "Re-launch " + offer.getTitle();
}
return "Re-launch %s using %s".formatted(program.getName(), offer.getTitle());
return "Re-launch %s using %s".formatted(getProgramName(program), offer.getTitle());
}
}

View File

@ -38,6 +38,7 @@ import ghidra.debug.api.tracermi.TraceRmiLaunchOffer.LaunchConfigurator;
import ghidra.debug.api.tracermi.TraceRmiLaunchOffer.PromptMode;
import ghidra.debug.spi.tracermi.TraceRmiLaunchOpinion;
import ghidra.formats.gfilesystem.FSRL;
import ghidra.framework.model.DomainFile;
import ghidra.framework.options.*;
import ghidra.framework.plugintool.*;
import ghidra.framework.plugintool.util.PluginStatus;
@ -236,10 +237,18 @@ public class TraceRmiLauncherServicePlugin extends Plugin
executeTask(new ConfigureAndLaunchTask(offer));
}
protected static String getProgramName(Program program) {
DomainFile df = program.getDomainFile();
if (df != null) {
return df.getName();
}
return program.getName();
}
protected String[] constructLaunchMenuPrefix() {
return new String[] {
DebuggerPluginPackage.NAME,
"Configure and Launch " + currentProgram.getName() + " using..." };
"Configure and Launch " + getProgramName(currentProgram) + " using..." };
}
protected String[] prependConfigAndLaunch(List<String> menuPath) {

View File

@ -810,6 +810,11 @@ public class TraceRmiHandler implements TraceRmiConnection {
}
DebuggerCoordinates finalCoords = object == null ? coords : coords.object(object);
Swing.runLater(() -> {
DebuggerTraceManagerService traceManager = this.traceManager;
if (traceManager == null) {
// Can happen during tear down.
return;
}
if (!traceManager.getOpenTraces().contains(open.trace)) {
traceManager.openTrace(open.trace);
traceManager.activate(finalCoords, ActivationCause.SYNC_MODEL);

View File

@ -26,7 +26,6 @@ import ghidra.app.plugin.core.debug.utils.MiscellaneousUtils;
import ghidra.app.services.DebuggerStaticMappingService;
import ghidra.app.services.ProgramManager;
import ghidra.framework.cmd.BackgroundCommand;
import ghidra.framework.model.DomainObject;
import ghidra.framework.options.SaveState;
import ghidra.framework.plugintool.AutoConfigState.ConfigFieldCodec;
import ghidra.framework.plugintool.PluginTool;
@ -105,9 +104,9 @@ public interface AutoMapSpec extends ExtensionPoint {
if (mappingService == null || programManager == null) {
return;
}
BackgroundCommand cmd = new BackgroundCommand(getTaskTitle(), true, true, false) {
BackgroundCommand<Trace> cmd = new BackgroundCommand<>(getTaskTitle(), true, true, false) {
@Override
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
public boolean applyTo(Trace trace, TaskMonitor monitor) {
try {
performMapping(mappingService, trace, programManager, monitor);
return true;

View File

@ -799,7 +799,7 @@ public class DebuggerCopyIntoProgramDialog extends ReusableDialogComponentProvid
protected void executeCapture(AddressRange range, Target target, TaskMonitor monitor)
throws Exception {
target.readMemory(new AddressSet(range), monitor);
target.readMemoryAsync(new AddressSet(range), monitor).get();
}
protected void executePlan(TaskMonitor monitor) throws Exception {

View File

@ -64,6 +64,11 @@ public interface DisplaysObjectValues {
.collect(Collectors.joining(":"));
}
default String getStringsDisplay(String[] strings) {
return Stream.of(strings)
.collect(Collectors.joining(":"));
}
default String getPrimitiveValueDisplay(Object value) {
assert !(value instanceof TraceObject);
assert !(value instanceof TraceObjectValue);
@ -89,6 +94,9 @@ public interface DisplaysObjectValues {
if (value instanceof long[] longs) {
return getLongsDisplay(longs);
}
if (value instanceof String[] strings) {
return getStringsDisplay(strings);
}
return value.toString();
}

View File

@ -42,13 +42,13 @@ public class DebuggerModuleMapProposalDialog
implements EnumeratedTableColumn<ModuleMapTableColumns, ModuleMapEntry> {
REMOVE("Remove", String.class, e -> "Remove Proposed Entry", (e, v) -> nop()),
MODULE_NAME("Module", String.class, e -> e.getModule().getName()),
DYNAMIC_BASE("Dynamic Base", Address.class, e -> e.getModule().getBase()),
DYNAMIC_BASE("Dynamic Base", Address.class, e -> e.getFromRange().getMinAddress()),
CHOOSE("Choose", String.class, e -> "Choose Program", (e, v) -> nop()),
PROGRAM_NAME("Program", String.class, e -> (e.getToProgram().getDomainFile() == null
? e.getToProgram().getName()
: e.getToProgram().getDomainFile().getName())),
STATIC_BASE("Static Base", Address.class, e -> e.getToProgram().getImageBase()),
SIZE("Size", Long.class, e -> e.getModuleRange().getLength()),
STATIC_BASE("Static Base", Address.class, e -> e.getToRange().getMinAddress()),
SIZE("Size", Long.class, e -> e.getFromRange().getLength()),
MEMORIZE("Memorize", Boolean.class, ModuleMapEntry::isMemorize, ModuleMapEntry::setMemorize);
private final String header;

View File

@ -32,6 +32,7 @@ import ghidra.framework.plugintool.util.PluginStatus;
packageName = DebuggerPluginPackage.NAME,
status = PluginStatus.RELEASED,
eventsConsumed = {
ProgramOpenedPluginEvent.class,
ProgramActivatedPluginEvent.class,
ProgramLocationPluginEvent.class,
ProgramClosedPluginEvent.class,
@ -65,7 +66,10 @@ public class DebuggerModulesPlugin extends AbstractDebuggerPlugin {
@Override
public void processEvent(PluginEvent event) {
super.processEvent(event);
if (event instanceof ProgramActivatedPluginEvent ev) {
if (event instanceof ProgramOpenedPluginEvent ev) {
provider.programOpened(ev.getProgram());
}
else if (event instanceof ProgramActivatedPluginEvent ev) {
provider.setProgram(ev.getActiveProgram());
}
else if (event instanceof ProgramLocationPluginEvent ev) {

View File

@ -1078,6 +1078,12 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
actionMapSectionTo.getPopupMenuData().setMenuItemName(name);
}
public void programOpened(Program program) {
// TODO: Debounce this?
cueAutoMap = true;
doCuedAutoMap();
}
public void programClosed(Program program) {
if (currentProgram == program) {
currentProgram = null;

View File

@ -614,7 +614,7 @@ public class DebuggerPcodeStepperProvider extends ComponentProviderAdapter {
pcodeTable.setTableHeader(null);
pcodeTable.setBackground(COLOR_BACKGROUND);
pcodeTable.setSelectionBackground(COLOR_BACKGROUND_CURSOR);
pcodeTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
pcodeTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
pcodeTable.getSelectionModel().addListSelectionListener(evt -> {
if (evt.getValueIsAdjusting()) {
return;

View File

@ -106,6 +106,9 @@ public class UniqueRow {
}
public RefType getRefType() {
if (provider.pcodeTable.getSelectedRowCount() != 1) {
return RefType.NONE;
}
int index = provider.pcodeTable.getSelectedRow();
if (index == -1) {
return RefType.NONE;

View File

@ -42,8 +42,8 @@ import ghidra.trace.database.DBTrace;
import ghidra.trace.model.*;
import ghidra.trace.model.memory.*;
import ghidra.trace.model.modules.TraceConflictedMappingException;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.TraceObjectKeyPath;
import ghidra.trace.model.target.*;
import ghidra.trace.model.target.TraceObject.ConflictResolution;
import ghidra.trace.model.thread.*;
import ghidra.trace.model.time.TraceSnapshot;
import ghidra.util.*;
@ -70,7 +70,8 @@ public class ProgramEmulationUtils {
<attribute name='Modules' schema='ModuleContainer' />
<attribute name='Threads' schema='ThreadContainer' />
</schema>
<schema name='BreakpointContainer' elementResync='NEVER' attributeResync='NEVER'>
<schema name='BreakpointContainer' canonical='yes' elementResync='NEVER'
attributeResync='NEVER'>
<interface name='BreakpointSpecContainer' />
<interface name='BreakpointLocationContainer' />
<element schema='Breakpoint' />
@ -494,6 +495,20 @@ public class ProgramEmulationUtils {
throw new EmulatorOutOfMemoryException();
}
protected static void createObjects(Trace trace) {
TraceObjectManager om = trace.getObjectManager();
om.createRootObject(EMU_SESSION_SCHEMA);
om.createObject(TraceObjectKeyPath.parse("Breakpoints"))
.insert(Lifespan.ALL, ConflictResolution.DENY);
om.createObject(TraceObjectKeyPath.parse("Memory"))
.insert(Lifespan.ALL, ConflictResolution.DENY);
om.createObject(TraceObjectKeyPath.parse("Modules"))
.insert(Lifespan.ALL, ConflictResolution.DENY);
om.createObject(TraceObjectKeyPath.parse("Threads"))
.insert(Lifespan.ALL, ConflictResolution.DENY);
}
/**
* Create a new trace with a single thread, ready for emulation of the given program
*
@ -510,7 +525,8 @@ public class ProgramEmulationUtils {
try {
trace = new DBTrace(getTraceName(program), program.getCompilerSpec(), consumer);
try (Transaction tx = trace.openTransaction("Emulate")) {
trace.getObjectManager().createRootObject(EMU_SESSION_SCHEMA);
createObjects(trace);
TraceSnapshot initial =
trace.getTimeManager().createSnapshot(EMULATION_STARTED_AT + pc);
long snap = initial.getKey();

View File

@ -34,7 +34,6 @@ import ghidra.program.util.ProgramLocation;
import ghidra.trace.model.*;
import ghidra.trace.model.modules.*;
import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.thread.TraceThread;
import ghidra.util.ComparatorMath;
import ghidra.util.Msg;
@ -163,11 +162,17 @@ public enum DebuggerStaticMappingUtils {
private Address min = null;
private Address max = null;
public void consider(Address min, Address max) {
this.min = this.min == null ? min : ComparatorMath.cmin(this.min, min);
this.max = this.max == null ? max : ComparatorMath.cmax(this.max, max);
}
public void consider(AddressRange range) {
min = min == null ? range.getMinAddress()
: ComparatorMath.cmin(min, range.getMinAddress());
max = max == null ? range.getMaxAddress()
: ComparatorMath.cmax(max, range.getMaxAddress());
consider(range.getMinAddress(), range.getMaxAddress());
}
public void consider(Address address) {
consider(address, address);
}
public Address getMin() {
@ -181,6 +186,10 @@ public enum DebuggerStaticMappingUtils {
public long getLength() {
return max.subtract(min) + 1;
}
public AddressRange getRange() {
return new AddressRangeImpl(getMin(), getMax());
}
}
public static boolean isReal(MemoryBlock block) {

View File

@ -17,6 +17,7 @@ package ghidra.app.plugin.core.debug.service.modules;
import java.util.*;
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils.Extrema;
import ghidra.app.services.DebuggerStaticMappingService;
import ghidra.debug.api.modules.ModuleMapProposal;
import ghidra.debug.api.modules.ModuleMapProposal.ModuleMapEntry;
@ -27,6 +28,7 @@ import ghidra.trace.model.Lifespan;
import ghidra.trace.model.memory.TraceMemoryRegion;
import ghidra.trace.model.memory.TraceObjectMemoryRegion;
import ghidra.trace.model.modules.TraceModule;
import ghidra.util.MathUtilities;
public class DefaultModuleMapProposal
extends AbstractMapProposal<TraceModule, Program, ModuleMapEntry>
@ -81,20 +83,24 @@ public class DefaultModuleMapProposal
* @param program the program image whose size to compute
* @return the size
*/
public static long computeImageSize(Program program) {
Address imageBase = program.getImageBase();
long imageSize = 0;
public static AddressRange computeImageRange(Program program) {
Extrema extrema = new Extrema();
// TODO: How to handle Harvard architectures?
for (MemoryBlock block : program.getMemory().getBlocks()) {
if (!includeBlock(program, block)) {
continue;
}
imageSize = Math.max(imageSize, block.getEnd().subtract(imageBase) + 1);
// includeBlock checks address space is same as image base
extrema.consider(block.getAddressRange());
}
return imageSize;
if (program.getImageBase().getOffset() != 0) {
extrema.consider(program.getImageBase());
}
return extrema.getRange();
}
protected AddressRange moduleRange;
protected AddressRange imageRange;
protected boolean memorize = false;
/**
@ -113,6 +119,7 @@ public class DefaultModuleMapProposal
AddressRange moduleRange) {
super(module.getTrace(), module, program, program);
this.moduleRange = moduleRange;
this.imageRange = quantize(computeImageRange(program));
}
@Override
@ -125,9 +132,18 @@ public class DefaultModuleMapProposal
return getModule().getLifespan();
}
private long getLength() {
return MathUtilities.unsignedMin(moduleRange.getLength(), imageRange.getLength());
}
@Override
public AddressRange getFromRange() {
return moduleRange;
try {
return new AddressRangeImpl(moduleRange.getMinAddress(), getLength());
}
catch (AddressOverflowException e) {
throw new AssertionError(e);
}
}
@Override
@ -138,21 +154,13 @@ public class DefaultModuleMapProposal
@Override
public void setProgram(Program program) {
setToObject(program, program);
try {
this.moduleRange = quantize(
new AddressRangeImpl(getModule().getBase(), computeImageSize(program)));
}
catch (AddressOverflowException e) {
// This is terribly unlikely
throw new IllegalArgumentException(
"Specified program is too large for module's memory space");
}
this.imageRange = quantize(computeImageRange(program));
}
@Override
public AddressRange getToRange() {
try {
return new AddressRangeImpl(getToProgram().getImageBase(), moduleRange.getLength());
return new AddressRangeImpl(imageRange.getMinAddress(), getLength());
}
catch (AddressOverflowException e) {
throw new AssertionError(e);
@ -174,10 +182,8 @@ public class DefaultModuleMapProposal
// indexed by region's offset from module base
protected final NavigableMap<Long, ModuleRegionMatcher> matchers = new TreeMap<>();
protected Address imageBase;
protected Address moduleBase;
protected long imageSize;
protected AddressRange moduleRange; // TODO: This is now in the trace schema. Use it.
protected AddressRange imageRange;
protected AddressRange moduleRange;
protected DefaultModuleMapProposal(TraceModule module, Program program) {
super(module.getTrace(), program);
@ -196,8 +202,8 @@ public class DefaultModuleMapProposal
}
private void processProgram() {
imageBase = program.getImageBase();
imageSize = DefaultModuleMapEntry.computeImageSize(program);
imageRange = quantize(DefaultModuleMapEntry.computeImageRange(program));
Address imageBase = imageRange.getMinAddress(); // not precisely, but good enough
// TODO: How to handle Harvard architectures?
for (MemoryBlock block : program.getMemory().getBlocks()) {
if (!DefaultModuleMapEntry.includeBlock(program, block)) {
@ -211,13 +217,8 @@ public class DefaultModuleMapProposal
* Must be called after processProgram, so that image size is known
*/
private void processModule() {
moduleBase = module.getBase();
try {
moduleRange = quantize(new AddressRangeImpl(moduleBase, imageSize));
}
catch (AddressOverflowException e) {
return; // Just score it as having no matches?
}
moduleRange = quantize(module.getRange());
Address moduleBase = moduleRange.getMinAddress();
Lifespan lifespan = module.getLifespan();
for (TraceMemoryRegion region : module.getTrace()
.getMemoryManager()

View File

@ -499,6 +499,21 @@ public enum PathUtils {
return Objects.equals(ancestor, successor.subList(0, ancestor.size()));
}
/**
* Assuming the first path is an ancestor of the second, compute the relative path from the
* first to the second.
*
* @param ancestor the ancestor (from)
* @param successor the successor (to)
* @return the relative path
*/
public static List<String> relativize(List<String> ancestor, List<String> successor) {
if (!isAncestor(ancestor, successor)) {
throw new IllegalArgumentException("First must be an ancestor of the second");
}
return successor.subList(ancestor.size(), successor.size());
}
/**
* Check whether a given object-valued attribute is a link.
*
@ -538,6 +553,7 @@ public enum PathUtils {
* Check whether a given attribute should be displayed.
*
* @param key the key of the given attribute
* @return true if hidden
*/
public static boolean isHidden(String key) {
return key.startsWith(TargetObject.PREFIX_INVISIBLE);

View File

@ -121,8 +121,19 @@ public class DBTraceObjectBreakpointLocation
@Override
public String getName() {
try (LockHold hold = object.getTrace().lockRead()) {
return TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(),
TargetObject.DISPLAY_ATTRIBUTE_NAME, String.class, "");
String display = TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(),
TargetObject.DISPLAY_ATTRIBUTE_NAME, String.class, null);
if (display != null) {
return display;
}
TraceObject container =
object.queryCanonicalAncestorsTargetInterface(TargetBreakpointSpecContainer.class)
.findFirst()
.orElse(null);
if (container == null) {
return ""; // Should be impossible, but maybe not a sane schema
}
return container.getCanonicalPath().relativize(object.getCanonicalPath()).toString();
}
}
@ -312,8 +323,16 @@ public class DBTraceObjectBreakpointLocation
@Override
public String getComment() {
try (LockHold hold = object.getTrace().lockRead()) {
return TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(), KEY_COMMENT,
String.class, "");
String comment = TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(),
KEY_COMMENT, String.class, "");
if (!comment.isBlank()) {
return comment;
}
TraceObjectBreakpointSpec spec = getSpecification();
if (spec == null) {
return "";
}
return spec.getExpression();
}
}

View File

@ -181,6 +181,12 @@ public class DBTraceObjectBreakpointSpec
}
}
@Override
public String getExpression() {
return TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(),
TargetBreakpointSpec.EXPRESSION_ATTRIBUTE_NAME, String.class, null);
}
@Override
public Set<TraceThread> getThreads() {
throw new UnsupportedOperationException("Ask a location instead");

View File

@ -18,7 +18,12 @@ package ghidra.trace.database.time;
import java.io.IOException;
import db.DBRecord;
import ghidra.dbg.target.TargetEventScope;
import ghidra.trace.database.target.DBTraceObject;
import ghidra.trace.model.Trace;
import ghidra.trace.model.target.TraceObject;
import ghidra.trace.model.target.TraceObjectValue;
import ghidra.trace.model.thread.TraceObjectThread;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.model.time.TraceSnapshot;
import ghidra.trace.model.time.schedule.TraceSchedule;
@ -143,7 +148,26 @@ public class DBTraceSnapshot extends DBAnnotatedObject implements TraceSnapshot
@Override
public TraceThread getEventThread() {
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
return eventThread;
if (eventThread != null) {
return eventThread;
}
// TODO: Can it be something other than root?
DBTraceObject root = manager.trace.getObjectManager().getRootObject();
if (root == null) {
return null;
}
if (!root.getTargetSchema().getInterfaces().contains(TargetEventScope.class)) {
return null;
}
TraceObjectValue eventAttr =
root.getAttribute(getKey(), TargetEventScope.EVENT_OBJECT_ATTRIBUTE_NAME);
if (eventAttr == null) {
return null;
}
if (!(eventAttr.getValue() instanceof TraceObject eventObj)) {
return null;
}
return eventObj.queryInterface(TraceObjectThread.class);
}
}

View File

@ -43,5 +43,7 @@ public interface TraceObjectBreakpointSpec extends TraceBreakpoint, TraceObjectI
Collection<? extends TraceObjectBreakpointLocation> getLocations();
String getExpression();
void setKinds(Lifespan lifespan, Collection<TraceBreakpointKind> kinds);
}

View File

@ -224,8 +224,8 @@ public final class TraceObjectKeyPath implements Comparable<TraceObjectKeyPath>
/**
* Stream, starting with the longer paths, paths that match the given predicates
*
* @param matcher
* @return
* @param predicates the predicates to filter the ancestor paths
* @return the stream of matching paths, longest to shortest
*/
public Stream<TraceObjectKeyPath> streamMatchingAncestry(PathPredicates predicates) {
if (!predicates.ancestorMatches(keyList, false)) {
@ -253,4 +253,15 @@ public final class TraceObjectKeyPath implements Comparable<TraceObjectKeyPath>
public boolean isAncestor(TraceObjectKeyPath that) {
return PathUtils.isAncestor(keyList, that.keyList);
}
/**
* Assuming this is an ancestor of the given successor, compute the relative path from here to
* there
*
* @param successor the successor
* @return the relative path
*/
public TraceObjectKeyPath relativize(TraceObjectKeyPath successor) {
return TraceObjectKeyPath.of(PathUtils.relativize(keyList, successor.keyList));
}
}

View File

@ -20,6 +20,7 @@ import static org.junit.Assert.assertTrue;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.util.*;
@ -50,23 +51,24 @@ import ghidra.app.plugin.core.debug.gui.memory.DebuggerMemoryBytesProvider;
import ghidra.app.plugin.core.debug.gui.memory.DebuggerRegionsProvider;
import ghidra.app.plugin.core.debug.gui.modules.DebuggerModulesProvider;
import ghidra.app.plugin.core.debug.gui.modules.DebuggerStaticMappingProvider;
import ghidra.app.plugin.core.debug.gui.objects.components.DebuggerMethodInvocationDialog;
import ghidra.app.plugin.core.debug.gui.pcode.DebuggerPcodeStepperPlugin;
import ghidra.app.plugin.core.debug.gui.pcode.DebuggerPcodeStepperProvider;
import ghidra.app.plugin.core.debug.gui.register.DebuggerRegistersProvider;
import ghidra.app.plugin.core.debug.gui.stack.DebuggerStackProvider;
import ghidra.app.plugin.core.debug.gui.stack.vars.VariableValueHoverPlugin;
import ghidra.app.plugin.core.debug.gui.target.DebuggerTargetsPlugin;
import ghidra.app.plugin.core.debug.gui.thread.DebuggerThreadsProvider;
import ghidra.app.plugin.core.debug.gui.time.DebuggerTimeProvider;
import ghidra.app.plugin.core.debug.gui.time.DebuggerTimeSelectionDialog;
import ghidra.app.plugin.core.debug.gui.tracermi.connection.TraceRmiConnectionManagerPlugin;
import ghidra.app.plugin.core.debug.gui.watch.DebuggerWatchesProvider;
import ghidra.app.plugin.core.debug.service.emulation.DebuggerEmulationServicePlugin;
import ghidra.app.plugin.core.debug.service.emulation.DebuggerEmulationServicePlugin.EmulateProgramAction;
import ghidra.app.plugin.core.debug.service.model.DebuggerConnectDialog;
import ghidra.app.plugin.core.debug.stack.StackUnwinderTest;
import ghidra.app.plugin.core.debug.stack.StackUnwinderTest.HoverLocation;
import ghidra.app.plugin.core.debug.stack.UnwindStackCommand;
import ghidra.app.plugin.core.decompile.DecompilerProvider;
import ghidra.app.plugin.core.terminal.TerminalProvider;
import ghidra.app.script.GhidraState;
import ghidra.app.services.*;
import ghidra.app.services.DebuggerEmulationService.EmulationResult;
@ -74,19 +76,17 @@ import ghidra.app.util.importer.AutoImporter;
import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.LoadResults;
import ghidra.async.AsyncTestUtils;
import ghidra.dbg.DebuggerModelFactory;
import ghidra.dbg.target.TargetLauncher;
import ghidra.dbg.target.TargetLauncher.TargetCmdLineLauncher;
import ghidra.dbg.testutil.DummyProc;
import ghidra.dbg.util.ConfigurableFactory.Property;
import ghidra.debug.api.model.DebuggerProgramLaunchOffer;
import ghidra.debug.api.model.DebuggerProgramLaunchOffer.*;
import ghidra.debug.api.modules.ModuleMapProposal;
import ghidra.debug.api.tracermi.RemoteMethod;
import ghidra.debug.api.tracermi.TraceRmiLaunchOffer;
import ghidra.debug.api.tracermi.TraceRmiLaunchOffer.*;
import ghidra.debug.api.watch.WatchRow;
import ghidra.debug.flatapi.FlatDebuggerAPI;
import ghidra.debug.flatapi.FlatDebuggerRmiAPI;
import ghidra.framework.Application;
import ghidra.framework.TestApplicationUtils;
import ghidra.framework.model.DomainFolder;
import ghidra.framework.model.DomainObject;
import ghidra.framework.plugintool.PluginTool;
import ghidra.framework.plugintool.util.PluginUtils;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSet;
@ -96,11 +96,11 @@ import ghidra.program.model.symbol.Reference;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.util.GhidraProgramUtilities;
import ghidra.program.util.ProgramSelection;
import ghidra.pty.*;
import ghidra.test.TestEnv;
import ghidra.trace.model.breakpoint.TraceBreakpoint;
import ghidra.trace.model.breakpoint.*;
import ghidra.trace.model.guest.TracePlatform;
import ghidra.trace.model.modules.TraceModule;
import ghidra.trace.model.modules.TraceSection;
import ghidra.trace.model.modules.*;
import ghidra.trace.model.program.TraceProgramView;
import ghidra.trace.model.time.schedule.*;
import ghidra.util.InvalidNameException;
@ -117,26 +117,36 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
protected static final String TERMMINES_PATH = "/tmp/termmines";
static class MyTestEnv extends TestEnv {
public MyTestEnv(String projectName) throws IOException {
super(projectName);
}
@Override
protected PluginTool launchDefaultToolByName(String toolName) {
return super.launchDefaultToolByName(toolName);
}
}
protected final ConsoleTaskMonitor monitor = new ConsoleTaskMonitor();
protected TerminalService terminalService;
protected ProgramManager programManager;
protected CodeViewerService staticListingService;
protected DebuggerModelService modelService;
protected MyTestEnv env;
protected DebuggerModelFactory gdbFactory;
protected final FlatDebuggerAPI flatDbg = new FlatDebuggerAPI() {
protected final FlatDebuggerRmiAPI flatDbg = new FlatDebuggerRmiAPI() {
@Override
public GhidraState getState() {
Navigatable nav = staticListingService.getNavigatable();
return new GhidraState(tool, env.getProject(),
nav.getProgram(), nav.getLocation(), nav.getSelection(), nav.getHighlight());
return new GhidraState(tool, env.getProject(), nav.getProgram(), nav.getLocation(),
nav.getSelection(), nav.getHighlight());
}
};
@Override
protected TestEnv newTestEnv() throws Exception {
return new TestEnv("DebuggerCourse");
return env = new MyTestEnv("DebuggerCourse");
}
// TODO: Propose this replace waitForProgram
@ -167,7 +177,7 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
@Override
public void prepareTool() {
tool = env.launchTool("Debugger");
tool = env.launchDefaultToolByName("Debugger");
}
@Override
@ -214,20 +224,23 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
}
termmines.setExecutable(true);
terminalService = tool.getService(TerminalService.class);
programManager = tool.getService(ProgramManager.class);
staticListingService = getStaticListingService();
}
modelService = tool.getService(DebuggerModelService.class);
gdbFactory = modelService.getModelFactories()
.stream()
.filter(f -> "gdb".equals(f.getBrief()))
.findAny()
.get();
@Test
public void testGettingStarted_Termmines() throws Throwable {
Pty pty = PtyFactory.local().openpty();
pty.getChild().session(new String[] { TERMMINES_PATH }, Map.of("TERM", "xterm-256color"));
PtyParent parent = pty.getParent();
try (Terminal terminal =
terminalService.createWithStreams(Charset.forName("utf8"), parent.getInputStream(),
parent.getOutputStream())) {
@SuppressWarnings("unchecked")
Property<String> gdbPathProp =
(Property<String>) gdbFactory.getOptions().get("GDB launch command");
gdbPathProp.setValue(DummyProc.which("gdb"));
TerminalProvider provider = waitForComponentProvider(TerminalProvider.class);
captureIsolatedProvider(provider, 600, 600);
}
}
@Test
@ -235,32 +248,46 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
captureToolWindow(1920, 1080);
}
protected void launchProgramInGdb(String extraArgs) throws Throwable {
DebuggerProgramLaunchOffer offer = modelService.getProgramLaunchOffers(program)
.filter(o -> "IN-VM GDB".equals(o.getConfigName()))
.findFirst()
.get();
LaunchConfigurator config = new LaunchConfigurator() {
protected void captureLaunchDialog(String title) {
TraceRmiLaunchOffer offer = flatDbg.getLaunchOffers(program)
.stream()
.filter(o -> title.equals(o.getTitle()))
.findAny()
.orElseThrow();
runSwingLater(() -> offer.launchProgram(monitor, new LaunchConfigurator() {
@Override
public Map<String, ?> configureLauncher(TargetLauncher launcher,
Map<String, ?> arguments, RelPrompt relPrompt) {
if (extraArgs.length() == 0) {
return arguments;
}
Map<String, Object> adjusted = new HashMap<>(arguments);
TargetCmdLineLauncher.PARAMETER_CMDLINE_ARGS.adjust(adjusted,
c -> c + " " + extraArgs);
return adjusted;
public PromptMode getPromptMode() {
return PromptMode.ALWAYS;
}
};
LaunchResult result = waitOn(offer.launchProgram(monitor, PromptMode.NEVER, config));
}));
captureDialog(DebuggerMethodInvocationDialog.class);
}
@Test
public void testGettingStarted_LaunchGDBDialog() {
captureLaunchDialog("gdb");
}
protected LaunchResult launchProgramInGdb(String extraArgs) throws Throwable {
TraceRmiLaunchOffer offer = flatDbg.getLaunchOffers(program)
.stream()
.filter(o -> "gdb".equals(o.getTitle()))
.findAny()
.orElseThrow();
LaunchResult result = flatDbg.launch(offer, Map.ofEntries(
Map.entry("env:OPT_START_CMD", "start"),
Map.entry("args", extraArgs)),
monitor);
if (result.exception() != null) {
throw result.exception();
}
return result;
}
protected void launchProgramInGdb() throws Throwable {
launchProgramInGdb("");
protected LaunchResult launchProgramInGdb() throws Throwable {
return launchProgramInGdb("");
}
@Test
@ -278,15 +305,33 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
captureProvider(DebuggerBreakpointsProvider.class);
}
protected void placeBreakpointsSRandRand() throws Throwable {
protected void waitBreakSpecExists(String expression) {
waitForCondition(() -> flatDbg.getAllBreakpoints()
.stream()
.flatMap(lb -> lb.getTraceBreakpoints().stream())
.<TraceObjectBreakpointSpec> mapMulti((loc, down) -> {
if (loc instanceof TraceObjectBreakpointLocation oloc) {
down.accept(oloc.getSpecification());
}
})
.distinct()
.filter(l -> expression.equals(l.getExpression()))
.count() == 1);
}
protected void placeBreakpointsSRand() throws Throwable {
assertTrue(flatDbg.execute("break srand"));
assertTrue(flatDbg.execute("break rand"));
waitForCondition(() -> flatDbg.getAllBreakpoints().size() == 2);
waitBreakSpecExists("srand");
}
protected void placeBreakpointsRand() throws Throwable {
assertTrue(flatDbg.execute("break rand"));
waitForCondition(() -> flatDbg.getAllBreakpoints().size() == 1);
waitBreakSpecExists("rand");
}
protected void placeBreakpointsSRandRand() throws Throwable {
placeBreakpointsSRand();
placeBreakpointsRand();
}
@Test
@ -298,11 +343,16 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
captureProvider(DebuggerBreakpointsProvider.class);
}
protected Address navigateToBreakpoint(String comment) {
protected Address navigateToBreakpoint(String expression) {
TraceBreakpoint bp = flatDbg.getAllBreakpoints()
.stream()
.flatMap(l -> l.getTraceBreakpoints().stream())
.filter(l -> comment.equals(l.getComment()))
.<TraceObjectBreakpointLocation> mapMulti((loc, down) -> {
if (loc instanceof TraceObjectBreakpointLocation oloc) {
down.accept(oloc);
}
})
.filter(l -> expression.equals(l.getSpecification().getExpression()))
.findAny()
.get();
Address dynAddr = bp.getMinAddress();
@ -367,6 +417,14 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
Address dynAddr = navigateToBreakpoint("srand");
TraceModule modLibC = getModuleContaining(dynAddr);
Program progLibC = importModule(modLibC);
// This module might be symlinked, so module name and file name may not match.
DebuggerStaticMappingService mappings = tool.getService(DebuggerStaticMappingService.class);
ModuleMapProposal proposal = mappings.proposeModuleMap(modLibC, progLibC);
try (Transaction tx = modLibC.getTrace().openTransaction("Map")) {
mappings.addModuleMappings(proposal.computeMap().values(), monitor, true);
}
waitForCondition(() -> flatDbg.translateDynamicToStatic(dynAddr) != null);
disassembleSymbol(progLibC, "srand");
// Just to be sure.
@ -385,9 +443,16 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
Address dynAddr = navigateToBreakpoint("srand");
TraceModule modLibC = getModuleContaining(dynAddr);
Program progLibC = importModule(modLibC);
waitForCondition(() -> flatDbg.translateDynamicToStatic(dynAddr) != null);
// This module might be symlinked, so module name and file name may not match.
DebuggerStaticMappingService mappings = tool.getService(DebuggerStaticMappingService.class);
ModuleMapProposal proposal = mappings.proposeModuleMap(modLibC, progLibC);
try (Transaction tx = modLibC.getTrace().openTransaction("Map")) {
mappings.addModuleMappings(proposal.computeMap().values(), monitor, true);
}
Address stAddr = waitForValue(() -> flatDbg.translateDynamicToStatic(dynAddr));
disassembleSymbol(progLibC, "srand");
Address stAddr = flatDbg.translateDynamicToStatic(dynAddr);
// Just to be sure.
goTo(tool, progLibC, stAddr);
flatDbg.resume();
@ -488,6 +553,18 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
public void testNavigation_ThreadsInCallRand() throws Throwable {
launchProgramInGdb();
placeBreakpointsRand();
Address dynAddr = navigateToBreakpoint("rand");
TraceModule modLibC = getModuleContaining(dynAddr);
Program progLibC = importModule(modLibC);
// This module might be symlinked, so module name and file name may not match.
DebuggerStaticMappingService mappings = tool.getService(DebuggerStaticMappingService.class);
ModuleMapProposal proposal = mappings.proposeModuleMap(modLibC, progLibC);
try (Transaction tx = modLibC.getTrace().openTransaction("Map")) {
mappings.addModuleMappings(proposal.computeMap().values(), monitor, true);
}
waitForCondition(() -> flatDbg.translateDynamicToStatic(dynAddr) != null);
flatDbg.resume();
runSwing(() -> tool.setSize(1920, 1080));
@ -500,7 +577,15 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
placeBreakpointsRand();
Address dynAddr = navigateToBreakpoint("rand");
TraceModule modLibC = getModuleContaining(dynAddr);
importModule(modLibC);
Program progLibC = importModule(modLibC);
// This module might be symlinked, so module name and file name may not match.
DebuggerStaticMappingService mappings = tool.getService(DebuggerStaticMappingService.class);
ModuleMapProposal proposal = mappings.proposeModuleMap(modLibC, progLibC);
try (Transaction tx = modLibC.getTrace().openTransaction("Map")) {
mappings.addModuleMappings(proposal.computeMap().values(), monitor, true);
}
waitForCondition(() -> flatDbg.translateDynamicToStatic(dynAddr) != null);
flatDbg.resume();
@ -513,8 +598,11 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
launchProgramInGdb();
placeBreakpointsSRandRand();
flatDbg.resume(); // srand
Thread.sleep(500);
flatDbg.resume(); // rand.1
Thread.sleep(500);
flatDbg.stepOut();
Thread.sleep(500);
runSwing(() -> tool.setSize(1920, 1080));
captureProvider(DebuggerTimeProvider.class);
@ -522,18 +610,29 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
@Test
public void testNavigation_DialogCompareTimes() throws Throwable {
launchProgramInGdb(); // main
LaunchResult result = launchProgramInGdb(); // main
placeBreakpointsRand();
Address pc = flatDbg.getProgramCounter();
long snapA = flatDbg.getCurrentSnap();
TraceModule modTermmines = Unique.assertOne(flatDbg.getCurrentTrace()
.getModuleManager()
.getModulesAt(snapA, pc));
try (Transaction tx = result.trace().openTransaction("Name snapshot")) {
result.trace()
.getTimeManager()
.getSnapshot(snapA, false)
.setDescription("Initial snapshot");
}
TraceObjectModule modTermmines =
(TraceObjectModule) Unique.assertOne(flatDbg.getCurrentTrace()
.getModuleManager()
.getModulesAt(snapA, pc));
RemoteMethod refreshSections = result.connection().getMethods().get("refresh_sections");
refreshSections.invoke(Map.of("node", modTermmines.getObject()));
TraceSection secTermminesData = modTermmines.getSectionByName(".data");
flatDbg.readMemory(secTermminesData.getStart(),
(int) secTermminesData.getRange().getLength(), monitor);
flatDbg.resume(); // rand.1
Thread.sleep(500);
flatDbg.readMemory(secTermminesData.getStart(),
(int) secTermminesData.getRange().getLength(), monitor);
@ -547,13 +646,23 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
@Test
public void testNavigation_CompareTimes() throws Throwable {
launchProgramInGdb("-M 15"); // main
LaunchResult result = launchProgramInGdb("-M 15"); // main
placeBreakpointsRand();
Address pc = flatDbg.getProgramCounter();
long snapA = flatDbg.getCurrentSnap();
TraceModule modTermmines = Unique.assertOne(flatDbg.getCurrentTrace()
.getModuleManager()
.getModulesAt(snapA, pc));
try (Transaction tx = result.trace().openTransaction("Name snapshot")) {
result.trace()
.getTimeManager()
.getSnapshot(snapA, false)
.setDescription("Initial snapshot");
}
TraceObjectModule modTermmines =
(TraceObjectModule) Unique.assertOne(flatDbg.getCurrentTrace()
.getModuleManager()
.getModulesAt(snapA, pc));
RemoteMethod refreshSections = result.connection().getMethods().get("refresh_sections");
refreshSections.invoke(Map.of("node", modTermmines.getObject()));
TraceSection secTermminesData = modTermmines.getSectionByName(".data");
flatDbg.readMemory(secTermminesData.getStart(),
(int) secTermminesData.getRange().getLength(), monitor);
@ -582,6 +691,10 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
});
waitForCondition(() -> actionNextDiff.isEnabled());
flatDbg.goToDynamic(secTermminesData.getStart());
// Because auto-strack is a little broken right now
Thread.sleep(500);
flatDbg.goToDynamic(secTermminesData.getStart());
performAction(actionNextDiff);
runSwing(() -> tool.setSize(1920, 1080));
@ -611,7 +724,15 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
showProvider(DebuggerStaticMappingProvider.class);
Address dynAddr = navigateToBreakpoint("srand");
TraceModule modLibC = getModuleContaining(dynAddr);
importModule(modLibC);
Program progLibC = importModule(modLibC);
// This module might be symlinked, so module name and file name may not match.
DebuggerStaticMappingService mappings = tool.getService(DebuggerStaticMappingService.class);
ModuleMapProposal proposal = mappings.proposeModuleMap(modLibC, progLibC);
try (Transaction tx = modLibC.getTrace().openTransaction("Map")) {
mappings.addModuleMappings(proposal.computeMap().values(), monitor, true);
}
waitForCondition(() -> flatDbg.translateDynamicToStatic(dynAddr) != null);
runSwing(() -> tool.setSize(1920, 1080));
@ -631,29 +752,30 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
DebuggerListingService listings = tool.getService(DebuggerListingService.class);
runSwing(() -> listings
.setCurrentSelection(new ProgramSelection(new AddressSet(modNcurses.getRange()))));
DebuggerListingProvider listingProvider =
waitForComponentProvider(DebuggerListingProvider.class);
performAction("Copy Into New Program",
PluginUtils.getPluginNameFromClass(DebuggerCopyActionsPlugin.class), false);
PluginUtils.getPluginNameFromClass(DebuggerCopyActionsPlugin.class), listingProvider,
false);
captureDialog(DebuggerCopyIntoProgramDialog.class);
}
@Test
public void testRemoteTargets_GdbOverSsh() throws Throwable {
performAction("Connect", PluginUtils.getPluginNameFromClass(DebuggerTargetsPlugin.class),
false);
DebuggerConnectDialog dialog = waitForDialogComponent(DebuggerConnectDialog.class);
runSwing(() -> dialog.setFactoryByBrief("gdb via SSH"));
captureDialog(dialog);
public void testRemoteTargets_GdbPlusGdbserverViaSsh() throws Throwable {
captureLaunchDialog("gdb + gdbserver via ssh");
}
@Test
public void testRemoteTargets_Gadp() throws Throwable {
performAction("Connect", PluginUtils.getPluginNameFromClass(DebuggerTargetsPlugin.class),
false);
DebuggerConnectDialog dialog = waitForDialogComponent(DebuggerConnectDialog.class);
runSwing(() -> dialog.setFactoryByBrief("Ghidra debug agent (GADP)"));
public void testRemoteTargets_GdbViaSsh() throws Throwable {
captureLaunchDialog("gdb via ssh");
}
captureDialog(dialog);
@Test
public void testRemoteTargets_AcceptTraceRmi() throws Throwable {
performAction("Connect by Accept",
PluginUtils.getPluginNameFromClass(TraceRmiConnectionManagerPlugin.class),
false);
captureDialog(DebuggerMethodInvocationDialog.class);
}
protected Function findCommandLineParser() throws Throwable {

View File

@ -128,16 +128,14 @@ icon in my Tool Chest</a></li>
<li><a href="#there-is-no-debug-launch-icon-in-the-global-toolbar"
id="toc-there-is-no-debug-launch-icon-in-the-global-toolbar">There is no
Debug / Launch icon in the global toolbar</a></li>
<li><a href="#there-is-no-gdb-option-in-the-launch-drop-down"
id="toc-there-is-no-gdb-option-in-the-launch-drop-down">There is no
<strong>gdb</strong> option in the launch drop-down</a></li>
<li><a
href="#there-is-no-debug-termmines-in-gdb-locally-in-vm-option-in-the-launch-drop-down"
id="toc-there-is-no-debug-termmines-in-gdb-locally-in-vm-option-in-the-launch-drop-down">There
is no “Debug termmines in GDB locally IN-VM” option in the launch
drop-down</a></li>
<li><a
href="#the-launch-hangs-for-several-seconds-and-then-prompt-for-a-recorder"
id="toc-the-launch-hangs-for-several-seconds-and-then-prompt-for-a-recorder">The
launch hangs for several seconds and then prompt for a
“recorder”</a></li>
href="#the-launch-hangs-for-several-seconds-and-then-i-get-prompted-with-a-wall-of-text"
id="toc-the-launch-hangs-for-several-seconds-and-then-i-get-prompted-with-a-wall-of-text">The
launch hangs for several seconds and then I get prompted with a wall of
text</a></li>
<li><a href="#the-dynamic-listing-is-empty"
id="toc-the-dynamic-listing-is-empty">The Dynamic Listing is
empty</a></li>
@ -192,8 +190,16 @@ trust. For <code>termmines</code>, the risk is negligible. Run it:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="ex">./termmines</span></span></code></pre></div>
<p>You should see a 9x9 grid and a cursor you can move with the arrow
keys. Hit <strong>Ctrl-C</strong> to exit. Probe it for help. Most Linux
programs accept a <code>-h</code> argument for help:</p>
keys.</p>
<figure>
<img src="images/GettingStarted_Termmines.png"
alt="Termmines running in a Terminal" />
<figcaption aria-hidden="true">Termmines running in a
Terminal</figcaption>
</figure>
<p>Hit <strong><code>CTRL</code>-<code>C</code></strong> to exit. Probe
it for help. Most Linux programs accept a <code>-h</code> argument for
help:</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ex">./termmines</span> <span class="at">-h</span></span></code></pre></div>
<p>You should now have all the information you need to understand how
@ -223,7 +229,18 @@ open</figcaption>
</figure></li>
<li><p>In the Debugger tool, click the dropdown ▾ for the debug <img
src="images/debugger.png" alt="debug button" /> icon in the global tool
bar, and select “Debug termmines in GDB locally IN-VM.”</p></li>
bar, and select <strong>Configure and Launch termmines using… →
gdb</strong>.</p>
<figure>
<img src="images/GettingStarted_LaunchGDBDialog.png"
alt="Launch GDB Dialog" />
<figcaption aria-hidden="true">Launch GDB Dialog</figcaption>
</figure></li>
<li><p>Change the <strong>Run Command</strong> to “start” (not
“starti”). <strong>NOTE</strong>: In practice, this is rarely
recommended, because most targets do not export their <code>main</code>
function.</p></li>
<li><p>Click the <strong>Launch</strong> button in the dialog.</p></li>
<li><p>Wait a bit then verify the Dynamic Listing window (top) is
displaying disassembly code.</p>
<figure>
@ -236,20 +253,18 @@ termmines</figcaption>
</section>
<section id="launching-on-windows" class="level2">
<h2>Launching on Windows</h2>
<p>On Windows, we will use dbgeng to debug the specimen. This is the
engine that backs WinDbg. You may choose an alternative Minesweeper,
since terminal applications are less representative of Windows
executables. Follow the same process as for Linux, except import
<code>termmines.exe</code> and select “Debug termmines.exe in dbgeng
locally IN-VM.”</p>
<p>On Windows, we will use the Windows Debugger dbgeng.dll to debug the
specimen. This is the engine that backs WinDbg. You may choose an
alternative Minesweeper, since terminal applications are less
representative of Windows executables. Follow the same process as for
Linux, except import <code>termmines.exe</code> and select
<strong>Configure and Launch termmines.exe using… → dbgeng</strong>.</p>
</section>
<section id="launching-on-macos" class="level2">
<h2>Launching on macOS</h2>
<p>Unfortunately, things are not so simple on macOS. See the
instructions for <a
href="../../../Ghidra/Debug/Debugger-swig-lldb/InstructionsForBuildingLLDBInterface.txt">Building
LLDB-Java Bindings</a>. Once built, follow the same process as for
Linux, except select “Debug termmines in LLDB locally IN-VM.”</p>
<p>On macOS, we will use LLDB to debug the specimen. This is the
debugger included with Xcode. Follow the same process as for Linux,
except choose <strong>lldb</strong> in the last menu.</p>
</section>
<section id="troubleshooting" class="level2">
<h2>Troubleshooting</h2>
@ -280,73 +295,71 @@ tool. If it is still not there, then you may need to re-import the
default Debugger tool as under the previous heading. If it is still not
there, your installation may be corrupt.</p>
</section>
<section
id="there-is-no-debug-termmines-in-gdb-locally-in-vm-option-in-the-launch-drop-down"
<section id="there-is-no-gdb-option-in-the-launch-drop-down"
class="level3">
<h3>There is no “Debug termmines in GDB locally IN-VM” option in the
launch drop-down</h3>
<p>You may need to install GDB and/or configure Ghidra with its
location. If you have a copy or custom build of GDB in a non-system
path, note its full path. If you intend to use the systems copy of GDB,
then in a terminal:</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="fu">which</span> gdb</span></code></pre></div>
<p>Note the path given. (If you get an error, then you need to install
GDB.) In a terminal, type the full path of GDB to ensure it executes
properly. Type <code>q</code> to quit GDB.</p>
<ol type="1">
<li>From the Debugger Targets window, click the Connect <img
src="images/connect.png" alt="connect button" /> button.</li>
<li>In the Connect dialog, select “gdb” from the dropdown at the
top.</li>
<li>Enter the full path, e.g., <code>/usr/bin/gdb</code>, in the “GDB
launch command” field.</li>
<li>Click “Connect”</li>
<li>If you get an Interpreter window, then things have gone well.</li>
<li>Type <code>echo test</code> into it to verify its responsive, then
type <code>q</code> to disconnect.</li>
<li>Close the Debugger tool, then retry.</li>
</ol>
<h3>There is no <strong>gdb</strong> option in the launch drop-down</h3>
<p>You may have an older Debugger tool still configured for
Recorder-based targets. We are transitioning to TraceRmi-based targets.
Delete your Debugger tool and re-import the default one using the
instructions above. If it is still not there, its possible your
installation is corrupt. Search for a file called
<code>local-gdb.sh</code> in your installation. Unlike the previous
system, Trace RMI will not probe your system for dependencies nor hide
incompatible launchers. All installed launchers should be present in the
menus, even though some may not work on your configuration.</p>
</section>
<section
id="the-launch-hangs-for-several-seconds-and-then-prompt-for-a-recorder"
id="the-launch-hangs-for-several-seconds-and-then-i-get-prompted-with-a-wall-of-text"
class="level3">
<h3>The launch hangs for several seconds and then prompt for a
“recorder”</h3>
<p>You probably have a stale GDB connection, so when you launched you
now have multiple connections. For the prompt, select the option with
the highest score. Examine the Targets window to confirm you have
multiple GDB connections. If you know which is the stale connection, you
can right-click it and choose <strong>Disconnect</strong>. Otherwise,
use <strong>Disconnect All</strong> from the drop-down menu and
re-launch.</p>
<h3>The launch hangs for several seconds and then I get prompted with a
wall of text</h3>
<p>Read the wall of text. The first line should tell you the exception
that it encountered. Often this is a timeout. Press the
<strong>Keep</strong> button and then find the Terminal, usually in the
bottom right. If you do not see it there, check the <strong>Window →
Terminals</strong> menu. Once you have found the Terminal, check its
output <em>starting at the top</em> for diagnostic messages. If you have
something like <code>bash: gdb: command not found</code>, it is because
you are missing <code>gdb</code>, or you need to tell Ghidra where to
find it.</p>
<p>If it is just missing, then install it and try again. If you need to
tell Ghidra where it is, then in the launcher drop-down, select
<strong>Configure and Launch termmines using… → gdb</strong>. DO NOT
select <strong>Re-launch termmines using gdb</strong>, since this will
not allow you to correct the configuration.</p>
</section>
<section id="the-dynamic-listing-is-empty" class="level3">
<h3>The Dynamic Listing is empty</h3>
<p>Check for an actual connection. You should see an entry in the
Debugger Targets window, a populated Object window, and there should be
an Interpreter window. If not, then your GDB connector may not be
configured properly. Try the steps under the previous heading.</p>
<p>If you have an Interpreter window, there are several
<strong>Connection Manager</strong> window, a populated
<strong>Model</strong> window, and there should be a
<strong>Terminal</strong> window. If not, then your GDB connector may
not be configured properly. Try the steps under the previous
heading.</p>
<p>If you have a <strong>Terminal</strong> window, there are several
possibilities:</p>
<section id="ghidra-or-gdb-failed-to-launch-the-target" class="level4">
<h4>Ghidra or GDB failed to launch the target:</h4>
<p>Check that the original <code>termmines</code> exists and is
executable. It must be at the path from where it was originally
imported. If you imported from a share, consider copying it locally,
setting its permissions, then re-importing.</p>
<p>If this is the case, you should see an error message in the Terminal,
e.g.: <code>termmines: no such file or directory</code>. Check that the
original <code>termmines</code> exists and is executable. You may also
need to adjust the <strong>Image</strong> option when configuring the
launch.</p>
</section>
<section id="the-target-was-launched-but-immediately-terminated"
class="level4">
<h4>The target was launched, but immediately terminated:</h4>
<p>Check that the specimen has a <code>main</code> symbol. NOTE: It is
<p>If this is the case, you should see a message in the Terminal, e.g.:
<code>[Inferior 1 (process 1234) exited normally]</code>. Check that the
specimen has a <code>main</code> symbol. <strong>NOTE</strong>: It is
not sufficient to place a <code>main</code> label in Ghidra. The
original file must have a <code>main</code> symbol.</p>
<p>Alternatively, in the menus try <strong>Debugger → Debug termmines →
in GDB locally IN-VM</strong>, and select “Use starti.” This will break
at the system entry point. If you have labeled <code>main</code> in
Ghidra, then you can place a breakpoint there and continue — these
features are covered later in the course.</p>
<p>Alternatively, in the menus try <strong>Debugger → Configure and
Launch termmines using → gdb</strong>, and select “starti” for
<strong>Run Command</strong>. This will break at the system entry point.
If you have labeled <code>main</code> in Ghidra, then you can place a
breakpoint there and continue — these features are covered later in the
course.</p>
<p>Alternatively, try debugging the target in GDB from a separate
terminal completely outside of Ghidra to see if things work as
expected.</p>
@ -356,37 +369,37 @@ class="level4">
<h4>The target was launched, but has not stopped, yet</h4>
<p>Try pressing the Interrupt <img src="images/interrupt.png"
alt="interrupt button" /> button. If that doesnt work or is
unsatisfactory, try the remedies under the previous heading — for an
immediately terminating target.</p>
unsatisfactory, try the remedies under the previous heading.</p>
</section>
<section
id="you-hit-an-uncommon-bug-where-the-memory-map-is-not-applied-properly"
class="level4">
<h4>You hit an uncommon bug where the memory map is not applied
properly</h4>
<p>This is the case if the Dynamic Listing is completely blank but the
Regions window is replete. The Dynamic Listing just needs to be kicked a
little. The easiest way is to step once, using the <img
src="images/stepinto.png" alt="step into" /> Step Into button in the
main toolbar. If this is not desirable, then you can toggle
<strong>Force Full View</strong> back and forth. In the Regions window,
use the drop-down menu to toggle it on, then toggle it off. The Dynamic
Listing should now be populated. To go to the program counter,
double-click the “pc = …” label in the top right.</p>
<p>This is the case if the <strong>Dynamic Listing</strong> is
completely blank but the <strong>Regions</strong> window is replete. The
<strong>Dynamic Listing</strong> just needs to be kicked a little. The
easiest way is to step once, using the <img src="images/stepinto.png"
alt="step into" /> <strong>Step Into</strong> button in the main
toolbar. If this is not desirable, then you can toggle <strong>Force
Full View</strong> back and forth. In the <strong>Regions</strong>
window, use the drop-down menu to toggle it on, then toggle it off. The
<strong>Dynamic Listing</strong> should now be populated. To go to the
program counter, double-click the “pc = …” label in the top right.</p>
</section>
<section id="something-else-has-gone-wrong" class="level4">
<h4>Something else has gone wrong</h4>
<p>Try typing <code>info inferiors</code> and similar GDB diagnostic
commands into the Interpreter.</p>
commands into the <strong>Terminal</strong>.</p>
</section>
</section>
<section
id="the-listings-are-in-sync-but-the-dynamic-listing-is-grey-00s"
class="level3">
<h3>The listings are in sync, but the Dynamic Listing is grey 00s</h3>
<p>Check the Auto-Read drop-down near the top right of the Dynamic
Listing. It should be set to <strong>Read Visible Memory, RO
Once</strong>.</p>
<p>Check the <strong>Auto-Read</strong> drop-down near the top right of
the <strong>Dynamic Listing</strong>. It should be set to <strong>Read
Visible Memory, RO Once</strong>.</p>
</section>
</section>
<section id="exercise-launch-termmines" class="level2">
@ -395,63 +408,66 @@ Once</strong>.</p>
<code>termmines</code> and/or start a new Ghidra Project. Starting from
the beginning, import <code>termmines</code> and launch it in the Ghidra
Debugger with GDB. When your tool looks like the screenshot with a
populated Dynamic Listing, you have completed the exercise. Disconnect
before proceeding to the next exercise.</p>
populated <strong>Dynamic Listing</strong>, you have completed the
exercise. Disconnect before proceeding to the next exercise.</p>
</section>
<section id="customized-launching" class="level2">
<h2>Customized Launching</h2>
<p>For this specimen, you may occasionally need to provide custom
command-line parameters. By default, Ghidra attempts to launch the
target without any parameters. In the menus, use <strong>Debugger
Debug termmmines → in GDB locally IN-VM</strong> to launch with
customizations. Ghidra will remember these customizations the next time
you launch using the drop-down button from the toolbar. The first dialog
allows you to customize the connection to the back-end debugger. Unless
you have a special copy of GDB, you should probably just click Connect.
The second dialog allows you to customize how the back-end debugger
launches the target. This is where you tweak the command line. You can
also change the actual image, in case it has moved or you want to
experiment with a patched version.</p>
target without any parameters. In the <strong>Debugger</strong> menu, or
the <strong>Launch</strong> buttons drop-down menu, use
<strong>Configure and Launch termmmines → gdb</strong> to adjust your
configuration. This is where you can specify the image path and
command-line parameters of your target. Ghidra will remember this
configuration the next time you launch using the drop-down button from
the toolbar. Launchers with memorized configurations are presented as
<strong>Re-launch termmines using…</strong> options. Using one of those
entries will re-launch with the saved configuration rather than
prompting.</p>
</section>
<section id="exercise-launch-with-command-line-help" class="level2">
<h2>Exercise: Launch with Command-line Help</h2>
<p>Launch the specimen so that it prints its usage. When successful, you
will see the usage info in the Debuggers Interpreter window.
<strong>NOTE</strong>: The process will terminate after printing its
usage, and as a result, the rest of the UI will be mostly empty.</p>
will see the usage info in the Debuggers <strong>Terminal</strong>
window. <strong>NOTE</strong>: The process will terminate after printing
its usage, and as a result, the rest of the UI will be mostly empty.</p>
</section>
<section id="attaching" class="level2">
<h2>Attaching</h2>
<p>Attaching is slightly more advanced, but because the target will need
to read from stdin, and Ghidra does not properly attach the Interpreter
to stdin, we will need to launch the target in a terminal and attach to
it instead. Note this technique is only possible because the target
waits for input. Depending on the task for future exercises, you may
still need to launch from the Debugger instead of attaching.</p>
<p>Attaching is slightly more advanced, but can be useful if the target
is part of a larger system, and it needs to be running <em>in situ</em>.
For this section, we will just run <code>termmines</code> in a separate
terminal and then attach to it from Ghidra. This used to be required,
because the older Recorder-based system did not provide target I/O, but
this limitation is overcome by the new <strong>Terminal</strong> window
when using Trace RMI. Note this technique is only possible because the
target waits for input.</p>
<ol type="1">
<li>Run <code>termmines</code> in a proper terminal with the desired
command-line parameters.</li>
<li>In the Ghidra Debugger, find the Targets window, and click the <img
src="images/connect.png" alt="connect" /> Connect button.</li>
<li>Select “gdb” from the drop-down box.</li>
<li>This dialog should look familiar from the Customized Launching
section. Just click the Connect button.</li>
<li>In the Objects window (below the Targets window), expand the node
labeled “Available.”</li>
<li>Run <code>termmines</code> in a terminal outside of Ghidra with the
desired command-line parameters.</li>
<li>In the Ghidra Debugger, use the <strong>Launch</strong> button
drop-down and select <strong>Configured and Launch termmines using… →
raw gdb</strong>. The “raw” connector will give us a GDB session without
a target.</li>
<li>Ghidra needs to know the location of gdb and the architecture of the
intended target. The defaults are correct for 64-bit x86 targets using
the systems copy of GDB. Probably, you can just click
<strong>Launch</strong>.</li>
<li>In the <strong>Model</strong> window (to the left), expand the
<em>Available</em> node.</li>
<li>In the filter box, type <code>termmines</code>.</li>
<li>Right-click on the termmines process and select Attach. If this
fails, select Available again, and click the
<img alt="refresh" src="images/view-refresh.png" width="16px"> Refresh
button.</li>
<li>Note the PID, e.g. 1234, then in the <strong>Terminal</strong> type,
e.g., <code>attach 1234</code>.</li>
</ol>
</section>
<section id="exercise-attach" class="level2">
<h2>Exercise: Attach</h2>
<p>Try attaching on your own, if you have not already. Check your work
by typing <code>bt</code> into the Interpreter. If you are in
<code>read</code> you have completed this exercise. Disconnect before
proceeding to the next module: <a href="A2-UITour.html">A Tour of the
UI</a></p>
by typing <code>bt</code> into the <strong>Terminal</strong>. If you are
in <code>read</code> you have completed this exercise. Quit GDB from the
<strong>Terminal</strong> before proceeding to the next module: <a
href="A2-UITour.html">A Tour of the UI</a></p>
</section>
<section id="troubleshooting-1" class="level2">
<h2>Troubleshooting</h2>
@ -464,14 +480,15 @@ be traced by any other process and then executes a shell command. Using
specimen in the permissive process, and thus you can attach to it as if
<code>ptrace_scope=0</code>, but without reducing the security of the
rest of the system. For example:</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ex">./anyptracer</span> <span class="st">&#39;exec ./termmines&#39;</span></span></code></pre></div>
<div class="sourceCode" id="cb4"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ex">./anyptracer</span> <span class="st">&#39;exec ./termmines&#39;</span></span></code></pre></div>
<p>Alternatively, if you have root access, you can rectify the issue
using the relevant documentation available online.
<strong>Beware!</strong> You should not modify this setting on your
daily driver, as this substantially reduces the security of your system.
Any compromised process would be allowed to attach to and steal data,
e.g., credentials, from any other process owned by the same user.</p>
<strong>Beware!</strong> You should not set <code>ptrace_scope=0</code>
globally, except on a system set aside for debugging, as this
substantially reduces the security of that system. Any compromised
process would be allowed to attach to and steal data, e.g., credentials,
from any other process owned by the same user.</p>
</section>
</section>
</body>

View File

@ -30,7 +30,10 @@ Run it:
```
You should see a 9x9 grid and a cursor you can move with the arrow keys.
Hit **Ctrl-C** to exit.
![Termmines running in a Terminal](images/GettingStarted_Termmines.png)
Hit **`CTRL`-`C`** to exit.
Probe it for help.
Most Linux programs accept a `-h` argument for help:
@ -55,23 +58,29 @@ There are many ways to do this, but for the sake of simplicity, import and launc
![Debugger tool with termmines open](images/GettingStarted_ToolWSpecimen.png)
1. In the Debugger tool, click the dropdown &blacktriangledown; for the debug ![debug button](images/debugger.png) icon in the global tool bar, and select "Debug termmines in GDB locally IN-VM."
1. In the Debugger tool, click the dropdown &blacktriangledown; for the debug ![debug button](images/debugger.png) icon in the global tool bar, and select **Configure and Launch termmines using... &rarr; gdb**.
![Launch GDB Dialog](images/GettingStarted_LaunchGDBDialog.png)
1. Change the **Run Command** to "start" (not "starti").
**NOTE**: In practice, this is rarely recommended, because most targets do not export their `main` function.
1. Click the **Launch** button in the dialog.
1. Wait a bit then verify the Dynamic Listing window (top) is displaying disassembly code.
![Debugger tool after launching termmines](images/GettingStarted_DisassemblyAfterLaunch.png)
## Launching on Windows
On Windows, we will use dbgeng to debug the specimen.
On Windows, we will use the Windows Debugger dbgeng.dll to debug the specimen.
This is the engine that backs WinDbg.
You may choose an alternative Minesweeper, since terminal applications are less representative of Windows executables.
Follow the same process as for Linux, except import `termmines.exe` and select "Debug termmines.exe in dbgeng locally IN-VM."
Follow the same process as for Linux, except import `termmines.exe` and select **Configure and Launch termmines.exe using... &rarr; dbgeng**.
## Launching on macOS
Unfortunately, things are not so simple on macOS.
See the instructions for [Building LLDB-Java Bindings](../../../Ghidra/Debug/Debugger-swig-lldb/InstructionsForBuildingLLDBInterface.txt).
Once built, follow the same process as for Linux, except select "Debug termmines in LLDB locally IN-VM."
On macOS, we will use LLDB to debug the specimen.
This is the debugger included with Xcode.
Follow the same process as for Linux, except choose **lldb** in the last menu.
## Troubleshooting
@ -97,59 +106,53 @@ Double-check that you are in the Debugger tool, not the CodeBrowser tool.
If it is still not there, then you may need to re-import the default Debugger tool as under the previous heading.
If it is still not there, your installation may be corrupt.
### There is no "Debug termmines in GDB locally IN-VM" option in the launch drop-down
### There is no **gdb** option in the launch drop-down
You may need to install GDB and/or configure Ghidra with its location.
If you have a copy or custom build of GDB in a non-system path, note its full path.
If you intend to use the system's copy of GDB, then in a terminal:
You may have an older Debugger tool still configured for Recorder-based targets.
We are transitioning to TraceRmi-based targets.
Delete your Debugger tool and re-import the default one using the instructions above.
If it is still not there, it's possible your installation is corrupt.
Search for a file called `local-gdb.sh` in your installation.
Unlike the previous system, Trace RMI will not probe your system for dependencies nor hide incompatible launchers.
All installed launchers should be present in the menus, even though some may not work on your configuration.
```bash
which gdb
```
### The launch hangs for several seconds and then I get prompted with a wall of text
Note the path given.
(If you get an error, then you need to install GDB.)
In a terminal, type the full path of GDB to ensure it executes properly.
Type `q` to quit GDB.
Read the wall of text.
The first line should tell you the exception that it encountered.
Often this is a timeout.
Press the **Keep** button and then find the Terminal, usually in the bottom right.
If you do not see it there, check the **Window &rarr; Terminals** menu.
Once you have found the Terminal, check its output *starting at the top* for diagnostic messages.
If you have something like `bash: gdb: command not found`, it is because you are missing `gdb`, or you need to tell Ghidra where to find it.
1. From the Debugger Targets window, click the Connect ![connect button](images/connect.png) button.
1. In the Connect dialog, select "gdb" from the dropdown at the top.
1. Enter the full path, e.g., `/usr/bin/gdb`, in the "GDB launch command" field.
1. Click "Connect"
1. If you get an Interpreter window, then things have gone well.
1. Type `echo test` into it to verify it's responsive, then type `q` to disconnect.
1. Close the Debugger tool, then retry.
### The launch hangs for several seconds and then prompt for a "recorder"
You probably have a stale GDB connection, so when you launched you now have multiple connections.
For the prompt, select the option with the highest score.
Examine the Targets window to confirm you have multiple GDB connections.
If you know which is the stale connection, you can right-click it and choose **Disconnect**.
Otherwise, use **Disconnect All** from the drop-down menu and re-launch.
If it is just missing, then install it and try again.
If you need to tell Ghidra where it is, then in the launcher drop-down, select **Configure and Launch termmines using... &rarr; gdb**.
DO NOT select **Re-launch termmines using gdb**, since this will not allow you to correct the configuration.
### The Dynamic Listing is empty
Check for an actual connection.
You should see an entry in the Debugger Targets window, a populated Object window, and there should be an Interpreter window.
You should see an entry in the **Connection Manager** window, a populated **Model** window, and there should be a **Terminal** window.
If not, then your GDB connector may not be configured properly.
Try the steps under the previous heading.
If you have an Interpreter window, there are several possibilities:
If you have a **Terminal** window, there are several possibilities:
#### Ghidra or GDB failed to launch the target:
If this is the case, you should see an error message in the Terminal, e.g.: `termmines: no such file or directory`.
Check that the original `termmines` exists and is executable.
It must be at the path from where it was originally imported.
If you imported from a share, consider copying it locally, setting its permissions, then re-importing.
You may also need to adjust the **Image** option when configuring the launch.
#### The target was launched, but immediately terminated:
If this is the case, you should see a message in the Terminal, e.g.: `[Inferior 1 (process 1234) exited normally]`.
Check that the specimen has a `main` symbol.
NOTE: It is not sufficient to place a `main` label in Ghidra.
**NOTE**: It is not sufficient to place a `main` label in Ghidra.
The original file must have a `main` symbol.
Alternatively, in the menus try **Debugger &rarr; Debug termmines &rarr; in GDB locally IN-VM**, and select "Use starti."
Alternatively, in the menus try **Debugger &rarr; Configure and Launch termmines using &rarr; gdb**, and select "starti" for **Run Command**.
This will break at the system entry point.
If you have labeled `main` in Ghidra, then you can place a breakpoint there and continue &mdash; these features are covered later in the course.
@ -158,75 +161,74 @@ Alternatively, try debugging the target in GDB from a separate terminal complete
#### The target was launched, but has not stopped, yet
Try pressing the Interrupt ![interrupt button](images/interrupt.png) button.
If that doesn't work or is unsatisfactory, try the remedies under the previous heading &mdash; for an immediately terminating target.
If that doesn't work or is unsatisfactory, try the remedies under the previous heading.
#### You hit an uncommon bug where the memory map is not applied properly
This is the case if the Dynamic Listing is completely blank but the Regions window is replete.
The Dynamic Listing just needs to be kicked a little.
The easiest way is to step once, using the ![step into](images/stepinto.png) Step Into button in the main toolbar.
This is the case if the **Dynamic Listing** is completely blank but the **Regions** window is replete.
The **Dynamic Listing** just needs to be kicked a little.
The easiest way is to step once, using the ![step into](images/stepinto.png) **Step Into** button in the main toolbar.
If this is not desirable, then you can toggle **Force Full View** back and forth.
In the Regions window, use the drop-down menu to toggle it on, then toggle it off.
The Dynamic Listing should now be populated.
In the **Regions** window, use the drop-down menu to toggle it on, then toggle it off.
The **Dynamic Listing** should now be populated.
To go to the program counter, double-click the "pc = ..." label in the top right.
#### Something else has gone wrong
Try typing `info inferiors` and similar GDB diagnostic commands into the Interpreter.
Try typing `info inferiors` and similar GDB diagnostic commands into the **Terminal**.
### The listings are in sync, but the Dynamic Listing is grey 00s
Check the Auto-Read drop-down near the top right of the Dynamic Listing.
Check the **Auto-Read** drop-down near the top right of the **Dynamic Listing**.
It should be set to **Read Visible Memory, RO Once**.
## Exercise: Launch `termmines`
If you were following along with an instructor, delete your import of `termmines` and/or start a new Ghidra Project.
Starting from the beginning, import `termmines` and launch it in the Ghidra Debugger with GDB.
When your tool looks like the screenshot with a populated Dynamic Listing, you have completed the exercise.
When your tool looks like the screenshot with a populated **Dynamic Listing**, you have completed the exercise.
Disconnect before proceeding to the next exercise.
## Customized Launching
For this specimen, you may occasionally need to provide custom command-line parameters.
By default, Ghidra attempts to launch the target without any parameters.
In the menus, use **Debugger &rarr; Debug termmmines &rarr; in GDB locally IN-VM** to launch with customizations.
Ghidra will remember these customizations the next time you launch using the drop-down button from the toolbar.
The first dialog allows you to customize the connection to the back-end debugger.
Unless you have a special copy of GDB, you should probably just click Connect.
The second dialog allows you to customize how the back-end debugger launches the target.
This is where you tweak the command line.
You can also change the actual image, in case it has moved or you want to experiment with a patched version.
In the **Debugger** menu, or the **Launch** button's drop-down menu, use **Configure and Launch termmmines &rarr; gdb** to adjust your configuration.
This is where you can specify the image path and command-line parameters of your target.
Ghidra will remember this configuration the next time you launch using the drop-down button from the toolbar.
Launchers with memorized configurations are presented as **Re-launch termmines using...** options.
Using one of those entries will re-launch with the saved configuration rather than prompting.
## Exercise: Launch with Command-line Help
Launch the specimen so that it prints its usage.
When successful, you will see the usage info in the Debugger's Interpreter window.
When successful, you will see the usage info in the Debugger's **Terminal** window.
**NOTE**: The process will terminate after printing its usage, and as a result, the rest of the UI will be mostly empty.
## Attaching
Attaching is slightly more advanced, but because the target will need to read from stdin, and Ghidra does not properly attach the Interpreter to stdin, we will need to launch the target in a terminal and attach to it instead.
Attaching is slightly more advanced, but can be useful if the target is part of a larger system, and it needs to be running *in situ*.
For this section, we will just run `termmines` in a separate terminal and then attach to it from Ghidra.
This used to be required, because the older Recorder-based system did not provide target I/O, but this limitation is overcome by the new **Terminal** window
when using Trace RMI.
Note this technique is only possible because the target waits for input.
Depending on the task for future exercises, you may still need to launch from the Debugger instead of attaching.
1. Run `termmines` in a proper terminal with the desired command-line parameters.
1. In the Ghidra Debugger, find the Targets window, and click the ![connect](images/connect.png) Connect button.
1. Select "gdb" from the drop-down box.
1. This dialog should look familiar from the Customized Launching section.
Just click the Connect button.
1. In the Objects window (below the Targets window), expand the node labeled "Available."
1. Run `termmines` in a terminal outside of Ghidra with the desired command-line parameters.
1. In the Ghidra Debugger, use the **Launch** button drop-down and select **Configured and Launch termmines using... &rarr; raw gdb**.
The "raw" connector will give us a GDB session without a target.
1. Ghidra needs to know the location of gdb and the architecture of the intended target.
The defaults are correct for 64-bit x86 targets using the system's copy of GDB.
Probably, you can just click **Launch**.
1. In the **Model** window (to the left), expand the *Available* node.
1. In the filter box, type `termmines`.
1. Right-click on the termmines process and select Attach.
If this fails, select Available again, and click the <img alt="refresh" src="images/view-refresh.png" width="16px"> Refresh button.
1. Note the PID, e.g. 1234, then in the **Terminal** type, e.g., `attach 1234`.
## Exercise: Attach
Try attaching on your own, if you have not already.
Check your work by typing `bt` into the Interpreter.
Check your work by typing `bt` into the **Terminal**.
If you are in `read` you have completed this exercise.
Disconnect before proceeding to the next module: [A Tour of the UI](A2-UITour.md)
Quit GDB from the **Terminal** before proceeding to the next module: [A Tour of the UI](A2-UITour.md)
## Troubleshooting
@ -241,5 +243,5 @@ For example:
```
Alternatively, if you have root access, you can rectify the issue using the relevant documentation available online.
**Beware!** You should not modify this setting on your daily driver, as this substantially reduces the security of your system.
**Beware!** You should not set `ptrace_scope=0` globally, except on a system set aside for debugging, as this substantially reduces the security of that system.
Any compromised process would be allowed to attach to and steal data, e.g., credentials, from any other process owned by the same user.

View File

@ -18,6 +18,70 @@
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
/* CSS for syntax highlighting */
pre > code.sourceCode { white-space: pre; position: relative; }
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
pre > code.sourceCode > span:empty { height: 1.2em; }
.sourceCode { overflow: visible; }
code.sourceCode > span { color: inherit; text-decoration: inherit; }
div.sourceCode { margin: 1em 0; }
pre.sourceCode { margin: 0; }
@media screen {
div.sourceCode { overflow: auto; }
}
@media print {
pre > code.sourceCode { white-space: pre-wrap; }
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
pre.numberSource code
{ counter-reset: source-line 0; }
pre.numberSource code > span
{ position: relative; left: -4em; counter-increment: source-line; }
pre.numberSource code > span > a:first-child::before
{ content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
div.sourceCode
{ }
@media screen {
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code span.at { color: #7d9029; } /* Attribute */
code span.bn { color: #40a070; } /* BaseN */
code span.bu { color: #008000; } /* BuiltIn */
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code span.ch { color: #4070a0; } /* Char */
code span.cn { color: #880000; } /* Constant */
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
code span.dt { color: #902000; } /* DataType */
code span.dv { color: #40a070; } /* DecVal */
code span.er { color: #ff0000; font-weight: bold; } /* Error */
code span.ex { } /* Extension */
code span.fl { color: #40a070; } /* Float */
code span.fu { color: #06287e; } /* Function */
code span.im { color: #008000; font-weight: bold; } /* Import */
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
code span.op { color: #666666; } /* Operator */
code span.ot { color: #007020; } /* Other */
code span.pp { color: #bc7a00; } /* Preprocessor */
code span.sc { color: #4070a0; } /* SpecialChar */
code span.ss { color: #bb6688; } /* SpecialString */
code span.st { color: #4070a0; } /* String */
code span.va { color: #19177c; } /* Variable */
code span.vs { color: #4070a0; } /* VerbatimString */
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
</style>
<link rel="stylesheet" href="style.css" />
<!--[if lt IE 9]>
@ -67,10 +131,9 @@ listings seem to move together, but their contents differ.</a></li>
<li><a href="#there-is-no-step-button."
id="toc-there-is-no-step-button.">There is no step button.</a></li>
<li><a
href="#i-can-step-but-i-dont-see-the-effects-in-the-interpreter-window."
id="toc-i-can-step-but-i-dont-see-the-effects-in-the-interpreter-window.">I
can step, but I dont see the effects in the Interpreter
window.</a></li>
href="#i-can-step-but-i-dont-see-the-effects-in-the-terminal-window."
id="toc-i-can-step-but-i-dont-see-the-effects-in-the-terminal-window.">I
can step, but I dont see the effects in the Terminal window.</a></li>
<li><a href="#the-step-buttons-are-grayed-out."
id="toc-the-step-buttons-are-grayed-out.">The Step buttons are grayed
out.</a></li>
@ -90,8 +153,8 @@ Debugger. We assume some familiarity with trap-and-trace debugging. If
you have not used GDB or a similar debugger before, you may find the
Ghidra Debugger difficult to grasp.</p>
<p>If you would like your tool to look more or less like the one
presented in the screenshots here, launch <code>termmines</code> from
the Debugger using GDB.</p>
presented in the screenshot here, launch <code>termmines</code> from the
Debugger using GDB.</p>
<section id="the-debugger-tool" class="level2">
<h2>The Debugger Tool</h2>
<p>Like the CodeBrowser tool, the Debugger tool is a preconfigured
@ -112,15 +175,16 @@ CodeBrowser. Coincidentally, in the screenshot, the debugger-specific
buttons start just above the Dynamic Listing in the global toolbar. They
are:</p>
<ul>
<li><img src="images/debugger.png" alt="launch button" />
<strong>Launch</strong>: This launches the current program (from the
Static Listing) using a suitable back-end debugger. The drop-down menu
provides a selection of previously-used launchers and a sub-menu of all
available launchers. Clicking the button will use the most recent
configuration, whether or not it succeeded.</li>
<li><img src="images/process.png" alt="emulate button" />
<strong>Emulate</strong>: To be covered in a later module. This will
load the current program (from the Static Listing) into the
emulator.</li>
<li><img src="images/debugger.png" alt="debug button" />
<strong>Debug</strong>: This launches the current program (from the
Static Listing) using a suitable back-end debugger. The drop-down menu
provides a selection of suitable back-end connectors. Clicking the
button will use the last successful connector or the default.</li>
<li><img src="images/record.png" alt="mode button" /> <strong>Control
Mode</strong>: This drop-down menu sets the mode of the controls and
machine state edits. By default, all actions are directed to the
@ -130,8 +194,8 @@ back-end debugger.</li>
<code>continue</code> in GDB.</li>
<li><img src="images/interrupt.png" alt="interrupt button" />
<strong>Interrupt</strong>: Interrupt, suspend, pause, break, etc. This
is equivalent to <strong>Ctrl-C</strong> or <code>interrupt</code> in
GDB.</li>
is equivalent to <strong><code>CTRL</code>-<code>C</code></strong> or
<code>interrupt</code> in GDB.</li>
<li><img src="images/kill.png" alt="kill button" />
<strong>Kill</strong>: Kill, terminate, etc. This is equivalent to
<code>kill</code> in GDB.</li>
@ -144,111 +208,138 @@ Typically, this will also end the session. It is equivalent to
alt="step over button" /> <strong>Step Over</strong>, <img
src="images/stepout.png" alt="step out button" /> <strong>Step
Out</strong>, <img src="images/steplast.png" alt="step last button" />
<strong>Step Last</strong>: These buttons step in various ways. In
<strong>Step [Extended]</strong>: These buttons step in various ways. In
order, the equivalent commands in GDB are <code>stepi</code>,
<code>nexti</code>, and <code>finish</code>. Step Last has no equivalent
in GDB; it is meant to repeat the last custom/extended step.</li>
<code>nexti</code>, and <code>finish</code>. Step [Extended] represents
additional step commands supported by the back end. GDB provides
<strong>Advance</strong> and <strong>Return</strong>.</li>
</ul>
</section>
<section id="windows" class="level3">
<h3>Windows</h3>
<p>Starting at the top left and working clockwise, the windows are:</p>
<ul>
<li>The <strong>Debugger Targets</strong> window: This lists active
sessions or connections. From here, you can establish new sessions or
terminate existing sessions.</li>
<li>The <strong>Debug Console</strong> window: (Not to be confused with
the CodeBrowsers Console window.) This lists problems, diagnostics,
progress, and recommendations throughout the tool. Some problems are
presented with remedial actions, which may expedite your workflow or aid
in troubleshooting.</li>
<li>The <strong>Connections</strong> window: This is stacked below the
Debug Console. This lists active sessions or connections. From here, you
can establish new sessions or terminate existing sessions.</li>
<li>The <strong>Dynamic Listing</strong> window: This is the primary
means of examining the instructions being executed. By default, it
follows the program counter and disassembles from there until the next
control transfer instruction. It supports many of the same operations as
the Static Listing, including patching. The nearest equivalent in GDB is
something like <code>x/10i $pc</code>.</li>
<li>The <strong>Interpreter</strong> window: This is essentially a
terminal emulator providing a command-line interface to the back-end
debugger. It is useful for diagnostics or for issuing commands that do
not have a button in the GUI. Some may also prefer to command the
debugger from here rather than the GUI.</li>
<li>The <strong>Breakpoints</strong> window: This is stacked below the
Interpreter. It lists and manages the breakpoints among all open images
and running targets. The nearest equivalent in GDB is
something like <code>x/10i $pc</code>. The tabs at the top list the
active traces. Traces with a <img src="images/record.png"
alt="record" /> icon represent live targets. The nearest equivalent to
the tabs in GDB is <code>info inferiors</code>.</li>
<li>The <strong>Breakpoints</strong> window: This is on the right. It
lists and manages the breakpoints among all open program databases and
running targets. The nearest equivalent in GDB is
<code>info break</code>.</li>
<li>The <strong>Registers</strong> window: This is stacked below the
Breakpoints window. It displays and edits the register values for the
current thread. The nearest equivalent in GDB is
<code>info registers</code></li>
<code>info registers</code>.</li>
<li>The <strong>Memory</strong> window: This is stacked below the
Breakpoints window. It displays the raw bytes of memory from the current
trace or target. It supports many of the same operations as the
CodeBrowsers Bytes window, including patching.</li>
<li>The <strong>Decompiler</strong> window: While not a dynamic analysis
window, it bears mentioning how this operates with the Debugger. It is
stacked below the Breakpoints window, more or less in the same place as
in the CodeBrowser. The Dynamic listing strives to synchronize Ghidras
static analysis windows with the dynamic target. So long as the correct
program database is imported and mapped at the program counter, this
window should display decompilation of the function containing it.</li>
<li>The <strong>Modules</strong> window: This is stacked below the
Registers window. It displays the images (and sections, if applicable)
loaded by the target. The equivalent in GDB is
<code>maintenance info sections</code>. Note that this differs from the
Regions window.</li>
<li>The <strong>Threads</strong> window: This lists the threads in the
current target. The tabs at the top list the active targets. The nearest
equivalents in GDB are <code>info threads</code> and
<code>info inferiors</code>.</li>
<li>The <strong>Time</strong> window: This is stacked below the Threads
<li>The <strong>Terminal</strong> window: This is on the bottom right.
This is a terminal emulator providing a command-line interface to the
back-end debugger and/or target I/O. It is useful for diagnostics or for
issuing commands that do not have a button in the GUI. Some may also
prefer to command the debugger from here rather than the GUI. In some
configurations, the target may have its own Terminal, separate from the
back-end debuggers.</li>
<li>The <strong>Threads</strong> window: This is stacked below the
Terminal window. It lists the threads in the current target. The nearest
equivalent in GDB is <code>info threads</code>.</li>
<li>The <strong>Time</strong> window: This is stacked below the Terminal
window. This lists the events and snapshots taken of the current
target.</li>
<li>The <strong>Stack</strong> window: This lists the stack frames for
the current thread. The equivalent in GDB is
<li>The <strong>Static Mappings</strong> window: This is stacked below
the Terminal window. It lists mappings from the current trace (dynamic
address ranges) to program databases (static address ranges). Generally,
this list is populated automatically, but may still be useful for
diagnostics or manual mapping.</li>
<li>The <strong>Stack</strong> window: This is on the bottom left. It
lists the stack frames for the current thread. The equivalent in GDB is
<code>backtrace</code>.</li>
<li>The <strong>Watches</strong> window: This is stacked below the Stack
window — pun not intended. It manages current watches. These are
<em>not</em> watchpoints, but rather expressions or variables whose
values to display. To manage watchpoints, use the Breakpoints window or
the Interpreter. The nearest equivalent in GDB is
values you wish to display. To manage watchpoints, use the Breakpoints
window or the Terminal. The nearest equivalent in GDB is
<code>display</code>.</li>
<li>The <strong>Regions</strong> window: This is stacked below the
Watches window. It lists memory regions for the current target. It
differs from the Modules window, since this includes not only
image-backed regions but other memory regions, e.g., stacks and heaps.
The equivalent in GDB is <code>info proc mappings</code>.</li>
<li>The <strong>Debug Console</strong> window: (Not to be confused with
the Console window from the CodeBrowser.) This displays logging messages
and problems encountered during a session. Some problems are presented
with remedial actions, which may expedite your workflow or aid in
troubleshooting.</li>
<li>The <strong>Objects</strong> window: This models the back-end
debugger as a tree of objects and provides generic actions on those
objects. It is generally more capable, though less integrated, than the
GUI, but not quite as capable as the Interpreter. It is useful for
troubleshooting and for advanced use cases.</li>
<li>The <strong>Regions</strong> window: This is stacked below the Stack
window. It lists memory regions for the current target. It differs from
the Modules window, since this includes not only image-backed regions
but other memory regions, e.g., stacks and heaps. The equivalent in GDB
is <code>info proc mappings</code>.</li>
<li>The <strong>Model</strong> window: The back-end debugger populates
an object model in the trace database. It is from this model that many
other windows derive their contents: Threads, Modules, Regions, etc.
This window presents that model and provides access to generic actions
on the contained objects. It is generally more capable, though less
integrated, than the other parts of the GUI, but not quite as capable as
the Terminal. For some advanced use cases, where Ghidra does not yet
provide built-in actions, it is essential.</li>
</ul>
</section>
</section>
<section id="controlling-the-target" class="level2">
<h2>Controlling the Target</h2>
<p>The control buttons are all located on the global toolbar. Start by
pressing the <img src="images/stepinto.png" alt="step into" /> Step Into
button. Notice that the Dynamic Listing moves forward a single
instruction each time you press it. Also notice that the Static Listing
moves with the Dynamic Listing. You may navigate in either listing, and
so long as there is a corresponding location in the other, the two will
stay synchronized. You may also open the Decompiler just as you would in
the CodeBrowser, and it will stay in sync, too.</p>
pressing the <img src="images/stepinto.png" alt="step into" />
<strong>Step Into</strong> button. Notice that the Dynamic Listing moves
forward a single instruction each time you press it. Also notice that
the Static Listing moves with the Dynamic Listing. You may navigate in
either listing, and so long as there is a corresponding location in the
other, the two will stay synchronized. You may also open the Decompiler
just as you would in the CodeBrowser, and it will stay in sync too.</p>
<p>When you have clicked <img src="images/stepinto.png"
alt="step into" /> Step Into a sufficient number of times, you should
end up in a subroutine. You can click <img src="images/stepout.png"
alt="step out" /> Step Out to leave the subroutine. Note that the target
is allowed to execute until it returns from the subroutine; it does not
skip out of it. Now, click <img src="images/stepover.png"
alt="step over" /> Step Over until you reach another <code>CALL</code>
instruction. Notice that when you click <img src="images/stepover.png"
alt="step over" /> Step Over again, it will not descend into the
subroutine. Instead, the target is allowed to execute the entire
subroutine before stopping again — after the <code>CALL</code>
alt="step into" /> <strong>Step Into</strong> a sufficient number of
times, you should end up in a subroutine. You can click <img
src="images/stepout.png" alt="step out" /> <strong>Step Out</strong> to
leave the subroutine. Note that the target is allowed to execute until
it returns from the subroutine; it does not skip out of it. Now, click
<img src="images/stepover.png" alt="step over" /> <strong>Step
Over</strong> until you reach another <code>CALL</code> instruction.
Notice that when you click <img src="images/stepover.png"
alt="step over" /> <strong>Step Over</strong> again, it will not descend
into the subroutine. Instead, the target is allowed to execute the
entire subroutine before stopping again — after the <code>CALL</code>
instruction.</p>
<p>If you prefer, you may use the GDB commands from the Interpreter
instead of the buttons. Try <code>si</code> and/or <code>ni</code>. You
can also pass arguments which is not possible with the buttons,
<p>If you prefer, you may use the GDB commands from the Terminal instead
of the buttons. Try <code>si</code> and/or <code>ni</code>. You can also
pass arguments which is not possible with the buttons,
e.g. <code>si 10</code> to step 10 instructions in one command.</p>
<p>If you need to terminate the target you should use the <img
src="images/disconnect.png" alt="disconnect" /> Disconnect button rather
than the Kill button, in general. Otherwise, each launch will create a
new connection, and you will end up with several stale connections.
Additionally, if your target exits or otherwise terminates on its own,
you will get a stale connection. Use the Targets window to clean such
connections up. The re-use of connections and/or the use of multiple
concurrent connections is <em>not</em> covered in this course.</p>
src="images/disconnect.png" alt="disconnect" />
<strong>Disconnect</strong> button rather than the <strong>Kill</strong>
button, in general. Otherwise, each launch will create a new connection,
and you will end up with several stale connections. Additionally, if
your target exits or otherwise terminates on its own, you will get a
stale connection. Use the Connections window to clean such connections
up, or just type <code>quit</code> into the sessions Terminal. The
re-use of connections and/or the use of multiple concurrent connections
is <em>not</em> covered in this course.</p>
</section>
<section id="troubleshooting" class="level2">
<h2>Troubleshooting</h2>
@ -264,14 +355,23 @@ Listing is its local drop-down menu. Click it and check that
Listing to see what module you are in. Also check the Debug Console
window. If you are in a system library, e.g., <code>ld-linux</code>,
then this is the expected behavior. You may optionally import it, as
suggested by the Debug Console, but this is covered later.</p>
suggested by the Debug Console, but this is covered later. You may also
try typing into the Terminal, <em>one command at a time</em>, checking
for errors after each:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode gdb"><code class="sourceCode gdbsyntax"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">break</span> main</span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a>continue</span></code></pre></div>
<p>That should get you from the system entry into the targets
<code>main</code> routine, assuming it has one. Next time you launch,
check the configuration and change <strong>Run Command</strong> to
“start”, not “starti”.</p>
<p>If you are not in a system library, then check the Modules window to
see if <code>termmines</code> is listed. If so, it seems the module
mapper failed to realize that module is the current program. Right-click
the module and select “Map to termmines.” Confirm the dialog. If
<code>termmines</code> is not listed, then your version of GDB may not
be supported. If you file a bug report, please include your GDB version,
Linux distribution, and/or other platform details.</p>
the module and select <strong>Map to termmines</strong>. Confirm the
dialog. If <code>termmines</code> is not listed, then your version of
GDB may not be supported. If you file a bug report, please include your
GDB version, Linux distribution, and/or other platform details.</p>
</section>
<section
id="the-listings-seem-to-move-together-but-their-contents-differ."
@ -284,29 +384,32 @@ importing and launching? For other system libraries, this could happen
if you or an administrator applied system updates since you imported.
You probably need to re-import the affected module image(s). If this
happens to you in practice, and you have substantial investment in the
old import, consider using the Version Tracker to port your knowledge to
the new import.</p>
old program database, consider using the Version Tracker to port your
knowledge to the new database.</p>
</section>
<section id="there-is-no-step-button." class="level3">
<h3>There is no step button.</h3>
<p>This can happen if the Control Mode is set to the Trace. Perhaps you
played with the Time window? Change the Control Mode back to “Control
Target.”</p>
<p>This can happen if the Control Mode is set to <strong>Control
Trace</strong>. Perhaps you played with the Time window? The Control
Mode drop-down is leftmost in the “Control” group, immediately right of
the <strong>Launch</strong> and <strong>Emulate</strong> buttons. Its
icon differs for each mode. Change it back to <strong>Control
Target</strong>.</p>
</section>
<section
id="i-can-step-but-i-dont-see-the-effects-in-the-interpreter-window."
id="i-can-step-but-i-dont-see-the-effects-in-the-terminal-window."
class="level3">
<h3>I can step, but I dont see the effects in the Interpreter
window.</h3>
<p>This can happen if the Control Mode is set to the Emulator. Change
the Control Mode back to “Control Target.”</p>
<h3>I can step, but I dont see the effects in the Terminal window.</h3>
<p>This can happen if the Control Mode is set to <strong>Control
Emulator</strong>. See the above heading about Control Mode. Change it
back to <strong>Control Target</strong>.</p>
</section>
<section id="the-step-buttons-are-grayed-out." class="level3">
<h3>The Step buttons are grayed out.</h3>
<p>The target has likely terminated, or you have not selected a thread.
Check the Threads window. If it is empty, re-launch, and perhaps look at
the Troubleshooting section in <a href="A1-GettingStarted.html">Getting
Started</a></p>
Check the Threads window or the Model window. If it is empty, re-launch,
and perhaps look at the Troubleshooting section in <a
href="A1-GettingStarted.html">Getting Started</a></p>
</section>
</section>
<section id="exercise-step-around" class="level2">
@ -318,7 +421,8 @@ you have entered that subroutine. <strong>TIP</strong>: Use the
Decompiler to help you recognize when you have entered the command-line
parsing subroutine. Alternatively, use the Static Listing and Decompiler
to identify the parsing subroutine (as you would in the CodeBrowser),
and then use the Step buttons to drive the target into it.</p>
and then use the <strong>Step</strong> buttons to drive the target into
it.</p>
</section>
</section>
</body>

View File

@ -8,7 +8,7 @@ This module will briefly introduce each window in the Ghidra Debugger.
We assume some familiarity with trap-and-trace debugging.
If you have not used GDB or a similar debugger before, you may find the Ghidra Debugger difficult to grasp.
If you would like your tool to look more or less like the one presented in the screenshots here,
If you would like your tool to look more or less like the one presented in the screenshot here,
launch `termmines` from the Debugger using GDB.
## The Debugger Tool
@ -25,13 +25,13 @@ Many of the buttons in the global toolbar are the same as in the CodeBrowser.
Coincidentally, in the screenshot, the debugger-specific buttons start just above the Dynamic Listing in the global toolbar.
They are:
* ![launch button](images/debugger.png) **Launch**:
This launches the current program (from the Static Listing) using a suitable back-end debugger.
The drop-down menu provides a selection of previously-used launchers and a sub-menu of all available launchers.
Clicking the button will use the most recent configuration, whether or not it succeeded.
* ![emulate button](images/process.png) **Emulate**:
To be covered in a later module.
This will load the current program (from the Static Listing) into the emulator.
* ![debug button](images/debugger.png) **Debug**:
This launches the current program (from the Static Listing) using a suitable back-end debugger.
The drop-down menu provides a selection of suitable back-end connectors.
Clicking the button will use the last successful connector or the default.
* ![mode button](images/record.png) **Control Mode**:
This drop-down menu sets the mode of the controls and machine state edits.
By default, all actions are directed to the back-end debugger.
@ -40,7 +40,7 @@ They are:
This is equivalent to `continue` in GDB.
* ![interrupt button](images/interrupt.png) **Interrupt**:
Interrupt, suspend, pause, break, etc.
This is equivalent to **Ctrl-C** or `interrupt` in GDB.
This is equivalent to **`CTRL`-`C`** or `interrupt` in GDB.
* ![kill button](images/kill.png) **Kill**:
Kill, terminate, etc.
This is equivalent to `kill` in GDB.
@ -48,16 +48,21 @@ They are:
Disconnect from the back-end debugger.
Typically, this will also end the session.
It is equivalent to `quit` in GDB.
* ![step into button](images/stepinto.png) **Step Into**, ![step over button](images/stepover.png) **Step Over**, ![step out button](images/stepout.png) **Step Out**, ![step last button](images/steplast.png) **Step Last**:
* ![step into button](images/stepinto.png) **Step Into**, ![step over button](images/stepover.png) **Step Over**, ![step out button](images/stepout.png) **Step Out**, ![step last button](images/steplast.png) **Step [Extended]**:
These buttons step in various ways.
In order, the equivalent commands in GDB are `stepi`, `nexti`, and `finish`.
Step Last has no equivalent in GDB; it is meant to repeat the last custom/extended step.
Step [Extended] represents additional step commands supported by the back end. GDB provides **Advance** and **Return**.
### Windows
Starting at the top left and working clockwise, the windows are:
* The **Debugger Targets** window:
* The **Debug Console** window:
(Not to be confused with the CodeBrowser's Console window.)
This lists problems, diagnostics, progress, and recommendations throughout the tool.
Some problems are presented with remedial actions, which may expedite your workflow or aid in troubleshooting.
* The **Connections** window:
This is stacked below the Debug Console.
This lists active sessions or connections.
From here, you can establish new sessions or terminate existing sessions.
* The **Dynamic Listing** window:
@ -65,77 +70,94 @@ Starting at the top left and working clockwise, the windows are:
By default, it follows the program counter and disassembles from there until the next control transfer instruction.
It supports many of the same operations as the Static Listing, including patching.
The nearest equivalent in GDB is something like `x/10i $pc`.
* The **Interpreter** window:
This is essentially a terminal emulator providing a command-line interface to the back-end debugger.
It is useful for diagnostics or for issuing commands that do not have a button in the GUI.
Some may also prefer to command the debugger from here rather than the GUI.
The tabs at the top list the active traces.
Traces with a ![record](images/record.png) icon represent live targets.
The nearest equivalent to the tabs in GDB is `info inferiors`.
* The **Breakpoints** window:
This is stacked below the Interpreter.
It lists and manages the breakpoints among all open images and running targets.
This is on the right.
It lists and manages the breakpoints among all open program databases and running targets.
The nearest equivalent in GDB is `info break`.
* The **Registers** window:
This is stacked below the Breakpoints window.
It displays and edits the register values for the current thread.
The nearest equivalent in GDB is `info registers`
The nearest equivalent in GDB is `info registers`.
* The **Memory** window:
This is stacked below the Breakpoints window.
It displays the raw bytes of memory from the current trace or target.
It supports many of the same operations as the CodeBrowser's Bytes window, including patching.
* The **Decompiler** window:
While not a dynamic analysis window, it bears mentioning how this operates with the Debugger.
It is stacked below the Breakpoints window, more or less in the same place as in the CodeBrowser.
The Dynamic listing strives to synchronize Ghidra's static analysis windows with the dynamic target.
So long as the correct program database is imported and mapped at the program counter, this window should display decompilation of the function containing it.
* The **Modules** window:
This is stacked below the Registers window.
It displays the images (and sections, if applicable) loaded by the target.
The equivalent in GDB is `maintenance info sections`.
Note that this differs from the Regions window.
* The **Terminal** window:
This is on the bottom right.
This is a terminal emulator providing a command-line interface to the back-end debugger and/or target I/O.
It is useful for diagnostics or for issuing commands that do not have a button in the GUI.
Some may also prefer to command the debugger from here rather than the GUI.
In some configurations, the target may have its own Terminal, separate from the back-end debugger's.
* The **Threads** window:
This lists the threads in the current target.
The tabs at the top list the active targets.
The nearest equivalents in GDB are `info threads` and `info inferiors`.
This is stacked below the Terminal window.
It lists the threads in the current target.
The nearest equivalent in GDB is `info threads`.
* The **Time** window:
This is stacked below the Threads window.
This is stacked below the Terminal window.
This lists the events and snapshots taken of the current target.
* The **Static Mappings** window:
This is stacked below the Terminal window.
It lists mappings from the current trace (dynamic address ranges) to program databases (static address ranges).
Generally, this list is populated automatically, but may still be useful for diagnostics or manual mapping.
* The **Stack** window:
This lists the stack frames for the current thread.
This is on the bottom left.
It lists the stack frames for the current thread.
The equivalent in GDB is `backtrace`.
* The **Watches** window:
This is stacked below the Stack window &mdash; pun not intended.
It manages current watches.
These are *not* watchpoints, but rather expressions or variables whose values to display.
To manage watchpoints, use the Breakpoints window or the Interpreter.
These are *not* watchpoints, but rather expressions or variables whose values you wish to display.
To manage watchpoints, use the Breakpoints window or the Terminal.
The nearest equivalent in GDB is `display`.
* The **Regions** window:
This is stacked below the Watches window.
This is stacked below the Stack window.
It lists memory regions for the current target.
It differs from the Modules window, since this includes not only image-backed regions but other memory regions, e.g., stacks and heaps.
The equivalent in GDB is `info proc mappings`.
* The **Debug Console** window:
(Not to be confused with the Console window from the CodeBrowser.)
This displays logging messages and problems encountered during a session.
Some problems are presented with remedial actions, which may expedite your workflow or aid in troubleshooting.
* The **Objects** window:
This models the back-end debugger as a tree of objects and provides generic actions on those objects.
It is generally more capable, though less integrated, than the GUI, but not quite as capable as the Interpreter.
It is useful for troubleshooting and for advanced use cases.
* The **Model** window:
The back-end debugger populates an object model in the trace database.
It is from this model that many other windows derive their contents: Threads, Modules, Regions, etc.
This window presents that model and provides access to generic actions on the contained objects.
It is generally more capable, though less integrated, than the other parts of the GUI, but not quite as capable as the Terminal.
For some advanced use cases, where Ghidra does not yet provide built-in actions, it is essential.
## Controlling the Target
The control buttons are all located on the global toolbar.
Start by pressing the ![step into](images/stepinto.png) Step Into button.
Start by pressing the ![step into](images/stepinto.png) **Step Into** button.
Notice that the Dynamic Listing moves forward a single instruction each time you press it.
Also notice that the Static Listing moves with the Dynamic Listing.
You may navigate in either listing, and so long as there is a corresponding location in the other, the two will stay synchronized.
You may also open the Decompiler just as you would in the CodeBrowser, and it will stay in sync, too.
You may also open the Decompiler just as you would in the CodeBrowser, and it will stay in sync too.
When you have clicked ![step into](images/stepinto.png) Step Into a sufficient number of times, you should end up in a subroutine.
You can click ![step out](images/stepout.png) Step Out to leave the subroutine.
When you have clicked ![step into](images/stepinto.png) **Step Into** a sufficient number of times, you should end up in a subroutine.
You can click ![step out](images/stepout.png) **Step Out** to leave the subroutine.
Note that the target is allowed to execute until it returns from the subroutine; it does not skip out of it.
Now, click ![step over](images/stepover.png) Step Over until you reach another `CALL` instruction.
Notice that when you click ![step over](images/stepover.png) Step Over again, it will not descend into the subroutine.
Now, click ![step over](images/stepover.png) **Step Over** until you reach another `CALL` instruction.
Notice that when you click ![step over](images/stepover.png) **Step Over** again, it will not descend into the subroutine.
Instead, the target is allowed to execute the entire subroutine before stopping again &mdash; after the `CALL` instruction.
If you prefer, you may use the GDB commands from the Interpreter instead of the buttons.
If you prefer, you may use the GDB commands from the Terminal instead of the buttons.
Try `si` and/or `ni`.
You can also pass arguments which is not possible with the buttons, e.g. `si 10` to step 10 instructions in one command.
If you need to terminate the target you should use the ![disconnect](images/disconnect.png) Disconnect button rather than the Kill button, in general.
If you need to terminate the target you should use the ![disconnect](images/disconnect.png) **Disconnect** button rather than the **Kill** button, in general.
Otherwise, each launch will create a new connection, and you will end up with several stale connections.
Additionally, if your target exits or otherwise terminates on its own, you will get a stale connection.
Use the Targets window to clean such connections up.
Use the Connections window to clean such connections up, or just type `quit` into the session's Terminal.
The re-use of connections and/or the use of multiple concurrent connections is *not* covered in this course.
## Troubleshooting
@ -151,10 +173,19 @@ If that does not work, check the top-left label of the Dynamic Listing to see wh
Also check the Debug Console window.
If you are in a system library, e.g., `ld-linux`, then this is the expected behavior.
You may optionally import it, as suggested by the Debug Console, but this is covered later.
You may also try typing into the Terminal, *one command at a time*, checking for errors after each:
```gdb
break main
continue
```
That should get you from the system entry into the target's `main` routine, assuming it has one.
Next time you launch, check the configuration and change **Run Command** to "start", not "starti".
If you are not in a system library, then check the Modules window to see if `termmines` is listed.
If so, it seems the module mapper failed to realize that module is the current program.
Right-click the module and select "Map to termmines."
Right-click the module and select **Map to termmines**.
Confirm the dialog.
If `termmines` is not listed, then your version of GDB may not be supported.
If you file a bug report, please include your GDB version, Linux distribution, and/or other platform details.
@ -165,23 +196,26 @@ There is probably a discrepancy between the version you imported and the version
This should not happen with `termmines`, but perhaps you re-ran `make` between importing and launching?
For other system libraries, this could happen if you or an administrator applied system updates since you imported.
You probably need to re-import the affected module image(s).
If this happens to you in practice, and you have substantial investment in the old import, consider using the Version Tracker to port your knowledge to the new import.
If this happens to you in practice, and you have substantial investment in the old program database, consider using the Version Tracker to port your knowledge to the new database.
### There is no step button.
This can happen if the Control Mode is set to the Trace.
This can happen if the Control Mode is set to **Control Trace**.
Perhaps you played with the Time window?
Change the Control Mode back to "Control Target."
The Control Mode drop-down is leftmost in the "Control" group, immediately right of the **Launch** and **Emulate** buttons.
Its icon differs for each mode.
Change it back to **Control Target**.
### I can step, but I don't see the effects in the Interpreter window.
### I can step, but I don't see the effects in the Terminal window.
This can happen if the Control Mode is set to the Emulator.
Change the Control Mode back to "Control Target."
This can happen if the Control Mode is set to **Control Emulator**.
See the above heading about Control Mode.
Change it back to **Control Target**.
### The Step buttons are grayed out.
The target has likely terminated, or you have not selected a thread.
Check the Threads window.
Check the Threads window or the Model window.
If it is empty, re-launch, and perhaps look at the Troubleshooting section in [Getting Started](A1-GettingStarted.md)
## Exercise: Step Around
@ -190,4 +224,4 @@ If you were not already following along with an instructor, then try some of the
One of the first subroutines called in `termmines` parses command-line arguments.
Try stepping until you have entered that subroutine.
**TIP**: Use the Decompiler to help you recognize when you have entered the command-line parsing subroutine.
Alternatively, use the Static Listing and Decompiler to identify the parsing subroutine (as you would in the CodeBrowser), and then use the Step buttons to drive the target into it.
Alternatively, use the Static Listing and Decompiler to identify the parsing subroutine (as you would in the CodeBrowser), and then use the **Step** buttons to drive the target into it.

View File

@ -158,28 +158,24 @@ several ways to set a new breakpoint:</p>
<li>From any static or dynamic listing window, including Disassembly,
Memory/Hex, and the Decompiler, right-click and select <img
src="images/breakpoint-enable.png" alt="set breakpoint" /> Set
Breakpoint, press <strong>K</strong> on the keyboard, or double-click
the margin.</li>
<li>From the Objects window click the <img
src="images/breakpoint-enable.png" alt="add breakpoint" /> Add
Breakpoint button or press <strong>F3</strong> on the keyboard.</li>
<li>From the Interpreter window, use the GDB command, e.g.,
Breakpoint, press <strong><code>K</code></strong> on the keyboard, or
double-click the margin.</li>
<li>From the Terminal window, use the GDB command, e.g.,
<code>break main</code>.</li>
</ol>
<p>The advantage of using the listings is that you can quickly set a
breakpoint at any address. The advantage of using the Objects or
Interpreter window is that you can specify something other than an
address. Often, those specifications still resolve to addresses, and
Ghidra will display them. Ghidra will memorize breakpoints by recording
them as special bookmarks in the imported program. There is some
iconography to communicate the various states of a breakpoint. When all
is well and normal, you should only see enabled <img
src="images/breakpoint-enable.png" alt="enabled breakpoint" /> and
disabled <img src="images/breakpoint-disable.png"
alt="disabled breakpoint" /> breakpoints. If the target is terminated
(or not launched yet), you may also see ineffective <img
src="images/breakpoint-enable-ineff.png" alt="ineffective breakpoint" />
breakpoints.</p>
breakpoint at any address. The advantage of using the Terminal window is
that you can specify something other than an address. Often, those
specifications still resolve to addresses, and Ghidra will display them.
Ghidra will memorize breakpoints by recording them as special bookmarks
in the program database. There is some iconography to communicate the
various states of a breakpoint. When all is well and normal, you should
only see enabled <img src="images/breakpoint-enable.png"
alt="enabled breakpoint" /> and disabled <img
src="images/breakpoint-disable.png" alt="disabled breakpoint" />
breakpoints. If the target is terminated (or not launched yet), you may
also see ineffective <img src="images/breakpoint-enable-ineff.png"
alt="ineffective breakpoint" /> breakpoints.</p>
</section>
<section id="examining-minesweeper-board-setup" class="level2">
<h2>Examining Minesweeper Board Setup</h2>
@ -195,7 +191,7 @@ breakpoint on <code>rand</code> will help us find the algorithm that
places the mines.</p>
<section id="set-the-breakpoints" class="level3">
<h3>Set the Breakpoints</h3>
<p>In the Interpreter, type the GDB commands to set breakpoints on
<p>In the Terminal, type the GDB commands to set breakpoints on
<code>srand</code> and <code>rand</code>:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode gdb"><code class="sourceCode gdbsyntax"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="kw">break</span> srand</span>
@ -208,15 +204,15 @@ alt="Populated breakpoints window" />
</figure>
<p>For a single target, the lower panel of the Breakpoints window does
not add much information, but it does have some. We will start with the
top panel. This lists the “logical” breakpoints, preferring static
addresses.</p>
top panel. This lists the <em>logical</em> breakpoints, preferring
static addresses.</p>
<ul>
<li>The left-most column <strong>Enabled</strong> indicates the
<li>The left-most column <strong>State</strong> indicates the
breakpoints state. Here, we see the inconsistent <img
src="images/breakpoint-overlay-inconsistent.png" alt="inconsistent" />
overlay, because Ghidra cannot save the breakpoint without a module
image. That is because <code>srand</code> and <code>rand</code> are in a
different module, and we have not yet imported it into Ghidra.</li>
overlay, because Ghidra cannot save the breakpoint without a program
database. That is because <code>srand</code> and <code>rand</code> are
in a different module, and we have not yet imported it into Ghidra.</li>
<li>The next column <strong>Name</strong> is the name of the breakpoint.
This is for informational purposes only. You can rename a breakpoint
however you like, and it will have no effect on the target nor back-end
@ -227,44 +223,43 @@ breakpoints were specified by symbol. Typically, this is the
<em>static</em> address of the breakpoint; however, if the module image
is not imported, yet, this will be the <em>dynamic</em> address, subject
to relocation or ASLR.</li>
<li>The next column <strong>Image</strong> gives the name of the
imported image containing the breakpoint. Again, because the module has
not been imported yet, this column is blank.</li>
<li>The next column <strong>Image</strong> gives the name of the program
database containing the breakpoint. Again, because the module has not
been imported yet, this column is blank.</li>
<li>The next column <strong>Length</strong> gives the length of the
breakpoint. In GDB, this generally applies to watchpoints only.</li>
<li>The next column <strong>Kinds</strong> gives the kinds of
breakpoint. Most breakpoints are software execution breakpoints,
indicated by “SW_EXECUTE.” That is, they are implemented by patching the
targets memory with a special instruction (<code>INT3</code> on x86)
that traps execution. There are also hardware execution breakpoints
targets memory with a special instruction that traps execution —
<code>INT3</code> on x86. There are also hardware execution breakpoints
indicated by “HW_EXECUTE,” and access breakpoints indicated by “HW_READ”
and/or “HW_WRITE”. <strong>NOTE</strong>: GDB would call these
“watchpoints.” An advantage to software breakpoints is that you can have
a practically unlimited number of them. Some disadvantages are they can
be detected easily, and they are limited to execution breakpoints.</li>
and/or “HW_WRITE”. <strong>NOTE</strong>: GDB would call access
breakpoints <em>watchpoints</em>. An advantage to software breakpoints
is that you can have a practically unlimited number of them. Some
disadvantages are they can be detected easily, and they are limited to
execution breakpoints.</li>
<li>The next column <strong>Locations</strong> counts the number of
locations for the breakpoint. For a single-target session, this should
always be 1.</li>
locations for the breakpoint. For a single-target session, this is most
likely 1.</li>
<li>The final column <strong>Sleigh</strong> is only applicable to the
emulator. It indicates that the breakpoints behavior has been
customized with Sleigh code. This is covered in <a
href="B2-Emulation.html">Emulation</a>.</li>
</ul>
<p>Now, we move to the bottom panel. This lists the breakpoint
locations, as reported by the back-end debugger(s). The Enabled,
Address, and Sleigh columns are the same as the top, but for the
individual <em>dynamic</em> addresses.</p>
locations, as reported by the back-end debugger(s). The State, Address,
and Sleigh columns are the same as the top, but for the individual
<em>dynamic</em> addresses.</p>
<ul>
<li>The <strong>Name</strong> column is the name as designated by the
back-end.</li>
<li>The <strong>Trace</strong> column indicates which target contains
the location. The text here should match one of the tabs from the
Threads panel.</li>
Dynamic Listing panel.</li>
<li>The <strong>Comment</strong> column is a user-defined comment. Its
default value is the specification that generated it, e.g.,
<code>srand</code>.</li>
<li>The <strong>Threads</strong> column indicates if the breakpoint is
scoped to a limited set of threads. Its use is atypical.</li>
</ul>
</section>
<section id="toggling-the-breakpoints" class="level3">
@ -274,25 +269,35 @@ good time to demonstrate the feature. There are several ways to toggle a
breakpoint:</p>
<ol type="1">
<li>In any listing, as in setting a breakpoint, right-click and select a
toggle action, press <strong>K</strong> on the keyboard, or double-click
its icon in the margin.</li>
<li>From the Objects window, expand the Breakpoints node, right-click a
breakpoint and select Toggle or press <strong>T</strong> on the
keyboard.</li>
toggle action, press <strong><code>K</code></strong> on the keyboard, or
double-click its icon in the margin.</li>
<li>From the Model window, expand the <em>Breakpoints</em> node and
double-click a breakpoint, or select one with the keyboard and press
<strong><code>ENTER</code></strong>.</li>
<li>From the Breakpoints window, single-click the breakpoints status
icon, right-click an entry and select a toggle action, or create a
selection and use a toggling action from the local toolbar. Either panel
works, but the top panel is preferred to keep the breakpoints
consistent. The local toolbar also has actions for toggling all
breakpoints in the session.</li>
<li>From the Interpreter window, use the GDB commands, e.g.,
<li>From the Terminal window, use the GDB commands, e.g.,
<code>disable 2</code>.</li>
</ol>
<p>Practice toggling them. Notice that no matter how you toggle the
breakpoints, the display updates. You might also type
<code>info break</code> into the Interpreter to confirm the effect of
<code>info break</code> into the Terminal to confirm the effect of
toggling breakpoints in the GUI. When you are finished, ensure both
breakpoints are enabled.</p>
<p><strong>NOTE</strong>: In all parts of the GUI, except the Model
window, Ghidra prefers to toggle breakpoint locations. Without getting
into details, this is the second level down of breakpoints shown in the
Model tree. If you set a breakpoint, and GDB calls this breakpoint 2,
then you toggle it in the listing, Ghidra will toggle, e.g., breakpoint
<em>location</em> 2.1, not the breakpoint <em>specification</em> 2. If
you disable breakpoint 2 using the Model or Terminal window, it may
become impossible to toggle the breakpoint in the Listing or Breakpoints
windows. If you find your session in this condition, just re-enable the
troublesome breakpoints in the Model or Terminal window.</p>
</section>
<section id="importing-libc" class="level3">
<h3>Importing <code>libc</code></h3>
@ -323,13 +328,32 @@ CodeBrowser.</p></li>
<p>Once imported, the Breakpoints window should update to reflect the
static addresses, the breakpoints should become consistent, and the
Static Listing should now be synchronized when navigating within
<code>libc</code>.</p>
<code>libc</code>. <strong>NOTE</strong>: Ghidra has not automatically
disassembled the dynamic listing, because the program counter has not
actually landed there, yet.</p>
<figure>
<img src="images/Breakpoints_SyncedAfterImportLibC.png"
alt="The debugger tool with breakpoints synchronized after importing libc" />
<figcaption aria-hidden="true">The debugger tool with breakpoints
synchronized after importing libc</figcaption>
</figure>
<section id="troubleshooting" class="level4">
<h4>Troubleshooting</h4>
<p>If it seems nothing has changed, except now you have a second program
database open, then the new module may not be successfully mapped.</p>
<ol type="1">
<li>Re-check the Debug Console window and verify the note has been
removed.</li>
<li>If not, it might be because the module is symlinked in the file
system, so the name of the module and the name of the program database
do not match.</li>
<li>Ensure that <code>libc</code> is the current program (tab) in the
Static Listing.</li>
<li>In the Modules window, right-click on <code>libc</code>, and select
<strong>Map Module to libc</strong>. (Names and titles will likely
differ.)</li>
</ol>
</section>
</section>
<section id="capturing-the-random-seed" class="level3">
<h3>Capturing the Random Seed</h3>
@ -388,18 +412,27 @@ course.</p>
</section>
<section id="exercise-diagram-the-mines" class="level3">
<h3>Exercise: Diagram the Mines</h3>
<p>You goal is to capture the location of all the mines. So that you can
check your work later, you should run <code>termmines</code> in a
terminal and attach to it from Ghidra. You will probably want to disable
the breakpoints on <code>rand</code> and <code>srand</code> for now.
Devise a strategy using breakpoints and the control buttons (Step,
Resume, etc.) so that you can observe the location of each mine. Use pen
and paper to draw a diagram of the board, and mark the location of each
mine as you observe the algorithm placing it. There should only be 10
mines in Beginner mode. Once the mines are placed, press <img
src="images/resume.png" alt="resume" /> Resume. Check you work by
winning the game. Alternatively, you can intentionally lose to have the
game reveal the mines.</p>
<p>You goal is to capture the location of all the mines. You will
probably want to disable the breakpoints on <code>rand</code> and
<code>srand</code> for now. Devise a strategy using breakpoints and the
control buttons (Step, Resume, etc.) so that you can observe the
location of each mine. Use pen and paper to draw a diagram of the board,
and mark the location of each mine as you observe the algorithm placing
it. There should only be 10 mines in Beginner mode. Once the mines are
placed, press <img src="images/resume.png" alt="resume" /> Resume. Check
you work by winning the game. Alternatively, you can intentionally lose
to have the game reveal the mines.</p>
<section id="troubleshooting-1" class="level4">
<h4>Troubleshooting</h4>
<p>You may find that running both GDB and <code>termmines</code> in the
same Terminal makes viewing the game board difficult. The next time you
launch, be sure to use the <strong>Configure and Launch</strong>
sub-menu, then enable the <strong>Inferior TTY</strong> option. This
should start two Terminals, one with GDB and a second dedicated to
<code>termmines</code>. The game board will no longer be corrupted by
GDBs prompts and diagnostics. You will probably want to undock the
<code>termmines</code> Terminal and resize it to fit the board.</p>
</section>
</section>
<section id="optional-exercise-replicate-the-boards-forward-engineering"
class="level3">
@ -412,77 +445,11 @@ the placement algorithm, we can perfectly replicate the sequence of game
boards for any <code>termmines</code> session.</p>
<p>Write a program that takes a seed from the user and prints a diagram
of the first game board with the mines indicated. Optionally, have it
print each subsequent game board when the user presses ENTER. Check your
work by re-launching <code>termmines</code> (see note about attaching
below), capturing its seed, inputting it into your program, and then
winning the game. Optionally, win 2 more games in the same session.</p>
<p><strong>NOTE</strong>: We will need a more advanced attaching
technique to check your work, because you will need both to break on
<code>srand</code> (which happens early in the process execution,
ruling out our usual attach technique) and to interact with it in the
terminal (which rules out launching in Ghidra). There are a few ways
around this, including using <code>gdbserver</code> or using
<code>set inferior-tty</code>. If you are already familiar with those,
you can try one. The technique we recommend here is using a stub that
will suspend itself and then execute <code>termmines</code>. We can then
run the stub in a terminal outside of Ghidra, attach to that stub, and
then allow it to proceed into <code>termmines</code>. In this way, we
can attach to the process in the terminal before it reaches
<code>srand</code>. The stub is fairly easy to write in Bash and should
be similar in other shells.</p>
<ol type="1">
<li><p>In a terminal running Bash (see note if youre using
<code>anyptracer</code>):</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">(</span><span class="bu">echo</span> <span class="va">$BASHPID</span><span class="kw">;</span> <span class="bu">kill</span> <span class="at">-SIGSTOP</span> <span class="va">$BASHPID</span><span class="kw">;</span> <span class="bu">exec</span> ./termmines<span class="kw">)</span></span></code></pre></div>
<p>The parentheses will start <code>bash</code> in a new subprocess. The
first two commands cause it to print its own process ID and then suspend
itself. Your terminal should display the PID and report the stopped
process.</p>
<p><strong>NOTE</strong>: If you need to use the <code>anyptracer</code>
stub, then the invocation is more complicated:</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ex">./anyptracer</span> <span class="st">&#39;exec bash -c &quot;echo $BASHPID; kill -SIGSTOP $BASHPID; exec ./termmines&quot;&#39;</span></span></code></pre></div>
<p>In principle, it works the same except wrapped in the
<code>anyptracer</code> stub. The parentheses are no longer needed, nor
allowed, since <code>anyptracer</code> is already a subprocess of your
shell. If you include parentheses, you will get a second sub-subprocess
to which you cannot attach.</p></li>
<li><p>In Ghidra, follow the usual steps to attach, but use the PID
printed in your terminal. <strong>NOTE</strong>: The process is still
technically running <code>bash</code> when you attach to it.</p></li>
<li><p>In the Interpreter panel:</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode gdb"><code class="sourceCode gdbsyntax"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">break</span> main</span></code></pre></div>
<p><strong>NOTE</strong>: At this point <code>main</code> technically
refers to the symbol in <code>bash</code>, but GDB will adjust its
location once the target loads <code>termmines</code>.</p></li>
<li><p>Back in your terminal running Bash:</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="bu">fg</span></span></code></pre></div>
<p>This will cause Bash to return the stub to the foreground of the
terminal. Without this step, the system will repeatedly suspend the
process whenever it attempts any I/O on that terminal.</p></li>
<li><p>In Ghidra, press Resume (or use <code>continue</code> in the
Interpreter) until you hit the breakpoint at <code>main</code>. This
permits the stub to complete its third command
<code>exec ./termmines</code>. The <code>exec</code> command is
different than normal command execution. Instead of creating a
subprocess, it <em>replaces</em> the image of the stub process, so the
process is now running <code>termmines</code>.</p></li>
<li><p>Refresh the Modules node in the Objects window. You may need to
clear your filter text. Expand the Modules node and verify it lists
<code>termmines</code> instead of <code>bash</code>. Without this step,
your listings may go out of sync.</p></li>
</ol>
<p>At this point, you are attached to your target running in the
terminal, and you have trapped it at <code>main</code>. Because you were
attached to it when it was still <code>bash</code>, you will likely see
a lot of extraneous history. For example, the Modules panel will report
many of the modules that had been loaded by <code>bash</code>. Please
note their lifespans, however. They should correctly indicate those
modules are no longer loaded. In any case, you now have the tools needed
to check your work for this exercise.</p>
print each subsequent game board when the user presses
<strong>ENTER</strong>. Check your work by re-launching
<code>termmines</code>, capturing its seed, inputting it into your
program, and then winning the game. Optionally, win 2 more games in the
same session.</p>
</section>
</section>
</section>

View File

@ -16,14 +16,13 @@ Most likely, this window is empty if you have been following the lesson.
From here, you can toggle and delete existing breakpoints.
There are several ways to set a new breakpoint:
1. From any static or dynamic listing window, including Disassembly, Memory/Hex, and the Decompiler, right-click and select ![set breakpoint](images/breakpoint-enable.png) Set Breakpoint, press **K** on the keyboard, or double-click the margin.
1. From the Objects window click the ![add breakpoint](images/breakpoint-enable.png) Add Breakpoint button or press **F3** on the keyboard.
1. From the Interpreter window, use the GDB command, e.g., `break main`.
1. From any static or dynamic listing window, including Disassembly, Memory/Hex, and the Decompiler, right-click and select ![set breakpoint](images/breakpoint-enable.png) Set Breakpoint, press **`K`** on the keyboard, or double-click the margin.
1. From the Terminal window, use the GDB command, e.g., `break main`.
The advantage of using the listings is that you can quickly set a breakpoint at any address.
The advantage of using the Objects or Interpreter window is that you can specify something other than an address.
The advantage of using the Terminal window is that you can specify something other than an address.
Often, those specifications still resolve to addresses, and Ghidra will display them.
Ghidra will memorize breakpoints by recording them as special bookmarks in the imported program.
Ghidra will memorize breakpoints by recording them as special bookmarks in the program database.
There is some iconography to communicate the various states of a breakpoint.
When all is well and normal, you should only see enabled ![enabled breakpoint](images/breakpoint-enable.png) and disabled ![disabled breakpoint](images/breakpoint-disable.png) breakpoints.
If the target is terminated (or not launched yet), you may also see ineffective ![ineffective breakpoint](images/breakpoint-enable-ineff.png) breakpoints.
@ -40,7 +39,7 @@ The breakpoint on `rand` will help us find the algorithm that places the mines.
### Set the Breakpoints
In the Interpreter, type the GDB commands to set breakpoints on `srand` and `rand`:
In the Terminal, type the GDB commands to set breakpoints on `srand` and `rand`:
```gdb
break srand
@ -53,10 +52,10 @@ The breakpoint window should now be updated:
For a single target, the lower panel of the Breakpoints window does not add much information, but it does have some.
We will start with the top panel.
This lists the "logical" breakpoints, preferring static addresses.
This lists the *logical* breakpoints, preferring static addresses.
* The left-most column **Enabled** indicates the breakpoint's state.
Here, we see the inconsistent ![inconsistent](images/breakpoint-overlay-inconsistent.png) overlay, because Ghidra cannot save the breakpoint without a module image.
* The left-most column **State** indicates the breakpoint's state.
Here, we see the inconsistent ![inconsistent](images/breakpoint-overlay-inconsistent.png) overlay, because Ghidra cannot save the breakpoint without a program database.
That is because `srand` and `rand` are in a different module, and we have not yet imported it into Ghidra.
* The next column **Name** is the name of the breakpoint.
This is for informational purposes only.
@ -64,51 +63,55 @@ This lists the "logical" breakpoints, preferring static addresses.
* The next column **Address** gives the address of the breakpoint.
Notice that the addresses were resolved, even though the breakpoints were specified by symbol.
Typically, this is the *static* address of the breakpoint; however, if the module image is not imported, yet, this will be the *dynamic* address, subject to relocation or ASLR.
* The next column **Image** gives the name of the imported image containing the breakpoint.
* The next column **Image** gives the name of the program database containing the breakpoint.
Again, because the module has not been imported yet, this column is blank.
* The next column **Length** gives the length of the breakpoint.
In GDB, this generally applies to watchpoints only.
* The next column **Kinds** gives the kinds of breakpoint.
Most breakpoints are software execution breakpoints, indicated by "SW_EXECUTE."
That is, they are implemented by patching the target's memory with a special instruction (`INT3` on x86) that traps execution.
That is, they are implemented by patching the target's memory with a special instruction that traps execution &mdash; `INT3` on x86.
There are also hardware execution breakpoints indicated by "HW_EXECUTE," and access breakpoints indicated by "HW_READ" and/or "HW_WRITE".
**NOTE**: GDB would call these "watchpoints."
**NOTE**: GDB would call access breakpoints *watchpoints*.
An advantage to software breakpoints is that you can have a practically unlimited number of them. Some disadvantages are they can be detected easily, and they are limited to execution breakpoints.
* The next column **Locations** counts the number of locations for the breakpoint.
For a single-target session, this should always be 1.
For a single-target session, this is most likely 1.
* The final column **Sleigh** is only applicable to the emulator.
It indicates that the breakpoint's behavior has been customized with Sleigh code.
This is covered in [Emulation](B2-Emulation.md).
Now, we move to the bottom panel.
This lists the breakpoint locations, as reported by the back-end debugger(s).
The Enabled, Address, and Sleigh columns are the same as the top, but for the individual *dynamic* addresses.
The State, Address, and Sleigh columns are the same as the top, but for the individual *dynamic* addresses.
* The **Name** column is the name as designated by the back-end.
* The **Trace** column indicates which target contains the location.
The text here should match one of the tabs from the Threads panel.
The text here should match one of the tabs from the Dynamic Listing panel.
* The **Comment** column is a user-defined comment.
Its default value is the specification that generated it, e.g., `srand`.
* The **Threads** column indicates if the breakpoint is scoped to a limited set of threads.
Its use is atypical.
### Toggling the Breakpoints
While there is no need to toggle the breakpoints right now, it is a good time to demonstrate the feature.
There are several ways to toggle a breakpoint:
1. In any listing, as in setting a breakpoint, right-click and select a toggle action, press **K** on the keyboard, or double-click its icon in the margin.
1. From the Objects window, expand the Breakpoints node, right-click a breakpoint and select Toggle or press **T** on the keyboard.
1. In any listing, as in setting a breakpoint, right-click and select a toggle action, press **`K`** on the keyboard, or double-click its icon in the margin.
1. From the Model window, expand the *Breakpoints* node and double-click a breakpoint, or select one with the keyboard and press **`ENTER`**.
1. From the Breakpoints window, single-click the breakpoint's status icon, right-click an entry and select a toggle action, or create a selection and use a toggling action from the local toolbar.
Either panel works, but the top panel is preferred to keep the breakpoints consistent.
The local toolbar also has actions for toggling all breakpoints in the session.
1. From the Interpreter window, use the GDB commands, e.g., `disable 2`.
1. From the Terminal window, use the GDB commands, e.g., `disable 2`.
Practice toggling them.
Notice that no matter how you toggle the breakpoints, the display updates.
You might also type `info break` into the Interpreter to confirm the effect of toggling breakpoints in the GUI.
You might also type `info break` into the Terminal to confirm the effect of toggling breakpoints in the GUI.
When you are finished, ensure both breakpoints are enabled.
**NOTE**: In all parts of the GUI, except the Model window, Ghidra prefers to toggle breakpoint locations.
Without getting into details, this is the second level down of breakpoints shown in the Model tree.
If you set a breakpoint, and GDB calls this breakpoint 2, then you toggle it in the listing, Ghidra will toggle, e.g., breakpoint *location* 2.1, not the breakpoint *specification* 2.
If you disable breakpoint 2 using the Model or Terminal window, it may become impossible to toggle the breakpoint in the Listing or Breakpoints windows.
If you find your session in this condition, just re-enable the troublesome breakpoints in the Model or Terminal window.
### Importing `libc`
While the Debugger can operate without importing external modules, it generally works better when you have.
@ -128,9 +131,19 @@ You could do this in the usual manner, but the Debugger offers a convenient way
1. Proceed with the import and initial analysis as you would in the CodeBrowser.
Once imported, the Breakpoints window should update to reflect the static addresses, the breakpoints should become consistent, and the Static Listing should now be synchronized when navigating within `libc`.
**NOTE**: Ghidra has not automatically disassembled the dynamic listing, because the program counter has not actually landed there, yet.
![The debugger tool with breakpoints synchronized after importing libc](images/Breakpoints_SyncedAfterImportLibC.png)
#### Troubleshooting
If it seems nothing has changed, except now you have a second program database open, then the new module may not be successfully mapped.
1. Re-check the Debug Console window and verify the note has been removed.
1. If not, it might be because the module is symlinked in the file system, so the name of the module and the name of the program database do not match.
1. Ensure that `libc` is the current program (tab) in the Static Listing.
1. In the Modules window, right-click on `libc`, and select **Map Module to libc**. (Names and titles will likely differ.)
### Capturing the Random Seed
We can now allow `termmines` to execute, expecting it to hit the `srand` breakpoint first.
@ -178,7 +191,6 @@ The advantages of a dynamic session along side static analysis should become mor
### Exercise: Diagram the Mines
You goal is to capture the location of all the mines.
So that you can check your work later, you should run `termmines` in a terminal and attach to it from Ghidra.
You will probably want to disable the breakpoints on `rand` and `srand` for now.
Devise a strategy using breakpoints and the control buttons (Step, Resume, etc.) so that you can observe the location of each mine.
Use pen and paper to draw a diagram of the board, and mark the location of each mine as you observe the algorithm placing it.
@ -187,6 +199,14 @@ Once the mines are placed, press ![resume](images/resume.png) Resume.
Check you work by winning the game.
Alternatively, you can intentionally lose to have the game reveal the mines.
#### Troubleshooting
You may find that running both GDB and `termmines` in the same Terminal makes viewing the game board difficult.
The next time you launch, be sure to use the **Configure and Launch** sub-menu, then enable the **Inferior TTY** option.
This should start two Terminals, one with GDB and a second dedicated to `termmines`.
The game board will no longer be corrupted by GDB's prompts and diagnostics.
You will probably want to undock the `termmines` Terminal and resize it to fit the board.
### Optional Exercise: Replicate the Boards (Forward Engineering)
You will need a C development environment for this exercise.
@ -194,58 +214,6 @@ Because, as we have now confirmed, `termmines` is importing its random number ge
Further, because we can capture the seed, and we know the placement algorithm, we can perfectly replicate the sequence of game boards for any `termmines` session.
Write a program that takes a seed from the user and prints a diagram of the first game board with the mines indicated.
Optionally, have it print each subsequent game board when the user presses ENTER.
Check your work by re-launching `termmines` (see note about attaching below), capturing its seed, inputting it into your program, and then winning the game.
Optionally, have it print each subsequent game board when the user presses **ENTER**.
Check your work by re-launching `termmines`, capturing its seed, inputting it into your program, and then winning the game.
Optionally, win 2 more games in the same session.
**NOTE**: We will need a more advanced attaching technique to check your work, because you will need both to break on `srand` (which happens early in the process' execution, ruling out our usual attach technique) and to interact with it in the terminal (which rules out launching in Ghidra).
There are a few ways around this, including using `gdbserver` or using `set inferior-tty`.
If you are already familiar with those, you can try one.
The technique we recommend here is using a stub that will suspend itself and then execute `termmines`.
We can then run the stub in a terminal outside of Ghidra, attach to that stub, and then allow it to proceed into `termmines`.
In this way, we can attach to the process in the terminal before it reaches `srand`.
The stub is fairly easy to write in Bash and should be similar in other shells.
1. In a terminal running Bash (see note if you're using `anyptracer`):
```bash
(echo $BASHPID; kill -SIGSTOP $BASHPID; exec ./termmines)
```
The parentheses will start `bash` in a new subprocess.
The first two commands cause it to print its own process ID and then suspend itself.
Your terminal should display the PID and report the stopped process.
**NOTE**: If you need to use the `anyptracer` stub, then the invocation is more complicated:
```bash
./anyptracer 'exec bash -c "echo $BASHPID; kill -SIGSTOP $BASHPID; exec ./termmines"'
```
In principle, it works the same except wrapped in the `anyptracer` stub.
The parentheses are no longer needed, nor allowed, since `anyptracer` is already a subprocess of your shell.
If you include parentheses, you will get a second sub-subprocess to which you cannot attach.
1. In Ghidra, follow the usual steps to attach, but use the PID printed in your terminal.
**NOTE**: The process is still technically running `bash` when you attach to it.
1. In the Interpreter panel:
```gdb
break main
```
**NOTE**: At this point `main` technically refers to the symbol in `bash`, but GDB will adjust its location once the target loads `termmines`.
1. Back in your terminal running Bash:
```bash
fg
```
This will cause Bash to return the stub to the foreground of the terminal.
Without this step, the system will repeatedly suspend the process whenever it attempts any I/O on that terminal.
1. In Ghidra, press Resume (or use `continue` in the Interpreter) until you hit the breakpoint at `main`.
This permits the stub to complete its third command `exec ./termmines`.
The `exec` command is different than normal command execution.
Instead of creating a subprocess, it *replaces* the image of the stub process, so the process is now running `termmines`.
1. Refresh the Modules node in the Objects window.
You may need to clear your filter text.
Expand the Modules node and verify it lists `termmines` instead of `bash`.
Without this step, your listings may go out of sync.
At this point, you are attached to your target running in the terminal, and you have trapped it at `main`.
Because you were attached to it when it was still `bash`, you will likely see a lot of extraneous history.
For example, the Modules panel will report many of the modules that had been loaded by `bash`.
Please note their lifespans, however.
They should correctly indicate those modules are no longer loaded.
In any case, you now have the tools needed to check your work for this exercise.

View File

@ -107,7 +107,7 @@ not, please refer to the previous modules.</p>
<p>This module will address the following features in more depth:</p>
<ul>
<li>Dynamic Listing window</li>
<li>Dynamic Bytes window</li>
<li>Dynamic Bytes (Memory) window</li>
<li>Registers window</li>
<li>Watches window</li>
<li>Sleigh expressions</li>
@ -154,10 +154,10 @@ may present tables with editable cells. These will often include a
accidental patching. Furthermore, you must use the <img
src="images/record.png" alt="control mode" /> Control Mode toggle in the
global toolbar (next to the control actions) to enable patching
throughout the Debugger tool. For now, please only use the “Control
Target” and “Control Target w/ Edits Disabled” options. The write toggle
is included here so that actions like copy-paste do not lead to
accidental patching.</p>
throughout the Debugger tool. For now, please only use the
<strong>Control Target</strong> and <strong>Control Target w/ Edits
Disabled</strong> options. The write toggle is included here so that
actions like copy-paste do not lead to accidental patching.</p>
</section>
</section>
<section id="the-dynamic-listing" class="level2">
@ -190,19 +190,19 @@ Location drop-down and select <strong>Track Stack Pointer</strong>. The
window should seek to (and highlight in pale green) the address in the
stack pointer. Since the target has just entered <code>main</code>, we
should expect a return address at the top of the stack. With your cursor
at the stack pointer, press <strong>P</strong> to place a pointer there,
just like you would in the Static Listing. You can now navigate to that
address by double-clicking it. To return to the stack pointer, you can
use the back arrow in the global toolbar, you can click the <img
src="images/register-marker.png" alt="track location" /> Track Location
button, or you can double-click the <code>sp = [Address]</code> label in
the top right of the Dynamic Listing.</p>
at the stack pointer, press <strong><code>P</code></strong> to place a
pointer there, just like you would in the Static Listing. You can now
navigate to that address by double-clicking it. To return to the stack
pointer, you can use the back arrow in the global toolbar, you can click
the <img src="images/register-marker.png" alt="track location" /> Track
Location button, or you can double-click the <code>sp = [Address]</code>
label in the top right of the Dynamic Listing.</p>
<p>To examine a more complicated stack segment, we will break at
<code>rand</code>. Ensure your breakpoint at <code>rand</code> is
enabled and press <img src="images/resume.png" alt="resume" /> Resume.
Your Dynamic Listing should follow the stack pointer. In the menus,
select <strong>Debugger → Analysis → Unwind Stack</strong> or press
<strong>U</strong>.</p>
select <strong>Debugger → Analysis → Unwind from frame 0</strong> or
press <strong><code>U</code></strong>.</p>
<figure>
<img src="images/State_ListingStackAfterCallRand.png"
alt="The dynamic listing of the stack after a call to rand" />
@ -231,9 +231,9 @@ snapshots of the machine state, discussed later in this module.</p>
<section id="cache-status-indication" class="level3">
<h3>Cache Status Indication</h3>
<p>The listings contents are read from a live target, which may become
unresponsive or otherwise temperamental. The Debugger uses a database,
which acts as a cache separating the GUI from the live target. The UI
requests memory pages from the target, the target asynchronously
unresponsive or otherwise temperamental. The Debugger uses a trace
database, which acts as a cache separating the GUI from the live target.
The UI requests memory pages from the target, the target asynchronously
retrieves those pages and stores them into the database, then the
database updates the UI. This sequence does not always go as expected;
thus, pages with stale data are displayed with a grey background. This
@ -241,8 +241,8 @@ may also happen if auto-read is disabled. Typically, user-space targets
are not so temperamental, but others may be, or memory reads could be
expensive, in which case disabling automatic memory reads may be
advantageous. If the back-end debugger reports an error while reading
memory, the first address of the page will have a red background. To
refresh the visible or selected page(s), click the
memory, the page will have a red background. To refresh the visible or
selected page(s), click the
<img alt="refresh" src="images/view-refresh.png" width="16px"/> Refresh
button. Examine the Debug Console window for errors / warnings before
spamming this button. To toggle auto read, use the
@ -269,12 +269,12 @@ memory map.</p>
</section>
<section id="go-to" class="level3">
<h3>Go To</h3>
<p>The Go To action in the Dynamic Listing differs from the one in the
Static Listing. Like the static one, it accepts an address in
hexadecimal, possibly prefixed with the address space and a colon.
However, it also accepts Sleigh expressions, allowing you to treat
<code>RAX</code> as a pointer and go to that address, for example. We
cover Sleigh expressions later in this module.</p>
<p>The <strong>Go To</strong> action in the Dynamic Listing differs from
the one in the Static Listing. Like the static one, it accepts an
address in hexadecimal, possibly prefixed with the address space and a
colon. However, it also accepts Sleigh expressions, allowing you to
treat <code>RAX</code> as a pointer and go to that address, for example.
We cover Sleigh expressions later in this module.</p>
</section>
<section id="compare" class="level3">
<h3>Compare</h3>
@ -315,12 +315,12 @@ alt="The dynamic memory view of the stack after a call to rand" />
after a call to rand</figcaption>
</figure>
<p>Just as the Dynamic Listing is the analog of the Static Listing, the
Memory viewer is the analog of the Byte viewer. It is not visible by
default. To open it, use <strong>Windows → Byte Viewer → Memory
</strong> in the menus. Its default configuration should be Auto PC,
the same as the Dynamic Listings default. It has all the same
additional Debugger features as the Dynamic Listing. Furthermore, bytes
that have changed are displayed in red text.</p>
Memory viewer is the analog of the Bytes viewer. To open it, use
<strong>Windows → Byte Viewer → Memory</strong> in the menus. Its
default configuration should be Auto PC, the same as the Dynamic
Listings default. It has all the same additional Debugger features as
the Dynamic Listing. Furthermore, bytes that have changed are displayed
in red text.</p>
<section id="exercise-display-the-board-in-hex" class="level3">
<h3>Exercise: Display the Board in Hex</h3>
<p>This is a bit quick and dirty, but it works and can be useful. Your
@ -401,16 +401,17 @@ srand</figcaption>
expressions. This can provide an alternative to the Registers window
when you are really only interested in a couple of registers. It can
also watch values in memory. Furthermore, when a watch has a memory
address, the expression will appear as an option in the Location
Tracking menus of the Listing and Memory viewers. Selecting that option
will cause the window to follow that watch as its address changes.</p>
address, the expression will appear as an option in the <strong>Location
Tracking</strong> menus of the Listing and Memory viewers. Selecting
that option will cause the window to follow that watch as its address
changes.</p>
<p>To add a watch, click the <img src="images/add.png" alt="add" /> Add
button. A new entry will appear. Double-click the left-most cell of the
row to set or edit the Sleigh expression. For starters, try something
like <code>RDI</code>. (Conventionally, this is the location for the
first parameter on Linux x86-64 systems.) The context menus for the
Listing and Registers windows include a “Watch” action, which adds the
current selection to the Watches window.</p>
Listing and Registers windows include a <strong>Watch</strong> action,
which adds the current selection to the Watches window.</p>
<p>The columns are:</p>
<ul>
<li>The <strong>Expression</strong> column is the user-defined Sleigh
@ -420,7 +421,8 @@ value, if applicable. This may be in <code>register</code> space.
Double-clicking this cell will go to the address in the Dynamic
Listing.</li>
<li>The <strong>Symbol</strong> column gives the symbol in a mapped
static image closest to or containing the address, if applicable.</li>
program database closest to or containing the address, if
applicable.</li>
<li>The <strong>Value</strong> column gives the “raw” value of the
expression. If the result is in memory, it displays a byte array;
otherwise, it displays an integer.</li>
@ -436,13 +438,14 @@ evaluating the expression.</li>
</section>
<section id="sleigh-expressions" class="level2">
<h2>Sleigh Expressions</h2>
<p>Watches and Go-To commands are expressed using Ghidras Sleigh
language. More precisely, expressions are the sub-language of Sleigh for
the right-hand side of assignment statements in semantic sections. If
you already know this language, then there is little more to learn. Of
note, you may use labels from mapped program images in your expression.
For example, to see how far a return address is into <code>main</code>,
you could use <code>*:8 RSP - main</code>.</p>
<p>Watches and Go-To commands are expressed using Ghidras
<em>Sleigh</em> language. More precisely, expressions are the
sub-language of Sleigh for the right-hand side of assignment statements
in semantic sections. If you already know this language, then there is
little more to learn. Of note, you may use labels from mapped program
databases in your expression. For example, to see how far a return
address is into <code>main</code>, you could use
<code>*:8 RSP - main</code>.</p>
<p>For the complete specification, see the Semantic Section in the <a
href="../../../Ghidra/Features/Decompiler/src/main/doc/sleigh.xml">Sleigh
documentation</a>.</p>
@ -521,7 +524,7 @@ array. To read memory:</p>
<li><strong>Dereference</strong>: <code>*:8 RSP</code> or
<code>*[ram]:8 RSP</code></li>
</ul>
<p><strong>NOTE</strong> The <code>[ram]</code> part is optional. On
<p><strong>NOTE</strong>: The <code>[ram]</code> part is optional. On
x86, you will rarely if ever specify the space, since there is only one
physical RAM space. The <code>:8</code> part specifies the number of
bytes to read from memory. It is also optional, but only if the size can
@ -636,7 +639,7 @@ variable, e.g., <code>7fffffffe618</code></li>
<li><strong>Bytes</strong>: The raw bytes currently stored in the memory
allocated to the variable</li>
<li><strong>Integer</strong>: The “raw” integer value of the variable,
rendered with varyied signedness and radix</li>
rendered with varied signedness and radix</li>
<li><strong>Value</strong>: The value of the variable, according to its
type</li>
<li><strong>Instruction</strong>: If the variable points to code, the

View File

@ -8,7 +8,7 @@ If not, please refer to the previous modules.
This module will address the following features in more depth:
* Dynamic Listing window
* Dynamic Bytes window
* Dynamic Bytes (Memory) window
* Registers window
* Watches window
* Sleigh expressions
@ -41,7 +41,7 @@ Edits in any *static* window will **not** patch the live target; they modify the
Some dynamic windows may present tables with editable cells.
These will often include a *write-lock* toggle, like the static Byte viewer, to avoid accidental patching.
Furthermore, you must use the ![control mode](images/record.png) Control Mode toggle in the global toolbar (next to the control actions) to enable patching throughout the Debugger tool.
For now, please only use the "Control Target" and "Control Target w/ Edits Disabled" options.
For now, please only use the **Control Target** and **Control Target w/ Edits Disabled** options.
The write toggle is included here so that actions like copy-paste do not lead to accidental patching.
## The Dynamic Listing
@ -65,7 +65,7 @@ Now, we will examine the stack segment.
Click the ![location tracking](images/register-marker.png) Track Location drop-down and select **Track Stack Pointer**.
The window should seek to (and highlight in pale green) the address in the stack pointer.
Since the target has just entered `main`, we should expect a return address at the top of the stack.
With your cursor at the stack pointer, press **P** to place a pointer there, just like
With your cursor at the stack pointer, press **`P`** to place a pointer there, just like
you would in the Static Listing.
You can now navigate to that address by double-clicking it.
To return to the stack pointer, you can use the back arrow in the global toolbar, you can click the ![track location](images/register-marker.png) Track Location button, or you can double-click the `sp = [Address]` label in the top right of the Dynamic Listing.
@ -73,7 +73,7 @@ To return to the stack pointer, you can use the back arrow in the global toolbar
To examine a more complicated stack segment, we will break at `rand`.
Ensure your breakpoint at `rand` is enabled and press ![resume](images/resume.png) Resume.
Your Dynamic Listing should follow the stack pointer.
In the menus, select **Debugger &rarr; Analysis &rarr; Unwind from frame 0** or press **U**.
In the menus, select **Debugger &rarr; Analysis &rarr; Unwind from frame 0** or press **`U`**.
![The dynamic listing of the stack after a call to rand](images/State_ListingStackAfterCallRand.png)
@ -93,12 +93,12 @@ The dynamic listing offers several additional features:
### Cache Status Indication
The listing's contents are read from a live target, which may become unresponsive or otherwise temperamental.
The Debugger uses a database, which acts as a cache separating the GUI from the live target.
The Debugger uses a trace database, which acts as a cache separating the GUI from the live target.
The UI requests memory pages from the target, the target asynchronously retrieves those pages and stores them into the database, then the database updates the UI.
This sequence does not always go as expected; thus, pages with stale data are displayed with a grey background.
This may also happen if auto-read is disabled.
Typically, user-space targets are not so temperamental, but others may be, or memory reads could be expensive, in which case disabling automatic memory reads may be advantageous.
If the back-end debugger reports an error while reading memory, the first address of the page will have a red background.
If the back-end debugger reports an error while reading memory, the page will have a red background.
To refresh the visible or selected page(s), click the <img alt="refresh" src="images/view-refresh.png" width="16px"/> Refresh button.
Examine the Debug Console window for errors / warnings before spamming this button.
To toggle auto read, use the <img src="images/autoread.png" alt="auto-read" width="16px"/> Auto-Read drop-down button from the local toolbar.
@ -119,7 +119,7 @@ This can happen when the cursor is outside any known region, which only happens
### Go To
The Go To action in the Dynamic Listing differs from the one in the Static Listing.
The **Go To** action in the Dynamic Listing differs from the one in the Static Listing.
Like the static one, it accepts an address in hexadecimal, possibly prefixed with the address space and a colon.
However, it also accepts Sleigh expressions, allowing you to treat `RAX` as a pointer and go to that address, for example.
We cover Sleigh expressions later in this module.
@ -147,8 +147,7 @@ You can also experiment by placing code units in the Dynamic Listing before comm
![The dynamic memory view of the stack after a call to rand](images/State_BytesStackAfterCallRand.png)
Just as the Dynamic Listing is the analog of the Static Listing, the Memory viewer is the analog of the Byte viewer.
It is not visible by default.
Just as the Dynamic Listing is the analog of the Static Listing, the Memory viewer is the analog of the Bytes viewer.
To open it, use **Windows &rarr; Byte Viewer &rarr; Memory ...** in the menus.
Its default configuration should be Auto PC, the same as the Dynamic Listing's default.
It has all the same additional Debugger features as the Dynamic Listing.
@ -209,7 +208,7 @@ Verify your work by playing the round.
The Watches window gives the values of several user-specified Sleigh expressions.
This can provide an alternative to the Registers window when you are really only interested in a couple of registers.
It can also watch values in memory.
Furthermore, when a watch has a memory address, the expression will appear as an option in the Location Tracking menus of the Listing and Memory viewers.
Furthermore, when a watch has a memory address, the expression will appear as an option in the **Location Tracking** menus of the Listing and Memory viewers.
Selecting that option will cause the window to follow that watch as its address changes.
To add a watch, click the ![add](images/add.png) Add button.
@ -217,7 +216,7 @@ A new entry will appear.
Double-click the left-most cell of the row to set or edit the Sleigh expression.
For starters, try something like `RDI`.
(Conventionally, this is the location for the first parameter on Linux x86-64 systems.)
The context menus for the Listing and Registers windows include a "Watch" action, which adds the current selection to the Watches window.
The context menus for the Listing and Registers windows include a **Watch** action, which adds the current selection to the Watches window.
The columns are:
@ -225,7 +224,7 @@ The columns are:
* The **Address** column is the address of the resulting value, if applicable.
This may be in `register` space.
Double-clicking this cell will go to the address in the Dynamic Listing.
* The **Symbol** column gives the symbol in a mapped static image closest to or containing the address, if applicable.
* The **Symbol** column gives the symbol in a mapped program database closest to or containing the address, if applicable.
* The **Value** column gives the "raw" value of the expression.
If the result is in memory, it displays a byte array; otherwise, it displays an integer.
* The **Type** and **Representation** columns work the same as in the Registers window, except they do *not* save the data unit to the database.
@ -236,10 +235,10 @@ The columns are:
## Sleigh Expressions
Watches and Go-To commands are expressed using Ghidra's Sleigh language.
Watches and Go-To commands are expressed using Ghidra's *Sleigh* language.
More precisely, expressions are the sub-language of Sleigh for the right-hand side of assignment statements in semantic sections.
If you already know this language, then there is little more to learn.
Of note, you may use labels from mapped program images in your expression.
Of note, you may use labels from mapped program databases in your expression.
For example, to see how far a return address is into `main`, you could use `*:8 RSP - main`.
For the complete specification, see the Semantic Section in the [Sleigh documentation](../../../Ghidra/Features/Decompiler/src/main/doc/sleigh.xml).
@ -303,7 +302,7 @@ To read memory:
* **Dereference**: `*:8 RSP` or `*[ram]:8 RSP`
**NOTE** The `[ram]` part is optional.
**NOTE**: The `[ram]` part is optional.
On x86, you will rarely if ever specify the space, since there is only one physical RAM space.
The `:8` part specifies the number of bytes to read from memory.
It is also optional, but only if the size can be inferred from the rest of the expression.
@ -386,7 +385,7 @@ Depending on the particular variable and other circumstances, the hover will con
* **Frame**: If evaluation required unwinding, a description of the frame used for context
* **Storage**: The dynamic, physical location of the variable, e.g., `7fffffffe618`
* **Bytes**: The raw bytes currently stored in the memory allocated to the variable
* **Integer**: The "raw" integer value of the variable, rendered with varyied signedness and radix
* **Integer**: The "raw" integer value of the variable, rendered with varied signedness and radix
* **Value**: The value of the variable, according to its type
* **Instruction**: If the variable points to code, the target instruction
* **Warnings**: Warnings emitted during evaluation

View File

@ -45,10 +45,8 @@
<li><a href="#navigation" id="toc-navigation">Navigation</a>
<ul>
<li><a href="#coordinates" id="toc-coordinates">Coordinates</a></li>
<li><a href="#threads" id="toc-threads">Threads</a>
<ul>
<li><a href="#trace-tabs" id="toc-trace-tabs">Trace Tabs</a></li>
</ul></li>
<li><a href="#threads" id="toc-threads">Threads</a></li>
<li><a href="#stack" id="toc-stack">Stack</a>
<ul>
<li><a href="#exercise-name-the-function"
@ -75,6 +73,7 @@ breakpoints and machine state in Ghidra. If not, please refer to the
previous modules.</p>
<p>This module will address the following features in more depth:</p>
<ul>
<li>The Trace tabs — in the Dynamic Listing window</li>
<li>The Threads window</li>
<li>The Stack window</li>
<li>The Time window</li>
@ -89,8 +88,9 @@ can affect the information displayed in other windows, especially those
dealing with machine state.</p>
<ul>
<li>The current <em>trace</em>. A trace database is where all of the
Debugger windows (except Targets and Objects) gather their information.
It is the analog of the program database, but for dynamic analysis.</li>
Debugger windows (except Connections and Terminal) gather their
information. It is the analog of the program database, but for dynamic
analysis.</li>
<li>The current <em>thread</em>. A thread is a unit of execution, either
a processor core or a platform-defined virtual thread. Each thread has
its own register context. In Ghidra, this means each has its own
@ -109,12 +109,26 @@ may also include steps of emulation, but that is covered in the <a
href="B2-Emulation.html">Emulation</a> module.</li>
</ul>
<p>In general, there is a window dedicated to navigating each element of
your current coordinates.</p>
your current coordinates. If you do not have an active session already,
launch <code>termmines</code>.</p>
</section>
<section id="trace-tabs" class="level2">
<h2>Trace Tabs</h2>
<p>The Dynamic Listing window has a row of tabs at the very top. This is
a list of open traces, i.e., of targets you are debugging. You can also
open old traces to examine a targets machine state <em>post
mortem</em>. In general, you should only have one trace open at a time,
but there are use cases where you might have multiple. For example, you
could debug both the client and server of a network application. To
switch to another trace, single-click its tab.</p>
<p>When you switch traces, every Debugger window that depends on the
current trace will update. Thats every window except Connections and
Terminal. (Each connection has its own Terminal windows.) The
Breakpoints window may change slightly, depending on its configuration,
because it is designed to present all breakpoints in the session.</p>
</section>
<section id="threads" class="level2">
<h2>Threads</h2>
<p>If you do not have an active session already, launch
<code>termmines</code>.</p>
<figure>
<img src="images/Navigation_ThreadsInCallRand.png"
alt="Threads window" />
@ -131,15 +145,12 @@ are:</p>
may include the back-end debuggers thread id, the target platforms
system thread id, and/or the back-end debuggers display text for the
thread.</li>
<li>The <strong>Created</strong> column gives the snapshot when the
thread was first observed.</li>
<li>The <strong>Destroyed</strong> column gives the snapshot when the
thread was first observed as terminated. If this is empty, the thread is
still alive.</li>
<li>The <strong>PC</strong> column gives the program counter of the
thread.</li>
<li>The <strong>Function</strong> column gives the function from a
mapped program database containing the program counter.</li>
<li>The <strong>State</strong> column gives the state of the thread.
This may be one of ALIVE, RUNNING, STOPPED, TERMINATED, or UNKNOWN.</li>
<li>The <strong>Comment</strong> column allows you to annotate the
thread, e.g., if you discover it has a dedicated purpose.</li>
<li>The <strong>Plot</strong> column plots the threads life spans in a
chart.</li>
</ul>
@ -161,21 +172,6 @@ the values for the new thread, the Watches window will re-evaluate all
expressions, and the Dynamic Listing and Memory views may seek to
different addresses, depending on their location tracking
configurations.</p>
<section id="trace-tabs" class="level3">
<h3>Trace Tabs</h3>
<p>The Threads window also has a row of tabs at the very top. This is a
list of open traces, i.e., of targets you are debugging. You can also
open old traces to examine a targets machine state <em>post
mortem</em>. In general, you should only have one trace open at a time,
but there are use cases where you might have multiple. For example, you
could debug both the client and server of a network application. To
switch to another trace, single-click its tab.</p>
<p>When you switch traces, every Debugger window that depends on the
current trace will update. Thats every window except Targets and
Objects. The Breakpoints window may change slightly, depending on its
configuration, because it is designed to present all breakpoints in the
session.</p>
</section>
</section>
<section id="stack" class="level2">
<h2>Stack</h2>
@ -202,8 +198,8 @@ so on.</li>
<li>The <strong>Function</strong> column gives the name of the function
containing the PC mapped to its static program database, if
available.</li>
<li>The <strong>Comment</strong> column allows you to annotate the
frame.</li>
<li>The <strong>Module</strong> column gives the name of the module
containing the PC.</li>
</ul>
<p>Double-click the row with the unnamed function (frame 1) to switch to
it. When you switch frames, any machine-state window that involves
@ -230,7 +226,7 @@ alt="Time window" />
<figcaption aria-hidden="true">Time window</figcaption>
</figure>
<p>It displays a list of all the snapshots for the current trace. In
general, every event generates a snapshot. By default, the most recent
general, every pause generates a snapshot. By default, the most recent
snapshot is at the bottom. The columns are:</p>
<ul>
<li>The <strong>Snap</strong> column numbers each snapshot. Other
@ -244,33 +240,36 @@ created because of an event, which is most.</li>
relation to another. It typically only applies to emulator / scratch
snapshots, which are covered later in this course.</li>
<li>The <strong>Description</strong> column describes the event that
generated the snapshot.</li>
generated the snapshot. This can be edited in the table, or by pressing
<strong><code>CTRL</code>-<code>SHIFT</code>-<code>N</code></strong> to
mark interesting snapshots.</li>
</ul>
<p>Switch to the snapshot where you hit <code>srand</code> (snapshot 2
in our screenshot) by double-clicking it in the table. This will cause
all the machine-state windows to update including the Stack window. If
you try navigating around the Dynamic Listing, you will likely find
stale areas indicated by a grey background.</p>
<p><strong>NOTE</strong>: Navigating into the past will automatically
change the Control mode. This is to avoid confusion, since you may
perform a control action based on the state you see, which is no longer
the state of the live target. Switch back by using the Control mode
drop-down button in the global toolbar. When you select <strong>Control
Target</strong> (with or without edits), the Debugger will navigate
forward to the latest snapshot.</p>
<p>Before we can navigate back in time, you must change the <em>Control
Mode</em> to <strong>Control Trace</strong>. Now, switch to the snapshot
where you hit <code>srand</code> (snapshot 1 in our screenshot) by
double-clicking it in the table. This will cause all the machine-state
windows to update including the Stack window. If you try navigating
around the Dynamic Listing, you will likely find stale areas indicated
by a grey background.</p>
<p><strong>NOTE</strong>: The control-mode change is required to avoid
confusion between recorded and live states. When you switch back to
<strong>Control Target</strong> (with or without edits), the Debugger
will navigate forward to the latest snapshot and prohibit navigating to
the past.</p>
<section id="sparse-vs.-full-snapshots" class="level3">
<h3>Sparse vs. Full Snapshots</h3>
<p>Regarding the stale areas: the Debugger cannot request the back-end
debugger provide machine state from the past. (Integration with timeless
back-end debuggers is not yet supported.) Remember, the trace is used as
a cache, so it will only be populated with the pages and registers that
you observed at the time. Thus, most snapshots are <em>sparse</em>
back-end debuggers is nascent.) Remember, the trace is used as a cache,
so it will only be populated with the pages and registers that you
observed at the time. Thus, most snapshots are <em>sparse</em>
snapshots. The most straightforward way to capture a <em>full</em>
snapshot is the
<img alt="refresh" src="images/view-refresh.png" width="16px"> Refresh
button with a broad selection in the Dynamic Listing. We give the exact
steps in the next heading. To capture registers, ensure you navigate to
each thread whose registers you want to capture.</p>
<img alt="refresh" src="images/view-refresh.png" width="16px">
<strong>Read Memory</strong> button with a broad selection in the
Dynamic Listing. We give the exact steps in the next heading. To capture
registers, ensure you navigate to each thread whose registers you want
to capture.</p>
</section>
<section id="comparing-snapshots" class="level3">
<h3>Comparing Snapshots</h3>
@ -289,15 +288,18 @@ will need to launch (not attach) the target.</p>
href="A1-GettingStarted.html">Getting Started</a> to review launching
with custom parameters.)</p></li>
<li><p>Ensure your breakpoint at <code>srand</code> is enabled.</p></li>
<li><p>Use <strong>Ctrl-A</strong> to Select All the addresses.</p></li>
<li><p>Use <strong><code>CTRL</code>-<code>A</code></strong> to Select
All the addresses.</p></li>
<li><p>Click the
<img alt="refresh" src="images/view-refresh.png" width="16px"> Refresh
button. <strong>NOTE</strong>: It is normal for some errors to occur
here. We note a more surgical approach below.</p></li>
<li><p>Wait a moment for the capture to finish.</p></li>
<li><p>Optionally, press <strong>Ctrl-Shift-N</strong> to rename the
snapshot so you can easily identify it later. Alternatively, edit the
snapshots Description from the table in the Time window.</p></li>
<li><p>Optionally, press
<strong><code>CTRL</code>-<code>SHIFT</code>-<code>N</code></strong> to
rename the snapshot so you can easily identify it later, e.g., “Initial
snapshot.” Alternatively, edit the snapshots Description from the table
in the Time window.</p></li>
<li><p>Press <img src="images/resume.png" alt="resume" /> Resume,
expecting it to break at <code>srand</code>.</p></li>
<li><p>Capture another full snapshot using Select All and
@ -310,7 +312,7 @@ alt="compare" /> Compare button in the Dynamic Listing.</p></li>
alt="The compare times dialog" />
<figcaption aria-hidden="true">The compare times dialog</figcaption>
</figure></li>
<li><p>Click OK.</p></li>
<li><p>Click <strong>OK</strong>.</p></li>
</ol>
<p>The result is a side-by-side listing of the two snapshots with
differences highlighted in orange. Unlike the Static program comparison
@ -341,14 +343,19 @@ navigate to the <code>.data</code> section. The Dynamic Listing will
stay in sync and consequently capture the contents of the first page.
This specimen has a small enough <code>.data</code> section to fit in a
single page, but that is generally not the case in practice.</li>
<li>Use the Regions window to select the addresses in the
<code>.data</code> section, then click Refresh in the Dynamic Listing.
<li>If there are more pages, use the Regions window. Click the
<strong>Select Rows</strong> then the <strong>Select Addresses</strong>
buttons to expand the selection to the whole region containing the
cursor. Then click <strong>Read Memory</strong> in the Dynamic Listing.
This will capture the full <code>.data</code> section, no matter how
many pages.</li>
<li>Use the lower pane of the Modules window to select the addresses in
the <code>.data</code> section, then click Refresh in the Dynamic
Listing. This will also capture the full <code>.data</code>
section.</li>
<li>Alternatively, Use the Modules window to select
<code>termmines</code> and load its sections. (Not all debuggers support
this.) Click the <strong>Show Sections Table</strong> button in the
local toolbar to enable the lower pane. Use the Sections table to select
the addresses in the <code>.data</code> section, then click <strong>Read
Memory</strong> in the Dynamic Listing. This will also capture the full
<code>.data</code> section.</li>
</ul>
</section>
<section id="exercise-find-the-time" class="level3">
@ -358,9 +365,10 @@ score is not printed until you win. Your goal is to achieve a remarkable
score by patching a variable right before winning. Considering it is a
single-threaded application, take a moment to think about how your time
might be measured. <strong>TIP</strong>: Because you will need to play
the game, you will need to attach rather than launch. Use the snapshot
comparison method to locate the variable. Then place an appropriate
breakpoint, win the game, patch the variable, and score 0 seconds!</p>
the game, you should enable <strong>Inferior TTY</strong> in the
launcher. Use the snapshot comparison method to locate the variable.
Then place an appropriate breakpoint, win the game, patch the variable,
and score 0 seconds!</p>
<p>If you chose a poor breakpoint or have no breakpoint at all, you
should still score better than 3 seconds. Once you know where the
variable is, you can check its XRefs in the Static Listing and devise a

View File

@ -7,6 +7,7 @@ If not, please refer to the previous modules.
This module will address the following features in more depth:
* The Trace tabs &mdash; in the Dynamic Listing window
* The Threads window
* The Stack window
* The Time window
@ -18,7 +19,7 @@ There are more elements to a "location" in a dynamic session, so we add addition
All of these elements can affect the information displayed in other windows, especially those dealing with machine state.
* The current *trace*.
A trace database is where all of the Debugger windows (except Targets and Objects) gather their information.
A trace database is where all of the Debugger windows (except Connections and Terminal) gather their information.
It is the analog of the program database, but for dynamic analysis.
* The current *thread*.
A thread is a unit of execution, either a processor core or a platform-defined virtual thread.
@ -36,11 +37,24 @@ All of these elements can affect the information displayed in other windows, esp
"Time" may also include steps of emulation, but that is covered in the [Emulation](B2-Emulation.md) module.
In general, there is a window dedicated to navigating each element of your current coordinates.
If you do not have an active session already, launch `termmines`.
## Trace Tabs
The Dynamic Listing window has a row of tabs at the very top.
This is a list of open traces, i.e., of targets you are debugging.
You can also open old traces to examine a target's machine state *post mortem*.
In general, you should only have one trace open at a time, but there are use cases where you might have multiple.
For example, you could debug both the client and server of a network application.
To switch to another trace, single-click its tab.
When you switch traces, every Debugger window that depends on the current trace will update.
That's every window except Connections and Terminal.
(Each connection has its own Terminal windows.)
The Breakpoints window may change slightly, depending on its configuration, because it is designed to present all breakpoints in the session.
## Threads
If you do not have an active session already, launch `termmines`.
![Threads window](images/Navigation_ThreadsInCallRand.png)
The Threads window displays a list of all threads ever observed in the target.
@ -51,12 +65,10 @@ The columns are:
* The **Name** column gives the name of the thread.
This may include the back-end debugger's thread id, the target platform's system thread id, and/or the back-end debugger's display text for the thread.
* The **Created** column gives the snapshot when the thread was first observed.
* The **Destroyed** column gives the snapshot when the thread was first observed as terminated.
If this is empty, the thread is still alive.
* The **PC** column gives the program counter of the thread.
* The **Function** column gives the function from a mapped program database containing the program counter.
* The **State** column gives the state of the thread.
This may be one of ALIVE, RUNNING, STOPPED, TERMINATED, or UNKNOWN.
* The **Comment** column allows you to annotate the thread, e.g., if you discover it has a dedicated purpose.
* The **Plot** column plots the threads' life spans in a chart.
**NOTE**: Most of the time, switching threads will also change what thread is being controlled by the Control actions in the global toolbar.
@ -68,19 +80,6 @@ It may step a different thread, it may cause the target to block until the threa
When you switch threads, everything that depends on the current thread may change, in particular the Stack window and any machine-state window that involves register values.
The Registers window will display the values for the new thread, the Watches window will re-evaluate all expressions, and the Dynamic Listing and Memory views may seek to different addresses, depending on their location tracking configurations.
### Trace Tabs
The Threads window also has a row of tabs at the very top.
This is a list of open traces, i.e., of targets you are debugging.
You can also open old traces to examine a target's machine state *post mortem*.
In general, you should only have one trace open at a time, but there are use cases where you might have multiple.
For example, you could debug both the client and server of a network application.
To switch to another trace, single-click its tab.
When you switch traces, every Debugger window that depends on the current trace will update.
That's every window except Targets and Objects.
The Breakpoints window may change slightly, depending on its configuration, because it is designed to present all breakpoints in the session.
## Stack
Ensure your breakpoint on `rand` is enabled, and resume until you hit it.
@ -99,7 +98,7 @@ The columns are:
The PC of frame 0 is the value of the PC register.
Then, the PC of frame 1 is the return address of frame 0, and so on.
* The **Function** column gives the name of the function containing the PC mapped to its static program database, if available.
* The **Comment** column allows you to annotate the frame.
* The **Module** column gives the name of the module containing the PC.
Double-click the row with the unnamed function (frame 1) to switch to it.
When you switch frames, any machine-state window that involves register values may change.
@ -119,7 +118,7 @@ Now, switch to the Time window.
![Time window](images/Navigation_TimeAfterCallSRandCallRand.png)
It displays a list of all the snapshots for the current trace.
In general, every event generates a snapshot.
In general, every pause generates a snapshot.
By default, the most recent snapshot is at the bottom.
The columns are:
@ -131,23 +130,23 @@ The columns are:
* The **Schedule** column describes the snapshot in relation to another.
It typically only applies to emulator / scratch snapshots, which are covered later in this course.
* The **Description** column describes the event that generated the snapshot.
This can be edited in the table, or by pressing **`CTRL`-`SHIFT`-`N`** to mark interesting snapshots.
Switch to the snapshot where you hit `srand` (snapshot 2 in our screenshot) by double-clicking it in the table.
Before we can navigate back in time, you must change the *Control Mode* to **Control Trace**.
Now, switch to the snapshot where you hit `srand` (snapshot 1 in our screenshot) by double-clicking it in the table.
This will cause all the machine-state windows to update including the Stack window.
If you try navigating around the Dynamic Listing, you will likely find stale areas indicated by a grey background.
**NOTE**: Navigating into the past will automatically change the Control mode.
This is to avoid confusion, since you may perform a control action based on the state you see, which is no longer the state of the live target.
Switch back by using the Control mode drop-down button in the global toolbar.
When you select **Control Target** (with or without edits), the Debugger will navigate forward to the latest snapshot.
**NOTE**: The control-mode change is required to avoid confusion between recorded and live states.
When you switch back to **Control Target** (with or without edits), the Debugger will navigate forward to the latest snapshot and prohibit navigating to the past.
### Sparse vs. Full Snapshots
Regarding the stale areas: the Debugger cannot request the back-end debugger provide machine state from the past.
(Integration with timeless back-end debuggers is not yet supported.)
(Integration with timeless back-end debuggers is nascent.)
Remember, the trace is used as a cache, so it will only be populated with the pages and registers that you observed at the time.
Thus, most snapshots are *sparse* snapshots.
The most straightforward way to capture a *full* snapshot is the <img alt="refresh" src="images/view-refresh.png" width="16px"> Refresh button with a broad selection in the Dynamic Listing.
The most straightforward way to capture a *full* snapshot is the <img alt="refresh" src="images/view-refresh.png" width="16px"> **Read Memory** button with a broad selection in the Dynamic Listing.
We give the exact steps in the next heading.
To capture registers, ensure you navigate to each thread whose registers you want to capture.
@ -164,12 +163,12 @@ Because parsing happens before waiting for user input, we will need to launch (n
1. Launch `termmines -M 15` in the Debugger.
(See [Getting Started](A1-GettingStarted.md) to review launching with custom parameters.)
1. Ensure your breakpoint at `srand` is enabled.
1. Use **Ctrl-A** to Select All the addresses.
1. Use **`CTRL`-`A`** to Select All the addresses.
1. Click the <img alt="refresh" src="images/view-refresh.png" width="16px"> Refresh button.
**NOTE**: It is normal for some errors to occur here.
We note a more surgical approach below.
1. Wait a moment for the capture to finish.
1. Optionally, press **Ctrl-Shift-N** to rename the snapshot so you can easily identify it later.
1. Optionally, press **`CTRL`-`SHIFT`-`N`** to rename the snapshot so you can easily identify it later, e.g., "Initial snapshot."
Alternatively, edit the snapshot's Description from the table in the Time window.
1. Press ![resume](images/resume.png) Resume, expecting it to break at `srand`.
1. Capture another full snapshot using Select All and Refresh.
@ -178,7 +177,7 @@ Because parsing happens before waiting for user input, we will need to launch (n
![The compare times dialog](images/Navigation_DialogCompareTimes.png)
1. Click OK.
1. Click **OK**.
The result is a side-by-side listing of the two snapshots with differences highlighted in orange.
Unlike the Static program comparison tool, this only highlights differences in *byte* values.
@ -199,9 +198,13 @@ Some alternatives, which we will cover in the [Memory Map](A6-MemoryMap.md) modu
* Use the Memory Map window (borrowed from the CodeBrowser) to navigate to the `.data` section.
The Dynamic Listing will stay in sync and consequently capture the contents of the first page.
This specimen has a small enough `.data` section to fit in a single page, but that is generally not the case in practice.
* Use the Regions window to select the addresses in the `.data` section, then click Refresh in the Dynamic Listing.
* If there are more pages, use the Regions window. Click the **Select Rows** then the **Select Addresses** buttons to expand the selection to the whole region containing the cursor.
Then click **Read Memory** in the Dynamic Listing.
This will capture the full `.data` section, no matter how many pages.
* Use the lower pane of the Modules window to select the addresses in the `.data` section, then click Refresh in the Dynamic Listing.
* Alternatively, Use the Modules window to select `termmines` and load its sections.
(Not all debuggers support this.)
Click the **Show Sections Table** button in the local toolbar to enable the lower pane.
Use the Sections table to select the addresses in the `.data` section, then click **Read Memory** in the Dynamic Listing.
This will also capture the full `.data` section.
### Exercise: Find the Time
@ -209,7 +212,7 @@ Some alternatives, which we will cover in the [Memory Map](A6-MemoryMap.md) modu
In `termmines`, unlike other Minesweeper clones, your score is not printed until you win.
Your goal is to achieve a remarkable score by patching a variable right before winning.
Considering it is a single-threaded application, take a moment to think about how your time might be measured.
**TIP**: Because you will need to play the game, you will need to attach rather than launch.
**TIP**: Because you will need to play the game, you should enable **Inferior TTY** in the launcher.
Use the snapshot comparison method to locate the variable.
Then place an appropriate breakpoint, win the game, patch the variable, and score 0 seconds!

View File

@ -94,26 +94,23 @@ stacks, heaps, or other system objects. The columns are:</p>
file-backed mappings, this should include the name of the file. It may
or may not include a section name. Typically, the name will include the
start address to avoid collisions.</li>
<li>The <strong>Lifespan</strong> column gives the span of snapshots
where the region has been observed. Memory maps can change during the
course of execution, and this is how Ghidra records and presents that
history.</li>
<li>The <strong>Start</strong> column gives the minimum address of the
region.</li>
<li>The <strong>End</strong> column gives the maximum (inclusive)
address of the region.</li>
<li>The <strong>Length</strong> column gives the number of bytes in the
region.</li>
<li>The <strong>Read</strong>, <strong>Write</strong>,
<strong>Execute</strong>, and <strong>Volatile</strong> columns give the
permissions/flags of the region.</li>
<li>The <strong>Read</strong>, <strong>Write</strong>, and
<strong>Execute</strong> columns give the permissions of the
region.</li>
</ul>
<p>Try using the filter and column headers to sift and sort for
interesting regions. Double-click the start or end address to navigate
to them in the Dynamic Listing. Select one or more regions, right-click,
and choose <strong>Select Addresses</strong>. That should select all the
addresses in those regions in the Dynamic Listing. Used with the Refresh
button, you can surgically capture memory into the current snapshot.</p>
addresses in those regions in the Dynamic Listing. Used with the
<strong>Read Memory</strong> button in the Dynamic Listing, you can
selectively capture memory into the current snapshot.</p>
</section>
<section id="modules" class="level2">
<h2>Modules</h2>
@ -122,14 +119,16 @@ button, you can surgically capture memory into the current snapshot.</p>
alt="Modules window after launch" />
<figcaption aria-hidden="true">Modules window after launch</figcaption>
</figure>
<p>The Modules window has two panes. The top pane displays a list of all
the <em>modules</em> known to the back-end debugger. The bottom pane
displays a list of all the <em>sections</em> known to the back-end
debugger. In practice, not all targets will report module information.
Fewer targets report section information. The nearest analog to the
bottom panel from the CodeBrowser is (also) the Memory Map window. The
top panel has no real analog; however, the tabs above the Static Listing
pane serve a similar purpose.</p>
<p>The Modules window has two panes, though the second is disabled by
default. The top pane displays a list of all the <em>modules</em> known
to the back-end debugger. The bottom pane displays a list of all the
<em>sections</em> known to the back-end debugger. In practice, not all
targets will report module information. Fewer targets report section
information, and those that do may only report them to Ghidra when
specifically requested. The nearest analog to the bottom panel from the
CodeBrowser is (also) the Memory Map window. The top panel has no real
analog; however, the tabs above the Static Listing pane serve a similar
purpose.</p>
<p>For a target that reports section information, the bottom panel will
display a lot of the same information as the Regions window. The columns
differ slightly, and the sections panel will <em>not</em> include
@ -138,44 +137,27 @@ stacks, heaps, etc.</p>
<ul>
<li>The <strong>Base</strong> column gives the image base for the
module. This should be the minimum address of the module.</li>
<li>The <strong>Max Address</strong> column gives the maximum address of
the module.</li>
<li>The <strong>Max</strong> column gives the maximum address of the
module.</li>
<li>The <strong>Name</strong> column gives the (short) name of the
module.</li>
<li>The <strong>Module Name</strong> column gives the full file path of
the module <em>on target</em>. In some cases, this gives some other
description of the module.</li>
<li>The <strong>Lifespan</strong> column gives the span of snapshots
where the module has been observed.</li>
<li>The <strong>Mapping</strong> column gives the mapped Ghidra program
database for the module.</li>
<li>The <strong>Length</strong> column gives the distance between the
base and max address (inclusive). Note that not every address between
base and max is necessarily mapped to the module. ELF headers specify
the load address of each section, so the memory footprint usually has
many gaps.</li>
</ul>
<p>The section columns are:</p>
<ul>
<li>The <strong>Start Address</strong> gives the minimum address of the
section.</li>
<li>The <strong>End Address</strong> gives the maximum (inclusive)
address of the section.</li>
<li>The <strong>Section Name</strong> gives the name of the
section.</li>
<li>The <strong>Module Name</strong> gives the name of the module
containing the section.</li>
<li>The <strong>Length</strong> gives the number of bytes contained in
the section.</li>
</ul>
<p><strong>NOTE</strong>: There is no lifespan column for a section. The
lifespan of a section is the lifespan of its containing module.</p>
<p>Try using the filter and column headers in each pane to sift and
sort. This is especially helpful for the sections: Type the name of a
module or section. You can also toggle the filter button in the local
toolbar to filter the sections pane to those contained in a selected
module from the top pane. Double-click any address to navigate to it.
Make a selection of modules or sections, right-click, and choose
<strong>Select Addresses</strong>. Again, combined with the Dynamic
Listings Refresh button, you can capture memory surgically.</p>
<p>See the Help (press <strong><code>F1</code></strong> in the Modules
panel) to learn more about the Sections table, if desired. It can be
enabled using the <strong>Show Sections Table</strong> button in the
local toolbar.</p>
<p>Double-click any address to navigate to it. Make a selection of
modules or sections, right-click, and choose <strong>Select
Addresses</strong>. Again, combined with the Dynamic Listings
<strong>Read Memory</strong> button, you can capture memory
selectively.</p>
</section>
<section id="optional-exercise-find-the-time-surgically" class="level2">
<h2>Optional Exercise: Find the Time Surgically</h2>
@ -232,19 +214,20 @@ and cope with module relocation, especially from ASLR.</p>
<li>From the Modules window, select one or more modules, and choose from
the <strong>Map Module</strong> actions. Selecting a single module at a
time, it is possible to surgically map each to a chosen program.</li>
<li>From the Sections window, select one or more sections, and choose
<li>From the Sections panel, select one or more sections, and choose
from the <strong>Map Section</strong> actions. This is certainly more
tedious and atypical, but it allows the surgical mapping of each section
to a chosen memory block from among your open programs.</li>
<li>From the Regions window, select one or more regions, and choose from
the <strong>Map Region</strong> actions.</li>
<li>Click the Map Identically button in the Modules window toolbar.</li>
<li>Use the Add and Remove buttons in the Static Mappings window
toolbar.</li>
<li>Click the <strong>Map Identically</strong> button in the Modules
window toolbar.</li>
<li>Use the <strong>Add</strong> and <strong>Remove</strong> buttons in
the Static Mappings window toolbar.</li>
</ul>
<p>These methods are not described in detail here. For more information,
hover over the relevant actions and press <strong>F1</strong> for
help.</p>
hover over the relevant actions and press
<strong><code>F1</code></strong> for help.</p>
</section>
<section id="moving-knowledge-from-dynamic-to-static" class="level2">
<h2>Moving Knowledge from Dynamic to Static</h2>
@ -256,14 +239,14 @@ memory is uninitialized in the Static Listing, and you preferred some
trial and error in the Dynamic Listing, where the memory is populated.
In this case, you would want to copy those code units (though not
necessarily the byte values) from the Dynamic Listing into the Static
Listing. After selecting the units to copy, from the menus, you would
use <strong>Debugger → Copy Into Current Program</strong>.</p>
Listing. After selecting the units to copy, you would use
<strong>Debugger → Copy Into Current Program</strong> in the menus.</p>
<p>In another example, you might not have an on-disk image for a module,
but you would still like to perform static analysis on that module. In
this case, you would want to copy everything within that module from the
dynamic session into a program database. After selecting the addresses
in that module, from the menus, you would use <strong>Debugger → Copy
Into New Program</strong>.</p>
in that module, you would use <strong>Debugger → Copy Into New
Program</strong>.</p>
<p>For demonstration, we will walk through this second case, pretending
we cannot load <code>libncurses</code> from disk:</p>
<ol type="1">
@ -279,20 +262,22 @@ Program</strong>.</p>
alt="Copy dialog for ncurses" />
<figcaption aria-hidden="true">Copy dialog for ncurses</figcaption>
</figure></li>
<li><p>Keep Destination set to “New Program.”</p></li>
<li><p>Ensure “Read live targets memory” is checked. This will spare
you from having to create a full snapshot manually.</p></li>
<li><p>Do <em>not</em> check “Use overlays where blocks already
present.” It should not have any effect for a new program,
<li><p>Keep <strong>Destination</strong> set to “&lt;New
Program&gt;.”</p></li>
<li><p>Ensure <strong>Read live targets memory</strong> is checked.
This will spare you from having to create a full snapshot
manually.</p></li>
<li><p>Do <em>not</em> check <strong>Use overlays where blocks already
exist</strong>. It should not have any effect for a new program,
anyway.</p></li>
<li><p>It is probably best to include everything, though “Bytes” is the
bare minimum.</p></li>
<li><p>It is probably best to include everything, though
<strong>Bytes</strong> is the bare minimum.</p></li>
<li><p>The table displays the <em>copy plan</em>. For a new program,
this will copy with an identical mapping of addresses, which is probably
the best plan, since the target system has already applied fixups. Do
not change any addresses, lest your corrupt references in the
copy.</p></li>
<li><p>Click Copy.</p></li>
<li><p>Click <strong>Copy</strong>.</p></li>
<li><p>When prompted, name the program <code>libncurses</code>.</p></li>
<li><p>You may need to click the <code>termmines</code> tab in the
Static Listing to get the UI to completely update.</p></li>
@ -302,17 +287,13 @@ If you are prompted to analyze, go ahead.</p></li>
<p>Undoubtedly, we would like to map that new program into our dynamic
session.</p>
<ol type="1">
<li>Again, in the top pane of the Modules window, right-click
<code>libncurses</code> and choose <strong>Select
Addresses</strong>.</li>
<li>Ensure the cursor in the Static Listing is at the minimum address of
<code>libncurses</code>.</li>
<li>In the Static Mappings window, click Add in the toolbar.</li>
<li>Click OK.</li>
<li>Ensure that the new <code>libncurses</code> capture is still the
current program.</li>
<li>In the top pane of the Modules window, right-click
<code>libncurses</code> and choose <strong>Map to
libncurses</strong>.</li>
<li>Check the proposed mapping and click <strong>OK</strong>.</li>
</ol>
<p><strong>NOTE</strong>: This should be done by choosing <strong>Map to
libncurses</strong> in the right-click menu, but a bug seems to stifle
that, currently.</p>
</section>
<section id="exercise-export-and-map-ncurses" class="level2">
<h2>Exercise: Export and Map <code>ncurses</code></h2>

View File

@ -26,28 +26,26 @@ The columns are:
For file-backed mappings, this should include the name of the file.
It may or may not include a section name.
Typically, the name will include the start address to avoid collisions.
* The **Lifespan** column gives the span of snapshots where the region has been observed.
Memory maps can change during the course of execution, and this is how Ghidra records and presents that history.
* The **Start** column gives the minimum address of the region.
* The **End** column gives the maximum (inclusive) address of the region.
* The **Length** column gives the number of bytes in the region.
* The **Read**, **Write**, **Execute**, and **Volatile** columns give the permissions/flags of the region.
* The **Read**, **Write**, and **Execute** columns give the permissions of the region.
Try using the filter and column headers to sift and sort for interesting regions.
Double-click the start or end address to navigate to them in the Dynamic Listing.
Select one or more regions, right-click, and choose **Select Addresses**.
That should select all the addresses in those regions in the Dynamic Listing.
Used with the Refresh button, you can surgically capture memory into the current snapshot.
Used with the **Read Memory** button in the Dynamic Listing, you can selectively capture memory into the current snapshot.
## Modules
![Modules window after launch](images/MemoryMap_ModulesAfterLaunch.png)
The Modules window has two panes.
The Modules window has two panes, though the second is disabled by default.
The top pane displays a list of all the *modules* known to the back-end debugger.
The bottom pane displays a list of all the *sections* known to the back-end debugger.
In practice, not all targets will report module information.
Fewer targets report section information.
Fewer targets report section information, and those that do may only report them to Ghidra when specifically requested.
The nearest analog to the bottom panel from the CodeBrowser is (also) the Memory Map window.
The top panel has no real analog; however, the tabs above the Static Listing pane serve a similar purpose.
@ -58,32 +56,19 @@ The module columns are:
* The **Base** column gives the image base for the module.
This should be the minimum address of the module.
* The **Max Address** column gives the maximum address of the module.
* The **Max** column gives the maximum address of the module.
* The **Name** column gives the (short) name of the module.
* The **Module Name** column gives the full file path of the module *on target*.
In some cases, this gives some other description of the module.
* The **Lifespan** column gives the span of snapshots where the module has been observed.
* The **Mapping** column gives the mapped Ghidra program database for the module.
* The **Length** column gives the distance between the base and max address (inclusive).
Note that not every address between base and max is necessarily mapped to the module.
ELF headers specify the load address of each section, so the memory footprint usually has many gaps.
The section columns are:
See the Help (press **`F1`** in the Modules panel) to learn more about the Sections table, if desired.
It can be enabled using the **Show Sections Table** button in the local toolbar.
* The **Start Address** gives the minimum address of the section.
* The **End Address** gives the maximum (inclusive) address of the section.
* The **Section Name** gives the name of the section.
* The **Module Name** gives the name of the module containing the section.
* The **Length** gives the number of bytes contained in the section.
**NOTE**: There is no lifespan column for a section.
The lifespan of a section is the lifespan of its containing module.
Try using the filter and column headers in each pane to sift and sort.
This is especially helpful for the sections: Type the name of a module or section.
You can also toggle the filter button in the local toolbar to filter the sections pane to those contained in a selected module from the top pane.
Double-click any address to navigate to it.
Make a selection of modules or sections, right-click, and choose **Select Addresses**.
Again, combined with the Dynamic Listing's Refresh button, you can capture memory surgically.
Again, combined with the Dynamic Listing's **Read Memory** button, you can capture memory selectively.
## Optional Exercise: Find the Time Surgically
@ -121,14 +106,14 @@ There are many ways to manually override the mappings:
* From the Modules window, select one or more modules, and choose from the **Map Module** actions.
Selecting a single module at a time, it is possible to surgically map each to a chosen program.
* From the Sections window, select one or more sections, and choose from the **Map Section** actions.
* From the Sections panel, select one or more sections, and choose from the **Map Section** actions.
This is certainly more tedious and atypical, but it allows the surgical mapping of each section to a chosen memory block from among your open programs.
* From the Regions window, select one or more regions, and choose from the **Map Region** actions.
* Click the Map Identically button in the Modules window toolbar.
* Use the Add and Remove buttons in the Static Mappings window toolbar.
* Click the **Map Identically** button in the Modules window toolbar.
* Use the **Add** and **Remove** buttons in the Static Mappings window toolbar.
These methods are not described in detail here.
For more information, hover over the relevant actions and press **F1** for help.
For more information, hover over the relevant actions and press **`F1`** for help.
## Moving Knowledge from Dynamic to Static
@ -136,11 +121,11 @@ There are occasions when it is necessary or convenient to transfer data or marku
For example, suppose during experimentation, you have placed a bunch of code units in the Dynamic Listing.
You might have done this because the memory is uninitialized in the Static Listing, and you preferred some trial and error in the Dynamic Listing, where the memory is populated.
In this case, you would want to copy those code units (though not necessarily the byte values) from the Dynamic Listing into the Static Listing.
After selecting the units to copy, from the menus, you would use **Debugger &rarr; Copy Into Current Program**.
After selecting the units to copy, you would use **Debugger &rarr; Copy Into Current Program** in the menus.
In another example, you might not have an on-disk image for a module, but you would still like to perform static analysis on that module.
In this case, you would want to copy everything within that module from the dynamic session into a program database.
After selecting the addresses in that module, from the menus, you would use **Debugger &rarr; Copy Into New Program**.
After selecting the addresses in that module, you would use **Debugger &rarr; Copy Into New Program**.
For demonstration, we will walk through this second case, pretending we cannot load `libncurses` from disk:
@ -151,16 +136,16 @@ For demonstration, we will walk through this second case, pretending we cannot l
![Copy dialog for ncurses](images/MemoryMap_CopyNcursesInto.png)
1. Keep Destination set to "New Program."
1. Ensure "Read live target's memory" is checked.
1. Keep **Destination** set to "&lt;New Program&gt;."
1. Ensure **Read live target's memory** is checked.
This will spare you from having to create a full snapshot manually.
1. Do *not* check "Use overlays where blocks already present."
1. Do *not* check **Use overlays where blocks already exist**.
It should not have any effect for a new program, anyway.
1. It is probably best to include everything, though "Bytes" is the bare minimum.
1. It is probably best to include everything, though **Bytes** is the bare minimum.
1. The table displays the *copy plan*.
For a new program, this will copy with an identical mapping of addresses, which is probably the best plan, since the target system has already applied fixups.
Do not change any addresses, lest your corrupt references in the copy.
1. Click Copy.
1. Click **Copy**.
1. When prompted, name the program `libncurses`.
1. You may need to click the `termmines` tab in the Static Listing to get the UI to completely update.
1. Click back over to `libncurses` and save the program.
@ -168,12 +153,9 @@ For demonstration, we will walk through this second case, pretending we cannot l
Undoubtedly, we would like to map that new program into our dynamic session.
1. Again, in the top pane of the Modules window, right-click `libncurses` and choose **Select Addresses**.
1. Ensure the cursor in the Static Listing is at the minimum address of `libncurses`.
1. In the Static Mappings window, click Add in the toolbar.
1. Click OK.
**NOTE**: This should be done by choosing **Map to libncurses** in the right-click menu, but a bug seems to stifle that, currently.
1. Ensure that the new `libncurses` capture is still the current program.
1. In the top pane of the Modules window, right-click `libncurses` and choose **Map to libncurses**.
1. Check the proposed mapping and click **OK**.
## Exercise: Export and Map `ncurses`

View File

@ -112,19 +112,21 @@
id="toc-module-mapping-caveats">Module Mapping Caveats</a></li>
<li><a href="#variation-in-configuration"
id="toc-variation-in-configuration">Variation in Configuration</a></li>
<li><a href="#using-gdbserver" id="toc-using-gdbserver">Using
<code>gdbserver</code></a></li>
<li><a href="#using-ssh" id="toc-using-ssh">Using SSH</a></li>
<li><a href="#using-gadp" id="toc-using-gadp">Using GADP</a>
<li><a href="#using-gdbserver-over-ssh"
id="toc-using-gdbserver-over-ssh">Using <code>gdbserver</code> over
SSH</a></li>
<li><a href="#using-trace-rmi-over-ssh"
id="toc-using-trace-rmi-over-ssh">Using Trace RMI over SSH</a>
<ul>
<li><a href="#using-gadp-locally" id="toc-using-gadp-locally">Using GADP
Locally</a></li>
<li><a href="#using-gadp-remotely" id="toc-using-gadp-remotely">Using
GADP Remotely</a></li>
<li><a href="#troubleshooting"
id="toc-troubleshooting">Troubleshooting</a></li>
</ul></li>
<li><a href="#using-a-pty-pseudo-terminal"
id="toc-using-a-pty-pseudo-terminal">Using a pty
(pseudo-terminal)</a></li>
<li><a href="#using-gdbserver-manually"
id="toc-using-gdbserver-manually">Using <code>gdbserver</code>
manually</a></li>
<li><a href="#connecting-trace-rmi-manually"
id="toc-connecting-trace-rmi-manually">Connecting Trace RMI
manually</a></li>
<li><a href="#rube-goldberg-configurations"
id="toc-rube-goldberg-configurations">Rube Goldberg
Configurations</a></li>
@ -158,176 +160,193 @@ some are not. Depending on your particular target and platform, there
may be several options available to you. Consider a remote Linux target
in user space. While this list is not exhaustive, some options are:</p>
<ul>
<li>Use <code>gdbserver</code></li>
<li>Use SSH</li>
<li>Use GADP</li>
<li>Use a pty</li>
<li>Use <code>gdbserver</code> over SSH</li>
<li>Use Trace RMI over SSH</li>
<li>Use <code>gdbserver</code> and connect to it manually</li>
<li>Connect Trace RMI manually</li>
</ul>
<p>Generally, for each of these options it boils down to which
components will be colocated with the target and which will be colocated
with Ghidra.</p>
</section>
<section id="using-gdbserver" class="level2">
<h2>Using <code>gdbserver</code></h2>
<section id="using-gdbserver-over-ssh" class="level2">
<h2>Using <code>gdbserver</code> over SSH</h2>
<p>In this configuration, Ghidra and GDB will be located in the users
local environment, while <code>gdbserver</code> and the specimen will be
located in the target environment. The procedure follows directly from
GDBs manual, but with some Ghidra-specific steps. First, prepare the
target, which for demonstration purposes has the IP address
10.0.0.1:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">gdbserver</span> 10.0.0.1:12345 termmines</span></code></pre></div>
<p>Then, connect from Ghidra using GDB:</p>
located in the target environment. We will connect the local
<code>gdb</code> to the remote <code>gdbserver</code> by forwarding
stdio over SSH.</p>
<ol type="1">
<li><p>From the Targets window, click Connect, select “gdb,” and click
Connect.</p></li>
<li><p>In the Interpreter, do as you would in GDB:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode gdb"><code class="sourceCode gdbsyntax"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">target</span> <span class="kw">remote</span> 10.0.0.1:12345</span></code></pre></div></li>
</ol>
<p>The target should now be added to the Debugger session, and things
should work as usual.</p>
</section>
<section id="using-ssh" class="level2">
<h2>Using SSH</h2>
<p>In this configuration, only Ghidra is required to be in the users
local environment, while <code>sshd</code>, <code>gdb</code> and the
specimen will be located in the target environment.
<strong>NOTE</strong>: The full <code>gdb</code>, not just
<code>gdbserver</code>, must be installed on the target system.</p>
<ol type="1">
<li><p>From the Targets window, click Connect, and select “gdb via
SSH.”</p>
<li><p>First, prepare the target, which for demonstration purposes has
the IP address 10.0.0.1. Generally, this just means booting it up and
ensuring it has <code>gdbserver</code> installed. <strong>NOTE</strong>:
You do not need to run <code>gdbserver</code> or the target binary. The
launcher will do that for you.</p></li>
<li><p>From the launch menu, select <strong>gdb + gdbserver via
ssh</strong>.</p>
<figure>
<img src="images/RemoteTargets_GdbOverSsh.png"
<img src="images/RemoteTargets_GdbPlusGdbserverViaSsh.png"
alt="Connect dialog for gdb + gdbserver via ssh" />
<figcaption aria-hidden="true">Connect dialog for gdb + gdbserver via
ssh</figcaption>
</figure></li>
<li><p>Read the wall of text, at least the first time, and verify the
remote system is prepared.</p></li>
<li><p>Fill out the options appropriately. Notably, correct the location
of the target image to point at its location on the <em>target</em>
system. Enter “user@10.0.0.1” for the <strong>[User@]Host</strong>
option, substituting your username for the remote system.</p></li>
<li><p>Click <strong>Launch</strong>.</p></li>
</ol>
<p>At this point, most things will work the same as they would for a
local target.</p>
</section>
<section id="using-trace-rmi-over-ssh" class="level2">
<h2>Using Trace RMI over SSH</h2>
<p>In this configuration, Ghidra will be located in the userls local
environment, while <code>gdb</code> and the specimen will be located in
the target environment. Notice that we are <em>not</em> using
<code>gdbserver</code>. We will connect the local Ghidra to the remote
<code>gdb</code> by forwarding Trace RMI over SSH. See the help (press
<strong><code>F1</code></strong> on the <strong>gdb via ssh</strong>
menu item for advantages and disadvantages of using this
vs. <code>gdbserver</code>.</p>
<ol type="1">
<li><p>First, prepare the target. This is more involved than using
<code>gdbserver</code>, since you will need to ensure <code>gdb</code>
and the Trace RMI plugin for it are installed. The packages, which
should be included with Ghidra, are <code>ghidratrace</code> and
<code>ghidragdb</code>. If you installed <code>gdb</code> and
<code>python3</code> from your distributions repositories, installation
of the Python packages should just be a matter of using
<code>pip</code>:</p>
<div class="sourceCode" id="cb1"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="ex">python3</span> <span class="at">-m</span> pip install /path/to/ghidratrace....whl</span></code></pre></div>
<p>Chances are, GDB embeds the same Python, so they become importable
from <code>gdb</code>:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode gdb"><code class="sourceCode gdbsyntax"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>python import ghidragdb</span></code></pre></div>
<p>You can quit GDB, since that was just for verifying the
installation.</p></li>
<li><p>From the launch menu, select <strong>gdb via ssh</strong>.</p>
<figure>
<img src="images/RemoteTargets_GdbViaSsh.png"
alt="Connect dialog for gdb via SSH" />
<figcaption aria-hidden="true">Connect dialog for gdb via
SSH</figcaption>
</figure></li>
<li><p>Set “GDB launch command” to the path of gdb <em>on the remote
file system</em>.</p></li>
<li><p>Leave “Use existing session via new-ui” unchecked.</p></li>
<li><p>Set “SSH hostname” to the name or IP address of the target
system.</p></li>
<li><p>If you are not using the standard SSH port, set “SSH TCP port”
accordingly.</p></li>
<li><p>Set “SSH username” to your username on the target
system.</p></li>
<li><p>Set “Open SSH config file” to the client config file <em>on the
local file system</em>.</p></li>
<li><p>If the remote uses DOS line endings (unlikely for a Linux
remote), then check the “Use DOS line endings” box.</p></li>
<li><p>Click Connect.</p></li>
<li><p>If prompted, enter your SSH credentials.</p></li>
<li><p>Fill out the options appropriately. Notably, correct the location
of the target image to point at its location on the <em>target</em>
system. Enter “user@10.0.0.1” for the <strong>[User@]Host</strong>
option, substituting your username for the remote system.</p></li>
<li><p>Click <strong>Launch</strong>.</p></li>
</ol>
<p>If everything goes well, the Objects window should populate, and you
should get an Interpreter window presenting the remote GDB CLI. You may
use it in the usual manner to launch your target. Alternatively, in the
Objects window, click the Launch or Quick Launch button to launch the
current program. If prompted for the target command line, remember you
must provide the path <em>on the remote file system</em>.</p>
<p>The target should now be added to the Debugger session, and things
should work as usual.</p>
</section>
<section id="using-gadp" class="level2">
<h2>Using GADP</h2>
<p>GADP (Ghidra Asynchronous Debugging Protocol) is a protocol
contributed by the Ghidra Debugger. It allows any of Ghidras back-end
connectors to be deployed as an <em>agent</em>. The agent connects to
the back-end as usual, but then opens a TCP socket and waits for Ghidra
to connect.</p>
<section id="using-gadp-locally" class="level3">
<h3>Using GADP Locally</h3>
<p>When debugging locally, the UI may offer “GADP” as an alternative to
“IN-VM”. If the back-end connector tends to crash Ghidra, you may prefer
to select GADP. Typically, GADP will slow things down as information is
marshalled across a TCP connection. However, if the connector crashes,
Ghidra will simply drop the connection, whereas the IN-VM connector
would crash Ghidra, too.</p>
</section>
<section id="using-gadp-remotely" class="level3">
<h3>Using GADP Remotely</h3>
<p>In this configuration, only Ghidra is required to be in the users
local environment. The target environment must have <code>gdb</code>,
<code>java</code>, and some portion of Ghidra installed.</p>
<p>If you can install Ghidra on the remote system, there is a script to
launch the headless agent:</p>
<p>At this point, most things will work the same as they would for a
local target.</p>
<section id="troubleshooting" class="level3">
<h3>Troubleshooting</h3>
<section id="i-cant-find-the-python-packages-to-install" class="level4">
<h4>I cant find the Python packages to install</h4>
<p>These should be located in the Ghidra installation. Search for files
ending in <code>.whl</code>. Alternatively, you can build the packages
from source. The source is included with Ghidra. If you are able to do
local debugging with Ghidra and <code>gdb</code>, then the source is
definitely present and functioning.</p>
<div class="sourceCode" id="cb3"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="bu">cd</span> /path/to/ghidra</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ex">support/gdbGADPServerRun</span> <span class="at">-h</span></span></code></pre></div>
<p>This should print help for you. Typically, you can just run the agent
without any extra command-line arguments:</p>
class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ex">python3</span> <span class="at">-m</span> pip install build</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="bu">cd</span> /path/to/ghidra/Ghidra/Debug/Debugger-rmi-trace/pypkg</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ex">python3</span> <span class="at">-m</span> build</span></code></pre></div>
<p>This should output a <code>.whl</code> file. Send that over to the
target system and install it. If that doesnt work, then in the worst
case, copy the Python source over and add it to your
<code>PYTHONPATH</code>.</p>
</section>
<section id="the-python-import-ghidragdb-command-fails" class="level4">
<h4>The <code>python import ghidragdb</code> command fails</h4>
<p>Double-check that you have installed all the required packages and
their dependencies. A common forgotten or incorrectly-versioned
dependency is <code>protobuf</code>. We developed using
<code>protobuf==3.20.3</code>.</p>
<p>It is also possible that <code>gdb</code> has embedded a different
version of the interpreter than the one that <code>python3</code>
provides. This can happen if you built GDB or Python yourself, or you
installed them from a non-standard repository. Check the actual path of
the Python library used by <code>gdb</code>:</p>
<div class="sourceCode" id="cb4"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ex">support/gdbGADPServerRun</span></span></code></pre></div>
<p>If not, then you probably just need to tell it where you installed
<code>gdb</code>:</p>
class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="fu">ldd</span> <span class="va">$(</span><span class="fu">which</span> gdb<span class="va">)</span></span></code></pre></div>
<p>Or, inside <code>gdb</code>:</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ex">support/gdbGADPServerRun</span> <span class="at">--agent-args</span> <span class="at">-g</span> /path/to/bin/gdb</span></code></pre></div>
<p>If you cannot install Ghidra, or do not want to, then you can build a
standalone jar. You will still need to install the JRE on the target,
likely the same version as recommended for Ghidra.</p>
<p>Refer to the root README file to get started with a build from
source. You may stop short of the <code>gradle buildGhidra</code> step,
though it may be helpful to avoid trouble. Then, build the executable
jar for the GDB agent:</p>
class="sourceCode gdb"><code class="sourceCode gdbsyntax"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>(gdb) python-interactive</span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>&gt;&gt;&gt; import sys</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>&gt;&gt;&gt; sys.version</span></code></pre></div>
<p>Suppose this identifies version 3.7. Retry the installation commands
using <code>python3.7 -m pip ...</code>. If you have multiple copies of
the same version in different locations, you may need to invoke
<code>python3</code> using its complete path.</p>
<p>In the worst case, copy the Python source over and add it to your
<code>PYTHONPATH</code>.</p>
</section>
</section>
</section>
<section id="using-gdbserver-manually" class="level2">
<h2>Using <code>gdbserver</code> manually</h2>
<p>The configuration and result here are similar using
<code>gdbserver</code> over SSH, but will be performed manually.</p>
<ol type="1">
<li><p>First, prepare the target. This time, you will need to start
<code>gdbserver</code> on the remote system manually. For demonstration,
we will listen on 10.0.0.1 port 12345:</p>
<div class="sourceCode" id="cb6"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ex">gradle</span> Debugger-agent-gdb:nodepJar</span></code></pre></div>
<p>This will create the file
<code>Ghidra/Debug/Debugger-agent-gdb/build/libs/Debugger-agent-gdb-nodep.jar</code>.
Copy the file to the target system. Now, run it:</p>
class="sourceCode bash"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="ex">gdbserver</span> 10.0.0.1:12345 termmines</span></code></pre></div></li>
<li><p>From the launch menu, select <strong>remote
gdb</strong>.</p></li>
<li><p>Fill out the options appropriately. Notably, enter “10.0.0.1” for
the <strong>Host</strong> option, and “12345” for the
<strong>Port</strong> option.</p></li>
<li><p>Click <strong>Launch</strong>.</p></li>
</ol>
<p>At this point, most things will work the same as they would for a
local target.</p>
</section>
<section id="connecting-trace-rmi-manually" class="level2">
<h2>Connecting Trace RMI manually</h2>
<p>The configuration and result here are similar to using Trace RMI over
SSH, but will be performed manually.</p>
<ol type="1">
<li><p>First, prepare the target. Follow the same installation steps as
above for Trace RMI over SSH, if you have not already.</p></li>
<li><p>In Ghidras Connections window, click <strong>Accept a single
inbound TCP connection</strong> in the local toolbar.</p>
<figure>
<img src="images/RemoteTargets_AcceptTraceRmi.png"
alt="TraceRMI Accept Dialog" />
<figcaption aria-hidden="true">TraceRMI Accept Dialog</figcaption>
</figure></li>
<li><p>Set <strong>Host/Address</strong> to “10.0.0.1”, so that we can
connect to it over the network. <strong>NOTE</strong>: You may leave the
port as “0” or pick a specific port, assuming you have permission to use
it.</p></li>
<li><p>Click <strong>Listen</strong>, and then take note of the
acceptors port number in the Connections window, e.g.,
“12345.”</p></li>
<li><p>Now, on the remote system, start <code>gdb</code> and type:</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="ex">java</span> <span class="at">-jar</span> Debugger-agent-gdb-nodep.jar <span class="at">-h</span></span></code></pre></div>
<p>Once the agent is running, it should print its port number, and you
can connect from Ghidra. For demonstration, we will assume it is
listening at 10.0.0.2 on port 15432.</p>
<ol type="1">
<li>From the Targets window, click Connect.</li>
<li>Select “Ghidra debug agent (GADP)” from the drop-down.</li>
<li>For “Agent network address”, enter 10.0.0.2.</li>
<li>For “Agent TCP port”, enter 15432.</li>
<li>Click Connect.</li>
class="sourceCode gdb"><code class="sourceCode gdbsyntax"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>python import ghidragdb</span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>file termmines</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a># set args, if you&#39;d like</span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>ghidra trace connect 10.0.0.1:12345</span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>ghidra trace start</span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>ghidra trace sync-enable</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>starti</span></code></pre></div></li>
</ol>
<p>That should complete the connection. You should see Objects populated
and get an Interpreter window. You can then proceed to launch or attach
a target in that connection using either the Objects window or the
Interpreter window.</p>
</section>
</section>
<section id="using-a-pty-pseudo-terminal" class="level2">
<h2>Using a pty (pseudo-terminal)</h2>
<p>If your copy of GDB supports the <code>new-ui</code> command (all
versions 8.0 and up should), then you may use any of the GDB connectors
(including the local IN-VM one) to join Ghidra to an existing GDB
session:</p>
<ol type="1">
<li><p>Run <code>gdb</code> from a proper terminal:</p>
<div class="sourceCode" id="cb8"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gdb</span> termmines</span></code></pre></div></li>
<li><p>If needed, do whatever you would like to do before connecting
with Ghidra.</p></li>
<li><p>In Ghidra, from the Targets window, click Connect, and select
<code>gdb</code>.</p></li>
<li><p>Check the “Use existing session via new-ui” box.</p></li>
<li><p>Click Connect.</p></li>
<li><p>You will be prompted with the name of a pseudo terminal, e.g.,
<code>/dev/pts/1</code>.</p></li>
<li><p>Back in <code>gdb</code>:</p>
<div class="sourceCode" id="cb9"><pre
class="sourceCode gdb"><code class="sourceCode gdbsyntax"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="kw">new-ui</span> /dev/pts/1</span></code></pre></div></li>
</ol>
<p>That should complete the connection. If there was a target active in
the existing GDB session, Ghidra should recognize it, and things should
work as usual. If there was not a target, then you should at least see
Objects populated and get an Interpreter window. You can then proceed to
launch or attach a target in that connection using either the Objects
window or the Interpreter window.</p>
<p>This same checkbox is available in the “gdb via SSH” connector. Note
that the remote system must support pseudo terminals, and the name of
the pseudo terminal is from the <em>remote file system</em>.</p>
<p>To activate this configuration in the standalone GADP agent, use the
<code>-x</code> option:</p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ex">java</span> <span class="at">-jar</span> Debugger-agent-gdb-node.jar <span class="at">--agent-args</span> <span class="at">-x</span></span></code></pre></div>
<p>At this point, most things will work the same as they would for a
local target. You may notice Ghidra has not given you a new terminal.
Just use the one you already have on the remote target.</p>
<p>A notable advantage of this configuration is that you can enter
whatever <code>gdb</code> commands you want to start your target. Here
we demonstrated the simplest case of a “native” target. It is also
possible to use this procedure to connect Ghidra into a running
<code>gdb</code> session.</p>
</section>
<section id="rube-goldberg-configurations" class="level2">
<h2>Rube Goldberg Configurations</h2>
@ -342,10 +361,10 @@ Android emulator.</p>
<h2>Exercise: Debug your Friends <code>termmines</code></h2>
<p>If you are in a classroom setting, pair up. Otherwise, play both
roles, preferably using separate machines for Ghidra and the target.
Using either <code>gdbserver</code>, gdb via SSH, or the GDB agent,
debug <code>termmines</code>. One of you should prepare the target
environment. The other should connect to it and launch the specimen.
Then trade roles, choose a different configuration, and do it again.</p>
Using one of the above procedures, debug <code>termmines</code>. One of
you should prepare the target environment. The other should connect to
it and launch the specimen. Then trade roles, choose a different
procedure, and do it again.</p>
</section>
</section>
</body>

View File

@ -20,166 +20,169 @@ Depending on your particular target and platform, there may be several options a
Consider a remote Linux target in user space.
While this list is not exhaustive, some options are:
* Use `gdbserver`
* Use SSH
* Use GADP
* Use a pty
* Use `gdbserver` over SSH
* Use Trace RMI over SSH
* Use `gdbserver` and connect to it manually
* Connect Trace RMI manually
Generally, for each of these options it boils down to which components will be colocated with the target and which will be colocated with Ghidra.
## Using `gdbserver`
## Using `gdbserver` over SSH
In this configuration, Ghidra and GDB will be located in the user's local environment, while `gdbserver` and the specimen will be located in the target environment.
The procedure follows directly from GDB's manual, but with some Ghidra-specific steps.
First, prepare the target, which for demonstration purposes has the IP address 10.0.0.1:
We will connect the local `gdb` to the remote `gdbserver` by forwarding stdio over SSH.
```bash
gdbserver 10.0.0.1:12345 termmines
```
1. First, prepare the target, which for demonstration purposes has the IP address 10.0.0.1.
Generally, this just means booting it up and ensuring it has `gdbserver` installed.
**NOTE**: You do not need to run `gdbserver` or the target binary.
The launcher will do that for you.
1. From the launch menu, select **gdb + gdbserver via ssh**.
Then, connect from Ghidra using GDB:
![Connect dialog for gdb + gdbserver via ssh](images/RemoteTargets_GdbPlusGdbserverViaSsh.png)
1. From the Targets window, click Connect, select "gdb," and click Connect.
1. In the Interpreter, do as you would in GDB:
1. Read the wall of text, at least the first time, and verify the remote system is prepared.
1. Fill out the options appropriately.
Notably, correct the location of the target image to point at its location on the *target* system.
Enter "user@10.0.0.1" for the **[User@]Host** option, substituting your username for the remote system.
1. Click **Launch**.
```gdb
target remote 10.0.0.1:12345
```
At this point, most things will work the same as they would for a local target.
The target should now be added to the Debugger session, and things should work as usual.
## Using Trace RMI over SSH
## Using SSH
In this configuration, Ghidra will be located in the user'ls local environment, while `gdb` and the specimen will be located in the target environment.
Notice that we are *not* using `gdbserver`.
We will connect the local Ghidra to the remote `gdb` by forwarding Trace RMI over SSH.
See the help (press **`F1`** on the **gdb via ssh** menu item for advantages and disadvantages of using this vs. `gdbserver`.
In this configuration, only Ghidra is required to be in the user's local environment, while `sshd`, `gdb` and the specimen will be located in the target environment.
**NOTE**: The full `gdb`, not just `gdbserver`, must be installed on the target system.
1. From the Targets window, click Connect, and select "gdb via SSH."
![Connect dialog for gdb via SSH](images/RemoteTargets_GdbOverSsh.png)
1. Set "GDB launch command" to the path of gdb *on the remote file system*.
1. Leave "Use existing session via new-ui" unchecked.
1. Set "SSH hostname" to the name or IP address of the target system.
1. If you are not using the standard SSH port, set "SSH TCP port" accordingly.
1. Set "SSH username" to your username on the target system.
1. Set "Open SSH config file" to the client config file *on the local file system*.
1. If the remote uses DOS line endings (unlikely for a Linux remote), then check the "Use DOS line endings" box.
1. Click Connect.
1. If prompted, enter your SSH credentials.
If everything goes well, the Objects window should populate, and you should get an Interpreter window presenting the remote GDB CLI.
You may use it in the usual manner to launch your target.
Alternatively, in the Objects window, click the Launch or Quick Launch button to launch the current program.
If prompted for the target command line, remember you must provide the path *on the remote file system*.
The target should now be added to the Debugger session, and things should work as usual.
## Using GADP
GADP (Ghidra Asynchronous Debugging Protocol) is a protocol contributed by the Ghidra Debugger.
It allows any of Ghidra's back-end connectors to be deployed as an *agent*.
The agent connects to the back-end as usual, but then opens a TCP socket and waits for Ghidra to connect.
### Using GADP Locally
When debugging locally, the UI may offer "GADP" as an alternative to "IN-VM".
If the back-end connector tends to crash Ghidra, you may prefer to select GADP.
Typically, GADP will slow things down as information is marshalled across a TCP connection.
However, if the connector crashes, Ghidra will simply drop the connection, whereas the IN-VM connector would crash Ghidra, too.
### Using GADP Remotely
In this configuration, only Ghidra is required to be in the user's local environment.
The target environment must have `gdb`, `java`, and some portion of Ghidra installed.
If you can install Ghidra on the remote system, there is a script to launch the headless agent:
```bash
cd /path/to/ghidra
support/gdbGADPServerRun -h
```
This should print help for you.
Typically, you can just run the agent without any extra command-line arguments:
```bash
support/gdbGADPServerRun
```
If not, then you probably just need to tell it where you installed `gdb`:
```bash
support/gdbGADPServerRun --agent-args -g /path/to/bin/gdb
```
If you cannot install Ghidra, or do not want to, then you can build a standalone jar.
You will still need to install the JRE on the target, likely the same version as recommended for Ghidra.
Refer to the root README file to get started with a build from source.
You may stop short of the `gradle buildGhidra` step, though it may be helpful to avoid trouble.
Then, build the executable jar for the GDB agent:
```bash
gradle Debugger-agent-gdb:nodepJar
```
This will create the file `Ghidra/Debug/Debugger-agent-gdb/build/libs/Debugger-agent-gdb-nodep.jar`.
Copy the file to the target system.
Now, run it:
```bash
java -jar Debugger-agent-gdb-nodep.jar -h
```
Once the agent is running, it should print its port number, and you can connect from Ghidra.
For demonstration, we will assume it is listening at 10.0.0.2 on port 15432.
1. From the Targets window, click Connect.
1. Select "Ghidra debug agent (GADP)" from the drop-down.
1. For "Agent network address", enter 10.0.0.2.
1. For "Agent TCP port", enter 15432.
1. Click Connect.
That should complete the connection.
You should see Objects populated and get an Interpreter window.
You can then proceed to launch or attach a target in that connection using either the Objects window or
the Interpreter window.
## Using a pty (pseudo-terminal)
If your copy of GDB supports the `new-ui` command (all versions 8.0 and up should), then you may use any of the GDB connectors (including the local IN-VM one) to join Ghidra to an existing GDB session:
1. Run `gdb` from a proper terminal:
1. First, prepare the target.
This is more involved than using `gdbserver`, since you will need to ensure `gdb` and the Trace RMI plugin for it are installed.
The packages, which should be included with Ghidra, are `ghidratrace` and `ghidragdb`.
If you installed `gdb` and `python3` from your distribution's repositories, installation of the Python packages should just be a matter of using `pip`:
```bash
gdb termmines
python3 -m pip install /path/to/ghidratrace....whl
```
1. If needed, do whatever you would like to do before connecting with Ghidra.
1. In Ghidra, from the Targets window, click Connect, and select `gdb`.
1. Check the "Use existing session via new-ui" box.
1. Click Connect.
1. You will be prompted with the name of a pseudo terminal, e.g., `/dev/pts/1`.
1. Back in `gdb`:
Chances are, GDB embeds the same Python, so they become importable from `gdb`:
```gdb
new-ui /dev/pts/1
python import ghidragdb
```
That should complete the connection.
If there was a target active in the existing GDB session, Ghidra should recognize it, and things should work as usual.
If there was not a target, then you should at least see Objects populated and get an Interpreter window.
You can then proceed to launch or attach a target in that connection using either the Objects window or the Interpreter window.
You can quit GDB, since that was just for verifying the installation.
This same checkbox is available in the "gdb via SSH" connector.
Note that the remote system must support pseudo terminals, and the name of the pseudo terminal is from the *remote file system*.
1. From the launch menu, select **gdb via ssh**.
To activate this configuration in the standalone GADP agent, use the `-x` option:
![Connect dialog for gdb via SSH](images/RemoteTargets_GdbViaSsh.png)
1. Fill out the options appropriately.
Notably, correct the location of the target image to point at its location on the *target* system.
Enter "user@10.0.0.1" for the **[User@]Host** option, substituting your username for the remote system.
1. Click **Launch**.
At this point, most things will work the same as they would for a local target.
### Troubleshooting
#### I can't find the Python packages to install
These should be located in the Ghidra installation.
Search for files ending in `.whl`.
Alternatively, you can build the packages from source.
The source is included with Ghidra.
If you are able to do local debugging with Ghidra and `gdb`, then the source is definitely present and functioning.
```bash
java -jar Debugger-agent-gdb-node.jar --agent-args -x
python3 -m pip install build
cd /path/to/ghidra/Ghidra/Debug/Debugger-rmi-trace/pypkg
python3 -m build
```
This should output a `.whl` file.
Send that over to the target system and install it.
If that doesn't work, then in the worst case, copy the Python source over and add it to your `PYTHONPATH`.
#### The `python import ghidragdb` command fails
Double-check that you have installed all the required packages and their dependencies.
A common forgotten or incorrectly-versioned dependency is `protobuf`.
We developed using `protobuf==3.20.3`.
It is also possible that `gdb` has embedded a different version of the interpreter than the one that `python3` provides.
This can happen if you built GDB or Python yourself, or you installed them from a non-standard repository.
Check the actual path of the Python library used by `gdb`:
```bash
ldd $(which gdb)
```
Or, inside `gdb`:
```gdb
(gdb) python-interactive
>>> import sys
>>> sys.version
```
Suppose this identifies version 3.7.
Retry the installation commands using `python3.7 -m pip ...`.
If you have multiple copies of the same version in different locations, you may need to invoke `python3` using its complete path.
In the worst case, copy the Python source over and add it to your `PYTHONPATH`.
## Using `gdbserver` manually
The configuration and result here are similar using `gdbserver` over SSH, but will be performed manually.
1. First, prepare the target.
This time, you will need to start `gdbserver` on the remote system manually.
For demonstration, we will listen on 10.0.0.1 port 12345:
```bash
gdbserver 10.0.0.1:12345 termmines
```
1. From the launch menu, select **remote gdb**.
1. Fill out the options appropriately.
Notably, enter "10.0.0.1" for the **Host** option, and "12345" for the **Port** option.
1. Click **Launch**.
At this point, most things will work the same as they would for a local target.
## Connecting Trace RMI manually
The configuration and result here are similar to using Trace RMI over SSH, but will be performed manually.
1. First, prepare the target.
Follow the same installation steps as above for Trace RMI over SSH, if you have not already.
1. In Ghidra's Connections window, click **Accept a single inbound TCP connection** in the local toolbar.
![TraceRMI Accept Dialog](images/RemoteTargets_AcceptTraceRmi.png)
1. Set **Host/Address** to "10.0.0.1", so that we can connect to it over the network.
**NOTE**: You may leave the port as "0" or pick a specific port, assuming you have permission to use it.
1. Click **Listen**, and then take note of the acceptor's port number in the Connections window, e.g., "12345."
1. Now, on the remote system, start `gdb` and type:
```gdb
python import ghidragdb
file termmines
# set args, if you'd like
ghidra trace connect 10.0.0.1:12345
ghidra trace start
ghidra trace sync-enable
starti
```
At this point, most things will work the same as they would for a local target.
You may notice Ghidra has not given you a new terminal.
Just use the one you already have on the remote target.
A notable advantage of this configuration is that you can enter whatever `gdb` commands you want to start your target.
Here we demonstrated the simplest case of a "native" target.
It is also possible to use this procedure to connect Ghidra into a running `gdb` session.
## Rube Goldberg Configurations
While you should always prefer the simpler configuration, it is possible to combine components to meet a variety of needs.
@ -189,7 +192,7 @@ For example, to debug a native Android target from Windows, you could run Ghidra
If you are in a classroom setting, pair up.
Otherwise, play both roles, preferably using separate machines for Ghidra and the target.
Using either `gdbserver`, gdb via SSH, or the GDB agent, debug `termmines`.
Using one of the above procedures, debug `termmines`.
One of you should prepare the target environment.
The other should connect to it and launch the specimen.
Then trade roles, choose a different configuration, and do it again.
Then trade roles, choose a different procedure, and do it again.

View File

@ -203,12 +203,14 @@ argument parsing function. It should be the first function called by
<code>main</code>.</li>
<li>Use a breakpoint to interrupt the live target when it enters this
function.</li>
<li>Change the “Control mode” drop-down to “Control Emulator.”</li>
<li>Click <img src="images/stepinto.png" alt="step into button" /> Step
Into to step the emulator forward.</li>
<li>Click <img src="images/skipover.png" alt="skip over button" /> Skip
Over and <img src="images/stepback.png" alt="step back button" /> Step
Back to experiment with different execution paths.</li>
<li>Change the <strong>Control mode</strong> drop-down to
<strong>Control Emulator</strong>.</li>
<li>Click <img src="images/stepinto.png" alt="step into button" />
<strong>Step Into</strong> to step the emulator forward.</li>
<li>Click <img src="images/skipover.png" alt="skip over button" />
<strong>Skip Over</strong> and <img src="images/stepback.png"
alt="step back button" /> <strong>Step Back</strong> to experiment with
different execution paths.</li>
</ol>
<p>About those two new actions:</p>
<ul>
@ -219,27 +221,27 @@ instruction.</li>
<strong>Step Back</strong>: Step the current thread backward one
instruction, or undo an emulated skip or patch.</li>
</ul>
<p>Try to get the program counter onto the call to <code>exit(-1)</code>
using only those three step buttons.</p>
<p><strong>Quick Exercise</strong>: Try to get the program counter onto
the call to <code>exit(-1)</code> using only those three step
buttons.</p>
<p>You should see things behave more or less the same as they would if
it were the live target. The main exceptions are the Objects and
Interpreter windows. Those always display the state of the live target,
as they are unaware of the emulator, and their sole purpose is to
interact with the live target. You can make changes to the emulators
machine state, set breakpoints, etc., just as you would in “Control
Target” mode. <strong>NOTE</strong>: You may see Ghidra interact with
the target, despite being in “Control Emulator” mode, because Ghidra
lazily initializes the emulators state. If the emulated target reads a
variable that Ghidra has not yet captured into the current snapshot,
Ghidra will read that variable from the live target, capture it, and
provide its value to the emulator.</p>
it were the live target. The main exception is the Terminal window. It
always displays the state of the live target, as it is unaware of the
emulator. You can make changes to the emulators machine state, set
breakpoints, etc., just as you would in <strong>Control Target</strong>
mode. <strong>NOTE</strong>: You may see Ghidra interact with the
target, despite being in <strong>Control Emulator</strong> mode, because
Ghidra lazily initializes the emulators state. If the emulated target
reads a variable that Ghidra has not yet captured into the current
snapshot, Ghidra will read that variable from the live target, capture
it, and provide its value to the emulator.</p>
<section id="stepping-schedules" class="level3">
<h3>Stepping Schedules</h3>
<p>If you had not noticed before, the subtitle of the Threads window
gives the current snapshot number. If you have stepped in the emulator,
it will also contain the sequence of steps emulated. Recall the
<em>time</em> element of the Debuggers “coordinates.” (See the <a
href="A5-Navigation.html">Navigation</a> module if you need a
<em>time</em> element of the Debuggers <em>coordinates</em>. (See the
<a href="A5-Navigation.html">Navigation</a> module if you need a
refresher.) The time element, called the <em>schedule</em>, consists of
both the current snapshot and the sequence of steps to emulate. The
subtitle displays that schedule. If you have done any patching of the
@ -282,17 +284,19 @@ with 0x1234, then step 10 instructions.</li>
<p>The explication of schedules allows Ghidra to cache emulated machine
states and manage its emulators internally. You can have Ghidra recall
or generate the machine state for any schedule by pressing
<strong>Ctrl-G</strong> or using <strong>Debugger → Go To Time</strong>
in the menus.</p>
<strong><code>CTRL</code>-<code>G</code></strong> or using
<strong>Debugger → Go To Time</strong> in the menus.</p>
<p>Assuming you got the program counter onto <code>exit(-1)</code>
earlier:</p>
<ol type="1">
<li>Write down the current schedule.</li>
<li>Change back to “Control Target” mode. Ghidra will navigate back to
the current snapshot, so PC will match the live target.</li>
<li>Press <strong>Ctrl-G</strong> and type or paste the schedule in, and
click OK. The program counter should be restored to
<code>exit(-1)</code>.</li>
<li>Change back to <strong>Control Target</strong> mode. Ghidra will
navigate back to the current snapshot, so PC will match the live
target.</li>
<li>Change back (again) to <strong>Control Emulator</strong> mode.</li>
<li>Press <strong><code>CTRL</code>-<code>G</code></strong> and type or
paste the schedule in, and click <strong>OK</strong>. The program
counter should be restored to <code>exit(-1)</code>.</li>
</ol>
<p><strong>NOTE</strong>: The thread IDs used in schedules are internal
to the current trace database. Most likely, they <em>do not</em>
@ -306,12 +310,12 @@ cells with mines. In this exercise, you will use extrapolation to
experiment and devise a patch to demonstrate all possible counts of
neighboring mines:</p>
<ol type="1">
<li>Run <code>termmines</code> in a proper terminal and attach to
it.</li>
<li>Launch <code>termmines</code> using GDB with <strong>Inferior
TTY</strong> enabled.</li>
<li>Use a breakpoint to trap it at the point where it has placed mines,
but before it has counted the neighboring cells with mines. (Use
<strong>Shift-R</strong> in <code>termmines</code> to reset the
game.)</li>
<strong><code>SHIFT</code>-<code>R</code></strong> in
<code>termmines</code> to reset the game.)</li>
<li>Use the emulator to extrapolate forward and begin understanding how
the algorithm works.</li>
<li>Move the mines by patching the board to demonstrate every number of
@ -384,56 +388,56 @@ listing following the program counter, then you are probably dealing
with self-modifying code.</p>
<p><strong>NOTE</strong>: If you prefer to see the Dynamic listing
initialized with the program image, you may select <strong>Load Emulator
from Program</strong> from the Auto-Read drop-down button in the Dynamic
Listing. The loading is still done lazily as each page is viewed in the
listing pane. You will want to change this back when debugging a live
target!</p>
from Program</strong> from the <strong>Auto-Read</strong> drop-down
button in the Dynamic Listing. The loading is still done lazily as each
page is viewed in the listing pane. You will want to change this back
when debugging a live target!</p>
<p>Because we can easily step back and forth as well as navigate to
arbitrary points in time, emulation should feel relatively free of risk;
however, the point about stubbing dependencies will become apparent. If
you feel the need to start over, there are two methods: First, you can
end the emulation session and restart it. To end the session, in the
Threads panel, right-click the “Emulate termmines” tab and select Close.
You can then restart by right-clicking the first instruction as before.
Second, you can use <strong>Ctrl-G</strong> to go to snapshot 0. This
method is not as clean as the first, because the trace will retain its
scratch snapshots.</p>
<p>Press <img src="images/resume.png" alt="resume button" /> Resume to
let the emulator run until it crashes. It should crash pretty quickly
and without much ceremony:</p>
end the emulation session and restart it. To end the session, close the
“Emulate termmines” tab in the Dynamic Listing window. You can then
restart by right-clicking the first instruction as before. Second, you
can use <strong><code>CTRL</code>-<code>G</code></strong> to go to
snapshot 0. This method is not as clean as the first, because the trace
will retain its scratch snapshots.</p>
<p>Press <img src="images/resume.png" alt="resume button" />
<strong>Resume</strong> to let the emulator run until it crashes. It
should crash pretty quickly and without much ceremony:</p>
<figure>
<img src="images/Emulation_ListingAfterResume.png"
alt="Listing after crashing" />
<figcaption aria-hidden="true">Listing after crashing</figcaption>
</figure>
<p>In this case, the clearest indication that something has gone wrong
is in the top-right of the Dynamic listing. Recall that the location
is in the top-right of the Dynamic Listing. Recall that the location
label is displayed in red when the program counter points outside of
mapped memory. Presumably, the crash was caused by the instruction to be
executed next. To get details about the error, press <img
src="images/stepinto.png" alt="step into button" /> Step Into. This
should display an error dialog with a full trace of the crash. In this
case, it should be an instruction decode error. When the emulator reads
uninitialized memory, it will get stale 0s; however, when the emulator
tries to <em>execute</em> uninitialized memory, it will crash. Most
likely, the target called an external function, causing the program
counter to land in the fake <code>EXTERNAL</code> block.</p>
src="images/stepinto.png" alt="step into button" /> <strong>Step
Into</strong>. This should display an error dialog with a full trace of
the crash. In this case, it should be an instruction decode error. When
the emulator reads uninitialized memory, it will get stale 0s; however,
when the emulator tries to <em>execute</em> uninitialized memory, it
will crash. Most likely, the target called an external function, causing
the program counter to land in the fake <code>EXTERNAL</code> block.</p>
<p>To diagnose the crash, press <img src="images/stepback.png"
alt="step back button" /> Step Back. After a couple steps back, you
should be able to confirm our hypothesis: we got here through a call to
the external function <code>printf</code>. You can continue stepping
back until you find the decision point that took us down this path. You
should notice it was because <code>param_1</code> was 0. The decompiler
can help you recognize that at a glance, but you will still want to use
the disassembly to get at precisely the deciding instruction. The
<code>JZ</code> (or other conditional jump) is too late; you need to
step back to the <code>TEST EDI,EDI</code> (or similar) instruction.
(This may, ironically, be the first instruction of the function.) In the
System V AMD64 ABI (Linux x86-64 calling conventions) <code>RDI</code>
is used to pass the first parameter. You can hover your mouse over
<code>param_1</code> in the Decompiler, and it will tell you the
location is <code>EDI:4</code>, and that its current value is a stale
0.</p>
alt="step back button" /> <strong>Step Back</strong>. After a couple
steps back, you should be able to confirm our hypothesis: we got here
through a call to the external function <code>printf</code>. You can
continue stepping back until you find the decision point that took us
down this path. You should notice it was because <code>param_1</code>
was 0. The decompiler can help you recognize that at a glance, but you
will still want to use the disassembly to get at precisely the deciding
instruction. The <code>JZ</code> (or other conditional jump) is too
late; you need to step back to the <code>TEST EDI,EDI</code> (or
similar) instruction. (This may, ironically, be the first instruction of
the function.) In the System V AMD64 ABI (Linux x86-64 calling
conventions) <code>RDI</code> is used to pass the first parameter. You
can hover your mouse over <code>param_1</code> in the Decompiler, and it
will tell you the location is <code>EDI:4</code>, and that its current
value is a stale 0.</p>
<section id="initializing-other-state" class="level3">
<h3>Initializing Other State</h3>
<p>We had just started executing the target function arbitrarily. Ghidra
@ -465,13 +469,14 @@ remember to invalidate the emulator cache any time you change the
initial state. For this tutorial, we will perform the patches in the
emulator.</p>
<p><strong>NOTE</strong>: If you wish to try patching the trace, then
change to “Control Trace” mode and use the “Navigate backward one
snapshot” control action that appears, so that you are patching the
initial state, and not a scratch snapshot. Scratch snapshots are
ephemeral snapshots in the trace used to display emulated state. Changes
to these snapshots will affect the display, but will not affect
subsequent emulation. If your current schedule includes any steps, then
“Control Trace” is patching a scratch snapshot.</p>
change to <strong>Control Trace</strong> mode and use the
<strong>Navigate backward one snapshot</strong> control action that
appears, so that you are patching the initial state, and not a scratch
snapshot. Scratch snapshots are ephemeral snapshots in the trace used to
display emulated state. Changes to these snapshots will affect the
display, but will not affect subsequent emulation. If your current
schedule includes any steps, then <strong>Control Trace</strong> is
patching a scratch snapshot.</p>
<p>Now, we will manually “allocate” memory for <code>argv</code>.
Luckily, Ghidra allocated 16K of stack space for us! The target function
should not need a full 16K, so we will allocate the lowest addresses of
@ -480,7 +485,7 @@ use the <strong>Add Region</strong> action in the Regions window to
manually fabricate a heap region, instead. In the Regions window, filter
for “stack” and take note of the start address, e.g.,
<code>00001000</code>. We will use the Watches window to perform our
patching, though we will also use the Dynamic listing to double check.
patching, though we will also use the Dynamic Listing to double check.
Add the following watches:</p>
<ul>
<li><code>RSP</code> — to confirm the stack pointer is far from
@ -503,15 +508,15 @@ possible we may only need to initialize <code>argc</code>, since the
parser may not actually <em>use</em> the value of
<code>argv[0]</code>.</p>
<p>Use the Watches window to set <code>RDI</code> to 1, then click <img
src="images/resume.png" alt="resume button" /> Resume. Like before, the
emulator will crash, but this time you should see “pc = 00000000” in
red. This probably indicates success. In the Threads window, you should
see a schedule similar to <code>0:t0-{RDI=0x1);t0-16</code>. This tells
us we first patched RDI, then emulated 16 machine instructions before
crashing. When the parser function returned, it probably read a stale 0
as the return address, so we would expect a decode error at
<code>00000000</code>. Step backward once to confirm this
hypothesis.</p>
src="images/resume.png" alt="resume button" /> <strong>Resume</strong>.
Like before, the emulator will crash, but this time you should see “pc =
00000000” in red. This probably indicates success. In the Threads
window, you should see a schedule similar to
<code>0:t0-{RDI=0x1);t0-16</code>. This tells us we first patched RDI,
then emulated 16 machine instructions before crashing. When the parser
function returned, it probably read a stale 0 as the return address, so
we would expect a decode error at <code>00000000</code>. Step backward
once to confirm this hypothesis.</p>
</section>
<section id="stubbing-external-calls" class="level3">
<h3>Stubbing External Calls</h3>
@ -520,8 +525,8 @@ patching in actual command-line arguments. This continues our lesson in
state initialization, but we may also need to stub some external calls,
e.g., to <code>strnlen</code> and <code>strcmp</code>. We will need to
pass in <code>termmines -s Advanced</code>, which is three arguments.
Use <strong>Ctrl-G</strong> to go back to snapshot 0, and add the
following watches:</p>
Use <strong><code>CTRL</code>-<code>G</code></strong> to go back to
snapshot 0, and add the following watches:</p>
<ul>
<li><code>*:8 (RSI + 0)</code> — the address of the first argument,
i.e., <code>argv[0]</code>.</li>
@ -552,20 +557,21 @@ is at the upper end of the stack region, so we allocate
<code>argv</code> at <code>00001000</code>. To do that, set the value of
<code>RSI</code> to <code>0x1000</code>. You should see the Address
column update for some other watches. You can double-click any of those
addresses to go there in the Dynamic listing.</p>
addresses to go there in the Dynamic Listing.</p>
<p><strong>NOTE</strong>: You <em>do not have</em> to allocate things in
a listed region, but if you want to see those things in the Dynamic
listing, it is easiest if you allocate them in a listed region.</p>
Listing, it is easiest if you allocate them in a listed region.</p>
<p>Now, we need to allocate space for each arguments string. To ensure
we do not collide with the space we have already allocated for
<code>argv</code>, we should place a data unit in the Dynamic listing.
Double-click the Address <code>00001000</code> in the Watches window to
go to that address in the Dynamic listing. Press <strong>P</strong> then
<strong>[</strong> (left square bracket) to place a 3-pointer array at
that address. We can now see the next available byte is at
<code>00001018</code>. <strong>NOTE</strong>: You might set the Dynamic
listing to <strong>Do Not Track</strong>, otherwise it may seek back to
the PC every time you patch.</p>
go to that address in the Dynamic Listing. Press
<strong><code>P</code></strong> then <strong><code>[</code></strong>
(left square bracket) to place a 3-pointer array at that address. We can
now see the next available byte is at <code>00001018</code>.
<strong>NOTE</strong>: You might set the Dynamic Listing to <strong>Do
Not Track</strong>, otherwise it may seek back to the PC every time you
patch.</p>
<p>Now that we know where to put <code>argv[0]</code>, we need to patch
it to <code>0x0001018</code>. This should be the watch on
<code>*:8 (RSI + 0)</code>. When you modify the Value column, you can
@ -574,19 +580,20 @@ type either bytes (in little-endian order for x86) or the integer value
<code>*:30 (*:8 (RSI + 0))</code> to get the address
<code>00001018</code>. Using the Repr column, set that watchs value to
<code>"termmines"</code>. (The quotes are required.) Place a string in
the Dynamic listing using the <strong></strong> (apostrophe) key. This
shows us the next available address is <code>00001022</code>, so repeat
the process to allocate <code>argv[1]</code> and set it to
<code>"-s"</code>. Then finally, allocate <code>argv[2]</code> and set
it to <code>"Advanced"</code>. When you have finished, the Watches pane
should look something like this:</p>
the Dynamic Listing using the <strong><code>'</code></strong>
(apostrophe) key. This shows us the next available address is
<code>00001022</code>, so repeat the process to allocate
<code>argv[1]</code> and set it to <code>"-s"</code>. Then finally,
allocate <code>argv[2]</code> and set it to <code>"Advanced"</code>.
When you have finished, the Watches pane should look something like
this:</p>
<figure>
<img src="images/Emulation_WatchesForCmdlineSet.png"
alt="Watches for patching command-line arguments after setting" />
<figcaption aria-hidden="true">Watches for patching command-line
arguments after setting</figcaption>
</figure>
<p>The Dynamic listing should look something like this:</p>
<p>The Dynamic Listing should look something like this:</p>
<figure>
<img src="images/Emulation_ListingForCmdlineSet.png"
alt="Listing after setting command-line arguments" />
@ -598,12 +605,12 @@ for the emulator to operate; it only cares about the bytes. However, it
is a useful aide in devising, understanding, and diagnosing machine
state.</p>
<p>Now, click <img src="images/resume.png" alt="resume button" />
Resume, and see where the emulator crashes next. Depending on your
compilation of <code>termmines</code>, it may crash after returning, or
it may crash trying to call <code>strnlen</code> or <code>strcmp</code>.
If the program counter is <code>00000000</code>, then it returned
successfully. This is unfortunate, because you no longer have motivation
to stub external calls.</p>
<strong>Resume</strong>, and see where the emulator crashes next.
Depending on your compilation of <code>termmines</code>, it may crash
after returning, or it may crash trying to call <code>strnlen</code> or
<code>strcmp</code>. If the program counter is <code>00000000</code>,
then it returned successfully. This is unfortunate, because you no
longer have motivation to stub external calls.</p>
<p>If the program counter is not <code>00000000</code>, then step
backward until you get to the <code>CALL</code>. There are at least
three techniques for overcoming this.</p>
@ -618,9 +625,10 @@ breakpoint.</li>
<h4>Skip Technique</h4>
<p>The skip technique is simplest, but will need to be performed
<em>every time</em> that call is encountered. Press <img
src="images/skipover.png" alt="skip over button" /> Skip Over, then use
the Registers or Watches pane to patch <code>RAX</code>. Then press <img
src="images/resume.png" alt="resume button" /> Resume.</p>
src="images/skipover.png" alt="skip over button" /> <strong>Skip
Over</strong>, then use the Registers or Watches pane to patch
<code>RAX</code>. Then press <img src="images/resume.png"
alt="resume button" /> <strong>Resume</strong>.</p>
</section>
<section id="call-override-technique" class="level4">
<h4><code>CALL</code> Override Technique</h4>
@ -628,8 +636,8 @@ src="images/resume.png" alt="resume button" /> Resume.</p>
will handle every encounter, it will not handle other calls to the same
external function.</p>
<ol type="1">
<li>Press <strong>K</strong> in the listing to place a breakpoint on the
<code>CALL</code> instruction.</li>
<li>Press <strong><code>K</code></strong> in the listing to place a
breakpoint on the <code>CALL</code> instruction.</li>
<li>Now, in the Breakpoints panel, right-click the new breakpoint and
select <strong>Set Injection (Emulator)</strong>.</li>
<li>This is the fun part: you must now implement the function in Sleigh,
@ -677,11 +685,11 @@ allows you to maintain breakpoint behavior, perhaps to debug your
injection.</p>
<p>After you have written your Sleigh code:</p>
<ol type="1">
<li>Click OK on the Set Injection dialog.</li>
<li>Click <strong>OK</strong> on the Set Injection dialog.</li>
<li>In the menus, select <strong>Debugger → Configure Emulator →
Invalidate Emulator Cache</strong>.</li>
<li>Click <img src="images/resume.png" alt="resume button" />
Resume.</li>
<strong>Resume</strong>.</li>
</ol>
<p>Stubbing any remaining external calls is left as an exercise. You are
successful when the emulator crashes with
@ -695,7 +703,7 @@ again before proceeding to the next technique.</p>
involved. It will handle all calls to the external function, e.g.,
<code>strnlen</code>, no matter the call site. If the call goes through
a program linkage table (PLT), then you are in luck, because the call
target will be visible in the Dynamic listing. The PLT entry usually
target will be visible in the Dynamic Listing. The PLT entry usually
contains a single <code>JMP</code> instruction to the actual
<code>strnlen</code>. For real target processes, the <code>JMP</code>
instruction will transfer control to a lazy linker the first time
@ -703,7 +711,7 @@ instruction will transfer control to a lazy linker the first time
then finds <code>strnlen</code> and patches the table. In contrast, the
Ghidra loader immediately patches the table to point to a fake
<code>&lt;EXTERNAL&gt;::strnlen</code> symbol. The <code>EXTERNAL</code>
block is not visible in the Dynamic listing, so we will override the
block is not visible in the Dynamic Listing, so we will override the
<code>JMP</code> in the PLT.</p>
<p>The Sleigh code is nearly identical, but we must code an x86
<code>RET</code> into it. Because we allow the <code>CALL</code> to
@ -736,10 +744,10 @@ particulars of the target function, emulating a program image can be
quite involved. Whatever technique you choose, once you have
successfully returned from the command-line argument parser, you should
check for the expected effects.</p>
<p>In the Static listing, navigate to the variable that stores the
<p>In the Static Listing, navigate to the variable that stores the
boards dimensions. (Finding that variable is a task in the Beginner
portion, but it can be found pretty easily with some manual static
analysis.) In the Dynamic listing, you should notice that the values
analysis.) In the Dynamic Listing, you should notice that the values
have changed to reflect the Advanced skill level.</p>
</section>
<section id="optional-exercise-patch-the-placement-algorithm"
@ -748,11 +756,12 @@ class="level3">
<p>In this exercise, you will use emulation to devise an assembly patch
to <code>termmines</code> to change the mine placement algorithm.
Instead of random placement, please have them placed left to right, top
to bottom. We recommend you devise your patch using the Assembler (Patch
Instruction action) in the Static listing, then test and debug your
patch using the Emulator. Perhaps patch the Dynamic listing to try quick
tweaks before committing them to the Static listing. Once you have it,
export the patched binary and run it in a proper terminal.</p>
to bottom. We recommend you devise your patch using the Assembler
(<strong>Patch Instruction</strong> action) in the Static Listing, then
test and debug your patch using the Emulator. Perhaps patch the Dynamic
Listing to try quick tweaks before committing them to the Static
Listing. Once you have it, export the patched binary and run it outside
of Ghidra.</p>
</section>
</section>
<section id="debugging-p-code-semantics" class="level2">
@ -769,11 +778,11 @@ tool, so it must be configured:</p>
<ol type="1">
<li>If you have not already, open the Debugger tool.</li>
<li>In the menus, select <strong>File → Configure</strong>.</li>
<li>Click the “Configure All Plugins” button in the top right of the
dialog.</li>
<li>Click the <strong>Configure All Plugins</strong> button in the top
right of the dialog.</li>
<li>Activate the <code>DebuggerPcodeStepperPlugin</code></li>
<li>Click OK</li>
<li>Click Close</li>
<li>Click <strong>OK</strong></li>
<li>Click <strong>Close</strong></li>
</ol>
<p>The stepper should appear stacked over the Threads panel in the
bottom right. Yours will probably still be empty, but here is what it
@ -791,10 +800,11 @@ instruction is overridden by a Sleigh breakpoint, the listing will
populate with the injected ops instead. You can then step forward and
backward within those. As you step, the other windows that display
machine state will update.</p>
<p>In addition to registers and memory, p-code has “unique” variables.
These are temporary variables used only within an instructions
implementation. They are displayed in the right panel. The table of
variables works similarly to the Registers pane. The columns are:</p>
<p>In addition to registers and memory, p-code has <em>unique</em>
variables. These are temporary variables used only within an
instructions implementation. They are displayed in the right panel. The
table of variables works similarly to the Registers pane. The columns
are:</p>
<ul>
<li>The <strong>Unique</strong> column gives the variables name and
size in bytes.</li>
@ -813,10 +823,10 @@ the steppers subtitle as well as the Threads panels subtitle. P-code
stepping is denoted by the portion of the schedule following the dot.
<strong>NOTE</strong>: You cannot mix instruction steps with p-code op
steps. The instruction steps always precede the p-code ops. If you click
Step Into from the global toolbar in the middle of an instruction, the
trailing p-code op steps will be removed and replaced with a single
instruction step. In most cases, this intuitively “finishes” the partial
instruction.</p>
<strong>Step Into</strong> from the global toolbar in the middle of an
instruction, the trailing p-code op steps will be removed and replaced
with a single instruction step. In most cases, this intuitively
“finishes” the partial instruction.</p>
</section>
</section>
</body>

View File

@ -51,9 +51,9 @@ In this tutorial, we will examine the command-line argument parser in `termmines
1. If you have not already, do a bit of static analysis to identify the argument parsing function.
It should be the first function called by `main`.
1. Use a breakpoint to interrupt the live target when it enters this function.
1. Change the "Control mode" drop-down to "Control Emulator."
1. Click ![step into button](images/stepinto.png) Step Into to step the emulator forward.
1. Click ![skip over button](images/skipover.png) Skip Over and ![step back button](images/stepback.png) Step Back to experiment with different execution paths.
1. Change the **Control mode** drop-down to **Control Emulator**.
1. Click ![step into button](images/stepinto.png) **Step Into** to step the emulator forward.
1. Click ![skip over button](images/skipover.png) **Skip Over** and ![step back button](images/stepback.png) **Step Back** to experiment with different execution paths.
About those two new actions:
@ -62,20 +62,20 @@ About those two new actions:
* ![step back button](images/stepback.png) **Step Back**:
Step the current thread backward one instruction, or undo an emulated skip or patch.
Try to get the program counter onto the call to `exit(-1)` using only those three step buttons.
**Quick Exercise**: Try to get the program counter onto the call to `exit(-1)` using only those three step buttons.
You should see things behave more or less the same as they would if it were the live target.
The main exceptions are the Objects and Interpreter windows.
Those always display the state of the live target, as they are unaware of the emulator, and their sole purpose is to interact with the live target.
You can make changes to the emulator's machine state, set breakpoints, etc., just as you would in "Control Target" mode.
**NOTE**: You may see Ghidra interact with the target, despite being in "Control Emulator" mode, because Ghidra lazily initializes the emulator's state.
The main exception is the Terminal window.
It always displays the state of the live target, as it is unaware of the emulator.
You can make changes to the emulator's machine state, set breakpoints, etc., just as you would in **Control Target** mode.
**NOTE**: You may see Ghidra interact with the target, despite being in **Control Emulator** mode, because Ghidra lazily initializes the emulator's state.
If the emulated target reads a variable that Ghidra has not yet captured into the current snapshot, Ghidra will read that variable from the live target, capture it, and provide its value to the emulator.
### Stepping Schedules
If you had not noticed before, the subtitle of the Threads window gives the current snapshot number.
If you have stepped in the emulator, it will also contain the sequence of steps emulated.
Recall the *time* element of the Debugger's "coordinates."
Recall the *time* element of the Debugger's *coordinates*.
(See the [Navigation](A5-Navigation.md) module if you need a refresher.)
The time element, called the *schedule*, consists of both the current snapshot and the sequence of steps to emulate.
The subtitle displays that schedule.
@ -106,14 +106,15 @@ Here are some examples:
* `3:{RAX=0x1234};10` &mdash; Start at snapshot 3. Override RAX with 0x1234, then step 10 instructions.
The explication of schedules allows Ghidra to cache emulated machine states and manage its emulators internally.
You can have Ghidra recall or generate the machine state for any schedule by pressing **Ctrl-G** or using **Debugger &rarr; Go To Time** in the menus.
You can have Ghidra recall or generate the machine state for any schedule by pressing **`CTRL`-`G`** or using **Debugger &rarr; Go To Time** in the menus.
Assuming you got the program counter onto `exit(-1)` earlier:
1. Write down the current schedule.
1. Change back to "Control Target" mode.
1. Change back to **Control Target** mode.
Ghidra will navigate back to the current snapshot, so PC will match the live target.
1. Press **Ctrl-G** and type or paste the schedule in, and click OK.
1. Change back (again) to **Control Emulator** mode.
1. Press **`CTRL`-`G`** and type or paste the schedule in, and click **OK**.
The program counter should be restored to `exit(-1)`.
**NOTE**: The thread IDs used in schedules are internal to the current trace database.
@ -124,9 +125,9 @@ Most likely, they *do not* correspond to the thread IDs assigned by the back-end
The board setup routine in `termmines` first places mines randomly and then, for each empty cell, counts the number of neighboring cells with mines.
In this exercise, you will use extrapolation to experiment and devise a patch to demonstrate all possible counts of neighboring mines:
1. Run `termmines` in a proper terminal and attach to it.
1. Launch `termmines` using GDB with **Inferior TTY** enabled.
1. Use a breakpoint to trap it at the point where it has placed mines, but before it has counted the neighboring cells with mines.
(Use **Shift-R** in `termmines` to reset the game.)
(Use **`SHIFT`-`R`** in `termmines` to reset the game.)
1. Use the emulator to extrapolate forward and begin understanding how the algorithm works.
1. Move the mines by patching the board to demonstrate every number of neighboring mines.
That is, when the board is revealed at the end of the game, all the numbers 1 through 8 should appear somewhere.
@ -172,33 +173,33 @@ This spares the loader from having to copy a potentially large program image int
In general, you should refer to the Static listing when following the program counter.
If you see contents in the Dynamic listing following the program counter, then you are probably dealing with self-modifying code.
**NOTE**: If you prefer to see the Dynamic listing initialized with the program image, you may select **Load Emulator from Program** from the Auto-Read drop-down button in the Dynamic Listing.
**NOTE**: If you prefer to see the Dynamic listing initialized with the program image, you may select **Load Emulator from Program** from the **Auto-Read** drop-down button in the Dynamic Listing.
The loading is still done lazily as each page is viewed in the listing pane.
You will want to change this back when debugging a live target!
Because we can easily step back and forth as well as navigate to arbitrary points in time, emulation should feel relatively free of risk; however, the point about stubbing dependencies will become apparent.
If you feel the need to start over, there are two methods:
First, you can end the emulation session and restart it.
To end the session, in the Threads panel, right-click the "Emulate termmines" tab and select Close.
To end the session, close the "Emulate termmines" tab in the Dynamic Listing window.
You can then restart by right-clicking the first instruction as before.
Second, you can use **Ctrl-G** to go to snapshot 0.
Second, you can use **`CTRL`-`G`** to go to snapshot 0.
This method is not as clean as the first, because the trace will retain its scratch snapshots.
Press ![resume button](images/resume.png) Resume to let the emulator run until it crashes.
Press ![resume button](images/resume.png) **Resume** to let the emulator run until it crashes.
It should crash pretty quickly and without much ceremony:
![Listing after crashing](images/Emulation_ListingAfterResume.png)
In this case, the clearest indication that something has gone wrong is in the top-right of the Dynamic listing.
In this case, the clearest indication that something has gone wrong is in the top-right of the Dynamic Listing.
Recall that the location label is displayed in red when the program counter points outside of mapped memory.
Presumably, the crash was caused by the instruction to be executed next.
To get details about the error, press ![step into button](images/stepinto.png) Step Into.
To get details about the error, press ![step into button](images/stepinto.png) **Step Into**.
This should display an error dialog with a full trace of the crash.
In this case, it should be an instruction decode error.
When the emulator reads uninitialized memory, it will get stale 0s; however, when the emulator tries to *execute* uninitialized memory, it will crash.
Most likely, the target called an external function, causing the program counter to land in the fake `EXTERNAL` block.
To diagnose the crash, press ![step back button](images/stepback.png) Step Back.
To diagnose the crash, press ![step back button](images/stepback.png) **Step Back**.
After a couple steps back, you should be able to confirm our hypothesis: we got here through a call to the external function `printf`.
You can continue stepping back until you find the decision point that took us down this path.
You should notice it was because `param_1` was 0.
@ -233,17 +234,17 @@ The advantage to patching the trace is that once you have completed your experim
The disadvantage is that you will need to remember to invalidate the emulator cache any time you change the initial state.
For this tutorial, we will perform the patches in the emulator.
**NOTE**: If you wish to try patching the trace, then change to "Control Trace" mode and use the "Navigate backward one snapshot" control action that appears, so that you are patching the initial state, and not a scratch snapshot.
**NOTE**: If you wish to try patching the trace, then change to **Control Trace** mode and use the **Navigate backward one snapshot** control action that appears, so that you are patching the initial state, and not a scratch snapshot.
Scratch snapshots are ephemeral snapshots in the trace used to display emulated state.
Changes to these snapshots will affect the display, but will not affect subsequent emulation.
If your current schedule includes any steps, then "Control Trace" is patching a scratch snapshot.
If your current schedule includes any steps, then **Control Trace** is patching a scratch snapshot.
Now, we will manually "allocate" memory for `argv`.
Luckily, Ghidra allocated 16K of stack space for us!
The target function should not need a full 16K, so we will allocate the lowest addresses of the stack region for our command-line arguments.
If you prefer, you may use the **Add Region** action in the Regions window to manually fabricate a heap region, instead.
In the Regions window, filter for "stack" and take note of the start address, e.g., `00001000`.
We will use the Watches window to perform our patching, though we will also use the Dynamic listing to double check.
We will use the Watches window to perform our patching, though we will also use the Dynamic Listing to double check.
Add the following watches:
* `RSP` &mdash; to confirm the stack pointer is far from `argv`.
@ -258,7 +259,7 @@ First, if the binary actually implements many commands, like `busybox` does, the
Second, if the binary needs to print usage information, it may like to echo back the actual invocation.
It is possible we may only need to initialize `argc`, since the parser may not actually *use* the value of `argv[0]`.
Use the Watches window to set `RDI` to 1, then click ![resume button](images/resume.png) Resume.
Use the Watches window to set `RDI` to 1, then click ![resume button](images/resume.png) **Resume**.
Like before, the emulator will crash, but this time you should see "pc = 00000000" in red.
This probably indicates success.
In the Threads window, you should see a schedule similar to `0:t0-{RDI=0x1);t0-16`.
@ -271,7 +272,7 @@ Step backward once to confirm this hypothesis.
For this tutorial, we will set the skill level to Advanced by patching in actual command-line arguments.
This continues our lesson in state initialization, but we may also need to stub some external calls, e.g., to `strnlen` and `strcmp`.
We will need to pass in `termmines -s Advanced`, which is three arguments.
Use **Ctrl-G** to go back to snapshot 0, and add the following watches:
Use **`CTRL`-`G`** to go back to snapshot 0, and add the following watches:
* `*:8 (RSI + 0)` &mdash; the address of the first argument, i.e., `argv[0]`.
* `*:30 (*:8 (RSI + 0))` with type `TerminatedCString` &mdash; at most 30 characters of the first argument.
@ -289,16 +290,16 @@ That was determined by the value of `RSI`, which is essentially telling us we ne
We can confirm `RSP` is at the upper end of the stack region, so we allocate `argv` at `00001000`.
To do that, set the value of `RSI` to `0x1000`.
You should see the Address column update for some other watches.
You can double-click any of those addresses to go there in the Dynamic listing.
You can double-click any of those addresses to go there in the Dynamic Listing.
**NOTE**: You *do not have* to allocate things in a listed region, but if you want to see those things in the Dynamic listing, it is easiest if you allocate them in a listed region.
**NOTE**: You *do not have* to allocate things in a listed region, but if you want to see those things in the Dynamic Listing, it is easiest if you allocate them in a listed region.
Now, we need to allocate space for each argument's string.
To ensure we do not collide with the space we have already allocated for `argv`, we should place a data unit in the Dynamic listing.
Double-click the Address `00001000` in the Watches window to go to that address in the Dynamic listing.
Press **P** then **[** (left square bracket) to place a 3-pointer array at that address.
Double-click the Address `00001000` in the Watches window to go to that address in the Dynamic Listing.
Press **`P`** then **`[`** (left square bracket) to place a 3-pointer array at that address.
We can now see the next available byte is at `00001018`.
**NOTE**: You might set the Dynamic listing to **Do Not Track**, otherwise it may seek back to the PC every time you patch.
**NOTE**: You might set the Dynamic Listing to **Do Not Track**, otherwise it may seek back to the PC every time you patch.
Now that we know where to put `argv[0]`, we need to patch it to `0x0001018`.
This should be the watch on `*:8 (RSI + 0)`.
@ -306,21 +307,21 @@ When you modify the Value column, you can type either bytes (in little-endian or
That should cause the watch on `*:30 (*:8 (RSI + 0))` to get the address `00001018`.
Using the Repr column, set that watch's value to `"termmines"`.
(The quotes are required.)
Place a string in the Dynamic listing using the **'** (apostrophe) key.
Place a string in the Dynamic Listing using the **`'`** (apostrophe) key.
This shows us the next available address is `00001022`, so repeat the process to allocate `argv[1]` and set it to `"-s"`.
Then finally, allocate `argv[2]` and set it to `"Advanced"`.
When you have finished, the Watches pane should look something like this:
![Watches for patching command-line arguments after setting](images/Emulation_WatchesForCmdlineSet.png)
The Dynamic listing should look something like this:
The Dynamic Listing should look something like this:
![Listing after setting command-line arguments](images/Emulation_ListingForCmdlineSet.png)
**NOTE**: The placement of data units is not necessary for the emulator to operate; it only cares about the bytes.
However, it is a useful aide in devising, understanding, and diagnosing machine state.
Now, click ![resume button](images/resume.png) Resume, and see where the emulator crashes next.
Now, click ![resume button](images/resume.png) **Resume**, and see where the emulator crashes next.
Depending on your compilation of `termmines`, it may crash after returning, or it may crash trying to call `strnlen` or `strcmp`.
If the program counter is `00000000`, then it returned successfully.
This is unfortunate, because you no longer have motivation to stub external calls.
@ -335,15 +336,15 @@ There are at least three techniques for overcoming this.
#### Skip Technique
The skip technique is simplest, but will need to be performed *every time* that call is encountered.
Press ![skip over button](images/skipover.png) Skip Over, then use the Registers or Watches pane to patch `RAX`.
Then press ![resume button](images/resume.png) Resume.
Press ![skip over button](images/skipover.png) **Skip Over**, then use the Registers or Watches pane to patch `RAX`.
Then press ![resume button](images/resume.png) **Resume**.
#### `CALL` Override Technique
Overriding the `CALL` is also fairly simple.
While this will handle every encounter, it will not handle other calls to the same external function.
1. Press **K** in the listing to place a breakpoint on the `CALL` instruction.
1. Press **`K`** in the listing to place a breakpoint on the `CALL` instruction.
1. Now, in the Breakpoints panel, right-click the new breakpoint and select **Set Injection (Emulator)**.
1. This is the fun part: you must now implement the function in Sleigh, or at least stub it well enough for this particular call.
@ -382,9 +383,9 @@ The `emu_swi()` userop allows you to maintain breakpoint behavior, perhaps to de
After you have written your Sleigh code:
1. Click OK on the Set Injection dialog.
1. Click **OK** on the Set Injection dialog.
1. In the menus, select **Debugger &rarr; Configure Emulator &rarr; Invalidate Emulator Cache**.
1. Click ![resume button](images/resume.png) Resume.
1. Click ![resume button](images/resume.png) **Resume**.
Stubbing any remaining external calls is left as an exercise.
You are successful when the emulator crashes with `pc = 00000000`.
@ -395,12 +396,12 @@ Clear or disable your breakpoint and invalidate the emulator cache again before
The target override technique is most thorough, but also the most involved.
It will handle all calls to the external function, e.g., `strnlen`, no matter the call site.
If the call goes through a program linkage table (PLT), then you are in luck, because the call target will be visible in the Dynamic listing.
If the call goes through a program linkage table (PLT), then you are in luck, because the call target will be visible in the Dynamic Listing.
The PLT entry usually contains a single `JMP` instruction to the actual `strnlen`.
For real target processes, the `JMP` instruction will transfer control to a lazy linker the first time `strnlen` is called from `termmines`.
The linker then finds `strnlen` and patches the table.
In contrast, the Ghidra loader immediately patches the table to point to a fake `<EXTERNAL>::strnlen` symbol.
The `EXTERNAL` block is not visible in the Dynamic listing, so we will override the `JMP` in the PLT.
The `EXTERNAL` block is not visible in the Dynamic Listing, so we will override the `JMP` in the PLT.
The Sleigh code is nearly identical, but we must code an x86 `RET` into it.
Because we allow the `CALL` to execute normally, we must restore the stack.
@ -429,17 +430,17 @@ You are successful when the emulator crashes with `pc = 00000000`.
As you can see, depending on the scope of emulation, and the particulars of the target function, emulating a program image can be quite involved.
Whatever technique you choose, once you have successfully returned from the command-line argument parser, you should check for the expected effects.
In the Static listing, navigate to the variable that stores the board's dimensions.
In the Static Listing, navigate to the variable that stores the board's dimensions.
(Finding that variable is a task in the Beginner portion, but it can be found pretty easily with some manual static analysis.)
In the Dynamic listing, you should notice that the values have changed to reflect the Advanced skill level.
In the Dynamic Listing, you should notice that the values have changed to reflect the Advanced skill level.
### Optional Exercise: Patch the Placement Algorithm
In this exercise, you will use emulation to devise an assembly patch to `termmines` to change the mine placement algorithm.
Instead of random placement, please have them placed left to right, top to bottom.
We recommend you devise your patch using the Assembler (Patch Instruction action) in the Static listing, then test and debug your patch using the Emulator.
Perhaps patch the Dynamic listing to try quick tweaks before committing them to the Static listing.
Once you have it, export the patched binary and run it in a proper terminal.
We recommend you devise your patch using the Assembler (**Patch Instruction** action) in the Static Listing, then test and debug your patch using the Emulator.
Perhaps patch the Dynamic Listing to try quick tweaks before committing them to the Static Listing.
Once you have it, export the patched binary and run it outside of Ghidra.
## Debugging P-code Semantics
@ -454,10 +455,10 @@ This panel is not included in the default Debugger tool, so it must be configure
1. If you have not already, open the Debugger tool.
1. In the menus, select **File &rarr; Configure**.
1. Click the "Configure All Plugins" button in the top right of the dialog.
1. Click the **Configure All Plugins** button in the top right of the dialog.
1. Activate the `DebuggerPcodeStepperPlugin`
1. Click OK
1. Click Close
1. Click **OK**
1. Click **Close**
The stepper should appear stacked over the Threads panel in the bottom right.
Yours will probably still be empty, but here is what it looks like populated:
@ -472,7 +473,7 @@ If the current instruction is overridden by a Sleigh breakpoint, the listing wil
You can then step forward and backward within those.
As you step, the other windows that display machine state will update.
In addition to registers and memory, p-code has "unique" variables.
In addition to registers and memory, p-code has *unique* variables.
These are temporary variables used only within an instruction's implementation.
They are displayed in the right panel.
The table of variables works similarly to the Registers pane.
@ -489,5 +490,5 @@ It is displayed in the stepper's subtitle as well as the Threads panel's subtitl
P-code stepping is denoted by the portion of the schedule following the dot.
**NOTE**: You cannot mix instruction steps with p-code op steps.
The instruction steps always precede the p-code ops.
If you click Step Into from the global toolbar in the middle of an instruction, the trailing p-code op steps will be removed and replaced with a single instruction step.
If you click **Step Into** from the global toolbar in the middle of an instruction, the trailing p-code op steps will be removed and replaced with a single instruction step.
In most cases, this intuitively "finishes" the partial instruction.

View File

@ -168,6 +168,17 @@ class="sourceCode numberSource java numberLines"><code class="sourceCode java"><
<span id="cb1-6"><a href="#cb1-6"></a> <span class="kw">protected</span> <span class="dt">void</span> <span class="fu">run</span><span class="op">()</span> <span class="kw">throws</span> <span class="bu">Exception</span> <span class="op">{</span></span>
<span id="cb1-7"><a href="#cb1-7"></a> <span class="op">}</span></span>
<span id="cb1-8"><a href="#cb1-8"></a><span class="op">}</span></span></code></pre></div>
<p><strong>NOTE</strong>: The scripting API has been refactored a little
since the transition from Recorder-based to TraceRmi-based targets.
Parts of the API that are back-end agnostic are accessible from the
<code>FlatDebuggerAPI</code> interface. Parts of the API that require a
specific back end are in <code>FlatDebuggerRmiAPI</code> and
<code>FlatDebuggerRecorderAPI</code>, the latter of which is deprecated.
If a script written for version 11.0.2 or prior is not compiling, it can
most likely be patched up by changing
<code>implements FlatDebuggerAPI</code> to
<code>implements FlatDebuggerRecorderAPI</code>, but we recommend
porting it to use <code>implements FlatDebuggerRmiAPI</code>.</p>
<p>Technically, the Debuggers “deep” API is accessible to scripts;
however, the flat API is preferred for scripting. Also, the flat API is
usually more stable than the deep API. However, because the dynamic
@ -244,10 +255,11 @@ This allows us to locate that symbol in the dynamic context.</p>
</section>
<section id="reading-the-data" class="level3">
<h3>Reading the Data</h3>
<p>Now, we want to read the dimensions and the whole board to the trace.
You should know from earlier exercises that the board is allocated 32
cells by 32 cells, so we will want to read at least 1024 bytes. Note
that this will implicitly capture the board to the trace:</p>
<p>Now, we want to read the dimensions and the whole board from the
target. You should know from earlier exercises that the board is
allocated 32 cells by 32 cells, so we will want to read at least 1024
bytes. Note that this will implicitly capture the board to the
trace:</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode numberSource java numberLines"><code class="sourceCode java"><span id="cb5-1"><a href="#cb5-1"></a><span class="dt">byte</span><span class="op">[]</span> widthDat <span class="op">=</span> <span class="fu">readMemory</span><span class="op">(</span>widthDyn<span class="op">,</span> <span class="dv">4</span><span class="op">,</span> monitor<span class="op">);</span></span>
<span id="cb5-2"><a href="#cb5-2"></a><span class="dt">byte</span><span class="op">[]</span> heightDat <span class="op">=</span> <span class="fu">readMemory</span><span class="op">(</span>heightDyn<span class="op">,</span> <span class="dv">4</span><span class="op">,</span> monitor<span class="op">);</span></span>
@ -271,18 +283,20 @@ class="sourceCode numberSource java numberLines"><code class="sourceCode java"><
</section>
<section id="test-the-script" class="level3">
<h3>Test the Script</h3>
<p>To test, run <code>termmines</code> in a proper terminal and attach
to it from Ghidra using GDB. Now, run the script. Resume and play the
game. Once you win, check that the script output describes the actual
board.</p>
<p>To test, launch <code>termmines</code> in Ghidra using GDB. You will
need to allow it to set up the first game board before running the
script. The simplest way to do that is to resume and then interrupt the
target while it waits for input. Now, run the script and examine its
output. Resume and play the game. Once you win, check that the script
output describes the actual board.</p>
</section>
<section id="exercise-remove-the-mines" class="level3">
<h3>Exercise: Remove the Mines</h3>
<p>Write a script that will remove the mines from the board.
<strong>NOTE</strong>: The <code>writeMemory()</code> and related
methods are all subject to the current control mode. If the mode is
read-only, the script cannot modify the targets machine state using
those methods.</p>
methods are all subject to the current <strong>Control Mode</strong>. If
the mode is read-only, the script cannot modify the targets machine
state using those methods.</p>
</section>
</section>
<section id="waiting-on-reacting-to-events" class="level2">
@ -326,9 +340,9 @@ run.</li>
<p><strong>NOTE</strong>: The solution to this exercise is given as a
tutorial below, but give it an honest try before peeking. If you are not
already familiar with Eclipses searching and discovery features, try
pressing <strong>Ctrl-O</strong> twice in the editor for your script.
You should now be able to type patterns, optionally with wildcards, to
help you find applicable methods.</p>
pressing <strong><code>CTRL</code>-<code>O</code></strong> twice in the
editor for your script. You should now be able to type patterns,
optionally with wildcards, to help you find applicable methods.</p>
<p>Your task is to write a script that will wait for the player to win
then patch the machine state, so that the game always prints a score of
0 seconds. Some gotchas to consider up front:</p>
@ -338,8 +352,8 @@ See <code>getExecutionState()</code> and <code>interrupt()</code>. You
will not likely be able to place or toggle breakpoints while the target
is running.</li>
<li>Methods like <code>writeMemory()</code> are subject to the current
control mode. You may want to check and/or correct this at the top of
your script.</li>
<strong>Control Mode</strong>. You may want to check and/or correct this
at the top of your script.</li>
<li>If you require the user to mark code locations with a label, note
that those labels will likely end up in the containing functions
namespace. You will need to provide that namespace to
@ -351,13 +365,13 @@ breakpoint numbers.</li>
</ul>
<p>You are successful when you can attach to a running
<code>termmines</code> and execute your script. Then, assuming you win
the game, the game should award you a score of 0 seconds. It is OK if
the game, the game should award you a score of 0 seconds. It is okay if
you have to re-execute your script after each win.</p>
</section>
<section id="solution-always-win-in-0-seconds" class="level3">
<h3>Solution: Always Win in 0 Seconds</h3>
<p>As in the previous scripting tutorial, we will do some verifications
at the top of the script. Your level of pedantry may vary.</p>
<p>As in the previous script, we will do some verifications at the top
of the script. Your level of pedantry may vary.</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode numberSource java numberLines"><code class="sourceCode java"><span id="cb7-1"><a href="#cb7-1"></a>Trace trace <span class="op">=</span> <span class="fu">getCurrentTrace</span><span class="op">();</span></span>
<span id="cb7-2"><a href="#cb7-2"></a><span class="cf">if</span> <span class="op">(</span>trace <span class="op">==</span> <span class="kw">null</span><span class="op">)</span> <span class="op">{</span></span>
@ -384,17 +398,17 @@ association of the current program to the current target will be
implicitly verified when we map symbols. The second block will interrupt
the target if it is running. We then allow everything to sync up before
checking the control mode. We could instead change the control mode to
<strong>Target w/Edits</strong>, but I prefer to keep the user aware
that the script needs to modify target machine state.</p>
<strong>Control Target</strong> (with edits), but I prefer to keep the
user aware that the script needs to modify target machine state.</p>
<p>Next, we retrieve and map our symbols. This works pretty much the
same as in the previous scripting tutorial, but with attention to the
containing function namespace. The way <code>termmines</code> computes
the score is to record the start time of the game. Then, when the player
wins, it subtracts the recorded time from the current time. This script
requires the user to label the start time variable <code>timer</code>,
and to label the instruction that computes the score
<code>reset_timer</code>. The function that prints the score must be
named <code>print_win</code>.</p>
same as in the previous script, but with attention to the containing
function namespace. The way <code>termmines</code> computes the score is
to record the start time of the game. Then, when the player wins, it
subtracts the recorded time from the current time. This script requires
the user to label the start time variable <code>timer</code>, and to
label the instruction that computes the score <code>reset_timer</code>.
The function that prints the score must be named
<code>print_win</code>.</p>
<div class="sourceCode" id="cb8"><pre
class="sourceCode numberSource java numberLines"><code class="sourceCode java"><span id="cb8-1"><a href="#cb8-1"></a><span class="bu">List</span><span class="op">&lt;</span>Symbol<span class="op">&gt;</span> timerSyms <span class="op">=</span> <span class="fu">getSymbols</span><span class="op">(</span><span class="st">&quot;timer&quot;</span><span class="op">,</span> <span class="kw">null</span><span class="op">);</span></span>
<span id="cb8-2"><a href="#cb8-2"></a><span class="cf">if</span> <span class="op">(</span>timerSyms<span class="op">.</span><span class="fu">isEmpty</span><span class="op">())</span> <span class="op">{</span></span>
@ -429,7 +443,7 @@ either. To establish that context, you must use a
<code>getCurrentView()</code>.</p>
<p>To avoid creating a pile of breakpoints, we will first attempt to
enable an existing breakpoint at the desired location. Technically, the
existing breakpoints may not be execute breakpoints, but we will blindly
existing breakpoints may not be EXECUTE breakpoints, but we will blindly
assume they are. Again, your level of pedantry may vary. The
<code>breakpointsEnable</code> method will return the existing
breakpoints, so we can check that and create a new breakpoint, if
@ -453,7 +467,7 @@ breakpoint. We do not need to be precise in this check; it suffices to
check the program counter:</p>
<div class="sourceCode" id="cb10"><pre
class="sourceCode numberSource java numberLines"><code class="sourceCode java"><span id="cb10-1"><a href="#cb10-1"></a><span class="cf">while</span> <span class="op">(</span><span class="kw">true</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb10-2"><a href="#cb10-2"></a> monitor<span class="op">.</span><span class="fu">checkCanceled</span><span class="op">();</span></span>
<span id="cb10-2"><a href="#cb10-2"></a> monitor<span class="op">.</span><span class="fu">checkCancelled</span><span class="op">();</span></span>
<span id="cb10-3"><a href="#cb10-3"></a></span>
<span id="cb10-4"><a href="#cb10-4"></a> TargetExecutionState execState <span class="op">=</span> <span class="fu">getExecutionState</span><span class="op">(</span>trace<span class="op">);</span></span>
<span id="cb10-5"><a href="#cb10-5"></a> <span class="cf">switch</span> <span class="op">(</span>execState<span class="op">)</span> <span class="op">{</span></span>
@ -491,12 +505,12 @@ class="sourceCode numberSource java numberLines"><code class="sourceCode java"><
<span id="cb10-37"><a href="#cb10-37"></a> <span class="cf">break</span><span class="op">;</span></span>
<span id="cb10-38"><a href="#cb10-38"></a> <span class="op">}</span></span>
<span id="cb10-39"><a href="#cb10-39"></a><span class="op">}</span></span></code></pre></div>
<p>The “center” of this loop is a call to <code>waitForBreak()</code>.
This is the simplest primitive for waiting on the target to meet any
condition. Because we expect the user to take more than a second to win
the game, we should expect a timeout exception and just keep waiting.
Using a timeout of 1 second ensures we can terminate promptly should the
user cancel the script.</p>
<p>The “center” of this loop is a call to <code>waitForBreak()</code> on
line 27. This is the simplest primitive for waiting on the target to
meet any condition. Because we expect the user to take more than a
second to win the game, we should expect a timeout exception and just
keep waiting. Using a timeout of 1 second ensures we can terminate
promptly should the user cancel the script.</p>
<p>Before waiting, we need to make sure the target is running. Because
we could repeat the loop while the target is already running, we should
only call <code>resume()</code> if the target is stopped. There are

View File

@ -24,6 +24,11 @@ public class DemoDebuggerScript extends GhidraScript implements FlatDebuggerAPI
}
```
**NOTE**: The scripting API has been refactored a little since the transition from Recorder-based to TraceRmi-based targets.
Parts of the API that are back-end agnostic are accessible from the `FlatDebuggerAPI` interface.
Parts of the API that require a specific back end are in `FlatDebuggerRmiAPI` and `FlatDebuggerRecorderAPI`, the latter of which is deprecated.
If a script written for version 11.0.2 or prior is not compiling, it can most likely be patched up by changing `implements FlatDebuggerAPI` to `implements FlatDebuggerRecorderAPI`, but we recommend porting it to use `implements FlatDebuggerRmiAPI`.
Technically, the Debugger's "deep" API is accessible to scripts; however, the flat API is preferred for scripting.
Also, the flat API is usually more stable than the deep API.
However, because the dynamic analysis flat API is newer, it may not be as stable as the static analysis flat API.
@ -97,7 +102,7 @@ This allows us to locate that symbol in the dynamic context.
### Reading the Data
Now, we want to read the dimensions and the whole board to the trace.
Now, we want to read the dimensions and the whole board from the target.
You should know from earlier exercises that the board is allocated 32 cells by 32 cells, so we will want to read at least 1024 bytes.
Note that this will implicitly capture the board to the trace:
@ -126,15 +131,17 @@ for (int y = 0; y < height; y++) {
### Test the Script
To test, run `termmines` in a proper terminal and attach to it from Ghidra using GDB.
Now, run the script.
To test, launch `termmines` in Ghidra using GDB.
You will need to allow it to set up the first game board before running the script.
The simplest way to do that is to resume and then interrupt the target while it waits for input.
Now, run the script and examine its output.
Resume and play the game.
Once you win, check that the script output describes the actual board.
### Exercise: Remove the Mines
Write a script that will remove the mines from the board.
**NOTE**: The `writeMemory()` and related methods are all subject to the current control mode.
**NOTE**: The `writeMemory()` and related methods are all subject to the current **Control Mode**.
If the mode is read-only, the script cannot modify the target's machine state using those methods.
## Waiting on / Reacting to Events
@ -168,7 +175,7 @@ The general template for waiting on a condition is a bit klunky, but conceptuall
### Exercise: Always Win in 0 Seconds
**NOTE**: The solution to this exercise is given as a tutorial below, but give it an honest try before peeking.
If you are not already familiar with Eclipse's searching and discovery features, try pressing **Ctrl-O** twice in the editor for your script.
If you are not already familiar with Eclipse's searching and discovery features, try pressing **`CTRL`-`O`** twice in the editor for your script.
You should now be able to type patterns, optionally with wildcards, to help you find applicable methods.
Your task is to write a script that will wait for the player to win then patch the machine state, so that the game always prints a score of 0 seconds.
@ -177,7 +184,7 @@ Some gotchas to consider up front:
* You may want to verify and/or correct the target's execution state.
See `getExecutionState()` and `interrupt()`.
You will not likely be able to place or toggle breakpoints while the target is running.
* Methods like `writeMemory()` are subject to the current control mode.
* Methods like `writeMemory()` are subject to the current **Control Mode**.
You may want to check and/or correct this at the top of your script.
* If you require the user to mark code locations with a label, note that those labels will likely end up in the containing function's namespace.
You will need to provide that namespace to `getSymbols()`.
@ -186,11 +193,11 @@ Some gotchas to consider up front:
You are successful when you can attach to a running `termmines` and execute your script.
Then, assuming you win the game, the game should award you a score of 0 seconds.
It is OK if you have to re-execute your script after each win.
It is okay if you have to re-execute your script after each win.
### Solution: Always Win in 0 Seconds
As in the previous scripting tutorial, we will do some verifications at the top of the script.
As in the previous script, we will do some verifications at the top of the script.
Your level of pedantry may vary.
```java {.numberLines}
@ -219,10 +226,10 @@ The first two blocks check that there is an active target with `termmines` as th
As before, the association of the current program to the current target will be implicitly verified when we map symbols.
The second block will interrupt the target if it is running.
We then allow everything to sync up before checking the control mode.
We could instead change the control mode to **Target w/Edits**, but I prefer to keep the user aware that the script needs to modify target machine state.
We could instead change the control mode to **Control Target** (with edits), but I prefer to keep the user aware that the script needs to modify target machine state.
Next, we retrieve and map our symbols.
This works pretty much the same as in the previous scripting tutorial, but with attention to the containing function namespace.
This works pretty much the same as in the previous script, but with attention to the containing function namespace.
The way `termmines` computes the score is to record the start time of the game.
Then, when the player wins, it subtracts the recorded time from the current time.
This script requires the user to label the start time variable `timer`, and to label the instruction that computes the score `reset_timer`.
@ -261,7 +268,7 @@ For static context, use the current (static) program as the program.
For dynamic context, use the current (dynamic) trace view as the program &mdash; see `getCurrentView()`.
To avoid creating a pile of breakpoints, we will first attempt to enable an existing breakpoint at the desired location.
Technically, the existing breakpoints may not be execute breakpoints, but we will blindly assume they are.
Technically, the existing breakpoints may not be EXECUTE breakpoints, but we will blindly assume they are.
Again, your level of pedantry may vary.
The `breakpointsEnable` method will return the existing breakpoints, so we can check that and create a new breakpoint, if necessary:
@ -284,7 +291,7 @@ We do not need to be precise in this check; it suffices to check the program cou
```java {.numberLines}
while (true) {
monitor.checkCanceled();
monitor.checkCancelled();
TargetExecutionState execState = getExecutionState(trace);
switch (execState) {
@ -324,7 +331,7 @@ while (true) {
}
```
The "center" of this loop is a call to `waitForBreak()`.
The "center" of this loop is a call to `waitForBreak()` on line 27.
This is the simplest primitive for waiting on the target to meet any condition.
Because we expect the user to take more than a second to win the game, we should expect a timeout exception and just keep waiting.
Using a timeout of 1 second ensures we can terminate promptly should the user cancel the script.

View File

@ -266,19 +266,20 @@ depending on where the breakpoint was placed.</p>
<section id="modeling-by-sleigh-semantics" class="level3">
<h3>Modeling by Sleigh Semantics</h3>
<p>The advantage to Java callbacks is that things are relatively
intuitive to do, but the temptation, which we intentionally demonstrate
here, is to make everything concrete. You may notice the library uses a
intuitive to do, but the temptation, which we intentionally demonstrated
above, is to make everything concrete. You may notice the library uses a
type parameter <code>T</code>, which specifies the type of all variables
in the emulators state. Leaving it as <code>T</code> indicates the
library is compatible with any type. For a concrete emulator,
<code>T = byte[]</code>, and so there is no loss in making things
<code>T := byte[]</code>, and so there is no loss in making things
concrete, and then converting back to <code>T</code> using the
arithmetic object. However, if the emulator has been augmented, as we
will discuss below, the model may become confused, because values
computed by a careless userop will appear to the model a literal
constant. To avoid this, you should keep everything a T and use the
arithmetic object to perform any arithmetic operations. Alternatively,
you can implement the userop using pre-compiled Sleigh code:</p>
<code>arithmetic</code> object. However, if the emulator has been
augmented, as we will discuss below, the model may become confused,
because values computed by a careless userop will appear to the model a
literal constant. To avoid this, you should keep everything a T and use
the <code>arithmetic</code> object to perform any arithmetic operations.
Alternatively, you can implement the userop using pre-compiled Sleigh
code:</p>
<div class="sourceCode" id="cb2"><pre
class="sourceCode numberSource java numberLines"><code class="sourceCode java"><span id="cb2-1"><a href="#cb2-1"></a><span class="kw">public</span> <span class="dt">static</span> <span class="kw">class</span> SleighStdLibPcodeUseropLibrary<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="kw">extends</span> AnnotatedPcodeUseropLibrary<span class="op">&lt;</span>T<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb2-2"><a href="#cb2-2"></a> <span class="kw">private</span> <span class="dt">static</span> <span class="dt">final</span> <span class="bu">String</span> SRC_RET <span class="op">=</span> <span class="st">&quot;&quot;&quot;</span></span>
@ -341,9 +342,9 @@ target architectures. We then lazily compile each userop upon its first
invocation. These are technically still Java callbacks, but our
implementation delegates to the executor, giving it the compiled p-code
program.</p>
<p>The advantage here is that the code will properly use the underlying
<p>The advantage here is that the p-code will use the underlying
arithmetic appropriately. However, for some models, that may actually
not be desired. Some symbolic models might just like to see a literal
not be desired. Some symbolic models might just like to see an abstract
call to <code>strlen()</code>.</p>
</section>
<section id="modeling-by-structured-sleigh" class="level3">
@ -466,7 +467,7 @@ into its state, and you should choose a different location for the
injection. Refer to the example scripts in Ghidras
<code>SystemEmulation</code> module.</p>
<p>If you would like to (temporarily) override the GUI with a custom
userop library, you can by overriding the GUIs emulator factory:</p>
userop library, you can by setting the GUIs emulator factory:</p>
<div class="sourceCode" id="cb5"><pre
class="sourceCode numberSource java numberLines"><code class="sourceCode java"><span id="cb5-1"><a href="#cb5-1"></a><span class="kw">public</span> <span class="kw">class</span> InstallCustomLibraryScript <span class="kw">extends</span> GhidraScript <span class="kw">implements</span> FlatDebuggerAPI <span class="op">{</span></span>
<span id="cb5-2"><a href="#cb5-2"></a> <span class="kw">public</span> <span class="dt">static</span> <span class="kw">class</span> CustomBytesDebuggerPcodeEmulator <span class="kw">extends</span> BytesDebuggerPcodeEmulator <span class="op">{</span></span>
@ -738,7 +739,7 @@ one we actually implement, by extending from
<code>AbstractLongOffsetPcodeExecutorStatePiece</code>.</p>
<p><strong>NOTE</strong>: If you do not desire a concrete address model,
then you should implement <code>PcodeExecutorState&lt;Expr&gt;</code>
directly. A “state” is also “state piece” whose address model is the
directly. A “state” is also a “state piece” whose address model is the
same as its value model, so states can still be composed. On one hand,
the abstractly-addressed state provides a component that is readily used
in both static and dynamic analysis; whereas, the concretely-addressed
@ -772,81 +773,85 @@ class="sourceCode numberSource java numberLines"><code class="sourceCode java"><
<span id="cb8-20"><a href="#cb8-20"></a> map<span class="op">.</span><span class="fu">put</span><span class="op">(</span>offset<span class="op">,</span> val<span class="op">);</span></span>
<span id="cb8-21"><a href="#cb8-21"></a> <span class="op">}</span></span>
<span id="cb8-22"><a href="#cb8-22"></a></span>
<span id="cb8-23"><a href="#cb8-23"></a> <span class="kw">public</span> Expr <span class="fu">get</span><span class="op">(</span><span class="dt">long</span> offset<span class="op">,</span> <span class="dt">int</span> size<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-24"><a href="#cb8-24"></a> <span class="co">// </span><span class="al">TODO</span><span class="co">: Handle overlaps / offcut gets and sets</span></span>
<span id="cb8-25"><a href="#cb8-25"></a> Expr expr <span class="op">=</span> map<span class="op">.</span><span class="fu">get</span><span class="op">(</span>offset<span class="op">);</span></span>
<span id="cb8-26"><a href="#cb8-26"></a> <span class="cf">return</span> expr <span class="op">!=</span> <span class="kw">null</span> <span class="op">?</span> expr <span class="op">:</span> <span class="kw">new</span> <span class="fu">VarExpr</span><span class="op">(</span>space<span class="op">,</span> offset<span class="op">,</span> size<span class="op">);</span></span>
<span id="cb8-27"><a href="#cb8-27"></a> <span class="op">}</span></span>
<span id="cb8-28"><a href="#cb8-28"></a><span class="op">}</span></span>
<span id="cb8-29"><a href="#cb8-29"></a></span>
<span id="cb8-30"><a href="#cb8-30"></a><span class="kw">public</span> <span class="dt">static</span> <span class="kw">abstract</span> <span class="kw">class</span> AbstractExprPcodeExecutorStatePiece<span class="op">&lt;</span>S <span class="kw">extends</span> ExprSpace<span class="op">&gt;</span> <span class="kw">extends</span></span>
<span id="cb8-31"><a href="#cb8-31"></a> AbstractLongOffsetPcodeExecutorStatePiece<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">,</span> S<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb8-32"><a href="#cb8-32"></a></span>
<span id="cb8-33"><a href="#cb8-33"></a> <span class="kw">protected</span> <span class="dt">final</span> AbstractSpaceMap<span class="op">&lt;</span>S<span class="op">&gt;</span> spaceMap <span class="op">=</span> <span class="fu">newSpaceMap</span><span class="op">();</span></span>
<span id="cb8-34"><a href="#cb8-34"></a></span>
<span id="cb8-35"><a href="#cb8-35"></a> <span class="kw">public</span> <span class="fu">AbstractExprPcodeExecutorStatePiece</span><span class="op">(</span>Language language<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-36"><a href="#cb8-36"></a> <span class="kw">super</span><span class="op">(</span>language<span class="op">,</span> BytesPcodeArithmetic<span class="op">.</span><span class="fu">forLanguage</span><span class="op">(</span>language<span class="op">),</span></span>
<span id="cb8-37"><a href="#cb8-37"></a> ExprPcodeArithmetic<span class="op">.</span><span class="fu">forLanguage</span><span class="op">(</span>language<span class="op">));</span></span>
<span id="cb8-38"><a href="#cb8-38"></a> <span class="op">}</span></span>
<span id="cb8-39"><a href="#cb8-39"></a></span>
<span id="cb8-40"><a href="#cb8-40"></a> <span class="kw">protected</span> <span class="kw">abstract</span> AbstractSpaceMap<span class="op">&lt;</span>S<span class="op">&gt;</span> <span class="fu">newSpaceMap</span><span class="op">();</span></span>
<span id="cb8-41"><a href="#cb8-41"></a></span>
<span id="cb8-42"><a href="#cb8-42"></a> <span class="at">@Override</span></span>
<span id="cb8-43"><a href="#cb8-43"></a> <span class="kw">public</span> MemBuffer <span class="fu">getConcreteBuffer</span><span class="op">(</span>Address address<span class="op">,</span> Purpose purpose<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-44"><a href="#cb8-44"></a> <span class="cf">throw</span> <span class="kw">new</span> <span class="bu">UnsupportedOperationException</span><span class="op">();</span></span>
<span id="cb8-45"><a href="#cb8-45"></a> <span class="op">}</span></span>
<span id="cb8-46"><a href="#cb8-46"></a></span>
<span id="cb8-47"><a href="#cb8-47"></a> <span class="at">@Override</span></span>
<span id="cb8-48"><a href="#cb8-48"></a> <span class="kw">public</span> <span class="dt">void</span> <span class="fu">clear</span><span class="op">()</span> <span class="op">{</span></span>
<span id="cb8-49"><a href="#cb8-49"></a> <span class="cf">for</span> <span class="op">(</span>S space <span class="op">:</span> spaceMap<span class="op">.</span><span class="fu">values</span><span class="op">())</span> <span class="op">{</span></span>
<span id="cb8-50"><a href="#cb8-50"></a> space<span class="op">.</span><span class="fu">clear</span><span class="op">();</span></span>
<span id="cb8-51"><a href="#cb8-51"></a> <span class="op">}</span></span>
<span id="cb8-52"><a href="#cb8-52"></a> <span class="op">}</span></span>
<span id="cb8-53"><a href="#cb8-53"></a></span>
<span id="cb8-54"><a href="#cb8-54"></a> <span class="at">@Override</span></span>
<span id="cb8-55"><a href="#cb8-55"></a> <span class="kw">protected</span> S <span class="fu">getForSpace</span><span class="op">(</span>AddressSpace space<span class="op">,</span> <span class="dt">boolean</span> toWrite<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-56"><a href="#cb8-56"></a> <span class="cf">return</span> spaceMap<span class="op">.</span><span class="fu">getForSpace</span><span class="op">(</span>space<span class="op">,</span> toWrite<span class="op">);</span></span>
<span id="cb8-57"><a href="#cb8-57"></a> <span class="op">}</span></span>
<span id="cb8-58"><a href="#cb8-58"></a></span>
<span id="cb8-59"><a href="#cb8-59"></a> <span class="at">@Override</span></span>
<span id="cb8-60"><a href="#cb8-60"></a> <span class="kw">protected</span> <span class="dt">void</span> <span class="fu">setInSpace</span><span class="op">(</span>ExprSpace space<span class="op">,</span> <span class="dt">long</span> offset<span class="op">,</span> <span class="dt">int</span> size<span class="op">,</span> Expr val<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-61"><a href="#cb8-61"></a> space<span class="op">.</span><span class="fu">set</span><span class="op">(</span>offset<span class="op">,</span> val<span class="op">);</span></span>
<span id="cb8-62"><a href="#cb8-62"></a> <span class="op">}</span></span>
<span id="cb8-63"><a href="#cb8-63"></a></span>
<span id="cb8-64"><a href="#cb8-64"></a> <span class="at">@Override</span></span>
<span id="cb8-65"><a href="#cb8-65"></a> <span class="kw">protected</span> Expr <span class="fu">getFromSpace</span><span class="op">(</span>S space<span class="op">,</span> <span class="dt">long</span> offset<span class="op">,</span> <span class="dt">int</span> size<span class="op">,</span> Reason reason<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-66"><a href="#cb8-66"></a> <span class="cf">return</span> space<span class="op">.</span><span class="fu">get</span><span class="op">(</span>offset<span class="op">,</span> size<span class="op">);</span></span>
<span id="cb8-67"><a href="#cb8-67"></a> <span class="op">}</span></span>
<span id="cb8-68"><a href="#cb8-68"></a></span>
<span id="cb8-69"><a href="#cb8-69"></a> <span class="at">@Override</span></span>
<span id="cb8-70"><a href="#cb8-70"></a> <span class="kw">protected</span> <span class="bu">Map</span><span class="op">&lt;</span>Register<span class="op">,</span> Expr<span class="op">&gt;</span> <span class="fu">getRegisterValuesFromSpace</span><span class="op">(</span>S s<span class="op">,</span> <span class="bu">List</span><span class="op">&lt;</span>Register<span class="op">&gt;</span> registers<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-71"><a href="#cb8-71"></a> <span class="cf">throw</span> <span class="kw">new</span> <span class="bu">UnsupportedOperationException</span><span class="op">();</span></span>
<span id="cb8-72"><a href="#cb8-72"></a> <span class="op">}</span></span>
<span id="cb8-73"><a href="#cb8-73"></a><span class="op">}</span></span>
<span id="cb8-74"><a href="#cb8-74"></a></span>
<span id="cb8-75"><a href="#cb8-75"></a><span class="kw">public</span> <span class="dt">static</span> <span class="kw">class</span> ExprPcodeExecutorStatePiece</span>
<span id="cb8-76"><a href="#cb8-76"></a> <span class="kw">extends</span> AbstractExprPcodeExecutorStatePiece<span class="op">&lt;</span>ExprSpace<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb8-77"><a href="#cb8-77"></a> <span class="kw">public</span> <span class="fu">ExprPcodeExecutorStatePiece</span><span class="op">(</span>Language language<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-78"><a href="#cb8-78"></a> <span class="kw">super</span><span class="op">(</span>language<span class="op">);</span></span>
<span id="cb8-79"><a href="#cb8-79"></a> <span class="op">}</span></span>
<span id="cb8-80"><a href="#cb8-80"></a></span>
<span id="cb8-81"><a href="#cb8-81"></a> <span class="at">@Override</span></span>
<span id="cb8-82"><a href="#cb8-82"></a> <span class="kw">protected</span> AbstractSpaceMap<span class="op">&lt;</span>ExprSpace<span class="op">&gt;</span> <span class="fu">newSpaceMap</span><span class="op">()</span> <span class="op">{</span></span>
<span id="cb8-83"><a href="#cb8-83"></a> <span class="cf">return</span> <span class="kw">new</span> SimpleSpaceMap<span class="op">&lt;</span>ExprSpace<span class="op">&gt;()</span> <span class="op">{</span></span>
<span id="cb8-84"><a href="#cb8-84"></a> <span class="at">@Override</span></span>
<span id="cb8-85"><a href="#cb8-85"></a> <span class="kw">protected</span> ExprSpace <span class="fu">newSpace</span><span class="op">(</span>AddressSpace space<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-86"><a href="#cb8-86"></a> <span class="cf">return</span> <span class="kw">new</span> <span class="fu">ExprSpace</span><span class="op">(</span>space<span class="op">);</span></span>
<span id="cb8-87"><a href="#cb8-87"></a> <span class="op">}</span></span>
<span id="cb8-88"><a href="#cb8-88"></a> <span class="op">};</span></span>
<span id="cb8-89"><a href="#cb8-89"></a> <span class="op">}</span></span>
<span id="cb8-90"><a href="#cb8-90"></a><span class="op">}</span></span>
<span id="cb8-91"><a href="#cb8-91"></a></span>
<span id="cb8-92"><a href="#cb8-92"></a><span class="kw">public</span> <span class="dt">static</span> <span class="kw">class</span> BytesExprPcodeExecutorState <span class="kw">extends</span> PairedPcodeExecutorState<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb8-93"><a href="#cb8-93"></a> <span class="kw">public</span> <span class="fu">BytesExprPcodeExecutorState</span><span class="op">(</span>PcodeExecutorStatePiece<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> <span class="dt">byte</span><span class="op">[]&gt;</span> concrete<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-94"><a href="#cb8-94"></a> <span class="kw">super</span><span class="op">(</span><span class="kw">new</span> PairedPcodeExecutorStatePiece<span class="op">&lt;&gt;(</span>concrete<span class="op">,</span></span>
<span id="cb8-95"><a href="#cb8-95"></a> <span class="kw">new</span> <span class="fu">ExprPcodeExecutorStatePiece</span><span class="op">(</span>concrete<span class="op">.</span><span class="fu">getLanguage</span><span class="op">())));</span></span>
<span id="cb8-96"><a href="#cb8-96"></a> <span class="op">}</span></span>
<span id="cb8-97"><a href="#cb8-97"></a><span class="op">}</span></span></code></pre></div>
<span id="cb8-23"><a href="#cb8-23"></a> <span class="kw">protected</span> Expr <span class="fu">whenNull</span><span class="op">(</span><span class="dt">long</span> offset<span class="op">,</span> <span class="dt">int</span> size<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-24"><a href="#cb8-24"></a> <span class="cf">return</span> <span class="kw">new</span> <span class="fu">VarExpr</span><span class="op">(</span>space<span class="op">,</span> offset<span class="op">,</span> size<span class="op">);</span></span>
<span id="cb8-25"><a href="#cb8-25"></a> <span class="op">}</span></span>
<span id="cb8-26"><a href="#cb8-26"></a></span>
<span id="cb8-27"><a href="#cb8-27"></a> <span class="kw">public</span> Expr <span class="fu">get</span><span class="op">(</span><span class="dt">long</span> offset<span class="op">,</span> <span class="dt">int</span> size<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-28"><a href="#cb8-28"></a> <span class="co">// </span><span class="al">TODO</span><span class="co">: Handle overlaps / offcut gets and sets</span></span>
<span id="cb8-29"><a href="#cb8-29"></a> Expr expr <span class="op">=</span> map<span class="op">.</span><span class="fu">get</span><span class="op">(</span>offset<span class="op">);</span></span>
<span id="cb8-30"><a href="#cb8-30"></a> <span class="cf">return</span> expr <span class="op">!=</span> <span class="kw">null</span> <span class="op">?</span> expr <span class="op">:</span> <span class="fu">whenNull</span><span class="op">(</span>offset<span class="op">,</span> size<span class="op">);</span></span>
<span id="cb8-31"><a href="#cb8-31"></a> <span class="op">}</span></span>
<span id="cb8-32"><a href="#cb8-32"></a><span class="op">}</span></span>
<span id="cb8-33"><a href="#cb8-33"></a></span>
<span id="cb8-34"><a href="#cb8-34"></a><span class="kw">public</span> <span class="dt">static</span> <span class="kw">abstract</span> <span class="kw">class</span> AbstractExprPcodeExecutorStatePiece<span class="op">&lt;</span>S <span class="kw">extends</span> ExprSpace<span class="op">&gt;</span> <span class="kw">extends</span></span>
<span id="cb8-35"><a href="#cb8-35"></a> AbstractLongOffsetPcodeExecutorStatePiece<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">,</span> S<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb8-36"><a href="#cb8-36"></a></span>
<span id="cb8-37"><a href="#cb8-37"></a> <span class="kw">protected</span> <span class="dt">final</span> AbstractSpaceMap<span class="op">&lt;</span>S<span class="op">&gt;</span> spaceMap <span class="op">=</span> <span class="fu">newSpaceMap</span><span class="op">();</span></span>
<span id="cb8-38"><a href="#cb8-38"></a></span>
<span id="cb8-39"><a href="#cb8-39"></a> <span class="kw">public</span> <span class="fu">AbstractExprPcodeExecutorStatePiece</span><span class="op">(</span>Language language<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-40"><a href="#cb8-40"></a> <span class="kw">super</span><span class="op">(</span>language<span class="op">,</span> BytesPcodeArithmetic<span class="op">.</span><span class="fu">forLanguage</span><span class="op">(</span>language<span class="op">),</span></span>
<span id="cb8-41"><a href="#cb8-41"></a> ExprPcodeArithmetic<span class="op">.</span><span class="fu">forLanguage</span><span class="op">(</span>language<span class="op">));</span></span>
<span id="cb8-42"><a href="#cb8-42"></a> <span class="op">}</span></span>
<span id="cb8-43"><a href="#cb8-43"></a></span>
<span id="cb8-44"><a href="#cb8-44"></a> <span class="kw">protected</span> <span class="kw">abstract</span> AbstractSpaceMap<span class="op">&lt;</span>S<span class="op">&gt;</span> <span class="fu">newSpaceMap</span><span class="op">();</span></span>
<span id="cb8-45"><a href="#cb8-45"></a></span>
<span id="cb8-46"><a href="#cb8-46"></a> <span class="at">@Override</span></span>
<span id="cb8-47"><a href="#cb8-47"></a> <span class="kw">public</span> MemBuffer <span class="fu">getConcreteBuffer</span><span class="op">(</span>Address address<span class="op">,</span> Purpose purpose<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-48"><a href="#cb8-48"></a> <span class="cf">throw</span> <span class="kw">new</span> <span class="bu">UnsupportedOperationException</span><span class="op">();</span></span>
<span id="cb8-49"><a href="#cb8-49"></a> <span class="op">}</span></span>
<span id="cb8-50"><a href="#cb8-50"></a></span>
<span id="cb8-51"><a href="#cb8-51"></a> <span class="at">@Override</span></span>
<span id="cb8-52"><a href="#cb8-52"></a> <span class="kw">public</span> <span class="dt">void</span> <span class="fu">clear</span><span class="op">()</span> <span class="op">{</span></span>
<span id="cb8-53"><a href="#cb8-53"></a> <span class="cf">for</span> <span class="op">(</span>S space <span class="op">:</span> spaceMap<span class="op">.</span><span class="fu">values</span><span class="op">())</span> <span class="op">{</span></span>
<span id="cb8-54"><a href="#cb8-54"></a> space<span class="op">.</span><span class="fu">clear</span><span class="op">();</span></span>
<span id="cb8-55"><a href="#cb8-55"></a> <span class="op">}</span></span>
<span id="cb8-56"><a href="#cb8-56"></a> <span class="op">}</span></span>
<span id="cb8-57"><a href="#cb8-57"></a></span>
<span id="cb8-58"><a href="#cb8-58"></a> <span class="at">@Override</span></span>
<span id="cb8-59"><a href="#cb8-59"></a> <span class="kw">protected</span> S <span class="fu">getForSpace</span><span class="op">(</span>AddressSpace space<span class="op">,</span> <span class="dt">boolean</span> toWrite<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-60"><a href="#cb8-60"></a> <span class="cf">return</span> spaceMap<span class="op">.</span><span class="fu">getForSpace</span><span class="op">(</span>space<span class="op">,</span> toWrite<span class="op">);</span></span>
<span id="cb8-61"><a href="#cb8-61"></a> <span class="op">}</span></span>
<span id="cb8-62"><a href="#cb8-62"></a></span>
<span id="cb8-63"><a href="#cb8-63"></a> <span class="at">@Override</span></span>
<span id="cb8-64"><a href="#cb8-64"></a> <span class="kw">protected</span> <span class="dt">void</span> <span class="fu">setInSpace</span><span class="op">(</span>ExprSpace space<span class="op">,</span> <span class="dt">long</span> offset<span class="op">,</span> <span class="dt">int</span> size<span class="op">,</span> Expr val<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-65"><a href="#cb8-65"></a> space<span class="op">.</span><span class="fu">set</span><span class="op">(</span>offset<span class="op">,</span> val<span class="op">);</span></span>
<span id="cb8-66"><a href="#cb8-66"></a> <span class="op">}</span></span>
<span id="cb8-67"><a href="#cb8-67"></a></span>
<span id="cb8-68"><a href="#cb8-68"></a> <span class="at">@Override</span></span>
<span id="cb8-69"><a href="#cb8-69"></a> <span class="kw">protected</span> Expr <span class="fu">getFromSpace</span><span class="op">(</span>S space<span class="op">,</span> <span class="dt">long</span> offset<span class="op">,</span> <span class="dt">int</span> size<span class="op">,</span> Reason reason<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-70"><a href="#cb8-70"></a> <span class="cf">return</span> space<span class="op">.</span><span class="fu">get</span><span class="op">(</span>offset<span class="op">,</span> size<span class="op">);</span></span>
<span id="cb8-71"><a href="#cb8-71"></a> <span class="op">}</span></span>
<span id="cb8-72"><a href="#cb8-72"></a></span>
<span id="cb8-73"><a href="#cb8-73"></a> <span class="at">@Override</span></span>
<span id="cb8-74"><a href="#cb8-74"></a> <span class="kw">protected</span> <span class="bu">Map</span><span class="op">&lt;</span>Register<span class="op">,</span> Expr<span class="op">&gt;</span> <span class="fu">getRegisterValuesFromSpace</span><span class="op">(</span>S s<span class="op">,</span> <span class="bu">List</span><span class="op">&lt;</span>Register<span class="op">&gt;</span> registers<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-75"><a href="#cb8-75"></a> <span class="cf">throw</span> <span class="kw">new</span> <span class="bu">UnsupportedOperationException</span><span class="op">();</span></span>
<span id="cb8-76"><a href="#cb8-76"></a> <span class="op">}</span></span>
<span id="cb8-77"><a href="#cb8-77"></a><span class="op">}</span></span>
<span id="cb8-78"><a href="#cb8-78"></a></span>
<span id="cb8-79"><a href="#cb8-79"></a><span class="kw">public</span> <span class="dt">static</span> <span class="kw">class</span> ExprPcodeExecutorStatePiece</span>
<span id="cb8-80"><a href="#cb8-80"></a> <span class="kw">extends</span> AbstractExprPcodeExecutorStatePiece<span class="op">&lt;</span>ExprSpace<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb8-81"><a href="#cb8-81"></a> <span class="kw">public</span> <span class="fu">ExprPcodeExecutorStatePiece</span><span class="op">(</span>Language language<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-82"><a href="#cb8-82"></a> <span class="kw">super</span><span class="op">(</span>language<span class="op">);</span></span>
<span id="cb8-83"><a href="#cb8-83"></a> <span class="op">}</span></span>
<span id="cb8-84"><a href="#cb8-84"></a></span>
<span id="cb8-85"><a href="#cb8-85"></a> <span class="at">@Override</span></span>
<span id="cb8-86"><a href="#cb8-86"></a> <span class="kw">protected</span> AbstractSpaceMap<span class="op">&lt;</span>ExprSpace<span class="op">&gt;</span> <span class="fu">newSpaceMap</span><span class="op">()</span> <span class="op">{</span></span>
<span id="cb8-87"><a href="#cb8-87"></a> <span class="cf">return</span> <span class="kw">new</span> SimpleSpaceMap<span class="op">&lt;</span>ExprSpace<span class="op">&gt;()</span> <span class="op">{</span></span>
<span id="cb8-88"><a href="#cb8-88"></a> <span class="at">@Override</span></span>
<span id="cb8-89"><a href="#cb8-89"></a> <span class="kw">protected</span> ExprSpace <span class="fu">newSpace</span><span class="op">(</span>AddressSpace space<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-90"><a href="#cb8-90"></a> <span class="cf">return</span> <span class="kw">new</span> <span class="fu">ExprSpace</span><span class="op">(</span>space<span class="op">);</span></span>
<span id="cb8-91"><a href="#cb8-91"></a> <span class="op">}</span></span>
<span id="cb8-92"><a href="#cb8-92"></a> <span class="op">};</span></span>
<span id="cb8-93"><a href="#cb8-93"></a> <span class="op">}</span></span>
<span id="cb8-94"><a href="#cb8-94"></a><span class="op">}</span></span>
<span id="cb8-95"><a href="#cb8-95"></a></span>
<span id="cb8-96"><a href="#cb8-96"></a><span class="kw">public</span> <span class="dt">static</span> <span class="kw">class</span> BytesExprPcodeExecutorState <span class="kw">extends</span> PairedPcodeExecutorState<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb8-97"><a href="#cb8-97"></a> <span class="kw">public</span> <span class="fu">BytesExprPcodeExecutorState</span><span class="op">(</span>PcodeExecutorStatePiece<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> <span class="dt">byte</span><span class="op">[]&gt;</span> concrete<span class="op">)</span> <span class="op">{</span></span>
<span id="cb8-98"><a href="#cb8-98"></a> <span class="kw">super</span><span class="op">(</span><span class="kw">new</span> PairedPcodeExecutorStatePiece<span class="op">&lt;&gt;(</span>concrete<span class="op">,</span></span>
<span id="cb8-99"><a href="#cb8-99"></a> <span class="kw">new</span> <span class="fu">ExprPcodeExecutorStatePiece</span><span class="op">(</span>concrete<span class="op">.</span><span class="fu">getLanguage</span><span class="op">())));</span></span>
<span id="cb8-100"><a href="#cb8-100"></a> <span class="op">}</span></span>
<span id="cb8-101"><a href="#cb8-101"></a><span class="op">}</span></span></code></pre></div>
<p>The abstract class implements a strategy where a dedicated object
handles each address space. Each object typically maintains of map of
offsets (type <code>long</code>) to the model type, i.e.,
@ -859,7 +864,8 @@ from the variables actually stored there. This may not seem like a huge
problem, but it is actually quite common, esp., since x86 registers are
structured. A write to <code>RAX</code> followed by a read from
<code>EAX</code> will immediately demonstrate this issue. Nevertheless,
we leave those details as an exercise.</p>
we leave those details as an exercise. We factor <code>whenNull</code>
so that it can be overridden later.</p>
<p>The remaining parts are mostly boilerplate. We implement the “state
piece” interface by creating another abstract class. An abstract class
is not absolutely necessary, but it will be useful when we integrate the
@ -1001,8 +1007,8 @@ class="sourceCode numberSource java numberLines"><code class="sourceCode java"><
<span id="cb10-19"><a href="#cb10-19"></a><span class="op">}</span></span></code></pre></div>
<p><strong>NOTE</strong>: When accessed as a paired state, all sets will
affect both pieces. If you use the arithmetic to generate them, remember
that it will use <code>fromConst</code> on both arithmetics to generate
the pair, so you may be setting the right side to a
that it will use <code>fromConst</code> on both sub-arithmetics to
generate the pair, so you may be setting the right side to a
<code>LitExpr</code>. To modify just one side of the pair, cast the
state to <code>PairedPcodeExecutorState</code>, and then use
<code>getLeft()</code>, and <code>getRight()</code> to retrieve the
@ -1072,7 +1078,7 @@ class="sourceCode numberSource java numberLines"><code class="sourceCode java"><
<span id="cb11-35"><a href="#cb11-35"></a><span class="kw">public</span> <span class="dt">static</span> <span class="kw">class</span> ExprTracePcodeExecutorStatePiece</span>
<span id="cb11-36"><a href="#cb11-36"></a> <span class="kw">extends</span> AbstractExprPcodeExecutorStatePiece<span class="op">&lt;</span>ExprTraceSpace<span class="op">&gt;</span></span>
<span id="cb11-37"><a href="#cb11-37"></a> <span class="kw">implements</span> TracePcodeExecutorStatePiece<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb11-38"><a href="#cb11-38"></a> <span class="kw">public</span> <span class="dt">static</span> <span class="dt">final</span> <span class="bu">String</span> NAME <span class="op">=</span> <span class="st">&quot;Taint&quot;</span><span class="op">;</span></span>
<span id="cb11-38"><a href="#cb11-38"></a> <span class="kw">public</span> <span class="dt">static</span> <span class="dt">final</span> <span class="bu">String</span> NAME <span class="op">=</span> <span class="st">&quot;Expr&quot;</span><span class="op">;</span></span>
<span id="cb11-39"><a href="#cb11-39"></a></span>
<span id="cb11-40"><a href="#cb11-40"></a> <span class="kw">protected</span> <span class="dt">final</span> PcodeTraceDataAccess data<span class="op">;</span></span>
<span id="cb11-41"><a href="#cb11-41"></a> <span class="kw">protected</span> <span class="dt">final</span> PcodeTracePropertyAccess<span class="op">&lt;</span><span class="bu">String</span><span class="op">&gt;</span> property<span class="op">;</span></span>
@ -1116,7 +1122,15 @@ class="sourceCode numberSource java numberLines"><code class="sourceCode java"><
<span id="cb11-79"><a href="#cb11-79"></a> space<span class="op">.</span><span class="fu">writeDown</span><span class="op">(</span>property<span class="op">);</span></span>
<span id="cb11-80"><a href="#cb11-80"></a> <span class="op">}</span></span>
<span id="cb11-81"><a href="#cb11-81"></a> <span class="op">}</span></span>
<span id="cb11-82"><a href="#cb11-82"></a><span class="op">}</span></span></code></pre></div>
<span id="cb11-82"><a href="#cb11-82"></a><span class="op">}</span></span>
<span id="cb11-83"><a href="#cb11-83"></a></span>
<span id="cb11-84"><a href="#cb11-84"></a><span class="kw">public</span> <span class="dt">static</span> <span class="kw">class</span> ExprTracePcodeExecutorState</span>
<span id="cb11-85"><a href="#cb11-85"></a> <span class="kw">extends</span> PairedTracePcodeExecutorState<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb11-86"><a href="#cb11-86"></a> <span class="kw">public</span> <span class="fu">ExprTracePcodeExecutorState</span><span class="op">(</span>TracePcodeExecutorStatePiece<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> <span class="dt">byte</span><span class="op">[]&gt;</span> concrete<span class="op">)</span> <span class="op">{</span></span>
<span id="cb11-87"><a href="#cb11-87"></a> <span class="kw">super</span><span class="op">(</span><span class="kw">new</span> PairedTracePcodeExecutorStatePiece<span class="op">&lt;&gt;(</span>concrete<span class="op">,</span></span>
<span id="cb11-88"><a href="#cb11-88"></a> <span class="kw">new</span> <span class="fu">ExprTracePcodeExecutorStatePiece</span><span class="op">(</span>concrete<span class="op">.</span><span class="fu">getData</span><span class="op">())));</span></span>
<span id="cb11-89"><a href="#cb11-89"></a> <span class="op">}</span></span>
<span id="cb11-90"><a href="#cb11-90"></a><span class="op">}</span></span></code></pre></div>
<p>Because we do not need any additional logic for target integration,
we do not need to extend the state pieces any further. The concrete
pieces that we augment will contain all the target integration needed.
@ -1124,30 +1138,101 @@ We have left the serialization as an exercise, though. Last, we
implement the full parts factory and use it to construct and install a
full <code>Expr</code>-augmented emulator factory:</p>
<div class="sourceCode" id="cb12"><pre
class="sourceCode numberSource java numberLines"><code class="sourceCode java"><span id="cb12-1"><a href="#cb12-1"></a><span class="kw">public</span> <span class="dt">static</span> <span class="kw">class</span> BytesExprDebuggerPcodeEmulator <span class="kw">extends</span> AuxDebuggerPcodeEmulator<span class="op">&lt;</span>Expr<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb12-2"><a href="#cb12-2"></a> <span class="kw">public</span> <span class="fu">BytesExprDebuggerPcodeEmulator</span><span class="op">(</span>PcodeDebuggerAccess access<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-3"><a href="#cb12-3"></a> <span class="kw">super</span><span class="op">(</span>access<span class="op">);</span></span>
<span id="cb12-4"><a href="#cb12-4"></a> <span class="op">}</span></span>
<span id="cb12-5"><a href="#cb12-5"></a></span>
<span id="cb12-6"><a href="#cb12-6"></a> <span class="at">@Override</span></span>
<span id="cb12-7"><a href="#cb12-7"></a> <span class="kw">protected</span> AuxDebuggerEmulatorPartsFactory<span class="op">&lt;</span>Expr<span class="op">&gt;</span> <span class="fu">getPartsFactory</span><span class="op">()</span> <span class="op">{</span></span>
<span id="cb12-8"><a href="#cb12-8"></a> <span class="cf">return</span> BytesExprDebuggerEmulatorPartsFactory<span class="op">.</span><span class="fu">INSTANCE</span><span class="op">;</span></span>
<span id="cb12-9"><a href="#cb12-9"></a> <span class="op">}</span></span>
<span id="cb12-10"><a href="#cb12-10"></a><span class="op">}</span></span>
<span id="cb12-11"><a href="#cb12-11"></a></span>
<span id="cb12-12"><a href="#cb12-12"></a><span class="kw">public</span> <span class="dt">static</span> <span class="kw">class</span> BytesExprDebuggerPcodeEmulatorFactory</span>
<span id="cb12-13"><a href="#cb12-13"></a> <span class="kw">implements</span> DebuggerPcodeEmulatorFactory <span class="op">{</span></span>
<span id="cb12-14"><a href="#cb12-14"></a></span>
<span id="cb12-15"><a href="#cb12-15"></a> <span class="at">@Override</span></span>
<span id="cb12-16"><a href="#cb12-16"></a> <span class="kw">public</span> <span class="bu">String</span> <span class="fu">getTitle</span><span class="op">()</span> <span class="op">{</span></span>
<span id="cb12-17"><a href="#cb12-17"></a> <span class="cf">return</span> <span class="st">&quot;Expr&quot;</span><span class="op">;</span></span>
<span id="cb12-18"><a href="#cb12-18"></a> <span class="op">}</span></span>
<span id="cb12-19"><a href="#cb12-19"></a></span>
<span id="cb12-20"><a href="#cb12-20"></a> <span class="at">@Override</span></span>
<span id="cb12-21"><a href="#cb12-21"></a> <span class="kw">public</span> DebuggerPcodeMachine<span class="op">&lt;?&gt;</span> <span class="fu">create</span><span class="op">(</span>PcodeDebuggerAccess access<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-22"><a href="#cb12-22"></a> <span class="cf">return</span> <span class="kw">new</span> <span class="fu">BytesExprDebuggerPcodeEmulator</span><span class="op">(</span>access<span class="op">);</span></span>
<span id="cb12-23"><a href="#cb12-23"></a> <span class="op">}</span></span>
<span id="cb12-24"><a href="#cb12-24"></a><span class="op">}</span></span></code></pre></div>
class="sourceCode numberSource java numberLines"><code class="sourceCode java"><span id="cb12-1"><a href="#cb12-1"></a><span class="kw">public</span> <span class="kw">enum</span> BytesExprDebuggerEmulatorPartsFactory</span>
<span id="cb12-2"><a href="#cb12-2"></a> <span class="kw">implements</span> AuxDebuggerEmulatorPartsFactory<span class="op">&lt;</span>Expr<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb12-3"><a href="#cb12-3"></a> INSTANCE<span class="op">;</span></span>
<span id="cb12-4"><a href="#cb12-4"></a></span>
<span id="cb12-5"><a href="#cb12-5"></a> <span class="at">@Override</span></span>
<span id="cb12-6"><a href="#cb12-6"></a> <span class="kw">public</span> PcodeArithmetic<span class="op">&lt;</span>Expr<span class="op">&gt;</span> <span class="fu">getArithmetic</span><span class="op">(</span>Language language<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-7"><a href="#cb12-7"></a> <span class="cf">return</span> ExprPcodeArithmetic<span class="op">.</span><span class="fu">forLanguage</span><span class="op">(</span>language<span class="op">);</span></span>
<span id="cb12-8"><a href="#cb12-8"></a> <span class="op">}</span></span>
<span id="cb12-9"><a href="#cb12-9"></a></span>
<span id="cb12-10"><a href="#cb12-10"></a> <span class="at">@Override</span></span>
<span id="cb12-11"><a href="#cb12-11"></a> <span class="kw">public</span> PcodeUseropLibrary<span class="op">&lt;</span>Pair<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">&gt;&gt;</span> <span class="fu">createSharedUseropLibrary</span><span class="op">(</span></span>
<span id="cb12-12"><a href="#cb12-12"></a> AuxPcodeEmulator<span class="op">&lt;</span>Expr<span class="op">&gt;</span> emulator<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-13"><a href="#cb12-13"></a> <span class="cf">return</span> PcodeUseropLibrary<span class="op">.</span><span class="fu">nil</span><span class="op">();</span></span>
<span id="cb12-14"><a href="#cb12-14"></a> <span class="op">}</span></span>
<span id="cb12-15"><a href="#cb12-15"></a></span>
<span id="cb12-16"><a href="#cb12-16"></a> <span class="at">@Override</span></span>
<span id="cb12-17"><a href="#cb12-17"></a> <span class="kw">public</span> PcodeUseropLibrary<span class="op">&lt;</span>Pair<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">&gt;&gt;</span> <span class="fu">createLocalUseropStub</span><span class="op">(</span></span>
<span id="cb12-18"><a href="#cb12-18"></a> AuxPcodeEmulator<span class="op">&lt;</span>Expr<span class="op">&gt;</span> emulator<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-19"><a href="#cb12-19"></a> <span class="cf">return</span> PcodeUseropLibrary<span class="op">.</span><span class="fu">nil</span><span class="op">();</span></span>
<span id="cb12-20"><a href="#cb12-20"></a> <span class="op">}</span></span>
<span id="cb12-21"><a href="#cb12-21"></a></span>
<span id="cb12-22"><a href="#cb12-22"></a> <span class="at">@Override</span></span>
<span id="cb12-23"><a href="#cb12-23"></a> <span class="kw">public</span> PcodeUseropLibrary<span class="op">&lt;</span>Pair<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">&gt;&gt;</span> <span class="fu">createLocalUseropLibrary</span><span class="op">(</span></span>
<span id="cb12-24"><a href="#cb12-24"></a> AuxPcodeEmulator<span class="op">&lt;</span>Expr<span class="op">&gt;</span> emulator<span class="op">,</span> PcodeThread<span class="op">&lt;</span>Pair<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">&gt;&gt;</span> thread<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-25"><a href="#cb12-25"></a> <span class="cf">return</span> PcodeUseropLibrary<span class="op">.</span><span class="fu">nil</span><span class="op">();</span></span>
<span id="cb12-26"><a href="#cb12-26"></a> <span class="op">}</span></span>
<span id="cb12-27"><a href="#cb12-27"></a></span>
<span id="cb12-28"><a href="#cb12-28"></a> <span class="at">@Override</span></span>
<span id="cb12-29"><a href="#cb12-29"></a> <span class="kw">public</span> PcodeExecutorState<span class="op">&lt;</span>Pair<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">&gt;&gt;</span> <span class="fu">createSharedState</span><span class="op">(</span></span>
<span id="cb12-30"><a href="#cb12-30"></a> AuxPcodeEmulator<span class="op">&lt;</span>Expr<span class="op">&gt;</span> emulator<span class="op">,</span> BytesPcodeExecutorStatePiece concrete<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-31"><a href="#cb12-31"></a> <span class="cf">return</span> <span class="kw">new</span> <span class="fu">BytesExprPcodeExecutorState</span><span class="op">(</span>concrete<span class="op">);</span></span>
<span id="cb12-32"><a href="#cb12-32"></a> <span class="op">}</span></span>
<span id="cb12-33"><a href="#cb12-33"></a></span>
<span id="cb12-34"><a href="#cb12-34"></a> <span class="at">@Override</span></span>
<span id="cb12-35"><a href="#cb12-35"></a> <span class="kw">public</span> PcodeExecutorState<span class="op">&lt;</span>Pair<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">&gt;&gt;</span> <span class="fu">createLocalState</span><span class="op">(</span></span>
<span id="cb12-36"><a href="#cb12-36"></a> AuxPcodeEmulator<span class="op">&lt;</span>Expr<span class="op">&gt;</span> emulator<span class="op">,</span> PcodeThread<span class="op">&lt;</span>Pair<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">&gt;&gt;</span> thread<span class="op">,</span></span>
<span id="cb12-37"><a href="#cb12-37"></a> BytesPcodeExecutorStatePiece concrete<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-38"><a href="#cb12-38"></a> <span class="cf">return</span> <span class="kw">new</span> <span class="fu">BytesExprPcodeExecutorState</span><span class="op">(</span>concrete<span class="op">);</span></span>
<span id="cb12-39"><a href="#cb12-39"></a> <span class="op">}</span></span>
<span id="cb12-40"><a href="#cb12-40"></a></span>
<span id="cb12-41"><a href="#cb12-41"></a> <span class="at">@Override</span></span>
<span id="cb12-42"><a href="#cb12-42"></a> <span class="kw">public</span> TracePcodeExecutorState<span class="op">&lt;</span>Pair<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">&gt;&gt;</span> <span class="fu">createTraceSharedState</span><span class="op">(</span></span>
<span id="cb12-43"><a href="#cb12-43"></a> AuxTracePcodeEmulator<span class="op">&lt;</span>ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">&gt;</span> emulator<span class="op">,</span></span>
<span id="cb12-44"><a href="#cb12-44"></a> BytesTracePcodeExecutorStatePiece concrete<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-45"><a href="#cb12-45"></a> <span class="cf">return</span> <span class="kw">new</span> <span class="fu">ExprTracePcodeExecutorState</span><span class="op">(</span>concrete<span class="op">);</span></span>
<span id="cb12-46"><a href="#cb12-46"></a> <span class="op">}</span></span>
<span id="cb12-47"><a href="#cb12-47"></a></span>
<span id="cb12-48"><a href="#cb12-48"></a> <span class="at">@Override</span></span>
<span id="cb12-49"><a href="#cb12-49"></a> <span class="kw">public</span> TracePcodeExecutorState<span class="op">&lt;</span>Pair<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">&gt;&gt;</span> <span class="fu">createTraceLocalState</span><span class="op">(</span></span>
<span id="cb12-50"><a href="#cb12-50"></a> AuxTracePcodeEmulator<span class="op">&lt;</span>ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">&gt;</span> emulator<span class="op">,</span></span>
<span id="cb12-51"><a href="#cb12-51"></a> PcodeThread<span class="op">&lt;</span>Pair<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">&gt;&gt;</span> thread<span class="op">,</span></span>
<span id="cb12-52"><a href="#cb12-52"></a> BytesTracePcodeExecutorStatePiece concrete<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-53"><a href="#cb12-53"></a> <span class="cf">return</span> <span class="kw">new</span> <span class="fu">ExprTracePcodeExecutorState</span><span class="op">(</span>concrete<span class="op">);</span></span>
<span id="cb12-54"><a href="#cb12-54"></a> <span class="op">}</span></span>
<span id="cb12-55"><a href="#cb12-55"></a></span>
<span id="cb12-56"><a href="#cb12-56"></a> <span class="at">@Override</span></span>
<span id="cb12-57"><a href="#cb12-57"></a> <span class="kw">public</span> TracePcodeExecutorState<span class="op">&lt;</span>Pair<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">&gt;&gt;</span> <span class="fu">createDebuggerSharedState</span><span class="op">(</span></span>
<span id="cb12-58"><a href="#cb12-58"></a> AuxDebuggerPcodeEmulator<span class="op">&lt;</span>ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">&gt;</span> emulator<span class="op">,</span></span>
<span id="cb12-59"><a href="#cb12-59"></a> RWTargetMemoryPcodeExecutorStatePiece concrete<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-60"><a href="#cb12-60"></a> <span class="cf">return</span> <span class="kw">new</span> <span class="fu">ExprTracePcodeExecutorState</span><span class="op">(</span>concrete<span class="op">);</span></span>
<span id="cb12-61"><a href="#cb12-61"></a> <span class="op">}</span></span>
<span id="cb12-62"><a href="#cb12-62"></a></span>
<span id="cb12-63"><a href="#cb12-63"></a> <span class="at">@Override</span></span>
<span id="cb12-64"><a href="#cb12-64"></a> <span class="kw">public</span> TracePcodeExecutorState<span class="op">&lt;</span>Pair<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">&gt;&gt;</span> <span class="fu">createDebuggerLocalState</span><span class="op">(</span></span>
<span id="cb12-65"><a href="#cb12-65"></a> AuxDebuggerPcodeEmulator<span class="op">&lt;</span>ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">&gt;</span> emulator<span class="op">,</span></span>
<span id="cb12-66"><a href="#cb12-66"></a> PcodeThread<span class="op">&lt;</span>Pair<span class="op">&lt;</span><span class="dt">byte</span><span class="op">[],</span> ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">&gt;&gt;</span> thread<span class="op">,</span></span>
<span id="cb12-67"><a href="#cb12-67"></a> RWTargetRegistersPcodeExecutorStatePiece concrete<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-68"><a href="#cb12-68"></a> <span class="cf">return</span> <span class="kw">new</span> <span class="fu">ExprTracePcodeExecutorState</span><span class="op">(</span>concrete<span class="op">);</span></span>
<span id="cb12-69"><a href="#cb12-69"></a> <span class="op">}</span></span>
<span id="cb12-70"><a href="#cb12-70"></a><span class="op">}</span></span>
<span id="cb12-71"><a href="#cb12-71"></a></span>
<span id="cb12-72"><a href="#cb12-72"></a><span class="kw">public</span> <span class="dt">static</span> <span class="kw">class</span> BytesExprDebuggerPcodeEmulator <span class="kw">extends</span> AuxDebuggerPcodeEmulator<span class="op">&lt;</span>Expr<span class="op">&gt;</span> <span class="op">{</span></span>
<span id="cb12-73"><a href="#cb12-73"></a> <span class="kw">public</span> <span class="fu">BytesExprDebuggerPcodeEmulator</span><span class="op">(</span>PcodeDebuggerAccess access<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-74"><a href="#cb12-74"></a> <span class="kw">super</span><span class="op">(</span>access<span class="op">);</span></span>
<span id="cb12-75"><a href="#cb12-75"></a> <span class="op">}</span></span>
<span id="cb12-76"><a href="#cb12-76"></a></span>
<span id="cb12-77"><a href="#cb12-77"></a> <span class="at">@Override</span></span>
<span id="cb12-78"><a href="#cb12-78"></a> <span class="kw">protected</span> AuxDebuggerEmulatorPartsFactory<span class="op">&lt;</span>Expr<span class="op">&gt;</span> <span class="fu">getPartsFactory</span><span class="op">()</span> <span class="op">{</span></span>
<span id="cb12-79"><a href="#cb12-79"></a> <span class="cf">return</span> BytesExprDebuggerEmulatorPartsFactory<span class="op">.</span><span class="fu">INSTANCE</span><span class="op">;</span></span>
<span id="cb12-80"><a href="#cb12-80"></a> <span class="op">}</span></span>
<span id="cb12-81"><a href="#cb12-81"></a><span class="op">}</span></span>
<span id="cb12-82"><a href="#cb12-82"></a></span>
<span id="cb12-83"><a href="#cb12-83"></a><span class="kw">public</span> <span class="dt">static</span> <span class="kw">class</span> BytesExprDebuggerPcodeEmulatorFactory</span>
<span id="cb12-84"><a href="#cb12-84"></a> <span class="kw">extends</span> AbstractDebuggerPcodeEmulatorFactory <span class="op">{</span></span>
<span id="cb12-85"><a href="#cb12-85"></a></span>
<span id="cb12-86"><a href="#cb12-86"></a> <span class="at">@Override</span></span>
<span id="cb12-87"><a href="#cb12-87"></a> <span class="kw">public</span> <span class="bu">String</span> <span class="fu">getTitle</span><span class="op">()</span> <span class="op">{</span></span>
<span id="cb12-88"><a href="#cb12-88"></a> <span class="cf">return</span> <span class="st">&quot;Expr&quot;</span><span class="op">;</span></span>
<span id="cb12-89"><a href="#cb12-89"></a> <span class="op">}</span></span>
<span id="cb12-90"><a href="#cb12-90"></a></span>
<span id="cb12-91"><a href="#cb12-91"></a> <span class="at">@Override</span></span>
<span id="cb12-92"><a href="#cb12-92"></a> <span class="kw">public</span> DebuggerPcodeMachine<span class="op">&lt;?&gt;</span> <span class="fu">create</span><span class="op">(</span>PcodeDebuggerAccess access<span class="op">)</span> <span class="op">{</span></span>
<span id="cb12-93"><a href="#cb12-93"></a> <span class="cf">return</span> <span class="kw">new</span> <span class="fu">BytesExprDebuggerPcodeEmulator</span><span class="op">(</span>access<span class="op">);</span></span>
<span id="cb12-94"><a href="#cb12-94"></a> <span class="op">}</span></span>
<span id="cb12-95"><a href="#cb12-95"></a><span class="op">}</span></span></code></pre></div>
<p>The factory can then be installed using a script. The script will set
your factory as the current emulator factory for the whole tool;
however, your script-based factory will not be listed in the menus.

View File

@ -95,12 +95,12 @@ A user would place a breakpoint at either the call site or the call target, have
### Modeling by Sleigh Semantics
The advantage to Java callbacks is that things are relatively intuitive to do, but the temptation, which we intentionally demonstrate here, is to make everything concrete.
The advantage to Java callbacks is that things are relatively intuitive to do, but the temptation, which we intentionally demonstrated above, is to make everything concrete.
You may notice the library uses a type parameter `T`, which specifies the type of all variables in the emulator's state.
Leaving it as `T` indicates the library is compatible with any type.
For a concrete emulator, `T = byte[]`, and so there is no loss in making things concrete, and then converting back to `T` using the arithmetic object.
For a concrete emulator, `T := byte[]`, and so there is no loss in making things concrete, and then converting back to `T` using the `arithmetic` object.
However, if the emulator has been augmented, as we will discuss below, the model may become confused, because values computed by a careless userop will appear to the model a literal constant.
To avoid this, you should keep everything a T and use the arithmetic object to perform any arithmetic operations.
To avoid this, you should keep everything a T and use the `arithmetic` object to perform any arithmetic operations.
Alternatively, you can implement the userop using pre-compiled Sleigh code:
```java {.numberLines}
@ -165,9 +165,9 @@ We could just use them directly in the source, but this demonstrates the ability
We then lazily compile each userop upon its first invocation.
These are technically still Java callbacks, but our implementation delegates to the executor, giving it the compiled p-code program.
The advantage here is that the code will properly use the underlying arithmetic appropriately.
The advantage here is that the p-code will use the underlying arithmetic appropriately.
However, for some models, that may actually not be desired.
Some symbolic models might just like to see a literal call to `strlen()`.
Some symbolic models might just like to see an abstract call to `strlen()`.
### Modeling by Structured Sleigh
@ -276,7 +276,7 @@ The emulation *is not* implicitly associated with the program!
You must copy the program image into its state, and you should choose a different location for the injection.
Refer to the example scripts in Ghidra's `SystemEmulation` module.
If you would like to (temporarily) override the GUI with a custom userop library, you can by overriding the GUI's emulator factory:
If you would like to (temporarily) override the GUI with a custom userop library, you can by setting the GUI's emulator factory:
```java {.numberLines}
public class InstallCustomLibraryScript extends GhidraScript implements FlatDebuggerAPI {
@ -517,7 +517,7 @@ The composition of states with the same addressing model is common enough that G
The relevant interface is `PcodeExecutorStatePiece`, which is the one we actually implement, by extending from `AbstractLongOffsetPcodeExecutorStatePiece`.
**NOTE**: If you do not desire a concrete address model, then you should implement `PcodeExecutorState<Expr>` directly.
A "state" is also "state piece" whose address model is the same as its value model, so states can still be composed.
A "state" is also a "state piece" whose address model is the same as its value model, so states can still be composed.
On one hand, the abstractly-addressed state provides a component that is readily used in both static and dynamic analysis; whereas, the concretely-addressed piece is suited only for dynamic analysis.
On the other hand, you may have some difficulty correlating concrete and abstract pieces during dynamic analysis when aliasing and indirection is involved.
@ -548,10 +548,14 @@ public static class ExprSpace {
map.put(offset, val);
}
protected Expr whenNull(long offset, int size) {
return new VarExpr(space, offset, size);
}
public Expr get(long offset, int size) {
// TODO: Handle overlaps / offcut gets and sets
Expr expr = map.get(offset);
return expr != null ? expr : new VarExpr(space, offset, size);
return expr != null ? expr : whenNull(offset, size);
}
}
@ -634,6 +638,7 @@ Notably, we have neglected the possibility that writes overlap or that reads are
This may not seem like a huge problem, but it is actually quite common, esp., since x86 registers are structured.
A write to `RAX` followed by a read from `EAX` will immediately demonstrate this issue.
Nevertheless, we leave those details as an exercise.
We factor `whenNull` so that it can be overridden later.
The remaining parts are mostly boilerplate.
We implement the "state piece" interface by creating another abstract class.
@ -760,7 +765,7 @@ public class ModelingScript extends GhidraScript {
```
**NOTE**: When accessed as a paired state, all sets will affect both pieces.
If you use the arithmetic to generate them, remember that it will use `fromConst` on both arithmetics to generate the pair, so you may be setting the right side to a `LitExpr`.
If you use the arithmetic to generate them, remember that it will use `fromConst` on both sub-arithmetics to generate the pair, so you may be setting the right side to a `LitExpr`.
To modify just one side of the pair, cast the state to `PairedPcodeExecutorState`, and then use `getLeft()`, and `getRight()` to retrieve the separate pieces.
## Use in Static Analysis
@ -820,7 +825,7 @@ public static class ExprTraceSpace extends ExprSpace {
public static class ExprTracePcodeExecutorStatePiece
extends AbstractExprPcodeExecutorStatePiece<ExprTraceSpace>
implements TracePcodeExecutorStatePiece<byte[], Expr> {
public static final String NAME = "Taint";
public static final String NAME = "Expr";
protected final PcodeTraceDataAccess data;
protected final PcodeTracePropertyAccess<String> property;
@ -865,6 +870,14 @@ public static class ExprTracePcodeExecutorStatePiece
}
}
}
public static class ExprTracePcodeExecutorState
extends PairedTracePcodeExecutorState<byte[], Expr> {
public ExprTracePcodeExecutorState(TracePcodeExecutorStatePiece<byte[], byte[]> concrete) {
super(new PairedTracePcodeExecutorStatePiece<>(concrete,
new ExprTracePcodeExecutorStatePiece(concrete.getData())));
}
}
```
Because we do not need any additional logic for target integration, we do not need to extend the state pieces any further.
@ -873,6 +886,77 @@ We have left the serialization as an exercise, though.
Last, we implement the full parts factory and use it to construct and install a full `Expr`-augmented emulator factory:
```java {.numberLines}
public enum BytesExprDebuggerEmulatorPartsFactory
implements AuxDebuggerEmulatorPartsFactory<Expr> {
INSTANCE;
@Override
public PcodeArithmetic<Expr> getArithmetic(Language language) {
return ExprPcodeArithmetic.forLanguage(language);
}
@Override
public PcodeUseropLibrary<Pair<byte[], Expr>> createSharedUseropLibrary(
AuxPcodeEmulator<Expr> emulator) {
return PcodeUseropLibrary.nil();
}
@Override
public PcodeUseropLibrary<Pair<byte[], Expr>> createLocalUseropStub(
AuxPcodeEmulator<Expr> emulator) {
return PcodeUseropLibrary.nil();
}
@Override
public PcodeUseropLibrary<Pair<byte[], Expr>> createLocalUseropLibrary(
AuxPcodeEmulator<Expr> emulator, PcodeThread<Pair<byte[], Expr>> thread) {
return PcodeUseropLibrary.nil();
}
@Override
public PcodeExecutorState<Pair<byte[], Expr>> createSharedState(
AuxPcodeEmulator<Expr> emulator, BytesPcodeExecutorStatePiece concrete) {
return new BytesExprPcodeExecutorState(concrete);
}
@Override
public PcodeExecutorState<Pair<byte[], Expr>> createLocalState(
AuxPcodeEmulator<Expr> emulator, PcodeThread<Pair<byte[], Expr>> thread,
BytesPcodeExecutorStatePiece concrete) {
return new BytesExprPcodeExecutorState(concrete);
}
@Override
public TracePcodeExecutorState<Pair<byte[], ModelingScript.Expr>> createTraceSharedState(
AuxTracePcodeEmulator<ModelingScript.Expr> emulator,
BytesTracePcodeExecutorStatePiece concrete) {
return new ExprTracePcodeExecutorState(concrete);
}
@Override
public TracePcodeExecutorState<Pair<byte[], ModelingScript.Expr>> createTraceLocalState(
AuxTracePcodeEmulator<ModelingScript.Expr> emulator,
PcodeThread<Pair<byte[], ModelingScript.Expr>> thread,
BytesTracePcodeExecutorStatePiece concrete) {
return new ExprTracePcodeExecutorState(concrete);
}
@Override
public TracePcodeExecutorState<Pair<byte[], ModelingScript.Expr>> createDebuggerSharedState(
AuxDebuggerPcodeEmulator<ModelingScript.Expr> emulator,
RWTargetMemoryPcodeExecutorStatePiece concrete) {
return new ExprTracePcodeExecutorState(concrete);
}
@Override
public TracePcodeExecutorState<Pair<byte[], ModelingScript.Expr>> createDebuggerLocalState(
AuxDebuggerPcodeEmulator<ModelingScript.Expr> emulator,
PcodeThread<Pair<byte[], ModelingScript.Expr>> thread,
RWTargetRegistersPcodeExecutorStatePiece concrete) {
return new ExprTracePcodeExecutorState(concrete);
}
}
public static class BytesExprDebuggerPcodeEmulator extends AuxDebuggerPcodeEmulator<Expr> {
public BytesExprDebuggerPcodeEmulator(PcodeDebuggerAccess access) {
super(access);
@ -885,7 +969,7 @@ public static class BytesExprDebuggerPcodeEmulator extends AuxDebuggerPcodeEmula
}
public static class BytesExprDebuggerPcodeEmulatorFactory
implements DebuggerPcodeEmulatorFactory {
extends AbstractDebuggerPcodeEmulatorFactory {
@Override
public String getTitle() {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 KiB

After

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 128 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -109,6 +109,12 @@ img {
max-width: 100%;
}
code {
background: #444;
border-radius: 1pt;
padding: 1pt;
}
div.sourceCode {
position: relative;
color: black;
@ -118,6 +124,10 @@ div.sourceCode {
box-shadow: 0 0 5px black inset;
}
code.sourceCode {
background: transparent;
}
pre > code.sourceCode > span > a:first-child::before {
text-decoration: none;
}

View File

@ -102,6 +102,8 @@ GhidraClass/Debugger/images/Emulation_PcodeStepper.png||GHIDRA||||END|
GhidraClass/Debugger/images/Emulation_WatchesForCmdline.png||GHIDRA||||END|
GhidraClass/Debugger/images/Emulation_WatchesForCmdlineSet.png||GHIDRA||||END|
GhidraClass/Debugger/images/GettingStarted_DisassemblyAfterLaunch.png||GHIDRA||||END|
GhidraClass/Debugger/images/GettingStarted_LaunchGDBDialog.png||GHIDRA||||END|
GhidraClass/Debugger/images/GettingStarted_Termmines.png||GHIDRA||||END|
GhidraClass/Debugger/images/GettingStarted_ToolWSpecimen.png||GHIDRA||||END|
GhidraClass/Debugger/images/MemoryMap_CopyNcursesInto.png||GHIDRA||||END|
GhidraClass/Debugger/images/MemoryMap_ModulesAfterLaunch.png||GHIDRA||||END|
@ -112,8 +114,9 @@ GhidraClass/Debugger/images/Navigation_DialogCompareTimes.png||GHIDRA||||END|
GhidraClass/Debugger/images/Navigation_StackInCallRand.png||GHIDRA||||END|
GhidraClass/Debugger/images/Navigation_ThreadsInCallRand.png||GHIDRA||||END|
GhidraClass/Debugger/images/Navigation_TimeAfterCallSRandCallRand.png||GHIDRA||||END|
GhidraClass/Debugger/images/RemoteTargets_Gadp.png||GHIDRA||||END|
GhidraClass/Debugger/images/RemoteTargets_GdbOverSsh.png||GHIDRA||||END|
GhidraClass/Debugger/images/RemoteTargets_AcceptTraceRmi.png||GHIDRA||||END|
GhidraClass/Debugger/images/RemoteTargets_GdbPlusGdbserverViaSsh.png||GHIDRA||||END|
GhidraClass/Debugger/images/RemoteTargets_GdbViaSsh.png||GHIDRA||||END|
GhidraClass/Debugger/images/State_BytesStackAfterCallRand.png||GHIDRA||||END|
GhidraClass/Debugger/images/State_ListingAfterCallRand.png||GHIDRA||||END|
GhidraClass/Debugger/images/State_ListingStackAfterCallRand.png||GHIDRA||||END|