diff options
author | Zoran Zaric <Zoran.Zaric@amd.com> | 2020-12-07 19:00:31 +0000 |
---|---|---|
committer | Simon Marchi <simon.marchi@polymtl.ca> | 2020-12-08 11:16:21 -0500 |
commit | 1127a49b3242844d45d90658c7bfa886cd742ef1 (patch) | |
tree | a304584cbadb93df024c5df62075c9b1f19a3d7c | |
parent | dab5aee6dc3a8b19d5058f7c1b24d632a78a7adf (diff) | |
download | gdb-users/zoran/allow-location-description-on-dwarf-stack.zip gdb-users/zoran/allow-location-description-on-dwarf-stack.tar.gz gdb-users/zoran/allow-location-description-on-dwarf-stack.tar.bz2 |
Add support for nested composite locationsusers/zoran/allow-location-description-on-dwarf-stack
After allowing a location description to be placed on a DWARF stack,
in an effort to achieve a full composability of the DWARF expression,
it is necessary to enable forming of a nested composite location
descriptions.
To be able do this, a new operation DW_OP_LLVM_piece_end needs to be
introduced, along with some additional rules on the way how the
composite location description is formed using the existing DW_OP_piece
and DW_OP_bit_piece operations. These new rules are fully compatible
with the composite forming rules from the DWARF 5 standard.
More details on the new operation and added rules can be found here:
https://llvm.org/docs/AMDGPUDwarfExtensionsForHeterogeneousDebugging.html
gdb/ChangeLog:
* compile/compile-loc2c.c (compute_stack_depth_worker): Add new
DW_OP_LLVM_piece_end operation support.
* dwarf2/expr.c (class dwarf_value): Add copy constructor.
(class dwarf_location): Add copy constructor.
(class dwarf_undefined): Add copy constructor.
(class dwarf_memory): Add copy constructor.
(class dwarf_register): Add copy constructor.
(class dwarf_implicit): Add copy constructor.
(class dwarf_implicit_pointer): Add copy constructor.
(class dwarf_composite): Add copy constructor.
(read_from_location): Add composite completed check.
(write_to_location): Add composite completed check.
(read_value_contents_from_location): New function.
(dwarf_entry_factory::copy_entry): New method.
(rw_closure_value): Now calls read_value_contents_from_location
function.
(dwarf_expr_context::add_piece): Use new composite forming
rules.
(dwarf_expr_context::execute_stack_op): Add new
DW_OP_LLVM_piece_end operation support.
* dwarf2/loc.c (dwarf2_get_symbol_read_needs): Add new
DW_OP_LLVM_piece_end operation support.
include/ChangeLog:
* dwarf2.def (DW_OP_DUP): Add new DW_OP_LLVM_piece_end
enumeration.
gdb/testsuite/ChangeLog:
* gdb.dwarf2/dw2-llvm-piece-end.exp: New test.
Change-Id: Ib0b25e5de3f23df89d7d9e86aad56029c7d173df
-rw-r--r-- | gdb/compile/compile-loc2c.c | 1 | ||||
-rw-r--r-- | gdb/dwarf2/expr.c | 305 | ||||
-rw-r--r-- | gdb/dwarf2/loc.c | 1 | ||||
-rw-r--r-- | gdb/testsuite/gdb.dwarf2/dw2-llvm-piece-end.exp | 191 | ||||
-rw-r--r-- | include/dwarf2.def | 1 |
5 files changed, 469 insertions, 30 deletions
diff --git a/gdb/compile/compile-loc2c.c b/gdb/compile/compile-loc2c.c index e9698a7..fd28f2c 100644 --- a/gdb/compile/compile-loc2c.c +++ b/gdb/compile/compile-loc2c.c @@ -365,6 +365,7 @@ compute_stack_depth_worker (int start, int *need_tempvar, ++stack_depth; break; + case DW_OP_LLVM_piece_end: case DW_OP_LLVM_offset_constu: case DW_OP_nop: break; diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c index a65d18d..647bf88 100644 --- a/gdb/dwarf2/expr.c +++ b/gdb/dwarf2/expr.c @@ -308,6 +308,17 @@ public: m_type = type; } + dwarf_value (const dwarf_value &value) + { + struct type *type = value.m_type; + size_t type_len = TYPE_LENGTH (type); + + m_contents.reset ((gdb_byte *) xzalloc (type_len)); + + memcpy (m_contents.get (), value.m_contents.get (), type_len); + m_type = type; + } + virtual ~dwarf_value () = default; const gdb_byte* get_contents () const @@ -352,6 +363,12 @@ public: m_bit_suboffset = bit_suboffset % HOST_CHAR_BIT; } + dwarf_location (const dwarf_location &location) + : m_offset (location.m_offset), + m_bit_suboffset (location.m_bit_suboffset), + m_initialised (location.m_initialised) + {} + virtual ~dwarf_location () = default; LONGEST get_offset () const @@ -404,6 +421,11 @@ public: dwarf_undefined (LONGEST offset = 0, LONGEST bit_suboffset = 0) : dwarf_location (offset, bit_suboffset) {} + + dwarf_undefined (const dwarf_undefined &undefined_entry) + : dwarf_location (undefined_entry) + {} + }; class dwarf_memory : public dwarf_location @@ -415,6 +437,11 @@ public: m_stack (stack) {} + dwarf_memory (const dwarf_memory &memory_entry) + : dwarf_location (memory_entry), + m_stack (memory_entry.m_stack) + {} + bool in_stack () const { return m_stack; @@ -440,6 +467,11 @@ public: m_regnum (regnum) {} + dwarf_register (const dwarf_register ®ister_entry) + : dwarf_location (register_entry), + m_regnum (register_entry.m_regnum) + {} + unsigned int get_regnum () const { return m_regnum; @@ -468,6 +500,17 @@ public: m_byte_order = byte_order; } + dwarf_implicit (const dwarf_implicit &implicit_entry) + : dwarf_location (implicit_entry) + { + size_t size = implicit_entry.m_size; + m_contents.reset ((gdb_byte *) xzalloc (size)); + + memcpy (m_contents.get (), implicit_entry.m_contents.get (), size); + m_size = size; + m_byte_order = implicit_entry.m_byte_order; + } + const gdb_byte* get_contents () const { return m_contents.get (); @@ -508,6 +551,14 @@ public: m_addr_size (addr_size), m_die_offset (die_offset) {} + dwarf_implicit_pointer (const dwarf_implicit_pointer &implicit_ptr_entry) + : dwarf_location (implicit_ptr_entry), + m_per_objfile (implicit_ptr_entry.m_per_objfile), + m_per_cu (implicit_ptr_entry.m_per_cu), + m_addr_size (implicit_ptr_entry.m_addr_size), + m_die_offset (implicit_ptr_entry.m_die_offset) + {} + dwarf2_per_objfile *get_per_objfile () const { return m_per_objfile; @@ -551,6 +602,22 @@ public: : dwarf_location (offset, bit_suboffset) {} + dwarf_composite (const dwarf_composite &composite_entry) + : dwarf_location (composite_entry) + { + /* We do a shallow copy of the pieces because they are not + expected to be modified after they are already formed. */ + for (unsigned int i = 0; i < composite_entry.m_pieces.size (); i++) + { + dwarf_location* location = composite_entry.m_pieces[i].m_location; + + location->incref (); + m_pieces.emplace_back (location, composite_entry.m_pieces[i].m_size); + } + + m_completed = composite_entry.m_completed; + } + /* A composite location gets detached from its factory object for the purpose of lval_computed resolution, which means that it needs to take care of garbage collecting its pieces. */ @@ -591,6 +658,16 @@ public: return m_pieces.size (); } + void set_completed (bool completed) + { + m_completed = completed; + }; + + bool is_completed () const + { + return m_completed; + }; + private: /* Composite piece that contains a piece location description and it's size. */ @@ -608,6 +685,9 @@ private: /* Vector of composite pieces. */ std::vector<struct piece> m_pieces; + + /* True if location description is completed. */ + bool m_completed = false; }; /* Read contents from the location specified by the DWARF location @@ -789,6 +869,9 @@ read_from_location (const dwarf_location *location, struct frame_info *frame, unsigned int pieces_num = composite_entry->get_pieces_num (); unsigned int i; + if (!composite_entry->is_completed ()) + ill_formed_expression (); + total_bits_to_skip += offset * HOST_CHAR_BIT + bit_suboffset; /* Skip pieces covered by the read offset. */ @@ -971,6 +1054,9 @@ write_to_location (const dwarf_location *location, struct frame_info *frame, unsigned int pieces_num = composite_entry->get_pieces_num (); unsigned int i; + if (!composite_entry->is_completed ()) + ill_formed_expression (); + total_bits_to_skip += offset * HOST_CHAR_BIT + bit_suboffset; /* Skip pieces covered by the write offset. */ @@ -1008,6 +1094,92 @@ write_to_location (const dwarf_location *location, struct frame_info *frame, internal_error (__FILE__, __LINE__, _("invalid location type")); } +/* Read value contents from the location specified by the DWARF + location description entry LOCATION. + + The read operation is performed in the context of FRAME. BIT_SIZE + is the number of bits to read. The data read is copied to the + caller-managed buffer BUF. BITS_TO_SKIP is a bit offset into the + location and BUF_BIT_OFFSET is buffer BUF's bit offset. + LOCATION_BIT_LIMIT is a maximum number of bits that location can + hold, where value zero signifies that there is no such restriction. + + Note that some location types can be read without a FRAME context. */ + +static void +read_value_contents_from_location (struct value * value, + const dwarf_location *location, + struct frame_info *frame, + LONGEST bits_to_skip, + int value_bit_offset, size_t bit_size, + size_t location_bit_limit) +{ + /* Implicit pointers are handled later. */ + if (dynamic_cast<const dwarf_implicit_pointer *> (location) != nullptr) + return; + + auto composite_entry = dynamic_cast<const dwarf_composite *> (location); + + if (composite_entry == nullptr) + { + int optimized, unavailable; + bool big_endian = type_byte_order (value_type (value)) == BFD_ENDIAN_BIG; + + read_from_location (location, frame, bits_to_skip, + value_contents_raw (value), + value_bit_offset, bit_size, location_bit_limit, + big_endian, &optimized, &unavailable); + + if (optimized) + mark_value_bits_optimized_out (value, value_bit_offset, bit_size); + if (unavailable) + mark_value_bits_unavailable (value, value_bit_offset, bit_size); + + return; + } + + if (!composite_entry->is_completed ()) + ill_formed_expression (); + + unsigned int pieces_num = composite_entry->get_pieces_num (); + unsigned int i; + + LONGEST total_bits_to_skip = bits_to_skip + + composite_entry->get_offset () * HOST_CHAR_BIT + + composite_entry->get_bit_suboffset (); + + /* Skip pieces covered by the read offset. */ + for (i = 0; i < pieces_num; i++) + { + LONGEST piece_bit_size = composite_entry->get_bit_size_at (i); + + if (total_bits_to_skip < piece_bit_size) + break; + + total_bits_to_skip -= piece_bit_size; + } + + for (; i < pieces_num; i++) + { + LONGEST piece_bit_size = composite_entry->get_bit_size_at (i); + const dwarf_location *piece = composite_entry->get_piece_at (i); + + if (piece_bit_size > bit_size) + piece_bit_size = bit_size; + + read_value_contents_from_location (value, piece, frame, + total_bits_to_skip, + value_bit_offset, piece_bit_size, + piece_bit_size); + + if (bit_size == piece_bit_size) + break; + + value_bit_offset += piece_bit_size; + bit_size -= piece_bit_size; + } +} + /* Convert a value entry to the matching struct value representation of a given TYPE. OFFSET defines the offset into the value contents. @@ -1107,6 +1279,9 @@ public: dwarf_composite *create_composite (LONGEST offset = 0, LONGEST bit_suboffset = 0); + /* Create a deep copy of the DWARF ENTRY. */ + dwarf_entry *copy_entry (dwarf_entry *entry); + /* Convert an entry to a location description entry. If the entry is a location description entry a dynamic cast is applied. @@ -1252,6 +1427,33 @@ dwarf_entry_factory::create_composite (LONGEST offset, LONGEST bit_suboffset) return composite_entry; } +dwarf_entry * +dwarf_entry_factory::copy_entry (dwarf_entry *entry) +{ + dwarf_entry *entry_copy; + + if (auto value = dynamic_cast<dwarf_value *> (entry)) + entry_copy = new dwarf_value (*value); + else if (auto undefined = dynamic_cast<dwarf_undefined *> (entry)) + entry_copy = new dwarf_undefined (*undefined); + else if (auto memory = dynamic_cast<dwarf_memory *> (entry)) + entry_copy = new dwarf_memory (*memory); + else if (auto reg = dynamic_cast<dwarf_register *> (entry)) + entry_copy = new dwarf_register (*reg); + else if (auto implicit = dynamic_cast<dwarf_implicit *> (entry)) + entry_copy = new dwarf_implicit (*implicit); + else if (auto implicit_pointer + = dynamic_cast<dwarf_implicit_pointer *> (entry)) + entry_copy = new dwarf_implicit_pointer (*implicit_pointer); + else if (auto composite = dynamic_cast<dwarf_composite *> (entry)) + entry_copy = new dwarf_composite (*composite); + else + internal_error (__FILE__, __LINE__, _("invalid DWARF entry to copy.")); + + record_entry (entry_copy); + return entry_copy; +} + dwarf_location * dwarf_entry_factory::entry_to_location (dwarf_entry *entry) { @@ -1460,30 +1662,19 @@ rw_closure_value (struct value *v, struct value *from) const dwarf_location *location = composite_entry->get_piece_at (i); ULONGEST bit_size = composite_entry->get_bit_size_at (i); size_t this_bit_size = bit_size - bits_to_skip; - int optimized, unavailable; if (this_bit_size > max_bit_offset - bit_offset) this_bit_size = max_bit_offset - bit_offset; if (from == NULL) { - /* Implicit pointers are handled later. */ - if (dynamic_cast<const dwarf_implicit_pointer *> - (location) == nullptr) - { - read_from_location (location, frame, bits_to_skip, - value_contents_raw (v), bit_offset, - this_bit_size, bit_size, big_endian, - &optimized, &unavailable); - - if (optimized) - mark_value_bits_optimized_out (v, bit_offset, this_bit_size); - if (unavailable) - mark_value_bits_unavailable (v, bit_offset, this_bit_size); - } + read_value_contents_from_location (v, location, frame, bits_to_skip, + bit_offset, this_bit_size, bit_size); } else { + int optimized, unavailable; + write_to_location (location, frame, bits_to_skip, value_contents (from), bit_offset, this_bit_size, bit_size, big_endian, @@ -1892,10 +2083,34 @@ private: /* Pop a top element of the stack and add as a composite piece. - If the fallowing top element of the stack is a composite - location description, the piece will be added to it. Otherwise - a new composite location description will be created and - the piece will be added to that composite. */ + The action is based on the context: + + - If the stack is empty, then an incomplete composite location + description (comprised of one undefined location description), + is pushed on the stack. + + - Otherwise, if the top stack entry is an incomplete composite + location description, then it is updated to append a new piece + comprised of one undefined location description. The + incomplete composite location description is then left on the + stack. + + - Otherwise, if the top stack entry is a location description or + can be converted to one, it is popped. Then: + + - If the top stack entry (after popping) is a location + description comprised of one incomplete composite location + description, then it is updated to append a new piece + specified by the previously popped location description. + The incomplete composite location description is then left + on the stack. + + - Otherwise, a new location description comprised of one + incomplete composite location description, with a new piece + specified by the previously popped location description, is + pushed on the stack. + + - Otherwise, the DWARF expression is ill-formed */ dwarf_entry *add_piece (ULONGEST bit_size, ULONGEST bit_offset); /* The engine for the expression evaluator. Using the context in this @@ -2534,26 +2749,39 @@ dwarf_expr_context::add_piece (ULONGEST bit_size, ULONGEST bit_offset) dwarf_location *piece_entry; dwarf_composite *composite_entry; - if (!stack_empty_p () - && dynamic_cast<dwarf_composite *> (fetch (0)) == nullptr) + if (stack_empty_p ()) + piece_entry = entry_factory->create_undefined (); + else { piece_entry = entry_factory->entry_to_location (fetch (0)); - pop (); + + if (auto old_composite_entry + = dynamic_cast<dwarf_composite *> (piece_entry)) + { + if (!old_composite_entry->is_completed ()) + piece_entry = entry_factory->create_undefined (); + } + else if (dynamic_cast<dwarf_undefined *> (piece_entry) != nullptr) + pop (); } - else - piece_entry = entry_factory->create_undefined (); - piece_entry->add_bit_offset (bit_offset); + if (dynamic_cast<dwarf_undefined *> (piece_entry) == nullptr) + { + piece_entry->add_bit_offset (bit_offset); + pop (); + } - /* If stack is empty then it is a start of a new composite. In the - future this will check if the composite is finished or not. */ if (stack_empty_p () || dynamic_cast<dwarf_composite *> (fetch (0)) == nullptr) composite_entry = entry_factory->create_composite (); else { composite_entry = dynamic_cast<dwarf_composite *> (fetch (0)); - pop (); + + if (composite_entry->is_completed ()) + composite_entry = entry_factory->create_composite (); + else + pop (); } composite_entry->add_piece (piece_entry, bit_size); @@ -3156,7 +3384,7 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr, break; case DW_OP_dup: - result_entry = fetch (0); + result_entry = entry_factory->copy_entry (fetch (0)); break; case DW_OP_drop: @@ -3182,7 +3410,7 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr, } case DW_OP_over: - result_entry = fetch (1); + result_entry = entry_factory->copy_entry (fetch (1)); break; case DW_OP_rot: @@ -3742,6 +3970,23 @@ dwarf_expr_context::execute_stack_op (const gdb_byte *op_ptr, result_entry = entry_factory->create_undefined (); break; + case DW_OP_LLVM_piece_end: + { + dwarf_entry *entry = fetch (0); + + dwarf_composite *composite_entry + = dynamic_cast<dwarf_composite *> (entry); + + if (composite_entry == nullptr) + ill_formed_expression (); + + if (composite_entry->is_completed ()) + ill_formed_expression (); + + composite_entry->set_completed (true); + goto no_push; + } + default: error (_("Unhandled dwarf expression opcode 0x%x"), op); } diff --git a/gdb/dwarf2/loc.c b/gdb/dwarf2/loc.c index 1a903ce..e98d6fb 100644 --- a/gdb/dwarf2/loc.c +++ b/gdb/dwarf2/loc.c @@ -1832,6 +1832,7 @@ dwarf2_get_symbol_read_needs (gdb::array_view<const gdb_byte> expr, case DW_OP_LLVM_offset: case DW_OP_LLVM_bit_offset: case DW_OP_LLVM_undefined: + case DW_OP_LLVM_piece_end: break; case DW_OP_form_tls_address: diff --git a/gdb/testsuite/gdb.dwarf2/dw2-llvm-piece-end.exp b/gdb/testsuite/gdb.dwarf2/dw2-llvm-piece-end.exp new file mode 100644 index 0000000..3da739e --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/dw2-llvm-piece-end.exp @@ -0,0 +1,191 @@ +# Copyright 2017-2020 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Test the nested composition location description by using the new +# DW_OP_LLVM_piece_end operation. +# +# The test uses three nested levels of composite location descriptions +# to define a location of an array. + +load_lib dwarf.exp + +# This test can only be run on targets which support DWARF-2 and use gas. +if {![dwarf2_support]} { + return 0 +} + +# Choose suitable integer registers for the test. + +set dwarf_regnum 0 + +if { [is_aarch64_target] } { + set regname x0 +} elseif { [is_aarch32_target] + || [istarget "s390*-*-*" ] + || [istarget "powerpc*-*-*"] + || [istarget "rs6000*-*-aix*"] } { + set regname r0 +} elseif { [is_x86_like_target] } { + set regname eax +} elseif { [is_amd64_regs_target] } { + set regname rax +} else { + verbose "Skipping ${gdb_test_file_name}." + return +} + +standard_testfile var-access.c ${gdb_test_file_name}-dw.S + +# Make some DWARF for the test. + +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + global dwarf_regnum regname srcdir subdir srcfile + set buf_src [gdb_target_symbol buf] + + set main_result [function_range main ${srcdir}/${subdir}/${srcfile}] + set main_start [lindex $main_result 0] + set main_length [lindex $main_result 1] + + cu {} { + DW_TAG_compile_unit { + {DW_AT_name var-access.c} + {DW_AT_comp_dir /tmp} + } { + declare_labels array_type_label int_type_label char_type_label + + # define char type + char_type_label: DW_TAG_base_type { + {DW_AT_name "char"} + {DW_AT_encoding @DW_ATE_signed} + {DW_AT_byte_size 1 DW_FORM_sdata} + } + + int_type_label: DW_TAG_base_type { + {DW_AT_name "int"} + {DW_AT_encoding @DW_ATE_signed} + {DW_AT_byte_size 4 DW_FORM_sdata} + } + + array_type_label: DW_TAG_array_type { + {DW_AT_type :$char_type_label} + } { + DW_TAG_subrange_type { + {DW_AT_type :$int_type_label} + {DW_AT_upper_bound 7 DW_FORM_udata} + } + } + + DW_TAG_subprogram { + {DW_AT_name main} + {DW_AT_low_pc $main_start addr} + {DW_AT_high_pc $main_length data8} + } { + # Array spread in different pieces, of which some are + # undefined (1st and sixth bytes) and some are either + # in buf variable or REGNAME register. + # + # Location consists of three nested composite levels: + # - Third level consists of a composite location + # descriptions which hold a single simple location + # description each. + # - Second level consist of two more composite location + # descriptions that hold two of the third level + # composite location descriptions. + # - First level holds two of the second level composite + # location descriptions. + + DW_TAG_variable { + {DW_AT_name var_array} + {DW_AT_type :$array_type_label} + {DW_AT_location { + # First level composite start + # Second level first composite start + # Third level first composite start + DW_OP_addr $buf_src + DW_OP_piece 0x2 + DW_OP_LLVM_piece_end + # Third level first composite end + + # Third level second composite start + DW_OP_LLVM_undefined + DW_OP_piece 0x1 + DW_OP_LLVM_piece_end + # Third level second composite end + + DW_OP_piece 0x1 + DW_OP_swap + DW_OP_piece 0x2 + DW_OP_LLVM_piece_end + # Second level first composite end + + # Second level second composite start + # Third level third composite start + DW_OP_regx $dwarf_regnum + DW_OP_piece 0x4 + DW_OP_LLVM_piece_end + # Third level third composite end + + # Third level fourth composite start + DW_OP_LLVM_undefined + DW_OP_piece 0x1 + DW_OP_LLVM_piece_end + # Third level fourth composite end + + DW_OP_piece 0x1 + DW_OP_swap + DW_OP_piece 0x4 + DW_OP_LLVM_piece_end + # Second level second composite end + + DW_OP_piece 0x5 + DW_OP_swap + DW_OP_piece 0x3 + DW_OP_LLVM_piece_end + # First level composite end + + } SPECIAL_expr} + } + } + } + } +} + +if { [prepare_for_testing ${testfile}.exp ${testfile} \ + [list $srcfile $asm_file] {nodebug}] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +gdb_test_no_output "set var \$$regname = 0x4030201" "init reg" + +# Determine byte order. +set endian [get_endianness] +set optimized "<optimized out>" + +switch $endian { + little { + set val "$optimized, 0x1, 0x2, 0x3, 0x4, $optimized, 0x0, 0x1" + } + big { + set val "$optimized, 0x4, 0x3, 0x2, 0x1, $optimized, 0x0, 0x1" + } +} + +gdb_test "print/x var_array" " = \\{${val}\\}" "var_array print" + diff --git a/include/dwarf2.def b/include/dwarf2.def index b585602..fa6c20a 100644 --- a/include/dwarf2.def +++ b/include/dwarf2.def @@ -709,6 +709,7 @@ DW_OP_DUP (DW_OP_LLVM_offset, 0xe3) DW_OP_DUP (DW_OP_LLVM_offset_constu, 0xe4) DW_OP_DUP (DW_OP_LLVM_bit_offset, 0xe5) DW_OP (DW_OP_LLVM_undefined, 0xe7) +DW_OP_DUP (DW_OP_LLVM_piece_end, 0xea) DW_END_OP DW_FIRST_ATE (DW_ATE_void, 0x0) |