35using std::string_view;
40 : motherBoard(motherBoard_)
41 , cmd(motherBoard.getCommandController(),
42 motherBoard.getStateChangeDistributor(),
43 motherBoard.getScheduler())
50 assert(debuggables.empty());
55 assert(!debuggables.contains(name));
56 debuggables.emplace_noDuplicateCheck(std::move(name), &debuggable);
61 assert(debuggables.contains(name));
62 assert(debuggables[name] == &debuggable); (void)debuggable;
63 debuggables.erase(name);
68 auto* v =
lookup(debuggables, name);
69 return v ? *v :
nullptr;
72Debuggable& Debugger::getDebuggable(string_view name)
83 assert(!probes.contains(probe.
getName()));
84 probes.insert_noDuplicateCheck(&probe);
89 assert(probes.contains(probe.
getName()));
95 auto it = probes.find(name);
96 return (it != std::end(probes)) ? *it :
nullptr;
99ProbeBase& Debugger::getProbe(string_view name)
108std::string Debugger::insertProbeBreakPoint(
109 TclObject command, TclObject condition,
110 ProbeBase& probe,
bool once,
unsigned newId )
112 auto bp = std::make_unique<ProbeBreakPoint>(
113 std::move(command), std::move(condition), *
this, probe, once, newId);
114 auto result = bp->getIdStr();
116 probeBreakPoints.push_back(std::move(bp));
126 it != std::end(probeBreakPoints)) {
133 throw CommandException(
"No such breakpoint: ", name);
136 auto it =
ranges::find(probeBreakPoints, name, [](
auto& bp) {
137 return bp->getProbe().getName();
139 if (it == std::end(probeBreakPoints)) {
140 throw CommandException(
141 "No (unconditional) breakpoint for probe: ", name);
154 [](
auto& v) {
return v.get(); }));
161 assert(cpuInterface.getWatchPoints().empty());
163 cpuInterface.setWatchPoint(std::make_shared<WatchPoint>(
168 assert(probeBreakPoints.empty());
169 for (
const auto& bp : other.probeBreakPoints) {
171 insertProbeBreakPoint(bp->getCommand(),
173 *probe, bp->onlyOnce(),
191 unsigned addr = token.
getInt(interp);
192 if (addr >= 0x10000) {
195 return narrow_cast<word>(addr);
198Debugger::Cmd::Cmd(CommandController& commandController_,
199 StateChangeDistributor& stateChangeDistributor_,
200 Scheduler& scheduler_)
201 : RecordedCommand(commandController_, stateChangeDistributor_,
206bool Debugger::Cmd::needRecord(std::span<const TclObject> tokens)
const
212 if (tokens.size() < 2)
return false;
213 return tokens[1].getString() ==
one_of(
"write",
"write_block");
216void Debugger::Cmd::execute(
217 std::span<const TclObject> tokens, TclObject& result, EmuTime::param time)
219 checkNumArgs(tokens, AtLeast{2},
"subcommand ?arg ...?");
220 executeSubCommand(tokens[1].getString(),
221 "read", [&]{ read(tokens, result); },
222 "read_block", [&]{ readBlock(tokens, result); },
223 "write", [&]{ write(tokens, result); },
224 "write_block", [&]{ writeBlock(tokens, result); },
225 "size", [&]{
size(tokens, result); },
226 "desc", [&]{ desc(tokens, result); },
227 "list", [&]{ list(result); },
228 "step", [&]{ debugger().motherBoard.getCPUInterface().doStep(); },
229 "cont", [&]{ debugger().motherBoard.getCPUInterface().doContinue(); },
230 "disasm", [&]{ disasm(tokens, result, time); },
231 "disasm_blob", [&]{ disasmBlob(tokens, result); },
232 "break", [&]{ debugger().motherBoard.getCPUInterface().doBreak(); },
234 "breakpoint", [&]{ breakPoint(tokens, result); },
235 "set_bp", [&]{ setBreakPoint(tokens, result); },
236 "remove_bp", [&]{ removeBreakPoint(tokens, result); },
237 "list_bp", [&]{ listBreakPoints(tokens, result); },
238 "watchpoint", [&]{ watchPoint(tokens, result); },
239 "set_watchpoint", [&]{ setWatchPoint(tokens, result); },
240 "remove_watchpoint", [&]{ removeWatchPoint(tokens, result); },
241 "list_watchpoints", [&]{ listWatchPoints(tokens, result); },
242 "condition", [&]{ condition(tokens, result); },
243 "set_condition", [&]{ setCondition(tokens, result); },
244 "remove_condition", [&]{ removeCondition(tokens, result); },
245 "list_conditions", [&]{ listConditions(tokens, result); },
246 "probe", [&]{ probe(tokens, result); },
247 "symbols", [&]{ symbols(tokens, result); });
250void Debugger::Cmd::list(TclObject& result)
252 result.addListElements(
view::keys(debugger().debuggables));
255void Debugger::Cmd::desc(std::span<const TclObject> tokens, TclObject& result)
257 checkNumArgs(tokens, 3,
"debuggable");
258 const Debuggable& device = debugger().getDebuggable(tokens[2].getString());
259 result = device.getDescription();
262void Debugger::Cmd::size(std::span<const TclObject> tokens, TclObject& result)
264 checkNumArgs(tokens, 3,
"debuggable");
265 const Debuggable& device = debugger().getDebuggable(tokens[2].getString());
266 result = device.getSize();
269void Debugger::Cmd::read(std::span<const TclObject> tokens, TclObject& result)
271 checkNumArgs(tokens, 4, Prefix{2},
"debuggable address");
272 Debuggable& device = debugger().getDebuggable(tokens[2].getString());
273 unsigned addr = tokens[3].getInt(getInterpreter());
274 if (addr >= device.getSize()) {
275 throw CommandException(
"Invalid address");
277 result = device.read(addr);
280void Debugger::Cmd::readBlock(std::span<const TclObject> tokens, TclObject& result)
282 checkNumArgs(tokens, 5, Prefix{2},
"debuggable address size");
283 auto& interp = getInterpreter();
284 Debuggable& device = debugger().getDebuggable(tokens[2].getString());
285 unsigned devSize = device.getSize();
286 unsigned addr = tokens[3].getInt(interp);
287 if (addr >= devSize) {
288 throw CommandException(
"Invalid address");
290 unsigned num = tokens[4].getInt(interp);
291 if (num > (devSize - addr)) {
292 throw CommandException(
"Invalid size");
295 MemBuffer<byte> buf(num);
296 for (
auto i :
xrange(num)) {
297 buf[i] = device.read(addr + i);
299 result = std::span{buf};
302void Debugger::Cmd::write(std::span<const TclObject> tokens, TclObject& )
304 checkNumArgs(tokens, 5, Prefix{2},
"debuggable address value");
305 auto& interp = getInterpreter();
306 Debuggable& device = debugger().getDebuggable(tokens[2].getString());
307 unsigned addr = tokens[3].getInt(interp);
308 if (addr >= device.getSize()) {
309 throw CommandException(
"Invalid address");
311 unsigned value = tokens[4].getInt(interp);
313 throw CommandException(
"Invalid value");
316 device.write(addr, narrow_cast<byte>(value));
319void Debugger::Cmd::writeBlock(std::span<const TclObject> tokens, TclObject& )
321 checkNumArgs(tokens, 5, Prefix{2},
"debuggable address values");
322 Debuggable& device = debugger().getDebuggable(tokens[2].getString());
323 unsigned devSize = device.getSize();
324 unsigned addr = tokens[3].getInt(getInterpreter());
325 if (addr >= devSize) {
326 throw CommandException(
"Invalid address");
328 auto buf = tokens[4].getBinary();
329 if ((buf.size() + addr) > devSize) {
330 throw CommandException(
"Invalid size");
334 device.write(
unsigned(addr + i), buf[i]);
338static constexpr char toHex(
byte x)
340 return narrow<char>((x < 10) ? (x +
'0') : (x - 10 +
'A'));
342static constexpr void toHex(
byte x, std::span<char, 3> buf)
344 buf[0] = toHex(x / 16);
345 buf[1] = toHex(x & 15);
348void Debugger::Cmd::disasm(std::span<const TclObject> tokens, TclObject& result, EmuTime::param time)
const
350 word address = (tokens.size() < 3) ? debugger().cpu->getRegisters().getPC()
351 :
word(tokens[2].getInt(getInterpreter()));
352 std::array<byte, 4> outBuf;
353 std::string dasmOutput;
354 unsigned len =
dasm(debugger().motherBoard.getCPUInterface(), address, outBuf, dasmOutput, time);
355 dasmOutput.resize(19,
' ');
356 result.addListElement(dasmOutput);
357 std::array<char, 3> tmp; tmp[2] = 0;
358 for (
auto i :
xrange(len)) {
359 toHex(outBuf[i], tmp);
360 result.addListElement(tmp.data());
364void Debugger::Cmd::disasmBlob(std::span<const TclObject> tokens, TclObject& result)
const
366 checkNumArgs(tokens, Between{4, 5}, Prefix{2},
"value addr ?function?");
367 std::span<const uint8_t> bin = tokens[2].getBinary();
369 if (!len || *len > bin.size()) {
370 throw CommandException(
"Blob does not contain a complete Z80 instruction");
372 std::string dasmOutput;
373 unsigned addr = tokens[3].getInt(getInterpreter());
374 dasm(bin.subspan(0, *len),
word(addr), dasmOutput,
375 [&](std::string& out, uint16_t a) {
377 if (tokens.size() > 4) {
378 auto command = makeTclList(tokens[4], a);
379 cmdRes = command.executeCommand(getInterpreter()).getString();
381 if (!cmdRes.
empty()) {
382 strAppend(out, cmdRes);
384 appendAddrAsHex(out, a);
387 dasmOutput.resize(19,
' ');
388 result.addListElement(dasmOutput);
389 result.addListElement(*len);
392void Debugger::Cmd::breakPoint(std::span<const TclObject> tokens, TclObject& result)
394 checkNumArgs(tokens, AtLeast{3},
"subcommand ?arg ...?");
395 executeSubCommand(tokens[2].getString(),
396 "list", [&]{ breakPointList(tokens, result); },
397 "create", [&]{ breakPointCreate(tokens, result); },
398 "configure", [&]{ breakPointConfigure(tokens, result); },
399 "remove", [&]{ breakPointRemove(tokens, result); });
402void Debugger::Cmd::watchPoint(std::span<const TclObject> tokens, TclObject& result)
404 checkNumArgs(tokens, AtLeast{3},
"subcommand ?arg ...?");
405 executeSubCommand(tokens[2].getString(),
406 "list", [&]{ watchPointList(tokens, result); },
407 "create", [&]{ watchPointCreate(tokens, result); },
408 "configure", [&]{ watchPointConfigure(tokens, result); },
409 "remove", [&]{ watchPointRemove(tokens, result); });
412void Debugger::Cmd::condition(std::span<const TclObject> tokens, TclObject& result)
414 checkNumArgs(tokens, AtLeast{3},
"subcommand ?arg ...?");
415 executeSubCommand(tokens[2].getString(),
416 "list", [&]{ conditionList(tokens, result); },
417 "create", [&]{ conditionCreate(tokens, result); },
418 "configure", [&]{ conditionConfigure(tokens, result); },
419 "remove", [&]{ conditionRemove(tokens, result); });
422BreakPoint* Debugger::Cmd::lookupBreakPoint(std::string_view str)
425 if (
auto id = StringOp::stringToBase<10, unsigned>(str.substr(
BreakPoint::prefix.size()))) {
428 it != std::end(breakPoints)) {
435std::shared_ptr<WatchPoint> Debugger::Cmd::lookupWatchPoint(std::string_view str)
438 if (
auto id = StringOp::stringToBase<10, unsigned>(str.substr(
WatchPoint::prefix.size()))) {
439 auto&
interface = debugger().motherBoard.getCPUInterface();
440 auto& watchPoints = interface.getWatchPoints();
442 it != std::end(watchPoints)) {
449DebugCondition* Debugger::Cmd::lookupCondition(std::string_view str)
455 it != std::end(conditions)) {
462static auto formatWpAddr(
const WatchPoint& wp)
465 result.addListElement(wp.getBeginAddressString());
466 if (
auto end = wp.getEndAddressString(); !
end.getString().empty()) {
467 result.addListElement(
end);
472void Debugger::Cmd::breakPointList(std::span<const TclObject> , TclObject& result)
476 TclObject(
"-address"), bp.getAddressString(),
477 TclObject(
"-condition"), bp.getCondition(),
478 TclObject(
"-command"), bp.getCommand(),
479 TclObject(
"-enabled"), bp.isEnabled(),
480 TclObject(
"-once"), bp.onlyOnce());
481 result.addDictKeyValue(bp.getIdStr(), std::move(dict));
485void Debugger::Cmd::watchPointList(std::span<const TclObject> , TclObject& result)
487 auto&
interface = debugger().motherBoard.getCPUInterface();
488 for (
const auto& wp : interface.getWatchPoints()) {
491 TclObject(
"-address"), formatWpAddr(*wp),
492 TclObject(
"-condition"), wp->getCondition(),
493 TclObject(
"-command"), wp->getCommand(),
494 TclObject(
"-enabled"), wp->isEnabled(),
495 TclObject(
"-once"), wp->onlyOnce());
496 result.addDictKeyValue(wp->getIdStr(), std::move(dict));
500void Debugger::Cmd::conditionList(std::span<const TclObject> , TclObject& result)
504 TclObject(
"-condition"), cond.getCondition(),
505 TclObject(
"-command"), cond.getCommand(),
506 TclObject(
"-enabled"), cond.isEnabled(),
507 TclObject(
"-once"), cond.onlyOnce());
508 result.addDictKeyValue(cond.getIdStr(), std::move(dict));
512void Debugger::Cmd::parseCreateBreakPoint(BreakPoint& bp, std::span<const TclObject> tokens)
515 funcArg(
"-address", [&](Interpreter& interp,
const TclObject& arg) {
516 bp.setAddress(interp, arg);
518 funcArg(
"-condition", [&](Interpreter& ,
const TclObject& arg) {
519 bp.setCondition(arg);
521 funcArg(
"-command", [&](Interpreter& ,
const TclObject& arg) {
524 funcArg(
"-enabled", [&](Interpreter& interp,
const TclObject& arg) {
525 bp.setEnabled(interp, arg);
527 funcArg(
"-once", [&](Interpreter& interp,
const TclObject& arg) {
528 bp.setOnce(interp, arg);
531 auto arguments =
parseTclArgs(getInterpreter(), tokens, info);
532 if (!arguments.empty())
throw SyntaxError();
535void Debugger::Cmd::parseCreateWatchPoint(WatchPoint& wp, std::span<const TclObject> tokens)
538 funcArg(
"-type", [&](Interpreter& interp,
const TclObject& arg) {
539 wp.setType(interp, arg);
541 funcArg(
"-address", [&](Interpreter& interp,
const TclObject& arg) {
542 wp.setAddress(interp, arg);
544 funcArg(
"-condition", [&](Interpreter& ,
const TclObject& arg) {
545 wp.setCondition(arg);
547 funcArg(
"-command", [&](Interpreter& ,
const TclObject& arg) {
550 funcArg(
"-enabled", [&](Interpreter& interp,
const TclObject& arg) {
551 wp.setEnabled(interp, arg);
553 funcArg(
"-once", [&](Interpreter& interp,
const TclObject& arg) {
554 wp.setOnce(interp, arg);
557 auto arguments =
parseTclArgs(getInterpreter(), tokens, info);
558 if (!arguments.empty())
throw SyntaxError();
561void Debugger::Cmd::parseCreateCondition(DebugCondition& cond, std::span<const TclObject> tokens)
564 funcArg(
"-condition", [&](Interpreter& ,
const TclObject& arg) {
565 cond.setCondition(arg);
567 funcArg(
"-command", [&](Interpreter& ,
const TclObject& arg) {
568 cond.setCommand(arg);
570 funcArg(
"-enabled", [&](Interpreter& interp,
const TclObject& arg) {
571 cond.setEnabled(interp, arg);
573 funcArg(
"-once", [&](Interpreter& interp,
const TclObject& arg) {
574 cond.setOnce(interp, arg);
577 auto arguments =
parseTclArgs(getInterpreter(), tokens, info);
578 if (!arguments.empty())
throw SyntaxError();
581void Debugger::Cmd::breakPointCreate(std::span<const TclObject> tokens, TclObject& result)
584 parseCreateBreakPoint(bp, tokens.subspan(3));
585 result = bp.getIdStr();
586 debugger().motherBoard.getCPUInterface().insertBreakPoint(std::move(bp));
589void Debugger::Cmd::watchPointCreate(std::span<const TclObject> tokens, TclObject& result)
591 auto wp = std::make_shared<WatchPoint>();
592 parseCreateWatchPoint(*wp, tokens.subspan(3));
593 result = wp->getIdStr();
594 debugger().motherBoard.getCPUInterface().setWatchPoint(std::move(wp));
597void Debugger::Cmd::conditionCreate(std::span<const TclObject> tokens, TclObject& result)
600 parseCreateCondition(cond, tokens.subspan(3));
601 result = cond.getIdStr();
602 debugger().motherBoard.getCPUInterface().setCondition(std::move(cond));
605void Debugger::Cmd::breakPointConfigure(std::span<const TclObject> tokens, TclObject& )
607 checkNumArgs(tokens, AtLeast{4},
"id ?arg ...?");
608 auto id = tokens[3].getString();
609 auto* bp = lookupBreakPoint(
id);
611 throw CommandException(
"No such breakpoint: ",
id);
614 parseCreateBreakPoint(*bp, tokens.subspan(4));
617void Debugger::Cmd::watchPointConfigure(std::span<const TclObject> tokens, TclObject& )
619 checkNumArgs(tokens, AtLeast{4},
"id ?arg ...?");
620 auto id = tokens[3].getString();
621 auto wp = lookupWatchPoint(
id);
623 throw CommandException(
"No such breakpoint: ",
id);
625 auto ch = debugger().motherBoard.getCPUInterface().getScopedChangeWatchpoint(wp);
626 parseCreateWatchPoint(*wp, tokens.subspan(4));
629void Debugger::Cmd::conditionConfigure(std::span<const TclObject> tokens, TclObject& )
631 checkNumArgs(tokens, AtLeast{4},
"id ?arg ...?");
632 auto id = tokens[3].getString();
633 auto* cond = lookupCondition(
id);
635 throw CommandException(
"No such condition: ",
id);
638 parseCreateCondition(*cond, tokens.subspan(4));
641void Debugger::Cmd::breakPointRemove(std::span<const TclObject> tokens, TclObject& )
643 checkNumArgs(tokens, 4,
"id");
644 auto id = tokens[3].getString();
645 auto* bp = lookupBreakPoint(tokens[3].getString());
647 throw CommandException(
"No such breakpoint: ",
id);
649 debugger().motherBoard.getCPUInterface().removeBreakPoint(*bp);
652void Debugger::Cmd::watchPointRemove(std::span<const TclObject> tokens, TclObject& )
654 checkNumArgs(tokens, 4,
"id");
655 auto id = tokens[3].getString();
656 auto wp = lookupWatchPoint(tokens[3].getString());
658 throw CommandException(
"No such watchpoint: ",
id);
660 debugger().motherBoard.getCPUInterface().removeWatchPoint(wp);
663void Debugger::Cmd::conditionRemove(std::span<const TclObject> tokens, TclObject& )
665 checkNumArgs(tokens, 4,
"id");
666 auto id = tokens[3].getString();
667 auto* cond = lookupCondition(tokens[3].getString());
669 throw CommandException(
"No such condition: ",
id);
671 debugger().motherBoard.getCPUInterface().removeCondition(*cond);
674void Debugger::Cmd::setBreakPoint(std::span<const TclObject> tokens, TclObject& result)
676 checkNumArgs(tokens, AtLeast{3},
"address ?-once? ?condition? ?command?");
679 std::array info = {
flagArg(
"-once", once)};
681 auto& interp = getInterpreter();
682 auto arguments =
parseTclArgs(interp, tokens.subspan(2), info);
683 if ((arguments.size() < 1) || (arguments.size() > 3)) {
690 switch (arguments.size()) {
692 bp.setCommand(arguments[2]);
695 bp.setCondition(arguments[1]);
698 bp.setAddress(interp, arguments[0]);
702 result = bp.getIdStr();
703 debugger().motherBoard.getCPUInterface().insertBreakPoint(std::move(bp));
706void Debugger::Cmd::removeBreakPoint(
707 std::span<const TclObject> tokens, TclObject& )
709 checkNumArgs(tokens, 3,
"id|address");
710 auto&
interface = debugger().motherBoard.getCPUInterface();
713 string_view tmp = tokens[2].getString();
716 if (
auto id = StringOp::stringToBase<10, unsigned>(tmp.substr(
BreakPoint::prefix.size()))) {
718 it != std::end(breakPoints)) {
719 interface.removeBreakPoint(*it);
723 throw CommandException(
"No such breakpoint: ", tmp);
726 word addr = getAddress(getInterpreter(), tokens[2]);
728 return (bp.getAddress() == addr) &&
729 bp.getCondition().getString().empty();
731 if (it == breakPoints.end()) {
732 throw CommandException(
733 "No (unconditional) breakpoint at address: ", tmp);
735 interface.removeBreakPoint(*it);
739void Debugger::Cmd::listBreakPoints(std::span<const TclObject> , TclObject& result)
const
744 bp.getIdStr(), bp.getAddressString(),
745 bp.getCondition(), bp.getCommand());
752void Debugger::Cmd::setWatchPoint(std::span<const TclObject> tokens, TclObject& result)
754 checkNumArgs(tokens, AtLeast{4}, Prefix{2},
"type address ?-once? ?condition? ?command?");
757 std::array info = {
flagArg(
"-once", once)};
759 auto& interp = getInterpreter();
760 auto arguments =
parseTclArgs(interp, tokens.subspan(2), info);
761 if ((arguments.size() < 2) || (arguments.size() > 4)) {
765 auto wp = std::make_shared<WatchPoint>();
768 switch (arguments.size()) {
770 wp->setCommand(arguments[3]);
773 wp->setCondition(arguments[2]);
776 wp->setType(interp, arguments[0]);
777 wp->setAddress(interp, arguments[1]);
783 result = wp->getIdStr();
784 debugger().motherBoard.getCPUInterface().setWatchPoint(std::move(wp));
787void Debugger::Cmd::removeWatchPoint(
788 std::span<const TclObject> tokens, TclObject& )
790 checkNumArgs(tokens, 3,
"id");
791 string_view tmp = tokens[2].getString();
794 if (
auto id = StringOp::stringToBase<10, unsigned>(tmp.substr(
WatchPoint::prefix.size()))) {
795 auto&
interface = debugger().motherBoard.getCPUInterface();
796 for (
auto& wp : interface.getWatchPoints()) {
797 if (wp->getId() == *
id) {
798 interface.removeWatchPoint(wp);
804 throw CommandException(
"No such watchpoint: ", tmp);
807void Debugger::Cmd::listWatchPoints(
808 std::span<const TclObject> , TclObject& result)
811 const auto&
interface = debugger().motherBoard.getCPUInterface();
812 for (
const auto& wp : interface.getWatchPoints()) {
813 auto address =
makeTclList(wp->getBeginAddressString());
814 if (
auto end = wp->getEndAddressString(); !
end.getString().empty()) {
815 address.addListElement(
end);
829void Debugger::Cmd::setCondition(std::span<const TclObject> tokens, TclObject& result)
831 checkNumArgs(tokens, AtLeast{3},
"condition ?-once? ?command?");
834 std::array info = {
flagArg(
"-once", once)};
836 auto arguments =
parseTclArgs(getInterpreter(), tokens.subspan(2), info);
837 if ((arguments.size() < 1) || (arguments.size() > 2)) {
844 switch (arguments.size()) {
846 dc.setCommand(arguments[1]);
849 dc.setCondition(arguments[0]);
853 result = dc.getIdStr();
854 debugger().motherBoard.getCPUInterface().setCondition(std::move(dc));
857void Debugger::Cmd::removeCondition(
858 std::span<const TclObject> tokens, TclObject& )
860 checkNumArgs(tokens, 3,
"id");
862 string_view tmp = tokens[2].getString();
867 if (c.getId() == *
id) {
868 auto&
interface = debugger().motherBoard.getCPUInterface();
869 interface.removeCondition(c);
875 throw CommandException(
"No such condition: ", tmp);
878void Debugger::Cmd::listConditions(std::span<const TclObject> , TclObject& result)
const
891void Debugger::Cmd::probe(std::span<const TclObject> tokens, TclObject& result)
893 checkNumArgs(tokens, AtLeast{3},
"subcommand ?arg ...?");
894 executeSubCommand(tokens[2].getString(),
895 "list", [&]{ probeList(tokens, result); },
896 "desc", [&]{ probeDesc(tokens, result); },
897 "read", [&]{ probeRead(tokens, result); },
898 "set_bp", [&]{ probeSetBreakPoint(tokens, result); },
899 "remove_bp", [&]{ probeRemoveBreakPoint(tokens, result); },
900 "list_bp", [&]{ probeListBreakPoints(tokens, result); });
902void Debugger::Cmd::probeList(std::span<const TclObject> , TclObject& result)
905 [](
auto* p) {
return p->getName(); }));
907void Debugger::Cmd::probeDesc(std::span<const TclObject> tokens, TclObject& result)
909 checkNumArgs(tokens, 4,
"probe");
910 result = debugger().getProbe(tokens[3].getString()).getDescription();
912void Debugger::Cmd::probeRead(std::span<const TclObject> tokens, TclObject& result)
914 checkNumArgs(tokens, 4,
"probe");
915 result = debugger().getProbe(tokens[3].getString()).getValue();
917void Debugger::Cmd::probeSetBreakPoint(
918 std::span<const TclObject> tokens, TclObject& result)
920 checkNumArgs(tokens, AtLeast{4},
"probe ?-once? ?condition? ?command?");
921 TclObject command(
"debug break");
926 std::array info = {
flagArg(
"-once", once)};
927 auto arguments =
parseTclArgs(getInterpreter(), tokens.subspan(3), info);
928 if ((arguments.size() < 1) || (arguments.size() > 3)) {
932 switch (arguments.size()) {
934 command = arguments[2];
937 condition = arguments[1];
940 p = &debugger().getProbe(arguments[0].getString());
947 result = debugger().insertProbeBreakPoint(command, condition, *p, once);
949void Debugger::Cmd::probeRemoveBreakPoint(
950 std::span<const TclObject> tokens, TclObject& )
952 checkNumArgs(tokens, 4,
"id");
953 debugger().removeProbeBreakPoint(tokens[3].getString());
955void Debugger::Cmd::probeListBreakPoints(
956 std::span<const TclObject> , TclObject& result)
959 for (
const auto& p : debugger().probeBreakPoints) {
961 p->getProbe().getName(),
969SymbolManager& Debugger::Cmd::getSymbolManager()
971 return debugger().getMotherBoard().getReactor().getSymbolManager();
973void Debugger::Cmd::symbols(std::span<const TclObject> tokens, TclObject& result)
975 checkNumArgs(tokens, AtLeast{3},
"subcommand ?arg ...?");
976 executeSubCommand(tokens[2].getString(),
977 "types", [&]{ symbolsTypes(tokens, result); },
978 "load", [&]{ symbolsLoad(tokens, result); },
979 "remove", [&]{ symbolsRemove(tokens, result); },
980 "files", [&]{ symbolsFiles(tokens, result); },
981 "lookup", [&]{ symbolsLookup(tokens, result); });
983void Debugger::Cmd::symbolsTypes(std::span<const TclObject> tokens, TclObject& result)
const
985 checkNumArgs(tokens, 3,
"");
992void Debugger::Cmd::symbolsLoad(std::span<const TclObject> tokens, TclObject& )
994 checkNumArgs(tokens, Between{4, 5},
"filename ?type?");
995 auto filename = std::string(tokens[3].getString());
998 auto str = tokens[4].getString();
1000 if (!
t)
throw CommandException(
"Invalid symbol file type: ", str);
1005 }
catch (MSXException& e) {
1006 throw CommandException(
"Couldn't load symbol file '", filename,
"': ",
e.getMessage());
1009void Debugger::Cmd::symbolsRemove(std::span<const TclObject> tokens, TclObject& )
1011 checkNumArgs(tokens, 4,
"filename");
1012 auto filename = tokens[3].getString();
1013 getSymbolManager().removeFile(filename);
1015void Debugger::Cmd::symbolsFiles(std::span<const TclObject> tokens, TclObject& result)
1017 checkNumArgs(tokens, 3,
"");
1018 for (
const auto& file : getSymbolManager().getFiles()) {
1019 result.addListElement(TclObject(TclObject::MakeDictTag{},
1020 "filename", file.filename,
1024void Debugger::Cmd::symbolsLookup(std::span<const TclObject> tokens, TclObject& result)
1026 std::string_view filename;
1027 std::string_view name;
1028 std::optional<int> value;
1029 std::array info = {
valueArg(
"-filename", filename),
1032 auto args =
parseTclArgs(getInterpreter(), tokens.subspan(3), info);
1033 if (!args.empty())
throw SyntaxError();
1034 if (!filename.empty() && !name.empty() && value)
throw SyntaxError();
1036 for (
const auto& file : getSymbolManager().getFiles()) {
1037 if (!filename.empty() && (file.filename != filename))
continue;
1038 for (
const auto& sym : file.symbols) {
1039 if (!name.empty() && (name != sym.name))
continue;
1040 if (value && (sym.value != *value))
continue;
1043 if (filename.empty()) elem.addDictKeyValue(
"filename", file.filename);
1044 if (name.empty()) elem.addDictKeyValue(
"name", sym.name);
1045 if (!value) elem.addDictKeyValue(
"value", sym.value);
1046 result.addListElement(std::move(elem));
1051string Debugger::Cmd::help(std::span<const TclObject> tokens)
const
1054 "debug <subcommand> [<arguments>]\n"
1055 " Possible subcommands are:\n"
1056 " list returns a list of all debuggables\n"
1057 " desc returns a description of this debuggable\n"
1058 " size returns the size of this debuggable\n"
1059 " read read a byte from a debuggable\n"
1060 " write write a byte to a debuggable\n"
1061 " read_block read a whole block at once\n"
1062 " write_block write a whole block at once\n"
1063 " breakpoint breakpoint related subcommands\n"
1064 " watchpoint watchpoint related subcommands\n"
1065 " condition debug condition related subcommands\n"
1066 " probe probe related subcommands\n"
1067 " cont continue execution after break\n"
1068 " step execute one instruction\n"
1069 " break break CPU at current position\n"
1070 " breaked query CPU breaked status\n"
1071 " disasm disassemble instructions\n"
1072 " disasm_blob disassemble a instruction in Tcl binary string\n"
1073 " symbols manage debug symbols\n"
1074 " The arguments are specific for each subcommand.\n"
1075 " Type 'help debug <subcommand>' for help about a specific subcommand.\n";
1079 " Returns a list with the names of all 'debuggables'.\n"
1080 " These names are used in other debug subcommands.\n";
1082 "debug desc <name>\n"
1083 " Returns a description for the debuggable with given name.\n";
1085 "debug size <name>\n"
1086 " Returns the size (in bytes) of the debuggable with given name.\n";
1088 "debug read <name> <addr>\n"
1089 " Read a byte at offset <addr> from the given debuggable.\n"
1090 " The offset must be smaller than the value returned from the "
1091 "'size' subcommand\n"
1092 " Note that openMSX comes with a bunch of Tcl scripts that make "
1093 "some of the debug reads much more convenient (e.g. reading from "
1094 "Z80 or VDP registers). See the Console Command Reference for more "
1095 "details about these.\n";
1097 "debug write <name> <addr> <val>\n"
1098 " Write a byte to the given debuggable at a certain offset.\n"
1099 " The offset must be smaller than the value returned from the "
1100 "'size' subcommand\n";
1101 auto readBlockHelp =
1102 "debug read_block <name> <addr> <size>\n"
1103 " Read a whole block at once. This is equivalent with repeated "
1104 "invocations of the 'read' subcommand, but using this subcommand "
1105 "may be faster. The result is a Tcl binary string (see Tcl manual).\n"
1106 " The block is specified as size/offset in the debuggable. The "
1107 "complete block must fit in the debuggable (see the 'size' "
1109 auto writeBlockHelp =
1110 "debug write_block <name> <addr> <values>\n"
1111 " Write a whole block at once. This is equivalent with repeated "
1112 "invocations of the 'write' subcommand, but using this subcommand "
1113 "may be faster. The <values> argument must be a Tcl binary string "
1114 "(see Tcl manual).\n"
1115 " The block has a size and an offset in the debuggable. The "
1116 "complete block must fit in the debuggable (see the 'size' "
1118 auto breakPointHelp =
1119 "debug breakpoint <subcommand> [<arguments>]\n"
1120 " Possible subcommands are:\n"
1121 " list list all active breakpoints\n"
1122 " create create a new breakpoint\n"
1123 " configure configure an existing breakpoint\n"
1124 " remove remove an existing breakpoint\n"
1125 " Type 'help debug breakpoint <subcommand>' for help about a specific subcommand.\n";
1126 auto watchPointHelp =
1127 "debug watchpoint <subcommand> [<arguments>]\n"
1128 " Possible subcommands are:\n"
1129 " list list all active watchpoints\n"
1130 " create create a new watchpoint\n"
1131 " configure configure an existing watchpoint\n"
1132 " remove remove an existing watchpoint\n"
1133 " Type 'help debug watchpoint <subcommand>' for help about a specific subcommand.\n";
1134 auto conditionHelp =
1135 "debug condition <subcommand> [<arguments>]\n"
1136 " Possible subcommands are:\n"
1137 " list list all active debug conditions\n"
1138 " create create a new debug conditions\n"
1139 " configure configure an existing debug condition\n"
1140 " remove remove an existing debug condition\n"
1141 " Type 'help debug condition <subcommand>' for help about a specific subcommand.\n";
1142 auto breakPointListHelp =
1143 "debug breakpoint list\n"
1144 " Lists all breakpoints. The result is a Tcl dict (<key>/<value>-pairs), where\n"
1145 " * <key> is the breakpoint ID\n"
1146 " * <value> is another Tcl dict containing the properties of the breakpoint.\n"
1147 " See 'help debug breakpoint create' for a description of these properties.\n";
1148 auto watchPointListHelp =
1149 "debug watchpoint list\n"
1150 " Lists all watchpoints. The result is a Tcl dict (<key>/<value>-pairs), where\n"
1151 " * <key> is the watchpoint ID\n"
1152 " * <value> is another Tcl dict containing the properties of the watchpoint.\n"
1153 " See 'help debug watchpoint create' for a description of these properties.\n";
1154 auto conditionListHelp =
1155 "debug condition list\n"
1156 " Lists all debug conditions. The result is a Tcl dict (<key>/<value>-pairs), where\n"
1157 " * <key> is the debug condition ID\n"
1158 " * <value> is another Tcl dict containing the properties of the debug condition.\n"
1159 " See 'help debug condition create' for a description of these properties.\n";
1160 auto breakPointCreateHelp =
1161 "debug breakpoint create [<property-name> <property-value>]...\n"
1162 " Create a new breakpoint with given properties. The following properties are supported:\n"
1163 " -address the address where the breakpoint should trigger\n"
1164 " -condition a Tcl expression that must evaluate to true for the breakpoint to trigger (default = no condition)\n"
1165 " -command a Tcl command that should be executed when the breakpoint triggers (default = 'debug break')\n"
1166 " -enabled set to false to (temporarily) disable this breakpoint\n"
1167 " -once if 'true' the breakpoint is automatically removed after it triggered (default = 'false', meaning recurring)\n";
1168 auto watchPointCreateHelp =
1169 "debug watchpoint create [<property-name> <property-value>]...\n"
1170 " Create a new watchpoint with given properties. The following properties are supported:\n"
1171 " -type one of 'read_io', 'write_io', 'read_mem', 'write_mem'\n"
1172 " -address the address(es) where the watchpoint should trigger, can be a single address or a begin/end-pair\n"
1173 " -condition a Tcl expression that must evaluate to true for the watchpoint to trigger (default = no condition)\n"
1174 " -command a Tcl command that should be executed when the watchpoint triggers (default = 'debug break')\n"
1175 " -enabled set to false to (temporarily) disable this watchpoint\n"
1176 " -once if 'true' the watchpoint is automatically removed after it triggered (default = 'false', meaning recurring)\n";
1177 auto conditionCreateHelp =
1178 "debug condition create [<property-name> <property-value>]...\n"
1179 " Create a new debug condition with given properties. The following properties are supported:\n"
1180 " -condition a Tcl expression that must evaluate to true for the debug condition to trigger (default = no condition)\n"
1181 " -command a Tcl command that should be executed when the debug condition triggers (default = 'debug break')\n"
1182 " -enabled set to false to (temporarily) disable this condition\n"
1183 " -once if 'true' the debug condition is automatically removed after it triggered (default = 'false', meaning recurring)\n";
1184 auto breakPointConfigureHelp =
1185 "debug breakpoint configure <id> [<property-name> <property-value>]...\n"
1186 " Change one or more properties of an existing breakpoint.\n"
1187 " See 'help debug breakpoint create' for a description of the properties.\n";
1188 auto watchPointConfigureHelp =
1189 "debug watchpoint configure <id> [<property-name> <property-value>]...\n"
1190 " Change one or more properties of an existing watchpoint.\n"
1191 " See 'help debug watchpoint create' for a description of the properties.\n";
1192 auto conditionConfigureHelp =
1193 "debug condition configure <id> [<property-name> <property-value>]...\n"
1194 " Change one or more properties of an existing debug condition.\n"
1195 " See 'help debug condition create' for a description of the properties.\n";
1196 auto breakPointRemoveHelp =
1197 "debug breakpoint remove <id>\n"
1198 " Remove the breakpoint with given ID.\n";
1199 auto watchPointRemoveHelp =
1200 "debug watchpoint remove <id>\n"
1201 " Remove the watchpoint with given ID.\n";
1202 auto conditionRemoveHelp =
1203 "debug condition remove <id>\n"
1204 " Remove the debug condition with given ID.\n";
1206 "[deprecated] replaced by: 'debug breakpoint create <args>...'\n"
1208 "debug set_bp [-once] <addr> [<cond>] [<cmd>]\n"
1209 " Insert a new breakpoint at given address. When the CPU is about "
1210 "to execute the instruction at this address, execution will be "
1211 "breaked. At least this is the default behaviour, see next "
1213 " When the -once flag is given, the breakpoint is automatically "
1214 "removed after it triggered. In other words: it only triggers once.\n"
1215 " Optionally you can specify a condition. When the CPU reaches "
1216 "the breakpoint this condition is evaluated, only when the condition "
1217 "evaluated to true execution will be breaked.\n"
1218 " A condition must be specified as a Tcl expression. For example\n"
1219 " debug set_bp 0xf37d {[reg C] == 0x2F}\n"
1220 " This breaks on address 0xf37d but only when Z80 register C has the "
1222 " Also optionally you can specify a command that should be "
1223 "executed when the breakpoint is reached (and condition is true). "
1224 "By default this command is 'debug break'.\n"
1225 " The result of this command is a breakpoint ID. This ID can "
1226 "later be used to remove this breakpoint again.\n";
1228 "[deprecated] replaced by: 'debug breakpoint remove <id>'\n"
1230 "debug remove_bp <id>\n"
1231 " Remove the breakpoint with given ID again. You can use the "
1232 "'list_bp' subcommand to see all valid IDs.\n";
1234 "[deprecated] replaced by: 'debug breakpoint list'\n"
1237 " Lists all active breakpoints. The result is printed in 4 "
1238 "columns. The first column contains the breakpoint ID. The "
1239 "second one has the address. The third has the condition "
1240 "(default condition is empty). And the last column contains "
1241 "the command that will be executed (default is 'debug break').\n";
1242 auto setWatchPointHelp =
1243 "[deprecated] replaced by: 'debug watchpoint create <args>...'\n"
1245 "debug set_watchpoint [-once] <type> <region> [<cond>] [<cmd>]\n"
1246 " Insert a new watchpoint of given type on the given region, "
1247 "there can be an optional -once flag, a condition and alternative "
1248 "command. See the 'set_bp' subcommand for details about these.\n"
1249 " Type must be one of the following:\n"
1250 " read_io break when CPU reads from given IO port(s)\n"
1251 " write_io break when CPU writes to given IO port(s)\n"
1252 " read_mem break when CPU reads from given memory location(s)\n"
1253 " write_mem break when CPU writes to given memory location(s)\n"
1254 " Region is either a single value, this corresponds to a single "
1255 "memory location or IO port. Otherwise region must be a list of "
1256 "two values (enclosed in braces) that specify a begin and end "
1257 "point of a whole memory region or a range of IO ports.\n"
1258 "During the execution of <cmd>, the following global Tcl "
1259 "variables are set:\n"
1260 " ::wp_last_address this is the actual address of the mem/io "
1261 "read/write that triggered the watchpoint\n"
1262 " ::wp_last_value this is the actual value that was written "
1263 "by the mem/io write that triggered the watchpoint\n"
1265 " debug set_watchpoint write_io 0x99 {[reg A] == 0x81}\n"
1266 " debug set_watchpoint read_mem {0xfbe5 0xfbef}\n";
1267 auto removeWatchPointHelp =
1268 "[deprecated] replaced by: 'debug watchpoint remove <id>'\n"
1270 "debug remove_watchpoint <id>\n"
1271 " Remove the watchpoint with given ID again. You can use the "
1272 "'list_watchpoints' subcommand to see all valid IDs.\n";
1273 auto listWatchPointsHelp =
1274 "[deprecated] replaced by: 'debug watchpoint list'\n"
1276 "debug list_watchpoints\n"
1277 " Lists all active watchpoints. The result is similar to the "
1278 "'list_bp' subcommand, but there is an extra column (2nd column) "
1279 "that contains the type of the watchpoint.\n";
1281 "[deprecated] replaced by: 'debug condition create <args>...'\n"
1283 "debug set_condition [-once] <cond> [<cmd>]\n"
1284 " Insert a new condition. These are much like breakpoints, "
1285 "except that they are checked before every instruction "
1286 "(breakpoints are tied to a specific address).\n"
1287 " Conditions will slow down simulation MUCH more than "
1288 "breakpoints. So only use them when you don't care about "
1289 "simulation speed (when you're debugging this is usually not "
1291 " See 'help debug set_bp' for more details.\n";
1292 auto removeCondHelp =
1293 "[deprecated] replaced by: 'debug condition remove <id>'\n"
1295 "debug remove_condition <id>\n"
1296 " Remove the condition with given ID again. You can use the "
1297 "'list_conditions' subcommand to see all valid IDs.\n";
1299 "[deprecated] replaced by: 'debug condition list'\n"
1301 "debug list_conditions\n"
1302 " Lists all active conditions. The result is similar to the "
1303 "'list_bp' subcommand, but without the 2nd column that would "
1304 "show the address.\n";
1306 "debug probe <subcommand> [<arguments>]\n"
1307 " Possible subcommands are:\n"
1308 " list returns a list of all probes\n"
1309 " desc <probe> returns a description of this probe\n"
1310 " read <probe> returns the current value of this probe\n"
1311 " set_bp <probe> [-once] [<cond>] [<cmd>] set a breakpoint on the given probe\n"
1312 " remove_bp <id> remove the given breakpoint\n"
1313 " list_bp returns a list of breakpoints that are set on probes\n";
1316 " Continue execution after CPU was breaked.\n";
1319 " Execute one instruction. This command is only meaningful in "
1323 " Immediately break CPU execution. When CPU was already breaked "
1324 "this command has no effect.\n";
1327 " Query the CPU breaked status. Returns '1' when CPU was "
1328 "breaked, '0' otherwise.\n";
1330 "debug disasm <addr>\n"
1331 " Disassemble the instruction at the given address. The result "
1332 "is a Tcl list. The first element in the list contains a textual "
1333 "representation of the instruction, the next elements contain the "
1334 "bytes that make up this instruction (thus the length of the "
1335 "resulting list can be used to derive the number of bytes in the "
1337 " Note that openMSX comes with a 'disasm' Tcl script that is much "
1338 "more convenient to use than this subcommand.";
1339 auto disasmBlobHelp =
1340 "debug disasm_blob <value> <addr> [<function>]\n"
1341 " This is a more generic version of the disasm subcommand, but it "
1342 "works on a Tcl binary string (see Tcl manual) to disassemble a "
1343 "single instruction. The given address is used when relative "
1344 "address to jump to is necessary. The optional fuction will be "
1345 "called with an address as parameter and may return a symbol name "
1346 "that replaces that address if a symbol that matches the address "
1349 "debug symbols <subcommand> [<arguments>]\n"
1350 " Possible subcommands are:\n"
1351 " types returns a list of symbol file types\n"
1352 " load <filename> [<type>] load a symbol file, auto-detect type if none is given\n"
1353 " remove <filename> remove a previously loaded symbol file\n"
1354 " files returns a list of all loaded symbol files\n"
1355 " lookup [-filename <filename>] [-name <name>] [-value <value>]\n"
1356 " returns a list of symbols in an optionally given file\n"
1357 " and/or with an optionally given name\n"
1358 " and/or with an optionally given value\n"
1359 " Note: an easier syntax to lookup a symbol value based on the name is:\n"
1362 "Unknown subcommand, use 'help debug' to see a list of valid "
1365 auto size = tokens.size();
1369 }
else if (tokens[1] ==
"list") {
1371 }
else if (tokens[1] ==
"desc") {
1373 }
else if (tokens[1] ==
"size") {
1375 }
else if (tokens[1] ==
"read") {
1377 }
else if (tokens[1] ==
"write") {
1379 }
else if (tokens[1] ==
"read_block") {
1380 return readBlockHelp;
1381 }
else if (tokens[1] ==
"write_block") {
1382 return writeBlockHelp;
1383 }
else if (tokens[1] ==
"breakpoint") {
1385 return breakPointHelp;
1386 }
else if (tokens[2] ==
"list") {
1387 return breakPointListHelp;
1388 }
else if (tokens[2] ==
"create") {
1389 return breakPointCreateHelp;
1390 }
else if (tokens[2] ==
"configure") {
1391 return breakPointConfigureHelp;
1392 }
else if (tokens[2] ==
"remove") {
1393 return breakPointRemoveHelp;
1395 return breakPointHelp;
1397 }
else if (tokens[1] ==
"watchpoint") {
1399 return watchPointHelp;
1400 }
else if (tokens[2] ==
"list") {
1401 return watchPointListHelp;
1402 }
else if (tokens[2] ==
"create") {
1403 return watchPointCreateHelp;
1404 }
else if (tokens[2] ==
"configure") {
1405 return watchPointConfigureHelp;
1406 }
else if (tokens[2] ==
"remove") {
1407 return watchPointRemoveHelp;
1409 return watchPointHelp;
1411 }
else if (tokens[1] ==
"condition") {
1413 return conditionHelp;
1414 }
else if (tokens[2] ==
"list") {
1415 return conditionListHelp;
1416 }
else if (tokens[2] ==
"create") {
1417 return conditionCreateHelp;
1418 }
else if (tokens[2] ==
"configure") {
1419 return conditionConfigureHelp;
1420 }
else if (tokens[2] ==
"remove") {
1421 return conditionRemoveHelp;
1423 return conditionHelp;
1425 }
else if (tokens[1] ==
"set_bp") {
1427 }
else if (tokens[1] ==
"remove_bp") {
1428 return removeBpHelp;
1429 }
else if (tokens[1] ==
"list_bp") {
1431 }
else if (tokens[1] ==
"set_watchpoint") {
1432 return setWatchPointHelp;
1433 }
else if (tokens[1] ==
"remove_watchpoint") {
1434 return removeWatchPointHelp;
1435 }
else if (tokens[1] ==
"list_watchpoints") {
1436 return listWatchPointsHelp;
1437 }
else if (tokens[1] ==
"set_condition") {
1439 }
else if (tokens[1] ==
"remove_condition") {
1440 return removeCondHelp;
1441 }
else if (tokens[1] ==
"list_conditions") {
1442 return listCondHelp;
1443 }
else if (tokens[1] ==
"probe") {
1445 }
else if (tokens[1] ==
"cont") {
1447 }
else if (tokens[1] ==
"step") {
1449 }
else if (tokens[1] ==
"break") {
1451 }
else if (tokens[1] ==
"breaked") {
1453 }
else if (tokens[1] ==
"disasm") {
1455 }
else if (tokens[1] ==
"disasm_blob") {
1456 return disasmBlobHelp;
1457 }
else if (tokens[1] ==
"symbols") {
1464std::vector<string> Debugger::Cmd::getBreakPointIds()
const
1468 [](
auto& bp) {
return bp.getIdStr(); }));
1470std::vector<string> Debugger::Cmd::getWatchPointIds()
const
1473 debugger().motherBoard.getCPUInterface().getWatchPoints(),
1474 [](
auto& w) { return w->getIdStr(); }));
1476std::vector<string> Debugger::Cmd::getConditionIds()
const
1480 [](
auto& c) {
return c.getIdStr(); }));
1483void Debugger::Cmd::tabCompletion(std::vector<string>& tokens)
const
1485 using namespace std::literals;
1486 static constexpr std::array singleArgCmds = {
1487 "list"sv,
"step"sv,
"cont"sv,
"break"sv,
"breaked"sv,
1488 "list_bp"sv,
"list_watchpoints"sv,
"list_conditions"sv,
1490 static constexpr std::array debuggableArgCmds = {
1491 "desc"sv,
"size"sv,
"read"sv,
"read_block"sv,
1492 "write"sv,
"write_block"sv,
1494 static constexpr std::array otherCmds = {
1495 "disasm"sv,
"disasm_blob"sv,
"set_bp"sv,
"remove_bp"sv,
"set_watchpoint"sv,
1496 "remove_watchpoint"sv,
"set_condition"sv,
"remove_condition"sv,
1497 "probe"sv,
"symbols"sv,
"breakpoint"sv,
"watchpoint"sv,
"condition"sv,
1499 static constexpr std::array types = {
1500 "read_io"sv,
"write_io"sv,
"read_mem"sv,
"write_mem"sv,
1502 switch (
auto size = tokens.size();
size) {
1504 completeString(tokens,
concatArray(singleArgCmds, debuggableArgCmds, otherCmds));
1508 if (!
contains(singleArgCmds, tokens[1])) {
1510 if (
contains(debuggableArgCmds, tokens[1])) {
1512 completeString(tokens,
view::keys(debugger().debuggables));
1513 }
else if (tokens[1] ==
one_of(
"breakpoint"sv,
"watchpoint"sv,
"condition"sv)) {
1514 static constexpr std::array subCmds = {
1515 "list"sv,
"create"sv,
1516 "configure"sv,
"remove"sv,
1518 completeString(tokens, subCmds);
1519 }
else if (tokens[1] ==
"remove_bp") {
1521 completeString(tokens, getBreakPointIds());
1522 }
else if (tokens[1] ==
"remove_watchpoint") {
1524 completeString(tokens, getWatchPointIds());
1525 }
else if (tokens[1] ==
"remove_condition") {
1527 completeString(tokens, getConditionIds());
1528 }
else if (tokens[1] ==
"set_watchpoint") {
1529 completeString(tokens, types);
1530 }
else if (tokens[1] ==
"probe") {
1531 static constexpr std::array subCmds = {
1532 "list"sv,
"desc"sv,
"read"sv,
"set_bp"sv,
1533 "remove_bp"sv,
"list_bp"sv,
1535 completeString(tokens, subCmds);
1536 }
else if (tokens[1] ==
"symbols") {
1537 static constexpr std::array subCmds = {
1538 "types"sv,
"load"sv,
"remove"sv,
1539 "files"sv,
"lookup"sv,
1541 completeString(tokens, subCmds);
1546 if ((size == 4) && (tokens[1] ==
"probe") &&
1547 (tokens[2] ==
one_of(
"desc",
"read",
"set_bp"))) {
1550 [](
auto* p) -> std::string_view {
return p->getName(); }));
1551 }
else if (tokens[1] ==
"breakpoint") {
1552 if ((size == 4) && tokens[2] ==
one_of(
"remove"sv,
"configure"sv)) {
1553 completeString(tokens, getBreakPointIds());
1554 }
else if (((size >= 4) && (tokens[2] ==
"create")) ||
1555 ((size >= 5) && (tokens[2] ==
"configure"))) {
1556 static constexpr std::array properties = {
1557 "-address"sv,
"-command"sv,
"-condition"sv,
"-enabled"sv,
"-once"sv,
1559 completeString(tokens, properties);
1561 }
else if (tokens[1] ==
"watchpoint") {
1562 if ((size == 4) && tokens[2] ==
one_of(
"remove"sv,
"configure"sv)) {
1563 completeString(tokens, getWatchPointIds());
1564 }
else if (((size >= 4) && (tokens[2] ==
"create")) ||
1565 ((size >= 5) && (tokens[2] ==
"configure"))) {
1566 if (tokens[size - 2] ==
"-type") {
1567 completeString(tokens, types);
1569 static constexpr std::array properties = {
1570 "-type"sv,
"-address"sv,
"-command"sv,
"-condition"sv,
"-enabled"sv,
"-once"sv,
1572 completeString(tokens, properties);
1575 }
else if (tokens[1] ==
"condition") {
1576 if ((size == 4) && tokens[2] ==
one_of(
"remove"sv,
"configure"sv)) {
1577 completeString(tokens, getConditionIds());
1578 }
else if (((size >= 4) && (tokens[2] ==
"create")) ||
1579 ((size >= 5) && (tokens[2] ==
"configure"))) {
1580 static constexpr std::array properties = {
1581 "-command"sv,
"-condition"sv,
"-enabled"sv,
"-once"sv,
1583 completeString(tokens, properties);
std::string getIdStr() const
static constexpr std::string_view prefix
static constexpr std::string_view prefix
void registerProbe(ProbeBase &probe)
Debuggable * findDebuggable(std::string_view name)
Interpreter & getInterpreter()
void transfer(Debugger &other)
void unregisterProbe(ProbeBase &probe)
void unregisterDebuggable(std::string_view name, Debuggable &debuggable)
ProbeBase * findProbe(std::string_view name)
Debugger(MSXMotherBoard &motherBoard)
void removeProbeBreakPoint(ProbeBreakPoint &bp)
void registerDebuggable(std::string name, Debuggable &debuggable)
static BreakPoints & getBreakPoints()
const WatchPoints & getWatchPoints() const
static Conditions & getConditions()
void update(UpdateType type, std::string_view name, std::string_view value) override
MSXCPUInterface & getCPUInterface()
MSXCliComm & getMSXCliComm()
const std::string & getName() const
static constexpr std::string_view prefix
Interpreter & getInterpreter()
int getInt(Interpreter &interp) const
static std::string_view format(Type type)
static constexpr std::string_view prefix
Like std::string_view, but with the extra guarantee that it refers to a zero-terminated string.
constexpr auto empty() const
const Value * lookup(const hash_map< Key, Value, Hasher, Equal > &map, const Key2 &key)
This file implemented 3 utility functions:
ArgsInfo funcArg(std::string_view name, std::function< void(Interpreter &, const TclObject &)> func)
ArgsInfo valueArg(std::string_view name, T &value)
std::optional< unsigned > instructionLength(std::span< const uint8_t > bin)
Calculate the length of the instruction at the given address.
std::vector< TclObject > parseTclArgs(Interpreter &interp, std::span< const TclObject > inArgs, std::span< const ArgsInfo > table)
uint16_t word
16 bit unsigned integer
ArgsInfo flagArg(std::string_view name, bool &flag)
TclObject makeTclList(Args &&... args)
unsigned dasm(std::span< const uint8_t > opcode, uint16_t pc, std::string &dest, function_ref< void(std::string &, uint16_t)> appendAddr)
Disassemble.
TclObject makeTclDict(Args &&... args)
auto find_if(InputRange &&range, UnaryPredicate pred)
auto find(InputRange &&range, const T &value)
size_t size(std::string_view utf8)
constexpr auto transform(Range &&range, UnaryOp op)
constexpr auto keys(Map &&map)
auto to_vector(Range &&range) -> std::vector< detail::ToVectorType< T, decltype(std::begin(range))> >
constexpr auto concatArray(const std::array< T, X > &x, const std::array< T, Y > &y)
void move_pop_back(VECTOR &v, typename VECTOR::iterator it)
Erase the pointed to element from the given vector.
auto rfind_unguarded(RANGE &range, const VAL &val, Proj proj={})
Similar to the find(_if)_unguarded functions above, but searches from the back to front.
constexpr bool contains(ITER first, ITER last, const VAL &val)
Check if a range contains a given value, using linear search.
void strAppend(std::string &result, Ts &&...ts)
static std::optional< Type > parseType(std::string_view str)
static zstring_view toString(Type type)
constexpr auto xrange(T e)
constexpr auto end(const zstring_view &x)