.gitignore | 1 + Makefile | 15 ++- allocate.c | 2 +- allocate.h | 7 +- blobhash.c | 92 +++++++++++++++ check-interrupt.c | 210 +++++++++++++++++++++++++++++++++ check-nullptr.c | 266 ++++++++++++++++++++++++++++++++++++++++++ checker.h | 144 +++++++++++++++++++++++ ctags.c | 207 ++++++++++++++++++++++++++++++++ dissect.c | 4 +- dissect.h | 8 +- evaluate.c | 5 +- example.c | 3 +- expand.c | 10 +- flow.c | 62 +++++----- inline.c | 11 +- lib.c | 116 +++++++++++++------ lib.h | 28 ++++- linearize.c | 156 +++++++++++++++--------- linearize.h | 43 ++++++- memops.c | 22 +--- parse.c | 246 ++++++++++++++++++++++++++++----------- parse.h | 3 + ptrlist.c | 45 ++++++-- ptrlist.h | 4 +- show-parse.c | 120 ++++++++++++------- simplify.c | 53 ++++++--- sparse.c | 15 +++- symbol.c | 35 +------ symbol.h | 21 +++- test-sort.c | 2 +- token.h | 2 +- validation/badtype3.c | 2 +- validation/init-char-array.c | 2 +- 34 files changed, 1602 insertions(+), 360 deletions(-) diff --git a/.gitignore b/.gitignore index b92d678..e22a8c6 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,7 @@ test-dissect test-linearize example test-unssa +ctags # tags tags diff --git a/Makefile b/Makefile index 3bc789b..af9ea9d 100644 --- a/Makefile +++ b/Makefile @@ -22,17 +22,19 @@ LIBDIR=$(PREFIX)/lib INCLUDEDIR=$(PREFIX)/include PKGCONFIGDIR=$(PREFIX)/share/pkgconfig -PROGRAMS=test-lexing test-parsing obfuscate compile graph sparse test-linearize example test-unssa test-dissect +PROGRAMS=test-lexing test-parsing obfuscate compile graph sparse test-linearize example \ + test-unssa test-dissect ctags INST_PROGRAMS=sparse cgcc LIB_H= token.h parse.h lib.h symbol.h scope.h expression.h target.h \ linearize.h bitmap.h ident-list.h compat.h flow.h allocate.h \ - storage.h ptrlist.h dissect.h + storage.h ptrlist.h dissect.h checker.h LIB_OBJS= target.o parse.o tokenize.o pre-process.o symbol.o lib.o scope.o \ expression.o show-parse.o evaluate.o expand.o inline.o linearize.o \ sort.o allocate.o compat-$(OS).o ptrlist.o \ - flow.o cse.o simplify.o memops.o liveness.o storage.o unssa.o dissect.o + flow.o cse.o simplify.o memops.o liveness.o storage.o unssa.o dissect.o \ + blobhash.o check-nullptr.o check-interrupt.o LIB_FILE= libsparse.a SLIB_FILE= libsparse.so @@ -93,6 +95,9 @@ test-unssa: test-unssa.o $(LIBS) test-dissect: test-dissect.o $(LIBS) $(CC) $(LDFLAGS) -o $@ $< $(LIBS) +ctags: ctags.o $(LIBS) + $(CC) $(LDFLAGS) -o $@ $< $(LIBS) + $(LIB_FILE): $(LIB_OBJS) $(AR) rcs $@ $(LIB_OBJS) @@ -122,6 +127,7 @@ test-lexing.o: $(LIB_H) test-parsing.o: $(LIB_H) test-linearize.o: $(LIB_H) test-dissect.o: $(LIB_H) +ctags.o: $(LIB_H) compile.o: $(LIB_H) compile.h compile-i386.o: $(LIB_H) compile.h tokenize.o: $(LIB_H) @@ -131,6 +137,9 @@ example.o: $(LIB_H) storage.o: $(LIB_H) dissect.o: $(LIB_H) graph.o: $(LIB_H) +blobstate.o: $(LIB_H) +check-nullptr.o: $(LIB_H) +check-interrupt.o: $(LIB_H) compat-linux.o: compat/strtold.c compat/mmap-blob.c \ $(LIB_H) diff --git a/allocate.c b/allocate.c index f3d29a6..5cc52a9 100644 --- a/allocate.c +++ b/allocate.c @@ -119,7 +119,7 @@ ALLOCATOR(expression, "expressions"); ALLOCATOR(statement, "statements"); ALLOCATOR(string, "strings"); ALLOCATOR(scope, "scopes"); -__ALLOCATOR(void, 0, 1, "bytes", bytes); +__DO_ALLOCATOR(void, 0, 1, "bytes", bytes); ALLOCATOR(basic_block, "basic_block"); ALLOCATOR(entrypoint, "entrypoint"); ALLOCATOR(instruction, "instruction"); diff --git a/allocate.h b/allocate.h index 33703fe..134e056 100644 --- a/allocate.h +++ b/allocate.h @@ -31,7 +31,7 @@ extern void show_allocations(struct allocator_struct *); extern void protect_##x##_alloc(void); #define DECLARE_ALLOCATOR(x) __DECLARE_ALLOCATOR(struct x, x) -#define __ALLOCATOR(type, objsize, objalign, objname, x) \ +#define __DO_ALLOCATOR(type, objsize, objalign, objname, x) \ static struct allocator_struct x##_allocator = { \ .name = objname, \ .alignment = objalign, \ @@ -57,7 +57,10 @@ extern void show_allocations(struct allocator_struct *); protect_allocations(&x##_allocator); \ } -#define ALLOCATOR(x, n) __ALLOCATOR(struct x, sizeof(struct x), __alignof__(struct x), n, x) +#define __ALLOCATOR(t, n, x) \ + __DO_ALLOCATOR(t, sizeof(t), __alignof__(t), n, x) + +#define ALLOCATOR(x, n) __ALLOCATOR(struct x, n, x) DECLARE_ALLOCATOR(ident); DECLARE_ALLOCATOR(token); diff --git a/blobhash.c b/blobhash.c new file mode 100644 index 0000000..3db71d6 --- /dev/null +++ b/blobhash.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2006 Christopher Li + * Copyright (C) 2003 Transmeta Corp. + * 2003 Linus Torvalds + * + * Licensed under the Open Software License version 1.1 + */ +#include +#include +#include +#include +#include +#include +#include + +#include "lib.h" +#include "allocate.h" +#include "token.h" +#include "parse.h" +#include "symbol.h" +#include "expression.h" +#include "linearize.h" +#include "storage.h" +#include "checker.h" + +/* + * steal from tokenize.c + */ +#define BLOB_HASH_BITS (13) +#define BLOB_HASH_SIZE (1<> BLOB_HASH_BITS) + (hash)) & BLOB_HASH_MASK) + +ALLOCATOR(blob, "pseudo state blob"); +ALLOCATOR(bb_state, "basic block state"); +ALLOCATOR(state, "one state"); + + +static struct blob_list *blob_hash_table[BLOB_HASH_SIZE]; + +static unsigned long blob_hash(const unsigned char *data, int len) +{ + unsigned long hash; + const unsigned char *p = data; + + hash = blob_hash_init(0); + while (len--) { + unsigned int i = *p++; + hash = blob_hash_add(hash, i); + } + return blob_hash_end(hash); +} + +struct blob *lookup_blob(const unsigned char *data, int len) +{ + struct blob_list *list = blob_hash_table[blob_hash(data, len)]; + struct blob *blob; + + FOR_EACH_PTR(list, blob) { + if (blob->len == len && !memcmp(blob->data, data, len)) + return blob; + } END_FOR_EACH_PTR(blob); + return NULL; +} + +struct blob *create_hashed_blob(const unsigned char *data, int len) +{ + struct blob_list **list = blob_hash_table + blob_hash(data, len); + struct blob *blob; + FOR_EACH_PTR(*list, blob) { + if (blob->len == len && !memcmp(blob->data, data, len)) + return blob; + } END_FOR_EACH_PTR(blob); + blob = alloc_blob(len); + memcpy(blob->data, data, len); + add_blob(list, blob); + return blob; +} + +void free_blob(void) +{ + int i; + + for (i = 0; i < BLOB_HASH_SIZE; i++) { + free_ptr_list(blob_hash_table + i); + } + clear_blob_alloc(); +} + diff --git a/check-interrupt.c b/check-interrupt.c new file mode 100644 index 0000000..6f4276f --- /dev/null +++ b/check-interrupt.c @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2006 Christopher Li + * + * Licensed under the Open Software License version 1.1 + */ + +#include +#include + +#include "lib.h" +#include "allocate.h" +#include "token.h" +#include "parse.h" +#include "symbol.h" +#include "expression.h" +#include "linearize.h" +#include "storage.h" +#include "checker.h" + + +static unsigned char current; +static struct blob *hashed_state; +static struct state_list *state_stack = NULL; +static struct ptr_list *irq_enable_list; +static struct ptr_list *irq_disable_list; +static struct ptr_list *irq_restore_list; + +enum { + OP_IRQ_ENABLE = OP_LAST, + OP_IRQ_DISABLE, + OP_IRQ_RESTORE, +}; + +enum { + INTR_ENABLE, + INTR_DISABLE, +}; + +static inline void execute_enable(struct instruction *insn) +{ + if (current == INTR_ENABLE) { + warning(insn->pos, "checker function %s double enable", + show_ident(insn->bb->ep->name->ident)); + return; + } + new_state(&state_stack, ¤t, INTR_ENABLE); + hashed_state = NULL; +} + +static inline void execute_disable(struct instruction *insn) +{ + if (current == INTR_DISABLE) { + warning(insn->pos, "checker function %s double enable", + show_ident(insn->bb->ep->name->ident)); + return; + } + new_state(&state_stack, ¤t, INTR_DISABLE); + hashed_state = NULL; +} + +static inline void execute_ret(struct instruction *insn) +{ + if (current == INTR_DISABLE) + warning(insn->pos, "checker function %s exit with interrupt disabled", + show_ident(insn->bb->ep->name->ident)); +} + +static void check_bb(struct basic_block *bb) +{ + struct bb_state *bbs = bb->state; + struct instruction *insn; + int stacksize = ptr_list_size((struct ptr_list*)state_stack); + struct basic_block *child; + + if (bbs->generation) + return; + + if (!hashed_state) + hashed_state = create_hashed_blob(¤t, 1); + + /* + * Try to find out if we execute the same state before. If the state is + * same, there is not point try to execute it again. + */ + if (find_ptr_in_list((struct ptr_list*)bbs->cached_state, hashed_state)) + return; + + add_ptr_list(&bbs->cached_state, hashed_state); + + bbs->generation = 1; + + FOR_EACH_PTR(bbs->insns, insn) { + switch (insn->opcode) { + case OP_IRQ_DISABLE: + execute_disable(insn); + break; + case OP_IRQ_ENABLE: + case OP_IRQ_RESTORE: + execute_enable(insn); + break; + case OP_RET: + execute_ret(insn); + break; + } + } END_FOR_EACH_PTR(insn); + + if (bbs->noret) + goto exit_bb; + + + FOR_EACH_PTR(bb->children, child) { + check_bb(child); + } END_FOR_EACH_PTR(child); + +exit_bb: + if (ptr_list_size((struct ptr_list*)state_stack) > stacksize) { + revert_state(unsigned char, &state_stack, stacksize); + hashed_state = NULL; + } + bbs->generation = 0; +} + +static inline void scan_call_instruction(struct bb_state *bbs, struct instruction *insn) +{ + pseudo_t fn = insn->func; + struct ident *name; + + if (fn->type != PSEUDO_SYM) + return; + name = fn->sym->ident; + if (find_ptr_in_list(irq_enable_list, name)) + add_instruction(&bbs->insns, checker_instruction(insn, OP_IRQ_ENABLE, NULL)); + else if (find_ptr_in_list(irq_disable_list, name)) + add_instruction(&bbs->insns, checker_instruction(insn, OP_IRQ_DISABLE, NULL)); + else if (find_ptr_in_list(irq_restore_list, name)) + add_instruction(&bbs->insns, checker_instruction(insn, OP_IRQ_RESTORE, NULL)); +} + +static inline void scan_interrupt_insn(struct entrypoint *ep) +{ + struct basic_block *bb; + struct instruction *insn; + + FOR_EACH_PTR(ep->bbs, bb) { + struct bb_state *bbs = bb->state; + FOR_EACH_PTR(bb->insns, insn) { + if (!insn->bb) + continue; + + switch (insn->opcode) { + case OP_RET: + add_instruction(&bbs->insns, insn); + break; + case OP_INLINED_CALL: + case OP_CALL: + scan_call_instruction(bbs, insn); + break; + } + } END_FOR_EACH_PTR(insn); + } END_FOR_EACH_PTR(bb); +} + +void check_interrupt_init(void) +{ + static const char *enable[] = { + "raw_local_irq_enable", + "raw_safe_halt", + "_spin_unlock_irq", + "_read_unlock_irq", + "_write_unlock_irq", + "schedule", // XXX: is it always true? + }; + static const char *disable[] = { + "raw_local_irq_disable", + "_spin_lock_irq", + "task_rq_lock", + "_spin_lock_irqsave", + "_read_lock_irq", + "_read_lock_irqsave", + "_write_lock_irq", + "_write_lock_irqsave", + "lock_timer_base", + "lock_timer", + }; + static const char *restore[] = { + "raw_local_irq_restore", + "_spin_unlock_irqrestore", + "_read_unlock_irqrestore", + "_write_unlock_irqrestore", + }; + + irq_enable_list = build_ident_list(enable); + irq_disable_list = build_ident_list(disable); + irq_restore_list = build_ident_list(restore); +} + +void check_interrupt(struct entrypoint *ep) +{ + struct basic_block *bb; + + FOR_EACH_PTR(ep->bbs, bb) { + bb->state = alloc_bb_state(); + } END_FOR_EACH_PTR(bb); + + current = INTR_ENABLE; + hashed_state = NULL; + scan_interrupt_insn(ep); + check_bb(ep->entry->bb); +} + diff --git a/check-nullptr.c b/check-nullptr.c new file mode 100644 index 0000000..69e0432 --- /dev/null +++ b/check-nullptr.c @@ -0,0 +1,266 @@ +/* + * Copyright (C) 2006 Christopher Li + * + * Licensed under the Open Software License version 1.1 + */ + +#include + +#include "lib.h" +#include "allocate.h" +#include "token.h" +#include "parse.h" +#include "symbol.h" +#include "expression.h" +#include "linearize.h" +#include "storage.h" +#include "checker.h" + + +static int state_count = 0; +static struct ptr_list *malloc_ident_list = NULL; +static struct ptr_list *free_ident_list = NULL; +static struct ptr_list *noret_ident_list = NULL; + +static struct blob *current; +static struct blob *hashed_state; +static struct state_list *state_stack; +static void check_bb(struct basic_block *bb); + +#define alloc_state() alloc_blob(state_count) +#define reg_state(pseudo) ((current)->data[pseudo->state_index]) + +#define PTR_NULL 1 +#define PTR_NOTNULL 2 +#define PTR_FREE 4 + +enum { + OP_DEF_PTR = OP_LAST, + OP_USE_PTR, + OP_FREE_PTR +}; + +static int cmp_insn_pos(const void *a, const void *b) +{ + int a1 = ((struct instruction *)a)->offset, b1 = ((struct instruction *)b)->offset; + if (a1 == b1) + return 0; + return a1 > b1 ? 1 : -1; +} + +static void check_bb_cond(struct basic_block *bb, pseudo_t cond, unsigned value) +{ + new_state(&state_stack, ®_state(cond), value); + hashed_state = NULL; + check_bb(bb); +} + + +static inline void execute_pointer_define(struct instruction *insn) +{ + new_state(&state_stack, ®_state(insn->src), PTR_NULL | PTR_NOTNULL); + hashed_state = NULL; +} + +static inline void execute_pointer_usage(struct instruction *insn) +{ + if (reg_state(insn->src) & PTR_NULL) + warning(insn->pos, "function %s possibly using NULL pointer", + show_ident(insn->bb->ep->name->ident)); + if (reg_state(insn->src) & PTR_FREE) + warning(insn->pos, "function %s possibly using pointer after free", + show_ident(insn->bb->ep->name->ident)); +} + +static inline void execute_pointer_free(struct instruction *insn) +{ + if (reg_state(insn->src) & PTR_FREE) + warning(insn->pos, "function %s possibly double free pointer", + show_ident(insn->bb->ep->name->ident)); + new_state(&state_stack, ®_state(insn->src), reg_state(insn->src) | PTR_FREE); + hashed_state = NULL; + +} + +static void check_bb(struct basic_block *bb) +{ + struct bb_state *bbs = bb->state; + struct instruction *insn; + int stacksize = ptr_list_size((struct ptr_list*)state_stack); + + if (bbs->generation) + return; + + if (!hashed_state) + hashed_state = create_hashed_blob(current->data, state_count); + + /* + * Try to find out if we execute the same state before. If the state is + * same, there is not point try to execute it again. + */ + if (find_ptr_in_list((struct ptr_list*)bbs->cached_state, hashed_state)) + return; + + add_ptr_list(&bbs->cached_state, hashed_state); + + bbs->generation = 1; + + FOR_EACH_PTR(bbs->insns, insn) { + switch (insn->opcode) { + case OP_DEF_PTR: + execute_pointer_define(insn); + break; + case OP_USE_PTR: + execute_pointer_usage(insn); + break; + case OP_FREE_PTR: + execute_pointer_free(insn); + break; + } + } END_FOR_EACH_PTR(insn); + + if (bbs->noret) + goto exit_bb; + + if (bbs->branch) { + struct instruction *br = bbs->branch; + unsigned char orig = reg_state(br->cond); + check_bb_cond(br->bb_true, br->cond, orig & ~PTR_NULL); + check_bb_cond(br->bb_false, br->cond, orig & ~PTR_NOTNULL); + } else { + struct basic_block *child; + + FOR_EACH_PTR(bb->children, child) { + check_bb(child); + } END_FOR_EACH_PTR(child); + } + +exit_bb: + if (ptr_list_size((struct ptr_list*)state_stack) > stacksize) { + revert_state(unsigned char, &state_stack, stacksize); + hashed_state = NULL; + } + bbs->generation = 0; +} + +static void follow_pointer_usage(struct instruction *insn, pseudo_t pseudo, int index) +{ + struct pseudo_user *pu; + + pseudo->tracking = 1; + pseudo->state_index = index; + + FOR_EACH_PTR(pseudo->users, pu) { + struct instruction *useri = pu->insn; + struct basic_block *bb = useri->bb; + struct bb_state *bb_state; + if (!bb) + continue; + bb_state = bb->state; + + switch(useri->opcode) { + case OP_CAST: case OP_SCAST: case OP_PTRCAST: + /* cast a pointer does not change the pointer state, it is just alias */ + follow_pointer_usage(useri, useri->target, index); + break; + case OP_STORE: + case OP_LOAD: + if (pseudo == useri->src) { + struct instruction *use = checker_instruction(useri, OP_USE_PTR, + pseudo); + add_instruction(&bb_state->insns, use); + } + break; + case OP_CALL: + case OP_INLINED_CALL: + if (match_call_function(useri, free_ident_list)) { + struct instruction *fr = checker_instruction(useri, OP_FREE_PTR, + pseudo); + add_instruction(&bb_state->insns, fr); + } + break; + case OP_BR: + bb_state->branch = useri; + break; + case OP_SWITCH: + warning(insn->pos, "switch on pointer not implemented\n"); + break; + } + } END_FOR_EACH_PTR(pu); +} + +static inline void scan_pointer_define(struct entrypoint *ep) +{ + struct basic_block *bb; + struct instruction *insn; + pseudo_t pseudo; + + FOR_EACH_PTR(ep->accesses, pseudo) { + struct ident *ident = pseudo->sym->ident; + if (!ident) + continue; + if (find_ptr_in_list(noret_ident_list, ident)) { + FOR_EACH_FUNC_CALL(pseudo, insn) { + insn->bb->state->noret = 1; + } END_FOR_EACH_FUNC_CALL(insn); + } + if (find_ptr_in_list(malloc_ident_list, ident)) { + FOR_EACH_FUNC_CALL(pseudo, insn) { + struct instruction *def = checker_instruction(insn, OP_DEF_PTR, insn->target); + add_instruction(&insn->bb->state->insns, def); + follow_pointer_usage(insn, insn->target, state_count++); + } END_FOR_EACH_FUNC_CALL(insn); + } + + } END_FOR_EACH_PTR(pseudo); + + FOR_EACH_PTR(ep->bbs, bb) { + sort_list((struct ptr_list **)&bb->state->insns, cmp_insn_pos); + } END_FOR_EACH_PTR(bb); +} + +void check_null_ptr(struct entrypoint *ep) +{ + struct basic_block *bb; + + state_count = 0; + + FOR_EACH_PTR(ep->bbs, bb) { + bb->state = alloc_bb_state(); + } END_FOR_EACH_PTR(bb); + + scan_pointer_define(ep); + current = alloc_state(); + check_bb(ep->entry->bb); +} + +void check_null_ptr_init(void) +{ + static const char *malloc_name[] = { + "malloc", + "kmalloc_node", + "kzalloc", + "kmem_cache_alloc", + "kmem_cache_zalloc", + "kmem_cache_alloc_node", + "vmalloc", + "vmalloc_user", + "vmalloc_node", + "vmalloc_32", + "vmalloc_32_user", + }; + static const char *free_name[] = { + "free", + "kfree", + "kmem_cache_free", + "vfree", + }; + static const char *noret[] = { + "panic", + }; + + malloc_ident_list = build_ident_list(malloc_name); + free_ident_list = build_ident_list(free_name); + noret_ident_list = build_ident_list(noret); +} + diff --git a/checker.h b/checker.h new file mode 100644 index 0000000..f92b735 --- /dev/null +++ b/checker.h @@ -0,0 +1,144 @@ +#ifndef _CHECKER_H_ +#define _CHECKER_H_ + +#include +#include "allocate.h" +#include "lib.h" +#include "linearize.h" + +struct blob { + unsigned int len; + unsigned char data[0]; +}; + +struct bb_state; + +DECLARE_PTR_LIST(blob_list, struct blob); + +struct bb_state { + unsigned long generation; + struct instruction_list *insns; // instruction relate to state. + struct blob_list *cached_state; + struct instruction *branch; + unsigned noret:1; +}; + +struct state { + unsigned char *statep; + unsigned long value; +}; + +DECLARE_ALLOCATOR(blob); +DECLARE_ALLOCATOR(bb_state); +DECLARE_ALLOCATOR(state); +DECLARE_PTR_LIST(state_list, struct state); + +struct blob *lookup_blob(const unsigned char *data, int len); +struct blob *create_hashed_blob(const unsigned char *data, int len); + +static inline struct blob* alloc_blob(int len) +{ + struct blob *blob = __alloc_blob(len); + blob->len = len; + return blob; +} + +static inline void add_blob(struct blob_list **list, struct blob *blob) +{ + add_ptr_list(list, blob); +} + +static inline struct bb_state* alloc_bb_state(void) +{ + return __alloc_bb_state(0); +} + +#define new_state(list, p, v) \ + do { \ + typeof(p) __p = p; \ + struct state *__state = __alloc_state(0); \ + __state->statep = __p; \ + __state->value = *__p; \ + *__p = (v); \ + add_ptr_list(list, __state); \ + } while (0) + + +#define revert_state(type, list, size) \ + do { \ + struct state *__state; \ + struct ptr_list **__list = (struct ptr_list **)(list); \ + type *__p; \ + while (ptr_list_size(*__list) > (size)) { \ + __state = undo_ptr_list_last(__list); \ + __p = __state->statep; \ + *__p = (type)__state->value; \ + __free_state(__state); \ + } \ + } while (0) + + +#define FOR_EACH_FUNC_CALL(p, i) \ + do { \ + struct pseudo_user *__pu_##i; \ + FOR_EACH_PTR((p)->users, __pu_##i) { \ + (i) = __pu_##i->insn; \ + if (!(i)->bb) \ + continue; \ + if ((i)->opcode != OP_CALL && (i)->opcode != OP_INLINED_CALL) \ + continue; \ + if (__pu_##i->userp != &(i)->func) \ + continue; \ + +#define END_FOR_EACH_FUNC_CALL(i) \ + } END_FOR_EACH_PTR(__pu_##i); \ + } while (0) + +static inline struct instruction *checker_instruction(struct instruction *insn, int opcode, pseudo_t src) +{ + struct instruction *new = __alloc_instruction(0); + new->opcode = opcode; + new->pos = insn->pos; + new->bb = insn->bb; + new->src = src; + new->offset = find_ptr_index((struct ptr_list *)insn->bb->insns, insn); + return new; +} + +static inline struct ptr_list *__build_ident_list(const char *names[], int size) +{ + int i; + struct ptr_list *idents = NULL; + for (i = 0; i < size; i++) { + void* name = (void*) built_in_ident(names[i]); + add_ptr_list(&idents, name); + } + return idents; +} + +#define build_ident_list(x) __build_ident_list(x, sizeof x/sizeof x[0]) + +static inline int match_call_function(struct instruction *insn, struct ptr_list *list) +{ + struct ident *ident; + pseudo_t fn; + + assert(insn->opcode == OP_CALL || insn->opcode == OP_INLINED_CALL); + + fn = insn->func; + if (fn->type != PSEUDO_SYM) + return 0; + ident = fn->sym->ident; + if (!ident) + return 0; + return find_ptr_in_list(list, ident); +} + + +extern void check_null_ptr_init(void); +extern void check_null_ptr(struct entrypoint *ep); +extern void check_interrupt(struct entrypoint *ep); +extern void check_interrupt_init(void); + +#endif + diff --git a/ctags.c b/ctags.c new file mode 100644 index 0000000..17dd1c1 --- /dev/null +++ b/ctags.c @@ -0,0 +1,207 @@ +/* + * Sparse Ctags + * + * Ctags generates tags from preprocessing results. + * + * Copyright (C) 2006 Christopher Li + * + * Licensed under the Open Software License version 1.1 + */ +#include +#include +#include +#include +#include + +#include "parse.h" +#include "scope.h" + +static struct symbol_list *taglist = NULL; + +static void examine_symbol(struct symbol *sym); + +#define MAX(_x,_y) ((_x) > (_y) ? (_x) : (_y)) + +static int cmp_sym(const void *m, const void *n) +{ + struct ident *a = ((struct symbol *)m)->ident; + struct ident *b = ((struct symbol *)n)->ident; + int ret = strncmp(a->name, b->name, MAX(a->len, b->len)); + if (!ret) { + struct position a = ((struct symbol *)m)->pos; + struct position b = ((struct symbol *)n)->pos; + + ret = strcmp(stream_name(a.stream), stream_name(b.stream)); + if (!ret) + return a.line < b.line; + } + return ret; +} + +static void show_tag_header(FILE *fp) +{ + fprintf(fp, "!_TAG_FILE_FORMAT\t2\t/extended format; --format=1 will not append ;\" to lines/\n"); + fprintf(fp, "!_TAG_FILE_SORTED\t0\t/0=unsorted, 1=sorted, 2=foldcase/\n"); + fprintf(fp, "!_TAG_PROGRAM_AUTHOR\tChristopher Li\t/sparse@chrisli.org/\n"); + fprintf(fp, "!_TAG_PROGRAM_NAME\tSparse Ctags\t//\n"); + fprintf(fp, "!_TAG_PROGRAM_URL\thttp://kernel.org/pub/linux/kernel/people/josh/sparse/\t/official site/\n"); + fprintf(fp, "!_TAG_PROGRAM_VERSION\t0.01\t//\n"); +} + +static inline void show_symbol_tag(FILE *fp, struct symbol *sym) +{ + fprintf(fp, "%s\t%s\t%d;\"\t%c\tfile:\n", show_ident(sym->ident), + stream_name(sym->pos.stream), sym->pos.line, (int)sym->kind); +} + +static void show_tags(struct symbol_list *list) +{ + struct symbol *sym; + struct ident *ident = NULL; + struct position pos = {}; + static const char *filename; + FILE *fp; + + if (!list) + return; + + fp = fopen("tags", "w"); + if (!fp) { + perror("open tags file"); + return; + } + show_tag_header(fp); + FOR_EACH_PTR(list, sym) { + if (ident == sym->ident && pos.line == sym->pos.line && + !strcmp(filename, stream_name(sym->pos.stream))) + continue; + + show_symbol_tag(fp, sym); + ident = sym->ident; + pos = sym->pos; + filename = stream_name(sym->pos.stream); + } END_FOR_EACH_PTR(sym); + fclose(fp); +} + +static inline void add_tag(struct symbol *sym) +{ + if (sym->ident && !sym->visited) { + sym->visited = 1; + add_symbol(&taglist, sym); + } +} + +static inline void examine_members(struct symbol_list *list) +{ + struct symbol *sym; + + FOR_EACH_PTR(list, sym) { + sym->kind = 'm'; + examine_symbol(sym); + } END_FOR_EACH_PTR(sym); +} + +static void examine_symbol(struct symbol *sym) +{ + struct symbol *base = sym; + + if (!sym || sym->visited) + return; + if (sym->ident && sym->ident->reserved) + return; + + add_tag(sym); + base = sym->ctype.base_type; + + switch (sym->type) { + case SYM_NODE: + if (base->type == SYM_FN) + sym->kind = 'f'; + examine_symbol(base); + break; + case SYM_STRUCT: + sym->kind = 's'; + examine_members(sym->symbol_list); + break; + case SYM_UNION: + sym->kind = 'u'; + examine_members(sym->symbol_list); + break; + case SYM_ENUM: + sym->kind = 'e'; + case SYM_PTR: + case SYM_TYPEOF: + case SYM_BITFIELD: + case SYM_FN: + case SYM_ARRAY: + examine_symbol(sym->ctype.base_type); + break; + case SYM_BASETYPE: + break; + + default: + die("unknown symbol %s namespace:%d type:%d\n", show_ident(sym->ident), + sym->namespace, sym->type); + } + if (!sym->kind) + sym->kind = 'v'; + return; +} + +static void examine_namespace(struct symbol *sym) +{ + if (sym->visited) + return; + if (sym->ident && sym->ident->reserved) + return; + + switch(sym->namespace) { + case NS_LABEL: + sym->kind = 'l'; + break; + case NS_PREPROCESSOR: + break; + case NS_MACRO: + case NS_UNDEF: + sym->kind = 'd'; + break; + case NS_TYPEDEF: + sym->kind = 't'; + case NS_SYMBOL: + case NS_STRUCT: + examine_symbol(sym); + break; + default: + die("unknown namespace %d symbol:%s type:%d\n", sym->namespace, + show_ident(sym->ident), sym->type); + } + add_tag(sym); +} + +static inline void examine_symbol_list(struct symbol_list *list) +{ + struct symbol *sym; + + if (!list) + return; + FOR_EACH_PTR(list, sym) { + examine_namespace(sym); + } END_FOR_EACH_PTR(sym); +} + +int main(int argc, char **argv) +{ + struct string_list *filelist = NULL; + char *file; + + examine_symbol_list(sparse_initialize(argc, argv, &filelist)); + FOR_EACH_PTR_NOTAG(filelist, file) { + sparse(file); + examine_symbol_list(file_scope->symbols); + } END_FOR_EACH_PTR_NOTAG(file); + examine_symbol_list(global_scope->symbols); + sort_list((struct ptr_list **)&taglist, cmp_sym); + show_tags(taglist); + return 0; +} diff --git a/dissect.c b/dissect.c index 018cebb..471eac0 100644 --- a/dissect.c +++ b/dissect.c @@ -42,7 +42,7 @@ static void do_sym_list(struct symbol_list *list); static struct symbol *base_type(struct symbol *sym), - *do_initializer(struct symbol *type, struct expression* expr), + *do_initializer(struct symbol *type, struct expression *expr), *do_expression(usage_t mode, struct expression *expr), *do_statement(usage_t mode, struct statement *stmt); @@ -497,7 +497,7 @@ static struct symbol *do_statement(usage_t mode, struct statement *stmt) return ret; } -static struct symbol *do_initializer(struct symbol *type, struct expression* expr) +static struct symbol *do_initializer(struct symbol *type, struct expression *expr) { struct symbol *m_type; struct expression *m_expr; diff --git a/dissect.h b/dissect.h index ffac806..3b72b89 100644 --- a/dissect.h +++ b/dissect.h @@ -18,13 +18,13 @@ struct reporter { - void (*r_symdef)(struct symbol*); + void (*r_symdef)(struct symbol *); - void (*r_symbol)(unsigned, struct position*, struct symbol*); - void (*r_member)(unsigned, struct position*, struct symbol*, struct symbol*); + void (*r_symbol)(unsigned, struct position *, struct symbol *); + void (*r_member)(unsigned, struct position *, struct symbol *, struct symbol *); }; -extern void dissect(struct symbol_list*, struct reporter*); +extern void dissect(struct symbol_list *, struct reporter *); #define MK_IDENT(s) ({ \ static struct { \ diff --git a/evaluate.c b/evaluate.c index ca49ed0..4ba4731 100644 --- a/evaluate.c +++ b/evaluate.c @@ -74,6 +74,7 @@ static struct symbol *evaluate_string(struct expression *expr) sym->array_size = alloc_const_expression(expr->pos, length); sym->bit_size = bits_in_char * length; sym->ctype.alignment = 1; + sym->string = 1; sym->ctype.modifiers = MOD_STATIC; sym->ctype.base_type = array; sym->initializer = initstr; @@ -179,7 +180,7 @@ left: static int same_cast_type(struct symbol *orig, struct symbol *new) { - return orig->bit_size == new->bit_size && orig->bit_offset == orig->bit_offset; + return orig->bit_size == new->bit_size && orig->bit_offset == new->bit_offset; } static struct symbol *base_type(struct symbol *node, unsigned long *modp, unsigned long *asp) @@ -2790,7 +2791,7 @@ struct symbol *evaluate_statement(struct statement *stmt) * Then, evaluate each statement, making the type of the * compound statement be the type of the last statement */ - type = NULL; + type = evaluate_statement(stmt->args); FOR_EACH_PTR(stmt->stmts, s) { type = evaluate_statement(s); } END_FOR_EACH_PTR(s); diff --git a/example.c b/example.c index fb0ad1a..e4679ae 100644 --- a/example.c +++ b/example.c @@ -14,7 +14,7 @@ #include "storage.h" #include "target.h" -static const char* opcodes[] = { +static const char *opcodes[] = { [OP_BADOP] = "bad_op", /* Fn entrypoint */ @@ -1946,6 +1946,7 @@ int main(int argc, char **argv) char *file; compile(sparse_initialize(argc, argv, &filelist)); + dbg_dead = 1; FOR_EACH_PTR_NOTAG(filelist, file) { compile(sparse(file)); } END_FOR_EACH_PTR_NOTAG(file); diff --git a/expand.c b/expand.c index 90f7f36..7a0a764 100644 --- a/expand.c +++ b/expand.c @@ -29,8 +29,8 @@ /* Random cost numbers */ #define SIDE_EFFECTS 10000 /* The expression has side effects */ #define UNSAFE 100 /* The expression may be "infinitely costly" due to exceptions */ -#define SELECT_COST 20 /* Cut-off for turning a conditional into a select */ -#define BRANCH_COST 10 /* Cost of a conditional branch */ +#define SELECT_COST 0 /* Cut-off for turning a conditional into a select */ +#define BRANCH_COST 0 /* Cost of a conditional branch */ static int expand_expression(struct expression *); static int expand_statement(struct statement *); @@ -1053,9 +1053,9 @@ static int expand_compound(struct statement *stmt) if (stmt->ret) expand_symbol(stmt->ret); - cost = 0; - last = NULL; - statements = 0; + last = stmt->args; + cost = expand_statement(last); + statements = last != NULL; FOR_EACH_PTR(stmt->stmts, s) { statements++; last = s; diff --git a/flow.c b/flow.c index 00bc807..fa4764a 100644 --- a/flow.c +++ b/flow.c @@ -195,6 +195,7 @@ try_to_rewrite_target: if (bb_list_size(target->parents) != 1) return retval; insert_branch(target, insn, final); + kill_instruction(insn); return 1; } @@ -229,27 +230,27 @@ int simplify_flow(struct entrypoint *ep) return simplify_branch_nodes(ep); } -static inline void concat_user_list(struct pseudo_ptr_list *src, struct pseudo_ptr_list **dst) +static inline void concat_user_list(struct pseudo_user_list *src, struct pseudo_user_list **dst) { concat_ptr_list((struct ptr_list *)src, (struct ptr_list **)dst); } void convert_instruction_target(struct instruction *insn, pseudo_t src) { - pseudo_t target, *usep; - + pseudo_t target; + struct pseudo_user *pu; /* * Go through the "insn->users" list and replace them all.. */ target = insn->target; if (target == src) return; - FOR_EACH_PTR(target->users, usep) { - if (*usep != VOID) { - assert(*usep == target); - *usep = src; + FOR_EACH_PTR(target->users, pu) { + if (*pu->userp != VOID) { + assert(*pu->userp == target); + *pu->userp = src; } - } END_FOR_EACH_PTR(usep); + } END_FOR_EACH_PTR(pu); concat_user_list(target->users, &src->users); target->users = NULL; } @@ -360,7 +361,7 @@ found_dominator: phi = alloc_phi(parent, one->target, one->size); phi->ident = phi->ident ? : pseudo->ident; add_instruction(&parent->insns, br); - use_pseudo(phi, add_pseudo(dominators, phi)); + use_pseudo(insn, phi, add_pseudo(dominators, phi)); } END_FOR_EACH_PTR(parent); return 1; } @@ -592,7 +593,8 @@ void check_access(struct instruction *insn) static void simplify_one_symbol(struct entrypoint *ep, struct symbol *sym) { - pseudo_t pseudo, src, *pp; + pseudo_t pseudo, src; + struct pseudo_user *pu; struct instruction *def; unsigned long mod; int all, stores, complex; @@ -614,9 +616,9 @@ static void simplify_one_symbol(struct entrypoint *ep, struct symbol *sym) def = NULL; stores = 0; complex = 0; - FOR_EACH_PTR(pseudo->users, pp) { + FOR_EACH_PTR(pseudo->users, pu) { /* We know that the symbol-pseudo use is the "src" in the instruction */ - struct instruction *insn = container(pp, struct instruction, src); + struct instruction *insn = pu->insn; switch (insn->opcode) { case OP_STORE: @@ -639,7 +641,7 @@ static void simplify_one_symbol(struct entrypoint *ep, struct symbol *sym) warning(sym->pos, "symbol '%s' pseudo used in unexpected way", show_ident(sym->ident)); } complex |= insn->offset; - } END_FOR_EACH_PTR(pp); + } END_FOR_EACH_PTR(pu); if (complex) goto complex_def; @@ -655,13 +657,13 @@ static void simplify_one_symbol(struct entrypoint *ep, struct symbol *sym) if (def) src = def->target; - FOR_EACH_PTR(pseudo->users, pp) { - struct instruction *insn = container(pp, struct instruction, src); + FOR_EACH_PTR(pseudo->users, pu) { + struct instruction *insn = pu->insn; if (insn->opcode == OP_LOAD) { check_access(insn); convert_load_instruction(insn, src); } - } END_FOR_EACH_PTR(pp); + } END_FOR_EACH_PTR(pu); /* Turn the store into a no-op */ kill_store(def); @@ -671,29 +673,29 @@ multi_def: complex_def: external_visibility: all = 1; - FOR_EACH_PTR_REVERSE(pseudo->users, pp) { - struct instruction *insn = container(pp, struct instruction, src); + FOR_EACH_PTR_REVERSE(pseudo->users, pu) { + struct instruction *insn = pu->insn; if (insn->opcode == OP_LOAD) all &= find_dominating_stores(pseudo, insn, ++bb_generation, !mod); - } END_FOR_EACH_PTR_REVERSE(pp); + } END_FOR_EACH_PTR_REVERSE(pu); /* If we converted all the loads, remove the stores. They are dead */ if (all && !mod) { - FOR_EACH_PTR(pseudo->users, pp) { - struct instruction *insn = container(pp, struct instruction, src); + FOR_EACH_PTR(pseudo->users, pu) { + struct instruction *insn = pu->insn; if (insn->opcode == OP_STORE) kill_store(insn); - } END_FOR_EACH_PTR(pp); + } END_FOR_EACH_PTR(pu); } else { /* * If we couldn't take the shortcut, see if we can at least kill some * of them.. */ - FOR_EACH_PTR(pseudo->users, pp) { - struct instruction *insn = container(pp, struct instruction, src); + FOR_EACH_PTR(pseudo->users, pu) { + struct instruction *insn = pu->insn; if (insn->opcode == OP_STORE) kill_dominated_stores(pseudo, insn, ++bb_generation, insn->bb, !mod, 0); - } END_FOR_EACH_PTR(pp); + } END_FOR_EACH_PTR(pu); if (!(mod & (MOD_NONLOCAL | MOD_STATIC))) { struct basic_block *bb; @@ -709,11 +711,11 @@ external_visibility: void simplify_symbol_usage(struct entrypoint *ep) { - struct symbol *sym; + pseudo_t pseudo; - FOR_EACH_PTR(ep->accesses, sym) { - simplify_one_symbol(ep, sym); - } END_FOR_EACH_PTR(sym); + FOR_EACH_PTR(ep->accesses, pseudo) { + simplify_one_symbol(ep, pseudo->sym); + } END_FOR_EACH_PTR(pseudo); } static void mark_bb_reachable(struct basic_block *bb, unsigned long generation) @@ -985,7 +987,7 @@ out: replace_bb_in_list(&child->parents, bb, parent, 0); } END_FOR_EACH_PTR(child); - delete_last_instruction(&parent->insns); + kill_instruction(delete_last_instruction(&parent->insns)); FOR_EACH_PTR(bb->insns, insn) { if (insn->bb) { assert(insn->bb == bb); diff --git a/inline.c b/inline.c index 77adfab..4a9fca4 100644 --- a/inline.c +++ b/inline.c @@ -443,8 +443,9 @@ void copy_statement(struct statement *src, struct statement *dst) FOR_EACH_PTR(src->stmts, stmt) { add_statement(&dst->stmts, copy_one_statement(stmt)); } END_FOR_EACH_PTR(stmt); - + dst->args = copy_one_statement(src->args); dst->ret = copy_symbol(src->pos, src->ret); + dst->inline_fn = src->inline_fn; } static struct symbol *create_copy_symbol(struct symbol *orig) @@ -489,6 +490,7 @@ int inline_function(struct expression *expr, struct symbol *sym) } if (fn->expanding) return 0; + fn->expanding = 1; name_list = fn->arguments; @@ -517,13 +519,14 @@ int inline_function(struct expression *expr, struct symbol *sym) } END_FOR_EACH_PTR(arg); FINISH_PTR_LIST(name); + copy_statement(fn->inline_stmt, stmt); + if (arg_decl) { struct statement *decl = alloc_statement(expr->pos, STMT_DECLARATION); decl->declaration = arg_decl; - add_statement(&stmt->stmts, decl); + stmt->args = decl; } - - copy_statement(fn->inline_stmt, stmt); + stmt->inline_fn = sym; unset_replace_list(fn_symbol_list); diff --git a/lib.c b/lib.c index 51c415d..e4d0f48 100644 --- a/lib.c +++ b/lib.c @@ -190,9 +190,18 @@ int Waddress_space = 1; int Wenum_mismatch = 1; int Wdo_while = 1; int Wuninitialized = 1; +int Wmalloc = 1; +int Winterrupt = 1; + +int dbg_entry = 0; +int dbg_dead = 0; + int preprocess_only; char *include; -int include_fd = -1; + +#define CMDLINE_INCLUDE 20 +int cmdline_include_nr = 0; +struct cmdline_include cmdline_include[CMDLINE_INCLUDE]; void add_pre_buffer(const char *fmt, ...) @@ -234,14 +243,6 @@ static char **handle_switch_E(char *arg, char **next) return next; } -static char **handle_switch_v(char *arg, char **next) -{ - do { - verbose++; - } while (*++arg == 'v'); - return next; -} - static char **handle_switch_I(char *arg, char **next) { char *path = arg+1; @@ -262,26 +263,26 @@ static char **handle_switch_I(char *arg, char **next) return next; } -static char **handle_switch_i(char *arg, char **next) +static void add_cmdline_include(char *filename) { - if (*next && !strcmp(arg, "include")) { - char *name = *++next; - int fd = open(name, O_RDONLY); - - include_fd = fd; - include = name; - if (fd < 0) - perror(name); + int fd = open(filename, O_RDONLY); + if (fd < 0) { + perror(filename); + return; } - if (*next && !strcmp(arg, "imacros")) { - char *name = *++next; - int fd = open(name, O_RDONLY); + if (cmdline_include_nr >= CMDLINE_INCLUDE) + die("too many include files for %s\n", filename); + cmdline_include[cmdline_include_nr].filename = filename; + cmdline_include[cmdline_include_nr].fd = fd; + cmdline_include_nr++; +} - include_fd = fd; - include = name; - if (fd < 0) - perror(name); - } +static char **handle_switch_i(char *arg, char **next) +{ + if (*next && !strcmp(arg, "include")) + add_cmdline_include(*++next); + else if (*next && !strcmp(arg, "imacros")) + add_cmdline_include(*++next); else if (*next && !strcmp(arg, "isystem")) { char *path = *++next; if (!path) @@ -340,6 +341,8 @@ static const struct warning { { "enum-mismatch", &Wenum_mismatch }, { "do-while", &Wdo_while }, { "uninitialized", &Wuninitialized }, + { "malloc", &Wmalloc}, + { "interrupt", &Winterrupt}, }; enum { @@ -349,14 +352,14 @@ enum { }; -static char **handle_switch_W(char *arg, char **next) +static char **handle_onoff_switch(char *arg, char **next, const struct warning warnings[], int n) { int flag = WARNING_ON; char *p = arg + 1; unsigned i; if (!strcmp(p, "all")) { - for (i = 0; i < sizeof(warnings) / sizeof(warnings[0]); i++) { + for (i = 0; i < n; i++) { if (*warnings[i].flag != WARNING_FORCE_OFF) *warnings[i].flag = WARNING_ON; } @@ -370,7 +373,7 @@ static char **handle_switch_W(char *arg, char **next) flag = WARNING_FORCE_OFF; } - for (i = 0; i < sizeof(warnings) / sizeof(warnings[0]); i++) { + for (i = 0; i < n; i++) { if (!strcmp(p,warnings[i].name)) { *warnings[i].flag = flag; return next; @@ -378,26 +381,66 @@ static char **handle_switch_W(char *arg, char **next) } // Unknown. + return NULL; +} + +static char **handle_switch_W(char *arg, char **next) +{ + char ** ret = handle_onoff_switch(arg, next, warnings, sizeof warnings/sizeof warnings[0]); + if (ret) + return ret; + + // Unknown. return next; } -static void handle_switch_W_finalize(void) +static struct warning debugs[] = { + { "entry", &dbg_entry}, + { "dead", &dbg_dead}, +}; + + +static char **handle_switch_v(char *arg, char **next) +{ + char ** ret = handle_onoff_switch(arg, next, debugs, sizeof debugs/sizeof debugs[0]); + if (ret) + return ret; + + // Unknown. + do { + verbose++; + } while (*++arg == 'v'); + return next; +} + + +static void handle_onoff_switch_finalize(const struct warning warnings[], int n) { unsigned i; - for (i = 0; i < sizeof(warnings) / sizeof(warnings[0]); i++) { + for (i = 0; i < n; i++) { if (*warnings[i].flag == WARNING_FORCE_OFF) *warnings[i].flag = WARNING_OFF; } } +static void handle_switch_W_finalize(void) +{ + handle_onoff_switch_finalize(warnings, sizeof(warnings) / sizeof(warnings[0])); +} + +static void handle_switch_v_finalize(void) +{ + handle_onoff_switch_finalize(debugs, sizeof(debugs) / sizeof(debugs[0])); +} + static char **handle_switch_U(char *arg, char **next) { const char *name = arg + 1; add_pre_buffer ("#undef %s\n", name); return next; } - + static char **handle_switch_O(char *arg, char **next) { int level = 1; @@ -446,7 +489,7 @@ static char **handle_dirafter(char *arg, char **next) struct switches { const char *name; - char **(*fn)(char *, char**); + char **(*fn)(char *, char **); }; char **handle_switch(char *arg, char **next) @@ -623,12 +666,14 @@ static struct symbol_list *sparse_file(const char *filename) static struct symbol_list *sparse_initial(void) { struct token *token; + int i; // Prepend any "include" file to the stream. // We're in global scope, it will affect all files! token = NULL; - if (include_fd >= 0) - token = tokenize(include, include_fd, NULL, includepath); + for (i = cmdline_include_nr - 1; i >= 0; i--) + token = tokenize(cmdline_include[i].filename, cmdline_include[i].fd, + token, includepath); // Prepend the initial built-in stream token = tokenize_buffer(pre_buffer, pre_buffer_size, token); @@ -656,6 +701,7 @@ struct symbol_list *sparse_initialize(int argc, char **argv, struct string_list add_ptr_list_notag(filelist, arg); } handle_switch_W_finalize(); + handle_switch_v_finalize(); list = NULL; if (!ptr_list_empty(filelist)) { diff --git a/lib.h b/lib.h index e133c16..bd98678 100644 --- a/lib.h +++ b/lib.h @@ -33,6 +33,15 @@ struct position { noexpand:1; }; +struct cmdline_include { + char *filename; + int fd; +}; + +extern struct cmdline_include cmdline_include[]; +extern int cmdline_include_nr; + + struct ident; struct token; struct symbol; @@ -87,39 +96,44 @@ extern int Wshadow; extern int Wcast_truncate; extern int Wdo_while; extern int Wuninitialized; +extern int Wmalloc; +extern int Winterrupt; + +extern int dbg_entry; +extern int dbg_dead; extern void declare_builtin_functions(void); extern void create_builtin_stream(void); -extern struct symbol_list *sparse_initialize(int argc, char **argv, struct string_list** files); +extern struct symbol_list *sparse_initialize(int argc, char **argv, struct string_list **files); extern struct symbol_list *__sparse(char *filename); extern struct symbol_list *sparse(char *filename); -static inline int symbol_list_size(struct symbol_list* list) +static inline int symbol_list_size(struct symbol_list *list) { return ptr_list_size((struct ptr_list *)(list)); } -static inline int statement_list_size(struct statement_list* list) +static inline int statement_list_size(struct statement_list *list) { return ptr_list_size((struct ptr_list *)(list)); } -static inline int expression_list_size(struct expression_list* list) +static inline int expression_list_size(struct expression_list *list) { return ptr_list_size((struct ptr_list *)(list)); } -static inline int instruction_list_size(struct instruction_list* list) +static inline int instruction_list_size(struct instruction_list *list) { return ptr_list_size((struct ptr_list *)(list)); } -static inline int pseudo_list_size(struct pseudo_list* list) +static inline int pseudo_list_size(struct pseudo_list *list) { return ptr_list_size((struct ptr_list *)(list)); } -static inline int bb_list_size(struct basic_block_list* list) +static inline int bb_list_size(struct basic_block_list *list) { return ptr_list_size((struct ptr_list *)(list)); } diff --git a/linearize.c b/linearize.c index 8a8a2d3..de0bf9b 100644 --- a/linearize.c +++ b/linearize.c @@ -27,16 +27,18 @@ pseudo_t linearize_expression(struct entrypoint *ep, struct expression *expr); static pseudo_t add_binary_op(struct entrypoint *ep, struct symbol *ctype, int op, pseudo_t left, pseudo_t right); static pseudo_t add_setval(struct entrypoint *ep, struct symbol *ctype, struct expression *val); -static void linearize_one_symbol(struct entrypoint *ep, struct symbol *sym); +static pseudo_t linearize_one_symbol(struct entrypoint *ep, struct symbol *sym); struct access_data; static pseudo_t add_load(struct entrypoint *ep, struct access_data *); -pseudo_t linearize_initializer(struct entrypoint *ep, struct expression *initializer, struct access_data *); +static pseudo_t linearize_initializer(struct entrypoint *ep, struct expression *initializer, struct access_data *); struct pseudo void_pseudo = {}; static struct position current_pos; +ALLOCATOR(pseudo_user, "pseudo_user"); + static struct instruction *alloc_instruction(int opcode, int size) { struct instruction * insn = __alloc_instruction(0); @@ -70,7 +72,7 @@ static struct basic_block *alloc_basic_block(struct entrypoint *ep, struct posit return bb; } -static struct multijmp* alloc_multijmp(struct basic_block *target, int begin, int end) +static struct multijmp *alloc_multijmp(struct basic_block *target, int begin, int end) { struct multijmp *multijmp = __alloc_multijmp(0); multijmp->target = target; @@ -114,14 +116,16 @@ const char *show_pseudo(pseudo_t pseudo) } expr = sym->initializer; snprintf(buf, 64, "", sym); - switch (expr->type) { - case EXPR_VALUE: - snprintf(buf, 64, "", expr->value); - break; - case EXPR_STRING: - return show_string(expr->string); - default: - break; + if (expr) { + switch (expr->type) { + case EXPR_VALUE: + snprintf(buf, 64, "", expr->value); + break; + case EXPR_STRING: + return show_string(expr->string); + default: + break; + } } break; } @@ -152,7 +156,7 @@ const char *show_pseudo(pseudo_t pseudo) return buf; } -static const char* opcodes[] = { +static const char *opcodes[] = { [OP_BADOP] = "bad_op", /* Fn entrypoint */ @@ -222,6 +226,7 @@ static const char* opcodes[] = { [OP_SCAST] = "scast", [OP_FPCAST] = "fpcast", [OP_PTRCAST] = "ptrcast", + [OP_INLINED_CALL] = "# call", [OP_CALL] = "call", [OP_VANEXT] = "va_next", [OP_VAARG] = "va_arg", @@ -268,7 +273,7 @@ static char *show_asm(char *buf, struct instruction *insn) const char *show_instruction(struct instruction *insn) { int opcode = insn->opcode; - static char buffer[1024]; + static char buffer[4096]; char *buf; buf = buffer; @@ -395,6 +400,7 @@ const char *show_instruction(struct instruction *insn) case OP_STORE: case OP_SNOP: buf += sprintf(buf, "%s -> %d[%s]", show_pseudo(insn->target), insn->offset, show_pseudo(insn->src)); break; + case OP_INLINED_CALL: case OP_CALL: { struct pseudo *arg; if (insn->target && insn->target != VOID) @@ -453,6 +459,9 @@ const char *show_instruction(struct instruction *insn) default: break; } + + if (buf >= buffer + sizeof buffer) + die("instruction buffer overflowed %d\n", buf - buffer); do { --buf; } while (*buf == ' '); *++buf = 0; return buffer; @@ -517,12 +526,12 @@ void show_bb(struct basic_block *bb) static void show_symbol_usage(pseudo_t pseudo) { + struct pseudo_user *pu; + if (pseudo) { - pseudo_t *pp; - FOR_EACH_PTR(pseudo->users, pp) { - struct instruction *insn = container(pp, struct instruction, src); - printf("\t%s\n", show_instruction(insn)); - } END_FOR_EACH_PTR(pp); + FOR_EACH_PTR(pseudo->users, pu) { + printf("\t%s\n", show_instruction(pu->insn)); + } END_FOR_EACH_PTR(pu); } } @@ -667,15 +676,15 @@ void insert_select(struct basic_block *bb, struct instruction *br, struct instru select->bb = bb; assert(br->cond); - use_pseudo(br->cond, &select->src1); + use_pseudo(select, br->cond, &select->src1); target = phi_node->target; assert(target->def == phi_node); select->target = target; target->def = select; - use_pseudo(true, &select->src2); - use_pseudo(false, &select->src3); + use_pseudo(select, true, &select->src2); + use_pseudo(select, false, &select->src3); add_instruction(&bb->insns, select); add_instruction(&bb->insns, br); @@ -711,7 +720,7 @@ static void add_branch(struct entrypoint *ep, struct expression *expr, pseudo_t if (bb_reachable(bb)) { br = alloc_instruction(OP_BR, 0); - use_pseudo(cond, &br->cond); + use_pseudo(br, cond, &br->cond); br->bb_true = bb_true; br->bb_false = bb_false; add_bb(&bb_true->parents, bb); @@ -735,11 +744,11 @@ pseudo_t alloc_pseudo(struct instruction *def) static void clear_symbol_pseudos(struct entrypoint *ep) { - struct symbol *sym; + pseudo_t pseudo; - FOR_EACH_PTR(ep->accesses, sym) { - sym->pseudo = NULL; - } END_FOR_EACH_PTR(sym); + FOR_EACH_PTR(ep->accesses, pseudo) { + pseudo->sym->pseudo = NULL; + } END_FOR_EACH_PTR(pseudo); } static pseudo_t symbol_pseudo(struct entrypoint *ep, struct symbol *sym) @@ -757,7 +766,7 @@ static pseudo_t symbol_pseudo(struct entrypoint *ep, struct symbol *sym) pseudo->sym = sym; pseudo->ident = sym->ident; sym->pseudo = pseudo; - add_symbol(&ep->accesses, sym); + add_pseudo(&ep->accesses, pseudo); } /* Symbol pseudos have neither nr, usage nor def */ return pseudo; @@ -809,7 +818,7 @@ pseudo_t alloc_phi(struct basic_block *source, pseudo_t pseudo, int size) phi->nr = ++nr; phi->def = insn; - use_pseudo(pseudo, &insn->phi_src); + use_pseudo(insn, pseudo, &insn->phi_src); insn->bb = source; insn->target = phi; add_instruction(&source->insns, insn); @@ -905,7 +914,7 @@ static pseudo_t add_load(struct entrypoint *ep, struct access_data *ad) insn->target = new; insn->offset = ad->offset; - use_pseudo(ad->address, &insn->src); + use_pseudo(insn, ad->address, &insn->src); add_one_insn(ep, insn); return new; } @@ -917,8 +926,8 @@ static void add_store(struct entrypoint *ep, struct access_data *ad, pseudo_t va if (bb_reachable(bb)) { struct instruction *store = alloc_typed_instruction(OP_STORE, ad->source_type); store->offset = ad->offset; - use_pseudo(value, &store->target); - use_pseudo(ad->address, &store->src); + use_pseudo(store, value, &store->target); + use_pseudo(store, ad->address, &store->src); add_one_insn(ep, store); } } @@ -950,8 +959,8 @@ static pseudo_t add_binary_op(struct entrypoint *ep, struct symbol *ctype, int o struct instruction *insn = alloc_typed_instruction(op, ctype); pseudo_t target = alloc_pseudo(insn); insn->target = target; - use_pseudo(left, &insn->src1); - use_pseudo(right, &insn->src2); + use_pseudo(insn, left, &insn->src1); + use_pseudo(insn, right, &insn->src2); add_one_insn(ep, insn); return target; } @@ -972,7 +981,7 @@ static pseudo_t add_symbol_address(struct entrypoint *ep, struct symbol *sym) pseudo_t target = alloc_pseudo(insn); insn->target = target; - use_pseudo(symbol_pseudo(ep, sym), &insn->symbol); + use_pseudo(insn, symbol_pseudo(ep, sym), &insn->symbol); add_one_insn(ep, insn); return target; } @@ -1026,7 +1035,7 @@ static pseudo_t add_uniop(struct entrypoint *ep, struct expression *expr, int op pseudo_t new = alloc_pseudo(insn); insn->target = new; - use_pseudo(src, &insn->src1); + use_pseudo(insn, src, &insn->src1); add_one_insn(ep, insn); return new; } @@ -1040,7 +1049,7 @@ static pseudo_t linearize_slice(struct entrypoint *ep, struct expression *expr) insn->target = new; insn->from = expr->r_bitpos; insn->len = expr->r_nrbits; - use_pseudo(pre, &insn->base); + use_pseudo(insn, pre, &insn->base); add_one_insn(ep, insn); return new; } @@ -1122,7 +1131,7 @@ static pseudo_t cast_pseudo(struct entrypoint *ep, pseudo_t src, struct symbol * result = alloc_pseudo(insn); insn->target = result; insn->orig_type = from; - use_pseudo(src, &insn->src); + use_pseudo(insn, src, &insn->src); add_one_insn(ep, insn); return result; } @@ -1193,7 +1202,7 @@ static pseudo_t linearize_call_expression(struct entrypoint *ep, struct expressi FOR_EACH_PTR(expr->args, arg) { pseudo_t new = linearize_expression(ep, arg); - use_pseudo(new, add_pseudo(&insn->arguments, new)); + use_pseudo(insn, new, add_pseudo(&insn->arguments, new)); } END_FOR_EACH_PTR(arg); fn = expr->fn; @@ -1213,7 +1222,7 @@ static pseudo_t linearize_call_expression(struct entrypoint *ep, struct expressi } else { call = linearize_expression(ep, fn); } - use_pseudo(call, &insn->func); + use_pseudo(insn, call, &insn->func); retval = VOID; if (expr->ctype != &void_ctype) retval = alloc_pseudo(insn); @@ -1286,9 +1295,9 @@ static pseudo_t linearize_select(struct entrypoint *ep, struct expression *expr) insn = alloc_typed_instruction(OP_SEL, expr->ctype); if (!expr->cond_true) true = cond; - use_pseudo(cond, &insn->src1); - use_pseudo(true, &insn->src2); - use_pseudo(false, &insn->src3); + use_pseudo(insn, cond, &insn->src1); + use_pseudo(insn, true, &insn->src2); + use_pseudo(insn, false, &insn->src3); res = alloc_pseudo(insn); insn->target = res; @@ -1308,8 +1317,8 @@ static pseudo_t add_join_conditional(struct entrypoint *ep, struct expression *e return phi1; phi_node = alloc_typed_instruction(OP_PHI, expr->ctype); - use_pseudo(phi1, add_pseudo(&phi_node->phi_list, phi1)); - use_pseudo(phi2, add_pseudo(&phi_node->phi_list, phi2)); + use_pseudo(phi_node, phi1, add_pseudo(&phi_node->phi_list, phi1)); + use_pseudo(phi_node, phi2, add_pseudo(&phi_node->phi_list, phi2)); phi_node->target = target = alloc_pseudo(phi_node); add_one_insn(ep, phi_node); return target; @@ -1480,7 +1489,7 @@ static pseudo_t linearize_position(struct entrypoint *ep, struct expression *pos return linearize_initializer(ep, init_expr, ad); } -pseudo_t linearize_initializer(struct entrypoint *ep, struct expression *initializer, struct access_data *ad) +static pseudo_t linearize_initializer(struct entrypoint *ep, struct expression *initializer, struct access_data *ad) { switch (initializer->type) { case EXPR_INITIALIZER: { @@ -1498,6 +1507,7 @@ pseudo_t linearize_initializer(struct entrypoint *ep, struct expression *initial ad->source_type = base_type(initializer->ctype); ad->result_type = initializer->ctype; linearize_store_gen(ep, value, ad); + return value; } } @@ -1588,21 +1598,23 @@ pseudo_t linearize_expression(struct entrypoint *ep, struct expression *expr) return VOID; } -static void linearize_one_symbol(struct entrypoint *ep, struct symbol *sym) +static pseudo_t linearize_one_symbol(struct entrypoint *ep, struct symbol *sym) { struct access_data ad = { NULL, }; + pseudo_t value; if (!sym || !sym->initializer || sym->initialized) - return; + return VOID; /* We need to output these puppies some day too.. */ if (sym->ctype.modifiers & (MOD_STATIC | MOD_TOPLEVEL)) - return; + return VOID; sym->initialized = 1; ad.address = symbol_pseudo(ep, sym); - linearize_initializer(ep, sym->initializer, &ad); + value = linearize_initializer(ep, sym->initializer, &ad); finish_address_gen(ep, &ad); + return value; } static pseudo_t linearize_compound_statement(struct entrypoint *ep, struct statement *stmt) @@ -1630,6 +1642,29 @@ static pseudo_t linearize_compound_statement(struct entrypoint *ep, struct state } return phi_node->target; } + + return pseudo; +} + +static pseudo_t linearize_inlined_call(struct entrypoint *ep, struct statement *stmt) +{ + struct instruction *insn = alloc_instruction(OP_INLINED_CALL, 0); + struct statement *args = stmt->args; + pseudo_t pseudo; + + if (args) { + struct symbol *sym; + + concat_symbol_list(args->declaration, &ep->syms); + FOR_EACH_PTR(args->declaration, sym) { + pseudo_t value = linearize_one_symbol(ep, sym); + use_pseudo(insn, value, add_pseudo(&insn->arguments, value)); + } END_FOR_EACH_PTR(sym); + } + + insn->target = pseudo = linearize_compound_statement(ep, stmt); + use_pseudo(insn, symbol_pseudo(ep, stmt->inline_fn), &insn->func); + add_one_insn(ep, insn); return pseudo; } @@ -1652,9 +1687,9 @@ static pseudo_t linearize_range(struct entrypoint *ep, struct statement *stmt) { struct instruction *insn = alloc_instruction(OP_RANGE, 0); - use_pseudo(linearize_expression(ep, stmt->range_expression), &insn->src1); - use_pseudo(linearize_expression(ep, stmt->range_low), &insn->src2); - use_pseudo(linearize_expression(ep, stmt->range_high), &insn->src3); + use_pseudo(insn, linearize_expression(ep, stmt->range_expression), &insn->src1); + use_pseudo(insn, linearize_expression(ep, stmt->range_low), &insn->src2); + use_pseudo(insn, linearize_expression(ep, stmt->range_high), &insn->src3); add_one_insn(ep, insn); return VOID; } @@ -1670,7 +1705,7 @@ static void add_asm_input(struct entrypoint *ep, struct instruction *insn, struc rule->ident = ident; rule->constraint = constraint; - use_pseudo(pseudo, &rule->pseudo); + use_pseudo(insn, pseudo, &rule->pseudo); add_ptr_list(&insn->asm_rules->inputs, rule); } @@ -1688,7 +1723,7 @@ static void add_asm_output(struct entrypoint *ep, struct instruction *insn, stru rule = __alloc_asm_constraint(0); rule->ident = ident; rule->constraint = constraint; - use_pseudo(pseudo, &rule->pseudo); + use_pseudo(insn, pseudo, &rule->pseudo); add_ptr_list(&insn->asm_rules->outputs, rule); } @@ -1847,7 +1882,7 @@ pseudo_t linearize_statement(struct entrypoint *ep, struct statement *stmt) } phi = alloc_phi(active, src, type_size(expr->ctype)); phi->ident = &return_ident; - use_pseudo(phi, add_pseudo(&phi_node->phi_list, phi)); + use_pseudo(phi_node, phi, add_pseudo(&phi_node->phi_list, phi)); } add_goto(ep, bb_return); return VOID; @@ -1897,7 +1932,7 @@ pseudo_t linearize_statement(struct entrypoint *ep, struct statement *stmt) pseudo = linearize_expression(ep, expr); goto_ins = alloc_instruction(OP_COMPUTEDGOTO, 0); - use_pseudo(pseudo, &goto_ins->target); + use_pseudo(goto_ins, pseudo, &goto_ins->target); add_one_insn(ep, goto_ins); FOR_EACH_PTR(stmt->target_list, sym) { @@ -1913,6 +1948,8 @@ pseudo_t linearize_statement(struct entrypoint *ep, struct statement *stmt) } case STMT_COMPOUND: + if (stmt->inline_fn) + return linearize_inlined_call(ep, stmt); return linearize_compound_statement(ep, stmt); /* @@ -1956,7 +1993,7 @@ pseudo_t linearize_statement(struct entrypoint *ep, struct statement *stmt) break; switch_ins = alloc_instruction(OP_SWITCH, 0); - use_pseudo(pseudo, &switch_ins->cond); + use_pseudo(switch_ins, pseudo, &switch_ins->cond); add_one_insn(ep, switch_ins); finish_block(ep); @@ -2086,7 +2123,7 @@ static struct entrypoint *linearize_fn(struct symbol *sym, struct symbol *base_t struct instruction *insn = alloc_typed_instruction(OP_RET, ret_type); if (type_size(ret_type) > 0) - use_pseudo(result, &insn->src); + use_pseudo(insn, result, &insn->src); add_one_insn(ep, insn); } @@ -2132,7 +2169,8 @@ repeat: } /* Finally, add deathnotes to pseudos now that we have them */ - track_pseudo_death(ep); + if (dbg_dead) + track_pseudo_death(ep); return ep; } diff --git a/linearize.h b/linearize.h index 517ec67..f4f4964 100644 --- a/linearize.h +++ b/linearize.h @@ -2,6 +2,7 @@ #define LINEARIZE_H #include "lib.h" +#include "allocate.h" #include "token.h" #include "parse.h" #include "symbol.h" @@ -9,6 +10,15 @@ struct instruction; DECLARE_PTR_LIST(pseudo_ptr_list, pseudo_t); +struct pseudo_user { + struct instruction *insn; + pseudo_t *userp; +}; + +DECLARE_ALLOCATOR(pseudo_user); +DECLARE_PTR_LIST(pseudo_user_list, struct pseudo_user); + + enum pseudo_type { PSEUDO_VOID, PSEUDO_REG, @@ -20,8 +30,10 @@ enum pseudo_type { struct pseudo { int nr; - enum pseudo_type type; - struct pseudo_ptr_list *users; + enum pseudo_type type:8; + unsigned state_index:16; + unsigned tracking:1; + struct pseudo_user_list *users; struct ident *ident; union { struct symbol *sym; @@ -186,6 +198,7 @@ enum opcode { OP_SCAST, OP_FPCAST, OP_PTRCAST, + OP_INLINED_CALL, OP_CALL, OP_VANEXT, OP_VAARG, @@ -202,14 +215,19 @@ enum opcode { /* Needed to translate SSA back to normal form */ OP_COPY, + OP_LAST, }; struct basic_block_list; struct instruction_list; +struct bb_state; struct basic_block { struct position pos; - unsigned long generation; + union { + unsigned long generation; + struct bb_state *state; + }; int context; struct entrypoint *ep; struct basic_block_list *parents; /* sources */ @@ -268,16 +286,29 @@ static inline void add_pseudo_ptr(pseudo_t *ptr, struct pseudo_ptr_list **list) add_ptr_list(list, ptr); } +static inline void add_pseudo_user_ptr(struct pseudo_user *user, struct pseudo_user_list **list) +{ + add_ptr_list(list, user); +} + static inline int has_use_list(pseudo_t p) { return (p && p->type != PSEUDO_VOID && p->type != PSEUDO_VAL); } -static inline void use_pseudo(pseudo_t p, pseudo_t *pp) +static inline struct pseudo_user *alloc_pseudo_user(struct instruction *insn, pseudo_t *pp) +{ + struct pseudo_user *user = __alloc_pseudo_user(0); + user->userp = pp; + user->insn = insn; + return user; +} + +static inline void use_pseudo(struct instruction *insn, pseudo_t p, pseudo_t *pp) { *pp = p; if (has_use_list(p)) - add_pseudo_ptr(pp, &p->users); + add_pseudo_user_ptr(alloc_pseudo_user(insn, pp), &p->users); } static inline void remove_bb_from_list(struct basic_block_list **list, struct basic_block *entry, int count) @@ -294,7 +325,7 @@ static inline void replace_bb_in_list(struct basic_block_list **list, struct entrypoint { struct symbol *name; struct symbol_list *syms; - struct symbol_list *accesses; + struct pseudo_list *accesses; struct basic_block_list *bbs; struct basic_block *active; struct instruction *entry; diff --git a/memops.c b/memops.c index bdecf14..027f05e 100644 --- a/memops.c +++ b/memops.c @@ -59,31 +59,19 @@ found_dominator: phi = alloc_phi(parent, one->target, one->size); phi->ident = phi->ident ? : one->target->ident; add_instruction(&parent->insns, br); - use_pseudo(phi, add_pseudo(dominators, phi)); + use_pseudo(insn, phi, add_pseudo(dominators, phi)); } END_FOR_EACH_PTR(parent); return 1; } -/* - * FIXME! This is wrong. Since we now distribute out the OP_SYMADDR, - * we can no longer really use "container()" to get from a user to - * the instruction that uses it. - * - * This happens to work, simply because the likelihood of the - * (possibly non-instruction) containing the right bitpattern - * in the right place is pretty low. But this is still wrong. - * - * We should make symbol-pseudos count non-load/store usage, - * or something. - */ static int address_taken(pseudo_t pseudo) { - pseudo_t *usep; - FOR_EACH_PTR(pseudo->users, usep) { - struct instruction *insn = container(usep, struct instruction, src); + struct pseudo_user *pu; + FOR_EACH_PTR(pseudo->users, pu) { + struct instruction *insn = pu->insn; if (insn->bb && (insn->opcode != OP_LOAD || insn->opcode != OP_STORE)) return 1; - } END_FOR_EACH_PTR(usep); + } END_FOR_EACH_PTR(pu); return 0; } diff --git a/parse.c b/parse.c index dc20812..6c81b08 100644 --- a/parse.c +++ b/parse.c @@ -35,6 +35,90 @@ struct statement_list *function_computed_goto_list; static struct token *statement(struct token *token, struct statement **tree); +static struct token *struct_specifier(struct token *token, struct ctype *ctype); +static struct token *union_specifier(struct token *token, struct ctype *ctype); +static struct token *enum_specifier(struct token *token, struct ctype *ctype); +static struct token *attribute_specifier(struct token *token, struct ctype *ctype); +static struct token *typeof_specifier(struct token *token, struct ctype *ctype); + +static struct symbol_op typeof_op = { + S_OP_TYPEOF, + .specifier = typeof_specifier, +}; + +static struct symbol_op attribute_op = { + S_OP_ATTRIBUTE, + .specifier = attribute_specifier, +}; + +static struct symbol_op struct_op = { + S_OP_TYPE_SPECIFIER, + .specifier = struct_specifier, +}; + +static struct symbol_op union_op = { + S_OP_TYPE_SPECIFIER, + .specifier = union_specifier, +}; + +static struct symbol_op enum_op = { + S_OP_TYPE_SPECIFIER, + .specifier = enum_specifier, +}; + +static struct keyword { + const char *name; + unsigned long modifiers; + struct symbol_op *op; +} keyword_init_table[] = { + /* Type qualifiers */ + { "const", MOD_CONST }, + { "__const", MOD_CONST }, + { "__const__", MOD_CONST }, + { "volatile", MOD_VOLATILE }, + { "__volatile", MOD_VOLATILE }, + { "__volatile__", MOD_VOLATILE }, + + /* Typedef.. */ + { "typedef", MOD_TYPEDEF }, + + /* Extended types */ + { "typeof", .op = &typeof_op }, + { "__typeof", .op = &typeof_op }, + { "__typeof__", .op = &typeof_op }, + +#if 0 + { "attribute", 0, &attribute_op }, +#endif + { "__attribute", .op = &attribute_op }, + { "__attribute__", .op = &attribute_op }, + + + { "struct", .op = &struct_op }, + { "union", .op = &union_op }, + { "enum", .op = &enum_op }, + + { "inline", MOD_INLINE }, + { "__inline", MOD_INLINE }, + { "__inline__", MOD_INLINE }, + + /* Ignored for now.. */ + { "restrict", }, + { "__restrict", }, +}; + +void init_parser(int stream) +{ + int i; + for (i = 0; i < sizeof keyword_init_table/sizeof keyword_init_table[0]; i++) { + struct keyword *ptr = keyword_init_table + i; + struct symbol *sym = create_symbol(stream, ptr->name, SYM_NODE, NS_TYPEDEF); + sym->ident->reserved = 1; + sym->ctype.modifiers = ptr->modifiers; + sym->op = ptr->op; + } +} + // Add a symbol to the list of function-local symbols static void fn_local_symbol(struct symbol *sym) { @@ -70,7 +154,51 @@ struct statement *alloc_statement(struct position pos, int type) static struct token *struct_declaration_list(struct token *token, struct symbol_list **list); -static struct symbol * indirect(struct position pos, struct ctype *ctype, int type) +static int apply_modifiers(struct position pos, struct ctype *ctype) +{ + struct symbol *base; + + while ((base = ctype->base_type)) { + switch (base->type) { + case SYM_FN: + case SYM_ENUM: + case SYM_ARRAY: + case SYM_BITFIELD: + case SYM_PTR: + ctype = &base->ctype; + continue; + } + break; + } + + /* Turn the "virtual types" into real types with real sizes etc */ + if (ctype->base_type == &int_type) { + ctype->base_type = ctype_integer(ctype->modifiers); + ctype->modifiers &= ~MOD_SPECIFIER; + } else if (ctype->base_type == &fp_type) { + ctype->base_type = ctype_fp(ctype->modifiers); + ctype->modifiers &= ~MOD_SPECIFIER; + } + + if (ctype->modifiers & MOD_BITWISE) { + struct symbol *type; + ctype->modifiers &= ~(MOD_BITWISE | MOD_SPECIFIER); + if (!is_int_type(ctype->base_type)) { + sparse_error(pos, "invalid modifier"); + return 1; + } + type = alloc_symbol(pos, SYM_BASETYPE); + *type = *ctype->base_type; + type->ctype.base_type = ctype->base_type; + type->type = SYM_RESTRICT; + type->ctype.modifiers &= ~MOD_SPECIFIER; + ctype->base_type = type; + create_fouled(type); + } + return 0; +} + +static struct symbol * alloc_indirect_symbol(struct position pos, struct ctype *ctype, int type) { struct symbol *sym = alloc_symbol(pos, type); @@ -161,11 +289,17 @@ static struct token *parse_struct_declaration(struct token *token, struct symbol return struct_declaration_list(token, &sym->symbol_list); } -static struct token *struct_or_union_specifier(enum type type, struct token *token, struct ctype *ctype) +static struct token *struct_specifier(struct token *token, struct ctype *ctype) +{ + return struct_union_enum_specifier(SYM_STRUCT, token, ctype, parse_struct_declaration); +} + +static struct token *union_specifier(struct token *token, struct ctype *ctype) { - return struct_union_enum_specifier(type, token, ctype, parse_struct_declaration); + return struct_union_enum_specifier(SYM_UNION, token, ctype, parse_struct_declaration); } + typedef struct { int x; unsigned long long y; @@ -698,13 +832,13 @@ static void apply_ctype(struct position pos, struct ctype *thistype, struct ctyp static void check_modifiers(struct position *pos, struct symbol *s, unsigned long mod) { unsigned long banned, wrong; - unsigned long this_mod = s->ctype.modifiers; const unsigned long BANNED_SIZE = MOD_LONG | MOD_LONGLONG | MOD_SHORT; const unsigned long BANNED_SIGN = MOD_SIGNED | MOD_UNSIGNED; + unsigned int type = s->op ? s->op->type : 0; - if (this_mod & (MOD_STRUCTOF | MOD_UNIONOF | MOD_ENUMOF)) + if (type & S_OP_TYPE_SPECIFIER) banned = BANNED_SIZE | BANNED_SIGN; - else if (this_mod & MOD_SPECIALBITS) + else if (type) banned = 0; else if (s->ctype.base_type == &fp_type) banned = BANNED_SIGN; @@ -724,7 +858,6 @@ static void check_modifiers(struct position *pos, struct symbol *s, unsigned lon modifier_string (wrong)); } - static struct token *declaration_specifiers(struct token *next, struct ctype *ctype, int qual) { struct token *token; @@ -734,6 +867,7 @@ static struct token *declaration_specifiers(struct token *next, struct ctype *ct struct ident *ident; struct symbol *s, *type; unsigned long mod; + unsigned int optype; next = token->next; if (token_type(token) != TOKEN_IDENT) @@ -745,19 +879,11 @@ static struct token *declaration_specifiers(struct token *next, struct ctype *ct break; thistype = s->ctype; mod = thistype.modifiers; - if (qual && (mod & ~(MOD_ATTRIBUTE | MOD_CONST | MOD_VOLATILE))) + optype = s->op ? s->op->type : 0; + if (qual && (optype & (S_OP_TYPE_SPECIFIER | S_OP_TYPEOF))) break; - if (mod & MOD_SPECIALBITS) { - if (mod & MOD_STRUCTOF) - next = struct_or_union_specifier(SYM_STRUCT, next, &thistype); - else if (mod & MOD_UNIONOF) - next = struct_or_union_specifier(SYM_UNION, next, &thistype); - else if (mod & MOD_ENUMOF) - next = enum_specifier(next, &thistype); - else if (mod & MOD_ATTRIBUTE) - next = attribute_specifier(next, &thistype); - else if (mod & MOD_TYPEOF) - next = typeof_specifier(next, &thistype); + if (s->op && s->op->specifier) { + next = s->op->specifier(next, &thistype); mod = thistype.modifiers; } type = thistype.base_type; @@ -778,7 +904,6 @@ static struct token *declaration_specifiers(struct token *next, struct ctype *ct apply_ctype(token->pos, &thistype, ctype); } - /* Turn the "virtual types" into real types with real sizes etc */ if (!ctype->base_type) { struct symbol *base = &incomplete_ctype; @@ -791,28 +916,6 @@ static struct token *declaration_specifiers(struct token *next, struct ctype *ct base = &int_type; ctype->base_type = base; } - if (ctype->base_type == &int_type) { - ctype->base_type = ctype_integer(ctype->modifiers); - ctype->modifiers &= ~MOD_SPECIFIER; - } else if (ctype->base_type == &fp_type) { - ctype->base_type = ctype_fp(ctype->modifiers); - ctype->modifiers &= ~MOD_SPECIFIER; - } - if (ctype->modifiers & MOD_BITWISE) { - struct symbol *type; - ctype->modifiers &= ~(MOD_BITWISE | MOD_SPECIFIER); - if (!is_int_type(ctype->base_type)) { - sparse_error(token->pos, "invalid modifier"); - return token; - } - type = alloc_symbol(token->pos, SYM_BASETYPE); - *type = *ctype->base_type; - type->ctype.base_type = ctype->base_type; - type->type = SYM_RESTRICT; - type->ctype.modifiers &= ~MOD_SPECIFIER; - ctype->base_type = type; - create_fouled(type); - } return token; } @@ -888,13 +991,13 @@ static struct token *direct_declarator(struct token *token, struct symbol *decl, continue; } - sym = indirect(token->pos, ctype, SYM_FN); + sym = alloc_indirect_symbol(token->pos, ctype, SYM_FN); token = parameter_type_list(next, sym, p); token = expect(token, ')', "in function declarator"); continue; } if (token->special == '[') { - struct symbol *array = indirect(token->pos, ctype, SYM_ARRAY); + struct symbol *array = alloc_indirect_symbol(token->pos, ctype, SYM_ARRAY); token = abstract_array_declarator(token->next, array); token = expect(token, ']', "in abstract_array_declarator"); ctype = &array->ctype; @@ -910,7 +1013,7 @@ static struct token *pointer(struct token *token, struct ctype *ctype) unsigned long modifiers; struct symbol *base_type; - modifiers = ctype->modifiers & ~(MOD_TYPEDEF | MOD_ATTRIBUTE); + modifiers = ctype->modifiers & ~MOD_TYPEDEF; base_type = ctype->base_type; ctype->modifiers = modifiers; @@ -947,14 +1050,14 @@ static struct token *handle_bitfield(struct token *token, struct symbol *decl) struct symbol *bitfield; long long width; - if (!is_int_type(ctype->base_type)) { + if (ctype->base_type != &int_type && !is_int_type(ctype->base_type)) { sparse_error(token->pos, "invalid bitfield specifier for type %s.", show_typename(ctype->base_type)); // Parse this to recover gracefully. return conditional_expression(token->next, &expr); } - bitfield = indirect(token->pos, ctype, SYM_BITFIELD); + bitfield = alloc_indirect_symbol(token->pos, ctype, SYM_BITFIELD); token = conditional_expression(token->next, &expr); width = get_expression_value(expr); bitfield->bit_size = width; @@ -968,15 +1071,16 @@ static struct token *handle_bitfield(struct token *token, struct symbol *decl) width = -1; } else if (decl->ident) { struct symbol *base_type = bitfield->ctype.base_type; - int is_signed = !(base_type->ctype.modifiers & MOD_UNSIGNED); + struct symbol *bitfield_type = base_type == &int_type ? bitfield : base_type; + int is_signed = !(bitfield_type->ctype.modifiers & MOD_UNSIGNED); if (Wone_bit_signed_bitfield && width == 1 && is_signed) { // Valid values are either {-1;0} or {0}, depending on integer // representation. The latter makes for very efficient code... sparse_error(token->pos, "dubious one-bit signed bitfield"); } if (Wdefault_bitfield_sign && - base_type->type != SYM_ENUM && - !(base_type->ctype.modifiers & MOD_EXPLICITLY_SIGNED) && + bitfield_type->type != SYM_ENUM && + !(bitfield_type->ctype.modifiers & MOD_EXPLICITLY_SIGNED) && is_signed) { // The sign of bitfields is unspecified by default. sparse_error(token->pos, "dubious bitfield without explicit `signed' or `unsigned'"); @@ -1001,6 +1105,7 @@ static struct token *declaration_list(struct token *token, struct symbol_list ** token = handle_bitfield(token, decl); token = handle_attributes(token, &decl->ctype); } + apply_modifiers(token->pos, &decl->ctype); add_symbol(list, decl); if (!match_op(token, ',')) break; @@ -1012,7 +1117,8 @@ static struct token *declaration_list(struct token *token, struct symbol_list ** static struct token *struct_declaration_list(struct token *token, struct symbol_list **list) { while (!match_op(token, '}')) { - token = declaration_list(token, list); + if (!match_op(token, ';')) + token = declaration_list(token, list); if (!match_op(token, ';')) { sparse_error(token->pos, "expected ; at end of declaration"); break; @@ -1034,6 +1140,7 @@ static struct token *parameter_declaration(struct token *token, struct symbol ** *tree = sym; token = declarator(token, sym, &ident); sym->ident = ident; + apply_modifiers(token->pos, &sym->ctype); return token; } @@ -1042,7 +1149,9 @@ struct token *typename(struct token *token, struct symbol **p) struct symbol *sym = alloc_symbol(token->pos, SYM_NODE); *p = sym; token = declaration_specifiers(token, &sym->ctype, 0); - return declarator(token, sym, NULL); + token = declarator(token, sym, NULL); + apply_modifiers(token->pos, &sym->ctype); + return token; } static struct token *expression_statement(struct token *token, struct expression **tree) @@ -1740,6 +1849,21 @@ static struct token *parse_k_r_arguments(struct token *token, struct symbol *dec return parse_function_body(token, decl, list); } +static struct token *toplevel_asm_declaration(struct token *token, struct symbol_list **list) +{ + struct symbol *anon = alloc_symbol(token->pos, SYM_NODE); + struct symbol *fn = alloc_symbol(token->pos, SYM_FN); + struct statement *stmt; + + anon->ctype.base_type = fn; + stmt = alloc_statement(token->pos, STMT_NONE); + fn->stmt = stmt; + + token = parse_asm(token->next, stmt); + + add_symbol(list, anon); + return token; +} struct token *external_declaration(struct token *token, struct symbol_list **list) { @@ -1750,26 +1874,15 @@ struct token *external_declaration(struct token *token, struct symbol_list **lis int is_typedef; /* Top-level inline asm? */ - if (match_idents(token, &asm_ident, &__asm___ident, &__asm_ident, NULL)) { - struct symbol *anon = alloc_symbol(token->pos, SYM_NODE); - struct symbol *fn = alloc_symbol(token->pos, SYM_FN); - struct statement *stmt; - - anon->ctype.base_type = fn; - stmt = alloc_statement(token->pos, STMT_NONE); - fn->stmt = stmt; - - token = parse_asm(token->next, stmt); - - add_symbol(list, anon); - return token; - } + if (match_idents(token, &asm_ident, &__asm___ident, &__asm_ident, NULL)) + return toplevel_asm_declaration(token, list); /* Parse declaration-specifiers, if any */ token = declaration_specifiers(token, &ctype, 0); decl = alloc_symbol(token->pos, SYM_NODE); decl->ctype = ctype; token = declarator(token, decl, &ident); + apply_modifiers(token->pos, &decl->ctype); /* Just a type declaration? */ if (!ident) @@ -1830,6 +1943,7 @@ struct token *external_declaration(struct token *token, struct symbol_list **lis decl->ctype = ctype; token = declaration_specifiers(token, &decl->ctype, 1); token = declarator(token, decl, &ident); + apply_modifiers(token->pos, &decl->ctype); if (!ident) { sparse_error(token->pos, "expected identifier name in type definition"); return token; diff --git a/parse.h b/parse.h index f43d431..609910f 100644 --- a/parse.h +++ b/parse.h @@ -55,6 +55,8 @@ struct statement { struct /* compound_struct */ { struct statement_list *stmts; struct symbol *ret; + struct symbol *inline_fn; + struct statement *args; }; struct /* labeled_struct */ { struct symbol *label_identifier; @@ -131,5 +133,6 @@ extern struct symbol *ctype_fp(unsigned long spec); extern void copy_statement(struct statement *src, struct statement *dst); extern int inline_function(struct expression *expr, struct symbol *sym); extern void uninline(struct symbol *sym); +extern void init_parser(int); #endif /* PARSE_H */ diff --git a/ptrlist.c b/ptrlist.c index 467a108..aa36999 100644 --- a/ptrlist.c +++ b/ptrlist.c @@ -10,6 +10,11 @@ #include #include "ptrlist.h" +#include "allocate.h" +#include "compat.h" + +__DECLARE_ALLOCATOR(struct ptr_list, ptrlist); +__ALLOCATOR(struct ptr_list, "ptr list", ptrlist); int ptr_list_size(struct ptr_list *head) { @@ -72,14 +77,14 @@ restart: if (!entry->nr) { struct ptr_list *prev; if (next == entry) { - free(entry); + __free_ptrlist(entry); *listp = NULL; return; } prev = entry->prev; prev->next = next; next->prev = prev; - free(entry); + __free_ptrlist(entry); if (entry == head) { *listp = next; head = next; @@ -95,7 +100,7 @@ restart: void split_ptr_list_head(struct ptr_list *head) { int old = head->nr, nr = old / 2; - struct ptr_list *newlist = malloc(sizeof(*newlist)); + struct ptr_list *newlist = __alloc_ptrlist(0); struct ptr_list *next = head->next; old -= nr; @@ -122,9 +127,7 @@ void **__add_ptr_list(struct ptr_list **listp, void *ptr, unsigned long tag) ptr = (void *)(tag | (unsigned long)ptr); if (!list || (nr = (last = list->prev)->nr) >= LIST_NODE_NR) { - struct ptr_list *newlist = malloc(sizeof(*newlist)); - assert(newlist); - memset(newlist, 0, sizeof(*newlist)); + struct ptr_list *newlist = __alloc_ptrlist(0); if (!list) { newlist->next = newlist; newlist->prev = newlist; @@ -214,7 +217,7 @@ void * delete_ptr_list_last(struct ptr_list **head) last->prev->next = first; if (last == first) *head = NULL; - free(last); + __free_ptrlist(last); } return ptr; } @@ -238,8 +241,34 @@ void __free_ptr_list(struct ptr_list **listp) while (list) { tmp = list; list = list->next; - free(tmp); + __free_ptrlist(tmp); } *listp = NULL; } + +int find_ptr_in_list(struct ptr_list* list, void *ptr) +{ + void *p; + FOR_EACH_PTR(list, p) { + if (p == ptr) + return 1; + } END_FOR_EACH_PTR(p); + return 0; +} + +int find_ptr_index(struct ptr_list* list, void *ptr) +{ + void *p; + int i = 0; + FOR_EACH_PTR(list, p) { + if (p == ptr) + return i; + i++; + } END_FOR_EACH_PTR(p); + return -1; +} + + + + diff --git a/ptrlist.h b/ptrlist.h index 8a58bad..c94a18b 100644 --- a/ptrlist.h +++ b/ptrlist.h @@ -45,6 +45,8 @@ extern void concat_ptr_list(struct ptr_list *a, struct ptr_list **b); extern void __free_ptr_list(struct ptr_list **); extern int ptr_list_size(struct ptr_list *); extern int linearize_ptr_list(struct ptr_list *, void **, int); +extern int find_ptr_in_list(struct ptr_list* list, void *ptr); +extern int find_ptr_index(struct ptr_list* list, void *ptr); /* * Hey, who said that you can't do overloading in C? @@ -56,7 +58,7 @@ extern int linearize_ptr_list(struct ptr_list *, void **, int); MKTYPE(*(list), (CHECK_TYPE(*(list),(entry)),__add_ptr_list((struct ptr_list **)(list), (entry), (tag)))) #define add_ptr_list_notag(list,entry) \ MKTYPE(*(list), (CHECK_TYPE(*(list),(entry)),__add_ptr_list((struct ptr_list **)(list), \ - (void*)((unsigned long)(entry) & ~3UL), \ + (void *)((unsigned long)(entry) & ~3UL), \ (unsigned long)(entry) & 3))) #define add_ptr_list(list,entry) \ add_ptr_list_tag(list,entry,0) diff --git a/show-parse.c b/show-parse.c index 2701d17..708a8ca 100644 --- a/show-parse.c +++ b/show-parse.c @@ -56,11 +56,12 @@ static void do_debug_symbol(struct symbol *sym, int indent) if (!sym) return; - fprintf(stderr, "%.*s%s%3d:%lu %lx %s (as: %d) %p (%s:%d:%d)\n", + fprintf(stderr, "%.*s%s%3d:%lu %s %s (as: %d) %p (%s:%d:%d) %s\n", indent, indent_string, typestr[sym->type], sym->bit_size, sym->ctype.alignment, - sym->ctype.modifiers, show_ident(sym->ident), sym->ctype.as, - sym, stream_name(sym->pos.stream), sym->pos.line, sym->pos.pos); + modifier_string(sym->ctype.modifiers), show_ident(sym->ident), sym->ctype.as, + sym, stream_name(sym->pos.stream), sym->pos.line, sym->pos.pos, + builtin_typename(sym) ?: ""); i = 0; FOR_EACH_PTR(sym->ctype.contexts, context) { /* FIXME: should print context expression */ @@ -98,7 +99,7 @@ const char *modifier_string(unsigned long mod) const char *res,**ptr, *names[] = { "auto", "register", "static", "extern", "const", "volatile", "[signed]", "[unsigned]", - "[char]", "[short]", "[long]", "[long]", + "[char]", "[short]", "[long]", "[long long]", "[typdef]", "[structof]", "[unionof]", "[enum]", "[typeof]", "[attribute]", "inline", "[addressable]", "[nocast]", "[noderef]", "[accessed]", "[toplevel]", @@ -171,53 +172,74 @@ static void append(struct type_name *name, const char *fmt, ...) name->end += n; } +static struct ctype_name { + struct symbol *sym; + const char *name; +} typenames[] = { + { & char_ctype, "char" }, + { &schar_ctype, "signed char" }, + { &uchar_ctype, "unsigned char" }, + { & short_ctype, "short" }, + { &sshort_ctype, "signed short" }, + { &ushort_ctype, "unsigned short" }, + { & int_ctype, "int" }, + { &sint_ctype, "signed int" }, + { &uint_ctype, "unsigned int" }, + { &slong_ctype, "signed long" }, + { & long_ctype, "long" }, + { &ulong_ctype, "unsigned long" }, + { & llong_ctype, "long long" }, + { &sllong_ctype, "signed long long" }, + { &ullong_ctype, "unsigned long long" }, + + { &void_ctype, "void" }, + { &bool_ctype, "bool" }, + { &string_ctype, "string" }, + + { &float_ctype, "float" }, + { &double_ctype, "double" }, + { &ldouble_ctype,"long double" }, + { &incomplete_ctype, "incomplete type" }, + { &int_type, "abstract int" }, + { &fp_type, "abstract fp" }, + { &label_ctype, "label type" }, + { &bad_ctype, "bad type" }, +}; + +const char *builtin_typename(struct symbol *sym) +{ + int i; + + for (i = 0; i < sizeof(typenames)/sizeof(typenames[0]); i++) + if (typenames[i].sym == sym) + return typenames[i].name; + return NULL; +} + +const char *builtin_ctypename(struct ctype *ctype) +{ + int i; + + for (i = 0; i < sizeof(typenames)/sizeof(typenames[0]); i++) + if (&typenames[i].sym->ctype == ctype) + return typenames[i].name; + return NULL; +} + static void do_show_type(struct symbol *sym, struct type_name *name) { - int i, modlen; + int modlen; const char *mod; - static struct ctype_name { - struct symbol *sym; - const char *name; - } typenames[] = { - { & char_ctype, "char" }, - { &schar_ctype, "signed char" }, - { &uchar_ctype, "unsigned char" }, - { & short_ctype, "short" }, - { &sshort_ctype, "signed short" }, - { &ushort_ctype, "unsigned short" }, - { & int_ctype, "int" }, - { &sint_ctype, "signed int" }, - { &uint_ctype, "unsigned int" }, - { &slong_ctype, "signed long" }, - { & long_ctype, "long" }, - { &ulong_ctype, "unsigned long" }, - { & llong_ctype, "long long" }, - { &sllong_ctype, "signed long long" }, - { &ullong_ctype, "unsigned long long" }, - - { &void_ctype, "void" }, - { &bool_ctype, "bool" }, - { &string_ctype, "string" }, - - { &float_ctype, "float" }, - { &double_ctype, "double" }, - { &ldouble_ctype,"long double" }, - { &incomplete_ctype, "incomplete type" }, - { &label_ctype, "label type" }, - { &bad_ctype, "bad type" }, - }; - + const char *typename; if (!sym) return; - for (i = 0; i < sizeof(typenames)/sizeof(typenames[0]); i++) { - if (typenames[i].sym == sym) { - int len = strlen(typenames[i].name); - *--name->start = ' '; - name->start -= len; - memcpy(name->start, typenames[i].name, len); - return; - } + if ((typename = builtin_typename(sym))) { + int len = strlen(typename); + *--name->start = ' '; + name->start -= len; + memcpy(name->start, typename, len); + return; } /* Prepend */ @@ -463,6 +485,10 @@ int show_statement(struct statement *stmt) struct statement *s; int last = 0; + if (stmt->inline_fn) { + show_statement(stmt->args); + printf("\tbegin_inline \t%s\n", show_ident(stmt->inline_fn->ident)); + } FOR_EACH_PTR(stmt->stmts, s) { last = show_statement(s); } END_FOR_EACH_PTR(s); @@ -474,6 +500,8 @@ int show_statement(struct statement *stmt) last = new_pseudo(); printf("\tld.%d\t\tv%d,[v%d]\n", bits, last, addr); } + if (stmt->inline_fn) + printf("\tend_inlined\t%s\n", show_ident(stmt->inline_fn->ident)); return last; } @@ -628,7 +656,7 @@ static int show_call_expression(struct expression *expr) } } if (direct) { - printf("\tcall\t\t%s\n", show_ident(direct->ident)); + printf("\tcall\t\t%s:%p\n", show_ident(direct->ident), direct); } else { fncall = show_expression(fn); printf("\tcall\t\t*v%d\n", fncall); diff --git a/simplify.c b/simplify.c index a8b736b..26a72f4 100644 --- a/simplify.c +++ b/simplify.c @@ -146,10 +146,27 @@ static int clean_up_phi(struct instruction *insn) return if_convert_phi(insn); } +int delete_pseudo_user_list_entry(struct pseudo_user_list **list, pseudo_t *entry, int count) +{ + struct pseudo_user *pu; + + FOR_EACH_PTR(*list, pu) { + if (pu->userp == entry) { + DELETE_CURRENT_PTR(pu); + if (!--count) + goto out; + } + } END_FOR_EACH_PTR(pu); + assert(count <= 0); +out: + pack_ptr_list((struct ptr_list **)list); + return count; +} + static inline void remove_usage(pseudo_t p, pseudo_t *usep) { if (has_use_list(p)) { - delete_ptr_list_entry((struct ptr_list **)&p->users, usep, 1); + delete_pseudo_user_list_entry(&p->users, usep, 1); if (!p->users) kill_instruction(p->def); } @@ -200,6 +217,12 @@ void kill_instruction(struct instruction *insn) kill_use(&insn->src2); kill_use(&insn->src3); return; + case OP_BR: + insn->bb = NULL; + repeat_phase |= REPEAT_CSE; + if (insn->cond) + kill_use(&insn->cond); + return; } } @@ -208,11 +231,11 @@ void kill_instruction(struct instruction *insn) */ static int dead_insn(struct instruction *insn, pseudo_t *src1, pseudo_t *src2, pseudo_t *src3) { - pseudo_t *usep; - FOR_EACH_PTR(insn->target->users, usep) { - if (*usep != VOID) + struct pseudo_user *pu; + FOR_EACH_PTR(insn->target->users, pu) { + if (*pu->userp != VOID) return 0; - } END_FOR_EACH_PTR(usep); + } END_FOR_EACH_PTR(pu); insn->bb = NULL; kill_use(src1); @@ -419,12 +442,12 @@ static int simplify_binop(struct instruction *insn) return 0; } -static void switch_pseudo(pseudo_t *pp1, pseudo_t *pp2) +static void switch_pseudo(struct instruction *insn1, pseudo_t *pp1, struct instruction *insn2, pseudo_t *pp2) { pseudo_t p1 = *pp1, p2 = *pp2; - use_pseudo(p2, pp1); - use_pseudo(p1, pp2); + use_pseudo(insn1, p2, pp1); + use_pseudo(insn2, p1, pp2); remove_usage(p1, pp1); remove_usage(p2, pp2); } @@ -444,7 +467,7 @@ static int canonical_order(pseudo_t p1, pseudo_t p2) static int simplify_commutative_binop(struct instruction *insn) { if (!canonical_order(insn->src1, insn->src2)) { - switch_pseudo(&insn->src1, &insn->src2); + switch_pseudo(insn, &insn->src1, insn, &insn->src2); return REPEAT_CSE; } return 0; @@ -473,7 +496,7 @@ static int simplify_associative_binop(struct instruction *insn) return 0; if (ptr_list_size((struct ptr_list *)def->target->users) != 1) return 0; - switch_pseudo(&def->src1, &insn->src2); + switch_pseudo(def, &def->src1, insn, &insn->src2); return REPEAT_CSE; } @@ -517,7 +540,7 @@ static int simplify_one_memop(struct instruction *insn, pseudo_t orig) struct instruction *def = addr->def; if (def->opcode == OP_SYMADDR && def->src) { kill_use(&insn->src); - use_pseudo(def->src, &insn->src); + use_pseudo(insn, def->src, &insn->src); return REPEAT_CSE | REPEAT_SYMBOL_CLEANUP; } if (def->opcode == OP_ADD) { @@ -543,7 +566,7 @@ offset: warning(insn->pos, "crazy programmer"); } insn->offset += off->value; - use_pseudo(new, &insn->src); + use_pseudo(insn, new, &insn->src); remove_usage(addr, &insn->src); return REPEAT_CSE | REPEAT_SYMBOL_CLEANUP; } @@ -699,7 +722,7 @@ static int simplify_range(struct instruction *insn) */ static int simplify_cond_branch(struct instruction *br, pseudo_t cond, struct instruction *def, pseudo_t *pp) { - use_pseudo(*pp, &br->cond); + use_pseudo(br, *pp, &br->cond); remove_usage(cond, &br->cond); if (def->opcode == OP_SET_EQ) { struct basic_block *true = br->bb_true; @@ -763,7 +786,7 @@ static int simplify_branch(struct instruction *insn) insn->bb_false = true; insn->bb_true = false; } - use_pseudo(def->src1, &insn->cond); + use_pseudo(insn, def->src1, &insn->cond); remove_usage(cond, &insn->cond); return REPEAT_CSE; } @@ -771,7 +794,7 @@ static int simplify_branch(struct instruction *insn) if (def->opcode == OP_CAST || def->opcode == OP_SCAST) { int orig_size = def->orig_type ? def->orig_type->bit_size : 0; if (def->size > orig_size) { - use_pseudo(def->src, &insn->cond); + use_pseudo(insn, def->src, &insn->cond); remove_usage(cond, &insn->cond); return REPEAT_CSE; } diff --git a/sparse.c b/sparse.c index 6c06988..81b87a8 100644 --- a/sparse.c +++ b/sparse.c @@ -23,6 +23,8 @@ #include "symbol.h" #include "expression.h" #include "linearize.h" +#include "storage.h" +#include "checker.h" static int context_increase(struct basic_block *bb, int entry) { @@ -264,8 +266,16 @@ static void check_symbols(struct symbol_list *list) expand_symbol(sym); ep = linearize_symbol(sym); - if (ep) + if (ep) { + if (dbg_entry) + show_entry(ep); + check_context(ep); + if (Wmalloc) + check_null_ptr(ep); + if (Winterrupt) + check_interrupt(ep); + } } END_FOR_EACH_PTR(sym); } @@ -276,6 +286,9 @@ int main(int argc, char **argv) // Expand, linearize and show it. check_symbols(sparse_initialize(argc, argv, &filelist)); + + check_null_ptr_init(); + check_interrupt_init(); FOR_EACH_PTR_NOTAG(filelist, file) { check_symbols(sparse(file)); } END_FOR_EACH_PTR_NOTAG(file); diff --git a/symbol.c b/symbol.c index 1a3f594..bad05fd 100644 --- a/symbol.c +++ b/symbol.c @@ -678,43 +678,9 @@ static struct sym_init { { "__label__", &label_ctype, MOD_LABEL | MOD_UNSIGNED }, { "_Bool", &bool_ctype, MOD_UNSIGNED }, - /* Type qualifiers */ - { "const", NULL, MOD_CONST }, - { "__const", NULL, MOD_CONST }, - { "__const__", NULL, MOD_CONST }, - { "volatile", NULL, MOD_VOLATILE }, - { "__volatile", NULL, MOD_VOLATILE }, - { "__volatile__", NULL, MOD_VOLATILE }, - /* Predeclared types */ { "__builtin_va_list", &int_type, 0 }, - /* Typedef.. */ - { "typedef", NULL, MOD_TYPEDEF }, - - /* Extended types */ - { "typeof", NULL, MOD_TYPEOF }, - { "__typeof", NULL, MOD_TYPEOF }, - { "__typeof__", NULL, MOD_TYPEOF }, - -#if 0 - { "attribute", NULL, MOD_ATTRIBUTE }, -#endif - { "__attribute", NULL, MOD_ATTRIBUTE }, - { "__attribute__", NULL, MOD_ATTRIBUTE }, - - { "struct", NULL, MOD_STRUCTOF }, - { "union", NULL, MOD_UNIONOF }, - { "enum", NULL, MOD_ENUMOF }, - - { "inline", NULL, MOD_INLINE }, - { "__inline", NULL, MOD_INLINE }, - { "__inline__", NULL, MOD_INLINE }, - - /* Ignored for now.. */ - { "restrict", NULL, 0 }, - { "__restrict", NULL, 0 }, - { NULL, NULL, 0 } }; @@ -794,6 +760,7 @@ void init_symbols(void) hash_ident(&n) #include "ident-list.h" + init_parser(stream); for (ptr = symbol_init_table; ptr->name; ptr++) { struct symbol *sym; sym = create_symbol(stream, ptr->name, SYM_NODE, NS_TYPEDEF); diff --git a/symbol.h b/symbol.h index 91cc06a..2874e8f 100644 --- a/symbol.h +++ b/symbol.h @@ -73,10 +73,16 @@ struct ctype { struct symbol *base_type; }; +#define S_OP_TYPE_SPECIFIER 0x0001 +#define S_OP_ATTRIBUTE 0x0002 +#define S_OP_TYPEOF 0x0004 + struct symbol_op { + unsigned long type; int (*evaluate)(struct expression *); int (*expand)(struct expression *, int); int (*args)(struct expression *); + struct token *(*specifier)(struct token *token, struct ctype *ctype); }; extern int expand_safe_p(struct expression *expr, int cost); @@ -118,7 +124,8 @@ struct symbol { initialized:1, examined:1, expanding:1, - evaluated:1; + evaluated:1, + string:1; struct expression *array_size; struct ctype ctype; struct symbol_list *arguments; @@ -133,6 +140,10 @@ struct symbol { union /* backend */ { struct basic_block *bb_target; /* label */ void *aux; /* Auxiliary info, eg. backend information */ + struct { /* sparse ctags */ + char kind; + unsigned char visited:1; + }; }; pseudo_t pseudo; }; @@ -154,12 +165,7 @@ struct symbol { #define MOD_LONGLONG 0x0800 #define MOD_TYPEDEF 0x1000 -#define MOD_STRUCTOF 0x2000 -#define MOD_UNIONOF 0x4000 -#define MOD_ENUMOF 0x8000 -#define MOD_TYPEOF 0x10000 -#define MOD_ATTRIBUTE 0x20000 #define MOD_INLINE 0x40000 #define MOD_ADDRESSABLE 0x80000 @@ -180,7 +186,6 @@ struct symbol { #define MOD_NONLOCAL (MOD_EXTERN | MOD_TOPLEVEL) #define MOD_STORAGE (MOD_AUTO | MOD_REGISTER | MOD_STATIC | MOD_EXTERN | MOD_INLINE | MOD_TOPLEVEL) -#define MOD_SPECIALBITS (MOD_STRUCTOF | MOD_UNIONOF | MOD_ENUMOF | MOD_ATTRIBUTE | MOD_TYPEOF) #define MOD_SIGNEDNESS (MOD_SIGNED | MOD_UNSIGNED | MOD_EXPLICITLY_SIGNED) #define MOD_SPECIFIER (MOD_CHAR | MOD_SHORT | MOD_LONG | MOD_LONGLONG | MOD_SIGNEDNESS) #define MOD_SIZE (MOD_CHAR | MOD_SHORT | MOD_LONG | MOD_LONGLONG) @@ -239,6 +244,8 @@ extern void bind_symbol(struct symbol *, struct ident *, enum namespace); extern struct symbol *examine_symbol_type(struct symbol *); extern void examine_simple_symbol_type(struct symbol *); extern const char *show_typename(struct symbol *sym); +extern const char *builtin_typename(struct symbol *sym); +extern const char *builtin_ctypename(struct ctype *ctype); extern void debug_symbol(struct symbol *); extern void merge_type(struct symbol *sym, struct symbol *base_type); diff --git a/test-sort.c b/test-sort.c index d0ffb67..5f17676 100644 --- a/test-sort.c +++ b/test-sort.c @@ -37,7 +37,7 @@ main (int argc, char **argv) do { l2->nr = MIN (l2->nr, rand () % 3); for (i = 0; i < l2->nr; i++) - *((int*)(l2->list[i])) = rand(); + *((int *)(l2->list[i])) = rand(); l2 = l2->next; } while (l2 != l); sort_list (&l, int_cmp); diff --git a/token.h b/token.h index 1f6ffb3..d60bb46 100644 --- a/token.h +++ b/token.h @@ -170,7 +170,7 @@ struct token { static inline struct token *containing_token(struct token **p) { - void *addr = (char*)p - ((char*)&((struct token *)0)->next - (char*)0); + void *addr = (char *)p - ((char *)&((struct token *)0)->next - (char *)0); return addr; } diff --git a/validation/badtype3.c b/validation/badtype3.c index 0aefe6a..198ef87 100644 --- a/validation/badtype3.c +++ b/validation/badtype3.c @@ -1,5 +1,5 @@ int -foo (int (*func) (undef, void*), void* data) +foo (int (*func) (undef, void *), void *data) { int err = 0; while (cur) { diff --git a/validation/init-char-array.c b/validation/init-char-array.c index 390f29d..cd19fdf 100644 --- a/validation/init-char-array.c +++ b/validation/init-char-array.c @@ -7,7 +7,7 @@ char u[] = {"aaaaaaaaa"}; char v[] = "aaaaaaaaa"; void f(void) { - char x[1/(sizeof(s) == sizeof(char*))]; + char x[1/(sizeof(s) == sizeof(char *))]; char y[1/(sizeof(u) == 10)]; char z[1/(sizeof(v) == 10)]; char w[1/(sizeof(t) == 10)];