mirror of
https://github.com/odin-lang/Odin.git
synced 2026-10-12 19:19:53 -04:00
Merge pull request #7826 from bbodi/fix/debug-info-printers
Fix/debug info printers
This commit is contained in:
2 files changed
+78
-16
No files matched your search
@@ -111,6 +111,19 @@ def odin_kind(type_name, field_names, data_is_pointer, data_is_array, data_targe
|
||||
return None
|
||||
|
||||
|
||||
def composite_type(name):
|
||||
# the element of a pointer, multi-pointer or fixed array type named by a `typeid` and the array's count,
|
||||
# which is None for a pointer; None for other types
|
||||
if name.startswith("^"):
|
||||
return name[1:], None
|
||||
if name.startswith("[^]"):
|
||||
return name[3:], None
|
||||
m = re.fullmatch(r"\[([0-9]+)\](.+)", name)
|
||||
if m:
|
||||
return m.group(2), int(m.group(1))
|
||||
return None
|
||||
|
||||
|
||||
def soa_fields(field_names):
|
||||
return [n for n in field_names if n not in ("__$len", "__$cap", "allocator", "_")]
|
||||
|
||||
@@ -278,6 +291,16 @@ if gdb is not None:
|
||||
return None
|
||||
|
||||
def _gdb_odin_type(name):
|
||||
composite = composite_type(name)
|
||||
if composite is not None:
|
||||
elem_name, count = composite
|
||||
elem = _gdb_odin_type(elem_name)
|
||||
if elem is None:
|
||||
return None
|
||||
if count is None:
|
||||
return elem.pointer()
|
||||
return elem.array(count - 1)
|
||||
|
||||
basic = ODIN_BASIC_TYPES.get(name)
|
||||
if basic is None:
|
||||
return _gdb_type(name, "struct " + name, "union " + name, "enum " + name)
|
||||
@@ -481,7 +504,11 @@ if gdb is not None:
|
||||
return "<%s>" % e
|
||||
if name is None or (tag is None and int(self._val[name]) == 0):
|
||||
return "nil"
|
||||
return self._val[name]
|
||||
value = self._val[name]
|
||||
if value.type.strip_typedefs().code == gdb.TYPE_CODE_PTR:
|
||||
# gdb prints nothing for a pointer value returned by `to_string`
|
||||
return value.format_string()
|
||||
return value
|
||||
|
||||
class _GdbAny(_GdbPrinter):
|
||||
# The value it holds, after the name of its type; an unknown type shows the `any` itself
|
||||
@@ -569,8 +596,19 @@ if lldb is not None:
|
||||
cell_data_size = _lldb_fields(cell)["v"].GetByteSize()
|
||||
return cell_layout(elem.GetByteSize(), cell.GetByteSize(), cell_data_size)
|
||||
|
||||
def _lldb_odin_type(target, name, id):
|
||||
# the type a `typeid` names, None when it cannot be found
|
||||
def _lldb_odin_type(target, basis, name, id):
|
||||
# the type a `typeid` names, None when it cannot be found; basic types come from the type system of `basis`,
|
||||
# an Odin type, as the target may answer from another, such as Swift's, whose types make no value
|
||||
composite = composite_type(name)
|
||||
if composite is not None and typeid_hash(name) == id:
|
||||
elem_name, count = composite
|
||||
elem = _lldb_odin_type(target, basis, elem_name, typeid_hash(elem_name))
|
||||
if elem is None:
|
||||
return None
|
||||
if count is None:
|
||||
return elem.GetPointerType()
|
||||
return elem.GetArrayType(count)
|
||||
|
||||
basic = ODIN_BASIC_TYPES.get(name)
|
||||
if basic is None:
|
||||
types = target.FindTypes(name)
|
||||
@@ -585,11 +623,11 @@ if lldb is not None:
|
||||
size = target.GetAddressByteSize()
|
||||
|
||||
if kind == "rawptr":
|
||||
return target.GetBasicType(lldb.eBasicTypeVoid).GetPointerType()
|
||||
return basis.GetBasicType(lldb.eBasicTypeVoid).GetPointerType()
|
||||
if kind == "cstring":
|
||||
return target.GetBasicType(lldb.eBasicTypeChar).GetPointerType()
|
||||
return basis.GetBasicType(lldb.eBasicTypeChar).GetPointerType()
|
||||
if kind == "cstring16":
|
||||
return target.GetBasicType(lldb.eBasicTypeChar16).GetPointerType()
|
||||
return basis.GetBasicType(lldb.eBasicTypeChar16).GetPointerType()
|
||||
|
||||
basics = {
|
||||
("int", 1): lldb.eBasicTypeSignedChar,
|
||||
@@ -611,7 +649,7 @@ if lldb is not None:
|
||||
basic_type = basics.get((kind, size))
|
||||
if basic_type is None:
|
||||
return None
|
||||
return target.GetBasicType(basic_type)
|
||||
return basis.GetBasicType(basic_type)
|
||||
|
||||
def lldb_is_string(sbtype, internal_dict):
|
||||
return _lldb_kind(sbtype) in ("string", "string16")
|
||||
@@ -657,10 +695,10 @@ if lldb is not None:
|
||||
name = id.GetValue() or ""
|
||||
if data == 0 or id.GetValueAsUnsigned() == 0:
|
||||
return "nil", None
|
||||
t = _lldb_odin_type(valobj.GetTarget(), name, id.GetValueAsUnsigned())
|
||||
t = _lldb_odin_type(valobj.GetTarget(), v.GetType(), name, id.GetValueAsUnsigned())
|
||||
if t is None:
|
||||
return name, None
|
||||
if name not in ODIN_BASIC_TYPES:
|
||||
if name not in ODIN_BASIC_TYPES and composite_type(name) is None:
|
||||
name = t.GetName()
|
||||
value = valobj.CreateValueFromAddress("value", data, t)
|
||||
value.SetPreferSyntheticValue(True)
|
||||
|
||||
@@ -884,6 +884,14 @@ gb_internal LLVMMetadataRef lb_debug_typeid_enum(lbModule *m) {
|
||||
);
|
||||
}
|
||||
|
||||
// NOTE: gdb reads a `wchar_t` as UTF-32 on Linux, but a 16-bit UTF character as UTF-16; CodeView knows `wchar_t` as UTF-16
|
||||
gb_internal LLVMMetadataRef lb_debug_char16_type(lbModule *m) {
|
||||
if (build_context.metrics.os == TargetOs_windows) {
|
||||
return lb_debug_type_basic_type(m, str_lit("wchar_t"), 16, LLVMDWARFTypeEncoding_Unsigned);
|
||||
}
|
||||
return lb_debug_type_basic_type(m, str_lit("char16_t"), 16, LLVMDWARFTypeEncoding_Utf);
|
||||
}
|
||||
|
||||
gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
|
||||
i64 size = type_size_of(type); // Check size
|
||||
gb_unused(size);
|
||||
@@ -1013,8 +1021,8 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
|
||||
|
||||
case Basic_rawptr:
|
||||
{
|
||||
LLVMMetadataRef void_type = lb_debug_type_basic_type(m, str_lit("void"), 8, LLVMDWARFTypeEncoding_Unsigned);
|
||||
return LLVMDIBuilderCreatePointerType(m->debug_builder, void_type, ptr_bits, ptr_bits, LLVMDWARFTypeEncoding_Address, "rawptr", 6);
|
||||
// NOTE: a pointer to no type is `void *`, as clang emits it, rather than a pointer to a byte shown as a C string
|
||||
return LLVMDIBuilderCreatePointerType(m->debug_builder, nullptr, ptr_bits, ptr_bits, 0, "rawptr", 6);
|
||||
}
|
||||
case Basic_string:
|
||||
{
|
||||
@@ -1034,8 +1042,8 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
|
||||
case Basic_string16:
|
||||
{
|
||||
// NOTE(bill): size_of(^u16) <= size_of(int)
|
||||
// The data is `^wchar_t`, as `cstring16` is, so that debuggers show it as text
|
||||
LLVMMetadataRef char_type = lb_debug_type_basic_type(m, str_lit("wchar_t"), 16, LLVMDWARFTypeEncoding_Unsigned);
|
||||
// The data is a pointer to a UTF-16 character, as `cstring16` is, so that debuggers show it as text
|
||||
LLVMMetadataRef char_type = lb_debug_char16_type(m);
|
||||
LLVMMetadataRef file = lb_get_file_metadata(m, m->info->runtime_package->files[0]);
|
||||
|
||||
LLVMMetadataRef elements[2] = {};
|
||||
@@ -1047,8 +1055,8 @@ gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
|
||||
}
|
||||
case Basic_cstring16:
|
||||
{
|
||||
LLVMMetadataRef char_type = lb_debug_type_basic_type(m, str_lit("wchar_t"), 16, LLVMDWARFTypeEncoding_Unsigned);
|
||||
return LLVMDIBuilderCreatePointerType(m->debug_builder, char_type, ptr_bits, ptr_bits, 0, "cstring16", 7);
|
||||
LLVMMetadataRef char_type = lb_debug_char16_type(m);
|
||||
return LLVMDIBuilderCreatePointerType(m->debug_builder, char_type, ptr_bits, ptr_bits, 0, "cstring16", 9);
|
||||
}
|
||||
|
||||
case Basic_any:
|
||||
@@ -1294,6 +1302,22 @@ gb_internal LLVMMetadataRef lb_get_base_scope_metadata(lbModule *m, Scope *scope
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: gdb looks a declared enum up by name and stops at the first declaration it finds rather than the definition,
|
||||
// and it cannot look up a declared type whose name starts with `#`, so on DWARF these are defined in every module
|
||||
// which uses them, as clang does with enums
|
||||
gb_internal bool lb_debug_type_is_defined_everywhere(Type *bt) {
|
||||
if (build_context.metrics.os == TargetOs_windows) {
|
||||
return false;
|
||||
}
|
||||
switch (bt->kind) {
|
||||
case Type_Enum: return true;
|
||||
case Type_BitSet: return lb_debug_bit_set_is_flag_enum(bt);
|
||||
case Type_Struct: return bt->Struct.soa_kind != StructSoa_None;
|
||||
case Type_Basic: return bt->Basic.kind == Basic_typeid;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
|
||||
GB_ASSERT(type != nullptr);
|
||||
|
||||
@@ -1352,7 +1376,7 @@ gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
|
||||
Array<lbModule *> const &types_modules = m->gen->debug_types_modules;
|
||||
String record_name = {};
|
||||
lbModule *owner = nullptr;
|
||||
if (is_record && types_modules.count != 0 && record_bt->kind != Type_Tuple) {
|
||||
if (is_record && types_modules.count != 0 && record_bt->kind != Type_Tuple && !lb_debug_type_is_defined_everywhere(record_bt)) {
|
||||
record_name = type_to_canonical_string(temporary_allocator(), type);
|
||||
owner = types_modules[string_hash(record_name) % types_modules.count];
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user