* cgen-ibld.in (extract_normal): Avoid memory range errors.
[deliverable/binutils-gdb.git] / opcodes / cgen-ibld.in
CommitLineData
f6e6b40f
BE
1/* Instruction building/extraction support for @arch@. -*- C -*-
2
47b0e7ad
NC
3 THIS FILE IS MACHINE GENERATED WITH CGEN: Cpu tools GENerator.
4 - the resultant file is machine generated, cgen-ibld.in isn't
f6e6b40f 5
54d46aca 6 Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2005, 2006
47b0e7ad 7 Free Software Foundation, Inc.
f6e6b40f 8
47b0e7ad 9 This file is part of the GNU Binutils and GDB, the GNU debugger.
f6e6b40f 10
47b0e7ad
NC
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
f6e6b40f 15
47b0e7ad
NC
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
f6e6b40f 20
47b0e7ad
NC
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software Foundation, Inc.,
23 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
f6e6b40f
BE
24
25/* ??? Eventually more and more of this stuff can go to cpu-independent files.
26 Keep that in mind. */
27
28#include "sysdep.h"
f6e6b40f
BE
29#include <stdio.h>
30#include "ansidecl.h"
31#include "dis-asm.h"
32#include "bfd.h"
33#include "symcat.h"
34#include "@prefix@-desc.h"
35#include "@prefix@-opc.h"
36#include "opintl.h"
37111cc7 37#include "safe-ctype.h"
f6e6b40f 38
47b0e7ad 39#undef min
f6e6b40f 40#define min(a,b) ((a) < (b) ? (a) : (b))
47b0e7ad 41#undef max
f6e6b40f
BE
42#define max(a,b) ((a) > (b) ? (a) : (b))
43
44/* Used by the ifield rtx function. */
45#define FLD(f) (fields->f)
46
47static const char * insert_normal
10e05405
MM
48 (CGEN_CPU_DESC, long, unsigned int, unsigned int, unsigned int,
49 unsigned int, unsigned int, unsigned int, CGEN_INSN_BYTES_PTR);
f6e6b40f 50static const char * insert_insn_normal
10e05405
MM
51 (CGEN_CPU_DESC, const CGEN_INSN *,
52 CGEN_FIELDS *, CGEN_INSN_BYTES_PTR, bfd_vma);
f6e6b40f 53static int extract_normal
10e05405
MM
54 (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, CGEN_INSN_INT,
55 unsigned int, unsigned int, unsigned int, unsigned int,
56 unsigned int, unsigned int, bfd_vma, long *);
f6e6b40f 57static int extract_insn_normal
10e05405
MM
58 (CGEN_CPU_DESC, const CGEN_INSN *, CGEN_EXTRACT_INFO *,
59 CGEN_INSN_INT, CGEN_FIELDS *, bfd_vma);
0e2ee3ca 60#if CGEN_INT_INSN_P
6bb95a0f 61static void put_insn_int_value
10e05405 62 (CGEN_CPU_DESC, CGEN_INSN_BYTES_PTR, int, int, CGEN_INSN_INT);
0e2ee3ca
NC
63#endif
64#if ! CGEN_INT_INSN_P
65static CGEN_INLINE void insert_1
10e05405 66 (CGEN_CPU_DESC, unsigned long, int, int, int, unsigned char *);
0e2ee3ca 67static CGEN_INLINE int fill_cache
10e05405 68 (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, bfd_vma);
0e2ee3ca 69static CGEN_INLINE long extract_1
10e05405 70 (CGEN_CPU_DESC, CGEN_EXTRACT_INFO *, int, int, int, unsigned char *, bfd_vma);
0e2ee3ca 71#endif
f6e6b40f
BE
72\f
73/* Operand insertion. */
74
75#if ! CGEN_INT_INSN_P
76
77/* Subroutine of insert_normal. */
78
79static CGEN_INLINE void
10e05405
MM
80insert_1 (CGEN_CPU_DESC cd,
81 unsigned long value,
44d221f0
MM
82 int start,
83 int length,
84 int word_length,
10e05405 85 unsigned char *bufp)
f6e6b40f
BE
86{
87 unsigned long x,mask;
88 int shift;
f6e6b40f 89
545ae501 90 x = cgen_get_insn_value (cd, bufp, word_length);
f6e6b40f
BE
91
92 /* Written this way to avoid undefined behaviour. */
93 mask = (((1L << (length - 1)) - 1) << 1) | 1;
94 if (CGEN_INSN_LSB0_P)
95 shift = (start + 1) - length;
96 else
97 shift = (word_length - (start + length));
98 x = (x & ~(mask << shift)) | ((value & mask) << shift);
99
545ae501 100 cgen_put_insn_value (cd, bufp, word_length, (bfd_vma) x);
f6e6b40f
BE
101}
102
103#endif /* ! CGEN_INT_INSN_P */
104
105/* Default insertion routine.
106
107 ATTRS is a mask of the boolean attributes.
108 WORD_OFFSET is the offset in bits from the start of the insn of the value.
109 WORD_LENGTH is the length of the word in bits in which the value resides.
110 START is the starting bit number in the word, architecture origin.
111 LENGTH is the length of VALUE in bits.
112 TOTAL_LENGTH is the total length of the insn in bits.
113
114 The result is an error message or NULL if success. */
115
116/* ??? This duplicates functionality with bfd's howto table and
117 bfd_install_relocation. */
118/* ??? This doesn't handle bfd_vma's. Create another function when
119 necessary. */
120
121static const char *
10e05405
MM
122insert_normal (CGEN_CPU_DESC cd,
123 long value,
124 unsigned int attrs,
125 unsigned int word_offset,
126 unsigned int start,
127 unsigned int length,
128 unsigned int word_length,
129 unsigned int total_length,
130 CGEN_INSN_BYTES_PTR buffer)
f6e6b40f
BE
131{
132 static char errbuf[100];
133 /* Written this way to avoid undefined behaviour. */
134 unsigned long mask = (((1L << (length - 1)) - 1) << 1) | 1;
135
136 /* If LENGTH is zero, this operand doesn't contribute to the value. */
137 if (length == 0)
138 return NULL;
139
f6e6b40f
BE
140 if (word_length > 32)
141 abort ();
142
143 /* For architectures with insns smaller than the base-insn-bitsize,
144 word_length may be too big. */
145 if (cd->min_insn_bitsize < cd->base_insn_bitsize)
146 {
147 if (word_offset == 0
148 && word_length > total_length)
149 word_length = total_length;
150 }
151
152 /* Ensure VALUE will fit. */
17f0ac84
GK
153 if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGN_OPT))
154 {
155 long minval = - (1L << (length - 1));
156 unsigned long maxval = mask;
157
158 if ((value > 0 && (unsigned long) value > maxval)
159 || value < minval)
160 {
161 /* xgettext:c-format */
162 sprintf (errbuf,
163 _("operand out of range (%ld not between %ld and %lu)"),
164 value, minval, maxval);
165 return errbuf;
166 }
167 }
168 else if (! CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED))
f6e6b40f
BE
169 {
170 unsigned long maxval = mask;
171
172 if ((unsigned long) value > maxval)
173 {
174 /* xgettext:c-format */
175 sprintf (errbuf,
176 _("operand out of range (%lu not between 0 and %lu)"),
177 value, maxval);
178 return errbuf;
179 }
180 }
181 else
182 {
183 if (! cgen_signed_overflow_ok_p (cd))
184 {
185 long minval = - (1L << (length - 1));
186 long maxval = (1L << (length - 1)) - 1;
187
188 if (value < minval || value > maxval)
189 {
190 sprintf
191 /* xgettext:c-format */
192 (errbuf, _("operand out of range (%ld not between %ld and %ld)"),
193 value, minval, maxval);
194 return errbuf;
195 }
196 }
197 }
198
199#if CGEN_INT_INSN_P
200
201 {
202 int shift;
203
204 if (CGEN_INSN_LSB0_P)
6bb95a0f 205 shift = (word_offset + start + 1) - length;
f6e6b40f 206 else
6bb95a0f 207 shift = total_length - (word_offset + start + length);
f6e6b40f
BE
208 *buffer = (*buffer & ~(mask << shift)) | ((value & mask) << shift);
209 }
210
211#else /* ! CGEN_INT_INSN_P */
212
213 {
214 unsigned char *bufp = (unsigned char *) buffer + word_offset / 8;
215
216 insert_1 (cd, value, start, length, word_length, bufp);
217 }
218
219#endif /* ! CGEN_INT_INSN_P */
220
221 return NULL;
222}
223
224/* Default insn builder (insert handler).
0e70c820
BE
225 The instruction is recorded in CGEN_INT_INSN_P byte order (meaning
226 that if CGEN_INSN_BYTES_PTR is an int * and thus, the value is
227 recorded in host byte order, otherwise BUFFER is an array of bytes
228 and the value is recorded in target byte order).
f6e6b40f
BE
229 The result is an error message or NULL if success. */
230
231static const char *
10e05405
MM
232insert_insn_normal (CGEN_CPU_DESC cd,
233 const CGEN_INSN * insn,
234 CGEN_FIELDS * fields,
235 CGEN_INSN_BYTES_PTR buffer,
236 bfd_vma pc)
f6e6b40f
BE
237{
238 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
239 unsigned long value;
4a9f416d 240 const CGEN_SYNTAX_CHAR_TYPE * syn;
f6e6b40f
BE
241
242 CGEN_INIT_INSERT (cd);
243 value = CGEN_INSN_BASE_VALUE (insn);
244
245 /* If we're recording insns as numbers (rather than a string of bytes),
246 target byte order handling is deferred until later. */
247
248#if CGEN_INT_INSN_P
249
6bb95a0f
DB
250 put_insn_int_value (cd, buffer, cd->base_insn_bitsize,
251 CGEN_FIELDS_BITSIZE (fields), value);
f6e6b40f
BE
252
253#else
254
0e2ee3ca
NC
255 cgen_put_insn_value (cd, buffer, min ((unsigned) cd->base_insn_bitsize,
256 (unsigned) CGEN_FIELDS_BITSIZE (fields)),
f6e6b40f
BE
257 value);
258
259#endif /* ! CGEN_INT_INSN_P */
260
261 /* ??? It would be better to scan the format's fields.
262 Still need to be able to insert a value based on the operand though;
263 e.g. storing a branch displacement that got resolved later.
264 Needs more thought first. */
265
4a9f416d 266 for (syn = CGEN_SYNTAX_STRING (syntax); * syn; ++ syn)
f6e6b40f
BE
267 {
268 const char *errmsg;
269
270 if (CGEN_SYNTAX_CHAR_P (* syn))
271 continue;
272
273 errmsg = (* cd->insert_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
274 fields, buffer, pc);
275 if (errmsg)
276 return errmsg;
277 }
278
279 return NULL;
280}
6bb95a0f 281
0e2ee3ca 282#if CGEN_INT_INSN_P
6bb95a0f 283/* Cover function to store an insn value into an integral insn. Must go here
47b0e7ad 284 because it needs <prefix>-desc.h for CGEN_INT_INSN_P. */
6bb95a0f
DB
285
286static void
10e05405
MM
287put_insn_int_value (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
288 CGEN_INSN_BYTES_PTR buf,
289 int length,
290 int insn_length,
291 CGEN_INSN_INT value)
6bb95a0f
DB
292{
293 /* For architectures with insns smaller than the base-insn-bitsize,
294 length may be too big. */
295 if (length > insn_length)
296 *buf = value;
297 else
298 {
299 int shift = insn_length - length;
300 /* Written this way to avoid undefined behaviour. */
301 CGEN_INSN_INT mask = (((1L << (length - 1)) - 1) << 1) | 1;
47b0e7ad 302
6bb95a0f
DB
303 *buf = (*buf & ~(mask << shift)) | ((value & mask) << shift);
304 }
305}
0e2ee3ca 306#endif
f6e6b40f
BE
307\f
308/* Operand extraction. */
309
310#if ! CGEN_INT_INSN_P
311
312/* Subroutine of extract_normal.
313 Ensure sufficient bytes are cached in EX_INFO.
314 OFFSET is the offset in bytes from the start of the insn of the value.
315 BYTES is the length of the needed value.
316 Returns 1 for success, 0 for failure. */
317
318static CGEN_INLINE int
10e05405
MM
319fill_cache (CGEN_CPU_DESC cd ATTRIBUTE_UNUSED,
320 CGEN_EXTRACT_INFO *ex_info,
44d221f0
MM
321 int offset,
322 int bytes,
10e05405 323 bfd_vma pc)
f6e6b40f
BE
324{
325 /* It's doubtful that the middle part has already been fetched so
326 we don't optimize that case. kiss. */
0e2ee3ca 327 unsigned int mask;
f6e6b40f
BE
328 disassemble_info *info = (disassemble_info *) ex_info->dis_info;
329
330 /* First do a quick check. */
331 mask = (1 << bytes) - 1;
332 if (((ex_info->valid >> offset) & mask) == mask)
333 return 1;
334
335 /* Search for the first byte we need to read. */
336 for (mask = 1 << offset; bytes > 0; --bytes, ++offset, mask <<= 1)
337 if (! (mask & ex_info->valid))
338 break;
339
340 if (bytes)
341 {
342 int status;
343
344 pc += offset;
345 status = (*info->read_memory_func)
346 (pc, ex_info->insn_bytes + offset, bytes, info);
347
348 if (status != 0)
349 {
350 (*info->memory_error_func) (status, pc, info);
351 return 0;
352 }
353
354 ex_info->valid |= ((1 << bytes) - 1) << offset;
355 }
356
357 return 1;
358}
359
360/* Subroutine of extract_normal. */
361
362static CGEN_INLINE long
10e05405
MM
363extract_1 (CGEN_CPU_DESC cd,
364 CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
365 int start,
366 int length,
367 int word_length,
368 unsigned char *bufp,
369 bfd_vma pc ATTRIBUTE_UNUSED)
f6e6b40f 370{
aed80dae 371 unsigned long x;
f6e6b40f 372 int shift;
47b0e7ad 373
e333d2c4
NC
374 x = cgen_get_insn_value (cd, bufp, word_length);
375
f6e6b40f
BE
376 if (CGEN_INSN_LSB0_P)
377 shift = (start + 1) - length;
378 else
379 shift = (word_length - (start + length));
aed80dae 380 return x >> shift;
f6e6b40f
BE
381}
382
383#endif /* ! CGEN_INT_INSN_P */
384
385/* Default extraction routine.
386
387 INSN_VALUE is the first base_insn_bitsize bits of the insn in host order,
388 or sometimes less for cases like the m32r where the base insn size is 32
389 but some insns are 16 bits.
390 ATTRS is a mask of the boolean attributes. We only need `SIGNED',
391 but for generality we take a bitmask of all of them.
392 WORD_OFFSET is the offset in bits from the start of the insn of the value.
393 WORD_LENGTH is the length of the word in bits in which the value resides.
394 START is the starting bit number in the word, architecture origin.
395 LENGTH is the length of VALUE in bits.
396 TOTAL_LENGTH is the total length of the insn in bits.
397
398 Returns 1 for success, 0 for failure. */
399
400/* ??? The return code isn't properly used. wip. */
401
402/* ??? This doesn't handle bfd_vma's. Create another function when
403 necessary. */
404
405static int
44d221f0 406extract_normal (CGEN_CPU_DESC cd,
f6e6b40f 407#if ! CGEN_INT_INSN_P
10e05405 408 CGEN_EXTRACT_INFO *ex_info,
f6e6b40f 409#else
10e05405 410 CGEN_EXTRACT_INFO *ex_info ATTRIBUTE_UNUSED,
f6e6b40f 411#endif
10e05405
MM
412 CGEN_INSN_INT insn_value,
413 unsigned int attrs,
414 unsigned int word_offset,
415 unsigned int start,
416 unsigned int length,
417 unsigned int word_length,
418 unsigned int total_length,
f6e6b40f 419#if ! CGEN_INT_INSN_P
10e05405 420 bfd_vma pc,
f6e6b40f 421#else
10e05405 422 bfd_vma pc ATTRIBUTE_UNUSED,
f6e6b40f 423#endif
10e05405 424 long *valuep)
f6e6b40f 425{
fc7bc883 426 long value, mask;
f6e6b40f
BE
427
428 /* If LENGTH is zero, this operand doesn't contribute to the value
429 so give it a standard value of zero. */
430 if (length == 0)
431 {
432 *valuep = 0;
433 return 1;
434 }
435
f6e6b40f
BE
436 if (word_length > 32)
437 abort ();
438
439 /* For architectures with insns smaller than the insn-base-bitsize,
440 word_length may be too big. */
441 if (cd->min_insn_bitsize < cd->base_insn_bitsize)
442 {
54d46aca
DD
443 if (word_offset + word_length > total_length)
444 word_length = total_length - word_offset;
f6e6b40f
BE
445 }
446
a00ad97d 447 /* Does the value reside in INSN_VALUE, and at the right alignment? */
f6e6b40f 448
a00ad97d 449 if (CGEN_INT_INSN_P || (word_offset == 0 && word_length == total_length))
f6e6b40f 450 {
f6e6b40f 451 if (CGEN_INSN_LSB0_P)
6bb95a0f 452 value = insn_value >> ((word_offset + start + 1) - length);
f6e6b40f 453 else
6bb95a0f 454 value = insn_value >> (total_length - ( word_offset + start + length));
f6e6b40f
BE
455 }
456
457#if ! CGEN_INT_INSN_P
458
459 else
460 {
461 unsigned char *bufp = ex_info->insn_bytes + word_offset / 8;
462
463 if (word_length > 32)
464 abort ();
465
466 if (fill_cache (cd, ex_info, word_offset / 8, word_length / 8, pc) == 0)
467 return 0;
468
469 value = extract_1 (cd, ex_info, start, length, word_length, bufp, pc);
470 }
471
472#endif /* ! CGEN_INT_INSN_P */
473
aed80dae
FCE
474 /* Written this way to avoid undefined behaviour. */
475 mask = (((1L << (length - 1)) - 1) << 1) | 1;
476
477 value &= mask;
478 /* sign extend? */
479 if (CGEN_BOOL_ATTR (attrs, CGEN_IFLD_SIGNED)
480 && (value & (1L << (length - 1))))
481 value |= ~mask;
482
f6e6b40f
BE
483 *valuep = value;
484
485 return 1;
486}
487
488/* Default insn extractor.
489
490 INSN_VALUE is the first base_insn_bitsize bits, translated to host order.
491 The extracted fields are stored in FIELDS.
492 EX_INFO is used to handle reading variable length insns.
493 Return the length of the insn in bits, or 0 if no match,
494 or -1 if an error occurs fetching data (memory_error_func will have
495 been called). */
496
497static int
10e05405
MM
498extract_insn_normal (CGEN_CPU_DESC cd,
499 const CGEN_INSN *insn,
500 CGEN_EXTRACT_INFO *ex_info,
501 CGEN_INSN_INT insn_value,
502 CGEN_FIELDS *fields,
503 bfd_vma pc)
f6e6b40f
BE
504{
505 const CGEN_SYNTAX *syntax = CGEN_INSN_SYNTAX (insn);
4a9f416d 506 const CGEN_SYNTAX_CHAR_TYPE *syn;
f6e6b40f
BE
507
508 CGEN_FIELDS_BITSIZE (fields) = CGEN_INSN_BITSIZE (insn);
509
510 CGEN_INIT_EXTRACT (cd);
511
512 for (syn = CGEN_SYNTAX_STRING (syntax); *syn; ++syn)
513 {
514 int length;
515
516 if (CGEN_SYNTAX_CHAR_P (*syn))
517 continue;
518
519 length = (* cd->extract_operand) (cd, CGEN_SYNTAX_FIELD (*syn),
520 ex_info, insn_value, fields, pc);
521 if (length <= 0)
522 return length;
523 }
524
525 /* We recognized and successfully extracted this insn. */
526 return CGEN_INSN_BITSIZE (insn);
527}
528\f
47b0e7ad 529/* Machine generated code added here. */
This page took 0.273649 seconds and 4 git commands to generate.