|  | /* DWARF 2 Expression Evaluator. | 
|  |  | 
|  | Copyright (C) 2001-2025 Free Software Foundation, Inc. | 
|  |  | 
|  | Contributed by Daniel Berlin <dan@dberlin.org>. | 
|  |  | 
|  | This file is part of GDB. | 
|  |  | 
|  | 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/>.  */ | 
|  |  | 
|  | #ifndef GDB_DWARF2_EXPR_H | 
|  | #define GDB_DWARF2_EXPR_H | 
|  |  | 
|  | #include "leb128.h" | 
|  | #include "dwarf2/call-site.h" | 
|  | #include "dwarf2.h" | 
|  |  | 
|  | struct dwarf2_per_objfile; | 
|  |  | 
|  | /* The location of a value.  */ | 
|  | enum dwarf_value_location | 
|  | { | 
|  | /* The piece is in memory. | 
|  | The value on the dwarf stack is its address.  */ | 
|  | DWARF_VALUE_MEMORY, | 
|  |  | 
|  | /* The piece is in a register. | 
|  | The value on the dwarf stack is the register number.  */ | 
|  | DWARF_VALUE_REGISTER, | 
|  |  | 
|  | /* The piece is on the dwarf stack.  */ | 
|  | DWARF_VALUE_STACK, | 
|  |  | 
|  | /* The piece is a literal.  */ | 
|  | DWARF_VALUE_LITERAL, | 
|  |  | 
|  | /* The piece was optimized out.  */ | 
|  | DWARF_VALUE_OPTIMIZED_OUT, | 
|  |  | 
|  | /* The piece is an implicit pointer.  */ | 
|  | DWARF_VALUE_IMPLICIT_POINTER | 
|  | }; | 
|  |  | 
|  | /* A piece of an object, as recorded by DW_OP_piece or DW_OP_bit_piece.  */ | 
|  | struct dwarf_expr_piece | 
|  | { | 
|  | /* The DWARF operation for which the piece was created.  */ | 
|  | enum dwarf_location_atom op; | 
|  |  | 
|  | enum dwarf_value_location location; | 
|  |  | 
|  | union | 
|  | { | 
|  | struct | 
|  | { | 
|  | /* This piece's address, for DWARF_VALUE_MEMORY pieces.  */ | 
|  | CORE_ADDR addr; | 
|  | /* Non-zero if the piece is known to be in memory and on | 
|  | the program's stack.  */ | 
|  | bool in_stack_memory; | 
|  | } mem; | 
|  |  | 
|  | /* The piece's register number, for DWARF_VALUE_REGISTER pieces.  */ | 
|  | int regno; | 
|  |  | 
|  | /* The piece's literal value, for DWARF_VALUE_STACK pieces.  */ | 
|  | struct value *value; | 
|  |  | 
|  | struct | 
|  | { | 
|  | /* A pointer to the data making up this piece, | 
|  | for DWARF_VALUE_LITERAL pieces.  */ | 
|  | const gdb_byte *data; | 
|  | /* The length of the available data.  */ | 
|  | ULONGEST length; | 
|  | } literal; | 
|  |  | 
|  | /* Used for DWARF_VALUE_IMPLICIT_POINTER.  */ | 
|  | struct | 
|  | { | 
|  | /* The referent DIE from DW_OP_implicit_pointer.  */ | 
|  | sect_offset die_sect_off; | 
|  | /* The byte offset into the resulting data.  */ | 
|  | LONGEST offset; | 
|  | } ptr; | 
|  | } v; | 
|  |  | 
|  | /* The length of the piece, in bits.  */ | 
|  | ULONGEST size; | 
|  | /* The piece offset, in bits.  */ | 
|  | ULONGEST offset; | 
|  | }; | 
|  |  | 
|  | /* The dwarf expression stack.  */ | 
|  |  | 
|  | struct dwarf_stack_value | 
|  | { | 
|  | dwarf_stack_value (struct value *value_, int in_stack_memory_) | 
|  | : value (value_), in_stack_memory (in_stack_memory_) | 
|  | {} | 
|  |  | 
|  | struct value *value; | 
|  |  | 
|  | /* True if the piece is in memory and is known to be on the program's stack. | 
|  | It is always ok to set this to zero.  This is used, for example, to | 
|  | optimize memory access from the target.  It can vastly speed up backtraces | 
|  | on long latency connections when "set stack-cache on".  */ | 
|  | bool in_stack_memory; | 
|  | }; | 
|  |  | 
|  | /* The expression evaluator works with a dwarf_expr_context, describing | 
|  | its current state and its callbacks.  */ | 
|  | struct dwarf_expr_context | 
|  | { | 
|  | dwarf_expr_context (dwarf2_per_objfile *per_objfile, | 
|  | int addr_size); | 
|  | virtual ~dwarf_expr_context () = default; | 
|  |  | 
|  | void push_address (CORE_ADDR value, bool in_stack_memory); | 
|  |  | 
|  | /* Evaluate the expression at ADDR (LEN bytes long) in a given PER_CU | 
|  | and FRAME context. | 
|  |  | 
|  | AS_LVAL defines if the returned struct value is expected to be a | 
|  | value (false) or a location description (true). | 
|  |  | 
|  | TYPE, SUBOBJ_TYPE and SUBOBJ_OFFSET describe the expected struct | 
|  | value representation of the evaluation result. | 
|  |  | 
|  | The ADDR_INFO property can be specified to override the range of | 
|  | memory addresses with the passed in buffer.  */ | 
|  | value *evaluate (const gdb_byte *addr, size_t len, bool as_lval, | 
|  | dwarf2_per_cu *per_cu, const frame_info_ptr &frame, | 
|  | const struct property_addr_info *addr_info = nullptr, | 
|  | struct type *type = nullptr, | 
|  | struct type *subobj_type = nullptr, | 
|  | LONGEST subobj_offset = 0); | 
|  |  | 
|  | private: | 
|  | /* The stack of values.  */ | 
|  | std::vector<dwarf_stack_value> m_stack; | 
|  |  | 
|  | /* Target address size in bytes.  */ | 
|  | int m_addr_size = 0; | 
|  |  | 
|  | /* The current depth of dwarf expression recursion, via DW_OP_call*, | 
|  | DW_OP_fbreg, DW_OP_push_object_address, etc., and the maximum | 
|  | depth we'll tolerate before raising an error.  */ | 
|  | int m_recursion_depth = 0, m_max_recursion_depth = 0x100; | 
|  |  | 
|  | /* Location of the value.  */ | 
|  | dwarf_value_location m_location = DWARF_VALUE_MEMORY; | 
|  |  | 
|  | /* For DWARF_VALUE_LITERAL, the current literal value's length and | 
|  | data.  For DWARF_VALUE_IMPLICIT_POINTER, LEN is the offset of the | 
|  | target DIE of sect_offset kind.  */ | 
|  | ULONGEST m_len = 0; | 
|  | const gdb_byte *m_data = nullptr; | 
|  |  | 
|  | /* Initialization status of variable: True if variable has been | 
|  | initialized; false otherwise.  */ | 
|  | bool m_initialized = false; | 
|  |  | 
|  | /* A vector of pieces. | 
|  |  | 
|  | Each time DW_OP_piece is executed, we add a new element to the | 
|  | end of this array, recording the current top of the stack, the | 
|  | current location, and the size given as the operand to | 
|  | DW_OP_piece.  We then pop the top value from the stack, reset the | 
|  | location, and resume evaluation. | 
|  |  | 
|  | The Dwarf spec doesn't say whether DW_OP_piece pops the top value | 
|  | from the stack.  We do, ensuring that clients of this interface | 
|  | expecting to see a value left on the top of the stack (say, code | 
|  | evaluating frame base expressions or CFA's specified with | 
|  | DW_CFA_def_cfa_expression) will get an error if the expression | 
|  | actually marks all the values it computes as pieces. | 
|  |  | 
|  | If an expression never uses DW_OP_piece, num_pieces will be zero. | 
|  | (It would be nice to present these cases as expressions yielding | 
|  | a single piece, so that callers need not distinguish between the | 
|  | no-DW_OP_piece and one-DW_OP_piece cases.  But expressions with | 
|  | no DW_OP_piece operations have no value to place in a piece's | 
|  | 'size' field; the size comes from the surrounding data.  So the | 
|  | two cases need to be handled separately.)  */ | 
|  | std::vector<dwarf_expr_piece> m_pieces; | 
|  |  | 
|  | /* We evaluate the expression in the context of this objfile.  */ | 
|  | dwarf2_per_objfile *m_per_objfile; | 
|  |  | 
|  | /* Frame information used for the evaluation.  */ | 
|  | frame_info_ptr m_frame = nullptr; | 
|  |  | 
|  | /* Compilation unit used for the evaluation.  */ | 
|  | dwarf2_per_cu *m_per_cu = nullptr; | 
|  |  | 
|  | /* Property address info used for the evaluation.  */ | 
|  | const struct property_addr_info *m_addr_info = nullptr; | 
|  |  | 
|  | void eval (const gdb_byte *addr, size_t len); | 
|  | struct type *address_type () const; | 
|  | void push (struct value *value, bool in_stack_memory); | 
|  | bool stack_empty_p () const; | 
|  | void add_piece (ULONGEST size, ULONGEST offset, enum dwarf_location_atom op); | 
|  | void execute_stack_op (const gdb_byte *op_ptr, const gdb_byte *op_end); | 
|  | void pop (); | 
|  | struct value *fetch (int n); | 
|  | CORE_ADDR fetch_address (int n); | 
|  | bool fetch_in_stack_memory (int n); | 
|  |  | 
|  | /* Fetch the result of the expression evaluation in a form of | 
|  | a struct value, where TYPE, SUBOBJ_TYPE and SUBOBJ_OFFSET | 
|  | describe the source level representation of that result. | 
|  | AS_LVAL defines if the fetched struct value is expected to | 
|  | be a value or a location description.  */ | 
|  | value *fetch_result (struct type *type, struct type *subobj_type, | 
|  | LONGEST subobj_offset, bool as_lval); | 
|  |  | 
|  | /* Return the location expression for the frame base attribute, in | 
|  | START and LENGTH.  The result must be live until the current | 
|  | expression evaluation is complete.  */ | 
|  | void get_frame_base (const gdb_byte **start, size_t *length); | 
|  |  | 
|  | /* Return the base type given by the indicated DIE at DIE_CU_OFF. | 
|  | This can throw an exception if the DIE is invalid or does not | 
|  | represent a base type.  */ | 
|  | struct type *get_base_type (cu_offset die_cu_off); | 
|  |  | 
|  | /* Execute DW_AT_location expression for the DWARF expression | 
|  | subroutine in the DIE at DIE_CU_OFF in the CU.  Do not touch | 
|  | STACK while it being passed to and returned from the called DWARF | 
|  | subroutine.  */ | 
|  | void dwarf_call (cu_offset die_cu_off); | 
|  |  | 
|  | /* Push on DWARF stack an entry evaluated for DW_TAG_call_site's | 
|  | parameter matching KIND and KIND_U at the caller of specified BATON. | 
|  | If DEREF_SIZE is not -1 then use DW_AT_call_data_value instead of | 
|  | DW_AT_call_value.  */ | 
|  | void push_dwarf_reg_entry_value (call_site_parameter_kind kind, | 
|  | call_site_parameter_u kind_u, | 
|  | int deref_size); | 
|  |  | 
|  | /* Read LENGTH bytes at ADDR into BUF.  This method also handles the | 
|  | case where a caller of the evaluator passes in some data, | 
|  | but with the address being 0.  In this situation, we arrange for | 
|  | memory reads to come from the passed-in buffer.  */ | 
|  | void read_mem (gdb_byte *buf, CORE_ADDR addr, size_t length); | 
|  |  | 
|  | /* Deref ADDR with size SIZE and return a value of type TYPE. | 
|  | If TYPE == nullptr, defaults to this->address_type ().  */ | 
|  | value *deref (CORE_ADDR addr, int size, struct type *type = nullptr); | 
|  | }; | 
|  |  | 
|  | /* Return the value of register number REG (a DWARF register number), | 
|  | read as an address in a given FRAME.  */ | 
|  | CORE_ADDR read_addr_from_reg (const frame_info_ptr &frame, int reg); | 
|  |  | 
|  | void dwarf_expr_require_composition (const gdb_byte *, const gdb_byte *, | 
|  | const char *); | 
|  |  | 
|  | int dwarf_block_to_dwarf_reg (const gdb_byte *buf, const gdb_byte *buf_end); | 
|  |  | 
|  | int dwarf_block_to_dwarf_reg_deref (const gdb_byte *buf, | 
|  | const gdb_byte *buf_end, | 
|  | CORE_ADDR *deref_size_return); | 
|  |  | 
|  | int dwarf_block_to_fb_offset (const gdb_byte *buf, const gdb_byte *buf_end, | 
|  | CORE_ADDR *fb_offset_return); | 
|  |  | 
|  | int dwarf_block_to_sp_offset (struct gdbarch *gdbarch, const gdb_byte *buf, | 
|  | const gdb_byte *buf_end, | 
|  | CORE_ADDR *sp_offset_return); | 
|  |  | 
|  | /* Wrappers around the leb128 reader routines to simplify them for our | 
|  | purposes.  */ | 
|  |  | 
|  | static inline const gdb_byte * | 
|  | gdb_read_uleb128 (const gdb_byte *buf, const gdb_byte *buf_end, | 
|  | uint64_t *r) | 
|  | { | 
|  | size_t bytes_read = read_uleb128_to_uint64 (buf, buf_end, r); | 
|  |  | 
|  | if (bytes_read == 0) | 
|  | return NULL; | 
|  | return buf + bytes_read; | 
|  | } | 
|  |  | 
|  | static inline const gdb_byte * | 
|  | gdb_read_sleb128 (const gdb_byte *buf, const gdb_byte *buf_end, | 
|  | int64_t *r) | 
|  | { | 
|  | size_t bytes_read = read_sleb128_to_int64 (buf, buf_end, r); | 
|  |  | 
|  | if (bytes_read == 0) | 
|  | return NULL; | 
|  | return buf + bytes_read; | 
|  | } | 
|  |  | 
|  | static inline const gdb_byte * | 
|  | gdb_skip_leb128 (const gdb_byte *buf, const gdb_byte *buf_end) | 
|  | { | 
|  | size_t bytes_read = skip_leb128 (buf, buf_end); | 
|  |  | 
|  | if (bytes_read == 0) | 
|  | return NULL; | 
|  | return buf + bytes_read; | 
|  | } | 
|  |  | 
|  | extern const gdb_byte *safe_read_uleb128 (const gdb_byte *buf, | 
|  | const gdb_byte *buf_end, | 
|  | uint64_t *r); | 
|  |  | 
|  | extern const gdb_byte *safe_read_sleb128 (const gdb_byte *buf, | 
|  | const gdb_byte *buf_end, | 
|  | int64_t *r); | 
|  |  | 
|  | extern const gdb_byte *safe_skip_leb128 (const gdb_byte *buf, | 
|  | const gdb_byte *buf_end); | 
|  |  | 
|  | #endif /* GDB_DWARF2_EXPR_H */ |