static inline void
handle_syscall_restart(unsigned long save_r0, struct pt_regs *regs,
		       struct sigaction *sa)
{
	/* If we're not from a syscall, bail out */
	if (regs->tra < 0)
		return;

	/* check for system call restart.. */
	switch (regs->regs[0]) {
		case -ERESTART_RESTARTBLOCK:
		case -ERESTARTNOHAND:
		no_system_call_restart:
			regs->regs[0] = -EINTR;
			break;

		case -ERESTARTSYS:
			if (!(sa->sa_flags & SA_RESTART))
				goto no_system_call_restart;
		/* fallthrough */
		case -ERESTARTNOINTR:
			regs->regs[0] = save_r0;
			regs->pc -= instruction_size(__raw_readw(regs->pc - 4));
			break;
	}
}
Exemple #2
0
/*
 * Note that 'init' is a special process: it doesn't get signals it doesn't
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 * mistake.
 *
 * Note that we go through the signals twice: once to check the signals that
 * the kernel can handle, and then we build all the user-level signal handling
 * stack-frames in one go after that.
 */
static void do_signal(struct pt_regs *regs, unsigned int save_r0)
{
	siginfo_t info;
	int signr;
	struct k_sigaction ka;

	/*
	 * We want the common case to go fast, which
	 * is why we may in certain cases get here from
	 * kernel mode. Just return without doing anything
	 * if so.
	 */
	if (!user_mode(regs))
		return;

	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
	if (signr > 0) {
		handle_syscall_restart(save_r0, regs, &ka.sa);

		/* Whee!  Actually deliver the signal.  */
		handle_signal(signr, &ka, &info, regs, save_r0);
		return;
	}

	/* Did we come from a system call? */
	if (regs->tra >= 0) {
		/* Restart the system call - no handlers present */
		if (regs->regs[0] == -ERESTARTNOHAND ||
		    regs->regs[0] == -ERESTARTSYS ||
		    regs->regs[0] == -ERESTARTNOINTR) {
			regs->regs[0] = save_r0;
			regs->pc -= instruction_size(__raw_readw(regs->pc - 4));
		} else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) {
			regs->pc -= instruction_size(__raw_readw(regs->pc - 4));
			regs->regs[3] = __NR_restart_syscall;
		}
	}

	/*
	 * If there's no signal to deliver, we just put the saved sigmask
	 * back.
	 */
	restore_saved_sigmask();
}
Exemple #3
0
static void handle_BUG(struct pt_regs *regs)
{
    enum bug_trap_type tt;
    tt = report_bug(regs->pc, regs);
    if (tt == BUG_TRAP_TYPE_WARN) {
        regs->pc += instruction_size(regs->pc);
        return;
    }

    die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
}
Exemple #4
0
  void assert_index_size(int required_size) const {
#ifdef ASSERT
    int isize = instruction_size() - (is_wide() ? 1 : 0) - 1;
    if (isize == 2 &&  cur_bc() == Bytecodes::_iinc)
      isize = 1;
    else if (isize <= 2)
      ;                         // no change
    else if (has_giant_index())
      isize = 4;
    else
      isize = 2;
    assert(isize = required_size, "wrong index size");
#endif
  }
Exemple #5
0
Fichier : cpu.c Projet : ezrec/vasm
/* Convert an instruction into a DATA atom including relocations,
   if necessary. */
dblock *eval_instruction(instruction *p,section *sec,taddr pc)
{
  /* Auch simpel. Fehlerchecks fehlen. */
  taddr size=instruction_size(p,sec,pc);
  dblock *db=new_dblock();
  int c=opt_inst(p,sec,pc);
  char *d;
  taddr val;
  db->size=size;
  d=db->data=mymalloc(size);
  *d=c;
  if(p->qualifiers[0]){
    if(c>5)
      cpu_error(1,p->qualifiers[0]);
    else if(!strcmp(p->qualifiers[0],"b"))
      *d|=128;
    else if(strcmp(p->qualifiers[0],"w"))
      cpu_error(1,p->qualifiers[0]);
  }
  d++;
  if(c==5){
    /* addq */
    taddr val;
    if(!eval_expr(p->op[0]->offset,&val,sec,pc)||val>15)
      cpu_error(0);
    *d=((val<<4)|operand_code(p->op[1]));
    return db;
  }
  if(c==7){
    expr *tree=p->op[0]->offset;
    if(!(tree->type==SYM&&tree->c.sym->sec==sec&&tree->c.sym->type==LABSYM&&
	 tree->c.sym->pc-pc>=-128&&tree->c.sym->pc-pc<=127))
      cpu_error(0);
    else
      *d=tree->c.sym->pc-pc;
    return db;
  }

  *d=((operand_code(p->op[0])<<4)|operand_code(p->op[1]));
  d++;
  d=fill_operand(p->op[0],sec,pc,d,&db->relocs,d-db->data);
  d=fill_operand(p->op[1],sec,pc,d,&db->relocs,d-db->data);
  return db;
}
static void handle_BUG(struct pt_regs *regs)
{
	const struct bug_entry *bug;
	unsigned long bugaddr = regs->pc;
	enum bug_trap_type tt;

	if (!is_valid_bugaddr(bugaddr))
		goto invalid;

	bug = find_bug(bugaddr);

	/* Switch unwinders when unwind_stack() is called */
	if (bug->flags & BUGFLAG_UNWINDER)
		unwinder_faulted = 1;

	tt = report_bug(bugaddr, regs);
	if (tt == BUG_TRAP_TYPE_WARN) {
		regs->pc += instruction_size(bugaddr);
		return;
	}

invalid:
	die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
}
/*
 * Note that 'init' is a special process: it doesn't get signals it doesn't
 * want to handle. Thus you cannot kill init even with a SIGKILL even by
 * mistake.
 *
 * Note that we go through the signals twice: once to check the signals that
 * the kernel can handle, and then we build all the user-level signal handling
 * stack-frames in one go after that.
 */
static void do_signal(struct pt_regs *regs, unsigned int save_r0)
{
	siginfo_t info;
	int signr;
	struct k_sigaction ka;
	sigset_t *oldset;

	/*
	 * We want the common case to go fast, which
	 * is why we may in certain cases get here from
	 * kernel mode. Just return without doing anything
	 * if so.
	 */
	if (!user_mode(regs))
		return;

	if (current_thread_info()->status & TS_RESTORE_SIGMASK)
		oldset = &current->saved_sigmask;
	else
		oldset = &current->blocked;

	signr = get_signal_to_deliver(&info, &ka, regs, NULL);
	if (signr > 0) {
		handle_syscall_restart(save_r0, regs, &ka.sa);

		/* Whee!  Actually deliver the signal.  */
		if (handle_signal(signr, &ka, &info, oldset,
				  regs, save_r0) == 0) {
			/*
			 * A signal was successfully delivered; the saved
			 * sigmask will have been stored in the signal frame,
			 * and will be restored by sigreturn, so we can simply
			 * clear the TS_RESTORE_SIGMASK flag
			 */
			current_thread_info()->status &= ~TS_RESTORE_SIGMASK;

			tracehook_signal_handler(signr, &info, &ka, regs,
					test_thread_flag(TIF_SINGLESTEP));
		}

		return;
	}

	/* Did we come from a system call? */
	if (regs->tra >= 0) {
		/* Restart the system call - no handlers present */
		if (regs->regs[0] == -ERESTARTNOHAND ||
		    regs->regs[0] == -ERESTARTSYS ||
		    regs->regs[0] == -ERESTARTNOINTR) {
			regs->regs[0] = save_r0;
			regs->pc -= instruction_size(__raw_readw(regs->pc - 4));
		} else if (regs->regs[0] == -ERESTART_RESTARTBLOCK) {
			regs->pc -= instruction_size(__raw_readw(regs->pc - 4));
			regs->regs[3] = __NR_restart_syscall;
		}
	}

	/*
	 * If there's no signal to deliver, we just put the saved sigmask
	 * back.
	 */
	if (current_thread_info()->status & TS_RESTORE_SIGMASK) {
		current_thread_info()->status &= ~TS_RESTORE_SIGMASK;
		sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
	}
}
Exemple #8
0
void predict(Options::PredictEnum mode, ReportWriter *writer, const RomAccessor &rom, Trace &trace, const AnnotationResolver &annotations) {

	if (mode == Options::PRD_NEVER)
		return;

	bool limit_to_functions = mode == Options::PRD_FUNCTIONS;

	Profile profile("Predict", true);

	struct PredictBranch {
		const Annotation *annotation;
		Pointer from_pc;
		Pointer pc;
		uint16_t DP, P;
		uint8_t DB;
	};

	std::vector<PredictBranch> predict_brances;
	LargeBitfield has_op(256*64*1024);
	LargeBitfield inside_op(256 * 64 * 1024);

	for (auto opsit : trace.ops) {
		const Pointer pc = opsit.first;

		const Trace::OpVariantLookup &vl = opsit.second;
		const OpInfo &example = trace.variant(vl, 0);

		const uint8_t* data = rom.evalPtr(pc);
		const uint8_t opcode = data[0];

		uint32_t op_size = instruction_size(opcode, is_memory_accumulator_wide(example.P), is_index_wide(example.P));

		for (uint32_t i = 0; i < op_size; ++i) {
			has_op.set_bit(bank_add(pc, i));
			if (i!=0) inside_op.set_bit(bank_add(pc, i));
		}

		StringBuilder sb;

		Pointer target_jump, target_no_jump;
		bool branch_or_jump = decode_static_jump(opcode, rom, pc, &target_jump, &target_no_jump);

		const Hint *hint = annotations.hint(pc);
		if (hint && hint->has_hint(Hint::BRANCH_ALWAYS)) {
			target_no_jump = INVALID_POINTER;
		}
		if (hint && hint->has_hint(Hint::BRANCH_NEVER)) {
			target_jump = INVALID_POINTER;
		}

		if (!branch_or_jump)
			continue;

		const Annotation *source_annotation = nullptr, *target_annotation = nullptr;
		annotations.resolve_annotation(pc,          &source_annotation);

		if (target_jump != INVALID_POINTER) {
			trace.labels.set_bit(target_jump);
			annotations.resolve_annotation(target_jump, &target_annotation);
		}

		if (source_annotation || !limit_to_functions) {
			PredictBranch p;
			p.annotation = source_annotation;
			p.from_pc = pc;
			p.DB = example.DB;
			p.DP = example.DP;
			p.P  = example.P;
			if (target_jump != INVALID_POINTER && (target_annotation == source_annotation || !limit_to_functions)) {
				p.pc = target_jump;
				CUSTOM_ASSERT(target_jump != INVALID_POINTER);
				predict_brances.push_back(p);
			}
			if (target_no_jump != INVALID_POINTER && (!limit_to_functions || (target_no_jump >= source_annotation->startOfRange && target_no_jump <= source_annotation->endOfRange))) {
				// BRA,BRL and the jumps always branches/jumps
				p.pc = target_no_jump;
				CUSTOM_ASSERT(target_no_jump != INVALID_POINTER);
				predict_brances.push_back(p);
			}
		}
	}

	StringBuilder sb;
	sb.clear();

	if (writer)
		writer->writeSeperator("Prediction diagnostics");

	for (int pbi=0; pbi<(int)predict_brances.size(); ++pbi) {
		const PredictBranch pb = predict_brances[pbi];

		Pointer pc = pb.pc;
		Pointer r0 = limit_to_functions ? pb.annotation->startOfRange : 0, r1 = limit_to_functions ? pb.annotation->endOfRange : 0xFFFFFF;
		uint16_t P = pb.P, DP = pb.DP;
		uint8_t DB = pb.DB;

		bool P_unknown = false;

		if (inside_op[pc]) {
			if (writer) {
				sb.clear();
				sb.format("Predicted jump at %06X jumped inside instruction at %06X. Consider adding a \"hint branch_always/branch_never %06X\" annotation.", pc, pb.from_pc, pb.from_pc);
				writer->writeComment(sb);
			}
			printf("Warning; predicted jump went inside instruction at %06X (from %06X)\n", pc, pb.from_pc);
		}

		while (!has_op[pc] && pc >= r0 && pc <= r1) {

			// Make sure we don't run into a data scope
			const Annotation *data_scope = nullptr, *function_scope = nullptr;
			annotations.resolve_annotation(pc, &function_scope, &data_scope);
			if (data_scope)
				continue;
			if (function_scope && function_scope != pb.annotation)
				continue;

			uint8_t opcode = rom.evalByte(pc);

			bool abort_unknown_P = P_unknown;

			if (P_unknown) {
				switch(opcode) {
				case 0x02: // COP const
				case 0x40: // RTI
				case 0x6B: // RTL
				case 0x60: // RTS
				case 0x3B: // TSC
				case 0xBA: // TSX
				case 0x8A: // TXA
				case 0x9A: // TXS
				case 0x9B: // TXY
				case 0x98: // TYA
				case 0xBB: // TYX
				case 0xCB: // WAI
				case 0xEB: // XBA
				case 0xFB: // XCE
				case 0xAA: // TAX
				case 0xA8: // TAY
				case 0x5B: // TCD
				case 0x1B: // TCS
				case 0x7B: // TDC
				case 0xDB: // STP
				case 0x38: // SEC
				case 0xF8: // SED
				case 0x78: // SEI
				case 0xE2: // SEP
				case 0xC2: // REP
				case 0x18: // CLC
				case 0xD8: // CLD
				case 0x58: // CLI
				case 0xB8: // CLV
				case 0xCA: // DEX
				case 0x88: // DEY
				case 0xE8: // INX
				case 0xC8: // INY
				case 0xEA: // NOP
				case 0x8B: // PHB
				case 0x0B: // PHD
				case 0x4B: // PHK
				case 0x08: // PHP
				case 0xDA: // PHX
				case 0x5A: // PHY
				case 0x68: // PLA
				case 0xAB: // PLB
				case 0x2B: // PLD
				case 0x28: // PLP
				case 0xFA: // PLX
				case 0x7A: // PLY
					abort_unknown_P = false;
				}
			}

			if (abort_unknown_P) {
				if (writer) {
					sb.clear();
					sb.format("Aborting trace at %06X due to unknown processor status", pc);
					if (pb.annotation)
						sb.format("(in %s)", pb.annotation->name.c_str());
					writer->writeComment(sb);
				}
				break;
			}

			uint8_t operand = rom.evalByte(pc + 1);

			Pointer target_jump, target_no_jump;
			bool is_jump_or_branch = decode_static_jump(opcode, rom, pc, &target_jump, &target_no_jump);

			{
				Trace::OpVariantLookup l;
				l.count = 1;
				l.offset = (uint32_t)trace.ops_variants.size();
				trace.ops[pc] = l;
				OpInfo info;
				info.P = P_unknown ? 0 : P;
				info.DB = DB;
				info.DP = DP;
				info.X = info.Y = 0;
				info.jump_target = target_jump;
				info.indirect_base_pointer = INVALID_POINTER; // TODO: We should be able to set this one sometimes
				trace.ops_variants.push_back(info);

				// Note that DB and DP here represent a lie :)
			}

			const int op_size = instruction_size(rom.evalByte(pc), is_memory_accumulator_wide(P), is_index_wide(P));

			for (int i=0; i<op_size; ++i) {
				// TODO: We should do overlap test for entire range we are "using" now
				//       Also first might not always be best!
				trace.is_predicted.set_bit(bank_add(pc, i));
				has_op.set_bit(bank_add(pc, i));
				if (i != 0) inside_op.set_bit(bank_add(pc, i));
			}

			const Hint *hint = annotations.hint(pc);
			if (hint && hint->has_hint(Hint::BRANCH_NEVER)) {
				target_jump = INVALID_POINTER;
			}

			bool is_jsr = opcode == 0x20||opcode==0x22||opcode==0xFC;

			if (hint && hint->has_hint(Hint::JUMP_IS_JSR)) {
				 is_jump_or_branch = false;
				 is_jsr = true;
			}

			if (is_jump_or_branch) {
				const Annotation *function = nullptr;
				if (target_jump != INVALID_POINTER) {
					annotations.resolve_annotation(target_jump, &function);
					trace.labels.set_bit(target_jump);
				}

				if (limit_to_functions && writer && (!function || function != pb.annotation)) {
					sb.clear();
					sb.format("Branch going out of %s to ", pb.annotation->name.c_str());
					if (function) {
						sb.format("%s [%06X]", function->name.c_str(), target_jump);
					} else {
						sb.format("%06X", target_jump);
					}
					sb.format(". Not following due to range restriction.");
					writer->writeComment(sb);
				}
				
				if (target_jump != INVALID_POINTER) {
					PredictBranch npb = pb;
					npb.from_pc = pc;
					npb.pc = target_jump;
					predict_brances.push_back(npb);
				}

				if (hint && hint->has_hint(Hint::BRANCH_ALWAYS)) {
					// Never continoue after this op since it always diverges control flow
					continue;
				}

			} else if (opcode == 0xE2) {
				//	TODO:
				//	* When we get a REP or SEP parts or P become known again. We could track unknown per the three flags and update.
				//	* Updating DB/DP might be interesting
				if (operand & 0x10) P |= 0x0010;
				if (operand & 0x20) P |= 0x0020;
			} else if (opcode == 0xC2) {
				if (operand & 0x10) P &= ~0x0010;
				if (operand & 0x20) P &= ~0x0020;
			} else if (opcode == 0x28 || opcode == 0xFB) {
				P_unknown = true; // PLP or XCE
				// A jump or BRA, stop execution flow (not JSR or non-BRA-branch)
			} else if (opcode == 0x4C||opcode==0x5C||opcode==0x6C||opcode==0x7C||opcode==0x80) {
				if (writer && opcode != 0x80) {
					sb.clear();
					sb.format("Not following jump (opcode %02X) at %06X in %s. Only absolute jumps supported.", opcode, pc, pb.annotation->name.c_str());
					writer->writeComment(sb);
				}
				// TODO: if there is a trace annotation about jmp being jsr we could go on
				continue;
			} else if (is_jsr) {
				if (writer) {
					sb.clear();
					sb.format("Not following jump with subroutine (opcode %02X) at %06X", opcode, pc);
					if (pb.annotation)
						sb.format(" in %s.", pb.annotation->name.c_str());
					writer->writeComment(sb);
				}
			} else if (opcode == 0x40 || opcode == 0x6B || opcode == 0x60) {
				// some sort of return, stop execution flow
				continue;
			}
			pc += op_size;
		}
	}
}
Exemple #9
0
static int
handle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info,
	      sigset_t *oldset, struct pt_regs *regs, unsigned int save_r0)
{
	int ret;

	/* Are we from a system call? */
	if (regs->tra >= 0) {
		/* If so, check system call restarting.. */
		switch (regs->regs[0]) {
			case -ERESTART_RESTARTBLOCK:
			case -ERESTARTNOHAND:
				regs->regs[0] = -EINTR;
				break;

			case -ERESTARTSYS:
				if (!(ka->sa.sa_flags & SA_RESTART)) {
					regs->regs[0] = -EINTR;
					break;
				}
			/* fallthrough */
			case -ERESTARTNOINTR:
				regs->regs[0] = save_r0;
				regs->pc -= instruction_size(
						ctrl_inw(regs->pc - 4));
				break;
		}
	} else {
		/* gUSA handling */
#ifdef CONFIG_PREEMPT
		unsigned long flags;

		local_irq_save(flags);
#endif
		if (regs->regs[15] >= 0xc0000000) {
			int offset = (int)regs->regs[15];

			/* Reset stack pointer: clear critical region mark */
			regs->regs[15] = regs->regs[1];
			if (regs->pc < regs->regs[0])
				/* Go to rewind point #1 */
				regs->pc = regs->regs[0] + offset -
					instruction_size(ctrl_inw(regs->pc-4));
		}
#ifdef CONFIG_PREEMPT
		local_irq_restore(flags);
#endif
	}

	/* Set up the stack frame */
	if (ka->sa.sa_flags & SA_SIGINFO)
		ret = setup_rt_frame(sig, ka, info, oldset, regs);
	else
		ret = setup_frame(sig, ka, oldset, regs);

	if (ka->sa.sa_flags & SA_ONESHOT)
		ka->sa.sa_handler = SIG_DFL;

	if (ret == 0) {
		spin_lock_irq(&current->sighand->siglock);
		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
		if (!(ka->sa.sa_flags & SA_NODEFER))
			sigaddset(&current->blocked,sig);
		recalc_sigpending();
		spin_unlock_irq(&current->sighand->siglock);
	}

	return ret;
}
Exemple #10
0
static void assemble(void)
{
    section *sec;
    atom *p;
    char *attr;
    int bss;

    final_pass=1;
    for(sec=first_section; sec; sec=sec->next) {
        source *lasterrsrc=NULL;
        int lasterrline=0;
        sec->pc=sec->org;
        attr=sec->attr;
        bss=0;
        while(*attr) {
            if(*attr++=='u') {
                bss=1;
                break;
            }
        }
        for(p=sec->first; p; p=p->next) {
            sec->pc=(sec->pc+p->align-1)/p->align*p->align;
            cur_src=p->src;
            cur_src->line=p->line;
            if(p->list&&p->list->atom==p) {
                p->list->sec=sec;
                p->list->pc=sec->pc;
            }
            if(p->type==INSTRUCTION) {
                dblock *db;
                cur_listing=p->list;
                db=eval_instruction(p->content.inst,sec,sec->pc);
                if(pic_check)
                    do_pic_check(db->relocs);
                cur_listing=0;
                if(DEBUG) {
                    if(db->size!=instruction_size(p->content.inst,sec,sec->pc))
                        ierror(0);
                }
                /*FIXME: sauber freigeben */
                myfree(p->content.inst);
                p->content.db=db;
                p->type=DATA;
            }
            else if(p->type==DATADEF) {
                dblock *db;
                cur_listing=p->list;
                db=eval_data(p->content.defb->op,p->content.defb->bitsize,sec,sec->pc);
                if(pic_check)
                    do_pic_check(db->relocs);
                cur_listing=0;
                /*FIXME: sauber freigeben */
                myfree(p->content.defb);
                p->content.db=db;
                p->type=DATA;
            }
            else if(p->type==RORG) {
                sblock *sb;
                taddr space;
                if(eval_expr(p->content.roffs,&space,sec,sec->pc)) {
                    space=sec->org+space-sec->pc;
                    if (space>=0) {
                        sb=new_sblock(number_expr(space),1,0);
                        p->content.sb=sb;
                        p->type=SPACE;
                    }
                    else
                        general_error(20);  /* rorg is lower than current pc */
                }
                else
                    general_error(30);  /* expression must be constant */
            }
            else if(p->type==DATA&&bss) {
                if(lasterrsrc!=p->src||lasterrline!=p->line) {
                    general_error(31);  /* initialized data in bss */
                    lasterrsrc=p->src;
                    lasterrline=p->line;
                }
            }
#ifdef HAVE_CPU_OPTS
            else if(p->type==OPTS)
                cpu_opts(p->content.opts);
#endif
            else if(p->type==PRINTTEXT)
                printf("%s\n",p->content.ptext);
            else if (p->type==PRINTEXPR) {
                taddr val;
                eval_expr(p->content.pexpr,&val,sec,sec->pc);
                printf("%ld (0x%lx)\n",(long)val,(unsigned long)val);
            }
            sec->pc+=atom_size(p,sec,sec->pc);
        }
    }
}
Exemple #11
0
 int get_constant_u2(bool is_wide = false) const { return bytecode()->get_constant_u2(instruction_size()-2, cur_bc_raw(), is_wide); }
Exemple #12
0
 // Sign-extended index byte/short, no widening
 int get_constant_u1()                     const { return bytecode()->get_constant_u1(instruction_size()-1, cur_bc_raw()); }