diff --git a/src/backend/lldb/lldb_backend.cpp b/src/backend/lldb/lldb_backend.cpp index 2dd6097..a9be681 100644 --- a/src/backend/lldb/lldb_backend.cpp +++ b/src/backend/lldb/lldb_backend.cpp @@ -1487,6 +1487,17 @@ void LLDBBackend::add_data_node(const data::source::Node &node) _data_dag.add_edge(node.id, src_id); break; } + case read_cstr: + { + auto src_id = std::get(node.data).src_id; + if (!_data_dag.nodes.contains(src_id)) + { + printf("Invalid add sequence\n"); + exit(1); + } + _data_dag.add_edge(node.id, src_id); + break; + } } _dag_linear_valid = false; @@ -2159,9 +2170,11 @@ std::optional> cache_idx = get_free_res_slot(); } - size_t addr_id = std::get(node.data).src_id; - uint16_t addr_idx = *find_node_for_src_id(addr_id); - if (!_data_res[addr_idx] || !_data_res[addr_idx]->node.success) + size_t addr_id = std::get(node.data).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(data::result::Node{ .idx = cache_idx, @@ -2170,7 +2183,11 @@ std::optional> }); } - if (_data_res[addr_idx]->node.type_id.type != data::type_info::Type::ptr) + 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(data::result::Node{ .idx = cache_idx, @@ -2179,7 +2196,7 @@ std::optional> }); } - auto addr = std::get(_data_res[addr_idx]->node.data); + auto addr = _data_res[addr_idx]->node.get_primitive(0); std::vector buf{}; char tmp_buf[256]; diff --git a/src/frontend/frontend.cpp b/src/frontend/frontend.cpp index f7a1486..631c22e 100644 --- a/src/frontend/frontend.cpp +++ b/src/frontend/frontend.cpp @@ -101,6 +101,10 @@ void Frontend::run_frame() auto &entry = this->target->expr_cache[i]; if (!entry.used_this_frame) { + if (entry.is_cstr) + { + this->target->backend->remove_data_node(entry.id2); + } this->target->backend->remove_data_node(entry.id); this->target->expr_cache.erase(this->target->expr_cache.begin() + i); } else diff --git a/src/frontend/target.h b/src/frontend/target.h index 782adac..790831d 100644 --- a/src/frontend/target.h +++ b/src/frontend/target.h @@ -82,7 +82,9 @@ namespace dbgui::frontend { std::string expr_path; size_t id; + size_t id2; bool used_this_frame = false; + bool is_cstr = false; }; Target(std::string filename); @@ -115,26 +117,37 @@ namespace dbgui::frontend return &*data_res_nodes[*idx]; } - size_t find_or_create_expr_path(std::string &&path) + size_t find_or_create_expr_path(std::string &&path, bool is_cstr = false) { for (auto &entry : expr_cache) { if (entry.expr_path == path) { entry.used_this_frame = true; - return entry.id; + return entry.is_cstr ? entry.id2 : entry.id; } } using namespace data::source; - auto id = this->id++; + auto id = this->id++; + size_t cstr_id = -1; this->backend->add_data_node( Node{.id = id, .type = Node::Type::source, .data = Source{.type = Source::Type::variable, .data = Source::Variable{.expr_path = path}}}); - expr_cache.push_back(ExprCacheEntry{ - .expr_path = std::move(path), .id = id, .used_this_frame = true}); + if (is_cstr) + { + cstr_id = this->id++; + this->backend->add_data_node(Node{.id = cstr_id, + .type = Node::Type::read_cstr, + .data = ReadAsCStr{.src_id = id}}); + } + expr_cache.push_back(ExprCacheEntry{.expr_path = std::move(path), + .id = id, + .id2 = cstr_id, + .used_this_frame = true, + .is_cstr = is_cstr}); return id; } diff --git a/src/frontend/window.cpp b/src/frontend/window.cpp index 7adfee0..17fd2a7 100644 --- a/src/frontend/window.cpp +++ b/src/frontend/window.cpp @@ -1283,9 +1283,10 @@ void WatchWindow::draw_value(Frontend &frontend, if (!is_editing) { - tree_open = - ImGui::TreeNodeEx(tree_id_buf, ImGuiTreeNodeFlags_SpanFullWidth, "%.*s", - static_cast(name_end - name_begin), name_begin); + tree_open = ImGui::TreeNodeEx( + tree_id_buf, + ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_SpanAvailWidth, + "%.*s", static_cast(name_end - name_begin), name_begin); if (name.index() == 1 && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && ImGui::IsItemHovered()) @@ -1542,20 +1543,33 @@ void WatchWindow::draw_value(Frontend &frontend, { // TODO: make this func be able to not print the "outer" line // and just accept a bool to only draw the containing value - std::string path{"*"}; + std::string path{}; + if (type_id.sub_type != Type::i8) + { + // TODO: better check if this is really a string + path = "*"; + } // why cant i just path name_begin, name_end to string_view? :[ construct_expr_path( path, expr_path, std::string_view{name_begin, static_cast(name_end - name_begin)}); - auto src_id = - frontend.target->find_or_create_expr_path(std::move(path)); + auto src_id = frontend.target->find_or_create_expr_path( + std::move(path), type_id.sub_type == Type::i8); auto res_idx = frontend.target->data_idx_for_src_id(src_id); if (res_idx) { const auto &node = *frontend.target->data_res_nodes[*res_idx]; - if (node.success && node.children.size() == 1) + if (type_id.sub_type == Type::i8 && node.success) + { + // TODO: make span whole row (see https://github.com/ocornut/imgui/issues/3565) + assert(node.type_id.type == Type::custom); + assert(node.vec_data().back() == '\0'); + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(1); + ImGui::TextWrapped("\"%s\"", node.vec_data().data()); + } else if (node.success && node.children.size() == 1) { auto data_idx = node.children[0]; const auto &data_node =