diff --git a/CMakeLists.txt b/CMakeLists.txt index ceb68d2..ce61185 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ set(DBGUI_SOURCES src/main.cpp src/frontend/frontend.cpp src/frontend/window.cpp src/backend/backend.cpp src/backend/lldb/lldb_backend.cpp + src/data.cpp ${IMGUI_SOURCES} ${DBGUI_HEADERS}) diff --git a/src/backend/backend.cpp b/src/backend/backend.cpp index 5df92db..2333cc8 100644 --- a/src/backend/backend.cpp +++ b/src/backend/backend.cpp @@ -58,6 +58,13 @@ void Backend::send_data_result(BackToFront::DataResult &&info) BackToFront::MsgType::data_result, std::move(info)); this->send_msg(std::move(msg)); } +void Backend::remove_data_node(uint16_t idx) +{ + auto msg = std::make_unique( + BackToFront::MsgType::remove_data_node, + std::move(BackToFront::RemoveDataNode{.node = idx})); + this->send_msg(std::move(msg)); +} void Backend::send_selected_thread_changed(uint16_t idx) { auto msg = std::make_unique( diff --git a/src/backend/debug_backend.h b/src/backend/debug_backend.h index 506790a..15c08aa 100644 --- a/src/backend/debug_backend.h +++ b/src/backend/debug_backend.h @@ -26,8 +26,8 @@ namespace dbgui::backend virtual void cont() = 0; virtual void pause() = 0; - virtual void add_data_node(const data::DataNode &) = 0; - virtual void remove_data_node(uint64_t id) = 0; + virtual void add_data_node(const data::source::Node &) = 0; + virtual void remove_data_node(uint64_t id) = 0; virtual void add_breakpoint(uint64_t addr, size_t id) = 0; virtual bool add_breakpoint(const char *file, uint32_t line, size_t id) = 0; @@ -68,6 +68,7 @@ namespace dbgui::backend void send_frame_changed(BackToFront::FrameChanged &&); void send_frame_removed(BackToFront::FrameRemoved &&); void send_data_result(BackToFront::DataResult &&); + void remove_data_node(uint16_t); void send_selected_thread_changed(uint16_t idx); void send_selected_frame_changed(uint16_t idx); diff --git a/src/backend/lldb/lldb_backend.cpp b/src/backend/lldb/lldb_backend.cpp index 2557970..b984f3c 100644 --- a/src/backend/lldb/lldb_backend.cpp +++ b/src/backend/lldb/lldb_backend.cpp @@ -10,6 +10,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -150,7 +154,8 @@ void LLDBBackend::handle_state_change(lldb::StateType state) } } - this->dump_threads(); + //this->dump_threads(); + this->dump_variables(); switch (state) { @@ -452,6 +457,476 @@ void LLDBBackend::dump_threads() } } +std::optional + basic_type_id(lldb::BasicType type) +{ + using namespace dbgui::data::type_info; + using namespace lldb; + switch (type) + { + case eBasicTypeVoid: return TypeID::basic(Type::_void); + case eBasicTypeChar: + case eBasicTypeSignedChar: return TypeID::basic(Type::i8); + case eBasicTypeUnsignedChar: return TypeID::basic(Type::u8); + case eBasicTypeWChar: + case eBasicTypeSignedWChar: + case eBasicTypeChar16: + case eBasicTypeShort: return TypeID::basic(Type::i16); + case eBasicTypeUnsignedWChar: + case eBasicTypeUnsignedShort: return TypeID::basic(Type::u16); + case eBasicTypeChar32: + case eBasicTypeInt: return TypeID::basic(Type::i32); + case eBasicTypeUnsignedInt: return TypeID::basic(Type::u32); + case eBasicTypeLong: + // TODO: decide based on target platform + return TypeID::basic(Type::i32); + case eBasicTypeUnsignedLong: + // TODO: decide based on target platform + return TypeID::basic(Type::u32); + case eBasicTypeLongLong: return TypeID::basic(Type::i64); + case eBasicTypeUnsignedLongLong: return TypeID::basic(Type::u64); + case eBasicTypeInt128: return TypeID::basic(Type::i128); + case eBasicTypeUnsignedInt128: return TypeID::basic(Type::u128); + case eBasicTypeBool: return TypeID::basic(Type::_bool); + case eBasicTypeFloat: return TypeID::basic(Type::f32); + case eBasicTypeDouble: return TypeID::basic(Type::f64); + case eBasicTypeLongDouble: return TypeID::basic(Type::f128); + case eBasicTypeNullPtr: + // TODO: target platform dependent + return TypeID::basic(Type::u64); + + // unhandled + case eBasicTypeHalf: + case eBasicTypeFloatComplex: + case eBasicTypeDoubleComplex: + case eBasicTypeLongDoubleComplex: + case eBasicTypeObjCID: + case eBasicTypeObjCClass: + case eBasicTypeObjCSel: + case eBasicTypeOther: + case eBasicTypeInvalid: return {}; + } + + assert(0); + exit(1); +} + +dbgui::data::type_info::TypeID + parse_type_inner(std::vector &out_vec, + lldb::SBType &type) +{ + using namespace lldb; + using namespace dbgui::data; + if (auto tmp = basic_type_id(type.GetBasicType()); tmp) + { + return *tmp; + } + + if (type.IsPointerType() || type.IsReferenceType()) + { + auto inner_type = SBType{}; + if (type.IsPointerType()) + { + inner_type = type.GetPointeeType(); + } else + { + inner_type = type.GetDereferencedType(); + } + + auto inner_id = parse_type_inner(out_vec, inner_type); + if (inner_id.is_basic()) + { + return type_info::TypeID{ + .type = type_info::Type::ptr, .sub_type = inner_id.type, .idx = 0}; + } else if (inner_id.type == type_info::Type::ptr) + { + auto idx = static_cast(out_vec.size()); + // TODO: byte_size + out_vec.push_back(type_info::TypeInfo{ + .type = type_info::Type::ptr, + .byte_size = 8, + .name = std::string{inner_type.GetDisplayTypeName()}, + .member_types = inner_id}); + return type_info::TypeID{.type = type_info::Type::ptr, + .sub_type = type_info::Type::ptr, + .idx = idx}; + } else + { + return type_info::TypeID{.type = type_info::Type::ptr, + .sub_type = inner_id.type, + .idx = inner_id.idx}; + } + } + + // should not be a basic type + if (type.GetBasicType() != eBasicTypeInvalid || type.IsPointerType() + || type.IsReferenceType()) + { + assert(0); + exit(1); + } + + auto name = type.GetDisplayTypeName(); + auto type_copy = type; + while (type_copy.IsTypedefType()) + { + type_copy = type_copy.GetTypedefedType(); + } + + // TODO: create entry for named basic types? + if (auto tmp = basic_type_id(type_copy.GetBasicType()); tmp) + { + return *tmp; + } + + printf("Name: %s\n", name); + printf("TrueName: %s\n", type_copy.GetDisplayTypeName()); + printf("Pointer: %u\n", type_copy.IsPointerType()); + printf("Ref: %u\n", type_copy.IsReferenceType()); + printf("Func: %u\n", type_copy.IsFunctionType()); + printf("Poly: %u\n", type_copy.IsPolymorphicClass()); + printf("Array: %u\n", type_copy.IsArrayType()); + printf("Vec: %u\n", type_copy.IsVectorType()); + printf("Typedef: %u\n", type_copy.IsTypedefType()); + printf("Anonymous: %u\n", type_copy.IsAnonymousType()); + printf("ScopedEnum: %u\n", type_copy.IsScopedEnumerationType()); + printf("Aggregate: %u\n", type_copy.IsAggregateType()); + printf("EnumIntTypeValid: %u\n", + type_copy.GetEnumerationIntegerType().IsValid()); + + // note: type can be both array and aggregate + if (type_copy.IsArrayType()) + { + out_vec.push_back(type_info::TypeInfo{.type = type_info::Type::array, + .byte_size = type.GetByteSize(), + .name = std::string{name}}); + uint32_t self_idx = out_vec.size() - 1; + auto inner_type = type_copy.GetArrayElementType(); + auto inner_id = parse_type_inner(out_vec, inner_type); + out_vec[self_idx].member_types = inner_id; + return type_info::TypeID{.type = type_info::Type::array, .idx = self_idx}; + } else if (auto base_type = type_copy.GetEnumerationIntegerType(); + base_type.IsValid()) + { + auto base_id = parse_type_inner(out_vec, base_type); + out_vec.push_back(type_info::TypeInfo{ + .type = type_info::Type::_enum, + .byte_size = type_copy.GetByteSize(), + .enum_base = base_id, + .name = std::string{name}, + .member_types = std::vector{}}); + uint32_t self_idx = out_vec.size() - 1; + + auto enum_list = type_copy.GetEnumMembers(); + uint32_t len = enum_list.GetSize(); + for (uint32_t i = 0; i < len; ++i) + { + auto member = enum_list.GetTypeEnumMemberAtIndex(i); + auto member_type = member.GetType(); + auto member_id = parse_type_inner(out_vec, member_type); + auto name = member.GetName(); + if (!name) + { + name = ""; + } + auto val = member.GetValueAsUnsigned(); + out_vec[self_idx].member_vec().push_back(type_info::MemberInfo{ + .name = name, .type_id = member_id, .enum_val = val}); + } + return type_info::TypeID{.type = type_info::Type::_enum, .idx = self_idx}; + } else if (type_copy.IsAggregateType()) + { + out_vec.push_back(type_info::TypeInfo{ + .type = type_info::Type::complex, + .byte_size = type_copy.GetByteSize(), + .name = std::string{name}, + .member_types = std::vector{}}); + uint32_t self_idx = out_vec.size() - 1; + uint32_t len = type_copy.GetNumberOfFields(); + for (uint32_t i = 0; i < len; ++i) + { + auto member = type_copy.GetFieldAtIndex(i); + auto member_type = member.GetType(); + auto member_id = parse_type_inner(out_vec, member_type); + auto name = member.GetName(); + if (!name) + { + name = ""; + } + auto offset = member.GetOffsetInBytes(); + auto bitfield_size = member.GetBitfieldSizeInBits(); + if (bitfield_size != 0) + { + offset = member.GetOffsetInBits(); + } + out_vec[self_idx].member_vec().push_back( + type_info::MemberInfo{.name = name, + .type_id = member_id, + .bitfield_size = bitfield_size, + .offset = offset}); + } + return type_info::TypeID{.type = type_info::Type::complex, .idx = self_idx}; + } else + { + printf("Unknown type encountered!\n"); + assert(0); + exit(1); + } +} + +void format_type(lldb::SBType &type, std::string &out) +{ + using namespace lldb; + using namespace dbgui::data; + + auto vec = std::vector{}; + auto type_id = parse_type_inner(vec, type); + + out += "Types:\n"; + for (size_t i = 0; i < vec.size(); ++i) + { + char buf[32]; + std::snprintf(buf, sizeof(buf), "Type %lu:\n", i); + out += buf; + vec[i].format(vec, out); + out += "\n\n"; + } + out += "Formatted type: "; + type_id.format(out); + out += "\n"; + + /*switch (type.GetBasicType()) + { + case eBasicTypeVoid: out = "void"; return; + case eBasicTypeChar: + case eBasicTypeSignedChar: out = "i8"; return; + case eBasicTypeUnsignedChar: out = "u8"; return; + case eBasicTypeWChar: + case eBasicTypeSignedWChar: + case eBasicTypeChar16: + case eBasicTypeShort: out = "i16"; return; + case eBasicTypeUnsignedWChar: + case eBasicTypeUnsignedShort: out = "u16"; return; + case eBasicTypeChar32: + case eBasicTypeInt: out = "i32"; return; + case eBasicTypeUnsignedInt: out = "u32"; return; + case eBasicTypeLong: + // TODO: decide based on target platform + out = "i32"; + return; + case eBasicTypeUnsignedLong: + // TODO: decide based on target platform + out = "u32"; + return; + case eBasicTypeLongLong: out = "i64"; return; + case eBasicTypeUnsignedLongLong: out = "u64"; return; + case eBasicTypeInt128: out = "i128"; return; + case eBasicTypeUnsignedInt128: out = "u128"; return; + case eBasicTypeBool: out = "bool"; return; + case eBasicTypeFloat: out = "f32"; return; + case eBasicTypeDouble: out = "f64"; return; + case eBasicTypeLongDouble: out = "f128"; return; + case eBasicTypeNullPtr: + // TODO: target platform dependent + out = "u64"; + return; + + // unhandled + case eBasicTypeHalf: + case eBasicTypeFloatComplex: + case eBasicTypeDoubleComplex: + case eBasicTypeLongDoubleComplex: + case eBasicTypeObjCID: + case eBasicTypeObjCClass: + case eBasicTypeObjCSel: + case eBasicTypeOther: out = ""; return; + + case eBasicTypeInvalid: + { + if (type.IsPointerType()) + { + auto inner_type = type.GetPointeeType(); + std::string tmp = {}; + format_type(inner_type, tmp); + out = "ptr<"; + out += tmp; + out += ">"; + } else if (type.IsReferenceType()) + { + auto inner_type = type.GetDereferencedType(); + std::string tmp = {}; + format_type(inner_type, tmp); + out = "ref<"; + out += tmp; + out += ">"; + } else + { + auto vec = std::vector{}; + parse_type_inner(vec, type); + dbgui::data::type_info::TypeInfo::format(vec, 0, out); + return; + } + } + + default: assert(0); exit(1); + }*/ +} + +#if 0 +namespace llvm +{ + int DisableABIBreakingChecks; +} +#endif + +void LLDBBackend::dump_variables() +{ + using namespace lldb; + auto thread = _process->GetSelectedThread(); + auto frame = thread.GetSelectedFrame(); + + if (!thread.IsValid() || !frame.IsValid()) + { + return; + } + + printf("Dumping Variables...\n"); + if (!_last_frame || !_last_frame->IsEqual(frame)) + { + printf("Frame changed!\n"); + _last_frame = frame; + } + auto stream = SBStream{}; + for (auto &[var, touched] : _locals) + { + touched = false; + stream.Clear(); + var.GetExpressionPath(stream); + auto name = var.GetName(); + if (!name) + { + name = ""; + } + printf("Var %.*s ('%s'): %lu\n", static_cast(stream.GetSize()), + stream.GetData(), name, var.GetID()); + stream.Clear(); + var.GetDescription(stream); + printf(" -> Desc: %.*s\n", static_cast(stream.GetSize()), + stream.GetData()); + printf(" -> Valid: %u\n", var.IsValid()); + printf(" -> InScope: %u\n", var.IsInScope()); + printf(" -> ValueDidChange: %u\n", var.GetValueDidChange()); + printf(" -> IsSynthetic: %u\n", var.IsSynthetic()); + printf(" -> IsDynamic: %u\n", var.IsDynamic()); + printf(" -> Value: %s\n", var.GetValue()); + auto loc = var.GetLocation(); + if (!loc) + { + loc = ""; + } + printf(" -> Location: %s\n", loc); + /*auto static_var = var.GetStaticValue(); + printf(" -> Static: '%s' %lu\n", static_var.GetName(), static_var.GetID()); + printf(" -> Valid: %u\n", static_var.IsValid()); + printf(" -> InScope: %u\n", static_var.IsInScope()); + printf(" -> ValueDidChange: %u\n", static_var.GetValueDidChange()); + printf(" -> IsSynthetic: %u\n", static_var.IsSynthetic()); + printf(" -> IsDynamic: %u\n", static_var.IsDynamic()); + printf(" -> Value: %s\n", static_var.GetValue());*/ + } + + auto fill_locals = _locals.empty(); + + // static includes globals and thread local values + // can't include them as we have no way of finding out + // whether a static is defined inside our scope or not + auto list = frame.GetVariables(true, true, false, true); + auto len = list.GetSize(); + + for (uint32_t i = 0; i < len; ++i) + { + auto var = list.GetValueAtIndex(i); + if (!var.IsValid()) + { + continue; + } + + /*for (auto &[prev_var, touched] : _locals) { + if (prev_var.) + }*/ + + stream.Clear(); + var.GetDescription(stream); + printf("Var %u: %.*s\n", i, static_cast(stream.GetSize()), + stream.GetData()); + + stream.Clear(); + var.GetExpressionPath(stream); + printf("ExprPath: %.*s\n", static_cast(stream.GetSize()), + stream.GetData()); + + if (fill_locals) + { + _locals.push_back(std::make_pair(var, true)); + } + + auto var_frame = var.GetFrame(); + stream.Clear(); + var_frame.GetDescription(stream); + printf(" -> VarFrame: %.*s\n", static_cast(stream.GetSize()), + stream.GetData()); + + auto decl = var.GetDeclaration(); + stream.Clear(); + decl.GetDescription(stream); + printf(" -> Declaration: %.*s\n", static_cast(stream.GetSize()), + stream.GetData()); + + auto type_name = var.GetTypeName() ?: ""; + auto type_display_name = var.GetDisplayTypeName() ?: ""; + printf(" -> TypeName: '%s', DisplayName: '%s'\n", type_name, + type_display_name); + + auto type = var.GetType(); + auto type_filter = var.GetTypeFilter(); + + stream.Clear(); + type.GetDescription(stream, eDescriptionLevelFull); + printf(" -> TypeDesc: %.*s\n", static_cast(stream.GetSize()), + stream.GetData()); + + stream.Clear(); + type_filter.GetDescription(stream, eDescriptionLevelFull); + printf(" -> TypeFilter: %.*s\n", static_cast(stream.GetSize()), + stream.GetData()); + + stream.Clear(); + var.GetTypeFormat().GetDescription(stream, eDescriptionLevelFull); + printf(" -> TypeFormat: %.*s\n", static_cast(stream.GetSize()), + stream.GetData()); + + stream.Clear(); + type.GetDescription(stream, eDescriptionLevelVerbose); + printf(" -> Type: %.*s\n", static_cast(stream.GetSize()), + stream.GetData()); + uint32_t num_fields = type.GetNumberOfFields(); + printf(" -> NumberOfFields: %u\n", num_fields); + // TODO: look through typedef to check whether it is a primitive type + for (uint32_t i = 0; i < num_fields; ++i) + { + auto field = type.GetFieldAtIndex(i); + stream.Clear(); + field.GetType().GetDescription(stream, eDescriptionLevelFull); + printf(" -> Field %u: '%s': %.*s\n", i, field.GetName(), + static_cast(stream.GetSize()), stream.GetData()); + } + + std::string fmt{}; + format_type(type, fmt); + printf(" -> Custom Type Info: %s\n", fmt.c_str()); + } +} + bool LLDBBackend::step_into(bool source_step) { std::lock_guard g{_data_lock}; @@ -955,7 +1430,7 @@ void LLDBBackend::check_frame_changes() } } -void LLDBBackend::add_data_node(const data::DataNode &node) +void LLDBBackend::add_data_node(const data::source::Node &node) { std::lock_guard g{_data_lock}; @@ -972,14 +1447,14 @@ void LLDBBackend::add_data_node(const data::DataNode &node) // TODO: make this somehow automatic switch (node.type) { - using enum data::DataNode::Type; + using enum data::source::Node::Type; - case data_source: + case source: // nothing to do rn break; case disassemble: { - auto src_id = std::get(node.data).src_id; + auto src_id = std::get(node.data).src_id; if (!_data_dag.nodes.contains(src_id)) { printf("Invalid add sequence\n"); @@ -990,7 +1465,7 @@ void LLDBBackend::add_data_node(const data::DataNode &node) } case line_entry: { - auto src_id = std::get(node.data).src_id; + auto src_id = std::get(node.data).src_id; if (!_data_dag.nodes.contains(src_id)) { printf("Invalid add sequence\n"); @@ -1024,12 +1499,30 @@ void LLDBBackend::remove_data_node(size_t id) } _data_nodes.erase(it); - auto cache_it = - std::find_if(_cached_data_results.begin(), _cached_data_results.end(), - [id](const auto &el) { return el.id == id; }); - if (cache_it != _cached_data_results.end()) + std::vector to_delete{}; + to_delete.push_back(id); + size_t old_size = 0; + while (to_delete.size() != old_size) { - _cached_data_results.erase(cache_it); + auto cur_size = to_delete.size(); + for (size_t i = old_size; i < cur_size; ++i) + { + for (size_t j = 0; j < _data_res.size(); ++j) + { + if (_data_res[j] && _data_res[j]->parent_node == to_delete[i]) + { + to_delete.push_back(j); + } + } + } + + old_size = cur_size; + } + + for (auto idx : to_delete) + { + this->remove_data_node(id); + _data_res[idx] = {}; } _dag_linear_valid = false; @@ -1055,103 +1548,169 @@ void LLDBBackend::check_data_changes() exit(1); } - const auto &result_it = - std::find_if(_cached_data_results.begin(), _cached_data_results.end(), - [id](const auto &el) { return el.id == id; }); - auto new_res = this->calc_data_res(*node_it); + auto res_vec = std::vector{}; + auto src_id_mapping = this->calc_data_res(*node_it, res_vec); - // TODO: for disasm it would be better to check if the bytes have changed - auto should_send = true; - if (result_it != _cached_data_results.end()) + if (!res_vec.empty()) { - if (new_res.success == result_it->success - && new_res.type == result_it->type) + // TODO: queue and send at once to prevent UI lag? + this->send_data_result( + {.nodes = std::move(res_vec), .src_node_id = src_id_mapping}); + } + } +} + +// TODO: call node src_node? +std::optional> + LLDBBackend::calc_data_res(const data::source::Node &node, + std::vector &data_res) +{ + const auto find_node_for_src_id = + [this](size_t src_id) -> std::optional { + for (uint16_t i = 0; i < this->_data_res.size(); ++i) + { + if (!this->_data_res[i]) { - if (new_res.data.size() == result_it->data.size()) + continue; + } + + if (this->_data_res[i]->src_id == src_id) + { + return i; + } + } + + return {}; + }; + + const auto get_free_res_slot = [this]() -> uint16_t { + for (uint16_t i = 0; i < this->_data_res.size(); ++i) + { + if (!this->_data_res[i]) + { + return i; + } + } + + auto idx = this->_data_res.size(); + this->_data_res.resize(idx + 1); + return idx; + }; + + const auto check_single_res_changed = + [this, node, &data_res]( + data::result::Node &&res) -> std::optional> { + auto val_changed = true; + if (this->_data_res.size() > res.idx && this->_data_res[res.idx]) + { + auto &cached = *this->_data_res[res.idx]; + if (cached.src_id == node.id) + { + if (!cached.child_node) { - if (!std::memcmp(new_res.data.data(), result_it->data.data(), - new_res.data.size())) + if (cached.node.success == res.success + && cached.node.type_id == res.type_id + && cached.node.data == res.data) { - should_send = false; + val_changed = false; } } } } - if (!should_send) + if (!val_changed) { - continue; + return {}; } - if (result_it == _cached_data_results.end()) + if (this->_data_res.size() <= res.idx) { - _cached_data_results.push_back(new_res); - } else - { - *result_it = new_res; + this->_data_res.resize(res.idx + 1); } + this->_data_res[res.idx] = CachedDataRes{.node = res, + .child_node = false, + .parent_node = 0, + .parent_member_id = 0, + .src_id = node.id}; - // TODO: queue and send at once to prevent UI lag? - this->send_data_result( - BackToFront::DataResult{.result = std::move(new_res)}); - } -} + auto idx = res.idx; + data_res.push_back(std::move(res)); + return std::make_pair(idx, node.id); + }; -dbgui::data::DataResult LLDBBackend::calc_data_res(const data::DataNode &node) -{ switch (node.type) { - using enum data::DataNode::Type; + using enum data::source::Node::Type; - case data_source: + case source: { - const auto &src_data = std::get(node.data); + const auto &src_data = std::get(node.data); switch (src_data.type) { - using enum data::DataSource::Type; + using enum data::source::Source::Type; case reg: { - const auto &info = std::get(src_data.data); - if (info.set >= _reg_sets.size() - || info.idx >= _reg_sets[info.set].values.size()) + uint16_t cache_idx = 0; + if (auto found_idx = find_node_for_src_id(node.id); found_idx) { - return data::DataResult{ - .id = node.id, - .success = false, - }; + cache_idx = *found_idx; + } else + { + cache_idx = get_free_res_slot(); } - // TODO: these indices *could* (very not likely) be incorrect - // TODO: for now, pretend every register is u64 - return data::DataResult{ - .id = node.id, - .success = true, - .type = data::TypeInfo{.type = data::TypeInfo::Type::u64}, - .data = _reg_sets[info.set].values[info.idx]}; + + auto res = + data::result::Node{.idx = cache_idx, + .type_id = data::type_info::TypeID::none(), + .success = false}; + { + const auto &info = + std::get(src_data.data); + if (info.set < _reg_sets.size() + && info.idx < _reg_sets[info.set].values.size()) + { + res.success = true; + res.type_id = data::type_info::TypeID::u64(); + // TODO: these indices *could* (very not likely) be incorrect + // TODO: for now, pretend every register is u64 + res.data = *reinterpret_cast( + _reg_sets[info.set].values[info.idx].data()); + } + } + + return check_single_res_changed(std::move(res)); } case frame_ip: { + 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(); + } + auto thread = _process->GetSelectedThread(); auto frame = thread.GetSelectedFrame(); if (!thread.IsValid() || !frame.IsValid()) { - return data::DataResult{ - .id = node.id, + return check_single_res_changed(data::result::Node{ + .idx = cache_idx, + .type_id = data::type_info::TypeID::none(), .success = false, - }; + }); } uint64_t pc = frame.GetPC(); - std::vector out{}; - out.resize(sizeof(uint64_t)); - *reinterpret_cast(out.data()) = pc; - return data::DataResult{ - .id = node.id, + return check_single_res_changed(data::result::Node{ + .idx = cache_idx, + .type_id = data::type_info::TypeID::u64(), .success = true, - .type = data::TypeInfo{.type = data::TypeInfo::Type::u64}, - .data = std::move(out), - }; + .data = pc, + }); } } break; @@ -1160,22 +1719,37 @@ dbgui::data::DataResult LLDBBackend::calc_data_res(const data::DataNode &node) case disassemble: { using namespace lldb; - size_t addr_id = std::get(node.data).src_id; - const auto res_it = - std::find_if(_cached_data_results.begin(), _cached_data_results.end(), - [addr_id](const auto &el) { return el.id == addr_id; }); - if (res_it == _cached_data_results.end() || !res_it->success) + uint16_t cache_idx = 0; + if (auto found_idx = find_node_for_src_id(node.id); found_idx) { - return data::DataResult{.id = node.id, .success = false}; + cache_idx = *found_idx; + } else + { + 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) + { + return check_single_res_changed(data::result::Node{ + .idx = cache_idx, + .type_id = data::type_info::TypeID::none(), + .success = false, + }); } // TODO: for now only accept u64 - if (res_it->type.type != data::TypeInfo::Type::u64) + if (_data_res[addr_idx]->node.type_id.type != data::type_info::Type::u64) { - return data::DataResult{.id = node.id, .success = false}; + return check_single_res_changed(data::result::Node{ + .idx = cache_idx, + .type_id = data::type_info::TypeID::none(), + .success = false, + }); } - const auto pc = *reinterpret_cast(res_it->data.data()); + const auto pc = std::get(_data_res[addr_idx]->node.data); auto sc = _target.ResolveSymbolContextForAddress( SBAddress{pc, _target}, eSymbolContextFunction | eSymbolContextSymbol); @@ -1288,31 +1862,47 @@ dbgui::data::DataResult LLDBBackend::calc_data_res(const data::DataNode &node) std::copy(comm.begin(), comm.end(), out.begin() + insert_idx); } - return data::DataResult{ - .id = node.id, + return check_single_res_changed(data::result::Node{ + .idx = cache_idx, + .type_id = data::type_info::TypeID::custom(), .success = true, - .type = data::TypeInfo{.type = data::TypeInfo::Type::custom}, - .data = std::move(out)}; + .data = std::move(out), + }); } case line_entry: { using namespace lldb; - size_t addr_id = std::get(node.data).src_id; - const auto res_it = - std::find_if(_cached_data_results.begin(), _cached_data_results.end(), - [addr_id](const auto &el) { return el.id == addr_id; }); - if (res_it == _cached_data_results.end() || !res_it->success) + uint16_t cache_idx = 0; + if (auto found_idx = find_node_for_src_id(node.id); found_idx) { - return data::DataResult{.id = node.id, .success = false}; + cache_idx = *found_idx; + } else + { + 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) + { + return check_single_res_changed(data::result::Node{ + .idx = cache_idx, + .type_id = data::type_info::TypeID::none(), + .success = false, + }); } // TODO: for now only accept u64 - if (res_it->type.type != data::TypeInfo::Type::u64) + if (_data_res[addr_idx]->node.type_id.type != data::type_info::Type::u64) { - return data::DataResult{.id = node.id, .success = false}; + return check_single_res_changed(data::result::Node{ + .idx = cache_idx, + .type_id = data::type_info::TypeID::none(), + .success = false, + }); } - const auto addr = *reinterpret_cast(res_it->data.data()); + const auto addr = std::get(_data_res[addr_idx]->node.data); auto sc = _target.ResolveSymbolContextForAddress(SBAddress{addr, _target}, eSymbolContextLineEntry); @@ -1334,7 +1924,11 @@ dbgui::data::DataResult LLDBBackend::calc_data_res(const data::DataNode &node) stream.GetData());*/ if (!le.IsValid() || !file_spec.IsValid()) { - return data::DataResult{.id = node.id, .success = false}; + return check_single_res_changed(data::result::Node{ + .idx = cache_idx, + .type_id = data::type_info::TypeID::none(), + .success = false, + }); } // TODO: for now the instlist is serialized in a custom format @@ -1359,11 +1953,12 @@ dbgui::data::DataResult LLDBBackend::calc_data_res(const data::DataNode &node) *reinterpret_cast(out.data() + 4) = path_len; std::memcpy(out.data() + 8, path_buf, path_len); - return data::DataResult{ - .id = node.id, + return check_single_res_changed(data::result::Node{ + .idx = cache_idx, + .type_id = data::type_info::TypeID::custom(), .success = true, - .type = data::TypeInfo{.type = data::TypeInfo::Type::custom}, - .data = std::move(out)}; + .data = std::move(out), + }); } } diff --git a/src/backend/lldb/lldb_backend.h b/src/backend/lldb/lldb_backend.h index 81dc67e..a64450e 100644 --- a/src/backend/lldb/lldb_backend.h +++ b/src/backend/lldb/lldb_backend.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "util/dag.h" @@ -47,6 +48,23 @@ namespace dbgui::backend lldb::break_id_t lldb_id; }; + struct CachedDataRes + { + struct DisasmInfo + { + uint64_t range_start, range_end; + std::vector bytes; + }; + + data::result::Node node; + bool child_node; + uint16_t parent_node; + uint16_t parent_member_id; + + size_t src_id; // invalid = size_t::MAX + // std::variant extra_info; + }; + // TODO: source_init_file: false LLDBBackend(std::string filename); virtual ~LLDBBackend(); @@ -60,7 +78,7 @@ namespace dbgui::backend void cont() override; void pause() override; - void add_data_node(const data::DataNode &) override; + void add_data_node(const data::source::Node &) override; void remove_data_node(uint64_t id) override; void add_breakpoint(uint64_t addr, size_t id) override; @@ -79,11 +97,14 @@ namespace dbgui::backend void prepare_proc_info(BackToFront::InitialProcessInfo &, std::vector &); void dump_threads(); + void dump_variables(); void check_reg_changes(); void check_thread_changes(); void check_frame_changes(); void check_data_changes(); - data::DataResult calc_data_res(const data::DataNode &); + std::optional> + calc_data_res(const data::source::Node &, + std::vector &data_res); std::string _filename; lldb::SBDebugger _instance; @@ -102,11 +123,16 @@ namespace dbgui::backend uint16_t _selected_frame = 0; uint16_t _selected_thread = 0; - util::DAG _data_dag = {}; - std::vector _data_nodes = {}; - std::vector _dag_linear = {}; - bool _dag_linear_valid = false; - std::vector _cached_data_results = {}; + util::DAG _data_dag = {}; + std::vector _data_nodes = {}; + std::vector _dag_linear = {}; + bool _dag_linear_valid = false; + // util::DAG _data_res_dag = {}; + std::vector> _data_res = {}; + std::vector> _locals = {}; + std::optional _last_frame = {}; + // std::unordered_map _src_id_to_data_idx = {}; + // std::vector _cached_data_results = {}; std::vector _breakpoints = {}; }; diff --git a/src/data.cpp b/src/data.cpp new file mode 100644 index 0000000..28e4705 --- /dev/null +++ b/src/data.cpp @@ -0,0 +1,175 @@ +#include "data.h" +#include + +using namespace dbgui::data; + +void type_info::TypeInfo::format(const std::vector &types, + std::string &out) +{ + switch (this->type) + { + using enum Type; + case none: out += ""; break; + case _void: out += "void"; break; + case custom: out += ""; break; + case _bool: out += "bool"; break; + case u8: out += "u8"; break; + case u16: out += "u16"; break; + case u32: out += "u32"; break; + case u64: out += "u64"; break; + case u128: out += "u128"; break; + case i8: out += "i8"; break; + case i16: out += "i16"; break; + case i32: out += "i32"; break; + case i64: out += "i64"; break; + case i128: out += "i128"; break; + case f32: out += "f32"; break; + case f64: out += "f64"; break; + case f128: out += "f128"; break; + case array: + { + out += "array"; + break; + } + case ptr: + { + out += "ptr"; + break; + } + case complex: + { + out += "complex"; + break; + } + case _union: + { + out += "union"; + break; + } + case _enum: + { + out += "enum"; + break; + } + } + + out += " "; + out += this->name; + char buf[32]; + std::snprintf(buf, sizeof(buf), " $%lu", this->byte_size); + out += buf; + + if (this->type == Type::array) + { + out += " "; + std::get(this->member_types).format(out); + // TODO: calc member size? + } else if (this->type == Type::complex || this->type == Type::_union) + { + out += " {"; + for (const auto &member : this->member_vec()) + { + out += "\n"; + out += member.name; + if (member.bitfield_size) + { + std::snprintf(buf, sizeof(buf), " +%lu:%u ", member.offset, + member.bitfield_size); + } else + { + std::snprintf(buf, sizeof(buf), " +%lu ", member.offset); + } + out += buf; + member.type_id.format(out); + out += ";"; + } + out += "\n}"; + } else if (this->type == Type::ptr) + { + std::get(this->member_types).format(out); + } else if (this->type == Type::_enum) + { + out += " "; + this->enum_base.format(out); + out += " {"; + for (const auto &member : this->member_vec()) + { + out += "\n "; + out += member.name; + std::snprintf(buf, sizeof(buf), " = %lu", member.enum_val); + out += buf; + out += ";"; + } + out += "\n}"; + } + + out += ";"; +} + +void type_info::TypeID::format(std::string &out) const +{ + switch (this->type) + { + using enum Type; + case none: out += ""; return; + case _void: out += "void"; return; + case custom: out += ""; return; + case _bool: out += "bool"; return; + case u8: out += "u8"; return; + case u16: out += "u16"; return; + case u32: out += "u32"; return; + case u64: out += "u64"; return; + case u128: out += "u128"; return; + case i8: out += "i8"; return; + case i16: out += "i16"; return; + case i32: out += "i32"; return; + case i64: out += "i64"; return; + case i128: out += "i128"; return; + case f32: out += "f32"; return; + case f64: out += "f64"; return; + case f128: out += "f128"; return; + case array: + { + char buf[32]; + std::snprintf(buf, sizeof(buf), "array #%u", this->idx); + out += buf; + return; + } + case ptr: + { + out += "ptr "; + if (sub_type == ptr) + { + char buf[32]; + std::snprintf(buf, sizeof(buf), "#%u", this->idx); + out += buf; + } else + { + auto tmp_id = TypeID{.type = sub_type, .idx = idx}; + tmp_id.format(out); + } + return; + } + case complex: + { + char buf[32]; + std::snprintf(buf, sizeof(buf), "complex #%u", this->idx); + out += buf; + return; + } + case _union: + { + char buf[32]; + std::snprintf(buf, sizeof(buf), "union #%u", this->idx); + out += buf; + return; + } + case _enum: + { + char buf[32]; + std::snprintf(buf, sizeof(buf), "enum #%u", this->idx); + out += buf; + return; + } + } +} \ No newline at end of file diff --git a/src/data.h b/src/data.h index b12c010..53c9579 100644 --- a/src/data.h +++ b/src/data.h @@ -4,10 +4,11 @@ #include #include #include +#include namespace dbgui::data { - struct TypeInfo + /*struct TypeInfo { enum class Type { @@ -97,6 +98,231 @@ namespace dbgui::data bool success; TypeInfo type; std::vector data; - }; + };*/ + + namespace type_info + { + struct TypeInfo; + + // TODO: vector types + enum class Type : uint32_t + { + none, + _void, + custom, + _bool, + u8, + u16, + u32, + u64, + u128, + i8, + i16, + i32, + i64, + i128, + f32, + f64, + f128, + array, + ptr, + complex, + _union, + _enum, + // if this grows to more than 32 elements, change the bitfield size in TypeID + }; + + struct TypeID + { + // TODO: just remove the bitfield? + Type type : 5; + // if type == ptr, then this is valid + Type sub_type : 5; + uint32_t idx : 22; + + static TypeID none() + { + return TypeID{.type = Type::none, .sub_type = Type::none, .idx = 0}; + } + + static TypeID u64() + { + return TypeID{.type = Type::u64, .sub_type = Type::none, .idx = 0}; + } + + static TypeID custom() + { + return TypeID{.type = Type::custom, .sub_type = Type::none, .idx = 0}; + } + + static TypeID basic(Type type) + { + return TypeID{.type = type, .sub_type = Type::none, .idx = 0}; + } + + static TypeID ref(Type type, uint32_t idx) + { + return TypeID{.type = type, .sub_type = Type::none, .idx = idx}; + } + + void format(std::string &out) const; + + bool is_basic() const + { + return type != Type::none && type != Type::custom && type != Type::array + && type != Type::complex && type != Type::ptr + && type != Type::_union && type != Type::_enum; + } + + bool operator==(const TypeID &rhs) const + { + if (this->type != rhs.type) + { + return false; + } + + if (this->type == Type::array || this->type == Type::complex + || this->type == Type::custom || this->type == Type::_enum) + { + if (this->idx != rhs.idx) + { + return false; + } + } + + if (this->type == Type::ptr) + { + if (this->sub_type != rhs.sub_type) + { + return false; + } + + if (this->sub_type == Type::array || this->sub_type == Type::complex + || this->sub_type == Type::custom) + { + if (this->idx != rhs.idx) + { + return false; + } + } + } + + return true; + } + }; + static_assert(sizeof(TypeID) == 4); + + struct MemberInfo + { + std::string name; + TypeID type_id; + uint32_t bitfield_size; + // for bitfields, this is the bit offset + uint64_t offset; + uint64_t enum_val; // no support for enum with complex values + }; + + // TODO: need to add all the scope information somehow? + // or let the backend resolve the type names that are needed for casting + // and then just tell the frontend the type id here? + // TODO: this currently inlines the size of an array + // so for each different array size one TypeInfo would be generated + // do we want to inline this into the MemberInfo? + // TODO: how to handle ADTs a la Rust enums? + struct TypeInfo + { + Type type; + uint64_t byte_size; + TypeID enum_base; + std::string name; + // sike, lldb doesnt give this to us + // std::string def_file_path; + // uint32_t def_file_line; + // if type==ptr, then TypeID.type == ptr and TypeID.sub_type is what is pointed to + std::variant, TypeID> + member_types; + + auto &member_vec() + { + return std::get>(this->member_types); + } + + void format(const std::vector &types, std::string &out); + }; + } // namespace type_info + + // source DAG nodes + namespace source + { + struct Source + { + enum class Type : uint8_t + { + reg, + frame_ip, // binds the selected frame + locals, // binds to selected frame + // TODO: special IP/SP source? so that scope selection can apply to that? + // variable, + // const, + }; + + struct Reg + { + // TODO: identify through names? + uint16_t set; + uint16_t idx; + }; + + Type type; + std::variant data; + }; + + struct Disassemble + { + // Node that provides the address to disassemble + // type must be u64 + size_t src_id; + }; + + struct LineEntry + { + // Node that provides address to resolve + // must be u64 + size_t src_id; + }; + + struct Node + { + enum class Type : uint8_t + { + source, + disassemble, + line_entry, + }; + + size_t id; + Type type; + // when adding something here, remember to update LLDBBackend::add_data_node + std::variant data; + }; + } // namespace source + + // result stuff + namespace result + { + struct Node + { + uint16_t idx; + // uint16_t gen; + type_info::TypeID type_id; + bool success; + std::variant, uint64_t, float, double> data; + + const std::vector &vec_data() const + { + return std::get>(this->data); + } + }; + } // namespace result } // namespace dbgui::data \ No newline at end of file diff --git a/src/frontend/frontend.cpp b/src/frontend/frontend.cpp index 727e64a..07b27aa 100644 --- a/src/frontend/frontend.cpp +++ b/src/frontend/frontend.cpp @@ -348,10 +348,37 @@ void Frontend::handle_msgs() case data_result: { const auto &result = std::get(msg->data); - printf("Result ID: %lu\n", result.result.id); - for (auto &window : _windows) + for (size_t i = 0; i < result.nodes.size(); ++i) { - window.handle_data_res(result); + uint16_t idx = result.nodes[i].idx; + if (this->target->data_res_nodes.size() <= idx) + { + this->target->data_res_nodes.resize(idx + 1); + } + this->target->data_res_nodes[idx] = std::move(result.nodes[i]); + } + if (result.src_node_id) + { + auto id = result.src_node_id->second; + auto found = false; + for (auto &entry : this->target->src_id_to_data_idx) + { + if (entry.first == id) + { + entry.second = result.src_node_id->first; + found = true; + break; + } + } + if (!found) + { + this->target->src_id_to_data_idx.push_back( + std::make_pair(id, result.src_node_id->first)); + } + for (auto &window : _windows) + { + window.handle_source_updated(*this->target, id); + } } break; } diff --git a/src/frontend/target.h b/src/frontend/target.h index 37a14a1..5b3cbdb 100644 --- a/src/frontend/target.h +++ b/src/frontend/target.h @@ -80,6 +80,34 @@ namespace dbgui::frontend Target(std::string filename); + std::optional data_idx_for_src_id(size_t id) + { + for (auto &[entry_id, idx] : this->src_id_to_data_idx) + { + if (entry_id == id) + { + return idx; + } + } + return {}; + } + + data::result::Node *data_node_for_src_id(size_t id) + { + auto idx = this->data_idx_for_src_id(id); + if (!idx) + { + return nullptr; + } + + if (*idx >= data_res_nodes.size() || !data_res_nodes[*idx]) + { + return nullptr; + } + + return &*data_res_nodes[*idx]; + } + TargetState state = TargetState::stopped; std::string filename; uint64_t id; @@ -93,6 +121,8 @@ namespace dbgui::frontend std::vector> threads; std::vector> frames; std::vector breakpoints; + std::vector> src_id_to_data_idx; + std::vector> data_res_nodes; std::shared_ptr backend = nullptr; }; diff --git a/src/frontend/window.cpp b/src/frontend/window.cpp index 6af8ce7..8fa3125 100644 --- a/src/frontend/window.cpp +++ b/src/frontend/window.cpp @@ -468,17 +468,18 @@ bool DisasmWindow::draw(Frontend &frontend) this->ip_src_id = frontend.target->data_node_id++; this->disas_src_id = frontend.target->data_node_id++; + using namespace data::source; frontend.target->backend->add_data_node( - data::DataNode{.id = this->ip_src_id, - .type = data::DataNode::Type::data_source, - .data = data::DataSource{ - .type = data::DataSource::Type::frame_ip, - }}); + Node{.id = this->ip_src_id, + .type = Node::Type::source, + .data = Source{ + .type = Source::Type::frame_ip, + }}); frontend.target->backend->add_data_node( - data::DataNode{.id = this->disas_src_id, - .type = data::DataNode::Type::disassemble, - .data = data::Disassemble{.src_id = this->ip_src_id}}); + Node{.id = this->disas_src_id, + .type = Node::Type::disassemble, + .data = Disassemble{.src_id = this->ip_src_id}}); first = false; } @@ -760,17 +761,18 @@ bool SourceWindow::draw(Frontend &frontend) this->ip_src_id = frontend.target->data_node_id++; this->line_entry_src_id = frontend.target->data_node_id++; + using namespace data::source; frontend.target->backend->add_data_node( - data::DataNode{.id = this->ip_src_id, - .type = data::DataNode::Type::data_source, - .data = data::DataSource{ - .type = data::DataSource::Type::frame_ip, - }}); + Node{.id = this->ip_src_id, + .type = Node::Type::source, + .data = Source{ + .type = Source::Type::frame_ip, + }}); frontend.target->backend->add_data_node( - data::DataNode{.id = this->line_entry_src_id, - .type = data::DataNode::Type::line_entry, - .data = data::LineEntry{.src_id = this->ip_src_id}}); + Node{.id = this->line_entry_src_id, + .type = Node::Type::line_entry, + .data = LineEntry{.src_id = this->ip_src_id}}); first = false; } @@ -968,29 +970,29 @@ bool SourceWindow::draw(Frontend &frontend) return false; } -void Window::handle_data_res(const BackToFront::DataResult &result) +void Window::handle_source_updated(Target &target, size_t id) { switch (this->type) { using enum WindowType; case disassembly: - std::get(this->data).handle_data_res(result); + std::get(this->data).handle_source_updated(target, id); break; case source: - std::get(this->data).handle_data_res(result); + std::get(this->data).handle_source_updated(target, id); break; default: break; } } -void DisasmWindow::handle_data_res( - const BackToFront::DataResult &result_wrapper) +void DisasmWindow::handle_source_updated(Target &target, size_t id) { - const auto &result = result_wrapper.result; - if (result.id == this->ip_src_id) + if (id == this->ip_src_id) { - if (!result.success || result.type.type != data::TypeInfo::Type::u64) + auto result = target.data_node_for_src_id(id); + if (!result || !result->success + || result->type_id.type != data::type_info::Type::u64) { this->ip_unsuccessful = true; return; @@ -998,17 +1000,19 @@ void DisasmWindow::handle_data_res( this->ip_unsuccessful = false; this->ip_changed = true; - this->ip = *reinterpret_cast(result.data.data()); + this->ip = std::get(result->data); printf("IP changed to %lX\n", this->ip); return; } - if (result.id != this->disas_src_id) + if (id != this->disas_src_id) { return; } - if (!result.success || result.type.type != data::TypeInfo::Type::custom) + auto result = target.data_node_for_src_id(id); + if (!result || !result->success + || result->type_id.type != data::type_info::Type::custom) { this->disas_unsuccessful = true; this->insts.clear(); @@ -1035,21 +1039,20 @@ void DisasmWindow::handle_data_res( uint8_t max_mnem_len = 0; uint8_t max_op_len = 0; - while (idx < result.data.size()) + const auto &data = result->vec_data(); + while (idx < data.size()) { - if (result.data.size() - idx < 12) + if (data.size() - idx < 12) { break; } - uint64_t addr = *reinterpret_cast(&result.data[idx]); - uint8_t mnem_len = - *reinterpret_cast(&result.data[idx + 8]); - uint8_t op_len = *reinterpret_cast(&result.data[idx + 9]); - uint8_t comment_len = - *reinterpret_cast(&result.data[idx + 10]); + uint64_t addr = *reinterpret_cast(&data[idx]); + uint8_t mnem_len = *reinterpret_cast(&data[idx + 8]); + uint8_t op_len = *reinterpret_cast(&data[idx + 9]); + uint8_t comment_len = *reinterpret_cast(&data[idx + 10]); // dc about inst_len rn idx += 12; - if (result.data.size() - idx < mnem_len + op_len + comment_len) + if (data.size() - idx < mnem_len + op_len + comment_len) { break; } @@ -1057,12 +1060,12 @@ void DisasmWindow::handle_data_res( if (comment_len) { std::snprintf(buf, sizeof(buf), "%.*s%%*c%.*s%%.*c ; %.*s", mnem_len, - &result.data[idx], op_len, &result.data[idx + mnem_len], - comment_len, &result.data[idx + mnem_len + op_len]); + &data[idx], op_len, &data[idx + mnem_len], comment_len, + &data[idx + mnem_len + op_len]); } else { - std::snprintf(buf, sizeof(buf), "%.*s%%*c%.*s%%.*c", mnem_len, - &result.data[idx], op_len, &result.data[idx + mnem_len]); + std::snprintf(buf, sizeof(buf), "%.*s%%*c%.*s%%.*c", mnem_len, &data[idx], + op_len, &data[idx + mnem_len]); } idx += mnem_len + op_len + comment_len; @@ -1086,22 +1089,22 @@ void DisasmWindow::handle_data_res( this->max_op_len = max_op_len; } -void SourceWindow::handle_data_res( - const BackToFront::DataResult &result_wrapper) +void SourceWindow::handle_source_updated(Target &target, size_t id) { - const auto &result = result_wrapper.result; - if (result.id == this->ip_src_id) + if (id == this->ip_src_id) { // should not need to care return; } - if (result.id != this->line_entry_src_id) + if (id != this->line_entry_src_id) { return; } - if (!result.success || result.type.type != data::TypeInfo::Type::custom) + auto result = target.data_node_for_src_id(id); + if (!result || !result->success + || result->type_id.type != data::type_info::Type::custom) { this->lines.clear(); this->file_data.clear(); @@ -1117,7 +1120,8 @@ void SourceWindow::handle_data_res( // char file_name[]; // }; - if (result.data.size() < 8) + const auto &data = result->vec_data(); + if (data.size() < 8) { this->lines.clear(); this->file_data.clear(); @@ -1126,10 +1130,9 @@ void SourceWindow::handle_data_res( return; } - const auto line = *reinterpret_cast(result.data.data()); - const auto name_len = - *reinterpret_cast(result.data.data() + 4); - if (result.data.size() < 8 + name_len) + const auto line = *reinterpret_cast(data.data()); + const auto name_len = *reinterpret_cast(data.data() + 4); + if (data.size() < 8 + name_len) { this->lines.clear(); this->file_data.clear(); @@ -1138,8 +1141,8 @@ void SourceWindow::handle_data_res( return; } - const auto file_view = std::string_view{ - reinterpret_cast(result.data.data() + 8), name_len}; + const auto file_view = + std::string_view{reinterpret_cast(data.data() + 8), name_len}; printf("New LE: %.*s:%u", static_cast(file_view.size()), file_view.data(), line); diff --git a/src/frontend/window.h b/src/frontend/window.h index 8004bda..da39aa1 100644 --- a/src/frontend/window.h +++ b/src/frontend/window.h @@ -84,7 +84,7 @@ namespace dbgui::frontend bool draw(Frontend &); - void handle_data_res(const BackToFront::DataResult &result); + void handle_source_updated(Target& target, size_t id); std::string id; bool open; @@ -110,7 +110,7 @@ namespace dbgui::frontend struct SourceWindow { bool draw(Frontend &); - void handle_data_res(const BackToFront::DataResult &result); + void handle_source_updated(Target& target, size_t id); std::string id; bool open; @@ -141,6 +141,6 @@ namespace dbgui::frontend static Window create_bp(size_t window_id); static Window create_source(size_t window_id); - void handle_data_res(const BackToFront::DataResult &result); + void handle_source_updated(Target& target, size_t id); }; } // namespace dbgui::frontend \ No newline at end of file diff --git a/src/msg.h b/src/msg.h index 00f08c8..98e1c7f 100644 --- a/src/msg.h +++ b/src/msg.h @@ -71,6 +71,7 @@ namespace dbgui frame_removed, // TODO: frame_moved, frame_added, etc? data_result, + remove_data_node, selected_frame_changed, selected_thread_changed, }; @@ -136,7 +137,15 @@ namespace dbgui struct DataResult { - data::DataResult result; + std::vector nodes; + + // if present, node at idx maps to specified src_id + std::optional> src_node_id; + }; + + struct RemoveDataNode + { + uint16_t node; }; struct SelectedFrameChanged @@ -149,13 +158,19 @@ namespace dbgui uint16_t idx; }; + struct TypeInfo + { + data::type_info::TypeInfo type_info; + uint32_t idx; + }; + struct Msg { MsgType type; std::variant + SelectedThreadChanged, RemoveDataNode> data; }; } // namespace BackToFront diff --git a/tmp/main b/tmp/main index d87e847..17ee69e 100755 Binary files a/tmp/main and b/tmp/main differ diff --git a/tmp/main.cpp b/tmp/main.cpp index d26ebb2..304f70c 100644 --- a/tmp/main.cpp +++ b/tmp/main.cpp @@ -8,11 +8,13 @@ namespace { } void helper_fn(); +void helper_fn2(); int main(int argc, char* argv[]) { MyType tmp = MyType{10}; while (tmp.data != 0) { helper_fn(); + helper_fn2(); tmp.data--; } return 0; diff --git a/tmp/sec.cpp b/tmp/sec.cpp index 44c18c5..8ad8c1e 100644 --- a/tmp/sec.cpp +++ b/tmp/sec.cpp @@ -1,13 +1,33 @@ #include #include +#include namespace test { + enum MyEnum : uint16_t { + ENUM_VAL1 = 10, + ENUM_VAL2 = 5, + ENUM_VAL3 = 0xFFF, + }; + struct MyType { int data; + uint32_t test_bits : 20; + uint32_t test_bits2: 12; + MyEnum enum_val; }; } void helper_fn() { test::MyType tmp = test::MyType{1}; + std::string test = "Hello World"; + sleep(tmp.data); + { + test::MyType tmp = test::MyType{2}; + sleep(tmp.data); + } +} + +void helper_fn2() { + test::MyType tmp = test::MyType{3}; sleep(tmp.data); }