1 /* 2 * This file is part of ltrace. 3 * Copyright (C) 2013 Petr Machata, Red Hat Inc. 4 * 5 * This program is free software; you can redistribute it and/or 6 * modify it under the terms of the GNU General Public License as 7 * published by the Free Software Foundation; either version 2 of the 8 * License, or (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 * 02110-1301 USA 19 */ 20 21 #include <sys/ptrace.h> 22 #include <asm/ptrace.h> 23 #include <assert.h> 24 #include <elf.h> 25 #include <libelf.h> 26 #include <stdint.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <stdbool.h> 31 32 #include "backend.h" 33 #include "fetch.h" 34 #include "library.h" 35 #include "proc.h" 36 #include "ptrace.h" 37 #include "regs.h" 38 #include "type.h" 39 #include "value.h" 40 41 enum { 42 /* How many (double) VFP registers the AAPCS uses for 43 * parameter passing. */ 44 NUM_VFP_REGS = 8, 45 }; 46 47 struct fetch_context { 48 struct pt_regs regs; 49 50 struct { 51 union { 52 double d[32]; 53 float s[64]; 54 }; 55 uint32_t fpscr; 56 } fpregs; 57 58 /* VFP register allocation. ALLOC.S tracks whether the 59 * corresponding FPREGS.S register is taken, ALLOC.D the same 60 * for FPREGS.D. We only track 8 (16) registers, because 61 * that's what the ABI uses for parameter passing. */ 62 union { 63 int16_t d[NUM_VFP_REGS]; 64 int8_t s[NUM_VFP_REGS * 2]; 65 } alloc; 66 67 unsigned ncrn; 68 arch_addr_t sp; 69 arch_addr_t nsaa; 70 arch_addr_t ret_struct; 71 72 bool hardfp:1; 73 bool in_varargs:1; 74 }; 75 76 static int 77 fetch_register_banks(struct process *proc, struct fetch_context *context) 78 { 79 if (ptrace(PTRACE_GETREGS, proc->pid, NULL, &context->regs) == -1) 80 return -1; 81 82 if (context->hardfp 83 && ptrace(PTRACE_GETVFPREGS, proc->pid, 84 NULL, &context->fpregs) == -1) 85 return -1; 86 87 context->ncrn = 0; 88 context->nsaa = context->sp = get_stack_pointer(proc); 89 memset(&context->alloc, 0, sizeof(context->alloc)); 90 91 return 0; 92 } 93 94 struct fetch_context * 95 arch_fetch_arg_init(enum tof type, struct process *proc, 96 struct arg_type_info *ret_info) 97 { 98 struct fetch_context *context = malloc(sizeof(*context)); 99 100 { 101 struct process *mainp = proc; 102 while (mainp->libraries == NULL && mainp->parent != NULL) 103 mainp = mainp->parent; 104 context->hardfp = mainp->libraries->arch.hardfp; 105 } 106 107 if (context == NULL 108 || fetch_register_banks(proc, context) < 0) { 109 free(context); 110 return NULL; 111 } 112 113 if (ret_info->type == ARGTYPE_STRUCT 114 || ret_info->type == ARGTYPE_ARRAY) { 115 size_t sz = type_sizeof(proc, ret_info); 116 assert(sz != (size_t)-1); 117 if (sz > 4) { 118 /* XXX double cast */ 119 context->ret_struct 120 = (arch_addr_t)context->regs.uregs[0]; 121 context->ncrn++; 122 } 123 } 124 125 return context; 126 } 127 128 struct fetch_context * 129 arch_fetch_arg_clone(struct process *proc, 130 struct fetch_context *context) 131 { 132 struct fetch_context *clone = malloc(sizeof(*context)); 133 if (clone == NULL) 134 return NULL; 135 *clone = *context; 136 return clone; 137 } 138 139 /* 0 is success, 1 is failure, negative value is an error. */ 140 static int 141 pass_in_vfp(struct fetch_context *ctx, struct process *proc, 142 enum arg_type type, size_t count, struct value *valuep) 143 { 144 assert(type == ARGTYPE_FLOAT || type == ARGTYPE_DOUBLE); 145 unsigned max = type == ARGTYPE_DOUBLE ? NUM_VFP_REGS : 2 * NUM_VFP_REGS; 146 if (count > max) 147 return 1; 148 149 size_t i; 150 size_t j; 151 for (i = 0; i < max; ++i) { 152 for (j = i; j < i + count; ++j) 153 if ((type == ARGTYPE_DOUBLE && ctx->alloc.d[j] != 0) 154 || (type == ARGTYPE_FLOAT && ctx->alloc.s[j] != 0)) 155 goto next; 156 157 /* Found COUNT consecutive unallocated registers at I. */ 158 const size_t sz = (type == ARGTYPE_FLOAT ? 4 : 8) * count; 159 unsigned char *data = value_reserve(valuep, sz); 160 if (data == NULL) 161 return -1; 162 163 for (j = i; j < i + count; ++j) 164 if (type == ARGTYPE_DOUBLE) 165 ctx->alloc.d[j] = -1; 166 else 167 ctx->alloc.s[j] = -1; 168 169 if (type == ARGTYPE_DOUBLE) 170 memcpy(data, ctx->fpregs.d + i, sz); 171 else 172 memcpy(data, ctx->fpregs.s + i, sz); 173 174 return 0; 175 176 next: 177 continue; 178 } 179 return 1; 180 } 181 182 /* 0 is success, 1 is failure, negative value is an error. */ 183 static int 184 consider_vfp(struct fetch_context *ctx, struct process *proc, 185 struct arg_type_info *info, struct value *valuep) 186 { 187 struct arg_type_info *float_info = NULL; 188 size_t hfa_size = 1; 189 if (info->type == ARGTYPE_FLOAT || info->type == ARGTYPE_DOUBLE) 190 float_info = info; 191 else 192 float_info = type_get_hfa_type(info, &hfa_size); 193 194 if (float_info != NULL && hfa_size <= 4) 195 return pass_in_vfp(ctx, proc, float_info->type, 196 hfa_size, valuep); 197 return 1; 198 } 199 200 int 201 arch_fetch_arg_next(struct fetch_context *ctx, enum tof type, 202 struct process *proc, 203 struct arg_type_info *info, struct value *valuep) 204 { 205 const size_t sz = type_sizeof(proc, info); 206 assert(sz != (size_t)-1); 207 208 if (ctx->hardfp && !ctx->in_varargs) { 209 int rc; 210 if ((rc = consider_vfp(ctx, proc, info, valuep)) != 1) 211 return rc; 212 } 213 214 /* IHI0042E_aapcs: If the argument requires double-word 215 * alignment (8-byte), the NCRN is rounded up to the next even 216 * register number. */ 217 const size_t al = type_alignof(proc, info); 218 assert(al != (size_t)-1); 219 if (al == 8) 220 ctx->ncrn = ((ctx->ncrn + 1) / 2) * 2; 221 222 /* If the size in words of the argument is not more than r4 223 * minus NCRN, the argument is copied into core registers, 224 * starting at the NCRN. */ 225 /* If the NCRN is less than r4 and the NSAA is equal to the 226 * SP, the argument is split between core registers and the 227 * stack. */ 228 229 const size_t words = (sz + 3) / 4; 230 if (ctx->ncrn < 4 && ctx->nsaa == ctx->sp) { 231 unsigned char *data = value_reserve(valuep, words * 4); 232 if (data == NULL) 233 return -1; 234 size_t i; 235 for (i = 0; i < words && ctx->ncrn < 4; ++i) { 236 memcpy(data, &ctx->regs.uregs[ctx->ncrn++], 4); 237 data += 4; 238 } 239 const size_t rest = (words - i) * 4; 240 if (rest > 0) { 241 umovebytes(proc, ctx->nsaa, data, rest); 242 ctx->nsaa += rest; 243 } 244 return 0; 245 } 246 247 assert(ctx->ncrn == 4); 248 249 /* If the argument required double-word alignment (8-byte), 250 * then the NSAA is rounded up to the next double-word 251 * address. */ 252 if (al == 8) 253 /* XXX double cast. */ 254 ctx->nsaa = (arch_addr_t)((((uintptr_t)ctx->nsaa + 7) / 8) * 8); 255 else 256 ctx->nsaa = (arch_addr_t)((((uintptr_t)ctx->nsaa + 3) / 4) * 4); 257 258 value_in_inferior(valuep, ctx->nsaa); 259 ctx->nsaa += sz; 260 261 return 0; 262 } 263 264 int 265 arch_fetch_retval(struct fetch_context *ctx, enum tof type, 266 struct process *proc, struct arg_type_info *info, 267 struct value *valuep) 268 { 269 if (fetch_register_banks(proc, ctx) < 0) 270 return -1; 271 272 if (ctx->hardfp && !ctx->in_varargs) { 273 int rc; 274 if ((rc = consider_vfp(ctx, proc, info, valuep)) != 1) 275 return rc; 276 } 277 278 size_t sz = type_sizeof(proc, info); 279 assert(sz != (size_t)-1); 280 281 switch (info->type) { 282 unsigned char *data; 283 284 case ARGTYPE_VOID: 285 return 0; 286 287 case ARGTYPE_FLOAT: 288 case ARGTYPE_DOUBLE: 289 if (ctx->hardfp && !ctx->in_varargs) { 290 unsigned char *data = value_reserve(valuep, sz); 291 if (data == NULL) 292 return -1; 293 memmove(data, &ctx->fpregs, sz); 294 return 0; 295 } 296 goto pass_in_registers; 297 298 case ARGTYPE_ARRAY: 299 case ARGTYPE_STRUCT: 300 if (sz > 4) { 301 value_in_inferior(valuep, ctx->ret_struct); 302 return 0; 303 } 304 /* Fall through. */ 305 306 case ARGTYPE_CHAR: 307 case ARGTYPE_SHORT: 308 case ARGTYPE_USHORT: 309 case ARGTYPE_INT: 310 case ARGTYPE_UINT: 311 case ARGTYPE_LONG: 312 case ARGTYPE_ULONG: 313 case ARGTYPE_POINTER: 314 pass_in_registers: 315 if ((data = value_reserve(valuep, sz)) == NULL) 316 return -1; 317 memmove(data, ctx->regs.uregs, sz); 318 return 0; 319 } 320 assert(info->type != info->type); 321 abort(); 322 } 323 324 void 325 arch_fetch_arg_done(struct fetch_context *context) 326 { 327 free(context); 328 } 329 330 int 331 arch_fetch_param_pack_start(struct fetch_context *context, 332 enum param_pack_flavor ppflavor) 333 { 334 if (ppflavor == PARAM_PACK_VARARGS) 335 context->in_varargs = true; 336 return 0; 337 } 338 339 void 340 arch_fetch_param_pack_end(struct fetch_context *context) 341 { 342 context->in_varargs = false; 343 } 344