GP-617: Fixing stepping. Fixes for object tree.

This commit is contained in:
d-millar 2021-01-22 17:50:10 +00:00 committed by Dan
parent 97b43a4c4e
commit 3ae09277f0
40 changed files with 773 additions and 260 deletions

View file

@ -55,7 +55,8 @@ public interface GdbManager extends AutoCloseable, GdbBreakpointInsertions {
STEP_INSTRUCTION("step-instruction"),
/** Equivalent to {@code until} in the CLI */
UNTIL("until"),
;
/** User-defined */
EXTENDED("until"),;
final String str;
@ -332,8 +333,12 @@ public interface GdbManager extends AutoCloseable, GdbBreakpointInsertions {
*
* <p>
* This waits for a prompt from GDB unless the last line printed is already a prompt. This is
* generally not necessary following normal commands, but may be necessary after interrupting a
* running inferior, or after waiting for an inferior to reach a stopped state.
* generally not necessary following normal commands. Note that depending on circumstances and
* GDB version, the MI console may produce a prompt before it produces all of the events
* associated with an interrupt. If the <em>last</em> line is not currently a prompt, then the
* returned future will not be complete. In other words, this is not a reliable way of verifying
* GDB is waiting for a command. It's primary use is confirming that GDB has started
* successfully and is awaiting its first command.
*
* @return a future which completes when GDB presents a prompt
*/
@ -393,7 +398,10 @@ public interface GdbManager extends AutoCloseable, GdbBreakpointInsertions {
* <p>
* The output will not be printed to the CLI console. To ensure a certain thread or inferior has
* focus for a console command, see {@link GdbThread#consoleCapture(String)} and
* {@link GdbInferior#consoleCapture(String)}.
* {@link GdbInferior#consoleCapture(String)}. The caller should take care that other commands
* or events are not actively producing console output. If they are, those lines may be captured
* though they are unrelated to the given command. Generally, this can be achieved by assuring
* that GDB is in the {@link GdbState#STOPPED} state using {@link #waitForState(GdbState)}.
*
* @param command the command to execute
* @return a future that completes with the captured output when GDB has executed the command
@ -404,14 +412,14 @@ public interface GdbManager extends AutoCloseable, GdbBreakpointInsertions {
* Interrupt the GDB session
*
* <p>
* This is equivalent to typing Ctrl-C in the CLI. This typically results in the target being
* interrupted, either because GDB and the target have the same controlling TTY, or because GDB
* will "forward" the interrupt to the target.
*
* <p>
* For whatever reason, interrupting the session does not always reliably interrupt the target.
* The manager will send Ctrl-C to the pseudo-terminal up to three times, waiting about 10ms
* between each, until GDB issues a stopped event and presents a new prompt.
* The manager may employ a variety of mechanisms depending on the current configuration. If
* multiple interpreters are available, it will issue an "interrupt" command on whichever
* interpreter it believes is responsive -- usually the opposite of the one issuing the last
* run, continue, step, etc. command. Otherwise, it sends Ctrl-C to GDB's TTY, which
* unfortunately is notoriously unreliable. The manager will send Ctrl-C to the TTY up to three
* times, waiting about 10ms between each, until GDB issues a stopped event and presents a new
* prompt. If that fails, it is up to the user to find an alternative means to interrupt the
* target, e.g., issuing {@code kill [pid]} from the a terminal on the target's host.
*
* @return a future that completes when GDB has entered the stopped state
*/

View file

@ -19,7 +19,6 @@ import agent.gdb.manager.GdbInferior;
import agent.gdb.manager.evt.*;
import agent.gdb.manager.impl.*;
import agent.gdb.manager.impl.GdbManagerImpl.Interpreter;
import ghidra.util.Msg;
/**
* Implementation of {@link GdbInferior#cont()}
@ -29,56 +28,6 @@ public class GdbContinueCommand extends AbstractGdbCommandWithThreadId<Void> {
super(manager, threadId);
}
@Override
public String encode(String threadPart) {
switch (getInterpreter()) {
case CLI:
return "continue";
case MI2:
return "-exec-continue" + threadPart;
default:
throw new AssertionError();
}
}
@Override
public boolean handle(GdbEvent<?> evt, GdbPendingCommand<?> pending) {
if (evt instanceof AbstractGdbCompletedCommandEvent) {
if (!pending.hasAny(AbstractGdbCompletedCommandEvent.class)) {
pending.claim(evt);
}
return evt instanceof GdbCommandErrorEvent || pending.hasAny(GdbRunningEvent.class);
}
else if (evt instanceof GdbRunningEvent) {
// Event happens no matter which interpreter received the command
pending.claim(evt);
return pending.hasAny(AbstractGdbCompletedCommandEvent.class);
}
else if (evt instanceof GdbConsoleOutputEvent) {
Msg.debug(this, "EXAMINING: " + evt);
if (pending.hasAny(GdbCommandRunningEvent.class)) {
// Only attempt to process/claim the first line after our command
return false;
}
GdbConsoleOutputEvent out = (GdbConsoleOutputEvent) evt;
if (out.getOutput().trim().equals("continue")) {
// Echoed back my command
return false;
}
pending.claim(evt);
if (out.getOutput().trim().startsWith("Continuing") &&
!pending.hasAny(GdbCommandRunningEvent.class)) {
pending.claim(new GdbCommandRunningEvent());
return pending.hasAny(GdbRunningEvent.class);
}
else {
pending.claim(GdbCommandErrorEvent.fromMessage(out.getOutput()));
return true;
}
}
return false;
}
@Override
public Interpreter getInterpreter() {
if (manager.hasCli()) {
@ -87,6 +36,38 @@ public class GdbContinueCommand extends AbstractGdbCommandWithThreadId<Void> {
return Interpreter.MI2;
}
@Override
public String encode(String threadPart) {
switch (getInterpreter()) {
case CLI:
// The significance is the Pty, not so much the actual command
// Using MI2 simplifies event processing (no console output parsing)
return "interpreter-exec mi2 \"-exec-continue" + threadPart + "\"";
case MI2:
return "-exec-continue" + threadPart;
default:
throw new AssertionError();
}
}
@Override
public boolean handle(GdbEvent<?> evt, GdbPendingCommand<?> pending) {
if (evt instanceof GdbCommandRunningEvent) {
pending.claim(evt);
return pending.hasAny(GdbRunningEvent.class);
}
else if (evt instanceof AbstractGdbCompletedCommandEvent) {
pending.claim(evt);
return true; // Not the expected Completed event
}
else if (evt instanceof GdbRunningEvent) {
// Event happens no matter which interpreter received the command
pending.claim(evt);
return pending.hasAny(GdbCommandRunningEvent.class);
}
return false;
}
@Override
public Void complete(GdbPendingCommand<?> pending) {
pending.checkCompletion(GdbCommandRunningEvent.class);

View file

@ -33,7 +33,7 @@ public class GdbGetThreadInfoCommand extends AbstractGdbCommandWithThreadId<GdbT
@Override
protected String encode(String threadPart) {
return "-thread-info" + threadPart;
return "-thread-info " + threadId; // Note the trailing space
}
@Override

View file

@ -67,7 +67,8 @@ public class GdbInterruptCommand extends AbstractGdbCommand<Void> {
@Override
public Void complete(GdbPendingCommand<?> pending) {
pending.findSingleOf(GdbStoppedEvent.class);
// When using -exec-interrupt, ^done will come before *stopped
//pending.findSingleOf(GdbStoppedEvent.class);
return null;
}

View file

@ -19,6 +19,7 @@ import agent.gdb.manager.GdbInferior;
import agent.gdb.manager.GdbThread;
import agent.gdb.manager.evt.*;
import agent.gdb.manager.impl.*;
import agent.gdb.manager.impl.GdbManagerImpl.Interpreter;
/**
* Implementation of {@link GdbInferior#run()}
@ -29,9 +30,26 @@ public class GdbRunCommand extends AbstractGdbCommand<GdbThread> {
super(manager);
}
@Override
public Interpreter getInterpreter() {
if (manager.hasCli()) {
return Interpreter.CLI;
}
return Interpreter.MI2;
}
@Override
public String encode() {
return "-exec-run";
switch (getInterpreter()) {
case CLI:
// The significance is the Pty, not so much the actual command
// Using MI2 simplifies event processing (no console output parsing)
return "interpreter-exec mi2 \"-exec-run\"";
case MI2:
return "-exec-run";
default:
throw new AssertionError();
}
}
@Override
@ -40,7 +58,7 @@ public class GdbRunCommand extends AbstractGdbCommand<GdbThread> {
pending.claim(evt);
return pending.hasAny(GdbRunningEvent.class);
}
if (evt instanceof AbstractGdbCompletedCommandEvent) {
else if (evt instanceof AbstractGdbCompletedCommandEvent) {
pending.claim(evt);
return true; // Not the expected Completed event
}

View file

@ -19,6 +19,7 @@ import agent.gdb.manager.GdbManager.ExecSuffix;
import agent.gdb.manager.GdbThread;
import agent.gdb.manager.evt.*;
import agent.gdb.manager.impl.*;
import agent.gdb.manager.impl.GdbManagerImpl.Interpreter;
/**
* Implementation of {@link GdbThread#stepInstruction()}
@ -31,9 +32,27 @@ public class GdbStepCommand extends AbstractGdbCommandWithThreadId<Void> {
this.suffix = suffix;
}
@Override
public Interpreter getInterpreter() {
if (manager.hasCli()) {
return Interpreter.CLI;
}
return Interpreter.MI2;
}
@Override
protected String encode(String threadPart) {
return "-exec-" + suffix + threadPart;
String mi2Cmd = "-exec-" + suffix + threadPart;
switch (getInterpreter()) {
case CLI:
// The significance is the Pty, not so much the actual command
// Using MI2 simplifies event processing (no console output parsing)
return "interpreter-exec mi2 \"" + mi2Cmd + "\"";
case MI2:
return mi2Cmd;
default:
throw new AssertionError();
}
}
@Override

View file

@ -33,11 +33,12 @@ import ghidra.dbg.util.PathUtils;
import ghidra.lifecycle.Internal;
import ghidra.util.Msg;
@TargetObjectSchemaInfo(name = "Inferior", elements = {
@TargetElementType(type = Void.class)
}, attributes = {
@TargetAttributeType(type = Void.class)
})
@TargetObjectSchemaInfo(
name = "Inferior",
elements = {
@TargetElementType(type = Void.class) },
attributes = {
@TargetAttributeType(type = Void.class) })
public class GdbModelTargetInferior
extends DefaultTargetObject<TargetObject, GdbModelTargetInferiorContainer> implements //
TargetProcess<GdbModelTargetInferior>, //
@ -92,20 +93,19 @@ public class GdbModelTargetInferior
this.registers = new GdbModelTargetRegisterContainer(this);
this.threads = new GdbModelTargetThreadContainer(this);
changeAttributes(List.of(),
List.of(
environment,
memory,
modules,
registers,
threads),
Map.of(
STATE_ATTRIBUTE_NAME, TargetExecutionState.INACTIVE,
DISPLAY_ATTRIBUTE_NAME, updateDisplay(),
TargetMethod.PARAMETERS_ATTRIBUTE_NAME, TargetCmdLineLauncher.PARAMETERS,
UPDATE_MODE_ATTRIBUTE_NAME, TargetUpdateMode.FIXED,
SUPPORTED_ATTACH_KINDS_ATTRIBUTE_NAME, SUPPORTED_KINDS,
SUPPORTED_STEP_KINDS_ATTRIBUTE_NAME, GdbModelTargetThread.SUPPORTED_KINDS),
changeAttributes(List.of(), //
List.of( //
environment, //
memory, //
modules, //
registers, //
threads), //
Map.of(STATE_ATTRIBUTE_NAME, TargetExecutionState.INACTIVE, //
DISPLAY_ATTRIBUTE_NAME, updateDisplay(), //
TargetMethod.PARAMETERS_ATTRIBUTE_NAME, TargetCmdLineLauncher.PARAMETERS, //
UPDATE_MODE_ATTRIBUTE_NAME, TargetUpdateMode.FIXED, //
SUPPORTED_ATTACH_KINDS_ATTRIBUTE_NAME, SUPPORTED_KINDS, //
SUPPORTED_STEP_KINDS_ATTRIBUTE_NAME, GdbModelTargetThread.SUPPORTED_KINDS), //
"Initialized");
}
@ -160,6 +160,8 @@ public class GdbModelTargetInferior
return ExecSuffix.RETURN;
case UNTIL:
return ExecSuffix.UNTIL;
case EXTENDED:
return ExecSuffix.EXTENDED;
default:
throw new AssertionError();
}

View file

@ -26,11 +26,12 @@ import ghidra.dbg.target.schema.*;
import ghidra.dbg.util.CollectionUtils.Delta;
import ghidra.dbg.util.PathUtils;
@TargetObjectSchemaInfo(name = "RegisterValue", elements = {
@TargetElementType(type = Void.class)
}, attributes = {
@TargetAttributeType(type = Void.class)
})
@TargetObjectSchemaInfo(
name = "RegisterValue",
elements = {
@TargetElementType(type = Void.class) },
attributes = {
@TargetAttributeType(type = Void.class) })
public class GdbModelTargetStackFrameRegister
extends DefaultTargetObject<TargetObject, GdbModelTargetStackFrameRegisterContainer> {
@ -57,7 +58,8 @@ public class GdbModelTargetStackFrameRegister
changeAttributes(List.of(), Map.of( //
DISPLAY_ATTRIBUTE_NAME, getName(), //
UPDATE_MODE_ATTRIBUTE_NAME, TargetUpdateMode.FIXED //
UPDATE_MODE_ATTRIBUTE_NAME, TargetUpdateMode.FIXED, //
MODIFIED_ATTRIBUTE_NAME, false //
), "Initialized");
}
@ -72,11 +74,11 @@ public class GdbModelTargetStackFrameRegister
boolean modified = (bigNewVal.longValue() != 0 && value.equals(oldval));
String newval = getName() + " : " + value;
Delta<?, ?> delta = changeAttributes(List.of(), Map.of(
VALUE_ATTRIBUTE_NAME, value,
DISPLAY_ATTRIBUTE_NAME, newval,
MODIFIED_ATTRIBUTE_NAME, modified),
"Value Updated");
Delta<?, ?> delta = changeAttributes(List.of(), Map.of( //
VALUE_ATTRIBUTE_NAME, value, //
DISPLAY_ATTRIBUTE_NAME, newval, //
MODIFIED_ATTRIBUTE_NAME, modified //
), "Value Updated");
if (delta.added.containsKey(DISPLAY_ATTRIBUTE_NAME)) {
listeners.fire.displayChanged(this, newval);
}

View file

@ -32,18 +32,25 @@ import ghidra.dbg.util.PathUtils;
import ghidra.lifecycle.Internal;
import ghidra.util.Msg;
@TargetObjectSchemaInfo(name = "Thread", elements = {
@TargetElementType(type = Void.class)
}, attributes = {
@TargetAttributeType(type = Void.class)
})
@TargetObjectSchemaInfo(
name = "Thread",
elements = {
@TargetElementType(type = Void.class) },
attributes = {
@TargetAttributeType(type = Void.class) })
public class GdbModelTargetThread
extends DefaultTargetObject<TargetObject, GdbModelTargetThreadContainer> implements
TargetThread<GdbModelTargetThread>, TargetExecutionStateful<GdbModelTargetThread>,
TargetSteppable<GdbModelTargetThread>, GdbModelSelectableObject {
protected static final TargetStepKindSet SUPPORTED_KINDS = TargetStepKindSet.of( //
TargetStepKind.ADVANCE, TargetStepKind.FINISH, TargetStepKind.LINE, TargetStepKind.OVER,
TargetStepKind.OVER_LINE, TargetStepKind.RETURN, TargetStepKind.UNTIL);
TargetStepKind.ADVANCE, //
TargetStepKind.FINISH, //
TargetStepKind.LINE, //
TargetStepKind.OVER, //
TargetStepKind.OVER_LINE, //
TargetStepKind.RETURN, //
TargetStepKind.UNTIL, //
TargetStepKind.EXTENDED);
protected static String indexThread(int threadId) {
return PathUtils.makeIndex(threadId);
@ -75,16 +82,14 @@ public class GdbModelTargetThread
this.stack = new GdbModelTargetStack(this, inferior);
changeAttributes(List.of(),
List.of(
stack),
Map.of(
STATE_ATTRIBUTE_NAME, convertState(thread.getState()),
SUPPORTED_STEP_KINDS_ATTRIBUTE_NAME, SUPPORTED_KINDS,
DISPLAY_ATTRIBUTE_NAME, display = computeDisplay(),
UPDATE_MODE_ATTRIBUTE_NAME, TargetUpdateMode.FIXED,
stack.getName(), stack),
"Initialized");
changeAttributes(List.of(), List.of(stack), Map.of( //
STATE_ATTRIBUTE_NAME, convertState(thread.getState()), //
SUPPORTED_STEP_KINDS_ATTRIBUTE_NAME, SUPPORTED_KINDS, //
SHORT_DISPLAY_ATTRIBUTE_NAME, shortDisplay = computeShortDisplay(), //
DISPLAY_ATTRIBUTE_NAME, display = computeDisplay(), //
UPDATE_MODE_ATTRIBUTE_NAME, TargetUpdateMode.FIXED, //
stack.getName(), stack //
), "Initialized");
updateInfo().exceptionally(ex -> {
Msg.error(this, "Could not initialize thread info");
@ -110,11 +115,9 @@ public class GdbModelTargetThread
protected String computeDisplay() {
StringBuilder sb = new StringBuilder();
sb.append(shortDisplay);
if (info != null) {
sb.append(shortDisplay);
sb.append(" ");
//sb.append(info.getTargetId());
//sb.append(" ");
sb.append(info.getInferiorName());
sb.append(" ");
sb.append(info.getState());
@ -127,22 +130,23 @@ public class GdbModelTargetThread
sb.append(" in ");
sb.append(frame.getFunc());
}
return sb.toString();
}
sb.append(thread.getId());
sb.append(" ");
sb.append(stack.inferior.inferior.getDescriptor());
sb.append(" ");
sb.append(stack.inferior.inferior.getExecutable());
GdbModelTargetStackFrame top = stack.framesByLevel.get(0);
if (top == null) {
return sb.toString();
else {
sb.append(" ");
String executableName = stack.inferior.inferior.getExecutable();
if (executableName != null) {
sb.append(executableName);
}
GdbModelTargetStackFrame top = stack.framesByLevel.get(0);
if (top == null) {
return sb.toString();
}
sb.append(" 0x");
sb.append(top.frame.getAddress().toString(16));
sb.append(" in ");
sb.append(top.frame.getFunction());
sb.append(" ()");
}
sb.append(" 0x");
sb.append(top.frame.getAddress().toString(16));
sb.append(" in ");
sb.append(top.frame.getFunction());
sb.append(" ()");
return sb.toString();
}
@ -151,10 +155,15 @@ public class GdbModelTargetThread
sb.append("[");
sb.append(inferior.getId());
sb.append(".");
sb.append(info.getId());
if (info.getTid() != null) {
sb.append(":");
sb.append(info.getTid());
if (info == null) {
sb.append(thread.getId());
}
else {
sb.append(info.getId());
if (info.getTid() != null) {
sb.append(":");
sb.append(info.getTid());
}
}
sb.append("]");
return sb.toString();
@ -205,6 +214,8 @@ public class GdbModelTargetThread
return ExecSuffix.RETURN;
case UNTIL:
return ExecSuffix.UNTIL;
case EXTENDED:
return ExecSuffix.EXTENDED;
default:
throw new AssertionError();
}

View file

@ -25,6 +25,7 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.*;
import java.util.concurrent.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import org.junit.*;
@ -183,6 +184,30 @@ public abstract class AbstractGdbManagerTest extends AbstractGhidraHeadlessInteg
}
}
public static class LibraryWaiter extends CompletableFuture<String>
implements GdbEventsListenerAdapter {
protected final Predicate<String> predicate;
public LibraryWaiter(Predicate<String> predicate) {
this.predicate = predicate;
}
@Override
public void libraryLoaded(GdbInferior inferior, String name, GdbCause cause) {
if (predicate.test(name)) {
complete(name);
}
}
}
public void assertResponsive(GdbManager mgr) throws Throwable {
//Msg.debug(this, "Waiting for prompt");
//waitOn(mgr.waitForPrompt());
Msg.debug(this, "Testing echo test");
String out = waitOn(mgr.consoleCapture("echo test"));
assertEquals("test", out.trim());
}
@Test
public void testStartInterrupt() throws Throwable {
assumeFalse("I know no way to get this to pass with these conditions",
@ -194,15 +219,8 @@ public abstract class AbstractGdbManagerTest extends AbstractGhidraHeadlessInteg
* and the time its signal handlers are installed. It seems waiting for libc to load
* guarantees that GDB is ready to interrupt the process.
*/
CompletableFuture<Void> libcLoaded = new CompletableFuture<>();
mgr.addEventsListener(new GdbEventsListenerAdapter() {
@Override
public void libraryLoaded(GdbInferior inferior, String name, GdbCause cause) {
if (name.contains("libc")) {
libcLoaded.complete(null);
}
}
});
LibraryWaiter libcLoaded = new LibraryWaiter(name -> name.contains("libc"));
mgr.addEventsListener(libcLoaded);
waitOn(startManager(mgr));
waitOn(mgr.currentInferior().fileExecAndSymbols("/usr/bin/sleep"));
waitOn(mgr.currentInferior().console("set args 3"));
@ -211,13 +229,40 @@ public abstract class AbstractGdbManagerTest extends AbstractGhidraHeadlessInteg
Thread.sleep(100); // TODO: Why?
Msg.debug(this, "Interrupting");
waitOn(mgr.interrupt());
Msg.debug(this, "Waiting for prompt");
waitOn(mgr.waitForPrompt());
Msg.debug(this, "Testing echo test");
String out = waitOn(mgr.consoleCapture("echo test"));
// Check that we have a responsive console, now.
// Otherwise, the interrupt failed
assertEquals("test", out.trim());
waitOn(mgr.waitForState(GdbState.STOPPED));
assertResponsive(mgr);
}
}
@Test
public void testStepSyscallInterrupt() throws Throwable {
assumeFalse("I know no way to get this to pass with these conditions",
this instanceof JoinedGdbManagerTest);
// Repeat the start-interrupt sequence, then verify we're preparing to step a syscall
try (GdbManager mgr = GdbManager.newInstance()) {
LibraryWaiter libcLoaded = new LibraryWaiter(name -> name.contains("libc"));
mgr.addEventsListener(libcLoaded);
waitOn(startManager(mgr));
waitOn(mgr.currentInferior().fileExecAndSymbols("/usr/bin/sleep"));
waitOn(mgr.currentInferior().console("set args 5"));
waitOn(mgr.currentInferior().run());
waitOn(libcLoaded);
Thread.sleep(100); // TODO: Why?
Msg.debug(this, "Interrupting");
waitOn(mgr.interrupt());
Msg.debug(this, "Verifying at syscall");
String out = waitOn(mgr.consoleCapture("x/1i $pc-2"));
// TODO: This is x86-specific
assertTrue("Didn't stop at syscall", out.contains("syscall"));
// Now the real test
waitOn(mgr.currentInferior().step(ExecSuffix.STEP_INSTRUCTION));
CompletableFuture<Void> stopped = mgr.waitForState(GdbState.STOPPED);
Thread.sleep(100); // NB: Not exactly reliable, but verify we're waiting
assertFalse(stopped.isDone());
waitOn(mgr.interrupt());
waitOn(stopped);
assertResponsive(mgr);
}
}
@ -229,7 +274,7 @@ public abstract class AbstractGdbManagerTest extends AbstractGhidraHeadlessInteg
waitOn(mgr.insertBreakpoint("main"));
waitOn(mgr.currentInferior().run());
waitOn(mgr.waitForState(GdbState.STOPPED));
waitOn(mgr.waitForPrompt());
//waitOn(mgr.waitForPrompt());
waitOn(mgr.currentInferior().setVar("$rax=", "0xdeadbeef")); // Corrupts it
String val = waitOn(mgr.currentInferior().evaluate("$rax+1"));
assertEquals(0xdeadbeef + 1, Integer.parseUnsignedInt(val));
@ -270,7 +315,7 @@ public abstract class AbstractGdbManagerTest extends AbstractGhidraHeadlessInteg
waitOn(mgr.insertBreakpoint("main"));
GdbThread thread = waitOn(mgr.currentInferior().run());
waitOn(mgr.waitForState(GdbState.STOPPED));
waitOn(mgr.waitForPrompt());
//waitOn(mgr.waitForPrompt());
GdbRegisterSet regs = waitOn(thread.listRegisters());
Set<GdbRegister> toRead = new HashSet<>();
toRead.add(regs.get("eflags"));
@ -306,7 +351,7 @@ public abstract class AbstractGdbManagerTest extends AbstractGhidraHeadlessInteg
waitOn(mgr.insertBreakpoint("main"));
GdbThread thread = waitOn(mgr.currentInferior().run());
waitOn(mgr.waitForState(GdbState.STOPPED));
waitOn(mgr.waitForPrompt());
//waitOn(mgr.waitForPrompt());
String str = waitOn(mgr.currentInferior().evaluate("(long)main"));
long addr = Long.parseLong(str);
ByteBuffer buf = ByteBuffer.allocate(1024);
@ -336,7 +381,7 @@ public abstract class AbstractGdbManagerTest extends AbstractGhidraHeadlessInteg
waitOn(mgr.insertBreakpoint("main"));
GdbThread thread = waitOn(mgr.currentInferior().run());
waitOn(mgr.waitForState(GdbState.STOPPED));
waitOn(mgr.waitForPrompt());
//waitOn(mgr.waitForPrompt());
waitOn(thread.cont());
waitOn(mgr.waitForState(GdbState.STOPPED));
assertEquals(0L, (long) mgr.currentInferior().getExitCode());
@ -351,7 +396,7 @@ public abstract class AbstractGdbManagerTest extends AbstractGhidraHeadlessInteg
waitOn(mgr.insertBreakpoint("main"));
GdbThread thread = waitOn(mgr.currentInferior().run());
waitOn(mgr.waitForState(GdbState.STOPPED));
waitOn(mgr.waitForPrompt());
//waitOn(mgr.waitForPrompt());
waitOn(thread.step(ExecSuffix.NEXT_INSTRUCTION));
waitOn(mgr.waitForState(GdbState.STOPPED));
assertNull(mgr.currentInferior().getExitCode());
@ -366,7 +411,7 @@ public abstract class AbstractGdbManagerTest extends AbstractGhidraHeadlessInteg
waitOn(mgr.insertBreakpoint("main"));
GdbThread thread = waitOn(mgr.currentInferior().run());
waitOn(mgr.waitForState(GdbState.STOPPED));
waitOn(mgr.waitForPrompt());
//waitOn(mgr.waitForPrompt());
waitOn(thread.select());
}
}
@ -379,7 +424,7 @@ public abstract class AbstractGdbManagerTest extends AbstractGhidraHeadlessInteg
waitOn(mgr.insertBreakpoint("main"));
GdbThread thread = waitOn(mgr.currentInferior().run());
waitOn(mgr.waitForState(GdbState.STOPPED));
waitOn(mgr.waitForPrompt());
//waitOn(mgr.waitForPrompt());
waitOn(mgr.insertBreakpoint("write"));
waitOn(mgr.currentInferior().cont());
waitOn(mgr.waitForState(GdbState.STOPPED));