1 /*
2 * This file is part of ltrace.
3 * Copyright (C) 2012, 2013 Petr Machata, Red Hat Inc.
4 * Copyright (C) 1998,2004,2008,2009 Juan Cespedes
5 * Copyright (C) 2006 Ian Wienand
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA
21 */
22
23 #include "config.h"
24
25 #include <string.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
28 #include <signal.h>
29 #include <sys/ptrace.h>
30 #include <asm/ptrace.h>
31
32 #include "bits.h"
33 #include "common.h"
34 #include "proc.h"
35 #include "output.h"
36 #include "ptrace.h"
37 #include "regs.h"
38 #include "type.h"
39
40 #if (!defined(PTRACE_PEEKUSER) && defined(PTRACE_PEEKUSR))
41 # define PTRACE_PEEKUSER PTRACE_PEEKUSR
42 #endif
43
44 #if (!defined(PTRACE_POKEUSER) && defined(PTRACE_POKEUSR))
45 # define PTRACE_POKEUSER PTRACE_POKEUSR
46 #endif
47
48 void
get_arch_dep(struct process * proc)49 get_arch_dep(struct process *proc)
50 {
51 proc_archdep *a;
52
53 if (!proc->arch_ptr)
54 proc->arch_ptr = (void *)malloc(sizeof(proc_archdep));
55 a = (proc_archdep *) (proc->arch_ptr);
56 a->valid = (ptrace(PTRACE_GETREGS, proc->pid, 0, &a->regs) >= 0);
57 }
58
59 /* Returns 0 if not a syscall,
60 * 1 if syscall entry, 2 if syscall exit,
61 * 3 if arch-specific syscall entry, 4 if arch-specific syscall exit,
62 * -1 on error.
63 */
64 int
syscall_p(struct process * proc,int status,int * sysnum)65 syscall_p(struct process *proc, int status, int *sysnum)
66 {
67 if (WIFSTOPPED(status)
68 && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
69 uint32_t pc, ip;
70 if (arm_get_register(proc, ARM_REG_PC, &pc) < 0
71 || arm_get_register(proc, ARM_REG_IP, &ip) < 0)
72 return -1;
73
74 pc = pc - 4;
75
76 /* fetch the SWI instruction */
77 unsigned insn = ptrace(PTRACE_PEEKTEXT, proc->pid,
78 (void *)pc, 0);
79
80 if (insn == 0xef000000 || insn == 0x0f000000
81 || (insn & 0xffff0000) == 0xdf000000) {
82 /* EABI syscall */
83 uint32_t r7;
84 if (arm_get_register(proc, ARM_REG_R7, &r7) < 0)
85 return -1;
86 *sysnum = r7;
87 } else if ((insn & 0xfff00000) == 0xef900000) {
88 /* old ABI syscall */
89 *sysnum = insn & 0xfffff;
90 } else {
91 /* TODO: handle swi<cond> variations */
92 /* one possible reason for getting in here is that we
93 * are coming from a signal handler, so the current
94 * PC does not point to the instruction just after the
95 * "swi" one. */
96 output_line(proc, "unexpected instruction 0x%x at %p",
97 insn, pc);
98 return 0;
99 }
100 if ((*sysnum & 0xf0000) == 0xf0000) {
101 /* arch-specific syscall */
102 *sysnum &= ~0xf0000;
103 return ip ? 4 : 3;
104 }
105 /* ARM syscall convention: on syscall entry, ip is zero;
106 * on syscall exit, ip is non-zero */
107 return ip ? 2 : 1;
108 }
109 return 0;
110 }
111
112 static arch_addr_t
arm_branch_dest(const arch_addr_t pc,const uint32_t insn)113 arm_branch_dest(const arch_addr_t pc, const uint32_t insn)
114 {
115 /* Bits 0-23 are signed immediate value. */
116 return pc + ((((insn & 0xffffff) ^ 0x800000) - 0x800000) << 2) + 8;
117 }
118
119 /* Addresses for calling Thumb functions have the bit 0 set.
120 Here are some macros to test, set, or clear bit 0 of addresses. */
121 /* XXX double cast */
122 #define IS_THUMB_ADDR(addr) ((uintptr_t)(addr) & 1)
123 #define MAKE_THUMB_ADDR(addr) ((arch_addr_t)((uintptr_t)(addr) | 1))
124 #define UNMAKE_THUMB_ADDR(addr) ((arch_addr_t)((uintptr_t)(addr) & ~1))
125
126 enum {
127 COND_ALWAYS = 0xe,
128 COND_NV = 0xf,
129 FLAG_C = 0x20000000,
130 };
131
132 static int
arm_get_next_pcs(struct process * proc,const arch_addr_t pc,arch_addr_t next_pcs[2])133 arm_get_next_pcs(struct process *proc,
134 const arch_addr_t pc, arch_addr_t next_pcs[2])
135 {
136 uint32_t this_instr;
137 uint32_t status;
138 if (proc_read_32(proc, pc, &this_instr) < 0
139 || arm_get_register(proc, ARM_REG_CPSR, &status) < 0)
140 return -1;
141
142 /* In theory, we sometimes don't even need to add any
143 * breakpoints at all. If the conditional bits of the
144 * instruction indicate that it should not be taken, then we
145 * can just skip it altogether without bothering. We could
146 * also emulate the instruction under the breakpoint.
147 *
148 * Here, we make it as simple as possible (though We Accept
149 * Patches). */
150 int nr = 0;
151
152 /* ARM can branch either relatively by using a branch
153 * instruction, or absolutely, by doing arbitrary arithmetic
154 * with PC as the destination. */
155 const unsigned cond = BITS(this_instr, 28, 31);
156 const unsigned opcode = BITS(this_instr, 24, 27);
157
158 if (cond == COND_NV)
159 switch (opcode) {
160 arch_addr_t addr;
161 case 0xa:
162 case 0xb:
163 /* Branch with Link and change to Thumb. */
164 /* XXX double cast. */
165 addr = (arch_addr_t)
166 ((uint32_t)arm_branch_dest(pc, this_instr)
167 | (((this_instr >> 24) & 0x1) << 1));
168 next_pcs[nr++] = MAKE_THUMB_ADDR(addr);
169 break;
170 }
171 else
172 switch (opcode) {
173 uint32_t operand1, operand2, result = 0;
174 case 0x0:
175 case 0x1: /* data processing */
176 case 0x2:
177 case 0x3:
178 if (BITS(this_instr, 12, 15) != ARM_REG_PC)
179 break;
180
181 if (BITS(this_instr, 22, 25) == 0
182 && BITS(this_instr, 4, 7) == 9) { /* multiply */
183 invalid:
184 fprintf(stderr,
185 "Invalid update to pc in instruction.\n");
186 break;
187 }
188
189 /* BX <reg>, BLX <reg> */
190 if (BITS(this_instr, 4, 27) == 0x12fff1
191 || BITS(this_instr, 4, 27) == 0x12fff3) {
192 enum arm_register reg = BITS(this_instr, 0, 3);
193 /* XXX double cast: no need to go
194 * through tmp. */
195 uint32_t tmp;
196 if (arm_get_register_offpc(proc, reg, &tmp) < 0)
197 return -1;
198 next_pcs[nr++] = (arch_addr_t)tmp;
199 return 0;
200 }
201
202 /* Multiply into PC. */
203 if (arm_get_register_offpc
204 (proc, BITS(this_instr, 16, 19), &operand1) < 0)
205 return -1;
206
207 int c = (status & FLAG_C) ? 1 : 0;
208 if (BIT(this_instr, 25)) {
209 uint32_t immval = BITS(this_instr, 0, 7);
210 uint32_t rotate = 2 * BITS(this_instr, 8, 11);
211 operand2 = (((immval >> rotate)
212 | (immval << (32 - rotate)))
213 & 0xffffffff);
214 } else {
215 /* operand 2 is a shifted register. */
216 if (arm_get_shifted_register
217 (proc, this_instr, c, pc, &operand2) < 0)
218 return -1;
219 }
220
221 switch (BITS(this_instr, 21, 24)) {
222 case 0x0: /*and */
223 result = operand1 & operand2;
224 break;
225
226 case 0x1: /*eor */
227 result = operand1 ^ operand2;
228 break;
229
230 case 0x2: /*sub */
231 result = operand1 - operand2;
232 break;
233
234 case 0x3: /*rsb */
235 result = operand2 - operand1;
236 break;
237
238 case 0x4: /*add */
239 result = operand1 + operand2;
240 break;
241
242 case 0x5: /*adc */
243 result = operand1 + operand2 + c;
244 break;
245
246 case 0x6: /*sbc */
247 result = operand1 - operand2 + c;
248 break;
249
250 case 0x7: /*rsc */
251 result = operand2 - operand1 + c;
252 break;
253
254 case 0x8:
255 case 0x9:
256 case 0xa:
257 case 0xb: /* tst, teq, cmp, cmn */
258 /* Only take the default branch. */
259 result = 0;
260 break;
261
262 case 0xc: /*orr */
263 result = operand1 | operand2;
264 break;
265
266 case 0xd: /*mov */
267 /* Always step into a function. */
268 result = operand2;
269 break;
270
271 case 0xe: /*bic */
272 result = operand1 & ~operand2;
273 break;
274
275 case 0xf: /*mvn */
276 result = ~operand2;
277 break;
278 }
279
280 /* XXX double cast */
281 next_pcs[nr++] = (arch_addr_t)result;
282 break;
283
284 case 0x4:
285 case 0x5: /* data transfer */
286 case 0x6:
287 case 0x7:
288 /* Ignore if insn isn't load or Rn not PC. */
289 if (!BIT(this_instr, 20)
290 || BITS(this_instr, 12, 15) != ARM_REG_PC)
291 break;
292
293 if (BIT(this_instr, 22))
294 goto invalid;
295
296 /* byte write to PC */
297 uint32_t base;
298 if (arm_get_register_offpc
299 (proc, BITS(this_instr, 16, 19), &base) < 0)
300 return -1;
301
302 if (BIT(this_instr, 24)) {
303 /* pre-indexed */
304 int c = (status & FLAG_C) ? 1 : 0;
305 uint32_t offset;
306 if (BIT(this_instr, 25)) {
307 if (arm_get_shifted_register
308 (proc, this_instr, c,
309 pc, &offset) < 0)
310 return -1;
311 } else {
312 offset = BITS(this_instr, 0, 11);
313 }
314
315 if (BIT(this_instr, 23))
316 base += offset;
317 else
318 base -= offset;
319 }
320
321 /* XXX two double casts. */
322 uint32_t next;
323 if (proc_read_32(proc, (arch_addr_t)base, &next) < 0)
324 return -1;
325 next_pcs[nr++] = (arch_addr_t)next;
326 break;
327
328 case 0x8:
329 case 0x9: /* block transfer */
330 if (!BIT(this_instr, 20))
331 break;
332 /* LDM */
333 if (BIT(this_instr, 15)) {
334 /* Loading pc. */
335 int offset = 0;
336 enum arm_register rn = BITS(this_instr, 16, 19);
337 uint32_t rn_val;
338 if (arm_get_register(proc, rn, &rn_val) < 0)
339 return -1;
340
341 int pre = BIT(this_instr, 24);
342 if (BIT(this_instr, 23)) {
343 /* Bit U = up. */
344 unsigned reglist
345 = BITS(this_instr, 0, 14);
346 offset = bitcount(reglist) * 4;
347 if (pre)
348 offset += 4;
349 } else if (pre) {
350 offset = -4;
351 }
352
353 /* XXX double cast. */
354 arch_addr_t addr
355 = (arch_addr_t)(rn_val + offset);
356 uint32_t next;
357 if (proc_read_32(proc, addr, &next) < 0)
358 return -1;
359 next_pcs[nr++] = (arch_addr_t)next;
360 }
361 break;
362
363 case 0xb: /* branch & link */
364 case 0xa: /* branch */
365 next_pcs[nr++] = arm_branch_dest(pc, this_instr);
366 break;
367
368 case 0xc:
369 case 0xd:
370 case 0xe: /* coproc ops */
371 case 0xf: /* SWI */
372 break;
373 }
374
375 /* Otherwise take the next instruction. */
376 if (cond != COND_ALWAYS || nr == 0)
377 next_pcs[nr++] = pc + 4;
378 return 0;
379 }
380
381 /* Return the size in bytes of the complete Thumb instruction whose
382 * first halfword is INST1. */
383
384 static int
thumb_insn_size(unsigned short inst1)385 thumb_insn_size (unsigned short inst1)
386 {
387 if ((inst1 & 0xe000) == 0xe000 && (inst1 & 0x1800) != 0)
388 return 4;
389 else
390 return 2;
391 }
392
393 static int
thumb_get_next_pcs(struct process * proc,const arch_addr_t pc,arch_addr_t next_pcs[2])394 thumb_get_next_pcs(struct process *proc,
395 const arch_addr_t pc, arch_addr_t next_pcs[2])
396 {
397 uint16_t inst1;
398 uint32_t status;
399 if (proc_read_16(proc, pc, &inst1) < 0
400 || arm_get_register(proc, ARM_REG_CPSR, &status) < 0)
401 return -1;
402
403 int nr = 0;
404
405 /* We currently ignore Thumb-2 conditional execution support
406 * (the IT instruction). No branches are allowed in IT block,
407 * and it's not legal to jump in the middle of it, so unless
408 * we need to singlestep through large swaths of code, which
409 * we currently don't, we can ignore them. */
410
411 if ((inst1 & 0xff00) == 0xbd00) { /* pop {rlist, pc} */
412 /* Fetch the saved PC from the stack. It's stored
413 * above all of the other registers. */
414 const unsigned offset = bitcount(BITS(inst1, 0, 7)) * 4;
415 uint32_t sp;
416 uint32_t next;
417 /* XXX two double casts */
418 if (arm_get_register(proc, ARM_REG_SP, &sp) < 0
419 || proc_read_32(proc, (arch_addr_t)(sp + offset),
420 &next) < 0)
421 return -1;
422 next_pcs[nr++] = (arch_addr_t)next;
423 } else if ((inst1 & 0xf000) == 0xd000) { /* conditional branch */
424 const unsigned long cond = BITS(inst1, 8, 11);
425 if (cond != 0x0f) { /* SWI */
426 next_pcs[nr++] = pc + (SBITS(inst1, 0, 7) << 1);
427 if (cond == COND_ALWAYS)
428 return 0;
429 }
430 } else if ((inst1 & 0xf800) == 0xe000) { /* unconditional branch */
431 next_pcs[nr++] = pc + (SBITS(inst1, 0, 10) << 1);
432 } else if (thumb_insn_size(inst1) == 4) { /* 32-bit instruction */
433 unsigned short inst2;
434 if (proc_read_16(proc, pc + 2, &inst2) < 0)
435 return -1;
436
437 if ((inst1 & 0xf800) == 0xf000 && (inst2 & 0x8000) == 0x8000) {
438 /* Branches and miscellaneous control instructions. */
439
440 if ((inst2 & 0x1000) != 0
441 || (inst2 & 0xd001) == 0xc000) {
442 /* B, BL, BLX. */
443
444 const int imm1 = SBITS(inst1, 0, 10);
445 const unsigned imm2 = BITS(inst2, 0, 10);
446 const unsigned j1 = BIT(inst2, 13);
447 const unsigned j2 = BIT(inst2, 11);
448
449 int32_t offset
450 = ((imm1 << 12) + (imm2 << 1));
451 offset ^= ((!j2) << 22) | ((!j1) << 23);
452
453 /* XXX double cast */
454 uint32_t next = (uint32_t)(pc + offset);
455 /* For BLX make sure to clear the low bits. */
456 if (BIT(inst2, 12) == 0)
457 next = next & 0xfffffffc;
458 /* XXX double cast */
459 next_pcs[nr++] = (arch_addr_t)next;
460 return 0;
461 } else if (inst1 == 0xf3de
462 && (inst2 & 0xff00) == 0x3f00) {
463 /* SUBS PC, LR, #imm8. */
464 uint32_t next;
465 if (arm_get_register(proc, ARM_REG_LR,
466 &next) < 0)
467 return -1;
468 next -= inst2 & 0x00ff;
469 /* XXX double cast */
470 next_pcs[nr++] = (arch_addr_t)next;
471 return 0;
472 } else if ((inst2 & 0xd000) == 0x8000
473 && (inst1 & 0x0380) != 0x0380) {
474 /* Conditional branch. */
475 const int sign = SBITS(inst1, 10, 10);
476 const unsigned imm1 = BITS(inst1, 0, 5);
477 const unsigned imm2 = BITS(inst2, 0, 10);
478 const unsigned j1 = BIT(inst2, 13);
479 const unsigned j2 = BIT(inst2, 11);
480
481 int32_t offset = (sign << 20)
482 + (j2 << 19) + (j1 << 18);
483 offset += (imm1 << 12) + (imm2 << 1);
484 next_pcs[nr++] = pc + offset;
485 if (BITS(inst1, 6, 9) == COND_ALWAYS)
486 return 0;
487 }
488 } else if ((inst1 & 0xfe50) == 0xe810) {
489 int load_pc = 1;
490 int offset;
491 const enum arm_register rn = BITS(inst1, 0, 3);
492
493 if (BIT(inst1, 7) && !BIT(inst1, 8)) {
494 /* LDMIA or POP */
495 if (!BIT(inst2, 15))
496 load_pc = 0;
497 offset = bitcount(inst2) * 4 - 4;
498 } else if (!BIT(inst1, 7) && BIT(inst1, 8)) {
499 /* LDMDB */
500 if (!BIT(inst2, 15))
501 load_pc = 0;
502 offset = -4;
503 } else if (BIT(inst1, 7) && BIT(inst1, 8)) {
504 /* RFEIA */
505 offset = 0;
506 } else if (!BIT(inst1, 7) && !BIT(inst1, 8)) {
507 /* RFEDB */
508 offset = -8;
509 } else {
510 load_pc = 0;
511 }
512
513 if (load_pc) {
514 uint32_t addr;
515 if (arm_get_register(proc, rn, &addr) < 0)
516 return -1;
517 arch_addr_t a = (arch_addr_t)(addr + offset);
518 uint32_t next;
519 if (proc_read_32(proc, a, &next) < 0)
520 return -1;
521 /* XXX double cast */
522 next_pcs[nr++] = (arch_addr_t)next;
523 }
524 } else if ((inst1 & 0xffef) == 0xea4f
525 && (inst2 & 0xfff0) == 0x0f00) {
526 /* MOV PC or MOVS PC. */
527 const enum arm_register rn = BITS(inst2, 0, 3);
528 uint32_t next;
529 if (arm_get_register(proc, rn, &next) < 0)
530 return -1;
531 /* XXX double cast */
532 next_pcs[nr++] = (arch_addr_t)next;
533 } else if ((inst1 & 0xff70) == 0xf850
534 && (inst2 & 0xf000) == 0xf000) {
535 /* LDR PC. */
536 const enum arm_register rn = BITS(inst1, 0, 3);
537 uint32_t base;
538 if (arm_get_register(proc, rn, &base) < 0)
539 return -1;
540
541 int load_pc = 1;
542 if (rn == ARM_REG_PC) {
543 base = (base + 4) & ~(uint32_t)0x3;
544 if (BIT(inst1, 7))
545 base += BITS(inst2, 0, 11);
546 else
547 base -= BITS(inst2, 0, 11);
548 } else if (BIT(inst1, 7)) {
549 base += BITS(inst2, 0, 11);
550 } else if (BIT(inst2, 11)) {
551 if (BIT(inst2, 10)) {
552 if (BIT(inst2, 9))
553 base += BITS(inst2, 0, 7);
554 else
555 base -= BITS(inst2, 0, 7);
556 }
557 } else if ((inst2 & 0x0fc0) == 0x0000) {
558 const int shift = BITS(inst2, 4, 5);
559 const enum arm_register rm = BITS(inst2, 0, 3);
560 uint32_t v;
561 if (arm_get_register(proc, rm, &v) < 0)
562 return -1;
563 base += v << shift;
564 } else {
565 /* Reserved. */
566 load_pc = 0;
567 }
568
569 if (load_pc) {
570 /* xxx double casts */
571 uint32_t next;
572 if (proc_read_32(proc,
573 (arch_addr_t)base, &next) < 0)
574 return -1;
575 next_pcs[nr++] = (arch_addr_t)next;
576 }
577 } else if ((inst1 & 0xfff0) == 0xe8d0
578 && (inst2 & 0xfff0) == 0xf000) {
579 /* TBB. */
580 const enum arm_register tbl_reg = BITS(inst1, 0, 3);
581 const enum arm_register off_reg = BITS(inst2, 0, 3);
582
583 uint32_t table;
584 if (tbl_reg == ARM_REG_PC)
585 /* Regcache copy of PC isn't right yet. */
586 /* XXX double cast */
587 table = (uint32_t)pc + 4;
588 else if (arm_get_register(proc, tbl_reg, &table) < 0)
589 return -1;
590
591 uint32_t offset;
592 if (arm_get_register(proc, off_reg, &offset) < 0)
593 return -1;
594
595 table += offset;
596 uint8_t length;
597 /* XXX double cast */
598 if (proc_read_8(proc, (arch_addr_t)table, &length) < 0)
599 return -1;
600
601 next_pcs[nr++] = pc + 2 * length;
602
603 } else if ((inst1 & 0xfff0) == 0xe8d0
604 && (inst2 & 0xfff0) == 0xf010) {
605 /* TBH. */
606 const enum arm_register tbl_reg = BITS(inst1, 0, 3);
607 const enum arm_register off_reg = BITS(inst2, 0, 3);
608
609 uint32_t table;
610 if (tbl_reg == ARM_REG_PC)
611 /* Regcache copy of PC isn't right yet. */
612 /* XXX double cast */
613 table = (uint32_t)pc + 4;
614 else if (arm_get_register(proc, tbl_reg, &table) < 0)
615 return -1;
616
617 uint32_t offset;
618 if (arm_get_register(proc, off_reg, &offset) < 0)
619 return -1;
620
621 table += 2 * offset;
622 uint16_t length;
623 /* XXX double cast */
624 if (proc_read_16(proc, (arch_addr_t)table, &length) < 0)
625 return -1;
626
627 next_pcs[nr++] = pc + 2 * length;
628 }
629 }
630
631
632 /* Otherwise take the next instruction. */
633 if (nr == 0)
634 next_pcs[nr++] = pc + thumb_insn_size(inst1);
635 return 0;
636 }
637
638 enum sw_singlestep_status
arch_sw_singlestep(struct process * proc,struct breakpoint * sbp,int (* add_cb)(arch_addr_t,struct sw_singlestep_data *),struct sw_singlestep_data * add_cb_data)639 arch_sw_singlestep(struct process *proc, struct breakpoint *sbp,
640 int (*add_cb)(arch_addr_t, struct sw_singlestep_data *),
641 struct sw_singlestep_data *add_cb_data)
642 {
643 const arch_addr_t pc = get_instruction_pointer(proc);
644
645 uint32_t cpsr;
646 if (arm_get_register(proc, ARM_REG_CPSR, &cpsr) < 0)
647 return SWS_FAIL;
648
649 const unsigned thumb_p = BIT(cpsr, 5);
650 arch_addr_t next_pcs[2] = {};
651 if ((thumb_p ? &thumb_get_next_pcs
652 : &arm_get_next_pcs)(proc, pc, next_pcs) < 0)
653 return SWS_FAIL;
654
655 int i;
656 for (i = 0; i < 2; ++i) {
657 /* XXX double cast. */
658 arch_addr_t target
659 = (arch_addr_t)(((uintptr_t)next_pcs[i]) | thumb_p);
660 if (next_pcs[i] != 0 && add_cb(target, add_cb_data) < 0)
661 return SWS_FAIL;
662 }
663
664 debug(1, "PTRACE_CONT");
665 ptrace(PTRACE_CONT, proc->pid, 0, 0);
666 return SWS_OK;
667 }
668
669 size_t
arch_type_sizeof(struct process * proc,struct arg_type_info * info)670 arch_type_sizeof(struct process *proc, struct arg_type_info *info)
671 {
672 if (proc == NULL)
673 return (size_t)-2;
674
675 switch (info->type) {
676 case ARGTYPE_VOID:
677 return 0;
678
679 case ARGTYPE_CHAR:
680 return 1;
681
682 case ARGTYPE_SHORT:
683 case ARGTYPE_USHORT:
684 return 2;
685
686 case ARGTYPE_INT:
687 case ARGTYPE_UINT:
688 case ARGTYPE_LONG:
689 case ARGTYPE_ULONG:
690 case ARGTYPE_POINTER:
691 return 4;
692
693 case ARGTYPE_FLOAT:
694 return 4;
695 case ARGTYPE_DOUBLE:
696 return 8;
697
698 case ARGTYPE_ARRAY:
699 case ARGTYPE_STRUCT:
700 /* Use default value. */
701 return (size_t)-2;
702
703 default:
704 assert(info->type != info->type);
705 abort();
706 }
707 }
708
709 size_t
arch_type_alignof(struct process * proc,struct arg_type_info * info)710 arch_type_alignof(struct process *proc, struct arg_type_info *info)
711 {
712 return arch_type_sizeof(proc, info);
713 }
714