| /* |
| * |
| * Most of this code is borrowed and adapted from the lkcd command "lcrash" |
| * and its supporting libarary. |
| * |
| * This kdb commands for casting memory structures. |
| * It provides |
| * "print" "px", "pd" * |
| * |
| * Careful of porting the klib KL_XXX functions (they call thru a jump table |
| * that we don't use here) |
| * |
| * The kernel type information is added be insmod'g the kdb debuginfo module |
| * It loads symbolic debugging info (provided from lcrash -o), |
| * (this information originally comes from the lcrash "kerntypes" file) |
| * |
| */ |
| |
| #define VMALLOC_START_IA64 0xa000000200000000 |
| #include <linux/kernel.h> |
| #include <linux/module.h> |
| #include <linux/lkdb.h> |
| #include <linux/kdbprivate.h> |
| #include <linux/fs.h> |
| #include <asm/processor.h> |
| #include <asm/uaccess.h> |
| #include <asm/fcntl.h> |
| #include <linux/vmalloc.h> |
| #include <linux/ctype.h> |
| #include <linux/file.h> |
| #include <linux/err.h> |
| #include "modules/lcrash/klib.h" |
| #include "modules/lcrash/kl_stringtab.h" |
| #include "modules/lcrash/kl_btnode.h" |
| #include "modules/lcrash/lc_eval.h" |
| |
| #undef next_node /* collision with nodemask.h */ |
| int have_debug_file = 0; |
| dbg_sym_t *types_tree_head; |
| dbg_sym_t *typedefs_tree_head; |
| kltype_t *kltype_array; |
| dbg_sym_t *dsym_types_array; |
| |
| |
| EXPORT_SYMBOL(types_tree_head); |
| EXPORT_SYMBOL(typedefs_tree_head); |
| EXPORT_SYMBOL(kltype_array); |
| EXPORT_SYMBOL(dsym_types_array); |
| |
| #define C_HEX 0x0002 |
| #define C_WHATIS 0x0004 |
| #define C_NOVARS 0x0008 |
| #define C_SIZEOF 0x0010 |
| #define C_SHOWOFFSET 0x0020 |
| #define C_LISTHEAD 0x0040 |
| #define C_LISTHEAD_N 0x0080 /* walk using list_head.next */ |
| #define C_LISTHEAD_P 0x0100 /* walk using list_head.prev */ |
| #define C_BINARY 0x0200 |
| #define MAX_LONG_LONG 0xffffffffffffffffULL |
| klib_t kdb_klib; |
| klib_t *KLP = &kdb_klib; |
| k_error_t klib_error = 0; |
| dbg_sym_t *type_tree = (dbg_sym_t *)NULL; |
| dbg_sym_t *typedef_tree = (dbg_sym_t *)NULL; |
| dbg_sym_t *func_tree = (dbg_sym_t *)NULL; |
| dbg_sym_t *srcfile_tree = (dbg_sym_t *)NULL; |
| dbg_sym_t *var_tree = (dbg_sym_t *)NULL; |
| dbg_sym_t *xtype_tree = (dbg_sym_t *)NULL; |
| dbg_hashrec_t *dbg_hash[TYPE_NUM_SLOTS]; |
| int all_count, deall_count; |
| void single_type(char *str); |
| void sizeof_type(char *str); |
| typedef struct chunk_s { |
| struct chunk_s *next; /* Must be first */ |
| struct chunk_s *prev; /* Must be second */ |
| void *addr; |
| struct bucket_s *bucketp; |
| uint32_t chunksz; /* size of memory chunk (via malloc()) */ |
| uint32_t blksz; /* Not including header */ |
| short blkcount; /* Number of blksz blocks in chunk */ |
| } chunk_t; |
| |
| typedef struct blkhdr_s { |
| struct blkhdr_s *next; |
| union { |
| struct blkhdr_s *prev; |
| chunk_t *chunkp; |
| } b_un; |
| int flg; |
| int size; |
| } blkhdr_t; |
| |
| int ptrsz64 = ((int)sizeof(void *) == 8); |
| alloc_functions_t alloc_functions; |
| |
| /* |
| * return 1 if addr is invalid |
| */ |
| static int |
| invalid_address(kaddr_t addr, int count) |
| { |
| unsigned char c; |
| unsigned long lcount; |
| /* FIXME: untested? */ |
| lcount = count; |
| /* FIXME: use kdb_verify_area */ |
| while (count--) { |
| if (lkdb_getarea(c, addr)) |
| return 1; |
| } |
| return 0; |
| } |
| |
| /* |
| * wrappers for calls to kernel-style allocation/deallocation |
| */ |
| static void * |
| kl_alloc_block(int size) |
| { |
| void *vp; |
| |
| vp = kmalloc(size, GFP_KERNEL); |
| if (!vp) { |
| lkdb_printf ("kmalloc of %d bytes failed\n", size); |
| } |
| /* important: the lcrash code sometimes assumes that the |
| * allocation is zeroed out |
| */ |
| memset(vp, 0, size); |
| all_count++; |
| return vp; |
| } |
| static void |
| kl_free_block(void *vp) |
| { |
| kfree(vp); |
| deall_count++; |
| return; |
| } |
| |
| int |
| get_value(char *s, uint64_t *value) |
| { |
| return kl_get_value(s, NULL, 0, value); |
| } |
| |
| /* |
| * kl_get_block() |
| * |
| * Read a size block from virtual address addr in the system memory image. |
| */ |
| k_error_t |
| kl_get_block(kaddr_t addr, unsigned size, void *bp, void *mmap) |
| { |
| if (!bp) { |
| return(KLE_NULL_BUFF); |
| } else if (!size) { |
| return(KLE_ZERO_SIZE); |
| } |
| |
| memcpy(bp, (void *)addr, size); |
| |
| return(0); |
| } |
| |
| /* |
| * print_value() |
| */ |
| void |
| print_value(char *ldstr, uint64_t value, int width) |
| { |
| int w = 0; |
| char fmtstr[12], f, s[2]="\000\000"; |
| |
| if (ldstr) { |
| lkdb_printf("%s", ldstr); |
| } |
| s[0] = '#'; |
| f = 'x'; |
| if (width) { |
| if (ptrsz64) { |
| w = 18; /* due to leading "0x" */ |
| } else { |
| w = 10; /* due to leading "0x" */ |
| } |
| } |
| if (w) { |
| sprintf(fmtstr, "%%%s%d"FMT64"%c", s, w, f); |
| } else { |
| sprintf(fmtstr, "%%%s"FMT64"%c", s, f); |
| } |
| lkdb_printf(fmtstr, value); |
| } |
| |
| /* |
| * print_list_head() |
| */ |
| void |
| print_list_head(kaddr_t saddr) |
| { |
| print_value("STRUCT ADDR: ", (uint64_t)saddr, 8); |
| lkdb_printf("\n"); |
| } |
| |
| /* |
| * check_prev_ptr() |
| */ |
| void |
| check_prev_ptr(kaddr_t ptr, kaddr_t prev) |
| { |
| if(ptr != prev) { |
| lkdb_printf("\nWARNING: Pointer broken. %#"FMTPTR"x," |
| " SHOULD BE: %#"FMTPTR"x\n", prev, ptr); |
| } |
| } |
| |
| /* |
| * kl_kaddr() -- Return a kernel virtual address stored in a structure |
| * |
| * Pointer 'p' points to a kernel structure |
| * of type 's.' Get the kernel address located in member 'm.' |
| */ |
| kaddr_t |
| kl_kaddr(void *p, char *s, char *m) |
| { |
| uint64_t *u64p; |
| int offset; |
| |
| offset = kl_member_offset(s, m); |
| u64p = (uint64_t *)(p + offset); |
| return((kaddr_t)*u64p); |
| } |
| |
| /* |
| * walk_structs() -- walk linked lists of kernel data structures |
| */ |
| int |
| walk_structs(char *s, char *f, char *member, kaddr_t addr, int flags) |
| { |
| int size, offset, mem_offset=0; |
| kaddr_t last = 0, next; |
| kltype_t *klt = (kltype_t *)NULL, *memklt=(kltype_t *)NULL; |
| unsigned long long iter_threshold = 10000; |
| |
| int counter = 0; |
| kaddr_t head=0, head_next=0, head_prev=0, entry=0; |
| kaddr_t entry_next=0, entry_prev; |
| |
| /* field name of link pointer, determine its offset in the struct. */ |
| if ((offset = kl_member_offset(s, f)) == -1) { |
| lkdb_printf("Could not determine offset for member %s of %s.\n", |
| f, s); |
| return 0; |
| } |
| |
| /* Get the type of the enclosing structure */ |
| if (!(klt = kl_find_type(s, (KLT_STRUCT|KLT_UNION)))) { |
| lkdb_printf("Could not find the type of %s\n", s); |
| return(1); |
| } |
| |
| /* Get the struct size */ |
| if ((size = kl_struct_len(s)) == 0) { |
| lkdb_printf ("could not get the length of %s\n", s); |
| return(1); |
| } |
| |
| /* test for a named member of the structure that should be displayed */ |
| if (member) { |
| memklt = kl_get_member(klt, member); |
| if (!memklt) { |
| lkdb_printf ("%s has no member %s\n", s, member); |
| return 1; |
| } |
| mem_offset = kl_get_member_offset(klt, member); |
| } |
| |
| if ((next = addr)) { |
| /* get head of list (anchor) when struct list_head is used */ |
| if (flags & C_LISTHEAD) { |
| head = next; |
| if (invalid_address(head, sizeof(head))) { |
| lkdb_printf ("invalid address %#lx\n", |
| head); |
| return 1; |
| } |
| /* get contents of addr struct member */ |
| head_next = kl_kaddr((void *)head, "list_head", "next"); |
| if (invalid_address(head, sizeof(head_next))) { |
| lkdb_printf ("invalid address %#lx\n", |
| head_next); |
| return 1; |
| } |
| /* get prev field of anchor */ |
| head_prev = kl_kaddr((void *)head, "list_head", "prev"); |
| if (invalid_address(head, sizeof(head_prev))) { |
| lkdb_printf ("invalid address %#lx\n", |
| head_prev); |
| return 1; |
| } |
| entry = 0; |
| } |
| } |
| |
| while(next && counter < iter_threshold) { |
| counter++; |
| if (counter > iter_threshold) { |
| lkdb_printf("\nWARNING: Iteration threshold reached.\n"); |
| lkdb_printf("Current threshold: %lld\n", iter_threshold); |
| break; |
| } |
| if(flags & C_LISTHEAD) { |
| if(!(entry)){ |
| if(flags & C_LISTHEAD_N){ |
| entry = head_next; |
| } else { |
| entry = head_prev; |
| } |
| last = head; |
| } |
| |
| if(head == entry) { |
| if(flags & C_LISTHEAD_N){ |
| check_prev_ptr(last, head_prev); |
| } else { |
| check_prev_ptr(last, head_next); |
| } |
| break; |
| } |
| |
| next = entry - offset; /* next structure */ |
| /* check that the whole structure can be addressed */ |
| if (invalid_address(next, size)) { |
| lkdb_printf( |
| "invalid struct address %#lx\n", next); |
| return 1; |
| } |
| /* and validate that it points to valid addresses */ |
| entry_next = kl_kaddr((void *)entry,"list_head","next"); |
| if (invalid_address(entry_next, sizeof(entry_next))) { |
| lkdb_printf("invalid address %#lx\n", |
| entry_next); |
| return 1; |
| } |
| entry_prev = kl_kaddr((void *)entry,"list_head","prev"); |
| if (invalid_address(entry_prev, sizeof(entry_prev))) { |
| lkdb_printf("invalid address %#lx\n", |
| entry_prev); |
| return 1; |
| } |
| if(flags & C_LISTHEAD_N){ |
| check_prev_ptr(last, entry_prev); |
| } else { |
| check_prev_ptr(last, entry_next); |
| } |
| print_list_head(next); |
| last = entry; |
| if(flags & C_LISTHEAD_N){ |
| entry = entry_next; /* next list_head */ |
| } else { |
| entry = entry_prev; /* next list_head */ |
| } |
| } |
| |
| if (memklt) { |
| /* print named sub-structure in C-like struct format. */ |
| kl_print_member( |
| (void *)((unsigned long)next+mem_offset), |
| memklt, 0, C_HEX); |
| } else { |
| /* print entire structure in C-like struct format. */ |
| kl_print_type((void *)next, klt, 0, C_HEX); |
| } |
| |
| if(!(flags & C_LISTHEAD)) { |
| last = next; |
| next = (kaddr_t) (*(uint64_t*)(next + offset)); |
| } |
| } |
| |
| return(0); |
| } |
| |
| /* |
| * Implement the lcrash walk -s command |
| * see lcrash cmd_walk.c |
| */ |
| int |
| kdb_walk(int argc, const char **argv) |
| { |
| int i, nonoptc=0, optc=0, flags=0, init_len=0; |
| char *cmd, *arg, *structp=NULL, *forwp=NULL, *memberp=NULL; |
| char *addrp=NULL; |
| uint64_t value; |
| kaddr_t start_addr; |
| |
| all_count=0; |
| deall_count=0; |
| if (!have_debug_file) { |
| lkdb_printf("no debuginfo file\n"); |
| return 0; |
| } |
| /* If there is nothing to evaluate, just return */ |
| if (argc == 0) { |
| return 0; |
| } |
| cmd = (char *)*argv; /* s/b "walk" */ |
| if (strcmp(cmd,"walk")) { |
| lkdb_printf("got %s, not \"walk\"\n", cmd); |
| return 0; |
| } |
| |
| for (i=1; i<=argc; i++) { |
| arg = (char *)*(argv+i); |
| if (*arg == '-') { |
| optc++; |
| if (optc > 2) { |
| lkdb_printf("too many options\n"); |
| lkdb_printf("see 'walkhelp'\n"); |
| return 0; |
| } |
| if (*(arg+1) == 's') { |
| continue; /* ignore -s */ |
| } else if (*(arg+1) == 'h') { |
| if ((init_len=kl_struct_len("list_head")) |
| == 0) { |
| lkdb_printf( |
| "could not find list_head\n"); |
| return 0; |
| } |
| if (*(arg+2) == 'p') { |
| flags = C_LISTHEAD; |
| flags |= C_LISTHEAD_P; |
| } else if (*(arg+2) == 'n') { |
| flags = C_LISTHEAD; |
| flags |= C_LISTHEAD_N; |
| } else { |
| lkdb_printf("invalid -h option <%s>\n", |
| arg); |
| lkdb_printf("see 'walkhelp'\n"); |
| return 0; |
| } |
| } else { |
| lkdb_printf("invalid option <%s>\n", arg); |
| lkdb_printf("see 'walkhelp'\n"); |
| return 0; |
| } |
| } else { |
| nonoptc++; |
| if (nonoptc > 4) { |
| lkdb_printf("too many arguments\n"); |
| lkdb_printf("see 'walkhelp'\n"); |
| return 0; |
| } |
| if (nonoptc == 1) { |
| structp = arg; |
| } else if (nonoptc == 2) { |
| forwp = arg; |
| } else if (nonoptc == 3) { |
| addrp = arg; |
| } else if (nonoptc == 4) { |
| /* the member is optional; if we get |
| a fourth, the previous was the member */ |
| memberp = addrp; |
| addrp = arg; |
| } else { |
| lkdb_printf("invalid argument <%s>\n", arg); |
| lkdb_printf("see 'walkhelp'\n"); |
| return 0; |
| } |
| } |
| } |
| if (nonoptc < 3) { |
| lkdb_printf("too few arguments\n"); |
| lkdb_printf("see 'walkhelp'\n"); |
| return 0; |
| } |
| if (!(flags & C_LISTHEAD)) { |
| if ((init_len=kl_struct_len(structp)) == 0) { |
| lkdb_printf("could not find %s\n", structp); |
| return 0; |
| } |
| } |
| |
| /* Get the start address of the structure */ |
| if (get_value(addrp, &value)) { |
| lkdb_printf ("address %s invalid\n", addrp); |
| return 0; |
| } |
| start_addr = (kaddr_t)value; |
| if (invalid_address(start_addr, init_len)) { |
| lkdb_printf ("address %#lx invalid\n", start_addr); |
| return 0; |
| } |
| |
| if (memberp) { |
| } |
| |
| if (walk_structs(structp, forwp, memberp, start_addr, flags)) { |
| lkdb_printf ("walk_structs failed\n"); |
| return 0; |
| } |
| /* lkdb_printf("ptc allocated:%d deallocated:%d\n", |
| all_count, deall_count); */ |
| return 0; |
| } |
| |
| /* |
| * Implement the lcrash px (print, pd) command |
| * see lcrash cmd_print.c |
| * |
| * px <expression> |
| * e.g. px *(task_struct *) <address> |
| */ |
| int |
| kdb_debuginfo_print(int argc, const char **argv) |
| { |
| /* argc does not count the command itself, which is argv[0] */ |
| char *cmd, *next, *end, *exp, *cp; |
| unsigned char *buf; |
| int i, j, iflags; |
| node_t *np; |
| uint64_t flags = 0; |
| |
| /* If there is nothing to evaluate, just return */ |
| if (argc == 0) { |
| return 0; |
| } |
| all_count=0; |
| deall_count=0; |
| |
| cmd = (char *)*argv; |
| |
| /* Set up the flags value. If this command was invoked via |
| * "pd" or "px", then make sure the appropriate flag is set. |
| */ |
| flags = 0; |
| if (!strcmp(cmd, "pd") || !strcmp(cmd, "print")) { |
| flags = 0; |
| } else if (!strcmp(cmd, "px")) { |
| flags |= C_HEX; |
| } else if (!strcmp(cmd, "whatis")) { |
| if (argc != 1) { |
| lkdb_printf("usage: whatis <symbol | type>\n"); |
| return 0; |
| } |
| cp = (char *)*(argv+1); |
| single_type(cp); |
| /* lkdb_printf("allocated:%d deallocated:%d\n", |
| all_count, deall_count); */ |
| return 0; |
| } else if (!strcmp(cmd, "sizeof")) { |
| if (!have_debug_file) { |
| lkdb_printf("no debuginfo file\n"); |
| return 0; |
| } |
| if (argc != 1) { |
| lkdb_printf("usage: sizeof type\n"); |
| return 0; |
| } |
| cp = (char *)*(argv+1); |
| sizeof_type(cp); |
| return 0; |
| } else { |
| lkdb_printf("command error: %s\n", cmd); |
| return 0; |
| } |
| |
| /* |
| * Count the number of bytes necessary to hold the entire expression |
| * string. |
| */ |
| for (i=1, j=0; i <= argc; i++) { |
| j += (strlen(*(argv+i)) + 1); |
| } |
| |
| /* |
| * Allocate space for the expression string and copy the individual |
| * arguments into it. |
| */ |
| buf = kl_alloc_block(j); |
| if (!buf) { |
| return 0; |
| } |
| |
| for (i=1; i <= argc; i++) { |
| strcat(buf, *(argv+i)); |
| /* put spaces between arguments */ |
| if (i < argc) { |
| strcat(buf, " "); |
| } |
| } |
| |
| /* Walk through the expression string, expression by expression. |
| * Note that a comma (',') is the delimiting character between |
| * expressions. |
| */ |
| next = buf; |
| while (next) { |
| if ((end = strchr(next, ','))) { |
| *end = (char)0; |
| } |
| |
| /* Copy the next expression to a separate expression string. |
| * A separate expresison string is necessary because it is |
| * likely to get freed up in eval() when variables get expanded. |
| */ |
| i = strlen(next)+1; |
| exp = (char *)kl_alloc_block(i); |
| if (!exp) { |
| return 0; |
| } |
| strcpy(exp, next); |
| |
| /* Evaluate the expression */ |
| np = eval(&exp, 0); |
| if (!np || eval_error) { |
| print_eval_error(cmd, exp, |
| (error_token ? error_token : (char*)NULL), |
| eval_error, CMD_NAME_FLG); |
| if (np) { |
| free_nodes(np); |
| } |
| kl_free_block(buf); |
| kl_free_block(exp); |
| free_eval_memory(); |
| return 0; |
| } |
| iflags = flags; |
| if (print_eval_results(np, iflags)) { |
| free_nodes(np); |
| kl_free_block(buf); |
| free_eval_memory(); |
| return 0; |
| } |
| kl_free_block(exp); |
| |
| if (end) { |
| next = end + 1; |
| lkdb_printf(" "); |
| } else { |
| next = (char*)NULL; |
| lkdb_printf("\n"); |
| } |
| free_nodes(np); |
| } |
| free_eval_memory(); |
| kl_free_block(buf); |
| /* lkdb_printf("allocated:%d deallocated:%d\n", |
| all_count, deall_count); */ |
| return 0; |
| } |
| |
| /* |
| * Display help for the px command |
| */ |
| int |
| kdb_pxhelp(int argc, const char **argv) |
| { |
| if (have_debug_file) { |
| lkdb_printf ("Some examples of using the px command:\n"); |
| lkdb_printf (" the whole structure:\n"); |
| lkdb_printf (" px *(task_struct *)0xe0000...\n"); |
| lkdb_printf (" one member:\n"); |
| lkdb_printf (" px (*(task_struct *)0xe0000...)->comm\n"); |
| lkdb_printf (" the address of a member\n"); |
| lkdb_printf (" px &((task_struct *)0xe0000...)->children\n"); |
| lkdb_printf (" a structure pointed to by a member:\n"); |
| lkdb_printf (" px ((*(class_device *)0xe0000...)->class)->name\n"); |
| lkdb_printf (" array element:\n"); |
| lkdb_printf (" px (cache_sizes *)0xa0000...[0]\n"); |
| lkdb_printf (" px (task_struct *)(0xe0000...)->cpus_allowed.bits[0]\n"); |
| } else { |
| lkdb_printf ("There is no debug info file.\n"); |
| lkdb_printf ("The px/pd/print commands can only evaluate "); |
| lkdb_printf ("arithmetic expressions.\n"); |
| } |
| return 0; |
| } |
| |
| /* |
| * Display help for the walk command |
| */ |
| int |
| kdb_walkhelp(int argc, const char **argv) |
| { |
| if (!have_debug_file) { |
| lkdb_printf("no debuginfo file\n"); |
| return 0; |
| } |
| lkdb_printf ("Using the walk command:\n"); |
| lkdb_printf (" (only the -s (symbolic) form is supported, so -s is ignored)\n"); |
| lkdb_printf ("\n"); |
| lkdb_printf (" If the list is not linked with list_head structures:\n"); |
| lkdb_printf (" walk [-s] struct name-of-forward-pointer address\n"); |
| lkdb_printf (" example: walk xyz_struct next 0xe00....\n"); |
| lkdb_printf ("\n"); |
| lkdb_printf (" If the list is linked with list_head structures, use -hn\n"); |
| lkdb_printf (" to walk the 'next' list, -hp for the 'prev' list\n"); |
| lkdb_printf (" walk -h[n|p] struct name-of-forward-pointer [member-to-show] address-of-list-head\n"); |
| lkdb_printf (" example, to show the entire task_struct:\n"); |
| lkdb_printf (" walk -hn task_struct tasks 0xe000....\n"); |
| lkdb_printf (" example, to show the task_struct member comm:\n"); |
| lkdb_printf (" walk -hn task_struct tasks comm 0xe000....\n"); |
| lkdb_printf (" (address is not the address of first member's list_head, "); |
| lkdb_printf ("but of the anchoring list_head\n"); |
| return 0; |
| } |
| |
| /* |
| * dup_block() |
| */ |
| void * |
| dup_block(void *b, int len) |
| { |
| void *b2; |
| |
| if ((b2 = kl_alloc_block(len))) { |
| memcpy(b2, b, len); /* dst, src, sz */ |
| } |
| return(b2); |
| } |
| |
| /* |
| * kl_reset_error() |
| */ |
| void |
| kl_reset_error(void) |
| { |
| klib_error = 0; |
| } |
| |
| /* |
| * given a symbol name, look up its address |
| * |
| * in lcrash, this would return a pointer to the syment_t in |
| * a binary tree of them |
| * |
| * In this one, look up the symbol in the standard kdb way, |
| * which fills in the lkdb_symtab_t. |
| * Then fill in the global syment_t "lkup_syment" -- assuming |
| * we'll only need one at a time! |
| * |
| * kl_lkup_symname returns the address of syment_t if the symbol is |
| * found, else null. |
| * |
| * Note: we allocate a syment_t the caller should kfree it |
| */ |
| syment_t * |
| kl_lkup_symname (char *cp) |
| { |
| syment_t *sp; |
| lkdb_symtab_t kdb_symtab; |
| |
| if (lkdbgetsymval(cp, &kdb_symtab)) { |
| sp = (syment_t *)kl_alloc_block(sizeof(syment_t)); |
| sp->s_addr = (kaddr_t)kdb_symtab.sym_start; |
| KL_ERROR = 0; |
| return (sp); |
| } else { |
| /* returns 0 if the symbol is not found */ |
| KL_ERROR = KLE_INVALID_VALUE; |
| return ((syment_t *)0); |
| } |
| } |
| |
| /* |
| * kl_get_ra() |
| * |
| * This function returns its own return address. |
| * Usefule when trying to capture where we came from. |
| */ |
| void* |
| kl_get_ra(void) |
| { |
| return (__builtin_return_address(0)); |
| } |
| |
| /* start kl_util.c */ |
| /* |
| * Definitions for the do_math() routine. |
| */ |
| #define M_ADD '+' |
| #define M_SUBTRACT '-' |
| #define M_MULTIPLY '*' |
| #define M_DIVIDE '/' |
| |
| /* |
| * do_math() -- Calculate some math values based on a string argument |
| * passed into the function. For example, if you use: |
| * |
| * 0xffffc000*2+6/5-3*19-8 |
| * |
| * And you will get the value 0xffff7fc0 back. I could |
| * probably optimize this a bit more, but right now, it |
| * works, which is good enough for me. |
| */ |
| static uint64_t |
| do_math(char *str) |
| { |
| int i = 0; |
| char *buf, *loc; |
| uint64_t value1, value2; |
| syment_t *sp; |
| |
| buf = (char *)kl_alloc_block((strlen(str) + 1)); |
| sprintf(buf, "%s", str); |
| for (i = strlen(str); i >= 0; i--) { |
| if ((str[i] == M_ADD) || (str[i] == M_SUBTRACT)) { |
| buf[i] = '\0'; |
| value1 = do_math(buf); |
| value2 = do_math(&str[i+1]); |
| kl_free_block((void *)buf); |
| if (str[i] == M_SUBTRACT) { |
| return value1 - value2; |
| } else { |
| return value1 + value2; |
| } |
| } |
| } |
| |
| for (i = strlen(str); i >= 0; i--) { |
| if ((str[i] == M_MULTIPLY) || (str[i] == M_DIVIDE)) { |
| buf[i] = '\0'; |
| value1 = do_math(buf); |
| value2 = do_math(&str[i+1]); |
| kl_free_block((void *)buf); |
| if (str[i] == M_MULTIPLY) { |
| return (value1 * value2); |
| } else { |
| if (value2 == 0) { |
| /* handle divide by zero */ |
| /* XXX -- set proper error code */ |
| klib_error = 1; |
| return (0); |
| } else { |
| return (value1 / value2); |
| } |
| } |
| } |
| } |
| |
| /* |
| * Otherwise, just process the value, and return it. |
| */ |
| sp = kl_lkup_symname(buf); |
| if (KL_ERROR) { |
| KL_ERROR = 0; |
| value2 = kl_strtoull(buf, &loc, 10); |
| if (((!value2) && (buf[0] != '0')) || (*loc) || |
| (!strncmp(buf, "0x", 2)) || (!strncmp(buf, "0X", 2))) { |
| value1 = (kaddr_t)kl_strtoull(buf, (char**)NULL, 16); |
| } else { |
| value1 = (unsigned)kl_strtoull(buf, (char**)NULL, 10); |
| } |
| } else { |
| value1 = (kaddr_t)sp->s_addr; |
| kl_free_block((void *)sp); |
| } |
| kl_free_block((void *)buf); |
| return (value1); |
| } |
| /* |
| * kl_get_value() -- Translate numeric input strings |
| * |
| * A generic routine for translating an input string (param) in a |
| * number of dfferent ways. If the input string is an equation |
| * (contains the characters '+', '-', '/', and '*'), then perform |
| * the math evaluation and return one of the following modes (if |
| * mode is passed): |
| * |
| * 0 -- if the resulting value is <= elements, if elements (number |
| * of elements in a table) is passed. |
| * |
| * 1 -- if the first character in param is a pound sign ('#'). |
| * |
| * 3 -- the numeric result of an equation. |
| * |
| * If the input string is NOT an equation, mode (if passed) will be |
| * set in one of the following ways (depending on the contents of |
| * param and elements). |
| * |
| * o When the first character of param is a pound sign ('#'), mode |
| * is set equal to one and the trailing numeric value (assumed to |
| * be decimal) is returned. |
| * |
| * o When the first two characters in param are "0x" or "0X," or |
| * when when param contains one of the characers "abcdef," or when |
| * the length of the input value is eight characters. mode is set |
| * equal to two and the numeric value contained in param is |
| * translated as hexadecimal and returned. |
| * |
| * o The value contained in param is translated as decimal and mode |
| * is set equal to zero. The resulting value is then tested to see |
| * if it exceeds elements (if passed). If it does, then value is |
| * translated as hexadecimal and mode is set equal to two. |
| * |
| * Note that mode is only set when a pointer is passed in the mode |
| * paramater. Also note that when elements is set equal to zero, any |
| * non-hex (as determined above) value not starting with a pound sign |
| * will be translated as hexadecimal (mode will be set equal to two) -- |
| * IF the length of the string of characters is less than 16 (kaddr_t). |
| * |
| */ |
| int |
| kl_get_value(char *param, int *mode, int elements, uint64_t *value) |
| { |
| char *loc; |
| uint64_t v; |
| |
| kl_reset_error(); |
| |
| /* Check to see if we are going to need to do any math |
| */ |
| if (strpbrk(param, "+-/*")) { |
| if (!strncmp(param, "#", 1)) { |
| v = do_math(¶m[1]); |
| if (mode) { |
| *mode = 1; |
| } |
| } else { |
| v = do_math(param); |
| if (mode) { |
| if (elements && (*value <= elements)) { |
| *mode = 0; |
| } else { |
| *mode = 3; |
| } |
| } |
| } |
| } else { |
| if (!strncmp(param, "#", 1)) { |
| if (!strncmp(param, "0x", 2) |
| || !strncmp(param, "0X", 2) |
| || strpbrk(param, "abcdef")) { |
| v = kl_strtoull(¶m[1], &loc, 16); |
| } else { |
| v = kl_strtoull(¶m[1], &loc, 10); |
| } |
| if (loc) { |
| KL_ERROR = KLE_INVALID_VALUE; |
| return (1); |
| } |
| if (mode) { |
| *mode = 1; |
| } |
| } else if (!strncmp(param, "0x", 2) || !strncmp(param, "0X", 2) |
| || strpbrk(param, "abcdef")) { |
| v = kl_strtoull(param, &loc, 16); |
| if (loc) { |
| KL_ERROR = KLE_INVALID_VALUE; |
| return (1); |
| } |
| if (mode) { |
| *mode = 2; /* HEX VALUE */ |
| } |
| } else if (elements || (strlen(param) < 16) || |
| (strlen(param) > 16)) { |
| v = kl_strtoull(param, &loc, 10); |
| if (loc) { |
| KL_ERROR = KLE_INVALID_VALUE; |
| return (1); |
| } |
| if (elements && (v >= elements)) { |
| v = (kaddr_t)kl_strtoull(param, |
| (char**)NULL, 16); |
| if (mode) { |
| *mode = 2; /* HEX VALUE */ |
| } |
| } else if (mode) { |
| *mode = 0; |
| } |
| } else { |
| v = kl_strtoull(param, &loc, 16); |
| if (loc) { |
| KL_ERROR = KLE_INVALID_VALUE; |
| return (1); |
| } |
| if (mode) { |
| *mode = 2; /* ASSUME HEX VALUE */ |
| } |
| } |
| } |
| *value = v; |
| return (0); |
| } |
| /* end kl_util.c */ |
| |
| /* start kl_libutil.c */ |
| static int |
| valid_digit(char c, int base) |
| { |
| switch(base) { |
| case 2: |
| if ((c >= '0') && (c <= '1')) { |
| return(1); |
| } else { |
| return(0); |
| } |
| case 8: |
| if ((c >= '0') && (c <= '7')) { |
| return(1); |
| } else { |
| return(0); |
| } |
| case 10: |
| if ((c >= '0') && (c <= '9')) { |
| return(1); |
| } else { |
| return(0); |
| } |
| case 16: |
| if (((c >= '0') && (c <= '9')) |
| || ((c >= 'a') && (c <= 'f')) |
| || ((c >= 'A') && (c <= 'F'))) { |
| return(1); |
| } else { |
| return(0); |
| } |
| } |
| return(0); |
| } |
| |
| static int |
| digit_value(char c, int base, int *val) |
| { |
| if (!valid_digit(c, base)) { |
| return(1); |
| } |
| switch (base) { |
| case 2: |
| case 8: |
| case 10: |
| *val = (int)((int)(c - 48)); |
| break; |
| case 16: |
| if ((c >= 'a') && (c <= 'f')) { |
| *val = ((int)(c - 87)); |
| } else if ((c >= 'A') && (c <= 'F')) { |
| *val = ((int)(c - 55)); |
| } else { |
| *val = ((int)(c - 48)); |
| } |
| } |
| return(0); |
| } |
| |
| uint64_t |
| kl_strtoull(char *str, char **loc, int base) |
| { |
| int dval; |
| uint64_t i = 1, v, value = 0; |
| char *c, *cp = str; |
| |
| *loc = (char *)NULL; |
| if (base == 0) { |
| if (!strncmp(cp, "0x", 2) || !strncmp(cp, "0X", 2)) { |
| base = 16; |
| } else if (cp[0] == '0') { |
| if (cp[1] == 'b') { |
| base = 2; |
| } else { |
| base = 8; |
| } |
| } else if (strpbrk(cp, "abcdefABCDEF")) { |
| base = 16; |
| } else { |
| base = 10; |
| } |
| } |
| if ((base == 8) && (*cp == '0')) { |
| cp += 1; |
| } else if ((base == 2) && !strncmp(cp, "0b", 2)) { |
| cp += 2; |
| } else if ((base == 16) && |
| (!strncmp(cp, "0x", 2) || !strncmp(cp, "0X", 2))) { |
| cp += 2; |
| } |
| c = &cp[strlen(cp) - 1]; |
| while (c >= cp) { |
| |
| if (digit_value(*c, base, &dval)) { |
| if (loc) { |
| *loc = c; |
| } |
| return(value); |
| } |
| v = dval * i; |
| if ((MAX_LONG_LONG - value) < v) { |
| return(MAX_LONG_LONG); |
| } |
| value += v; |
| i *= (uint64_t)base; |
| c--; |
| } |
| return(value); |
| } |
| /* end kl_libutil.c */ |
| |
| /* |
| * dbg_hash_sym() |
| */ |
| void |
| dbg_hash_sym(uint64_t typenum, dbg_sym_t *stp) |
| { |
| dbg_hashrec_t *shp, *hshp; |
| |
| if ((typenum == 0) || (!stp)) { |
| return; |
| } |
| shp = (dbg_hashrec_t *)kl_alloc_block(sizeof(dbg_hashrec_t)); |
| shp->h_typenum = typenum; |
| shp->h_ptr = stp; |
| shp->h_next = (dbg_hashrec_t *)NULL; |
| if ((hshp = dbg_hash[TYPE_NUM_HASH(typenum)])) { |
| while (hshp->h_next) { |
| hshp = hshp->h_next; |
| } |
| hshp->h_next = shp; |
| } else { |
| dbg_hash[TYPE_NUM_HASH(typenum)] = shp; |
| } |
| } |
| |
| /* |
| * dbg_find_sym() |
| */ |
| dbg_sym_t * |
| dbg_find_sym(char *name, int type, uint64_t typenum) |
| { |
| dbg_sym_t *stp = (dbg_sym_t *)NULL; |
| |
| if (name && strlen(name)) { |
| /* Cycle through the type flags and see if any records are |
| * present. Note that if multiple type flags or DBG_ALL is |
| * passed in, only the first occurance of 'name' will be |
| * found and returned. If name exists in multiple trees, |
| * then multiple searches are necessary to find them. |
| */ |
| if (type & DBG_TYPE) { |
| if ((stp = (dbg_sym_t *)kl_find_btnode((btnode_t *) |
| type_tree, name, (int *)NULL))) { |
| goto found_sym; |
| } |
| } |
| if (type & DBG_TYPEDEF) { |
| if ((stp = (dbg_sym_t *)kl_find_btnode((btnode_t *) |
| typedef_tree, name, (int *)NULL))) { |
| goto found_sym; |
| } |
| } |
| if (!stp) { |
| return((dbg_sym_t*)NULL); |
| } |
| } |
| found_sym: |
| if (typenum) { |
| dbg_hashrec_t *hshp; |
| |
| if (stp) { |
| if (stp->sym_typenum == typenum) { |
| return(stp); |
| } |
| } else if ((hshp = dbg_hash[TYPE_NUM_HASH(typenum)])) { |
| while (hshp) { |
| if (hshp->h_typenum == typenum) { |
| return(hshp->h_ptr); |
| } |
| hshp = hshp->h_next; |
| } |
| } |
| } |
| return(stp); |
| } |
| |
| /* |
| * kl_find_type() -- find a KLT type by name. |
| */ |
| kltype_t * |
| kl_find_type(char *name, int tnum) |
| { |
| dbg_sym_t *stp; |
| kltype_t *kltp = (kltype_t *)NULL; |
| |
| if (!have_debug_file) { |
| lkdb_printf("no debuginfo file\n"); |
| return kltp; |
| } |
| |
| if (!tnum || IS_TYPE(tnum)) { |
| if ((stp = dbg_find_sym(name, DBG_TYPE, 0))) { |
| kltp = (kltype_t *)stp->sym_kltype; |
| if (tnum && !(kltp->kl_type & tnum)) { |
| /* We have found a type by this name |
| * but it does not have the right |
| * type number (e.g., we're looking |
| * for a struct and we don't find |
| * a KLT_STRUCT type by this name). |
| */ |
| return((kltype_t *)NULL); |
| } |
| } |
| } |
| if (!tnum || IS_TYPEDEF(tnum)) { |
| if ((stp = dbg_find_sym(name, DBG_TYPEDEF, 0))) { |
| kltp = (kltype_t *)stp->sym_kltype; |
| } |
| } |
| return(kltp); |
| } |
| |
| /* |
| * kl_first_btnode() -- non-recursive implementation. |
| */ |
| btnode_t * |
| kl_first_btnode(btnode_t *np) |
| { |
| if (!np) { |
| return((btnode_t *)NULL); |
| } |
| |
| /* Walk down the left side 'til the end... |
| */ |
| while (np->bt_left) { |
| np = np->bt_left; |
| } |
| return(np); |
| } |
| |
| /* |
| * kl_next_btnode() -- non-recursive implementation. |
| */ |
| btnode_t * |
| kl_next_btnode(btnode_t *node) |
| { |
| btnode_t *np = node, *parent; |
| |
| if (np) { |
| if (np->bt_right) { |
| return(kl_first_btnode(np->bt_right)); |
| } else { |
| parent = np->bt_parent; |
| next: |
| if (parent) { |
| if (parent->bt_left == np) { |
| return(parent); |
| } |
| np = parent; |
| parent = parent->bt_parent; |
| goto next; |
| } |
| } |
| } |
| return((btnode_t *)NULL); |
| } |
| |
| /* |
| * dbg_next_sym() |
| */ |
| dbg_sym_t * |
| dbg_next_sym(dbg_sym_t *stp) |
| { |
| dbg_sym_t *next_stp; |
| |
| next_stp = (dbg_sym_t *)kl_next_btnode((btnode_t *)stp); |
| return(next_stp); |
| } |
| |
| /* |
| * kl_prev_btnode() -- non-recursive implementation. |
| */ |
| btnode_t * |
| kl_prev_btnode(btnode_t *node) |
| { |
| btnode_t *np = node, *parent; |
| |
| if (np) { |
| if (np->bt_left) { |
| np = np->bt_left; |
| while (np->bt_right) { |
| np = np->bt_right; |
| } |
| return(np); |
| } |
| parent = np->bt_parent; |
| next: |
| if (parent) { |
| if (parent->bt_right == np) { |
| return(parent); |
| } |
| np = parent; |
| parent = parent->bt_parent; |
| goto next; |
| } |
| } |
| return((btnode_t *)NULL); |
| } |
| |
| /* |
| * dbg_prev_sym() |
| */ |
| dbg_sym_t * |
| dbg_prev_sym(dbg_sym_t *stp) |
| { |
| dbg_sym_t *prev_stp; |
| |
| prev_stp = (dbg_sym_t *)kl_prev_btnode((btnode_t *)stp); |
| return(prev_stp); |
| } |
| |
| /* |
| * kl_find_next_type() -- find next KLT type |
| */ |
| kltype_t * |
| kl_find_next_type(kltype_t *kltp, int type) |
| { |
| kltype_t *nkltp = NULL; |
| dbg_sym_t *nstp; |
| |
| if (kltp && kltp->kl_ptr) { |
| nstp = (dbg_sym_t *)kltp->kl_ptr; |
| nkltp = (kltype_t *)nstp->sym_kltype; |
| if (type) { |
| while(nkltp && !(nkltp->kl_type & type)) { |
| if ((nstp = dbg_next_sym(nstp))) { |
| nkltp = (kltype_t *)nstp->sym_kltype; |
| } else { |
| nkltp = (kltype_t *)NULL; |
| } |
| } |
| } |
| } |
| return(nkltp); |
| } |
| |
| /* |
| * dbg_first_sym() |
| */ |
| dbg_sym_t * |
| dbg_first_sym(int type) |
| { |
| dbg_sym_t *stp = (dbg_sym_t *)NULL; |
| |
| switch(type) { |
| case DBG_TYPE: |
| stp = (dbg_sym_t *) |
| kl_first_btnode((btnode_t *)type_tree); |
| break; |
| case DBG_TYPEDEF: |
| stp = (dbg_sym_t *) |
| kl_first_btnode((btnode_t *)typedef_tree); |
| break; |
| } |
| return(stp); |
| } |
| |
| /* |
| * kl_first_type() |
| */ |
| kltype_t * |
| kl_first_type(int tnum) |
| { |
| kltype_t *kltp = NULL; |
| dbg_sym_t *stp; |
| |
| if (IS_TYPE(tnum)) { |
| /* If (tnum == KLT_TYPE), then return the first type |
| * record, regardless of the type. Otherwise, search |
| * for the frst type that mapps into tnum. |
| */ |
| if ((stp = dbg_first_sym(DBG_TYPE))) { |
| kltp = (kltype_t *)stp->sym_kltype; |
| if (tnum != KLT_TYPE) { |
| while (kltp && !(kltp->kl_type & tnum)) { |
| if ((stp = dbg_next_sym(stp))) { |
| kltp = (kltype_t *)stp->sym_kltype; |
| } else { |
| kltp = (kltype_t *)NULL; |
| } |
| } |
| } |
| } |
| } else if (IS_TYPEDEF(tnum)) { |
| if ((stp = dbg_first_sym(DBG_TYPEDEF))) { |
| kltp = (kltype_t *)stp->sym_kltype; |
| } |
| } |
| return(kltp); |
| } |
| |
| /* |
| * kl_next_type() |
| */ |
| kltype_t * |
| kl_next_type(kltype_t *kltp) |
| { |
| dbg_sym_t *stp, *nstp; |
| kltype_t *nkltp = (kltype_t *)NULL; |
| |
| if (!kltp) { |
| return((kltype_t *)NULL); |
| } |
| stp = (dbg_sym_t *)kltp->kl_ptr; |
| if ((nstp = dbg_next_sym(stp))) { |
| nkltp = (kltype_t *)nstp->sym_kltype; |
| } |
| return(nkltp); |
| } |
| |
| /* |
| * kl_prev_type() |
| */ |
| kltype_t * |
| kl_prev_type(kltype_t *kltp) |
| { |
| dbg_sym_t *stp, *pstp; |
| kltype_t *pkltp = (kltype_t *)NULL; |
| |
| if (!kltp) { |
| return((kltype_t *)NULL); |
| } |
| stp = (dbg_sym_t *)kltp->kl_ptr; |
| if ((pstp = dbg_prev_sym(stp))) { |
| pkltp = (kltype_t *)pstp->sym_kltype; |
| } |
| return(pkltp); |
| } |
| |
| /* |
| * kl_realtype() |
| */ |
| kltype_t * |
| kl_realtype(kltype_t *kltp, int tnum) |
| { |
| kltype_t *rkltp = kltp; |
| |
| while (rkltp) { |
| if (tnum && (rkltp->kl_type == tnum)) { |
| break; |
| } |
| if (!rkltp->kl_realtype) { |
| break; |
| } |
| if (rkltp->kl_realtype == rkltp) { |
| break; |
| } |
| rkltp = rkltp->kl_realtype; |
| if (rkltp == kltp) { |
| break; |
| } |
| } |
| return(rkltp); |
| } |
| |
| /* |
| * dbg_find_typenum() |
| */ |
| dbg_type_t * |
| dbg_find_typenum(uint64_t typenum) |
| { |
| dbg_sym_t *stp; |
| dbg_type_t *sp = (dbg_type_t *)NULL; |
| |
| if ((stp = dbg_find_sym(0, DBG_TYPE, typenum))) { |
| sp = (dbg_type_t *)stp->sym_kltype; |
| } |
| return(sp); |
| } |
| |
| /* |
| * find type by typenum |
| */ |
| kltype_t * |
| kl_find_typenum(uint64_t typenum) |
| { |
| kltype_t *kltp; |
| |
| kltp = (kltype_t *)dbg_find_typenum(typenum); |
| return(kltp); |
| } |
| |
| /* |
| * kl_find_btnode() -- non-recursive implementation. |
| */ |
| btnode_t * |
| _kl_find_btnode(btnode_t *np, char *key, int *max_depth, size_t len) |
| { |
| int ret; |
| btnode_t *next, *prev; |
| |
| if (np) { |
| if (max_depth) { |
| (*max_depth)++; |
| } |
| next = np; |
| again: |
| if (len) { |
| ret = strncmp(key, next->bt_key, len); |
| } else { |
| ret = strcmp(key, next->bt_key); |
| } |
| if (ret == 0) { |
| if ((prev = kl_prev_btnode(next))) { |
| if (len) { |
| ret = strncmp(key, prev->bt_key, len); |
| } else { |
| ret = strcmp(key, prev->bt_key); |
| } |
| if (ret == 0) { |
| next = prev; |
| goto again; |
| } |
| } |
| return(next); |
| } else if (ret < 0) { |
| if ((next = next->bt_left)) { |
| goto again; |
| } |
| } else { |
| if ((next = next->bt_right)) { |
| goto again; |
| } |
| } |
| } |
| return((btnode_t *)NULL); |
| } |
| |
| /* |
| * kl_type_size() |
| */ |
| int |
| kl_type_size(kltype_t *kltp) |
| { |
| kltype_t *rkltp; |
| |
| if (!kltp) { |
| return(0); |
| } |
| if (!(rkltp = kl_realtype(kltp, 0))) { |
| return(0); |
| } |
| return(rkltp->kl_size); |
| } |
| |
| /* |
| * kl_struct_len() |
| */ |
| int |
| kl_struct_len(char *s) |
| { |
| kltype_t *kltp; |
| |
| if ((kltp = kl_find_type(s, (KLT_TYPES)))) { |
| return kl_type_size(kltp); |
| } |
| return(0); |
| } |
| |
| /* |
| * kl_get_member() |
| */ |
| kltype_t * |
| kl_get_member(kltype_t *kltp, char *f) |
| { |
| kltype_t *mp; |
| |
| if ((mp = kltp->kl_member)) { |
| while (mp) { |
| if (mp->kl_flags & TYP_ANONYMOUS_FLG) { |
| kltype_t *amp; |
| |
| if ((amp = kl_get_member(mp->kl_realtype, f))) { |
| return(amp); |
| } |
| } else if (!strcmp(mp->kl_name, f)) { |
| break; |
| } |
| mp = mp->kl_member; |
| } |
| } |
| return(mp); |
| } |
| |
| /* |
| * kl_member() |
| */ |
| kltype_t * |
| kl_member(char *s, char *f) |
| { |
| kltype_t *kltp, *mp = NULL; |
| |
| if (!(kltp = kl_find_type(s, (KLT_STRUCT|KLT_UNION)))) { |
| if ((kltp = kl_find_type(s, KLT_TYPEDEF))) { |
| kltp = kl_realtype(kltp, 0); |
| } |
| } |
| if (kltp) { |
| mp = kl_get_member(kltp, f); |
| } |
| return(mp); |
| } |
| |
| |
| /* |
| * kl_get_member_offset() |
| */ |
| int |
| kl_get_member_offset(kltype_t *kltp, char *f) |
| { |
| kltype_t *mp; |
| |
| if ((mp = kltp->kl_member)) { |
| while (mp) { |
| if (mp->kl_flags & TYP_ANONYMOUS_FLG) { |
| int off; |
| |
| /* Drill down to see if the member we are looking for is in |
| * an anonymous union or struct. Since this call is recursive, |
| * the drill down may actually be multi-layer. |
| */ |
| off = kl_get_member_offset(mp->kl_realtype, f); |
| if (off >= 0) { |
| return(mp->kl_offset + off); |
| } |
| } else if (!strcmp(mp->kl_name, f)) { |
| return(mp->kl_offset); |
| } |
| mp = mp->kl_member; |
| } |
| } |
| return(-1); |
| } |
| |
| /* |
| * kl_member_offset() |
| */ |
| int |
| kl_member_offset(char *s, char *f) |
| { |
| int off = -1; |
| kltype_t *kltp; |
| |
| if (!(kltp = kl_find_type(s, (KLT_STRUCT|KLT_UNION)))) { |
| if ((kltp = kl_find_type(s, KLT_TYPEDEF))) { |
| kltp = kl_realtype(kltp, 0); |
| } |
| } |
| if (kltp) { |
| off = kl_get_member_offset(kltp, f); |
| } |
| return(off); |
| } |
| |
| /* |
| * kl_is_member() |
| */ |
| int |
| kl_is_member(char *s, char *f) |
| { |
| kltype_t *mp; |
| |
| if ((mp = kl_member(s, f))) { |
| return(1); |
| } |
| return(0); |
| } |
| |
| /* |
| * kl_member_size() |
| */ |
| int |
| kl_member_size(char *s, char *f) |
| { |
| kltype_t *mp; |
| |
| if ((mp = kl_member(s, f))) { |
| return(mp->kl_size); |
| } |
| return(0); |
| } |
| |
| #define TAB_SPACES 8 |
| #define LEVEL_INDENT(level, flags) {\ |
| int i, j; \ |
| if (!(flags & NO_INDENT)) { \ |
| for (i = 0; i < level; i++) { \ |
| for (j = 0; j < TAB_SPACES; j++) { \ |
| lkdb_printf(" "); \ |
| } \ |
| }\ |
| } \ |
| } |
| #define PRINT_NL(flags) \ |
| if (!(flags & SUPPRESS_NL)) { \ |
| lkdb_printf("\n"); \ |
| } |
| #define PRINT_SEMI_COLON(level, flags) \ |
| if (level && (!(flags & SUPPRESS_SEMI_COLON))) { \ |
| lkdb_printf(";"); \ |
| } |
| |
| /* |
| * print_realtype() |
| */ |
| static void |
| print_realtype(kltype_t *kltp) |
| { |
| kltype_t *rkltp; |
| |
| if ((rkltp = kltp->kl_realtype)) { |
| while (rkltp && rkltp->kl_realtype) { |
| rkltp = rkltp->kl_realtype; |
| } |
| if (rkltp->kl_type == KLT_BASE) { |
| lkdb_printf(" (%s)", rkltp->kl_name); |
| } |
| } |
| } |
| |
| int align_chk = 0; |
| /* |
| * kl_print_uint16() |
| * |
| */ |
| void |
| kl_print_uint16(void *ptr, int flags) |
| { |
| unsigned long long a; |
| |
| /* Make sure the pointer is properly aligned (or we will |
| * * dump core) |
| * */ |
| if (align_chk && (uaddr_t)ptr % 16) { |
| lkdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); |
| return; |
| } |
| a = *(unsigned long long *) ptr; |
| if (flags & C_HEX) { |
| lkdb_printf("%#llx", a); |
| } else if (flags & C_BINARY) { |
| lkdb_printf("0b"); |
| kl_binary_print(a); |
| } else { |
| lkdb_printf("%llu", a); |
| } |
| } |
| |
| #if 0 |
| /* |
| * kl_print_float16() |
| * |
| */ |
| void |
| kl_print_float16(void *ptr, int flags) |
| { |
| double a; |
| |
| /* Make sure the pointer is properly aligned (or we will |
| * * dump core) |
| * */ |
| if (align_chk && (uaddr_t)ptr % 16) { |
| lkdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); |
| return; |
| } |
| a = *(double*) ptr; |
| lkdb_printf("%f", a); |
| } |
| #endif |
| |
| /* |
| * kl_print_int16() |
| * |
| */ |
| void |
| kl_print_int16(void *ptr, int flags) |
| { |
| long long a; |
| |
| /* Make sure the pointer is properly aligned (or we will |
| * * dump core) |
| * */ |
| if (align_chk && (uaddr_t)ptr % 16) { |
| lkdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); |
| return; |
| } |
| a = *(long long *) ptr; |
| if (flags & C_HEX) { |
| lkdb_printf("%#llx", a); |
| } else if (flags & C_BINARY) { |
| lkdb_printf("0b"); |
| kl_binary_print(a); |
| } else { |
| lkdb_printf("%lld", a); |
| } |
| } |
| |
| /* |
| * kl_print_int8() |
| */ |
| void |
| kl_print_int8(void *ptr, int flags) |
| { |
| long long a; |
| |
| /* Make sure the pointer is properly aligned (or we will |
| * dump core) |
| */ |
| if (align_chk && (uaddr_t)ptr % 8) { |
| lkdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); |
| return; |
| } |
| a = *(long long *) ptr; |
| if (flags & C_HEX) { |
| lkdb_printf("%#llx", a); |
| } else if (flags & C_BINARY) { |
| lkdb_printf("0b"); |
| kl_binary_print(a); |
| } else { |
| lkdb_printf("%lld", a); |
| } |
| } |
| |
| #if 0 |
| /* |
| * kl_print_float8() |
| */ |
| void |
| kl_print_float8(void *ptr, int flags) |
| { |
| double a; |
| |
| /* Make sure the pointer is properly aligned (or we will |
| * dump core) |
| */ |
| if (align_chk && (uaddr_t)ptr % 8) { |
| lkdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); |
| return; |
| } |
| a = *(double*) ptr; |
| lkdb_printf("%f", a); |
| } |
| #endif |
| |
| /* |
| * kl_print_uint8() |
| */ |
| void |
| kl_print_uint8(void *ptr, int flags) |
| { |
| unsigned long long a; |
| |
| /* Make sure the pointer is properly aligned (or we will |
| * dump core) |
| */ |
| if (align_chk && (uaddr_t)ptr % 8) { |
| lkdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); |
| return; |
| } |
| a = *(unsigned long long *) ptr; |
| if (flags & C_HEX) { |
| lkdb_printf("%#llx", a); |
| } else if (flags & C_BINARY) { |
| lkdb_printf("0b"); |
| kl_binary_print(a); |
| } else { |
| lkdb_printf("%llu", a); |
| } |
| } |
| |
| /* |
| * kl_print_int4() |
| */ |
| void |
| kl_print_int4(void *ptr, int flags) |
| { |
| int32_t a; |
| |
| /* Make sure the pointer is properly aligned (or we will |
| * dump core |
| */ |
| if (align_chk && (uaddr_t)ptr % 4) { |
| lkdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); |
| return; |
| } |
| a = *(int32_t*) ptr; |
| if (flags & C_HEX) { |
| lkdb_printf("0x%x", a); |
| } else if (flags & C_BINARY) { |
| uint64_t value = a & 0xffffffff; |
| lkdb_printf("0b"); |
| kl_binary_print(value); |
| } else { |
| lkdb_printf("%d", a); |
| } |
| } |
| |
| #if 0 |
| /* |
| * kl_print_float4() |
| */ |
| void |
| kl_print_float4(void *ptr, int flags) |
| { |
| float a; |
| |
| /* Make sure the pointer is properly aligned (or we will |
| * dump core) |
| */ |
| if (align_chk && (uaddr_t)ptr % 4) { |
| lkdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); |
| return; |
| } |
| a = *(float*) ptr; |
| lkdb_printf("%f", a); |
| } |
| #endif |
| |
| /* |
| * kl_print_uint4() |
| */ |
| void |
| kl_print_uint4(void *ptr, int flags) |
| { |
| uint32_t a; |
| |
| /* Make sure the pointer is properly aligned (or we will |
| * dump core) |
| */ |
| if (align_chk && (uaddr_t)ptr % 4) { |
| lkdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); |
| return; |
| } |
| a = *(uint32_t*) ptr; |
| if (flags & C_HEX) { |
| lkdb_printf("0x%x", a); |
| } else if (flags & C_BINARY) { |
| uint64_t value = a & 0xffffffff; |
| lkdb_printf("0b"); |
| kl_binary_print(value); |
| } else { |
| lkdb_printf("%u", a); |
| } |
| } |
| |
| /* |
| * kl_print_int2() |
| */ |
| void |
| kl_print_int2(void *ptr, int flags) |
| { |
| int16_t a; |
| |
| /* Make sure the pointer is properly aligned (or we will |
| * dump core |
| */ |
| if (align_chk && (uaddr_t)ptr % 2) { |
| lkdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); |
| return; |
| } |
| a = *(int16_t*) ptr; |
| if (flags & C_HEX) { |
| lkdb_printf("0x%hx", a); |
| } else if (flags & C_BINARY) { |
| uint64_t value = a & 0xffff; |
| lkdb_printf("0b"); |
| kl_binary_print(value); |
| } else { |
| lkdb_printf("%hd", a); |
| } |
| } |
| |
| /* |
| * kl_print_uint2() |
| */ |
| void |
| kl_print_uint2(void *ptr, int flags) |
| { |
| uint16_t a; |
| |
| /* Make sure the pointer is properly aligned (or we will |
| * dump core |
| */ |
| if (align_chk && (uaddr_t)ptr % 2) { |
| lkdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); |
| return; |
| } |
| a = *(uint16_t*) ptr; |
| if (flags & C_HEX) { |
| lkdb_printf("0x%hx", a); |
| } else if (flags & C_BINARY) { |
| uint64_t value = a & 0xffff; |
| lkdb_printf("0b"); |
| kl_binary_print(value); |
| } else { |
| lkdb_printf("%hu", a); |
| } |
| } |
| |
| /* |
| * kl_print_char() |
| */ |
| void |
| kl_print_char(void *ptr, int flags) |
| { |
| char c; |
| |
| if (flags & C_HEX) { |
| lkdb_printf("0x%x", (*(char *)ptr) & 0xff); |
| } else if (flags & C_BINARY) { |
| uint64_t value = (*(char *)ptr) & 0xff; |
| lkdb_printf("0b"); |
| kl_binary_print(value); |
| } else { |
| c = *(char *)ptr; |
| |
| lkdb_printf("\'\\%03o\'", (unsigned char)c); |
| switch (c) { |
| case '\a' : |
| lkdb_printf(" = \'\\a\'"); |
| break; |
| case '\b' : |
| lkdb_printf(" = \'\\b\'"); |
| break; |
| case '\t' : |
| lkdb_printf(" = \'\\t\'"); |
| break; |
| case '\n' : |
| lkdb_printf(" = \'\\n\'"); |
| break; |
| case '\f' : |
| lkdb_printf(" = \'\\f\'"); |
| break; |
| case '\r' : |
| lkdb_printf(" = \'\\r\'"); |
| break; |
| case '\e' : |
| lkdb_printf(" = \'\\e\'"); |
| break; |
| default : |
| if( !iscntrl((unsigned char) c) ) { |
| lkdb_printf(" = \'%c\'", c); |
| } |
| break; |
| } |
| } |
| } |
| |
| /* |
| * kl_print_uchar() |
| */ |
| void |
| kl_print_uchar(void *ptr, int flags) |
| { |
| if (flags & C_HEX) { |
| lkdb_printf("0x%x", *(unsigned char *)ptr); |
| } else if (flags & C_BINARY) { |
| uint64_t value = (*(unsigned char *)ptr) & 0xff; |
| lkdb_printf("0b"); |
| kl_binary_print(value); |
| } else { |
| lkdb_printf("%u", *(unsigned char *)ptr); |
| } |
| } |
| |
| /* |
| * kl_print_base() |
| */ |
| void |
| kl_print_base(void *ptr, int size, int encoding, int flags) |
| { |
| /* FIXME: untested */ |
| if (invalid_address((kaddr_t)ptr, size)) { |
| lkdb_printf("ILLEGAL ADDRESS (%lx)", (uaddr_t)ptr); |
| return; |
| } |
| switch (size) { |
| |
| case 1: |
| if (encoding == ENC_UNSIGNED) { |
| kl_print_uchar(ptr, flags); |
| } else { |
| kl_print_char(ptr, flags); |
| } |
| break; |
| |
| case 2: |
| if (encoding == ENC_UNSIGNED) { |
| kl_print_uint2(ptr, flags); |
| } else { |
| kl_print_int2(ptr, flags); |
| } |
| break; |
| |
| case 4: |
| if (encoding == ENC_UNSIGNED) { |
| kl_print_uint4(ptr, flags); |
| } else if (encoding == ENC_FLOAT) { |
| printk("error: print of 4-byte float\n"); |
| /* kl_print_float4(ptr, flags); */ |
| } else { |
| kl_print_int4(ptr, flags); |
| } |
| break; |
| |
| case 8: |
| if (encoding == ENC_UNSIGNED) { |
| kl_print_uint8(ptr, flags); |
| } else if (encoding == ENC_FLOAT) { |
| printk("error: print of 8-byte float\n"); |
| /* kl_print_float8(ptr, flags); */ |
| } else { |
| kl_print_int8(ptr, flags); |
| } |
| break; |
| |
| case 16: |
| if (encoding == ENC_UNSIGNED) { |
| /* Ex: unsigned long long */ |
| kl_print_uint16(ptr, flags); |
| } else if (encoding == ENC_FLOAT) { |
| printk("error: print of 16-byte float\n"); |
| /* Ex: long double */ |
| /* kl_print_float16(ptr, flags); */ |
| } else { |
| /* Ex: long long */ |
| kl_print_int16(ptr, flags); |
| } |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| /* |
| * kl_print_base_value() |
| */ |
| void |
| kl_print_base_value(void *ptr, kltype_t *kltp, int flags) |
| { |
| kltype_t *rkltp=NULL; |
| |
| if (kltp->kl_type != KLT_BASE) { |
| if (!(rkltp = kltp->kl_realtype)) { |
| return; |
| } |
| if (rkltp->kl_type != KLT_BASE) { |
| return; |
| } |
| } else { |
| rkltp = kltp; |
| } |
| kl_print_base(ptr, rkltp->kl_size, rkltp->kl_encoding, flags); |
| } |
| |
| /* |
| * kl_print_typedef_type() |
| */ |
| void |
| kl_print_typedef_type( |
| void *ptr, |
| kltype_t *kltp, |
| int level, |
| int flags) |
| { |
| char *name; |
| kltype_t *rkltp; |
| |
| if (ptr) { |
| rkltp = kltp->kl_realtype; |
| while (rkltp->kl_type == KLT_TYPEDEF) { |
| if (rkltp->kl_realtype) { |
| rkltp = rkltp->kl_realtype; |
| } |
| } |
| if (rkltp->kl_type == KLT_POINTER) { |
| kl_print_pointer_type(ptr, kltp, level, flags); |
| return; |
| } |
| switch (rkltp->kl_type) { |
| case KLT_BASE: |
| kl_print_base_type(ptr, kltp, |
| level, flags); |
| break; |
| |
| case KLT_UNION: |
| case KLT_STRUCT: |
| kl_print_struct_type(ptr, kltp, |
| level, flags); |
| break; |
| |
| case KLT_ARRAY: |
| kl_print_array_type(ptr, kltp, |
| level, flags); |
| break; |
| |
| case KLT_ENUMERATION: |
| kl_print_enumeration_type(ptr, |
| kltp, level, flags); |
| break; |
| |
| default: |
| kl_print_base_type(ptr, kltp, |
| level, flags); |
| break; |
| } |
| } else { |
| LEVEL_INDENT(level, flags); |
| if (flags & NO_REALTYPE) { |
| rkltp = kltp; |
| } else { |
| rkltp = kltp->kl_realtype; |
| while (rkltp && rkltp->kl_type == KLT_POINTER) { |
| rkltp = rkltp->kl_realtype; |
| } |
| } |
| if (!rkltp) { |
| if (SUPPRESS_NAME) { |
| lkdb_printf("<UNKNOWN>"); |
| } else { |
| lkdb_printf( "typedef <UNKNOWN>%s;", |
| kltp->kl_name); |
| } |
| return; |
| } |
| if (rkltp->kl_type == KLT_FUNCTION) { |
| if (kltp->kl_realtype->kl_type == KLT_POINTER) { |
| lkdb_printf("typedef %s(*%s)();", |
| kltp->kl_typestr, kltp->kl_name); |
| } else { |
| lkdb_printf( "typedef %s(%s)();", |
| kltp->kl_typestr, kltp->kl_name); |
| } |
| } else if (rkltp->kl_type == KLT_ARRAY) { |
| kl_print_array_type(ptr, rkltp, level, flags); |
| } else if (rkltp->kl_type == KLT_TYPEDEF) { |
| if (!(name = rkltp->kl_name)) { |
| name = rkltp->kl_typestr; |
| } |
| |
| if (SUPPRESS_NAME) { |
| lkdb_printf("%s", name); |
| } else { |
| lkdb_printf("typedef %s%s;", |
| name, kltp->kl_name); |
| } |
| print_realtype(rkltp); |
| } else { |
| kl_print_type(ptr, rkltp, level, flags); |
| } |
| PRINT_NL(flags); |
| } |
| } |
| |
| /* |
| * kl_print_pointer_type() |
| */ |
| void |
| kl_print_pointer_type( |
| void *ptr, |
| kltype_t *kltp, |
| int level, |
| int flags) |
| { |
| kltype_t *itp; |
| |
| if (kltp->kl_type == KLT_MEMBER) { |
| itp = kltp->kl_realtype; |
| } else { |
| itp = kltp; |
| } |
| |
| /* See if this is a pointer to a function. If it is, then it |
| * has to be handled differently... |
| */ |
| while (itp->kl_type == KLT_POINTER) { |
| if ((itp = itp->kl_realtype)) { |
| if (itp->kl_type == KLT_FUNCTION) { |
| kl_print_function_type(ptr, |
| kltp, level, flags); |
| return; |
| } |
| } else { |
| LEVEL_INDENT(level, flags); |
| lkdb_printf("%s%s;\n", |
| kltp->kl_typestr, kltp->kl_name); |
| return; |
| } |
| } |
| |
| LEVEL_INDENT(level, flags); |
| if (ptr) { |
| kaddr_t tmp; |
| tmp = *(kaddr_t *)ptr; |
| flags |= SUPPRESS_SEMI_COLON; |
| if(kltp->kl_name){ |
| if (*(kaddr_t *)ptr) { |
| lkdb_printf("%s = 0x%"FMTPTR"x", |
| kltp->kl_name, tmp); |
| } else { |
| lkdb_printf("%s = (nil)", kltp->kl_name); |
| } |
| } else { |
| if (tmp != 0) { |
| lkdb_printf("0x%"FMTPTR"x", tmp); |
| } else { |
| lkdb_printf( "(nil)"); |
| } |
| } |
| } else { |
| if (kltp->kl_typestr) { |
| if (kltp->kl_name && !(flags & SUPPRESS_NAME)) { |
| lkdb_printf("%s%s", |
| kltp->kl_typestr, kltp->kl_name); |
| } else { |
| lkdb_printf("%s", kltp->kl_typestr); |
| } |
| } else { |
| lkdb_printf("<UNKNOWN>"); |
| } |
| } |
| PRINT_SEMI_COLON(level, flags); |
| PRINT_NL(flags); |
| } |
| |
| /* |
| * kl_print_function_type() |
| */ |
| void |
| kl_print_function_type( |
| void *ptr, |
| kltype_t *kltp, |
| int level, |
| int flags) |
| { |
| LEVEL_INDENT(level, flags); |
| if (ptr) { |
| kaddr_t a; |
| |
| a = *(kaddr_t *)ptr; |
| lkdb_printf("%s = 0x%"FMTPTR"x", kltp->kl_name, a); |
| } else { |
| if (flags & SUPPRESS_NAME) { |
| lkdb_printf("%s(*)()", kltp->kl_typestr); |
| } else { |
| lkdb_printf("%s(*%s)();", |
| kltp->kl_typestr, kltp->kl_name); |
| } |
| } |
| PRINT_NL(flags); |
| } |
| |
| /* |
| * kl_print_array_type() |
| */ |
| void |
| kl_print_array_type(void *ptr, kltype_t *kltp, int level, int flags) |
| { |
| int i, count = 0, anon = 0, size, low, high, multi = 0; |
| char typestr[128], *name, *p; |
| kltype_t *rkltp, *etp, *retp; |
| |
| if (kltp->kl_type != KLT_ARRAY) { |
| if ((rkltp = kltp->kl_realtype)) { |
| while (rkltp->kl_type != KLT_ARRAY) { |
| if (!(rkltp = rkltp->kl_realtype)) { |
| break; |
| } |
| } |
| } |
| if (!rkltp) { |
| LEVEL_INDENT(level, flags); |
| lkdb_printf("<ARRAY_TYPE>"); |
| PRINT_SEMI_COLON(level, flags); |
| PRINT_NL(flags); |
| return; |
| } |
| } else { |
| rkltp = kltp; |
| } |
| |
| etp = rkltp->kl_elementtype; |
| if (!etp) { |
| LEVEL_INDENT(level, flags); |
| lkdb_printf("<BAD_ELEMENT_TYPE> %s", rkltp->kl_name); |
| PRINT_SEMI_COLON(level, flags); |
| PRINT_NL(flags); |
| return; |
| } |
| |
| /* Set retp to point to the actual element type. This is necessary |
| * for multi-dimensional arrays, which link using the kl_elementtype |
| * member. |
| */ |
| retp = etp; |
| while (retp->kl_type == KLT_ARRAY) { |
| retp = retp->kl_elementtype; |
| } |
| low = rkltp->kl_low_bounds + 1; |
| high = rkltp->kl_high_bounds; |
| |
| if (ptr) { |
| |
| p = ptr; |
| |
| if ((retp->kl_size == 1) && (retp->kl_encoding == ENC_CHAR)) { |
| if (kltp->kl_type == KLT_MEMBER) { |
| LEVEL_INDENT(level, flags); |
| } |
| if (flags & SUPPRESS_NAME) { |
| lkdb_printf("\""); |
| flags &= ~SUPPRESS_NAME; |
| } else { |
| lkdb_printf("%s = \"", kltp->kl_name); |
| } |
| for (i = 0; i < high; i++) { |
| if (*(char*)p == 0) { |
| break; |
| } |
| lkdb_printf("%c", *(char *)p); |
| p++; |
| } |
| lkdb_printf("\""); |
| PRINT_NL(flags); |
| } else { |
| if (kltp->kl_type == KLT_MEMBER) { |
| LEVEL_INDENT(level, flags); |
| } |
| |
| if (flags & SUPPRESS_NAME) { |
| lkdb_printf("{\n"); |
| flags &= ~SUPPRESS_NAME; |
| } else { |
| lkdb_printf("%s = {\n", kltp->kl_name); |
| } |
| |
| if (retp->kl_type == KLT_POINTER) { |
| size = sizeof(void *); |
| } else { |
| while (retp->kl_realtype) { |
| retp = retp->kl_realtype; |
| } |
| size = retp->kl_size; |
| } |
| if ((retp->kl_type != KLT_STRUCT) && |
| (retp->kl_type != KLT_UNION)) { |
| /* Turn off the printing of names for all |
| * but structs and unions. |
| */ |
| flags |= SUPPRESS_NAME; |
| } |
| for (i = low; i <= high; i++) { |
| |
| LEVEL_INDENT(level + 1, flags); |
| lkdb_printf("[%d] ", i); |
| |
| switch (retp->kl_type) { |
| case KLT_POINTER : |
| kl_print_pointer_type( |
| p, retp, level, |
| flags|NO_INDENT); |
| break; |
| |
| case KLT_TYPEDEF: |
| kl_print_typedef_type( |
| p, retp, level, |
| flags|NO_INDENT); |
| break; |
| |
| case KLT_BASE: |
| kl_print_base_value(p, |
| retp, flags|NO_INDENT); |
| lkdb_printf("\n"); |
| break; |
| |
| case KLT_ARRAY: |
| kl_print_array_type(p, retp, |
| level + 1, |
| flags|SUPPRESS_NAME); |
| break; |
| |
| case KLT_STRUCT: |
| case KLT_UNION: |
| kl_print_struct_type(p, |
| retp, level + 1, |
| flags|NO_INDENT); |
| break; |
| |
| default: |
| kl_print_base_value( |
| p, retp, |
| flags|NO_INDENT); |
| lkdb_printf("\n"); |
| break; |
| } |
| p = (void *)((uaddr_t)p + size); |
| } |
| LEVEL_INDENT(level, flags); |
| lkdb_printf("}"); |
| PRINT_SEMI_COLON(level, flags); |
| PRINT_NL(flags); |
| } |
| } else { |
| if (rkltp) { |
| count = (rkltp->kl_high_bounds - |
| rkltp->kl_low_bounds) + 1; |
| } else { |
| count = 1; |
| } |
| |
| if (!strcmp(retp->kl_typestr, "struct ") || |
| !strcmp(retp->kl_typestr, "union ")) { |
| anon = 1; |
| } |
| next_dimension: |
| switch (retp->kl_type) { |
| |
| case KLT_UNION: |
| case KLT_STRUCT: |
| if (anon) { |
| if (multi) { |
| lkdb_printf("[%d]", count); |
| break; |
| } |
| kl_print_struct_type(ptr, retp, level, |
| flags| |
| SUPPRESS_NL| |
| SUPPRESS_SEMI_COLON); |
| if (kltp->kl_type == KLT_MEMBER) { |
| lkdb_printf(" %s[%d]", |
| kltp->kl_name, count); |
| } else { |
| lkdb_printf(" [%d]", count); |
| } |
| break; |
| } |
| /* else drop through */ |
| |
| default: |
| LEVEL_INDENT(level, flags); |
| if (multi) { |
| lkdb_printf("[%d]", count); |
| break; |
| } |
| name = kltp->kl_name; |
| if (retp->kl_type == KLT_TYPEDEF) { |
| strcpy(typestr, retp->kl_name); |
| strcat(typestr, " "); |
| } else { |
| strcpy(typestr, retp->kl_typestr); |
| } |
| if (!name || (flags & SUPPRESS_NAME)) { |
| lkdb_printf("%s[%d]", typestr, count); |
| } else { |
| lkdb_printf("%s%s[%d]", |
| typestr, name, count); |
| } |
| } |
| if (etp->kl_type == KLT_ARRAY) { |
| count = etp->kl_high_bounds - etp->kl_low_bounds + 1; |
| etp = etp->kl_elementtype; |
| multi++; |
| goto next_dimension; |
| } |
| PRINT_SEMI_COLON(level, flags); |
| PRINT_NL(flags); |
| } |
| } |
| |
| /* |
| * kl_print_enumeration_type() |
| */ |
| void |
| kl_print_enumeration_type( |
| void *ptr, |
| kltype_t *kltp, |
| int level, |
| int flags) |
| { |
| unsigned long long val = 0; |
| kltype_t *mp, *rkltp; |
| |
| rkltp = kl_realtype(kltp, KLT_ENUMERATION); |
| if (ptr) { |
| switch (kltp->kl_size) { |
| case 1: |
| val = *(unsigned long long *)ptr; |
| break; |
| |
| case 2: |
| val = *(uint16_t *)ptr; |
| break; |
| |
| case 4: |
| val = *(uint32_t *)ptr; |
| break; |
| |
| case 8: |
| val = *(uint64_t *)ptr; |
| break; |
| } |
| mp = rkltp->kl_member; |
| while (mp) { |
| if (mp->kl_value == val) { |
| break; |
| } |
| mp = mp->kl_member; |
| } |
| LEVEL_INDENT(level, flags); |
| if (mp) { |
| lkdb_printf("%s = (%s=%lld)", |
| kltp->kl_name, mp->kl_name, val); |
| } else { |
| lkdb_printf("%s = %lld", kltp->kl_name, val); |
| } |
| PRINT_NL(flags); |
| } else { |
| LEVEL_INDENT(level, flags); |
| lkdb_printf ("%s {", kltp->kl_typestr); |
| mp = rkltp->kl_member; |
| while (mp) { |
| lkdb_printf("%s = %d", mp->kl_name, mp->kl_value); |
| if ((mp = mp->kl_member)) { |
| lkdb_printf(", "); |
| } |
| } |
| mp = kltp; |
| if (level) { |
| lkdb_printf("} %s;", mp->kl_name); |
| } else { |
| lkdb_printf("};"); |
| } |
| PRINT_NL(flags); |
| } |
| } |
| |
| /* |
| * kl_binary_print() |
| */ |
| void |
| kl_binary_print(uint64_t num) |
| { |
| int i, pre = 1; |
| |
| for (i = 63; i >= 0; i--) { |
| if (num & ((uint64_t)1 << i)) { |
| lkdb_printf("1"); |
| if (pre) { |
| pre = 0; |
| } |
| } else { |
| if (!pre) { |
| lkdb_printf("0"); |
| } |
| } |
| } |
| if (pre) { |
| lkdb_printf("0"); |
| } |
| } |
| |
| /* |
| * kl_get_bit_value() |
| * |
| * x = byte_size, y = bit_size, z = bit_offset |
| */ |
| uint64_t |
| kl_get_bit_value(void *ptr, unsigned int x, unsigned int y, unsigned int z) |
| { |
| uint64_t value=0, mask; |
| |
| /* handle x bytes of buffer -- doing just memcpy won't work |
| * on big endian architectures |
| */ |
| switch (x) { |
| case 5: |
| case 6: |
| case 7: |
| case 8: |
| x = 8; |
| value = *(uint64_t*) ptr; |
| break; |
| case 3: |
| case 4: |
| x = 4; |
| value = *(uint32_t*) ptr; |
| break; |
| case 2: |
| value = *(uint16_t*) ptr; |
| break; |
| case 1: |
| value = *(uint8_t *)ptr; |
| break; |
| default: |
| /* FIXME: set KL_ERROR */ |
| return(0); |
| } |
| /* |
| o FIXME: correct handling of overlapping fields |
| */ |
| |
| /* goto bit offset */ |
| value = value >> z; |
| |
| /* mask bit size bits */ |
| mask = (((uint64_t)1 << y) - 1); |
| return (value & mask); |
| } |
| |
| /* |
| * kl_print_bit_value() |
| * |
| * x = byte_size, y = bit_size, z = bit_offset |
| */ |
| void |
| kl_print_bit_value(void *ptr, int x, int y, int z, int flags) |
| { |
| unsigned long long value; |
| |
| value = kl_get_bit_value(ptr, x, y, z); |
| if (flags & C_HEX) { |
| lkdb_printf("%#llx", value); |
| } else if (flags & C_BINARY) { |
| lkdb_printf("0b"); |
| kl_binary_print(value); |
| } else { |
| lkdb_printf("%lld", value); |
| } |
| } |
| |
| /* |
| * kl_print_base_type() |
| */ |
| void |
| kl_print_base_type(void *ptr, kltype_t *kltp, int level, int flags) |
| { |
| LEVEL_INDENT(level, flags); |
| if (ptr) { |
| if (!(flags & SUPPRESS_NAME)) { |
| lkdb_printf ("%s = ", kltp->kl_name); |
| } |
| } |
| if (kltp->kl_type == KLT_MEMBER) { |
| if (kltp->kl_bit_size < (kltp->kl_size * 8)) { |
| if (ptr) { |
| kl_print_bit_value(ptr, kltp->kl_size, |
| kltp->kl_bit_size, |
| kltp->kl_bit_offset, flags); |
| } else { |
| if (kltp->kl_name) { |
| lkdb_printf ("%s%s :%d;", |
| kltp->kl_typestr, |
| kltp->kl_name, |
| kltp->kl_bit_size); |
| } else { |
| lkdb_printf ("%s :%d;", |
| kltp->kl_typestr, |
| kltp->kl_bit_size); |
| } |
| } |
| PRINT_NL(flags); |
| return; |
| } |
| } |
| if (ptr) { |
| kltype_t *rkltp; |
| |
| rkltp = kl_realtype(kltp, 0); |
| if (rkltp->kl_encoding == ENC_UNDEFINED) { |
| /* This is a void value |
| */ |
| lkdb_printf("<VOID>"); |
| } else { |
| kl_print_base(ptr, kltp->kl_size, |
| rkltp->kl_encoding, flags); |
| } |
| } else { |
| if (kltp->kl_type == KLT_MEMBER) { |
| if (flags & SUPPRESS_NAME) { |
| lkdb_printf ("%s", kltp->kl_typestr); |
| } else { |
| if (kltp->kl_name) { |
| lkdb_printf("%s%s;", kltp->kl_typestr, |
| kltp->kl_name); |
| } else { |
| lkdb_printf ("%s :%d;", |
| kltp->kl_typestr, |
| kltp->kl_bit_size); |
| } |
| } |
| } else { |
| if (SUPPRESS_NAME) { |
| lkdb_printf("%s", kltp->kl_name); |
| } else { |
| lkdb_printf("%s;", kltp->kl_name); |
| } |
| } |
| } |
| PRINT_NL(flags); |
| } |
| |
| /* |
| * kl_print_member() |
| */ |
| void |
| kl_print_member(void *ptr, kltype_t *mp, int level, int flags) |
| { |
| int kl_type = 0; |
| kltype_t *rkltp; |
| |
| if (flags & C_SHOWOFFSET) { |
| lkdb_printf("%#x ", mp->kl_offset); |
| } |
| |
| if ((rkltp = mp->kl_realtype)) { |
| kl_type = rkltp->kl_type; |
| } else |
| kl_type = mp->kl_type; |
| switch (kl_type) { |
| case KLT_STRUCT: |
| case KLT_UNION: |
| kl_print_struct_type(ptr, mp, level, flags); |
| break; |
| case KLT_ARRAY: |
| kl_print_array_type(ptr, mp, level, flags); |
| break; |
| case KLT_POINTER: |
| kl_print_pointer_type(ptr, mp, level, flags); |
| break; |
| case KLT_FUNCTION: |
| kl_print_function_type(ptr, mp, level, flags); |
| break; |
| case KLT_BASE: |
| kl_print_base_type(ptr, mp, level, flags); |
| break; |
| case KLT_ENUMERATION: |
| kl_print_enumeration_type(ptr, mp, level, flags); |
| break; |
| case KLT_TYPEDEF: |
| while (rkltp && rkltp->kl_realtype) { |
| if (rkltp->kl_realtype == rkltp) { |
| break; |
| } |
| rkltp = rkltp->kl_realtype; |
| } |
| if (ptr) { |
| kl_print_typedef_type(ptr, mp, |
| level, flags); |
| break; |
| } |
| LEVEL_INDENT(level, flags); |
| if (flags & SUPPRESS_NAME) { |
| if (rkltp && (mp->kl_bit_size < |
| (rkltp->kl_size * 8))) { |
| lkdb_printf ("%s :%d", |
| mp->kl_typestr, |
| mp->kl_bit_size); |
| } else { |
| lkdb_printf("%s", |
| mp->kl_realtype->kl_name); |
| } |
| print_realtype(mp->kl_realtype); |
| } else { |
| if (rkltp && (mp->kl_bit_size < |
| (rkltp->kl_size * 8))) { |
| if (mp->kl_name) { |
| lkdb_printf ("%s%s :%d;", |
| mp->kl_typestr, |
| mp->kl_name, |
| mp->kl_bit_size); |
| } else { |
| lkdb_printf ("%s :%d;", |
| mp->kl_typestr, |
| mp->kl_bit_size); |
| } |
| } else { |
| lkdb_printf("%s %s;", |
| mp->kl_realtype->kl_name, |
| mp->kl_name); |
| } |
| } |
| PRINT_NL(flags); |
| break; |
| |
| default: |
| LEVEL_INDENT(level, flags); |
| if (mp->kl_typestr) { |
| lkdb_printf("%s%s;", |
| mp->kl_typestr, mp->kl_name); |
| } else { |
| lkdb_printf("<\?\?\? kl_type:%d> %s;", |
| kl_type, mp->kl_name); |
| } |
| PRINT_NL(flags); |
| break; |
| } |
| } |
| |
| /* |
| * kl_print_struct_type() |
| */ |
| void |
| kl_print_struct_type(void *buf, kltype_t *kltp, int level, int flags) |
| { |
| int orig_flags = flags; |
| void *ptr = NULL; |
| kltype_t *mp, *rkltp; |
| |
| /* If we are printing out an actual struct, then don't print any |
| * semi colons. |
| */ |
| if (buf) { |
| flags |= SUPPRESS_SEMI_COLON; |
| } |
| |
| LEVEL_INDENT(level, flags); |
| if ((level == 0) || (flags & NO_INDENT)) { |
| lkdb_printf("%s{\n", kltp->kl_typestr); |
| } else { |
| if (buf) { |
| if (level && !(kltp->kl_flags & TYP_ANONYMOUS_FLG)) { |
| lkdb_printf("%s = %s{\n", |
| kltp->kl_name, kltp->kl_typestr); |
| } else { |
| lkdb_printf("%s{\n", kltp->kl_typestr); |
| } |
| flags &= (~SUPPRESS_NL); |
| } else { |
| if (kltp->kl_typestr) { |
| lkdb_printf("%s{\n", kltp->kl_typestr); |
| } else { |
| lkdb_printf("<UNKNOWN> {\n"); |
| } |
| } |
| } |
| |
| /* If the SUPPRESS_NL, SUPPRESS_SEMI_COLON, and SUPPRESS_NAME flags |
| * are set and buf is NULL, then turn them off as they only apply |
| * at the end of the struct. We save the original flags for that |
| * purpose. |
| */ |
| if (!buf) { |
| flags &= ~(SUPPRESS_NL|SUPPRESS_SEMI_COLON|SUPPRESS_NAME); |
| } |
| |
| /* If the NO_INDENT is set, we need to turn it off at this |
| * point -- just in case we come across a member of this struct |
| * that is also a struct. |
| */ |
| if (flags & NO_INDENT) { |
| flags &= ~(NO_INDENT); |
| } |
| |
| if (kltp->kl_type == KLT_MEMBER) { |
| rkltp = kl_realtype(kltp, 0); |
| } else { |
| rkltp = kltp; |
| } |
| level++; |
| if ((mp = rkltp->kl_member)) { |
| while (mp) { |
| if (buf) { |
| ptr = buf + mp->kl_offset; |
| } |
| kl_print_member(ptr, mp, level, flags); |
| mp = mp->kl_member; |
| } |
| } else { |
| if (kltp->kl_flags & TYP_INCOMPLETE_FLG) { |
| LEVEL_INDENT(level, flags); |
| lkdb_printf("<INCOMPLETE TYPE>\n"); |
| } |
| } |
| level--; |
| LEVEL_INDENT(level, flags); |
| |
| /* kl_size = 0 for empty structs */ |
| if (ptr || ((kltp->kl_size == 0) && buf)) { |
| lkdb_printf("}"); |
| } else if ((kltp->kl_type == KLT_MEMBER) && |
| !(orig_flags & SUPPRESS_NAME) && |
| !(kltp->kl_flags & TYP_ANONYMOUS_FLG)) { |
| lkdb_printf("} %s", kltp->kl_name); |
| } else { |
| lkdb_printf("}"); |
| } |
| PRINT_SEMI_COLON(level, orig_flags); |
| PRINT_NL(orig_flags); |
| } |
| |
| /* |
| * kl_print_type() |
| */ |
| void |
| kl_print_type(void *buf, kltype_t *kltp, int level, int flags) |
| { |
| void *ptr; |
| |
| if (buf) { |
| if (kltp->kl_offset) { |
| ptr = (void *)((uaddr_t)buf + kltp->kl_offset); |
| } else { |
| ptr = buf; |
| } |
| } else { |
| ptr = 0; |
| } |
| |
| /* Only allow binary printing for base types |
| */ |
| if (kltp->kl_type != KLT_BASE) { |
| flags &= (~C_BINARY); |
| } |
| switch (kltp->kl_type) { |
| |
| case KLT_TYPEDEF: |
| kl_print_typedef_type(ptr, kltp, level, flags); |
| break; |
| |
| case KLT_STRUCT: |
| case KLT_UNION: |
| kl_print_struct_type(ptr, kltp, level, flags); |
| break; |
| |
| case KLT_MEMBER: |
| kl_print_member(ptr, kltp, level, flags); |
| break; |
| |
| case KLT_POINTER: |
| kl_print_pointer_type(ptr, kltp, level, flags); |
| break; |
| |
| case KLT_FUNCTION: |
| LEVEL_INDENT(level, flags); |
| kl_print_function_type(ptr, kltp, level, flags); |
| break; |
| |
| case KLT_ARRAY: |
| kl_print_array_type(ptr, kltp, level, flags); |
| break; |
| |
| case KLT_ENUMERATION: |
| kl_print_enumeration_type(ptr, |
| kltp, level, flags); |
| break; |
| |
| case KLT_BASE: |
| kl_print_base_type(ptr, kltp, level, flags); |
| break; |
| |
| default: |
| LEVEL_INDENT(level, flags); |
| if (flags & SUPPRESS_NAME) { |
| lkdb_printf ("%s", kltp->kl_name); |
| } else { |
| lkdb_printf ("%s %s;", |
| kltp->kl_name, kltp->kl_name); |
| } |
| PRINT_NL(flags); |
| } |
| } |
| |
| /* |
| * eval is from lcrash eval.c |
| */ |
| |
| /* Forward declarations */ |
| static void free_node(node_t *); |
| static node_t *make_node(token_t *, int); |
| static node_t *get_node_list(token_t *, int); |
| static node_t *do_eval(int); |
| static int is_unary(int); |
| static int is_binary(int); |
| static int precedence(int); |
| static node_t *get_sizeof(void); |
| static int replace_cast(node_t *, int); |
| static int replace_unary(node_t *, int); |
| static node_t *replace(node_t *, int); |
| static void array_to_element(node_t*, node_t*); |
| static int type_to_number(node_t *); |
| kltype_t *number_to_type(node_t *); |
| static type_t *eval_type(node_t *); |
| static type_t *get_type(char *, int); |
| static int add_rchild(node_t *, node_t *); |
| static void free_nodelist(node_t *); |
| |
| /* Global variables |
| */ |
| static int logical_flag; |
| static node_t *node_list = (node_t *)NULL; |
| uint64_t eval_error; |
| char *error_token; |
| |
| /* |
| * set_eval_error() |
| */ |
| static void |
| set_eval_error(uint64_t ecode) |
| { |
| eval_error = ecode; |
| } |
| |
| /* |
| * is_typestr() |
| * |
| * We check for "struct", "union", etc. separately because they |
| * would not be an actual part of the type name. We also assume |
| * that the string passed in |
| * |
| * - does not have any leading blanks or tabs |
| * - is NULL terminated |
| * - contains only one type name to check |
| * - does not contain any '*' characters |
| */ |
| static int |
| is_typestr(char *str) |
| { |
| int len; |
| |
| len = strlen(str); |
| if ((len >= 6) && !strncmp(str, "struct", 6)) { |
| return(1); |
| } else if ((len >= 5) &&!strncmp(str, "union", 5)) { |
| return(1); |
| } else if ((len >= 5) &&!strncmp(str, "short", 5)) { |
| return(1); |
| } else if ((len >= 8) &&!strncmp(str, "unsigned", 8)) { |
| return(1); |
| } else if ((len >= 6) &&!strncmp(str, "signed", 6)) { |
| return(1); |
| } else if ((len >= 4) &&!strncmp(str, "long", 4)) { |
| return(1); |
| } |
| /* Strip off any trailing blanks |
| */ |
| while(*str && ((str[strlen(str) - 1] == ' ') |
| || (str[strlen(str) - 1] == '\t'))) { |
| str[strlen(str) - 1] = 0; |
| } |
| if (kl_find_type(str, KLT_TYPES)) { |
| return (1); |
| } |
| return(0); |
| } |
| |
| /* |
| * free_tokens() |
| */ |
| static void |
| free_tokens(token_t *tp) |
| { |
| token_t *t, *tnext; |
| |
| t = tp; |
| while (t) { |
| tnext = t->next; |
| if (t->string) { |
| kl_free_block((void *)t->string); |
| } |
| kl_free_block((void *)t); |
| t = tnext; |
| } |
| } |
| |
| /* |
| * process_text() |
| */ |
| static int |
| process_text(char **str, token_t *tok) |
| { |
| char *cp = *str; |
| char *s = NULL; |
| int len = 0; |
| |
| /* Check and see if this token is a STRING or CHARACTER |
| * type (beginning with a single or double quote). |
| */ |
| if (*cp == '\'') { |
| /* make sure that only a single character is between |
| * the single quotes (it can be an escaped character |
| * too). |
| */ |
| s = strpbrk((cp + 1), "\'"); |
| if (!s) { |
| set_eval_error(E_SINGLE_QUOTE); |
| error_token = tok->ptr; |
| return(1); |
| } |
| len = (uaddr_t)s - (uaddr_t)cp; |
| if ((*(cp+1) == '\\')) { |
| if (*(cp+2) == '0') { |
| long int val; |
| unsigned long uval; |
| char *ep; |
| |
| uval = kl_strtoull((char*)(cp+2), |
| (char **)&ep, 8); |
| val = uval; |
| if ((val > 255) || (*ep != '\'')) { |
| set_eval_error(E_BAD_CHAR); |
| error_token = tok->ptr; |
| return(1); |
| } |
| } else if (*(cp+3) != '\'') { |
| set_eval_error(E_BAD_CHAR); |
| error_token = tok->ptr; |
| return(1); |
| } |
| tok->type = CHARACTER; |
| } else if (len == 2) { |
| tok->type = CHARACTER; |
| } else { |
| |
| /* Treat as a single token entry. It's possible |
| * that what's between the single quotes is a |
| * type name. That will be determined later on. |
| */ |
| tok->type = STRING; |
| } |
| *str = cp + len; |
| } else if (*cp == '\"') { |
| s = strpbrk((cp + 1), "\""); |
| if (!s) { |
| set_eval_error(E_BAD_STRING); |
| error_token = tok->ptr; |
| return(1); |
| } |
| len = (uaddr_t)s - (uaddr_t)cp; |
| tok->type = TEXT; |
| *str = cp + len; |
| } |
| if ((tok->type == STRING) || (tok->type == TEXT)) { |
| |
| if ((tok->type == TEXT) && (strlen(cp) > (len + 1))) { |
| |
| /* Check to see if there is a comma or semi-colon |
| * directly following the string. If there is, |
| * then the string is OK (the following characters |
| * are part of the next expression). Also, it's OK |
| * to have trailing blanks as long as that's all |
| * threre is. |
| */ |
| char *c; |
| |
| c = s + 1; |
| while (*c) { |
| if ((*c == ',') || (*c == ';')) { |
| break; |
| } else if (*c != ' ') { |
| set_eval_error(E_END_EXPECTED); |
| tok->ptr = c; |
| error_token = tok->ptr; |
| return(1); |
| } |
| c++; |
| } |
| /* Truncate the trailing blanks (they are not |
| * part of the string). |
| */ |
| if (c != (s + 1)) { |
| *(s + 1) = 0; |
| } |
| } |
| tok->string = (char *)kl_alloc_block(len); |
| memcpy(tok->string, (cp + 1), len - 1); |
| tok->string[len - 1] = 0; |
| } |
| return(0); |
| } |
| |
| /* |
| * get_token_list() |
| */ |
| static token_t * |
| get_token_list(char *str) |
| { |
| int paren_count = 0; |
| char *cp; |
| token_t *tok = (token_t*)NULL, *tok_head = (token_t*)NULL; |
| token_t *tok_last = (token_t*)NULL; |
| |
| cp = str; |
| eval_error = 0; |
| |
| while (*cp) { |
| |
| /* Skip past any "white space" (spaces and tabs). |
| */ |
| switch (*cp) { |
| case ' ' : |
| case '\t' : |
| case '`' : |
| cp++; |
| continue; |
| default : |
| break; |
| } |
| |
| /* Allocate space for the next token */ |
| tok = (token_t *)kl_alloc_block(sizeof(token_t)); |
| tok->ptr = cp; |
| |
| switch(*cp) { |
| |
| /* Check for operators |
| */ |
| case '+' : |
| if (*((char*)cp + 1) == '+') { |
| |
| /* We aren't doing asignment here, |
| * so the ++ operator is not |
| * considered valid. |
| */ |
| set_eval_error(E_BAD_OPERATOR); |
| error_token = tok_last->ptr; |
| free_tokens(tok_head); |
| free_tokens(tok); |
| return ((token_t*)NULL); |
| } else if (!tok_last || |
| (tok_last->operator && |
| (tok_last->operator != CLOSE_PAREN))) { |
| tok->operator = UNARY_PLUS; |
| } else { |
| tok->operator = ADD; |
| } |
| break; |
| |
| case '-' : |
| if (*((char*)cp + 1) == '-') { |
| |
| /* We aren't doing asignment here, so |
| * the -- operator is not considered |
| * valid. |
| */ |
| set_eval_error(E_BAD_OPERATOR); |
| error_token = tok_last->ptr; |
| free_tokens(tok_head); |
| free_tokens(tok); |
| return ((token_t*)NULL); |
| } else if (*((char*)cp + 1) == '>') { |
| tok->operator = RIGHT_ARROW; |
| cp++; |
| } else if (!tok_last || (tok_last->operator && |
| (tok_last->operator != CLOSE_PAREN))) { |
| tok->operator = UNARY_MINUS; |
| } else { |
| tok->operator = SUBTRACT; |
| } |
| break; |
| |
| case '.' : |
| /* XXX - need to check to see if this is a |
| * decimal point in the middle fo a floating |
| * point value. |
| */ |
| tok->operator = DOT; |
| break; |
| |
| case '*' : |
| /* XXX - need a better way to tell if this is |
| * an INDIRECTION. perhaps check the next |
| * token? |
| */ |
| if (!tok_last || (tok_last->operator && |
| ((tok_last->operator != CLOSE_PAREN) && |
| (tok_last->operator != CAST)))) { |
| tok->operator = INDIRECTION; |
| } else { |
| tok->operator = MULTIPLY; |
| } |
| break; |
| |
| case '/' : |
| tok->operator = DIVIDE; |
| break; |
| |
| case '%' : |
| tok->operator = MODULUS; |
| break; |
| |
| case '(' : { |
| char *s, *s1, *s2; |
| int len; |
| |
| /* Make sure the previous token is an operator |
| */ |
| if (tok_last && !tok_last->operator) { |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = tok_last->ptr; |
| free_tokens(tok_head); |
| free_tokens(tok); |
| return ((token_t*)NULL); |
| } |
| |
| if (tok_last && |
| ((tok_last->operator == RIGHT_ARROW) || |
| (tok_last->operator == DOT))) { |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = tok_last->ptr; |
| free_tokens(tok_head); |
| free_tokens(tok); |
| return ((token_t*)NULL); |
| } |
| |
| /* Check here to see if following tokens |
| * constitute a cast. |
| */ |
| |
| /* Skip past any "white space" (spaces |
| * and tabs) |
| */ |
| while ((*(cp+1) == ' ') || (*(cp+1) == '\t')) { |
| cp++; |
| } |
| if ((*(cp+1) == '(') || isdigit(*(cp+1)) || |
| (*(cp+1) == '+') || (*(cp+1) == '-') || |
| (*(cp+1) == '*') || (*(cp+1) == '&') || |
| (*(cp+1) == ')')){ |
| tok->operator = OPEN_PAREN; |
| paren_count++; |
| break; |
| } |
| |
| /* Make sure we have a CLOSE_PAREN. |
| */ |
| if (!(s1 = strchr(cp+1, ')'))) { |
| set_eval_error(E_OPEN_PAREN); |
| error_token = tok->ptr; |
| free_tokens(tok_head); |
| free_tokens(tok); |
| return ((token_t*)NULL); |
| } |
| /* Check to see if this is NOT a simple |
| * typecast. |
| */ |
| if (!(s2 = strchr(cp+1, '.'))) { |
| s2 = strstr(cp+1, "->"); |
| } |
| if (s2 && (s2 < s1)) { |
| tok->operator = OPEN_PAREN; |
| paren_count++; |
| break; |
| } |
| |
| if ((s = strpbrk(cp+1, "*)"))) { |
| char str[128]; |
| |
| len = (uaddr_t)s - (uaddr_t)(cp+1); |
| strncpy(str, cp+1, len); |
| str[len] = 0; |
| if (!is_typestr(str)) { |
| set_eval_error(E_BAD_TYPE); |
| error_token = tok->ptr; |
| free_tokens(tok_head); |
| free_tokens(tok); |
| return ((token_t*)NULL); |
| } |
| if (!(s = strpbrk((cp+1), ")"))) { |
| set_eval_error(E_OPEN_PAREN); |
| error_token = tok->ptr; |
| free_tokens(tok_head); |
| free_tokens(tok); |
| return ((token_t*)NULL); |
| } |
| len = (uaddr_t)s - (uaddr_t)(cp+1); |
| tok->string = (char *) |
| kl_alloc_block(len + 1); |
| memcpy(tok->string, (cp+1), len); |
| tok->string[len] = 0; |
| tok->operator = CAST; |
| cp = (char *)((uaddr_t)(cp+1) + len); |
| break; |
| } |
| tok->operator = OPEN_PAREN; |
| paren_count++; |
| break; |
| } |
| |
| case ')' : |
| if (tok_last && ((tok_last->operator == |
| RIGHT_ARROW) || |
| (tok_last->operator == DOT))) { |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = tok_last->ptr; |
| free_tokens(tok_head); |
| free_tokens(tok); |
| return ((token_t*)NULL); |
| } |
| tok->operator = CLOSE_PAREN; |
| paren_count--; |
| break; |
| |
| case '&' : |
| if (*((char*)cp + 1) == '&') { |
| tok->operator = LOGICAL_AND; |
| cp++; |
| } else if (!tok_last || (tok_last && |
| (tok_last->operator && |
| tok_last->operator != |
| CLOSE_PAREN))) { |
| tok->operator = ADDRESS; |
| } else { |
| tok->operator = BITWISE_AND; |
| } |
| break; |
| |
| case '|' : |
| if (*((char*)cp + 1) == '|') { |
| tok->operator = LOGICAL_OR; |
| cp++; |
| } else { |
| tok->operator = BITWISE_OR; |
| } |
| break; |
| |
| case '=' : |
| if (*((char*)cp + 1) == '=') { |
| tok->operator = EQUAL; |
| cp++; |
| } else { |
| /* ASIGNMENT -- NOT IMPLEMENTED |
| */ |
| tok->operator = NOT_YET; |
| } |
| break; |
| |
| case '<' : |
| if (*((char*)cp + 1) == '<') { |
| tok->operator = LEFT_SHIFT; |
| cp++; |
| } else if (*((char*)cp + 1) == '=') { |
| tok->operator = LESS_THAN_OR_EQUAL; |
| cp++; |
| } else { |
| tok->operator = LESS_THAN; |
| } |
| break; |
| |
| case '>' : |
| if (*((char*)(cp + 1)) == '>') { |
| tok->operator = RIGHT_SHIFT; |
| cp++; |
| } else if (*((char*)cp + 1) == '=') { |
| tok->operator = GREATER_THAN_OR_EQUAL; |
| cp++; |
| } else { |
| tok->operator = GREATER_THAN; |
| } |
| break; |
| |
| case '!' : |
| if (*((char*)cp + 1) == '=') { |
| tok->operator = NOT_EQUAL; |
| cp++; |
| } else { |
| tok->operator = LOGICAL_NEGATION; |
| } |
| break; |
| |
| case '$' : |
| set_eval_error(E_NOT_IMPLEMENTED); |
| error_token = tok->ptr; |
| free_tokens(tok_head); |
| free_tokens(tok); |
| return((token_t*)NULL); |
| case '~' : |
| tok->operator = ONES_COMPLEMENT; |
| break; |
| |
| case '^' : |
| tok->operator = BITWISE_EXCLUSIVE_OR; |
| break; |
| |
| case '?' : |
| set_eval_error(E_NOT_IMPLEMENTED); |
| error_token = tok->ptr; |
| free_tokens(tok_head); |
| free_tokens(tok); |
| return((token_t*)NULL); |
| case ':' : |
| set_eval_error(E_NOT_IMPLEMENTED); |
| error_token = tok->ptr; |
| free_tokens(tok_head); |
| free_tokens(tok); |
| return((token_t*)NULL); |
| case '[' : |
| tok->operator = OPEN_SQUARE_BRACKET;; |
| break; |
| |
| case ']' : |
| tok->operator = CLOSE_SQUARE_BRACKET;; |
| break; |
| |
| default: { |
| |
| char *s; |
| int len; |
| |
| /* See if the last token is a RIGHT_ARROW |
| * or a DOT. If it is, then this token must |
| * be the name of a struct/union member. |
| */ |
| if (tok_last && |
| ((tok_last->operator == RIGHT_ARROW) || |
| (tok_last->operator == DOT))) { |
| tok->type = MEMBER; |
| } else if (process_text(&cp, tok)) { |
| free_tokens(tok_head); |
| free_tokens(tok); |
| return((token_t*)NULL); |
| } |
| if (tok->type == TEXT) { |
| return(tok); |
| } else if (tok->type == STRING) { |
| if (is_typestr(tok->string)) { |
| tok->type = TYPE_DEF; |
| } else { |
| tok->operator = TEXT; |
| return(tok); |
| } |
| break; |
| } else if (tok->type == CHARACTER) { |
| break; |
| } |
| |
| /* Check and See if the entire string is |
| * a typename (valid only for whatis case). |
| */ |
| s = strpbrk(cp, |
| ".\t+-*/()[]|~!$&%^<>?:&=^\"\'"); |
| if (!s && !tok->type && is_typestr(cp)) { |
| tok->type = TYPE_DEF; |
| len = strlen(cp) + 1; |
| tok->string = (char *) |
| kl_alloc_block(len); |
| memcpy(tok->string, cp, len - 1); |
| tok->string[len - 1] = 0; |
| cp = (char *)((uaddr_t)cp + len - 2); |
| break; |
| } |
| |
| /* Now check for everything else |
| */ |
| if ((s = strpbrk(cp, |
| " .\t+-*/()[]|~!$&%^<>?:&=^\"\'"))) { |
| len = (uaddr_t)s - (uaddr_t)cp + 1; |
| } else { |
| len = strlen(cp) + 1; |
| } |
| |
| tok->string = |
| (char *)kl_alloc_block(len); |
| memcpy(tok->string, cp, len - 1); |
| tok->string[len - 1] = 0; |
| |
| cp = (char *)((uaddr_t)cp + len - 2); |
| |
| /* Check to see if this is the keyword |
| * "sizeof". If not, then check to see if |
| * the string is a member name. |
| */ |
| if (!strcmp(tok->string, "sizeof")) { |
| tok->operator = SIZEOF; |
| kl_free_block((void *)tok->string); |
| tok->string = 0; |
| } else if (tok_last && |
| ((tok_last->operator == RIGHT_ARROW) || |
| (tok_last->operator == DOT))) { |
| tok->type = MEMBER; |
| } else { |
| tok->type = STRING; |
| } |
| break; |
| } |
| } |
| if (!(tok->type)) { |
| tok->type = OPERATOR; |
| } |
| if (!tok_head) { |
| tok_head = tok_last = tok; |
| } else { |
| tok_last->next = tok; |
| tok_last = tok; |
| } |
| cp++; |
| } |
| if (paren_count < 0) { |
| set_eval_error(E_CLOSE_PAREN); |
| error_token = tok->ptr; |
| free_tokens(tok_head); |
| return((token_t*)NULL); |
| } else if (paren_count > 0) { |
| set_eval_error(E_OPEN_PAREN); |
| error_token = tok->ptr; |
| free_tokens(tok_head); |
| return((token_t*)NULL); |
| } |
| return(tok_head); |
| } |
| |
| /* |
| * valid_binary_args() |
| */ |
| int |
| valid_binary_args(node_t *np, node_t *left, node_t *right) |
| { |
| int op = np->operator; |
| |
| if ((op == RIGHT_ARROW) || (op == DOT)) { |
| if (!left) { |
| set_eval_error(E_MISSING_STRUCTURE); |
| error_token = np->tok_ptr; |
| return(0); |
| } else if (!(left->node_type == TYPE_DEF) && |
| !(left->node_type == MEMBER) && |
| !(left->operator == CLOSE_PAREN) && |
| !(left->operator == CLOSE_SQUARE_BRACKET)) { |
| set_eval_error(E_BAD_STRUCTURE); |
| error_token = left->tok_ptr; |
| return(0); |
| } |
| if (!right || (!(right->node_type == MEMBER))) { |
| set_eval_error(E_BAD_MEMBER); |
| error_token = np->tok_ptr; |
| return(0); |
| } |
| return(1); |
| } |
| if (!left || !right) { |
| set_eval_error(E_MISSING_OPERAND); |
| error_token = np->tok_ptr; |
| return(0); |
| } |
| switch (left->operator) { |
| case CLOSE_PAREN: |
| case CLOSE_SQUARE_BRACKET: |
| break; |
| default: |
| switch(left->node_type) { |
| case NUMBER: |
| case STRING: |
| case TEXT: |
| case CHARACTER: |
| case EVAL_VAR: |
| case MEMBER: |
| break; |
| default: |
| set_eval_error(E_BAD_OPERAND); |
| error_token = np->tok_ptr; |
| return(0); |
| } |
| } |
| switch (right->operator) { |
| case OPEN_PAREN: |
| break; |
| default: |
| switch(right->node_type) { |
| case NUMBER: |
| case STRING: |
| case TEXT: |
| case CHARACTER: |
| case EVAL_VAR: |
| case MEMBER: |
| break; |
| default: |
| set_eval_error(E_BAD_OPERAND); |
| error_token = np->tok_ptr; |
| return(0); |
| } |
| } |
| return(1); |
| } |
| |
| /* |
| * get_node_list() |
| */ |
| static node_t * |
| get_node_list(token_t *tp, int flags) |
| { |
| node_t *root = (node_t *)NULL; |
| node_t *np = (node_t *)NULL; |
| node_t *last = (node_t *)NULL; |
| |
| /* Loop through the tokens and convert them to nodes. |
| */ |
| while (tp) { |
| np = make_node(tp, flags); |
| if (eval_error) { |
| return((node_t *)NULL); |
| } |
| if (root) { |
| last->next = np; |
| last = np; |
| } else { |
| root = last = np; |
| } |
| tp = tp->next; |
| } |
| last->next = (node_t *)NULL; |
| last = (node_t *)NULL; |
| for (np = root; np; np = np->next) { |
| if (is_binary(np->operator)) { |
| if (!valid_binary_args(np, last, np->next)) { |
| free_nodelist(root); |
| return((node_t *)NULL); |
| } |
| } |
| last = np; |
| } |
| return(root); |
| } |
| |
| /* |
| * next_node() |
| */ |
| static node_t * |
| next_node(void) |
| { |
| node_t *np; |
| if ((np = node_list)) { |
| node_list = node_list->next; |
| np->next = (node_t*)NULL; |
| } |
| return(np); |
| } |
| |
| /* |
| * eval_unary() |
| */ |
| static node_t * |
| eval_unary(node_t *curnp, int flags) |
| { |
| node_t *n0, *n1; |
| |
| n0 = curnp; |
| |
| /* Peek ahead and make sure there is a next node. |
| * Also check to see if the next node requires |
| * a recursive call to do_eval(). If it does, we'll |
| * let the do_eval() call take care of pulling it |
| * off the list. |
| */ |
| if (!node_list) { |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = n0->tok_ptr; |
| free_nodes(n0); |
| return((node_t*)NULL); |
| } |
| if (n0->operator == CAST) { |
| if (node_list->operator == CLOSE_PAREN) { |
| |
| /* Free the CLOSE_PAREN and return |
| */ |
| free_node(next_node()); |
| return(n0); |
| } |
| if (!(node_list->node_type == NUMBER) && |
| !(node_list->node_type == VADDR) && |
| !((node_list->operator == ADDRESS) || |
| (node_list->operator == CAST) || |
| (node_list->operator == UNARY_MINUS) || |
| (node_list->operator == UNARY_PLUS) || |
| (node_list->operator == INDIRECTION) || |
| (node_list->operator == OPEN_PAREN))) { |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = node_list->tok_ptr; |
| free_nodes(n0); |
| return((node_t*)NULL); |
| } |
| } |
| if ((n0->operator == INDIRECTION) || |
| (n0->operator == ADDRESS) || |
| (n0->operator == OPEN_PAREN) || |
| is_unary(node_list->operator)) { |
| n1 = do_eval(flags); |
| if (eval_error) { |
| free_nodes(n0); |
| free_nodes(n1); |
| return((node_t*)NULL); |
| } |
| } else { |
| n1 = next_node(); |
| } |
| |
| if (n1->operator == OPEN_PAREN) { |
| /* Get the value contained within the parenthesis. |
| * If there was an error, just return. |
| */ |
| free_node(n1); |
| n1 = do_eval(flags); |
| if (eval_error) { |
| free_nodes(n1); |
| free_nodes(n0); |
| return((node_t*)NULL); |
| } |
| } |
| |
| n0->right = n1; |
| if (replace_unary(n0, flags) == -1) { |
| if (!eval_error) { |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = n0->tok_ptr; |
| } |
| free_nodes(n0); |
| return((node_t*)NULL); |
| } |
| return(n0); |
| } |
| |
| /* |
| * do_eval() -- Reduces an equation to a single value. |
| * |
| * Any parenthesis (and nested parenthesis) within the equation will |
| * be solved first via recursive calls to do_eval(). |
| */ |
| static node_t * |
| do_eval(int flags) |
| { |
| node_t *root = (node_t*)NULL, *curnp, *n0, *n1; |
| |
| /* Loop through the list of nodes until we run out of nodes |
| * or we hit a CLOSE_PAREN. If we hit an OPEN_PAREN, make a |
| * recursive call to do_eval(). |
| */ |
| curnp = next_node(); |
| while (curnp) { |
| n0 = n1 = (node_t *)NULL; |
| |
| if (curnp->operator == OPEN_PAREN) { |
| /* Get the value contained within the parenthesis. |
| * If there was an error, just return. |
| */ |
| free_node(curnp); |
| n0 = do_eval(flags); |
| if (eval_error) { |
| free_nodes(n0); |
| free_nodes(root); |
| return((node_t *)NULL); |
| } |
| |
| } else if (curnp->operator == SIZEOF) { |
| /* Free the SIZEOF node and then make a call |
| * to the get_sizeof() function (which will |
| * get the next node off the list). |
| */ |
| n0 = get_sizeof(); |
| if (eval_error) { |
| if (!error_token) { |
| error_token = curnp->tok_ptr; |
| } |
| free_node(curnp); |
| free_nodes(root); |
| return((node_t *)NULL); |
| } |
| free_node(curnp); |
| curnp = (node_t *)NULL; |
| } else if (is_unary(curnp->operator)) { |
| n0 = eval_unary(curnp, flags); |
| } else { |
| n0 = curnp; |
| curnp = (node_t *)NULL; |
| } |
| if (eval_error) { |
| free_nodes(n0); |
| free_nodes(root); |
| return((node_t *)NULL); |
| } |
| |
| /* n0 should now contain a non-operator node. Check to see if |
| * there is a next token. If there isn't, just add the last |
| * rchild and return. |
| */ |
| if (!node_list) { |
| if (root) { |
| add_rchild(root, n0); |
| } else { |
| root = n0; |
| } |
| replace(root, flags); |
| if (eval_error) { |
| free_nodes(root); |
| return((node_t *)NULL); |
| } |
| return(root); |
| } |
| |
| /* Make sure the next token is an operator. |
| */ |
| if (!node_list->operator) { |
| free_nodes(root); |
| free_node(n0); |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = node_list->tok_ptr; |
| return((node_t *)NULL); |
| } else if ((node_list->operator == CLOSE_PAREN) || |
| (node_list->operator == CLOSE_SQUARE_BRACKET)) { |
| |
| if (root) { |
| add_rchild(root, n0); |
| } else { |
| root = n0; |
| } |
| |
| /* Reduce the resulting tree to a single value |
| */ |
| replace(root, flags); |
| if (eval_error) { |
| free_nodes(root); |
| return((node_t *)NULL); |
| } |
| |
| /* Step over the CLOSE_PAREN or CLOSE_SQUARE_BRACKET |
| * and then return. |
| */ |
| free_node(next_node()); |
| return(root); |
| } else if (node_list->operator == OPEN_SQUARE_BRACKET) { |
| next_dimension1: |
| /* skip over the OPEN_SQUARE_BRACKET token |
| */ |
| free_node(next_node()); |
| |
| /* Get the value contained within the brackets. This |
| * value must represent an array index (value or |
| * equation). |
| */ |
| n1 = do_eval(0); |
| if (eval_error) { |
| free_nodes(root); |
| free_node(n0); |
| free_node(n1); |
| return((node_t *)NULL); |
| } |
| |
| /* Convert the array (or pointer type) to an |
| * element type using the index value obtained |
| * above. Make sure that n0 contains some sort |
| * of type definition first, however. |
| */ |
| if (n0->node_type != TYPE_DEF) { |
| set_eval_error(E_BAD_TYPE); |
| error_token = n0->tok_ptr; |
| free_nodes(n0); |
| free_nodes(n1); |
| free_nodes(root); |
| return((node_t *)NULL); |
| } |
| array_to_element(n0, n1); |
| free_node(n1); |
| if (eval_error) { |
| free_nodes(root); |
| free_nodes(n0); |
| return((node_t *)NULL); |
| } |
| |
| /* If there aren't any more nodes, just |
| * return. |
| */ |
| if (!node_list) { |
| return(n0); |
| } |
| if (node_list->operator == OPEN_SQUARE_BRACKET) { |
| goto next_dimension1; |
| } |
| } else if (!is_binary(node_list->operator)) { |
| set_eval_error(E_BAD_OPERATOR); |
| error_token = node_list->tok_ptr; |
| free_nodes(root); |
| free_nodes(n0); |
| return((node_t *)NULL); |
| } |
| |
| /* Now get the operator node |
| */ |
| if (!(n1 = next_node())) { |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = n0->tok_ptr; |
| free_nodes(n0); |
| free_nodes(root); |
| return((node_t *)NULL); |
| } |
| |
| /* Check to see if this binary operator is RIGHT_ARROW or DOT. |
| * If it is, we need to reduce it to a single value node now. |
| */ |
| while ((n1->operator == RIGHT_ARROW) || (n1->operator == DOT)) { |
| |
| /* The next node must contain the name of the |
| * struct|union member. |
| */ |
| if (!node_list || (node_list->node_type != MEMBER)) { |
| set_eval_error(E_BAD_MEMBER); |
| error_token = n1->tok_ptr; |
| free_nodes(n0); |
| free_nodes(n1); |
| free_nodes(root); |
| return((node_t *)NULL); |
| } |
| n1->left = n0; |
| |
| /* Now get the next node and link it as the |
| * right child. |
| */ |
| if (!(n0 = next_node())) { |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = n1->tok_ptr; |
| free_nodes(n1); |
| free_nodes(root); |
| return((node_t *)NULL); |
| } |
| n1->right = n0; |
| if (!(n0 = replace(n1, flags))) { |
| if (!(eval_error)) { |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = n1->tok_ptr; |
| } |
| free_nodes(n1); |
| free_nodes(root); |
| return((node_t *)NULL); |
| } |
| n1 = (node_t *)NULL; |
| |
| /* Check to see if there is a next node. If there |
| * is, check to see if it is the operator CLOSE_PAREN. |
| * If it is, then return (skipping over the |
| * CLOSE_PAREN first). |
| */ |
| if (node_list && ((node_list->operator == CLOSE_PAREN) |
| || (node_list->operator == |
| CLOSE_SQUARE_BRACKET))) { |
| if (root) { |
| add_rchild(root, n0); |
| } else { |
| root = n0; |
| } |
| |
| /* Reduce the resulting tree to a single |
| * value |
| */ |
| replace(root, flags); |
| if (eval_error) { |
| free_nodes(root); |
| return((node_t *)NULL); |
| } |
| |
| /* Advance the token pointer past the |
| * CLOSE_PAREN and then return. |
| */ |
| free_node(next_node()); |
| return(root); |
| } |
| |
| /* Check to see if the next node is an |
| * OPEN_SQUARE_BRACKET. If it is, then we have to |
| * reduce the contents of the square brackets to |
| * an index array. |
| */ |
| if (node_list && (node_list->operator |
| == OPEN_SQUARE_BRACKET)) { |
| |
| /* Advance the token pointer and call |
| * do_eval() again. |
| */ |
| free_node(next_node()); |
| next_dimension2: |
| n1 = do_eval(0); |
| if (eval_error) { |
| free_node(n0); |
| free_node(n1); |
| free_nodes(root); |
| return((node_t *)NULL); |
| } |
| |
| /* Convert the array (or pointer type) to |
| * an element type using the index value |
| * obtained above. Make sure that n0 |
| * contains some sort of type definition |
| * first, however. |
| */ |
| if (n0->node_type != TYPE_DEF) { |
| set_eval_error(E_BAD_TYPE); |
| error_token = n0->tok_ptr; |
| free_node(n0); |
| free_node(n1); |
| free_node(root); |
| return((node_t *)NULL); |
| } |
| array_to_element(n0, n1); |
| free_node(n1); |
| if (eval_error) { |
| free_node(n0); |
| free_node(root); |
| return((node_t *)NULL); |
| } |
| } |
| |
| /* Now get the next operator node (if there is one). |
| */ |
| if (!node_list) { |
| if (root) { |
| add_rchild(root, n0); |
| } else { |
| root = n0; |
| } |
| return(root); |
| } |
| n1 = next_node(); |
| if (n1->operator == OPEN_SQUARE_BRACKET) { |
| goto next_dimension2; |
| } |
| } |
| |
| if (n1 && ((n1->operator == CLOSE_PAREN) || |
| (n1->operator == CLOSE_SQUARE_BRACKET))) { |
| free_node(n1); |
| if (root) { |
| add_rchild(root, n0); |
| } else { |
| root = n0; |
| } |
| replace(root, flags); |
| if (eval_error) { |
| free_nodes(root); |
| return((node_t *)NULL); |
| } |
| return(root); |
| } |
| |
| if (!root) { |
| root = n1; |
| n1->left = n0; |
| } else if (precedence(root->operator) |
| >= precedence(n1->operator)) { |
| add_rchild(root, n0); |
| n1->left = root; |
| root = n1; |
| } else { |
| if (!root->right) { |
| n1->left = n0; |
| root->right = n1; |
| } else { |
| add_rchild(root, n0); |
| n1->left = root->right; |
| root->right = n1; |
| } |
| } |
| curnp = next_node(); |
| } /* while(curnp) */ |
| return(root); |
| } |
| |
| /* |
| * is_unary() |
| */ |
| static int |
| is_unary(int op) |
| { |
| switch (op) { |
| case LOGICAL_NEGATION : |
| case ADDRESS : |
| case INDIRECTION : |
| case UNARY_MINUS : |
| case UNARY_PLUS : |
| case ONES_COMPLEMENT : |
| case CAST : |
| return(1); |
| |
| default : |
| return(0); |
| } |
| } |
| |
| |
| /* |
| * is_binary() |
| */ |
| static int |
| is_binary(int op) |
| { |
| switch (op) { |
| |
| case BITWISE_OR : |
| case BITWISE_EXCLUSIVE_OR : |
| case BITWISE_AND : |
| case RIGHT_SHIFT : |
| case LEFT_SHIFT : |
| case ADD : |
| case SUBTRACT : |
| case MULTIPLY : |
| case DIVIDE : |
| case MODULUS : |
| case LOGICAL_OR : |
| case LOGICAL_AND : |
| case EQUAL : |
| case NOT_EQUAL : |
| case LESS_THAN : |
| case GREATER_THAN : |
| case LESS_THAN_OR_EQUAL : |
| case GREATER_THAN_OR_EQUAL : |
| case RIGHT_ARROW : |
| case DOT : |
| return(1); |
| |
| default : |
| return(0); |
| } |
| } |
| |
| /* |
| * precedence() |
| */ |
| static int |
| precedence(int a) |
| { |
| if ((a >= CONDITIONAL) && (a <= CONDITIONAL_ELSE)) { |
| return(1); |
| } else if (a == LOGICAL_OR) { |
| return(2); |
| } else if (a == LOGICAL_AND) { |
| return(3); |
| } else if (a == BITWISE_OR) { |
| return(4); |
| } else if (a == BITWISE_EXCLUSIVE_OR) { |
| return(5); |
| } else if (a == BITWISE_AND) { |
| return(6); |
| } else if ((a >= EQUAL) && (a <= NOT_EQUAL)) { |
| return(7); |
| } else if ((a >= LESS_THAN) && (a <= GREATER_THAN_OR_EQUAL)) { |
| return(8); |
| } else if ((a >= RIGHT_SHIFT) && (a <= LEFT_SHIFT)) { |
| return(9); |
| } else if ((a >= ADD) && (a <= SUBTRACT)) { |
| return(10); |
| } else if ((a >= MULTIPLY) && (a <= MODULUS)) { |
| return(11); |
| } else if ((a >= LOGICAL_NEGATION) && (a <= SIZEOF)) { |
| return(12); |
| } else if ((a >= RIGHT_ARROW) && (a <= DOT)) { |
| return(13); |
| } else { |
| return(0); |
| } |
| } |
| |
| /* |
| * esc_char() |
| */ |
| char |
| esc_char(char *str) |
| { |
| long int val; |
| unsigned long uval; |
| char ch; |
| |
| if (strlen(str) > 1) { |
| uval = kl_strtoull(str, (char **)NULL, 8); |
| val = uval; |
| ch = (char)val; |
| } else { |
| ch = str[0]; |
| } |
| switch (ch) { |
| case 'a' : |
| return((char)7); |
| case 'b' : |
| return((char)8); |
| case 't' : |
| return((char)9); |
| case 'n' : |
| return((char)10); |
| case 'f' : |
| return((char)12); |
| case 'r' : |
| return((char)13); |
| case 'e' : |
| return((char)27); |
| default: |
| return(ch); |
| } |
| } |
| |
| /* |
| * make_node() |
| */ |
| static node_t * |
| make_node(token_t *t, int flags) |
| { |
| node_t *np; |
| |
| set_eval_error(0); |
| np = (node_t*)kl_alloc_block(sizeof(*np)); |
| |
| if (t->type == OPERATOR) { |
| |
| /* Check to see if this token represents a typecast |
| */ |
| if (t->operator == CAST) { |
| type_t *tp; |
| |
| if (!(np->type = get_type(t->string, flags))) { |
| set_eval_error(E_BAD_CAST); |
| error_token = t->ptr; |
| free_nodes(np); |
| return((node_t*)NULL); |
| } |
| |
| /* Determin if this is a pointer to a type |
| */ |
| tp = np->type; |
| if (tp->flag == POINTER_FLAG) { |
| np->flags = POINTER_FLAG; |
| tp = tp->t_next; |
| while (tp->flag == POINTER_FLAG) { |
| tp = tp->t_next; |
| } |
| } |
| switch(tp->flag) { |
| case KLTYPE_FLAG: |
| np->flags |= KLTYPE_FLAG; |
| break; |
| |
| default: |
| free_nodes(np); |
| set_eval_error(E_BAD_CAST); |
| error_token = t->ptr; |
| return((node_t*)NULL); |
| } |
| if (!t->next) { |
| if (flags & C_WHATIS) { |
| np->node_type = TYPE_DEF; |
| } else { |
| set_eval_error(E_BAD_CAST); |
| error_token = t->ptr; |
| return((node_t*)NULL); |
| } |
| } else { |
| np->node_type = OPERATOR; |
| np->operator = CAST; |
| } |
| } else { |
| np->node_type = OPERATOR; |
| np->operator = t->operator; |
| } |
| } else if (t->type == MEMBER) { |
| np->name = (char *)dup_block((void *)t->string, strlen(t->string)+1); |
| np->node_type = MEMBER; |
| } else if ((t->type == STRING) || (t->type == TYPE_DEF)) { |
| syment_t *sp; |
| dbg_sym_t *stp; |
| dbg_type_t *sttp; |
| |
| if ((sp = kl_lkup_symname(t->string))) { |
| if (!(flags & C_NOVARS)) { |
| int has_type = 0; |
| |
| /* The string is a symbol name. We'll treat it as |
| * a global kernel variable and, at least, gather in |
| * the address of the symbol and the value it points |
| * to. |
| */ |
| np->address = sp->s_addr; |
| np->flags |= ADDRESS_FLAG; |
| np->name = t->string; |
| t->string = (char*)NULL; |
| |
| /* Need to see if there is type information available |
| * for this variable. Since this mapping is not |
| * available yet, we will just attach a type struct |
| * for either uint32_t or uint64_t (depending on the |
| * size of a kernel pointer). That will at least let |
| * us do something and will prevent the scenario where |
| * we have a type node with out a pointer to a type |
| * struct! |
| */ |
| np->node_type = TYPE_DEF; |
| np->flags |= KLTYPE_FLAG; |
| np->value = *((kaddr_t *)np->address); |
| /* try to get the actual type info for the variable */ |
| if(((stp = dbg_find_sym(sp->s_name, DBG_VAR, |
| (uint64_t)0)) != NULL)){ |
| if((sttp = (dbg_type_t *) |
| kl_find_typenum(stp->sym_typenum)) |
| != NULL){ |
| /* kl_get_typestring(sttp); */ |
| has_type = 1; |
| if(sttp->st_klt.kl_type == KLT_POINTER){ |
| np->flags ^= KLTYPE_FLAG; |
| np->flags |= POINTER_FLAG; |
| np->type = |
| get_type(sttp->st_typestr, |
| flags); |
| } else { |
| np->type = |
| kl_alloc_block(sizeof(type_t)); |
| np->type->un.kltp = |
| &sttp->st_klt; |
| } |
| } |
| } |
| /* no type info for the variable found */ |
| if(!has_type){ |
| if (ptrsz64) { |
| np->type = get_type("uint64_t", flags); |
| } else { |
| np->type = get_type("uint32_t", flags); |
| } |
| } |
| } |
| kl_free_block((void *)sp); |
| } else if (flags & (C_WHATIS|C_SIZEOF)) { |
| |
| kltype_t *kltp; |
| |
| if ((kltp = kl_find_type(t->string, KLT_TYPES))) { |
| |
| np->node_type = TYPE_DEF; |
| np->flags = KLTYPE_FLAG; |
| np->type = (type_t*) |
| kl_alloc_block(sizeof(type_t)); |
| np->type->flag = KLTYPE_FLAG; |
| np->type->t_kltp = kltp; |
| } else { |
| if (get_value(t->string, |
| (uint64_t *)&np->value)) { |
| set_eval_error(E_BAD_VALUE); |
| error_token = t->ptr; |
| free_nodes(np); |
| return((node_t*)NULL); |
| } |
| if (!strncmp(t->string, "0x", 2) || |
| !strncmp(t->string, "0X", 2)) { |
| np->flags |= UNSIGNED_FLAG; |
| } |
| np->node_type = NUMBER; |
| } |
| np->tok_ptr = t->ptr; |
| return(np); |
| } else { |
| if (get_value(t->string, (uint64_t *)&np->value)) { |
| set_eval_error(E_BAD_VALUE); |
| error_token = t->ptr; |
| free_nodes(np); |
| return((node_t*)NULL); |
| } |
| if (np->value > 0xffffffff) { |
| np->byte_size = 8; |
| } else { |
| np->byte_size = 4; |
| } |
| if (!strncmp(t->string, "0x", 2) || |
| !strncmp(t->string, "0X", 2)) { |
| np->flags |= UNSIGNED_FLAG; |
| } |
| np->node_type = NUMBER; |
| } |
| } else if (t->type == CHARACTER) { |
| char *cp; |
| |
| /* Step over the single quote |
| */ |
| cp = (t->ptr + 1); |
| if (*cp == '\\') { |
| int i = 0; |
| char str[16]; |
| |
| /* Step over the back slash |
| */ |
| cp++; |
| while (*cp != '\'') { |
| str[i++] = *cp++; |
| } |
| str[i] = 0; |
| np->value = esc_char(str); |
| } else { |
| np->value = *cp; |
| } |
| np->type = get_type("char", flags); |
| np->node_type = TYPE_DEF; |
| np->flags |= KLTYPE_FLAG; |
| } else if (t->type == TEXT) { |
| np->node_type = TEXT; |
| np->name = t->string; |
| /* So the block doesn't get freed twice */ |
| t->string = (char*)NULL; |
| } else { |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = t->ptr; |
| return((node_t*)NULL); |
| } |
| np->tok_ptr = t->ptr; |
| return(np); |
| } |
| |
| /* |
| * add_node() |
| */ |
| static int |
| add_node(node_t *root, node_t *new_node) |
| { |
| node_t *n = root; |
| |
| /* Find the most lower-right node |
| */ |
| while (n->right) { |
| n = n->right; |
| } |
| |
| /* If the node we found is a leaf node, return an error (we will |
| * have to insert the node instead). |
| */ |
| if (n->node_type == NUMBER) { |
| return(-1); |
| } else { |
| n->right = new_node; |
| } |
| return(0); |
| } |
| |
| /* |
| * add_rchild() |
| */ |
| static int |
| add_rchild(node_t *root, node_t *new_node) |
| { |
| if (add_node(root, new_node) == -1) { |
| return(-1); |
| } |
| return(0); |
| } |
| |
| /* |
| * free_type() |
| */ |
| static void |
| free_type(type_t *head) |
| { |
| type_t *t0, *t1; |
| |
| t0 = head; |
| while(t0) { |
| if (t0->flag == POINTER_FLAG) { |
| t1 = t0->t_next; |
| kl_free_block((void *)t0); |
| t0 = t1; |
| } else { |
| if (t0->flag != KLTYPE_FLAG) { |
| kl_free_block((void *)t0->t_kltp); |
| } |
| kl_free_block((void *)t0); |
| t0 = (type_t *)NULL; |
| } |
| } |
| return; |
| } |
| |
| /* |
| * get_type() -- Convert a typecast string into a type. |
| * |
| * Returns a pointer to a struct containing type information. |
| * The type of struct returned is indicated by the contents |
| * of type. If the typecast contains an asterisk, set ptr_type |
| * equal to one, otherwise set it equal to zero. |
| */ |
| static type_t * |
| get_type(char *s, int flags) |
| { |
| int len, type = 0; |
| char *cp, typename[128]; |
| type_t *t, *head, *last; |
| kltype_t *kltp; |
| |
| head = last = (type_t *)NULL; |
| |
| /* Get the type string |
| */ |
| if (!strncmp(s, "struct", 6)) { |
| if ((cp = strpbrk(s + 7, " \t*"))) { |
| len = cp - (s + 7); |
| } else { |
| len = strlen(s + 7); |
| } |
| memcpy(typename, s + 7, len); |
| } else if (!strncmp(s, "union", 5)) { |
| if ((cp = strpbrk(s + 6, " \t*"))) { |
| len = cp - (s + 6); |
| } else { |
| len = strlen(s + 6); |
| } |
| memcpy(typename, s + 6, len); |
| } else { |
| if ((cp = strpbrk(s, "*)"))) { |
| len = cp - s; |
| } else { |
| len = strlen(s); |
| } |
| memcpy(typename, s, len); |
| } |
| |
| /* Strip off any trailing spaces |
| */ |
| while (len && ((typename[len - 1] == ' ') || |
| (typename[len - 1] == '\t'))) { |
| len--; |
| } |
| typename[len] = 0; |
| |
| if (!(kltp = kl_find_type(typename, KLT_TYPES))) { |
| return ((type_t *)NULL); |
| } |
| type = KLTYPE_FLAG; |
| |
| /* check to see if this cast is a pointer to a type, a pointer |
| * to a pointer to a type, etc. |
| */ |
| cp = s; |
| while ((cp = strpbrk(cp, "*"))) { |
| t = (type_t *)kl_alloc_block(sizeof(type_t)); |
| t->flag = POINTER_FLAG; |
| if (last) { |
| last->t_next = t; |
| last = t; |
| } else { |
| head = last = t; |
| } |
| cp++; |
| } |
| |
| /* Allocate a type block that will point to the type specific |
| * record. |
| */ |
| t = (type_t *)kl_alloc_block(sizeof(type_t)); |
| t->flag = type; |
| |
| switch (t->flag) { |
| |
| case KLTYPE_FLAG: |
| t->t_kltp = kltp; |
| break; |
| |
| default: |
| free_type(head); |
| return((type_t*)NULL); |
| } |
| if (last) { |
| last->t_next = t; |
| } else { |
| head = t; |
| } |
| return(head); |
| } |
| |
| /* |
| * free_node() |
| */ |
| static void |
| free_node(node_t *np) |
| { |
| /* If there is nothing to free, just return. |
| */ |
| if (!np) { |
| return; |
| } |
| if (np->name) { |
| kl_free_block((void *)np->name); |
| } |
| free_type(np->type); |
| kl_free_block((void *)np); |
| } |
| |
| /* |
| * free_nodes() |
| */ |
| void |
| free_nodes(node_t *np) |
| { |
| node_t *q; |
| |
| /* If there is nothing to free, just return. |
| */ |
| if (!np) { |
| return; |
| } |
| if ((q = np->left)) { |
| free_nodes(q); |
| } |
| if ((q = np->right)) { |
| free_nodes(q); |
| } |
| if (np->name) { |
| kl_free_block((void *)np->name); |
| } |
| free_type(np->type); |
| kl_free_block((void *)np); |
| } |
| |
| /* |
| * free_nodelist() |
| */ |
| static void |
| free_nodelist(node_t *np) |
| { |
| node_t *nnp; |
| |
| while(np) { |
| nnp = np->next; |
| free_node(np); |
| np = nnp; |
| } |
| } |
| |
| extern int alloc_debug; |
| |
| /* |
| * free_eval_memory() |
| */ |
| void |
| free_eval_memory(void) |
| { |
| free_nodelist(node_list); |
| node_list = (node_t*)NULL; |
| } |
| |
| /* |
| * get_sizeof() |
| */ |
| static node_t * |
| get_sizeof() |
| { |
| node_t *curnp, *n0 = NULL; |
| |
| if (!(curnp = next_node())) { |
| set_eval_error(E_SYNTAX_ERROR); |
| return((node_t*)NULL); |
| } |
| |
| /* The next token should be a CAST or an open paren. |
| * If it's something else, then return an error. |
| */ |
| if (curnp->operator == OPEN_PAREN) { |
| free_nodes(curnp); |
| n0 = do_eval(C_SIZEOF); |
| if (eval_error) { |
| error_token = n0->tok_ptr; |
| free_nodes(n0); |
| return((node_t*)NULL); |
| } |
| } else if (curnp->operator == CAST) { |
| n0 = curnp; |
| } else { |
| set_eval_error(E_BAD_TYPE); |
| error_token = n0->tok_ptr; |
| free_nodes(n0); |
| return((node_t*)NULL); |
| } |
| |
| if (!n0->type) { |
| set_eval_error(E_NOTYPE); |
| error_token = n0->tok_ptr; |
| free_nodes(n0); |
| return((node_t*)NULL); |
| } |
| |
| if (n0->type->flag & POINTER_FLAG) { |
| n0->value = sizeof(void *); |
| } else if (n0->type->flag & KLTYPE_FLAG) { |
| kltype_t *kltp; |
| |
| kltp = kl_realtype(n0->type->t_kltp, 0); |
| |
| if (kltp->kl_bit_size) { |
| n0->value = kltp->kl_bit_size / 8; |
| if (kltp->kl_bit_size % 8) { |
| n0->value += 1; |
| } |
| } else { |
| n0->value = kltp->kl_size; |
| } |
| } else { |
| set_eval_error(E_BAD_TYPE); |
| error_token = n0->tok_ptr; |
| free_nodes(n0); |
| return((node_t*)NULL); |
| } |
| n0->node_type = NUMBER; |
| n0->flags = 0; |
| n0->operator = 0; |
| n0->byte_size = 0; |
| n0->address = 0; |
| if (n0->type) { |
| free_type(n0->type); |
| n0->type = 0; |
| } |
| return(n0); |
| } |
| |
| /* |
| * apply_unary() |
| */ |
| static int |
| apply_unary(node_t *n, uint64_t *value) |
| { |
| if (!n || !n->right) { |
| return(-1); |
| } |
| |
| switch (n->operator) { |
| |
| case UNARY_MINUS : |
| *value = (0 - n->right->value); |
| break; |
| |
| case UNARY_PLUS : |
| *value = (n->right->value); |
| break; |
| |
| case ONES_COMPLEMENT : |
| *value = ~(n->right->value); |
| break; |
| |
| case LOGICAL_NEGATION : |
| if (n->right->value) { |
| *value = 0; |
| } else { |
| *value = 1; |
| } |
| logical_flag++; |
| break; |
| |
| default : |
| break; |
| } |
| return(0); |
| } |
| |
| /* |
| * pointer_math() |
| */ |
| static int |
| pointer_math(node_t *np, uint64_t *value, int type, int flags) |
| { |
| int size; |
| uint64_t lvalue, rvalue; |
| type_t *tp = NULL, *tp1; |
| |
| if (type < 0) { |
| if (np->left->flags & POINTER_FLAG) { |
| |
| /* Since we only allow pointer math, |
| * anything other than a pointer causes |
| * failure. |
| */ |
| tp = (type_t*)np->left->type; |
| if (tp->flag != POINTER_FLAG) { |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = np->left->tok_ptr; |
| return(-1); |
| } |
| |
| tp = tp->t_next; |
| |
| switch (tp->flag) { |
| |
| case POINTER_FLAG : |
| size = sizeof(void *); |
| break; |
| |
| case KLTYPE_FLAG : { |
| /* Get the size of the real type, |
| * not just the size of a pointer |
| * If there isn't any type info, |
| * then just set size equal to the |
| * size of a pointer. |
| */ |
| kltype_t *kltp, *rkltp; |
| |
| kltp = tp->t_kltp; |
| rkltp = kl_realtype(kltp, 0); |
| if (!(size = rkltp->kl_size)) { |
| if (kltp != rkltp) { |
| size = kltp->kl_size; |
| } else { |
| size = sizeof(void *); |
| } |
| } |
| break; |
| } |
| |
| default : |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = np->left->tok_ptr; |
| return(-1); |
| } |
| lvalue = np->left->value; |
| } else { |
| size = sizeof(void *); |
| lvalue = np->left->address; |
| } |
| switch (np->operator) { |
| case ADD : |
| *value = lvalue + (np->right->value * size); |
| break; |
| |
| case SUBTRACT : |
| *value = lvalue - (np->right->value * size); |
| break; |
| |
| default : |
| set_eval_error(E_BAD_OPERATOR); |
| error_token = np->tok_ptr; |
| return(-1); |
| } |
| } else if (type > 0) { |
| if (np->right->flags & POINTER_FLAG) { |
| |
| /* Since we only allow pointer math, |
| * anything other than a pointer causes |
| * failure. |
| */ |
| tp = (type_t*)np->right->type; |
| if (tp->flag != POINTER_FLAG) { |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = np->right->tok_ptr; |
| return(-1); |
| } |
| |
| tp = tp->t_next; |
| |
| switch (tp->flag) { |
| |
| case POINTER_FLAG : |
| size = sizeof(void *); |
| break; |
| |
| case KLTYPE_FLAG : |
| size = tp->t_kltp->kl_size; |
| break; |
| |
| default : |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = np->right->tok_ptr; |
| return(-1); |
| } |
| rvalue = np->right->value; |
| } else { |
| size = sizeof(void *); |
| rvalue = np->right->address; |
| } |
| switch (np->operator) { |
| case ADD : |
| *value = rvalue + (np->left->value * size); |
| break; |
| |
| case SUBTRACT : |
| *value = rvalue - (np->left->value * size); |
| break; |
| |
| default : |
| set_eval_error(E_BAD_OPERATOR); |
| error_token = np->tok_ptr; |
| return(-1); |
| } |
| } else { |
| return(-1); |
| } |
| tp1 = (type_t *)kl_alloc_block(sizeof(type_t)); |
| tp1->flag = POINTER_FLAG; |
| np->type = tp1; |
| while (tp->flag == POINTER_FLAG) { |
| tp1->t_next = (type_t *)kl_alloc_block(sizeof(type_t)); |
| tp1->flag = POINTER_FLAG; |
| tp1 = tp1->t_next; |
| tp = tp->t_next; |
| } |
| if (tp) { |
| tp1->t_next = (type_t *)kl_alloc_block(sizeof(type_t)); |
| tp1 = tp1->t_next; |
| tp1->flag = KLTYPE_FLAG; |
| tp1->t_kltp = tp->t_kltp; |
| if (type < 0) { |
| if (np->left->flags & POINTER_FLAG) { |
| np->flags |= POINTER_FLAG; |
| } else { |
| np->flags |= VADDR; |
| } |
| } else { |
| if (np->right->flags & POINTER_FLAG) { |
| np->flags |= POINTER_FLAG; |
| } else { |
| np->flags |= VADDR; |
| } |
| } |
| } |
| return(0); |
| } |
| |
| /* |
| * check_unsigned() |
| */ |
| int |
| check_unsigned(node_t *np) |
| { |
| kltype_t *kltp, *rkltp; |
| |
| if (np->flags & UNSIGNED_FLAG) { |
| return(1); |
| } |
| if (!np->type) { |
| return(0); |
| } |
| if (np->type->flag == POINTER_FLAG) { |
| return(0); |
| } |
| kltp = np->type->t_kltp; |
| if ((rkltp = kl_realtype(kltp, 0))) { |
| if (rkltp->kl_encoding == ENC_UNSIGNED) { |
| np->flags |= UNSIGNED_FLAG; |
| return(1); |
| } |
| } |
| return(0); |
| } |
| |
| /* |
| * apply() |
| */ |
| static int |
| apply(node_t *np, uint64_t *value, int flags) |
| { |
| int ltype, rtype, do_signed = 0; |
| |
| /* There must be two operands |
| */ |
| if (!np->right || !np->left) { |
| set_eval_error(E_MISSING_OPERAND); |
| error_token = np->tok_ptr; |
| return(-1); |
| } |
| |
| if (np->right->node_type == OPERATOR) { |
| replace(np->right, flags); |
| if (eval_error) { |
| return(-1); |
| } |
| } |
| |
| ltype = np->left->node_type; |
| rtype = np->right->node_type; |
| if ((ltype == TYPE_DEF) || (ltype == VADDR)) { |
| if ((rtype == TYPE_DEF) || (rtype == VADDR)) { |
| set_eval_error(E_NO_VALUE); |
| error_token = np->tok_ptr; |
| return(-1); |
| } |
| if (check_unsigned(np->left)) { |
| np->flags |= UNSIGNED_FLAG; |
| } else { |
| do_signed++; |
| } |
| if (!type_to_number(np->left)) { |
| return(pointer_math(np, value, -1, flags)); |
| } |
| np->byte_size = np->left->byte_size; |
| } else if ((rtype == TYPE_DEF) || (rtype == VADDR)) { |
| if ((ltype == TYPE_DEF) || (ltype == VADDR)) { |
| error_token = np->tok_ptr; |
| set_eval_error(E_NO_VALUE); |
| return(-1); |
| } |
| if (check_unsigned(np->right)) { |
| np->flags |= UNSIGNED_FLAG; |
| } else { |
| do_signed++; |
| } |
| if (!type_to_number(np->right)) { |
| return(pointer_math(np, value, 1, flags)); |
| } |
| np->byte_size = np->right->byte_size; |
| } else if ((np->left->flags & UNSIGNED_FLAG) || |
| (np->right->flags & UNSIGNED_FLAG)) { |
| np->flags |= UNSIGNED_FLAG; |
| } else { |
| do_signed++; |
| } |
| |
| if (do_signed) { |
| switch (np->operator) { |
| case ADD : |
| *value = (int64_t)np->left->value + |
| (int64_t)np->right->value; |
| break; |
| |
| case SUBTRACT : |
| *value = (int64_t)np->left->value - |
| (int64_t)np->right->value; |
| break; |
| |
| case MULTIPLY : |
| *value = (int64_t)np->left->value * |
| (int64_t)np->right->value; |
| break; |
| |
| case DIVIDE : |
| if ((int64_t)np->right->value == 0) { |
| set_eval_error(E_DIVIDE_BY_ZERO); |
| error_token = np->right->tok_ptr; |
| return(-1); |
| } |
| *value = (int64_t)np->left->value / |
| (int64_t)np->right->value; |
| break; |
| |
| case BITWISE_OR : |
| *value = (int64_t)np->left->value | |
| (int64_t)np->right->value; |
| break; |
| |
| case BITWISE_AND : |
| *value = (int64_t)np->left->value & |
| (int64_t)np->right->value; |
| break; |
| |
| case MODULUS : |
| if ((int64_t)np->right->value == 0) { |
| set_eval_error(E_DIVIDE_BY_ZERO); |
| error_token = np->right->tok_ptr; |
| return(-1); |
| } |
| *value = (int64_t)np->left->value % |
| (int64_t)np->right->value; |
| break; |
| |
| case RIGHT_SHIFT : |
| *value = |
| (int64_t)np->left->value >> |
| (int64_t)np->right->value; |
| break; |
| |
| case LEFT_SHIFT : |
| *value = |
| (int64_t)np->left->value << |
| (int64_t)np->right->value; |
| break; |
| |
| case LOGICAL_OR : |
| if ((int64_t)np->left->value || |
| (int64_t)np->right->value) { |
| *value = 1; |
| } else { |
| *value = 0; |
| } |
| logical_flag++; |
| break; |
| |
| case LOGICAL_AND : |
| if ((int64_t)np->left->value && |
| (int64_t)np->right->value) { |
| *value = 1; |
| } else { |
| *value = 0; |
| } |
| logical_flag++; |
| break; |
| |
| case EQUAL : |
| if ((int64_t)np->left->value == |
| (int64_t)np->right->value) { |
| *value = 1; |
| } else { |
| *value = 0; |
| } |
| logical_flag++; |
| break; |
| |
| case NOT_EQUAL : |
| if ((int64_t)np->left->value != |
| (int64_t)np->right->value) { |
| *value = 1; |
| } else { |
| *value = 0; |
| } |
| logical_flag++; |
| break; |
| |
| case LESS_THAN : |
| if ((int64_t)np->left->value < |
| (int64_t)np->right->value) { |
| *value = 1; |
| } else { |
| *value = 0; |
| } |
| logical_flag++; |
| break; |
| |
| case GREATER_THAN : |
| if ((int64_t)np->left->value > |
| (int64_t)np->right->value) { |
| *value = 1; |
| } else { |
| *value = 0; |
| } |
| logical_flag++; |
| break; |
| |
| case LESS_THAN_OR_EQUAL : |
| if ((int64_t)np->left->value <= |
| (int64_t)np->right->value) { |
| *value = 1; |
| } else { |
| *value = 0; |
| } |
| logical_flag++; |
| break; |
| |
| case GREATER_THAN_OR_EQUAL : |
| if ((int64_t)np->left->value >= |
| (int64_t)np->right->value) { |
| *value = 1; |
| } else { |
| *value = 0; |
| } |
| logical_flag++; |
| break; |
| |
| default : |
| break; |
| } |
| } else { |
| switch (np->operator) { |
| case ADD : |
| *value = np->left->value + np->right->value; |
| break; |
| |
| case SUBTRACT : |
| *value = np->left->value - np->right->value; |
| break; |
| |
| case MULTIPLY : |
| *value = np->left->value * np->right->value; |
| break; |
| |
| case DIVIDE : |
| *value = np->left->value / np->right->value; |
| break; |
| |
| case BITWISE_OR : |
| *value = np->left->value | np->right->value; |
| break; |
| |
| case BITWISE_AND : |
| *value = np->left->value & np->right->value; |
| break; |
| |
| case MODULUS : |
| *value = np->left->value % np->right->value; |
| break; |
| |
| case RIGHT_SHIFT : |
| *value = np->left->value >> np->right->value; |
| break; |
| |
| case LEFT_SHIFT : |
| *value = np->left->value << np->right->value; |
| break; |
| |
| case LOGICAL_OR : |
| if (np->left->value || np->right->value) { |
| *value = 1; |
| } else { |
| *value = 0; |
| } |
| logical_flag++; |
| break; |
| |
| case LOGICAL_AND : |
| if (np->left->value && np->right->value) { |
| *value = 1; |
| } else { |
| *value = 0; |
| } |
| logical_flag++; |
| break; |
| |
| case EQUAL : |
| if (np->left->value == np->right->value) { |
| *value = 1; |
| } else { |
| *value = 0; |
| } |
| logical_flag++; |
| break; |
| |
| case NOT_EQUAL : |
| if (np->left->value != np->right->value) { |
| *value = 1; |
| } else { |
| *value = 0; |
| } |
| logical_flag++; |
| break; |
| |
| case LESS_THAN : |
| if (np->left->value < np->right->value) { |
| *value = 1; |
| } else { |
| *value = 0; |
| } |
| logical_flag++; |
| break; |
| |
| case GREATER_THAN : |
| if (np->left->value > np->right->value) { |
| *value = 1; |
| } else { |
| *value = 0; |
| } |
| logical_flag++; |
| break; |
| |
| case LESS_THAN_OR_EQUAL : |
| if (np->left->value <= np->right->value) { |
| *value = 1; |
| } else { |
| *value = 0; |
| } |
| logical_flag++; |
| break; |
| |
| case GREATER_THAN_OR_EQUAL : |
| if (np->left->value >= np->right->value) { |
| *value = 1; |
| } else { |
| *value = 0; |
| } |
| logical_flag++; |
| break; |
| |
| default : |
| break; |
| } |
| } |
| return(0); |
| } |
| |
| /* |
| * member_to_type() |
| */ |
| static type_t * |
| member_to_type(kltype_t *kltp, int flags) |
| { |
| kltype_t *rkltp; |
| type_t *tp, *head = (type_t *)NULL, *last = (type_t *)NULL; |
| |
| /* Make sure this is a member |
| */ |
| if (kltp->kl_type != KLT_MEMBER) { |
| return((type_t *)NULL); |
| } |
| |
| rkltp = kltp->kl_realtype; |
| while (rkltp && rkltp->kl_type == KLT_POINTER) { |
| tp = (type_t *)kl_alloc_block(sizeof(type_t)); |
| tp->flag = POINTER_FLAG; |
| if (last) { |
| last->t_next = tp; |
| last = tp; |
| } else { |
| head = last = tp; |
| } |
| rkltp = rkltp->kl_realtype; |
| } |
| |
| /* If We step past all the pointer records and don't point |
| * at anything, this must be a void pointer. Setup a VOID |
| * type struct so that we can maintain a pointer to some |
| * type info. |
| */ |
| if (!rkltp) { |
| tp = (type_t *)kl_alloc_block(sizeof(type_t)); |
| tp->flag = VOID_FLAG; |
| tp->t_kltp = kltp; |
| if (last) { |
| last->t_next = tp; |
| last = tp; |
| } else { |
| head = last = tp; |
| } |
| return(head); |
| } |
| |
| tp = (type_t *)kl_alloc_block(sizeof(type_t)); |
| tp->flag = KLTYPE_FLAG; |
| tp->t_kltp = kltp; |
| if (last) { |
| last->t_next = tp; |
| } else { |
| head = tp; |
| } |
| return(head); |
| } |
| |
| /* |
| * replace() -- |
| * |
| * Replace the tree with a node containing the numerical result of |
| * the equation. If pointer math is performed, the result will have |
| * the same type as the pointer. |
| */ |
| static node_t * |
| replace(node_t *np, int flags) |
| { |
| int offset; |
| uint64_t value; |
| node_t *q; |
| |
| if (!np) { |
| return((node_t *)NULL); |
| } |
| |
| if (np->node_type == OPERATOR) { |
| if (!(q = np->left)) { |
| return((node_t *)NULL); |
| } |
| while (q) { |
| if (!replace(q, flags)) { |
| return((node_t *)NULL); |
| } |
| q = q->right; |
| } |
| |
| if ((np->operator == RIGHT_ARROW) || (np->operator == DOT)) { |
| kaddr_t addr = 0; |
| type_t *tp; |
| |
| if (!have_debug_file) { |
| lkdb_printf("no debuginfo file\n"); |
| return 0; |
| } |
| |
| /* The left node must point to a TYPE_DEF |
| */ |
| if (np->left->node_type != TYPE_DEF) { |
| if (np->left->flags & NOTYPE_FLAG) { |
| set_eval_error(E_NOTYPE); |
| error_token = np->left->tok_ptr; |
| } else { |
| set_eval_error(E_BAD_TYPE); |
| error_token = np->left->tok_ptr; |
| } |
| return((node_t *)NULL); |
| } |
| |
| /* Get the type information. Check to see if we |
| * have a pointer to a type. If we do, we need |
| * to strip off the pointer and get the type info. |
| */ |
| if (np->left->type->flag == POINTER_FLAG) { |
| tp = np->left->type->t_next; |
| kl_free_block((void *)np->left->type); |
| } else { |
| tp = np->left->type; |
| } |
| |
| /* We need to zero out the left child's type pointer |
| * to prevent the type structs from being prematurely |
| * freed (upon success). We have to remember, however, |
| * to the free the type information before we return. |
| */ |
| np->left->type = (type_t*)NULL; |
| |
| /* tp should now point at a type_t struct that |
| * references a kltype_t struct. If it points |
| * to anything else, return failure. |
| * |
| */ |
| if (tp->flag != KLTYPE_FLAG) { |
| set_eval_error(E_BAD_TYPE); |
| error_token = np->left->tok_ptr; |
| free_type(tp); |
| return((node_t *)NULL); |
| } |
| |
| switch (tp->flag) { |
| case KLTYPE_FLAG: { |
| /* Make sure that the type referenced |
| * is a struct, union, or pointer to |
| * a struct or union. If it isn't one |
| * of these, then return failure. |
| */ |
| kltype_t *kltp, *kltmp; |
| |
| kltp = kl_realtype(tp->t_kltp, 0); |
| if ((kltp->kl_type != KLT_STRUCT) && |
| (kltp->kl_type != KLT_UNION)) { |
| error_token = |
| np->left->tok_ptr; |
| set_eval_error(E_BAD_TYPE); |
| free_type(tp); |
| return((node_t *)NULL); |
| } |
| |
| /* Get type information for member. |
| * If member is a pointer to a type, |
| * get the pointer address and load |
| * it into value. In any event, load |
| * the struct/union address plus the |
| * offset of the member. |
| */ |
| kltmp = kl_get_member(kltp, |
| np->right->name); |
| if (!kltmp) { |
| set_eval_error(E_BAD_MEMBER); |
| error_token = |
| np->right->tok_ptr; |
| free_type(tp); |
| return((node_t *)NULL); |
| } |
| |
| /* We can't just use the offset value |
| * for the member. That's because it |
| * may be from an anonymous struct or |
| * union within another struct |
| * definition. |
| */ |
| offset = kl_get_member_offset(kltp, |
| np->right->name); |
| np->type = member_to_type(kltmp, flags); |
| if (!np->type) { |
| set_eval_error(E_BAD_MEMBER); |
| error_token = |
| np->right->tok_ptr; |
| free_type(tp); |
| return((node_t *)NULL); |
| } |
| |
| /* Now free the struct type information |
| */ |
| free_type(tp); |
| np->node_type = TYPE_DEF; |
| np->flags |= KLTYPE_FLAG; |
| np->operator = 0; |
| addr = 0; |
| if (np->left->flags & POINTER_FLAG) { |
| addr = np->left->value + |
| offset; |
| } else if (np->left->flags & |
| ADDRESS_FLAG) { |
| addr = np->left->address + |
| offset; |
| } |
| if (addr) { |
| np->address = addr; |
| np->flags |= ADDRESS_FLAG; |
| } |
| |
| if (np->type->flag == POINTER_FLAG) { |
| np->flags |= POINTER_FLAG; |
| np->value = *((kaddr_t *)addr); |
| } else { |
| np->value = addr; |
| } |
| break; |
| } |
| } |
| free_nodes(np->left); |
| free_nodes(np->right); |
| np->left = np->right = (node_t*)NULL; |
| return(np); |
| } else { |
| if (!np->left || !np->right) { |
| set_eval_error(E_MISSING_OPERAND); |
| error_token = np->tok_ptr; |
| return((node_t *)NULL); |
| } |
| if (np->left->byte_size && np->right->byte_size) { |
| if (np->left->byte_size > |
| np->right->byte_size) { |
| |
| /* Left byte_size is greater than right |
| */ |
| np->byte_size = np->left->byte_size; |
| np->type = np->left->type; |
| np->flags = np->left->flags; |
| free_type(np->right->type); |
| } else if (np->left->byte_size < |
| np->right->byte_size) { |
| |
| /* Right byte_size is greater than left |
| */ |
| np->byte_size = np->right->byte_size; |
| np->type = np->right->type; |
| np->flags = np->right->flags; |
| free_type(np->left->type); |
| } else { |
| |
| /* Left and right byte_size is equal |
| */ |
| if (np->left->flags & UNSIGNED_FLAG) { |
| np->byte_size = |
| np->left->byte_size; |
| np->type = np->left->type; |
| np->flags = np->left->flags; |
| free_type(np->right->type); |
| } else if (np->right->flags & |
| UNSIGNED_FLAG) { |
| np->byte_size = |
| np->right->byte_size; |
| np->type = np->right->type; |
| np->flags = np->right->flags; |
| free_type(np->left->type); |
| } else { |
| np->byte_size = |
| np->left->byte_size; |
| np->type = np->left->type; |
| np->flags = np->left->flags; |
| free_type(np->right->type); |
| } |
| } |
| } else if (np->left->byte_size) { |
| np->byte_size = np->left->byte_size; |
| np->type = np->left->type; |
| np->flags = np->left->flags; |
| free_type(np->right->type); |
| } else if (np->right->byte_size) { |
| np->byte_size = np->right->byte_size; |
| np->type = np->right->type; |
| np->flags = np->right->flags; |
| } else { |
| /* XXX - No byte sizes |
| */ |
| } |
| |
| if (apply(np, &value, flags)) { |
| return((node_t *)NULL); |
| } |
| } |
| np->right->type = np->left->type = (type_t*)NULL; |
| |
| /* Flesh out the rest of the node struct. |
| */ |
| if (np->type) { |
| np->node_type = TYPE_DEF; |
| np->flags |= KLTYPE_FLAG; |
| } else { |
| np->node_type = NUMBER; |
| np->flags &= ~(KLTYPE_FLAG); |
| } |
| np->operator = 0; |
| np->value = value; |
| kl_free_block((void *)np->left); |
| kl_free_block((void *)np->right); |
| np->left = np->right = (node_t*)NULL; |
| } |
| return(np); |
| } |
| |
| /* |
| * replace_cast() |
| */ |
| static int |
| replace_cast(node_t *n, int flags) |
| { |
| type_t *t; |
| |
| if (!n) { |
| set_eval_error(E_SYNTAX_ERROR); |
| return(-1); |
| } else if (!n->right) { |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = n->tok_ptr; |
| return(-1); |
| } |
| if (n->flags & POINTER_FLAG) { |
| if (n->right->node_type == VADDR) { |
| if (n->right->flags & ADDRESS_FLAG) { |
| n->value = n->right->address; |
| } else { |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = n->right->tok_ptr; |
| return(-1); |
| } |
| |
| } else { |
| n->value = n->right->value; |
| n->address = 0; |
| } |
| } else if (n->right->flags & ADDRESS_FLAG) { |
| n->flags |= ADDRESS_FLAG; |
| n->address = n->right->address; |
| n->value = n->right->value; |
| } else { |
| kltype_t *kltp; |
| |
| if (!(t = eval_type(n))) { |
| set_eval_error(E_BAD_TYPE); |
| error_token = n->tok_ptr; |
| return(-1); |
| } |
| if (t->t_kltp->kl_type != KLT_BASE) { |
| |
| kltp = kl_realtype(t->t_kltp, 0); |
| if (kltp->kl_type != KLT_BASE) { |
| set_eval_error(E_BAD_CAST); |
| error_token = n->tok_ptr; |
| return(-1); |
| } |
| } |
| n->value = n->right->value; |
| n->type = t; |
| } |
| n->node_type = TYPE_DEF; |
| n->operator = 0; |
| free_node(n->right); |
| n->right = (node_t *)NULL; |
| return(0); |
| } |
| |
| /* |
| * replace_indirection() |
| */ |
| static int |
| replace_indirection(node_t *n, int flags) |
| { |
| kaddr_t addr; |
| type_t *t, *tp, *rtp; |
| |
| /* Make sure there is a right child and that it is a TYPE_DEF. |
| */ |
| if (!n->right) { |
| set_eval_error(E_BAD_TYPE); |
| error_token = n->tok_ptr; |
| return(-1); |
| } else if (n->right->node_type != TYPE_DEF) { |
| set_eval_error(E_BAD_TYPE); |
| error_token = n->right->tok_ptr; |
| return(-1); |
| } |
| |
| /* Make sure the right node contains a pointer or address value. |
| * Note that it's possible for the whatis command to generate |
| * this case without any actual pointer/address value. |
| */ |
| if (!(n->right->flags & (POINTER_FLAG|ADDRESS_FLAG))) { |
| set_eval_error(E_BAD_POINTER); |
| error_token = n->right->tok_ptr; |
| return(-1); |
| } |
| |
| /* Get the pointer to the first type struct and make sure |
| * it's a pointer. |
| */ |
| if (!(tp = n->right->type) || (tp->flag != POINTER_FLAG)) { |
| set_eval_error(E_BAD_TYPE); |
| error_token = n->right->tok_ptr; |
| return(-1); |
| } |
| |
| /* Make sure we have a pointer to a type structure. |
| */ |
| if (!(n->right->flags & KLTYPE_FLAG)) { |
| set_eval_error(E_BAD_TYPE); |
| error_token = n->right->tok_ptr; |
| return(-1); |
| } |
| |
| n->node_type = TYPE_DEF; |
| n->flags = KLTYPE_FLAG; |
| n->operator = 0; |
| |
| if (!(t = tp->t_next)) { |
| set_eval_error(E_BAD_TYPE); |
| error_token = n->right->tok_ptr; |
| return(-1); |
| } |
| |
| if (!(rtp = eval_type(n->right))) { |
| set_eval_error(E_BAD_TYPE); |
| error_token = n->right->tok_ptr; |
| return(-1); |
| } |
| |
| /* Zero out the type field in the right child so |
| * it wont accidently be freed when the right child |
| * is freed (upon success). |
| */ |
| n->right->type = (type_t*)NULL; |
| |
| n->type = t; |
| |
| /* Free the pointer struct |
| */ |
| kl_free_block((void *)tp); |
| |
| /* Get the pointer address |
| */ |
| addr = n->address = n->right->value; |
| n->flags |= ADDRESS_FLAG; |
| |
| if (rtp->t_kltp->kl_type == KLT_MEMBER) { |
| /* If this is a member, we have to step over the KLT_MEMBER |
| * struct and then make sure we have a KLT_POINTER struct. |
| * If we do, we step over it too...otherwise return an |
| * error. |
| */ |
| if (rtp->t_kltp->kl_realtype->kl_type != KLT_POINTER) { |
| set_eval_error(E_BAD_TYPE); |
| error_token = n->right->tok_ptr; |
| return(-1); |
| } |
| rtp->t_kltp = rtp->t_kltp->kl_realtype; |
| } |
| |
| if (rtp->t_kltp->kl_type == KLT_POINTER) { |
| /* Strip off the pointer type record so that |
| * we pick up the actual type definition with |
| * our indirection. |
| */ |
| rtp->t_kltp = rtp->t_kltp->kl_realtype; |
| if (rtp->t_kltp->kl_name && |
| !strcmp(rtp->t_kltp->kl_name, "char")) { |
| n->flags |= STRING_FLAG; |
| } |
| } |
| |
| |
| /* If this is a pointer to a pointer, get the next |
| * pointer value. |
| */ |
| if (n->type->flag == POINTER_FLAG) { |
| n->value = *((kaddr_t *)addr); |
| |
| /* Set the appropriate node flag values |
| */ |
| n->flags |= POINTER_FLAG; |
| free_node(n->right); |
| n->left = n->right = (node_t *)NULL; |
| return(0); |
| } |
| /* Zero out the type field in the right child so it doesn't |
| * accidently get freed up when the right child is freed |
| * (upon success). |
| */ |
| n->right->type = (type_t*)NULL; |
| free_node(n->right); |
| n->left = n->right = (node_t *)NULL; |
| return(0); |
| } |
| |
| /* |
| * replace_unary() |
| * |
| * Convert a unary operator node that contains a pointer to a value |
| * with a node containing the numerical result. Free the node that |
| * originally contained the value. |
| */ |
| static int |
| replace_unary(node_t *n, int flags) |
| { |
| uint64_t value; |
| |
| if (!n->right) { |
| set_eval_error(E_MISSING_OPERAND); |
| error_token = n->tok_ptr; |
| return(-1); |
| } |
| if (is_unary(n->right->operator)) { |
| if (replace_unary(n->right, flags) == -1) { |
| return(-1); |
| } |
| } |
| if (n->operator == CAST) { |
| return(replace_cast(n, flags)); |
| } else if (n->operator == INDIRECTION) { |
| return(replace_indirection(n, flags)); |
| } else if (n->operator == ADDRESS) { |
| type_t *t; |
| |
| if (n->right->node_type == TYPE_DEF) { |
| if (!(n->right->flags & ADDRESS_FLAG)) { |
| set_eval_error(E_NO_ADDRESS); |
| error_token = n->right->tok_ptr; |
| return(-1); |
| } |
| t = n->right->type; |
| } else { |
| set_eval_error(E_BAD_TYPE); |
| error_token = n->right->tok_ptr; |
| return(-1); |
| } |
| n->type = (type_t*)kl_alloc_block(sizeof(type_t)); |
| n->type->flag = POINTER_FLAG; |
| n->type->t_next = t; |
| n->node_type = TYPE_DEF; |
| n->operator = 0; |
| n->value = n->right->address; |
| n->flags = POINTER_FLAG; |
| if (!(t = eval_type(n))) { |
| set_eval_error(E_BAD_TYPE); |
| error_token = n->tok_ptr; |
| return(-1); |
| } |
| n->flags |= t->flag; |
| n->right->type = 0; |
| free_nodes(n->right); |
| n->left = n->right = (node_t *)NULL; |
| return(0); |
| } else if (apply_unary(n, &value) == -1) { |
| return(-1); |
| } |
| free_nodes(n->right); |
| n->node_type = NUMBER; |
| n->operator = 0; |
| n->left = n->right = (node_t *)NULL; |
| memcpy(&n->value, &value, sizeof(uint64_t)); |
| return(0); |
| } |
| |
| /* |
| * pointer_to_element() |
| */ |
| static void |
| pointer_to_element(node_t *n0, node_t *n1) |
| { |
| int size; |
| kltype_t *kltp, *rkltp; |
| type_t *tp; |
| |
| if (!(tp = n0->type)) { |
| set_eval_error(E_BAD_INDEX); |
| error_token = n0->tok_ptr; |
| return; |
| } |
| if (tp->t_next->flag == POINTER_FLAG) { |
| size = sizeof(void *); |
| } else { |
| kltp = tp->t_next->t_kltp; |
| if (!(rkltp = kl_realtype(kltp, 0))) { |
| set_eval_error(E_BAD_INDEX); |
| error_token = n0->tok_ptr; |
| return; |
| } |
| size = rkltp->kl_size; |
| } |
| |
| /* Get the details on the array element |
| */ |
| n0->flags |= ADDRESS_FLAG; |
| n0->address = n0->value + (n1->value * size); |
| n0->type = tp->t_next; |
| kl_free_block((char *)tp); |
| if (tp->t_next->flag == POINTER_FLAG) { |
| n0->flags |= POINTER_FLAG; |
| n0->value = *((kaddr_t *)n0->address); |
| } else { |
| n0->flags &= (~POINTER_FLAG); |
| n0->value = 0; |
| } |
| } |
| |
| /* |
| * array_to_element() |
| */ |
| static void |
| array_to_element(node_t *n0, node_t *n1) |
| { |
| kltype_t *kltp, *rkltp, *ip, *ep; |
| type_t *tp, *troot = (type_t *)NULL; |
| |
| if (!(tp = n0->type)) { |
| set_eval_error(E_BAD_INDEX); |
| error_token = n0->tok_ptr; |
| return; |
| } |
| |
| /* If we are indexing a pointer, then make a call to the |
| * pointer_to_element() and return. |
| */ |
| if (tp->flag == POINTER_FLAG) { |
| return(pointer_to_element(n0, n1)); |
| } |
| |
| if (!(kltp = n0->type->t_kltp)) { |
| set_eval_error(E_BAD_INDEX); |
| error_token = n0->tok_ptr; |
| return; |
| } |
| if (!(rkltp = kl_realtype(kltp, KLT_ARRAY))) { |
| set_eval_error(E_BAD_INDEX); |
| error_token = n0->tok_ptr; |
| return; |
| } |
| ip = rkltp->kl_indextype; |
| ep = rkltp->kl_elementtype; |
| if (!ip || !ep) { |
| set_eval_error(E_BAD_INDEX); |
| error_token = n1->tok_ptr; |
| return; |
| } |
| /* Get the details on the array element |
| */ |
| n0->address = n0->address + (n1->value * ep->kl_size); |
| if (ep->kl_type == KLT_POINTER) { |
| n0->flags |= POINTER_FLAG; |
| n0->value = *((kaddr_t *)n0->address); |
| } else { |
| n0->value = 0; |
| } |
| n0->flags |= ADDRESS_FLAG; |
| kltp = ep; |
| while (kltp->kl_type == KLT_POINTER) { |
| if (troot) { |
| tp->t_next = (type_t*)kl_alloc_block(sizeof(type_t)); |
| tp = tp->t_next; |
| } else { |
| tp = (type_t*)kl_alloc_block(sizeof(type_t)); |
| troot = tp; |
| } |
| tp->flag = POINTER_FLAG; |
| kltp = kltp->kl_realtype; |
| } |
| if (troot) { |
| tp->t_next = (type_t*)kl_alloc_block(sizeof(type_t)); |
| tp = tp->t_next; |
| n0->type = troot; |
| } else { |
| tp = (type_t*)kl_alloc_block(sizeof(type_t)); |
| n0->type = tp; |
| } |
| tp->flag = KLTYPE_FLAG; |
| tp->t_kltp = ep; |
| } |
| |
| /* |
| * number_to_size() |
| */ |
| int |
| number_to_size(node_t *np) |
| { |
| int unsigned_flag = 0; |
| |
| if (np->node_type != NUMBER) { |
| set_eval_error(E_BAD_TYPE); |
| error_token = np->tok_ptr; |
| return(0); |
| } |
| if (np->flags & UNSIGNED_FLAG) { |
| unsigned_flag = 1; |
| } |
| if ((np->value >= 0) && (np->value <= 0xffffffff)) { |
| return(4); |
| } else if (((np->value >> 32) & 0xffffffff) == 0xffffffff) { |
| if (unsigned_flag) { |
| return(8); |
| } else if (sizeof(void *) == 4) { |
| return(4); |
| } else { |
| return(8); |
| } |
| } |
| return(8); |
| } |
| |
| /* |
| * number_to_type() |
| */ |
| kltype_t * |
| number_to_type(node_t *np) |
| { |
| int unsigned_flag = 0; |
| kltype_t *kltp, *rkltp = (kltype_t *)NULL; |
| |
| if (np->node_type != NUMBER) { |
| set_eval_error(E_BAD_TYPE); |
| error_token = np->tok_ptr; |
| return((kltype_t *)NULL); |
| } |
| if (np->flags & UNSIGNED_FLAG) { |
| unsigned_flag = 1; |
| } |
| if ((np->value >= 0) && (np->value <= 0xffffffff)) { |
| if (unsigned_flag) { |
| kltp = kl_find_type("uint32_t", KLT_TYPEDEF); |
| } else { |
| kltp = kl_find_type("int32_t", KLT_TYPEDEF); |
| } |
| } else if (((np->value >> 32) & 0xffffffff) == 0xffffffff) { |
| if (unsigned_flag) { |
| kltp = kl_find_type("uint64_t", KLT_TYPEDEF); |
| } else if (sizeof(void *) == 4) { |
| kltp = kl_find_type("int32_t", KLT_TYPEDEF); |
| } else { |
| kltp = kl_find_type("int64_t", KLT_TYPEDEF); |
| } |
| } else { |
| if (unsigned_flag) { |
| kltp = kl_find_type("uint64_t", KLT_TYPEDEF); |
| } else { |
| kltp = kl_find_type("int64_t", KLT_TYPEDEF); |
| } |
| } |
| if (kltp) { |
| if (!(rkltp = kl_realtype(kltp, 0))) { |
| rkltp = kltp; |
| } |
| } else { |
| set_eval_error(E_BAD_TYPE); |
| error_token = np->tok_ptr; |
| } |
| return(rkltp); |
| } |
| |
| /* |
| * type_to_number() |
| * |
| * Convert a base type to a numeric value. Return 1 on successful |
| * conversion, 0 if nothing was done. |
| */ |
| static int |
| type_to_number(node_t *np) |
| { |
| int byte_size, bit_offset, bit_size, encoding; |
| uint64_t value, value1; |
| kltype_t *kltp, *rkltp; |
| |
| /* Sanity check... |
| */ |
| if (np->node_type != TYPE_DEF) { |
| set_eval_error(E_NOTYPE); |
| error_token = np->tok_ptr; |
| return(0); |
| } |
| if (!np->type) { |
| set_eval_error(E_NOTYPE); |
| error_token = np->tok_ptr; |
| return(0); |
| } |
| if (np->type->flag == POINTER_FLAG) { |
| return(0); |
| } |
| |
| /* Get the real type record and make sure that it is |
| * for a base type. |
| */ |
| kltp = np->type->t_kltp; |
| rkltp = kl_realtype(kltp, 0); |
| if (rkltp->kl_type != KLT_BASE) { |
| set_eval_error(E_NOTYPE); |
| error_token = np->tok_ptr; |
| return(0); |
| } |
| |
| byte_size = rkltp->kl_size; |
| bit_offset = rkltp->kl_bit_offset; |
| if (!(bit_size = rkltp->kl_bit_size)) { |
| bit_size = byte_size * 8; |
| } |
| encoding = rkltp->kl_encoding; |
| if (np->flags & ADDRESS_FLAG) { |
| /* FIXME: untested */ |
| if (invalid_address(np->address, byte_size)) { |
| lkdb_printf("ILLEGAL ADDRESS (%lx)", |
| (uaddr_t)np->address); |
| return (0); |
| } |
| kl_get_block(np->address, byte_size,(void *)&value1,(void *)0); |
| } else { |
| value1 = np->value; |
| } |
| value = kl_get_bit_value(&value1, byte_size, bit_size, bit_offset); |
| switch (byte_size) { |
| |
| case 1 : |
| if (encoding == ENC_UNSIGNED) { |
| np->value = (unsigned char)value; |
| np->flags |= UNSIGNED_FLAG; |
| } else if (encoding == ENC_SIGNED) { |
| np->value = (signed char)value; |
| } else { |
| np->value = (char)value; |
| } |
| break; |
| |
| case 2 : |
| if (encoding == ENC_UNSIGNED) { |
| np->value = (uint16_t)value; |
| np->flags |= UNSIGNED_FLAG; |
| } else { |
| np->value = (int16_t)value; |
| } |
| break; |
| |
| case 4 : |
| if (encoding == ENC_UNSIGNED) { |
| np->value = (uint32_t)value; |
| np->flags |= UNSIGNED_FLAG; |
| } else { |
| np->value = (int32_t)value; |
| } |
| break; |
| |
| case 8 : |
| if (encoding == ENC_UNSIGNED) { |
| np->value = (uint64_t)value; |
| np->flags |= UNSIGNED_FLAG; |
| } else { |
| np->value = (int64_t)value; |
| } |
| break; |
| |
| default : |
| set_eval_error(E_BAD_TYPE); |
| error_token = np->tok_ptr; |
| return(0); |
| } |
| np->byte_size = byte_size; |
| np->node_type = NUMBER; |
| return(1); |
| } |
| |
| /* |
| * eval_type() |
| */ |
| static type_t * |
| eval_type(node_t *n) |
| { |
| type_t *t; |
| |
| if (!(t = n->type)) { |
| return((type_t*)NULL); |
| } |
| while (t->flag == POINTER_FLAG) { |
| t = t->t_next; |
| |
| /* If for some reason, there is no type pointer (this shouldn't |
| * happen but...), we have to make sure that we don't try to |
| * reference a NULL pointer and get a SEGV. Return an error if |
| * 't' is NULL. |
| */ |
| if (!t) { |
| return((type_t*)NULL); |
| } |
| } |
| if (t->flag == KLTYPE_FLAG) { |
| return (t); |
| } |
| return((type_t*)NULL); |
| } |
| |
| /* |
| * expand_variables() |
| */ |
| static char * |
| expand_variables(char *exp, int flags) |
| { |
| return((char *)NULL); |
| } |
| |
| /* |
| * eval() |
| */ |
| node_t * |
| eval(char **exp, int flags) |
| { |
| token_t *tok; |
| node_t *n, *root; |
| char *e, *s; |
| |
| eval_error = 0; |
| logical_flag = 0; |
| |
| /* Make sure there is an expression to evaluate |
| */ |
| if (!(*exp)) { |
| return ((node_t*)NULL); |
| } |
| |
| /* Expand any variables that are in the expression string. If |
| * a new string is allocated by the expand_variables() function, |
| * we need to make sure the original expression string gets |
| * freed. In any event, point s at the current expression string |
| * so that it gets freed up when we are done. |
| */ |
| if ((e = expand_variables(*exp, 0))) { |
| kl_free_block((void *)*exp); |
| *exp = e; |
| } else if (eval_error) { |
| eval_error |= E_BAD_EVAR; |
| error_token = *exp; |
| } |
| s = *exp; |
| tok = get_token_list(s); |
| if (eval_error) { |
| return((node_t*)NULL); |
| } |
| |
| /* Get the node_list and evaluate the expression. |
| */ |
| node_list = get_node_list(tok, flags); |
| if (eval_error) { |
| free_nodelist(node_list); |
| node_list = (node_t*)NULL; |
| free_tokens(tok); |
| return((node_t*)NULL); |
| } |
| if (!(n = do_eval(flags))) { |
| if (!eval_error) { |
| set_eval_error(E_SYNTAX_ERROR); |
| error_token = s + strlen(s) - 1; |
| } |
| free_nodes(n); |
| free_tokens(tok); |
| return((node_t*)NULL); |
| } |
| |
| if (!(root = replace(n, flags))) { |
| if (eval_error) { |
| free_nodes(n); |
| free_tokens(tok); |
| return((node_t*)NULL); |
| } |
| root = n; |
| } |
| |
| /* Check to see if the the result should |
| * be interpreted as 'true' or 'false' |
| */ |
| if (logical_flag && ((root->value == 0) || (root->value == 1))) { |
| root->flags |= BOOLIAN_FLAG; |
| } |
| free_tokens(tok); |
| return(root); |
| } |
| |
| /* |
| * print_number() |
| */ |
| void |
| print_number(node_t *np, int flags) |
| { |
| int size; |
| unsigned long long value; |
| |
| if ((size = number_to_size(np)) && (size != sizeof(uint64_t))) { |
| value = np->value & (((uint64_t)1 << (uint64_t)(size*8))-1); |
| } else { |
| value = np->value; |
| } |
| if (flags & C_HEX) { |
| lkdb_printf("0x%llx", value); |
| } else if (flags & C_BINARY) { |
| lkdb_printf("0b"); |
| kl_binary_print(value); |
| } else { |
| if (np->flags & UNSIGNED_FLAG) { |
| lkdb_printf("%llu", value); |
| } else { |
| lkdb_printf("%lld", np->value); |
| } |
| } |
| } |
| |
| /* |
| * print_string() |
| */ |
| void |
| print_string(kaddr_t addr, int size) |
| { |
| int i; |
| char *str; |
| |
| if (!size) { |
| size = 255; |
| } |
| /* FIXME: untested */ |
| if (invalid_address(addr, size)) { |
| klib_error = KLE_INVALID_PADDR; |
| return; |
| } |
| str = (char*)kl_alloc_block(size); |
| kl_get_block(addr, size, (void *)str, (void *)0); |
| lkdb_printf("\"%s", str); |
| for (i = 0; i < size; i++) { |
| if (!str[i]) { |
| break; |
| } |
| } |
| if (KL_ERROR || (i == size)) { |
| lkdb_printf("..."); |
| } |
| lkdb_printf("\""); |
| kl_free_block(str); |
| } |
| |
| /* |
| * kl_print_error() |
| */ |
| void |
| kl_print_error(void) |
| { |
| int ecode; |
| |
| ecode = klib_error & 0xffffffff; |
| switch(ecode) { |
| |
| /** General klib error codes |
| **/ |
| case KLE_NO_MEMORY: |
| lkdb_printf("insufficient memory"); |
| break; |
| case KLE_OPEN_ERROR: |
| lkdb_printf("unable to open file"); |
| break; |
| case KLE_ZERO_BLOCK: |
| lkdb_printf("tried to allocate a zero-sized block"); |
| break; |
| case KLE_INVALID_VALUE: |
| lkdb_printf("invalid input value"); |
| break; |
| case KLE_NULL_BUFF: |
| lkdb_printf( "NULL buffer pointer"); |
| break; |
| case KLE_ZERO_SIZE: |
| lkdb_printf("zero sized block requested"); |
| break; |
| case KLE_ACTIVE: |
| lkdb_printf("operation not supported on a live system"); |
| break; |
| case KLE_UNSUPPORTED_ARCH: |
| lkdb_printf("unsupported architecture"); |
| break; |
| case KLE_MISC_ERROR: |
| lkdb_printf("KLIB error"); |
| break; |
| case KLE_NOT_SUPPORTED: |
| lkdb_printf("operation not supported"); |
| break; |
| case KLE_UNKNOWN_ERROR: |
| lkdb_printf("unknown error"); |
| break; |
| |
| /** memory error codes |
| **/ |
| case KLE_BAD_MAP_FILE: |
| lkdb_printf("bad map file"); |
| break; |
| case KLE_BAD_DUMP: |
| lkdb_printf("bad dump file"); |
| break; |
| case KLE_BAD_DUMPTYPE: |
| lkdb_printf("bad dumptype"); |
| break; |
| case KLE_INVALID_LSEEK: |
| lkdb_printf("lseek error"); |
| break; |
| case KLE_INVALID_READ: |
| lkdb_printf("not found in dump file"); |
| break; |
| case KLE_BAD_KERNINFO: |
| lkdb_printf("bad kerninfo struct"); |
| break; |
| case KLE_INVALID_PADDR: |
| lkdb_printf("invalid physical address"); |
| break; |
| case KLE_INVALID_VADDR: |
| lkdb_printf("invalid virtual address"); |
| break; |
| case KLE_INVALID_VADDR_ALIGN: |
| lkdb_printf("invalid vaddr alignment"); |
| break; |
| case KLE_INVALID_MAPPING: |
| lkdb_printf("invalid address mapping"); |
| break; |
| case KLE_PAGE_NOT_PRESENT: |
| lkdb_printf("page not present"); |
| break; |
| case KLE_BAD_ELF_FILE: |
| lkdb_printf("bad elf file"); |
| break; |
| case KLE_ARCHIVE_FILE: |
| lkdb_printf("archive file"); |
| break; |
| case KLE_MAP_FILE_PRESENT: |
| lkdb_printf("map file present"); |
| break; |
| case KLE_BAD_MAP_FILENAME: |
| lkdb_printf("bad map filename"); |
| break; |
| case KLE_BAD_DUMP_FILENAME: |
| lkdb_printf("bad dump filename"); |
| break; |
| case KLE_BAD_NAMELIST_FILE: |
| lkdb_printf("bad namelist file"); |
| break; |
| case KLE_BAD_NAMELIST_FILENAME: |
| lkdb_printf("bad namelist filename"); |
| break; |
| |
| /** symbol error codes |
| **/ |
| case KLE_NO_SYMTAB: |
| lkdb_printf("no symtab"); |
| break; |
| case KLE_NO_SYMBOLS: |
| lkdb_printf("no symbol information"); |
| break; |
| case KLE_NO_MODULE_LIST: |
| lkdb_printf("kernel without module support"); |
| break; |
| |
| /** kernel data error codes |
| **/ |
| case KLE_INVALID_KERNELSTACK: |
| lkdb_printf("invalid kernel stack"); |
| break; |
| case KLE_INVALID_STRUCT_SIZE: |
| lkdb_printf("invalid struct size"); |
| break; |
| case KLE_BEFORE_RAM_OFFSET: |
| lkdb_printf("physical address proceeds start of RAM"); |
| break; |
| case KLE_AFTER_MAXPFN: |
| lkdb_printf("PFN exceeds maximum PFN"); |
| break; |
| case KLE_AFTER_PHYSMEM: |
| lkdb_printf("address exceeds physical memory"); |
| break; |
| case KLE_AFTER_MAXMEM: |
| lkdb_printf("address exceeds maximum physical address"); |
| break; |
| case KLE_PHYSMEM_NOT_INSTALLED: |
| lkdb_printf("physical memory not installed"); |
| break; |
| case KLE_NO_DEFTASK: |
| lkdb_printf("default task not set"); |
| break; |
| case KLE_PID_NOT_FOUND: |
| lkdb_printf("PID not found"); |
| break; |
| case KLE_DEFTASK_NOT_ON_CPU: |
| lkdb_printf("default task not running on a cpu"); |
| break; |
| case KLE_NO_CURCPU: |
| lkdb_printf("current cpu could not be determined"); |
| break; |
| |
| case KLE_KERNEL_MAGIC_MISMATCH: |
| lkdb_printf("kernel_magic mismatch " |
| "of map and memory image"); |
| break; |
| |
| case KLE_INVALID_DUMP_HEADER: |
| lkdb_printf("invalid dump header in dump"); |
| break; |
| |
| case KLE_DUMP_INDEX_CREATION: |
| lkdb_printf("cannot create index file"); |
| break; |
| |
| case KLE_DUMP_HEADER_ONLY: |
| lkdb_printf("dump only has a dump header"); |
| break; |
| |
| case KLE_NO_END_SYMBOL: |
| lkdb_printf("no _end symbol in kernel"); |
| break; |
| |
| case KLE_NO_CPU: |
| lkdb_printf("CPU not installed"); |
| break; |
| |
| default: |
| break; |
| } |
| lkdb_printf("\n"); |
| } |
| |
| /* |
| * kl_print_string() |
| * |
| * print out a string, translating all embeded control characters |
| * (e.g., '\n' for newline, '\t' for tab, etc.) |
| */ |
| void |
| kl_print_string(char *s) |
| { |
| char *sp, *cp; |
| |
| kl_reset_error(); |
| |
| if (!(sp = s)) { |
| klib_error = KLE_BAD_STRING; |
| return; |
| } |
| /* FIXME: untested */ |
| if (invalid_address((kaddr_t)sp, 1)) { |
| klib_error = KLE_INVALID_PADDR; |
| return; |
| } |
| |
| while (sp) { |
| if ((cp = strchr(sp, '\\'))) { |
| switch (*(cp + 1)) { |
| |
| case 'n' : |
| *cp++ = '\n'; |
| *cp++ = 0; |
| break; |
| |
| case 't' : |
| *cp++ = '\t'; |
| *cp++ = 0; |
| break; |
| |
| default : |
| if (*(cp + 1) == 0) { |
| klib_error = KLE_BAD_STRING; |
| return; |
| } |
| /* Change the '\' character to a zero |
| * and then print the string (the rest |
| * of the string will be picked |
| * up on the next pass). |
| */ |
| *cp++ = 0; |
| break; |
| } |
| lkdb_printf("%s", sp); |
| sp = cp; |
| } else { |
| lkdb_printf("%s", sp); |
| sp = 0; |
| } |
| } |
| } |
| |
| /* |
| * print_eval_results() |
| */ |
| int |
| print_eval_results(node_t *np, int flags) |
| { |
| int size, i, count, ptr_cnt = 0; |
| kaddr_t addr; |
| char *typestr; |
| kltype_t *kltp, *rkltp = NULL, *nkltp; |
| type_t *tp; |
| |
| /* Print the results |
| */ |
| switch (np->node_type) { |
| |
| case NUMBER: |
| print_number(np, flags); |
| break; |
| |
| case TYPE_DEF: { |
| |
| /* First, determine the number of levels of indirection |
| * by determining the number of pointer type records. |
| */ |
| if ((tp = np->type)) { |
| while (tp && (tp->flag == POINTER_FLAG)) { |
| ptr_cnt++; |
| tp = tp->t_next; |
| } |
| if (tp) { |
| rkltp = tp->t_kltp; |
| } |
| } |
| if (!rkltp) { |
| lkdb_printf("Type information not available\n"); |
| return(1); |
| } |
| |
| if (ptr_cnt) { |
| |
| /* If this is a member, we need to get the |
| * first type record. |
| */ |
| if (rkltp->kl_type == KLT_MEMBER) { |
| /* We need to get down to the first |
| * real type record... |
| */ |
| rkltp = rkltp->kl_realtype; |
| } |
| |
| /* step over any KLT_POINTER type records. |
| */ |
| while (rkltp && rkltp->kl_type == KLT_POINTER) { |
| rkltp = rkltp->kl_realtype; |
| } |
| if (!rkltp) { |
| lkdb_printf("Bad type information\n"); |
| return(1); |
| } |
| typestr = rkltp->kl_typestr; |
| if (rkltp->kl_type == KLT_FUNCTION) { |
| lkdb_printf("%s(", typestr); |
| } else if (rkltp->kl_type == KLT_ARRAY) { |
| lkdb_printf("(%s(", typestr); |
| } else { |
| lkdb_printf("(%s", typestr); |
| } |
| for (i = 0; i < ptr_cnt; i++) { |
| lkdb_printf("*"); |
| } |
| if (rkltp->kl_type == KLT_FUNCTION) { |
| lkdb_printf(")("); |
| } else if (rkltp->kl_type == KLT_ARRAY) { |
| lkdb_printf(")"); |
| |
| nkltp = rkltp; |
| while (nkltp->kl_type == KLT_ARRAY) { |
| count = nkltp->kl_high_bounds - |
| nkltp->kl_low_bounds + 1; |
| lkdb_printf("[%d]", count); |
| nkltp = nkltp->kl_elementtype; |
| } |
| } |
| lkdb_printf(") "); |
| lkdb_printf("0x%llx", np->value); |
| |
| if (ptr_cnt > 1) { |
| break; |
| } |
| |
| if ((rkltp->kl_type == KLT_BASE) && |
| rkltp->kl_encoding == ENC_CHAR) { |
| lkdb_printf(" = "); |
| print_string(np->value, 0); |
| } |
| break; |
| } |
| if (np->flags & KLTYPE_FLAG) { |
| void * ptr; |
| |
| /* Get the type information. It's possible |
| * that the type is a member. In which case, |
| * the size may only be from this record |
| * (which would be the casse if this is an |
| * array). We must check the original type |
| * record first, and try the realtype record |
| * if the value is zero. |
| */ |
| kltp = np->type->t_kltp; |
| |
| if (kltp->kl_type == KLT_MEMBER) { |
| rkltp = kltp->kl_realtype; |
| } else { |
| rkltp = kltp; |
| } |
| |
| /* Check to see if this is a typedef. If |
| * it is, then it might be a typedef for |
| * a pointer type. Don't walk to the last |
| * type record. |
| */ |
| while (rkltp->kl_type == KLT_TYPEDEF) { |
| rkltp = rkltp->kl_realtype; |
| } |
| |
| if (rkltp->kl_type == KLT_POINTER) { |
| lkdb_printf("0x%llx", np->value); |
| break; |
| } |
| if((rkltp->kl_name != 0) && |
| !(strcmp(rkltp->kl_name, "void"))) { |
| /* we are about to dereference |
| * a void pointer. |
| */ |
| lkdb_printf("Can't dereference a " |
| "generic pointer.\n"); |
| return(1); |
| } |
| |
| size = rkltp->kl_size; |
| if (!size || (size < 0)) { |
| size = kltp->kl_size; |
| } |
| |
| if(rkltp->kl_type==KLT_ARRAY) { |
| size = rkltp->kl_high_bounds - |
| rkltp->kl_low_bounds + 1; |
| if(rkltp->kl_elementtype == NULL){ |
| lkdb_printf("Incomplete array" |
| " type.\n"); |
| return(1); |
| } |
| if(rkltp->kl_elementtype->kl_type == |
| KLT_POINTER){ |
| size *= sizeof(void *); |
| } else { |
| size *= rkltp->kl_elementtype->kl_size; |
| } |
| } |
| if(size){ |
| ptr = kl_alloc_block(size); |
| } else { |
| ptr = NULL; |
| } |
| if ((rkltp->kl_type == KLT_BASE) && |
| !(np->flags & ADDRESS_FLAG)) { |
| switch (size) { |
| case 1: |
| *(unsigned char *)ptr = |
| np->value; |
| break; |
| |
| case 2: |
| *(unsigned short *)ptr = |
| np->value; |
| break; |
| |
| case 4: |
| *(unsigned int *)ptr = |
| np->value; |
| break; |
| |
| case 8: |
| *(unsigned long long *) |
| ptr = np->value; |
| break; |
| } |
| kl_print_type(ptr, rkltp, 0, |
| flags|SUPPRESS_NAME); |
| kl_free_block(ptr); |
| return(1); |
| } |
| |
| if(size){ |
| addr = np->address; |
| if (invalid_address(addr, size)) { |
| lkdb_printf ( |
| "invalid address %#lx\n", |
| addr); |
| return 1; |
| } |
| kl_get_block(addr, size, (void *)ptr, |
| (void *)0); |
| if (KL_ERROR) { |
| kl_print_error(); |
| kl_free_block(ptr); |
| return(1); |
| } |
| } |
| /* Print out the actual type |
| */ |
| switch (rkltp->kl_type) { |
| case KLT_STRUCT: |
| case KLT_UNION: |
| kl_print_type(ptr, rkltp, 0, |
| flags); |
| break; |
| |
| case KLT_ARRAY: |
| kl_print_type(ptr, rkltp, 0, |
| flags| SUPPRESS_NAME); |
| break; |
| |
| default: |
| kl_print_type(ptr, rkltp, 0, |
| (flags| |
| SUPPRESS_NAME| |
| SUPPRESS_NL)); |
| break; |
| } |
| if(ptr){ |
| kl_free_block(ptr); |
| } |
| } |
| break; |
| } |
| |
| case VADDR: |
| /* If we get here, there was no type info available. |
| * The ADDRESS_FLAG should be set (otherwise we |
| * would have returned an error). So, print out |
| * the address. |
| */ |
| lkdb_printf("0x%lx", np->address); |
| break; |
| |
| default: |
| if (np->node_type == TEXT) { |
| kl_print_string(np->name); |
| if (KL_ERROR) { |
| kl_print_error(); |
| return(1); |
| } |
| } else if (np->node_type == CHARACTER) { |
| lkdb_printf("\'%c\'", (char)np->value); |
| } |
| break; |
| } |
| return(0); |
| } |
| |
| /* |
| * print_eval_error() |
| */ |
| void |
| print_eval_error( |
| char *cmdname, |
| char *s, |
| char *bad_ptr, |
| uint64_t error, |
| int flags) |
| { |
| int i, cmd_len; |
| |
| lkdb_printf("%s %s\n", cmdname, s); |
| cmd_len = strlen(cmdname); |
| |
| if (!bad_ptr) { |
| for (i = 0; i < (strlen(s) + cmd_len); i++) { |
| lkdb_printf(" "); |
| } |
| } else { |
| for (i = 0; i < (bad_ptr - s + 1 + cmd_len); i++) { |
| lkdb_printf(" "); |
| } |
| } |
| lkdb_printf("^ "); |
| switch (error) { |
| case E_OPEN_PAREN : |
| lkdb_printf("Too many open parenthesis\n"); |
| break; |
| |
| case E_CLOSE_PAREN : |
| lkdb_printf("Too many close parenthesis\n"); |
| break; |
| |
| case E_BAD_STRUCTURE : |
| lkdb_printf("Invalid structure\n"); |
| break; |
| |
| case E_MISSING_STRUCTURE : |
| lkdb_printf("Missing structure\n"); |
| break; |
| |
| case E_BAD_MEMBER : |
| lkdb_printf("No such member\n"); |
| break; |
| |
| case E_BAD_OPERATOR : |
| lkdb_printf("Invalid operator\n"); |
| break; |
| |
| case E_MISSING_OPERAND : |
| lkdb_printf("Missing operand\n"); |
| break; |
| |
| case E_BAD_OPERAND : |
| lkdb_printf("Invalid operand\n"); |
| break; |
| |
| case E_BAD_TYPE : |
| lkdb_printf("Invalid type\n"); |
| if (!have_debug_file) { |
| lkdb_printf("no debuginfo file\n"); |
| return; |
| } |
| break; |
| |
| case E_NOTYPE : |
| lkdb_printf("Could not find type information\n"); |
| break; |
| |
| case E_BAD_POINTER : |
| lkdb_printf("Invalid pointer\n"); |
| break; |
| |
| case E_BAD_INDEX : |
| lkdb_printf("Invalid array index\n"); |
| break; |
| |
| case E_BAD_CHAR : |
| lkdb_printf("Invalid character value\n"); |
| break; |
| |
| case E_BAD_STRING : |
| lkdb_printf("Non-termining string\n"); |
| break; |
| |
| case E_END_EXPECTED : |
| lkdb_printf( |
| "Expected end of print statement\n"); |
| break; |
| |
| case E_BAD_EVAR : |
| lkdb_printf("Invalid eval variable\n"); |
| break; |
| |
| case E_BAD_VALUE : |
| lkdb_printf("Invalid value\n"); |
| break; |
| |
| case E_NO_VALUE : |
| lkdb_printf("No value supplied\n"); |
| break; |
| |
| case E_DIVIDE_BY_ZERO : |
| lkdb_printf("Divide by zero\n"); |
| break; |
| |
| case E_BAD_CAST : |
| lkdb_printf("Invalid cast\n"); |
| break; |
| |
| case E_NO_ADDRESS : |
| lkdb_printf("Not an address\n"); |
| break; |
| |
| case E_SINGLE_QUOTE : |
| lkdb_printf("Missing single quote\n"); |
| break; |
| |
| case E_BAD_WHATIS : |
| lkdb_printf("Invalid whatis Operation\n"); |
| break; |
| |
| case E_NOT_IMPLEMENTED : |
| lkdb_printf("Not implemented\n"); |
| break; |
| |
| default : |
| lkdb_printf("Syntax error\n"); |
| break; |
| } |
| } |
| |
| /* |
| * single_type() |
| */ |
| void |
| single_type(char *str) |
| { |
| char buffer[256], *type_name; |
| kltype_t *kltp; |
| syment_t *sp; |
| |
| type_name = buffer; |
| strcpy(type_name, str); |
| |
| if (have_debug_file) { |
| if ((kltp = kl_find_type(type_name, KLT_TYPE))) { |
| kl_print_type((void *)NULL, kltp, 0, C_SHOWOFFSET); |
| return; |
| } |
| if ((kltp = kl_find_type(type_name, KLT_TYPEDEF))) { |
| lkdb_printf ("typedef %s:\n", type_name); |
| kl_print_type((void *)NULL, kltp, 0, C_SHOWOFFSET); |
| return; |
| } |
| } |
| if ((sp = kl_lkup_symname(type_name))) { |
| lkdb_printf ("symbol %s value: %#lx\n", str, sp->s_addr); |
| kl_free_block((void *)sp); |
| return; |
| } |
| lkdb_printf("could not find type or symbol information for %s\n", |
| type_name); |
| return; |
| } |
| |
| /* |
| * sizeof_type() |
| */ |
| void |
| sizeof_type(char *str) |
| { |
| char buffer[256], *type_name; |
| kltype_t *kltp; |
| |
| type_name = buffer; |
| strcpy(type_name, str); |
| |
| if ((kltp = kl_find_type(type_name, KLT_TYPE))) { |
| lkdb_printf ("%s %d %#x\n", kltp->kl_typestr, |
| kltp->kl_size, kltp->kl_size); |
| return; |
| } |
| if ((kltp = kl_find_type(type_name, KLT_TYPEDEF))) { |
| lkdb_printf ("%s %d %#x\n", kltp->kl_typestr, |
| kltp->kl_size, kltp->kl_size); |
| return; |
| } |
| lkdb_printf("could not find type information for %s\n", type_name); |
| } |
| |
| EXPORT_SYMBOL(have_debug_file); |
| EXPORT_SYMBOL(type_tree); |
| EXPORT_SYMBOL(typedef_tree); |
| |
| #if defined(CONFIG_X86_32) |
| /* needed for i386: */ |
| #include <linux/types.h> |
| #include <asm/div64.h> |
| /* |
| * Generic C version of full 64 bit by 64 bit division |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License |
| * version 2 as published by the Free Software Foundation. |
| * |
| * Code generated for this function might be very inefficient |
| * for some CPUs, can be overridden by linking arch-specific |
| * assembly versions such as arch/sparc/lib/udivdi.S |
| */ |
| uint64_t |
| __udivdi3(uint64_t dividend, uint64_t divisor) |
| { |
| uint32_t d = divisor; |
| /* Scale divisor to 32 bits */ |
| if (divisor > 0xffffffffULL) { |
| unsigned int shift = fls(divisor >> 32); |
| d = divisor >> shift; |
| dividend >>= shift; |
| } |
| /* avoid 64 bit division if possible */ |
| if (dividend >> 32) |
| do_div(dividend, d); |
| else |
| dividend = (uint32_t) dividend / d; |
| return dividend; |
| } |
| |
| int64_t |
| __divdi3(int64_t dividend, int64_t divisor) |
| { |
| int32_t d = divisor; |
| /* Scale divisor to 32 bits */ |
| if (divisor > 0xffffffffLL) { |
| unsigned int shift = fls(divisor >> 32); |
| d = divisor >> shift; |
| dividend >>= shift; |
| } |
| /* avoid 64 bit division if possible */ |
| if (dividend >> 32) |
| do_div(dividend, d); |
| else |
| dividend = (int32_t) dividend / d; |
| return dividend; |
| } |
| |
| uint64_t |
| __umoddi3(uint64_t dividend, uint64_t divisor) |
| { |
| return dividend - (__udivdi3(dividend, divisor) * divisor); |
| } |
| |
| int64_t |
| __moddi3(int64_t dividend, int64_t divisor) |
| { |
| return dividend - (__divdi3(dividend, divisor) * divisor); |
| } |
| #endif /* CONFIG_x86_32 */ |