x86: Handle failures of parsing immediate operands in the instruction decoder
This can happen if the instruction is much longer than the maximum length, or if insn->opnd_bytes is manually changed. This patch also fixes warnings from -Wswitch-default flag. Reported-by: Prashanth Nageshappa <prashanth@linux.vnet.ibm.com> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Cc: Jim Keniston <jkenisto@linux.vnet.ibm.com> Cc: Linux-mm <linux-mm@kvack.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Andi Kleen <andi@firstfloor.org> Cc: Christoph Hellwig <hch@infradead.org> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Arnaldo Carvalho de Melo <acme@infradead.org> Cc: Anton Arapov <anton@redhat.com> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Cc: yrl.pp-manager.tt@hitachi.com Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/20120413032427.32577.42602.stgit@localhost.localdomain Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
parent
7ea6411f4c
commit
6c7b8e82aa
|
@ -379,8 +379,8 @@ err_out:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decode moffset16/32/64 */
|
/* Decode moffset16/32/64. Return 0 if failed */
|
||||||
static void __get_moffset(struct insn *insn)
|
static int __get_moffset(struct insn *insn)
|
||||||
{
|
{
|
||||||
switch (insn->addr_bytes) {
|
switch (insn->addr_bytes) {
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -397,15 +397,19 @@ static void __get_moffset(struct insn *insn)
|
||||||
insn->moffset2.value = get_next(int, insn);
|
insn->moffset2.value = get_next(int, insn);
|
||||||
insn->moffset2.nbytes = 4;
|
insn->moffset2.nbytes = 4;
|
||||||
break;
|
break;
|
||||||
|
default: /* opnd_bytes must be modified manually */
|
||||||
|
goto err_out;
|
||||||
}
|
}
|
||||||
insn->moffset1.got = insn->moffset2.got = 1;
|
insn->moffset1.got = insn->moffset2.got = 1;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
err_out:
|
err_out:
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decode imm v32(Iz) */
|
/* Decode imm v32(Iz). Return 0 if failed */
|
||||||
static void __get_immv32(struct insn *insn)
|
static int __get_immv32(struct insn *insn)
|
||||||
{
|
{
|
||||||
switch (insn->opnd_bytes) {
|
switch (insn->opnd_bytes) {
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -417,14 +421,18 @@ static void __get_immv32(struct insn *insn)
|
||||||
insn->immediate.value = get_next(int, insn);
|
insn->immediate.value = get_next(int, insn);
|
||||||
insn->immediate.nbytes = 4;
|
insn->immediate.nbytes = 4;
|
||||||
break;
|
break;
|
||||||
|
default: /* opnd_bytes must be modified manually */
|
||||||
|
goto err_out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
err_out:
|
err_out:
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decode imm v64(Iv/Ov) */
|
/* Decode imm v64(Iv/Ov), Return 0 if failed */
|
||||||
static void __get_immv(struct insn *insn)
|
static int __get_immv(struct insn *insn)
|
||||||
{
|
{
|
||||||
switch (insn->opnd_bytes) {
|
switch (insn->opnd_bytes) {
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -441,15 +449,18 @@ static void __get_immv(struct insn *insn)
|
||||||
insn->immediate2.value = get_next(int, insn);
|
insn->immediate2.value = get_next(int, insn);
|
||||||
insn->immediate2.nbytes = 4;
|
insn->immediate2.nbytes = 4;
|
||||||
break;
|
break;
|
||||||
|
default: /* opnd_bytes must be modified manually */
|
||||||
|
goto err_out;
|
||||||
}
|
}
|
||||||
insn->immediate1.got = insn->immediate2.got = 1;
|
insn->immediate1.got = insn->immediate2.got = 1;
|
||||||
|
|
||||||
|
return 1;
|
||||||
err_out:
|
err_out:
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Decode ptr16:16/32(Ap) */
|
/* Decode ptr16:16/32(Ap) */
|
||||||
static void __get_immptr(struct insn *insn)
|
static int __get_immptr(struct insn *insn)
|
||||||
{
|
{
|
||||||
switch (insn->opnd_bytes) {
|
switch (insn->opnd_bytes) {
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -462,14 +473,17 @@ static void __get_immptr(struct insn *insn)
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
/* ptr16:64 is not exist (no segment) */
|
/* ptr16:64 is not exist (no segment) */
|
||||||
return;
|
return 0;
|
||||||
|
default: /* opnd_bytes must be modified manually */
|
||||||
|
goto err_out;
|
||||||
}
|
}
|
||||||
insn->immediate2.value = get_next(unsigned short, insn);
|
insn->immediate2.value = get_next(unsigned short, insn);
|
||||||
insn->immediate2.nbytes = 2;
|
insn->immediate2.nbytes = 2;
|
||||||
insn->immediate1.got = insn->immediate2.got = 1;
|
insn->immediate1.got = insn->immediate2.got = 1;
|
||||||
|
|
||||||
|
return 1;
|
||||||
err_out:
|
err_out:
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -489,7 +503,8 @@ void insn_get_immediate(struct insn *insn)
|
||||||
insn_get_displacement(insn);
|
insn_get_displacement(insn);
|
||||||
|
|
||||||
if (inat_has_moffset(insn->attr)) {
|
if (inat_has_moffset(insn->attr)) {
|
||||||
__get_moffset(insn);
|
if (!__get_moffset(insn))
|
||||||
|
goto err_out;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,16 +532,20 @@ void insn_get_immediate(struct insn *insn)
|
||||||
insn->immediate2.nbytes = 4;
|
insn->immediate2.nbytes = 4;
|
||||||
break;
|
break;
|
||||||
case INAT_IMM_PTR:
|
case INAT_IMM_PTR:
|
||||||
__get_immptr(insn);
|
if (!__get_immptr(insn))
|
||||||
|
goto err_out;
|
||||||
break;
|
break;
|
||||||
case INAT_IMM_VWORD32:
|
case INAT_IMM_VWORD32:
|
||||||
__get_immv32(insn);
|
if (!__get_immv32(insn))
|
||||||
|
goto err_out;
|
||||||
break;
|
break;
|
||||||
case INAT_IMM_VWORD:
|
case INAT_IMM_VWORD:
|
||||||
__get_immv(insn);
|
if (!__get_immv(insn))
|
||||||
|
goto err_out;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
/* Here, insn must have an immediate, but failed */
|
||||||
|
goto err_out;
|
||||||
}
|
}
|
||||||
if (inat_has_second_immediate(insn->attr)) {
|
if (inat_has_second_immediate(insn->attr)) {
|
||||||
insn->immediate2.value = get_next(char, insn);
|
insn->immediate2.value = get_next(char, insn);
|
||||||
|
|
Loading…
Reference in New Issue