xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/arch/aarch64-insn.c (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
1 /* Copyright (C) 2009-2023 Free Software Foundation, Inc.
2    Contributed by ARM Ltd.
3 
4    This file is part of GDB.
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18 
19 #include "gdbsupport/common-defs.h"
20 #include "aarch64-insn.h"
21 
22 /* Toggle this file's internal debugging dump.  */
23 bool aarch64_debug = false;
24 
25 /* Determine if specified bits within an instruction opcode matches a
26    specific pattern.
27 
28    INSN is the instruction opcode.
29 
30    MASK specifies the bits within the opcode that are to be tested
31    against for a match with PATTERN.  */
32 
33 static int
34 decode_masked_match (uint32_t insn, uint32_t mask, uint32_t pattern)
35 {
36   return (insn & mask) == pattern;
37 }
38 
39 /* Decode an opcode if it represents an ADR or ADRP instruction.
40 
41    ADDR specifies the address of the opcode.
42    INSN specifies the opcode to test.
43    IS_ADRP receives the 'op' field from the decoded instruction.
44    RD receives the 'rd' field from the decoded instruction.
45    OFFSET receives the 'immhi:immlo' field from the decoded instruction.
46 
47    Return 1 if the opcodes matches and is decoded, otherwise 0.  */
48 
49 int
50 aarch64_decode_adr (CORE_ADDR addr, uint32_t insn, int *is_adrp,
51 		    unsigned *rd, int32_t *offset)
52 {
53   /* adr  0ii1 0000 iiii iiii iiii iiii iiir rrrr */
54   /* adrp 1ii1 0000 iiii iiii iiii iiii iiir rrrr */
55   if (decode_masked_match (insn, 0x1f000000, 0x10000000))
56     {
57       uint32_t immlo = (insn >> 29) & 0x3;
58       int32_t immhi = sbits (insn, 5, 23) * 4;
59 
60       *is_adrp = (insn >> 31) & 0x1;
61       *rd = (insn >> 0) & 0x1f;
62 
63       if (*is_adrp)
64 	{
65 	  /* The ADRP instruction has an offset with a -/+ 4GB range,
66 	     encoded as (immhi:immlo * 4096).  */
67 	  *offset = (immhi | immlo) * 4096;
68 	}
69       else
70 	*offset = (immhi | immlo);
71 
72       aarch64_debug_printf ("decode: 0x%s 0x%x %s x%u, #?",
73 			    core_addr_to_string_nz (addr), insn,
74 			    *is_adrp ?  "adrp" : "adr", *rd);
75       return 1;
76     }
77   return 0;
78 }
79 
80 /* Decode an opcode if it represents an branch immediate or branch
81    and link immediate instruction.
82 
83    ADDR specifies the address of the opcode.
84    INSN specifies the opcode to test.
85    IS_BL receives the 'op' bit from the decoded instruction.
86    OFFSET receives the immediate offset from the decoded instruction.
87 
88    Return 1 if the opcodes matches and is decoded, otherwise 0.  */
89 
90 int
91 aarch64_decode_b (CORE_ADDR addr, uint32_t insn, int *is_bl,
92 		  int32_t *offset)
93 {
94   /* b  0001 01ii iiii iiii iiii iiii iiii iiii */
95   /* bl 1001 01ii iiii iiii iiii iiii iiii iiii */
96   if (decode_masked_match (insn, 0x7c000000, 0x14000000))
97     {
98       *is_bl = (insn >> 31) & 0x1;
99       *offset = sbits (insn, 0, 25) * 4;
100 
101       if (aarch64_debug)
102 	{
103 	  debug_printf ("decode: 0x%s 0x%x %s 0x%s\n",
104 			core_addr_to_string_nz (addr), insn,
105 			*is_bl ? "bl" : "b",
106 			core_addr_to_string_nz (addr + *offset));
107 	}
108 
109       return 1;
110     }
111   return 0;
112 }
113 
114 /* Decode an opcode if it represents a conditional branch instruction.
115 
116    ADDR specifies the address of the opcode.
117    INSN specifies the opcode to test.
118    COND receives the branch condition field from the decoded
119    instruction.
120    OFFSET receives the immediate offset from the decoded instruction.
121 
122    Return 1 if the opcodes matches and is decoded, otherwise 0.  */
123 
124 int
125 aarch64_decode_bcond (CORE_ADDR addr, uint32_t insn, unsigned *cond,
126 		      int32_t *offset)
127 {
128   /* b.cond  0101 0100 iiii iiii iiii iiii iii0 cccc */
129   if (decode_masked_match (insn, 0xff000010, 0x54000000))
130     {
131       *cond = (insn >> 0) & 0xf;
132       *offset = sbits (insn, 5, 23) * 4;
133 
134       if (aarch64_debug)
135 	{
136 	  debug_printf ("decode: 0x%s 0x%x b<%u> 0x%s\n",
137 			core_addr_to_string_nz (addr), insn, *cond,
138 			core_addr_to_string_nz (addr + *offset));
139 	}
140       return 1;
141     }
142   return 0;
143 }
144 
145 /* Decode an opcode if it represents a CBZ or CBNZ instruction.
146 
147    ADDR specifies the address of the opcode.
148    INSN specifies the opcode to test.
149    IS64 receives the 'sf' field from the decoded instruction.
150    IS_CBNZ receives the 'op' field from the decoded instruction.
151    RN receives the 'rn' field from the decoded instruction.
152    OFFSET receives the 'imm19' field from the decoded instruction.
153 
154    Return 1 if the opcodes matches and is decoded, otherwise 0.  */
155 
156 int
157 aarch64_decode_cb (CORE_ADDR addr, uint32_t insn, int *is64, int *is_cbnz,
158 		   unsigned *rn, int32_t *offset)
159 {
160   /* cbz  T011 010o iiii iiii iiii iiii iiir rrrr */
161   /* cbnz T011 010o iiii iiii iiii iiii iiir rrrr */
162   if (decode_masked_match (insn, 0x7e000000, 0x34000000))
163     {
164       *rn = (insn >> 0) & 0x1f;
165       *is64 = (insn >> 31) & 0x1;
166       *is_cbnz = (insn >> 24) & 0x1;
167       *offset = sbits (insn, 5, 23) * 4;
168 
169       if (aarch64_debug)
170 	{
171 	  debug_printf ("decode: 0x%s 0x%x %s 0x%s\n",
172 			core_addr_to_string_nz (addr), insn,
173 			*is_cbnz ? "cbnz" : "cbz",
174 			core_addr_to_string_nz (addr + *offset));
175 	}
176       return 1;
177     }
178   return 0;
179 }
180 
181 /* Decode an opcode if it represents a TBZ or TBNZ instruction.
182 
183    ADDR specifies the address of the opcode.
184    INSN specifies the opcode to test.
185    IS_TBNZ receives the 'op' field from the decoded instruction.
186    BIT receives the bit position field from the decoded instruction.
187    RT receives 'rt' field from the decoded instruction.
188    IMM receives 'imm' field from the decoded instruction.
189 
190    Return 1 if the opcodes matches and is decoded, otherwise 0.  */
191 
192 int
193 aarch64_decode_tb (CORE_ADDR addr, uint32_t insn, int *is_tbnz,
194 		   unsigned *bit, unsigned *rt, int32_t *imm)
195 {
196   /* tbz  b011 0110 bbbb biii iiii iiii iiir rrrr */
197   /* tbnz B011 0111 bbbb biii iiii iiii iiir rrrr */
198   if (decode_masked_match (insn, 0x7e000000, 0x36000000))
199     {
200       *rt = (insn >> 0) & 0x1f;
201       *is_tbnz = (insn >> 24) & 0x1;
202       *bit = ((insn >> (31 - 4)) & 0x20) | ((insn >> 19) & 0x1f);
203       *imm = sbits (insn, 5, 18) * 4;
204 
205       if (aarch64_debug)
206 	{
207 	  debug_printf ("decode: 0x%s 0x%x %s x%u, #%u, 0x%s\n",
208 			core_addr_to_string_nz (addr), insn,
209 			*is_tbnz ? "tbnz" : "tbz", *rt, *bit,
210 			core_addr_to_string_nz (addr + *imm));
211 	}
212       return 1;
213     }
214   return 0;
215 }
216 
217 /* Decode an opcode if it represents an LDR or LDRSW instruction taking a
218    literal offset from the current PC.
219 
220    ADDR specifies the address of the opcode.
221    INSN specifies the opcode to test.
222    IS_W is set if the instruction is LDRSW.
223    IS64 receives size field from the decoded instruction.
224    RT receives the 'rt' field from the decoded instruction.
225    OFFSET receives the 'imm' field from the decoded instruction.
226 
227    Return 1 if the opcodes matches and is decoded, otherwise 0.  */
228 
229 int
230 aarch64_decode_ldr_literal (CORE_ADDR addr, uint32_t insn, int *is_w,
231 			    int *is64, unsigned *rt, int32_t *offset)
232 {
233   /* LDR    0T01 1000 iiii iiii iiii iiii iiir rrrr */
234   /* LDRSW  1001 1000 iiii iiii iiii iiii iiir rrrr */
235   if ((insn & 0x3f000000) == 0x18000000)
236     {
237       *is_w = (insn >> 31) & 0x1;
238 
239       if (*is_w)
240 	{
241 	  /* LDRSW always takes a 64-bit destination registers.  */
242 	  *is64 = 1;
243 	}
244       else
245 	*is64 = (insn >> 30) & 0x1;
246 
247       *rt = (insn >> 0) & 0x1f;
248       *offset = sbits (insn, 5, 23) * 4;
249 
250       if (aarch64_debug)
251 	debug_printf ("decode: %s 0x%x %s %s%u, #?\n",
252 		      core_addr_to_string_nz (addr), insn,
253 		      *is_w ? "ldrsw" : "ldr",
254 		      *is64 ? "x" : "w", *rt);
255 
256       return 1;
257     }
258 
259   return 0;
260 }
261 
262 /* Visit an instruction INSN by VISITOR with all needed information in DATA.
263 
264    PC relative instructions need to be handled specifically:
265 
266    - B/BL
267    - B.COND
268    - CBZ/CBNZ
269    - TBZ/TBNZ
270    - ADR/ADRP
271    - LDR/LDRSW (literal)  */
272 
273 void
274 aarch64_relocate_instruction (uint32_t insn,
275 			      const struct aarch64_insn_visitor *visitor,
276 			      struct aarch64_insn_data *data)
277 {
278   int is_bl;
279   int is64;
280   int is_sw;
281   int is_cbnz;
282   int is_tbnz;
283   int is_adrp;
284   unsigned rn;
285   unsigned rt;
286   unsigned rd;
287   unsigned cond;
288   unsigned bit;
289   int32_t offset;
290 
291   if (aarch64_decode_b (data->insn_addr, insn, &is_bl, &offset))
292     visitor->b (is_bl, offset, data);
293   else if (aarch64_decode_bcond (data->insn_addr, insn, &cond, &offset))
294     visitor->b_cond (cond, offset, data);
295   else if (aarch64_decode_cb (data->insn_addr, insn, &is64, &is_cbnz, &rn,
296 			      &offset))
297     visitor->cb (offset, is_cbnz, rn, is64, data);
298   else if (aarch64_decode_tb (data->insn_addr, insn, &is_tbnz, &bit, &rt,
299 			      &offset))
300     visitor->tb (offset, is_tbnz, rt, bit, data);
301   else if (aarch64_decode_adr (data->insn_addr, insn, &is_adrp, &rd, &offset))
302     visitor->adr (offset, rd, is_adrp, data);
303   else if (aarch64_decode_ldr_literal (data->insn_addr, insn, &is_sw, &is64,
304 				       &rt, &offset))
305     visitor->ldr_literal (offset, is_sw, rt, is64, data);
306   else
307     visitor->others (insn, data);
308 }
309 
310 /* Write a 32-bit unsigned integer INSN info *BUF.  Return the number of
311    instructions written (aka. 1).  */
312 
313 int
314 aarch64_emit_insn (uint32_t *buf, uint32_t insn)
315 {
316   *buf = insn;
317   return 1;
318 }
319 
320 /* Helper function emitting a load or store instruction.  */
321 
322 int
323 aarch64_emit_load_store (uint32_t *buf, uint32_t size,
324 			 enum aarch64_opcodes opcode,
325 			 struct aarch64_register rt,
326 			 struct aarch64_register rn,
327 			 struct aarch64_memory_operand operand)
328 {
329   uint32_t op;
330 
331   switch (operand.type)
332     {
333     case MEMORY_OPERAND_OFFSET:
334       {
335 	op = ENCODE (1, 1, 24);
336 
337 	return aarch64_emit_insn (buf, opcode | ENCODE (size, 2, 30) | op
338 				  | ENCODE (operand.index >> 3, 12, 10)
339 				  | ENCODE (rn.num, 5, 5)
340 				  | ENCODE (rt.num, 5, 0));
341       }
342     case MEMORY_OPERAND_POSTINDEX:
343       {
344 	uint32_t post_index = ENCODE (1, 2, 10);
345 
346 	op = ENCODE (0, 1, 24);
347 
348 	return aarch64_emit_insn (buf, opcode | ENCODE (size, 2, 30) | op
349 				  | post_index | ENCODE (operand.index, 9, 12)
350 				  | ENCODE (rn.num, 5, 5)
351 				  | ENCODE (rt.num, 5, 0));
352       }
353     case MEMORY_OPERAND_PREINDEX:
354       {
355 	uint32_t pre_index = ENCODE (3, 2, 10);
356 
357 	op = ENCODE (0, 1, 24);
358 
359 	return aarch64_emit_insn (buf, opcode | ENCODE (size, 2, 30) | op
360 				  | pre_index | ENCODE (operand.index, 9, 12)
361 				  | ENCODE (rn.num, 5, 5)
362 				  | ENCODE (rt.num, 5, 0));
363       }
364     default:
365       return 0;
366     }
367 }
368