Compare commits
6 Commits
d4e4fc8c5a
...
oldDAGBack
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdf015302a | ||
|
|
eb98d911f6 | ||
|
|
53899ef3c3 | ||
|
|
843ca4dd5f | ||
|
|
4f065dca4d | ||
|
|
608cec26b1 |
@@ -83,6 +83,4 @@ SpacesInSquareBrackets: 'false'
|
||||
Standard: Cpp11
|
||||
TabWidth: '2'
|
||||
UseTab: ForIndentation
|
||||
CommentPragmas: '^\\.+'
|
||||
|
||||
...
|
||||
CommentPragmas: '^\\.+'
|
||||
2
deps/imgui
vendored
2
deps/imgui
vendored
Submodule deps/imgui updated: 3418d50949...ebb8d78102
@@ -30,9 +30,10 @@ namespace
|
||||
|
||||
LLDBBackend::~LLDBBackend() {}
|
||||
|
||||
LLDBBackend::LLDBBackend(std::string filename)
|
||||
LLDBBackend::LLDBBackend(std::string filename, bool stop_at_entry)
|
||||
{
|
||||
_filename = filename;
|
||||
_filename = filename;
|
||||
_stop_at_entry = stop_at_entry;
|
||||
char buf[256];
|
||||
buf[0] = '\0';
|
||||
pthread_getname_np(pthread_self(), buf, sizeof(buf));
|
||||
@@ -60,11 +61,24 @@ void LLDBBackend::start()
|
||||
}
|
||||
_process = _target.Launch(listener, argv, nullptr, nullptr, nullptr, nullptr,
|
||||
cwd.c_str(), lldb::LaunchFlags::eLaunchFlagNone,
|
||||
true, error);
|
||||
_stop_at_entry, error);
|
||||
{
|
||||
pthread_setname_np(pthread_self(), buf);
|
||||
}
|
||||
|
||||
if (!_stop_at_entry)
|
||||
{
|
||||
// Create a breakpoint at main
|
||||
auto bp = _target.BreakpointCreateByName("main");
|
||||
if (!bp.IsValid())
|
||||
{
|
||||
spdlog::warn("Failed to create breakpoint for main");
|
||||
} else
|
||||
{
|
||||
_hidden_main_bp = bp.GetID();
|
||||
}
|
||||
}
|
||||
|
||||
_msg_thread = std::thread{[this]() {
|
||||
auto ptr = this->shared_from_this();
|
||||
static_cast<LLDBBackend *>(ptr.get())->run_msg_loop();
|
||||
@@ -146,6 +160,12 @@ void LLDBBackend::handle_state_change(lldb::StateType state)
|
||||
this->check_frame_changes();
|
||||
this->check_data_changes();
|
||||
|
||||
if (!_stop_at_entry)
|
||||
{
|
||||
// TODO: if we delete this, lldb continues the process again (?)
|
||||
//_target.BreakpointDelete(_hidden_main_bp);
|
||||
}
|
||||
|
||||
if (state == StateType::eStateStopped)
|
||||
{
|
||||
_state = TargetState::paused;
|
||||
@@ -171,7 +191,11 @@ void LLDBBackend::handle_state_change(lldb::StateType state)
|
||||
auto sel_thread = _process->GetSelectedThread();
|
||||
auto change_reason = StateChangeReason::unknown;
|
||||
auto extra = 0;
|
||||
switch (sel_thread.GetStopReason())
|
||||
auto stop_reason = sel_thread.GetStopReason();
|
||||
// step over seems to cause the reason to be eStopReasonPlanComplete, when pausing the stop reason seems to be eStopReasonSignal
|
||||
spdlog::trace("Thread stopped because of reason {}",
|
||||
static_cast<int>(stop_reason));
|
||||
switch (stop_reason)
|
||||
{
|
||||
case eStopReasonBreakpoint:
|
||||
{
|
||||
@@ -1804,14 +1828,16 @@ std::optional<std::pair<uint16_t, size_t>>
|
||||
return check_single_res_changed(std::move(res_node));
|
||||
}
|
||||
|
||||
auto res_idx = this->build_nodes_for_var(var, data_res);
|
||||
auto res_idx = this->build_nodes_for_var(var, data_res,
|
||||
info.address_of_or_pointer);
|
||||
if (!res_idx)
|
||||
{
|
||||
return check_single_res_changed(std::move(res_node));
|
||||
}
|
||||
|
||||
printf("Got res for %s: %u (%u)\n", info.expr_path.c_str(), *res_idx,
|
||||
_data_res[*res_idx]->node.type_id.type);
|
||||
spdlog::trace(
|
||||
"Got res for {}: {} ({})", info.expr_path, *res_idx,
|
||||
static_cast<uint8_t>(_data_res[*res_idx]->node.type_id.type));
|
||||
res_node.success = true;
|
||||
res_node.children.push_back(*res_idx);
|
||||
return check_single_res_changed(std::move(res_node));
|
||||
@@ -2113,7 +2139,7 @@ std::optional<std::pair<uint16_t, size_t>>
|
||||
}
|
||||
printf("Got local %s\n", name);
|
||||
|
||||
auto res_idx = this->build_nodes_for_var(var, data_res);
|
||||
auto res_idx = this->build_nodes_for_var(var, data_res, false);
|
||||
if (!res_idx)
|
||||
{
|
||||
printf("No result\n");
|
||||
@@ -2938,7 +2964,8 @@ bool LLDBBackend::is_type_equal(data::type_info::TypeID type_id,
|
||||
|
||||
std::optional<dbgui::data::result::NodeIdx>
|
||||
LLDBBackend::build_nodes_for_var(lldb::SBValue &val,
|
||||
std::vector<data::result::Node> &to_send)
|
||||
std::vector<data::result::Node> &to_send,
|
||||
bool address_of_or_pointer)
|
||||
{
|
||||
using namespace lldb;
|
||||
using namespace data;
|
||||
@@ -2963,7 +2990,8 @@ std::optional<dbgui::data::result::NodeIdx>
|
||||
for (auto i = 0; i < _var_cache.size(); ++i)
|
||||
{
|
||||
auto &entry = _var_cache[i];
|
||||
if (!entry.global_or_static)
|
||||
if (!entry.global_or_static
|
||||
|| entry.address_of_or_pointer != address_of_or_pointer)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -2992,7 +3020,8 @@ std::optional<dbgui::data::result::NodeIdx>
|
||||
for (auto i = 0; i < _var_cache.size(); ++i)
|
||||
{
|
||||
auto &entry = _var_cache[i];
|
||||
if (entry.global_or_static)
|
||||
if (entry.global_or_static
|
||||
|| entry.address_of_or_pointer != address_of_or_pointer)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -3064,12 +3093,14 @@ std::optional<dbgui::data::result::NodeIdx>
|
||||
}
|
||||
auto node_idx = *_var_cache[*cache_entry].cached_node;
|
||||
_var_cache[*cache_entry].used = true;
|
||||
this->build_nodes_for_var_cached(val, node_idx, to_send);
|
||||
this->build_nodes_for_var_cached(val, node_idx, to_send,
|
||||
address_of_or_pointer);
|
||||
|
||||
return node_idx;
|
||||
}
|
||||
|
||||
auto idx = this->build_nodes_for_var_uncached(val, to_send);
|
||||
auto idx =
|
||||
this->build_nodes_for_var_uncached(val, to_send, address_of_or_pointer);
|
||||
_var_cache.push_back(
|
||||
VarCacheEntry{.lldb_val = val,
|
||||
.sym_ctx = val.GetFrame().GetSymbolContext(true),
|
||||
@@ -3081,7 +3112,8 @@ std::optional<dbgui::data::result::NodeIdx>
|
||||
}
|
||||
|
||||
dbgui::data::result::NodeIdx LLDBBackend::build_nodes_for_var_uncached(
|
||||
lldb::SBValue &val, std::vector<data::result::Node> &to_send)
|
||||
lldb::SBValue &val, std::vector<data::result::Node> &to_send,
|
||||
bool address_of_or_pointer)
|
||||
{
|
||||
auto lldb_type = val.GetType();
|
||||
auto type_id = this->build_type_from_lldb_type(lldb_type);
|
||||
@@ -3111,45 +3143,77 @@ dbgui::data::result::NodeIdx LLDBBackend::build_nodes_for_var_uncached(
|
||||
|
||||
// TODO: error handling
|
||||
auto err = lldb::SBError{};
|
||||
switch (no_alias_type.type)
|
||||
if (address_of_or_pointer)
|
||||
{
|
||||
using enum data::type_info::Type;
|
||||
|
||||
case _bool:
|
||||
case u8:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetUnsignedInt8(err, 0));
|
||||
break;
|
||||
case u16:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetUnsignedInt16(err, 0));
|
||||
break;
|
||||
case u32:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetUnsignedInt32(err, 0));
|
||||
break;
|
||||
case u64:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetUnsignedInt64(err, 0));
|
||||
break;
|
||||
case i8:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetSignedInt8(err, 0));
|
||||
break;
|
||||
case i16:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetSignedInt16(err, 0));
|
||||
break;
|
||||
case i32:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetSignedInt32(err, 0));
|
||||
break;
|
||||
case i64:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetSignedInt64(err, 0));
|
||||
break;
|
||||
case f32: res_node.data = var_data.GetFloat(err, 0); break;
|
||||
case f64: res_node.data = var_data.GetDouble(err, 0); break;
|
||||
default:
|
||||
if (no_alias_type.type == data::type_info::Type::ptr)
|
||||
{
|
||||
res_node.data = std::vector<uint8_t>{};
|
||||
auto &vec = res_node.vec_data();
|
||||
auto size = var_data.GetByteSize();
|
||||
vec.resize(size);
|
||||
var_data.ReadRawData(err, 0, vec.data(), size);
|
||||
break;
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetAddress(err, 0));
|
||||
} else
|
||||
{
|
||||
// so we don't need to create a new type for the pointer i think so just replace the node type
|
||||
res_node.type_id =
|
||||
data::type_info::TypeID{.type = data::type_info::Type::ptr,
|
||||
.sub_type = type_id.type,
|
||||
.idx = type_id.idx};
|
||||
auto addr_of = val.AddressOf();
|
||||
auto data = addr_of.GetData();
|
||||
if (!data.IsValid())
|
||||
{
|
||||
// copypasted from above
|
||||
to_send.push_back(res_node);
|
||||
_data_res[res_idx] =
|
||||
CachedDataRes{.node = std::move(res_node),
|
||||
.no_delete_on_src_delete = true,
|
||||
.src_id = std::numeric_limits<size_t>::max()};
|
||||
return res_idx;
|
||||
}
|
||||
res_node.data = static_cast<uint64_t>(data.GetAddress(err, 0));
|
||||
}
|
||||
} else
|
||||
{
|
||||
switch (no_alias_type.type)
|
||||
{
|
||||
using enum data::type_info::Type;
|
||||
|
||||
case _bool:
|
||||
case u8:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetUnsignedInt8(err, 0));
|
||||
break;
|
||||
case u16:
|
||||
res_node.data =
|
||||
static_cast<uint64_t>(var_data.GetUnsignedInt16(err, 0));
|
||||
break;
|
||||
case u32:
|
||||
res_node.data =
|
||||
static_cast<uint64_t>(var_data.GetUnsignedInt32(err, 0));
|
||||
break;
|
||||
case u64:
|
||||
res_node.data =
|
||||
static_cast<uint64_t>(var_data.GetUnsignedInt64(err, 0));
|
||||
break;
|
||||
case i8:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetSignedInt8(err, 0));
|
||||
break;
|
||||
case i16:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetSignedInt16(err, 0));
|
||||
break;
|
||||
case i32:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetSignedInt32(err, 0));
|
||||
break;
|
||||
case i64:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetSignedInt64(err, 0));
|
||||
break;
|
||||
case f32: res_node.data = var_data.GetFloat(err, 0); break;
|
||||
case f64: res_node.data = var_data.GetDouble(err, 0); break;
|
||||
default:
|
||||
{
|
||||
res_node.data = std::vector<uint8_t>{};
|
||||
auto &vec = res_node.vec_data();
|
||||
auto size = var_data.GetByteSize();
|
||||
vec.resize(size);
|
||||
var_data.ReadRawData(err, 0, vec.data(), size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3168,7 +3232,7 @@ dbgui::data::result::NodeIdx LLDBBackend::build_nodes_for_var_uncached(
|
||||
|
||||
void LLDBBackend::build_nodes_for_var_cached(
|
||||
lldb::SBValue &val, data::result::NodeIdx cache_idx,
|
||||
std::vector<data::result::Node> &to_send)
|
||||
std::vector<data::result::Node> &to_send, bool address_of_or_pointer)
|
||||
{
|
||||
auto lldb_type = val.GetType();
|
||||
// auto type_id = this->build_type_from_lldb_type(lldb_type);
|
||||
@@ -3196,47 +3260,81 @@ void LLDBBackend::build_nodes_for_var_cached(
|
||||
_types[no_alias_type.idx]->second.member_types);
|
||||
}
|
||||
|
||||
// TODO: this is copypasted from build_nodes_for_var_uncached so that should be consolidated in the future
|
||||
// TODO: error handling
|
||||
auto err = lldb::SBError{};
|
||||
switch (no_alias_type.type)
|
||||
{
|
||||
using enum data::type_info::Type;
|
||||
|
||||
case _bool:
|
||||
case u8:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetUnsignedInt8(err, 0));
|
||||
break;
|
||||
case u16:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetUnsignedInt16(err, 0));
|
||||
break;
|
||||
case u32:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetUnsignedInt32(err, 0));
|
||||
break;
|
||||
case u64:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetUnsignedInt64(err, 0));
|
||||
break;
|
||||
case i8:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetSignedInt8(err, 0));
|
||||
break;
|
||||
case i16:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetSignedInt16(err, 0));
|
||||
break;
|
||||
case i32:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetSignedInt32(err, 0));
|
||||
break;
|
||||
case i64:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetSignedInt64(err, 0));
|
||||
break;
|
||||
case f32: res_node.data = var_data.GetFloat(err, 0); break;
|
||||
case f64: res_node.data = var_data.GetDouble(err, 0); break;
|
||||
default:
|
||||
if (address_of_or_pointer)
|
||||
{
|
||||
if (no_alias_type.type == data::type_info::Type::ptr)
|
||||
{
|
||||
res_node.data = std::vector<uint8_t>{};
|
||||
auto &vec = res_node.vec_data();
|
||||
auto size = var_data.GetByteSize();
|
||||
vec.resize(size);
|
||||
var_data.ReadRawData(err, 0, vec.data(), size);
|
||||
break;
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetAddress(err, 0));
|
||||
} else
|
||||
{
|
||||
// so we don't need to create a new type for the pointer i think so just replace the node type
|
||||
res_node.type_id =
|
||||
data::type_info::TypeID{.type = data::type_info::Type::ptr,
|
||||
.sub_type = type_id.type,
|
||||
.idx = type_id.idx};
|
||||
auto addr_of = val.AddressOf();
|
||||
auto data = addr_of.GetData();
|
||||
if (!data.IsValid())
|
||||
{
|
||||
// copypasted from above
|
||||
if (_data_res[cache_idx]->node.success)
|
||||
{
|
||||
to_send.push_back(res_node);
|
||||
_data_res[cache_idx]->node.success = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
res_node.data = static_cast<uint64_t>(data.GetAddress(err, 0));
|
||||
}
|
||||
} else
|
||||
{
|
||||
switch (no_alias_type.type)
|
||||
{
|
||||
using enum data::type_info::Type;
|
||||
|
||||
case _bool:
|
||||
case u8:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetUnsignedInt8(err, 0));
|
||||
break;
|
||||
case u16:
|
||||
res_node.data =
|
||||
static_cast<uint64_t>(var_data.GetUnsignedInt16(err, 0));
|
||||
break;
|
||||
case u32:
|
||||
res_node.data =
|
||||
static_cast<uint64_t>(var_data.GetUnsignedInt32(err, 0));
|
||||
break;
|
||||
case u64:
|
||||
res_node.data =
|
||||
static_cast<uint64_t>(var_data.GetUnsignedInt64(err, 0));
|
||||
break;
|
||||
case i8:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetSignedInt8(err, 0));
|
||||
break;
|
||||
case i16:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetSignedInt16(err, 0));
|
||||
break;
|
||||
case i32:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetSignedInt32(err, 0));
|
||||
break;
|
||||
case i64:
|
||||
res_node.data = static_cast<uint64_t>(var_data.GetSignedInt64(err, 0));
|
||||
break;
|
||||
case f32: res_node.data = var_data.GetFloat(err, 0); break;
|
||||
case f64: res_node.data = var_data.GetDouble(err, 0); break;
|
||||
default:
|
||||
{
|
||||
res_node.data = std::vector<uint8_t>{};
|
||||
auto &vec = res_node.vec_data();
|
||||
auto size = var_data.GetByteSize();
|
||||
vec.resize(size);
|
||||
var_data.ReadRawData(err, 0, vec.data(), size);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -86,11 +86,12 @@ namespace dbgui::backend
|
||||
bool used;
|
||||
bool
|
||||
global_or_static; // need to only compare compilation unit and module
|
||||
bool address_of_or_pointer;
|
||||
std::optional<data::result::NodeIdx> cached_node;
|
||||
};
|
||||
|
||||
// TODO: source_init_file: false
|
||||
LLDBBackend(std::string filename);
|
||||
LLDBBackend(std::string filename, bool stop_at_entry);
|
||||
virtual ~LLDBBackend();
|
||||
|
||||
void start() override;
|
||||
@@ -135,13 +136,16 @@ namespace dbgui::backend
|
||||
|
||||
std::optional<data::result::NodeIdx>
|
||||
build_nodes_for_var(lldb::SBValue &val,
|
||||
std::vector<data::result::Node> &to_send);
|
||||
std::vector<data::result::Node> &to_send,
|
||||
bool address_of_or_pointer);
|
||||
data::result::NodeIdx
|
||||
build_nodes_for_var_uncached(lldb::SBValue &,
|
||||
std::vector<data::result::Node> &to_send);
|
||||
std::vector<data::result::Node> &to_send,
|
||||
bool address_of_or_pointer);
|
||||
void build_nodes_for_var_cached(lldb::SBValue &,
|
||||
data::result::NodeIdx cache_idx,
|
||||
std::vector<data::result::Node> &to_send);
|
||||
std::vector<data::result::Node> &to_send,
|
||||
bool address_of_or_pointer);
|
||||
|
||||
void clear_unused_vars_from_cache();
|
||||
|
||||
@@ -161,7 +165,9 @@ namespace dbgui::backend
|
||||
std::thread _msg_thread;
|
||||
|
||||
// process state
|
||||
bool _first_run = true;
|
||||
bool _first_run = true;
|
||||
bool _stop_at_entry = false;
|
||||
lldb::break_id_t _hidden_main_bp;
|
||||
TargetState _state = TargetState::stopped;
|
||||
std::vector<RegSet> _reg_sets = {};
|
||||
std::vector<Thread> _threads = {};
|
||||
|
||||
@@ -254,8 +254,9 @@ namespace dbgui::data
|
||||
struct TypeInfo
|
||||
{
|
||||
Type type;
|
||||
uint64_t byte_size;
|
||||
TypeID enum_base;
|
||||
uint64_t byte_size;
|
||||
// TODO: maybe we want a string array somewhere else? Harder to garbage collect but we save some space here
|
||||
std::string display_name;
|
||||
std::string internal_name;
|
||||
// sike, lldb doesnt give this to us
|
||||
@@ -324,6 +325,8 @@ namespace dbgui::data
|
||||
struct Variable
|
||||
{
|
||||
std::string expr_path;
|
||||
// if this is set we want the address of whatever we got or the pointer value in case what we have is a pointer
|
||||
bool address_of_or_pointer = false;
|
||||
};
|
||||
|
||||
Type type;
|
||||
|
||||
@@ -9,12 +9,13 @@
|
||||
using namespace dbgui;
|
||||
using namespace dbgui::frontend;
|
||||
|
||||
Target::Target(std::string filename)
|
||||
Target::Target(std::string filename, bool stop_at_entry)
|
||||
{
|
||||
state = TargetState::startup;
|
||||
this->filename = filename;
|
||||
id = 0;
|
||||
backend = std::make_shared<backend::LLDBBackend>(this->filename.c_str());
|
||||
backend = std::make_shared<backend::LLDBBackend>(this->filename.c_str(),
|
||||
stop_at_entry);
|
||||
}
|
||||
|
||||
Frontend::Frontend()
|
||||
@@ -43,6 +44,11 @@ void Frontend::run_frame()
|
||||
ImGui::ShowStackToolWindow();
|
||||
}
|
||||
|
||||
if (_draw_demo_window)
|
||||
{
|
||||
ImGui::ShowDemoWindow();
|
||||
}
|
||||
|
||||
this->handle_msgs();
|
||||
this->draw_open_popup();
|
||||
this->draw_header();
|
||||
@@ -154,6 +160,7 @@ void Frontend::draw_header()
|
||||
{
|
||||
ImGui::MenuItem("Metrics", nullptr, &_draw_metric_window);
|
||||
ImGui::MenuItem("Stack Tool", nullptr, &_draw_stack_tool);
|
||||
ImGui::MenuItem("Demo Window", nullptr, &_draw_demo_window);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMainMenuBar();
|
||||
@@ -314,10 +321,13 @@ void Frontend::draw_open_popup()
|
||||
|
||||
if (ImGui::Button("Start"))
|
||||
{
|
||||
this->target = Target{_open_popup_name_buf.data()};
|
||||
this->target =
|
||||
Target{_open_popup_name_buf.data(), _open_popup_stop_at_entry};
|
||||
this->target->backend->start();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::Checkbox("Stop at _start", &_open_popup_stop_at_entry);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,10 +44,12 @@ namespace dbgui::frontend
|
||||
|
||||
bool _draw_metric_window = false;
|
||||
bool _draw_stack_tool = false;
|
||||
bool _draw_demo_window = false;
|
||||
|
||||
bool _draw_open_popup = false;
|
||||
ImGuiID _open_popup_id = 0;
|
||||
std::vector<char> _open_popup_name_buf = {};
|
||||
bool _open_popup_stop_at_entry = false;
|
||||
|
||||
std::vector<Window> _windows = {};
|
||||
};
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace dbgui::frontend
|
||||
bool is_cstr = false;
|
||||
};
|
||||
|
||||
Target(std::string filename);
|
||||
Target(std::string filename, bool stop_at_entry);
|
||||
|
||||
std::optional<uint16_t> data_idx_for_src_id(size_t id)
|
||||
{
|
||||
|
||||
@@ -908,6 +908,8 @@ bool SourceWindow::draw(Frontend &frontend)
|
||||
|
||||
ImGui::GetWindowDrawList()->AddTriangleFilled(
|
||||
pos, p2, p3, IM_COL32(227, 197, 103, 255));
|
||||
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0,
|
||||
ImGui::GetColorU32(ImVec4(1.f, 1.f, 1.f, 0.2f)));
|
||||
}
|
||||
|
||||
// TODO: write custom code to catch mouse clicks in the whole cell, including padding
|
||||
@@ -1117,13 +1119,15 @@ bool WatchWindow::draw(Frontend &frontend)
|
||||
if (slot.buf[0] != '\0')
|
||||
{
|
||||
frontend.target->backend->remove_data_node(slot.id);
|
||||
|
||||
using namespace data::source;
|
||||
frontend.target->backend->add_data_node(Node{
|
||||
.id = slot.id,
|
||||
.type = Node::Type::source,
|
||||
.data =
|
||||
Source{.type = Source::Type::variable,
|
||||
.data = Source::Variable{.expr_path = slot.buf}}});
|
||||
frontend.target->backend->add_data_node(
|
||||
Node{.id = slot.id,
|
||||
.type = Node::Type::source,
|
||||
.data = Source{.type = Source::Type::variable,
|
||||
.data = Source::Variable{
|
||||
.expr_path = slot.buf,
|
||||
.address_of_or_pointer = false}}});
|
||||
}
|
||||
|
||||
slot.bak = slot.buf;
|
||||
@@ -1170,14 +1174,23 @@ bool WatchWindow::draw(Frontend &frontend)
|
||||
{
|
||||
if (this->add_slot_buf[0] != '\0')
|
||||
{
|
||||
auto id = frontend.target->data_node_id++;
|
||||
auto id = frontend.target->data_node_id++;
|
||||
const auto *expr_path_buf = this->add_slot_buf;
|
||||
bool address_of_or_pointer = false;
|
||||
if (expr_path_buf[0] == '+')
|
||||
{
|
||||
address_of_or_pointer = true;
|
||||
++expr_path_buf;
|
||||
}
|
||||
|
||||
using namespace data::source;
|
||||
frontend.target->backend->add_data_node(Node{
|
||||
.id = id,
|
||||
.type = Node::Type::source,
|
||||
.data =
|
||||
Source{.type = Source::Type::variable,
|
||||
.data = Source::Variable{.expr_path = this->add_slot_buf}}});
|
||||
.data = Source{.type = Source::Type::variable,
|
||||
.data = Source::Variable{.expr_path = expr_path_buf,
|
||||
.address_of_or_pointer =
|
||||
address_of_or_pointer}}});
|
||||
extra_slots.push_back(ExtraSlot{.id = id, .bak = this->add_slot_buf});
|
||||
memcpy(extra_slots.back().buf, this->add_slot_buf,
|
||||
sizeof(this->add_slot_buf));
|
||||
@@ -1374,7 +1387,8 @@ void WatchWindow::draw_value(Frontend &frontend,
|
||||
}
|
||||
|
||||
expr_path.push_back(ExprPathPart{
|
||||
.ident = std::string_view{name_begin, name_end - name_begin},
|
||||
.ident = std::string_view{name_begin, static_cast<size_t>(
|
||||
name_end - name_begin)},
|
||||
.deref = false});
|
||||
this->draw_value(frontend, member.type_id, member.name, node_idx,
|
||||
off + member.offset, expr_path);
|
||||
@@ -1390,7 +1404,8 @@ void WatchWindow::draw_value(Frontend &frontend,
|
||||
frontend.target->types[type_id.idx].byte_size / member_size;
|
||||
|
||||
expr_path.push_back(ExprPathPart{
|
||||
.ident = std::string_view{name_begin, name_end - name_begin},
|
||||
.ident = std::string_view{name_begin,
|
||||
static_cast<size_t>(name_end - name_begin)},
|
||||
.array = true});
|
||||
|
||||
char buf[32];
|
||||
@@ -1398,8 +1413,11 @@ void WatchWindow::draw_value(Frontend &frontend,
|
||||
for (size_t i = 0; i < el_count; ++i)
|
||||
{
|
||||
std::snprintf(buf, sizeof(buf), "[%lu]", i);
|
||||
auto expr_path_size = expr_path.size();
|
||||
expr_path.back().array_idx = i;
|
||||
this->draw_value(frontend, member_ty_id, buf, node_idx,
|
||||
off + member_off, expr_path);
|
||||
assert(expr_path.size() == expr_path_size);
|
||||
member_off += member_size;
|
||||
}
|
||||
|
||||
|
||||
@@ -139,8 +139,9 @@ namespace dbgui::frontend
|
||||
struct ExprPathPart
|
||||
{
|
||||
std::string_view ident;
|
||||
bool deref = false;
|
||||
bool array = false;
|
||||
bool deref = false;
|
||||
bool array = false;
|
||||
uint64_t array_idx = 0;
|
||||
};
|
||||
|
||||
bool draw(Frontend &);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
namespace {
|
||||
struct MyType {
|
||||
int data;
|
||||
int data[3];
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@ void helper_fn();
|
||||
void helper_fn2();
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
MyType tmp = MyType{10};
|
||||
while (tmp.data != 0) {
|
||||
MyType tmp = MyType{{10, 5, 19}};
|
||||
while (tmp.data[0] != 0) {
|
||||
helper_fn();
|
||||
helper_fn2();
|
||||
tmp.data--;
|
||||
tmp.data[0]--;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
13
todos.txt
13
todos.txt
@@ -4,3 +4,16 @@
|
||||
- visualization for branches (draw arror if branch is taken (or in both cases?))
|
||||
- allow (partial) path override for symbol source paths
|
||||
- check if classes with base classes work
|
||||
- next item: array variable specifier
|
||||
- search/show/open all files in the debug symbols of the executable
|
||||
- allow setting breakpoint by name + manually set them with a textbox
|
||||
- make stop/restart buttons work
|
||||
- make it work if you open a file again that it doesn't break
|
||||
- add a context menu option to display the type of a variable in the watch window
|
||||
- auto-switch to disassembly if there is no source (auto-switch to source if there is one for the first time?)
|
||||
- allow for copying + changing the display type for a variable in the watch window (esp. important for locals)
|
||||
- when stopping, still keep the binary around (so like a workspace)
|
||||
- add smth that detects if the binary changes and adds a button to reload/restart it
|
||||
- automatically detect cycles in pointer and stop the UI recursion if so
|
||||
|
||||
old imgui commit: a02315e1c4c80f94008779bfa0cc552542cb2f08
|
||||
44
watchsyntax.txt
Normal file
44
watchsyntax.txt
Normal file
@@ -0,0 +1,44 @@
|
||||
mystruct.ptr, mystruct.arrsize
|
||||
|
||||
mystruct.ptr[$1].field.ptr[$2], mystruct.arrsize, mystruct.ptr[$1].field.arrsize
|
||||
|
||||
mystruct.ptr.field
|
||||
|
||||
mystruct.ptr[.arrsize].field.ptr[.arrsize]
|
||||
|
||||
cast<MyType*>(mystruct.ptr).field, dbl
|
||||
|
||||
%rax
|
||||
%rbx
|
||||
|
||||
(int[mystruct.arraysize]*)(mystruct.ptr)
|
||||
|
||||
builtin functions? (e.g. casts)
|
||||
|
||||
|
||||
<watch desc> = <data desc>, <format spec>
|
||||
|
||||
<data desc> = <data desc>.<data desc> | <array desc> | <ident> | <reg>
|
||||
|
||||
<array desc> = <ident>\[<arrsize spec>|<arrpath>\]
|
||||
|
||||
<arrsize spec> = [<arrpath>]..<arrpath>
|
||||
|
||||
<arrpath> = (\^*<ident path>) | <num literal> | #<num literal>
|
||||
|
||||
<ident path> = <ident> | <ident>.<ident path>
|
||||
|
||||
<reg> = $<ident>
|
||||
|
||||
$ for registers
|
||||
# for special indices
|
||||
% for various builtins
|
||||
|
||||
|
||||
<format spec> = <type>[<num literal>[x<num literal>]]
|
||||
|
||||
<type> = <base type>
|
||||
|
||||
<base type> = i8 | i16 | i32 | i64 | i128 | u8 | u16 | u32 | u64 | u128 | f32 | f64 | flt | dbl | str | cstr
|
||||
|
||||
this is still missing the syntax to search in upper frames for variables
|
||||
Reference in New Issue
Block a user