From 75e208318c70e92d32921bfea13c196869c3badc Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Sat, 4 May 2024 12:59:14 +0800 Subject: [PATCH 1/2] hppa: remove GNU plugin --- librz/arch/isa_gnu/hppa/hppa-dis.c | 1269 --------------------------- librz/arch/isa_gnu/hppa/libhppa.h | 552 ------------ librz/arch/meson.build | 3 - librz/arch/p_gnu/arch_hppa.c | 9 - librz/arch/p_gnu/asm/asm_hppa_gnu.c | 88 -- 5 files changed, 1921 deletions(-) delete mode 100644 librz/arch/isa_gnu/hppa/hppa-dis.c delete mode 100644 librz/arch/isa_gnu/hppa/libhppa.h delete mode 100644 librz/arch/p_gnu/arch_hppa.c delete mode 100644 librz/arch/p_gnu/asm/asm_hppa_gnu.c diff --git a/librz/arch/isa_gnu/hppa/hppa-dis.c b/librz/arch/isa_gnu/hppa/hppa-dis.c deleted file mode 100644 index aa53f0af5be..00000000000 --- a/librz/arch/isa_gnu/hppa/hppa-dis.c +++ /dev/null @@ -1,1269 +0,0 @@ -/* Disassembler for the PA-RISC. Somewhat derived from sparc-pinsn.c. - Copyright (C) 1989-2014 Free Software Foundation, Inc. - - Contributed by the Center for Software Science at the - University of Utah (pa-gdb-bugs@cs.utah.edu). - - This file is part of the GNU opcodes library. - - This library 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, or (at your option) - any later version. - - It 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, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#include -#include -#include "libhppa.h" -#include -#include -#include - -/* Integer register names, indexed by the numbers which appear in the - opcodes. */ -static const char *const reg_names[] = -{ - "flags", "r1", "rp", "r3", "r4", "r5", "r6", "r7", "r8", "r9", - "r10", "r11", "r12", "r13", "r14", "r15", "r16", "r17", "r18", "r19", - "r20", "r21", "r22", "r23", "r24", "r25", "r26", "dp", "ret0", "ret1", - "sp", "r31" -}; - -/* Floating point register names, indexed by the numbers which appear in the - opcodes. */ -static const char *const fp_reg_names[] = -{ - "fpsr", "fpe2", "fpe4", "fpe6", - "fr4", "fr5", "fr6", "fr7", "fr8", - "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15", - "fr16", "fr17", "fr18", "fr19", "fr20", "fr21", "fr22", "fr23", - "fr24", "fr25", "fr26", "fr27", "fr28", "fr29", "fr30", "fr31" -}; - -typedef unsigned int CORE_ADDR; - -/* Get at various relevant fields of an instruction word. */ - -#define MASK_5 0x1f -#define MASK_10 0x3ff -#define MASK_11 0x7ff -#define MASK_14 0x3fff -#define MASK_16 0xffff -#define MASK_21 0x1fffff - -/* These macros get bit fields using HP's numbering (MSB = 0). */ - -#define GET_FIELD(X, FROM, TO) \ - ((X) >> (31 - (TO)) & ((1 << ((TO) - (FROM) + 1)) - 1)) - -#define GET_BIT(X, WHICH) \ - GET_FIELD (X, WHICH, WHICH) - -/* Some of these have been converted to 2-d arrays because they - consume less storage this way. If the maintenance becomes a - problem, convert them back to const 1-d pointer arrays. */ -static const char *const control_reg[] = -{ - "rctr", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", - "pidr1", "pidr2", "ccr", "sar", "pidr3", "pidr4", - "iva", "eiem", "itmr", "pcsq", "pcoq", "iir", "isr", - "ior", "ipsw", "eirr", "tr0", "tr1", "tr2", "tr3", - "tr4", "tr5", "tr6", "tr7" -}; - -static const char *const compare_cond_names[] = -{ - "", ",=", ",<", ",<=", ",<<", ",<<=", ",sv", ",od", - ",tr", ",<>", ",>=", ",>", ",>>=", ",>>", ",nsv", ",ev" -}; -static const char *const compare_cond_64_names[] = -{ - ",*", ",*=", ",*<", ",*<=", ",*<<", ",*<<=", ",*sv", ",*od", - ",*tr", ",*<>", ",*>=", ",*>", ",*>>=", ",*>>", ",*nsv", ",*ev" -}; -static const char *const cmpib_cond_64_names[] = -{ - ",*<<", ",*=", ",*<", ",*<=", ",*>>=", ",*<>", ",*>=", ",*>" -}; -static const char *const add_cond_names[] = -{ - "", ",=", ",<", ",<=", ",nuv", ",znv", ",sv", ",od", - ",tr", ",<>", ",>=", ",>", ",uv", ",vnz", ",nsv", ",ev" -}; -static const char *const add_cond_64_names[] = -{ - ",*", ",*=", ",*<", ",*<=", ",*nuv", ",*znv", ",*sv", ",*od", - ",*tr", ",*<>", ",*>=", ",*>", ",*uv", ",*vnz", ",*nsv", ",*ev" -}; -static const char *const wide_add_cond_names[] = -{ - "", ",=", ",<", ",<=", ",nuv", ",*=", ",*<", ",*<=", - ",tr", ",<>", ",>=", ",>", ",uv", ",*<>", ",*>=", ",*>" -}; -static const char *const logical_cond_names[] = -{ - "", ",=", ",<", ",<=", 0, 0, 0, ",od", - ",tr", ",<>", ",>=", ",>", 0, 0, 0, ",ev"}; -static const char *const logical_cond_64_names[] = -{ - ",*", ",*=", ",*<", ",*<=", 0, 0, 0, ",*od", - ",*tr", ",*<>", ",*>=", ",*>", 0, 0, 0, ",*ev"}; -static const char *const unit_cond_names[] = -{ - "", ",swz", ",sbz", ",shz", ",sdc", ",swc", ",sbc", ",shc", - ",tr", ",nwz", ",nbz", ",nhz", ",ndc", ",nwc", ",nbc", ",nhc" -}; -static const char *const unit_cond_64_names[] = -{ - ",*", ",*swz", ",*sbz", ",*shz", ",*sdc", ",*swc", ",*sbc", ",*shc", - ",*tr", ",*nwz", ",*nbz", ",*nhz", ",*ndc", ",*nwc", ",*nbc", ",*nhc" -}; -static const char *const shift_cond_names[] = -{ - "", ",=", ",<", ",od", ",tr", ",<>", ",>=", ",ev" -}; -static const char *const shift_cond_64_names[] = -{ - ",*", ",*=", ",*<", ",*od", ",*tr", ",*<>", ",*>=", ",*ev" -}; -static const char *const bb_cond_64_names[] = -{ - ",*<", ",*>=" -}; -static const char *const index_compl_names[] = {"", ",m", ",s", ",sm"}; -static const char *const short_ldst_compl_names[] = {"", ",ma", "", ",mb"}; -static const char *const short_bytes_compl_names[] = -{ - "", ",b,m", ",e", ",e,m" -}; -static const char *const float_format_names[] = {",sgl", ",dbl", "", ",quad"}; -static const char *const fcnv_fixed_names[] = {",w", ",dw", "", ",qw"}; -static const char *const fcnv_ufixed_names[] = {",uw", ",udw", "", ",uqw"}; -static const char *const float_comp_names[] = -{ - ",false?", ",false", ",?", ",!<=>", ",=", ",=t", ",?=", ",!<>", - ",!?>=", ",<", ",?<", ",!>=", ",!?>", ",<=", ",?<=", ",!>", - ",!?<=", ",>", ",?>", ",!<=", ",!?<", ",>=", ",?>=", ",!<", - ",!?=", ",<>", ",!=", ",!=t", ",!?", ",<=>", ",true?", ",true" -}; -static const char *const signed_unsigned_names[] = {",u", ",s"}; -static const char *const mix_half_names[] = {",l", ",r"}; -static const char *const saturation_names[] = {",us", ",ss", 0, ""}; -static const char *const read_write_names[] = {",r", ",w"}; -static const char *const add_compl_names[] = { 0, "", ",l", ",tsv" }; - -/* For a bunch of different instructions form an index into a - completer name table. */ -#define GET_COMPL(insn) (GET_FIELD (insn, 26, 26) | \ - GET_FIELD (insn, 18, 18) << 1) - -#define GET_COND(insn) (GET_FIELD ((insn), 16, 18) + \ - (GET_FIELD ((insn), 19, 19) ? 8 : 0)) - -/* Utility function to print registers. Put these first, so gcc's function - inlining can do its stuff. */ - -#define fputs_filtered(STR,F) (*info->fprintf_func) (info->stream, "%s", STR) - -static void -fput_reg (unsigned reg, disassemble_info *info) -{ - (*info->fprintf_func) (info->stream, "%s", reg ? reg_names[reg] : "r0"); -} - -static void -fput_fp_reg (unsigned reg, disassemble_info *info) -{ - (*info->fprintf_func) (info->stream, "%s", reg ? fp_reg_names[reg] : "fr0"); -} - -static void -fput_fp_reg_r (unsigned reg, disassemble_info *info) -{ - /* Special case floating point exception registers. */ - if (reg < 4) { - (*info->fprintf_func) (info->stream, "fpe%d", reg * 2 + 1); - } else { - (*info->fprintf_func) (info->stream, "%sR", fp_reg_names[reg]); - } -} - -static void -fput_creg (unsigned reg, disassemble_info *info) -{ - (*info->fprintf_func) (info->stream, "%s", control_reg[reg]); -} - -/* Print constants with sign. */ - -static void -fput_const (unsigned num, disassemble_info *info) -{ - if ((int)num < 0) { - (*info->fprintf_func) (info->stream, "-%x", -(int)num); - } else { - (*info->fprintf_func) (info->stream, "%x", num); - } -} - -/* Routines to extract various sized constants out of hppa - instructions. */ - -/* Extract a 3-bit space register number from a be, ble, mtsp or mfsp. */ -static int -extract_3 (unsigned word) -{ - return GET_FIELD (word, 18, 18) << 2 | GET_FIELD (word, 16, 17); -} - -static int -extract_5_load (unsigned word) -{ - return low_sign_extend (word >> 16 & MASK_5, 5); -} - -/* Extract the immediate field from a st{bhw}s instruction. */ - -static int -extract_5_store (unsigned word) -{ - return low_sign_extend (word & MASK_5, 5); -} - -/* Extract the immediate field from a break instruction. */ - -static unsigned -extract_5r_store (unsigned word) -{ - return (word & MASK_5); -} - -/* Extract the immediate field from a {sr}sm instruction. */ - -static unsigned -extract_5R_store (unsigned word) -{ - return (word >> 16 & MASK_5); -} - -/* Extract the 10 bit immediate field from a {sr}sm instruction. */ - -static unsigned -extract_10U_store (unsigned word) -{ - return (word >> 16 & MASK_10); -} - -/* Extract the immediate field from a bb instruction. */ - -static unsigned -extract_5Q_store (unsigned word) -{ - return (word >> 21 & MASK_5); -} - -/* Extract an 11 bit immediate field. */ - -static int -extract_11 (unsigned word) -{ - return low_sign_extend (word & MASK_11, 11); -} - -/* Extract a 14 bit immediate field. */ - -static int -extract_14 (unsigned word) -{ - return low_sign_extend (word & MASK_14, 14); -} - -/* Extract a 16 bit immediate field (PA2.0 wide only). */ - -static int -extract_16 (unsigned word) -{ - int m15, m0, m1; - - m0 = GET_BIT (word, 16); - m1 = GET_BIT (word, 17); - m15 = GET_BIT (word, 31); - word = (word >> 1) & 0x1fff; - word = word | (m15 << 15) | ((m15 ^ m0) << 14) | ((m15 ^ m1) << 13); - return sign_extend (word, 16); -} - -/* Extract a 21 bit constant. */ - -static int -extract_21 (unsigned word) -{ - int val; - - word &= MASK_21; - word <<= 11; - val = GET_FIELD (word, 20, 20); - val <<= 11; - val |= GET_FIELD (word, 9, 19); - val <<= 2; - val |= GET_FIELD (word, 5, 6); - val <<= 5; - val |= GET_FIELD (word, 0, 4); - val <<= 2; - val |= GET_FIELD (word, 7, 8); - return sign_extend (val, 21) << 11; -} - -/* Extract a 12 bit constant from branch instructions. */ - -static int -extract_12 (unsigned word) -{ - return sign_extend (GET_FIELD (word, 19, 28) - | GET_FIELD (word, 29, 29) << 10 - | (word & 0x1) << 11, 12) << 2; -} - -/* Extract a 17 bit constant from branch instructions, returning the - 19 bit signed value. */ - -static int -extract_17 (unsigned word) -{ - return sign_extend (GET_FIELD (word, 19, 28) - | GET_FIELD (word, 29, 29) << 10 - | GET_FIELD (word, 11, 15) << 11 - | (word & 0x1) << 16, 17) << 2; -} - -static int -extract_22 (unsigned word) -{ - return sign_extend (GET_FIELD (word, 19, 28) - | GET_FIELD (word, 29, 29) << 10 - | GET_FIELD (word, 11, 15) << 11 - | GET_FIELD (word, 6, 10) << 16 - | (word & 0x1) << 21, 22) << 2; -} - -/* Print one instruction. */ - -int -print_insn_hppa (bfd_vma memaddr, disassemble_info *info) -{ - bfd_byte buffer[4]; - unsigned int insn, i; - - { - int status = - (*info->read_memory_func) (memaddr, buffer, sizeof (buffer), info); - if (status != 0) - { - (*info->memory_error_func) (status, memaddr, info); - return -1; - } - } - - insn = bfd_getb32 (buffer); - - for (i = 0; i < NUMOPCODES; ++i) - { - const struct pa_opcode *opcode = &pa_opcodes[i]; - - if ((insn & opcode->mask) == opcode->match) - { - const char *s; -#ifndef BFD64 - if (opcode->arch == pa20w) - continue; -#endif - (*info->fprintf_func) (info->stream, "%s", opcode->name); - - if (!strchr ("cfCY?-+nHNZFIuv{", opcode->args[0])) { - (*info->fprintf_func) (info->stream, " "); - } - for (s = opcode->args; *s != '\0'; ++s) - { - switch (*s) - { - case 'x': - fput_reg (GET_FIELD (insn, 11, 15), info); - break; - case 'a': - case 'b': - fput_reg (GET_FIELD (insn, 6, 10), info); - break; - case '^': - fput_creg (GET_FIELD (insn, 6, 10), info); - break; - case 't': - fput_reg (GET_FIELD (insn, 27, 31), info); - break; - - /* Handle floating point registers. */ - case 'f': - switch (*++s) - { - case 't': - fput_fp_reg (GET_FIELD (insn, 27, 31), info); - break; - case 'T': - if (GET_FIELD (insn, 25, 25)) { - fput_fp_reg_r (GET_FIELD (insn, 27, 31), info); - } else { - fput_fp_reg (GET_FIELD (insn, 27, 31), info); - } - break; - case 'a': - if (GET_FIELD (insn, 25, 25)) { - fput_fp_reg_r (GET_FIELD (insn, 6, 10), info); - } else { - fput_fp_reg (GET_FIELD (insn, 6, 10), info); - } - break; - - /* 'fA' will not generate a space before the register - name. Normally that is fine. Except that it - causes problems with xmpyu which has no FP format - completer. */ - case 'X': - fputs_filtered (" ", info); - /* FALLTHRU */ - - case 'A': - if (GET_FIELD (insn, 24, 24)) { - fput_fp_reg_r (GET_FIELD (insn, 6, 10), info); - } else { - fput_fp_reg (GET_FIELD (insn, 6, 10), info); - } - break; - case 'b': - if (GET_FIELD (insn, 25, 25)) { - fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); - } else { - fput_fp_reg (GET_FIELD (insn, 11, 15), info); - } - break; - case 'B': - if (GET_FIELD (insn, 19, 19)) { - fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); - } else { - fput_fp_reg (GET_FIELD (insn, 11, 15), info); - } - break; - case 'C': - { - int reg = GET_FIELD (insn, 21, 22); - reg |= GET_FIELD (insn, 16, 18) << 2; - if (GET_FIELD (insn, 23, 23) != 0) { - fput_fp_reg_r (reg, info); - } else { - fput_fp_reg (reg, info); - } - break; - } - case 'i': - { - int reg = GET_FIELD (insn, 6, 10); - - reg |= (GET_FIELD (insn, 26, 26) << 4); - fput_fp_reg (reg, info); - break; - } - case 'j': - { - int reg = GET_FIELD (insn, 11, 15); - - reg |= (GET_FIELD (insn, 26, 26) << 4); - fput_fp_reg (reg, info); - break; - } - case 'k': - { - int reg = GET_FIELD (insn, 27, 31); - - reg |= (GET_FIELD (insn, 26, 26) << 4); - fput_fp_reg (reg, info); - break; - } - case 'l': - { - int reg = GET_FIELD (insn, 21, 25); - - reg |= (GET_FIELD (insn, 26, 26) << 4); - fput_fp_reg (reg, info); - break; - } - case 'm': - { - int reg = GET_FIELD (insn, 16, 20); - - reg |= (GET_FIELD (insn, 26, 26) << 4); - fput_fp_reg (reg, info); - break; - } - - /* 'fe' will not generate a space before the register - name. Normally that is fine. Except that it - causes problems with fstw fe,y(b) which has no FP - format completer. */ - case 'E': - fputs_filtered (" ", info); - /* FALLTHRU */ - - case 'e': - if (GET_FIELD (insn, 30, 30)) { - fput_fp_reg_r (GET_FIELD (insn, 11, 15), info); - } else { - fput_fp_reg (GET_FIELD (insn, 11, 15), info); - } - break; - case 'x': - fput_fp_reg (GET_FIELD (insn, 11, 15), info); - break; - } - break; - - case '5': - fput_const (extract_5_load (insn), info); - break; - case 's': - { - int space = GET_FIELD (insn, 16, 17); - /* Zero means implicit addressing, not use of sr0. */ - if (space != 0) { - (*info->fprintf_func) (info->stream, "sr%d", space); - } - } - break; - - case 'S': - (*info->fprintf_func) (info->stream, "sr%d", - extract_3 (insn)); - break; - - /* Handle completers. */ - case 'c': - switch (*++s) - { - case 'x': - (*info->fprintf_func) - (info->stream, "%s", - index_compl_names[GET_COMPL (insn)]); - break; - case 'X': - (*info->fprintf_func) - (info->stream, "%s ", - index_compl_names[GET_COMPL (insn)]); - break; - case 'm': - (*info->fprintf_func) - (info->stream, "%s", - short_ldst_compl_names[GET_COMPL (insn)]); - break; - case 'M': - (*info->fprintf_func) - (info->stream, "%s ", - short_ldst_compl_names[GET_COMPL (insn)]); - break; - case 'A': - (*info->fprintf_func) - (info->stream, "%s ", - short_bytes_compl_names[GET_COMPL (insn)]); - break; - case 's': - (*info->fprintf_func) - (info->stream, "%s", - short_bytes_compl_names[GET_COMPL (insn)]); - break; - case 'c': - case 'C': - switch (GET_FIELD (insn, 20, 21)) - { - case 1: - (*info->fprintf_func) (info->stream, ",bc "); - break; - case 2: - (*info->fprintf_func) (info->stream, ",sl "); - break; - default: - (*info->fprintf_func) (info->stream, " "); - } - break; - case 'd': - switch (GET_FIELD (insn, 20, 21)) - { - case 1: - (*info->fprintf_func) (info->stream, ",co "); - break; - default: - (*info->fprintf_func) (info->stream, " "); - } - break; - case 'o': - (*info->fprintf_func) (info->stream, ",o"); - break; - case 'g': - (*info->fprintf_func) (info->stream, ",gate"); - break; - case 'p': - (*info->fprintf_func) (info->stream, ",l,push"); - break; - case 'P': - (*info->fprintf_func) (info->stream, ",pop"); - break; - case 'l': - case 'L': - (*info->fprintf_func) (info->stream, ",l"); - break; - case 'w': - (*info->fprintf_func) - (info->stream, "%s ", - read_write_names[GET_FIELD (insn, 25, 25)]); - break; - case 'W': - (*info->fprintf_func) (info->stream, ",w "); - break; - case 'r': - if (GET_FIELD (insn, 23, 26) == 5) { - (*info->fprintf_func) (info->stream, ",r"); - } - break; - case 'Z': - if (GET_FIELD (insn, 26, 26)) { - (*info->fprintf_func) (info->stream, ",m "); - } else { - (*info->fprintf_func) (info->stream, " "); - } - break; - case 'i': - if (GET_FIELD (insn, 25, 25)) { - (*info->fprintf_func) (info->stream, ",i"); - } - break; - case 'z': - if (!GET_FIELD (insn, 21, 21)) { - (*info->fprintf_func) (info->stream, ",z"); - } - break; - case 'a': - (*info->fprintf_func) - (info->stream, "%s", - add_compl_names[GET_FIELD (insn, 20, 21)]); - break; - case 'Y': - (*info->fprintf_func) - (info->stream, ",dc%s", - add_compl_names[GET_FIELD (insn, 20, 21)]); - break; - case 'y': - (*info->fprintf_func) - (info->stream, ",c%s", - add_compl_names[GET_FIELD (insn, 20, 21)]); - break; - case 'v': - if (GET_FIELD (insn, 20, 20)) { - (*info->fprintf_func) (info->stream, ",tsv"); - } - break; - case 't': - (*info->fprintf_func) (info->stream, ",tc"); - if (GET_FIELD (insn, 20, 20)) { - (*info->fprintf_func) (info->stream, ",tsv"); - } - break; - case 'B': - (*info->fprintf_func) (info->stream, ",db"); - if (GET_FIELD (insn, 20, 20)) { - (*info->fprintf_func) (info->stream, ",tsv"); - } - break; - case 'b': - (*info->fprintf_func) (info->stream, ",b"); - if (GET_FIELD (insn, 20, 20)) { - (*info->fprintf_func) (info->stream, ",tsv"); - } - break; - case 'T': - if (GET_FIELD (insn, 25, 25)) { - (*info->fprintf_func) (info->stream, ",tc"); - } - break; - case 'S': - /* EXTRD/W has a following condition. */ - if (*(s + 1) == '?') { - (*info->fprintf_func) (info->stream, "%s", - signed_unsigned_names[GET_FIELD (insn, 21, 21)]); - } else { - (*info->fprintf_func) (info->stream, "%s ", - signed_unsigned_names[GET_FIELD (insn, 21, 21)]); - } - break; - case 'h': - (*info->fprintf_func) - (info->stream, "%s", - mix_half_names[GET_FIELD (insn, 17, 17)]); - break; - case 'H': - (*info->fprintf_func) - (info->stream, "%s ", - saturation_names[GET_FIELD (insn, 24, 25)]); - break; - case '*': - (*info->fprintf_func) - (info->stream, ",%d%d%d%d ", - GET_FIELD (insn, 17, 18), GET_FIELD (insn, 20, 21), - GET_FIELD (insn, 22, 23), GET_FIELD (insn, 24, 25)); - break; - - case 'q': - { - int m, a; - - m = GET_FIELD (insn, 28, 28); - a = GET_FIELD (insn, 29, 29); - - if (m && !a) { - fputs_filtered (",ma ", info); - } else if (m && a) { - fputs_filtered (",mb ", info); - } else { - fputs_filtered (" ", info); - } - break; - } - - case 'J': - { - int opc = GET_FIELD (insn, 0, 5); - - if (opc == 0x16 || opc == 0x1e) - { - if (GET_FIELD (insn, 29, 29) == 0) { - fputs_filtered (",ma ", info); - } else { - fputs_filtered (",mb ", info); - } - } else { - fputs_filtered (" ", info); - } - break; - } - - case 'e': - { - int opc = GET_FIELD (insn, 0, 5); - - if (opc == 0x13 || opc == 0x1b) - { - if (GET_FIELD (insn, 18, 18) == 1) { - fputs_filtered (",mb ", info); - } else { - fputs_filtered (",ma ", info); - } - } - else if (opc == 0x17 || opc == 0x1f) - { - if (GET_FIELD (insn, 31, 31) == 1) { - fputs_filtered (",ma ", info); - } else { - fputs_filtered (",mb ", info); - } - } else { - fputs_filtered (" ", info); - } - - break; - } - } - break; - - /* Handle conditions. */ - case '?': - { - s++; - switch (*s) - { - case 'f': - (*info->fprintf_func) - (info->stream, "%s ", - float_comp_names[GET_FIELD (insn, 27, 31)]); - break; - - /* These four conditions are for the set of instructions - which distinguish true/false conditions by opcode - rather than by the 'f' bit (sigh): comb, comib, - addb, addib. */ - case 't': - fputs_filtered - (compare_cond_names[GET_FIELD (insn, 16, 18)], info); - break; - case 'n': - fputs_filtered - (compare_cond_names[GET_FIELD (insn, 16, 18) - + GET_FIELD (insn, 4, 4) * 8], - info); - break; - case 'N': - fputs_filtered - (compare_cond_64_names[GET_FIELD (insn, 16, 18) - + GET_FIELD (insn, 2, 2) * 8], - info); - break; - case 'Q': - fputs_filtered - (cmpib_cond_64_names[GET_FIELD (insn, 16, 18)], - info); - break; - case '@': - fputs_filtered - (add_cond_names[GET_FIELD (insn, 16, 18) - + GET_FIELD (insn, 4, 4) * 8], - info); - break; - case 's': - (*info->fprintf_func) - (info->stream, "%s ", - compare_cond_names[GET_COND (insn)]); - break; - case 'S': - (*info->fprintf_func) - (info->stream, "%s ", - compare_cond_64_names[GET_COND (insn)]); - break; - case 'a': - (*info->fprintf_func) - (info->stream, "%s ", - add_cond_names[GET_COND (insn)]); - break; - case 'A': - (*info->fprintf_func) - (info->stream, "%s ", - add_cond_64_names[GET_COND (insn)]); - break; - case 'd': - (*info->fprintf_func) - (info->stream, "%s", - add_cond_names[GET_FIELD (insn, 16, 18)]); - break; - - case 'W': - (*info->fprintf_func) - (info->stream, "%s", - wide_add_cond_names[GET_FIELD (insn, 16, 18) + - GET_FIELD (insn, 4, 4) * 8]); - break; - - case 'l': - (*info->fprintf_func) - (info->stream, "%s ", - logical_cond_names[GET_COND (insn)]); - break; - case 'L': - (*info->fprintf_func) - (info->stream, "%s ", - logical_cond_64_names[GET_COND (insn)]); - break; - case 'u': - (*info->fprintf_func) - (info->stream, "%s ", - unit_cond_names[GET_COND (insn)]); - break; - case 'U': - (*info->fprintf_func) - (info->stream, "%s ", - unit_cond_64_names[GET_COND (insn)]); - break; - case 'y': - case 'x': - case 'b': - (*info->fprintf_func) - (info->stream, "%s", - shift_cond_names[GET_FIELD (insn, 16, 18)]); - - /* If the next character in args is 'n', it will handle - putting out the space. */ - if (s[1] != 'n') { - (*info->fprintf_func) (info->stream, " "); - } - break; - case 'X': - (*info->fprintf_func) - (info->stream, "%s ", - shift_cond_64_names[GET_FIELD (insn, 16, 18)]); - break; - case 'B': - (*info->fprintf_func) - (info->stream, "%s", - bb_cond_64_names[GET_FIELD (insn, 16, 16)]); - - /* If the next character in args is 'n', it will handle - putting out the space. */ - if (s[1] != 'n') { - (*info->fprintf_func) (info->stream, " "); - } - break; - } - break; - } - - case 'V': - fput_const (extract_5_store (insn), info); - break; - case 'r': - fput_const (extract_5r_store (insn), info); - break; - case 'R': - fput_const (extract_5R_store (insn), info); - break; - case 'U': - fput_const (extract_10U_store (insn), info); - break; - case 'B': - case 'Q': - fput_const (extract_5Q_store (insn), info); - break; - case 'i': - fput_const (extract_11 (insn), info); - break; - case 'j': - fput_const (extract_14 (insn), info); - break; - case 'k': - fputs_filtered ("L%", info); - fput_const (extract_21 (insn), info); - break; - case '<': - case 'l': - /* 16-bit long disp., PA2.0 wide only. */ - fput_const (extract_16 (insn), info); - break; - case 'n': - if (insn & 0x2) { - (*info->fprintf_func) (info->stream, ",n "); - } else { - (*info->fprintf_func) (info->stream, " "); - } - break; - case 'N': - if ((insn & 0x20) && s[1]) { - (*info->fprintf_func) (info->stream, ",n "); - } else if (insn & 0x20) { - (*info->fprintf_func) (info->stream, ",n"); - } else if (s[1]) { - (*info->fprintf_func) (info->stream, " "); - } - break; - case 'w': - (*info->print_address_func) - (memaddr + 8 + extract_12 (insn), info); - break; - case 'W': - /* 17 bit PC-relative branch. */ - (*info->print_address_func) - ((memaddr + 8 + extract_17 (insn)), info); - break; - case 'z': - /* 17 bit displacement. This is an offset from a register - so it gets disasssembled as just a number, not any sort - of address. */ - fput_const (extract_17 (insn), info); - break; - - case 'Z': - /* addil %r1 implicit output. */ - fputs_filtered ("r1", info); - break; - - case 'Y': - /* be,l %sr0,%r31 implicit output. */ - fputs_filtered ("sr0,r31", info); - break; - - case '@': - (*info->fprintf_func) (info->stream, "0"); - break; - - case '.': - (*info->fprintf_func) (info->stream, "%d", - GET_FIELD (insn, 24, 25)); - break; - case '*': - (*info->fprintf_func) (info->stream, "%d", - GET_FIELD (insn, 22, 25)); - break; - case '!': - fputs_filtered ("sar", info); - break; - case 'p': - (*info->fprintf_func) (info->stream, "%d", - 31 - GET_FIELD (insn, 22, 26)); - break; - case '~': - { - int num; - num = GET_FIELD (insn, 20, 20) << 5; - num |= GET_FIELD (insn, 22, 26); - (*info->fprintf_func) (info->stream, "%d", 63 - num); - break; - } - case 'P': - (*info->fprintf_func) (info->stream, "%d", - GET_FIELD (insn, 22, 26)); - break; - case 'q': - { - int num; - num = GET_FIELD (insn, 20, 20) << 5; - num |= GET_FIELD (insn, 22, 26); - (*info->fprintf_func) (info->stream, "%d", num); - break; - } - case 'T': - (*info->fprintf_func) (info->stream, "%d", - 32 - GET_FIELD (insn, 27, 31)); - break; - case '%': - { - int num; - num = (GET_FIELD (insn, 23, 23) + 1) * 32; - num -= GET_FIELD (insn, 27, 31); - (*info->fprintf_func) (info->stream, "%d", num); - break; - } - case '|': - { - int num; - num = (GET_FIELD (insn, 19, 19) + 1) * 32; - num -= GET_FIELD (insn, 27, 31); - (*info->fprintf_func) (info->stream, "%d", num); - break; - } - case '$': - fput_const (GET_FIELD (insn, 20, 28), info); - break; - case 'A': - fput_const (GET_FIELD (insn, 6, 18), info); - break; - case 'D': - fput_const (GET_FIELD (insn, 6, 31), info); - break; - case 'v': - (*info->fprintf_func) (info->stream, ",%d", - GET_FIELD (insn, 23, 25)); - break; - case 'O': - fput_const ((GET_FIELD (insn, 6,20) << 5 | - GET_FIELD (insn, 27, 31)), info); - break; - case 'o': - fput_const (GET_FIELD (insn, 6, 20), info); - break; - case '2': - fput_const ((GET_FIELD (insn, 6, 22) << 5 | - GET_FIELD (insn, 27, 31)), info); - break; - case '1': - fput_const ((GET_FIELD (insn, 11, 20) << 5 | - GET_FIELD (insn, 27, 31)), info); - break; - case '0': - fput_const ((GET_FIELD (insn, 16, 20) << 5 | - GET_FIELD (insn, 27, 31)), info); - break; - case 'u': - (*info->fprintf_func) (info->stream, ",%d", - GET_FIELD (insn, 23, 25)); - break; - case 'F': - /* If no destination completer and not before a completer - for fcmp, need a space here. */ - if (s[1] == 'G' || s[1] == '?') { - fputs_filtered (float_format_names[GET_FIELD (insn, 19, 20)], info); - } else { - (*info->fprintf_func) (info->stream, "%s ", - float_format_names[GET_FIELD (insn, 19, 20)]); - } - break; - case 'G': - (*info->fprintf_func) - (info->stream, "%s ", - float_format_names[GET_FIELD (insn, 17, 18)]); - break; - case 'H': - if (GET_FIELD (insn, 26, 26) == 1) { - (*info->fprintf_func) (info->stream, "%s ", - float_format_names[0]); - } else { - (*info->fprintf_func) (info->stream, "%s ", - float_format_names[1]); - } - break; - case 'I': - /* If no destination completer and not before a completer - for fcmp, need a space here. */ - if (s[1] == '?') { - fputs_filtered (float_format_names[GET_FIELD (insn, 20, 20)], info); - } else { - (*info->fprintf_func) (info->stream, "%s ", - float_format_names[GET_FIELD (insn, 20, 20)]); - } - break; - - case 'J': - fput_const (extract_14 (insn), info); - break; - - case '#': - { - int sign = GET_FIELD (insn, 31, 31); - int imm10 = GET_FIELD (insn, 18, 27); - int disp; - - if (sign) { - disp = (UT64_MAX << 10) | imm10; - } else { - disp = imm10; - } - - disp <<= 3; - fput_const (disp, info); - break; - } - case 'K': - case 'd': - { - int sign = GET_FIELD (insn, 31, 31); - int imm11 = GET_FIELD (insn, 18, 28); - int disp; - - if (sign) { - disp = (UT64_MAX << 11) | imm11; - } else { - disp = imm11; - } - - disp <<= 2; - fput_const (disp, info); - break; - } - - case '>': - case 'y': - { - /* 16-bit long disp., PA2.0 wide only. */ - int disp = extract_16 (insn); - disp &= ~3; - fput_const (disp, info); - break; - } - - case '&': - { - /* 16-bit long disp., PA2.0 wide only. */ - int disp = extract_16 (insn); - disp &= ~7; - fput_const (disp, info); - break; - } - - case '_': - break; /* Dealt with by '{' */ - - case '{': - { - int sub = GET_FIELD (insn, 14, 16); - int df = GET_FIELD (insn, 17, 18); - int sf = GET_FIELD (insn, 19, 20); - const char * const * source = float_format_names; - const char * const * dest = float_format_names; - char *t = ""; - - if (sub == 4) - { - fputs_filtered (",UND ", info); - break; - } - if ((sub & 3) == 3) { - t = ",t"; - } - if ((sub & 3) == 1) { - source = sub & 4 ? fcnv_ufixed_names : fcnv_fixed_names; - } - if (sub & 2) { - dest = sub & 4 ? fcnv_ufixed_names : fcnv_fixed_names; - } - - (*info->fprintf_func) (info->stream, "%s%s%s ", - t, source[sf], dest[df]); - break; - } - - case 'm': - { - int y = GET_FIELD (insn, 16, 18); - - if (y != 1) { - fput_const ((y ^ 1) - 1, info); - } - } - break; - - case 'h': - { - int cbit; - - cbit = GET_FIELD (insn, 16, 18); - - if (cbit > 0) { - (*info->fprintf_func) (info->stream, ",%d", cbit - 1); - } - break; - } - - case '=': - { - int cond = GET_FIELD (insn, 27, 31); - - switch (cond) - { - case 0: fputs_filtered (" ", info); break; - case 1: fputs_filtered ("acc ", info); break; - case 2: fputs_filtered ("rej ", info); break; - case 5: fputs_filtered ("acc8 ", info); break; - case 6: fputs_filtered ("rej8 ", info); break; - case 9: fputs_filtered ("acc6 ", info); break; - case 13: fputs_filtered ("acc4 ", info); break; - case 17: fputs_filtered ("acc2 ", info); break; - default: break; - } - break; - } - - case 'X': - (*info->print_address_func) - (memaddr + 8 + extract_22 (insn), info); - break; - case 'L': - fputs_filtered (",rp", info); - break; - default: - (*info->fprintf_func) (info->stream, "%c", *s); - break; - } - } - return sizeof (insn); - } - } - (*info->fprintf_func) (info->stream, "#%8x", insn); - return sizeof (insn); -} diff --git a/librz/arch/isa_gnu/hppa/libhppa.h b/librz/arch/isa_gnu/hppa/libhppa.h deleted file mode 100644 index 82da072bd50..00000000000 --- a/librz/arch/isa_gnu/hppa/libhppa.h +++ /dev/null @@ -1,552 +0,0 @@ -// SPDX-FileCopyrightText: 1990-2014 Free Software Foundation, Inc. -// SPDX-License-Identifier: GPL-3.0-or-later - -/* HP PA-RISC SOM object file format: definitions internal to BFD. - Copyright (C) 1990-2014 Free Software Foundation, Inc. - - Contributed by the Center for Software Science at the - University of Utah (pa-gdb-bugs@cs.utah.edu). - - This file is part of BFD, the Binary File Descriptor library. - - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, - MA 02110-1301, USA. */ - -#ifndef _LIBHPPA_H -#define _LIBHPPA_H - -#define BYTES_IN_WORD 4 -#define PA_PAGESIZE 0x1000 - -/* The PA instruction set variants. */ -enum pa_arch { pa10 = 10, - pa11 = 11, - pa20 = 20, - pa20w = 25 }; - -/* HP PA-RISC relocation types */ - -enum hppa_reloc_field_selector_type { - RZ_HPPA_FSEL = 0x0, - RZ_HPPA_LSSEL = 0x1, - RZ_HPPA_RSSEL = 0x2, - RZ_HPPA_LSEL = 0x3, - RZ_HPPA_RSEL = 0x4, - RZ_HPPA_LDSEL = 0x5, - RZ_HPPA_RDSEL = 0x6, - RZ_HPPA_LRSEL = 0x7, - RZ_HPPA_RRSEL = 0x8, - RZ_HPPA_NSEL = 0x9, - RZ_HPPA_NLSEL = 0xa, - RZ_HPPA_NLRSEL = 0xb, - RZ_HPPA_PSEL = 0xc, - RZ_HPPA_LPSEL = 0xd, - RZ_HPPA_RPSEL = 0xe, - RZ_HPPA_TSEL = 0xf, - RZ_HPPA_LTSEL = 0x10, - RZ_HPPA_RTSEL = 0x11, - RZ_HPPA_LTPSEL = 0x12, - RZ_HPPA_RTPSEL = 0x13 -}; - -/* /usr/include/reloc.h defines these to constants. We want to use - them in enums, so #undef them before we start using them. We might - be able to fix this another way by simply managing not to include - /usr/include/reloc.h, but currently GDB picks up these defines - somewhere. */ -#undef e_fsel -#undef e_lssel -#undef e_rssel -#undef e_lsel -#undef e_rsel -#undef e_ldsel -#undef e_rdsel -#undef e_lrsel -#undef e_rrsel -#undef e_nsel -#undef e_nlsel -#undef e_nlrsel -#undef e_psel -#undef e_lpsel -#undef e_rpsel -#undef e_tsel -#undef e_ltsel -#undef e_rtsel -#undef e_one -#undef e_two -#undef e_pcrel -#undef e_con -#undef e_plabel -#undef e_abs - -/* for compatibility */ -enum hppa_reloc_field_selector_type_alt { - e_fsel = RZ_HPPA_FSEL, - e_lssel = RZ_HPPA_LSSEL, - e_rssel = RZ_HPPA_RSSEL, - e_lsel = RZ_HPPA_LSEL, - e_rsel = RZ_HPPA_RSEL, - e_ldsel = RZ_HPPA_LDSEL, - e_rdsel = RZ_HPPA_RDSEL, - e_lrsel = RZ_HPPA_LRSEL, - e_rrsel = RZ_HPPA_RRSEL, - e_nsel = RZ_HPPA_NSEL, - e_nlsel = RZ_HPPA_NLSEL, - e_nlrsel = RZ_HPPA_NLRSEL, - e_psel = RZ_HPPA_PSEL, - e_lpsel = RZ_HPPA_LPSEL, - e_rpsel = RZ_HPPA_RPSEL, - e_tsel = RZ_HPPA_TSEL, - e_ltsel = RZ_HPPA_LTSEL, - e_rtsel = RZ_HPPA_RTSEL, - e_ltpsel = RZ_HPPA_LTPSEL, - e_rtpsel = RZ_HPPA_RTPSEL -}; - -enum hppa_reloc_expr_type { - RZ_HPPA_E_ONE = 0, - RZ_HPPA_E_TWO = 1, - RZ_HPPA_E_PCREL = 2, - RZ_HPPA_E_CON = 3, - RZ_HPPA_E_PLABEL = 7, - RZ_HPPA_E_ABS = 18 -}; - -/* for compatibility */ -enum hppa_reloc_expr_type_alt { - e_one = RZ_HPPA_E_ONE, - e_two = RZ_HPPA_E_TWO, - e_pcrel = RZ_HPPA_E_PCREL, - e_con = RZ_HPPA_E_CON, - e_plabel = RZ_HPPA_E_PLABEL, - e_abs = RZ_HPPA_E_ABS -}; - -/* Relocations for function calls must be accompanied by parameter - relocation bits. These bits describe exactly where the caller has - placed the function's arguments and where it expects to find a return - value. - - Both ELF and SOM encode this information within the addend field - of the call relocation. (Note this could break very badly if one - was to make a call like bl foo + 0x12345678). - - The high order 10 bits contain parameter relocation information, - the low order 22 bits contain the constant offset. */ - -#define HPPA_R_ARG_RELOC(a) \ - (((a) >> 22) & 0x3ff) -#define HPPA_R_CONSTANT(a) \ - ((((bfd_signed_vma)(a)) << (BFD_ARCH_SIZE - 22)) >> (BFD_ARCH_SIZE - 22)) -#define HPPA_R_ADDEND(r, c) \ - (((r) << 22) + ((c)&0x3fffff)) - -/* Some functions to manipulate PA instructions. */ - -/* Declare the functions with the unused attribute to avoid warnings. */ -static inline int sign_extend(int, int) ATTRIBUTE_UNUSED; -static inline int low_sign_extend(int, int) ATTRIBUTE_UNUSED; -static inline int sign_unext(int, int) ATTRIBUTE_UNUSED; -static inline int low_sign_unext(int, int) ATTRIBUTE_UNUSED; -static inline int re_assemble_3(int) ATTRIBUTE_UNUSED; -static inline int re_assemble_12(int) ATTRIBUTE_UNUSED; -static inline int re_assemble_14(int) ATTRIBUTE_UNUSED; -static inline int re_assemble_16(int) ATTRIBUTE_UNUSED; -static inline int re_assemble_17(int) ATTRIBUTE_UNUSED; -static inline int re_assemble_21(int) ATTRIBUTE_UNUSED; -static inline int re_assemble_22(int) ATTRIBUTE_UNUSED; -static inline bfd_signed_vma hppa_field_adjust(bfd_vma, bfd_signed_vma, enum hppa_reloc_field_selector_type_alt) - ATTRIBUTE_UNUSED; -static inline int bfd_hppa_insn2fmt(bfd *, int) ATTRIBUTE_UNUSED; -static inline int hppa_rebuild_insn(int, int, int) ATTRIBUTE_UNUSED; - -/* The *sign_extend functions are used to assemble various bitfields - taken from an instruction and return the resulting immediate - value. */ - -static inline int -sign_extend(int x, int len) { - int signbit = (1 << (len - 1)); - int mask = (signbit << 1) - 1; - return ((x & mask) ^ signbit) - signbit; -} - -static inline int -low_sign_extend(int x, int len) { - return (x >> 1) - ((x & 1) << (len - 1)); -} - -/* The re_assemble_* functions prepare an immediate value for - insertion into an opcode. pa-risc uses all sorts of weird bitfields - in the instruction to hold the value. */ - -static inline int -sign_unext(int x, int len) { - int len_ones; - - len_ones = (1 << len) - 1; - - return x & len_ones; -} - -static inline int -low_sign_unext(int x, int len) { - int temp; - int sign; - - sign = (x >> (len - 1)) & 1; - - temp = sign_unext(x, len - 1); - - return (temp << 1) | sign; -} - -static inline int -re_assemble_3(int as3) { - return (((as3 & 4) << (13 - 2)) | ((as3 & 3) << (13 + 1))); -} - -static inline int -re_assemble_12(int as12) { - return (((as12 & 0x800) >> 11) | ((as12 & 0x400) >> (10 - 2)) | ((as12 & 0x3ff) << (1 + 2))); -} - -static inline int -re_assemble_14(int as14) { - return (((as14 & 0x1fff) << 1) | ((as14 & 0x2000) >> 13)); -} - -static inline int -re_assemble_16(int as16) { - int s, t; - - /* Unusual 16-bit encoding, for wide mode only. */ - t = (as16 << 1) & 0xffff; - s = (as16 & 0x8000); - return (t ^ s ^ (s >> 1)) | (s >> 15); -} - -static inline int -re_assemble_17(int as17) { - return (((as17 & 0x10000) >> 16) | ((as17 & 0x0f800) << (16 - 11)) | ((as17 & 0x00400) >> (10 - 2)) | ((as17 & 0x003ff) << (1 + 2))); -} - -static inline int -re_assemble_21(int as21) { - return (((as21 & 0x100000) >> 20) | ((as21 & 0x0ffe00) >> 8) | ((as21 & 0x000180) << 7) | ((as21 & 0x00007c) << 14) | ((as21 & 0x000003) << 12)); -} - -static inline int -re_assemble_22(int as22) { - return (((as22 & 0x200000) >> 21) | ((as22 & 0x1f0000) << (21 - 16)) | ((as22 & 0x00f800) << (16 - 11)) | ((as22 & 0x000400) >> (10 - 2)) | ((as22 & 0x0003ff) << (1 + 2))); -} - -/* Handle field selectors for PA instructions. - The L and R (and LS, RS etc.) selectors are used in pairs to form a - full 32 bit address. eg. - - LDIL L'start,%r1 ; put left part into r1 - LDW R'start(%r1),%r2 ; add r1 and right part to form address - - This function returns sign extended values in all cases. -*/ - -static inline bfd_signed_vma -hppa_field_adjust(bfd_vma sym_val, - bfd_signed_vma addend, - enum hppa_reloc_field_selector_type_alt rz_field) { - bfd_signed_vma value; - - value = sym_val + addend; - switch (rz_field) { - case e_fsel: - /* F: No change. */ - break; - - case e_nsel: - /* N: null selector. I don't really understand what this is all - about, but HP's documentation says "this indicates that zero - bits are to be used for the displacement on the instruction. - This fixup is used to identify three-instruction sequences to - access data (for importing shared library data)." */ - value = 0; - break; - - case e_lsel: - case e_nlsel: - /* L: Select top 21 bits. */ - value = value >> 11; - break; - - case e_rsel: - /* R: Select bottom 11 bits. */ - value = value & 0x7ff; - break; - - case e_lssel: - /* LS: Round to nearest multiple of 2048 then select top 21 bits. */ - value = value + 0x400; - value = value >> 11; - break; - - case e_rssel: - /* RS: Select bottom 11 bits for LS. - We need to return a value such that 2048 * LS'x + RS'x == x. - ie. RS'x = x - ((x + 0x400) & -0x800) - this is just a sign extension from bit 21. */ - value = ((value & 0x7ff) ^ 0x400) - 0x400; - break; - - case e_ldsel: - /* LD: Round to next multiple of 2048 then select top 21 bits. - Yes, if we are already on a multiple of 2048, we go up to the - next one. RD in this case will be -2048. */ - value = value + 0x800; - value = value >> 11; - break; - - case e_rdsel: - /* RD: Set bits 0-20 to one. */ - value = value | -0x800; - break; - - case e_lrsel: - case e_nlrsel: - /* LR: L with rounding of the addend to nearest 8k. */ - value = sym_val + ((addend + 0x1000) & -0x2000); - value = value >> 11; - break; - - case e_rrsel: - /* RR: R with rounding of the addend to nearest 8k. - We need to return a value such that 2048 * LR'x + RR'x == x - ie. RR'x = s+a - (s + (((a + 0x1000) & -0x2000) & -0x800)) - . = s+a - ((s & -0x800) + ((a + 0x1000) & -0x2000)) - . = (s & 0x7ff) + a - ((a + 0x1000) & -0x2000) */ - value = (sym_val & 0x7ff) + (((addend & 0x1fff) ^ 0x1000) - 0x1000); - break; - - default: - return -1; - } - return value; -} - -/* PA-RISC OPCODES */ -#define get_opcode(insn) (((insn) >> 26) & 0x3f) - -enum hppa_opcode_type { - /* None of the opcodes in the first group generate relocs, so we - aren't too concerned about them. */ - OP_SYSOP = 0x00, - OP_MEMMNG = 0x01, - OP_ALU = 0x02, - OP_NDXMEM = 0x03, - OP_SPOP = 0x04, - OP_DIAG = 0x05, - OP_FMPYADD = 0x06, - OP_UNDEF07 = 0x07, - OP_COPRW = 0x09, - OP_COPRDW = 0x0b, - OP_COPR = 0x0c, - OP_FLOAT = 0x0e, - OP_PRDSPEC = 0x0f, - OP_UNDEF15 = 0x15, - OP_UNDEF1d = 0x1d, - OP_FMPYSUB = 0x26, - OP_FPFUSED = 0x2e, - OP_SHEXDP0 = 0x34, - OP_SHEXDP1 = 0x35, - OP_SHEXDP2 = 0x36, - OP_UNDEF37 = 0x37, - OP_SHEXDP3 = 0x3c, - OP_SHEXDP4 = 0x3d, - OP_MULTMED = 0x3e, - OP_UNDEF3f = 0x3f, - - OP_LDIL = 0x08, - OP_ADDIL = 0x0a, - - OP_LDO = 0x0d, - OP_LDB = 0x10, - OP_LDH = 0x11, - OP_LDW = 0x12, - OP_LDWM = 0x13, - OP_STB = 0x18, - OP_STH = 0x19, - OP_STW = 0x1a, - OP_STWM = 0x1b, - - OP_LDD = 0x14, - OP_STD = 0x1c, - - OP_FLDW = 0x16, - OP_LDWL = 0x17, - OP_FSTW = 0x1e, - OP_STWL = 0x1f, - - OP_COMBT = 0x20, - OP_COMIBT = 0x21, - OP_COMBF = 0x22, - OP_COMIBF = 0x23, - OP_CMPBDT = 0x27, - OP_ADDBT = 0x28, - OP_ADDIBT = 0x29, - OP_ADDBF = 0x2a, - OP_ADDIBF = 0x2b, - OP_CMPBDF = 0x2f, - OP_BVB = 0x30, - OP_BB = 0x31, - OP_MOVB = 0x32, - OP_MOVIB = 0x33, - OP_CMPIBD = 0x3b, - - OP_COMICLR = 0x24, - OP_SUBI = 0x25, - OP_ADDIT = 0x2c, - OP_ADDI = 0x2d, - - OP_BE = 0x38, - OP_BLE = 0x39, - OP_BL = 0x3a -}; - -/* Given a machine instruction, return its format. */ - -static inline int -bfd_hppa_insn2fmt(bfd *abfd, int insn) { - enum hppa_opcode_type op = get_opcode(insn); - - switch (op) { - case OP_COMICLR: - case OP_SUBI: - case OP_ADDIT: - case OP_ADDI: - return 11; - - case OP_COMBT: - case OP_COMIBT: - case OP_COMBF: - case OP_COMIBF: - case OP_CMPBDT: - case OP_ADDBT: - case OP_ADDIBT: - case OP_ADDBF: - case OP_ADDIBF: - case OP_CMPBDF: - case OP_BVB: - case OP_BB: - case OP_MOVB: - case OP_MOVIB: - case OP_CMPIBD: - return 12; - - case OP_LDO: - case OP_LDB: - case OP_LDH: - case OP_LDW: - case OP_LDWM: - case OP_STB: - case OP_STH: - case OP_STW: - case OP_STWM: - if (abfd->arch_info->mach >= 25) - return 16; /* Wide mode, format 16. */ - return 14; - - case OP_FLDW: - case OP_LDWL: - case OP_FSTW: - case OP_STWL: - /* This is a hack. Unfortunately, format 11 is already taken - and we're using integers rather than an enum, so it's hard - to describe the 11a format. */ - if (abfd->arch_info->mach >= 25) - return -16; /* Wide mode, format 16a. */ - return -11; - - case OP_LDD: - case OP_STD: - if (abfd->arch_info->mach >= 25) - return -10; /* Wide mode, format 10a. */ - return 10; - - case OP_BL: - if ((insn & 0x8000) != 0) - return 22; - /* fall thru */ - case OP_BE: - case OP_BLE: - return 17; - - case OP_LDIL: - case OP_ADDIL: - return 21; - - default: - break; - } - return 32; -} - -/* Insert VALUE into INSN using RZ_FORMAT to determine exactly what - bits to change. */ - -static inline int -hppa_rebuild_insn(int insn, int value, int rz_format) { - switch (rz_format) { - case 11: - return (insn & ~0x7ff) | low_sign_unext(value, 11); - - case 12: - return (insn & ~0x1ffd) | re_assemble_12(value); - - case 10: - return (insn & ~0x3ff1) | re_assemble_14(value & -8); - - case -11: - return (insn & ~0x3ff9) | re_assemble_14(value & -4); - - case 14: - return (insn & ~0x3fff) | re_assemble_14(value); - - case -10: - return (insn & ~0xfff1) | re_assemble_16(value & -8); - - case -16: - return (insn & ~0xfff9) | re_assemble_16(value & -4); - - case 16: - return (insn & ~0xffff) | re_assemble_16(value); - - case 17: - return (insn & ~0x1f1ffd) | re_assemble_17(value); - - case 21: - return (insn & ~0x1fffff) | re_assemble_21(value); - - case 22: - return (insn & ~0x3ff1ffd) | re_assemble_22(value); - - case 32: - return value; - - default: - return -1; - } - return insn; -} - -#endif /* _LIBHPPA_H */ diff --git a/librz/arch/meson.build b/librz/arch/meson.build index ad531c23411..ff61678f377 100644 --- a/librz/arch/meson.build +++ b/librz/arch/meson.build @@ -346,7 +346,6 @@ if get_option('use_gpl') arch_plugins_list += [ 'arc_gnu', 'cris_gnu', - 'hppa_gnu', 'lanai_gnu', 'mips_gnu', 'riscv_gnu', @@ -359,7 +358,6 @@ if get_option('use_gpl') arch_plugin_sources += [ 'p_gnu/arch_arc.c', 'p_gnu/arch_cris.c', - 'p_gnu/arch_hppa.c', 'p_gnu/arch_lanai.c', 'p_gnu/arch_mips.c', 'p_gnu/arch_riscv.c', @@ -376,7 +374,6 @@ if get_option('use_gpl') 'isa_gnu/arc/arcompact-dis.c', 'isa_gnu/cris/cris-dis.c', 'isa_gnu/cris/cris-opc.c', - 'isa_gnu/hppa/hppa-dis.c', 'isa_gnu/lanai/lanai-dis.c', 'isa_gnu/lanai/lanai-opc.c', 'isa_gnu/mips/mips-dis.c', diff --git a/librz/arch/p_gnu/arch_hppa.c b/librz/arch/p_gnu/arch_hppa.c deleted file mode 100644 index 4bff5bb54bb..00000000000 --- a/librz/arch/p_gnu/arch_hppa.c +++ /dev/null @@ -1,9 +0,0 @@ -// SPDX-FileCopyrightText: 2024 RizinOrg -// SPDX-FileCopyrightText: 2024 deroad -// SPDX-License-Identifier: LGPL-3.0-only - -#include - -#include "asm/asm_hppa_gnu.c" - -RZ_ARCH_ASM_ONLY_PLUGIN_DEFINE_DEPRECATED(hppa_gnu); diff --git a/librz/arch/p_gnu/asm/asm_hppa_gnu.c b/librz/arch/p_gnu/asm/asm_hppa_gnu.c deleted file mode 100644 index ea8ce5811aa..00000000000 --- a/librz/arch/p_gnu/asm/asm_hppa_gnu.c +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-FileCopyrightText: 2015 pancake -// SPDX-License-Identifier: LGPL-3.0-only - -#include -#include -#include - -#include -#include -#include -#include - -#include - -static unsigned long Offset = 0; -static RzStrBuf *buf_global = NULL; -static unsigned char bytes[4]; - -static int hppa_buffer_read_memory(bfd_vma memaddr, bfd_byte *myaddr, ut32 length, struct disassemble_info *info) { -#if 0 // XXX rewrite needed - if (length == 4) { - // swap - myaddr[0] = bytes[3]; - myaddr[1] = bytes[2]; - myaddr[2] = bytes[1]; - myaddr[3] = bytes[0]; - return 0; - } -#endif - int delta = (memaddr - Offset); - if (delta < 0) { - return -1; // disable backward reads - } - if ((delta + length) > 4) { - return -1; - } - memcpy(myaddr, bytes + delta, length); - return 0; -} - -static int symbol_at_address(bfd_vma addr, struct disassemble_info *info) { - return 0; -} - -static void memory_error_func(int status, bfd_vma memaddr, struct disassemble_info *info) { - //-- -} - -DECLARE_GENERIC_PRINT_ADDRESS_FUNC() -DECLARE_GENERIC_FPRINTF_FUNC() - -static int disassemble(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len) { - struct disassemble_info disasm_obj; - if (len < 4) { - return -1; - } - buf_global = &op->buf_asm; - Offset = a->pc; - memcpy(bytes, buf, 4); // TODO handle thumb - - /* prepare disassembler */ - memset(&disasm_obj, '\0', sizeof(struct disassemble_info)); - disasm_obj.disassembler_options = (a->bits == 64) ? "64" : ""; - disasm_obj.buffer = bytes; - disasm_obj.read_memory_func = &hppa_buffer_read_memory; - disasm_obj.symbol_at_address_func = &symbol_at_address; - disasm_obj.memory_error_func = &memory_error_func; - disasm_obj.print_address_func = &generic_print_address_func; - disasm_obj.endian = BFD_ENDIAN_BIG; - disasm_obj.fprintf_func = &generic_fprintf_func; - disasm_obj.stream = stdout; - - op->size = print_insn_hppa((bfd_vma)Offset, &disasm_obj); - if (op->size == -1) { - rz_strbuf_set(&op->buf_asm, "(data)"); - } - return op->size; -} - -RzAsmPlugin rz_asm_plugin_hppa_gnu = { - .name = "hppa", - .arch = "hppa", - .license = "GPL3", - .bits = 32, - .endian = RZ_SYS_ENDIAN_BIG, - .desc = "HP PA-RISC", - .disassemble = &disassemble -}; From 45de281f9fa02ee578f58bd282b9fb57475cde74 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Sat, 4 May 2024 18:48:21 +0800 Subject: [PATCH 2/2] hppa: use capstone disassembler --- librz/arch/isa/hppa/hppa.h | 19 + librz/arch/isa/hppa/hppa.inc | 116 ++++++ librz/arch/meson.build | 2 + librz/arch/p/analysis/analysis_hppa_cs.c | 493 +++++++++++++++++++++++ librz/arch/p/arch_hppa_cs.c | 9 + librz/arch/p/asm/asm_hppa_cs.c | 123 ++++++ librz/bin/format/elf/elf_imports.c | 22 + librz/bin/format/elf/elf_info.c | 29 +- librz/bin/p/bin_elf.inc | 16 + test/db/analysis/hppa | 11 + test/db/cmd/cmd_list | 4 +- 11 files changed, 839 insertions(+), 5 deletions(-) create mode 100644 librz/arch/isa/hppa/hppa.h create mode 100644 librz/arch/isa/hppa/hppa.inc create mode 100644 librz/arch/p/analysis/analysis_hppa_cs.c create mode 100644 librz/arch/p/arch_hppa_cs.c create mode 100644 librz/arch/p/asm/asm_hppa_cs.c create mode 100644 test/db/analysis/hppa diff --git a/librz/arch/isa/hppa/hppa.h b/librz/arch/isa/hppa/hppa.h new file mode 100644 index 00000000000..bd235250ed4 --- /dev/null +++ b/librz/arch/isa/hppa/hppa.h @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: 2024 Anton Kochkov +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include + +#ifndef RZ_HPPA_H +#define RZ_HPPA_H + +typedef struct { + csh h; + cs_mode mode; + cs_insn *insn; + ut32 count; + ut32 word; + RzPVector /**/ *token_patterns; +} RzAsmHPPAContext; + +#endif // RZ_HPPA_H diff --git a/librz/arch/isa/hppa/hppa.inc b/librz/arch/isa/hppa/hppa.inc new file mode 100644 index 00000000000..c03a163bdda --- /dev/null +++ b/librz/arch/isa/hppa/hppa.inc @@ -0,0 +1,116 @@ +// SPDX-FileCopyrightText: 2023 billow +// SPDX-FileCopyrightText: 2024 Anton Kochkov +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include +#include "hppa.h" + +static inline cs_mode hppa_cpu_to_cs_mode(const char *cpu_type) { + if (RZ_STR_ISNOTEMPTY(cpu_type)) { + if (!strcmp(cpu_type, "hppa1.1")) { + return CS_MODE_HPPA_11; + } + if (!strcmp(cpu_type, "hppa2.0")) { + return CS_MODE_HPPA_20; + } + if (!strcmp(cpu_type, "hppa2.0w")) { + return CS_MODE_HPPA_20W; + } + } + return CS_MODE_HPPA_11; +} + +static inline bool hppa_setup_cs_handle(RzAsmHPPAContext *ctx, const char *cpu, const char *features, bool big_endian) { + const cs_mode mode = hppa_cpu_to_cs_mode(cpu) | (big_endian ? CS_MODE_BIG_ENDIAN : CS_MODE_LITTLE_ENDIAN); + if (mode != ctx->mode) { + cs_close(&ctx->h); + ctx->h = 0; + ctx->mode = mode; + } + + if (ctx->h != 0) { + return true; + } + cs_err err = cs_open(CS_ARCH_HPPA, mode, &ctx->h); + if (err) { + RZ_LOG_ERROR("Failed on cs_open() with error returned: %u\n", err); + return false; + } + err = cs_option(ctx->h, CS_OPT_DETAIL, + RZ_STR_ISNOTEMPTY(features) || features == NULL ? CS_OPT_ON : CS_OPT_OFF); + if (err) { + RZ_LOG_ERROR("Failed on cs_open() with error returned: %u\n", err); + return false; + } + return true; +} + +static inline ut8 hppa_op_count(cs_insn *insn) { + return insn->detail->hppa.op_count; +} + +static inline cs_hppa_op *hppa_op_get(cs_insn *insn, int idx) { + if (idx >= hppa_op_count(insn)) { + RZ_LOG_WARN("Failed to get operand%d [%d]: \"%s %s\"\n", + idx, hppa_op_count(insn), insn->mnemonic, insn->op_str); + rz_warn_if_reached(); + return NULL; + } + return &insn->detail->hppa.operands[idx]; +} + +static inline const char *hppa_op_as_reg(RzAsmHPPAContext *ctx, int idx) { + const cs_hppa_op *op = hppa_op_get(ctx->insn, idx); + if (op->type != HPPA_OP_REG) { + RZ_LOG_WARN("Failed to get operand%d [%d]: \"%s %s\" [reg]\n", + idx, hppa_op_count(ctx->insn), ctx->insn->mnemonic, ctx->insn->op_str); + rz_warn_if_reached(); + return NULL; + } + return cs_reg_name(ctx->h, op->reg); +} + +static inline const char *hppa_op_as_mem(RzAsmHPPAContext *ctx, int idx) { + const cs_hppa_op *op = hppa_op_get(ctx->insn, idx); + if (op->type != HPPA_OP_MEM) { + RZ_LOG_WARN("Failed to get operand%d [%d]: \"%s %s\" [reg]\n", + idx, hppa_op_count(ctx->insn), ctx->insn->mnemonic, ctx->insn->op_str); + rz_warn_if_reached(); + return NULL; + } + return cs_reg_name(ctx->h, op->reg); +} + +static inline st64 hppa_op_as_imm(RzAsmHPPAContext *ctx, int idx) { + const cs_hppa_op *op = hppa_op_get(ctx->insn, idx); + if (op->type != HPPA_OP_IMM) { + RZ_LOG_WARN("Failed to get operand%d [%d]: \"%s %s\" [imm]\n", + idx, hppa_op_count(ctx->insn), ctx->insn->mnemonic, ctx->insn->op_str); + rz_warn_if_reached(); + return 0; + } + return op->imm; +} + +static inline st64 hppa_op_as_disp(RzAsmHPPAContext *ctx, int idx) { + const cs_hppa_op *op = hppa_op_get(ctx->insn, idx); + if (op->type != HPPA_OP_DISP) { + RZ_LOG_WARN("Failed to get operand%d [%d]: \"%s %s\" [imm]\n", + idx, hppa_op_count(ctx->insn), ctx->insn->mnemonic, ctx->insn->op_str); + rz_warn_if_reached(); + return 0; + } + return op->imm; +} + +static inline st64 hppa_op_as_target(RzAsmHPPAContext *ctx, int idx) { + const cs_hppa_op *op = hppa_op_get(ctx->insn, idx); + if (op->type != HPPA_OP_TARGET) { + RZ_LOG_WARN("Failed to get operand%d [%d]: \"%s %s\" [imm]\n", + idx, hppa_op_count(ctx->insn), ctx->insn->mnemonic, ctx->insn->op_str); + rz_warn_if_reached(); + return 0; + } + return op->imm; +} diff --git a/librz/arch/meson.build b/librz/arch/meson.build index ff61678f377..72b0ee848b9 100644 --- a/librz/arch/meson.build +++ b/librz/arch/meson.build @@ -325,12 +325,14 @@ if capstone_dep.version() == 'next' # plugins arch_plugins_list += [ 'alpha_cs', + 'hppa_cs', 'xtensa_cs', ] # plugins sources arch_plugin_sources += [ 'p/arch_alpha.c', + 'p/arch_hppa_cs.c', 'p/arch_xtensa_cs.c', ] diff --git a/librz/arch/p/analysis/analysis_hppa_cs.c b/librz/arch/p/analysis/analysis_hppa_cs.c new file mode 100644 index 00000000000..f307a118dbc --- /dev/null +++ b/librz/arch/p/analysis/analysis_hppa_cs.c @@ -0,0 +1,493 @@ +// SPDX-FileCopyrightText: 2024 Anton Kochkov +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include +#include +#include + +#include + +static char *hppa_reg_profile(RzAnalysis *analysis) { + if (analysis->bits == 64) { + const char *p = + "=PC pc\n" + "=SP r30\n" + "=A0 r26\n" + "=A1 r25\n" + "=A2 r24\n" + "=A3 r23\n" + "gpr r0 .64 0 0\n" + "gpr r1 .64 8 0\n" + "gpr r2 .64 16 0\n" + "gpr r3 .64 24 0\n" + "gpr r4 .64 32 0\n" + "gpr r5 .64 40 0\n" + "gpr r6 .64 48 0\n" + "gpr r7 .64 56 0\n" + "gpr r8 .64 64 0\n" + "gpr r9 .64 72 0\n" + "gpr r10 .64 80 0\n" + "gpr r11 .64 88 0\n" + "gpr r12 .64 96 0\n" + "gpr r13 .64 104 0\n" + "gpr r14 .64 112 0\n" + "gpr r15 .64 120 0\n" + "gpr r16 .64 128 0\n" + "gpr r17 .64 136 0\n" + "gpr r18 .64 144 0\n" + "gpr r19 .64 152 0\n" + "gpr r20 .64 160 0\n" + "gpr r21 .64 168 0\n" + "gpr r22 .64 176 0\n" + "gpr r23 .64 184 0\n" + "gpr r24 .64 192 0\n" + "gpr r25 .64 200 0\n" + "gpr r26 .64 208 0\n" + "gpr r27 .64 216 0\n" + "gpr r28 .64 224 0\n" + "gpr r29 .64 232 0\n" + "gpr r30 .64 240 0\n" + "gpr r31 .64 248 0\n" + "ctr sr0 .64 256 0\n" + "ctr sr1 .64 264 0\n" + "ctr sr2 .64 272 0\n" + "ctr sr3 .64 280 0\n" + "ctr sr4 .64 288 0\n" + "ctr sr5 .64 296 0\n" + "ctr sr6 .64 304 0\n" + "ctr sr7 .64 312 0\n" + "flg psw .64 320 0\n"; + return strdup(p); + } else { + const char *p = + "=PC pc\n" + "=SP r30\n" + "=A0 r26\n" + "=A1 r25\n" + "=A2 r24\n" + "=A3 r23\n" + "gpr r0 .32 0 0\n" + "gpr r1 .32 4 0\n" + "gpr r2 .32 8 0\n" + "gpr r3 .32 12 0\n" + "gpr r4 .32 16 0\n" + "gpr r5 .32 20 0\n" + "gpr r6 .32 24 0\n" + "gpr r7 .32 28 0\n" + "gpr r8 .32 32 0\n" + "gpr r9 .32 36 0\n" + "gpr r10 .32 40 0\n" + "gpr r11 .32 44 0\n" + "gpr r12 .32 48 0\n" + "gpr r13 .32 52 0\n" + "gpr r14 .32 56 0\n" + "gpr r15 .32 60 0\n" + "gpr r16 .32 64 0\n" + "gpr r17 .32 68 0\n" + "gpr r18 .32 72 0\n" + "gpr r19 .32 76 0\n" + "gpr r20 .32 80 0\n" + "gpr r21 .32 84 0\n" + "gpr r22 .32 88 0\n" + "gpr r23 .32 92 0\n" + "gpr r24 .32 96 0\n" + "gpr r25 .32 100 0\n" + "gpr r26 .32 104 0\n" + "gpr r27 .32 108 0\n" + "gpr r28 .32 112 0\n" + "gpr r29 .32 116 0\n" + "gpr r30 .32 120 0\n" + "gpr r31 .32 124 0\n" + "ctr sr0 .32 128 0\n" + "ctr sr1 .32 132 0\n" + "ctr sr2 .32 136 0\n" + "ctr sr3 .32 140 0\n" + "ctr sr4 .32 144 0\n" + "ctr sr5 .32 148 0\n" + "ctr sr6 .32 152 0\n" + "ctr sr7 .32 156 0\n" + "flg psw .32 160 0\n"; + return strdup(p); + } +} + +static inline void hppa_fillval(RzReg *rz_reg, csh handle, RzAnalysisValue *av, cs_hppa_op *hop) { + switch (hop->type) { + case HPPA_OP_INVALID: + default: + av->type = RZ_ANALYSIS_VAL_UNK; + break; + case HPPA_OP_IMM: + case HPPA_OP_DISP: + case HPPA_OP_TARGET: + av->type = RZ_ANALYSIS_VAL_IMM; + av->imm = hop->imm; + break; + case HPPA_OP_REG: + case HPPA_OP_IDX_REG: + av->type = RZ_ANALYSIS_VAL_REG; + av->reg = rz_reg_get(rz_reg, cs_reg_name(handle, hop->reg), RZ_REG_TYPE_ANY); + break; + case HPPA_OP_MEM: + av->type = RZ_ANALYSIS_VAL_MEM; + // FIXME: Handle also the space + av->reg = rz_reg_get(rz_reg, cs_reg_name(handle, hop->mem.base), RZ_REG_TYPE_ANY); + av->delta = 0; + break; + } +} + +static void hppa_fillvals(RzAsmHPPAContext *ctx, RzAnalysis *a, RzAnalysisOp *op) { + uint8_t srci = 0; + cs_hppa *hc = &ctx->insn->detail->hppa; + for (uint8_t i = 0; i < hc->op_count; ++i) { + cs_hppa_op *hop = &hc->operands[i]; + RzAnalysisValue *av = rz_analysis_value_new(); + hppa_fillval(a->reg, ctx->h, av, hop); + if (hop->access & CS_AC_READ) { + av->access |= RZ_ANALYSIS_ACC_R; + op->src[srci++] = av; + } + if (hop->access & CS_AC_WRITE) { + av->access |= RZ_ANALYSIS_ACC_W; + if (srci > 0 && av == op->src[srci - 1]) { + av = rz_mem_dup(av, sizeof(RzAnalysisValue)); + } + op->dst = av; + } + } +} + +static void hppa_opex(RzAsmHPPAContext *ctx, RzStrBuf *sb) { + PJ *pj = pj_new(); + if (!pj) { + return; + } + pj_o(pj); + pj_ka(pj, "operands"); + cs_hppa *hpc = &ctx->insn->detail->hppa; + for (st32 i = 0; i < hpc->op_count; i++) { + cs_hppa_op *op = hpc->operands + i; + pj_o(pj); + switch (op->type) { + case HPPA_OP_INVALID: { + pj_ks(pj, "type", "invalid"); + break; + } + case HPPA_OP_REG: { + pj_ks(pj, "type", "reg"); + pj_ks(pj, "value", cs_reg_name(ctx->h, op->reg)); + break; + } + case HPPA_OP_IDX_REG: { + pj_ks(pj, "type", "idx_reg"); + pj_ks(pj, "value", cs_reg_name(ctx->h, op->reg)); + break; + } + case HPPA_OP_IMM: { + pj_ks(pj, "type", "imm"); + pj_ki(pj, "value", op->imm); + break; + } + case HPPA_OP_DISP: { + pj_ks(pj, "type", "disp"); + pj_ki(pj, "value", op->imm); + break; + } + case HPPA_OP_TARGET: { + pj_ks(pj, "type", "target"); + pj_ki(pj, "value", op->imm); + break; + } + case HPPA_OP_MEM: { + pj_ks(pj, "type", "mem"); + pj_ks(pj, "base", cs_reg_name(ctx->h, op->mem.base)); + if (op->mem.space != HPPA_REG_INVALID) { + pj_ks(pj, "space", cs_reg_name(ctx->h, op->mem.space)); + } else { + pj_ks(pj, "space", "unavailable"); + } + break; + } + } + pj_end(pj); + } + pj_end(pj); + pj_end(pj); + + rz_strbuf_init(sb); + rz_strbuf_append(sb, pj_string(pj)); + pj_free(pj); +} + +static void hppa_op_set_type(RzAsmHPPAContext *ctx, RzAnalysisOp *op) { + switch (ctx->insn->id) { + default: + op->type = RZ_ANALYSIS_OP_TYPE_UNK; + break; + case HPPA_INS_NOP: + op->type = RZ_ANALYSIS_OP_TYPE_NOP; + break; + case HPPA_INS_ADD: + case HPPA_INS_ADDI: + case HPPA_INS_ADDIO: + case HPPA_INS_ADDIT: + case HPPA_INS_ADDITO: + case HPPA_INS_ADDIL: + case HPPA_INS_ADDC: + case HPPA_INS_ADDCO: + case HPPA_INS_ADDL: + case HPPA_INS_ADDO: + op->type = RZ_ANALYSIS_OP_TYPE_ADD; + break; + case HPPA_INS_ADDB: + case HPPA_INS_ADDIB: + op->type = RZ_ANALYSIS_OP_TYPE_JMP; + op->jump = ctx->insn->address + hppa_op_as_target(ctx, 2); + break; + case HPPA_INS_ADDBT: + case HPPA_INS_ADDBF: + case HPPA_INS_ADDIBT: + case HPPA_INS_ADDIBF: + op->type = RZ_ANALYSIS_OP_TYPE_CJMP; + op->jump = ctx->insn->address + hppa_op_as_target(ctx, 2); + op->fail = ctx->insn->address + ctx->insn->size; + break; + case HPPA_INS_AND: + case HPPA_INS_ANDCM: + op->type = RZ_ANALYSIS_OP_TYPE_AND; + break; + case HPPA_INS_BB: + op->type = RZ_ANALYSIS_OP_TYPE_CJMP; + op->jump = ctx->insn->address + hppa_op_as_target(ctx, 2); + op->fail = ctx->insn->address + ctx->insn->size; + break; + case HPPA_INS_BE: + op->type = RZ_ANALYSIS_OP_TYPE_IRCALL; + op->reg = hppa_op_as_mem(ctx, 1); + break; + case HPPA_INS_BL: + op->type = RZ_ANALYSIS_OP_TYPE_IRCALL; + op->jump = ctx->insn->address + hppa_op_as_target(ctx, 0); + break; + case HPPA_INS_BLE: + op->type = RZ_ANALYSIS_OP_TYPE_IRCALL; + op->reg = hppa_op_as_mem(ctx, 1); + break; + case HPPA_INS_BLR: + op->type = RZ_ANALYSIS_OP_TYPE_IRJMP; + op->reg = hppa_op_as_reg(ctx, 0); + break; + case HPPA_INS_BV: + op->type = RZ_ANALYSIS_OP_TYPE_IRCALL; + // FIXME: Should be result of the *two* registers actually + op->reg = hppa_op_as_mem(ctx, 1); + break; + case HPPA_INS_BVB: + op->type = RZ_ANALYSIS_OP_TYPE_CJMP; + op->jump = ctx->insn->address + hppa_op_as_target(ctx, 1); + break; + case HPPA_INS_GATE: + op->type = RZ_ANALYSIS_OP_TYPE_JMP; + op->jump = hppa_op_as_target(ctx, 0); + break; + case HPPA_INS_LDB: + case HPPA_INS_LDBS: + case HPPA_INS_LDCD: + case HPPA_INS_LDCW: + case HPPA_INS_LDCWS: + case HPPA_INS_LDD: + case HPPA_INS_LDDA: + case HPPA_INS_LDH: + case HPPA_INS_LDHS: + case HPPA_INS_LDI: + case HPPA_INS_LDW: + case HPPA_INS_LDWA: + case HPPA_INS_LDWAS: + case HPPA_INS_LDWM: + case HPPA_INS_LDWS: + op->type = RZ_ANALYSIS_OP_TYPE_LOAD; + const cs_hppa_op *op1 = hppa_op_get(ctx->insn, 1); + if (op1->type == HPPA_OP_REG && op1->reg == HPPA_REG_GR30 /* SP */) { + op->stackop = RZ_ANALYSIS_STACK_GET; + op->stackptr = 0; + } + op->ptr = (st64)hppa_op_as_disp(ctx, 0); + break; + case HPPA_INS_LDSID: + case HPPA_INS_LDHX: + case HPPA_INS_LDBX: + case HPPA_INS_LDCWX: + case HPPA_INS_LDWAX: + case HPPA_INS_LDWX: + op->type = RZ_ANALYSIS_OP_TYPE_LOAD; + break; + case HPPA_INS_LDIL: + op->type = RZ_ANALYSIS_OP_TYPE_MOV; + break; + case HPPA_INS_LCI: + case HPPA_INS_LDO: + op->type = RZ_ANALYSIS_OP_TYPE_LEA; + break; + case HPPA_INS_MOVB: + case HPPA_INS_MOVIB: + op->type = RZ_ANALYSIS_OP_TYPE_CJMP; + op->jump = ctx->insn->address + hppa_op_as_target(ctx, 2); + op->fail = ctx->insn->address + ctx->insn->size; + break; + case HPPA_INS_OR: + op->type = RZ_ANALYSIS_OP_TYPE_OR; + break; + case HPPA_INS_CALL: + op->type = RZ_ANALYSIS_OP_TYPE_CALL; + op->jump = hppa_op_as_target(ctx, 0); + break; + case HPPA_INS_COMIB: + case HPPA_INS_COMIBT: + case HPPA_INS_COMIBF: + case HPPA_INS_COMB: + case HPPA_INS_COMBT: + case HPPA_INS_COMBF: + op->type = RZ_ANALYSIS_OP_TYPE_CJMP; + op->jump = ctx->insn->address + hppa_op_as_target(ctx, 2); + op->fail = ctx->insn->address + ctx->insn->size; + break; + case HPPA_INS_STB: + case HPPA_INS_STBS: + case HPPA_INS_STBY: + case HPPA_INS_STBYS: + case HPPA_INS_STD: + case HPPA_INS_STDA: + case HPPA_INS_STDBY: + case HPPA_INS_STH: + case HPPA_INS_STHS: + case HPPA_INS_STW: + case HPPA_INS_STWA: + case HPPA_INS_STWAS: + case HPPA_INS_STWS: + case HPPA_INS_STWM: + op->type = RZ_ANALYSIS_OP_TYPE_STORE; + const cs_hppa_op *op2 = hppa_op_get(ctx->insn, 2); + if (op2->type == HPPA_OP_REG && op2->reg == HPPA_REG_GR30 /* SP */) { + op->stackop = RZ_ANALYSIS_STACK_SET; + op->stackptr = 0; + } + op->ptr = (st64)hppa_op_as_disp(ctx, 1); + break; + case HPPA_INS_SUB: + case HPPA_INS_SUBB: + case HPPA_INS_SUBBO: + case HPPA_INS_SUBI: + case HPPA_INS_SUBIO: + case HPPA_INS_SUBO: + case HPPA_INS_SUBT: + case HPPA_INS_SUBTO: + op->type = RZ_ANALYSIS_OP_TYPE_SUB; + break; + case HPPA_INS_XOR: + op->type = RZ_ANALYSIS_OP_TYPE_XOR; + break; + } +} + +static int +hppa_op(RzAnalysis *a, RzAnalysisOp *op, ut64 addr, const ut8 *data, int len, RzAnalysisOpMask mask) { + if (!(a && op && data && len > 0)) { + return -1; + } + + RzAsmHPPAContext *ctx = a->plugin_data; + if (!hppa_setup_cs_handle(ctx, a->cpu, NULL, a->big_endian)) { + return -1; + } + + op->size = 4; + + ctx->insn = NULL; + ctx->count = cs_disasm(ctx->h, (const ut8 *)data, len, addr, 1, &ctx->insn); + if (ctx->count <= 0 || !ctx->insn) { + op->type = RZ_ANALYSIS_OP_TYPE_ILL; + if (mask & RZ_ANALYSIS_OP_MASK_DISASM) { + op->mnemonic = strdup("invalid"); + } + goto beach; + } + + if (mask & RZ_ANALYSIS_OP_MASK_DISASM) { + op->mnemonic = rz_str_newf("%s%s%s", + ctx->insn->mnemonic, ctx->insn->op_str[0] ? " " : "", ctx->insn->op_str); + } + op->size = ctx->insn->size; + op->id = (int)ctx->insn->id; + op->addr = ctx->insn->address; + hppa_op_set_type(ctx, op); + if (mask & RZ_ANALYSIS_OP_MASK_OPEX) { + hppa_opex(ctx, &op->opex); + } + if (mask & RZ_ANALYSIS_OP_MASK_VAL) { + hppa_fillvals(ctx, a, op); + } + +beach: + cs_free(ctx->insn, ctx->count); + return op->size; +} + +static int hppa_archinfo(RzAnalysis *a, RzAnalysisInfoType query) { + switch (query) { + case RZ_ANALYSIS_ARCHINFO_MIN_OP_SIZE: + return 4; + case RZ_ANALYSIS_ARCHINFO_MAX_OP_SIZE: + return 4; + case RZ_ANALYSIS_ARCHINFO_TEXT_ALIGN: + case RZ_ANALYSIS_ARCHINFO_DATA_ALIGN: + case RZ_ANALYSIS_ARCHINFO_CAN_USE_POINTERS: + default: + return -1; + } +} + +static bool hppa_init(void **u) { + if (!u) { + return false; + } + RzAsmHPPAContext *ctx = RZ_NEW0(RzAsmHPPAContext); + if (!ctx) { + return false; + } + *u = ctx; + return true; +} + +static bool hppa_fini(void *u) { + if (!u) { + return true; + } + RzAsmHPPAContext *ctx = u; + cs_close(&ctx->h); + free(u); + return true; +} + +RzAnalysisPlugin rz_analysis_plugin_hppa_cs = { + .name = "hppa", + .desc = "Capstone HP PA-RISC analysis plugin", + .author = "xvilka", + .license = "LGPL3", + .arch = "hppa", + .bits = 32 | 64, + .get_reg_profile = hppa_reg_profile, + .archinfo = hppa_archinfo, + .op = hppa_op, + .init = hppa_init, + .fini = hppa_fini, +}; + +#ifndef RZ_PLUGIN_INCORE +RZ_API RzLibStruct rizin_plugin = { + .type = RZ_LIB_TYPE_ANALYSIS, + .data = &rz_analysis_plugin_hppa_cs, + .version = RZ_VERSION +}; +#endif diff --git a/librz/arch/p/arch_hppa_cs.c b/librz/arch/p/arch_hppa_cs.c new file mode 100644 index 00000000000..58ec66cbc8e --- /dev/null +++ b/librz/arch/p/arch_hppa_cs.c @@ -0,0 +1,9 @@ +// SPDX-FileCopyrightText: 2024 RizinOrg +// SPDX-License-Identifier: LGPL-3.0-only + +#include + +#include "analysis/analysis_hppa_cs.c" +#include "asm/asm_hppa_cs.c" + +RZ_ARCH_PLUGIN_DEFINE_DEPRECATED(hppa_cs); diff --git a/librz/arch/p/asm/asm_hppa_cs.c b/librz/arch/p/asm/asm_hppa_cs.c new file mode 100644 index 00000000000..a7ec7648d6f --- /dev/null +++ b/librz/arch/p/asm/asm_hppa_cs.c @@ -0,0 +1,123 @@ +// SPDX-FileCopyrightText: 2024 Anton Kochkov +// SPDX-License-Identifier: LGPL-3.0-only + +#include +#include +#include + +static int disassemble(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len) { + if (!buf || !op || !a->plugin_data) { + return -1; + } + + RzAsmHPPAContext *ctx = a->plugin_data; + if (!hppa_setup_cs_handle(ctx, a->cpu, a->features, a->big_endian)) { + return -1; + } + + op->size = 4; + + ctx->insn = NULL; + ctx->count = cs_disasm(ctx->h, buf, len, a->pc, 1, &ctx->insn); + if (ctx->count <= 0) { + RZ_LOG_ERROR("HPPA: disasm error @ 0x%08" PFMT64x ", len = %d\n", a->pc, len); + rz_asm_op_set_asm(op, "invalid"); + goto beach; + } + + op->size = ctx->insn->size; + rz_asm_op_setf_asm(op, "%s%s%s", + ctx->insn->mnemonic, RZ_STR_ISNOTEMPTY(ctx->insn->op_str) ? " " : "", ctx->insn->op_str); + + op->asm_toks = rz_asm_tokenize_asm_regex(&op->buf_asm, ctx->token_patterns); + +beach: + cs_free(ctx->insn, ctx->count); + ctx->insn = NULL; + ctx->count = 0; + return op->size; +} + +#define TOKEN(_type, _pat) \ + do { \ + RzAsmTokenPattern *pat = RZ_NEW0(RzAsmTokenPattern); \ + pat->type = RZ_ASM_TOKEN_##_type; \ + pat->pattern = strdup(_pat); \ + rz_pvector_push(pvec, pat); \ + } while (0) + +static RZ_OWN RzPVector /**/ *get_token_patterns() { + RzPVector *pvec = rz_pvector_new(rz_asm_token_pattern_free); + if (!pvec) { + return NULL; + } + + TOKEN(META, "(\\[|\\]|-)"); + TOKEN(META, "(\\+[rc]?)"); + + TOKEN(NUMBER, "(0x[[:digit:]abcdef]+)"); + + TOKEN(REGISTER, "([cfstr]{1,2}[[:digit:]]{1,2})|(sp|psw|pc|rp|dp|ret0|ret1|rctr|pidr1|pidr2|pidr3|ccr|sar|iva|eiem|itmr|pcsq|pcoq|iir|isr|ior|ipsw|eirr|flags)"); + + TOKEN(MNEMONIC, "([[:alpha:]]+[[:alnum:]\\,]*([[:alpha:]]+|(<|>|=)+))"); + + TOKEN(SEPARATOR, "([[:blank:]]+)|([,;\\(\\)\\{\\}:])"); + + TOKEN(NUMBER, "([[:digit:]]+)"); + + return pvec; +} + +static bool init(void **u) { + if (!u) { + return false; + } + // u = RzAsm.plugin_data + RzAsmHPPAContext *ctx = NULL; + if (*u) { + rz_mem_memzero(*u, sizeof(RzAsmHPPAContext)); + ctx = *u; + } else { + ctx = RZ_NEW0(RzAsmHPPAContext); + if (!ctx) { + return false; + } + *u = ctx; + } + ctx->token_patterns = get_token_patterns(); + rz_asm_compile_token_patterns(ctx->token_patterns); + return true; +} + +static bool fini(void *u) { + if (!u) { + return true; + } + RzAsmHPPAContext *ctx = u; + cs_close(&ctx->h); + rz_pvector_free(ctx->token_patterns); + free(u); + return true; +} + +RzAsmPlugin rz_asm_plugin_hppa_cs = { + .name = "hppa", + .arch = "hppa", + .author = "xvilka", + .license = "LGPL3", + .bits = 32 | 64, + .endian = RZ_SYS_ENDIAN_LITTLE | RZ_SYS_ENDIAN_BIG, + .cpus = "hppa1.1,hppa2.0,hppa2.0w", + .desc = "Capstone HP PA-RISC disassembler", + .disassemble = &disassemble, + .init = &init, + .fini = &fini, +}; + +#ifndef RZ_PLUGIN_INCORE +RZ_API RzLibStruct rizin_plugin = { + .type = RZ_LIB_TYPE_ASM, + .data = &rz_asm_plugin_hppa_cs, + .version = RZ_VERSION +}; +#endif diff --git a/librz/bin/format/elf/elf_imports.c b/librz/bin/format/elf/elf_imports.c index ac27867f029..371efb9bcc3 100644 --- a/librz/bin/format/elf/elf_imports.c +++ b/librz/bin/format/elf/elf_imports.c @@ -57,6 +57,26 @@ static ut64 get_import_addr_mips(ELFOBJ *bin, RzBinElfReloc *rel) { return plt_addr; } +static ut64 get_import_addr_hppa(ELFOBJ *bin, RzBinElfReloc *rel) { + ut64 got_addr = 0; + + if (!Elf_(rz_bin_elf_get_dt_info)(bin, DT_PLTGOT, &got_addr)) { + return UT64_MAX; + } + + RZ_LOG_ERROR("GOT_ADDR = 0x%08" PFMT64x " for REL @ 0x%08" PFMT64x "\n", got_addr, rel->vaddr); + + ut64 plt_addr = get_got_entry(bin, rel); + if (plt_addr == UT64_MAX) { + return UT64_MAX; + } + + RZ_LOG_ERROR("PLT_ADDR = 0x%08" PFMT64x " for REL @ 0x%08" PFMT64x "\n", plt_addr, rel->vaddr); + + ut64 pos = COMPUTE_PLTGOT_POSITION(rel, got_addr, 0x2); + return plt_addr + pos * 16; +} + /** * \brief Determines and returns the import address for the given relocation * for the Hexagon architecture. @@ -306,6 +326,8 @@ static ut64 get_import_addr_aux(ELFOBJ *bin, RzBinElfReloc *reloc) { return get_import_addr_alpha(bin, reloc); case EM_MIPS: // MIPS32 BIG ENDIAN relocs return get_import_addr_mips(bin, reloc); + case EM_PARISC: + return get_import_addr_hppa(bin, reloc); case EM_RISCV: return get_import_addr_riscv(bin, reloc); case EM_SPARC: diff --git a/librz/bin/format/elf/elf_info.c b/librz/bin/format/elf/elf_info.c index dd01264f9d0..f8dbb5be8a3 100644 --- a/librz/bin/format/elf/elf_info.c +++ b/librz/bin/format/elf/elf_info.c @@ -32,7 +32,7 @@ struct class_translation { const char *name; }; -struct cpu_mips_translation { +struct cpu_arch_translation { Elf_(Word) arch; const char *name; }; @@ -230,7 +230,7 @@ static const struct class_translation class_translation_table[] = { { ELFCLASS64, "ELF64" } }; -static const struct cpu_mips_translation cpu_mips_translation_table[] = { +static const struct cpu_arch_translation cpu_mips_translation_table[] = { { EF_MIPS_ARCH_1, "mips1" }, { EF_MIPS_ARCH_2, "mips2" }, { EF_MIPS_ARCH_3, "mips3" }, @@ -242,6 +242,12 @@ static const struct cpu_mips_translation cpu_mips_translation_table[] = { { EF_MIPS_ARCH_64R2, "mips64r2" }, }; +static const struct cpu_arch_translation cpu_hppa_translation_table[] = { + { EFA_PARISC_1_0, "hppa1.0" }, + { EFA_PARISC_1_1, "hppa1.1" }, + { EFA_PARISC_2_0, "hppa2.0" }, +}; + static const struct arch_translation arch_translation_table[] = { { EM_ALPHA, "alpha" }, { EM_ARC, "arc" }, @@ -848,6 +854,18 @@ static char *get_cpu_mips(ELFOBJ *bin) { return rz_str_dup(" Unknown mips ISA"); } +static char *get_cpu_hppa(ELFOBJ *bin) { + Elf_(Word) hppa_arch = bin->ehdr.e_flags & EF_PARISC_ARCH; + + for (size_t i = 0; i < RZ_ARRAY_SIZE(cpu_hppa_translation_table); i++) { + if (hppa_arch == cpu_hppa_translation_table[i].arch) { + return strdup(cpu_hppa_translation_table[i].name); + } + } + + return strdup(" Unknown HP PARISC ISA"); +} + static bool is_elf_class64(ELFOBJ *bin) { return bin->ehdr.e_ident[EI_CLASS] == ELFCLASS64; } @@ -1472,8 +1490,13 @@ RZ_OWN char *Elf_(rz_bin_elf_get_cpu)(RZ_NONNULL ELFOBJ *bin) { return NULL; } - if (bin->ehdr.e_machine == EM_MIPS) { + switch (bin->ehdr.e_machine) { + case EM_MIPS: return get_cpu_mips(bin); + case EM_PARISC: + return get_cpu_hppa(bin); + default: + break; } return NULL; diff --git a/librz/bin/p/bin_elf.inc b/librz/bin/p/bin_elf.inc index 5f330b736d5..05ad961284e 100644 --- a/librz/bin/p/bin_elf.inc +++ b/librz/bin/p/bin_elf.inc @@ -1382,6 +1382,8 @@ static void patch_reloc(struct Elf_(rz_bin_elf_obj_t) * obj, RzBinElfReloc *rel, RZ_LOG_WARN("Reloc type %d for DEC Alpha is not implemented yet.\n", rel->type); break; } + default: + RZ_LOG_DEBUG("Unimplemented relocation type %d for the machine %d\n", rel->type, e_machine); break; } } @@ -1612,6 +1614,20 @@ static RzBinReloc *reloc_convert(ELFOBJ *bin, RzBinElfReloc *rel, ut64 GOT) { RZ_LOG_WARN("unimplemented ELF/Alpha reloc type %d\n", rel->type); break; } + break; + case EM_PARISC: + switch (rel->type) { + case RZ_PARISC_NONE: break; + case RZ_PARISC_DIR32: ADD(32, 0, "R_PARISC_DIR32"); + case RZ_PARISC_DIR64: ADD(64, 0, "R_PARISC_DIR64"); + case RZ_PARISC_COPY: ADD(64, 0, "R_PARISC_COPY"); // copy symbol at runtime + case RZ_PARISC_IPLT: ADD(64, -P, "R_PARISC_IPLT"); + case RZ_PARISC_EPLT: ADD(64, -P, "R_PARISC_EPLT"); + default: + RZ_LOG_WARN("unimplemented ELF/HPPA (PARISC) reloc type %d\n", rel->type); + break; + } + break; default: break; } diff --git a/test/db/analysis/hppa b/test/db/analysis/hppa new file mode 100644 index 00000000000..c58d73ad734 --- /dev/null +++ b/test/db/analysis/hppa @@ -0,0 +1,11 @@ +NAME=hppa analysis graph +FILE=bins/hppa/elf-Linux-hppa-bash +CMDS=<