From 30225b399be843dc83014159e06d414a5626b9fe Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 3 Aug 2010 14:12:39 +0200 Subject: [PATCH] unwind: register unwind functions that unwind everything A bunch of places unwind in a special unwind function instead of doing it directly. For now I made a function count as an unwind function if it calls free_irq() on something that was passed in as a parameter. Signed-off-by: Dan Carpenter --- check_unwind.c | 69 ++++++++++++++++ smatch_data/kernel.unwind_functions | 143 +++++++++++++++++++++++++++++++++ smatch_scripts/gen_unwind_functions.sh | 23 ++++++ 3 files changed, 235 insertions(+) create mode 100644 smatch_data/kernel.unwind_functions create mode 100755 smatch_scripts/gen_unwind_functions.sh diff --git a/check_unwind.c b/check_unwind.c index 014b411e..619a41b3 100644 --- a/check_unwind.c +++ b/check_unwind.c @@ -25,6 +25,42 @@ static int my_id; STATE(allocated); STATE(unallocated); +/* state of unwind function */ +STATE(called); + +static int was_passed_as_param(struct expression *expr) +{ + char *name; + struct symbol *sym; + struct symbol *arg; + + name = get_variable_from_expr(expr, &sym); + if (!name) + return 0; + free_string(name); + + FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) { + if (arg == sym) + return 1; + } END_FOR_EACH_PTR(arg); + return 0; +} + +static void print_unwind_functions(const char *fn, struct expression *expr, void *_arg_no) +{ + struct expression *arg_expr; + int arg_no = (int)_arg_no; + static struct symbol *last_printed = NULL; + + arg_expr = get_argument_from_call_expr(expr->args, arg_no); + if (!was_passed_as_param(arg_expr)) + return; + if (last_printed == cur_func_sym) + return; + last_printed = cur_func_sym; + sm_msg("info: is unwind function"); +} + static void request_granted(const char *fn, struct expression *call_expr, struct expression *assign_expr, void *_arg_no) { @@ -62,6 +98,11 @@ static void match_release(const char *fn, struct expression *expr, void *_arg_no set_equiv_state_expr(my_id, arg_expr, &unallocated); } +static void match_unwind_function(const char *fn, struct expression *expr, void *unused) +{ + set_state(my_id, "unwind_function", NULL, &called); +} + static int func_returns_int() { struct symbol *type; @@ -85,6 +126,8 @@ static void match_return(struct expression *ret_value) return; if (!implied_not_equal(ret_value, 0)) return; + if (get_state(my_id, "unwind_function", NULL) == &called) + return; slist = get_all_states(my_id); FOR_EACH_PTR(slist, tmp) { @@ -94,12 +137,35 @@ static void match_return(struct expression *ret_value) free_slist(&slist); } +static void register_unwind_functions(void) +{ + struct token *token; + const char *func; + + token = get_tokens_file("kernel.unwind_functions"); + if (!token) + return; + if (token_type(token) != TOKEN_STREAMBEGIN) + return; + token = token->next; + while (token_type(token) != TOKEN_STREAMEND) { + if (token_type(token) != TOKEN_IDENT) + return; + func = show_ident(token->ident); + add_function_hook(func, &match_unwind_function, NULL); + token = token->next; + } + clear_token_alloc(); +} + void check_unwind(int id) { if (option_project != PROJ_KERNEL) return; my_id = id; + register_unwind_functions(); + return_implies_state("request_resource", 0, 0, &request_granted, INT_PTR(1)); return_implies_state("request_resource", -EBUSY, -EBUSY, &request_denied, INT_PTR(1)); add_function_hook("release_resource", &match_release, INT_PTR(0)); @@ -134,4 +200,7 @@ void check_unwind(int id) add_function_hook("misc_deregister", &match_release, INT_PTR(0)); add_hook(&match_return, RETURN_HOOK); + + if (option_info) + add_function_hook("free_irq", &print_unwind_functions, INT_PTR(0)); } diff --git a/smatch_data/kernel.unwind_functions b/smatch_data/kernel.unwind_functions new file mode 100644 index 00000000..875ba07d --- /dev/null +++ b/smatch_data/kernel.unwind_functions @@ -0,0 +1,143 @@ +// list of unwind functions. +// generated by `gen_unwind_functions.sh` +a2150_detach +ace_init_cleanup +adapter_init +adapter_uninit +adpt_i2o_delete_hba +amd8111e_close +amd8111e_open +asd_pci_probe +asd_pci_remove +ath5k_pci_probe +ath5k_pci_remove +atmio16d_detach +aty_disable_irq +BusLogic_ReleaseResources +c101_destroy_card +c6xdigio_detach +cb_pcidas_detach +cleanup_card +corkscrew_close +daqboard2000_detach +das16cs_detach +das16_detach +das16m1_detach +das1800_detach +das6402_detach +das800_detach +deinit_card +depca_close +detach +device_close +dio200_detach +dmm32at_detach +dscc4_init_one +dscc4_remove_one +dt2811_detach +dt2814_detach +dt3000_detach +eata2x_release +eepro_close +el16_probe1 +el2_close +el3_close +ergo_releasehardware +fdomain_16x0_release +free_irq_resources +free_resources +happy_meal_close +happy_meal_open +he_stop +hp100_close +hpc_release_ctlr +hpdi_detach +hp_probe1 +hw_card_shutdown +icp_multi_detach +init_card +init_irq +ipc_remove +ks8851_remove +labpc_common_detach +lmc_ifdown +__megaraid_shutdown +mgsl_release_resources +mio_cs_detach +mpt2sas_base_free_resources +mpt_adapter_dispose +mpt_do_ioc_recovery +multiq3_detach +n2_destroy_card +NCR53c406a_release +NCR_D700_remove_one +net_close +netdev_close +net_open +ni52_close +ni_atmio_detach +nozomi_card_exit +ns_init_card_error +parport_detach +pc236_detach +pci224_detach +pci230_detach +pci9111_detach +pci9118_detach +pcimio_detach +pcl711_detach +pcmad_detach +pcxhr_free +pvscsi_shutdown_intr +qla4xxx_free_adapter +r6040_close +release_card +release_resources +rr_close +rtd_detach +rti800_detach +s626_detach +sb1000_close +sbni_close +sdla_set_config +setup_card +smsc9420_open +smsc9420_stop +snd_ad1816a_free +snd_als300_free +snd_bt87x_free +snd_ca0106_free +snd_cmipci_free +snd_cs4281_free +snd_cs46xx_free +snd_emu10k1_free +snd_emu10k1x_free +snd_ensoniq_free +snd_es1688_free +snd_gus_free +snd_hdsp_free +snd_hdspm_free +snd_ice1712_free +snd_intel8x0_free +snd_korg1212_free +snd_legacy_find_free_irq +snd_lx6464es_create +snd_lx6464es_free +snd_mixart_free +snd_riptide_free +snd_sbdsp_free +snd_sonicvibes_free +snd_trident_free +snd_vt1724_free +snd_wss_free +snd_ymfpci_free +streamer_close +streamer_open +synaptics_i2c_remove +tsc2007_free_irq +ultrastor_release +unload_mpu401 +vortex_close +vortex_open +wd7000_init +wd7000_release diff --git a/smatch_scripts/gen_unwind_functions.sh b/smatch_scripts/gen_unwind_functions.sh new file mode 100755 index 00000000..7badf802 --- /dev/null +++ b/smatch_scripts/gen_unwind_functions.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +file=$1 + +if [[ "$file" = "" ]] ; then + echo "Usage: $0 " + exit 1 +fi + +outfile="kernel.unwind_functions" +bin_dir=$(dirname $0) +remove=$(echo ${bin_dir}/../smatch_data/${outfile}.remove) +tmp=$(mktemp /tmp/smatch.XXXX) +tmp2=$(mktemp /tmp/smatch.XXXX) + +echo "// list of unwind functions." > $outfile +echo '// generated by `gen_unwind_functions.sh`' >> $outfile +grep "is unwind function" $file | cut -d ' ' -f 3 | cut -d '(' -f 1 >> $tmp +cat $tmp | sort -u > $tmp2 +mv $tmp2 $tmp +cat $tmp $remove $remove 2> /dev/null | sort | uniq -u >> $outfile +rm $tmp +echo "Done. List saved as '$outfile'" -- 2.11.4.GIT