/* dwarf-expr.pk - DWARF implementation for GNU poke.
                   Expressions.  */

/* Copyright (C) 2020, 2021, 2022, 2023 Jose E. Marchesi.  */

/* 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/>.
 */

load leb128;

/* Opcodes.  */

var DW_OP_FIRST                = 0x03 as uint<8>,
    DW_OP_addr                 = 0x03 as uint<8>,
    DW_OP_deref                = 0x06 as uint<8>,
    DW_OP_const1u              = 0x08 as uint<8>,
    DW_OP_const1s              = 0x09 as uint<8>,
    DW_OP_const2u              = 0x0a as uint<8>,
    DW_OP_const2s              = 0x0b as uint<8>,
    DW_OP_const4u              = 0x0c as uint<8>,
    DW_OP_const4s              = 0x0d as uint<8>,
    DW_OP_const8u              = 0x0e as uint<8>,
    DW_OP_const8s              = 0x0f as uint<8>,
    DW_OP_constu               = 0x10 as uint<8>,
    DW_OP_consts               = 0x11 as uint<8>,
    DW_OP_dup                  = 0x12 as uint<8>,
    DW_OP_drop                 = 0x13 as uint<8>,
    DW_OP_over                 = 0x14 as uint<8>,
    DW_OP_pick                 = 0x15 as uint<8>,
    DW_OP_swap                 = 0x16 as uint<8>,
    DW_OP_rot                  = 0x17 as uint<8>,
    DW_OP_xderef               = 0x18 as uint<8>,
    DW_OP_abs                  = 0x19 as uint<8>,
    DW_OP_and                  = 0x1a as uint<8>,
    DW_OP_div                  = 0x1b as uint<8>,
    DW_OP_minus                = 0x1c as uint<8>,
    DW_OP_mod                  = 0x1d as uint<8>,
    DW_OP_mul                  = 0x1e as uint<8>,
    DW_OP_neg                  = 0x1f as uint<8>,
    DW_OP_not                  = 0x20 as uint<8>,
    DW_OP_or                   = 0x21 as uint<8>,
    DW_OP_plus                 = 0x22 as uint<8>,
    DW_OP_plus_uconst          = 0x23 as uint<8>,
    DW_OP_shl                  = 0x24 as uint<8>,
    DW_OP_shr                  = 0x25 as uint<8>,
    DW_OP_shra                 = 0x26 as uint<8>,
    DW_OP_xor                  = 0x27 as uint<8>,
    DW_OP_bra                  = 0x28 as uint<8>,
    DW_OP_eq                   = 0x29 as uint<8>,
    DW_OP_ge                   = 0x2a as uint<8>,
    DW_OP_gt                   = 0x2b as uint<8>,
    DW_OP_le                   = 0x2c as uint<8>,
    DW_OP_lt                   = 0x2d as uint<8>,
    DW_OP_ne                   = 0x2e as uint<8>,
    DW_OP_skip                 = 0x2f as uint<8>,
    DW_OP_lit0                 = 0x30 as uint<8>,
    DW_OP_lit1                 = 0x31 as uint<8>,
    DW_OP_lit2                 = 0x32 as uint<8>,
    DW_OP_lit3                 = 0x33 as uint<8>,
    DW_OP_lit4                 = 0x34 as uint<8>,
    DW_OP_lit5                 = 0x35 as uint<8>,
    DW_OP_lit6                 = 0x36 as uint<8>,
    DW_OP_lit7                 = 0x37 as uint<8>,
    DW_OP_lit8                 = 0x38 as uint<8>,
    DW_OP_lit9                 = 0x39 as uint<8>,
    DW_OP_lit10                = 0x3a as uint<8>,
    DW_OP_lit11                = 0x3b as uint<8>,
    DW_OP_lit12                = 0x3c as uint<8>,
    DW_OP_lit13                = 0x3d as uint<8>,
    DW_OP_lit14                = 0x3e as uint<8>,
    DW_OP_lit15                = 0x3f as uint<8>,
    DW_OP_lit16                = 0x40 as uint<8>,
    DW_OP_lit17                = 0x41 as uint<8>,
    DW_OP_lit18                = 0x42 as uint<8>,
    DW_OP_lit19                = 0x43 as uint<8>,
    DW_OP_lit20                = 0x44 as uint<8>,
    DW_OP_lit21                = 0x45 as uint<8>,
    DW_OP_lit22                = 0x46 as uint<8>,
    DW_OP_lit23                = 0x47 as uint<8>,
    DW_OP_lit24                = 0x48 as uint<8>,
    DW_OP_lit25                = 0x49 as uint<8>,
    DW_OP_lit26                = 0x4a as uint<8>,
    DW_OP_lit27                = 0x4b as uint<8>,
    DW_OP_lit28                = 0x4c as uint<8>,
    DW_OP_lit29                = 0x4d as uint<8>,
    DW_OP_lit30                = 0x4e as uint<8>,
    DW_OP_lit31                = 0x4f as uint<8>,
    DW_OP_reg0                 = 0x50 as uint<8>,
    DW_OP_reg1                 = 0x51 as uint<8>,
    DW_OP_reg2                 = 0x52 as uint<8>,
    DW_OP_reg3                 = 0x53 as uint<8>,
    DW_OP_reg4                 = 0x54 as uint<8>,
    DW_OP_reg5                 = 0x55 as uint<8>,
    DW_OP_reg6                 = 0x56 as uint<8>,
    DW_OP_reg7                 = 0x57 as uint<8>,
    DW_OP_reg8                 = 0x58 as uint<8>,
    DW_OP_reg9                 = 0x59 as uint<8>,
    DW_OP_reg10                = 0x5a as uint<8>,
    DW_OP_reg11                = 0x5b as uint<8>,
    DW_OP_reg12                = 0x5c as uint<8>,
    DW_OP_reg13                = 0x5d as uint<8>,
    DW_OP_reg14                = 0x5e as uint<8>,
    DW_OP_reg15                = 0x5f as uint<8>,
    DW_OP_reg16                = 0x60 as uint<8>,
    DW_OP_reg17                = 0x61 as uint<8>,
    DW_OP_reg18                = 0x62 as uint<8>,
    DW_OP_reg19                = 0x63 as uint<8>,
    DW_OP_reg20                = 0x64 as uint<8>,
    DW_OP_reg21                = 0x65 as uint<8>,
    DW_OP_reg22                = 0x66 as uint<8>,
    DW_OP_reg23                = 0x67 as uint<8>,
    DW_OP_reg24                = 0x68 as uint<8>,
    DW_OP_reg25                = 0x69 as uint<8>,
    DW_OP_reg26                = 0x6a as uint<8>,
    DW_OP_reg27                = 0x6b as uint<8>,
    DW_OP_reg28                = 0x6c as uint<8>,
    DW_OP_reg29                = 0x6d as uint<8>,
    DW_OP_reg30                = 0x6e as uint<8>,
    DW_OP_reg31                = 0x6f as uint<8>,
    DW_OP_breg0                = 0x70 as uint<8>,
    DW_OP_breg1                = 0x71 as uint<8>,
    DW_OP_breg2                = 0x72 as uint<8>,
    DW_OP_breg3                = 0x73 as uint<8>,
    DW_OP_breg4                = 0x74 as uint<8>,
    DW_OP_breg5                = 0x75 as uint<8>,
    DW_OP_breg6                = 0x76 as uint<8>,
    DW_OP_breg7                = 0x77 as uint<8>,
    DW_OP_breg8                = 0x78 as uint<8>,
    DW_OP_breg9                = 0x79 as uint<8>,
    DW_OP_breg10               = 0x7a as uint<8>,
    DW_OP_breg11               = 0x7b as uint<8>,
    DW_OP_breg12               = 0x7c as uint<8>,
    DW_OP_breg13               = 0x7d as uint<8>,
    DW_OP_breg14               = 0x7e as uint<8>,
    DW_OP_breg15               = 0x7f as uint<8>,
    DW_OP_breg16               = 0x80 as uint<8>,
    DW_OP_breg17               = 0x81 as uint<8>,
    DW_OP_breg18               = 0x82 as uint<8>,
    DW_OP_breg19               = 0x83 as uint<8>,
    DW_OP_breg20               = 0x84 as uint<8>,
    DW_OP_breg21               = 0x85 as uint<8>,
    DW_OP_breg22               = 0x86 as uint<8>,
    DW_OP_breg23               = 0x87 as uint<8>,
    DW_OP_breg24               = 0x88 as uint<8>,
    DW_OP_breg25               = 0x89 as uint<8>,
    DW_OP_breg26               = 0x8a as uint<8>,
    DW_OP_breg27               = 0x8b as uint<8>,
    DW_OP_breg28               = 0x8c as uint<8>,
    DW_OP_breg29               = 0x8d as uint<8>,
    DW_OP_breg30               = 0x8e as uint<8>,
    DW_OP_breg31               = 0x8f as uint<8>,
    DW_OP_regx                 = 0x90 as uint<8>,
    DW_OP_fbreg                = 0x91 as uint<8>,
    DW_OP_bregx                = 0x92 as uint<8>,
    DW_OP_piece                = 0x93 as uint<8>,
    DW_OP_deref_size           = 0x94 as uint<8>,
    DW_OP_xderef_size          = 0x95 as uint<8>,
    DW_OP_nop                  = 0x96 as uint<8>,
    DW_OP_push_object_address  = 0x97 as uint<8>,
    DW_OP_call2                = 0x98 as uint<8>,
    DW_OP_call4                = 0x99 as uint<8>,
    DW_OP_call_ref             = 0x9a as uint<8>,
    DW_OP_form_tls_address     = 0x9b as uint<8>,
    DW_OP_call_frame_cfa       = 0x9c as uint<8>,
    DW_OP_bit_piece            = 0x9d as uint<8>,
    DW_OP_implicit_value       = 0x9e as uint<8>,
    DW_OP_stack_value          = 0x9f as uint<8>,
    DW_OP_implicit_pointer     = 0xa0 as uint<8>,
    DW_OP_addrx                = 0xa1 as uint<8>,
    DW_OP_constx               = 0xa2 as uint<8>,
    DW_OP_entry_value          = 0xa3 as uint<8>,
    DW_OP_const_type           = 0xa4 as uint<8>,
    DW_OP_regval_type          = 0xa5 as uint<8>,
    DW_OP_deref_type           = 0xa6 as uint<8>,
    DW_OP_xderef_type          = 0xa7 as uint<8>,
    DW_OP_convert              = 0xa8 as uint<8>,
    DW_OP_reinterpret          = 0xa9 as uint<8>,
    /* GNU extensions.  */
    DW_OP_GNU_push_tls_address = 0xe0 as uint<8>,
    DW_OP_GNU_uninit           = 0xf0 as uint<8>,
    DW_OP_GNU_encoded_addr     = 0xf1 as uint<8>,
    DW_OP_GNU_implicit_pointer = 0xf2 as uint<8>,
    DW_OP_GNU_entry_value      = 0xf3 as uint<8>,
    DW_OP_GNU_const_type       = 0xf4 as uint<8>,
    DW_OP_GNU_regval_type      = 0xf5 as uint<8>,
    DW_OP_GNU_deref_type       = 0xf6 as uint<8>,
    DW_OP_GNU_convert          = 0xf7 as uint<8>,
    DW_OP_GNU_reinterpret      = 0xf9 as uint<8>,
    DW_OP_GNU_parameter_ref    = 0xfa as uint<8>,
    /* GNU Debug Fission extensions.  */
    DW_OP_GNU_addr_index       = 0xfb as uint<8>,
    DW_OP_GNU_const_index      = 0xfc as uint<8>,
    DW_OP_GNU_variable_value   = 0xfd as uint<8>,
    DW_OP_lo_user              = 0xe0 as uint<8>,
    DW_OP_hi_user              = 0xff as uint<8>,
    DW_OP_LAST                 = DW_OP_hi_user;

/* Each DWARF operation contains a 1-byte opcode that identifies the
   operation; followed by a variable number of arguments.  */

type Dwarf_Op =
  struct
  {
    uint<8> code : code >= DW_OP_FIRST && code <= DW_OP_LAST;
    union
    {
      uint<8>  u8 : code in [DW_OP_const1u, DW_OP_pick,
                             DW_OP_deref_size, DW_OP_xderef_size];
      int<8>   i8 : code == DW_OP_const1s;

      uint<16> u16 : code in [DW_OP_const2u, DW_OP_call2];
      int<16>  i16 : code in [DW_OP_const2s, DW_OP_skip, DW_OP_bra];

      uint<32> u32 : code in [DW_OP_const4u, DW_OP_call4];
      int<32>  i32 : code == DW_OP_const4s;

      uint<64> u64 : code == DW_OP_const8u;
      int<64>  i64 : code == DW_OP_const8s;

      ULEB128 u128 : (code in [DW_OP_constu, DW_OP_plus_uconst,
                               DW_OP_fbreg, DW_OP_regx, DW_OP_piece]
                      || (code >= DW_OP_breg0 && code <= DW_OP_breg31));

      struct
      {
        ULEB128 reg;
        LEB128 offset;
      } reg_offset : code in [DW_OP_bregx, DW_OP_bit_piece];

      struct
      {
        ULEB128 length;
        byte[length.value] block;
      } size : code == DW_OP_implicit_value;

      Dwarf_Address addr : code == DW_OP_addr;
      Dwarf_Section_Offset offset : code == DW_OP_call_ref;

      /* Other operations have no arguments.  */
      struct {} nothing;
    } arg;
  };
