From: Christopher Li <sparse@chrisli.org>
To: linux-sparse@vger.kernel.org
Cc: Josh Triplett <josh@freedesktop.org>
Subject: [PATCH 7] Adding the interrupt checker
Date: Fri, 9 Feb 2007 16:26:04 -0800 [thread overview]
Message-ID: <20070210002604.GA20748@chrisli.org> (raw)
Changelog:
- Using the new inline function calling annotation to find
out the irq related call. It now works both inline and
external functions. Bonus is no more x86 asm any more.
- The noise level of interrupt check drop considerably.
I think it is less nosier than the context checking.
Signed-off-by: Christopher Li<sparse@chrisli.org>
Index: sparse/lib.c
===================================================================
--- sparse.orig/lib.c 2007-02-09 14:14:33.000000000 -0800
+++ sparse/lib.c 2007-02-09 14:15:08.000000000 -0800
@@ -191,6 +191,7 @@ 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;
@@ -341,6 +342,7 @@ static const struct warning {
{ "do-while", &Wdo_while },
{ "uninitialized", &Wuninitialized },
{ "malloc", &Wmalloc},
+ { "interrupt", &Winterrupt},
};
enum {
Index: sparse/Makefile
===================================================================
--- sparse.orig/Makefile 2007-02-09 14:14:33.000000000 -0800
+++ sparse/Makefile 2007-02-09 14:15:08.000000000 -0800
@@ -34,7 +34,7 @@ LIB_OBJS= target.o parse.o tokenize.o pr
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 \
- blobhash.o check-nullptr.o
+ blobhash.o check-nullptr.o check-interrupt.o
LIB_FILE= libsparse.a
SLIB_FILE= libsparse.so
@@ -139,6 +139,7 @@ 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)
Index: sparse/checker.h
===================================================================
--- sparse.orig/checker.h 2007-02-09 14:14:53.000000000 -0800
+++ sparse/checker.h 2007-02-09 14:15:27.000000000 -0800
@@ -137,6 +137,8 @@ static inline int match_call_function(st
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
Index: sparse/lib.h
===================================================================
--- sparse.orig/lib.h 2007-02-09 14:14:33.000000000 -0800
+++ sparse/lib.h 2007-02-09 14:15:08.000000000 -0800
@@ -97,6 +97,7 @@ 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;
Index: sparse/sparse.c
===================================================================
--- sparse.orig/sparse.c 2007-02-09 14:14:33.000000000 -0800
+++ sparse/sparse.c 2007-02-09 14:15:08.000000000 -0800
@@ -273,6 +273,8 @@ static void check_symbols(struct symbol_
check_context(ep);
if (Wmalloc)
check_null_ptr(ep);
+ if (Winterrupt)
+ check_interrupt(ep);
}
} END_FOR_EACH_PTR(sym);
}
Index: sparse/check-interrupt.c
===================================================================
--- sparse.orig/check-interrupt.c 2007-02-09 14:15:08.000000000 -0800
+++ sparse/check-interrupt.c 2007-02-09 14:15:08.000000000 -0800
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2006 Christopher Li <sparse@chrisli.org>
+ *
+ * Licensed under the Open Software License version 1.1
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#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);
+}
+
next reply other threads:[~2007-02-10 0:54 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-02-10 0:26 Christopher Li [this message]
2007-03-01 6:07 ` [PATCH 7] Adding the interrupt checker Pavel Roskin
-- strict thread matches above, loose matches on Subject: below --
2007-03-31 0:26 Suhabe Bugrara
2007-04-02 16:52 ` Pavel Roskin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20070210002604.GA20748@chrisli.org \
--to=sparse@chrisli.org \
--cc=josh@freedesktop.org \
--cc=linux-sparse@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.