pub enum JdwpError {
Io(Error),
Protocol(String),
InvalidHandshake,
JdwpErrorCode(u16, String),
ConnectionClosed(String),
NotJdwpFramed(String),
ReplyTimeout(u64),
InvokeTimeout(u64),
ReadOnly(String),
}Variants§
Io(Error)
Protocol(String)
InvalidHandshake
JdwpErrorCode(u16, String)
ConnectionClosed(String)
The connection to the debuggee ended, carrying why it ended.
The payload is the point. Every one of these was once reported as Reply channel closed, a
message produced by four different worlds — a dead socket, a dropped event consumer, a lapsed
reply, and a loop that had already gone — none of which the reader could tell apart. The event
loop is the only thing that knows which, and it used to log the cause at a level nobody enables
and then throw the value away, so a debuggee that died mid-question was indistinguishable from a
bug in this crate. See crate::eventloop.
NotJdwpFramed(String)
The bytes where a JDWP packet header should be are not a JDWP packet header (TEST-24, #65).
Its own variant because the remedy is different from every other protocol failure. A
Protocol error means we mis-read something the debuggee legitimately sent; this
means the stream itself is not ours to parse — a peer that is not a JDWP agent, a socket carrying
someone else’s traffic, or a stream that has lost packet alignment. Nothing in the command is
wrong, so retrying the command is pointless, and the session cannot be salvaged by reading on.
It exists because the honest version of this was being reported as its own opposite. A header whose
length field reads 1701737519 was announced as Packet too large: 1701737519 bytes — a sentence
that sends the reader looking for an enormous reply, when those four bytes are the ASCII text
ent/ and no large packet was ever involved. The payload carries the bytes so the speaker can be
identified rather than guessed at.
ReplyTimeout(u64)
A command was sent, the connection stayed up, and no reply arrived within the budget.
Distinct from ConnectionClosed because the remedy differs: the socket
is still there, so the session is worth keeping and the question is what failed. Distinct from
InvokeTimeout because nothing was being executed in the debuggee — this
is the JVM not answering a question it should have answered.
InvokeTimeout(u64)
A debuggee invocation did not return within its budget.
Distinct from a lost reply on purpose. INVOKE_SINGLE_THREADED runs only the target thread, so a
method needing a monitor held by one of the other (still suspended) threads cannot finish — the
classic debugger-invocation deadlock. That is not a protocol failure and not something the caller
did wrong, and it must be reported as itself rather than folded into a generic error, because the
right response is different: render shallowly and move on.
“Render shallowly and move on” is what WE do, and the message now says what the DEBUGGEE does
(DUMP-8, #123), because the two had been allowed to sound like the same thing. Measured on Temurin
11.0.32 and 21.0.12 against a lock held 3000 ms past a 2000 ms budget: the call completes when the
lock is finally released and the JVM re-suspends the thread at that moment — 1.2 s after this
side had given up, resumed the thread and moved on. From then on the thread is suspended for good.
Nothing here clears it: the watchdog resumes a suspended VM, and the VM is running. So the one
remedy is a caller-issued debug.continue (which decrements every thread) or debug.resume_thread,
and a message that did not name it left the reader believing the cost was the two seconds.
ReadOnly(String)
The connection is in read-only mode and something tried to execute code in the debuggee.
Enforced at the point of invocation rather than by inspecting expressions up in the MCP layer,
because invocation is reached from many directions — a toString() render, a List.get
subscript, valueOf boxing, a breakpoint condition — and a text-level guard misses whichever
one nobody thought of.
Trait Implementations§
Source§impl Error for JdwpError
impl Error for JdwpError
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()