]> sourceware.org Git - systemtap.git/commitdiff
Add support for python target variable numeric array indexing.
authorDavid Smith <dsmith@redhat.com>
Wed, 30 Nov 2016 16:53:38 +0000 (10:53 -0600)
committerDavid Smith <dsmith@redhat.com>
Wed, 30 Nov 2016 16:53:38 +0000 (10:53 -0600)
* tapset-python.cxx (python_var_expanding_visitor::visit_target_symbol):
  Add support for numeric array indexing.
* tapset/python2.stp (Py2Dict_GetItem_FromLong): New function.
  (Py2Object_Repr): Add variant of Py2Object_Repr() that takes a numeric
  index.
  (python2_get_variable): Add variant of python2_get_variable() that takes
  a numeric index.
* tapset/python3.stp (Py3Dict_GetItem_FromLong): New function.
  (Py3Object_Repr): Add variant of Py3Object_Repr() that takes a numeric
  index.
  (python3_get_variable): Add variant of python3_get_variable() that takes
  a numeric index.

tapset-python.cxx
tapset/python2.stp
tapset/python3.stp

index 295de6ca914548adf8938ecd43a22ec8e454453f..1c25848ce3afa5283e5256a535b5cf901035fb0d 100644 (file)
@@ -337,6 +337,27 @@ python_var_expanding_visitor::visit_target_symbol (target_symbol* e)
        ls->tok = e->tok;
        fcall->args.push_back(ls);
 
+       // Here we try to handle array indexing. Note that we can't
+       // really know if the python variable type supports array
+       // indexing at compile time. If the python variable type
+       // doesn't support array indexing, the user will get an error
+       // at runtime.
+       const target_symbol::component* c =
+         e->components.empty() ? NULL : &e->components[0];
+       if (c)
+         {
+           if (c->type == target_symbol::comp_literal_array_index)
+             {
+               literal_number* ln = new literal_number(c->num_index);
+               ln->tok = e->tok;
+               fcall->args.push_back(ln);
+             }
+           else if (c->type == target_symbol::comp_expression_array_index)
+             throw SEMANTIC_ERROR(_("unhandled expression array indexing"));
+           else
+             throw SEMANTIC_ERROR(_("unhandled array indexing type"));
+         }
+
        provide (fcall);
        return;
       }
index dbde9f8c206b14f5e11cb1db8916ae9ff5a4034d..687b6e968a9192bb9706b8d6cfc528e0900cdc89 100644 (file)
@@ -547,11 +547,44 @@ private function Py2Dict_GetItem:long(op:long, key:string)
     n = @Py2DictObject(op)->ma_mask;
     for (i = 0; i < n; i++) {
        entry_ptr = &@Py2DictObject(op)->ma_table[i]
-       if (entry_ptr->me_key == 0 || entry_ptr->me_value == 0
-           || ! @Py2String_Check(entry_ptr->me_key))
+       if (@Py2DictEntry(entry_ptr)->me_key == 0
+           || @Py2DictEntry(entry_ptr)->me_value == 0
+           || ! @Py2String_Check(@Py2DictEntry(entry_ptr)->me_key))
           continue
-       if (Py2String_AsString(entry_ptr->me_key) == key)
-          return entry_ptr->me_value
+       if (Py2String_AsString(@Py2DictEntry(entry_ptr)->me_key) == key)
+          return @Py2DictEntry(entry_ptr)->me_value
+    }
+    return 0
+}
+
+# This function isn't really based on a function in dictobject.c, but
+# it is based on Py2Dict_GetItem().
+private function Py2Dict_GetItem_FromLong:long(op:long, key:long)
+{
+    if (!@Py2Dict_Check(op)) {
+       error(sprintf("Py2Dict_GetItem called on %s object at %p\n",
+                     python2_get_typename(op), @__pointer(op)))
+        return 0
+    }
+    // We'd like to hash 'key' here, but we can't (easily). Python
+    // randomizes its hash function at python process startup. So,
+    // instead of hashing the key and then searching for that hash in
+    // the dictionary, we'll do a linear search of the dictionary for
+    // the key.
+    n = @Py2DictObject(op)->ma_mask;
+    for (i = 0; i < n; i++) {
+       entry_ptr = &@Py2DictObject(op)->ma_table[i]
+       if (@Py2DictEntry(entry_ptr)->me_key == 0
+           || @Py2DictEntry(entry_ptr)->me_value == 0
+           || (! @Py2Int_Check(@Py2DictEntry(entry_ptr)->me_key)
+               && ! @Py2Long_Check(@Py2DictEntry(entry_ptr)->me_key)))
+          continue
+       if ((@Py2Int_Check(@Py2DictEntry(entry_ptr)->me_key)
+            && @Py2Int_AS_LONG(@Py2DictEntry(entry_ptr)->me_key) == key)
+           || (@Py2Long_Check(@Py2DictEntry(entry_ptr)->me_key)
+               && Py2Long_AsLongLong(@Py2DictEntry(entry_ptr)->me_key)
+               == key))
+          return @Py2DictEntry(entry_ptr)->me_value
     }
     return 0
 }
@@ -571,15 +604,16 @@ private function Py2Dict_Repr:string(object:long)
     first = 1
     for (i = 0; i < n; i++) {
        entry_ptr = &@Py2DictObject(object)->ma_table[i]
-       if (entry_ptr->me_key == 0 || entry_ptr->me_value == 0)
+       if (@Py2DictEntry(entry_ptr)->me_key == 0
+           || @Py2DictEntry(entry_ptr)->me_value == 0)
           continue
 
        if (! first)
            retstr .= " "
        first = 0
-       retstr .= Py2Object_Repr(entry_ptr->me_key)
+       retstr .= Py2Object_Repr(@Py2DictEntry(entry_ptr)->me_key)
        retstr .= ":"
-       retstr .= Py2Object_Repr(entry_ptr->me_value)
+       retstr .= Py2Object_Repr(@Py2DictEntry(entry_ptr)->me_value)
     }
     retstr .= "}"
     return retstr
@@ -609,6 +643,26 @@ private function Py2Object_Repr:string(object:long)
                   @__pointer(object))
 }
 
+# This function isn't really based on a function in object.c, but
+# it is based on Py2Object_Repr().
+private function Py2Object_Repr:string(object:long, index:long)
+{
+    if (object == 0)
+       return "<NULL>"
+    if (@Py2String_Check(object))
+       return sprintf("\"%c\"", stringat(Py2String_AsString(object), index))
+    if (@Py2Tuple_Check(object))
+       return Py2Object_Repr(Py2Tuple_GetItem(object, index))
+    if (@Py2List_Check(object))
+       return Py2Object_Repr(Py2List_GetItem(object, index))
+    if (@Py2Dict_Check(object))
+       return Py2Object_Repr(Py2Dict_GetItem_FromLong(object, index))
+
+    error(sprintf("TypeError: '%s' object cannot be indexed",
+         python2_get_typename(object)))
+    return ""
+}
+
 #
 # Systemtap support functions for python 2.
 #
@@ -629,9 +683,9 @@ function python2_print_backtrace:long(frame:long)
     printf("Traceback (most recent call first):\n")
     while (frame != 0) {
        lineno = Py2Frame_GetLineNumber(frame)
-       code = @Py2FrameObject(frame)->f_code
-       filename = Py2String_AsString(code->co_filename)
-       name = Py2String_AsString(code->co_name)
+       f_code = @Py2FrameObject(frame)->f_code
+       filename = Py2String_AsString(@Py2CodeObject(f_code)->co_filename)
+       name = Py2String_AsString(@Py2CodeObject(f_code)->co_name)
 
        # Quit when we make it back to the HelperSDT module.
        if (isinstr(filename, "/HelperSDT/"))
@@ -663,9 +717,9 @@ function python2_sprint_backtrace:string(frame:long)
     retstr = "Traceback (most recent call first):\n"
     while (frame != 0) {
        lineno = Py2Frame_GetLineNumber(frame)
-       code = @Py2FrameObject(frame)->f_code
-       filename = Py2String_AsString(code->co_filename)
-       name = Py2String_AsString(code->co_name)
+       f_code = @Py2FrameObject(frame)->f_code
+       filename = Py2String_AsString(@Py2CodeObject(f_code)->co_filename)
+       name = Py2String_AsString(@Py2CodeObject(f_code)->co_name)
 
        # Quit when we make it back to the HelperSDT module.
        if (isinstr(filename, "/HelperSDT/"))
@@ -714,13 +768,13 @@ function python2_get_locals:string(frame:long, flags:long)
     # flags == 2: get all variables
     if (flags == 2) {          
        i = 0
-       n = f_code->co_nlocals
+       n = @Py2CodeObject(f_code)->co_nlocals
     }
     else {
-       n = f_code->co_argcount
-       if (f_code->co_flags & %{ Py2_CO_VARARGS %})
+       n = @Py2CodeObject(f_code)->co_argcount
+       if (@Py2CodeObject(f_code)->co_flags & %{ Py2_CO_VARARGS %})
            n++
-       if (f_code->co_flags & %{ Py2_CO_VARKEYWORDS %})
+       if (@Py2CodeObject(f_code)->co_flags & %{ Py2_CO_VARKEYWORDS %})
            n++
 
        # flags == 0 (parms only): 0 to n (argcount)
@@ -729,7 +783,7 @@ function python2_get_locals:string(frame:long, flags:long)
        # flags == 1 (locals only): n (argcount) to max
        else if (flags == 1) {
            i = n
-           n = f_code->co_nlocals
+           n = @Py2CodeObject(f_code)->co_nlocals
        }
     }
     if (i < 0 || i > n) {
@@ -739,7 +793,7 @@ function python2_get_locals:string(frame:long, flags:long)
            
     # Each element in co_varnames is a tuple of strings. The values
     # are in f_localsplus.
-    p = f_code->co_varnames
+    p = @Py2CodeObject(f_code)->co_varnames
     localsplus = @Py2FrameObject(frame)->f_localsplus
     first = 1
     for (; i < n; i++) {
@@ -757,11 +811,11 @@ function python2_get_locals:string(frame:long, flags:long)
 function python2_get_variable:string(frame:long, var:string)
 {
     f_code = @Py2FrameObject(frame)->f_code
-    n = f_code->co_nlocals
+    n = @Py2CodeObject(f_code)->co_nlocals
            
     # Each element in co_varnames is a tuple of strings. The values
     # are in f_localsplus.
-    p = f_code->co_varnames
+    p = @Py2CodeObject(f_code)->co_varnames
     localsplus = @Py2FrameObject(frame)->f_localsplus
     for (i = 0; i < n; i++) {
        key_obj = Py2Tuple_GetItem(p, i)
@@ -780,3 +834,30 @@ function python2_get_variable:string(frame:long, var:string)
     }
     return Py2Object_Repr(value)
 }
+
+function python2_get_variable:string(frame:long, var:string, index:long)
+{
+    f_code = @Py2FrameObject(frame)->f_code
+    n = @Py2CodeObject(f_code)->co_nlocals
+           
+    # Each element in co_varnames is a tuple of strings. The values
+    # are in f_localsplus.
+    p = @Py2CodeObject(f_code)->co_varnames
+    localsplus = @Py2FrameObject(frame)->f_localsplus
+    for (i = 0; i < n; i++) {
+       key_obj = Py2Tuple_GetItem(p, i)
+       if (var == Py2String_AsString(key_obj)) {
+           value_obj = user_long(localsplus + (i * %{ sizeof(intptr_t) %}))
+           return Py2Object_Repr(value_obj, index)
+       }
+    }
+
+    # If we can't find it in the locals, we look in the globals.
+    f_globals = @Py2FrameObject(frame)->f_globals
+    value_obj = Py2Dict_GetItem(f_globals, var)
+    if (value_obj == 0) {
+       error(sprintf("Python variable '%s' cannot be found\n", var))
+       return ""
+    }
+    return Py2Object_Repr(value_obj, index)
+}
index 60fb851f479a54882777fea16796bcfa8ee8eef5..2c0f9f242c37b6906f5abcf021fb0114a16e3664 100644 (file)
@@ -663,6 +663,46 @@ private function Py3Dict_GetItem:long(op:long, key:string)
     return 0
 }
 
+# This function isn't really based on a function in dictobject.c, but
+# it is based on Py3Dict_GetItem().
+private function Py3Dict_GetItem_FromLong:long(op:long, key:long)
+{
+    if (!@Py3Dict_Check(op)) {
+       error(sprintf("Py3Dict_GetItem called on %s object at %p\n",
+                     python3_get_typename(op), @__pointer(op)))
+        return 0
+    }
+
+    // See Py3Dict_GetItem() for details on dicts.
+
+    // If we've got a split table...
+    if (@Py3DictObject(op)->ma_values != 0) {
+        n = @Py3DictObject(op)->ma_used
+       for (i = 0; i < n; i++) {
+           entry_ptr = &@DK_ENTRIES(@Py3DictObject(op)->ma_keys)[i]
+           if (entry_ptr->me_key == 0
+               || ! @Py3Long_Check(entry_ptr->me_key))
+               continue
+           if (Py3Long_AsLongLong(entry_ptr->me_key) == key)
+               return @Py3DictObject(op)->ma_values[i]
+       }
+    }
+    // If we've got a combined table...
+    else {
+       n = @choose_defined(@Py3DictObject(op)->ma_keys->dk_nentries,
+                           @DK_SIZE(@Py3DictObject(op)->ma_keys))
+       for (i = 0; i < n; i++) {
+           entry_ptr = &@DK_ENTRIES(@Py3DictObject(op)->ma_keys)[i]
+           if (entry_ptr->me_key == 0 || entry_ptr->me_value == 0
+               || ! @Py3Long_Check(entry_ptr->me_key))
+               continue
+           if (Py3Long_AsLongLong(entry_ptr->me_key) == key)
+               return entry_ptr->me_value
+       }
+    }
+    return 0
+}
+
 private function Py3Dict_Repr:string(object:long)
 {
     if (!@Py3Dict_Check(object)) {
@@ -741,6 +781,27 @@ private function Py3Object_Repr:string(object:long)
                   @__pointer(object))
 }
 
+# This function isn't really based on a function in object.c, but
+# it is based on Py3Object_Repr().
+private function Py3Object_Repr:string(object:long, index:long)
+{
+    if (object == 0)
+       return "<NULL>"
+    if (@Py3Unicode_Check(object))
+       return sprintf("\"%c\"", stringat(Py3Unicode_AsASCIIString(object),
+                                         index))
+    if (@Py3Tuple_Check(object))
+       return Py3Object_Repr(Py3Tuple_GetItem(object, index))
+    if (@Py3List_Check(object))
+       return Py3Object_Repr(Py3List_GetItem(object, index))
+    if (@Py3Dict_Check(object))
+       return Py3Object_Repr(Py3Dict_GetItem_FromLong(object, index))
+
+    error(sprintf("TypeError: '%s' object cannot be indexed",
+         python3_get_typename(object)))
+    return ""
+}
+
 #
 # Systemtap support functions for python 3.
 #
@@ -913,3 +974,30 @@ function python3_get_variable:string(frame:long, var:string)
     }
     return Py3Object_Repr(value)
 }
+
+function python3_get_variable:string(frame:long, var:string, index:long)
+{
+    f_code = @Py3FrameObject(frame)->f_code
+    n = @Py3CodeObject(f_code)->co_nlocals
+           
+    # Each element in co_varnames is a tuple of strings. The values
+    # are in f_localsplus.
+    p = @Py3CodeObject(f_code)->co_varnames
+    localsplus = @Py3FrameObject(frame)->f_localsplus
+    for (i = 0; i < n; i++) {
+       key_obj = Py3Tuple_GetItem(p, i)
+       if (var == Py3Unicode_AsASCIIString(key_obj)) {
+           value_obj = user_long(localsplus + (i * %{ sizeof(intptr_t) %}))
+           return Py3Object_Repr(value_obj, index)
+       }
+    }
+
+    # If we can't find it in the locals, we look in the globals.
+    f_globals = @Py3FrameObject(frame)->f_globals
+    value_obj = Py3Dict_GetItem(f_globals, var)
+    if (value_obj == 0) {
+       error(sprintf("Python variable '%s' cannot be found\n", var))
+       return ""
+    }
+    return Py3Object_Repr(value_obj, index)
+}
This page took 0.038368 seconds and 5 git commands to generate.