From: Zoran Zaric Date: Mon, 7 Dec 2020 19:00:21 +0000 (+0000) Subject: Add dwarf_entry factory class to expr.c X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=7200429a7263063c337295982d3fafabd82dbed0;p=thirdparty%2Fbinutils-gdb.git Add dwarf_entry factory class to expr.c This patch introduces a new class in charge of creating, tracking and destroying dwarf_entry class based objects. gdb/ChangeLog: * dwarf2/expr.c (ill_formed_expression): New function. (value_to_gdb_value): New function. (class dwarf_entry_factory): New class. (dwarf_entry_factory::~dwarf_entry_factory): New method. (dwarf_entry_factory::record_entry): New method. (dwarf_entry_factory::create_value): New method. (dwarf_entry_factory::create_undefined): New method. (dwarf_entry_factory::create_memory): New method. (dwarf_entry_factory::create_register): New method. (dwarf_entry_factory::create_implicit): New method. (dwarf_entry_factory::create_implicit_pointer): New method. (dwarf_entry_factory::create_composite): New method. (dwarf_entry_factory::entry_to_location): New method. (dwarf_entry_factory::entry_to_value): New method. (dwarf_entry_factory::value_binary_op): New method. (dwarf_entry_factory::value_negation_op): New method. (dwarf_entry_factory::value_complement_op): New method. (dwarf_entry_factory::value_cast_op): New method. Change-Id: I679d2a80d9d9a64d6d19fefe6c18afc7a4357fe9 --- diff --git a/gdb/dwarf2/expr.c b/gdb/dwarf2/expr.c index fea82f8a87b..f188240d8b3 100644 --- a/gdb/dwarf2/expr.c +++ b/gdb/dwarf2/expr.c @@ -89,6 +89,14 @@ bits_to_bytes (ULONGEST start, ULONGEST n_bits) return (start % HOST_CHAR_BIT + n_bits + HOST_CHAR_BIT - 1) / HOST_CHAR_BIT; } +/* Throw an exception about the invalid DWARF expression. */ + +static void +ill_formed_expression () +{ + error (_("Ill-formed DWARF expression")); +} + /* See expr.h. */ CORE_ADDR @@ -1011,6 +1019,314 @@ write_to_location (const dwarf_location *location, struct frame_info *frame, internal_error (__FILE__, __LINE__, _("invalid location type")); } +/* Convert a value entry to the matching struct value representation + of a given TYPE. OFFSET defines the offset into the value + contents. + + We only need to support dwarf_value to gdb struct value conversion + here so that we can utilize the existing unary and binary operations + on struct value's. + + We could implement them for the dwarf_value's but that would lead + to code duplication with no real gain at the moment. */ + +static struct value * +value_to_gdb_value (const dwarf_value *value, struct type *type, + LONGEST offset = 0) +{ + size_t type_len = TYPE_LENGTH (type); + + if (offset + type_len > TYPE_LENGTH (value->get_type ())) + invalid_synthetic_pointer (); + + struct value *retval = allocate_value (type); + memcpy (value_contents_raw (retval), + value->get_contents () + offset, type_len); + + return retval; +} + +/* Factory class for creation and lifetime management of all DWARF + entries found on a DWARF evaluation stack. */ + +class dwarf_entry_factory +{ +public: + dwarf_entry_factory () = default; + ~dwarf_entry_factory (); + + /* Create a value entry of a given TYPE and copy a type size number of + bytes from the CONTENTS byte stream to the entry. */ + dwarf_value *create_value (const gdb_byte* contents, struct type *type); + + /* Creates a value entry of a TYPE type and copies the NUM + value to it's contents byte stream. */ + dwarf_value *create_value (ULONGEST num, struct type *type); + + /* Create a value entry of TYPE type and copy the NUM value to its + contents byte stream. */ + dwarf_value *create_value (LONGEST num, struct type *type); + + /* Create an undefined location description entry. */ + dwarf_undefined *create_undefined (); + + /* Create a memory location description entry. */ + dwarf_memory *create_memory (LONGEST offset, LONGEST bit_suboffset = 0, + bool stack = false); + + /* Create a register location description entry. */ + dwarf_register *create_register (unsigned int regnum, LONGEST offset = 0, + LONGEST bit_suboffset = 0); + + /* Create an implicit location description entry and copy SIZE + number of bytes from the CONTENTS byte stream to the location. + BYTE_ORDER holds the byte order of the location described. */ + dwarf_implicit *create_implicit (const gdb_byte *content, size_t size, + enum bfd_endian byte_order); + + /* Create an implicit pointer location description entry. */ + dwarf_implicit_pointer *create_implicit_pointer + (dwarf2_per_objfile *per_objfile, struct dwarf2_per_cu_data *per_cu, + int addr_size, sect_offset die_offset, LONGEST offset, + LONGEST bit_suboffset = 0); + + /* Create a composite location description entry. */ + dwarf_composite *create_composite (LONGEST offset = 0, + LONGEST bit_suboffset = 0); + + /* Convert an entry to a location description entry. If the entry + is a location description entry a dynamic cast is applied. + + In a case of a value entry, the value is implicitly + converted to a memory location description entry. */ + dwarf_location *entry_to_location (dwarf_entry *entry); + + /* Convert an entry to a value entry. If the entry is a value entry + a dynamic cast is applied. + + A location description entry is implicitly converted to a value + entry of DEFAULT_TYPE type. + Note that only 'memory location description entry' to 'value + entry' conversion is currently supported. */ + dwarf_value *entry_to_value (dwarf_entry *entry, struct type *default_type); + + /* Execute OP operation between ARG1 and ARG2 and return a new value + entry containing the result of that operation. */ + dwarf_value *value_binary_op (const dwarf_value *arg1, + const dwarf_value *arg2, enum exp_opcode op); + + /* Execute a negation operation on ARG and return a new value entry + containing the result of that operation. */ + dwarf_value *value_negation_op (const dwarf_value *arg); + + /* Execute a complement operation on ARG and return a new value + entry containing the result of that operation. */ + dwarf_value *value_complement_op (const dwarf_value *arg); + + /* Execute a cast operation on ARG and return a new value entry + containing the result of that operation. */ + dwarf_value *value_cast_op (const dwarf_value *arg, struct type *type); + +private: + /* Record entry for garbage collection. */ + void record_entry (dwarf_entry *entry); + + /* List of all entries created by the factory. */ + std::vector m_dwarf_entries; +}; + +dwarf_entry_factory::~dwarf_entry_factory () +{ + for (unsigned int i = 0; i < m_dwarf_entries.size (); i++) + { + dwarf_entry* entry = m_dwarf_entries[i]; + + entry->decref (); + + if (entry->refcount () == 0) + delete entry; + } +} + +void +dwarf_entry_factory::record_entry (dwarf_entry *entry) +{ + entry->incref (); + m_dwarf_entries.push_back (entry); +} + +dwarf_value * +dwarf_entry_factory::create_value (const gdb_byte* content, struct type *type) +{ + dwarf_value *value = new dwarf_value (content, type); + record_entry (value); + return value; +} + +dwarf_value * +dwarf_entry_factory::create_value (ULONGEST num, struct type *type) +{ + dwarf_value *value = new dwarf_value (num, type); + record_entry (value); + return value; +} + +dwarf_value * +dwarf_entry_factory::create_value (LONGEST num, struct type *type) +{ + dwarf_value *value = new dwarf_value (num, type); + record_entry (value); + return value; +} + +dwarf_undefined * +dwarf_entry_factory::create_undefined () +{ + dwarf_undefined *undefined_entry = new dwarf_undefined (); + record_entry (undefined_entry); + return undefined_entry; +} + +dwarf_memory * +dwarf_entry_factory::create_memory (LONGEST offset, LONGEST bit_suboffset, + bool stack) +{ + dwarf_memory *memory_entry + = new dwarf_memory (offset, bit_suboffset, stack); + record_entry (memory_entry); + return memory_entry; +} + +dwarf_register * +dwarf_entry_factory::create_register (unsigned int regnum, LONGEST offset, + LONGEST bit_suboffset) +{ + dwarf_register *register_entry + = new dwarf_register (regnum, offset, bit_suboffset); + record_entry (register_entry); + return register_entry; +} + +dwarf_implicit * +dwarf_entry_factory::create_implicit (const gdb_byte* content, size_t size, + enum bfd_endian byte_order) +{ + dwarf_implicit *implicit_entry + = new dwarf_implicit (content, size, byte_order); + record_entry (implicit_entry); + return implicit_entry; +} + +dwarf_implicit_pointer * +dwarf_entry_factory::create_implicit_pointer + (dwarf2_per_objfile *per_objfile, struct dwarf2_per_cu_data *per_cu, + int addr_size, sect_offset die_offset, LONGEST offset, + LONGEST bit_suboffset) +{ + dwarf_implicit_pointer *implicit_pointer_entry + = new dwarf_implicit_pointer (per_objfile, per_cu, addr_size, + die_offset, offset, bit_suboffset); + record_entry (implicit_pointer_entry); + return implicit_pointer_entry; +} + +dwarf_composite * +dwarf_entry_factory::create_composite (LONGEST offset, LONGEST bit_suboffset) +{ + dwarf_composite *composite_entry + = new dwarf_composite (offset, bit_suboffset); + record_entry (composite_entry); + return composite_entry; +} + +dwarf_location * +dwarf_entry_factory::entry_to_location (dwarf_entry *entry) +{ + /* If the given entry is already a location, + just send it back to the caller. */ + if (auto location = dynamic_cast (entry)) + return location; + + auto value = dynamic_cast (entry); + gdb_assert (value != nullptr); + + struct type *type = value->get_type (); + struct gdbarch *gdbarch = get_type_arch (type); + LONGEST offset; + + if (gdbarch_integer_to_address_p (gdbarch)) + offset = gdbarch_integer_to_address (gdbarch, type, + value->get_contents ()); + + offset = extract_unsigned_integer (value->get_contents (), + TYPE_LENGTH (type), + type_byte_order (type)); + + return create_memory (offset); +} + +dwarf_value * +dwarf_entry_factory::entry_to_value (dwarf_entry *entry, + struct type *default_type) +{ + /* If the given entry is already a value, + just send it back to the caller. */ + if (auto value = dynamic_cast (entry)) + return value; + + auto location = dynamic_cast (entry); + gdb_assert (location != nullptr); + + /* We only support memory location to value conversion at this point. + It is hard to define how would that conversion work for other + location description types. */ + if (dynamic_cast (location) == nullptr) + ill_formed_expression (); + + return create_value (location->get_offset (), default_type); +} + +/* We use the existing struct value operations to avoid code + duplication. Vector types are planned to be promoted to base types + in the future anyway which means that the subset we actually need + from these operations is just going to grow anyway. */ + +dwarf_value * +dwarf_entry_factory::value_binary_op (const dwarf_value *arg1, + const dwarf_value *arg2, + enum exp_opcode op) +{ + struct value *arg1_value = value_to_gdb_value (arg1, arg1->get_type ()); + struct value *arg2_value = value_to_gdb_value (arg2, arg2->get_type ()); + struct value *result = value_binop (arg1_value, arg2_value, op); + + return create_value (value_contents_raw (result), value_type (result)); +} + +dwarf_value * +dwarf_entry_factory::value_negation_op (const dwarf_value *arg) +{ + struct value *result + = value_neg (value_to_gdb_value (arg, arg->get_type ())); + return create_value (value_contents_raw (result), value_type (result)); +} + +dwarf_value * +dwarf_entry_factory::value_complement_op (const dwarf_value *arg) +{ + struct value *result + = value_complement (value_to_gdb_value (arg, arg->get_type ())); + return create_value (value_contents_raw (result), value_type (result)); +} + +dwarf_value * +dwarf_entry_factory::value_cast_op (const dwarf_value *arg, struct type *type) +{ + struct value *result + = value_cast (type, value_to_gdb_value (arg, arg->get_type ())); + return create_value (value_contents_raw (result), type); +} + struct piece_closure { /* Reference count. */