Revision: 953 Author: teawater Date: Sat Mar 3 20:23:24 2012 Log: Adding actionx http://code.google.com/p/kgtp/source/detail?r=953 Modified: /branches/actionx/gtp.c ======================================= --- /branches/actionx/gtp.c Sat Mar 3 02:49:47 2012 +++ /branches/actionx/gtp.c Sat Mar 3 20:23:24 2012 @@ -249,40 +249,6 @@ #define INT2CHAR(h) ((h) > 9 ? (h) + 'a' - 10 : (h) + '0') -#define OP_CHECK_ADD -#define OP_CHECK_SUB -#define OP_CHECK_MUL -#ifndef CONFIG_MIPS -#define OP_CHECK_DIV_SIGNED -#define OP_CHECK_DIV_UNSIGNED -#define OP_CHECK_REM_SIGNED -#define OP_CHECK_REM_UNSIGNED -#endif -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ -#define OP_CHECK_ - enum { op_check_add = 0xe6, op_check_sub, @@ -303,7 +269,7 @@ op_check_less_unsigned, op_check_pop, op_check_swap, - op_check_printf, + op_check_printf, /* XXX: still not used. */ op_special_getv = 0xfa, op_special_setv, @@ -4603,13 +4569,33 @@ ret->addr = pc; ret->non_goto_done = non_goto_done; - if (*list) { - ret->next = *list; - *list = ret; - } else { - ret->next = NULL; - *list = ret; - } + ret->next = *list; + *list = ret; + +out: + return ret; +} + +struct gtp_x_if_goto { + struct gtp_x_if_goto *next; + unsigned int ip; + unsigned int sp; +}; + +static struct gtp_x_if_goto *+gtp_x_if_goto_add(struct gtp_x_if_goto **list, unsigned int pc, unsigned int sp)
+{ + struct gtp_x_if_goto *ret; + + ret = kmalloc(sizeof(struct gtp_x_loop), GFP_KERNEL); + if (!ret) + goto out; + + ret->ip = pc; + ret->sp = sp; + + ret->next = *list; + *list = ret; out: return ret; @@ -4652,11 +4638,11 @@ } static int -gtp_check_x(struct gtp_entry *tpe, struct action *ae) +gtp_check_x_simple(struct gtp_entry *tpe, struct action *ae) { int ret = -EINVAL; unsigned int pc = 0, sp = 0; - struct gtp_x_loop *glist = NULL, *gtmp; + struct gtp_x_if_goto *glist = NULL, *gtmp; struct gtp_x_var *vlist = NULL, *vtmp; uint8_t *ebuf = ae->u.exp.buf; int last_trace_pc = -1; @@ -4665,7 +4651,7 @@ reswitch: while (pc < ae->u.exp.size) { #ifdef GTP_DEBUG - printk(GTP_DEBUG "gtp_check_x: cmd %x\n", ebuf[pc]); + printk(GTP_DEBUG "gtp_check_x_simple: cmd %x\n", ebuf[pc]); #endif switch (ebuf[pc++]) { /* add */ @@ -4696,14 +4682,14 @@ case 0x29: /* swap */ case 0x2b: - if (ae->type == 'X') { - if (sp < 1) { - printk(KERN_WARNING "gtp_check_x: " - "stack overflow " - "in %d.\n", - pc - 1); - goto release_out; - } + if (sp < 1) { + printk(KERN_WARNING "gtp_check_x_simple: stack " + "overflow in %d.\n", + pc - 1); + goto release_out; + } else { + if (ebuf[pc - 1] != 0x2b) + sp--; } break; @@ -4712,16 +4698,13 @@ if (tpe->have_printk) last_trace_pc = pc - 1; - if (ae->type == 'X') { - if (sp < 2) { - printk(KERN_WARNING "gtp_check_x: " - "stack overflow " - "in %d.\n", - pc - 1); - goto release_out; - } else - sp -= 2; - } + if (sp < 2) { + printk(KERN_WARNING "gtp_check_x_simple: stack " + "overflow in %d.\n", + pc - 1); + goto release_out; + } else + sp -= 2; break; /* log_not */ @@ -4740,20 +4723,16 @@ /* dup */ case 0x28: - if (ae->type == 'X') { - sp++; - if (sp_max < sp) - sp_max = sp; - } + sp++; + if (sp_max < sp) + sp_max = sp; break; /* const8 */ case 0x22: - if (ae->type == 'X') { - sp++; - if (sp_max < sp) - sp_max = sp; - } + sp++; + if (sp_max < sp) + sp_max = sp; /* ext */ case 0x16: /* zero_ext */ @@ -4780,11 +4759,10 @@ if (pc + 1 >= ae->u.exp.size) goto release_out; pc += 2; - if (ae->type == 'X') { - sp++; - if (sp_max < sp) - sp_max = sp; - } + + sp++; + if (sp_max < sp) + sp_max = sp; break; /* const32 */ @@ -4792,11 +4770,10 @@ if (pc + 3 >= ae->u.exp.size) goto release_out; pc += 4; - if (ae->type == 'X') { - sp++; - if (sp_max < sp) - sp_max = sp; - } + + sp++; + if (sp_max < sp) + sp_max = sp; break; /* const64 */ @@ -4804,53 +4781,59 @@ if (pc + 7 >= ae->u.exp.size) goto release_out; pc += 8; - if (ae->type == 'X') { - sp++; - if (sp_max < sp) - sp_max = sp; - } + + sp++; + if (sp_max < sp) + sp_max = sp; break; /* if_goto */ case 0x20: - if (tpe->have_printk) + if (tpe->have_printk) { + printk(KERN_WARNING "If_goto action doesn't" + "support printk.\n"); goto release_out; - + } if (pc + 1 >= ae->u.exp.size) goto release_out; - gtmp = gtp_x_loop_find(glist, pc); - if (gtmp) { - if (gtmp->non_goto_done) - goto out; - else { - gtmp->non_goto_done = 1; - pc += 2; - } - } else { - if (!gtp_x_loop_add(&glist, pc, 0)) { + + { + unsigned int dpc = (ebuf[pc] << 8) + + ebuf[pc + 1]; + + if (dpc < pc) { + /* This action X include loop. */ + ae->type = 0xff; + ret = 0; + goto release_out; + } + + if (!gtp_x_if_goto_add(&glist, dpc, sp)) { ret = -ENOMEM; goto release_out; } - pc = (ebuf[pc] << 8) - + (ebuf[pc + 1]); - } - /* Mark this action X need sp check when it exec. */ - ae->type = 0xff; + } + + pc += 2; break; /* goto */ case 0x21: if (pc + 1 >= ae->u.exp.size) goto release_out; - gtmp = gtp_x_loop_find(glist, pc); - if (gtmp) - goto out; - else { - if (!gtp_x_loop_add(&glist, pc, 1)) { - ret = -ENOMEM; + + { + unsigned int dpc = (ebuf[pc] << 8) + + ebuf[pc + 1]; + + if (dpc < pc) { + /* This action X include loop. */ + ae->type = 0xff; + ret = 0; goto release_out; } - pc = (ebuf[pc] << 8) + (ebuf[pc + 1]); + + pc = dpc; } break; @@ -4889,11 +4872,9 @@ ebuf[pc - 3] = op_special_getv; } } - if (ae->type == 'X') { - sp++; - if (sp_max < sp) - sp_max = sp; - } + sp++; + if (sp_max < sp) + sp_max = sp; break; /* setv */ @@ -4966,20 +4947,11 @@ break; /* printf */ - case 0x31: { - int arg = ebuf[pc++]; - if (arg && ae->type == 'X') { - if (sp < 1) { - printk(KERN_WARNING - "gtp_check_x: stack " - "overflow in %d.\n", - pc - 2); - goto release_out; - } else - sp--; - } - pc += strlen((char *)ebuf + pc) + 1; - } + case 0x31: + if (pc + 1 >= ae->u.exp.size) + goto release_out; + pc++; + pc += strlen((char *)ebuf + pc) + 1; break; /* div_signed */ @@ -4994,16 +4966,13 @@ /* XXX, mips don't have 64 bit div. */ goto release_out; #endif - if (ae->type == 'X') { - if (sp < 1) { - printk(KERN_WARNING "gtp_check_x: " - "stack overflow " - "in %d.\n", - pc - 1); - goto release_out; - } else - sp--; - } + if (sp < 1) { + printk(KERN_WARNING "gtp_check_x_simple: stack " + "overflow in %d.\n", + pc - 1); + goto release_out; + } else + sp--; break; /* float */ @@ -5028,26 +4997,24 @@ goto release_out; out: - for (gtmp = glist; gtmp; gtmp = gtmp->next) { - if (!gtmp->non_goto_done) - break; - } - if (gtmp) { - pc = gtmp->addr + 2; - gtmp->non_goto_done = 1; + if (glist) { + pc = glist->ip; + sp = glist->sp; + gtmp = glist; + glist = glist->next; + kfree(gtmp); goto reswitch; } if (sp_max >= STACK_MAX) { - printk(KERN_WARNING "gtp_check_x: stack overflow, " + printk(KERN_WARNING "gtp_check_x_simple: stack overflow, " "current %d, max %d.\n", sp_max, STACK_MAX); goto release_out; } ret = 0; #ifdef GTP_DEBUG - printk(GTP_DEBUG "gtp_check_x: Code is OK. sp_checked is %d. " - "sp_max is %d.\n", - (ae->type == 'X'), sp_max); + printk(GTP_DEBUG "gtp_check_x_simple: Code is OK. sp_max is %d.\n", + sp_max); #endif release_out: @@ -5065,7 +5032,7 @@ /* Get the var of vtmp. */ var = gtp_var_find(vtmp->num); if (var == NULL) { - printk(KERN_WARNING "gtp_check_x: cannot find " + printk(KERN_WARNING "gtp_check_x_simple: cannot find " "tvar %d.\n", vtmp->num); ret = -EINVAL; } else { @@ -5087,7 +5054,7 @@ break; /* trace_quick */ case 0x0d: - ebuf[last_trace_pc] = op_trace_printk; + ebuf[last_trace_pc] = op_trace_quick_printk; break; /* tracev */ case 0x2e: @@ -5098,6 +5065,411 @@ return ret; } + +static int +gtp_check_x_loop(struct gtp_entry *tpe, struct action *ae) +{ + int ret = -EINVAL; + unsigned int pc = 0; + struct gtp_x_loop *glist = NULL, *gtmp; + struct gtp_x_var *vlist = NULL, *vtmp; + uint8_t *ebuf = ae->u.exp.buf; + int last_trace_pc = -1; + + printk(KERN_WARNING "Action of tracepoint %d have loop.\n", + (int)tpe->num); + + tpe->have_printk = 0; + +reswitch: + while (pc < ae->u.exp.size) { +#ifdef GTP_DEBUG + printk(GTP_DEBUG "gtp_check_x_loop: cmd %x\n", ebuf[pc]); +#endif + switch (ebuf[pc++]) { + /* add */ + case 0x02: + ebuf[pc - 1] = op_check_add; + break; + /* sub */ + case 0x03: + ebuf[pc - 1] = op_check_sub; + break; + /* mul */ + case 0x04: + ebuf[pc - 1] = op_check_mul; + break; + /* lsh */ + case 0x09: + ebuf[pc - 1] = op_check_lsh; + break; + /* rsh_signed */ + case 0x0a: + ebuf[pc - 1] = op_check_rsh_signed; + break; + /* rsh_unsigned */ + case 0x0b: + ebuf[pc - 1] = op_check_rsh_unsigned; + break; + /* bit_and */ + case 0x0f: + ebuf[pc - 1] = op_check_bit_and; + break; + /* bit_or */ + case 0x10: + ebuf[pc - 1] = op_check_bit_or; + break; + /* bit_xor */ + case 0x11: + ebuf[pc - 1] = op_check_bit_xor; + break; + /* equal */ + case 0x13: + ebuf[pc - 1] = op_check_equal; + break; + /* less_signed */ + case 0x14: + ebuf[pc - 1] = op_check_less_signed; + break; + /* less_unsigned */ + case 0x15: + ebuf[pc - 1] = op_check_less_unsigned; + break; + /* pop */ + case 0x29: + ebuf[pc - 1] = op_check_pop; + break; + /* swap */ + case 0x2b: + ebuf[pc - 1] = op_check_swap; + break; + + /* trace */ + case 0x0c: + ebuf[pc - 1] = op_check_trace; + break; + + /* log_not */ + case 0x0e: + /* bit_not */ + case 0x12: + /* ref8 */ + case 0x17: + /* ref16 */ + case 0x18: + /* ref32 */ + case 0x19: + /* ref64 */ + case 0x1a: + /* dup */ + case 0x28: + break; + + /* const8 */ + case 0x22: + /* ext */ + case 0x16: + /* zero_ext */ + case 0x2a: + /* trace_quick */ + case 0x0d: + if (pc >= ae->u.exp.size) + goto release_out; + pc++; + break; + + /* const16 */ + case 0x23: + /* reg */ + case 0x26: + if (pc + 1 >= ae->u.exp.size) + goto release_out; + pc += 2; + break; + + /* const32 */ + case 0x24: + if (pc + 3 >= ae->u.exp.size) + goto release_out; + pc += 4; + break; + + /* const64 */ + case 0x25: + if (pc + 7 >= ae->u.exp.size) + goto release_out; + pc += 8; + break; + + /* if_goto */ + case 0x20: + if (pc + 1 >= ae->u.exp.size) + goto release_out; + + gtmp = gtp_x_loop_find(glist, pc); + if (gtmp) { + if (gtmp->non_goto_done) + goto out; + else { + gtmp->non_goto_done = 1; + pc += 2; + } + } else { + if (!gtp_x_loop_add(&glist, pc, 0)) { + ret = -ENOMEM; + goto release_out; + } + pc = (ebuf[pc] << 8) + ebuf[pc + 1]; + } + break; + + /* goto */ + case 0x21: + if (pc + 1 >= ae->u.exp.size) + goto release_out; + + gtmp = gtp_x_loop_find(glist, pc); + if (gtmp) + goto out; + else { + if (!gtp_x_loop_add(&glist, pc, 1)) { + ret = -ENOMEM; + goto release_out; + } + } + + pc = (ebuf[pc] << 8) + (ebuf[pc + 1]); + break; + + /* end */ + case 0x27: + goto out; + break; + + /* getv */ + case 0x2c: { + int arg; + + if (pc + 1 >= ae->u.exp.size) + goto release_out; + arg = ebuf[pc++]; + arg = (arg << 8) + ebuf[pc++]; + + if (!GTP_VAR_IS_SPECIAL(arg)) { + if (gtp_x_var_add(&vlist, arg, 1)) { + ret = -ENOMEM; + goto release_out; + } + } else { + if (arg == GTP_VAR_NO_SELF_TRACE_ID) { + tpe->no_self_trace = 1; + ret = 1; + goto release_out; + } + + if (arg == GTP_VAR_COOKED_CLOCK_ID) + gtp_access_cooked_clock = 1; +#ifdef CONFIG_X86 + else if (arg == GTP_VAR_COOKED_RDTSC_ID) + gtp_access_cooked_rdtsc = 1; +#endif + ebuf[pc - 3] = op_special_getv; + } + } + break; + + /* setv */ + case 0x2d: { + int arg; + + if (pc + 1 >= ae->u.exp.size) + goto release_out; + arg = ebuf[pc++]; + arg = (arg << 8) + ebuf[pc++]; + + if (!GTP_VAR_IS_SPECIAL(arg)) { + if (gtp_x_var_add(&vlist, arg, 2)) { + ret = -ENOMEM; + goto release_out; + } + } else { + if (arg == GTP_VAR_NO_SELF_TRACE_ID) { + tpe->no_self_trace = 1; + ret = 1; + goto release_out; + } else if (arg == GTP_VAR_KRET_ID) { + /* XXX: still not set it + value to maxactive. */ + tpe->is_kretprobe = 1; + ret = 1; + goto release_out; + } + + if (arg == GTP_VAR_PRINTK_LEVEL_ID) { + printk(KERN_WARNING "Loop " + "action doesn't" + "support printk.\n"); + goto release_out; + } + + ebuf[pc - 3] = op_special_setv; + } + } + break; + + /* tracev */ + case 0x2e: { + int arg; + + if (tpe->have_printk) + last_trace_pc = pc - 1; + + if (pc + 1 >= ae->u.exp.size) + goto release_out; + arg = ebuf[pc++]; + arg = (arg << 8) + ebuf[pc++]; + + if (!GTP_VAR_IS_SPECIAL(arg)) { + if (gtp_x_var_add(&vlist, arg, 4)) { + ret = -ENOMEM; + goto release_out; + } + } else { + if (arg == GTP_VAR_NO_SELF_TRACE_ID) { + tpe->no_self_trace = 1; + ret = 1; + goto release_out; + } + if (arg == GTP_VAR_COOKED_CLOCK_ID) + gtp_access_cooked_clock = 1; +#ifdef CONFIG_X86 + else if (arg == GTP_VAR_COOKED_RDTSC_ID) + gtp_access_cooked_rdtsc = 1; +#endif + ebuf[pc - 3] = op_special_tracev; + } + } + break; + + /* printf */ + case 0x31: + if (pc + 1 >= ae->u.exp.size) + goto release_out; + pc++; + pc += strlen((char *)ebuf + pc) + 1; + break; + + /* div_signed */ + case 0x05: +#ifdef CONFIG_MIPS + /* XXX, mips don't have 64 bit div. */ + printk(KERN_WARNING "MIPS don't have 64 bit div.\n"); + goto release_out; +#endif + ebuf[pc - 1] = op_check_div_signed; + break; + /* div_unsigned */ + case 0x06: +#ifdef CONFIG_MIPS + /* XXX, mips don't have 64 bit div. */ + printk(KERN_WARNING "MIPS don't have 64 bit div.\n"); + goto release_out; +#endif + ebuf[pc - 1] = op_check_div_unsigned; + break; + /* rem_signed */ + case 0x07: +#ifdef CONFIG_MIPS + /* XXX, mips don't have 64 bit div. */ + printk(KERN_WARNING "MIPS don't have 64 bit div.\n"); + goto release_out; +#endif + ebuf[pc - 1] = op_check_rem_signed; + break; + /* rem_unsigned */ + case 0x08: +#ifdef CONFIG_MIPS + /* XXX, mips don't have 64 bit div. */ + printk(KERN_WARNING "MIPS don't have 64 bit div.\n"); + goto release_out; +#endif + ebuf[pc - 1] = op_check_rem_unsigned; + break; + + /* float */ + case 0x01: + /* ref_float */ + case 0x1b: + /* ref_double */ + case 0x1c: + /* ref_long_double */ + case 0x1d: + /* l_to_d */ + case 0x1e: + /* d_to_l */ + case 0x1f: + /* trace16 */ + case 0x30: + default: + goto release_out; + break; + } + } + goto release_out; + +out: + for (gtmp = glist; gtmp; gtmp = gtmp->next) { + if (!gtmp->non_goto_done) + break; + } + if (gtmp) { + pc = gtmp->addr + 2; + gtmp->non_goto_done = 1; + goto reswitch; + } + ret = 0; + +release_out: + while (glist) { + gtmp = glist; + glist = glist->next; + kfree(gtmp); + } + while (vlist) { + struct gtp_var *var; + + vtmp = vlist; + vlist = vlist->next; + + /* Get the var of vtmp. */ + var = gtp_var_find(vtmp->num); + if (var == NULL) { + printk(KERN_WARNING "gtp_check_x_loop: cannot find " + "tvar %d.\n", vtmp->num); + ret = -EINVAL; + } else { + if (var->per_cpu == NULL) { + if ((vtmp->flags & 2) + && ((vtmp->flags & 1) || (vtmp->flags & 4))) + ae->u.exp.need_var_lock = 1; + } + } + kfree(vtmp); + } + + return ret; +} + +static int +gtp_check_x(struct gtp_entry *tpe, struct action *ae) +{ + int ret = gtp_check_x_simple(tpe, ae); + + if (ret != 0 || ae->type == 'X') + return ret; + + return gtp_check_x_loop(tpe, ae); +} #if defined(GTP_FTRACE_RING_BUFFER) || defined(GTP_RB) static void