Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 83803d97 authored by Wang Nan's avatar Wang Nan Committed by Jon Medhurst
Browse files

ARM: kprobes: introduces checker



This patch introdces 'checker' to decoding phase, and calls checkers
when instruction decoding. This allows further decoding for specific
instructions.  This patch introduces a stub call of checkers in kprobe
arch_prepare_kprobe() as an example and for further expansion.

Signed-off-by: default avatarWang Nan <wangnan0@huawei.com>
Reviewed-by: default avatarJon Medhurst <tixy@linaro.org>
Reviewed-by: default avatarMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: default avatarJon Medhurst <tixy@linaro.org>
parent 832607e7
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -726,10 +726,11 @@ static void __kprobes arm_singlestep(probes_opcode_t insn,
 */
enum probes_insn __kprobes
arm_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
		       bool emulate, const union decode_action *actions)
		       bool emulate, const union decode_action *actions,
		       const struct decode_checker *checkers[])
{
	asi->insn_singlestep = arm_singlestep;
	asi->insn_check_cc = probes_condition_checks[insn>>28];
	return probes_decode_insn(insn, asi, probes_decode_arm_table, false,
				  emulate, actions);
				  emulate, actions, checkers);
}
+2 −1
Original line number Diff line number Diff line
@@ -68,6 +68,7 @@ extern const union decode_item probes_decode_arm_table[];

enum probes_insn arm_probes_decode_insn(probes_opcode_t,
		struct arch_probes_insn *, bool emulate,
		const union decode_action *actions);
		const union decode_action *actions,
		const struct decode_checker *checkers[]);

#endif
+6 −4
Original line number Diff line number Diff line
@@ -863,20 +863,22 @@ static void __kprobes thumb32_singlestep(probes_opcode_t opcode,

enum probes_insn __kprobes
thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
			   bool emulate, const union decode_action *actions)
			   bool emulate, const union decode_action *actions,
			   const struct decode_checker *checkers[])
{
	asi->insn_singlestep = thumb16_singlestep;
	asi->insn_check_cc = thumb_check_cc;
	return probes_decode_insn(insn, asi, probes_decode_thumb16_table, true,
				  emulate, actions);
				  emulate, actions, checkers);
}

enum probes_insn __kprobes
thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
			   bool emulate, const union decode_action *actions)
			   bool emulate, const union decode_action *actions,
			   const struct decode_checker *checkers[])
{
	asi->insn_singlestep = thumb32_singlestep;
	asi->insn_check_cc = thumb_check_cc;
	return probes_decode_insn(insn, asi, probes_decode_thumb32_table, true,
				  emulate, actions);
				  emulate, actions, checkers);
}
+4 −2
Original line number Diff line number Diff line
@@ -91,9 +91,11 @@ extern const union decode_item probes_decode_thumb16_table[];

enum probes_insn __kprobes
thumb16_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
		bool emulate, const union decode_action *actions);
		bool emulate, const union decode_action *actions,
		const struct decode_checker *checkers[]);
enum probes_insn __kprobes
thumb32_probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
		bool emulate, const union decode_action *actions);
		bool emulate, const union decode_action *actions,
		const struct decode_checker *checkers[]);

#endif
+54 −6
Original line number Diff line number Diff line
@@ -342,6 +342,31 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
	[DECODE_TYPE_REJECT]	= sizeof(struct decode_reject)
};

static int run_checkers(const struct decode_checker *checkers[],
		int action, probes_opcode_t insn,
		struct arch_probes_insn *asi,
		const struct decode_header *h)
{
	const struct decode_checker **p;

	if (!checkers)
		return INSN_GOOD;

	p = checkers;
	while (*p != NULL) {
		int retval;
		probes_check_t *checker_func = (*p)[action].checker;

		retval = INSN_GOOD;
		if (checker_func)
			retval = checker_func(insn, asi, h);
		if (retval == INSN_REJECTED)
			return retval;
		p++;
	}
	return INSN_GOOD;
}

/*
 * probes_decode_insn operates on data tables in order to decode an ARM
 * architecture instruction onto which a kprobe has been placed.
@@ -388,11 +413,17 @@ static const int decode_struct_sizes[NUM_DECODE_TYPES] = {
int __kprobes
probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
		   const union decode_item *table, bool thumb,
		   bool emulate, const union decode_action *actions)
		   bool emulate, const union decode_action *actions,
		   const struct decode_checker *checkers[])
{
	const struct decode_header *h = (struct decode_header *)table;
	const struct decode_header *next;
	bool matched = false;
	/*
	 * @insn can be modified by decode_regs. Save its original
	 * value for checkers.
	 */
	probes_opcode_t origin_insn = insn;

	if (emulate)
		insn = prepare_emulated_insn(insn, asi, thumb);
@@ -422,24 +453,41 @@ probes_decode_insn(probes_opcode_t insn, struct arch_probes_insn *asi,
		}

		case DECODE_TYPE_CUSTOM: {
			int err;
			struct decode_custom *d = (struct decode_custom *)h;
			return actions[d->decoder.action].decoder(insn, asi, h);
			int action = d->decoder.action;

			err = run_checkers(checkers, action, origin_insn, asi, h);
			if (err == INSN_REJECTED)
				return INSN_REJECTED;
			return actions[action].decoder(insn, asi, h);
		}

		case DECODE_TYPE_SIMULATE: {
			int err;
			struct decode_simulate *d = (struct decode_simulate *)h;
			asi->insn_handler = actions[d->handler.action].handler;
			int action = d->handler.action;

			err = run_checkers(checkers, action, origin_insn, asi, h);
			if (err == INSN_REJECTED)
				return INSN_REJECTED;
			asi->insn_handler = actions[action].handler;
			return INSN_GOOD_NO_SLOT;
		}

		case DECODE_TYPE_EMULATE: {
			int err;
			struct decode_emulate *d = (struct decode_emulate *)h;
			int action = d->handler.action;

			err = run_checkers(checkers, action, origin_insn, asi, h);
			if (err == INSN_REJECTED)
				return INSN_REJECTED;

			if (!emulate)
				return actions[d->handler.action].decoder(insn,
					asi, h);
				return actions[action].decoder(insn, asi, h);

			asi->insn_handler = actions[d->handler.action].handler;
			asi->insn_handler = actions[action].handler;
			set_emulated_insn(insn, asi, thumb);
			return INSN_GOOD;
		}
Loading