Home | History | Annotate | Download | only in metag
      1 /*
      2  * This file is part of ltrace.
      3  *
      4  * Copyright (C) 2013 Imagination Technologies Ltd.
      5  *
      6  * This program is free software; you can redistribute it and/or
      7  * modify it under the terms of the GNU General Public License
      8  * version 2 as published by the Free Software Foundation.
      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 "config.h"
     22 
     23 #include <sys/types.h>
     24 #include <sys/wait.h>
     25 #include <signal.h>
     26 #include <sys/ptrace.h>
     27 #include <linux/uio.h>
     28 #include <asm/ptrace.h>
     29 #include <assert.h>
     30 
     31 #include "proc.h"
     32 #include "common.h"
     33 
     34 #define METAG_INSN_SIZE	4
     35 #define N_UNITS 2
     36 #define REG_SIZE 4
     37 
     38 /* unit codes  */
     39 enum metag_unitnum {
     40 	METAG_UNIT_CT,       /* 0x0 */
     41 	METAG_UNIT_D0,
     42 	METAG_UNIT_D1,
     43 	METAG_UNIT_A0,
     44 	METAG_UNIT_A1,       /* 0x4 */
     45 	METAG_UNIT_PC,
     46 	METAG_UNIT_RA,
     47 	METAG_UNIT_TR,
     48 	METAG_UNIT_TT,       /* 0x8 */
     49 	METAG_UNIT_FX,
     50 	METAG_UNIT_MAX,
     51 };
     52 
     53 /**
     54     \param proc The process that had an event.
     55 
     56     Called by \c next_event() right after the return from wait.
     57  */
     58 void
     59 get_arch_dep(struct process *proc)
     60 {
     61 
     62 }
     63 
     64 /**
     65     \param proc Process that had event.
     66     \param status From \c\ waitpid().
     67     \param sysnum 0-based syscall number.
     68     \return 1 if syscall, 2 if sysret, 0 otherwise.
     69 
     70     Called by \c next_event() after the call to get_arch_dep().
     71 
     72  */
     73 int
     74 syscall_p(struct process *proc, int status, int *sysnum)
     75 {
     76 	if (WIFSTOPPED(status)
     77 	    && WSTOPSIG(status) == (SIGTRAP | proc->tracesysgood)) {
     78 		struct user_gp_regs regs;
     79 		struct iovec iov;
     80 
     81 		/* Get GP registers.  */
     82 		iov.iov_base = &regs;
     83 		iov.iov_len = sizeof(regs);
     84 		if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS,
     85 			   (long)&iov))
     86 			return -1;
     87 
     88 		/* Fetch the SWITCH instruction.  */
     89 		unsigned int insn = ptrace(PTRACE_PEEKTEXT, proc->pid, regs.pc,
     90 					   0);
     91 		*sysnum = regs.dx[0][1];
     92 
     93 		if (insn != 0xaf440001) {
     94 			/* Check if we're returning from the system call.  */
     95 			insn = ptrace(PTRACE_PEEKTEXT, proc->pid, regs.pc - 4,
     96 				      0);
     97 			if (insn == 0xaf440001)
     98 				return 2;
     99 
    100 			return 0;
    101 		}
    102 
    103 		if (*sysnum >= 0)
    104 			return 1;
    105 	}
    106 	return 0;
    107 }
    108 
    109 /* 2-bit base unit (BU) mapping.  */
    110 static enum metag_unitnum metag_bu_map[4] = {
    111 	METAG_UNIT_A1,
    112 	METAG_UNIT_D0,
    113 	METAG_UNIT_D1,
    114 	METAG_UNIT_A0,
    115 };
    116 
    117 static int
    118 get_regval_from_unit(enum metag_unitnum unit, unsigned int reg,
    119 		     struct user_gp_regs *regs)
    120 {
    121 	/*
    122 	 * Check if reg has a sane value.
    123 	 * We do have N_UNITS, each one having X registers
    124 	 * and each register is REG_SIZE bytes.
    125 	 */
    126 	if ((unit == METAG_UNIT_A0) || (unit == METAG_UNIT_A1)) {
    127 		if (reg >= ((sizeof(regs->ax)/N_UNITS/REG_SIZE)))
    128 			goto bad_reg;
    129 	} else if ((unit == METAG_UNIT_D0) || (unit == METAG_UNIT_D1)) {
    130 		if (reg >= ((sizeof(regs->dx)/N_UNITS/REG_SIZE)))
    131 			goto bad_reg;
    132 	}
    133 
    134 	switch(unit) {
    135 	case METAG_UNIT_A1:
    136 		return regs->ax[reg][1];
    137 	case METAG_UNIT_D0:
    138 		return regs->dx[reg][0];
    139 	case METAG_UNIT_D1:
    140 		return regs->dx[reg][1];
    141 	case METAG_UNIT_A0:
    142 		return regs->ax[reg][0];
    143 	/* We really shouldn't be here.  */
    144 	default:
    145 		assert(unit != unit);
    146 		abort();
    147 	}
    148 	return 0;
    149 
    150 bad_reg:
    151 	fprintf(stderr,
    152 		"Reading from register %d of unit %d is not implemented.",
    153 		reg, unit);
    154 	return 0;
    155 
    156 }
    157 
    158 static int
    159 metag_next_pcs(struct process *proc, uint32_t pc, uint32_t *newpc)
    160 {
    161 	uint32_t inst;
    162 	int nr = 0, imm, reg_val;
    163 	unsigned int unit = 0, reg;
    164 	struct user_gp_regs regs;
    165 	struct iovec iov;
    166 
    167 	inst = ptrace(PTRACE_PEEKTEXT, proc->pid, pc, 0);
    168 
    169 	if (inst == 0xa0fffffe) { /* NOP (Special branch instruction) */
    170 		newpc[nr++] = pc + 4;
    171 	} else if ((inst & 0xff000000) == 0xa0000000) {
    172 		/* Matching 0xA 0x0 for opcode for B #S19 or B<cc> #S19.
    173 		 *
    174 		 * Potential Targets:
    175 		 * - pc + #S19 * METAG_INSN_SIZE if R=1 or <CC> true
    176 		 * - pc + 4  */
    177 		imm = ((inst << 8) >> 13) * METAG_INSN_SIZE;
    178 		newpc[nr++] = pc + imm;
    179 		newpc[nr++] = pc + 4;
    180 	} else if ((inst & 0xff000000) == 0xac000000) {
    181 		/* Matching 0xA 0xC for opcode.
    182 		 * JUMP BBx.r,#X16 or CALL BBx.r,#X16
    183 		 *
    184 		 * pc = reg + #x16 (aligned)  */
    185 		imm = (inst >> 3) & 0xffff;
    186 		reg = (inst >> 19) & 0x1f;
    187 		unit = metag_bu_map[inst & 0x3];
    188 		iov.iov_base = &regs;
    189 		iov.iov_len = sizeof(regs);
    190 		if (ptrace(PTRACE_GETREGSET, proc->pid,
    191 			   NT_PRSTATUS, (long)&iov))
    192 			goto ptrace_fail;
    193 
    194 		reg_val = get_regval_from_unit(unit, reg, &regs);
    195 		newpc[nr++] = (reg_val + imm) & -METAG_INSN_SIZE;
    196 	} else if ((inst & 0xff000000) == 0xab000000) {
    197 		/* Matching 0xA 0xB for opcode.
    198 		 *
    199 		 * CALLR BBx.r,#S19  */
    200 		imm = ((inst << 8) >> 13) * METAG_INSN_SIZE;
    201 		newpc[nr++] = pc + imm;
    202 	} else if ((inst & 0xff0001e0) == 0xa30000a0) {
    203 		/*
    204 		 * Matching 0xA 0x3 for opcode and then
    205 		 * Ud (bit 8-5) = 0x5 = METAG_UNIT_PC
    206 		 *
    207 		 * Potential MOV PC,.. or SWAP<cc> PC,.. or SWAP<cc> ..,PC
    208 		 */
    209 
    210 		iov.iov_base = &regs;
    211 		iov.iov_len = sizeof(regs);
    212 		if (ptrace(PTRACE_GETREGSET, proc->pid,
    213 			   NT_PRSTATUS, (long)&iov))
    214 			goto ptrace_fail;
    215 
    216 		/*
    217 		 * Maybe PC is the source register for a SWAP?
    218 		 * bit9 = 1 and bit13-10(Us) == METAG_UNIT_PC
    219 		 */
    220 		if (((inst >> 9 ) & 0x1) &&
    221 		    (((inst >> 10) & 0xf) == METAG_UNIT_PC)) {
    222 			/* PC will get its value from the
    223 			 * destination register.  */
    224 			reg = (inst >> 14) & 0x1f;
    225 			unit = (inst >> 5) & 0xf;
    226 		} else { /* PC is the destination register.
    227 			  * Find the source register.  */
    228 			reg = (inst >> 19) & 0x1f;
    229 			unit = (inst >> 10) & 0xf;
    230 		}
    231 
    232 		switch(unit) {
    233 		case METAG_UNIT_D0:
    234 		case METAG_UNIT_D1:
    235 		case METAG_UNIT_A0:
    236 		case METAG_UNIT_A1:
    237 			reg_val = get_regval_from_unit(unit, reg, &regs);
    238 			break;
    239 		case METAG_UNIT_PC:
    240 			reg_val = regs.pc;
    241 			break;
    242 		default:
    243 			goto unhandled;
    244 		}
    245 		newpc[nr++] = reg_val;
    246 		/* In case it is a conditional instruction.  */
    247 		newpc[nr++] = pc + 4;
    248 	} else if ((inst & 0xff00001f) == 0xc600000a){
    249 		/* Matching 0xC 0x{4,6} for opcode
    250 		 * and UD == 0x5 == METAG_UNIT_PC
    251 		 *
    252 		 * GETD PC, [A0.r + #S6] or
    253 		 * GETD PC, [A0.r + A0.r]  */
    254 		unit = metag_bu_map[(inst >> 5) & 0x3];
    255 		iov.iov_base = &regs;
    256 		iov.iov_len = sizeof(regs);
    257 		reg = (inst >> 14) & 0x1f;
    258 		imm = (inst << 18) >> 5; /* sign-extend it */
    259 		if (ptrace(PTRACE_GETREGSET, proc->pid,
    260 			   NT_PRSTATUS, (long)&iov))
    261 			goto ptrace_fail;
    262 		reg_val = get_regval_from_unit(unit, reg, &regs) + imm;
    263 		/* See where reg_val actually points to.  */
    264 		newpc[nr++] = ptrace(PTRACE_PEEKTEXT, proc->pid, reg_val, 0);
    265 	} else if (((inst & 0xfe0001e0) == 0x840000a0) || /* ADDcc R, A, R */
    266 		   ((inst & 0xfe00003f) == 0x8600002a) || /* ADD R, A, #X8 */
    267 		   ((inst & 0xfe0001e0) == 0x8c0000a0) || /* SUBcc R, A, R */
    268 		   ((inst & 0xfe00003f) == 0x8e00002a) || /* SUB R, A, #X8 */
    269 		   ((inst & 0xf40001e0) == 0x040000a0) || /* ADDcc R, D, D */
    270 		   ((inst & 0xfe00003f) == 0x0600002a) || /* ADD R, D, #X8 */
    271 		   ((inst & 0xf40001e0) == 0x140000a0) || /* SUBcc R, D, D */
    272 		   ((inst & 0xf600003f) == 0x1600002a)) { /* SUB R, D, #X8 */
    273 
    274 		/* bits4-1(Ud) == METAG_UNIT_PC */
    275 
    276 		int src1, src2, pc_src1 = 0, pc_src2 = 0, is_aunit = 0;
    277 		int umask = 0, optype = 0;
    278 
    279 		/* Look for O2R bit */
    280 		if ((((inst >> 24) & 0x6) == 0x4) && (inst & 0x1))
    281 			goto unhandled;
    282 
    283 		iov.iov_base = &regs;
    284 		iov.iov_len = sizeof(regs);
    285 		if (ptrace(PTRACE_GETREGSET, proc->pid,
    286 			   NT_PRSTATUS, (long)&iov))
    287 			goto ptrace_fail;
    288 
    289 		/* Figure out unit for source registers based on the opcode.  */
    290 		switch((inst >> 28) & 0xf) {
    291 		case 0: /* ADD<cc> Rx.r, Dx.r, De.r|#X8 */
    292 		case 1: /* SUB<cc> Rx.r, Dx.r, De.r|#X8 */
    293 			unit = METAG_UNIT_D0 + ((inst >> 24) & 0x1);
    294 			is_aunit = 0;
    295 			umask = 0x1f;
    296 			optype = (inst >> 28) & 0x1;
    297 			break;
    298 		case 8:
    299 			unit = METAG_UNIT_A0 + ((inst >> 24) & 0x1);
    300 			is_aunit = 1;
    301 			umask = 0xf;
    302 			optype = (inst >> 27) & 0x1;
    303 			break;
    304 		}
    305 
    306 		/* Get pc bits (if any).  */
    307 		if (is_aunit) {
    308 			pc_src1 = (inst >> 18) & 0x1;
    309 			pc_src2 = (inst >> 13) & 0x1;
    310 		}
    311 
    312 		/* Determine ADD|SUB format. Immediate or register ?  */
    313 		if ((inst >> 25) & 0x1) { /* ADD|SUB cc PC, X, #imm8 */
    314 			src2 = (inst >> 6) & 0xff; /* so we can share code.  */
    315 			reg = (inst >> 14) & umask;
    316 			if (pc_src1)	/* This can only be true for AU ops.  */
    317 				src1 = regs.pc;
    318 			else		/* This covers both AU an DU ops.  */
    319 				src1 = get_regval_from_unit(unit, reg, &regs);
    320 		} else { /* ADD|SUB cc PC, X, X */
    321 			if (pc_src1)
    322 				src1 = regs.pc;
    323 			else
    324 				src1 = get_regval_from_unit(unit, (inst >> 14)
    325 							    & umask, &regs);
    326 			if (pc_src2)
    327 				src2 = regs.pc;
    328 			else
    329 				src2 = get_regval_from_unit(unit, (inst >> 9)
    330 							    & umask, &regs);
    331 		}
    332 
    333 		/* Construct the new PC.  */
    334 		if (optype)
    335 			/* SUB */
    336 			newpc[nr++] = src1 - src2;
    337 		else 	/* ADD */
    338 			newpc[nr++] = src1 + src2;
    339 		/* Conditional instruction so PC may not change.  */
    340 		newpc[nr++] = pc + 4;
    341 	} else {
    342 		newpc[nr++] = pc + 4;
    343 	}
    344 
    345 	if (nr <= 0 || nr > 2)
    346 		goto fail;
    347 	if (nr == 2 && newpc[1] == 0)
    348 		goto fail;
    349 
    350 	return nr;
    351 
    352 ptrace_fail:
    353 	fprintf(stderr, "Failed to read the registers pid=%d @ pc=0x%08x\n",
    354 		proc->pid, pc);
    355 	return 0;
    356 unhandled:
    357 	fprintf(stderr, "Unhandled instruction: pc=0x%08x, inst=0x%08x\n",
    358 		pc, inst);
    359 	return 0;
    360 fail:
    361 	fprintf(stderr, "nr=%d pc=0x%08x\n", nr, pc);
    362 	fprintf(stderr, "newpc=0x%08x 0x%08x\n", newpc[0], newpc[1]);
    363 	return 0;
    364 
    365 }
    366 
    367 enum sw_singlestep_status
    368 arch_sw_singlestep(struct process *proc, struct breakpoint *bp,
    369 		   int (*add_cb)(arch_addr_t, struct sw_singlestep_data *),
    370 		   struct sw_singlestep_data *add_cb_data)
    371 {
    372 	arch_addr_t pc = get_instruction_pointer(proc);
    373 	uint32_t newpcs[2];
    374 	int nr;
    375 
    376 	nr = metag_next_pcs(proc, (uint32_t)pc, newpcs);
    377 
    378 	while (nr-- > 0) {
    379 		arch_addr_t baddr = (arch_addr_t) newpcs[nr];
    380 		if (dict_find(proc->leader->breakpoints, &baddr) != NULL) {
    381 			fprintf(stderr, "skip %p %p\n", baddr, add_cb_data);
    382 			continue;
    383 		}
    384 
    385 		if (add_cb(baddr, add_cb_data) < 0)
    386 			return SWS_FAIL;
    387 	}
    388 
    389 	ptrace(PTRACE_SYSCALL, proc->pid, 0, 0);
    390 	return SWS_OK;
    391 }
    392 
    393 long
    394 gimme_arg(enum tof type, struct process *proc, int arg_num,
    395 	  struct arg_type_info *info)
    396 {
    397 	long ret;
    398 	struct user_gp_regs regs;
    399 	struct iovec iov;
    400 
    401 	/* get GP registers */
    402 	iov.iov_base = &regs;
    403 	iov.iov_len = sizeof(regs);
    404 	if (ptrace(PTRACE_GETREGSET, proc->pid, NT_PRSTATUS, (long)&iov))
    405 		return 0;
    406 
    407 	debug(2, "type %d arg %d arg",type, arg_num);
    408 	if (type == LT_TOF_FUNCTION || type == LT_TOF_SYSCALL) {
    409 		if (arg_num < 6) {
    410 			/* Args go backwards starting from D1Ar1 (D1.3) */
    411 			ret = ((unsigned long *)&regs.dx[3][1])[-arg_num];
    412 			debug(2,"ret = %#lx",ret);
    413 			return ret;
    414 		} else {
    415 			return 0;
    416 		}
    417 	}
    418 	if (arg_num >= 0) {
    419 		fprintf(stderr,"args on return?");
    420 	}
    421 	if (type == LT_TOF_FUNCTIONR || type == LT_TOF_SYSCALLR) {
    422 		return regs.dx[0][0]; /* D0Re0 (D0.0) */
    423 	}
    424 
    425 	fprintf(stderr, "gimme_arg called with wrong arguments\n");
    426 
    427 	return 0;
    428 }
    429