add basic array sizing with constant size, tho the parsing is probably not correct
this should just be a normal array index also missing handling to correctly construct the expr path when accessing pointers (maybe just make this node based in the future?)
This commit is contained in:
@@ -143,9 +143,11 @@ void LLDBBackend::handle_state_change(lldb::StateType state)
|
|||||||
{
|
{
|
||||||
spdlog::trace("Got initial state change: {}", static_cast<uint32_t>(state));
|
spdlog::trace("Got initial state change: {}", static_cast<uint32_t>(state));
|
||||||
|
|
||||||
if (state != lldb::StateType::eStateStopped) {
|
if (state != lldb::StateType::eStateStopped)
|
||||||
|
{
|
||||||
// TODO: handle other stopped states, e.g. crashed
|
// TODO: handle other stopped states, e.g. crashed
|
||||||
spdlog::trace("Not handling initial state {}", static_cast<uint32_t>(state));
|
spdlog::trace("Not handling initial state {}",
|
||||||
|
static_cast<uint32_t>(state));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,8 +288,8 @@ void LLDBBackend::prepare_proc_info(
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto frame = _process->GetThreadAtIndex(0).GetFrameAtIndex(0);
|
auto frame = _process->GetThreadAtIndex(0).GetFrameAtIndex(0);
|
||||||
/*const auto regs = frame.GetRegisters();
|
const auto regs = frame.GetRegisters();
|
||||||
const auto len = regs.GetSize();
|
/*const auto len = regs.GetSize();
|
||||||
for (size_t i = 0; i < len; ++i) {
|
for (size_t i = 0; i < len; ++i) {
|
||||||
auto reg_or_set = regs.GetValueAtIndex(i);
|
auto reg_or_set = regs.GetValueAtIndex(i);
|
||||||
if (reg_or_set.GetValueType() == eValueTypeRegister) {
|
if (reg_or_set.GetValueType() == eValueTypeRegister) {
|
||||||
@@ -1530,6 +1532,29 @@ void LLDBBackend::add_data_node(const data::source::Node &node)
|
|||||||
_data_dag.add_edge(node.id, src_id);
|
_data_dag.add_edge(node.id, src_id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case read_array:
|
||||||
|
{
|
||||||
|
const auto &arr_node = std::get<data::source::ReadAsArray>(node.data);
|
||||||
|
auto src_id = arr_node.addr_src_id;
|
||||||
|
if (!_data_dag.nodes.contains(src_id))
|
||||||
|
{
|
||||||
|
printf("Invalid add sequence\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
_data_dag.add_edge(node.id, src_id);
|
||||||
|
|
||||||
|
if (!arr_node.is_const_size)
|
||||||
|
{
|
||||||
|
auto size_id = arr_node.size_src_id;
|
||||||
|
if (!_data_dag.nodes.contains(size_id))
|
||||||
|
{
|
||||||
|
printf("Invalid add sequence\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
_data_dag.add_edge(node.id, size_id);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_dag_linear_valid = false;
|
_dag_linear_valid = false;
|
||||||
@@ -1681,6 +1706,7 @@ std::optional<std::pair<uint16_t, size_t>>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: reserve the slot
|
||||||
auto idx = this->_data_res.size();
|
auto idx = this->_data_res.size();
|
||||||
this->_data_res.resize(idx + 1);
|
this->_data_res.resize(idx + 1);
|
||||||
return idx;
|
return idx;
|
||||||
@@ -2292,6 +2318,121 @@ std::optional<std::pair<uint16_t, size_t>>
|
|||||||
.success = true,
|
.success = true,
|
||||||
.data = std::move(buf)});
|
.data = std::move(buf)});
|
||||||
}
|
}
|
||||||
|
case read_array:
|
||||||
|
{
|
||||||
|
using namespace lldb;
|
||||||
|
uint16_t cache_idx = 0;
|
||||||
|
if (auto found_idx = find_node_for_src_id(node.id); found_idx)
|
||||||
|
{
|
||||||
|
cache_idx = *found_idx;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
cache_idx = get_free_res_slot();
|
||||||
|
// reserve the slot
|
||||||
|
_data_res[cache_idx] = CachedDataRes{.src_id = node.id};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &arr_node = std::get<data::source::ReadAsArray>(node.data);
|
||||||
|
auto res_node = data::result::Node{
|
||||||
|
.idx = cache_idx,
|
||||||
|
.type_id = data::type_info::TypeID::none(),
|
||||||
|
.success = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
size_t addr_id = arr_node.addr_src_id;
|
||||||
|
uint16_t addr_parent_idx = *find_node_for_src_id(addr_id);
|
||||||
|
if (!_data_res[addr_parent_idx]
|
||||||
|
|| !_data_res[addr_parent_idx]->node.success
|
||||||
|
|| _data_res[addr_parent_idx]->node.children.size() != 1)
|
||||||
|
{
|
||||||
|
return check_single_res_changed(std::move(res_node));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t addr_idx = _data_res[addr_parent_idx]->node.children[0];
|
||||||
|
|
||||||
|
if (!_data_res[addr_idx] || !_data_res[addr_idx]->node.success
|
||||||
|
|| _data_res[addr_idx]->node.type_id.type
|
||||||
|
!= data::type_info::Type::ptr)
|
||||||
|
{
|
||||||
|
return check_single_res_changed(std::move(res_node));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!arr_node.is_const_size)
|
||||||
|
{
|
||||||
|
spdlog::trace("read_as_array: non-const size not supported");
|
||||||
|
return check_single_res_changed(std::move(res_node));
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto addr = _data_res[addr_idx]->node.get_primitive<uint64_t>(0);
|
||||||
|
spdlog::trace("read_as_array: addr: {:X}", addr);
|
||||||
|
|
||||||
|
const auto pointee_type_idx = _data_res[addr_idx]->node.type_id.idx;
|
||||||
|
if (!_types[pointee_type_idx])
|
||||||
|
{
|
||||||
|
spdlog::trace("Found no pointee type for read_as_array");
|
||||||
|
return check_single_res_changed(std::move(res_node));
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pointee_type = _types[pointee_type_idx]->first;
|
||||||
|
if (pointee_type.IsArrayType())
|
||||||
|
{
|
||||||
|
// TODO: should we do this until there is no array left?
|
||||||
|
pointee_type = pointee_type.GetArrayElementType();
|
||||||
|
}
|
||||||
|
spdlog::trace("read_as_array: pointee_type valid?: {}",
|
||||||
|
pointee_type.IsValid());
|
||||||
|
|
||||||
|
std::string type_buf;
|
||||||
|
format_type(pointee_type, type_buf);
|
||||||
|
spdlog::trace("read_as_array: pointee_type: {}", type_buf);
|
||||||
|
|
||||||
|
auto arr_type = pointee_type.GetArrayType(arr_node.size_const);
|
||||||
|
|
||||||
|
spdlog::trace("read_as_array: arr_type valid?: {}", arr_type.IsValid());
|
||||||
|
type_buf.clear();
|
||||||
|
format_type(arr_type, type_buf);
|
||||||
|
spdlog::trace("read_as_array: arr_type: {}", type_buf);
|
||||||
|
|
||||||
|
char buf[128], buf2[32];
|
||||||
|
/*std::snprintf(buf2, sizeof(buf2), "%zX", node.id);
|
||||||
|
std::snprintf(buf, sizeof(buf), "*((%s *)0x%zX)", arr_type.GetName(),
|
||||||
|
addr);
|
||||||
|
auto arr_val = _target.CreateValueFromExpression(buf2, buf);
|
||||||
|
if (!arr_val.IsValid())
|
||||||
|
{
|
||||||
|
spdlog::trace("read_as_array: arr_val not valid");
|
||||||
|
return check_single_res_changed(std::move(res_node));
|
||||||
|
}*/
|
||||||
|
std::snprintf(buf, sizeof(buf), "(char*)0x%zX", addr);
|
||||||
|
auto tmp_val = _target.CreateValueFromExpression("arr_tmp", buf);
|
||||||
|
if (!tmp_val.IsValid())
|
||||||
|
{
|
||||||
|
spdlog::trace("read_as_array: tmp_val not valid");
|
||||||
|
return check_single_res_changed(std::move(res_node));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::snprintf(buf, sizeof(buf), "%zX", node.id);
|
||||||
|
auto arr_val = tmp_val.CreateValueFromAddress(buf, addr, arr_type);
|
||||||
|
if (!arr_val.IsValid())
|
||||||
|
{
|
||||||
|
spdlog::trace("read_as_array: arr_val not valid");
|
||||||
|
return check_single_res_changed(std::move(res_node));
|
||||||
|
}
|
||||||
|
//arr_val = arr_val.Cast(arr_type);
|
||||||
|
|
||||||
|
auto res_idx = this->build_nodes_for_var(arr_val, data_res, false);
|
||||||
|
if (!res_idx)
|
||||||
|
{
|
||||||
|
return check_single_res_changed(std::move(res_node));
|
||||||
|
}
|
||||||
|
|
||||||
|
spdlog::trace(
|
||||||
|
"Got res for {}: {} ({})", node.id, *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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Unhandled data type\n");
|
printf("Unhandled data type\n");
|
||||||
|
|||||||
12
src/data.h
12
src/data.h
@@ -355,6 +355,15 @@ namespace dbgui::data
|
|||||||
size_t src_id;
|
size_t src_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ReadAsArray {
|
||||||
|
size_t addr_src_id;
|
||||||
|
union {
|
||||||
|
size_t size_src_id;
|
||||||
|
uint64_t size_const;
|
||||||
|
};
|
||||||
|
bool is_const_size;
|
||||||
|
};
|
||||||
|
|
||||||
struct Node
|
struct Node
|
||||||
{
|
{
|
||||||
enum class Type : uint8_t
|
enum class Type : uint8_t
|
||||||
@@ -364,12 +373,13 @@ namespace dbgui::data
|
|||||||
line_entry,
|
line_entry,
|
||||||
locals,
|
locals,
|
||||||
read_cstr,
|
read_cstr,
|
||||||
|
read_array,
|
||||||
};
|
};
|
||||||
|
|
||||||
size_t id;
|
size_t id;
|
||||||
Type type;
|
Type type;
|
||||||
// when adding something here, remember to update LLDBBackend::add_data_node
|
// when adding something here, remember to update LLDBBackend::add_data_node
|
||||||
std::variant<std::monostate, Source, Disassemble, LineEntry, ReadAsCStr>
|
std::variant<std::monostate, Source, Disassemble, LineEntry, ReadAsCStr, ReadAsArray>
|
||||||
data;
|
data;
|
||||||
};
|
};
|
||||||
} // namespace source
|
} // namespace source
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "imgui_internal.h"
|
#include "imgui_internal.h"
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <charconv>
|
||||||
|
|
||||||
using namespace dbgui;
|
using namespace dbgui;
|
||||||
using namespace dbgui::frontend;
|
using namespace dbgui::frontend;
|
||||||
@@ -818,6 +819,9 @@ namespace
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<size_t> parse_array_desc_inner(ParseState& state, size_t addr_src_id);
|
||||||
|
|
||||||
|
|
||||||
// <data desc> = <data desc>.<data desc> | <array desc> | <ident> | <reg>
|
// <data desc> = <data desc>.<data desc> | <array desc> | <ident> | <reg>
|
||||||
std::optional<size_t> parse_data_desc(ParseState &state)
|
std::optional<size_t> parse_data_desc(ParseState &state)
|
||||||
{
|
{
|
||||||
@@ -917,6 +921,27 @@ namespace
|
|||||||
}
|
}
|
||||||
state.path_buf.append(ident);
|
state.path_buf.append(ident);
|
||||||
|
|
||||||
|
const auto create_var_node = [&](bool address_of) -> size_t {
|
||||||
|
spdlog::trace("Parsing data_desc: creating variable source (address?: {}) with path {}",
|
||||||
|
address_of, state.path_buf);
|
||||||
|
auto node_id = state.frontend->target->data_node_id++;
|
||||||
|
state.nodes.push_back(data::source::Node{
|
||||||
|
.id = node_id,
|
||||||
|
.type = data::source::Node::Type::source,
|
||||||
|
.data =
|
||||||
|
data::source::Source{
|
||||||
|
.type = data::source::Source::Type::variable,
|
||||||
|
.data =
|
||||||
|
data::source::Source::Variable{
|
||||||
|
.expr_path = state.path_buf,
|
||||||
|
.address_of_or_pointer = address_of,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
state.path_buf.clear();
|
||||||
|
return node_id;
|
||||||
|
};
|
||||||
|
|
||||||
// differentiate between <data desc>, <array desc> and end of <data desc>
|
// differentiate between <data desc>, <array desc> and end of <data desc>
|
||||||
const auto peek_token_opt = peek_token(state);
|
const auto peek_token_opt = peek_token(state);
|
||||||
if (peek_token_opt)
|
if (peek_token_opt)
|
||||||
@@ -934,30 +959,85 @@ namespace
|
|||||||
|
|
||||||
if (peek_token == WatchToken::bracket_open)
|
if (peek_token == WatchToken::bracket_open)
|
||||||
{
|
{
|
||||||
// TODO: parse <array desc>
|
// parse <array desc>
|
||||||
assert(0);
|
// consume token
|
||||||
return {};
|
next_token(state);
|
||||||
|
const auto src_node = create_var_node(true);
|
||||||
|
const auto res = parse_array_desc_inner(state, src_node);
|
||||||
|
if (!res) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we expect a closing bracket
|
||||||
|
const auto closing_opt = next_token(state);
|
||||||
|
if (!closing_opt) {
|
||||||
|
spdlog::trace("Failed to parse data_desc: Expected closing bracket in array_desc but got none");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*closing_opt != WatchToken::bracket_close) {
|
||||||
|
spdlog::trace("Failed to parse data_desc: Expected closing bracket in array_desc but got {}", token_to_str(state, *closing_opt));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
spdlog::trace("Parsing data_desc: creating variable source with path {}",
|
|
||||||
state.path_buf);
|
|
||||||
// something else, end of <data desc>
|
// something else, end of <data desc>
|
||||||
auto node_id = state.frontend->target->data_node_id++;
|
return create_var_node(false);
|
||||||
state.nodes.push_back(data::source::Node{
|
}
|
||||||
.id = node_id,
|
|
||||||
.type = data::source::Node::Type::source,
|
|
||||||
.data =
|
|
||||||
data::source::Source{
|
|
||||||
.type = data::source::Source::Type::variable,
|
|
||||||
.data =
|
|
||||||
data::source::Source::Variable{
|
|
||||||
.expr_path = state.path_buf,
|
|
||||||
.address_of_or_pointer = false,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
|
// <array desc> = <ident>\[<arrsize spec>|<arrpath>\]
|
||||||
|
std::optional<size_t> parse_array_desc_inner(ParseState& state, size_t addr_src_id) {
|
||||||
|
// the bracket has already been consumed by the caller
|
||||||
|
spdlog::trace("Parsing array_desc_inner");
|
||||||
|
|
||||||
|
// for now only support constant sized arrays
|
||||||
|
const auto peek_opt = peek_token(state);
|
||||||
|
if (!peek_opt) {
|
||||||
|
spdlog::trace("Failed to parse array_desc_inner: end of token");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto peek_token = *peek_opt;
|
||||||
|
if (!token_is_literal(peek_token)) {
|
||||||
|
spdlog::trace("Failed to parse array_desc_inner: Expected literal but got {}", token_to_str(state, peek_token));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// consume
|
||||||
|
next_token(state);
|
||||||
|
|
||||||
|
auto literal = token_literal(state, peek_token);
|
||||||
|
spdlog::trace("Parsing array_desc_inner: Got literal {}", literal);
|
||||||
|
|
||||||
|
int base = 10;
|
||||||
|
if (literal.starts_with("0x")) {
|
||||||
|
base = 16;
|
||||||
|
literal.remove_prefix(2);
|
||||||
|
}
|
||||||
|
uint64_t size = 0;
|
||||||
|
|
||||||
|
const auto parse_res = std::from_chars(literal.begin(), literal.end(), size, base);
|
||||||
|
if (parse_res.ec != std::errc{} || parse_res.ptr != literal.end()) {
|
||||||
|
spdlog::trace("Failed parsing array_desc_inner: Literal is not a number");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto node_id = state.frontend->target->data_node_id++;
|
||||||
|
spdlog::trace("Parsing array_desc_inner: creating read_as_array with size {} and id {}",
|
||||||
|
size, node_id);
|
||||||
|
state.nodes.push_back(data::source::Node{
|
||||||
|
.id = node_id,
|
||||||
|
.type = data::source::Node::Type::read_array,
|
||||||
|
.data =
|
||||||
|
data::source::ReadAsArray{
|
||||||
|
.addr_src_id = addr_src_id,
|
||||||
|
.size_const = size,
|
||||||
|
.is_const_size = true,
|
||||||
|
},
|
||||||
|
});
|
||||||
return node_id;
|
return node_id;
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
Reference in New Issue
Block a user