示例#1
0
int main(int argc, char **argv)
{	char	src[10];
	char	dst[10];
	int	size = sizeof(src);
	int	ret;

//	__copy_user(dst, src, size);
	if (*xyzzy)
		printf("hello\n");
	getpid(&xyzzy);
	ret = validate_ptr(xyzzy);

	printf("ret=%d\n", ret);
}
示例#2
0
void
dtrace_getupcstack(uint64_t *pcstack, int pcstack_limit)
{   uint64_t *pcstack_end = pcstack + pcstack_limit;
    volatile uint8_t *flags =
        (volatile uint8_t *)&cpu_core[cpu_get_id()].cpuc_dtrace_flags;
    unsigned long *sp;
    unsigned long *bos;

    if (*flags & CPU_DTRACE_FAULT)
        return;

    if (pcstack_limit <= 0)
        return;

    *pcstack++ = (uint64_t)current->pid;

    if (pcstack >= pcstack_end)
        return;

    /***********************************************/
    /*   Linux provides a built in function which  */
    /*   is  good  because  stack walking is arch  */
    /*   dependent.            (save_stack_trace)  */
    /*   					       */
    /*   Unfortunately  this is options dependent  */
    /*   (CONFIG_STACKTRACE) so we cannot use it.  */
    /*   And  its  GPL  anyhow, so we cannot copy  */
    /*   it.				       */
    /*   					       */
    /*   Whats worse is that we might be compiled  */
    /*   with a frame pointer (only on x86-32) so  */
    /*   we have three scenarios to handle.	       */
    /***********************************************/

    /***********************************************/
    /*   Ye  gods! The world is an awful place to  */
    /*   live. The target process, may or may not  */
    /*   have   frame  pointers.  In  fact,  some  */
    /*   frames  may have it and some may not (eg  */
    /*   different   libraries  may  be  compiled  */
    /*   differently).			       */
    /*   					       */
    /*   Looks like distro owners dont care about  */
    /*   debuggabiity,   and  give  us  no  frame  */
    /*   pointers.				       */
    /*   					       */
    /*   This  function  is  really important and  */
    /*   useful.  On  modern  Linux  systems, gdb  */
    /*   (and  pstack) contain all the smarts. In  */
    /*   fact,  pstack  is often a wrapper around  */
    /*   gdb  -  i.e. its so complex we cannot do  */
    /*   this.				       */
    /***********************************************/

    /***********************************************/
    /*   Bear  in  mind  that  user stacks can be  */
    /*   megabytes  in  size,  vs  kernel  stacks  */
    /*   which  are  limited  to a few K (4 or 8K  */
    /*   typically).			       */
    /***********************************************/

//	sp = current->thread.rsp;
# if defined(__i386)
    bos = sp = KSTK_ESP(current);
#	define	ALIGN_MASK	3
# else
    /***********************************************/
    /*   KSTK_ESP()  doesnt exist for x86_64 (its  */
    /*   set to -1).			       */
    /***********************************************/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
#  if defined(KSTK_EIP)
    /***********************************************/
    /*   Handle  ARM and more kernel independent,  */
    /*   but might not exist.		       */
    /***********************************************/
    bos = sp = (unsigned long *) KSTK_EIP(current);
#  else
    bos = sp = (unsigned long *) task_pt_regs(current)->sp;
#  endif
#else
    bos = sp = task_pt_regs(current)->rsp;
#endif
#	define	ALIGN_MASK	7
#endif

    /***********************************************/
    /*   Walk  the  stack.  We  cannot  rely on a  */
    /*   frame  pointer  at  each  level,  and we  */
    /*   really  want to avoid probing every word  */
    /*   in  the  stack  - a large stack will eat  */
    /*   cpu  looking at thousands of entries. So  */
    /*   try  and  heuristically see if we have a  */
    /*   likely  frame  pointer  to jump over the  */
    /*   frame,  but, if not, just go one word at  */
    /*   a time.				       */
    /*   					       */
    /*   Try  and be careful we dont walk outside  */
    /*   the  stack  or  walk  backwards  in  the  */
    /*   stack, too.			       */
    /***********************************************/
    {   uintptr_t *spend = sp + 1024;
        struct vm_area_struct *vma = find_vma(current->mm, (unsigned long) sp);
        if (vma)
            spend = (uintptr_t *) (vma->vm_end - sizeof(int *));

        /*printk("xbos=%p %p\n", bos, spend);*/

        /***********************************************/
        /*   Have  you ever looked at the output from  */
        /*   GCC in amd64 mode? Things like:	       */
        /*   					       */
        /*   push %r12				       */
        /*   push %rbp				       */
        /*   					       */
        /*   will make you come out in a cold sweat -  */
        /*   no   way  to  find  the  frame  pointer,  */
        /*   without doing what GDB does (ie read the  */
        /*   DWARF  stack  unwind info). So, for now,  */
        /*   you  get  some  false  positives  in the  */
        /*   output - but we try to be conservative.   */
        /***********************************************/
        while (sp >= bos && sp < spend && validate_ptr(sp)) {
            /*printk("  %p %d: %p %d\n", sp, validate_ptr(sp), sp[0], validate_ptr(sp[0]));*/
            if (validate_ptr((void *) sp[0])) {
                uintptr_t p = sp[-1];
                /***********************************************/
                /*   Try  and  avoid false positives in stack  */
                /*   entries   -   we  want  this  to  be  an  */
                /*   executable instruction.		       */
                /***********************************************/
                if (((unsigned long *) sp[0] < bos || (unsigned long *) sp[0] > spend) &&
                        (vma = find_vma(current->mm, sp[0])) != NULL &&
                        vma->vm_flags & VM_EXEC) {
                    *pcstack++ = sp[0];
                    if (pcstack >= pcstack_end)
                        break;
                }
                if (((int) p & ALIGN_MASK) == 0 && p > (uintptr_t) sp && p < (uintptr_t) spend)
                    sp = (unsigned long *) p;
            }
            sp++;
        }
    }

    /***********************************************/
    /*   Erase  anything  else  in  the buffer to  */
    /*   avoid confusion.			       */
    /***********************************************/
    while (pcstack < pcstack_end)
        *pcstack++ = (pc_t) NULL;
}
bool sections_virtual_to_raw(BYTE* payload, SIZE_T payload_size, OUT BYTE* destAddress, OUT SIZE_T *raw_size_ptr)
{
    if (payload == NULL) return false;

    bool is64b = is64bit(payload);

    BYTE* payload_nt_hdr = get_nt_hrds(payload);
    if (payload_nt_hdr == NULL) {
        printf("Invalid payload: %p\n", payload);
        return false;
    }

    IMAGE_FILE_HEADER *fileHdr = NULL;
    DWORD hdrsSize = 0;
    LPVOID secptr = NULL;
    if (is64b) {
        IMAGE_NT_HEADERS64* payload_nt_hdr64 = (IMAGE_NT_HEADERS64*) payload_nt_hdr;
        fileHdr = &(payload_nt_hdr64->FileHeader);
        hdrsSize = payload_nt_hdr64->OptionalHeader.SizeOfHeaders;
        secptr = (LPVOID)((ULONGLONG)&(payload_nt_hdr64->OptionalHeader) + fileHdr->SizeOfOptionalHeader);
    } else {
        IMAGE_NT_HEADERS32* payload_nt_hdr32 = (IMAGE_NT_HEADERS32*) payload_nt_hdr;
        fileHdr = &(payload_nt_hdr32->FileHeader);
        hdrsSize = payload_nt_hdr32->OptionalHeader.SizeOfHeaders;
        secptr = (LPVOID)((ULONGLONG)&(payload_nt_hdr32->OptionalHeader) + fileHdr->SizeOfOptionalHeader);
    }
    if (!validate_ptr(payload, payload_size, payload, hdrsSize)) {
        return false;
    }
    //copy payload's headers:
    memcpy(destAddress, payload, hdrsSize);

    //copy all the sections, one by one:
    printf("Coping sections:\n");

    SIZE_T raw_end = 0;
    for (WORD i = 0; i < fileHdr->NumberOfSections; i++) {
        PIMAGE_SECTION_HEADER next_sec = (PIMAGE_SECTION_HEADER)((ULONGLONG)secptr + (IMAGE_SIZEOF_SECTION_HEADER * i));
        if (!validate_ptr(payload, payload_size, next_sec, IMAGE_SIZEOF_SECTION_HEADER)) {
           return false;
        }
        LPVOID section_mapped = (BYTE*) payload + next_sec->VirtualAddress;
        LPVOID section_raw_ptr = destAddress + next_sec->PointerToRawData;
        SIZE_T sec_size = next_sec->SizeOfRawData;
        raw_end = next_sec->SizeOfRawData + next_sec->PointerToRawData;

        if (next_sec->VirtualAddress + sec_size >= payload_size) {
            printf("[!] Virtual section size is out ouf bounds: %lx\n", sec_size);
            sec_size = SIZE_T(payload_size - next_sec->VirtualAddress);
            printf("[!] Truncated to maximal size: %lx\n", sec_size);
        }
        if (next_sec->VirtualAddress >= payload_size && sec_size != 0) {
            printf("[-] VirtualAddress of section is out ouf bounds: %lx\n", static_cast<SIZE_T>(next_sec->VirtualAddress));
            return false;
        }
        if (next_sec->PointerToRawData + sec_size >= payload_size) {
            printf("[-] Raw section size is out ouf bounds: %lx\n", sec_size);
            return false;
        }
        printf("[+] %s to: %p\n", next_sec->Name, section_raw_ptr);
        memcpy(section_raw_ptr, section_mapped, sec_size);
    }
    if (raw_end > payload_size) raw_end = payload_size;
    if (raw_size_ptr != NULL) {
        (*raw_size_ptr) = raw_end;
    }
    return true;
}
/*ARGSUSED*/
static void
instr_provide_module(void *arg, struct modctl *ctl)
{	int	i;
	struct module *mp = (struct module *) ctl;
	char *modname = mp->name;
	char	*str = mp->strtab;
	char	*name;
    	par_module_t *pmp;

	int	init;
	/***********************************************/
	/*   Possible  memleak  here...we  allocate a  */
	/*   parallel  struct, but need to free if we  */
	/*   are offloaded.			       */
	/***********************************************/
	pmp = par_alloc(mp, sizeof *pmp, &init);
	if (pmp->fbt_nentries) {
		/*
		 * This module has some FBT entries allocated; we're afraid
		 * to screw with it.
		 */
		return;
	}

	if (dtrace_here) 
		printk("%s(%d):modname=%s num_symtab=%u\n", __FILE__, __LINE__, modname, (unsigned) mp->num_symtab);
	if (strcmp(modname, "dtracedrv") == 0)
		return;

	for (i = 1; i < mp->num_symtab; i++) {
		uint8_t *instr, *limit;
		Elf_Sym *sym = (Elf_Sym *) &mp->symtab[i];
int dtrace_here = 0;
if (strcmp(modname, "dummy") == 0) dtrace_here = 1;

		name = str + sym->st_name;
		if (sym->st_name == NULL || *name == '\0')
			continue;

		/***********************************************/
		/*   Linux re-encodes the symbol types.	       */
		/***********************************************/
		if (sym->st_info != 't' && sym->st_info != 'T')
			continue;

//		if (strstr(name, "init")) 
//			continue;
//if (sym->st_info != 'T') {printk("skip -- %02d %c:%s\n", i, sym->st_info, name); continue;}

#if 0
		if (ELF_ST_TYPE(sym->st_info) != STT_FUNC)
			continue;


		/*
		 * Weak symbols are not candidates.  This could be made to
		 * work (where weak functions and their underlying function
		 * appear as two disjoint probes), but it's not simple.
		 */
		if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
			continue;
#endif

		if (strstr(name, "dtrace_") == name &&
		    strstr(name, "dtrace_safe_") != name) {
			/*
			 * Anything beginning with "dtrace_" may be called
			 * from probe context unless it explitly indicates
			 * that it won't be called from probe context by
			 * using the prefix "dtrace_safe_".
			 */
			continue;
		}

		if (strstr(name, "dtracedrv_") == name)
			continue;

		if (strstr(name, "kdi_") == name ||
		    strstr(name, "kprobe") == name) {
			/*
			 * Anything beginning with "kdi_" is a part of the
			 * kernel debugger interface and may be called in
			 * arbitrary context -- including probe context.
			 */
			continue;
		}

		if (strcmp(name, "_init") == 0)
			continue;

		if (strcmp(name, "_fini") == 0)
			continue;

		instr = (uint8_t *)sym->st_value;
		limit = (uint8_t *)(sym->st_value + sym->st_size);
//printk("trying -- %02d %c:%s\n", i, sym->st_info, name);
//HERE();

		/***********************************************/
		/*   Ignore the init function of modules - we  */
		/*   will  never  execute them now the module  */
		/*   is loaded, and we dont want to be poking  */
		/*   potential  pages  which  dont  exist  in  */
		/*   memory or which are being used for data.  */
		/***********************************************/
		if (instr == (uint8_t *) mp->init)
			continue;

		/***********************************************/
		/*   We  do have syms that appear to point to  */
		/*   unmapped  pages.  Maybe  these are freed  */
		/*   pages after a driver loads. Double check  */
		/*   -  if /proc/kallsyms says its not there,  */
		/*   then ignore it. 			       */
		/***********************************************/
		if (!validate_ptr(instr))
			continue;

		/***********************************************/
		/*   Look  at the section this symbol is in -  */
		/*   we   dont   want   sections   which  can  */
		/*   disappear   or   have   disappeared  (eg  */
		/*   .init).				       */
		/*   					       */
		/*   I'm  not sure I follow this code for all  */
		/*   kernel  releases - if we have the field,  */
		/*   it should have a fixed meaning, but some  */
		/*   modules  have  bogus  section attributes  */
		/*   pointers   (maybe   pointers   to  freed  */
		/*   segments?). Lets be careful out there.    */
		/*   					       */
		/*   20090425  Ok  - heres the deal. In 2.6.9  */
		/*   (at   least)   the   section   table  is  */
		/*   allocated  but  only  for sections which  */
		/*   are  SHF_ALLOC.  This means the array of  */
		/*   sections    cannot    be    indexed   by  */
		/*   sym->st_shndx since the mappings are now  */
		/*   bogus  (kernel  doesnt adjust the symbol  */
		/*   section  indexes). What we need to do is  */
		/*   attempt to find the section by address.   */
		/***********************************************/
		if (!instr_in_text_seg(mp, name, sym))
			continue;

		/***********************************************/
		/*   We are good to go...		       */
		/***********************************************/
		instr_provide_function(mp, pmp,
			modname, name, 
			(uint8_t *) sym->st_value, 
			instr, limit, i);
		}
}
示例#5
0
/*ARGSUSED*/
static void
fbt_provide_module(void *arg, struct modctl *ctl)
{	int	i;
	struct module *mp = (struct module *) ctl;
	char *modname = mp->name;
	char	*str = mp->strtab;
	char	*name;
    	par_module_t *pmp;
	int	ret;

# if 0
	struct module *mp = ctl->mod_mp;
	char *str = mp->strings;
	int nsyms = mp->nsyms;
	Shdr *symhdr = mp->symhdr;
	char *name;
	size_t symsize;

	/*
	 * Employees of dtrace and their families are ineligible.  Void
	 * where prohibited.
	 */
	if (strcmp(modname, "dtrace") == 0)
		return;

TODO();
	if (ctl->mod_requisites != NULL) {
		struct modctl_list *list;

		list = (struct modctl_list *)ctl->mod_requisites;

		for (; list != NULL; list = list->modl_next) {
			if (strcmp(list->modl_modp->mod_modname, "dtrace") == 0)
				return;
		}
	}

TODO();
	/*
	 * KMDB is ineligible for instrumentation -- it may execute in
	 * any context, including probe context.
	 */
	if (strcmp(modname, "kmdbmod") == 0)
		return;

	if (str == NULL || symhdr == NULL || symhdr->sh_addr == NULL) {
		/*
		 * If this module doesn't (yet) have its string or symbol
		 * table allocated, clear out.
		 */
		return;
	}

	symsize = symhdr->sh_entsize;

# endif

	int	init;

	if (strcmp(modname, "dtracedrv") == 0)
		return;

	/***********************************************/
	/*   Possible  memleak  here...we  allocate a  */
	/*   parallel  struct, but need to free if we  */
	/*   are offloaded.			       */
	/***********************************************/
	pmp = par_alloc(PARD_FBT, mp, sizeof *pmp, &init);
	if (pmp == NULL || pmp->fbt_nentries) {
		/*
		 * This module has some FBT entries allocated; we're afraid
		 * to screw with it.
		 */
		return;
	}

	if (dtrace_here) 
		printk("%s(%d):modname=%s num_symtab=%u\n", dtrace_basename(__FILE__), __LINE__, modname, (unsigned) mp->num_symtab);

	for (i = 1; i < mp->num_symtab; i++) {
		uint8_t *instr, *limit;
		Elf_Sym *sym = (Elf_Sym *) &mp->symtab[i];
int dtrace_here = 0;
if (strcmp(modname, "dummy") == 0) dtrace_here = 1;

		name = str + sym->st_name;
		if (sym->st_name == NULL || *name == '\0')
			continue;

		/***********************************************/
		/*   Linux re-encodes the symbol types.	       */
		/***********************************************/
		if (sym->st_info != 't' && sym->st_info != 'T')
			continue;

//		if (strstr(name, "init")) 
//			continue;
//if (sym->st_info != 'T') {printk("skip -- %02d %c:%s\n", i, sym->st_info, name); continue;}

#if 0
		if (ELF_ST_TYPE(sym->st_info) != STT_FUNC)
			continue;


		/*
		 * Weak symbols are not candidates.  This could be made to
		 * work (where weak functions and their underlying function
		 * appear as two disjoint probes), but it's not simple.
		 */
		if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
			continue;
#endif

		if (strstr(name, "dtrace_") == name &&
		    strstr(name, "dtrace_safe_") != name) {
			/*
			 * Anything beginning with "dtrace_" may be called
			 * from probe context unless it explitly indicates
			 * that it won't be called from probe context by
			 * using the prefix "dtrace_safe_".
			 */
			continue;
		}

		if (strstr(name, "dtracedrv_") == name)
			continue;

		if (strstr(name, "kdi_") == name ||
		    strstr(name, "kprobe") == name) {
			/*
			 * Anything beginning with "kdi_" is a part of the
			 * kernel debugger interface and may be called in
			 * arbitrary context -- including probe context.
			 */
			continue;
		}

		/*
		 * Due to 4524008, _init and _fini may have a bloated st_size.
		 * While this bug was fixed quite some time ago, old drivers
		 * may be lurking.  We need to develop a better solution to
		 * this problem, such that correct _init and _fini functions
		 * (the vast majority) may be correctly traced.  One solution
		 * may be to scan through the entire symbol table to see if
		 * any symbol overlaps with _init.  If none does, set a bit in
		 * the module structure that this module has correct _init and
		 * _fini sizes.  This will cause some pain the first time a
		 * module is scanned, but at least it would be O(N) instead of
		 * O(N log N)...
		 */
		if (strcmp(name, "_init") == 0)
			continue;

		if (strcmp(name, "_fini") == 0)
			continue;

		/*
		 * In order to be eligible, the function must begin with the
		 * following sequence:
		 *
		 * 	pushl	%esp
		 *	movl	%esp, %ebp
		 *
		 * Note that there are two variants of encodings that generate
		 * the movl; we must check for both.  For 64-bit, we would
		 * normally insist that a function begin with the following
		 * sequence:
		 *
		 *	pushq	%rbp
		 *	movq	%rsp, %rbp
		 *
		 * However, the compiler for 64-bit often splits these two
		 * instructions -- and the first instruction in the function
		 * is often not the pushq.  As a result, on 64-bit we look
		 * for any "pushq %rbp" in the function and we instrument
		 * this with a breakpoint instruction.
		 */
		instr = (uint8_t *)sym->st_value;
		limit = (uint8_t *)(sym->st_value + sym->st_size);
//printk("trying -- %02d %c:%s\n", i, sym->st_info, name);
//HERE();

		/***********************************************/
		/*   If  we  were  called because a module is  */
		/*   loaded  after  dtrace,  then mp contains  */
		/*   references to the .init section. We want  */
		/*   to  ignore these because the pages where  */
		/*   the  code resides will go away. Not only  */
		/*   dont   we   want   to   put   probes  on  */
		/*   non-existant pages, but /proc/dtrace/fbt  */
		/*   will  have problems and, fbt_enable will  */
		/*   if  that  page is now used by some other  */
		/*   driver.				       */
		/***********************************************/
		if (mp->module_init && mp->init_size &&
		    instr >= (uint8_t *) mp->module_init && 
		    instr < (uint8_t *) mp->module_init + mp->init_size) {
		    	continue;
		}

		/***********************************************/
		/*   We  do have syms that appear to point to  */
		/*   unmapped  pages.  Maybe  these are freed  */
		/*   pages after a driver loads. Double check  */
		/*   -  if /proc/kallsyms says its not there,  */
		/*   then ignore it. 			       */
		/***********************************************/
		if (!validate_ptr(instr))
			continue;

		/***********************************************/
		/*   Look  at the section this symbol is in -  */
		/*   we   dont   want   sections   which  can  */
		/*   disappear   or   have   disappeared  (eg  */
		/*   .init).				       */
		/*   					       */
		/*   I'm  not sure I follow this code for all  */
		/*   kernel  releases - if we have the field,  */
		/*   it should have a fixed meaning, but some  */
		/*   modules  have  bogus  section attributes  */
		/*   pointers   (maybe   pointers   to  freed  */
		/*   segments?). Lets be careful out there.    */
		/*   					       */
		/*   20090425  Ok  - heres the deal. In 2.6.9  */
		/*   (at   least)   the   section   table  is  */
		/*   allocated  but  only  for sections which  */
		/*   are  SHF_ALLOC.  This means the array of  */
		/*   sections    cannot    be    indexed   by  */
		/*   sym->st_shndx since the mappings are now  */
		/*   bogus  (kernel  doesnt adjust the symbol  */
		/*   section  indexes). What we need to do is  */
		/*   attempt to find the section by address.   */
		/***********************************************/
		ret = instr_in_text_seg(mp, name, sym);
		if (!ret)
			continue;

		/***********************************************/
		/*   We are good to go...		       */
		/***********************************************/
		fbt_provide_function(mp, pmp,
			modname, name, 
			(uint8_t *) sym->st_value, 
			instr, limit, i);
	}
}
示例#6
0
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;
}