All of lore.kernel.org
 help / color / mirror / Atom feed
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, &current, 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, &current, 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(&current, 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);
+}
+

             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.