1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177 |
- /* Convert a DWARF location expression to C
- Copyright (C) 2014-2022 Free Software Foundation, Inc.
- 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/>. */
- #include "defs.h"
- #include "dwarf2.h"
- #include "objfiles.h"
- #include "dwarf2/expr.h"
- #include "dwarf2/loc.h"
- #include "dwarf2/read.h"
- #include "ui-file.h"
- #include "utils.h"
- #include "compile-internal.h"
- #include "compile-c.h"
- #include "compile.h"
- #include "block.h"
- #include "dwarf2/frame.h"
- #include "gdbsupport/gdb_vecs.h"
- #include "value.h"
- #include "gdbarch.h"
- /* Information about a given instruction. */
- struct insn_info
- {
- /* Stack depth at entry. */
- unsigned int depth;
- /* Whether this instruction has been visited. */
- unsigned int visited : 1;
- /* Whether this instruction needs a label. */
- unsigned int label : 1;
- /* Whether this instruction is DW_OP_GNU_push_tls_address or
- DW_OP_form_tls_address. This is a hack until we can add a
- feature to glibc to let us properly generate code for TLS. */
- unsigned int is_tls : 1;
- };
- /* A helper function for compute_stack_depth that does the work. This
- examines the DWARF expression starting from START and computes
- stack effects.
- NEED_TEMPVAR is an out parameter which is set if this expression
- needs a special temporary variable to be emitted (see the code
- generator).
- INFO is a vector of insn_info objects, indexed by offset from the
- start of the DWARF expression.
- TO_DO is a list of bytecodes which must be examined; it may be
- added to by this function.
- BYTE_ORDER and ADDR_SIZE describe this bytecode in the obvious way.
- OP_PTR and OP_END are the bounds of the DWARF expression. */
- static void
- compute_stack_depth_worker (int start, int *need_tempvar,
- std::vector<struct insn_info> *info,
- std::vector<int> *to_do,
- enum bfd_endian byte_order, unsigned int addr_size,
- const gdb_byte *op_ptr, const gdb_byte *op_end)
- {
- const gdb_byte * const base = op_ptr;
- int stack_depth;
- op_ptr += start;
- gdb_assert ((*info)[start].visited);
- stack_depth = (*info)[start].depth;
- while (op_ptr < op_end)
- {
- enum dwarf_location_atom op = (enum dwarf_location_atom) *op_ptr;
- uint64_t reg;
- int64_t offset;
- int ndx = op_ptr - base;
- #define SET_CHECK_DEPTH(WHERE) \
- if ((*info)[WHERE].visited) \
- { \
- if ((*info)[WHERE].depth != stack_depth) \
- error (_("inconsistent stack depths")); \
- } \
- else \
- { \
- /* Stack depth not set, so set it. */ \
- (*info)[WHERE].visited = 1; \
- (*info)[WHERE].depth = stack_depth; \
- }
- SET_CHECK_DEPTH (ndx);
- ++op_ptr;
- switch (op)
- {
- case DW_OP_lit0:
- case DW_OP_lit1:
- case DW_OP_lit2:
- case DW_OP_lit3:
- case DW_OP_lit4:
- case DW_OP_lit5:
- case DW_OP_lit6:
- case DW_OP_lit7:
- case DW_OP_lit8:
- case DW_OP_lit9:
- case DW_OP_lit10:
- case DW_OP_lit11:
- case DW_OP_lit12:
- case DW_OP_lit13:
- case DW_OP_lit14:
- case DW_OP_lit15:
- case DW_OP_lit16:
- case DW_OP_lit17:
- case DW_OP_lit18:
- case DW_OP_lit19:
- case DW_OP_lit20:
- case DW_OP_lit21:
- case DW_OP_lit22:
- case DW_OP_lit23:
- case DW_OP_lit24:
- case DW_OP_lit25:
- case DW_OP_lit26:
- case DW_OP_lit27:
- case DW_OP_lit28:
- case DW_OP_lit29:
- case DW_OP_lit30:
- case DW_OP_lit31:
- ++stack_depth;
- break;
- case DW_OP_addr:
- op_ptr += addr_size;
- ++stack_depth;
- break;
- case DW_OP_const1u:
- case DW_OP_const1s:
- op_ptr += 1;
- ++stack_depth;
- break;
- case DW_OP_const2u:
- case DW_OP_const2s:
- op_ptr += 2;
- ++stack_depth;
- break;
- case DW_OP_const4u:
- case DW_OP_const4s:
- op_ptr += 4;
- ++stack_depth;
- break;
- case DW_OP_const8u:
- case DW_OP_const8s:
- op_ptr += 8;
- ++stack_depth;
- break;
- case DW_OP_constu:
- case DW_OP_consts:
- op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
- ++stack_depth;
- break;
- case DW_OP_reg0:
- case DW_OP_reg1:
- case DW_OP_reg2:
- case DW_OP_reg3:
- case DW_OP_reg4:
- case DW_OP_reg5:
- case DW_OP_reg6:
- case DW_OP_reg7:
- case DW_OP_reg8:
- case DW_OP_reg9:
- case DW_OP_reg10:
- case DW_OP_reg11:
- case DW_OP_reg12:
- case DW_OP_reg13:
- case DW_OP_reg14:
- case DW_OP_reg15:
- case DW_OP_reg16:
- case DW_OP_reg17:
- case DW_OP_reg18:
- case DW_OP_reg19:
- case DW_OP_reg20:
- case DW_OP_reg21:
- case DW_OP_reg22:
- case DW_OP_reg23:
- case DW_OP_reg24:
- case DW_OP_reg25:
- case DW_OP_reg26:
- case DW_OP_reg27:
- case DW_OP_reg28:
- case DW_OP_reg29:
- case DW_OP_reg30:
- case DW_OP_reg31:
- ++stack_depth;
- break;
- case DW_OP_regx:
- op_ptr = safe_read_uleb128 (op_ptr, op_end, ®);
- ++stack_depth;
- break;
- case DW_OP_breg0:
- case DW_OP_breg1:
- case DW_OP_breg2:
- case DW_OP_breg3:
- case DW_OP_breg4:
- case DW_OP_breg5:
- case DW_OP_breg6:
- case DW_OP_breg7:
- case DW_OP_breg8:
- case DW_OP_breg9:
- case DW_OP_breg10:
- case DW_OP_breg11:
- case DW_OP_breg12:
- case DW_OP_breg13:
- case DW_OP_breg14:
- case DW_OP_breg15:
- case DW_OP_breg16:
- case DW_OP_breg17:
- case DW_OP_breg18:
- case DW_OP_breg19:
- case DW_OP_breg20:
- case DW_OP_breg21:
- case DW_OP_breg22:
- case DW_OP_breg23:
- case DW_OP_breg24:
- case DW_OP_breg25:
- case DW_OP_breg26:
- case DW_OP_breg27:
- case DW_OP_breg28:
- case DW_OP_breg29:
- case DW_OP_breg30:
- case DW_OP_breg31:
- op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
- ++stack_depth;
- break;
- case DW_OP_bregx:
- {
- op_ptr = safe_read_uleb128 (op_ptr, op_end, ®);
- op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
- ++stack_depth;
- }
- break;
- case DW_OP_fbreg:
- op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
- ++stack_depth;
- break;
- case DW_OP_dup:
- ++stack_depth;
- break;
- case DW_OP_drop:
- --stack_depth;
- break;
- case DW_OP_pick:
- ++op_ptr;
- ++stack_depth;
- break;
- case DW_OP_rot:
- case DW_OP_swap:
- *need_tempvar = 1;
- break;
- case DW_OP_over:
- ++stack_depth;
- break;
- case DW_OP_abs:
- case DW_OP_neg:
- case DW_OP_not:
- case DW_OP_deref:
- break;
- case DW_OP_deref_size:
- ++op_ptr;
- break;
- case DW_OP_plus_uconst:
- op_ptr = safe_read_uleb128 (op_ptr, op_end, ®);
- break;
- case DW_OP_div:
- case DW_OP_shra:
- case DW_OP_and:
- case DW_OP_minus:
- case DW_OP_mod:
- case DW_OP_mul:
- case DW_OP_or:
- case DW_OP_plus:
- case DW_OP_shl:
- case DW_OP_shr:
- case DW_OP_xor:
- case DW_OP_le:
- case DW_OP_ge:
- case DW_OP_eq:
- case DW_OP_lt:
- case DW_OP_gt:
- case DW_OP_ne:
- --stack_depth;
- break;
- case DW_OP_call_frame_cfa:
- ++stack_depth;
- break;
- case DW_OP_GNU_push_tls_address:
- case DW_OP_form_tls_address:
- (*info)[ndx].is_tls = 1;
- break;
- case DW_OP_skip:
- offset = extract_signed_integer (op_ptr, 2, byte_order);
- op_ptr += 2;
- offset = op_ptr + offset - base;
- /* If the destination has not been seen yet, add it to the
- to-do list. */
- if (!(*info)[offset].visited)
- to_do->push_back (offset);
- SET_CHECK_DEPTH (offset);
- (*info)[offset].label = 1;
- /* We're done with this line of code. */
- return;
- case DW_OP_bra:
- offset = extract_signed_integer (op_ptr, 2, byte_order);
- op_ptr += 2;
- offset = op_ptr + offset - base;
- --stack_depth;
- /* If the destination has not been seen yet, add it to the
- to-do list. */
- if (!(*info)[offset].visited)
- to_do->push_back (offset);
- SET_CHECK_DEPTH (offset);
- (*info)[offset].label = 1;
- break;
- case DW_OP_nop:
- break;
- default:
- error (_("unhandled DWARF op: %s"), get_DW_OP_name (op));
- }
- }
- gdb_assert (op_ptr == op_end);
- #undef SET_CHECK_DEPTH
- }
- /* Compute the maximum needed stack depth of a DWARF expression, and
- some other information as well.
- BYTE_ORDER and ADDR_SIZE describe this bytecode in the obvious way.
- NEED_TEMPVAR is an out parameter which is set if this expression
- needs a special temporary variable to be emitted (see the code
- generator).
- IS_TLS is an out parameter which is set if this expression refers
- to a TLS variable.
- OP_PTR and OP_END are the bounds of the DWARF expression.
- INITIAL_DEPTH is the initial depth of the DWARF expression stack.
- INFO is an array of insn_info objects, indexed by offset from the
- start of the DWARF expression.
- This returns the maximum stack depth. */
- static int
- compute_stack_depth (enum bfd_endian byte_order, unsigned int addr_size,
- int *need_tempvar, int *is_tls,
- const gdb_byte *op_ptr, const gdb_byte *op_end,
- int initial_depth,
- std::vector<struct insn_info> *info)
- {
- std::vector<int> to_do;
- int stack_depth, i;
- info->resize (op_end - op_ptr);
- to_do.push_back (0);
- (*info)[0].depth = initial_depth;
- (*info)[0].visited = 1;
- while (!to_do.empty ())
- {
- int ndx = to_do.back ();
- to_do.pop_back ();
- compute_stack_depth_worker (ndx, need_tempvar, info, &to_do,
- byte_order, addr_size,
- op_ptr, op_end);
- }
- stack_depth = 0;
- *is_tls = 0;
- for (i = 0; i < op_end - op_ptr; ++i)
- {
- if ((*info)[i].depth > stack_depth)
- stack_depth = (*info)[i].depth;
- if ((*info)[i].is_tls)
- *is_tls = 1;
- }
- return stack_depth + 1;
- }
- #define GCC_UINTPTR "__gdb_uintptr"
- #define GCC_INTPTR "__gdb_intptr"
- /* Emit code to push a constant. */
- static void
- push (int indent, string_file *stream, ULONGEST l)
- {
- gdb_printf (stream,
- "%*s__gdb_stack[++__gdb_tos] = (" GCC_UINTPTR ") %s;\n",
- indent, "", hex_string (l));
- }
- /* Emit code to push an arbitrary expression. This works like
- printf. */
- static void pushf (int indent, string_file *stream, const char *format, ...)
- ATTRIBUTE_PRINTF (3, 4);
- static void
- pushf (int indent, string_file *stream, const char *format, ...)
- {
- va_list args;
- gdb_printf (stream, "%*s__gdb_stack[__gdb_tos + 1] = ", indent, "");
- va_start (args, format);
- stream->vprintf (format, args);
- va_end (args);
- stream->puts (";\n");
- gdb_printf (stream, "%*s++__gdb_tos;\n", indent, "");
- }
- /* Emit code for a unary expression -- one which operates in-place on
- the top-of-stack. This works like printf. */
- static void unary (int indent, string_file *stream, const char *format, ...)
- ATTRIBUTE_PRINTF (3, 4);
- static void
- unary (int indent, string_file *stream, const char *format, ...)
- {
- va_list args;
- gdb_printf (stream, "%*s__gdb_stack[__gdb_tos] = ", indent, "");
- va_start (args, format);
- stream->vprintf (format, args);
- va_end (args);
- stream->puts (";\n");
- }
- /* Emit code for a unary expression -- one which uses the top two
- stack items, popping the topmost one. This works like printf. */
- static void binary (int indent, string_file *stream, const char *format, ...)
- ATTRIBUTE_PRINTF (3, 4);
- static void
- binary (int indent, string_file *stream, const char *format, ...)
- {
- va_list args;
- gdb_printf (stream, "%*s__gdb_stack[__gdb_tos - 1] = ", indent, "");
- va_start (args, format);
- stream->vprintf (format, args);
- va_end (args);
- stream->puts (";\n");
- gdb_printf (stream, "%*s--__gdb_tos;\n", indent, "");
- }
- /* Print the name of a label given its "SCOPE", an arbitrary integer
- used for uniqueness, and its TARGET, the bytecode offset
- corresponding to the label's point of definition. */
- static void
- print_label (string_file *stream, unsigned int scope, int target)
- {
- stream->printf ("__label_%u_%s", scope, pulongest (target));
- }
- /* Note that a register was used. */
- static void
- note_register (int regnum, std::vector<bool> ®isters_used)
- {
- gdb_assert (regnum >= 0);
- /* If the expression uses a cooked register, then we currently can't
- compile it. We would need a gdbarch method to handle this
- situation. */
- if (regnum >= registers_used.size ())
- error (_("Expression uses \"cooked\" register and cannot be compiled."));
- registers_used[regnum] = true;
- }
- /* Emit code that pushes a register's address on the stack.
- REGISTERS_USED is an out parameter which is updated to note which
- register was needed by this expression. */
- static void
- pushf_register_address (int indent, string_file *stream,
- std::vector<bool> ®isters_used,
- struct gdbarch *gdbarch, int regnum)
- {
- std::string regname = compile_register_name_mangled (gdbarch, regnum);
- note_register (regnum, registers_used);
- pushf (indent, stream,
- "(" GCC_UINTPTR ") &" COMPILE_I_SIMPLE_REGISTER_ARG_NAME "->%s",
- regname.c_str ());
- }
- /* Emit code that pushes a register's value on the stack.
- REGISTERS_USED is an out parameter which is updated to note which
- register was needed by this expression. OFFSET is added to the
- register's value before it is pushed. */
- static void
- pushf_register (int indent, string_file *stream,
- std::vector<bool> ®isters_used,
- struct gdbarch *gdbarch, int regnum, uint64_t offset)
- {
- std::string regname = compile_register_name_mangled (gdbarch, regnum);
- note_register (regnum, registers_used);
- if (offset == 0)
- pushf (indent, stream, COMPILE_I_SIMPLE_REGISTER_ARG_NAME "->%s",
- regname.c_str ());
- else
- pushf (indent, stream,
- COMPILE_I_SIMPLE_REGISTER_ARG_NAME "->%s + (" GCC_UINTPTR ") %s",
- regname.c_str (), hex_string (offset));
- }
- /* Compile a DWARF expression to C code.
- INDENT is the indentation level to use.
- STREAM is the stream where the code should be written.
- TYPE_NAME names the type of the result of the DWARF expression.
- For locations this is "void *" but for array bounds it will be an
- integer type.
- RESULT_NAME is the name of a variable in the resulting C code. The
- result of the expression will be assigned to this variable.
- SYM is the symbol corresponding to this expression.
- PC is the location at which the expression is being evaluated.
- ARCH is the architecture to use.
- REGISTERS_USED is an out parameter which is updated to note which
- registers were needed by this expression.
- ADDR_SIZE is the DWARF address size to use.
- OPT_PTR and OP_END are the bounds of the DWARF expression.
- If non-NULL, INITIAL points to an initial value to write to the
- stack. If NULL, no initial value is written.
- PER_CU is the per-CU object used for looking up various other
- things. */
- static void
- do_compile_dwarf_expr_to_c (int indent, string_file *stream,
- const char *type_name,
- const char *result_name,
- struct symbol *sym, CORE_ADDR pc,
- struct gdbarch *arch,
- std::vector<bool> ®isters_used,
- unsigned int addr_size,
- const gdb_byte *op_ptr, const gdb_byte *op_end,
- CORE_ADDR *initial,
- dwarf2_per_cu_data *per_cu,
- dwarf2_per_objfile *per_objfile)
- {
- /* We keep a counter so that labels and other objects we create have
- unique names. */
- static unsigned int scope;
- enum bfd_endian byte_order = gdbarch_byte_order (arch);
- const gdb_byte * const base = op_ptr;
- int need_tempvar = 0;
- int is_tls = 0;
- std::vector<struct insn_info> info;
- int stack_depth;
- ++scope;
- gdb_printf (stream, "%*s__attribute__ ((unused)) %s %s;\n",
- indent, "", type_name, result_name);
- gdb_printf (stream, "%*s{\n", indent, "");
- indent += 2;
- stack_depth = compute_stack_depth (byte_order, addr_size,
- &need_tempvar, &is_tls,
- op_ptr, op_end, initial != NULL,
- &info);
- /* This is a hack until we can add a feature to glibc to let us
- properly generate code for TLS. You might think we could emit
- the address in the ordinary course of translating
- DW_OP_GNU_push_tls_address, but since the operand appears on the
- stack, it is relatively hard to find, and the idea of calling
- target_translate_tls_address with OFFSET==0 and then adding the
- offset by hand seemed too hackish. */
- if (is_tls)
- {
- struct frame_info *frame = get_selected_frame (NULL);
- struct value *val;
- if (frame == NULL)
- error (_("Symbol \"%s\" cannot be used because "
- "there is no selected frame"),
- sym->print_name ());
- val = read_var_value (sym, NULL, frame);
- if (VALUE_LVAL (val) != lval_memory)
- error (_("Symbol \"%s\" cannot be used for compilation evaluation "
- "as its address has not been found."),
- sym->print_name ());
- warning (_("Symbol \"%s\" is thread-local and currently can only "
- "be referenced from the current thread in "
- "compiled code."),
- sym->print_name ());
- gdb_printf (stream, "%*s%s = %s;\n",
- indent, "", result_name,
- core_addr_to_string (value_address (val)));
- gdb_printf (stream, "%*s}\n", indent - 2, "");
- return;
- }
- gdb_printf (stream, "%*s" GCC_UINTPTR " __gdb_stack[%d];\n",
- indent, "", stack_depth);
- if (need_tempvar)
- gdb_printf (stream, "%*s" GCC_UINTPTR " __gdb_tmp;\n", indent, "");
- gdb_printf (stream, "%*sint __gdb_tos = -1;\n", indent, "");
- if (initial != NULL)
- pushf (indent, stream, "%s", core_addr_to_string (*initial));
- while (op_ptr < op_end)
- {
- enum dwarf_location_atom op = (enum dwarf_location_atom) *op_ptr;
- uint64_t uoffset, reg;
- int64_t offset;
- stream->printf ("%*s", indent - 2, "");
- if (info[op_ptr - base].label)
- {
- print_label (stream, scope, op_ptr - base);
- stream->puts (":;");
- }
- stream->printf ("/* %s */\n", get_DW_OP_name (op));
- /* This is handy for debugging the generated code:
- gdb_printf (stream, "if (__gdb_tos != %d) abort ();\n",
- (int) info[op_ptr - base].depth - 1);
- */
- ++op_ptr;
- switch (op)
- {
- case DW_OP_lit0:
- case DW_OP_lit1:
- case DW_OP_lit2:
- case DW_OP_lit3:
- case DW_OP_lit4:
- case DW_OP_lit5:
- case DW_OP_lit6:
- case DW_OP_lit7:
- case DW_OP_lit8:
- case DW_OP_lit9:
- case DW_OP_lit10:
- case DW_OP_lit11:
- case DW_OP_lit12:
- case DW_OP_lit13:
- case DW_OP_lit14:
- case DW_OP_lit15:
- case DW_OP_lit16:
- case DW_OP_lit17:
- case DW_OP_lit18:
- case DW_OP_lit19:
- case DW_OP_lit20:
- case DW_OP_lit21:
- case DW_OP_lit22:
- case DW_OP_lit23:
- case DW_OP_lit24:
- case DW_OP_lit25:
- case DW_OP_lit26:
- case DW_OP_lit27:
- case DW_OP_lit28:
- case DW_OP_lit29:
- case DW_OP_lit30:
- case DW_OP_lit31:
- push (indent, stream, op - DW_OP_lit0);
- break;
- case DW_OP_addr:
- uoffset = extract_unsigned_integer (op_ptr, addr_size, byte_order);
- op_ptr += addr_size;
- /* Some versions of GCC emit DW_OP_addr before
- DW_OP_GNU_push_tls_address. In this case the value is an
- index, not an address. We don't support things like
- branching between the address and the TLS op. */
- if (op_ptr >= op_end || *op_ptr != DW_OP_GNU_push_tls_address)
- uoffset += per_objfile->objfile->text_section_offset ();
- push (indent, stream, uoffset);
- break;
- case DW_OP_const1u:
- push (indent, stream,
- extract_unsigned_integer (op_ptr, 1, byte_order));
- op_ptr += 1;
- break;
- case DW_OP_const1s:
- push (indent, stream,
- extract_signed_integer (op_ptr, 1, byte_order));
- op_ptr += 1;
- break;
- case DW_OP_const2u:
- push (indent, stream,
- extract_unsigned_integer (op_ptr, 2, byte_order));
- op_ptr += 2;
- break;
- case DW_OP_const2s:
- push (indent, stream,
- extract_signed_integer (op_ptr, 2, byte_order));
- op_ptr += 2;
- break;
- case DW_OP_const4u:
- push (indent, stream,
- extract_unsigned_integer (op_ptr, 4, byte_order));
- op_ptr += 4;
- break;
- case DW_OP_const4s:
- push (indent, stream,
- extract_signed_integer (op_ptr, 4, byte_order));
- op_ptr += 4;
- break;
- case DW_OP_const8u:
- push (indent, stream,
- extract_unsigned_integer (op_ptr, 8, byte_order));
- op_ptr += 8;
- break;
- case DW_OP_const8s:
- push (indent, stream,
- extract_signed_integer (op_ptr, 8, byte_order));
- op_ptr += 8;
- break;
- case DW_OP_constu:
- op_ptr = safe_read_uleb128 (op_ptr, op_end, &uoffset);
- push (indent, stream, uoffset);
- break;
- case DW_OP_consts:
- op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
- push (indent, stream, offset);
- break;
- case DW_OP_reg0:
- case DW_OP_reg1:
- case DW_OP_reg2:
- case DW_OP_reg3:
- case DW_OP_reg4:
- case DW_OP_reg5:
- case DW_OP_reg6:
- case DW_OP_reg7:
- case DW_OP_reg8:
- case DW_OP_reg9:
- case DW_OP_reg10:
- case DW_OP_reg11:
- case DW_OP_reg12:
- case DW_OP_reg13:
- case DW_OP_reg14:
- case DW_OP_reg15:
- case DW_OP_reg16:
- case DW_OP_reg17:
- case DW_OP_reg18:
- case DW_OP_reg19:
- case DW_OP_reg20:
- case DW_OP_reg21:
- case DW_OP_reg22:
- case DW_OP_reg23:
- case DW_OP_reg24:
- case DW_OP_reg25:
- case DW_OP_reg26:
- case DW_OP_reg27:
- case DW_OP_reg28:
- case DW_OP_reg29:
- case DW_OP_reg30:
- case DW_OP_reg31:
- dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
- pushf_register_address (indent, stream, registers_used, arch,
- dwarf_reg_to_regnum_or_error
- (arch, op - DW_OP_reg0));
- break;
- case DW_OP_regx:
- op_ptr = safe_read_uleb128 (op_ptr, op_end, ®);
- dwarf_expr_require_composition (op_ptr, op_end, "DW_OP_regx");
- pushf_register_address (indent, stream, registers_used, arch,
- dwarf_reg_to_regnum_or_error (arch, reg));
- break;
- case DW_OP_breg0:
- case DW_OP_breg1:
- case DW_OP_breg2:
- case DW_OP_breg3:
- case DW_OP_breg4:
- case DW_OP_breg5:
- case DW_OP_breg6:
- case DW_OP_breg7:
- case DW_OP_breg8:
- case DW_OP_breg9:
- case DW_OP_breg10:
- case DW_OP_breg11:
- case DW_OP_breg12:
- case DW_OP_breg13:
- case DW_OP_breg14:
- case DW_OP_breg15:
- case DW_OP_breg16:
- case DW_OP_breg17:
- case DW_OP_breg18:
- case DW_OP_breg19:
- case DW_OP_breg20:
- case DW_OP_breg21:
- case DW_OP_breg22:
- case DW_OP_breg23:
- case DW_OP_breg24:
- case DW_OP_breg25:
- case DW_OP_breg26:
- case DW_OP_breg27:
- case DW_OP_breg28:
- case DW_OP_breg29:
- case DW_OP_breg30:
- case DW_OP_breg31:
- op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
- pushf_register (indent, stream, registers_used, arch,
- dwarf_reg_to_regnum_or_error (arch,
- op - DW_OP_breg0),
- offset);
- break;
- case DW_OP_bregx:
- {
- op_ptr = safe_read_uleb128 (op_ptr, op_end, ®);
- op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
- pushf_register (indent, stream, registers_used, arch,
- dwarf_reg_to_regnum_or_error (arch, reg), offset);
- }
- break;
- case DW_OP_fbreg:
- {
- const gdb_byte *datastart;
- size_t datalen;
- const struct block *b;
- struct symbol *framefunc;
- char fb_name[50];
- b = block_for_pc (pc);
- if (!b)
- error (_("No block found for address"));
- framefunc = block_linkage_function (b);
- if (!framefunc)
- error (_("No function found for block"));
- func_get_frame_base_dwarf_block (framefunc, pc,
- &datastart, &datalen);
- op_ptr = safe_read_sleb128 (op_ptr, op_end, &offset);
- /* Generate a unique-enough name, in case the frame base
- is computed multiple times in this expression. */
- xsnprintf (fb_name, sizeof (fb_name), "__frame_base_%ld",
- (long) (op_ptr - base));
- do_compile_dwarf_expr_to_c (indent, stream,
- GCC_UINTPTR, fb_name,
- sym, pc,
- arch, registers_used, addr_size,
- datastart, datastart + datalen,
- NULL, per_cu, per_objfile);
- pushf (indent, stream, "%s + %s", fb_name, hex_string (offset));
- }
- break;
- case DW_OP_dup:
- pushf (indent, stream, "__gdb_stack[__gdb_tos]");
- break;
- case DW_OP_drop:
- gdb_printf (stream, "%*s--__gdb_tos;\n", indent, "");
- break;
- case DW_OP_pick:
- offset = *op_ptr++;
- pushf (indent, stream, "__gdb_stack[__gdb_tos - %s]",
- plongest (offset));
- break;
- case DW_OP_swap:
- gdb_printf (stream,
- "%*s__gdb_tmp = __gdb_stack[__gdb_tos - 1];\n",
- indent, "");
- gdb_printf (stream,
- "%*s__gdb_stack[__gdb_tos - 1] = "
- "__gdb_stack[__gdb_tos];\n",
- indent, "");
- gdb_printf (stream, ("%*s__gdb_stack[__gdb_tos] = "
- "__gdb_tmp;\n"),
- indent, "");
- break;
- case DW_OP_over:
- pushf (indent, stream, "__gdb_stack[__gdb_tos - 1]");
- break;
- case DW_OP_rot:
- gdb_printf (stream, ("%*s__gdb_tmp = "
- "__gdb_stack[__gdb_tos];\n"),
- indent, "");
- gdb_printf (stream,
- "%*s__gdb_stack[__gdb_tos] = "
- "__gdb_stack[__gdb_tos - 1];\n",
- indent, "");
- gdb_printf (stream,
- "%*s__gdb_stack[__gdb_tos - 1] = "
- "__gdb_stack[__gdb_tos -2];\n",
- indent, "");
- gdb_printf (stream, "%*s__gdb_stack[__gdb_tos - 2] = "
- "__gdb_tmp;\n",
- indent, "");
- break;
- case DW_OP_deref:
- case DW_OP_deref_size:
- {
- int size;
- const char *mode;
- if (op == DW_OP_deref_size)
- size = *op_ptr++;
- else
- size = addr_size;
- mode = c_get_mode_for_size (size);
- if (mode == NULL)
- error (_("Unsupported size %d in %s"),
- size, get_DW_OP_name (op));
- /* Cast to a pointer of the desired type, then
- dereference. */
- gdb_printf (stream,
- "%*s__gdb_stack[__gdb_tos] = "
- "*((__gdb_int_%s *) "
- "__gdb_stack[__gdb_tos]);\n",
- indent, "", mode);
- }
- break;
- case DW_OP_abs:
- unary (indent, stream,
- "((" GCC_INTPTR ") __gdb_stack[__gdb_tos]) < 0 ? "
- "-__gdb_stack[__gdb_tos] : __gdb_stack[__gdb_tos]");
- break;
- case DW_OP_neg:
- unary (indent, stream, "-__gdb_stack[__gdb_tos]");
- break;
- case DW_OP_not:
- unary (indent, stream, "~__gdb_stack[__gdb_tos]");
- break;
- case DW_OP_plus_uconst:
- op_ptr = safe_read_uleb128 (op_ptr, op_end, ®);
- unary (indent, stream, "__gdb_stack[__gdb_tos] + %s",
- hex_string (reg));
- break;
- case DW_OP_div:
- binary (indent, stream, ("((" GCC_INTPTR
- ") __gdb_stack[__gdb_tos-1]) / (("
- GCC_INTPTR ") __gdb_stack[__gdb_tos])"));
- break;
- case DW_OP_shra:
- binary (indent, stream,
- "((" GCC_INTPTR ") __gdb_stack[__gdb_tos-1]) >> "
- "__gdb_stack[__gdb_tos]");
- break;
- #define BINARY(OP) \
- binary (indent, stream, "%s", "__gdb_stack[__gdb_tos-1] " #OP \
- " __gdb_stack[__gdb_tos]"); \
- break
- case DW_OP_and:
- BINARY (&);
- case DW_OP_minus:
- BINARY (-);
- case DW_OP_mod:
- BINARY (%);
- case DW_OP_mul:
- BINARY (*);
- case DW_OP_or:
- BINARY (|);
- case DW_OP_plus:
- BINARY (+);
- case DW_OP_shl:
- BINARY (<<);
- case DW_OP_shr:
- BINARY (>>);
- case DW_OP_xor:
- BINARY (^);
- #undef BINARY
- #define COMPARE(OP) \
- binary (indent, stream, \
- "(((" GCC_INTPTR ") __gdb_stack[__gdb_tos-1]) " #OP \
- " ((" GCC_INTPTR \
- ") __gdb_stack[__gdb_tos]))"); \
- break
- case DW_OP_le:
- COMPARE (<=);
- case DW_OP_ge:
- COMPARE (>=);
- case DW_OP_eq:
- COMPARE (==);
- case DW_OP_lt:
- COMPARE (<);
- case DW_OP_gt:
- COMPARE (>);
- case DW_OP_ne:
- COMPARE (!=);
- #undef COMPARE
- case DW_OP_call_frame_cfa:
- {
- int regnum;
- CORE_ADDR text_offset;
- LONGEST off;
- const gdb_byte *cfa_start, *cfa_end;
- if (dwarf2_fetch_cfa_info (arch, pc, per_cu,
- ®num, &off,
- &text_offset, &cfa_start, &cfa_end))
- {
- /* Register. */
- pushf_register (indent, stream, registers_used, arch, regnum,
- off);
- }
- else
- {
- /* Another expression. */
- char cfa_name[50];
- /* Generate a unique-enough name, in case the CFA is
- computed multiple times in this expression. */
- xsnprintf (cfa_name, sizeof (cfa_name),
- "__cfa_%ld", (long) (op_ptr - base));
- do_compile_dwarf_expr_to_c (indent, stream,
- GCC_UINTPTR, cfa_name,
- sym, pc, arch, registers_used,
- addr_size,
- cfa_start, cfa_end,
- &text_offset, per_cu, per_objfile);
- pushf (indent, stream, "%s", cfa_name);
- }
- }
- break;
- case DW_OP_skip:
- offset = extract_signed_integer (op_ptr, 2, byte_order);
- op_ptr += 2;
- gdb_printf (stream, "%*sgoto ", indent, "");
- print_label (stream, scope, op_ptr + offset - base);
- stream->puts (";\n");
- break;
- case DW_OP_bra:
- offset = extract_signed_integer (op_ptr, 2, byte_order);
- op_ptr += 2;
- gdb_printf (stream,
- "%*sif ((( " GCC_INTPTR
- ") __gdb_stack[__gdb_tos--]) != 0) goto ",
- indent, "");
- print_label (stream, scope, op_ptr + offset - base);
- stream->puts (";\n");
- break;
- case DW_OP_nop:
- break;
- default:
- error (_("unhandled DWARF op: %s"), get_DW_OP_name (op));
- }
- }
- gdb_printf (stream, "%*s%s = __gdb_stack[__gdb_tos];\n",
- indent, "", result_name);
- gdb_printf (stream, "%*s}\n", indent - 2, "");
- }
- /* See compile.h. */
- void
- compile_dwarf_expr_to_c (string_file *stream, const char *result_name,
- struct symbol *sym, CORE_ADDR pc,
- struct gdbarch *arch,
- std::vector<bool> ®isters_used,
- unsigned int addr_size,
- const gdb_byte *op_ptr, const gdb_byte *op_end,
- dwarf2_per_cu_data *per_cu,
- dwarf2_per_objfile *per_objfile)
- {
- do_compile_dwarf_expr_to_c (2, stream, GCC_UINTPTR, result_name, sym, pc,
- arch, registers_used, addr_size, op_ptr, op_end,
- NULL, per_cu, per_objfile);
- }
- /* See compile.h. */
- void
- compile_dwarf_bounds_to_c (string_file *stream,
- const char *result_name,
- const struct dynamic_prop *prop,
- struct symbol *sym, CORE_ADDR pc,
- struct gdbarch *arch,
- std::vector<bool> ®isters_used,
- unsigned int addr_size,
- const gdb_byte *op_ptr, const gdb_byte *op_end,
- dwarf2_per_cu_data *per_cu,
- dwarf2_per_objfile *per_objfile)
- {
- do_compile_dwarf_expr_to_c (2, stream, "unsigned long ", result_name,
- sym, pc, arch, registers_used,
- addr_size, op_ptr, op_end, NULL, per_cu,
- per_objfile);
- }
|