mirror of
https://github.com/open-goal/jak-project
synced 2026-08-06 18:03:30 -04:00
fe2086acfb
This adds a debug server to `goalc` that sends JSON over the socket to communicate with an external debugger using the Debug Adapter Protocol. This lets us debug GOAL code in a proper debugger with breakpoints, step over, step in and step out per line, stack frames and supports watches for global symbols, registers and local variables (local variables only work within the most recent stack frame). Special registers (`r13`, `r14`, `r15`, argument registers, etc.) are tracked separately and the current process register even displays the type of the current `pp` if possible. Watches that track addresses holding a reference type generate a list of field names according to the object's type. All fields will show their name, type and value and, depending on the type, will try to infer extra info like symbol names/values, function names for `function` fields, enum values and more. This also works nested, so any field that is also a reference type can also be accessed and display its fields, etc. Dynamic arrays are also supported where possible, e.g. in `inline-array-class` children and boxed arrays, it will figure out the value of the `length` field and access the memory up to that point so all the elements can be accessed and viewed from the `data` field. Our VS Code extension implements the DAP in open-goal/opengoal-vscode#375. Using it is as simple as connecting a REPL to a running game instance with `(lt)`, compiling with `(mi)` and, with the extension installed, pressing F5 in VS Code to start the debugger. By default, it will try to connect to the game that the active `.gc` file is from, the socket port is different per game (8128 for Jak 1, 8129 for Jak 2, 8130 for Jak 3). The `launch.json` was updated with two entries for this, the second entry lets you pick the game/port manually if desired. ~~Not tested on Windows.~~ Only supports x86 for now.
78 lines
2.2 KiB
C++
78 lines
2.2 KiB
C++
#pragma once
|
|
|
|
#include <optional>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#include "common/listener_common.h"
|
|
#include "common/versions/versions.h"
|
|
|
|
#include "third-party/json.hpp"
|
|
|
|
using json = nlohmann::json;
|
|
|
|
namespace REPL {
|
|
struct KeyBind {
|
|
// NOTE - in my experience, meta doesn't work on windows and shift is probably a bad idea when
|
|
// typing text! but I leave it up to the user.
|
|
enum class Modifier { CTRL, SHIFT, META };
|
|
Modifier modifier;
|
|
std::string key;
|
|
std::string description;
|
|
std::string command;
|
|
|
|
std::string string() const;
|
|
};
|
|
void to_json(json& j, const KeyBind& obj);
|
|
void from_json(const json& j, KeyBind& obj);
|
|
|
|
// TODO - per-game config
|
|
struct Config {
|
|
GameVersion game_version;
|
|
Config(GameVersion _game_version) : game_version(_game_version) {};
|
|
|
|
// this is the default REPL configuration
|
|
int nrepl_port = 8181;
|
|
int temp_nrepl_port = -1;
|
|
int debug_port = -1;
|
|
int temp_debug_port = -1;
|
|
std::string game_version_folder;
|
|
int target_connect_attempts = 30;
|
|
std::vector<std::string> asm_file_search_dirs = {};
|
|
bool append_keybinds = true;
|
|
std::vector<KeyBind> keybinds = {
|
|
{KeyBind::Modifier::CTRL, "T", "Starts up the game runtime", "(test-play)"},
|
|
{KeyBind::Modifier::CTRL, "Q", "Exit the REPL", "(e)"},
|
|
{KeyBind::Modifier::CTRL, "L", "Listen to an available game process", "(lt)"},
|
|
{KeyBind::Modifier::CTRL, "W",
|
|
"Halt the attached process so you can re-launch a crashed game", "(:stop)"},
|
|
{KeyBind::Modifier::CTRL, "G", "Attach the debugger to the process", "(dbgc)"},
|
|
{KeyBind::Modifier::CTRL, "B", "Displays the most recently caught backtrace", "(:di)"},
|
|
{KeyBind::Modifier::CTRL, "N", "Full build of the game", "(mi)"}};
|
|
bool per_game_history = true;
|
|
bool permissive_redefinitions = false;
|
|
std::string iso_path;
|
|
|
|
int get_nrepl_port() {
|
|
if (temp_nrepl_port != -1) {
|
|
return temp_nrepl_port;
|
|
}
|
|
return nrepl_port;
|
|
}
|
|
|
|
int get_debug_port() {
|
|
if (temp_debug_port != -1) {
|
|
return temp_debug_port;
|
|
}
|
|
if (debug_port != -1) {
|
|
return debug_port;
|
|
}
|
|
return DEBUG_SERVER_PORT - 1 + (int)game_version;
|
|
}
|
|
};
|
|
void to_json(json& j, const Config& obj);
|
|
void from_json(const json& j, Config& obj);
|
|
|
|
} // namespace REPL
|