Skip to content
Snippets Groups Projects
bedbug.c 29.9 KiB
Newer Older
  • Learn to ignore specific revisions
  • Wolfgang Denk's avatar
    Wolfgang Denk committed
    	if (*txt == '-') {
    		is_neg = 1;
    		++txt;
    	}
    
    	if (txt[0] == '0' && (txt[1] == 'x' || txt[1] == 'X'))	/* hex */
    		val = simple_strtoul (&txt[2], NULL, 16);
    	else						/* decimal */
    		val = simple_strtoul (txt, NULL, 10);
    
    	if (is_neg)
    		val = -val;
    
    	return val;
    }								/* read_number */
    
    
    int downstring (char *s)
    {
    	if (!s || !*s)
    		return 0;
    
    	while (*s) {
    		if (isupper (*s))
    			*s = tolower (*s);
    		s++;
    	}
    
    	return 0;
    }								/* downstring */
    
    
    
    /*======================================================================
     * Examines the instruction at the current address and determines the
     * next address to be executed.  This will take into account branches
     * of different types so that a "step" and "next" operations can be
     * supported.
     *
     * Arguments:
     *	nextaddr	The address (to be filled in) of the next
     *			instruction to execute.  This will only be a valid
    
    York Sun's avatar
    York Sun committed
     *			address if true is returned.
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
     *
     *	step_over	A flag indicating how to compute addresses for
     *			branch statements:
    
    York Sun's avatar
    York Sun committed
     *			 true  = Step over the branch (next)
     *			 false = step into the branch (step)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
     *
    
    York Sun's avatar
    York Sun committed
     * Returns true if it was able to compute the address.  Returns false if
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
     * it has a problem reading the current instruction or one of the registers.
     */
    
    int find_next_address (unsigned char *nextaddr, int step_over,
    					   struct pt_regs *regs)
    {
    	unsigned long pc;			/* SRR0 register from PPC */
    	unsigned long ctr;			/* CTR register from PPC */
    	unsigned long cr;			/* CR register from PPC */
    	unsigned long lr;			/* LR register from PPC */
    	unsigned long instr;		/* instruction at SRR0 */
    	unsigned long next;			/* computed instruction for 'next' */
    	unsigned long step;			/* computed instruction for 'step' */
    	unsigned long addr = 0;		/* target address operand */
    	unsigned long aa = 0;		/* AA operand */
    	unsigned long lk = 0;		/* LK operand */
    	unsigned long bo = 0;		/* BO operand */
    	unsigned long bi = 0;		/* BI operand */
    	struct opcode *op = 0;		/* opcode structure for 'instr' */
    	int ctr_ok = 0;
    	int cond_ok = 0;
    	int conditional = 0;
    	int branch = 0;
    
      /*------------------------------------------------------------*/
    
    	if (nextaddr == 0 || regs == 0) {
    		printf ("find_next_address: bad args");
    
    York Sun's avatar
    York Sun committed
    		return false;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	}
    
    	pc = regs->nip & 0xfffffffc;
    	instr = INSTRUCTION (pc);
    
    	if ((op = find_opcode (instr)) == (struct opcode *) 0) {
    		printf ("find_next_address: can't parse opcode 0x%lx", instr);
    
    York Sun's avatar
    York Sun committed
    		return false;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    	}
    
    	ctr = regs->ctr;
    	cr = regs->ccr;
    	lr = regs->link;
    
    	switch (op->opcode) {
    	case B_OPCODE (16, 0, 0):	/* bc */
    	case B_OPCODE (16, 0, 1):	/* bcl */
    	case B_OPCODE (16, 1, 0):	/* bca */
    	case B_OPCODE (16, 1, 1):	/* bcla */
    		if (!get_operand_value (op, instr, O_BD, &addr) ||
    			!get_operand_value (op, instr, O_BO, &bo) ||
    			!get_operand_value (op, instr, O_BI, &bi) ||
    			!get_operand_value (op, instr, O_AA, &aa) ||
    			!get_operand_value (op, instr, O_LK, &lk))
    
    York Sun's avatar
    York Sun committed
    			return false;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    		if ((addr & (1 << 13)) != 0)
    			addr = addr - (1 << 14);
    		addr <<= 2;
    		conditional = 1;
    		branch = 1;
    		break;
    
    	case I_OPCODE (18, 0, 0):	/* b */
    	case I_OPCODE (18, 0, 1):	/* bl */
    	case I_OPCODE (18, 1, 0):	/* ba */
    	case I_OPCODE (18, 1, 1):	/* bla */
    		if (!get_operand_value (op, instr, O_LI, &addr) ||
    			!get_operand_value (op, instr, O_AA, &aa) ||
    			!get_operand_value (op, instr, O_LK, &lk))
    
    York Sun's avatar
    York Sun committed
    			return false;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    		if ((addr & (1 << 23)) != 0)
    			addr = addr - (1 << 24);
    		addr <<= 2;
    		conditional = 0;
    		branch = 1;
    		break;
    
    	case XL_OPCODE (19, 528, 0):	/* bcctr */
    	case XL_OPCODE (19, 528, 1):	/* bcctrl */
    		if (!get_operand_value (op, instr, O_BO, &bo) ||
    			!get_operand_value (op, instr, O_BI, &bi) ||
    			!get_operand_value (op, instr, O_LK, &lk))
    
    York Sun's avatar
    York Sun committed
    			return false;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    		addr = ctr;
    		aa = 1;
    		conditional = 1;
    		branch = 1;
    		break;
    
    	case XL_OPCODE (19, 16, 0):	/* bclr */
    	case XL_OPCODE (19, 16, 1):	/* bclrl */
    		if (!get_operand_value (op, instr, O_BO, &bo) ||
    			!get_operand_value (op, instr, O_BI, &bi) ||
    			!get_operand_value (op, instr, O_LK, &lk))
    
    York Sun's avatar
    York Sun committed
    			return false;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    
    		addr = lr;
    		aa = 1;
    		conditional = 1;
    		branch = 1;
    		break;
    
    	default:
    		conditional = 0;
    		branch = 0;
    		break;
    	}
    
    	if (conditional) {
    		switch ((bo & 0x1e) >> 1) {
    		case 0:				/* 0000y */
    			if (--ctr != 0)
    				ctr_ok = 1;
    
    			cond_ok = !(cr & (1 << (31 - bi)));
    			break;
    
    		case 1:				/* 0001y */
    			if (--ctr == 0)
    				ctr_ok = 1;
    
    			cond_ok = !(cr & (1 << (31 - bi)));
    			break;
    
    		case 2:				/* 001zy */
    			ctr_ok = 1;
    			cond_ok = !(cr & (1 << (31 - bi)));
    			break;
    
    		case 4:				/* 0100y */
    			if (--ctr != 0)
    				ctr_ok = 1;
    
    			cond_ok = cr & (1 << (31 - bi));
    			break;
    
    		case 5:				/* 0101y */
    			if (--ctr == 0)
    				ctr_ok = 1;
    
    			cond_ok = cr & (1 << (31 - bi));
    			break;
    
    		case 6:				/* 011zy */
    			ctr_ok = 1;
    			cond_ok = cr & (1 << (31 - bi));
    			break;
    
    		case 8:				/* 1z00y */
    			if (--ctr != 0)
    				ctr_ok = cond_ok = 1;
    			break;
    
    		case 9:				/* 1z01y */
    			if (--ctr == 0)
    				ctr_ok = cond_ok = 1;
    			break;
    
    		case 10:				/* 1z1zz */
    			ctr_ok = cond_ok = 1;
    			break;
    		}
    	}
    
    	if (branch && (!conditional || (ctr_ok && cond_ok))) {
    		if (aa)
    			step = addr;
    		else
    			step = addr + pc;
    
    		if (lk)
    			next = pc + 4;
    		else
    			next = step;
    	} else {
    		step = next = pc + 4;
    	}
    
    
    York Sun's avatar
    York Sun committed
    	if (step_over == true)
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    		*(unsigned long *) nextaddr = next;
    	else
    		*(unsigned long *) nextaddr = step;
    
    
    York Sun's avatar
    York Sun committed
    	return true;
    
    Wolfgang Denk's avatar
    Wolfgang Denk committed
    }								/* find_next_address */
    
    
    /*
     * Copyright (c) 2000 William L. Pitts and W. Gerald Hicks
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms are freely
     * permitted provided that the above copyright notice and this
     * paragraph and the following disclaimer are duplicated in all
     * such forms.
     *
     * This software is provided "AS IS" and without any express or
     * implied warranties, including, without limitation, the implied
     * warranties of merchantability and fitness for a particular
     * purpose.
     */