Skip to content

Commit 59ad4b9

Browse files
committed
feat(debugger): creating a very basic debugger, started by VM::showBacktraceWithException
1 parent f4650b0 commit 59ad4b9

4 files changed

Lines changed: 124 additions & 8 deletions

File tree

include/Ark/VM/Debugger.hpp

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* @file Debugger.hpp
3+
* @author Lexy Plateau (lexplt.dev@gmail.com)
4+
* @brief Debugger used by the VM when an error or a breakpoint is reached
5+
* @date 2026-01-12
6+
*
7+
* @copyright Copyright (c) 2026-01-12
8+
*
9+
*/
10+
11+
#ifndef ARK_VM_DEBUGGER_HPP
12+
#define ARK_VM_DEBUGGER_HPP
13+
14+
#include <Ark/VM/ExecutionContext.hpp>
15+
16+
#include <vector>
17+
#include <memory>
18+
19+
namespace Ark::internal
20+
{
21+
struct SavedState
22+
{
23+
std::size_t ip;
24+
std::size_t pp;
25+
uint16_t sp;
26+
uint16_t fc;
27+
std::vector<ScopeView> locals;
28+
std::vector<std::shared_ptr<ClosureScope>> closure_scopes;
29+
};
30+
31+
class Debugger
32+
{
33+
public:
34+
/**
35+
* @brief Create a new Debugger object
36+
*
37+
* @param context context from the VM before displaying a backtrace
38+
*/
39+
explicit Debugger(const ExecutionContext& context);
40+
41+
void saveState(const ExecutionContext& context);
42+
43+
void resetContextToErrorState(ExecutionContext& context);
44+
45+
void run();
46+
47+
private:
48+
std::vector<std::unique_ptr<SavedState>> m_states;
49+
};
50+
}
51+
52+
#endif // ARK_VM_DEBUGGER_HPP

include/Ark/VM/VM.hpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include <Ark/Utils/Literals.hpp>
3535
#include <Ark/VM/SharedLibrary.hpp>
3636
#include <Ark/VM/Value/Future.hpp>
37+
#include <Ark/VM/Debugger.hpp>
3738

3839
namespace Ark
3940
{
@@ -175,6 +176,7 @@ namespace Ark
175176
std::mutex m_mutex, m_mutex_futures;
176177
std::vector<std::shared_ptr<internal::SharedLibrary>> m_shared_lib_objects;
177178
std::vector<std::unique_ptr<internal::Future>> m_futures; ///< Storing the promises while we are resolving them
179+
std::unique_ptr<internal::Debugger> m_debugger { nullptr };
178180

179181
// a little trick for operator[] and for pop
180182
Value m_no_value = internal::Builtins::nil;
@@ -352,6 +354,8 @@ namespace Ark
352354

353355
[[noreturn]] void throwArityError(std::size_t passed_arg_count, std::size_t expected_arg_count, internal::ExecutionContext& context);
354356

357+
void initDebugger(internal::ExecutionContext& context);
358+
355359
void showBacktraceWithException(const std::exception& e, internal::ExecutionContext& context);
356360

357361
/**
@@ -361,9 +365,9 @@ namespace Ark
361365
* @param pp
362366
* @return std::optional<InstLoc>
363367
*/
364-
std::optional<internal::InstLoc> findSourceLocation(std::size_t ip, std::size_t pp) const;
368+
[[nodiscard]] std::optional<internal::InstLoc> findSourceLocation(std::size_t ip, std::size_t pp) const;
365369

366-
std::string debugShowSource() const;
370+
[[nodiscard]] std::string debugShowSource() const;
367371

368372
/**
369373
* @brief Display a backtrace when the VM encounter an exception

src/arkreactor/VM/Debugger.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#include <Ark/VM/Debugger.hpp>
2+
3+
#include <fmt/core.h>
4+
5+
namespace Ark::internal
6+
{
7+
// TODO: Create a new context?
8+
// Creating a new context meaning modifying where the scope views points to,
9+
// because the underlying storage won't have the same address.
10+
Debugger::Debugger(const ExecutionContext& context)
11+
{
12+
saveState(context);
13+
}
14+
15+
void Debugger::saveState(const ExecutionContext& context)
16+
{
17+
m_states.emplace_back(
18+
std::make_unique<SavedState>(
19+
context.ip,
20+
context.pp,
21+
context.sp,
22+
context.fc,
23+
context.locals,
24+
context.stacked_closure_scopes));
25+
}
26+
27+
void Debugger::resetContextToErrorState(ExecutionContext& context)
28+
{
29+
const auto& [ip, pp, sp, fc, locals, closure_scopes] = *m_states.back();
30+
context.locals = locals;
31+
context.stacked_closure_scopes = closure_scopes;
32+
context.ip = ip;
33+
context.pp = pp;
34+
context.sp = sp;
35+
context.fc = fc;
36+
37+
m_states.pop_back();
38+
}
39+
40+
void Debugger::run()
41+
{
42+
// TODO: create a shell
43+
fmt::println("debugger running");
44+
}
45+
}

src/arkreactor/VM/VM.cpp

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,7 @@ namespace Ark
918918
args.push_back(*popAndResolveAsPtr(context));
919919
throw types::TypeCheckingError(
920920
"append",
921-
{ { types::Contract { { types::Typedef("list", ValueType::List), types::Typedef("value", ValueType::Any, /* variadic= */ true) } } } },
921+
{ { types::Contract { { types::Typedef("list", ValueType::List), types::Typedef("value", ValueType::Any, /* is_variadic= */ true) } } } },
922922
args);
923923
}
924924

@@ -1188,8 +1188,11 @@ namespace Ark
11881188
{
11891189
{
11901190
const Value cond = *popAndResolveAsPtr(context);
1191-
if (cond == Builtins::trueSym) // todo: trigger debugger
1192-
{}
1191+
if (cond == Builtins::trueSym)
1192+
{
1193+
initDebugger(context);
1194+
m_debugger->run();
1195+
}
11931196
}
11941197
DISPATCH();
11951198
}
@@ -2254,13 +2257,24 @@ namespace Ark
22542257
fmt::join(arg_names, " ")));
22552258
}
22562259

2257-
void VM::showBacktraceWithException(const std::exception& e, internal::ExecutionContext& context)
2260+
void VM::initDebugger(internal::ExecutionContext& context)
2261+
{
2262+
if (!m_debugger)
2263+
m_debugger = std::make_unique<Debugger>(context);
2264+
else
2265+
m_debugger->saveState(context);
2266+
}
2267+
2268+
void VM::showBacktraceWithException(const std::exception& e, ExecutionContext& context)
22582269
{
22592270
std::string text = e.what();
22602271
if (!text.empty() && text.back() != '\n')
22612272
text += '\n';
22622273
fmt::println("{}", text);
22632274

2275+
if (m_state.m_features & FeatureVMDebugger)
2276+
initDebugger(context);
2277+
22642278
const std::size_t saved_ip = context.ip;
22652279
const std::size_t saved_pp = context.pp;
22662280
const uint16_t saved_sp = context.sp;
@@ -2274,9 +2288,10 @@ namespace Ark
22742288
fmt::styled(saved_pp, fmt::fg(fmt::color::green)),
22752289
fmt::styled(saved_sp, fmt::fg(fmt::color::yellow)));
22762290

2277-
if (m_state.m_features & FeatureVMDebugger)
2291+
if (m_debugger)
22782292
{
2279-
// TODO: launch debugger
2293+
m_debugger->resetContextToErrorState(context);
2294+
m_debugger->run();
22802295
}
22812296

22822297
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION

0 commit comments

Comments
 (0)