Thanks for the info. Comments inlined below!
Hi LLDB devs,
short question. Since the method
bool ValueObjectChild::SetData(DataExtractor &data, Status &error)
doesn’t exist, what is the preferred way to update the contents of
scalar bitfields?
Is there any code in the repo demonstrating the technique?
I am interested, because for the language I am writing a plugin for
certain datatypes are MSBit-aligned, e.g. a Nat16 occupies the upper
portion of the bits in a (32-bit) word.
Viewing and setting of such variables thus involves shifting bits, and
I’d expect that ValueObjectChild (in bitfield mode) would do that for
me.
Thanks in advance for any clues,
cheers,
Gabor
What is the debug information format being used for these? If it is DWARF,
the location expression for the variable should take care of extracting the
value correctly.
Hi Greg,
thanks for the very elaborate answer! Please find my replies inline, below.
In my case lldb
is reading DWARF. Things are being complicated a bit
by the fact that I am targeting a Wasm platform (WASI), and thus the
location of the
formal arguments is in locals (but this is comparable to registers on
common architectures).
Are you suggesting that the location expression should massage the
formal parameter?
Currently I emit
0x000000db: DW_TAG_formal_parameter
DW_AT_name ("n")
DW_AT_decl_line (5)
DW_AT_decl_column (0x09)
DW_AT_type (0x0000002b "Nat16")
DW_AT_location (DW_OP_WASM_location 0x0 +1, DW_OP_stack_value)
DW_OP_stack_value implies that after running this expression the value of this variable exists on the DWARF stack. This should mean that the “Value” would have a ValueType of eValueTypeScalar. I am guessing when you see these variables you always get the entire integer value of all bitfields that shared this integer. Is that correct?
and Nat16
is defined as:
0x0000002b: DW_TAG_base_type
DW_AT_name ("Nat16")
DW_AT_bit_size (0x20)
DW_AT_data_bit_offset (0x10)
DW_AT_encoding (DW_ATE_unsigned)
Interesting, from reading the DWARF specification, it is legal for a DW_TAG_base_type to have a DW_AT_bit_size and DW_AT_data_bit_offset, but LLDB is currently not handling this situation. We handle these for bitfields, which are currently attached to DW_TAG_member of a struct.
So we have two options to fix these kinds of variables:
- fix LLDB to handle the DW_AT_data_bit_offset and DW_AT_bit_size on DW_TAG_base_type types (requires LLDB fix)
- fix the DW_AT_location expression to shift and mask the integer with extra DW_OP opcodes (no fix required in LLDB)
The expression could be modified to add the data bit offset
DW_AT_location (DW_OP_WASM_location 0x0 +1, DW_OP_stack_value, DW_OP_const1u(0x10), DW_OP_shr, DW_OP_const4u(0xffffffff), DW_OP_and)
To break this down:
This gets the integer value and places it on the stack:
DW_OP_WASM_location 0x0 +1, DW_OP_stack_value
stack[0] = full_value
This pushes the data bit offset onto the stack:
DW_OP_const1u(0x10)
stack[0] = full_value
stack[1] = 0x10
This shifts the full_value to the right by 0x10:
DW_OP_shr
stack[0] = full_value >> 0x10
Now we need to make up a mask to mask of the first DW_AT_bit_size bits:
DW_OP_const4u(0xffffffff)
stack[0] = full_value >> 0x10
stack[1] = (1 << 0x20) - 1 (which makes the mask of 0xffffffff)
Now we mask off the high bits using the mask we just created
DW_OP_and
stack[0] = (full_value >> 0x10) & 0xffffffff
Now the value of the variable is correct.