GP-3887: Update Debugger course for Trace RMI.
|
@ -1224,6 +1224,7 @@ def put_regions():
|
||||||
regobj.set_value('_executable', r.perms == None or 'x' in r.perms)
|
regobj.set_value('_executable', r.perms == None or 'x' in r.perms)
|
||||||
regobj.set_value('_offset', r.offset)
|
regobj.set_value('_offset', r.offset)
|
||||||
regobj.set_value('_objfile', r.objfile)
|
regobj.set_value('_objfile', r.objfile)
|
||||||
|
regobj.set_value('_display', f'{r.objfile} (0x{r.start:x}-0x{r.end:x})')
|
||||||
regobj.insert()
|
regobj.insert()
|
||||||
STATE.trace.proxy_object_path(
|
STATE.trace.proxy_object_path(
|
||||||
MEMORY_PATTERN.format(infnum=inf.num)).retain_values(keys)
|
MEMORY_PATTERN.format(infnum=inf.num)).retain_values(keys)
|
||||||
|
|
|
@ -57,6 +57,7 @@ GNU_DEBUGDATA_PREFIX = ".gnu_debugdata for "
|
||||||
class Module(namedtuple('BaseModule', ['name', 'base', 'max', 'sections'])):
|
class Module(namedtuple('BaseModule', ['name', 'base', 'max', 'sections'])):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class Index:
|
class Index:
|
||||||
def __init__(self, regions):
|
def __init__(self, regions):
|
||||||
self.regions = {}
|
self.regions = {}
|
||||||
|
@ -64,6 +65,7 @@ class Index:
|
||||||
for r in regions:
|
for r in regions:
|
||||||
self.regions[r.start] = r
|
self.regions[r.start] = r
|
||||||
self.bases.append(r.start)
|
self.bases.append(r.start)
|
||||||
|
|
||||||
def compute_base(self, address):
|
def compute_base(self, address):
|
||||||
index = bisect.bisect_right(self.bases, address) - 1
|
index = bisect.bisect_right(self.bases, address) - 1
|
||||||
if index == -1:
|
if index == -1:
|
||||||
|
@ -78,6 +80,7 @@ class Index:
|
||||||
else:
|
else:
|
||||||
return region.start
|
return region.start
|
||||||
|
|
||||||
|
|
||||||
class Section(namedtuple('BaseSection', ['name', 'start', 'end', 'offset', 'attrs'])):
|
class Section(namedtuple('BaseSection', ['name', 'start', 'end', 'offset', 'attrs'])):
|
||||||
def better(self, other):
|
def better(self, other):
|
||||||
start = self.start if self.start != 0 else other.start
|
start = self.start if self.start != 0 else other.start
|
||||||
|
@ -103,8 +106,6 @@ class ModuleInfoReader(object):
|
||||||
if mat is None:
|
if mat is None:
|
||||||
return None
|
return None
|
||||||
n = mat['name']
|
n = mat['name']
|
||||||
if n.startswith(GNU_DEBUGDATA_PREFIX):
|
|
||||||
return None
|
|
||||||
return None if mat is None else mat['name']
|
return None if mat is None else mat['name']
|
||||||
|
|
||||||
def section_from_line(self, line):
|
def section_from_line(self, line):
|
||||||
|
@ -135,7 +136,7 @@ class ModuleInfoReader(object):
|
||||||
for line in out.split('\n'):
|
for line in out.split('\n'):
|
||||||
n = self.name_from_line(line)
|
n = self.name_from_line(line)
|
||||||
if n is not None:
|
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)
|
modules[name] = self.finish_module(name, sections, index)
|
||||||
name = n
|
name = n
|
||||||
sections = {}
|
sections = {}
|
||||||
|
@ -148,7 +149,7 @@ class ModuleInfoReader(object):
|
||||||
if s.name in sections:
|
if s.name in sections:
|
||||||
s = s.better(sections[s.name])
|
s = s.better(sections[s.name])
|
||||||
sections[s.name] = s
|
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)
|
modules[name] = self.finish_module(name, sections, index)
|
||||||
return modules
|
return modules
|
||||||
|
|
||||||
|
@ -292,8 +293,9 @@ class BreakpointLocationInfoReaderV8(object):
|
||||||
inf = gdb.selected_inferior()
|
inf = gdb.selected_inferior()
|
||||||
thread_groups = [inf.num]
|
thread_groups = [inf.num]
|
||||||
if breakpoint.location is not None and breakpoint.location.startswith("*0x"):
|
if breakpoint.location is not None and breakpoint.location.startswith("*0x"):
|
||||||
address = int(breakpoint.location[1:],16)
|
address = int(breakpoint.location[1:], 16)
|
||||||
loc = BreakpointLocation(address, breakpoint.enabled, thread_groups)
|
loc = BreakpointLocation(
|
||||||
|
address, breakpoint.enabled, thread_groups)
|
||||||
return [loc]
|
return [loc]
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
@ -312,7 +314,8 @@ class BreakpointLocationInfoReaderV9(object):
|
||||||
return []
|
return []
|
||||||
try:
|
try:
|
||||||
address = gdb.parse_and_eval(breakpoint.location).address
|
address = gdb.parse_and_eval(breakpoint.location).address
|
||||||
loc = BreakpointLocation(address, breakpoint.enabled, thread_groups)
|
loc = BreakpointLocation(
|
||||||
|
address, breakpoint.enabled, thread_groups)
|
||||||
return [loc]
|
return [loc]
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Error parsing bpt location = {breakpoint.location}")
|
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()
|
BREAKPOINT_LOCATION_INFO_READER = _choose_breakpoint_location_info_reader()
|
||||||
|
|
||||||
|
|
||||||
def set_bool_param_by_api(name, value):
|
def set_bool_param_by_api(name, value):
|
||||||
gdb.set_parameter(name, value)
|
gdb.set_parameter(name, value)
|
||||||
|
|
||||||
|
@ -353,6 +357,7 @@ def choose_set_parameter():
|
||||||
else:
|
else:
|
||||||
return set_bool_param_by_cmd
|
return set_bool_param_by_cmd
|
||||||
|
|
||||||
|
|
||||||
set_bool_param = choose_set_parameter()
|
set_bool_param = choose_set_parameter()
|
||||||
|
|
||||||
|
|
||||||
|
@ -360,7 +365,7 @@ def get_level(frame):
|
||||||
if hasattr(frame, "level"):
|
if hasattr(frame, "level"):
|
||||||
return frame.level()
|
return frame.level()
|
||||||
else:
|
else:
|
||||||
level = -1;
|
level = -1
|
||||||
f = frame
|
f = frame
|
||||||
while f is not None:
|
while f is not None:
|
||||||
level += 1
|
level += 1
|
||||||
|
@ -371,16 +376,16 @@ def get_level(frame):
|
||||||
class RegisterDesc(namedtuple('BaseRegisterDesc', ['name'])):
|
class RegisterDesc(namedtuple('BaseRegisterDesc', ['name'])):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def get_register_descs(arch, group='all'):
|
def get_register_descs(arch, group='all'):
|
||||||
if hasattr(arch, "registers"):
|
if hasattr(arch, "registers"):
|
||||||
return arch.registers(group)
|
return arch.registers(group)
|
||||||
else:
|
else:
|
||||||
descs = []
|
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:
|
for line in regset:
|
||||||
if not line.startswith(" "):
|
if not line.startswith(" "):
|
||||||
tokens = line.strip().split()
|
tokens = line.strip().split()
|
||||||
descs.append(RegisterDesc(tokens[0]))
|
descs.append(RegisterDesc(tokens[0]))
|
||||||
return descs
|
return descs
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.debug.gui.tracermi.launcher;
|
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.*;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
@ -52,7 +54,7 @@ public class LaunchAction extends MultiActionDockingAction {
|
||||||
Program program = plugin.currentProgram;
|
Program program = plugin.currentProgram;
|
||||||
String title = program == null
|
String title = program == null
|
||||||
? "Configure and Launch ..."
|
? "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);
|
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());
|
Long last = saved.get(offer.getConfigName());
|
||||||
if (last == null) {
|
if (last == null) {
|
||||||
// NB. If program == null, this will always happen.
|
// NB. If program == null, this will always happen.
|
||||||
// Thus, no worries about program.getName() below.
|
// Thus, no worries about getProgramName(program) below.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
String title = program == null
|
String title = program == null
|
||||||
? "Re-launch " + offer.getTitle()
|
? "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())
|
actions.add(new ActionBuilder(offer.getConfigName(), plugin.getName())
|
||||||
.popupMenuPath(title)
|
.popupMenuPath(title)
|
||||||
.popupMenuGroup("0", "%016x".formatted(Long.MAX_VALUE - last))
|
.popupMenuGroup("0", "%016x".formatted(Long.MAX_VALUE - last))
|
||||||
|
@ -158,11 +160,11 @@ public class LaunchAction extends MultiActionDockingAction {
|
||||||
return "Configure and launch";
|
return "Configure and launch";
|
||||||
}
|
}
|
||||||
if (offer == null) {
|
if (offer == null) {
|
||||||
return "Configure and launch " + program.getName();
|
return "Configure and launch " + getProgramName(program);
|
||||||
}
|
}
|
||||||
if (program == null) {
|
if (program == null) {
|
||||||
return "Re-launch " + offer.getTitle();
|
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ import ghidra.debug.api.tracermi.TraceRmiLaunchOffer.LaunchConfigurator;
|
||||||
import ghidra.debug.api.tracermi.TraceRmiLaunchOffer.PromptMode;
|
import ghidra.debug.api.tracermi.TraceRmiLaunchOffer.PromptMode;
|
||||||
import ghidra.debug.spi.tracermi.TraceRmiLaunchOpinion;
|
import ghidra.debug.spi.tracermi.TraceRmiLaunchOpinion;
|
||||||
import ghidra.formats.gfilesystem.FSRL;
|
import ghidra.formats.gfilesystem.FSRL;
|
||||||
|
import ghidra.framework.model.DomainFile;
|
||||||
import ghidra.framework.options.*;
|
import ghidra.framework.options.*;
|
||||||
import ghidra.framework.plugintool.*;
|
import ghidra.framework.plugintool.*;
|
||||||
import ghidra.framework.plugintool.util.PluginStatus;
|
import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
|
@ -236,10 +237,18 @@ public class TraceRmiLauncherServicePlugin extends Plugin
|
||||||
executeTask(new ConfigureAndLaunchTask(offer));
|
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() {
|
protected String[] constructLaunchMenuPrefix() {
|
||||||
return new String[] {
|
return new String[] {
|
||||||
DebuggerPluginPackage.NAME,
|
DebuggerPluginPackage.NAME,
|
||||||
"Configure and Launch " + currentProgram.getName() + " using..." };
|
"Configure and Launch " + getProgramName(currentProgram) + " using..." };
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String[] prependConfigAndLaunch(List<String> menuPath) {
|
protected String[] prependConfigAndLaunch(List<String> menuPath) {
|
||||||
|
|
|
@ -810,6 +810,11 @@ public class TraceRmiHandler implements TraceRmiConnection {
|
||||||
}
|
}
|
||||||
DebuggerCoordinates finalCoords = object == null ? coords : coords.object(object);
|
DebuggerCoordinates finalCoords = object == null ? coords : coords.object(object);
|
||||||
Swing.runLater(() -> {
|
Swing.runLater(() -> {
|
||||||
|
DebuggerTraceManagerService traceManager = this.traceManager;
|
||||||
|
if (traceManager == null) {
|
||||||
|
// Can happen during tear down.
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!traceManager.getOpenTraces().contains(open.trace)) {
|
if (!traceManager.getOpenTraces().contains(open.trace)) {
|
||||||
traceManager.openTrace(open.trace);
|
traceManager.openTrace(open.trace);
|
||||||
traceManager.activate(finalCoords, ActivationCause.SYNC_MODEL);
|
traceManager.activate(finalCoords, ActivationCause.SYNC_MODEL);
|
||||||
|
|
|
@ -26,7 +26,6 @@ import ghidra.app.plugin.core.debug.utils.MiscellaneousUtils;
|
||||||
import ghidra.app.services.DebuggerStaticMappingService;
|
import ghidra.app.services.DebuggerStaticMappingService;
|
||||||
import ghidra.app.services.ProgramManager;
|
import ghidra.app.services.ProgramManager;
|
||||||
import ghidra.framework.cmd.BackgroundCommand;
|
import ghidra.framework.cmd.BackgroundCommand;
|
||||||
import ghidra.framework.model.DomainObject;
|
|
||||||
import ghidra.framework.options.SaveState;
|
import ghidra.framework.options.SaveState;
|
||||||
import ghidra.framework.plugintool.AutoConfigState.ConfigFieldCodec;
|
import ghidra.framework.plugintool.AutoConfigState.ConfigFieldCodec;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
|
@ -104,9 +103,9 @@ public interface AutoMapSpec extends ExtensionPoint {
|
||||||
if (mappingService == null || programManager == null) {
|
if (mappingService == null || programManager == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
BackgroundCommand cmd = new BackgroundCommand(getTaskTitle(), true, true, false) {
|
BackgroundCommand<Trace> cmd = new BackgroundCommand<>(getTaskTitle(), true, true, false) {
|
||||||
@Override
|
@Override
|
||||||
public boolean applyTo(DomainObject obj, TaskMonitor monitor) {
|
public boolean applyTo(Trace trace, TaskMonitor monitor) {
|
||||||
try {
|
try {
|
||||||
performMapping(mappingService, trace, programManager, monitor);
|
performMapping(mappingService, trace, programManager, monitor);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -799,7 +799,7 @@ public class DebuggerCopyIntoProgramDialog extends ReusableDialogComponentProvid
|
||||||
|
|
||||||
protected void executeCapture(AddressRange range, Target target, TaskMonitor monitor)
|
protected void executeCapture(AddressRange range, Target target, TaskMonitor monitor)
|
||||||
throws Exception {
|
throws Exception {
|
||||||
target.readMemory(new AddressSet(range), monitor);
|
target.readMemoryAsync(new AddressSet(range), monitor).get();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void executePlan(TaskMonitor monitor) throws Exception {
|
protected void executePlan(TaskMonitor monitor) throws Exception {
|
||||||
|
|
|
@ -64,6 +64,11 @@ public interface DisplaysObjectValues {
|
||||||
.collect(Collectors.joining(":"));
|
.collect(Collectors.joining(":"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
default String getStringsDisplay(String[] strings) {
|
||||||
|
return Stream.of(strings)
|
||||||
|
.collect(Collectors.joining(":"));
|
||||||
|
}
|
||||||
|
|
||||||
default String getPrimitiveValueDisplay(Object value) {
|
default String getPrimitiveValueDisplay(Object value) {
|
||||||
assert !(value instanceof TraceObject);
|
assert !(value instanceof TraceObject);
|
||||||
assert !(value instanceof TraceObjectValue);
|
assert !(value instanceof TraceObjectValue);
|
||||||
|
@ -89,6 +94,9 @@ public interface DisplaysObjectValues {
|
||||||
if (value instanceof long[] longs) {
|
if (value instanceof long[] longs) {
|
||||||
return getLongsDisplay(longs);
|
return getLongsDisplay(longs);
|
||||||
}
|
}
|
||||||
|
if (value instanceof String[] strings) {
|
||||||
|
return getStringsDisplay(strings);
|
||||||
|
}
|
||||||
return value.toString();
|
return value.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,13 +42,13 @@ public class DebuggerModuleMapProposalDialog
|
||||||
implements EnumeratedTableColumn<ModuleMapTableColumns, ModuleMapEntry> {
|
implements EnumeratedTableColumn<ModuleMapTableColumns, ModuleMapEntry> {
|
||||||
REMOVE("Remove", String.class, e -> "Remove Proposed Entry", (e, v) -> nop()),
|
REMOVE("Remove", String.class, e -> "Remove Proposed Entry", (e, v) -> nop()),
|
||||||
MODULE_NAME("Module", String.class, e -> e.getModule().getName()),
|
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()),
|
CHOOSE("Choose", String.class, e -> "Choose Program", (e, v) -> nop()),
|
||||||
PROGRAM_NAME("Program", String.class, e -> (e.getToProgram().getDomainFile() == null
|
PROGRAM_NAME("Program", String.class, e -> (e.getToProgram().getDomainFile() == null
|
||||||
? e.getToProgram().getName()
|
? e.getToProgram().getName()
|
||||||
: e.getToProgram().getDomainFile().getName())),
|
: e.getToProgram().getDomainFile().getName())),
|
||||||
STATIC_BASE("Static Base", Address.class, e -> e.getToProgram().getImageBase()),
|
STATIC_BASE("Static Base", Address.class, e -> e.getToRange().getMinAddress()),
|
||||||
SIZE("Size", Long.class, e -> e.getModuleRange().getLength()),
|
SIZE("Size", Long.class, e -> e.getFromRange().getLength()),
|
||||||
MEMORIZE("Memorize", Boolean.class, ModuleMapEntry::isMemorize, ModuleMapEntry::setMemorize);
|
MEMORIZE("Memorize", Boolean.class, ModuleMapEntry::isMemorize, ModuleMapEntry::setMemorize);
|
||||||
|
|
||||||
private final String header;
|
private final String header;
|
||||||
|
|
|
@ -32,6 +32,7 @@ import ghidra.framework.plugintool.util.PluginStatus;
|
||||||
packageName = DebuggerPluginPackage.NAME,
|
packageName = DebuggerPluginPackage.NAME,
|
||||||
status = PluginStatus.RELEASED,
|
status = PluginStatus.RELEASED,
|
||||||
eventsConsumed = {
|
eventsConsumed = {
|
||||||
|
ProgramOpenedPluginEvent.class,
|
||||||
ProgramActivatedPluginEvent.class,
|
ProgramActivatedPluginEvent.class,
|
||||||
ProgramLocationPluginEvent.class,
|
ProgramLocationPluginEvent.class,
|
||||||
ProgramClosedPluginEvent.class,
|
ProgramClosedPluginEvent.class,
|
||||||
|
@ -65,7 +66,10 @@ public class DebuggerModulesPlugin extends AbstractDebuggerPlugin {
|
||||||
@Override
|
@Override
|
||||||
public void processEvent(PluginEvent event) {
|
public void processEvent(PluginEvent event) {
|
||||||
super.processEvent(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());
|
provider.setProgram(ev.getActiveProgram());
|
||||||
}
|
}
|
||||||
else if (event instanceof ProgramLocationPluginEvent ev) {
|
else if (event instanceof ProgramLocationPluginEvent ev) {
|
||||||
|
|
|
@ -1078,6 +1078,12 @@ public class DebuggerModulesProvider extends ComponentProviderAdapter {
|
||||||
actionMapSectionTo.getPopupMenuData().setMenuItemName(name);
|
actionMapSectionTo.getPopupMenuData().setMenuItemName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void programOpened(Program program) {
|
||||||
|
// TODO: Debounce this?
|
||||||
|
cueAutoMap = true;
|
||||||
|
doCuedAutoMap();
|
||||||
|
}
|
||||||
|
|
||||||
public void programClosed(Program program) {
|
public void programClosed(Program program) {
|
||||||
if (currentProgram == program) {
|
if (currentProgram == program) {
|
||||||
currentProgram = null;
|
currentProgram = null;
|
||||||
|
|
|
@ -614,7 +614,7 @@ public class DebuggerPcodeStepperProvider extends ComponentProviderAdapter {
|
||||||
pcodeTable.setTableHeader(null);
|
pcodeTable.setTableHeader(null);
|
||||||
pcodeTable.setBackground(COLOR_BACKGROUND);
|
pcodeTable.setBackground(COLOR_BACKGROUND);
|
||||||
pcodeTable.setSelectionBackground(COLOR_BACKGROUND_CURSOR);
|
pcodeTable.setSelectionBackground(COLOR_BACKGROUND_CURSOR);
|
||||||
pcodeTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
pcodeTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
|
||||||
pcodeTable.getSelectionModel().addListSelectionListener(evt -> {
|
pcodeTable.getSelectionModel().addListSelectionListener(evt -> {
|
||||||
if (evt.getValueIsAdjusting()) {
|
if (evt.getValueIsAdjusting()) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -106,6 +106,9 @@ public class UniqueRow {
|
||||||
}
|
}
|
||||||
|
|
||||||
public RefType getRefType() {
|
public RefType getRefType() {
|
||||||
|
if (provider.pcodeTable.getSelectedRowCount() != 1) {
|
||||||
|
return RefType.NONE;
|
||||||
|
}
|
||||||
int index = provider.pcodeTable.getSelectedRow();
|
int index = provider.pcodeTable.getSelectedRow();
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
return RefType.NONE;
|
return RefType.NONE;
|
||||||
|
|
|
@ -42,8 +42,8 @@ import ghidra.trace.database.DBTrace;
|
||||||
import ghidra.trace.model.*;
|
import ghidra.trace.model.*;
|
||||||
import ghidra.trace.model.memory.*;
|
import ghidra.trace.model.memory.*;
|
||||||
import ghidra.trace.model.modules.TraceConflictedMappingException;
|
import ghidra.trace.model.modules.TraceConflictedMappingException;
|
||||||
import ghidra.trace.model.target.TraceObject;
|
import ghidra.trace.model.target.*;
|
||||||
import ghidra.trace.model.target.TraceObjectKeyPath;
|
import ghidra.trace.model.target.TraceObject.ConflictResolution;
|
||||||
import ghidra.trace.model.thread.*;
|
import ghidra.trace.model.thread.*;
|
||||||
import ghidra.trace.model.time.TraceSnapshot;
|
import ghidra.trace.model.time.TraceSnapshot;
|
||||||
import ghidra.util.*;
|
import ghidra.util.*;
|
||||||
|
@ -70,7 +70,8 @@ public class ProgramEmulationUtils {
|
||||||
<attribute name='Modules' schema='ModuleContainer' />
|
<attribute name='Modules' schema='ModuleContainer' />
|
||||||
<attribute name='Threads' schema='ThreadContainer' />
|
<attribute name='Threads' schema='ThreadContainer' />
|
||||||
</schema>
|
</schema>
|
||||||
<schema name='BreakpointContainer' elementResync='NEVER' attributeResync='NEVER'>
|
<schema name='BreakpointContainer' canonical='yes' elementResync='NEVER'
|
||||||
|
attributeResync='NEVER'>
|
||||||
<interface name='BreakpointSpecContainer' />
|
<interface name='BreakpointSpecContainer' />
|
||||||
<interface name='BreakpointLocationContainer' />
|
<interface name='BreakpointLocationContainer' />
|
||||||
<element schema='Breakpoint' />
|
<element schema='Breakpoint' />
|
||||||
|
@ -494,6 +495,20 @@ public class ProgramEmulationUtils {
|
||||||
throw new EmulatorOutOfMemoryException();
|
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
|
* Create a new trace with a single thread, ready for emulation of the given program
|
||||||
*
|
*
|
||||||
|
@ -510,7 +525,8 @@ public class ProgramEmulationUtils {
|
||||||
try {
|
try {
|
||||||
trace = new DBTrace(getTraceName(program), program.getCompilerSpec(), consumer);
|
trace = new DBTrace(getTraceName(program), program.getCompilerSpec(), consumer);
|
||||||
try (Transaction tx = trace.openTransaction("Emulate")) {
|
try (Transaction tx = trace.openTransaction("Emulate")) {
|
||||||
trace.getObjectManager().createRootObject(EMU_SESSION_SCHEMA);
|
createObjects(trace);
|
||||||
|
|
||||||
TraceSnapshot initial =
|
TraceSnapshot initial =
|
||||||
trace.getTimeManager().createSnapshot(EMULATION_STARTED_AT + pc);
|
trace.getTimeManager().createSnapshot(EMULATION_STARTED_AT + pc);
|
||||||
long snap = initial.getKey();
|
long snap = initial.getKey();
|
||||||
|
|
|
@ -34,7 +34,6 @@ import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.trace.model.*;
|
import ghidra.trace.model.*;
|
||||||
import ghidra.trace.model.modules.*;
|
import ghidra.trace.model.modules.*;
|
||||||
import ghidra.trace.model.program.TraceProgramView;
|
import ghidra.trace.model.program.TraceProgramView;
|
||||||
import ghidra.trace.model.thread.TraceThread;
|
|
||||||
import ghidra.util.ComparatorMath;
|
import ghidra.util.ComparatorMath;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
|
|
||||||
|
@ -163,11 +162,17 @@ public enum DebuggerStaticMappingUtils {
|
||||||
private Address min = null;
|
private Address min = null;
|
||||||
private Address max = 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) {
|
public void consider(AddressRange range) {
|
||||||
min = min == null ? range.getMinAddress()
|
consider(range.getMinAddress(), range.getMaxAddress());
|
||||||
: ComparatorMath.cmin(min, range.getMinAddress());
|
}
|
||||||
max = max == null ? range.getMaxAddress()
|
|
||||||
: ComparatorMath.cmax(max, range.getMaxAddress());
|
public void consider(Address address) {
|
||||||
|
consider(address, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Address getMin() {
|
public Address getMin() {
|
||||||
|
@ -181,6 +186,10 @@ public enum DebuggerStaticMappingUtils {
|
||||||
public long getLength() {
|
public long getLength() {
|
||||||
return max.subtract(min) + 1;
|
return max.subtract(min) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AddressRange getRange() {
|
||||||
|
return new AddressRangeImpl(getMin(), getMax());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isReal(MemoryBlock block) {
|
public static boolean isReal(MemoryBlock block) {
|
||||||
|
|
|
@ -17,6 +17,7 @@ package ghidra.app.plugin.core.debug.service.modules;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
|
import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils.Extrema;
|
||||||
import ghidra.app.services.DebuggerStaticMappingService;
|
import ghidra.app.services.DebuggerStaticMappingService;
|
||||||
import ghidra.debug.api.modules.ModuleMapProposal;
|
import ghidra.debug.api.modules.ModuleMapProposal;
|
||||||
import ghidra.debug.api.modules.ModuleMapProposal.ModuleMapEntry;
|
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.TraceMemoryRegion;
|
||||||
import ghidra.trace.model.memory.TraceObjectMemoryRegion;
|
import ghidra.trace.model.memory.TraceObjectMemoryRegion;
|
||||||
import ghidra.trace.model.modules.TraceModule;
|
import ghidra.trace.model.modules.TraceModule;
|
||||||
|
import ghidra.util.MathUtilities;
|
||||||
|
|
||||||
public class DefaultModuleMapProposal
|
public class DefaultModuleMapProposal
|
||||||
extends AbstractMapProposal<TraceModule, Program, ModuleMapEntry>
|
extends AbstractMapProposal<TraceModule, Program, ModuleMapEntry>
|
||||||
|
@ -81,20 +83,24 @@ public class DefaultModuleMapProposal
|
||||||
* @param program the program image whose size to compute
|
* @param program the program image whose size to compute
|
||||||
* @return the size
|
* @return the size
|
||||||
*/
|
*/
|
||||||
public static long computeImageSize(Program program) {
|
public static AddressRange computeImageRange(Program program) {
|
||||||
Address imageBase = program.getImageBase();
|
Extrema extrema = new Extrema();
|
||||||
long imageSize = 0;
|
|
||||||
// TODO: How to handle Harvard architectures?
|
// TODO: How to handle Harvard architectures?
|
||||||
for (MemoryBlock block : program.getMemory().getBlocks()) {
|
for (MemoryBlock block : program.getMemory().getBlocks()) {
|
||||||
if (!includeBlock(program, block)) {
|
if (!includeBlock(program, block)) {
|
||||||
continue;
|
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 moduleRange;
|
||||||
|
protected AddressRange imageRange;
|
||||||
protected boolean memorize = false;
|
protected boolean memorize = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -113,6 +119,7 @@ public class DefaultModuleMapProposal
|
||||||
AddressRange moduleRange) {
|
AddressRange moduleRange) {
|
||||||
super(module.getTrace(), module, program, program);
|
super(module.getTrace(), module, program, program);
|
||||||
this.moduleRange = moduleRange;
|
this.moduleRange = moduleRange;
|
||||||
|
this.imageRange = quantize(computeImageRange(program));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -125,9 +132,18 @@ public class DefaultModuleMapProposal
|
||||||
return getModule().getLifespan();
|
return getModule().getLifespan();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long getLength() {
|
||||||
|
return MathUtilities.unsignedMin(moduleRange.getLength(), imageRange.getLength());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AddressRange getFromRange() {
|
public AddressRange getFromRange() {
|
||||||
return moduleRange;
|
try {
|
||||||
|
return new AddressRangeImpl(moduleRange.getMinAddress(), getLength());
|
||||||
|
}
|
||||||
|
catch (AddressOverflowException e) {
|
||||||
|
throw new AssertionError(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -138,21 +154,13 @@ public class DefaultModuleMapProposal
|
||||||
@Override
|
@Override
|
||||||
public void setProgram(Program program) {
|
public void setProgram(Program program) {
|
||||||
setToObject(program, program);
|
setToObject(program, program);
|
||||||
try {
|
this.imageRange = quantize(computeImageRange(program));
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AddressRange getToRange() {
|
public AddressRange getToRange() {
|
||||||
try {
|
try {
|
||||||
return new AddressRangeImpl(getToProgram().getImageBase(), moduleRange.getLength());
|
return new AddressRangeImpl(imageRange.getMinAddress(), getLength());
|
||||||
}
|
}
|
||||||
catch (AddressOverflowException e) {
|
catch (AddressOverflowException e) {
|
||||||
throw new AssertionError(e);
|
throw new AssertionError(e);
|
||||||
|
@ -174,10 +182,8 @@ public class DefaultModuleMapProposal
|
||||||
|
|
||||||
// indexed by region's offset from module base
|
// indexed by region's offset from module base
|
||||||
protected final NavigableMap<Long, ModuleRegionMatcher> matchers = new TreeMap<>();
|
protected final NavigableMap<Long, ModuleRegionMatcher> matchers = new TreeMap<>();
|
||||||
protected Address imageBase;
|
protected AddressRange imageRange;
|
||||||
protected Address moduleBase;
|
protected AddressRange moduleRange;
|
||||||
protected long imageSize;
|
|
||||||
protected AddressRange moduleRange; // TODO: This is now in the trace schema. Use it.
|
|
||||||
|
|
||||||
protected DefaultModuleMapProposal(TraceModule module, Program program) {
|
protected DefaultModuleMapProposal(TraceModule module, Program program) {
|
||||||
super(module.getTrace(), program);
|
super(module.getTrace(), program);
|
||||||
|
@ -196,8 +202,8 @@ public class DefaultModuleMapProposal
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processProgram() {
|
private void processProgram() {
|
||||||
imageBase = program.getImageBase();
|
imageRange = quantize(DefaultModuleMapEntry.computeImageRange(program));
|
||||||
imageSize = DefaultModuleMapEntry.computeImageSize(program);
|
Address imageBase = imageRange.getMinAddress(); // not precisely, but good enough
|
||||||
// TODO: How to handle Harvard architectures?
|
// TODO: How to handle Harvard architectures?
|
||||||
for (MemoryBlock block : program.getMemory().getBlocks()) {
|
for (MemoryBlock block : program.getMemory().getBlocks()) {
|
||||||
if (!DefaultModuleMapEntry.includeBlock(program, block)) {
|
if (!DefaultModuleMapEntry.includeBlock(program, block)) {
|
||||||
|
@ -211,13 +217,8 @@ public class DefaultModuleMapProposal
|
||||||
* Must be called after processProgram, so that image size is known
|
* Must be called after processProgram, so that image size is known
|
||||||
*/
|
*/
|
||||||
private void processModule() {
|
private void processModule() {
|
||||||
moduleBase = module.getBase();
|
moduleRange = quantize(module.getRange());
|
||||||
try {
|
Address moduleBase = moduleRange.getMinAddress();
|
||||||
moduleRange = quantize(new AddressRangeImpl(moduleBase, imageSize));
|
|
||||||
}
|
|
||||||
catch (AddressOverflowException e) {
|
|
||||||
return; // Just score it as having no matches?
|
|
||||||
}
|
|
||||||
Lifespan lifespan = module.getLifespan();
|
Lifespan lifespan = module.getLifespan();
|
||||||
for (TraceMemoryRegion region : module.getTrace()
|
for (TraceMemoryRegion region : module.getTrace()
|
||||||
.getMemoryManager()
|
.getMemoryManager()
|
||||||
|
|
|
@ -499,6 +499,21 @@ public enum PathUtils {
|
||||||
return Objects.equals(ancestor, successor.subList(0, ancestor.size()));
|
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.
|
* 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.
|
* Check whether a given attribute should be displayed.
|
||||||
*
|
*
|
||||||
* @param key the key of the given attribute
|
* @param key the key of the given attribute
|
||||||
|
* @return true if hidden
|
||||||
*/
|
*/
|
||||||
public static boolean isHidden(String key) {
|
public static boolean isHidden(String key) {
|
||||||
return key.startsWith(TargetObject.PREFIX_INVISIBLE);
|
return key.startsWith(TargetObject.PREFIX_INVISIBLE);
|
||||||
|
|
|
@ -121,8 +121,19 @@ public class DBTraceObjectBreakpointLocation
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
try (LockHold hold = object.getTrace().lockRead()) {
|
try (LockHold hold = object.getTrace().lockRead()) {
|
||||||
return TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(),
|
String display = TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(),
|
||||||
TargetObject.DISPLAY_ATTRIBUTE_NAME, String.class, "");
|
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
|
@Override
|
||||||
public String getComment() {
|
public String getComment() {
|
||||||
try (LockHold hold = object.getTrace().lockRead()) {
|
try (LockHold hold = object.getTrace().lockRead()) {
|
||||||
return TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(), KEY_COMMENT,
|
String comment = TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(),
|
||||||
String.class, "");
|
KEY_COMMENT, String.class, "");
|
||||||
|
if (!comment.isBlank()) {
|
||||||
|
return comment;
|
||||||
|
}
|
||||||
|
TraceObjectBreakpointSpec spec = getSpecification();
|
||||||
|
if (spec == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return spec.getExpression();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -181,6 +181,12 @@ public class DBTraceObjectBreakpointSpec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getExpression() {
|
||||||
|
return TraceObjectInterfaceUtils.getValue(object, getPlacedSnap(),
|
||||||
|
TargetBreakpointSpec.EXPRESSION_ATTRIBUTE_NAME, String.class, null);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<TraceThread> getThreads() {
|
public Set<TraceThread> getThreads() {
|
||||||
throw new UnsupportedOperationException("Ask a location instead");
|
throw new UnsupportedOperationException("Ask a location instead");
|
||||||
|
|
|
@ -18,7 +18,12 @@ package ghidra.trace.database.time;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import db.DBRecord;
|
import db.DBRecord;
|
||||||
|
import ghidra.dbg.target.TargetEventScope;
|
||||||
|
import ghidra.trace.database.target.DBTraceObject;
|
||||||
import ghidra.trace.model.Trace;
|
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.thread.TraceThread;
|
||||||
import ghidra.trace.model.time.TraceSnapshot;
|
import ghidra.trace.model.time.TraceSnapshot;
|
||||||
import ghidra.trace.model.time.schedule.TraceSchedule;
|
import ghidra.trace.model.time.schedule.TraceSchedule;
|
||||||
|
@ -143,7 +148,26 @@ public class DBTraceSnapshot extends DBAnnotatedObject implements TraceSnapshot
|
||||||
@Override
|
@Override
|
||||||
public TraceThread getEventThread() {
|
public TraceThread getEventThread() {
|
||||||
try (LockHold hold = LockHold.lock(manager.lock.readLock())) {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,5 +43,7 @@ public interface TraceObjectBreakpointSpec extends TraceBreakpoint, TraceObjectI
|
||||||
|
|
||||||
Collection<? extends TraceObjectBreakpointLocation> getLocations();
|
Collection<? extends TraceObjectBreakpointLocation> getLocations();
|
||||||
|
|
||||||
|
String getExpression();
|
||||||
|
|
||||||
void setKinds(Lifespan lifespan, Collection<TraceBreakpointKind> kinds);
|
void setKinds(Lifespan lifespan, Collection<TraceBreakpointKind> kinds);
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,8 +224,8 @@ public final class TraceObjectKeyPath implements Comparable<TraceObjectKeyPath>
|
||||||
/**
|
/**
|
||||||
* Stream, starting with the longer paths, paths that match the given predicates
|
* Stream, starting with the longer paths, paths that match the given predicates
|
||||||
*
|
*
|
||||||
* @param matcher
|
* @param predicates the predicates to filter the ancestor paths
|
||||||
* @return
|
* @return the stream of matching paths, longest to shortest
|
||||||
*/
|
*/
|
||||||
public Stream<TraceObjectKeyPath> streamMatchingAncestry(PathPredicates predicates) {
|
public Stream<TraceObjectKeyPath> streamMatchingAncestry(PathPredicates predicates) {
|
||||||
if (!predicates.ancestorMatches(keyList, false)) {
|
if (!predicates.ancestorMatches(keyList, false)) {
|
||||||
|
@ -253,4 +253,15 @@ public final class TraceObjectKeyPath implements Comparable<TraceObjectKeyPath>
|
||||||
public boolean isAncestor(TraceObjectKeyPath that) {
|
public boolean isAncestor(TraceObjectKeyPath that) {
|
||||||
return PathUtils.isAncestor(keyList, that.keyList);
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import static org.junit.Assert.assertTrue;
|
||||||
import java.awt.Rectangle;
|
import java.awt.Rectangle;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.FileAlreadyExistsException;
|
import java.nio.file.FileAlreadyExistsException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.*;
|
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.memory.DebuggerRegionsProvider;
|
||||||
import ghidra.app.plugin.core.debug.gui.modules.DebuggerModulesProvider;
|
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.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.DebuggerPcodeStepperPlugin;
|
||||||
import ghidra.app.plugin.core.debug.gui.pcode.DebuggerPcodeStepperProvider;
|
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.register.DebuggerRegistersProvider;
|
||||||
import ghidra.app.plugin.core.debug.gui.stack.DebuggerStackProvider;
|
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.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.thread.DebuggerThreadsProvider;
|
||||||
import ghidra.app.plugin.core.debug.gui.time.DebuggerTimeProvider;
|
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.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.gui.watch.DebuggerWatchesProvider;
|
||||||
import ghidra.app.plugin.core.debug.service.emulation.DebuggerEmulationServicePlugin;
|
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.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;
|
||||||
import ghidra.app.plugin.core.debug.stack.StackUnwinderTest.HoverLocation;
|
import ghidra.app.plugin.core.debug.stack.StackUnwinderTest.HoverLocation;
|
||||||
import ghidra.app.plugin.core.debug.stack.UnwindStackCommand;
|
import ghidra.app.plugin.core.debug.stack.UnwindStackCommand;
|
||||||
import ghidra.app.plugin.core.decompile.DecompilerProvider;
|
import ghidra.app.plugin.core.decompile.DecompilerProvider;
|
||||||
|
import ghidra.app.plugin.core.terminal.TerminalProvider;
|
||||||
import ghidra.app.script.GhidraState;
|
import ghidra.app.script.GhidraState;
|
||||||
import ghidra.app.services.*;
|
import ghidra.app.services.*;
|
||||||
import ghidra.app.services.DebuggerEmulationService.EmulationResult;
|
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.importer.MessageLog;
|
||||||
import ghidra.app.util.opinion.LoadResults;
|
import ghidra.app.util.opinion.LoadResults;
|
||||||
import ghidra.async.AsyncTestUtils;
|
import ghidra.async.AsyncTestUtils;
|
||||||
import ghidra.dbg.DebuggerModelFactory;
|
import ghidra.debug.api.modules.ModuleMapProposal;
|
||||||
import ghidra.dbg.target.TargetLauncher;
|
import ghidra.debug.api.tracermi.RemoteMethod;
|
||||||
import ghidra.dbg.target.TargetLauncher.TargetCmdLineLauncher;
|
import ghidra.debug.api.tracermi.TraceRmiLaunchOffer;
|
||||||
import ghidra.dbg.testutil.DummyProc;
|
import ghidra.debug.api.tracermi.TraceRmiLaunchOffer.*;
|
||||||
import ghidra.dbg.util.ConfigurableFactory.Property;
|
|
||||||
import ghidra.debug.api.model.DebuggerProgramLaunchOffer;
|
|
||||||
import ghidra.debug.api.model.DebuggerProgramLaunchOffer.*;
|
|
||||||
import ghidra.debug.api.watch.WatchRow;
|
import ghidra.debug.api.watch.WatchRow;
|
||||||
import ghidra.debug.flatapi.FlatDebuggerAPI;
|
import ghidra.debug.flatapi.FlatDebuggerRmiAPI;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
import ghidra.framework.TestApplicationUtils;
|
import ghidra.framework.TestApplicationUtils;
|
||||||
import ghidra.framework.model.DomainFolder;
|
import ghidra.framework.model.DomainFolder;
|
||||||
import ghidra.framework.model.DomainObject;
|
import ghidra.framework.model.DomainObject;
|
||||||
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.framework.plugintool.util.PluginUtils;
|
import ghidra.framework.plugintool.util.PluginUtils;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.address.AddressSet;
|
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.model.symbol.Symbol;
|
||||||
import ghidra.program.util.GhidraProgramUtilities;
|
import ghidra.program.util.GhidraProgramUtilities;
|
||||||
import ghidra.program.util.ProgramSelection;
|
import ghidra.program.util.ProgramSelection;
|
||||||
|
import ghidra.pty.*;
|
||||||
import ghidra.test.TestEnv;
|
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.guest.TracePlatform;
|
||||||
import ghidra.trace.model.modules.TraceModule;
|
import ghidra.trace.model.modules.*;
|
||||||
import ghidra.trace.model.modules.TraceSection;
|
|
||||||
import ghidra.trace.model.program.TraceProgramView;
|
import ghidra.trace.model.program.TraceProgramView;
|
||||||
import ghidra.trace.model.time.schedule.*;
|
import ghidra.trace.model.time.schedule.*;
|
||||||
import ghidra.util.InvalidNameException;
|
import ghidra.util.InvalidNameException;
|
||||||
|
@ -117,26 +117,36 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
|
|
||||||
protected static final String TERMMINES_PATH = "/tmp/termmines";
|
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 final ConsoleTaskMonitor monitor = new ConsoleTaskMonitor();
|
||||||
|
|
||||||
|
protected TerminalService terminalService;
|
||||||
protected ProgramManager programManager;
|
protected ProgramManager programManager;
|
||||||
protected CodeViewerService staticListingService;
|
protected CodeViewerService staticListingService;
|
||||||
protected DebuggerModelService modelService;
|
protected MyTestEnv env;
|
||||||
|
|
||||||
protected DebuggerModelFactory gdbFactory;
|
protected final FlatDebuggerRmiAPI flatDbg = new FlatDebuggerRmiAPI() {
|
||||||
|
|
||||||
protected final FlatDebuggerAPI flatDbg = new FlatDebuggerAPI() {
|
|
||||||
@Override
|
@Override
|
||||||
public GhidraState getState() {
|
public GhidraState getState() {
|
||||||
Navigatable nav = staticListingService.getNavigatable();
|
Navigatable nav = staticListingService.getNavigatable();
|
||||||
return new GhidraState(tool, env.getProject(),
|
return new GhidraState(tool, env.getProject(), nav.getProgram(), nav.getLocation(),
|
||||||
nav.getProgram(), nav.getLocation(), nav.getSelection(), nav.getHighlight());
|
nav.getSelection(), nav.getHighlight());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected TestEnv newTestEnv() throws Exception {
|
protected TestEnv newTestEnv() throws Exception {
|
||||||
return new TestEnv("DebuggerCourse");
|
return env = new MyTestEnv("DebuggerCourse");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Propose this replace waitForProgram
|
// TODO: Propose this replace waitForProgram
|
||||||
|
@ -167,7 +177,7 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void prepareTool() {
|
public void prepareTool() {
|
||||||
tool = env.launchTool("Debugger");
|
tool = env.launchDefaultToolByName("Debugger");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -214,20 +224,23 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
}
|
}
|
||||||
termmines.setExecutable(true);
|
termmines.setExecutable(true);
|
||||||
|
|
||||||
|
terminalService = tool.getService(TerminalService.class);
|
||||||
programManager = tool.getService(ProgramManager.class);
|
programManager = tool.getService(ProgramManager.class);
|
||||||
staticListingService = getStaticListingService();
|
staticListingService = getStaticListingService();
|
||||||
|
}
|
||||||
|
|
||||||
modelService = tool.getService(DebuggerModelService.class);
|
@Test
|
||||||
gdbFactory = modelService.getModelFactories()
|
public void testGettingStarted_Termmines() throws Throwable {
|
||||||
.stream()
|
Pty pty = PtyFactory.local().openpty();
|
||||||
.filter(f -> "gdb".equals(f.getBrief()))
|
pty.getChild().session(new String[] { TERMMINES_PATH }, Map.of("TERM", "xterm-256color"));
|
||||||
.findAny()
|
PtyParent parent = pty.getParent();
|
||||||
.get();
|
try (Terminal terminal =
|
||||||
|
terminalService.createWithStreams(Charset.forName("utf8"), parent.getInputStream(),
|
||||||
|
parent.getOutputStream())) {
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
TerminalProvider provider = waitForComponentProvider(TerminalProvider.class);
|
||||||
Property<String> gdbPathProp =
|
captureIsolatedProvider(provider, 600, 600);
|
||||||
(Property<String>) gdbFactory.getOptions().get("GDB launch command");
|
}
|
||||||
gdbPathProp.setValue(DummyProc.which("gdb"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -235,32 +248,46 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
captureToolWindow(1920, 1080);
|
captureToolWindow(1920, 1080);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void launchProgramInGdb(String extraArgs) throws Throwable {
|
protected void captureLaunchDialog(String title) {
|
||||||
DebuggerProgramLaunchOffer offer = modelService.getProgramLaunchOffers(program)
|
TraceRmiLaunchOffer offer = flatDbg.getLaunchOffers(program)
|
||||||
.filter(o -> "IN-VM GDB".equals(o.getConfigName()))
|
.stream()
|
||||||
.findFirst()
|
.filter(o -> title.equals(o.getTitle()))
|
||||||
.get();
|
.findAny()
|
||||||
LaunchConfigurator config = new LaunchConfigurator() {
|
.orElseThrow();
|
||||||
|
|
||||||
|
runSwingLater(() -> offer.launchProgram(monitor, new LaunchConfigurator() {
|
||||||
@Override
|
@Override
|
||||||
public Map<String, ?> configureLauncher(TargetLauncher launcher,
|
public PromptMode getPromptMode() {
|
||||||
Map<String, ?> arguments, RelPrompt relPrompt) {
|
return PromptMode.ALWAYS;
|
||||||
if (extraArgs.length() == 0) {
|
|
||||||
return arguments;
|
|
||||||
}
|
|
||||||
Map<String, Object> adjusted = new HashMap<>(arguments);
|
|
||||||
TargetCmdLineLauncher.PARAMETER_CMDLINE_ARGS.adjust(adjusted,
|
|
||||||
c -> c + " " + extraArgs);
|
|
||||||
return adjusted;
|
|
||||||
}
|
}
|
||||||
};
|
}));
|
||||||
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) {
|
if (result.exception() != null) {
|
||||||
throw result.exception();
|
throw result.exception();
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void launchProgramInGdb() throws Throwable {
|
protected LaunchResult launchProgramInGdb() throws Throwable {
|
||||||
launchProgramInGdb("");
|
return launchProgramInGdb("");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -278,15 +305,33 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
captureProvider(DebuggerBreakpointsProvider.class);
|
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 srand"));
|
||||||
assertTrue(flatDbg.execute("break rand"));
|
waitBreakSpecExists("srand");
|
||||||
waitForCondition(() -> flatDbg.getAllBreakpoints().size() == 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void placeBreakpointsRand() throws Throwable {
|
protected void placeBreakpointsRand() throws Throwable {
|
||||||
assertTrue(flatDbg.execute("break rand"));
|
assertTrue(flatDbg.execute("break rand"));
|
||||||
waitForCondition(() -> flatDbg.getAllBreakpoints().size() == 1);
|
waitBreakSpecExists("rand");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void placeBreakpointsSRandRand() throws Throwable {
|
||||||
|
placeBreakpointsSRand();
|
||||||
|
placeBreakpointsRand();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -298,11 +343,16 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
captureProvider(DebuggerBreakpointsProvider.class);
|
captureProvider(DebuggerBreakpointsProvider.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Address navigateToBreakpoint(String comment) {
|
protected Address navigateToBreakpoint(String expression) {
|
||||||
TraceBreakpoint bp = flatDbg.getAllBreakpoints()
|
TraceBreakpoint bp = flatDbg.getAllBreakpoints()
|
||||||
.stream()
|
.stream()
|
||||||
.flatMap(l -> l.getTraceBreakpoints().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()
|
.findAny()
|
||||||
.get();
|
.get();
|
||||||
Address dynAddr = bp.getMinAddress();
|
Address dynAddr = bp.getMinAddress();
|
||||||
|
@ -367,6 +417,14 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
Address dynAddr = navigateToBreakpoint("srand");
|
Address dynAddr = navigateToBreakpoint("srand");
|
||||||
TraceModule modLibC = getModuleContaining(dynAddr);
|
TraceModule modLibC = getModuleContaining(dynAddr);
|
||||||
Program progLibC = 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);
|
waitForCondition(() -> flatDbg.translateDynamicToStatic(dynAddr) != null);
|
||||||
disassembleSymbol(progLibC, "srand");
|
disassembleSymbol(progLibC, "srand");
|
||||||
// Just to be sure.
|
// Just to be sure.
|
||||||
|
@ -385,9 +443,16 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
Address dynAddr = navigateToBreakpoint("srand");
|
Address dynAddr = navigateToBreakpoint("srand");
|
||||||
TraceModule modLibC = getModuleContaining(dynAddr);
|
TraceModule modLibC = getModuleContaining(dynAddr);
|
||||||
Program progLibC = importModule(modLibC);
|
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");
|
disassembleSymbol(progLibC, "srand");
|
||||||
Address stAddr = flatDbg.translateDynamicToStatic(dynAddr);
|
|
||||||
// Just to be sure.
|
// Just to be sure.
|
||||||
goTo(tool, progLibC, stAddr);
|
goTo(tool, progLibC, stAddr);
|
||||||
flatDbg.resume();
|
flatDbg.resume();
|
||||||
|
@ -488,6 +553,18 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
public void testNavigation_ThreadsInCallRand() throws Throwable {
|
public void testNavigation_ThreadsInCallRand() throws Throwable {
|
||||||
launchProgramInGdb();
|
launchProgramInGdb();
|
||||||
placeBreakpointsRand();
|
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();
|
flatDbg.resume();
|
||||||
|
|
||||||
runSwing(() -> tool.setSize(1920, 1080));
|
runSwing(() -> tool.setSize(1920, 1080));
|
||||||
|
@ -500,7 +577,15 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
placeBreakpointsRand();
|
placeBreakpointsRand();
|
||||||
Address dynAddr = navigateToBreakpoint("rand");
|
Address dynAddr = navigateToBreakpoint("rand");
|
||||||
TraceModule modLibC = getModuleContaining(dynAddr);
|
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);
|
waitForCondition(() -> flatDbg.translateDynamicToStatic(dynAddr) != null);
|
||||||
flatDbg.resume();
|
flatDbg.resume();
|
||||||
|
|
||||||
|
@ -513,8 +598,11 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
launchProgramInGdb();
|
launchProgramInGdb();
|
||||||
placeBreakpointsSRandRand();
|
placeBreakpointsSRandRand();
|
||||||
flatDbg.resume(); // srand
|
flatDbg.resume(); // srand
|
||||||
|
Thread.sleep(500);
|
||||||
flatDbg.resume(); // rand.1
|
flatDbg.resume(); // rand.1
|
||||||
|
Thread.sleep(500);
|
||||||
flatDbg.stepOut();
|
flatDbg.stepOut();
|
||||||
|
Thread.sleep(500);
|
||||||
|
|
||||||
runSwing(() -> tool.setSize(1920, 1080));
|
runSwing(() -> tool.setSize(1920, 1080));
|
||||||
captureProvider(DebuggerTimeProvider.class);
|
captureProvider(DebuggerTimeProvider.class);
|
||||||
|
@ -522,18 +610,29 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNavigation_DialogCompareTimes() throws Throwable {
|
public void testNavigation_DialogCompareTimes() throws Throwable {
|
||||||
launchProgramInGdb(); // main
|
LaunchResult result = launchProgramInGdb(); // main
|
||||||
placeBreakpointsRand();
|
placeBreakpointsRand();
|
||||||
Address pc = flatDbg.getProgramCounter();
|
Address pc = flatDbg.getProgramCounter();
|
||||||
long snapA = flatDbg.getCurrentSnap();
|
long snapA = flatDbg.getCurrentSnap();
|
||||||
TraceModule modTermmines = Unique.assertOne(flatDbg.getCurrentTrace()
|
try (Transaction tx = result.trace().openTransaction("Name snapshot")) {
|
||||||
.getModuleManager()
|
result.trace()
|
||||||
.getModulesAt(snapA, pc));
|
.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");
|
TraceSection secTermminesData = modTermmines.getSectionByName(".data");
|
||||||
flatDbg.readMemory(secTermminesData.getStart(),
|
flatDbg.readMemory(secTermminesData.getStart(),
|
||||||
(int) secTermminesData.getRange().getLength(), monitor);
|
(int) secTermminesData.getRange().getLength(), monitor);
|
||||||
|
|
||||||
flatDbg.resume(); // rand.1
|
flatDbg.resume(); // rand.1
|
||||||
|
Thread.sleep(500);
|
||||||
flatDbg.readMemory(secTermminesData.getStart(),
|
flatDbg.readMemory(secTermminesData.getStart(),
|
||||||
(int) secTermminesData.getRange().getLength(), monitor);
|
(int) secTermminesData.getRange().getLength(), monitor);
|
||||||
|
|
||||||
|
@ -547,13 +646,23 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNavigation_CompareTimes() throws Throwable {
|
public void testNavigation_CompareTimes() throws Throwable {
|
||||||
launchProgramInGdb("-M 15"); // main
|
LaunchResult result = launchProgramInGdb("-M 15"); // main
|
||||||
placeBreakpointsRand();
|
placeBreakpointsRand();
|
||||||
Address pc = flatDbg.getProgramCounter();
|
Address pc = flatDbg.getProgramCounter();
|
||||||
long snapA = flatDbg.getCurrentSnap();
|
long snapA = flatDbg.getCurrentSnap();
|
||||||
TraceModule modTermmines = Unique.assertOne(flatDbg.getCurrentTrace()
|
try (Transaction tx = result.trace().openTransaction("Name snapshot")) {
|
||||||
.getModuleManager()
|
result.trace()
|
||||||
.getModulesAt(snapA, pc));
|
.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");
|
TraceSection secTermminesData = modTermmines.getSectionByName(".data");
|
||||||
flatDbg.readMemory(secTermminesData.getStart(),
|
flatDbg.readMemory(secTermminesData.getStart(),
|
||||||
(int) secTermminesData.getRange().getLength(), monitor);
|
(int) secTermminesData.getRange().getLength(), monitor);
|
||||||
|
@ -582,6 +691,10 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
});
|
});
|
||||||
waitForCondition(() -> actionNextDiff.isEnabled());
|
waitForCondition(() -> actionNextDiff.isEnabled());
|
||||||
flatDbg.goToDynamic(secTermminesData.getStart());
|
flatDbg.goToDynamic(secTermminesData.getStart());
|
||||||
|
// Because auto-strack is a little broken right now
|
||||||
|
Thread.sleep(500);
|
||||||
|
flatDbg.goToDynamic(secTermminesData.getStart());
|
||||||
|
|
||||||
performAction(actionNextDiff);
|
performAction(actionNextDiff);
|
||||||
|
|
||||||
runSwing(() -> tool.setSize(1920, 1080));
|
runSwing(() -> tool.setSize(1920, 1080));
|
||||||
|
@ -611,7 +724,15 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
showProvider(DebuggerStaticMappingProvider.class);
|
showProvider(DebuggerStaticMappingProvider.class);
|
||||||
Address dynAddr = navigateToBreakpoint("srand");
|
Address dynAddr = navigateToBreakpoint("srand");
|
||||||
TraceModule modLibC = getModuleContaining(dynAddr);
|
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);
|
waitForCondition(() -> flatDbg.translateDynamicToStatic(dynAddr) != null);
|
||||||
|
|
||||||
runSwing(() -> tool.setSize(1920, 1080));
|
runSwing(() -> tool.setSize(1920, 1080));
|
||||||
|
@ -631,29 +752,30 @@ public class TutorialDebuggerScreenShots extends GhidraScreenShotGenerator
|
||||||
DebuggerListingService listings = tool.getService(DebuggerListingService.class);
|
DebuggerListingService listings = tool.getService(DebuggerListingService.class);
|
||||||
runSwing(() -> listings
|
runSwing(() -> listings
|
||||||
.setCurrentSelection(new ProgramSelection(new AddressSet(modNcurses.getRange()))));
|
.setCurrentSelection(new ProgramSelection(new AddressSet(modNcurses.getRange()))));
|
||||||
|
DebuggerListingProvider listingProvider =
|
||||||
|
waitForComponentProvider(DebuggerListingProvider.class);
|
||||||
performAction("Copy Into New Program",
|
performAction("Copy Into New Program",
|
||||||
PluginUtils.getPluginNameFromClass(DebuggerCopyActionsPlugin.class), false);
|
PluginUtils.getPluginNameFromClass(DebuggerCopyActionsPlugin.class), listingProvider,
|
||||||
|
false);
|
||||||
captureDialog(DebuggerCopyIntoProgramDialog.class);
|
captureDialog(DebuggerCopyIntoProgramDialog.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoteTargets_GdbOverSsh() throws Throwable {
|
public void testRemoteTargets_GdbPlusGdbserverViaSsh() throws Throwable {
|
||||||
performAction("Connect", PluginUtils.getPluginNameFromClass(DebuggerTargetsPlugin.class),
|
captureLaunchDialog("gdb + gdbserver via ssh");
|
||||||
false);
|
|
||||||
DebuggerConnectDialog dialog = waitForDialogComponent(DebuggerConnectDialog.class);
|
|
||||||
runSwing(() -> dialog.setFactoryByBrief("gdb via SSH"));
|
|
||||||
|
|
||||||
captureDialog(dialog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRemoteTargets_Gadp() throws Throwable {
|
public void testRemoteTargets_GdbViaSsh() throws Throwable {
|
||||||
performAction("Connect", PluginUtils.getPluginNameFromClass(DebuggerTargetsPlugin.class),
|
captureLaunchDialog("gdb via ssh");
|
||||||
false);
|
}
|
||||||
DebuggerConnectDialog dialog = waitForDialogComponent(DebuggerConnectDialog.class);
|
|
||||||
runSwing(() -> dialog.setFactoryByBrief("Ghidra debug agent (GADP)"));
|
|
||||||
|
|
||||||
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 {
|
protected Function findCommandLineParser() throws Throwable {
|
||||||
|
|
|
@ -128,16 +128,14 @@ icon in my Tool Chest</a></li>
|
||||||
<li><a href="#there-is-no-debug-launch-icon-in-the-global-toolbar"
|
<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
|
id="toc-there-is-no-debug-launch-icon-in-the-global-toolbar">There is no
|
||||||
Debug / Launch icon in the global toolbar</a></li>
|
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
|
<li><a
|
||||||
href="#there-is-no-debug-termmines-in-gdb-locally-in-vm-option-in-the-launch-drop-down"
|
href="#the-launch-hangs-for-several-seconds-and-then-i-get-prompted-with-a-wall-of-text"
|
||||||
id="toc-there-is-no-debug-termmines-in-gdb-locally-in-vm-option-in-the-launch-drop-down">There
|
id="toc-the-launch-hangs-for-several-seconds-and-then-i-get-prompted-with-a-wall-of-text">The
|
||||||
is no “Debug termmines in GDB locally IN-VM” option in the launch
|
launch hangs for several seconds and then I get prompted with a wall of
|
||||||
drop-down</a></li>
|
text</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>
|
|
||||||
<li><a href="#the-dynamic-listing-is-empty"
|
<li><a href="#the-dynamic-listing-is-empty"
|
||||||
id="toc-the-dynamic-listing-is-empty">The Dynamic Listing is
|
id="toc-the-dynamic-listing-is-empty">The Dynamic Listing is
|
||||||
empty</a></li>
|
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
|
<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>
|
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
|
<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
|
keys.</p>
|
||||||
programs accept a <code>-h</code> argument for help:</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
|
<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>
|
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
|
<p>You should now have all the information you need to understand how
|
||||||
|
@ -223,7 +229,18 @@ open</figcaption>
|
||||||
</figure></li>
|
</figure></li>
|
||||||
<li><p>In the Debugger tool, click the dropdown ▾ for the debug <img
|
<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
|
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
|
<li><p>Wait a bit then verify the Dynamic Listing window (top) is
|
||||||
displaying disassembly code.</p>
|
displaying disassembly code.</p>
|
||||||
<figure>
|
<figure>
|
||||||
|
@ -236,20 +253,18 @@ termmines</figcaption>
|
||||||
</section>
|
</section>
|
||||||
<section id="launching-on-windows" class="level2">
|
<section id="launching-on-windows" class="level2">
|
||||||
<h2>Launching on Windows</h2>
|
<h2>Launching on Windows</h2>
|
||||||
<p>On Windows, we will use dbgeng to debug the specimen. This is the
|
<p>On Windows, we will use the Windows Debugger dbgeng.dll to debug the
|
||||||
engine that backs WinDbg. You may choose an alternative Minesweeper,
|
specimen. This is the engine that backs WinDbg. You may choose an
|
||||||
since terminal applications are less representative of Windows
|
alternative Minesweeper, since terminal applications are less
|
||||||
executables. Follow the same process as for Linux, except import
|
representative of Windows executables. Follow the same process as for
|
||||||
<code>termmines.exe</code> and select “Debug termmines.exe in dbgeng
|
Linux, except import <code>termmines.exe</code> and select
|
||||||
locally IN-VM.”</p>
|
<strong>Configure and Launch termmines.exe using… → dbgeng</strong>.</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="launching-on-macos" class="level2">
|
<section id="launching-on-macos" class="level2">
|
||||||
<h2>Launching on macOS</h2>
|
<h2>Launching on macOS</h2>
|
||||||
<p>Unfortunately, things are not so simple on macOS. See the
|
<p>On macOS, we will use LLDB to debug the specimen. This is the
|
||||||
instructions for <a
|
debugger included with Xcode. Follow the same process as for Linux,
|
||||||
href="../../../Ghidra/Debug/Debugger-swig-lldb/InstructionsForBuildingLLDBInterface.txt">Building
|
except choose <strong>lldb</strong> in the last menu.</p>
|
||||||
LLDB-Java Bindings</a>. Once built, follow the same process as for
|
|
||||||
Linux, except select “Debug termmines in LLDB locally IN-VM.”</p>
|
|
||||||
</section>
|
</section>
|
||||||
<section id="troubleshooting" class="level2">
|
<section id="troubleshooting" class="level2">
|
||||||
<h2>Troubleshooting</h2>
|
<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
|
default Debugger tool as under the previous heading. If it is still not
|
||||||
there, your installation may be corrupt.</p>
|
there, your installation may be corrupt.</p>
|
||||||
</section>
|
</section>
|
||||||
<section
|
<section id="there-is-no-gdb-option-in-the-launch-drop-down"
|
||||||
id="there-is-no-debug-termmines-in-gdb-locally-in-vm-option-in-the-launch-drop-down"
|
|
||||||
class="level3">
|
class="level3">
|
||||||
<h3>There is no “Debug termmines in GDB locally IN-VM” option in the
|
<h3>There is no <strong>gdb</strong> option in the launch drop-down</h3>
|
||||||
launch drop-down</h3>
|
<p>You may have an older Debugger tool still configured for
|
||||||
<p>You may need to install GDB and/or configure Ghidra with its
|
Recorder-based targets. We are transitioning to TraceRmi-based targets.
|
||||||
location. If you have a copy or custom build of GDB in a non-system
|
Delete your Debugger tool and re-import the default one using the
|
||||||
path, note its full path. If you intend to use the system’s copy of GDB,
|
instructions above. If it is still not there, it’s possible your
|
||||||
then in a terminal:</p>
|
installation is corrupt. Search for a file called
|
||||||
<div class="sourceCode" id="cb4"><pre
|
<code>local-gdb.sh</code> in your installation. Unlike the previous
|
||||||
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>
|
system, Trace RMI will not probe your system for dependencies nor hide
|
||||||
<p>Note the path given. (If you get an error, then you need to install
|
incompatible launchers. All installed launchers should be present in the
|
||||||
GDB.) In a terminal, type the full path of GDB to ensure it executes
|
menus, even though some may not work on your configuration.</p>
|
||||||
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 it’s responsive, then
|
|
||||||
type <code>q</code> to disconnect.</li>
|
|
||||||
<li>Close the Debugger tool, then retry.</li>
|
|
||||||
</ol>
|
|
||||||
</section>
|
</section>
|
||||||
<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">
|
class="level3">
|
||||||
<h3>The launch hangs for several seconds and then prompt for a
|
<h3>The launch hangs for several seconds and then I get prompted with a
|
||||||
“recorder”</h3>
|
wall of text</h3>
|
||||||
<p>You probably have a stale GDB connection, so when you launched you
|
<p>Read the wall of text. The first line should tell you the exception
|
||||||
now have multiple connections. For the prompt, select the option with
|
that it encountered. Often this is a timeout. Press the
|
||||||
the highest score. Examine the Targets window to confirm you have
|
<strong>Keep</strong> button and then find the Terminal, usually in the
|
||||||
multiple GDB connections. If you know which is the stale connection, you
|
bottom right. If you do not see it there, check the <strong>Window →
|
||||||
can right-click it and choose <strong>Disconnect</strong>. Otherwise,
|
Terminals</strong> menu. Once you have found the Terminal, check its
|
||||||
use <strong>Disconnect All</strong> from the drop-down menu and
|
output <em>starting at the top</em> for diagnostic messages. If you have
|
||||||
re-launch.</p>
|
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>
|
||||||
<section id="the-dynamic-listing-is-empty" class="level3">
|
<section id="the-dynamic-listing-is-empty" class="level3">
|
||||||
<h3>The Dynamic Listing is empty</h3>
|
<h3>The Dynamic Listing is empty</h3>
|
||||||
<p>Check for an actual connection. You should see an entry in the
|
<p>Check for an actual connection. You should see an entry in the
|
||||||
Debugger Targets window, a populated Object window, and there should be
|
<strong>Connection Manager</strong> window, a populated
|
||||||
an Interpreter window. If not, then your GDB connector may not be
|
<strong>Model</strong> window, and there should be a
|
||||||
configured properly. Try the steps under the previous heading.</p>
|
<strong>Terminal</strong> window. If not, then your GDB connector may
|
||||||
<p>If you have an Interpreter window, there are several
|
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>
|
possibilities:</p>
|
||||||
<section id="ghidra-or-gdb-failed-to-launch-the-target" class="level4">
|
<section id="ghidra-or-gdb-failed-to-launch-the-target" class="level4">
|
||||||
<h4>Ghidra or GDB failed to launch the target:</h4>
|
<h4>Ghidra or GDB failed to launch the target:</h4>
|
||||||
<p>Check that the original <code>termmines</code> exists and is
|
<p>If this is the case, you should see an error message in the Terminal,
|
||||||
executable. It must be at the path from where it was originally
|
e.g.: <code>termmines: no such file or directory</code>. Check that the
|
||||||
imported. If you imported from a share, consider copying it locally,
|
original <code>termmines</code> exists and is executable. You may also
|
||||||
setting its permissions, then re-importing.</p>
|
need to adjust the <strong>Image</strong> option when configuring the
|
||||||
|
launch.</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="the-target-was-launched-but-immediately-terminated"
|
<section id="the-target-was-launched-but-immediately-terminated"
|
||||||
class="level4">
|
class="level4">
|
||||||
<h4>The target was launched, but immediately terminated:</h4>
|
<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
|
not sufficient to place a <code>main</code> label in Ghidra. The
|
||||||
original file must have a <code>main</code> symbol.</p>
|
original file must have a <code>main</code> symbol.</p>
|
||||||
<p>Alternatively, in the menus try <strong>Debugger → Debug termmines →
|
<p>Alternatively, in the menus try <strong>Debugger → Configure and
|
||||||
in GDB locally IN-VM</strong>, and select “Use starti.” This will break
|
Launch termmines using → gdb</strong>, and select “starti” for
|
||||||
at the system entry point. If you have labeled <code>main</code> in
|
<strong>Run Command</strong>. This will break at the system entry point.
|
||||||
Ghidra, then you can place a breakpoint there and continue — these
|
If you have labeled <code>main</code> in Ghidra, then you can place a
|
||||||
features are covered later in the course.</p>
|
breakpoint there and continue — these features are covered later in the
|
||||||
|
course.</p>
|
||||||
<p>Alternatively, try debugging the target in GDB from a separate
|
<p>Alternatively, try debugging the target in GDB from a separate
|
||||||
terminal completely outside of Ghidra to see if things work as
|
terminal completely outside of Ghidra to see if things work as
|
||||||
expected.</p>
|
expected.</p>
|
||||||
|
@ -356,37 +369,37 @@ class="level4">
|
||||||
<h4>The target was launched, but has not stopped, yet</h4>
|
<h4>The target was launched, but has not stopped, yet</h4>
|
||||||
<p>Try pressing the Interrupt <img src="images/interrupt.png"
|
<p>Try pressing the Interrupt <img src="images/interrupt.png"
|
||||||
alt="interrupt button" /> button. If that doesn’t work or is
|
alt="interrupt button" /> button. If that doesn’t work or is
|
||||||
unsatisfactory, try the remedies under the previous heading — for an
|
unsatisfactory, try the remedies under the previous heading.</p>
|
||||||
immediately terminating target.</p>
|
|
||||||
</section>
|
</section>
|
||||||
<section
|
<section
|
||||||
id="you-hit-an-uncommon-bug-where-the-memory-map-is-not-applied-properly"
|
id="you-hit-an-uncommon-bug-where-the-memory-map-is-not-applied-properly"
|
||||||
class="level4">
|
class="level4">
|
||||||
<h4>You hit an uncommon bug where the memory map is not applied
|
<h4>You hit an uncommon bug where the memory map is not applied
|
||||||
properly</h4>
|
properly</h4>
|
||||||
<p>This is the case if the Dynamic Listing is completely blank but the
|
<p>This is the case if the <strong>Dynamic Listing</strong> is
|
||||||
Regions window is replete. The Dynamic Listing just needs to be kicked a
|
completely blank but the <strong>Regions</strong> window is replete. The
|
||||||
little. The easiest way is to step once, using the <img
|
<strong>Dynamic Listing</strong> just needs to be kicked a little. The
|
||||||
src="images/stepinto.png" alt="step into" /> Step Into button in the
|
easiest way is to step once, using the <img src="images/stepinto.png"
|
||||||
main toolbar. If this is not desirable, then you can toggle
|
alt="step into" /> <strong>Step Into</strong> button in the main
|
||||||
<strong>Force Full View</strong> back and forth. In the Regions window,
|
toolbar. If this is not desirable, then you can toggle <strong>Force
|
||||||
use the drop-down menu to toggle it on, then toggle it off. The Dynamic
|
Full View</strong> back and forth. In the <strong>Regions</strong>
|
||||||
Listing should now be populated. To go to the program counter,
|
window, use the drop-down menu to toggle it on, then toggle it off. The
|
||||||
double-click the “pc = …” label in the top right.</p>
|
<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>
|
||||||
<section id="something-else-has-gone-wrong" class="level4">
|
<section id="something-else-has-gone-wrong" class="level4">
|
||||||
<h4>Something else has gone wrong</h4>
|
<h4>Something else has gone wrong</h4>
|
||||||
<p>Try typing <code>info inferiors</code> and similar GDB diagnostic
|
<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>
|
</section>
|
||||||
<section
|
<section
|
||||||
id="the-listings-are-in-sync-but-the-dynamic-listing-is-grey-00s"
|
id="the-listings-are-in-sync-but-the-dynamic-listing-is-grey-00s"
|
||||||
class="level3">
|
class="level3">
|
||||||
<h3>The listings are in sync, but the Dynamic Listing is grey 00s</h3>
|
<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
|
<p>Check the <strong>Auto-Read</strong> drop-down near the top right of
|
||||||
Listing. It should be set to <strong>Read Visible Memory, RO
|
the <strong>Dynamic Listing</strong>. It should be set to <strong>Read
|
||||||
Once</strong>.</p>
|
Visible Memory, RO Once</strong>.</p>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<section id="exercise-launch-termmines" class="level2">
|
<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
|
<code>termmines</code> and/or start a new Ghidra Project. Starting from
|
||||||
the beginning, import <code>termmines</code> and launch it in the Ghidra
|
the beginning, import <code>termmines</code> and launch it in the Ghidra
|
||||||
Debugger with GDB. When your tool looks like the screenshot with a
|
Debugger with GDB. When your tool looks like the screenshot with a
|
||||||
populated Dynamic Listing, you have completed the exercise. Disconnect
|
populated <strong>Dynamic Listing</strong>, you have completed the
|
||||||
before proceeding to the next exercise.</p>
|
exercise. Disconnect before proceeding to the next exercise.</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="customized-launching" class="level2">
|
<section id="customized-launching" class="level2">
|
||||||
<h2>Customized Launching</h2>
|
<h2>Customized Launching</h2>
|
||||||
<p>For this specimen, you may occasionally need to provide custom
|
<p>For this specimen, you may occasionally need to provide custom
|
||||||
command-line parameters. By default, Ghidra attempts to launch the
|
command-line parameters. By default, Ghidra attempts to launch the
|
||||||
target without any parameters. In the menus, use <strong>Debugger →
|
target without any parameters. In the <strong>Debugger</strong> menu, or
|
||||||
Debug termmmines → in GDB locally IN-VM</strong> to launch with
|
the <strong>Launch</strong> button’s drop-down menu, use
|
||||||
customizations. Ghidra will remember these customizations the next time
|
<strong>Configure and Launch termmmines → gdb</strong> to adjust your
|
||||||
you launch using the drop-down button from the toolbar. The first dialog
|
configuration. This is where you can specify the image path and
|
||||||
allows you to customize the connection to the back-end debugger. Unless
|
command-line parameters of your target. Ghidra will remember this
|
||||||
you have a special copy of GDB, you should probably just click Connect.
|
configuration the next time you launch using the drop-down button from
|
||||||
The second dialog allows you to customize how the back-end debugger
|
the toolbar. Launchers with memorized configurations are presented as
|
||||||
launches the target. This is where you tweak the command line. You can
|
<strong>Re-launch termmines using…</strong> options. Using one of those
|
||||||
also change the actual image, in case it has moved or you want to
|
entries will re-launch with the saved configuration rather than
|
||||||
experiment with a patched version.</p>
|
prompting.</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="exercise-launch-with-command-line-help" class="level2">
|
<section id="exercise-launch-with-command-line-help" class="level2">
|
||||||
<h2>Exercise: Launch with Command-line Help</h2>
|
<h2>Exercise: Launch with Command-line Help</h2>
|
||||||
<p>Launch the specimen so that it prints its usage. When successful, you
|
<p>Launch the specimen so that it prints its usage. When successful, you
|
||||||
will see the usage info in the Debugger’s Interpreter window.
|
will see the usage info in the Debugger’s <strong>Terminal</strong>
|
||||||
<strong>NOTE</strong>: The process will terminate after printing its
|
window. <strong>NOTE</strong>: The process will terminate after printing
|
||||||
usage, and as a result, the rest of the UI will be mostly empty.</p>
|
its usage, and as a result, the rest of the UI will be mostly empty.</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="attaching" class="level2">
|
<section id="attaching" class="level2">
|
||||||
<h2>Attaching</h2>
|
<h2>Attaching</h2>
|
||||||
<p>Attaching is slightly more advanced, but because the target will need
|
<p>Attaching is slightly more advanced, but can be useful if the target
|
||||||
to read from stdin, and Ghidra does not properly attach the Interpreter
|
is part of a larger system, and it needs to be running <em>in situ</em>.
|
||||||
to stdin, we will need to launch the target in a terminal and attach to
|
For this section, we will just run <code>termmines</code> in a separate
|
||||||
it instead. Note this technique is only possible because the target
|
terminal and then attach to it from Ghidra. This used to be required,
|
||||||
waits for input. Depending on the task for future exercises, you may
|
because the older Recorder-based system did not provide target I/O, but
|
||||||
still need to launch from the Debugger instead of attaching.</p>
|
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">
|
<ol type="1">
|
||||||
<li>Run <code>termmines</code> in a proper terminal with the desired
|
<li>Run <code>termmines</code> in a terminal outside of Ghidra with the
|
||||||
command-line parameters.</li>
|
desired command-line parameters.</li>
|
||||||
<li>In the Ghidra Debugger, find the Targets window, and click the <img
|
<li>In the Ghidra Debugger, use the <strong>Launch</strong> button
|
||||||
src="images/connect.png" alt="connect" /> Connect button.</li>
|
drop-down and select <strong>Configured and Launch termmines using… →
|
||||||
<li>Select “gdb” from the drop-down box.</li>
|
raw gdb</strong>. The “raw” connector will give us a GDB session without
|
||||||
<li>This dialog should look familiar from the Customized Launching
|
a target.</li>
|
||||||
section. Just click the Connect button.</li>
|
<li>Ghidra needs to know the location of gdb and the architecture of the
|
||||||
<li>In the Objects window (below the Targets window), expand the node
|
intended target. The defaults are correct for 64-bit x86 targets using
|
||||||
labeled “Available.”</li>
|
the system’s 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>In the filter box, type <code>termmines</code>.</li>
|
||||||
<li>Right-click on the termmines process and select Attach. If this
|
<li>Note the PID, e.g. 1234, then in the <strong>Terminal</strong> type,
|
||||||
fails, select Available again, and click the
|
e.g., <code>attach 1234</code>.</li>
|
||||||
<img alt="refresh" src="images/view-refresh.png" width="16px"> Refresh
|
|
||||||
button.</li>
|
|
||||||
</ol>
|
</ol>
|
||||||
</section>
|
</section>
|
||||||
<section id="exercise-attach" class="level2">
|
<section id="exercise-attach" class="level2">
|
||||||
<h2>Exercise: Attach</h2>
|
<h2>Exercise: Attach</h2>
|
||||||
<p>Try attaching on your own, if you have not already. Check your work
|
<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
|
by typing <code>bt</code> into the <strong>Terminal</strong>. If you are
|
||||||
<code>read</code> you have completed this exercise. Disconnect before
|
in <code>read</code> you have completed this exercise. Quit GDB from the
|
||||||
proceeding to the next module: <a href="A2-UITour.html">A Tour of the
|
<strong>Terminal</strong> before proceeding to the next module: <a
|
||||||
UI</a></p>
|
href="A2-UITour.html">A Tour of the UI</a></p>
|
||||||
</section>
|
</section>
|
||||||
<section id="troubleshooting-1" class="level2">
|
<section id="troubleshooting-1" class="level2">
|
||||||
<h2>Troubleshooting</h2>
|
<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
|
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
|
<code>ptrace_scope=0</code>, but without reducing the security of the
|
||||||
rest of the system. For example:</p>
|
rest of the system. For example:</p>
|
||||||
<div class="sourceCode" id="cb5"><pre
|
<div class="sourceCode" id="cb4"><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">'exec ./termmines'</span></span></code></pre></div>
|
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">'exec ./termmines'</span></span></code></pre></div>
|
||||||
<p>Alternatively, if you have root access, you can rectify the issue
|
<p>Alternatively, if you have root access, you can rectify the issue
|
||||||
using the relevant documentation available online.
|
using the relevant documentation available online.
|
||||||
<strong>Beware!</strong> You should not modify this setting on your
|
<strong>Beware!</strong> You should not set <code>ptrace_scope=0</code>
|
||||||
daily driver, as this substantially reduces the security of your system.
|
globally, except on a system set aside for debugging, as this
|
||||||
Any compromised process would be allowed to attach to and steal data,
|
substantially reduces the security of that system. Any compromised
|
||||||
e.g., credentials, from any other process owned by the same user.</p>
|
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>
|
||||||
</section>
|
</section>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -30,7 +30,10 @@ Run it:
|
||||||
```
|
```
|
||||||
|
|
||||||
You should see a 9x9 grid and a cursor you can move with the arrow keys.
|
You should see a 9x9 grid and a cursor you can move with the arrow keys.
|
||||||
Hit **Ctrl-C** to exit.
|
|
||||||
|

|
||||||
|
|
||||||
|
Hit **`CTRL`-`C`** to exit.
|
||||||
Probe it for help.
|
Probe it for help.
|
||||||
Most Linux programs accept a `-h` argument 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
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
1. In the Debugger tool, click the dropdown ▾ for the debug  icon in the global tool bar, and select "Debug termmines in GDB locally IN-VM."
|
1. In the Debugger tool, click the dropdown ▾ for the debug  icon in the global tool bar, and select **Configure and Launch termmines using... → gdb**.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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.
|
1. Wait a bit then verify the Dynamic Listing window (top) is displaying disassembly code.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Launching on Windows
|
## 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.
|
This is the engine that backs WinDbg.
|
||||||
You may choose an alternative Minesweeper, since terminal applications are less representative of Windows executables.
|
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... → dbgeng**.
|
||||||
|
|
||||||
## Launching on macOS
|
## Launching on macOS
|
||||||
|
|
||||||
Unfortunately, things are not so simple on macOS.
|
On macOS, we will use LLDB to debug the specimen.
|
||||||
See the instructions for [Building LLDB-Java Bindings](../../../Ghidra/Debug/Debugger-swig-lldb/InstructionsForBuildingLLDBInterface.txt).
|
This is the debugger included with Xcode.
|
||||||
Once built, follow the same process as for Linux, except select "Debug termmines in LLDB locally IN-VM."
|
Follow the same process as for Linux, except choose **lldb** in the last menu.
|
||||||
|
|
||||||
## Troubleshooting
|
## 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, 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.
|
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.
|
You may have an older Debugger tool still configured for Recorder-based targets.
|
||||||
If you have a copy or custom build of GDB in a non-system path, note its full path.
|
We are transitioning to TraceRmi-based targets.
|
||||||
If you intend to use the system's copy of GDB, then in a terminal:
|
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
|
### The launch hangs for several seconds and then I get prompted with a wall of text
|
||||||
which gdb
|
|
||||||
```
|
|
||||||
|
|
||||||
Note the path given.
|
Read the wall of text.
|
||||||
(If you get an error, then you need to install GDB.)
|
The first line should tell you the exception that it encountered.
|
||||||
In a terminal, type the full path of GDB to ensure it executes properly.
|
Often this is a timeout.
|
||||||
Type `q` to quit GDB.
|
Press the **Keep** button and then find the Terminal, usually in the bottom right.
|
||||||
|
If you do not see it there, check the **Window → 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  button.
|
If it is just missing, then install it and try again.
|
||||||
1. In the Connect dialog, select "gdb" from the dropdown at the top.
|
If you need to tell Ghidra where it is, then in the launcher drop-down, select **Configure and Launch termmines using... → gdb**.
|
||||||
1. Enter the full path, e.g., `/usr/bin/gdb`, in the "GDB launch command" field.
|
DO NOT select **Re-launch termmines using gdb**, since this will not allow you to correct the configuration.
|
||||||
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.
|
|
||||||
|
|
||||||
### The Dynamic Listing is empty
|
### The Dynamic Listing is empty
|
||||||
|
|
||||||
Check for an actual connection.
|
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.
|
If not, then your GDB connector may not be configured properly.
|
||||||
Try the steps under the previous heading.
|
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:
|
#### 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.
|
Check that the original `termmines` exists and is executable.
|
||||||
It must be at the path from where it was originally imported.
|
You may also need to adjust the **Image** option when configuring the launch.
|
||||||
If you imported from a share, consider copying it locally, setting its permissions, then re-importing.
|
|
||||||
|
|
||||||
#### The target was launched, but immediately terminated:
|
#### 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.
|
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.
|
The original file must have a `main` symbol.
|
||||||
|
|
||||||
Alternatively, in the menus try **Debugger → Debug termmines → in GDB locally IN-VM**, and select "Use starti."
|
Alternatively, in the menus try **Debugger → Configure and Launch termmines using → gdb**, and select "starti" for **Run Command**.
|
||||||
This will break at the system entry point.
|
This will break at the system entry point.
|
||||||
If you have labeled `main` in Ghidra, then you can place a breakpoint there and continue — these features are covered later in the course.
|
If you have labeled `main` in Ghidra, then you can place a breakpoint there and continue — 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
|
#### The target was launched, but has not stopped, yet
|
||||||
|
|
||||||
Try pressing the Interrupt  button.
|
Try pressing the Interrupt  button.
|
||||||
If that doesn't work or is unsatisfactory, try the remedies under the previous heading — 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
|
#### 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.
|
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 **Dynamic Listing** just needs to be kicked a little.
|
||||||
The easiest way is to step once, using the  Step Into button in the main toolbar.
|
The easiest way is to step once, using the  **Step Into** button in the main toolbar.
|
||||||
If this is not desirable, then you can toggle **Force Full View** back and forth.
|
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.
|
In the **Regions** window, use the drop-down menu to toggle it on, then toggle it off.
|
||||||
The Dynamic Listing should now be populated.
|
The **Dynamic Listing** should now be populated.
|
||||||
To go to the program counter, double-click the "pc = ..." label in the top right.
|
To go to the program counter, double-click the "pc = ..." label in the top right.
|
||||||
|
|
||||||
#### Something else has gone wrong
|
#### 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
|
### 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**.
|
It should be set to **Read Visible Memory, RO Once**.
|
||||||
|
|
||||||
## Exercise: Launch `termmines`
|
## Exercise: Launch `termmines`
|
||||||
|
|
||||||
If you were following along with an instructor, delete your import of `termmines` and/or start a new Ghidra Project.
|
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.
|
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.
|
Disconnect before proceeding to the next exercise.
|
||||||
|
|
||||||
## Customized Launching
|
## Customized Launching
|
||||||
|
|
||||||
For this specimen, you may occasionally need to provide custom command-line parameters.
|
For this specimen, you may occasionally need to provide custom command-line parameters.
|
||||||
By default, Ghidra attempts to launch the target without any parameters.
|
By default, Ghidra attempts to launch the target without any parameters.
|
||||||
In the menus, use **Debugger → Debug termmmines → in GDB locally IN-VM** to launch with customizations.
|
In the **Debugger** menu, or the **Launch** button's drop-down menu, use **Configure and Launch termmmines → gdb** to adjust your configuration.
|
||||||
Ghidra will remember these customizations the next time you launch using the drop-down button from the toolbar.
|
This is where you can specify the image path and command-line parameters of your target.
|
||||||
The first dialog allows you to customize the connection to the back-end debugger.
|
Ghidra will remember this configuration the next time you launch using the drop-down button from the toolbar.
|
||||||
Unless you have a special copy of GDB, you should probably just click Connect.
|
Launchers with memorized configurations are presented as **Re-launch termmines using...** options.
|
||||||
The second dialog allows you to customize how the back-end debugger launches the target.
|
Using one of those entries will re-launch with the saved configuration rather than prompting.
|
||||||
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.
|
|
||||||
|
|
||||||
## Exercise: Launch with Command-line Help
|
## Exercise: Launch with Command-line Help
|
||||||
|
|
||||||
Launch the specimen so that it prints its usage.
|
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.
|
**NOTE**: The process will terminate after printing its usage, and as a result, the rest of the UI will be mostly empty.
|
||||||
|
|
||||||
## Attaching
|
## 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.
|
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. Run `termmines` in a terminal outside of Ghidra with the desired command-line parameters.
|
||||||
1. In the Ghidra Debugger, find the Targets window, and click the  Connect button.
|
1. In the Ghidra Debugger, use the **Launch** button drop-down and select **Configured and Launch termmines using... → raw gdb**.
|
||||||
1. Select "gdb" from the drop-down box.
|
The "raw" connector will give us a GDB session without a target.
|
||||||
1. This dialog should look familiar from the Customized Launching section.
|
1. Ghidra needs to know the location of gdb and the architecture of the intended target.
|
||||||
Just click the Connect button.
|
The defaults are correct for 64-bit x86 targets using the system's copy of GDB.
|
||||||
1. In the Objects window (below the Targets window), expand the node labeled "Available."
|
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. In the filter box, type `termmines`.
|
||||||
1. Right-click on the termmines process and select Attach.
|
1. Note the PID, e.g. 1234, then in the **Terminal** type, e.g., `attach 1234`.
|
||||||
If this fails, select Available again, and click the <img alt="refresh" src="images/view-refresh.png" width="16px"> Refresh button.
|
|
||||||
|
|
||||||
|
|
||||||
## Exercise: Attach
|
## Exercise: Attach
|
||||||
|
|
||||||
Try attaching on your own, if you have not already.
|
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.
|
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
|
## Troubleshooting
|
||||||
|
|
||||||
|
@ -241,5 +243,5 @@ For example:
|
||||||
```
|
```
|
||||||
|
|
||||||
Alternatively, if you have root access, you can rectify the issue using the relevant documentation available online.
|
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.
|
Any compromised process would be allowed to attach to and steal data, e.g., credentials, from any other process owned by the same user.
|
||||||
|
|
|
@ -18,6 +18,70 @@
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
}
|
}
|
||||||
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
|
.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>
|
</style>
|
||||||
<link rel="stylesheet" href="style.css" />
|
<link rel="stylesheet" href="style.css" />
|
||||||
<!--[if lt IE 9]>
|
<!--[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."
|
<li><a href="#there-is-no-step-button."
|
||||||
id="toc-there-is-no-step-button.">There is no step button.</a></li>
|
id="toc-there-is-no-step-button.">There is no step button.</a></li>
|
||||||
<li><a
|
<li><a
|
||||||
href="#i-can-step-but-i-dont-see-the-effects-in-the-interpreter-window."
|
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-interpreter-window.">I
|
id="toc-i-can-step-but-i-dont-see-the-effects-in-the-terminal-window.">I
|
||||||
can step, but I don’t see the effects in the Interpreter
|
can step, but I don’t see the effects in the Terminal window.</a></li>
|
||||||
window.</a></li>
|
|
||||||
<li><a href="#the-step-buttons-are-grayed-out."
|
<li><a href="#the-step-buttons-are-grayed-out."
|
||||||
id="toc-the-step-buttons-are-grayed-out.">The Step buttons are grayed
|
id="toc-the-step-buttons-are-grayed-out.">The Step buttons are grayed
|
||||||
out.</a></li>
|
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
|
you have not used GDB or a similar debugger before, you may find the
|
||||||
Ghidra Debugger difficult to grasp.</p>
|
Ghidra Debugger difficult to grasp.</p>
|
||||||
<p>If you would like your tool to look more or less like the one
|
<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
|
presented in the screenshot here, launch <code>termmines</code> from the
|
||||||
the Debugger using GDB.</p>
|
Debugger using GDB.</p>
|
||||||
<section id="the-debugger-tool" class="level2">
|
<section id="the-debugger-tool" class="level2">
|
||||||
<h2>The Debugger Tool</h2>
|
<h2>The Debugger Tool</h2>
|
||||||
<p>Like the CodeBrowser tool, the Debugger tool is a preconfigured
|
<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
|
buttons start just above the Dynamic Listing in the global toolbar. They
|
||||||
are:</p>
|
are:</p>
|
||||||
<ul>
|
<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" />
|
<li><img src="images/process.png" alt="emulate button" />
|
||||||
<strong>Emulate</strong>: To be covered in a later module. This will
|
<strong>Emulate</strong>: To be covered in a later module. This will
|
||||||
load the current program (from the Static Listing) into the
|
load the current program (from the Static Listing) into the
|
||||||
emulator.</li>
|
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
|
<li><img src="images/record.png" alt="mode button" /> <strong>Control
|
||||||
Mode</strong>: This drop-down menu sets the mode of the controls and
|
Mode</strong>: This drop-down menu sets the mode of the controls and
|
||||||
machine state edits. By default, all actions are directed to the
|
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>
|
<code>continue</code> in GDB.</li>
|
||||||
<li><img src="images/interrupt.png" alt="interrupt button" />
|
<li><img src="images/interrupt.png" alt="interrupt button" />
|
||||||
<strong>Interrupt</strong>: Interrupt, suspend, pause, break, etc. This
|
<strong>Interrupt</strong>: Interrupt, suspend, pause, break, etc. This
|
||||||
is equivalent to <strong>Ctrl-C</strong> or <code>interrupt</code> in
|
is equivalent to <strong><code>CTRL</code>-<code>C</code></strong> or
|
||||||
GDB.</li>
|
<code>interrupt</code> in GDB.</li>
|
||||||
<li><img src="images/kill.png" alt="kill button" />
|
<li><img src="images/kill.png" alt="kill button" />
|
||||||
<strong>Kill</strong>: Kill, terminate, etc. This is equivalent to
|
<strong>Kill</strong>: Kill, terminate, etc. This is equivalent to
|
||||||
<code>kill</code> in GDB.</li>
|
<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
|
alt="step over button" /> <strong>Step Over</strong>, <img
|
||||||
src="images/stepout.png" alt="step out button" /> <strong>Step
|
src="images/stepout.png" alt="step out button" /> <strong>Step
|
||||||
Out</strong>, <img src="images/steplast.png" alt="step last button" />
|
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>,
|
order, the equivalent commands in GDB are <code>stepi</code>,
|
||||||
<code>nexti</code>, and <code>finish</code>. Step Last has no equivalent
|
<code>nexti</code>, and <code>finish</code>. Step [Extended] represents
|
||||||
in GDB; it is meant to repeat the last custom/extended step.</li>
|
additional step commands supported by the back end. GDB provides
|
||||||
|
<strong>Advance</strong> and <strong>Return</strong>.</li>
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
<section id="windows" class="level3">
|
<section id="windows" class="level3">
|
||||||
<h3>Windows</h3>
|
<h3>Windows</h3>
|
||||||
<p>Starting at the top left and working clockwise, the windows are:</p>
|
<p>Starting at the top left and working clockwise, the windows are:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>The <strong>Debugger Targets</strong> window: This lists active
|
<li>The <strong>Debug Console</strong> window: (Not to be confused with
|
||||||
sessions or connections. From here, you can establish new sessions or
|
the CodeBrowser’s Console window.) This lists problems, diagnostics,
|
||||||
terminate existing sessions.</li>
|
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
|
<li>The <strong>Dynamic Listing</strong> window: This is the primary
|
||||||
means of examining the instructions being executed. By default, it
|
means of examining the instructions being executed. By default, it
|
||||||
follows the program counter and disassembles from there until the next
|
follows the program counter and disassembles from there until the next
|
||||||
control transfer instruction. It supports many of the same operations as
|
control transfer instruction. It supports many of the same operations as
|
||||||
the Static Listing, including patching. The nearest equivalent in GDB is
|
the Static Listing, including patching. The nearest equivalent in GDB is
|
||||||
something like <code>x/10i $pc</code>.</li>
|
something like <code>x/10i $pc</code>. The tabs at the top list the
|
||||||
<li>The <strong>Interpreter</strong> window: This is essentially a
|
active traces. Traces with a <img src="images/record.png"
|
||||||
terminal emulator providing a command-line interface to the back-end
|
alt="record" /> icon represent live targets. The nearest equivalent to
|
||||||
debugger. It is useful for diagnostics or for issuing commands that do
|
the tabs in GDB is <code>info inferiors</code>.</li>
|
||||||
not have a button in the GUI. Some may also prefer to command the
|
<li>The <strong>Breakpoints</strong> window: This is on the right. It
|
||||||
debugger from here rather than the GUI.</li>
|
lists and manages the breakpoints among all open program databases and
|
||||||
<li>The <strong>Breakpoints</strong> window: This is stacked below the
|
running targets. The nearest equivalent in GDB is
|
||||||
Interpreter. It lists and manages the breakpoints among all open images
|
|
||||||
and running targets. The nearest equivalent in GDB is
|
|
||||||
<code>info break</code>.</li>
|
<code>info break</code>.</li>
|
||||||
<li>The <strong>Registers</strong> window: This is stacked below the
|
<li>The <strong>Registers</strong> window: This is stacked below the
|
||||||
Breakpoints window. It displays and edits the register values for the
|
Breakpoints window. It displays and edits the register values for the
|
||||||
current thread. The nearest equivalent in GDB is
|
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
|
||||||
|
CodeBrowser’s 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 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.</li>
|
||||||
<li>The <strong>Modules</strong> window: This is stacked below the
|
<li>The <strong>Modules</strong> window: This is stacked below the
|
||||||
Registers window. It displays the images (and sections, if applicable)
|
Registers window. It displays the images (and sections, if applicable)
|
||||||
loaded by the target. The equivalent in GDB is
|
loaded by the target. The equivalent in GDB is
|
||||||
<code>maintenance info sections</code>. Note that this differs from the
|
<code>maintenance info sections</code>. Note that this differs from the
|
||||||
Regions window.</li>
|
Regions window.</li>
|
||||||
<li>The <strong>Threads</strong> window: This lists the threads in the
|
<li>The <strong>Terminal</strong> window: This is on the bottom right.
|
||||||
current target. The tabs at the top list the active targets. The nearest
|
This is a terminal emulator providing a command-line interface to the
|
||||||
equivalents in GDB are <code>info threads</code> and
|
back-end debugger and/or target I/O. It is useful for diagnostics or for
|
||||||
<code>info inferiors</code>.</li>
|
issuing commands that do not have a button in the GUI. Some may also
|
||||||
<li>The <strong>Time</strong> window: This is stacked below the Threads
|
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.</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
|
window. This lists the events and snapshots taken of the current
|
||||||
target.</li>
|
target.</li>
|
||||||
<li>The <strong>Stack</strong> window: This lists the stack frames for
|
<li>The <strong>Static Mappings</strong> window: This is stacked below
|
||||||
the current thread. The equivalent in GDB is
|
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>
|
<code>backtrace</code>.</li>
|
||||||
<li>The <strong>Watches</strong> window: This is stacked below the Stack
|
<li>The <strong>Watches</strong> window: This is stacked below the Stack
|
||||||
window — pun not intended. It manages current watches. These are
|
window — pun not intended. It manages current watches. These are
|
||||||
<em>not</em> watchpoints, but rather expressions or variables whose
|
<em>not</em> watchpoints, but rather expressions or variables whose
|
||||||
values to display. To manage watchpoints, use the Breakpoints window or
|
values you wish to display. To manage watchpoints, use the Breakpoints
|
||||||
the Interpreter. The nearest equivalent in GDB is
|
window or the Terminal. The nearest equivalent in GDB is
|
||||||
<code>display</code>.</li>
|
<code>display</code>.</li>
|
||||||
<li>The <strong>Regions</strong> window: This is stacked below the
|
<li>The <strong>Regions</strong> window: This is stacked below the Stack
|
||||||
Watches window. It lists memory regions for the current target. It
|
window. It lists memory regions for the current target. It differs from
|
||||||
differs from the Modules window, since this includes not only
|
the Modules window, since this includes not only image-backed regions
|
||||||
image-backed regions but other memory regions, e.g., stacks and heaps.
|
but other memory regions, e.g., stacks and heaps. The equivalent in GDB
|
||||||
The equivalent in GDB is <code>info proc mappings</code>.</li>
|
is <code>info proc mappings</code>.</li>
|
||||||
<li>The <strong>Debug Console</strong> window: (Not to be confused with
|
<li>The <strong>Model</strong> window: The back-end debugger populates
|
||||||
the Console window from the CodeBrowser.) This displays logging messages
|
an object model in the trace database. It is from this model that many
|
||||||
and problems encountered during a session. Some problems are presented
|
other windows derive their contents: Threads, Modules, Regions, etc.
|
||||||
with remedial actions, which may expedite your workflow or aid in
|
This window presents that model and provides access to generic actions
|
||||||
troubleshooting.</li>
|
on the contained objects. It is generally more capable, though less
|
||||||
<li>The <strong>Objects</strong> window: This models the back-end
|
integrated, than the other parts of the GUI, but not quite as capable as
|
||||||
debugger as a tree of objects and provides generic actions on those
|
the Terminal. For some advanced use cases, where Ghidra does not yet
|
||||||
objects. It is generally more capable, though less integrated, than the
|
provide built-in actions, it is essential.</li>
|
||||||
GUI, but not quite as capable as the Interpreter. It is useful for
|
|
||||||
troubleshooting and for advanced use cases.</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<section id="controlling-the-target" class="level2">
|
<section id="controlling-the-target" class="level2">
|
||||||
<h2>Controlling the Target</h2>
|
<h2>Controlling the Target</h2>
|
||||||
<p>The control buttons are all located on the global toolbar. Start by
|
<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
|
pressing the <img src="images/stepinto.png" alt="step into" />
|
||||||
button. Notice that the Dynamic Listing moves forward a single
|
<strong>Step Into</strong> button. Notice that the Dynamic Listing moves
|
||||||
instruction each time you press it. Also notice that the Static Listing
|
forward a single instruction each time you press it. Also notice that
|
||||||
moves with the Dynamic Listing. You may navigate in either listing, and
|
the Static Listing moves with the Dynamic Listing. You may navigate in
|
||||||
so long as there is a corresponding location in the other, the two will
|
either listing, and so long as there is a corresponding location in the
|
||||||
stay synchronized. You may also open the Decompiler just as you would in
|
other, the two will stay synchronized. You may also open the Decompiler
|
||||||
the CodeBrowser, and it will stay in sync, too.</p>
|
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"
|
<p>When you have clicked <img src="images/stepinto.png"
|
||||||
alt="step into" /> Step Into a sufficient number of times, you should
|
alt="step into" /> <strong>Step Into</strong> a sufficient number of
|
||||||
end up in a subroutine. You can click <img src="images/stepout.png"
|
times, you should end up in a subroutine. You can click <img
|
||||||
alt="step out" /> Step Out to leave the subroutine. Note that the target
|
src="images/stepout.png" alt="step out" /> <strong>Step Out</strong> to
|
||||||
is allowed to execute until it returns from the subroutine; it does not
|
leave the subroutine. Note that the target is allowed to execute until
|
||||||
skip out of it. Now, click <img src="images/stepover.png"
|
it returns from the subroutine; it does not skip out of it. Now, click
|
||||||
alt="step over" /> Step Over until you reach another <code>CALL</code>
|
<img src="images/stepover.png" alt="step over" /> <strong>Step
|
||||||
instruction. Notice that when you click <img src="images/stepover.png"
|
Over</strong> until you reach another <code>CALL</code> instruction.
|
||||||
alt="step over" /> Step Over again, it will not descend into the
|
Notice that when you click <img src="images/stepover.png"
|
||||||
subroutine. Instead, the target is allowed to execute the entire
|
alt="step over" /> <strong>Step Over</strong> again, it will not descend
|
||||||
subroutine before stopping again — after the <code>CALL</code>
|
into the subroutine. Instead, the target is allowed to execute the
|
||||||
|
entire subroutine before stopping again — after the <code>CALL</code>
|
||||||
instruction.</p>
|
instruction.</p>
|
||||||
<p>If you prefer, you may use the GDB commands from the Interpreter
|
<p>If you prefer, you may use the GDB commands from the Terminal instead
|
||||||
instead of the buttons. Try <code>si</code> and/or <code>ni</code>. You
|
of the buttons. Try <code>si</code> and/or <code>ni</code>. You can also
|
||||||
can also pass arguments which is not possible with the buttons,
|
pass arguments which is not possible with the buttons,
|
||||||
e.g. <code>si 10</code> to step 10 instructions in one command.</p>
|
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
|
<p>If you need to terminate the target you should use the <img
|
||||||
src="images/disconnect.png" alt="disconnect" /> Disconnect button rather
|
src="images/disconnect.png" alt="disconnect" />
|
||||||
than the Kill button, in general. Otherwise, each launch will create a
|
<strong>Disconnect</strong> button rather than the <strong>Kill</strong>
|
||||||
new connection, and you will end up with several stale connections.
|
button, in general. Otherwise, each launch will create a new connection,
|
||||||
Additionally, if your target exits or otherwise terminates on its own,
|
and you will end up with several stale connections. Additionally, if
|
||||||
you will get a stale connection. Use the Targets window to clean such
|
your target exits or otherwise terminates on its own, you will get a
|
||||||
connections up. The re-use of connections and/or the use of multiple
|
stale connection. Use the Connections window to clean such connections
|
||||||
concurrent connections is <em>not</em> covered in this course.</p>
|
up, or just type <code>quit</code> into the session’s 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>
|
||||||
<section id="troubleshooting" class="level2">
|
<section id="troubleshooting" class="level2">
|
||||||
<h2>Troubleshooting</h2>
|
<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
|
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>,
|
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
|
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 target’s
|
||||||
|
<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
|
<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
|
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
|
mapper failed to realize that module is the current program. Right-click
|
||||||
the module and select “Map to termmines.” Confirm the dialog. If
|
the module and select <strong>Map to termmines</strong>. Confirm the
|
||||||
<code>termmines</code> is not listed, then your version of GDB may not
|
dialog. If <code>termmines</code> is not listed, then your version of
|
||||||
be supported. If you file a bug report, please include your GDB version,
|
GDB may not be supported. If you file a bug report, please include your
|
||||||
Linux distribution, and/or other platform details.</p>
|
GDB version, Linux distribution, and/or other platform details.</p>
|
||||||
</section>
|
</section>
|
||||||
<section
|
<section
|
||||||
id="the-listings-seem-to-move-together-but-their-contents-differ."
|
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.
|
if you or an administrator applied system updates since you imported.
|
||||||
You probably need to re-import the affected module image(s). If this
|
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
|
happens to you in practice, and you have substantial investment in the
|
||||||
old import, consider using the Version Tracker to port your knowledge to
|
old program database, consider using the Version Tracker to port your
|
||||||
the new import.</p>
|
knowledge to the new database.</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="there-is-no-step-button." class="level3">
|
<section id="there-is-no-step-button." class="level3">
|
||||||
<h3>There is no step button.</h3>
|
<h3>There is no step button.</h3>
|
||||||
<p>This can happen if the Control Mode is set to the Trace. Perhaps you
|
<p>This can happen if the Control Mode is set to <strong>Control
|
||||||
played with the Time window? Change the Control Mode back to “Control
|
Trace</strong>. Perhaps you played with the Time window? The Control
|
||||||
Target.”</p>
|
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>
|
||||||
<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">
|
class="level3">
|
||||||
<h3>I can step, but I don’t see the effects in the Interpreter
|
<h3>I can step, but I don’t see the effects in the Terminal window.</h3>
|
||||||
window.</h3>
|
<p>This can happen if the Control Mode is set to <strong>Control
|
||||||
<p>This can happen if the Control Mode is set to the Emulator. Change
|
Emulator</strong>. See the above heading about Control Mode. Change it
|
||||||
the Control Mode back to “Control Target.”</p>
|
back to <strong>Control Target</strong>.</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="the-step-buttons-are-grayed-out." class="level3">
|
<section id="the-step-buttons-are-grayed-out." class="level3">
|
||||||
<h3>The Step buttons are grayed out.</h3>
|
<h3>The Step buttons are grayed out.</h3>
|
||||||
<p>The target has likely terminated, or you have not selected a thread.
|
<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
|
Check the Threads window or the Model window. If it is empty, re-launch,
|
||||||
the Troubleshooting section in <a href="A1-GettingStarted.html">Getting
|
and perhaps look at the Troubleshooting section in <a
|
||||||
Started</a></p>
|
href="A1-GettingStarted.html">Getting Started</a></p>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<section id="exercise-step-around" class="level2">
|
<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
|
Decompiler to help you recognize when you have entered the command-line
|
||||||
parsing subroutine. Alternatively, use the Static Listing and Decompiler
|
parsing subroutine. Alternatively, use the Static Listing and Decompiler
|
||||||
to identify the parsing subroutine (as you would in the CodeBrowser),
|
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>
|
||||||
</section>
|
</section>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -8,7 +8,7 @@ This module will briefly introduce each window in the Ghidra Debugger.
|
||||||
We assume some familiarity with trap-and-trace debugging.
|
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 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.
|
launch `termmines` from the Debugger using GDB.
|
||||||
|
|
||||||
## The Debugger Tool
|
## 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.
|
Coincidentally, in the screenshot, the debugger-specific buttons start just above the Dynamic Listing in the global toolbar.
|
||||||
They are:
|
They are:
|
||||||
|
|
||||||
|
*  **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**:
|
*  **Emulate**:
|
||||||
To be covered in a later module.
|
To be covered in a later module.
|
||||||
This will load the current program (from the Static Listing) into the emulator.
|
This will load the current program (from the Static Listing) into the emulator.
|
||||||
*  **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.
|
|
||||||
*  **Control Mode**:
|
*  **Control Mode**:
|
||||||
This drop-down menu sets the mode of the controls and machine state edits.
|
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.
|
By default, all actions are directed to the back-end debugger.
|
||||||
|
@ -40,7 +40,7 @@ They are:
|
||||||
This is equivalent to `continue` in GDB.
|
This is equivalent to `continue` in GDB.
|
||||||
*  **Interrupt**:
|
*  **Interrupt**:
|
||||||
Interrupt, suspend, pause, break, etc.
|
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**:
|
*  **Kill**:
|
||||||
Kill, terminate, etc.
|
Kill, terminate, etc.
|
||||||
This is equivalent to `kill` in GDB.
|
This is equivalent to `kill` in GDB.
|
||||||
|
@ -48,16 +48,21 @@ They are:
|
||||||
Disconnect from the back-end debugger.
|
Disconnect from the back-end debugger.
|
||||||
Typically, this will also end the session.
|
Typically, this will also end the session.
|
||||||
It is equivalent to `quit` in GDB.
|
It is equivalent to `quit` in GDB.
|
||||||
*  **Step Into**,  **Step Over**,  **Step Out**,  **Step Last**:
|
*  **Step Into**,  **Step Over**,  **Step Out**,  **Step [Extended]**:
|
||||||
These buttons step in various ways.
|
These buttons step in various ways.
|
||||||
In order, the equivalent commands in GDB are `stepi`, `nexti`, and `finish`.
|
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
|
### Windows
|
||||||
|
|
||||||
Starting at the top left and working clockwise, the windows are:
|
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.
|
This lists active sessions or connections.
|
||||||
From here, you can establish new sessions or terminate existing sessions.
|
From here, you can establish new sessions or terminate existing sessions.
|
||||||
* The **Dynamic Listing** window:
|
* 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.
|
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.
|
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 nearest equivalent in GDB is something like `x/10i $pc`.
|
||||||
* The **Interpreter** window:
|
The tabs at the top list the active traces.
|
||||||
This is essentially a terminal emulator providing a command-line interface to the back-end debugger.
|
Traces with a  icon represent live targets.
|
||||||
It is useful for diagnostics or for issuing commands that do not have a button in the GUI.
|
The nearest equivalent to the tabs in GDB is `info inferiors`.
|
||||||
Some may also prefer to command the debugger from here rather than the GUI.
|
|
||||||
* The **Breakpoints** window:
|
* The **Breakpoints** window:
|
||||||
This is stacked below the Interpreter.
|
This is on the right.
|
||||||
It lists and manages the breakpoints among all open images and running targets.
|
It lists and manages the breakpoints among all open program databases and running targets.
|
||||||
The nearest equivalent in GDB is `info break`.
|
The nearest equivalent in GDB is `info break`.
|
||||||
* The **Registers** window:
|
* The **Registers** window:
|
||||||
This is stacked below the Breakpoints window.
|
This is stacked below the Breakpoints window.
|
||||||
It displays and edits the register values for the current thread.
|
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:
|
* The **Modules** window:
|
||||||
This is stacked below the Registers window.
|
This is stacked below the Registers window.
|
||||||
It displays the images (and sections, if applicable) loaded by the target.
|
It displays the images (and sections, if applicable) loaded by the target.
|
||||||
The equivalent in GDB is `maintenance info sections`.
|
The equivalent in GDB is `maintenance info sections`.
|
||||||
Note that this differs from the Regions window.
|
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:
|
* The **Threads** window:
|
||||||
This lists the threads in the current target.
|
This is stacked below the Terminal window.
|
||||||
The tabs at the top list the active targets.
|
It lists the threads in the current target.
|
||||||
The nearest equivalents in GDB are `info threads` and `info inferiors`.
|
The nearest equivalent in GDB is `info threads`.
|
||||||
* The **Time** window:
|
* 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.
|
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:
|
* 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 equivalent in GDB is `backtrace`.
|
||||||
* The **Watches** window:
|
* The **Watches** window:
|
||||||
This is stacked below the Stack window — pun not intended.
|
This is stacked below the Stack window — pun not intended.
|
||||||
It manages current watches.
|
It manages current watches.
|
||||||
These are *not* watchpoints, but rather expressions or variables whose values to display.
|
These are *not* watchpoints, but rather expressions or variables whose values you wish to display.
|
||||||
To manage watchpoints, use the Breakpoints window or the Interpreter.
|
To manage watchpoints, use the Breakpoints window or the Terminal.
|
||||||
The nearest equivalent in GDB is `display`.
|
The nearest equivalent in GDB is `display`.
|
||||||
* The **Regions** window:
|
* 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 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.
|
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 equivalent in GDB is `info proc mappings`.
|
||||||
* The **Debug Console** window:
|
* The **Model** window:
|
||||||
(Not to be confused with the Console window from the CodeBrowser.)
|
The back-end debugger populates an object model in the trace database.
|
||||||
This displays logging messages and problems encountered during a session.
|
It is from this model that many other windows derive their contents: Threads, Modules, Regions, etc.
|
||||||
Some problems are presented with remedial actions, which may expedite your workflow or aid in troubleshooting.
|
This window presents that model and provides access to generic actions on the contained objects.
|
||||||
* The **Objects** window:
|
It is generally more capable, though less integrated, than the other parts of the GUI, but not quite as capable as the Terminal.
|
||||||
This models the back-end debugger as a tree of objects and provides generic actions on those objects.
|
For some advanced use cases, where Ghidra does not yet provide built-in actions, it is essential.
|
||||||
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.
|
|
||||||
|
|
||||||
## Controlling the Target
|
## Controlling the Target
|
||||||
|
|
||||||
The control buttons are all located on the global toolbar.
|
The control buttons are all located on the global toolbar.
|
||||||
Start by pressing the  Step Into button.
|
Start by pressing the  **Step Into** button.
|
||||||
Notice that the Dynamic Listing moves forward a single instruction each time you press it.
|
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.
|
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 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 a sufficient number of times, you should end up in a subroutine.
|
When you have clicked  **Step Into** a sufficient number of times, you should end up in a subroutine.
|
||||||
You can click  Step Out to leave the subroutine.
|
You can click  **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.
|
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 until you reach another `CALL` instruction.
|
Now, click  **Step Over** until you reach another `CALL` instruction.
|
||||||
Notice that when you click  Step Over again, it will not descend into the subroutine.
|
Notice that when you click  **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 `CALL` instruction.
|
Instead, the target is allowed to execute the entire subroutine before stopping again — 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`.
|
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.
|
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 button rather than the Kill button, in general.
|
If you need to terminate the target you should use the  **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.
|
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.
|
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.
|
The re-use of connections and/or the use of multiple concurrent connections is *not* covered in this course.
|
||||||
|
|
||||||
## Troubleshooting
|
## 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.
|
Also check the Debug Console window.
|
||||||
If you are in a system library, e.g., `ld-linux`, then this is the expected behavior.
|
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 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 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.
|
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.
|
Confirm the dialog.
|
||||||
If `termmines` is not listed, then your version of GDB may not be supported.
|
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.
|
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?
|
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.
|
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).
|
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.
|
### 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?
|
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.
|
This can happen if the Control Mode is set to **Control Emulator**.
|
||||||
Change the Control Mode back to "Control Target."
|
See the above heading about Control Mode.
|
||||||
|
Change it back to **Control Target**.
|
||||||
|
|
||||||
### The Step buttons are grayed out.
|
### The Step buttons are grayed out.
|
||||||
|
|
||||||
The target has likely terminated, or you have not selected a thread.
|
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)
|
If it is empty, re-launch, and perhaps look at the Troubleshooting section in [Getting Started](A1-GettingStarted.md)
|
||||||
|
|
||||||
## Exercise: Step Around
|
## 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.
|
One of the first subroutines called in `termmines` parses command-line arguments.
|
||||||
Try stepping until you have entered that subroutine.
|
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.
|
**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.
|
||||||
|
|
|
@ -158,28 +158,24 @@ several ways to set a new breakpoint:</p>
|
||||||
<li>From any static or dynamic listing window, including Disassembly,
|
<li>From any static or dynamic listing window, including Disassembly,
|
||||||
Memory/Hex, and the Decompiler, right-click and select <img
|
Memory/Hex, and the Decompiler, right-click and select <img
|
||||||
src="images/breakpoint-enable.png" alt="set breakpoint" /> Set
|
src="images/breakpoint-enable.png" alt="set breakpoint" /> Set
|
||||||
Breakpoint, press <strong>K</strong> on the keyboard, or double-click
|
Breakpoint, press <strong><code>K</code></strong> on the keyboard, or
|
||||||
the margin.</li>
|
double-click the margin.</li>
|
||||||
<li>From the Objects window click the <img
|
<li>From the Terminal window, use the GDB command, e.g.,
|
||||||
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.,
|
|
||||||
<code>break main</code>.</li>
|
<code>break main</code>.</li>
|
||||||
</ol>
|
</ol>
|
||||||
<p>The advantage of using the listings is that you can quickly set a
|
<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
|
breakpoint at any address. The advantage of using the Terminal window is
|
||||||
Interpreter window is that you can specify something other than an
|
that you can specify something other than an address. Often, those
|
||||||
address. Often, those specifications still resolve to addresses, and
|
specifications still resolve to addresses, and Ghidra will display them.
|
||||||
Ghidra will display them. Ghidra will memorize breakpoints by recording
|
Ghidra will memorize breakpoints by recording them as special bookmarks
|
||||||
them as special bookmarks in the imported program. There is some
|
in the program database. There is some iconography to communicate the
|
||||||
iconography to communicate the various states of a breakpoint. When all
|
various states of a breakpoint. When all is well and normal, you should
|
||||||
is well and normal, you should only see enabled <img
|
only see enabled <img src="images/breakpoint-enable.png"
|
||||||
src="images/breakpoint-enable.png" alt="enabled breakpoint" /> and
|
alt="enabled breakpoint" /> and disabled <img
|
||||||
disabled <img src="images/breakpoint-disable.png"
|
src="images/breakpoint-disable.png" alt="disabled breakpoint" />
|
||||||
alt="disabled breakpoint" /> breakpoints. If the target is terminated
|
breakpoints. If the target is terminated (or not launched yet), you may
|
||||||
(or not launched yet), you may also see ineffective <img
|
also see ineffective <img src="images/breakpoint-enable-ineff.png"
|
||||||
src="images/breakpoint-enable-ineff.png" alt="ineffective breakpoint" />
|
alt="ineffective breakpoint" /> breakpoints.</p>
|
||||||
breakpoints.</p>
|
|
||||||
</section>
|
</section>
|
||||||
<section id="examining-minesweeper-board-setup" class="level2">
|
<section id="examining-minesweeper-board-setup" class="level2">
|
||||||
<h2>Examining Minesweeper Board Setup</h2>
|
<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>
|
places the mines.</p>
|
||||||
<section id="set-the-breakpoints" class="level3">
|
<section id="set-the-breakpoints" class="level3">
|
||||||
<h3>Set the Breakpoints</h3>
|
<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>
|
<code>srand</code> and <code>rand</code>:</p>
|
||||||
<div class="sourceCode" id="cb1"><pre
|
<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>
|
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>
|
</figure>
|
||||||
<p>For a single target, the lower panel of the Breakpoints window does
|
<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
|
not add much information, but it does have some. We will start with the
|
||||||
top panel. This lists the “logical” breakpoints, preferring static
|
top panel. This lists the <em>logical</em> breakpoints, preferring
|
||||||
addresses.</p>
|
static addresses.</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>The left-most column <strong>Enabled</strong> indicates the
|
<li>The left-most column <strong>State</strong> indicates the
|
||||||
breakpoint’s state. Here, we see the inconsistent <img
|
breakpoint’s state. Here, we see the inconsistent <img
|
||||||
src="images/breakpoint-overlay-inconsistent.png" alt="inconsistent" />
|
src="images/breakpoint-overlay-inconsistent.png" alt="inconsistent" />
|
||||||
overlay, because Ghidra cannot save the breakpoint without a module
|
overlay, because Ghidra cannot save the breakpoint without a program
|
||||||
image. That is because <code>srand</code> and <code>rand</code> are in a
|
database. That is because <code>srand</code> and <code>rand</code> are
|
||||||
different module, and we have not yet imported it into Ghidra.</li>
|
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.
|
<li>The next column <strong>Name</strong> is the name of the breakpoint.
|
||||||
This is for informational purposes only. You can rename a 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
|
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
|
<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
|
is not imported, yet, this will be the <em>dynamic</em> address, subject
|
||||||
to relocation or ASLR.</li>
|
to relocation or ASLR.</li>
|
||||||
<li>The next column <strong>Image</strong> gives the name of the
|
<li>The next column <strong>Image</strong> gives the name of the program
|
||||||
imported image containing the breakpoint. Again, because the module has
|
database containing the breakpoint. Again, because the module has not
|
||||||
not been imported yet, this column is blank.</li>
|
been imported yet, this column is blank.</li>
|
||||||
<li>The next column <strong>Length</strong> gives the length of the
|
<li>The next column <strong>Length</strong> gives the length of the
|
||||||
breakpoint. In GDB, this generally applies to watchpoints only.</li>
|
breakpoint. In GDB, this generally applies to watchpoints only.</li>
|
||||||
<li>The next column <strong>Kinds</strong> gives the kinds of
|
<li>The next column <strong>Kinds</strong> gives the kinds of
|
||||||
breakpoint. Most breakpoints are software execution breakpoints,
|
breakpoint. Most breakpoints are software execution breakpoints,
|
||||||
indicated by “SW_EXECUTE.” That is, they are implemented by patching the
|
indicated by “SW_EXECUTE.” That is, they are implemented by patching the
|
||||||
target’s memory with a special instruction (<code>INT3</code> on x86)
|
target’s memory with a special instruction that traps execution —
|
||||||
that traps execution. There are also hardware execution breakpoints
|
<code>INT3</code> on x86. There are also hardware execution breakpoints
|
||||||
indicated by “HW_EXECUTE,” and access breakpoints indicated by “HW_READ”
|
indicated by “HW_EXECUTE,” and access breakpoints indicated by “HW_READ”
|
||||||
and/or “HW_WRITE”. <strong>NOTE</strong>: GDB would call these
|
and/or “HW_WRITE”. <strong>NOTE</strong>: GDB would call access
|
||||||
“watchpoints.” An advantage to software breakpoints is that you can have
|
breakpoints <em>watchpoints</em>. An advantage to software breakpoints
|
||||||
a practically unlimited number of them. Some disadvantages are they can
|
is that you can have a practically unlimited number of them. Some
|
||||||
be detected easily, and they are limited to execution breakpoints.</li>
|
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
|
<li>The next column <strong>Locations</strong> counts the number of
|
||||||
locations for the breakpoint. For a single-target session, this should
|
locations for the breakpoint. For a single-target session, this is most
|
||||||
always be 1.</li>
|
likely 1.</li>
|
||||||
<li>The final column <strong>Sleigh</strong> is only applicable to the
|
<li>The final column <strong>Sleigh</strong> is only applicable to the
|
||||||
emulator. It indicates that the breakpoint’s behavior has been
|
emulator. It indicates that the breakpoint’s behavior has been
|
||||||
customized with Sleigh code. This is covered in <a
|
customized with Sleigh code. This is covered in <a
|
||||||
href="B2-Emulation.html">Emulation</a>.</li>
|
href="B2-Emulation.html">Emulation</a>.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Now, we move to the bottom panel. This lists the breakpoint
|
<p>Now, we move to the bottom panel. This lists the breakpoint
|
||||||
locations, as reported by the back-end debugger(s). The Enabled,
|
locations, as reported by the back-end debugger(s). The State, Address,
|
||||||
Address, and Sleigh columns are the same as the top, but for the
|
and Sleigh columns are the same as the top, but for the individual
|
||||||
individual <em>dynamic</em> addresses.</p>
|
<em>dynamic</em> addresses.</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>The <strong>Name</strong> column is the name as designated by the
|
<li>The <strong>Name</strong> column is the name as designated by the
|
||||||
back-end.</li>
|
back-end.</li>
|
||||||
<li>The <strong>Trace</strong> column indicates which target contains
|
<li>The <strong>Trace</strong> column indicates which target contains
|
||||||
the location. The text here should match one of the tabs from the
|
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
|
<li>The <strong>Comment</strong> column is a user-defined comment. Its
|
||||||
default value is the specification that generated it, e.g.,
|
default value is the specification that generated it, e.g.,
|
||||||
<code>srand</code>.</li>
|
<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>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
<section id="toggling-the-breakpoints" class="level3">
|
<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>
|
breakpoint:</p>
|
||||||
<ol type="1">
|
<ol type="1">
|
||||||
<li>In any listing, as in setting a breakpoint, right-click and select a
|
<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
|
toggle action, press <strong><code>K</code></strong> on the keyboard, or
|
||||||
its icon in the margin.</li>
|
double-click its icon in the margin.</li>
|
||||||
<li>From the Objects window, expand the Breakpoints node, right-click a
|
<li>From the Model window, expand the <em>Breakpoints</em> node and
|
||||||
breakpoint and select Toggle or press <strong>T</strong> on the
|
double-click a breakpoint, or select one with the keyboard and press
|
||||||
keyboard.</li>
|
<strong><code>ENTER</code></strong>.</li>
|
||||||
<li>From the Breakpoints window, single-click the breakpoint’s status
|
<li>From the Breakpoints window, single-click the breakpoint’s status
|
||||||
icon, right-click an entry and select a toggle action, or create a
|
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
|
selection and use a toggling action from the local toolbar. Either panel
|
||||||
works, but the top panel is preferred to keep the breakpoints
|
works, but the top panel is preferred to keep the breakpoints
|
||||||
consistent. The local toolbar also has actions for toggling all
|
consistent. The local toolbar also has actions for toggling all
|
||||||
breakpoints in the session.</li>
|
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>
|
<code>disable 2</code>.</li>
|
||||||
</ol>
|
</ol>
|
||||||
<p>Practice toggling them. Notice that no matter how you toggle the
|
<p>Practice toggling them. Notice that no matter how you toggle the
|
||||||
breakpoints, the display updates. You might also type
|
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
|
toggling breakpoints in the GUI. When you are finished, ensure both
|
||||||
breakpoints are enabled.</p>
|
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>
|
||||||
<section id="importing-libc" class="level3">
|
<section id="importing-libc" class="level3">
|
||||||
<h3>Importing <code>libc</code></h3>
|
<h3>Importing <code>libc</code></h3>
|
||||||
|
@ -323,13 +328,32 @@ CodeBrowser.</p></li>
|
||||||
<p>Once imported, the Breakpoints window should update to reflect the
|
<p>Once imported, the Breakpoints window should update to reflect the
|
||||||
static addresses, the breakpoints should become consistent, and the
|
static addresses, the breakpoints should become consistent, and the
|
||||||
Static Listing should now be synchronized when navigating within
|
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>
|
<figure>
|
||||||
<img src="images/Breakpoints_SyncedAfterImportLibC.png"
|
<img src="images/Breakpoints_SyncedAfterImportLibC.png"
|
||||||
alt="The debugger tool with breakpoints synchronized after importing libc" />
|
alt="The debugger tool with breakpoints synchronized after importing libc" />
|
||||||
<figcaption aria-hidden="true">The debugger tool with breakpoints
|
<figcaption aria-hidden="true">The debugger tool with breakpoints
|
||||||
synchronized after importing libc</figcaption>
|
synchronized after importing libc</figcaption>
|
||||||
</figure>
|
</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>
|
||||||
<section id="capturing-the-random-seed" class="level3">
|
<section id="capturing-the-random-seed" class="level3">
|
||||||
<h3>Capturing the Random Seed</h3>
|
<h3>Capturing the Random Seed</h3>
|
||||||
|
@ -388,18 +412,27 @@ course.</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="exercise-diagram-the-mines" class="level3">
|
<section id="exercise-diagram-the-mines" class="level3">
|
||||||
<h3>Exercise: Diagram the Mines</h3>
|
<h3>Exercise: Diagram the Mines</h3>
|
||||||
<p>You goal is to capture the location of all the mines. So that you can
|
<p>You goal is to capture the location of all the mines. You will
|
||||||
check your work later, you should run <code>termmines</code> in a
|
probably want to disable the breakpoints on <code>rand</code> and
|
||||||
terminal and attach to it from Ghidra. You will probably want to disable
|
<code>srand</code> for now. Devise a strategy using breakpoints and the
|
||||||
the breakpoints on <code>rand</code> and <code>srand</code> for now.
|
control buttons (Step, Resume, etc.) so that you can observe the
|
||||||
Devise a strategy using breakpoints and the control buttons (Step,
|
location of each mine. Use pen and paper to draw a diagram of the board,
|
||||||
Resume, etc.) so that you can observe the location of each mine. Use pen
|
and mark the location of each mine as you observe the algorithm placing
|
||||||
and paper to draw a diagram of the board, and mark the location of each
|
it. There should only be 10 mines in Beginner mode. Once the mines are
|
||||||
mine as you observe the algorithm placing it. There should only be 10
|
placed, press <img src="images/resume.png" alt="resume" /> Resume. Check
|
||||||
mines in Beginner mode. Once the mines are placed, press <img
|
you work by winning the game. Alternatively, you can intentionally lose
|
||||||
src="images/resume.png" alt="resume" /> Resume. Check you work by
|
to have the game reveal the mines.</p>
|
||||||
winning the game. Alternatively, you can intentionally lose to have the
|
<section id="troubleshooting-1" class="level4">
|
||||||
game reveal the mines.</p>
|
<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
|
||||||
|
GDB’s 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>
|
||||||
<section id="optional-exercise-replicate-the-boards-forward-engineering"
|
<section id="optional-exercise-replicate-the-boards-forward-engineering"
|
||||||
class="level3">
|
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>
|
boards for any <code>termmines</code> session.</p>
|
||||||
<p>Write a program that takes a seed from the user and prints a diagram
|
<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
|
of the first game board with the mines indicated. Optionally, have it
|
||||||
print each subsequent game board when the user presses ENTER. Check your
|
print each subsequent game board when the user presses
|
||||||
work by re-launching <code>termmines</code> (see note about attaching
|
<strong>ENTER</strong>. Check your work by re-launching
|
||||||
below), capturing its seed, inputting it into your program, and then
|
<code>termmines</code>, capturing its seed, inputting it into your
|
||||||
winning the game. Optionally, win 2 more games in the same session.</p>
|
program, and then winning the game. Optionally, win 2 more games in the
|
||||||
<p><strong>NOTE</strong>: We will need a more advanced attaching
|
same session.</p>
|
||||||
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 you’re 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">'exec bash -c "echo $BASHPID; kill -SIGSTOP $BASHPID; exec ./termmines"'</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>
|
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -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.
|
From here, you can toggle and delete existing breakpoints.
|
||||||
There are several ways to set a new breakpoint:
|
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, press **K** on the keyboard, or double-click the margin.
|
1. From any static or dynamic listing window, including Disassembly, Memory/Hex, and the Decompiler, right-click and select  Set Breakpoint, press **`K`** on the keyboard, or double-click the margin.
|
||||||
1. From the Objects window click the  Add Breakpoint button or press **F3** on the keyboard.
|
1. From the Terminal window, use the GDB command, e.g., `break main`.
|
||||||
1. From the Interpreter 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 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.
|
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.
|
There is some iconography to communicate the various states of a breakpoint.
|
||||||
When all is well and normal, you should only see enabled  and disabled  breakpoints.
|
When all is well and normal, you should only see enabled  and disabled  breakpoints.
|
||||||
If the target is terminated (or not launched yet), you may also see ineffective  breakpoints.
|
If the target is terminated (or not launched yet), you may also see ineffective  breakpoints.
|
||||||
|
@ -40,7 +39,7 @@ The breakpoint on `rand` will help us find the algorithm that places the mines.
|
||||||
|
|
||||||
### Set the Breakpoints
|
### 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
|
```gdb
|
||||||
break srand
|
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.
|
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.
|
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.
|
* The left-most column **State** indicates the breakpoint's state.
|
||||||
Here, we see the inconsistent  overlay, because Ghidra cannot save the breakpoint without a module image.
|
Here, we see the inconsistent  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.
|
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.
|
* The next column **Name** is the name of the breakpoint.
|
||||||
This is for informational purposes only.
|
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.
|
* The next column **Address** gives the address of the breakpoint.
|
||||||
Notice that the addresses were resolved, even though the breakpoints were specified by symbol.
|
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.
|
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.
|
Again, because the module has not been imported yet, this column is blank.
|
||||||
* The next column **Length** gives the length of the breakpoint.
|
* The next column **Length** gives the length of the breakpoint.
|
||||||
In GDB, this generally applies to watchpoints only.
|
In GDB, this generally applies to watchpoints only.
|
||||||
* The next column **Kinds** gives the kinds of breakpoint.
|
* The next column **Kinds** gives the kinds of breakpoint.
|
||||||
Most breakpoints are software execution breakpoints, indicated by "SW_EXECUTE."
|
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 — `INT3` on x86.
|
||||||
There are also hardware execution breakpoints indicated by "HW_EXECUTE," and access breakpoints indicated by "HW_READ" and/or "HW_WRITE".
|
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.
|
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.
|
* 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.
|
* The final column **Sleigh** is only applicable to the emulator.
|
||||||
It indicates that the breakpoint's behavior has been customized with Sleigh code.
|
It indicates that the breakpoint's behavior has been customized with Sleigh code.
|
||||||
This is covered in [Emulation](B2-Emulation.md).
|
This is covered in [Emulation](B2-Emulation.md).
|
||||||
|
|
||||||
Now, we move to the bottom panel.
|
Now, we move to the bottom panel.
|
||||||
This lists the breakpoint locations, as reported by the back-end debugger(s).
|
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 **Name** column is the name as designated by the back-end.
|
||||||
* The **Trace** column indicates which target contains the location.
|
* 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.
|
* The **Comment** column is a user-defined comment.
|
||||||
Its default value is the specification that generated it, e.g., `srand`.
|
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
|
### Toggling the Breakpoints
|
||||||
|
|
||||||
While there is no need to toggle the breakpoints right now, it is a good time to demonstrate the feature.
|
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:
|
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. 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. 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.
|
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.
|
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.
|
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.
|
Practice toggling them.
|
||||||
Notice that no matter how you toggle the breakpoints, the display updates.
|
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.
|
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`
|
### Importing `libc`
|
||||||
|
|
||||||
While the Debugger can operate without importing external modules, it generally works better when you have.
|
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.
|
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`.
|
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.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
#### 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
|
### Capturing the Random Seed
|
||||||
|
|
||||||
We can now allow `termmines` to execute, expecting it to hit the `srand` breakpoint first.
|
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
|
### Exercise: Diagram the Mines
|
||||||
|
|
||||||
You goal is to capture the location of all 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.
|
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.
|
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.
|
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.
|
||||||
Check you work by winning the game.
|
Check you work by winning the game.
|
||||||
Alternatively, you can intentionally lose to have the game reveal the mines.
|
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)
|
### Optional Exercise: Replicate the Boards (Forward Engineering)
|
||||||
|
|
||||||
You will need a C development environment for this exercise.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
|
||||||
|
|
|
@ -107,7 +107,7 @@ not, please refer to the previous modules.</p>
|
||||||
<p>This module will address the following features in more depth:</p>
|
<p>This module will address the following features in more depth:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Dynamic Listing window</li>
|
<li>Dynamic Listing window</li>
|
||||||
<li>Dynamic Bytes window</li>
|
<li>Dynamic Bytes (Memory) window</li>
|
||||||
<li>Registers window</li>
|
<li>Registers window</li>
|
||||||
<li>Watches window</li>
|
<li>Watches window</li>
|
||||||
<li>Sleigh expressions</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
|
accidental patching. Furthermore, you must use the <img
|
||||||
src="images/record.png" alt="control mode" /> Control Mode toggle in the
|
src="images/record.png" alt="control mode" /> Control Mode toggle in the
|
||||||
global toolbar (next to the control actions) to enable patching
|
global toolbar (next to the control actions) to enable patching
|
||||||
throughout the Debugger tool. For now, please only use the “Control
|
throughout the Debugger tool. For now, please only use the
|
||||||
Target” and “Control Target w/ Edits Disabled” options. The write toggle
|
<strong>Control Target</strong> and <strong>Control Target w/ Edits
|
||||||
is included here so that actions like copy-paste do not lead to
|
Disabled</strong> options. The write toggle is included here so that
|
||||||
accidental patching.</p>
|
actions like copy-paste do not lead to accidental patching.</p>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<section id="the-dynamic-listing" class="level2">
|
<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
|
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
|
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
|
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,
|
at the stack pointer, press <strong><code>P</code></strong> to place a
|
||||||
just like you would in the Static Listing. You can now navigate to that
|
pointer there, just like you would in the Static Listing. You can now
|
||||||
address by double-clicking it. To return to the stack pointer, you can
|
navigate to that address by double-clicking it. To return to the stack
|
||||||
use the back arrow in the global toolbar, you can click the <img
|
pointer, you can use the back arrow in the global toolbar, you can click
|
||||||
src="images/register-marker.png" alt="track location" /> Track Location
|
the <img src="images/register-marker.png" alt="track location" /> Track
|
||||||
button, or you can double-click the <code>sp = [Address]</code> label in
|
Location button, or you can double-click the <code>sp = [Address]</code>
|
||||||
the top right of the Dynamic Listing.</p>
|
label in the top right of the Dynamic Listing.</p>
|
||||||
<p>To examine a more complicated stack segment, we will break at
|
<p>To examine a more complicated stack segment, we will break at
|
||||||
<code>rand</code>. Ensure your breakpoint at <code>rand</code> is
|
<code>rand</code>. Ensure your breakpoint at <code>rand</code> is
|
||||||
enabled and press <img src="images/resume.png" alt="resume" /> Resume.
|
enabled and press <img src="images/resume.png" alt="resume" /> Resume.
|
||||||
Your Dynamic Listing should follow the stack pointer. In the menus,
|
Your Dynamic Listing should follow the stack pointer. In the menus,
|
||||||
select <strong>Debugger → Analysis → Unwind Stack</strong> or press
|
select <strong>Debugger → Analysis → Unwind from frame 0</strong> or
|
||||||
<strong>U</strong>.</p>
|
press <strong><code>U</code></strong>.</p>
|
||||||
<figure>
|
<figure>
|
||||||
<img src="images/State_ListingStackAfterCallRand.png"
|
<img src="images/State_ListingStackAfterCallRand.png"
|
||||||
alt="The dynamic listing of the stack after a call to rand" />
|
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">
|
<section id="cache-status-indication" class="level3">
|
||||||
<h3>Cache Status Indication</h3>
|
<h3>Cache Status Indication</h3>
|
||||||
<p>The listing’s contents are read from a live target, which may become
|
<p>The listing’s contents are read from a live target, which may become
|
||||||
unresponsive or otherwise temperamental. The Debugger uses a database,
|
unresponsive or otherwise temperamental. The Debugger uses a trace
|
||||||
which acts as a cache separating the GUI from the live target. The UI
|
database, which acts as a cache separating the GUI from the live target.
|
||||||
requests memory pages from the target, the target asynchronously
|
The UI requests memory pages from the target, the target asynchronously
|
||||||
retrieves those pages and stores them into the database, then the
|
retrieves those pages and stores them into the database, then the
|
||||||
database updates the UI. This sequence does not always go as expected;
|
database updates the UI. This sequence does not always go as expected;
|
||||||
thus, pages with stale data are displayed with a grey background. This
|
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
|
are not so temperamental, but others may be, or memory reads could be
|
||||||
expensive, in which case disabling automatic memory reads may be
|
expensive, in which case disabling automatic memory reads may be
|
||||||
advantageous. If the back-end debugger reports an error while reading
|
advantageous. If the back-end debugger reports an error while reading
|
||||||
memory, the first address of the page will have a red background. To
|
memory, the page will have a red background. To refresh the visible or
|
||||||
refresh the visible or selected page(s), click the
|
selected page(s), click the
|
||||||
<img alt="refresh" src="images/view-refresh.png" width="16px"/> Refresh
|
<img alt="refresh" src="images/view-refresh.png" width="16px"/> Refresh
|
||||||
button. Examine the Debug Console window for errors / warnings before
|
button. Examine the Debug Console window for errors / warnings before
|
||||||
spamming this button. To toggle auto read, use the
|
spamming this button. To toggle auto read, use the
|
||||||
|
@ -269,12 +269,12 @@ memory map.</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="go-to" class="level3">
|
<section id="go-to" class="level3">
|
||||||
<h3>Go To</h3>
|
<h3>Go To</h3>
|
||||||
<p>The Go To action in the Dynamic Listing differs from the one in the
|
<p>The <strong>Go To</strong> action in the Dynamic Listing differs from
|
||||||
Static Listing. Like the static one, it accepts an address in
|
the one in the Static Listing. Like the static one, it accepts an
|
||||||
hexadecimal, possibly prefixed with the address space and a colon.
|
address in hexadecimal, possibly prefixed with the address space and a
|
||||||
However, it also accepts Sleigh expressions, allowing you to treat
|
colon. However, it also accepts Sleigh expressions, allowing you to
|
||||||
<code>RAX</code> as a pointer and go to that address, for example. We
|
treat <code>RAX</code> as a pointer and go to that address, for example.
|
||||||
cover Sleigh expressions later in this module.</p>
|
We cover Sleigh expressions later in this module.</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="compare" class="level3">
|
<section id="compare" class="level3">
|
||||||
<h3>Compare</h3>
|
<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>
|
after a call to rand</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
<p>Just as the Dynamic Listing is the analog of the Static Listing, the
|
<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
|
Memory viewer is the analog of the Bytes viewer. To open it, use
|
||||||
default. To open it, use <strong>Windows → Byte Viewer → Memory
|
<strong>Windows → Byte Viewer → Memory …</strong> in the menus. Its
|
||||||
…</strong> in the menus. Its default configuration should be Auto PC,
|
default configuration should be Auto PC, the same as the Dynamic
|
||||||
the same as the Dynamic Listing’s default. It has all the same
|
Listing’s default. It has all the same additional Debugger features as
|
||||||
additional Debugger features as the Dynamic Listing. Furthermore, bytes
|
the Dynamic Listing. Furthermore, bytes that have changed are displayed
|
||||||
that have changed are displayed in red text.</p>
|
in red text.</p>
|
||||||
<section id="exercise-display-the-board-in-hex" class="level3">
|
<section id="exercise-display-the-board-in-hex" class="level3">
|
||||||
<h3>Exercise: Display the Board in Hex</h3>
|
<h3>Exercise: Display the Board in Hex</h3>
|
||||||
<p>This is a bit quick and dirty, but it works and can be useful. Your
|
<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
|
expressions. This can provide an alternative to the Registers window
|
||||||
when you are really only interested in a couple of registers. It can
|
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
|
also watch values in memory. Furthermore, when a watch has a memory
|
||||||
address, the expression will appear as an option in the Location
|
address, the expression will appear as an option in the <strong>Location
|
||||||
Tracking menus of the Listing and Memory viewers. Selecting that option
|
Tracking</strong> menus of the Listing and Memory viewers. Selecting
|
||||||
will cause the window to follow that watch as its address changes.</p>
|
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
|
<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
|
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
|
row to set or edit the Sleigh expression. For starters, try something
|
||||||
like <code>RDI</code>. (Conventionally, this is the location for the
|
like <code>RDI</code>. (Conventionally, this is the location for the
|
||||||
first parameter on Linux x86-64 systems.) The context menus 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
|
Listing and Registers windows include a <strong>Watch</strong> action,
|
||||||
current selection to the Watches window.</p>
|
which adds the current selection to the Watches window.</p>
|
||||||
<p>The columns are:</p>
|
<p>The columns are:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>The <strong>Expression</strong> column is the user-defined Sleigh
|
<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
|
Double-clicking this cell will go to the address in the Dynamic
|
||||||
Listing.</li>
|
Listing.</li>
|
||||||
<li>The <strong>Symbol</strong> column gives the symbol in a mapped
|
<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
|
<li>The <strong>Value</strong> column gives the “raw” value of the
|
||||||
expression. If the result is in memory, it displays a byte array;
|
expression. If the result is in memory, it displays a byte array;
|
||||||
otherwise, it displays an integer.</li>
|
otherwise, it displays an integer.</li>
|
||||||
|
@ -436,13 +438,14 @@ evaluating the expression.</li>
|
||||||
</section>
|
</section>
|
||||||
<section id="sleigh-expressions" class="level2">
|
<section id="sleigh-expressions" class="level2">
|
||||||
<h2>Sleigh Expressions</h2>
|
<h2>Sleigh Expressions</h2>
|
||||||
<p>Watches and Go-To commands are expressed using Ghidra’s Sleigh
|
<p>Watches and Go-To commands are expressed using Ghidra’s
|
||||||
language. More precisely, expressions are the sub-language of Sleigh for
|
<em>Sleigh</em> language. More precisely, expressions are the
|
||||||
the right-hand side of assignment statements in semantic sections. If
|
sub-language of Sleigh for the right-hand side of assignment statements
|
||||||
you already know this language, then there is little more to learn. Of
|
in semantic sections. If you already know this language, then there is
|
||||||
note, you may use labels from mapped program images in your expression.
|
little more to learn. Of note, you may use labels from mapped program
|
||||||
For example, to see how far a return address is into <code>main</code>,
|
databases in your expression. For example, to see how far a return
|
||||||
you could use <code>*:8 RSP - main</code>.</p>
|
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
|
<p>For the complete specification, see the Semantic Section in the <a
|
||||||
href="../../../Ghidra/Features/Decompiler/src/main/doc/sleigh.xml">Sleigh
|
href="../../../Ghidra/Features/Decompiler/src/main/doc/sleigh.xml">Sleigh
|
||||||
documentation</a>.</p>
|
documentation</a>.</p>
|
||||||
|
@ -521,7 +524,7 @@ array. To read memory:</p>
|
||||||
<li><strong>Dereference</strong>: <code>*:8 RSP</code> or
|
<li><strong>Dereference</strong>: <code>*:8 RSP</code> or
|
||||||
<code>*[ram]:8 RSP</code></li>
|
<code>*[ram]:8 RSP</code></li>
|
||||||
</ul>
|
</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
|
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
|
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
|
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
|
<li><strong>Bytes</strong>: The raw bytes currently stored in the memory
|
||||||
allocated to the variable</li>
|
allocated to the variable</li>
|
||||||
<li><strong>Integer</strong>: The “raw” integer value of the variable,
|
<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
|
<li><strong>Value</strong>: The value of the variable, according to its
|
||||||
type</li>
|
type</li>
|
||||||
<li><strong>Instruction</strong>: If the variable points to code, the
|
<li><strong>Instruction</strong>: If the variable points to code, the
|
||||||
|
|
|
@ -8,7 +8,7 @@ If not, please refer to the previous modules.
|
||||||
This module will address the following features in more depth:
|
This module will address the following features in more depth:
|
||||||
|
|
||||||
* Dynamic Listing window
|
* Dynamic Listing window
|
||||||
* Dynamic Bytes window
|
* Dynamic Bytes (Memory) window
|
||||||
* Registers window
|
* Registers window
|
||||||
* Watches window
|
* Watches window
|
||||||
* Sleigh expressions
|
* 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.
|
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.
|
These will often include a *write-lock* toggle, like the static Byte viewer, to avoid accidental patching.
|
||||||
Furthermore, you must use the  Control Mode toggle in the global toolbar (next to the control actions) to enable patching throughout the Debugger tool.
|
Furthermore, you must use the  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 write toggle is included here so that actions like copy-paste do not lead to accidental patching.
|
||||||
|
|
||||||
## The Dynamic Listing
|
## The Dynamic Listing
|
||||||
|
@ -65,7 +65,7 @@ Now, we will examine the stack segment.
|
||||||
Click the  Track Location drop-down and select **Track Stack Pointer**.
|
Click the  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.
|
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.
|
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 would in the Static Listing.
|
||||||
You can now navigate to that address by double-clicking it.
|
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 button, or you can double-click the `sp = [Address]` label in the top right of the Dynamic Listing.
|
To return to the stack pointer, you can use the back arrow in the global toolbar, you can click the  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`.
|
To examine a more complicated stack segment, we will break at `rand`.
|
||||||
Ensure your breakpoint at `rand` is enabled and press  Resume.
|
Ensure your breakpoint at `rand` is enabled and press  Resume.
|
||||||
Your Dynamic Listing should follow the stack pointer.
|
Your Dynamic Listing should follow the stack pointer.
|
||||||
In the menus, select **Debugger → Analysis → Unwind from frame 0** or press **U**.
|
In the menus, select **Debugger → Analysis → Unwind from frame 0** or press **`U`**.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
@ -93,12 +93,12 @@ The dynamic listing offers several additional features:
|
||||||
### Cache Status Indication
|
### Cache Status Indication
|
||||||
|
|
||||||
The listing's contents are read from a live target, which may become unresponsive or otherwise temperamental.
|
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.
|
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 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.
|
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.
|
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.
|
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.
|
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.
|
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
|
### 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.
|
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.
|
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.
|
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
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Just as the Dynamic Listing is the analog of the Static Listing, the Memory viewer is the analog of the Byte viewer.
|
Just as the Dynamic Listing is the analog of the Static Listing, the Memory viewer is the analog of the Bytes viewer.
|
||||||
It is not visible by default.
|
|
||||||
To open it, use **Windows → Byte Viewer → Memory ...** in the menus.
|
To open it, use **Windows → Byte Viewer → Memory ...** in the menus.
|
||||||
Its default configuration should be Auto PC, the same as the Dynamic Listing's default.
|
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.
|
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.
|
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.
|
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.
|
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.
|
Selecting that option will cause the window to follow that watch as its address changes.
|
||||||
|
|
||||||
To add a watch, click the  Add button.
|
To add a watch, click the  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.
|
Double-click the left-most cell of the row to set or edit the Sleigh expression.
|
||||||
For starters, try something like `RDI`.
|
For starters, try something like `RDI`.
|
||||||
(Conventionally, this is the location for the first parameter on Linux x86-64 systems.)
|
(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:
|
The columns are:
|
||||||
|
|
||||||
|
@ -225,7 +224,7 @@ The columns are:
|
||||||
* The **Address** column is the address of the resulting value, if applicable.
|
* The **Address** column is the address of the resulting value, if applicable.
|
||||||
This may be in `register` space.
|
This may be in `register` space.
|
||||||
Double-clicking this cell will go to the address in the Dynamic Listing.
|
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.
|
* 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.
|
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.
|
* 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
|
## 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.
|
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.
|
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 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).
|
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`
|
* **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.
|
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.
|
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.
|
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
|
* **Frame**: If evaluation required unwinding, a description of the frame used for context
|
||||||
* **Storage**: The dynamic, physical location of the variable, e.g., `7fffffffe618`
|
* **Storage**: The dynamic, physical location of the variable, e.g., `7fffffffe618`
|
||||||
* **Bytes**: The raw bytes currently stored in the memory allocated to the variable
|
* **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
|
* **Value**: The value of the variable, according to its type
|
||||||
* **Instruction**: If the variable points to code, the target instruction
|
* **Instruction**: If the variable points to code, the target instruction
|
||||||
* **Warnings**: Warnings emitted during evaluation
|
* **Warnings**: Warnings emitted during evaluation
|
||||||
|
|
|
@ -45,10 +45,8 @@
|
||||||
<li><a href="#navigation" id="toc-navigation">Navigation</a>
|
<li><a href="#navigation" id="toc-navigation">Navigation</a>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#coordinates" id="toc-coordinates">Coordinates</a></li>
|
<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>
|
<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>
|
<li><a href="#stack" id="toc-stack">Stack</a>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#exercise-name-the-function"
|
<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>
|
previous modules.</p>
|
||||||
<p>This module will address the following features in more depth:</p>
|
<p>This module will address the following features in more depth:</p>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li>The Trace tabs — in the Dynamic Listing window</li>
|
||||||
<li>The Threads window</li>
|
<li>The Threads window</li>
|
||||||
<li>The Stack window</li>
|
<li>The Stack window</li>
|
||||||
<li>The Time 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>
|
dealing with machine state.</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>The current <em>trace</em>. A trace database is where all of the
|
<li>The current <em>trace</em>. A trace database is where all of the
|
||||||
Debugger windows (except Targets and Objects) gather their information.
|
Debugger windows (except Connections and Terminal) gather their
|
||||||
It is the analog of the program database, but for dynamic analysis.</li>
|
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
|
<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
|
a processor core or a platform-defined virtual thread. Each thread has
|
||||||
its own register context. In Ghidra, this means each has its own
|
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>
|
href="B2-Emulation.html">Emulation</a> module.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>In general, there is a window dedicated to navigating each element of
|
<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 target’s 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. 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.</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="threads" class="level2">
|
<section id="threads" class="level2">
|
||||||
<h2>Threads</h2>
|
<h2>Threads</h2>
|
||||||
<p>If you do not have an active session already, launch
|
|
||||||
<code>termmines</code>.</p>
|
|
||||||
<figure>
|
<figure>
|
||||||
<img src="images/Navigation_ThreadsInCallRand.png"
|
<img src="images/Navigation_ThreadsInCallRand.png"
|
||||||
alt="Threads window" />
|
alt="Threads window" />
|
||||||
|
@ -131,15 +145,12 @@ are:</p>
|
||||||
may include the back-end debugger’s thread id, the target platform’s
|
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
|
system thread id, and/or the back-end debugger’s display text for the
|
||||||
thread.</li>
|
thread.</li>
|
||||||
<li>The <strong>Created</strong> column gives the snapshot when the
|
<li>The <strong>PC</strong> column gives the program counter of the
|
||||||
thread was first observed.</li>
|
thread.</li>
|
||||||
<li>The <strong>Destroyed</strong> column gives the snapshot when the
|
<li>The <strong>Function</strong> column gives the function from a
|
||||||
thread was first observed as terminated. If this is empty, the thread is
|
mapped program database containing the program counter.</li>
|
||||||
still alive.</li>
|
|
||||||
<li>The <strong>State</strong> column gives the state of the thread.
|
<li>The <strong>State</strong> column gives the state of the thread.
|
||||||
This may be one of ALIVE, RUNNING, STOPPED, TERMINATED, or UNKNOWN.</li>
|
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
|
<li>The <strong>Plot</strong> column plots the threads’ life spans in a
|
||||||
chart.</li>
|
chart.</li>
|
||||||
</ul>
|
</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
|
expressions, and the Dynamic Listing and Memory views may seek to
|
||||||
different addresses, depending on their location tracking
|
different addresses, depending on their location tracking
|
||||||
configurations.</p>
|
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 target’s 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. 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.</p>
|
|
||||||
</section>
|
|
||||||
</section>
|
</section>
|
||||||
<section id="stack" class="level2">
|
<section id="stack" class="level2">
|
||||||
<h2>Stack</h2>
|
<h2>Stack</h2>
|
||||||
|
@ -202,8 +198,8 @@ so on.</li>
|
||||||
<li>The <strong>Function</strong> column gives the name of the function
|
<li>The <strong>Function</strong> column gives the name of the function
|
||||||
containing the PC mapped to its static program database, if
|
containing the PC mapped to its static program database, if
|
||||||
available.</li>
|
available.</li>
|
||||||
<li>The <strong>Comment</strong> column allows you to annotate the
|
<li>The <strong>Module</strong> column gives the name of the module
|
||||||
frame.</li>
|
containing the PC.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Double-click the row with the unnamed function (frame 1) to switch to
|
<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
|
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>
|
<figcaption aria-hidden="true">Time window</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
<p>It displays a list of all the snapshots for the current trace. In
|
<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>
|
snapshot is at the bottom. The columns are:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>The <strong>Snap</strong> column numbers each snapshot. Other
|
<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
|
relation to another. It typically only applies to emulator / scratch
|
||||||
snapshots, which are covered later in this course.</li>
|
snapshots, which are covered later in this course.</li>
|
||||||
<li>The <strong>Description</strong> column describes the event that
|
<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>
|
</ul>
|
||||||
<p>Switch to the snapshot where you hit <code>srand</code> (snapshot 2
|
<p>Before we can navigate back in time, you must change the <em>Control
|
||||||
in our screenshot) by double-clicking it in the table. This will cause
|
Mode</em> to <strong>Control Trace</strong>. Now, switch to the snapshot
|
||||||
all the machine-state windows to update including the Stack window. If
|
where you hit <code>srand</code> (snapshot 1 in our screenshot) by
|
||||||
you try navigating around the Dynamic Listing, you will likely find
|
double-clicking it in the table. This will cause all the machine-state
|
||||||
stale areas indicated by a grey background.</p>
|
windows to update including the Stack window. If you try navigating
|
||||||
<p><strong>NOTE</strong>: Navigating into the past will automatically
|
around the Dynamic Listing, you will likely find stale areas indicated
|
||||||
change the Control mode. This is to avoid confusion, since you may
|
by a grey background.</p>
|
||||||
perform a control action based on the state you see, which is no longer
|
<p><strong>NOTE</strong>: The control-mode change is required to avoid
|
||||||
the state of the live target. Switch back by using the Control mode
|
confusion between recorded and live states. When you switch back to
|
||||||
drop-down button in the global toolbar. When you select <strong>Control
|
<strong>Control Target</strong> (with or without edits), the Debugger
|
||||||
Target</strong> (with or without edits), the Debugger will navigate
|
will navigate forward to the latest snapshot and prohibit navigating to
|
||||||
forward to the latest snapshot.</p>
|
the past.</p>
|
||||||
<section id="sparse-vs.-full-snapshots" class="level3">
|
<section id="sparse-vs.-full-snapshots" class="level3">
|
||||||
<h3>Sparse vs. Full Snapshots</h3>
|
<h3>Sparse vs. Full Snapshots</h3>
|
||||||
<p>Regarding the stale areas: the Debugger cannot request the back-end
|
<p>Regarding the stale areas: the Debugger cannot request the back-end
|
||||||
debugger provide machine state from the past. (Integration with timeless
|
debugger provide machine state from the past. (Integration with timeless
|
||||||
back-end debuggers is not yet supported.) Remember, the trace is used as
|
back-end debuggers is nascent.) Remember, the trace is used as a cache,
|
||||||
a cache, so it will only be populated with the pages and registers that
|
so it will only be populated with the pages and registers that you
|
||||||
you observed at the time. Thus, most snapshots are <em>sparse</em>
|
observed at the time. Thus, most snapshots are <em>sparse</em>
|
||||||
snapshots. The most straightforward way to capture a <em>full</em>
|
snapshots. The most straightforward way to capture a <em>full</em>
|
||||||
snapshot is the
|
snapshot is the
|
||||||
<img alt="refresh" src="images/view-refresh.png" width="16px"> Refresh
|
<img alt="refresh" src="images/view-refresh.png" width="16px">
|
||||||
button with a broad selection in the Dynamic Listing. We give the exact
|
<strong>Read Memory</strong> button with a broad selection in the
|
||||||
steps in the next heading. To capture registers, ensure you navigate to
|
Dynamic Listing. We give the exact steps in the next heading. To capture
|
||||||
each thread whose registers you want to capture.</p>
|
registers, ensure you navigate to each thread whose registers you want
|
||||||
|
to capture.</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="comparing-snapshots" class="level3">
|
<section id="comparing-snapshots" class="level3">
|
||||||
<h3>Comparing Snapshots</h3>
|
<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
|
href="A1-GettingStarted.html">Getting Started</a> to review launching
|
||||||
with custom parameters.)</p></li>
|
with custom parameters.)</p></li>
|
||||||
<li><p>Ensure your breakpoint at <code>srand</code> is enabled.</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
|
<li><p>Click the
|
||||||
<img alt="refresh" src="images/view-refresh.png" width="16px"> Refresh
|
<img alt="refresh" src="images/view-refresh.png" width="16px"> Refresh
|
||||||
button. <strong>NOTE</strong>: It is normal for some errors to occur
|
button. <strong>NOTE</strong>: It is normal for some errors to occur
|
||||||
here. We note a more surgical approach below.</p></li>
|
here. We note a more surgical approach below.</p></li>
|
||||||
<li><p>Wait a moment for the capture to finish.</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
|
<li><p>Optionally, press
|
||||||
snapshot so you can easily identify it later. Alternatively, edit the
|
<strong><code>CTRL</code>-<code>SHIFT</code>-<code>N</code></strong> to
|
||||||
snapshot’s Description from the table in the Time window.</p></li>
|
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.</p></li>
|
||||||
<li><p>Press <img src="images/resume.png" alt="resume" /> Resume,
|
<li><p>Press <img src="images/resume.png" alt="resume" /> Resume,
|
||||||
expecting it to break at <code>srand</code>.</p></li>
|
expecting it to break at <code>srand</code>.</p></li>
|
||||||
<li><p>Capture another full snapshot using Select All and
|
<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" />
|
alt="The compare times dialog" />
|
||||||
<figcaption aria-hidden="true">The compare times dialog</figcaption>
|
<figcaption aria-hidden="true">The compare times dialog</figcaption>
|
||||||
</figure></li>
|
</figure></li>
|
||||||
<li><p>Click OK.</p></li>
|
<li><p>Click <strong>OK</strong>.</p></li>
|
||||||
</ol>
|
</ol>
|
||||||
<p>The result is a side-by-side listing of the two snapshots with
|
<p>The result is a side-by-side listing of the two snapshots with
|
||||||
differences highlighted in orange. Unlike the Static program comparison
|
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.
|
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
|
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>
|
single page, but that is generally not the case in practice.</li>
|
||||||
<li>Use the Regions window to select the addresses in the
|
<li>If there are more pages, use the Regions window. Click the
|
||||||
<code>.data</code> section, then click Refresh in the Dynamic Listing.
|
<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
|
This will capture the full <code>.data</code> section, no matter how
|
||||||
many pages.</li>
|
many pages.</li>
|
||||||
<li>Use the lower pane of the Modules window to select the addresses in
|
<li>Alternatively, Use the Modules window to select
|
||||||
the <code>.data</code> section, then click Refresh in the Dynamic
|
<code>termmines</code> and load its sections. (Not all debuggers support
|
||||||
Listing. This will also capture the full <code>.data</code>
|
this.) Click the <strong>Show Sections Table</strong> button in the
|
||||||
section.</li>
|
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>
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
<section id="exercise-find-the-time" class="level3">
|
<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
|
score by patching a variable right before winning. Considering it is a
|
||||||
single-threaded application, take a moment to think about how your time
|
single-threaded application, take a moment to think about how your time
|
||||||
might be measured. <strong>TIP</strong>: Because you will need to play
|
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
|
the game, you should enable <strong>Inferior TTY</strong> in the
|
||||||
comparison method to locate the variable. Then place an appropriate
|
launcher. Use the snapshot comparison method to locate the variable.
|
||||||
breakpoint, win the game, patch the variable, and score 0 seconds!</p>
|
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
|
<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
|
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
|
variable is, you can check its XRefs in the Static Listing and devise a
|
||||||
|
|
|
@ -7,6 +7,7 @@ If not, please refer to the previous modules.
|
||||||
|
|
||||||
This module will address the following features in more depth:
|
This module will address the following features in more depth:
|
||||||
|
|
||||||
|
* The Trace tabs — in the Dynamic Listing window
|
||||||
* The Threads window
|
* The Threads window
|
||||||
* The Stack window
|
* The Stack window
|
||||||
* The Time 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.
|
All of these elements can affect the information displayed in other windows, especially those dealing with machine state.
|
||||||
|
|
||||||
* The current *trace*.
|
* 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.
|
It is the analog of the program database, but for dynamic analysis.
|
||||||
* The current *thread*.
|
* The current *thread*.
|
||||||
A thread is a unit of execution, either a processor core or a platform-defined virtual 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.
|
"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.
|
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
|
## Threads
|
||||||
|
|
||||||
If you do not have an active session already, launch `termmines`.
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
The Threads window displays a list of all threads ever observed in the target.
|
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.
|
* 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.
|
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 **PC** column gives the program counter of the thread.
|
||||||
* The **Destroyed** column gives the snapshot when the thread was first observed as terminated.
|
* The **Function** column gives the function from a mapped program database containing the program counter.
|
||||||
If this is empty, the thread is still alive.
|
|
||||||
* The **State** column gives the state of the thread.
|
* The **State** column gives the state of the thread.
|
||||||
This may be one of ALIVE, RUNNING, STOPPED, TERMINATED, or UNKNOWN.
|
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.
|
* 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.
|
**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.
|
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.
|
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
|
## Stack
|
||||||
|
|
||||||
Ensure your breakpoint on `rand` is enabled, and resume until you hit it.
|
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.
|
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.
|
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 **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.
|
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.
|
When you switch frames, any machine-state window that involves register values may change.
|
||||||
|
@ -119,7 +118,7 @@ Now, switch to the Time window.
|
||||||

|

|
||||||
|
|
||||||
It displays a list of all the snapshots for the current trace.
|
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.
|
By default, the most recent snapshot is at the bottom.
|
||||||
The columns are:
|
The columns are:
|
||||||
|
|
||||||
|
@ -131,23 +130,23 @@ The columns are:
|
||||||
* The **Schedule** column describes the snapshot in relation to another.
|
* 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.
|
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.
|
* 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.
|
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.
|
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.
|
**NOTE**: The control-mode change is required to avoid confusion between recorded and live states.
|
||||||
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.
|
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.
|
||||||
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.
|
|
||||||
|
|
||||||
### Sparse vs. Full Snapshots
|
### Sparse vs. Full Snapshots
|
||||||
|
|
||||||
Regarding the stale areas: the Debugger cannot request the back-end debugger provide machine state from the past.
|
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.
|
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.
|
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.
|
We give the exact steps in the next heading.
|
||||||
To capture registers, ensure you navigate to each thread whose registers you want to capture.
|
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.
|
1. Launch `termmines -M 15` in the Debugger.
|
||||||
(See [Getting Started](A1-GettingStarted.md) to review launching with custom parameters.)
|
(See [Getting Started](A1-GettingStarted.md) to review launching with custom parameters.)
|
||||||
1. Ensure your breakpoint at `srand` is enabled.
|
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.
|
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.
|
**NOTE**: It is normal for some errors to occur here.
|
||||||
We note a more surgical approach below.
|
We note a more surgical approach below.
|
||||||
1. Wait a moment for the capture to finish.
|
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.
|
Alternatively, edit the snapshot's Description from the table in the Time window.
|
||||||
1. Press  Resume, expecting it to break at `srand`.
|
1. Press  Resume, expecting it to break at `srand`.
|
||||||
1. Capture another full snapshot using Select All and Refresh.
|
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
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
1. Click OK.
|
1. Click **OK**.
|
||||||
|
|
||||||
The result is a side-by-side listing of the two snapshots with differences highlighted in orange.
|
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.
|
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.
|
* 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.
|
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.
|
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.
|
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.
|
This will also capture the full `.data` section.
|
||||||
|
|
||||||
### Exercise: Find the Time
|
### 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.
|
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.
|
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.
|
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.
|
Use the snapshot comparison method to locate the variable.
|
||||||
Then place an appropriate breakpoint, win the game, patch the variable, and score 0 seconds!
|
Then place an appropriate breakpoint, win the game, patch the variable, and score 0 seconds!
|
||||||
|
|
||||||
|
|
|
@ -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
|
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
|
or may not include a section name. Typically, the name will include the
|
||||||
start address to avoid collisions.</li>
|
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
|
<li>The <strong>Start</strong> column gives the minimum address of the
|
||||||
region.</li>
|
region.</li>
|
||||||
<li>The <strong>End</strong> column gives the maximum (inclusive)
|
<li>The <strong>End</strong> column gives the maximum (inclusive)
|
||||||
address of the region.</li>
|
address of the region.</li>
|
||||||
<li>The <strong>Length</strong> column gives the number of bytes in the
|
<li>The <strong>Length</strong> column gives the number of bytes in the
|
||||||
region.</li>
|
region.</li>
|
||||||
<li>The <strong>Read</strong>, <strong>Write</strong>,
|
<li>The <strong>Read</strong>, <strong>Write</strong>, and
|
||||||
<strong>Execute</strong>, and <strong>Volatile</strong> columns give the
|
<strong>Execute</strong> columns give the permissions of the
|
||||||
permissions/flags of the region.</li>
|
region.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Try using the filter and column headers to sift and sort for
|
<p>Try using the filter and column headers to sift and sort for
|
||||||
interesting regions. Double-click the start or end address to navigate
|
interesting regions. Double-click the start or end address to navigate
|
||||||
to them in the Dynamic Listing. Select one or more regions, right-click,
|
to them in the Dynamic Listing. Select one or more regions, right-click,
|
||||||
and choose <strong>Select Addresses</strong>. That should select all the
|
and choose <strong>Select Addresses</strong>. That should select all the
|
||||||
addresses in those regions in the Dynamic Listing. Used with the Refresh
|
addresses in those regions in the Dynamic Listing. Used with the
|
||||||
button, you can surgically capture memory into the current snapshot.</p>
|
<strong>Read Memory</strong> button in the Dynamic Listing, you can
|
||||||
|
selectively capture memory into the current snapshot.</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="modules" class="level2">
|
<section id="modules" class="level2">
|
||||||
<h2>Modules</h2>
|
<h2>Modules</h2>
|
||||||
|
@ -122,14 +119,16 @@ button, you can surgically capture memory into the current snapshot.</p>
|
||||||
alt="Modules window after launch" />
|
alt="Modules window after launch" />
|
||||||
<figcaption aria-hidden="true">Modules window after launch</figcaption>
|
<figcaption aria-hidden="true">Modules window after launch</figcaption>
|
||||||
</figure>
|
</figure>
|
||||||
<p>The Modules window has two panes. The top pane displays a list of all
|
<p>The Modules window has two panes, though the second is disabled by
|
||||||
the <em>modules</em> known to the back-end debugger. The bottom pane
|
default. The top pane displays a list of all the <em>modules</em> known
|
||||||
displays a list of all the <em>sections</em> known to the back-end
|
to the back-end debugger. The bottom pane displays a list of all the
|
||||||
debugger. In practice, not all targets will report module information.
|
<em>sections</em> known to the back-end debugger. In practice, not all
|
||||||
Fewer targets report section information. The nearest analog to the
|
targets will report module information. Fewer targets report section
|
||||||
bottom panel from the CodeBrowser is (also) the Memory Map window. The
|
information, and those that do may only report them to Ghidra when
|
||||||
top panel has no real analog; however, the tabs above the Static Listing
|
specifically requested. The nearest analog to the bottom panel from the
|
||||||
pane serve a similar purpose.</p>
|
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
|
<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
|
display a lot of the same information as the Regions window. The columns
|
||||||
differ slightly, and the sections panel will <em>not</em> include
|
differ slightly, and the sections panel will <em>not</em> include
|
||||||
|
@ -138,44 +137,27 @@ stacks, heaps, etc.</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>The <strong>Base</strong> column gives the image base for the
|
<li>The <strong>Base</strong> column gives the image base for the
|
||||||
module. This should be the minimum address of the module.</li>
|
module. This should be the minimum address of the module.</li>
|
||||||
<li>The <strong>Max Address</strong> column gives the maximum address of
|
<li>The <strong>Max</strong> column gives the maximum address of the
|
||||||
the module.</li>
|
module.</li>
|
||||||
<li>The <strong>Name</strong> column gives the (short) name of the
|
<li>The <strong>Name</strong> column gives the (short) name of the
|
||||||
module.</li>
|
module.</li>
|
||||||
<li>The <strong>Module Name</strong> column gives the full file path of
|
<li>The <strong>Mapping</strong> column gives the mapped Ghidra program
|
||||||
the module <em>on target</em>. In some cases, this gives some other
|
database for the module.</li>
|
||||||
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>Length</strong> column gives the distance between the
|
<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 address (inclusive). Note that not every address between
|
||||||
base and max is necessarily mapped to the module. ELF headers specify
|
base and max is necessarily mapped to the module. ELF headers specify
|
||||||
the load address of each section, so the memory footprint usually has
|
the load address of each section, so the memory footprint usually has
|
||||||
many gaps.</li>
|
many gaps.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>The section columns are:</p>
|
<p>See the Help (press <strong><code>F1</code></strong> in the Modules
|
||||||
<ul>
|
panel) to learn more about the Sections table, if desired. It can be
|
||||||
<li>The <strong>Start Address</strong> gives the minimum address of the
|
enabled using the <strong>Show Sections Table</strong> button in the
|
||||||
section.</li>
|
local toolbar.</p>
|
||||||
<li>The <strong>End Address</strong> gives the maximum (inclusive)
|
<p>Double-click any address to navigate to it. Make a selection of
|
||||||
address of the section.</li>
|
modules or sections, right-click, and choose <strong>Select
|
||||||
<li>The <strong>Section Name</strong> gives the name of the
|
Addresses</strong>. Again, combined with the Dynamic Listing’s
|
||||||
section.</li>
|
<strong>Read Memory</strong> button, you can capture memory
|
||||||
<li>The <strong>Module Name</strong> gives the name of the module
|
selectively.</p>
|
||||||
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
|
|
||||||
Listing’s Refresh button, you can capture memory surgically.</p>
|
|
||||||
</section>
|
</section>
|
||||||
<section id="optional-exercise-find-the-time-surgically" class="level2">
|
<section id="optional-exercise-find-the-time-surgically" class="level2">
|
||||||
<h2>Optional Exercise: Find the Time Surgically</h2>
|
<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
|
<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
|
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>
|
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
|
from the <strong>Map Section</strong> actions. This is certainly more
|
||||||
tedious and atypical, but it allows the surgical mapping of each section
|
tedious and atypical, but it allows the surgical mapping of each section
|
||||||
to a chosen memory block from among your open programs.</li>
|
to a chosen memory block from among your open programs.</li>
|
||||||
<li>From the Regions window, select one or more regions, and choose from
|
<li>From the Regions window, select one or more regions, and choose from
|
||||||
the <strong>Map Region</strong> actions.</li>
|
the <strong>Map Region</strong> actions.</li>
|
||||||
<li>Click the Map Identically button in the Modules window toolbar.</li>
|
<li>Click the <strong>Map Identically</strong> button in the Modules
|
||||||
<li>Use the Add and Remove buttons in the Static Mappings window
|
window toolbar.</li>
|
||||||
toolbar.</li>
|
<li>Use the <strong>Add</strong> and <strong>Remove</strong> buttons in
|
||||||
|
the Static Mappings window toolbar.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>These methods are not described in detail here. For more information,
|
<p>These methods are not described in detail here. For more information,
|
||||||
hover over the relevant actions and press <strong>F1</strong> for
|
hover over the relevant actions and press
|
||||||
help.</p>
|
<strong><code>F1</code></strong> for help.</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="moving-knowledge-from-dynamic-to-static" class="level2">
|
<section id="moving-knowledge-from-dynamic-to-static" class="level2">
|
||||||
<h2>Moving Knowledge from Dynamic to Static</h2>
|
<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.
|
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
|
In this case, you would want to copy those code units (though not
|
||||||
necessarily the byte values) from the Dynamic Listing into the Static
|
necessarily the byte values) from the Dynamic Listing into the Static
|
||||||
Listing. After selecting the units to copy, from the menus, you would
|
Listing. After selecting the units to copy, you would use
|
||||||
use <strong>Debugger → Copy Into Current Program</strong>.</p>
|
<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,
|
<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
|
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
|
this case, you would want to copy everything within that module from the
|
||||||
dynamic session into a program database. After selecting the addresses
|
dynamic session into a program database. After selecting the addresses
|
||||||
in that module, from the menus, you would use <strong>Debugger → Copy
|
in that module, you would use <strong>Debugger → Copy Into New
|
||||||
Into New Program</strong>.</p>
|
Program</strong>.</p>
|
||||||
<p>For demonstration, we will walk through this second case, pretending
|
<p>For demonstration, we will walk through this second case, pretending
|
||||||
we cannot load <code>libncurses</code> from disk:</p>
|
we cannot load <code>libncurses</code> from disk:</p>
|
||||||
<ol type="1">
|
<ol type="1">
|
||||||
|
@ -279,20 +262,22 @@ Program</strong>.</p>
|
||||||
alt="Copy dialog for ncurses" />
|
alt="Copy dialog for ncurses" />
|
||||||
<figcaption aria-hidden="true">Copy dialog for ncurses</figcaption>
|
<figcaption aria-hidden="true">Copy dialog for ncurses</figcaption>
|
||||||
</figure></li>
|
</figure></li>
|
||||||
<li><p>Keep Destination set to “New Program.”</p></li>
|
<li><p>Keep <strong>Destination</strong> set to “<New
|
||||||
<li><p>Ensure “Read live target’s memory” is checked. This will spare
|
Program>.”</p></li>
|
||||||
you from having to create a full snapshot manually.</p></li>
|
<li><p>Ensure <strong>Read live target’s memory</strong> is checked.
|
||||||
<li><p>Do <em>not</em> check “Use overlays where blocks already
|
This will spare you from having to create a full snapshot
|
||||||
present.” It should not have any effect for a new program,
|
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>
|
anyway.</p></li>
|
||||||
<li><p>It is probably best to include everything, though “Bytes” is the
|
<li><p>It is probably best to include everything, though
|
||||||
bare minimum.</p></li>
|
<strong>Bytes</strong> is the bare minimum.</p></li>
|
||||||
<li><p>The table displays the <em>copy plan</em>. For a new program,
|
<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
|
this will copy with an identical mapping of addresses, which is probably
|
||||||
the best plan, since the target system has already applied fixups. Do
|
the best plan, since the target system has already applied fixups. Do
|
||||||
not change any addresses, lest your corrupt references in the
|
not change any addresses, lest your corrupt references in the
|
||||||
copy.</p></li>
|
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>When prompted, name the program <code>libncurses</code>.</p></li>
|
||||||
<li><p>You may need to click the <code>termmines</code> tab in the
|
<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>
|
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
|
<p>Undoubtedly, we would like to map that new program into our dynamic
|
||||||
session.</p>
|
session.</p>
|
||||||
<ol type="1">
|
<ol type="1">
|
||||||
<li>Again, in the top pane of the Modules window, right-click
|
<li>Ensure that the new <code>libncurses</code> capture is still the
|
||||||
<code>libncurses</code> and choose <strong>Select
|
current program.</li>
|
||||||
Addresses</strong>.</li>
|
<li>In the top pane of the Modules window, right-click
|
||||||
<li>Ensure the cursor in the Static Listing is at the minimum address of
|
<code>libncurses</code> and choose <strong>Map to
|
||||||
<code>libncurses</code>.</li>
|
libncurses</strong>.</li>
|
||||||
<li>In the Static Mappings window, click Add in the toolbar.</li>
|
<li>Check the proposed mapping and click <strong>OK</strong>.</li>
|
||||||
<li>Click OK.</li>
|
|
||||||
</ol>
|
</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>
|
||||||
<section id="exercise-export-and-map-ncurses" class="level2">
|
<section id="exercise-export-and-map-ncurses" class="level2">
|
||||||
<h2>Exercise: Export and Map <code>ncurses</code></h2>
|
<h2>Exercise: Export and Map <code>ncurses</code></h2>
|
||||||
|
|
|
@ -26,28 +26,26 @@ The columns are:
|
||||||
For file-backed mappings, this should include the name of the file.
|
For file-backed mappings, this should include the name of the file.
|
||||||
It may or may not include a section name.
|
It may or may not include a section name.
|
||||||
Typically, the name will include the start address to avoid collisions.
|
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 **Start** column gives the minimum address of the region.
|
||||||
* The **End** column gives the maximum (inclusive) 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 **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.
|
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.
|
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**.
|
Select one or more regions, right-click, and choose **Select Addresses**.
|
||||||
That should select all the addresses in those regions in the Dynamic Listing.
|
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
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
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 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.
|
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.
|
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 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.
|
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.
|
* The **Base** column gives the image base for the module.
|
||||||
This should be the minimum address of 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 **Name** column gives the (short) name of the module.
|
||||||
* The **Module Name** column gives the full file path of the module *on target*.
|
* The **Mapping** column gives the mapped Ghidra program database for the module.
|
||||||
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 **Length** column gives the distance between the base and max address (inclusive).
|
* 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.
|
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.
|
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.
|
Double-click any address to navigate to it.
|
||||||
Make a selection of modules or sections, right-click, and choose **Select Addresses**.
|
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
|
## 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.
|
* 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.
|
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.
|
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.
|
* 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.
|
* Click the **Map Identically** button in the Modules window toolbar.
|
||||||
* Use the Add and Remove buttons in the Static Mappings window toolbar.
|
* Use the **Add** and **Remove** buttons in the Static Mappings window toolbar.
|
||||||
|
|
||||||
These methods are not described in detail here.
|
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
|
## 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.
|
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.
|
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.
|
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 → Copy Into Current Program**.
|
After selecting the units to copy, you would use **Debugger → 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 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.
|
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 → Copy Into New Program**.
|
After selecting the addresses in that module, you would use **Debugger → Copy Into New Program**.
|
||||||
|
|
||||||
For demonstration, we will walk through this second case, pretending we cannot load `libncurses` from disk:
|
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
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
1. Keep Destination set to "New Program."
|
1. Keep **Destination** set to "<New Program>."
|
||||||
1. Ensure "Read live target's memory" is checked.
|
1. Ensure **Read live target's memory** is checked.
|
||||||
This will spare you from having to create a full snapshot manually.
|
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.
|
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*.
|
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.
|
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.
|
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. 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. 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.
|
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.
|
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 that the new `libncurses` capture is still the current program.
|
||||||
1. Ensure the cursor in the Static Listing is at the minimum address of `libncurses`.
|
1. In the top pane of the Modules window, right-click `libncurses` and choose **Map to libncurses**.
|
||||||
1. In the Static Mappings window, click Add in the toolbar.
|
1. Check the proposed mapping and click **OK**.
|
||||||
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.
|
|
||||||
|
|
||||||
## Exercise: Export and Map `ncurses`
|
## Exercise: Export and Map `ncurses`
|
||||||
|
|
||||||
|
|
|
@ -112,19 +112,21 @@
|
||||||
id="toc-module-mapping-caveats">Module Mapping Caveats</a></li>
|
id="toc-module-mapping-caveats">Module Mapping Caveats</a></li>
|
||||||
<li><a href="#variation-in-configuration"
|
<li><a href="#variation-in-configuration"
|
||||||
id="toc-variation-in-configuration">Variation in Configuration</a></li>
|
id="toc-variation-in-configuration">Variation in Configuration</a></li>
|
||||||
<li><a href="#using-gdbserver" id="toc-using-gdbserver">Using
|
<li><a href="#using-gdbserver-over-ssh"
|
||||||
<code>gdbserver</code></a></li>
|
id="toc-using-gdbserver-over-ssh">Using <code>gdbserver</code> over
|
||||||
<li><a href="#using-ssh" id="toc-using-ssh">Using SSH</a></li>
|
SSH</a></li>
|
||||||
<li><a href="#using-gadp" id="toc-using-gadp">Using GADP</a>
|
<li><a href="#using-trace-rmi-over-ssh"
|
||||||
|
id="toc-using-trace-rmi-over-ssh">Using Trace RMI over SSH</a>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#using-gadp-locally" id="toc-using-gadp-locally">Using GADP
|
<li><a href="#troubleshooting"
|
||||||
Locally</a></li>
|
id="toc-troubleshooting">Troubleshooting</a></li>
|
||||||
<li><a href="#using-gadp-remotely" id="toc-using-gadp-remotely">Using
|
|
||||||
GADP Remotely</a></li>
|
|
||||||
</ul></li>
|
</ul></li>
|
||||||
<li><a href="#using-a-pty-pseudo-terminal"
|
<li><a href="#using-gdbserver-manually"
|
||||||
id="toc-using-a-pty-pseudo-terminal">Using a pty
|
id="toc-using-gdbserver-manually">Using <code>gdbserver</code>
|
||||||
(pseudo-terminal)</a></li>
|
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"
|
<li><a href="#rube-goldberg-configurations"
|
||||||
id="toc-rube-goldberg-configurations">Rube Goldberg
|
id="toc-rube-goldberg-configurations">Rube Goldberg
|
||||||
Configurations</a></li>
|
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
|
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>
|
in user space. While this list is not exhaustive, some options are:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Use <code>gdbserver</code></li>
|
<li>Use <code>gdbserver</code> over SSH</li>
|
||||||
<li>Use SSH</li>
|
<li>Use Trace RMI over SSH</li>
|
||||||
<li>Use GADP</li>
|
<li>Use <code>gdbserver</code> and connect to it manually</li>
|
||||||
<li>Use a pty</li>
|
<li>Connect Trace RMI manually</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Generally, for each of these options it boils down to which
|
<p>Generally, for each of these options it boils down to which
|
||||||
components will be colocated with the target and which will be colocated
|
components will be colocated with the target and which will be colocated
|
||||||
with Ghidra.</p>
|
with Ghidra.</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="using-gdbserver" class="level2">
|
<section id="using-gdbserver-over-ssh" class="level2">
|
||||||
<h2>Using <code>gdbserver</code></h2>
|
<h2>Using <code>gdbserver</code> over SSH</h2>
|
||||||
<p>In this configuration, Ghidra and GDB will be located in the user’s
|
<p>In this configuration, Ghidra and GDB will be located in the user’s
|
||||||
local environment, while <code>gdbserver</code> and the specimen will be
|
local environment, while <code>gdbserver</code> and the specimen will be
|
||||||
located in the target environment. The procedure follows directly from
|
located in the target environment. We will connect the local
|
||||||
GDB’s manual, but with some Ghidra-specific steps. First, prepare the
|
<code>gdb</code> to the remote <code>gdbserver</code> by forwarding
|
||||||
target, which for demonstration purposes has the IP address
|
stdio over SSH.</p>
|
||||||
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>
|
|
||||||
<ol type="1">
|
<ol type="1">
|
||||||
<li><p>From the Targets window, click Connect, select “gdb,” and click
|
<li><p>First, prepare the target, which for demonstration purposes has
|
||||||
Connect.</p></li>
|
the IP address 10.0.0.1. Generally, this just means booting it up and
|
||||||
<li><p>In the Interpreter, do as you would in GDB:</p>
|
ensuring it has <code>gdbserver</code> installed. <strong>NOTE</strong>:
|
||||||
<div class="sourceCode" id="cb2"><pre
|
You do not need to run <code>gdbserver</code> or the target binary. The
|
||||||
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>
|
launcher will do that for you.</p></li>
|
||||||
</ol>
|
<li><p>From the launch menu, select <strong>gdb + gdbserver via
|
||||||
<p>The target should now be added to the Debugger session, and things
|
ssh</strong>.</p>
|
||||||
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 user’s
|
|
||||||
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>
|
|
||||||
<figure>
|
<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 user’ls 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 distribution’s 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" />
|
alt="Connect dialog for gdb via SSH" />
|
||||||
<figcaption aria-hidden="true">Connect dialog for gdb via
|
<figcaption aria-hidden="true">Connect dialog for gdb via
|
||||||
SSH</figcaption>
|
SSH</figcaption>
|
||||||
</figure></li>
|
</figure></li>
|
||||||
<li><p>Set “GDB launch command” to the path of gdb <em>on the remote
|
<li><p>Fill out the options appropriately. Notably, correct the location
|
||||||
file system</em>.</p></li>
|
of the target image to point at its location on the <em>target</em>
|
||||||
<li><p>Leave “Use existing session via new-ui” unchecked.</p></li>
|
system. Enter “user@10.0.0.1” for the <strong>[User@]Host</strong>
|
||||||
<li><p>Set “SSH hostname” to the name or IP address of the target
|
option, substituting your username for the remote system.</p></li>
|
||||||
system.</p></li>
|
<li><p>Click <strong>Launch</strong>.</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>
|
|
||||||
</ol>
|
</ol>
|
||||||
<p>If everything goes well, the Objects window should populate, and you
|
<p>At this point, most things will work the same as they would for a
|
||||||
should get an Interpreter window presenting the remote GDB CLI. You may
|
local target.</p>
|
||||||
use it in the usual manner to launch your target. Alternatively, in the
|
<section id="troubleshooting" class="level3">
|
||||||
Objects window, click the Launch or Quick Launch button to launch the
|
<h3>Troubleshooting</h3>
|
||||||
current program. If prompted for the target command line, remember you
|
<section id="i-cant-find-the-python-packages-to-install" class="level4">
|
||||||
must provide the path <em>on the remote file system</em>.</p>
|
<h4>I can’t find the Python packages to install</h4>
|
||||||
<p>The target should now be added to the Debugger session, and things
|
<p>These should be located in the Ghidra installation. Search for files
|
||||||
should work as usual.</p>
|
ending in <code>.whl</code>. Alternatively, you can build the packages
|
||||||
</section>
|
from source. The source is included with Ghidra. If you are able to do
|
||||||
<section id="using-gadp" class="level2">
|
local debugging with Ghidra and <code>gdb</code>, then the source is
|
||||||
<h2>Using GADP</h2>
|
definitely present and functioning.</p>
|
||||||
<p>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 <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 user’s
|
|
||||||
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>
|
|
||||||
<div class="sourceCode" id="cb3"><pre
|
<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>
|
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="ex">support/gdbGADPServerRun</span> <span class="at">-h</span></span></code></pre></div>
|
<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>
|
||||||
<p>This should print help for you. Typically, you can just run the agent
|
<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>
|
||||||
without any extra command-line arguments:</p>
|
<p>This should output a <code>.whl</code> 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
|
||||||
|
<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
|
<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>
|
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>If not, then you probably just need to tell it where you installed
|
<p>Or, inside <code>gdb</code>:</p>
|
||||||
<code>gdb</code>:</p>
|
|
||||||
<div class="sourceCode" id="cb5"><pre
|
<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>
|
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>
|
||||||
<p>If you cannot install Ghidra, or do not want to, then you can build a
|
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>>>> import sys</span>
|
||||||
standalone jar. You will still need to install the JRE on the target,
|
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>>>> sys.version</span></code></pre></div>
|
||||||
likely the same version as recommended for Ghidra.</p>
|
<p>Suppose this identifies version 3.7. Retry the installation commands
|
||||||
<p>Refer to the root README file to get started with a build from
|
using <code>python3.7 -m pip ...</code>. If you have multiple copies of
|
||||||
source. You may stop short of the <code>gradle buildGhidra</code> step,
|
the same version in different locations, you may need to invoke
|
||||||
though it may be helpful to avoid trouble. Then, build the executable
|
<code>python3</code> using its complete path.</p>
|
||||||
jar for the GDB agent:</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
|
<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>
|
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>
|
||||||
<p>This will create the file
|
<li><p>From the launch menu, select <strong>remote
|
||||||
<code>Ghidra/Debug/Debugger-agent-gdb/build/libs/Debugger-agent-gdb-nodep.jar</code>.
|
gdb</strong>.</p></li>
|
||||||
Copy the file to the target system. Now, run it:</p>
|
<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 Ghidra’s 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
|
||||||
|
acceptor’s 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
|
<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>
|
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>
|
||||||
<p>Once the agent is running, it should print its port number, and you
|
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>file termmines</span>
|
||||||
can connect from Ghidra. For demonstration, we will assume it is
|
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a># set args, if you'd like</span>
|
||||||
listening at 10.0.0.2 on port 15432.</p>
|
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a>ghidra trace connect 10.0.0.1:12345</span>
|
||||||
<ol type="1">
|
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>ghidra trace start</span>
|
||||||
<li>From the Targets window, click Connect.</li>
|
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>ghidra trace sync-enable</span>
|
||||||
<li>Select “Ghidra debug agent (GADP)” from the drop-down.</li>
|
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a>starti</span></code></pre></div></li>
|
||||||
<li>For “Agent network address”, enter 10.0.0.2.</li>
|
|
||||||
<li>For “Agent TCP port”, enter 15432.</li>
|
|
||||||
<li>Click Connect.</li>
|
|
||||||
</ol>
|
</ol>
|
||||||
<p>That should complete the connection. You should see Objects populated
|
<p>At this point, most things will work the same as they would for a
|
||||||
and get an Interpreter window. You can then proceed to launch or attach
|
local target. You may notice Ghidra has not given you a new terminal.
|
||||||
a target in that connection using either the Objects window or the
|
Just use the one you already have on the remote target.</p>
|
||||||
Interpreter window.</p>
|
<p>A notable advantage of this configuration is that you can enter
|
||||||
</section>
|
whatever <code>gdb</code> commands you want to start your target. Here
|
||||||
</section>
|
we demonstrated the simplest case of a “native” target. It is also
|
||||||
<section id="using-a-pty-pseudo-terminal" class="level2">
|
possible to use this procedure to connect Ghidra into a running
|
||||||
<h2>Using a pty (pseudo-terminal)</h2>
|
<code>gdb</code> session.</p>
|
||||||
<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>
|
|
||||||
</section>
|
</section>
|
||||||
<section id="rube-goldberg-configurations" class="level2">
|
<section id="rube-goldberg-configurations" class="level2">
|
||||||
<h2>Rube Goldberg Configurations</h2>
|
<h2>Rube Goldberg Configurations</h2>
|
||||||
|
@ -342,10 +361,10 @@ Android emulator.</p>
|
||||||
<h2>Exercise: Debug your Friend’s <code>termmines</code></h2>
|
<h2>Exercise: Debug your Friend’s <code>termmines</code></h2>
|
||||||
<p>If you are in a classroom setting, pair up. Otherwise, play both
|
<p>If you are in a classroom setting, pair up. Otherwise, play both
|
||||||
roles, preferably using separate machines for Ghidra and the target.
|
roles, preferably using separate machines for Ghidra and the target.
|
||||||
Using either <code>gdbserver</code>, gdb via SSH, or the GDB agent,
|
Using one of the above procedures, debug <code>termmines</code>. One of
|
||||||
debug <code>termmines</code>. One of you should prepare the target
|
you should prepare the target environment. The other should connect to
|
||||||
environment. The other should connect to it and launch the specimen.
|
it and launch the specimen. Then trade roles, choose a different
|
||||||
Then trade roles, choose a different configuration, and do it again.</p>
|
procedure, and do it again.</p>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
@ -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.
|
Consider a remote Linux target in user space.
|
||||||
While this list is not exhaustive, some options are:
|
While this list is not exhaustive, some options are:
|
||||||
|
|
||||||
* Use `gdbserver`
|
* Use `gdbserver` over SSH
|
||||||
* Use SSH
|
* Use Trace RMI over SSH
|
||||||
* Use GADP
|
* Use `gdbserver` and connect to it manually
|
||||||
* Use a pty
|
* 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.
|
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.
|
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.
|
We will connect the local `gdb` to the remote `gdbserver` by forwarding stdio over SSH.
|
||||||
First, prepare the target, which for demonstration purposes has the IP address 10.0.0.1:
|
|
||||||
|
|
||||||
```bash
|
1. First, prepare the target, which for demonstration purposes has the IP address 10.0.0.1.
|
||||||
gdbserver 10.0.0.1:12345 termmines
|
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:
|

|
||||||
|
|
||||||
1. From the Targets window, click Connect, select "gdb," and click Connect.
|
1. Read the wall of text, at least the first time, and verify the remote system is prepared.
|
||||||
1. In the Interpreter, do as you would in GDB:
|
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
|
At this point, most things will work the same as they would for a local target.
|
||||||
target remote 10.0.0.1:12345
|
|
||||||
```
|
|
||||||
|
|
||||||
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.
|
1. First, prepare the target.
|
||||||
**NOTE**: The full `gdb`, not just `gdbserver`, must be installed on the target system.
|
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`.
|
||||||
1. From the Targets window, click Connect, and select "gdb via SSH."
|
If you installed `gdb` and `python3` from your distribution's repositories, installation of the Python packages should just be a matter of using `pip`:
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
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:
|
|
||||||
|
|
||||||
```bash
|
```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.
|
Chances are, GDB embeds the same Python, so they become importable from `gdb`:
|
||||||
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`:
|
|
||||||
|
|
||||||
```gdb
|
```gdb
|
||||||
new-ui /dev/pts/1
|
python import ghidragdb
|
||||||
```
|
```
|
||||||
|
|
||||||
That should complete the connection.
|
You can quit GDB, since that was just for verifying the installation.
|
||||||
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.
|
|
||||||
|
|
||||||
This same checkbox is available in the "gdb via SSH" connector.
|
1. From the launch menu, select **gdb via ssh**.
|
||||||
Note that the remote system must support pseudo terminals, and the name of the pseudo terminal is from the *remote file system*.
|
|
||||||
|
|
||||||
To activate this configuration in the standalone GADP agent, use the `-x` option:
|

|
||||||
|
|
||||||
|
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
|
```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.
|
||||||
|
|
||||||
|

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

|

|
||||||
|
|
||||||
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.
|
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.
|
Presumably, the crash was caused by the instruction to be executed next.
|
||||||
To get details about the error, press  Step Into.
|
To get details about the error, press  **Step Into**.
|
||||||
This should display an error dialog with a full trace of the crash.
|
This should display an error dialog with a full trace of the crash.
|
||||||
In this case, it should be an instruction decode error.
|
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.
|
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.
|
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.
|
To diagnose the crash, press  **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`.
|
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 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.
|
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.
|
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.
|
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.
|
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.
|
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`.
|
Now, we will manually "allocate" memory for `argv`.
|
||||||
Luckily, Ghidra allocated 16K of stack space for us!
|
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.
|
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.
|
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`.
|
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:
|
Add the following watches:
|
||||||
|
|
||||||
* `RSP` — to confirm the stack pointer is far from `argv`.
|
* `RSP` — 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.
|
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]`.
|
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.
|
Use the Watches window to set `RDI` to 1, then click  **Resume**.
|
||||||
Like before, the emulator will crash, but this time you should see "pc = 00000000" in red.
|
Like before, the emulator will crash, but this time you should see "pc = 00000000" in red.
|
||||||
This probably indicates success.
|
This probably indicates success.
|
||||||
In the Threads window, you should see a schedule similar to `0:t0-{RDI=0x1);t0-16`.
|
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.
|
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`.
|
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.
|
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)` — the address of the first argument, i.e., `argv[0]`.
|
* `*:8 (RSI + 0)` — the address of the first argument, i.e., `argv[0]`.
|
||||||
* `*:30 (*:8 (RSI + 0))` with type `TerminatedCString` — at most 30 characters of the first argument.
|
* `*:30 (*:8 (RSI + 0))` with type `TerminatedCString` — 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`.
|
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`.
|
To do that, set the value of `RSI` to `0x1000`.
|
||||||
You should see the Address column update for some other watches.
|
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.
|
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.
|
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.
|
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.
|
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`.
|
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`.
|
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)`.
|
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`.
|
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"`.
|
Using the Repr column, set that watch's value to `"termmines"`.
|
||||||
(The quotes are required.)
|
(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"`.
|
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"`.
|
Then finally, allocate `argv[2]` and set it to `"Advanced"`.
|
||||||
When you have finished, the Watches pane should look something like this:
|
When you have finished, the Watches pane should look something like this:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
The Dynamic listing should look something like this:
|
The Dynamic Listing should look something like this:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
**NOTE**: The placement of data units is not necessary for the emulator to operate; it only cares about the bytes.
|
**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.
|
However, it is a useful aide in devising, understanding, and diagnosing machine state.
|
||||||
|
|
||||||
Now, click  Resume, and see where the emulator crashes next.
|
Now, click  **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`.
|
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.
|
If the program counter is `00000000`, then it returned successfully.
|
||||||
This is unfortunate, because you no longer have motivation to stub external calls.
|
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
|
#### Skip Technique
|
||||||
|
|
||||||
The skip technique is simplest, but will need to be performed *every time* that call is encountered.
|
The skip technique is simplest, but will need to be performed *every time* that call is encountered.
|
||||||
Press  Skip Over, then use the Registers or Watches pane to patch `RAX`.
|
Press  **Skip Over**, then use the Registers or Watches pane to patch `RAX`.
|
||||||
Then press  Resume.
|
Then press  **Resume**.
|
||||||
|
|
||||||
#### `CALL` Override Technique
|
#### `CALL` Override Technique
|
||||||
|
|
||||||
Overriding the `CALL` is also fairly simple.
|
Overriding the `CALL` is also fairly simple.
|
||||||
While this will handle every encounter, it will not handle other calls to the same external function.
|
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. 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.
|
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:
|
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 → Configure Emulator → Invalidate Emulator Cache**.
|
1. In the menus, select **Debugger → Configure Emulator → Invalidate Emulator Cache**.
|
||||||
1. Click  Resume.
|
1. Click  **Resume**.
|
||||||
|
|
||||||
Stubbing any remaining external calls is left as an exercise.
|
Stubbing any remaining external calls is left as an exercise.
|
||||||
You are successful when the emulator crashes with `pc = 00000000`.
|
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.
|
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.
|
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`.
|
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`.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.)
|
(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
|
### 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.
|
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.
|
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.
|
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.
|
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.
|
Once you have it, export the patched binary and run it outside of Ghidra.
|
||||||
|
|
||||||
## Debugging P-code Semantics
|
## 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. If you have not already, open the Debugger tool.
|
||||||
1. In the menus, select **File → Configure**.
|
1. In the menus, select **File → 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. Activate the `DebuggerPcodeStepperPlugin`
|
||||||
1. Click OK
|
1. Click **OK**
|
||||||
1. Click Close
|
1. Click **Close**
|
||||||
|
|
||||||
The stepper should appear stacked over the Threads panel in the bottom right.
|
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:
|
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.
|
You can then step forward and backward within those.
|
||||||
As you step, the other windows that display machine state will update.
|
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.
|
These are temporary variables used only within an instruction's implementation.
|
||||||
They are displayed in the right panel.
|
They are displayed in the right panel.
|
||||||
The table of variables works similarly to the Registers pane.
|
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.
|
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.
|
**NOTE**: You cannot mix instruction steps with p-code op steps.
|
||||||
The instruction steps always precede the p-code ops.
|
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.
|
In most cases, this intuitively "finishes" the partial instruction.
|
||||||
|
|
|
@ -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-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-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>
|
<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 Debugger’s “deep” API is accessible to scripts;
|
<p>Technically, the Debugger’s “deep” API is accessible to scripts;
|
||||||
however, the flat API is preferred for scripting. Also, the flat API is
|
however, the flat API is preferred for scripting. Also, the flat API is
|
||||||
usually more stable than the deep API. However, because the dynamic
|
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>
|
||||||
<section id="reading-the-data" class="level3">
|
<section id="reading-the-data" class="level3">
|
||||||
<h3>Reading the Data</h3>
|
<h3>Reading the Data</h3>
|
||||||
<p>Now, we want to read the dimensions and the whole board to the trace.
|
<p>Now, we want to read the dimensions and the whole board from the
|
||||||
You should know from earlier exercises that the board is allocated 32
|
target. You should know from earlier exercises that the board is
|
||||||
cells by 32 cells, so we will want to read at least 1024 bytes. Note
|
allocated 32 cells by 32 cells, so we will want to read at least 1024
|
||||||
that this will implicitly capture the board to the trace:</p>
|
bytes. Note that this will implicitly capture the board to the
|
||||||
|
trace:</p>
|
||||||
<div class="sourceCode" id="cb5"><pre
|
<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>
|
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>
|
<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>
|
||||||
<section id="test-the-script" class="level3">
|
<section id="test-the-script" class="level3">
|
||||||
<h3>Test the Script</h3>
|
<h3>Test the Script</h3>
|
||||||
<p>To test, run <code>termmines</code> in a proper terminal and attach
|
<p>To test, launch <code>termmines</code> in Ghidra using GDB. You will
|
||||||
to it from Ghidra using GDB. Now, run the script. Resume and play the
|
need to allow it to set up the first game board before running the
|
||||||
game. Once you win, check that the script output describes the actual
|
script. The simplest way to do that is to resume and then interrupt the
|
||||||
board.</p>
|
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>
|
||||||
<section id="exercise-remove-the-mines" class="level3">
|
<section id="exercise-remove-the-mines" class="level3">
|
||||||
<h3>Exercise: Remove the Mines</h3>
|
<h3>Exercise: Remove the Mines</h3>
|
||||||
<p>Write a script that will remove the mines from the board.
|
<p>Write a script that will remove the mines from the board.
|
||||||
<strong>NOTE</strong>: The <code>writeMemory()</code> and related
|
<strong>NOTE</strong>: The <code>writeMemory()</code> and related
|
||||||
methods are all subject to the current control mode. If the mode is
|
methods are all subject to the current <strong>Control Mode</strong>. If
|
||||||
read-only, the script cannot modify the target’s machine state using
|
the mode is read-only, the script cannot modify the target’s machine
|
||||||
those methods.</p>
|
state using those methods.</p>
|
||||||
</section>
|
</section>
|
||||||
</section>
|
</section>
|
||||||
<section id="waiting-on-reacting-to-events" class="level2">
|
<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
|
<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
|
tutorial below, but give it an honest try before peeking. If you are not
|
||||||
already familiar with Eclipse’s searching and discovery features, try
|
already familiar with Eclipse’s searching and discovery features, try
|
||||||
pressing <strong>Ctrl-O</strong> twice in the editor for your script.
|
pressing <strong><code>CTRL</code>-<code>O</code></strong> twice in the
|
||||||
You should now be able to type patterns, optionally with wildcards, to
|
editor for your script. You should now be able to type patterns,
|
||||||
help you find applicable methods.</p>
|
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
|
<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
|
then patch the machine state, so that the game always prints a score of
|
||||||
0 seconds. Some gotchas to consider up front:</p>
|
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
|
will not likely be able to place or toggle breakpoints while the target
|
||||||
is running.</li>
|
is running.</li>
|
||||||
<li>Methods like <code>writeMemory()</code> are subject to the current
|
<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
|
<strong>Control Mode</strong>. You may want to check and/or correct this
|
||||||
your script.</li>
|
at the top of your script.</li>
|
||||||
<li>If you require the user to mark code locations with a label, note
|
<li>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
|
that those labels will likely end up in the containing function’s
|
||||||
namespace. You will need to provide that namespace to
|
namespace. You will need to provide that namespace to
|
||||||
|
@ -351,13 +365,13 @@ breakpoint numbers.</li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>You are successful when you can attach to a running
|
<p>You are successful when you can attach to a running
|
||||||
<code>termmines</code> and execute your script. Then, assuming you win
|
<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>
|
you have to re-execute your script after each win.</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="solution-always-win-in-0-seconds" class="level3">
|
<section id="solution-always-win-in-0-seconds" class="level3">
|
||||||
<h3>Solution: Always Win in 0 Seconds</h3>
|
<h3>Solution: Always Win in 0 Seconds</h3>
|
||||||
<p>As in the previous scripting tutorial, we will do some verifications
|
<p>As in the previous script, we will do some verifications at the top
|
||||||
at the top of the script. Your level of pedantry may vary.</p>
|
of the script. Your level of pedantry may vary.</p>
|
||||||
<div class="sourceCode" id="cb7"><pre
|
<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>
|
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>
|
<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
|
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
|
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
|
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
|
<strong>Control Target</strong> (with edits), but I prefer to keep the
|
||||||
that the script needs to modify target machine state.</p>
|
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
|
<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
|
same as in the previous script, but with attention to the containing
|
||||||
containing function namespace. The way <code>termmines</code> computes
|
function namespace. The way <code>termmines</code> computes the score is
|
||||||
the score is to record the start time of the game. Then, when the player
|
to record the start time of the game. Then, when the player wins, it
|
||||||
wins, it subtracts the recorded time from the current time. This script
|
subtracts the recorded time from the current time. This script requires
|
||||||
requires the user to label the start time variable <code>timer</code>,
|
the user to label the start time variable <code>timer</code>, and to
|
||||||
and to label the instruction that computes the score
|
label the instruction that computes the score <code>reset_timer</code>.
|
||||||
<code>reset_timer</code>. The function that prints the score must be
|
The function that prints the score must be named
|
||||||
named <code>print_win</code>.</p>
|
<code>print_win</code>.</p>
|
||||||
<div class="sourceCode" id="cb8"><pre
|
<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"><</span>Symbol<span class="op">></span> timerSyms <span class="op">=</span> <span class="fu">getSymbols</span><span class="op">(</span><span class="st">"timer"</span><span class="op">,</span> <span class="kw">null</span><span class="op">);</span></span>
|
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"><</span>Symbol<span class="op">></span> timerSyms <span class="op">=</span> <span class="fu">getSymbols</span><span class="op">(</span><span class="st">"timer"</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>
|
<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>
|
<code>getCurrentView()</code>.</p>
|
||||||
<p>To avoid creating a pile of breakpoints, we will first attempt to
|
<p>To avoid creating a pile of breakpoints, we will first attempt to
|
||||||
enable an existing breakpoint at the desired location. Technically, the
|
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
|
assume they are. Again, your level of pedantry may vary. The
|
||||||
<code>breakpointsEnable</code> method will return the existing
|
<code>breakpointsEnable</code> method will return the existing
|
||||||
breakpoints, so we can check that and create a new breakpoint, if
|
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>
|
check the program counter:</p>
|
||||||
<div class="sourceCode" id="cb10"><pre
|
<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>
|
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-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-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>
|
<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-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-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>
|
<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>.
|
<p>The “center” of this loop is a call to <code>waitForBreak()</code> on
|
||||||
This is the simplest primitive for waiting on the target to meet any
|
line 27. This is the simplest primitive for waiting on the target to
|
||||||
condition. Because we expect the user to take more than a second to win
|
meet any condition. Because we expect the user to take more than a
|
||||||
the game, we should expect a timeout exception and just keep waiting.
|
second to win the game, we should expect a timeout exception and just
|
||||||
Using a timeout of 1 second ensures we can terminate promptly should the
|
keep waiting. Using a timeout of 1 second ensures we can terminate
|
||||||
user cancel the script.</p>
|
promptly should the user cancel the script.</p>
|
||||||
<p>Before waiting, we need to make sure the target is running. Because
|
<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
|
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
|
only call <code>resume()</code> if the target is stopped. There are
|
||||||
|
|
|
@ -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.
|
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.
|
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.
|
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
|
### 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.
|
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:
|
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
|
### Test the Script
|
||||||
|
|
||||||
To test, run `termmines` in a proper terminal and attach to it from Ghidra using GDB.
|
To test, launch `termmines` in Ghidra using GDB.
|
||||||
Now, run the script.
|
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.
|
Resume and play the game.
|
||||||
Once you win, check that the script output describes the actual board.
|
Once you win, check that the script output describes the actual board.
|
||||||
|
|
||||||
### Exercise: Remove the Mines
|
### Exercise: Remove the Mines
|
||||||
|
|
||||||
Write a script that will remove the mines from the board.
|
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.
|
If the mode is read-only, the script cannot modify the target's machine state using those methods.
|
||||||
|
|
||||||
## Waiting on / Reacting to Events
|
## 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
|
### 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.
|
**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.
|
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.
|
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.
|
* You may want to verify and/or correct the target's execution state.
|
||||||
See `getExecutionState()` and `interrupt()`.
|
See `getExecutionState()` and `interrupt()`.
|
||||||
You will not likely be able to place or toggle breakpoints while the target is running.
|
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.
|
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.
|
* 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()`.
|
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.
|
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.
|
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
|
### 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.
|
Your level of pedantry may vary.
|
||||||
|
|
||||||
```java {.numberLines}
|
```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.
|
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.
|
The second block will interrupt the target if it is running.
|
||||||
We then allow everything to sync up before checking the control mode.
|
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.
|
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.
|
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.
|
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`.
|
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 — see `getCurrentView()`.
|
For dynamic context, use the current (dynamic) trace view as the program — see `getCurrentView()`.
|
||||||
|
|
||||||
To avoid creating a pile of breakpoints, we will first attempt to enable an existing breakpoint at the desired location.
|
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.
|
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:
|
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}
|
```java {.numberLines}
|
||||||
while (true) {
|
while (true) {
|
||||||
monitor.checkCanceled();
|
monitor.checkCancelled();
|
||||||
|
|
||||||
TargetExecutionState execState = getExecutionState(trace);
|
TargetExecutionState execState = getExecutionState(trace);
|
||||||
switch (execState) {
|
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.
|
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.
|
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.
|
Using a timeout of 1 second ensures we can terminate promptly should the user cancel the script.
|
||||||
|
|
|
@ -266,19 +266,20 @@ depending on where the breakpoint was placed.</p>
|
||||||
<section id="modeling-by-sleigh-semantics" class="level3">
|
<section id="modeling-by-sleigh-semantics" class="level3">
|
||||||
<h3>Modeling by Sleigh Semantics</h3>
|
<h3>Modeling by Sleigh Semantics</h3>
|
||||||
<p>The advantage to Java callbacks is that things are relatively
|
<p>The advantage to Java callbacks is that things are relatively
|
||||||
intuitive to do, but the temptation, which we intentionally demonstrate
|
intuitive to do, but the temptation, which we intentionally demonstrated
|
||||||
here, is to make everything concrete. You may notice the library uses a
|
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
|
type parameter <code>T</code>, which specifies the type of all variables
|
||||||
in the emulator’s state. Leaving it as <code>T</code> indicates the
|
in the emulator’s state. Leaving it as <code>T</code> indicates the
|
||||||
library is compatible with any type. For a concrete emulator,
|
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
|
concrete, and then converting back to <code>T</code> using the
|
||||||
arithmetic object. However, if the emulator has been augmented, as we
|
<code>arithmetic</code> object. However, if the emulator has been
|
||||||
will discuss below, the model may become confused, because values
|
augmented, as we will discuss below, the model may become confused,
|
||||||
computed by a careless userop will appear to the model a literal
|
because values computed by a careless userop will appear to the model a
|
||||||
constant. To avoid this, you should keep everything a T and use the
|
literal constant. To avoid this, you should keep everything a T and use
|
||||||
arithmetic object to perform any arithmetic operations. Alternatively,
|
the <code>arithmetic</code> object to perform any arithmetic operations.
|
||||||
you can implement the userop using pre-compiled Sleigh code:</p>
|
Alternatively, you can implement the userop using pre-compiled Sleigh
|
||||||
|
code:</p>
|
||||||
<div class="sourceCode" id="cb2"><pre
|
<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"><</span>T<span class="op">></span> <span class="kw">extends</span> AnnotatedPcodeUseropLibrary<span class="op"><</span>T<span class="op">></span> <span class="op">{</span></span>
|
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"><</span>T<span class="op">></span> <span class="kw">extends</span> AnnotatedPcodeUseropLibrary<span class="op"><</span>T<span class="op">></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">"""</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">"""</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
|
invocation. These are technically still Java callbacks, but our
|
||||||
implementation delegates to the executor, giving it the compiled p-code
|
implementation delegates to the executor, giving it the compiled p-code
|
||||||
program.</p>
|
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
|
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>
|
call to <code>strlen()</code>.</p>
|
||||||
</section>
|
</section>
|
||||||
<section id="modeling-by-structured-sleigh" class="level3">
|
<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 Ghidra’s
|
injection. Refer to the example scripts in Ghidra’s
|
||||||
<code>SystemEmulation</code> module.</p>
|
<code>SystemEmulation</code> module.</p>
|
||||||
<p>If you would like to (temporarily) override the GUI with a custom
|
<p>If you would like to (temporarily) override the GUI with a custom
|
||||||
userop library, you can by overriding the GUI’s emulator factory:</p>
|
userop library, you can by setting the GUI’s emulator factory:</p>
|
||||||
<div class="sourceCode" id="cb5"><pre
|
<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>
|
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>
|
<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>
|
<code>AbstractLongOffsetPcodeExecutorStatePiece</code>.</p>
|
||||||
<p><strong>NOTE</strong>: If you do not desire a concrete address model,
|
<p><strong>NOTE</strong>: If you do not desire a concrete address model,
|
||||||
then you should implement <code>PcodeExecutorState<Expr></code>
|
then you should implement <code>PcodeExecutorState<Expr></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,
|
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
|
the abstractly-addressed state provides a component that is readily used
|
||||||
in both static and dynamic analysis; whereas, the concretely-addressed
|
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-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-21"><a href="#cb8-21"></a> <span class="op">}</span></span>
|
||||||
<span id="cb8-22"><a href="#cb8-22"></a></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-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="co">// </span><span class="al">TODO</span><span class="co">: Handle overlaps / offcut gets and sets</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> 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-25"><a href="#cb8-25"></a> <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-26"><a href="#cb8-26"></a></span>
|
||||||
<span id="cb8-27"><a href="#cb8-27"></a> <span class="op">}</span></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="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></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="kw">public</span> <span class="dt">static</span> <span class="kw">abstract</span> <span class="kw">class</span> AbstractExprPcodeExecutorStatePiece<span class="op"><</span>S <span class="kw">extends</span> ExprSpace<span class="op">></span> <span class="kw">extends</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> AbstractLongOffsetPcodeExecutorStatePiece<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">,</span> S<span class="op">></span> <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>
|
<span id="cb8-32"><a href="#cb8-32"></a><span class="op">}</span></span>
|
||||||
<span id="cb8-33"><a href="#cb8-33"></a> <span class="kw">protected</span> <span class="dt">final</span> AbstractSpaceMap<span class="op"><</span>S<span class="op">></span> spaceMap <span class="op">=</span> <span class="fu">newSpaceMap</span><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>
|
<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"><</span>S <span class="kw">extends</span> ExprSpace<span class="op">></span> <span class="kw">extends</span></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-35"><a href="#cb8-35"></a> AbstractLongOffsetPcodeExecutorStatePiece<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">,</span> S<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-36"><a href="#cb8-36"></a></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-37"><a href="#cb8-37"></a> <span class="kw">protected</span> <span class="dt">final</span> AbstractSpaceMap<span class="op"><</span>S<span class="op">></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 class="op">}</span></span>
|
<span id="cb8-38"><a href="#cb8-38"></a></span>
|
||||||
<span id="cb8-39"><a href="#cb8-39"></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">protected</span> <span class="kw">abstract</span> AbstractSpaceMap<span class="op"><</span>S<span class="op">></span> <span class="fu">newSpaceMap</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></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="at">@Override</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 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-43"><a href="#cb8-43"></a></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-44"><a href="#cb8-44"></a> <span class="kw">protected</span> <span class="kw">abstract</span> AbstractSpaceMap<span class="op"><</span>S<span class="op">></span> <span class="fu">newSpaceMap</span><span class="op">();</span></span>
|
||||||
<span id="cb8-45"><a href="#cb8-45"></a> <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>
|
<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="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="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-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="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-49"><a href="#cb8-49"></a> <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-50"><a href="#cb8-50"></a></span>
|
||||||
<span id="cb8-51"><a href="#cb8-51"></a> <span class="op">}</span></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="op">}</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>
|
<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> <span class="at">@Override</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="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-55"><a href="#cb8-55"></a> <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-56"><a href="#cb8-56"></a> <span class="op">}</span></span>
|
||||||
<span id="cb8-57"><a href="#cb8-57"></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>
|
<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="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="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-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> 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-61"><a href="#cb8-61"></a> <span class="op">}</span></span>
|
||||||
<span id="cb8-62"><a href="#cb8-62"></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>
|
<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="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> <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-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="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-66"><a href="#cb8-66"></a> <span class="op">}</span></span>
|
||||||
<span id="cb8-67"><a href="#cb8-67"></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>
|
<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="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="kw">protected</span> <span class="bu">Map</span><span class="op"><</span>Register<span class="op">,</span> Expr<span class="op">></span> <span class="fu">getRegisterValuesFromSpace</span><span class="op">(</span>S s<span class="op">,</span> <span class="bu">List</span><span class="op"><</span>Register<span class="op">></span> registers<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="cf">throw</span> <span class="kw">new</span> <span class="bu">UnsupportedOperationException</span><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 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="op">}</span></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>
|
<span id="cb8-74"><a href="#cb8-74"></a> <span class="kw">protected</span> <span class="bu">Map</span><span class="op"><</span>Register<span class="op">,</span> Expr<span class="op">></span> <span class="fu">getRegisterValuesFromSpace</span><span class="op">(</span>S s<span class="op">,</span> <span class="bu">List</span><span class="op"><</span>Register<span class="op">></span> registers<span class="op">)</span> <span class="op">{</span></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-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="kw">extends</span> AbstractExprPcodeExecutorStatePiece<span class="op"><</span>ExprSpace<span class="op">></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="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-77"><a href="#cb8-77"></a><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-78"><a href="#cb8-78"></a></span>
|
||||||
<span id="cb8-79"><a href="#cb8-79"></a> <span class="op">}</span></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>
|
<span id="cb8-80"><a href="#cb8-80"></a> <span class="kw">extends</span> AbstractExprPcodeExecutorStatePiece<span class="op"><</span>ExprSpace<span class="op">></span> <span class="op">{</span></span>
|
||||||
<span id="cb8-81"><a href="#cb8-81"></a> <span class="at">@Override</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">protected</span> AbstractSpaceMap<span class="op"><</span>ExprSpace<span class="op">></span> <span class="fu">newSpaceMap</span><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="cf">return</span> <span class="kw">new</span> SimpleSpaceMap<span class="op"><</span>ExprSpace<span class="op">>()</span> <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 class="at">@Override</span></span>
|
<span id="cb8-84"><a href="#cb8-84"></a></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-85"><a href="#cb8-85"></a> <span class="at">@Override</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-86"><a href="#cb8-86"></a> <span class="kw">protected</span> AbstractSpaceMap<span class="op"><</span>ExprSpace<span class="op">></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="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"><</span>ExprSpace<span class="op">>()</span> <span class="op">{</span></span>
|
||||||
<span id="cb8-88"><a href="#cb8-88"></a> <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="op">}</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="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>
|
<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="kw">public</span> <span class="dt">static</span> <span class="kw">class</span> BytesExprPcodeExecutorState <span class="kw">extends</span> PairedPcodeExecutorState<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">></span> <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="kw">public</span> <span class="fu">BytesExprPcodeExecutorState</span><span class="op">(</span>PcodeExecutorStatePiece<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> <span class="dt">byte</span><span class="op">[]></span> concrete<span class="op">)</span> <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="kw">super</span><span class="op">(</span><span class="kw">new</span> PairedPcodeExecutorStatePiece<span class="op"><>(</span>concrete<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 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-95"><a href="#cb8-95"></a></span>
|
||||||
<span id="cb8-96"><a href="#cb8-96"></a> <span class="op">}</span></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"><</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">></span> <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-97"><a href="#cb8-97"></a> <span class="kw">public</span> <span class="fu">BytesExprPcodeExecutorState</span><span class="op">(</span>PcodeExecutorStatePiece<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> <span class="dt">byte</span><span class="op">[]></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"><>(</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
|
<p>The abstract class implements a strategy where a dedicated object
|
||||||
handles each address space. Each object typically maintains of map of
|
handles each address space. Each object typically maintains of map of
|
||||||
offsets (type <code>long</code>) to the model type, i.e.,
|
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
|
problem, but it is actually quite common, esp., since x86 registers are
|
||||||
structured. A write to <code>RAX</code> followed by a read from
|
structured. A write to <code>RAX</code> followed by a read from
|
||||||
<code>EAX</code> will immediately demonstrate this issue. Nevertheless,
|
<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
|
<p>The remaining parts are mostly boilerplate. We implement the “state
|
||||||
piece” interface by creating another abstract class. An abstract class
|
piece” interface by creating another abstract class. An abstract class
|
||||||
is not absolutely necessary, but it will be useful when we integrate the
|
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>
|
<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
|
<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
|
affect both pieces. If you use the arithmetic to generate them, remember
|
||||||
that it will use <code>fromConst</code> on both arithmetics to generate
|
that it will use <code>fromConst</code> on both sub-arithmetics to
|
||||||
the pair, so you may be setting the right side to a
|
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
|
<code>LitExpr</code>. To modify just one side of the pair, cast the
|
||||||
state to <code>PairedPcodeExecutorState</code>, and then use
|
state to <code>PairedPcodeExecutorState</code>, and then use
|
||||||
<code>getLeft()</code>, and <code>getRight()</code> to retrieve the
|
<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-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"><</span>ExprTraceSpace<span class="op">></span></span>
|
<span id="cb11-36"><a href="#cb11-36"></a> <span class="kw">extends</span> AbstractExprPcodeExecutorStatePiece<span class="op"><</span>ExprTraceSpace<span class="op">></span></span>
|
||||||
<span id="cb11-37"><a href="#cb11-37"></a> <span class="kw">implements</span> TracePcodeExecutorStatePiece<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">></span> <span class="op">{</span></span>
|
<span id="cb11-37"><a href="#cb11-37"></a> <span class="kw">implements</span> TracePcodeExecutorStatePiece<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">></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">"Taint"</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">"Expr"</span><span class="op">;</span></span>
|
||||||
<span id="cb11-39"><a href="#cb11-39"></a></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-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"><</span><span class="bu">String</span><span class="op">></span> property<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"><</span><span class="bu">String</span><span class="op">></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-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-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-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"><</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">></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"><</span><span class="dt">byte</span><span class="op">[],</span> <span class="dt">byte</span><span class="op">[]></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"><>(</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,
|
<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
|
we do not need to extend the state pieces any further. The concrete
|
||||||
pieces that we augment will contain all the target integration needed.
|
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
|
implement the full parts factory and use it to construct and install a
|
||||||
full <code>Expr</code>-augmented emulator factory:</p>
|
full <code>Expr</code>-augmented emulator factory:</p>
|
||||||
<div class="sourceCode" id="cb12"><pre
|
<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"><</span>Expr<span class="op">></span> <span class="op">{</span></span>
|
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">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-2"><a href="#cb12-2"></a> <span class="kw">implements</span> AuxDebuggerEmulatorPartsFactory<span class="op"><</span>Expr<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-3"><a href="#cb12-3"></a> INSTANCE<span class="op">;</span></span>
|
||||||
<span id="cb12-4"><a href="#cb12-4"></a> <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>
|
<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="at">@Override</span></span>
|
<span id="cb12-6"><a href="#cb12-6"></a> <span class="kw">public</span> PcodeArithmetic<span class="op"><</span>Expr<span class="op">></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="kw">protected</span> AuxDebuggerEmulatorPartsFactory<span class="op"><</span>Expr<span class="op">></span> <span class="fu">getPartsFactory</span><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="cf">return</span> BytesExprDebuggerEmulatorPartsFactory<span class="op">.</span><span class="fu">INSTANCE</span><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 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="op">}</span></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>
|
<span id="cb12-11"><a href="#cb12-11"></a> <span class="kw">public</span> PcodeUseropLibrary<span class="op"><</span>Pair<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">>></span> <span class="fu">createSharedUseropLibrary</span><span class="op">(</span></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-12"><a href="#cb12-12"></a> AuxPcodeEmulator<span class="op"><</span>Expr<span class="op">></span> emulator<span class="op">)</span> <span class="op">{</span></span>
|
||||||
<span id="cb12-13"><a href="#cb12-13"></a> <span class="kw">implements</span> DebuggerPcodeEmulatorFactory <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>
|
<span id="cb12-14"><a href="#cb12-14"></a> <span class="op">}</span></span>
|
||||||
<span id="cb12-15"><a href="#cb12-15"></a> <span class="at">@Override</span></span>
|
<span id="cb12-15"><a href="#cb12-15"></a></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-16"><a href="#cb12-16"></a> <span class="at">@Override</span></span>
|
||||||
<span id="cb12-17"><a href="#cb12-17"></a> <span class="cf">return</span> <span class="st">"Expr"</span><span class="op">;</span></span>
|
<span id="cb12-17"><a href="#cb12-17"></a> <span class="kw">public</span> PcodeUseropLibrary<span class="op"><</span>Pair<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">>></span> <span class="fu">createLocalUseropStub</span><span class="op">(</span></span>
|
||||||
<span id="cb12-18"><a href="#cb12-18"></a> <span class="op">}</span></span>
|
<span id="cb12-18"><a href="#cb12-18"></a> AuxPcodeEmulator<span class="op"><</span>Expr<span class="op">></span> emulator<span class="op">)</span> <span class="op">{</span></span>
|
||||||
<span id="cb12-19"><a href="#cb12-19"></a></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="at">@Override</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 class="kw">public</span> DebuggerPcodeMachine<span class="op"><?></span> <span class="fu">create</span><span class="op">(</span>PcodeDebuggerAccess access<span class="op">)</span> <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="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-22"><a href="#cb12-22"></a> <span class="at">@Override</span></span>
|
||||||
<span id="cb12-23"><a href="#cb12-23"></a> <span class="op">}</span></span>
|
<span id="cb12-23"><a href="#cb12-23"></a> <span class="kw">public</span> PcodeUseropLibrary<span class="op"><</span>Pair<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">>></span> <span class="fu">createLocalUseropLibrary</span><span class="op">(</span></span>
|
||||||
<span id="cb12-24"><a href="#cb12-24"></a><span class="op">}</span></span></code></pre></div>
|
<span id="cb12-24"><a href="#cb12-24"></a> AuxPcodeEmulator<span class="op"><</span>Expr<span class="op">></span> emulator<span class="op">,</span> PcodeThread<span class="op"><</span>Pair<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">>></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"><</span>Pair<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">>></span> <span class="fu">createSharedState</span><span class="op">(</span></span>
|
||||||
|
<span id="cb12-30"><a href="#cb12-30"></a> AuxPcodeEmulator<span class="op"><</span>Expr<span class="op">></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"><</span>Pair<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">>></span> <span class="fu">createLocalState</span><span class="op">(</span></span>
|
||||||
|
<span id="cb12-36"><a href="#cb12-36"></a> AuxPcodeEmulator<span class="op"><</span>Expr<span class="op">></span> emulator<span class="op">,</span> PcodeThread<span class="op"><</span>Pair<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> Expr<span class="op">>></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"><</span>Pair<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">>></span> <span class="fu">createTraceSharedState</span><span class="op">(</span></span>
|
||||||
|
<span id="cb12-43"><a href="#cb12-43"></a> AuxTracePcodeEmulator<span class="op"><</span>ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">></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"><</span>Pair<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">>></span> <span class="fu">createTraceLocalState</span><span class="op">(</span></span>
|
||||||
|
<span id="cb12-50"><a href="#cb12-50"></a> AuxTracePcodeEmulator<span class="op"><</span>ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">></span> emulator<span class="op">,</span></span>
|
||||||
|
<span id="cb12-51"><a href="#cb12-51"></a> PcodeThread<span class="op"><</span>Pair<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">>></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"><</span>Pair<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">>></span> <span class="fu">createDebuggerSharedState</span><span class="op">(</span></span>
|
||||||
|
<span id="cb12-58"><a href="#cb12-58"></a> AuxDebuggerPcodeEmulator<span class="op"><</span>ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">></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"><</span>Pair<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">>></span> <span class="fu">createDebuggerLocalState</span><span class="op">(</span></span>
|
||||||
|
<span id="cb12-65"><a href="#cb12-65"></a> AuxDebuggerPcodeEmulator<span class="op"><</span>ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">></span> emulator<span class="op">,</span></span>
|
||||||
|
<span id="cb12-66"><a href="#cb12-66"></a> PcodeThread<span class="op"><</span>Pair<span class="op"><</span><span class="dt">byte</span><span class="op">[],</span> ModelingScript<span class="op">.</span><span class="fu">Expr</span><span class="op">>></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"><</span>Expr<span class="op">></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"><</span>Expr<span class="op">></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">"Expr"</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"><?></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
|
<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;
|
your factory as the current emulator factory for the whole tool;
|
||||||
however, your script-based factory will not be listed in the menus.
|
however, your script-based factory will not be listed in the menus.
|
||||||
|
|
|
@ -95,12 +95,12 @@ A user would place a breakpoint at either the call site or the call target, have
|
||||||
|
|
||||||
### Modeling by Sleigh Semantics
|
### 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.
|
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.
|
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.
|
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:
|
Alternatively, you can implement the userop using pre-compiled Sleigh code:
|
||||||
|
|
||||||
```java {.numberLines}
|
```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.
|
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.
|
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.
|
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
|
### 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.
|
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.
|
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}
|
```java {.numberLines}
|
||||||
public class InstallCustomLibraryScript extends GhidraScript implements FlatDebuggerAPI {
|
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`.
|
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.
|
**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 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.
|
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);
|
map.put(offset, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected Expr whenNull(long offset, int size) {
|
||||||
|
return new VarExpr(space, offset, size);
|
||||||
|
}
|
||||||
|
|
||||||
public Expr get(long offset, int size) {
|
public Expr get(long offset, int size) {
|
||||||
// TODO: Handle overlaps / offcut gets and sets
|
// TODO: Handle overlaps / offcut gets and sets
|
||||||
Expr expr = map.get(offset);
|
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.
|
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.
|
A write to `RAX` followed by a read from `EAX` will immediately demonstrate this issue.
|
||||||
Nevertheless, we leave those details as an exercise.
|
Nevertheless, we leave those details as an exercise.
|
||||||
|
We factor `whenNull` so that it can be overridden later.
|
||||||
|
|
||||||
The remaining parts are mostly boilerplate.
|
The remaining parts are mostly boilerplate.
|
||||||
We implement the "state piece" interface by creating another abstract class.
|
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.
|
**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.
|
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
|
## Use in Static Analysis
|
||||||
|
@ -820,7 +825,7 @@ public static class ExprTraceSpace extends ExprSpace {
|
||||||
public static class ExprTracePcodeExecutorStatePiece
|
public static class ExprTracePcodeExecutorStatePiece
|
||||||
extends AbstractExprPcodeExecutorStatePiece<ExprTraceSpace>
|
extends AbstractExprPcodeExecutorStatePiece<ExprTraceSpace>
|
||||||
implements TracePcodeExecutorStatePiece<byte[], Expr> {
|
implements TracePcodeExecutorStatePiece<byte[], Expr> {
|
||||||
public static final String NAME = "Taint";
|
public static final String NAME = "Expr";
|
||||||
|
|
||||||
protected final PcodeTraceDataAccess data;
|
protected final PcodeTraceDataAccess data;
|
||||||
protected final PcodeTracePropertyAccess<String> property;
|
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.
|
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:
|
Last, we implement the full parts factory and use it to construct and install a full `Expr`-augmented emulator factory:
|
||||||
|
|
||||||
```java {.numberLines}
|
```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 static class BytesExprDebuggerPcodeEmulator extends AuxDebuggerPcodeEmulator<Expr> {
|
||||||
public BytesExprDebuggerPcodeEmulator(PcodeDebuggerAccess access) {
|
public BytesExprDebuggerPcodeEmulator(PcodeDebuggerAccess access) {
|
||||||
super(access);
|
super(access);
|
||||||
|
@ -885,7 +969,7 @@ public static class BytesExprDebuggerPcodeEmulator extends AuxDebuggerPcodeEmula
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class BytesExprDebuggerPcodeEmulatorFactory
|
public static class BytesExprDebuggerPcodeEmulatorFactory
|
||||||
implements DebuggerPcodeEmulatorFactory {
|
extends AbstractDebuggerPcodeEmulatorFactory {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getTitle() {
|
public String getTitle() {
|
||||||
|
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 207 KiB After Width: | Height: | Size: 214 KiB |
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 34 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 190 KiB After Width: | Height: | Size: 199 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 126 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 21 KiB |
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 33 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 35 KiB |
After Width: | Height: | Size: 34 KiB |
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
@ -109,6 +109,12 @@ img {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
background: #444;
|
||||||
|
border-radius: 1pt;
|
||||||
|
padding: 1pt;
|
||||||
|
}
|
||||||
|
|
||||||
div.sourceCode {
|
div.sourceCode {
|
||||||
position: relative;
|
position: relative;
|
||||||
color: black;
|
color: black;
|
||||||
|
@ -118,6 +124,10 @@ div.sourceCode {
|
||||||
box-shadow: 0 0 5px black inset;
|
box-shadow: 0 0 5px black inset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
code.sourceCode {
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
pre > code.sourceCode > span > a:first-child::before {
|
pre > code.sourceCode > span > a:first-child::before {
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,6 +102,8 @@ GhidraClass/Debugger/images/Emulation_PcodeStepper.png||GHIDRA||||END|
|
||||||
GhidraClass/Debugger/images/Emulation_WatchesForCmdline.png||GHIDRA||||END|
|
GhidraClass/Debugger/images/Emulation_WatchesForCmdline.png||GHIDRA||||END|
|
||||||
GhidraClass/Debugger/images/Emulation_WatchesForCmdlineSet.png||GHIDRA||||END|
|
GhidraClass/Debugger/images/Emulation_WatchesForCmdlineSet.png||GHIDRA||||END|
|
||||||
GhidraClass/Debugger/images/GettingStarted_DisassemblyAfterLaunch.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/GettingStarted_ToolWSpecimen.png||GHIDRA||||END|
|
||||||
GhidraClass/Debugger/images/MemoryMap_CopyNcursesInto.png||GHIDRA||||END|
|
GhidraClass/Debugger/images/MemoryMap_CopyNcursesInto.png||GHIDRA||||END|
|
||||||
GhidraClass/Debugger/images/MemoryMap_ModulesAfterLaunch.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_StackInCallRand.png||GHIDRA||||END|
|
||||||
GhidraClass/Debugger/images/Navigation_ThreadsInCallRand.png||GHIDRA||||END|
|
GhidraClass/Debugger/images/Navigation_ThreadsInCallRand.png||GHIDRA||||END|
|
||||||
GhidraClass/Debugger/images/Navigation_TimeAfterCallSRandCallRand.png||GHIDRA||||END|
|
GhidraClass/Debugger/images/Navigation_TimeAfterCallSRandCallRand.png||GHIDRA||||END|
|
||||||
GhidraClass/Debugger/images/RemoteTargets_Gadp.png||GHIDRA||||END|
|
GhidraClass/Debugger/images/RemoteTargets_AcceptTraceRmi.png||GHIDRA||||END|
|
||||||
GhidraClass/Debugger/images/RemoteTargets_GdbOverSsh.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_BytesStackAfterCallRand.png||GHIDRA||||END|
|
||||||
GhidraClass/Debugger/images/State_ListingAfterCallRand.png||GHIDRA||||END|
|
GhidraClass/Debugger/images/State_ListingAfterCallRand.png||GHIDRA||||END|
|
||||||
GhidraClass/Debugger/images/State_ListingStackAfterCallRand.png||GHIDRA||||END|
|
GhidraClass/Debugger/images/State_ListingStackAfterCallRand.png||GHIDRA||||END|
|
||||||
|
|