1 1.1 skrll /* ppc-dis.c -- Disassemble PowerPC instructions 2 1.13 christos Copyright (C) 1994-2026 Free Software Foundation, Inc. 3 1.1 skrll Written by Ian Lance Taylor, Cygnus Support 4 1.1 skrll 5 1.1 skrll This file is part of the GNU opcodes library. 6 1.1 skrll 7 1.1 skrll This library is free software; you can redistribute it and/or modify 8 1.1 skrll it under the terms of the GNU General Public License as published by 9 1.1 skrll the Free Software Foundation; either version 3, or (at your option) 10 1.1 skrll any later version. 11 1.1 skrll 12 1.1 skrll It is distributed in the hope that it will be useful, but WITHOUT 13 1.1 skrll ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14 1.1 skrll or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 15 1.1 skrll License for more details. 16 1.1 skrll 17 1.1 skrll You should have received a copy of the GNU General Public License 18 1.1 skrll along with this file; see the file COPYING. If not, write to the 19 1.1 skrll Free Software Foundation, 51 Franklin Street - Fifth Floor, Boston, 20 1.1 skrll MA 02110-1301, USA. */ 21 1.1 skrll 22 1.4 christos #include "sysdep.h" 23 1.1 skrll #include <stdio.h> 24 1.7 christos #include "disassemble.h" 25 1.4 christos #include "elf-bfd.h" 26 1.4 christos #include "elf/ppc.h" 27 1.3 christos #include "opintl.h" 28 1.1 skrll #include "opcode/ppc.h" 29 1.7 christos #include "libiberty.h" 30 1.1 skrll 31 1.1 skrll /* This file provides several disassembler functions, all of which use 32 1.1 skrll the disassembler interface defined in dis-asm.h. Several functions 33 1.1 skrll are provided because this file handles disassembly for the PowerPC 34 1.1 skrll in both big and little endian mode and also for the POWER (RS/6000) 35 1.1 skrll chip. */ 36 1.1 skrll static int print_insn_powerpc (bfd_vma, struct disassemble_info *, int, 37 1.1 skrll ppc_cpu_t); 38 1.1 skrll 39 1.1 skrll struct dis_private 40 1.1 skrll { 41 1.1 skrll /* Stash the result of parsing disassembler_options here. */ 42 1.1 skrll ppc_cpu_t dialect; 43 1.10 christos 44 1.10 christos /* .got and .plt sections. NAME is set to NULL if not present. */ 45 1.10 christos struct sec_buf { 46 1.10 christos asection *sec; 47 1.10 christos bfd_byte *buf; 48 1.10 christos const char *name; 49 1.10 christos } special[2]; 50 1.9 christos }; 51 1.1 skrll 52 1.10 christos static inline struct dis_private * 53 1.10 christos private_data (struct disassemble_info *info) 54 1.10 christos { 55 1.10 christos return (struct dis_private *) info->private_data; 56 1.10 christos } 57 1.1 skrll 58 1.3 christos struct ppc_mopt { 59 1.7 christos /* Option string, without -m or -M prefix. */ 60 1.3 christos const char *opt; 61 1.7 christos /* CPU option flags. */ 62 1.3 christos ppc_cpu_t cpu; 63 1.7 christos /* Flags that should stay on, even when combined with another cpu 64 1.7 christos option. This should only be used for generic options like 65 1.7 christos "-many" or "-maltivec" where it is reasonable to add some 66 1.7 christos capability to another cpu selection. The added flags are sticky 67 1.7 christos so that, for example, "-many -me500" and "-me500 -many" result in 68 1.7 christos the same assembler or disassembler behaviour. Do not use 69 1.7 christos "sticky" for specific cpus, as this will prevent that cpu's flags 70 1.7 christos from overriding the defaults set in powerpc_init_dialect or a 71 1.7 christos prior -m option. */ 72 1.3 christos ppc_cpu_t sticky; 73 1.3 christos }; 74 1.3 christos 75 1.13 christos static const struct ppc_mopt ppc_opts[] = { 76 1.6 christos { "403", PPC_OPCODE_PPC | PPC_OPCODE_403, 77 1.3 christos 0 }, 78 1.6 christos { "405", PPC_OPCODE_PPC | PPC_OPCODE_403 | PPC_OPCODE_405, 79 1.3 christos 0 }, 80 1.3 christos { "440", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_440 81 1.3 christos | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI), 82 1.3 christos 0 }, 83 1.3 christos { "464", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_440 84 1.3 christos | PPC_OPCODE_ISEL | PPC_OPCODE_RFMCI), 85 1.3 christos 0 }, 86 1.7 christos { "476", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_476 87 1.7 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5), 88 1.3 christos 0 }, 89 1.6 christos { "601", PPC_OPCODE_PPC | PPC_OPCODE_601, 90 1.3 christos 0 }, 91 1.6 christos { "603", PPC_OPCODE_PPC, 92 1.3 christos 0 }, 93 1.6 christos { "604", PPC_OPCODE_PPC, 94 1.3 christos 0 }, 95 1.6 christos { "620", PPC_OPCODE_PPC | PPC_OPCODE_64, 96 1.3 christos 0 }, 97 1.6 christos { "7400", PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC, 98 1.3 christos 0 }, 99 1.6 christos { "7410", PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC, 100 1.3 christos 0 }, 101 1.6 christos { "7450", PPC_OPCODE_PPC | PPC_OPCODE_7450 | PPC_OPCODE_ALTIVEC, 102 1.3 christos 0 }, 103 1.6 christos { "7455", PPC_OPCODE_PPC | PPC_OPCODE_ALTIVEC, 104 1.3 christos 0 }, 105 1.6 christos { "750cl", PPC_OPCODE_PPC | PPC_OPCODE_750 | PPC_OPCODE_PPCPS 106 1.3 christos , 0 }, 107 1.9 christos { "gekko", PPC_OPCODE_PPC | PPC_OPCODE_750 | PPC_OPCODE_PPCPS 108 1.9 christos , 0 }, 109 1.9 christos { "broadway", PPC_OPCODE_PPC | PPC_OPCODE_750 | PPC_OPCODE_PPCPS 110 1.9 christos , 0 }, 111 1.6 christos { "821", PPC_OPCODE_PPC | PPC_OPCODE_860, 112 1.5 christos 0 }, 113 1.6 christos { "850", PPC_OPCODE_PPC | PPC_OPCODE_860, 114 1.5 christos 0 }, 115 1.6 christos { "860", PPC_OPCODE_PPC | PPC_OPCODE_860, 116 1.5 christos 0 }, 117 1.3 christos { "a2", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_POWER4 118 1.3 christos | PPC_OPCODE_POWER5 | PPC_OPCODE_CACHELCK | PPC_OPCODE_64 119 1.3 christos | PPC_OPCODE_A2), 120 1.3 christos 0 }, 121 1.6 christos { "altivec", PPC_OPCODE_PPC, 122 1.7 christos PPC_OPCODE_ALTIVEC }, 123 1.7 christos { "any", PPC_OPCODE_PPC, 124 1.3 christos PPC_OPCODE_ANY }, 125 1.6 christos { "booke", PPC_OPCODE_PPC | PPC_OPCODE_BOOKE, 126 1.3 christos 0 }, 127 1.6 christos { "booke32", PPC_OPCODE_PPC | PPC_OPCODE_BOOKE, 128 1.3 christos 0 }, 129 1.3 christos { "cell", (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4 130 1.3 christos | PPC_OPCODE_CELL | PPC_OPCODE_ALTIVEC), 131 1.3 christos 0 }, 132 1.6 christos { "com", PPC_OPCODE_COMMON, 133 1.3 christos 0 }, 134 1.11 christos { "e200z2", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_LSP 135 1.7 christos | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK 136 1.7 christos | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI 137 1.7 christos | PPC_OPCODE_E500 | PPC_OPCODE_VLE | PPC_OPCODE_E200Z4 138 1.11 christos | PPC_OPCODE_EFS2), 139 1.11 christos 0 }, 140 1.11 christos { "e200z4", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE 141 1.11 christos | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK 142 1.11 christos | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI 143 1.11 christos | PPC_OPCODE_E500 | PPC_OPCODE_VLE | PPC_OPCODE_E200Z4 144 1.11 christos | PPC_OPCODE_EFS2), 145 1.7 christos 0 }, 146 1.6 christos { "e300", PPC_OPCODE_PPC | PPC_OPCODE_E300, 147 1.3 christos 0 }, 148 1.3 christos { "e500", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE 149 1.3 christos | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK 150 1.3 christos | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI 151 1.3 christos | PPC_OPCODE_E500), 152 1.3 christos 0 }, 153 1.3 christos { "e500mc", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL 154 1.3 christos | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI 155 1.3 christos | PPC_OPCODE_E500MC), 156 1.3 christos 0 }, 157 1.3 christos { "e500mc64", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL 158 1.3 christos | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI 159 1.3 christos | PPC_OPCODE_E500MC | PPC_OPCODE_64 | PPC_OPCODE_POWER5 160 1.3 christos | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7), 161 1.3 christos 0 }, 162 1.4 christos { "e5500", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL 163 1.4 christos | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI 164 1.4 christos | PPC_OPCODE_E500MC | PPC_OPCODE_64 | PPC_OPCODE_POWER4 165 1.7 christos | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7), 166 1.4 christos 0 }, 167 1.4 christos { "e6500", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_ISEL 168 1.4 christos | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI 169 1.4 christos | PPC_OPCODE_E500MC | PPC_OPCODE_64 | PPC_OPCODE_ALTIVEC 170 1.7 christos | PPC_OPCODE_E6500 | PPC_OPCODE_TMR | PPC_OPCODE_POWER4 171 1.4 christos | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_POWER7), 172 1.4 christos 0 }, 173 1.3 christos { "e500x2", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE 174 1.3 christos | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK 175 1.3 christos | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI 176 1.3 christos | PPC_OPCODE_E500), 177 1.3 christos 0 }, 178 1.6 christos { "efs", PPC_OPCODE_PPC | PPC_OPCODE_EFS, 179 1.3 christos 0 }, 180 1.7 christos { "efs2", PPC_OPCODE_PPC | PPC_OPCODE_EFS | PPC_OPCODE_EFS2, 181 1.7 christos 0 }, 182 1.11 christos { "lsp", PPC_OPCODE_PPC, 183 1.11 christos PPC_OPCODE_LSP }, 184 1.6 christos { "power4", PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4, 185 1.3 christos 0 }, 186 1.3 christos { "power5", (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4 187 1.3 christos | PPC_OPCODE_POWER5), 188 1.3 christos 0 }, 189 1.3 christos { "power6", (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4 190 1.3 christos | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC), 191 1.3 christos 0 }, 192 1.3 christos { "power7", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64 193 1.3 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 194 1.3 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX), 195 1.3 christos 0 }, 196 1.5 christos { "power8", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64 197 1.5 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 198 1.7 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 199 1.7 christos | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX), 200 1.5 christos 0 }, 201 1.5 christos { "power9", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64 202 1.5 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 203 1.5 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 204 1.7 christos | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX), 205 1.5 christos 0 }, 206 1.10 christos { "power10", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64 207 1.10 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 208 1.10 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 209 1.10 christos | PPC_OPCODE_POWER10 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX), 210 1.10 christos 0 }, 211 1.12 christos { "power11", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64 212 1.12 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 213 1.12 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 214 1.12 christos | PPC_OPCODE_POWER10 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX), 215 1.12 christos 0 }, 216 1.11 christos { "libresoc",(PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64 217 1.11 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 218 1.11 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 219 1.11 christos | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX | PPC_OPCODE_SVP64), 220 1.11 christos 0 }, 221 1.9 christos { "future", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64 222 1.9 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 223 1.9 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 224 1.11 christos | PPC_OPCODE_POWER10 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX 225 1.11 christos | PPC_OPCODE_FUTURE), 226 1.9 christos 0 }, 227 1.6 christos { "ppc", PPC_OPCODE_PPC, 228 1.3 christos 0 }, 229 1.6 christos { "ppc32", PPC_OPCODE_PPC, 230 1.3 christos 0 }, 231 1.7 christos { "32", PPC_OPCODE_PPC, 232 1.7 christos 0 }, 233 1.6 christos { "ppc64", PPC_OPCODE_PPC | PPC_OPCODE_64, 234 1.3 christos 0 }, 235 1.7 christos { "64", PPC_OPCODE_PPC | PPC_OPCODE_64, 236 1.7 christos 0 }, 237 1.6 christos { "ppc64bridge", PPC_OPCODE_PPC | PPC_OPCODE_64_BRIDGE, 238 1.3 christos 0 }, 239 1.6 christos { "ppcps", PPC_OPCODE_PPC | PPC_OPCODE_PPCPS, 240 1.3 christos 0 }, 241 1.6 christos { "pwr", PPC_OPCODE_POWER, 242 1.3 christos 0 }, 243 1.6 christos { "pwr2", PPC_OPCODE_POWER | PPC_OPCODE_POWER2, 244 1.3 christos 0 }, 245 1.6 christos { "pwr4", PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4, 246 1.3 christos 0 }, 247 1.3 christos { "pwr5", (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4 248 1.3 christos | PPC_OPCODE_POWER5), 249 1.3 christos 0 }, 250 1.3 christos { "pwr5x", (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4 251 1.3 christos | PPC_OPCODE_POWER5), 252 1.3 christos 0 }, 253 1.3 christos { "pwr6", (PPC_OPCODE_PPC | PPC_OPCODE_64 | PPC_OPCODE_POWER4 254 1.3 christos | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 | PPC_OPCODE_ALTIVEC), 255 1.3 christos 0 }, 256 1.3 christos { "pwr7", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64 257 1.3 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 258 1.3 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX), 259 1.3 christos 0 }, 260 1.5 christos { "pwr8", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64 261 1.5 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 262 1.7 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 263 1.7 christos | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX), 264 1.5 christos 0 }, 265 1.5 christos { "pwr9", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64 266 1.5 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 267 1.5 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 268 1.7 christos | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX), 269 1.5 christos 0 }, 270 1.10 christos { "pwr10", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64 271 1.10 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 272 1.10 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 273 1.10 christos | PPC_OPCODE_POWER10 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX), 274 1.10 christos 0 }, 275 1.12 christos { "pwr11", (PPC_OPCODE_PPC | PPC_OPCODE_ISEL | PPC_OPCODE_64 276 1.12 christos | PPC_OPCODE_POWER4 | PPC_OPCODE_POWER5 | PPC_OPCODE_POWER6 277 1.12 christos | PPC_OPCODE_POWER7 | PPC_OPCODE_POWER8 | PPC_OPCODE_POWER9 278 1.12 christos | PPC_OPCODE_POWER10 | PPC_OPCODE_ALTIVEC | PPC_OPCODE_VSX), 279 1.12 christos 0 }, 280 1.6 christos { "pwrx", PPC_OPCODE_POWER | PPC_OPCODE_POWER2, 281 1.3 christos 0 }, 282 1.7 christos { "raw", PPC_OPCODE_PPC, 283 1.7 christos PPC_OPCODE_RAW }, 284 1.6 christos { "spe", PPC_OPCODE_PPC | PPC_OPCODE_EFS, 285 1.3 christos PPC_OPCODE_SPE }, 286 1.7 christos { "spe2", PPC_OPCODE_PPC | PPC_OPCODE_EFS | PPC_OPCODE_EFS2 | PPC_OPCODE_SPE, 287 1.7 christos PPC_OPCODE_SPE2 }, 288 1.3 christos { "titan", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_PMR 289 1.3 christos | PPC_OPCODE_RFMCI | PPC_OPCODE_TITAN), 290 1.3 christos 0 }, 291 1.11 christos { "vle", (PPC_OPCODE_PPC | PPC_OPCODE_BOOKE | PPC_OPCODE_SPE 292 1.6 christos | PPC_OPCODE_ISEL | PPC_OPCODE_EFS | PPC_OPCODE_BRLOCK 293 1.6 christos | PPC_OPCODE_PMR | PPC_OPCODE_CACHELCK | PPC_OPCODE_RFMCI 294 1.11 christos | PPC_OPCODE_EFS2 | PPC_OPCODE_SPE2), 295 1.4 christos PPC_OPCODE_VLE }, 296 1.6 christos { "vsx", PPC_OPCODE_PPC, 297 1.7 christos PPC_OPCODE_VSX }, 298 1.3 christos }; 299 1.3 christos 300 1.4 christos /* Switch between Booke and VLE dialects for interlinked dumps. */ 301 1.4 christos static ppc_cpu_t 302 1.4 christos get_powerpc_dialect (struct disassemble_info *info) 303 1.4 christos { 304 1.4 christos ppc_cpu_t dialect = 0; 305 1.4 christos 306 1.9 christos if (info->private_data) 307 1.10 christos dialect = private_data (info)->dialect; 308 1.4 christos 309 1.4 christos /* Disassemble according to the section headers flags for VLE-mode. */ 310 1.4 christos if (dialect & PPC_OPCODE_VLE 311 1.7 christos && info->section != NULL && info->section->owner != NULL 312 1.4 christos && bfd_get_flavour (info->section->owner) == bfd_target_elf_flavour 313 1.4 christos && elf_object_id (info->section->owner) == PPC32_ELF_DATA 314 1.4 christos && (elf_section_flags (info->section) & SHF_PPC_VLE) != 0) 315 1.4 christos return dialect; 316 1.4 christos else 317 1.4 christos return dialect & ~ PPC_OPCODE_VLE; 318 1.4 christos } 319 1.4 christos 320 1.3 christos /* Handle -m and -M options that set cpu type, and .machine arg. */ 321 1.3 christos 322 1.3 christos ppc_cpu_t 323 1.4 christos ppc_parse_cpu (ppc_cpu_t ppc_cpu, ppc_cpu_t *sticky, const char *arg) 324 1.3 christos { 325 1.3 christos unsigned int i; 326 1.3 christos 327 1.7 christos for (i = 0; i < ARRAY_SIZE (ppc_opts); i++) 328 1.13 christos if (strcmp (ppc_opts[i].opt, arg) == 0) 329 1.3 christos { 330 1.3 christos if (ppc_opts[i].sticky) 331 1.3 christos { 332 1.4 christos *sticky |= ppc_opts[i].sticky; 333 1.4 christos if ((ppc_cpu & ~*sticky) != 0) 334 1.3 christos break; 335 1.3 christos } 336 1.3 christos ppc_cpu = ppc_opts[i].cpu; 337 1.3 christos break; 338 1.3 christos } 339 1.7 christos if (i >= ARRAY_SIZE (ppc_opts)) 340 1.3 christos return 0; 341 1.3 christos 342 1.11 christos /* SPE and LSP are mutually exclusive, don't allow them both in 343 1.11 christos sticky options. However do allow them both in ppc_cpu, so that 344 1.11 christos for example, -mvle -mlsp enables both SPE and LSP for assembly. */ 345 1.11 christos if ((ppc_opts[i].sticky & PPC_OPCODE_LSP) != 0) 346 1.11 christos *sticky &= ~(PPC_OPCODE_SPE | PPC_OPCODE_SPE2); 347 1.11 christos else if ((ppc_opts[i].sticky & (PPC_OPCODE_SPE | PPC_OPCODE_SPE2)) != 0) 348 1.11 christos *sticky &= ~PPC_OPCODE_LSP; 349 1.4 christos ppc_cpu |= *sticky; 350 1.11 christos 351 1.3 christos return ppc_cpu; 352 1.3 christos } 353 1.3 christos 354 1.13 christos struct ppc_parse_data 355 1.13 christos { 356 1.13 christos ppc_cpu_t dialect; 357 1.13 christos ppc_cpu_t sticky; 358 1.13 christos }; 359 1.13 christos 360 1.13 christos static bool 361 1.13 christos ppc_parse_option (const char *opt, void *data) 362 1.13 christos { 363 1.13 christos struct ppc_parse_data *res = data; 364 1.13 christos ppc_cpu_t new_cpu; 365 1.13 christos 366 1.13 christos if (strcmp (opt, "32") == 0) 367 1.13 christos res->dialect &= ~(ppc_cpu_t) PPC_OPCODE_64; 368 1.13 christos else if (strcmp (opt, "64") == 0) 369 1.13 christos res->dialect |= PPC_OPCODE_64; 370 1.13 christos else if ((new_cpu = ppc_parse_cpu (res->dialect, &res->sticky, opt)) != 0) 371 1.13 christos res->dialect = new_cpu; 372 1.13 christos else 373 1.13 christos /* xgettext: c-format */ 374 1.13 christos opcodes_error_handler (_("warning: ignoring unknown -M%s option"), opt); 375 1.13 christos return true; 376 1.13 christos } 377 1.13 christos 378 1.3 christos /* Determine which set of machines to disassemble for. */ 379 1.1 skrll 380 1.4 christos static void 381 1.1 skrll powerpc_init_dialect (struct disassemble_info *info) 382 1.1 skrll { 383 1.13 christos struct ppc_parse_data out = { 0, 0 }; 384 1.11 christos struct dis_private *priv = calloc (1, sizeof (*priv)); 385 1.1 skrll 386 1.1 skrll if (priv == NULL) 387 1.9 christos return; 388 1.4 christos 389 1.4 christos switch (info->mach) 390 1.4 christos { 391 1.4 christos case bfd_mach_ppc_403: 392 1.4 christos case bfd_mach_ppc_403gc: 393 1.13 christos out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "403"); 394 1.4 christos break; 395 1.4 christos case bfd_mach_ppc_405: 396 1.13 christos out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "405"); 397 1.4 christos break; 398 1.4 christos case bfd_mach_ppc_601: 399 1.13 christos out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "601"); 400 1.4 christos break; 401 1.9 christos case bfd_mach_ppc_750: 402 1.13 christos out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "750cl"); 403 1.9 christos break; 404 1.4 christos case bfd_mach_ppc_a35: 405 1.4 christos case bfd_mach_ppc_rs64ii: 406 1.4 christos case bfd_mach_ppc_rs64iii: 407 1.13 christos out.dialect = (ppc_parse_cpu (out.dialect, &out.sticky, "pwr2") 408 1.13 christos | PPC_OPCODE_64); 409 1.4 christos break; 410 1.4 christos case bfd_mach_ppc_e500: 411 1.13 christos out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "e500"); 412 1.4 christos break; 413 1.4 christos case bfd_mach_ppc_e500mc: 414 1.13 christos out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "e500mc"); 415 1.4 christos break; 416 1.4 christos case bfd_mach_ppc_e500mc64: 417 1.13 christos out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "e500mc64"); 418 1.4 christos break; 419 1.4 christos case bfd_mach_ppc_e5500: 420 1.13 christos out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "e5500"); 421 1.4 christos break; 422 1.4 christos case bfd_mach_ppc_e6500: 423 1.13 christos out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "e6500"); 424 1.4 christos break; 425 1.4 christos case bfd_mach_ppc_titan: 426 1.13 christos out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "titan"); 427 1.4 christos break; 428 1.4 christos case bfd_mach_ppc_vle: 429 1.13 christos out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "vle"); 430 1.4 christos break; 431 1.4 christos default: 432 1.8 christos if (info->arch == bfd_arch_powerpc) 433 1.13 christos out.dialect = (ppc_parse_cpu (out.dialect, &out.sticky, "power11") 434 1.13 christos | PPC_OPCODE_ANY); 435 1.8 christos else 436 1.13 christos out.dialect = ppc_parse_cpu (out.dialect, &out.sticky, "pwr"); 437 1.7 christos break; 438 1.4 christos } 439 1.1 skrll 440 1.13 christos for_each_disassembler_option (info, ppc_parse_option, &out); 441 1.1 skrll 442 1.4 christos info->private_data = priv; 443 1.13 christos private_data (info)->dialect = out.dialect; 444 1.4 christos } 445 1.4 christos 446 1.8 christos #define PPC_OPCD_SEGS (1 + PPC_OP (-1)) 447 1.8 christos static unsigned short powerpc_opcd_indices[PPC_OPCD_SEGS + 1]; 448 1.9 christos #define PREFIX_OPCD_SEGS (1 + PPC_PREFIX_SEG (-1)) 449 1.9 christos static unsigned short prefix_opcd_indices[PREFIX_OPCD_SEGS + 1]; 450 1.8 christos #define VLE_OPCD_SEGS (1 + VLE_OP_TO_SEG (VLE_OP (-1, 0xffff))) 451 1.8 christos static unsigned short vle_opcd_indices[VLE_OPCD_SEGS + 1]; 452 1.11 christos #define LSP_OPCD_SEGS (1 + LSP_OP_TO_SEG (-1)) 453 1.11 christos static unsigned short lsp_opcd_indices[LSP_OPCD_SEGS + 1]; 454 1.8 christos #define SPE2_OPCD_SEGS (1 + SPE2_XOP_TO_SEG (SPE2_XOP (-1))) 455 1.8 christos static unsigned short spe2_opcd_indices[SPE2_OPCD_SEGS + 1]; 456 1.4 christos 457 1.10 christos static bool 458 1.10 christos ppc_symbol_is_valid (asymbol *sym, 459 1.10 christos struct disassemble_info *info ATTRIBUTE_UNUSED) 460 1.10 christos { 461 1.10 christos elf_symbol_type * est; 462 1.10 christos 463 1.10 christos if (sym == NULL) 464 1.10 christos return false; 465 1.10 christos 466 1.10 christos est = elf_symbol_from (sym); 467 1.10 christos 468 1.10 christos /* Ignore ELF hidden, local, no-type symbols. 469 1.10 christos These are generated by annobin. */ 470 1.10 christos if (est != NULL 471 1.10 christos && ELF_ST_VISIBILITY (est->internal_elf_sym.st_other) == STV_HIDDEN 472 1.10 christos && ELF_ST_BIND (est->internal_elf_sym.st_info) == STB_LOCAL 473 1.10 christos && ELF_ST_TYPE (est->internal_elf_sym.st_info) == STT_NOTYPE) 474 1.10 christos return false; 475 1.10 christos 476 1.10 christos return true; 477 1.10 christos } 478 1.10 christos 479 1.4 christos /* Calculate opcode table indices to speed up disassembly, 480 1.4 christos and init dialect. */ 481 1.4 christos 482 1.4 christos void 483 1.4 christos disassemble_init_powerpc (struct disassemble_info *info) 484 1.4 christos { 485 1.10 christos info->symbol_is_valid = ppc_symbol_is_valid; 486 1.10 christos 487 1.5 christos if (powerpc_opcd_indices[PPC_OPCD_SEGS] == 0) 488 1.4 christos { 489 1.8 christos unsigned seg, idx, op; 490 1.4 christos 491 1.8 christos /* PPC opcodes */ 492 1.8 christos for (seg = 0, idx = 0; seg <= PPC_OPCD_SEGS; seg++) 493 1.7 christos { 494 1.8 christos powerpc_opcd_indices[seg] = idx; 495 1.8 christos for (; idx < powerpc_num_opcodes; idx++) 496 1.8 christos if (seg < PPC_OP (powerpc_opcodes[idx].opcode)) 497 1.8 christos break; 498 1.7 christos } 499 1.4 christos 500 1.9 christos /* 64-bit prefix opcodes */ 501 1.9 christos for (seg = 0, idx = 0; seg <= PREFIX_OPCD_SEGS; seg++) 502 1.9 christos { 503 1.9 christos prefix_opcd_indices[seg] = idx; 504 1.9 christos for (; idx < prefix_num_opcodes; idx++) 505 1.9 christos if (seg < PPC_PREFIX_SEG (prefix_opcodes[idx].opcode)) 506 1.9 christos break; 507 1.9 christos } 508 1.9 christos 509 1.8 christos /* VLE opcodes */ 510 1.8 christos for (seg = 0, idx = 0; seg <= VLE_OPCD_SEGS; seg++) 511 1.7 christos { 512 1.8 christos vle_opcd_indices[seg] = idx; 513 1.8 christos for (; idx < vle_num_opcodes; idx++) 514 1.8 christos { 515 1.8 christos op = VLE_OP (vle_opcodes[idx].opcode, vle_opcodes[idx].mask); 516 1.8 christos if (seg < VLE_OP_TO_SEG (op)) 517 1.8 christos break; 518 1.8 christos } 519 1.7 christos } 520 1.1 skrll 521 1.11 christos /* LSP opcodes */ 522 1.11 christos for (seg = 0, idx = 0; seg <= LSP_OPCD_SEGS; seg++) 523 1.11 christos { 524 1.11 christos lsp_opcd_indices[seg] = idx; 525 1.11 christos for (; idx < lsp_num_opcodes; idx++) 526 1.11 christos if (seg < LSP_OP_TO_SEG (lsp_opcodes[idx].opcode)) 527 1.11 christos break; 528 1.11 christos } 529 1.11 christos 530 1.8 christos /* SPE2 opcodes */ 531 1.8 christos for (seg = 0, idx = 0; seg <= SPE2_OPCD_SEGS; seg++) 532 1.7 christos { 533 1.8 christos spe2_opcd_indices[seg] = idx; 534 1.8 christos for (; idx < spe2_num_opcodes; idx++) 535 1.8 christos { 536 1.8 christos op = SPE2_XOP (spe2_opcodes[idx].opcode); 537 1.8 christos if (seg < SPE2_XOP_TO_SEG (op)) 538 1.8 christos break; 539 1.8 christos } 540 1.7 christos } 541 1.7 christos } 542 1.7 christos 543 1.8 christos powerpc_init_dialect (info); 544 1.10 christos if (info->private_data != NULL) 545 1.10 christos { 546 1.10 christos private_data (info)->special[0].name = ".got"; 547 1.10 christos private_data (info)->special[1].name = ".plt"; 548 1.10 christos } 549 1.1 skrll } 550 1.1 skrll 551 1.12 christos void 552 1.12 christos disassemble_free_powerpc (struct disassemble_info *info) 553 1.12 christos { 554 1.12 christos if (info->private_data != NULL) 555 1.12 christos { 556 1.12 christos free (private_data (info)->special[0].buf); 557 1.12 christos free (private_data (info)->special[1].buf); 558 1.12 christos } 559 1.12 christos } 560 1.12 christos 561 1.1 skrll /* Print a big endian PowerPC instruction. */ 562 1.1 skrll 563 1.1 skrll int 564 1.1 skrll print_insn_big_powerpc (bfd_vma memaddr, struct disassemble_info *info) 565 1.1 skrll { 566 1.4 christos return print_insn_powerpc (memaddr, info, 1, get_powerpc_dialect (info)); 567 1.1 skrll } 568 1.1 skrll 569 1.1 skrll /* Print a little endian PowerPC instruction. */ 570 1.1 skrll 571 1.1 skrll int 572 1.1 skrll print_insn_little_powerpc (bfd_vma memaddr, struct disassemble_info *info) 573 1.1 skrll { 574 1.4 christos return print_insn_powerpc (memaddr, info, 0, get_powerpc_dialect (info)); 575 1.1 skrll } 576 1.1 skrll 577 1.1 skrll /* Extract the operand value from the PowerPC or POWER instruction. */ 578 1.1 skrll 579 1.7 christos static int64_t 580 1.1 skrll operand_value_powerpc (const struct powerpc_operand *operand, 581 1.7 christos uint64_t insn, ppc_cpu_t dialect) 582 1.1 skrll { 583 1.7 christos int64_t value; 584 1.9 christos int invalid = 0; 585 1.1 skrll /* Extract the value from the instruction. */ 586 1.1 skrll if (operand->extract) 587 1.1 skrll value = (*operand->extract) (insn, dialect, &invalid); 588 1.1 skrll else 589 1.1 skrll { 590 1.4 christos if (operand->shift >= 0) 591 1.4 christos value = (insn >> operand->shift) & operand->bitm; 592 1.4 christos else 593 1.4 christos value = (insn << -operand->shift) & operand->bitm; 594 1.1 skrll if ((operand->flags & PPC_OPERAND_SIGNED) != 0) 595 1.1 skrll { 596 1.1 skrll /* BITM is always some number of zeros followed by some 597 1.4 christos number of ones, followed by some number of zeros. */ 598 1.7 christos uint64_t top = operand->bitm; 599 1.1 skrll /* top & -top gives the rightmost 1 bit, so this 600 1.1 skrll fills in any trailing zeros. */ 601 1.1 skrll top |= (top & -top) - 1; 602 1.1 skrll top &= ~(top >> 1); 603 1.1 skrll value = (value ^ top) - top; 604 1.1 skrll } 605 1.1 skrll } 606 1.1 skrll 607 1.11 christos if ((operand->flags & PPC_OPERAND_NONZERO) != 0) 608 1.11 christos ++value; 609 1.11 christos 610 1.1 skrll return value; 611 1.1 skrll } 612 1.1 skrll 613 1.1 skrll /* Determine whether the optional operand(s) should be printed. */ 614 1.1 skrll 615 1.10 christos static bool 616 1.10 christos skip_optional_operands (const ppc_opindex_t *opindex, 617 1.10 christos uint64_t insn, ppc_cpu_t dialect, bool *is_pcrel) 618 1.1 skrll { 619 1.1 skrll const struct powerpc_operand *operand; 620 1.9 christos int num_optional; 621 1.1 skrll 622 1.9 christos for (num_optional = 0; *opindex != 0; opindex++) 623 1.1 skrll { 624 1.1 skrll operand = &powerpc_operands[*opindex]; 625 1.9 christos if ((operand->flags & PPC_OPERAND_NEXT) != 0) 626 1.10 christos return false; 627 1.9 christos if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0) 628 1.9 christos { 629 1.10 christos int64_t value = operand_value_powerpc (operand, insn, dialect); 630 1.10 christos 631 1.10 christos if (operand->shift == 52) 632 1.10 christos *is_pcrel = value != 0; 633 1.10 christos 634 1.9 christos /* Negative count is used as a flag to extract function. */ 635 1.9 christos --num_optional; 636 1.10 christos if (value != ppc_optional_operand_value (operand, insn, dialect, 637 1.10 christos num_optional)) 638 1.10 christos return false; 639 1.9 christos } 640 1.1 skrll } 641 1.1 skrll 642 1.10 christos return true; 643 1.1 skrll } 644 1.1 skrll 645 1.7 christos /* Find a match for INSN in the opcode table, given machine DIALECT. */ 646 1.4 christos 647 1.4 christos static const struct powerpc_opcode * 648 1.7 christos lookup_powerpc (uint64_t insn, ppc_cpu_t dialect) 649 1.4 christos { 650 1.10 christos const struct powerpc_opcode *opcode, *opcode_end; 651 1.4 christos unsigned long op; 652 1.4 christos 653 1.4 christos /* Get the major opcode of the instruction. */ 654 1.4 christos op = PPC_OP (insn); 655 1.4 christos 656 1.4 christos /* Find the first match in the opcode table for this major opcode. */ 657 1.4 christos opcode_end = powerpc_opcodes + powerpc_opcd_indices[op + 1]; 658 1.4 christos for (opcode = powerpc_opcodes + powerpc_opcd_indices[op]; 659 1.4 christos opcode < opcode_end; 660 1.4 christos ++opcode) 661 1.4 christos { 662 1.10 christos const ppc_opindex_t *opindex; 663 1.4 christos const struct powerpc_operand *operand; 664 1.4 christos int invalid; 665 1.4 christos 666 1.4 christos if ((insn & opcode->mask) != opcode->opcode 667 1.7 christos || ((dialect & PPC_OPCODE_ANY) == 0 668 1.4 christos && ((opcode->flags & dialect) == 0 669 1.10 christos || (opcode->deprecated & dialect) != 0)) 670 1.10 christos || (opcode->deprecated & dialect & PPC_OPCODE_RAW) != 0) 671 1.4 christos continue; 672 1.4 christos 673 1.4 christos /* Check validity of operands. */ 674 1.4 christos invalid = 0; 675 1.4 christos for (opindex = opcode->operands; *opindex != 0; opindex++) 676 1.4 christos { 677 1.4 christos operand = powerpc_operands + *opindex; 678 1.4 christos if (operand->extract) 679 1.4 christos (*operand->extract) (insn, dialect, &invalid); 680 1.4 christos } 681 1.4 christos if (invalid) 682 1.4 christos continue; 683 1.4 christos 684 1.10 christos return opcode; 685 1.4 christos } 686 1.4 christos 687 1.10 christos return NULL; 688 1.4 christos } 689 1.4 christos 690 1.9 christos /* Find a match for INSN in the PREFIX opcode table. */ 691 1.9 christos 692 1.9 christos static const struct powerpc_opcode * 693 1.9 christos lookup_prefix (uint64_t insn, ppc_cpu_t dialect) 694 1.9 christos { 695 1.10 christos const struct powerpc_opcode *opcode, *opcode_end; 696 1.9 christos unsigned long seg; 697 1.9 christos 698 1.9 christos /* Get the opcode segment of the instruction. */ 699 1.9 christos seg = PPC_PREFIX_SEG (insn); 700 1.9 christos 701 1.9 christos /* Find the first match in the opcode table for this major opcode. */ 702 1.9 christos opcode_end = prefix_opcodes + prefix_opcd_indices[seg + 1]; 703 1.9 christos for (opcode = prefix_opcodes + prefix_opcd_indices[seg]; 704 1.9 christos opcode < opcode_end; 705 1.9 christos ++opcode) 706 1.9 christos { 707 1.10 christos const ppc_opindex_t *opindex; 708 1.9 christos const struct powerpc_operand *operand; 709 1.9 christos int invalid; 710 1.9 christos 711 1.9 christos if ((insn & opcode->mask) != opcode->opcode 712 1.9 christos || ((dialect & PPC_OPCODE_ANY) == 0 713 1.10 christos && (opcode->flags & dialect) == 0) 714 1.10 christos || (opcode->deprecated & dialect) != 0) 715 1.9 christos continue; 716 1.9 christos 717 1.9 christos /* Check validity of operands. */ 718 1.9 christos invalid = 0; 719 1.9 christos for (opindex = opcode->operands; *opindex != 0; opindex++) 720 1.9 christos { 721 1.9 christos operand = powerpc_operands + *opindex; 722 1.9 christos if (operand->extract) 723 1.9 christos (*operand->extract) (insn, dialect, &invalid); 724 1.9 christos } 725 1.9 christos if (invalid) 726 1.9 christos continue; 727 1.9 christos 728 1.10 christos return opcode; 729 1.9 christos } 730 1.9 christos 731 1.10 christos return NULL; 732 1.9 christos } 733 1.9 christos 734 1.4 christos /* Find a match for INSN in the VLE opcode table. */ 735 1.4 christos 736 1.4 christos static const struct powerpc_opcode * 737 1.10 christos lookup_vle (uint64_t insn, ppc_cpu_t dialect) 738 1.4 christos { 739 1.4 christos const struct powerpc_opcode *opcode; 740 1.4 christos const struct powerpc_opcode *opcode_end; 741 1.4 christos unsigned op, seg; 742 1.4 christos 743 1.4 christos op = PPC_OP (insn); 744 1.4 christos if (op >= 0x20 && op <= 0x37) 745 1.4 christos { 746 1.4 christos /* This insn has a 4-bit opcode. */ 747 1.4 christos op &= 0x3c; 748 1.4 christos } 749 1.4 christos seg = VLE_OP_TO_SEG (op); 750 1.4 christos 751 1.4 christos /* Find the first match in the opcode table for this major opcode. */ 752 1.4 christos opcode_end = vle_opcodes + vle_opcd_indices[seg + 1]; 753 1.4 christos for (opcode = vle_opcodes + vle_opcd_indices[seg]; 754 1.4 christos opcode < opcode_end; 755 1.4 christos ++opcode) 756 1.4 christos { 757 1.7 christos uint64_t table_opcd = opcode->opcode; 758 1.7 christos uint64_t table_mask = opcode->mask; 759 1.10 christos bool table_op_is_short = PPC_OP_SE_VLE(table_mask); 760 1.7 christos uint64_t insn2; 761 1.10 christos const ppc_opindex_t *opindex; 762 1.4 christos const struct powerpc_operand *operand; 763 1.4 christos int invalid; 764 1.4 christos 765 1.4 christos insn2 = insn; 766 1.4 christos if (table_op_is_short) 767 1.4 christos insn2 >>= 16; 768 1.10 christos if ((insn2 & table_mask) != table_opcd 769 1.10 christos || (opcode->deprecated & dialect) != 0) 770 1.4 christos continue; 771 1.4 christos 772 1.4 christos /* Check validity of operands. */ 773 1.4 christos invalid = 0; 774 1.4 christos for (opindex = opcode->operands; *opindex != 0; ++opindex) 775 1.4 christos { 776 1.4 christos operand = powerpc_operands + *opindex; 777 1.4 christos if (operand->extract) 778 1.4 christos (*operand->extract) (insn, (ppc_cpu_t)0, &invalid); 779 1.4 christos } 780 1.4 christos if (invalid) 781 1.4 christos continue; 782 1.4 christos 783 1.4 christos return opcode; 784 1.4 christos } 785 1.4 christos 786 1.4 christos return NULL; 787 1.4 christos } 788 1.4 christos 789 1.11 christos /* Find a match for INSN in the LSP opcode table. */ 790 1.11 christos 791 1.11 christos static const struct powerpc_opcode * 792 1.11 christos lookup_lsp (uint64_t insn, ppc_cpu_t dialect) 793 1.11 christos { 794 1.11 christos const struct powerpc_opcode *opcode, *opcode_end; 795 1.11 christos unsigned op, seg; 796 1.11 christos 797 1.11 christos op = PPC_OP (insn); 798 1.11 christos if (op != 0x4) 799 1.11 christos return NULL; 800 1.11 christos 801 1.11 christos seg = LSP_OP_TO_SEG (insn); 802 1.11 christos 803 1.11 christos /* Find the first match in the opcode table for this opcode. */ 804 1.11 christos opcode_end = lsp_opcodes + lsp_opcd_indices[seg + 1]; 805 1.11 christos for (opcode = lsp_opcodes + lsp_opcd_indices[seg]; 806 1.11 christos opcode < opcode_end; 807 1.11 christos ++opcode) 808 1.11 christos { 809 1.11 christos const ppc_opindex_t *opindex; 810 1.11 christos const struct powerpc_operand *operand; 811 1.11 christos int invalid; 812 1.11 christos 813 1.11 christos if ((insn & opcode->mask) != opcode->opcode 814 1.11 christos || (opcode->deprecated & dialect) != 0) 815 1.11 christos continue; 816 1.11 christos 817 1.11 christos /* Check validity of operands. */ 818 1.11 christos invalid = 0; 819 1.11 christos for (opindex = opcode->operands; *opindex != 0; ++opindex) 820 1.11 christos { 821 1.11 christos operand = powerpc_operands + *opindex; 822 1.11 christos if (operand->extract) 823 1.11 christos (*operand->extract) (insn, (ppc_cpu_t) 0, &invalid); 824 1.11 christos } 825 1.11 christos if (invalid) 826 1.11 christos continue; 827 1.11 christos 828 1.11 christos return opcode; 829 1.11 christos } 830 1.11 christos 831 1.11 christos return NULL; 832 1.11 christos } 833 1.11 christos 834 1.7 christos /* Find a match for INSN in the SPE2 opcode table. */ 835 1.7 christos 836 1.7 christos static const struct powerpc_opcode * 837 1.10 christos lookup_spe2 (uint64_t insn, ppc_cpu_t dialect) 838 1.7 christos { 839 1.7 christos const struct powerpc_opcode *opcode, *opcode_end; 840 1.7 christos unsigned op, xop, seg; 841 1.7 christos 842 1.7 christos op = PPC_OP (insn); 843 1.7 christos if (op != 0x4) 844 1.7 christos { 845 1.7 christos /* This is not SPE2 insn. 846 1.7 christos * All SPE2 instructions have OP=4 and differs by XOP */ 847 1.7 christos return NULL; 848 1.7 christos } 849 1.7 christos xop = SPE2_XOP (insn); 850 1.7 christos seg = SPE2_XOP_TO_SEG (xop); 851 1.7 christos 852 1.11 christos /* Find the first match in the opcode table for this opcode. */ 853 1.7 christos opcode_end = spe2_opcodes + spe2_opcd_indices[seg + 1]; 854 1.7 christos for (opcode = spe2_opcodes + spe2_opcd_indices[seg]; 855 1.7 christos opcode < opcode_end; 856 1.7 christos ++opcode) 857 1.7 christos { 858 1.7 christos uint64_t table_opcd = opcode->opcode; 859 1.7 christos uint64_t table_mask = opcode->mask; 860 1.7 christos uint64_t insn2; 861 1.10 christos const ppc_opindex_t *opindex; 862 1.7 christos const struct powerpc_operand *operand; 863 1.7 christos int invalid; 864 1.7 christos 865 1.7 christos insn2 = insn; 866 1.10 christos if ((insn2 & table_mask) != table_opcd 867 1.10 christos || (opcode->deprecated & dialect) != 0) 868 1.7 christos continue; 869 1.7 christos 870 1.7 christos /* Check validity of operands. */ 871 1.7 christos invalid = 0; 872 1.7 christos for (opindex = opcode->operands; *opindex != 0; ++opindex) 873 1.7 christos { 874 1.7 christos operand = powerpc_operands + *opindex; 875 1.7 christos if (operand->extract) 876 1.7 christos (*operand->extract) (insn, (ppc_cpu_t)0, &invalid); 877 1.7 christos } 878 1.7 christos if (invalid) 879 1.7 christos continue; 880 1.7 christos 881 1.7 christos return opcode; 882 1.7 christos } 883 1.7 christos 884 1.7 christos return NULL; 885 1.7 christos } 886 1.7 christos 887 1.10 christos static arelent * 888 1.10 christos bsearch_reloc (arelent **lo, arelent **hi, bfd_vma vma) 889 1.10 christos { 890 1.10 christos while (lo < hi) 891 1.10 christos { 892 1.10 christos arelent **mid = lo + (hi - lo) / 2; 893 1.10 christos arelent *rel = *mid; 894 1.10 christos 895 1.10 christos if (vma < rel->address) 896 1.10 christos hi = mid; 897 1.10 christos else if (vma > rel->address) 898 1.10 christos lo = mid + 1; 899 1.10 christos else 900 1.10 christos return rel; 901 1.10 christos } 902 1.10 christos return NULL; 903 1.10 christos } 904 1.10 christos 905 1.10 christos static bool 906 1.10 christos print_got_plt (struct sec_buf *sb, uint64_t vma, struct disassemble_info *info) 907 1.10 christos { 908 1.10 christos if (sb->name != NULL) 909 1.10 christos { 910 1.10 christos asection *s = sb->sec; 911 1.10 christos if (s == NULL) 912 1.10 christos { 913 1.10 christos s = bfd_get_section_by_name (info->section->owner, sb->name); 914 1.10 christos sb->sec = s; 915 1.10 christos if (s == NULL) 916 1.10 christos sb->name = NULL; 917 1.10 christos } 918 1.10 christos if (s != NULL 919 1.10 christos && vma >= s->vma 920 1.10 christos && vma < s->vma + s->size) 921 1.10 christos { 922 1.10 christos asymbol *sym = NULL; 923 1.10 christos uint64_t ent = 0; 924 1.10 christos if (info->dynrelcount > 0) 925 1.10 christos { 926 1.10 christos arelent **lo = info->dynrelbuf; 927 1.10 christos arelent **hi = lo + info->dynrelcount; 928 1.10 christos arelent *rel = bsearch_reloc (lo, hi, vma); 929 1.10 christos if (rel != NULL && rel->sym_ptr_ptr != NULL) 930 1.10 christos sym = *rel->sym_ptr_ptr; 931 1.10 christos } 932 1.10 christos if (sym == NULL && (s->flags & SEC_HAS_CONTENTS) != 0) 933 1.10 christos { 934 1.10 christos if (sb->buf == NULL 935 1.10 christos && !bfd_malloc_and_get_section (s->owner, s, &sb->buf)) 936 1.10 christos sb->name = NULL; 937 1.10 christos if (sb->buf != NULL) 938 1.10 christos { 939 1.10 christos ent = bfd_get_64 (s->owner, sb->buf + (vma - s->vma)); 940 1.10 christos if (ent != 0) 941 1.10 christos sym = (*info->symbol_at_address_func) (ent, info); 942 1.10 christos } 943 1.10 christos } 944 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_text, " ["); 945 1.10 christos if (sym != NULL) 946 1.11 christos { 947 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_symbol, 948 1.11 christos "%s", bfd_asymbol_name (sym)); 949 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_text, "@"); 950 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_symbol, 951 1.11 christos "%s", sb->name + 1); 952 1.11 christos } 953 1.10 christos else 954 1.11 christos { 955 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_address, 956 1.11 christos "%" PRIx64, ent); 957 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_text, "@"); 958 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_symbol, 959 1.11 christos "%s", sb->name + 1); 960 1.11 christos } 961 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_text, "]"); 962 1.10 christos return true; 963 1.10 christos } 964 1.10 christos } 965 1.10 christos return false; 966 1.10 christos } 967 1.10 christos 968 1.1 skrll /* Print a PowerPC or POWER instruction. */ 969 1.1 skrll 970 1.1 skrll static int 971 1.1 skrll print_insn_powerpc (bfd_vma memaddr, 972 1.1 skrll struct disassemble_info *info, 973 1.1 skrll int bigendian, 974 1.1 skrll ppc_cpu_t dialect) 975 1.1 skrll { 976 1.1 skrll bfd_byte buffer[4]; 977 1.1 skrll int status; 978 1.7 christos uint64_t insn; 979 1.1 skrll const struct powerpc_opcode *opcode; 980 1.8 christos int insn_length = 4; /* Assume we have a normal 4-byte instruction. */ 981 1.1 skrll 982 1.1 skrll status = (*info->read_memory_func) (memaddr, buffer, 4, info); 983 1.8 christos 984 1.8 christos /* The final instruction may be a 2-byte VLE insn. */ 985 1.8 christos if (status != 0 && (dialect & PPC_OPCODE_VLE) != 0) 986 1.8 christos { 987 1.8 christos /* Clear buffer so unused bytes will not have garbage in them. */ 988 1.10 christos buffer[2] = buffer[3] = 0; 989 1.8 christos status = (*info->read_memory_func) (memaddr, buffer, 2, info); 990 1.10 christos insn_length = 2; 991 1.8 christos } 992 1.8 christos 993 1.1 skrll if (status != 0) 994 1.1 skrll { 995 1.8 christos (*info->memory_error_func) (status, memaddr, info); 996 1.8 christos return -1; 997 1.1 skrll } 998 1.1 skrll 999 1.1 skrll if (bigendian) 1000 1.1 skrll insn = bfd_getb32 (buffer); 1001 1.1 skrll else 1002 1.1 skrll insn = bfd_getl32 (buffer); 1003 1.1 skrll 1004 1.4 christos /* Get the major opcode of the insn. */ 1005 1.4 christos opcode = NULL; 1006 1.10 christos if ((dialect & PPC_OPCODE_POWER10) != 0 1007 1.9 christos && PPC_OP (insn) == 0x1) 1008 1.9 christos { 1009 1.9 christos uint64_t temp_insn, suffix; 1010 1.9 christos status = (*info->read_memory_func) (memaddr + 4, buffer, 4, info); 1011 1.9 christos if (status == 0) 1012 1.9 christos { 1013 1.9 christos if (bigendian) 1014 1.9 christos suffix = bfd_getb32 (buffer); 1015 1.9 christos else 1016 1.9 christos suffix = bfd_getl32 (buffer); 1017 1.9 christos temp_insn = (insn << 32) | suffix; 1018 1.9 christos opcode = lookup_prefix (temp_insn, dialect & ~PPC_OPCODE_ANY); 1019 1.9 christos if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0) 1020 1.9 christos opcode = lookup_prefix (temp_insn, dialect); 1021 1.9 christos if (opcode != NULL) 1022 1.9 christos { 1023 1.9 christos insn = temp_insn; 1024 1.9 christos insn_length = 8; 1025 1.9 christos if ((info->flags & WIDE_OUTPUT) != 0) 1026 1.9 christos info->bytes_per_line = 8; 1027 1.9 christos } 1028 1.9 christos } 1029 1.9 christos } 1030 1.9 christos if (opcode == NULL && (dialect & PPC_OPCODE_VLE) != 0) 1031 1.4 christos { 1032 1.10 christos opcode = lookup_vle (insn, dialect); 1033 1.8 christos if (opcode != NULL && PPC_OP_SE_VLE (opcode->mask)) 1034 1.8 christos { 1035 1.8 christos /* The operands will be fetched out of the 16-bit instruction. */ 1036 1.8 christos insn >>= 16; 1037 1.8 christos insn_length = 2; 1038 1.8 christos } 1039 1.4 christos } 1040 1.10 christos if (opcode == NULL && insn_length == 4) 1041 1.10 christos { 1042 1.11 christos if ((dialect & PPC_OPCODE_LSP) != 0) 1043 1.11 christos opcode = lookup_lsp (insn, dialect); 1044 1.10 christos if ((dialect & PPC_OPCODE_SPE2) != 0) 1045 1.10 christos opcode = lookup_spe2 (insn, dialect); 1046 1.10 christos if (opcode == NULL) 1047 1.10 christos opcode = lookup_powerpc (insn, dialect & ~PPC_OPCODE_ANY); 1048 1.10 christos if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0) 1049 1.10 christos opcode = lookup_powerpc (insn, dialect); 1050 1.11 christos if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0) 1051 1.11 christos opcode = lookup_spe2 (insn, dialect); 1052 1.11 christos if (opcode == NULL && (dialect & PPC_OPCODE_ANY) != 0) 1053 1.11 christos opcode = lookup_lsp (insn, dialect); 1054 1.10 christos } 1055 1.1 skrll 1056 1.4 christos if (opcode != NULL) 1057 1.1 skrll { 1058 1.10 christos const ppc_opindex_t *opindex; 1059 1.1 skrll const struct powerpc_operand *operand; 1060 1.9 christos enum { 1061 1.9 christos need_comma = 0, 1062 1.9 christos need_1space = 1, 1063 1.9 christos need_2spaces = 2, 1064 1.9 christos need_3spaces = 3, 1065 1.9 christos need_4spaces = 4, 1066 1.9 christos need_5spaces = 5, 1067 1.9 christos need_6spaces = 6, 1068 1.9 christos need_7spaces = 7, 1069 1.9 christos need_paren 1070 1.9 christos } op_separator; 1071 1.10 christos bool skip_optional; 1072 1.10 christos bool is_pcrel; 1073 1.10 christos uint64_t d34; 1074 1.9 christos int blanks; 1075 1.9 christos 1076 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_mnemonic, 1077 1.11 christos "%s", opcode->name); 1078 1.11 christos /* gdb fprintf_styled_func doesn't return count printed. */ 1079 1.9 christos blanks = 8 - strlen (opcode->name); 1080 1.9 christos if (blanks <= 0) 1081 1.9 christos blanks = 1; 1082 1.1 skrll 1083 1.1 skrll /* Now extract and print the operands. */ 1084 1.9 christos op_separator = blanks; 1085 1.10 christos skip_optional = false; 1086 1.10 christos is_pcrel = false; 1087 1.10 christos d34 = 0; 1088 1.1 skrll for (opindex = opcode->operands; *opindex != 0; opindex++) 1089 1.1 skrll { 1090 1.7 christos int64_t value; 1091 1.1 skrll 1092 1.1 skrll operand = powerpc_operands + *opindex; 1093 1.1 skrll 1094 1.9 christos /* If all of the optional operands past this one have their 1095 1.9 christos default value, then don't print any of them. Except in 1096 1.9 christos raw mode, print them all. */ 1097 1.9 christos if ((operand->flags & PPC_OPERAND_OPTIONAL) != 0 1098 1.9 christos && (dialect & PPC_OPCODE_RAW) == 0) 1099 1.1 skrll { 1100 1.9 christos if (!skip_optional) 1101 1.10 christos skip_optional = skip_optional_operands (opindex, insn, 1102 1.10 christos dialect, &is_pcrel); 1103 1.1 skrll if (skip_optional) 1104 1.1 skrll continue; 1105 1.1 skrll } 1106 1.1 skrll 1107 1.1 skrll value = operand_value_powerpc (operand, insn, dialect); 1108 1.1 skrll 1109 1.9 christos if (op_separator == need_comma) 1110 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_text, ","); 1111 1.9 christos else if (op_separator == need_paren) 1112 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_text, "("); 1113 1.9 christos else 1114 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_text, "%*s", 1115 1.11 christos op_separator, " "); 1116 1.1 skrll 1117 1.1 skrll /* Print the operand as directed by the flags. */ 1118 1.1 skrll if ((operand->flags & PPC_OPERAND_GPR) != 0 1119 1.1 skrll || ((operand->flags & PPC_OPERAND_GPR_0) != 0 && value != 0)) 1120 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_register, 1121 1.11 christos "r%" PRId64, value); 1122 1.1 skrll else if ((operand->flags & PPC_OPERAND_FPR) != 0) 1123 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_register, 1124 1.11 christos "f%" PRId64, value); 1125 1.1 skrll else if ((operand->flags & PPC_OPERAND_VR) != 0) 1126 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_register, 1127 1.11 christos "v%" PRId64, value); 1128 1.1 skrll else if ((operand->flags & PPC_OPERAND_VSR) != 0) 1129 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_register, 1130 1.11 christos "vs%" PRId64, value); 1131 1.11 christos else if ((operand->flags & PPC_OPERAND_DMR) != 0) 1132 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_register, 1133 1.11 christos "dm%" PRId64, value); 1134 1.10 christos else if ((operand->flags & PPC_OPERAND_ACC) != 0) 1135 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_register, 1136 1.11 christos "a%" PRId64, value); 1137 1.1 skrll else if ((operand->flags & PPC_OPERAND_RELATIVE) != 0) 1138 1.1 skrll (*info->print_address_func) (memaddr + value, info); 1139 1.1 skrll else if ((operand->flags & PPC_OPERAND_ABSOLUTE) != 0) 1140 1.1 skrll (*info->print_address_func) ((bfd_vma) value & 0xffffffff, info); 1141 1.5 christos else if ((operand->flags & PPC_OPERAND_FSL) != 0) 1142 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_register, 1143 1.11 christos "fsl%" PRId64, value); 1144 1.1 skrll else if ((operand->flags & PPC_OPERAND_FCR) != 0) 1145 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_register, 1146 1.11 christos "fcr%" PRId64, value); 1147 1.1 skrll else if ((operand->flags & PPC_OPERAND_UDI) != 0) 1148 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_register, 1149 1.11 christos "%" PRId64, value); 1150 1.4 christos else if ((operand->flags & PPC_OPERAND_CR_REG) != 0 1151 1.9 christos && (operand->flags & PPC_OPERAND_CR_BIT) == 0 1152 1.4 christos && (((dialect & PPC_OPCODE_PPC) != 0) 1153 1.4 christos || ((dialect & PPC_OPCODE_VLE) != 0))) 1154 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_register, 1155 1.11 christos "cr%" PRId64, value); 1156 1.9 christos else if ((operand->flags & PPC_OPERAND_CR_BIT) != 0 1157 1.9 christos && (operand->flags & PPC_OPERAND_CR_REG) == 0 1158 1.4 christos && (((dialect & PPC_OPCODE_PPC) != 0) 1159 1.4 christos || ((dialect & PPC_OPCODE_VLE) != 0))) 1160 1.1 skrll { 1161 1.4 christos static const char *cbnames[4] = { "lt", "gt", "eq", "so" }; 1162 1.4 christos int cr; 1163 1.4 christos int cc; 1164 1.4 christos 1165 1.4 christos cr = value >> 2; 1166 1.11 christos cc = value & 3; 1167 1.4 christos if (cr != 0) 1168 1.11 christos { 1169 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_text, 1170 1.11 christos "4*"); 1171 1.11 christos (*info->fprintf_styled_func) (info->stream, 1172 1.11 christos dis_style_register, 1173 1.11 christos "cr%d", cr); 1174 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_text, 1175 1.11 christos "+"); 1176 1.11 christos } 1177 1.11 christos 1178 1.11 christos (*info->fprintf_styled_func) (info->stream, 1179 1.11 christos dis_style_sub_mnemonic, 1180 1.11 christos "%s", cbnames[cc]); 1181 1.1 skrll } 1182 1.3 christos else 1183 1.11 christos { 1184 1.11 christos /* An immediate, but what style? */ 1185 1.11 christos enum disassembler_style style; 1186 1.11 christos 1187 1.11 christos if ((operand->flags & PPC_OPERAND_PARENS) != 0) 1188 1.11 christos style = dis_style_address_offset; 1189 1.11 christos else 1190 1.11 christos style = dis_style_immediate; 1191 1.11 christos 1192 1.11 christos (*info->fprintf_styled_func) (info->stream, style, 1193 1.11 christos "%" PRId64, value); 1194 1.11 christos } 1195 1.1 skrll 1196 1.10 christos if (operand->shift == 52) 1197 1.10 christos is_pcrel = value != 0; 1198 1.10 christos else if (operand->bitm == UINT64_C (0x3ffffffff)) 1199 1.10 christos d34 = value; 1200 1.10 christos 1201 1.9 christos if (op_separator == need_paren) 1202 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_text, ")"); 1203 1.1 skrll 1204 1.9 christos op_separator = need_comma; 1205 1.9 christos if ((operand->flags & PPC_OPERAND_PARENS) != 0) 1206 1.9 christos op_separator = need_paren; 1207 1.1 skrll } 1208 1.1 skrll 1209 1.10 christos if (is_pcrel) 1210 1.10 christos { 1211 1.10 christos d34 += memaddr; 1212 1.11 christos (*info->fprintf_styled_func) (info->stream, 1213 1.11 christos dis_style_comment_start, 1214 1.11 christos "\t# %" PRIx64, d34); 1215 1.10 christos asymbol *sym = (*info->symbol_at_address_func) (d34, info); 1216 1.10 christos if (sym) 1217 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_text, 1218 1.11 christos " <%s>", bfd_asymbol_name (sym)); 1219 1.10 christos 1220 1.10 christos if (info->private_data != NULL 1221 1.10 christos && info->section != NULL 1222 1.10 christos && info->section->owner != NULL 1223 1.10 christos && (bfd_get_file_flags (info->section->owner) 1224 1.10 christos & (EXEC_P | DYNAMIC)) != 0 1225 1.10 christos && ((insn & ((-1ULL << 50) | (0x3fULL << 26))) 1226 1.10 christos == ((1ULL << 58) | (1ULL << 52) | (57ULL << 26)) /* pld */)) 1227 1.10 christos { 1228 1.10 christos for (int i = 0; i < 2; i++) 1229 1.10 christos if (print_got_plt (private_data (info)->special + i, d34, info)) 1230 1.10 christos break; 1231 1.10 christos } 1232 1.10 christos } 1233 1.10 christos 1234 1.8 christos /* We have found and printed an instruction. */ 1235 1.8 christos return insn_length; 1236 1.1 skrll } 1237 1.1 skrll 1238 1.1 skrll /* We could not find a match. */ 1239 1.10 christos if (insn_length == 4) 1240 1.11 christos (*info->fprintf_styled_func) (info->stream, 1241 1.11 christos dis_style_assembler_directive, ".long"); 1242 1.10 christos else 1243 1.11 christos { 1244 1.11 christos (*info->fprintf_styled_func) (info->stream, 1245 1.11 christos dis_style_assembler_directive, ".word"); 1246 1.11 christos insn >>= 16; 1247 1.11 christos } 1248 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_text, " "); 1249 1.11 christos (*info->fprintf_styled_func) (info->stream, dis_style_immediate, "0x%x", 1250 1.11 christos (unsigned int) insn); 1251 1.11 christos 1252 1.11 christos 1253 1.10 christos return insn_length; 1254 1.1 skrll } 1255 1.1 skrll 1256 1.9 christos const disasm_options_and_args_t * 1257 1.7 christos disassembler_options_powerpc (void) 1258 1.7 christos { 1259 1.9 christos static disasm_options_and_args_t *opts_and_args; 1260 1.7 christos 1261 1.9 christos if (opts_and_args == NULL) 1262 1.7 christos { 1263 1.7 christos size_t i, num_options = ARRAY_SIZE (ppc_opts); 1264 1.9 christos disasm_options_t *opts; 1265 1.9 christos 1266 1.9 christos opts_and_args = XNEW (disasm_options_and_args_t); 1267 1.9 christos opts_and_args->args = NULL; 1268 1.9 christos 1269 1.9 christos opts = &opts_and_args->options; 1270 1.7 christos opts->name = XNEWVEC (const char *, num_options + 1); 1271 1.9 christos opts->description = NULL; 1272 1.9 christos opts->arg = NULL; 1273 1.7 christos for (i = 0; i < num_options; i++) 1274 1.7 christos opts->name[i] = ppc_opts[i].opt; 1275 1.7 christos /* The array we return must be NULL terminated. */ 1276 1.7 christos opts->name[i] = NULL; 1277 1.7 christos } 1278 1.7 christos 1279 1.9 christos return opts_and_args; 1280 1.7 christos } 1281 1.7 christos 1282 1.1 skrll void 1283 1.1 skrll print_ppc_disassembler_options (FILE *stream) 1284 1.1 skrll { 1285 1.3 christos unsigned int i, col; 1286 1.3 christos 1287 1.3 christos fprintf (stream, _("\n\ 1288 1.1 skrll The following PPC specific disassembler options are supported for use with\n\ 1289 1.3 christos the -M switch:\n")); 1290 1.1 skrll 1291 1.7 christos for (col = 0, i = 0; i < ARRAY_SIZE (ppc_opts); i++) 1292 1.3 christos { 1293 1.3 christos col += fprintf (stream, " %s,", ppc_opts[i].opt); 1294 1.3 christos if (col > 66) 1295 1.3 christos { 1296 1.3 christos fprintf (stream, "\n"); 1297 1.3 christos col = 0; 1298 1.3 christos } 1299 1.3 christos } 1300 1.7 christos fprintf (stream, "\n"); 1301 1.1 skrll } 1302