CompilerType GoASTContext::GetFieldAtIndex(lldb::opaque_compiler_type_t type, size_t idx, std::string &name, uint64_t *bit_offset_ptr, uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr) { if (bit_offset_ptr) *bit_offset_ptr = 0; if (bitfield_bit_size_ptr) *bitfield_bit_size_ptr = 0; if (is_bitfield_ptr) *is_bitfield_ptr = false; if (!type || !GetCompleteType(type)) return CompilerType(); GoType *t = static_cast<GoType *>(type); if (t->IsTypedef()) return t->GetElementType().GetFieldAtIndex(idx, name, bit_offset_ptr, bitfield_bit_size_ptr, is_bitfield_ptr); GoStruct *s = t->GetStruct(); if (s) { const auto *field = s->GetField(idx); if (field) { name = field->m_name.GetStringRef(); if (bit_offset_ptr) *bit_offset_ptr = field->m_byte_offset * 8; return field->m_type; } } return CompilerType(); }
CompilerType GoASTContext::GetCanonicalType(lldb::opaque_compiler_type_t type) { GoType *t = static_cast<GoType *>(type); if (t->IsTypedef()) return t->GetElementType(); return CompilerType(this, type); }
uint64_t GoASTContext::GetBitSize(lldb::opaque_compiler_type_t type, ExecutionContextScope *exe_scope) { if (!type) return 0; if (!GetCompleteType(type)) return 0; GoType *t = static_cast<GoType *>(type); GoArray *array = nullptr; switch (t->GetGoKind()) { case GoType::KIND_BOOL: case GoType::KIND_INT8: case GoType::KIND_UINT8: return 8; case GoType::KIND_INT16: case GoType::KIND_UINT16: return 16; case GoType::KIND_INT32: case GoType::KIND_UINT32: case GoType::KIND_FLOAT32: return 32; case GoType::KIND_INT64: case GoType::KIND_UINT64: case GoType::KIND_FLOAT64: case GoType::KIND_COMPLEX64: return 64; case GoType::KIND_COMPLEX128: return 128; case GoType::KIND_INT: case GoType::KIND_UINT: return m_int_byte_size * 8; case GoType::KIND_UINTPTR: case GoType::KIND_FUNC: // I assume this is a pointer? case GoType::KIND_CHAN: case GoType::KIND_PTR: case GoType::KIND_UNSAFEPOINTER: case GoType::KIND_MAP: return m_pointer_byte_size * 8; case GoType::KIND_ARRAY: array = t->GetArray(); return array->GetLength() * array->GetElementType().GetBitSize(exe_scope); case GoType::KIND_INTERFACE: return t->GetElementType().GetBitSize(exe_scope); case GoType::KIND_SLICE: case GoType::KIND_STRING: case GoType::KIND_STRUCT: return t->GetStruct()->GetByteSize() * 8; default: assert(false); } return 0; }
CompilerType GoASTContext::GetFunctionReturnType(lldb::opaque_compiler_type_t type) { CompilerType result; if (type) { GoType *t = static_cast<GoType *>(type); if (t->GetGoKind() == GoType::KIND_FUNC) result = t->GetElementType(); } return result; }
bool GoASTContext::IsCompleteType(lldb::opaque_compiler_type_t type) { if (!type) return false; GoType *t = static_cast<GoType *>(type); if (GoStruct *s = t->GetStruct()) return s->IsComplete(); if (t->IsTypedef() || t->GetGoKind() == GoType::KIND_PTR) return t->GetElementType().IsCompleteType(); return true; }
void GoASTContext::CompleteStructType(const lldb_private::CompilerType &struct_type) { if (!struct_type) return; GoASTContext *ast = llvm::dyn_cast_or_null<GoASTContext>(struct_type.GetTypeSystem()); if (!ast) return; GoType *type = static_cast<GoType *>(struct_type.GetOpaqueQualType()); if (GoStruct *s = type->GetStruct()) s->SetComplete(); }
void GoASTContext::AddFieldToStruct(const lldb_private::CompilerType &struct_type, const lldb_private::ConstString &name, const lldb_private::CompilerType &field_type, uint32_t byte_offset) { if (!struct_type) return; GoASTContext *ast = llvm::dyn_cast_or_null<GoASTContext>(struct_type.GetTypeSystem()); if (!ast) return; GoType *type = static_cast<GoType *>(struct_type.GetOpaqueQualType()); if (GoStruct *s = type->GetStruct()) s->AddField(name, field_type, byte_offset); }
uint32_t GoASTContext::GetNumFields(lldb::opaque_compiler_type_t type) { if (!type || !GetCompleteType(type)) return 0; GoType *t = static_cast<GoType *>(type); if (t->IsTypedef()) return t->GetElementType().GetNumFields(); GoStruct *s = t->GetStruct(); if (s) return s->GetNumFields(); return 0; }
uint32_t GoASTContext::GetTypeInfo(lldb::opaque_compiler_type_t type, CompilerType *pointee_or_element_compiler_type) { if (pointee_or_element_compiler_type) pointee_or_element_compiler_type->Clear(); if (!type) return 0; GoType *t = static_cast<GoType *>(type); if (pointee_or_element_compiler_type) *pointee_or_element_compiler_type = t->GetElementType(); int kind = t->GetGoKind(); if (kind == GoType::KIND_ARRAY) return eTypeHasChildren | eTypeIsArray; if (kind < GoType::KIND_ARRAY) { uint32_t builtin_type_flags = eTypeIsBuiltIn | eTypeHasValue; if (kind < GoType::KIND_FLOAT32) { builtin_type_flags |= eTypeIsInteger | eTypeIsScalar; if (kind >= GoType::KIND_INT && kind <= GoType::KIND_INT64) builtin_type_flags |= eTypeIsSigned; } else { builtin_type_flags |= eTypeIsFloat; if (kind < GoType::KIND_COMPLEX64) builtin_type_flags |= eTypeIsComplex; else builtin_type_flags |= eTypeIsScalar; } return builtin_type_flags; } if (kind == GoType::KIND_STRING) return eTypeHasValue | eTypeIsBuiltIn; if (kind == GoType::KIND_FUNC) return eTypeIsFuncPrototype | eTypeHasValue; if (IsPointerType(type)) return eTypeIsPointer | eTypeHasValue | eTypeHasChildren; if (kind == GoType::KIND_LLDB_VOID) return 0; return eTypeHasChildren | eTypeIsStructUnion; }
bool GoASTContext::IsPointerType(lldb::opaque_compiler_type_t type, CompilerType *pointee_type) { if (!type) return false; GoType *t = static_cast<GoType *>(type); if (pointee_type) { *pointee_type = t->GetElementType(); } switch (t->GetGoKind()) { case GoType::KIND_PTR: case GoType::KIND_UNSAFEPOINTER: case GoType::KIND_CHAN: case GoType::KIND_MAP: // TODO: is function a pointer? return true; default: return false; } }
// Lookup a child given a name. This function will match base class names // and member member names in "clang_type" only, not descendants. uint32_t GoASTContext::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type, const char *name, bool omit_empty_base_classes) { if (!type || !GetCompleteType(type)) return UINT_MAX; GoType *t = static_cast<GoType *>(type); GoStruct *s = t->GetStruct(); if (s) { for (uint32_t i = 0; i < s->GetNumFields(); ++i) { const GoStruct::Field *f = s->GetField(i); if (f->m_name.GetStringRef() == name) return i; } } else if (t->GetGoKind() == GoType::KIND_PTR || t->IsTypedef()) { return t->GetElementType().GetIndexOfChildWithName(name, omit_empty_base_classes); } return UINT_MAX; }
bool GoASTContext::GetCompleteType(lldb::opaque_compiler_type_t type) { if (!type) return false; GoType *t = static_cast<GoType *>(type); if (t->IsTypedef() || t->GetGoKind() == GoType::KIND_PTR || t->GetArray()) return t->GetElementType().GetCompleteType(); if (GoStruct *s = t->GetStruct()) { if (s->IsComplete()) return true; CompilerType compiler_type(this, s); SymbolFile *symbols = GetSymbolFile(); return symbols && symbols->CompleteType(compiler_type); } return true; }
uint32_t GoASTContext::GetNumChildren(lldb::opaque_compiler_type_t type, bool omit_empty_base_classes) { if (!type || !GetCompleteType(type)) return 0; GoType *t = static_cast<GoType *>(type); if (t->GetGoKind() == GoType::KIND_PTR) { CompilerType elem = t->GetElementType(); if (elem.IsAggregateType()) return elem.GetNumChildren(omit_empty_base_classes); return 1; } else if (GoArray *array = t->GetArray()) { return array->GetLength(); } else if (t->IsTypedef()) { return t->GetElementType().GetNumChildren(omit_empty_base_classes); } return GetNumFields(type); }
bool GoASTContext::DumpTypeValue(lldb::opaque_compiler_type_t type, Stream *s, lldb::Format format, const DataExtractor &data, lldb::offset_t byte_offset, size_t byte_size, uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, ExecutionContextScope *exe_scope, bool is_base_class) { if (!type) return false; if (IsAggregateType(type)) { return false; } else { GoType *t = static_cast<GoType *>(type); if (t->IsTypedef()) { CompilerType typedef_compiler_type = t->GetElementType(); if (format == eFormatDefault) format = typedef_compiler_type.GetFormat(); uint64_t typedef_byte_size = typedef_compiler_type.GetByteSize(exe_scope); return typedef_compiler_type.DumpTypeValue( s, format, // The format with which to display the element data, // Data buffer containing all bytes for this type byte_offset, // Offset into "data" where to grab value from typedef_byte_size, // Size of this type in bytes bitfield_bit_size, // Size in bits of a bitfield value, if zero don't treat as a bitfield bitfield_bit_offset, // Offset in bits of a bitfield value if bitfield_bit_size != 0 exe_scope, is_base_class); } uint32_t item_count = 1; // A few formats, we might need to modify our size and count for depending // on how we are trying to display the value... switch (format) { default: case eFormatBoolean: case eFormatBinary: case eFormatComplex: case eFormatCString: // NULL terminated C strings case eFormatDecimal: case eFormatEnum: case eFormatHex: case eFormatHexUppercase: case eFormatFloat: case eFormatOctal: case eFormatOSType: case eFormatUnsigned: case eFormatPointer: case eFormatVectorOfChar: case eFormatVectorOfSInt8: case eFormatVectorOfUInt8: case eFormatVectorOfSInt16: case eFormatVectorOfUInt16: case eFormatVectorOfSInt32: case eFormatVectorOfUInt32: case eFormatVectorOfSInt64: case eFormatVectorOfUInt64: case eFormatVectorOfFloat32: case eFormatVectorOfFloat64: case eFormatVectorOfUInt128: break; case eFormatChar: case eFormatCharPrintable: case eFormatCharArray: case eFormatBytes: case eFormatBytesWithASCII: item_count = byte_size; byte_size = 1; break; case eFormatUnicode16: item_count = byte_size / 2; byte_size = 2; break; case eFormatUnicode32: item_count = byte_size / 4; byte_size = 4; break; } return data.Dump(s, byte_offset, format, byte_size, item_count, UINT32_MAX, LLDB_INVALID_ADDRESS, bitfield_bit_size, bitfield_bit_offset, exe_scope); } return 0; }
CompilerType GoASTContext::GetChildCompilerTypeAtIndex(lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers, bool omit_empty_base_classes, bool ignore_array_bounds, std::string &child_name, uint32_t &child_byte_size, int32_t &child_byte_offset, uint32_t &child_bitfield_bit_size, uint32_t &child_bitfield_bit_offset, bool &child_is_base_class, bool &child_is_deref_of_parent, ValueObject *valobj, uint64_t &language_flags) { child_name.clear(); child_byte_size = 0; child_byte_offset = 0; child_bitfield_bit_size = 0; child_bitfield_bit_offset = 0; child_is_base_class = false; child_is_deref_of_parent = false; language_flags = 0; if (!type || !GetCompleteType(type)) return CompilerType(); GoType *t = static_cast<GoType *>(type); if (t->GetStruct()) { uint64_t bit_offset; CompilerType ret = GetFieldAtIndex(type, idx, child_name, &bit_offset, nullptr, nullptr); child_byte_size = ret.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr); child_byte_offset = bit_offset / 8; return ret; } else if (t->GetGoKind() == GoType::KIND_PTR) { CompilerType pointee = t->GetElementType(); if (!pointee.IsValid() || pointee.IsVoidType()) return CompilerType(); if (transparent_pointers && pointee.IsAggregateType()) { bool tmp_child_is_deref_of_parent = false; return pointee.GetChildCompilerTypeAtIndex(exe_ctx, idx, transparent_pointers, omit_empty_base_classes, ignore_array_bounds, child_name, child_byte_size, child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, tmp_child_is_deref_of_parent, valobj, language_flags); } else { child_is_deref_of_parent = true; const char *parent_name = valobj ? valobj->GetName().GetCString() : NULL; if (parent_name) { child_name.assign(1, '*'); child_name += parent_name; } // We have a pointer to an simple type if (idx == 0 && pointee.GetCompleteType()) { child_byte_size = pointee.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL); child_byte_offset = 0; return pointee; } } } else if (GoArray *a = t->GetArray()) { if (ignore_array_bounds || idx < a->GetLength()) { CompilerType element_type = a->GetElementType(); if (element_type.GetCompleteType()) { char element_name[64]; ::snprintf(element_name, sizeof(element_name), "[%zu]", idx); child_name.assign(element_name); child_byte_size = element_type.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL); child_byte_offset = (int32_t)idx * (int32_t)child_byte_size; return element_type; } } } else if (t->IsTypedef()) { return t->GetElementType().GetChildCompilerTypeAtIndex( exe_ctx, idx, transparent_pointers, omit_empty_base_classes, ignore_array_bounds, child_name, child_byte_size, child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class, child_is_deref_of_parent, valobj, language_flags); } return CompilerType(); }