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(); }
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; }
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; }
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; }
// 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; }
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(); }