From eb98d911f6bc06f05e57d1a203ac833db4566e69 Mon Sep 17 00:00:00 2001 From: T0b1 Date: Mon, 6 May 2024 04:10:13 +0200 Subject: [PATCH] add way to get the address of variable --- src/backend/lldb/lldb_backend.cpp | 244 +++++++++++++++++++----------- src/backend/lldb/lldb_backend.h | 10 +- src/data.h | 3 + src/frontend/window.cpp | 34 +++-- src/frontend/window.h | 5 +- tmp/main | Bin 55232 -> 55272 bytes tmp/main.cpp | 8 +- 7 files changed, 200 insertions(+), 104 deletions(-) diff --git a/src/backend/lldb/lldb_backend.cpp b/src/backend/lldb/lldb_backend.cpp index 25e9aad..f0f25f9 100644 --- a/src/backend/lldb/lldb_backend.cpp +++ b/src/backend/lldb/lldb_backend.cpp @@ -1824,14 +1824,16 @@ std::optional> 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(_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)); @@ -2133,7 +2135,7 @@ std::optional> } 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"); @@ -2958,7 +2960,8 @@ bool LLDBBackend::is_type_equal(data::type_info::TypeID type_id, std::optional LLDBBackend::build_nodes_for_var(lldb::SBValue &val, - std::vector &to_send) + std::vector &to_send, + bool address_of_or_pointer) { using namespace lldb; using namespace data; @@ -2983,7 +2986,8 @@ std::optional 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; } @@ -3012,7 +3016,8 @@ std::optional 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; } @@ -3084,12 +3089,14 @@ std::optional } 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), @@ -3101,7 +3108,8 @@ std::optional } dbgui::data::result::NodeIdx LLDBBackend::build_nodes_for_var_uncached( - lldb::SBValue &val, std::vector &to_send) + lldb::SBValue &val, std::vector &to_send, + bool address_of_or_pointer) { auto lldb_type = val.GetType(); auto type_id = this->build_type_from_lldb_type(lldb_type); @@ -3131,45 +3139,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(var_data.GetUnsignedInt8(err, 0)); - break; - case u16: - res_node.data = static_cast(var_data.GetUnsignedInt16(err, 0)); - break; - case u32: - res_node.data = static_cast(var_data.GetUnsignedInt32(err, 0)); - break; - case u64: - res_node.data = static_cast(var_data.GetUnsignedInt64(err, 0)); - break; - case i8: - res_node.data = static_cast(var_data.GetSignedInt8(err, 0)); - break; - case i16: - res_node.data = static_cast(var_data.GetSignedInt16(err, 0)); - break; - case i32: - res_node.data = static_cast(var_data.GetSignedInt32(err, 0)); - break; - case i64: - res_node.data = static_cast(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{}; - 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(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::max()}; + return res_idx; + } + res_node.data = static_cast(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(var_data.GetUnsignedInt8(err, 0)); + break; + case u16: + res_node.data = + static_cast(var_data.GetUnsignedInt16(err, 0)); + break; + case u32: + res_node.data = + static_cast(var_data.GetUnsignedInt32(err, 0)); + break; + case u64: + res_node.data = + static_cast(var_data.GetUnsignedInt64(err, 0)); + break; + case i8: + res_node.data = static_cast(var_data.GetSignedInt8(err, 0)); + break; + case i16: + res_node.data = static_cast(var_data.GetSignedInt16(err, 0)); + break; + case i32: + res_node.data = static_cast(var_data.GetSignedInt32(err, 0)); + break; + case i64: + res_node.data = static_cast(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{}; + auto &vec = res_node.vec_data(); + auto size = var_data.GetByteSize(); + vec.resize(size); + var_data.ReadRawData(err, 0, vec.data(), size); + break; + } } } @@ -3188,7 +3228,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 &to_send) + std::vector &to_send, bool address_of_or_pointer) { auto lldb_type = val.GetType(); // auto type_id = this->build_type_from_lldb_type(lldb_type); @@ -3216,47 +3256,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(var_data.GetUnsignedInt8(err, 0)); - break; - case u16: - res_node.data = static_cast(var_data.GetUnsignedInt16(err, 0)); - break; - case u32: - res_node.data = static_cast(var_data.GetUnsignedInt32(err, 0)); - break; - case u64: - res_node.data = static_cast(var_data.GetUnsignedInt64(err, 0)); - break; - case i8: - res_node.data = static_cast(var_data.GetSignedInt8(err, 0)); - break; - case i16: - res_node.data = static_cast(var_data.GetSignedInt16(err, 0)); - break; - case i32: - res_node.data = static_cast(var_data.GetSignedInt32(err, 0)); - break; - case i64: - res_node.data = static_cast(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{}; - 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(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(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(var_data.GetUnsignedInt8(err, 0)); + break; + case u16: + res_node.data = + static_cast(var_data.GetUnsignedInt16(err, 0)); + break; + case u32: + res_node.data = + static_cast(var_data.GetUnsignedInt32(err, 0)); + break; + case u64: + res_node.data = + static_cast(var_data.GetUnsignedInt64(err, 0)); + break; + case i8: + res_node.data = static_cast(var_data.GetSignedInt8(err, 0)); + break; + case i16: + res_node.data = static_cast(var_data.GetSignedInt16(err, 0)); + break; + case i32: + res_node.data = static_cast(var_data.GetSignedInt32(err, 0)); + break; + case i64: + res_node.data = static_cast(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{}; + auto &vec = res_node.vec_data(); + auto size = var_data.GetByteSize(); + vec.resize(size); + var_data.ReadRawData(err, 0, vec.data(), size); + break; + } } } diff --git a/src/backend/lldb/lldb_backend.h b/src/backend/lldb/lldb_backend.h index 5125071..6d98ee4 100644 --- a/src/backend/lldb/lldb_backend.h +++ b/src/backend/lldb/lldb_backend.h @@ -86,6 +86,7 @@ namespace dbgui::backend bool used; bool global_or_static; // need to only compare compilation unit and module + bool address_of_or_pointer; std::optional cached_node; }; @@ -135,13 +136,16 @@ namespace dbgui::backend std::optional build_nodes_for_var(lldb::SBValue &val, - std::vector &to_send); + std::vector &to_send, + bool address_of_or_pointer); data::result::NodeIdx build_nodes_for_var_uncached(lldb::SBValue &, - std::vector &to_send); + std::vector &to_send, + bool address_of_or_pointer); void build_nodes_for_var_cached(lldb::SBValue &, data::result::NodeIdx cache_idx, - std::vector &to_send); + std::vector &to_send, + bool address_of_or_pointer); void clear_unused_vars_from_cache(); diff --git a/src/data.h b/src/data.h index 9ff7756..93c0f73 100644 --- a/src/data.h +++ b/src/data.h @@ -256,6 +256,7 @@ namespace dbgui::data Type type; 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; diff --git a/src/frontend/window.cpp b/src/frontend/window.cpp index 7558ae4..ac6f137 100644 --- a/src/frontend/window.cpp +++ b/src/frontend/window.cpp @@ -1119,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; @@ -1172,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)); @@ -1402,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; } diff --git a/src/frontend/window.h b/src/frontend/window.h index 699ece4..f604bc6 100644 --- a/src/frontend/window.h +++ b/src/frontend/window.h @@ -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 &); diff --git a/tmp/main b/tmp/main index 6506200a3107a2dc4da39a24470d5a0fb3bbeb6c..f2f2a674dd308ed6a9f4dc25d071d9f47c46258f 100755 GIT binary patch delta 2705 zcmZWrYiv|S6rQ>JVDG-SwY__{*u7gziw|BR-D;rSRSAn$Q;aAzNVkcp72|^hd_O?c zl&DGZ7!@K0{2}5G!PG}3v|L+!#OLxV)7^Bly3FC+0OV>wB|YwHy##B%UFZKTs1K4gNu5Y ziSHbC@DlLuXOS^e(|-@GY|xAB7dmbD+OfpFpzfWtKU{mM58+h^vv^MlY)(S$hi_oNz|3tvWZY_nNo%7k zd0W33y^Hfz{c|gZUFw9a00#Y0wHG1mslG>vH&H^XRm8Q|YGY=-ftl?D67&q+p>?`& z-EkYMXhM4+^7|}90L+U6LZf@S=gLC%b%XS_!Qz~mN9j3WXQZET zi`ytQ8|ZCdLlPUZu>W$S5<6{Sb|o zo9J9Dcmrnh&0zVA@bMC4j*lxAFxEjI7zXnFlre|5kuNnL$8mY8?jqE*)z`kRBrhO$ zTOCjLH@5Ar;C=Mk>Mat=F+Qj%GRElEf{y6pQ3DMlD|M*ow^dOqenW|aFb4V zHllas8+m~)&NnL2db%-xF`rEv^E%Ja_WUBA?=R#NH}jSB1|xy+ND4T8KBsOWzz!==aJj^jL0jxS*WHS&3q%raL(*K{f{i zg+X&q4KZFSHs($=6|rY3ISeshg3YFc?aVKG6rlNNla>7sO% zx4$I%DRlweCzlkKDj_c1hgmyq1u6?-b1AosKGQ=q!q&&pHFuT&*MefHr%N@r!LC3XkNS^Vjh!XBiJB$ zhN5VTwi;-ig=R-~>&}T@V1sPLWupb+hcqOje&~K=;MPN($iTDc$7#h!*1y8qkA4sE zTd3>sJk{CVXKCBvv^xFAaS~j6$gpN^C;doz`d>>v;*U|+k$I|9zD(M7Bt2EW&d^D4 z6LR+v$!fl-#N9C zhT2{)={vrj?3=bZWE(FN1!fmG7jE6Rm3U6Wi!1C?x*{oc0P& delta 2830 zcmZWrdu&uy8b9aGOzEA@bY@!H+nLtsnNr%qLg@fyltelsYNuFO2K4FS~X+4_AES@steeXgDhyv9N@v%p!ANjgJzy> zXHtk8McEQt$~Fq?C)-G?cumMOlu@%yo3xGBhFGc1vXwT==pA0$^7|%i?W7zDO3-Vg z64~vacWriqI_|Ui<33^i9H+2$KHq$3=Y_T3jC@Kdtzxg~?yqoN z_RY&@tO8UAz8{Ne*dOJm>4LwKkJBa87wOu!37A)tF7{iiUxYzAVHbbCA3?b|uGI+*U4 zZkYLv(ru6;f#$Z2Wf<(%`atE=;28TM5dC@V_~kM%f#gWvAnUGT8CaHn#_ZBRki_iN z*50wLmwf}3Nj7ZRcYiZMM*=ZELFWVI#XDrzj}~u8_k2G6`0VWLN1g{s58klidG~?_ zjJ48Ex~v%u3B37d||sulBi9<(_N=PeziS6|Z21ZaGbs&mZtGCL?N>1K7br2uqO3tIY{?i>T)v^r%?0(9J#i z>M&!Ez<}pT+e}h6_yqo(23N(gOX$21NbO(65}u?*u?DQi##q%N9AQu1`j$3ZMK!He z+~{vAOvL-FZRvjX^P2xFoIZ>8MzZ|Mp8taT|nNTzj%lK7b^5ML&kfnhRml z6%+E`I_7N8PRo;JvN1Z)zKQqIrS@9X3o^C*Fx{4^)w1*HvCJRJ^HqRkpYDGZqR;Kh zQ_x_h5xMkzCUO^FPyT_$Q70ZQAA;b`zuQyvnn%l9>v84XcekgYzilAn##D|B{vACn zAF9#N`NpApAq)*g(CsHfG0gtwp;u++FAvAKprfdhbYZx$JXR&-3|OzimlVEMWu@WH zP8EawF(J)ZUrb0~U&e$4mW>Gs4E7fGDSTJqVTJ!yIH~Zn`L=ylVX+E`PH7`%YFY^ANqp33adv-=Qm=xx z2vc&B%DOI~YXUEr!OW||ngJhT1#AWF8C}Xv8X0Xzvc<-XcwbCdZ8lpqW2G8nRcP5s z33&_1@@K{O(fwlw_G!Y{ zeTW9`S%&Ay-Vc8&;OnU8#8O>eQ?l%$krN61@*9VrOz2LulaxA{n0wth54K0B=j774 zbFq&`;NhH$gTzlI^hp(QjO|py>m*IKgm#}=>77w8xtS6gJ+)H5{8rEoT!vkGjt`>0kfb<~(!^7T*rr(xlZ;#kp!MaOzwW-%j1