# Global Python variables global gp_vars_seen # which vars we have seen global gp_dict_key = 0 # set by get_dict_item global gp_dict_value = 0 global gp_dict_hash = 0 global gp_probe_backtrace_ = 0 # controls which probes fire global gp_probe_get_variable_ = 0 # FUNCTION GET_TYPE # OBJ: PyObject # RETURNS: string representation of type function get_type:string (obj) { if (obj == 0) return "" ob_type = @cast (obj, "PyObject", "/usr/local/bin/python")->ob_type if (ob_type == 0) return "" ob_type_name = @cast (ob_type, "PyTypeObject", "/usr/local/bin/python")->tp_name return set_string (ob_type_name) } # FUNCTION SET_STRING # STR_P: pointer to string # RETURNS: string as a stap string function set_string (str_p) { if (str_p == 0) return "" else return user_string (str_p) } # FUNCTION GET_SEQUENCE_ITEM # TUPLE: array of PyObject # I: index to retrieve # SEQ_TYPE: PyTupleObject or PyListObject # RETURNS: array entry PyObject function get_sequence_item (tuple, i, seq_type) { if (seq_type == "tuple") ob_items = @cast (tuple, "PyTupleObject", "/usr/local/bin/python")->ob_item; else if (seq_type == "list") ob_items = @cast (tuple, "PyListObject", "/usr/local/bin/python")->ob_item; ob_item = user_long (ob_items + (i * %{ sizeof (intptr_t) %})) return ob_item } # FUNCTION DISPLAY_VALUE # VALUE: PyObject # PREFIX: prefix string to display # SUFFIX: suffix string to display function display_value (value, prefix, suffix) { if (value == 0) { return 0 } value_type_str = get_type (value) if (value_type_str == "str") { value_s = @cast (value, "PyStringObject", "/usr/local/bin/python")->ob_sval; value_str = set_string (value_s) printf ("%s\"%s\"%s", prefix, value_str, suffix) } else if (value_type_str == "int") { arg_value_int = @cast (value, "PyIntObject", "/usr/local/bin/python")->ob_ival; printf ("%s%d%s", prefix, arg_value_int, suffix) } else if (value_type_str == "tuple" || value_type_str == "list") { n = @cast (value, "PyTupleObject", "/usr/local/bin/python")->ob_size; if (value_type_str == "list") printf (" = [") else printf (" = ") for (i = 0; i < n; i++) display_value (get_sequence_item (value, i, value_type_str), " ", ",") if (value_type_str == "list") printf ("]") } else if (value_type_str == "set") { printf (" = {") n = @cast (value, "PySetObject", "/usr/local/bin/python")->used; for (i = 0; i <= n; i++) display_value (get_set_item (value, i), " ", ",") printf ("}") } else if (value_type_str == "dict") { printf (" = {") n = @cast (value, "PyDictObject", "/usr/local/bin/python")->ma_used; for (i = 0; i <= n; i++) { get_dict_item (value, i) if (gp_dict_hash == 0 && gp_dict_key == 0) continue display_value (gp_dict_key, " ", ":") display_value (gp_dict_value, "", "") } printf (" }") } } # FUNCTION GET_SET_ITEM # SET: PySetObject # I: set index to retrieve # RETURNS: set entry PyObject function get_set_item (set, i) { entries = @cast (set, "PySetObject", "/usr/local/bin/python")->table; n = @cast (set, "PySetObject", "/usr/local/bin/python")->used; if (i > n) return 0 return @cast (entries, "setentry", "/usr/local/bin/python")[i]->key } # FUNCTION GET_DICT_ITEM # DICT: PySetObject # I: set index to retrieve # RETURNS: sets the global variables GP_DICT_KEY, GP_DICT_VALUE, GP_DICT_HASH function get_dict_item (dict, i) { entries = @cast (dict, "PyDictObject", "/usr/local/bin/python")->ma_table; n = @cast (dict, "PyDictObject", "/usr/local/bin/python")->ma_used; if (i > n) return 0 gp_dict_hash = @cast (entries, "PyDictEntry", "/usr/local/bin/python")[i]->me_hash gp_dict_key = @cast (entries, "PyDictEntry", "/usr/local/bin/python")[i]->me_key gp_dict_value = @cast (entries, "PyDictEntry", "/usr/local/bin/python")[i]->me_value; } # FUNCTION DISPLAY_DICT_VARIABLE # DICT: local or global variable name dictionary # VARIABLE: variable to retrieve # NAMESPACE: local or global function display_dict_variable (dict, variable, namespace, co_name_str, co_filename_str) { n = @cast (dict, "PyDictObject", "/usr/local/bin/python")->ma_used; for (i = 0; i < n; i++) { get_dict_item (dict, i) key_str = set_string (@cast (gp_dict_key, "PyStringObject", "/usr/local/bin/python")->ob_sval) key_type_str = get_type (gp_dict_key) if (gp_dict_key == 0 || gp_dict_value == 0) break if (wildcard_match (key_str, variable)) { foreach ([var, file] in gp_vars_seen) { if (var == key_str && file == co_filename_str) return 0 } printf (" %s %s %s", namespace, key_type_str, key_str) printf (" in %s at %s", co_name_str, co_filename_str) display_value (gp_dict_value, " = ", " ") printf ("\n") gp_vars_seen[key_str, co_filename_str] = co_name_str } } } # FUNCTION WILDCARD_MATCH # STR: String to check for a wildcard # PATTERN: The wildcard pattern. Wildcard special characters are limited to '*' function wildcard_match (str, pattern) { if (pattern == "*") return 1 # Does pattern start at the beginning of str or is it '*'? if (substr (pattern, 0, 1) != "*" && substr (str, 0, 1) != substr (pattern, 0, 1)) return 0 hunk = tokenize (pattern,"*") while (hunk != "") { # find pattern hunk in str if (isinstr (str, hunk) == 0) { return 0 } match = 0 for (i = 0; i < strlen (str) - strlen (hunk) + 1; i++) { if (hunk == substr (str, i, strlen (hunk))) { match = 1 break } } if (!match) return 0 # skip past hunk in str str = substr (str, i, strlen (str)-i+1) hunk = tokenize ("","*") } # Does pattern end at the end of str or is it '*'? if (substr (pattern, strlen (pattern)-1, 1) != "*" && substr (str, strlen (str)-1, 1) != substr (pattern, strlen (pattern)-1, 1)) return 0 else return 1 } # PROBE BACKTRACE # @1: Pathnames containing this string are ignored. Default is "/lib/" to # ignore system python libraries probe process ("/usr/local/bin/python").mark ("backtrace") if (gp_probe_backtrace_) { frame = $arg1 %( $# == 1 %? skip_name = @1 %: skip_name = "/lib/" %) frame_n = 0 while (frame) { f_code = @cast (frame, "struct _frame", "/usr/local/bin/python")->f_code; co_filename = @cast (f_code, "PyCodeObject", "/usr/local/bin/python")->co_filename; co_filename_s = @cast (co_filename, "PyStringObject", "/usr/local/bin/python")->ob_sval; co_filename_str = set_string (co_filename_s) if (isinstr (co_filename_str, skip_name) == 1) next co_name = @cast (f_code, "PyCodeObject", "/usr/local/bin/python")->co_name; co_name_s = @cast (co_name, "PyStringObject", "/usr/local/bin/python")->ob_sval; co_name_str = set_string (co_name_s) co_firstlineno = @cast (f_code, "PyCodeObject", "/usr/local/bin/python")->co_firstlineno; printf ("#%d %s ", frame_n, co_name_str) co_varnames = @cast (f_code, "PyCodeObject", "/usr/local/bin/python")->co_varnames; if (co_varnames == 0) continue co_argcount = @cast (f_code, "PyCodeObject", "/usr/local/bin/python")->co_argcount; f_localsplus = @cast (frame, "struct _frame", "/usr/local/bin/python")->f_localsplus; for (i = 0; i < co_argcount; i++) { if (i == 0) print ("("); arg_name_str = user_string (@cast (get_sequence_item (co_varnames, i, "tuple"), "PyStringObject", "/usr/local/bin/python")->ob_sval) arg_value = user_long (f_localsplus + (i * %{ sizeof (intptr_t) %})) arg_type_name_str = get_type (arg_value) printf ("%s:%s ", arg_name_str, arg_type_name_str) } if (co_argcount) printf (")"); printf (" at %s:%d\n", co_filename_str, co_firstlineno) frame_n += 1 frame = @cast (frame, "struct _frame", "/usr/local/bin/python")->f_back; } } # PROBE GET_VARIABLE # @1: Variable wildcard to be matched. Default is "*" to match all variables. # @2: Pathnames containing this string are ignored. Default is "/lib/" to # ignore system python libraries probe process ("/usr/local/bin/python").mark ("get_variable") if (gp_probe_get_variable_) { frame = $arg1 %( $# >= 1 %? variable = @1 %: variable = "*" %) %( $# >= 2 %? skip_name = @2 %: skip_name = "/lib/" %) frame_n = 0 while (frame) { f_code = @cast (frame, "struct _frame", "/usr/local/bin/python")->f_code; co_filename = @cast (f_code, "PyCodeObject", "/usr/local/bin/python")->co_filename; co_filename_s = @cast (co_filename, "PyStringObject", "/usr/local/bin/python")->ob_sval; co_filename_str = set_string (co_filename_s) if (isinstr (co_filename_str, skip_name) == 1) next co_name = @cast (f_code, "PyCodeObject", "/usr/local/bin/python")->co_name; co_name_s = @cast (co_name, "PyStringObject", "/usr/local/bin/python")->ob_sval; co_name_str = set_string (co_name_s) f_globals = @cast (frame, "struct _frame", "/usr/local/bin/python")->f_globals; if (f_globals != 0) { display_dict_variable (f_globals, variable, "global", co_name_str, co_filename_str) } f_locals = @cast (frame, "struct _frame", "/usr/local/bin/python")->f_locals; if (f_locals != 0) { display_dict_variable (f_locals, variable, "local", co_name_str, co_filename_str) } co_varnames = @cast (f_code, "PyCodeObject", "/usr/local/bin/python")->co_varnames; if (co_varnames == 0) continue co_argcount = @cast (f_code, "PyCodeObject", "/usr/local/bin/python")->co_argcount; f_localsplus = @cast (frame, "struct _frame", "/usr/local/bin/python")->f_localsplus; ob_size = @cast (co_varnames, "PyTypeObject", "/usr/local/bin/python")->ob_size; for (i = 0; i < ob_size; i++) { if (i < co_argcount - 1) continue arg_name_str = user_string (@cast (get_sequence_item (co_varnames, i, "tuple"), "PyStringObject", "/usr/local/bin/python")->ob_sval) if (! wildcard_match (arg_name_str, variable)) continue arg_value = user_long (f_localsplus + (i * %{ sizeof (intptr_t) %})) arg_type_name_str = get_type (arg_value) next_var = 0 foreach ([var, file] in gp_vars_seen) if (var == arg_name_str && file == co_filename_str) next_var = 1 if (next_var || arg_type_name_str == "") continue gp_vars_seen[arg_name_str, co_filename_str] = co_name_str printf ("%s %s", arg_type_name_str, arg_name_str) printf (" in %s at %s", co_name_str, co_filename_str) display_value (arg_value, " = ", " ") printf ("\n") } frame_n += 1 frame = @cast (frame, "struct _frame", "/usr/local/bin/python")->f_back; } } probe python_get_variable = process ("/usr/local/bin/python").mark ("get_variable") { gp_probe_backtrace_ = 0 gp_probe_get_variable_ = 1 } probe python_backtrace = process ("/usr/local/bin/python").mark ("backtrace") { gp_probe_backtrace_ = 1 gp_probe_get_variable_ = 0 }