trace.c revision f25af517a06521f69fbc53eaf3c245a7a2298c75
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 48void 49get_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 */ 64int 65syscall_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 112static arch_addr_t 113arm_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 126enum { 127 COND_ALWAYS = 0xe, 128 COND_NV = 0xf, 129 FLAG_C = 0x20000000, 130}; 131 132static int 133arm_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 384static int 385thumb_insn_size (unsigned short inst1) 386{ 387 if ((inst1 & 0xe000) == 0xe000 && (inst1 & 0x1800) != 0) 388 return 4; 389 else 390 return 2; 391} 392 393static int 394thumb_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 638enum sw_singlestep_status 639arch_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 669size_t 670arch_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 709size_t 710arch_type_alignof(struct process *proc, struct arg_type_info *info) 711{ 712 return arch_type_sizeof(proc, info); 713} 714