static int instr_seq_show(struct seq_file *seq, void *v) { int i; long n = (long) v; int target; instr_probe_t *fbt = NULL; unsigned long size; unsigned long offset; char *modname = NULL; char name[KSYM_NAME_LEN]; const char *cp; //printk("%s v=%p\n", __func__, v); if (n == 1) { seq_printf(seq, "# patchpoint opcode inslen modrm name\n"); return 0; } if (n > num_probes) return 0; /***********************************************/ /* Find first probe. */ /***********************************************/ target = n; for (i = 0; target > 0 && i < instr_probetab_size; i++) { fbt = instr_probetab[i]; if (fbt == NULL) continue; target--; while (target > 0 && fbt) { if ((fbt = fbt->insp_hashnext) == NULL) break; target--; } } if (fbt == NULL) return 0; cp = my_kallsyms_lookup((unsigned long) fbt->insp_patchpoint, &size, &offset, &modname, name); seq_printf(seq, "%ld %p %02x %d %2d %s:%s\n", n-1, fbt->insp_patchpoint, fbt->insp_savedval, fbt->insp_inslen, fbt->insp_modrm, modname ? modname : "kernel", cp ? cp : "NULL"); return 0; }
void instr_provide_kernel(void) { static struct module kern; int n; static caddr_t ktext; static caddr_t ketext; static int first_time = TRUE; caddr_t a, aend; char name[KSYM_NAME_LEN]; if (first_time) { first_time = FALSE; ktext = get_proc_addr("_text"); if (ktext == NULL) ktext = get_proc_addr("_stext"); ketext = get_proc_addr("_etext"); my_kallsyms_lookup = get_proc_addr("kallsyms_lookup"); } if (ktext == NULL) { printk("dtracedrv:instr_provide_kernel: Cannot find _text/_stext\n"); return; } if (kern.name[0]) return; strcpy(kern.name, "kernel"); /***********************************************/ /* Walk the code segment, finding the */ /* symbols, and creating a probe for each */ /* one. */ /***********************************************/ for (n = 0, a = ktext; my_kallsyms_lookup && a < ketext; ) { const char *cp; unsigned long size; unsigned long offset; char *modname = NULL; //printk("lookup %p kallsyms_lookup=%p\n", a, kallsyms_lookup); cp = my_kallsyms_lookup((unsigned long) a, &size, &offset, &modname, name); if (cp && size == 0) printk("instr_linux: size=0 %p %s\n", a, cp ? cp : "??"); /* printk("a:%p cp:%s size:%lx offset:%lx\n", a, cp ? cp : "--undef--", size, offset);*/ if (cp == NULL) aend = a + 4; else aend = a + (size - offset); /***********************************************/ /* If this function is toxic, we mustnt */ /* touch it. */ /***********************************************/ if (cp && *cp && !is_toxic_func((unsigned long) a, cp)) { instr_provide_function(&kern, (par_module_t *) &kern, //uck on the cast..we dont really need it "kernel", name, a, a, aend, n); } a = aend; n++; } }
static int fbt_seq_show(struct seq_file *seq, void *v) { int i, s; int n = (int) (long) v; int target; fbt_probe_t *fbt = NULL; unsigned long size; unsigned long offset; char *modname = NULL; char name[KSYM_NAME_LEN]; char ibuf[64]; char *cp; //printk("%s v=%p\n", __func__, v); if (n == 1) { seq_printf(seq, "# count patchpoint opcode inslen modrm name\n"); return 0; } if (n > num_probes) return 0; /***********************************************/ /* Find first probe. This is incredibly */ /* slow and inefficient, but we dont want */ /* to waste memory keeping a list (an extra */ /* ptr for each probe). */ /***********************************************/ target = n; for (i = 0; target > 0 && i < fbt_probetab_size; i++) { fbt = fbt_probetab[i]; if (fbt == NULL) continue; target--; while (target > 0 && fbt) { if ((fbt = fbt->fbtp_hashnext) == NULL) break; target--; } } if (fbt == NULL) return 0; /***********************************************/ /* Dump the instruction so we can make sure */ /* we can single step them in the adjust */ /* cpu code. */ /* When a module is loaded and we parse the */ /* module, this may include syms which may */ /* get unmapped later on. So, trying to */ /* access a patchpoint instruction can GPF. */ /* We need to tread very carefully here not */ /* to GPF whilst catting /proc/dtrace/fbt. */ /* We actually need to disable these */ /* probes. */ /***********************************************/ //printk("fbtproc %p\n", fbt->fbtp_patchpoint); if (!validate_ptr(fbt->fbtp_patchpoint)) { s = 0xfff; strcpy(ibuf, "<unmapped>"); } else { s = dtrace_instr_size((uchar_t *) fbt->fbtp_patchpoint); ibuf[0] = '\0'; for (cp = ibuf, i = 0; i < s; i++) { snprintf(cp, sizeof ibuf - (cp - ibuf) - 3, "%02x ", fbt->fbtp_patchpoint[i] & 0xff); cp += 3; } } cp = (char *) my_kallsyms_lookup((unsigned long) fbt->fbtp_patchpoint, &size, &offset, &modname, name); # if defined(__arm__) seq_printf(seq, "%d %04u%c %p %08x %d %2d %s:%s:%s %s\n", n-1, # else seq_printf(seq, "%d %04u%c %p %02x %d %2d %s:%s:%s %s\n", n-1, # endif fbt->fbtp_fired, fbt->fbtp_overrun ? '*' : ' ', fbt->fbtp_patchpoint, fbt->fbtp_savedval, fbt->fbtp_inslen, fbt->fbtp_modrm, modname ? modname : "kernel", cp ? cp : "NULL", fbt->fbtp_type ? "return" : "entry", ibuf); return 0; }