This commit is contained in:
T0b1
2023-06-15 02:25:57 +02:00
parent b393f3dd28
commit 9ab08de243
15 changed files with 1294 additions and 166 deletions

View File

@@ -10,6 +10,10 @@
#include <lldb/API/SBInstruction.h>
#include <lldb/API/SBBreakpoint.h>
#include <lldb/API/SBBreakpointLocation.h>
#include <lldb/API/SBTypeFilter.h>
#include <lldb/API/SBTypeFormat.h>
#include <lldb/API/SBDeclaration.h>
#include <lldb/API/SBTypeEnumMember.h>
#include <filesystem>
#include <array>
#include <cassert>
@@ -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<dbgui::data::type_info::TypeID>
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<dbgui::data::type_info::TypeInfo> &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<uint32_t>(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<type_info::MemberInfo>{}});
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 = "<none>";
}
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<type_info::MemberInfo>{}});
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 = "<none>";
}
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<type_info::TypeInfo>{};
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 = "<unk>"; 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<dbgui::data::type_info::TypeInfo>{};
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 = "<null>";
}
printf("Var %.*s ('%s'): %lu\n", static_cast<int>(stream.GetSize()),
stream.GetData(), name, var.GetID());
stream.Clear();
var.GetDescription(stream);
printf(" -> Desc: %.*s\n", static_cast<int>(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 = "<null>";
}
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<int>(stream.GetSize()),
stream.GetData());
stream.Clear();
var.GetExpressionPath(stream);
printf("ExprPath: %.*s\n", static_cast<int>(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<int>(stream.GetSize()),
stream.GetData());
auto decl = var.GetDeclaration();
stream.Clear();
decl.GetDescription(stream);
printf(" -> Declaration: %.*s\n", static_cast<int>(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<int>(stream.GetSize()),
stream.GetData());
stream.Clear();
type_filter.GetDescription(stream, eDescriptionLevelFull);
printf(" -> TypeFilter: %.*s\n", static_cast<int>(stream.GetSize()),
stream.GetData());
stream.Clear();
var.GetTypeFormat().GetDescription(stream, eDescriptionLevelFull);
printf(" -> TypeFormat: %.*s\n", static_cast<int>(stream.GetSize()),
stream.GetData());
stream.Clear();
type.GetDescription(stream, eDescriptionLevelVerbose);
printf(" -> Type: %.*s\n", static_cast<int>(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<int>(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<data::Disassemble>(node.data).src_id;
auto src_id = std::get<data::source::Disassemble>(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<data::LineEntry>(node.data).src_id;
auto src_id = std::get<data::source::LineEntry>(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<uint16_t> 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<data::result::Node>{};
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<std::pair<uint16_t, size_t>>
LLDBBackend::calc_data_res(const data::source::Node &node,
std::vector<data::result::Node> &data_res)
{
const auto find_node_for_src_id =
[this](size_t src_id) -> std::optional<uint16_t> {
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<std::pair<uint16_t, size_t>> {
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<data::DataSource>(node.data);
const auto &src_data = std::get<data::source::Source>(node.data);
switch (src_data.type)
{
using enum data::DataSource::Type;
using enum data::source::Source::Type;
case reg:
{
const auto &info = std::get<data::DataSource::Reg>(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<data::source::Source::Reg>(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<const uint64_t *>(
_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<uint8_t> out{};
out.resize(sizeof(uint64_t));
*reinterpret_cast<uint64_t *>(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<data::Disassemble>(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<data::source::Disassemble>(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<uint64_t *>(res_it->data.data());
const auto pc = std::get<uint64_t>(_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<data::LineEntry>(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<data::source::LineEntry>(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<uint64_t *>(res_it->data.data());
const auto addr = std::get<uint64_t>(_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<uint32_t *>(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),
});
}
}