protected ReplyDisassemble handleDisassemble(RequestDisassemble req) {
		OpenTrace open = requireOpenTrace(req.getOid());
		long snap = req.getSnap().getSnap();

		// Want addresses satisfying {@code known | (readOnly & everKnown)}
		TraceMemoryManager memoryManager = open.trace.getMemoryManager();
		AddressSetView readOnly =
			memoryManager.getRegionsAddressSetWith(snap, r -> !r.isWrite(snap));
		AddressSetView everKnown = memoryManager.getAddressesWithState(Lifespan.since(snap),
			s -> s == TraceMemoryState.KNOWN);
		AddressSetView roEverKnown = new IntersectionAddressSetView(readOnly, everKnown);
		AddressSetView known =
			memoryManager.getAddressesWithState(snap, s -> s == TraceMemoryState.KNOWN);
		AddressSetView disassemblable = new AddressSet(new UnionAddressSetView(known, roEverKnown));

		Address start = open.toAddress(req.getStart(), true);
		TracePlatform host = open.trace.getPlatformManager().getHostPlatform();

		TraceDisassembleCommand dis = new TraceDisassembleCommand(host, start, disassemblable);
		dis.setInitialContext(DebuggerDisassemblerPlugin.deriveAlternativeDefaultContext(
			host.getLanguage(), host.getLanguage().getLanguageID(), start));

		try (CloseableTaskMonitor monitor = plugin.createMonitor()) {
			dis.applyTo(open.trace.getFixedProgramView(snap), monitor);
		}

		AddressSetView result = dis.getDisassembledAddressSet();
		return ReplyDisassemble.newBuilder()
				.setLength(result == null ? 0 : result.getNumAddresses())
				.build();
	}
The likely cause of this failing is that the remote end has closed the socket.
However, we don't return, because there may be commands still in the queue, and
we should process them until we reach the end of input. This will ensure clients
that brazenly send a bunch of commands and then disconnect before receiving the
replies will have their commands processed, even if unsuccessfully.
Ghidra/Debug/Debugger-rmi-trace/src/main/java/ghidra/app/plugin/core/debug/service/tracermi/TraceRmiHandler.java