| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_DATA_MEMBER_H_ |
| #define SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_DATA_MEMBER_H_ |
| |
| #include "src/developer/debug/zxdb/symbols/value.h" |
| |
| namespace zxdb { |
| |
| // Represents a data member in a class. Not to be confused with function parameters and local |
| // variables which are represented by a Variable. |
| // |
| // The type and name come from the Value base class. |
| class DataMember final : public Value { |
| public: |
| // Construct with fxl::MakeRefCounted(). |
| |
| // Symbol overrides. |
| const DataMember* AsDataMember() const; |
| |
| // The byte offset from the containing class or struct of this data member. This is only valid |
| // if !is_external() -- see the base class' Value::is_external(). |
| uint32_t member_location() const { return member_location_; } |
| void set_member_location(uint32_t m) { member_location_ = m; } |
| |
| bool is_bitfield() const { return bit_size_ != 0; } |
| |
| // The DW_AT_data_bit_offset is used in DWARF 4 to indicate the bit position of a member bitfield. |
| // Unlike bit_offset, this will measure from the beginning of the containing structure. Currently |
| // all of our toolchains emit bit_offset (DWARF 2 style) and don't use this. |
| uint32_t data_bit_offset() const { return data_bit_offset_; } |
| void set_data_bit_offset(uint32_t dbo) { data_bit_offset_ = dbo; } |
| |
| // The DW_AT_byte_size attribute on the data member. |
| // |
| // Normally the byte size will be 0 which means to take the size from the type. For bitfields |
| // this will indicate the size of the larger field containing the bitfield, and the bit_offset |
| // will count from the high bit inside this byte_size (where byte_size is read as little-endian |
| // on little-endian machines). |
| // |
| // As of this writing I've only ever seen GCC and Clang generated byte_size() that matches the |
| // type().byte_size() even when the actual data occupies more physical bytes than the size of |
| // the type (because it's not aligned). This case will generated negative bit offsets. |
| // |
| // Note that for bitfields reading this many bytes may read off the end of the structure. For |
| // example: |
| // |
| // struct MyStruct { |
| // long long data : 2; |
| // }; |
| // |
| // MyStruct will have a byte_size of 1, while MyStruct.data will have a byte_size of 8! The bit |
| // offset will select the value bits from the structure. |
| uint32_t byte_size() const { return byte_size_; } |
| void set_byte_size(uint32_t bs) { byte_size_ = bs; } |
| |
| // Bit offset from the member_location(). This is counting from the high bit of the byte_size(). |
| // When that many bytes is read into memory (swapping the byte order for little-endian). |
| // |
| // As an example, a little-endian "int foo : 3;" might be defined as having: |
| // - byte_size = 4 |
| // - bit_offset = 29 |
| // - bit_size = 3 |
| // |
| // Bit layout (stored in the low 3 bits of a 32-bit integer): |
| // |
| // Byte 0 (low) Byte 1 Byte 2 Byte 3 (high bits) |
| // 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 |
| // x x x |
| // |
| // It can be negative which means it starts *beyond* the byte_size(). I have not seen this be |
| // more than one byte extra since otherwise the address will likely be one greater. For example: |
| // |
| // struct { |
| // // member_location = 0 |
| // // byte_size = 1 |
| // // bit_size = 6 |
| // // bit_offset = 2 |
| // bool a : 6; |
| // |
| // // member_location = 0 |
| // // byte_size = 1 |
| // // bit_size = 7 |
| // // bit_offset =-5 |
| // bool b : 7; |
| // }; |
| // |
| // Bit layout: |
| // |
| // Byte 0 Byte 1 |
| // 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 |
| // b b a a a a a a b b b b b |
| // ^ -5 bits in little-endian from the high bit of byte 0. |
| int32_t bit_offset() const { return bit_offset_; } |
| void set_bit_offset(int32_t bo) { bit_offset_ = bo; } |
| |
| // Number of bits that count. 0 means all. |
| uint32_t bit_size() const { return bit_size_; } |
| void set_bit_size(uint32_t bs) { bit_size_ = bs; } |
| |
| private: |
| FRIEND_REF_COUNTED_THREAD_SAFE(DataMember); |
| FRIEND_MAKE_REF_COUNTED(DataMember); |
| |
| DataMember(); |
| DataMember(const std::string& assigned_name, LazySymbol type, uint32_t member_loc); |
| ~DataMember(); |
| |
| uint32_t member_location_ = 0; |
| uint32_t data_bit_offset_ = 0; |
| uint32_t byte_size_ = 0; |
| int32_t bit_offset_ = 0; |
| uint32_t bit_size_ = 0; |
| }; |
| |
| } // namespace zxdb |
| |
| #endif // SRC_DEVELOPER_DEBUG_ZXDB_SYMBOLS_DATA_MEMBER_H_ |