Sindbad~EG File Manager
// python 3 tapset
// Copyright (C) 2016 Red Hat Inc.
//
// This file is part of systemtap, and is free software. You can
// redistribute it and/or modify it under the terms of the GNU General
// Public License (GPL); either version 2, or (at your option) any
// later version.
// Here we store to address of 'PyObject_GenericGetAttr', which we use
// down in Py3Object_GetAttr().
private global Py3Object_GenericGetAttr_addr = 0
%{
/*
* Defines borrowed from object.h.
*/
/* These flags are used to determine if a type is a subclass. */
#define Py3_TPFLAGS_LONG_SUBCLASS (1L<<24)
#define Py3_TPFLAGS_LIST_SUBCLASS (1L<<25)
#define Py3_TPFLAGS_TUPLE_SUBCLASS (1L<<26)
#define Py3_TPFLAGS_BYTES_SUBCLASS (1L<<27)
#define Py3_TPFLAGS_UNICODE_SUBCLASS (1L<<28)
#define Py3_TPFLAGS_DICT_SUBCLASS (1L<<29)
#define Py3_TPFLAGS_BASE_EXC_SUBCLASS (1L<<30)
#define Py3_TPFLAGS_TYPE_SUBCLASS (1L<<31)
/*
* Defines borrowed from code.h.
*/
/* Masks for co_flags above */
#define Py3_CO_OPTIMIZED 0x0001
#define Py3_CO_NEWLOCALS 0x0002
#define Py3_CO_VARARGS 0x0004
#define Py3_CO_VARKEYWORDS 0x0008
#define Py3_CO_NESTED 0x0010
#define Py3_CO_GENERATOR 0x0020
/* The Py3_CO_NOFREE flag is set if there are no free or cell variables.
This information is redundant, but it allows a single flag test
to determine whether there is any extra work to be done when the
call frame it setup.
*/
#define Py3_CO_NOFREE 0x0040
/*
* Defines borrowed from longintrepr.h
*/
#define Py3Long_SHIFT_SMALL 15
#define Py3Long_SHIFT_BIG 30
/*
* Defines borrowed from pycore_dict.h
*/
#define DICT_KEYS_GENERAL 0
#define DICT_KEYS_UNICODE 1
%}
#
# Macros to cast to various python 3 types
# PR25841 makes this easy
#
@define Py3Object(object) %(
@cast(@object, "PyObject")
%)
@define Py3VarObject(object) %(
@cast(@object, "PyVarObject")
%)
@define Py3LongObject(object) %(
@cast(@object, "PyLongObject")
%)
@define Py3BytesObject(object) %(
@cast(@object, "PyBytesObject")
%)
@define Py3UnicodeObject(object) %(
@cast(@object, "PyUnicodeObject")
%)
@define Py3TypeObject(object) %(
@cast(@object, "PyTypeObject")
%)
@define Py3TupleObject(object) %(
@cast(@object, "PyTupleObject")
%)
@define Py3ListObject(object) %(
@cast(@object, "PyListObject")
%)
@define Py3SetObject(object) %(
@cast(@object, "PySetObject")
%)
@define Py3DictObject(object) %(
@cast(@object, "PyDictObject")
%)
@define Py3DictEntry(object) %(
@cast(@object, "PyDictEntry")
%)
@define Py3DictKeysObject(object) %(
@cast(@object, "PyDictKeysObject")
%)
@define Py3DictKeyEntry(object) %(
@cast(@object, "PyDictKeyEntry")
%)
@define Py3DictUnicodeEntry(object) %(
@cast(@object, "PyDictUnicodeEntry")
%)
@define Py3FrameObject (object) %(
@cast(@object, "PyFrameObject")
%)
@define Py3CodeObject(object) %(
@cast(@object, "PyCodeObject")
%)
@define Py3ASCIIObject(object) %(
@cast(@object, "PyASCIIObject")
%)
@define Py3ASCIIObject_Sizeof %(
@cast_sizeof("PyASCIIObject")
%)
@define Py3CompactUnicodeObject(object) %(
@cast(@object, "PyCompactUnicodeObject")
%)
@define Py3CompactUnicodeObject_Sizeof %(
@cast_sizeof("PyCompactUnicodeObject")
%)
private function Py3Frame_GetCode (object)
{
return @choose_defined(@Py3FrameObject(object)->f_code,
@cast(object, "_stp_Py3FrameObject")->f_frame->f_code)
}
private function Py3Frame_GetTrace (object)
{
return @choose_defined(
@Py3FrameObject(object)->f_trace,
@cast(object, "_stp_Py3FrameObject")->f_trace)
}
private function Py3Frame_GetBack (object)
{
if (@defined (@Py3FrameObject(object)->f_back))
return @Py3FrameObject(object)->f_back
else
{
f_frame = @cast(object, "_stp_Py3FrameObject")->f_frame
back = @cast(object, "_stp_Py3FrameObject")->f_back;
if (back == NULL && f_frame->previous != NULL) {
back = f_frame->previous->frame_obj;
}
return back;
}
}
private function Py3Frame_GetFilename (object)
{
return @choose_defined(@Py3FrameObject(object)->f_code->co_filename,
@cast(object, "_stp_Py3FrameObject")->f_frame->f_code->co_filename)
}
private function Py3Frame_GetLocalsplus (object)
{
return @choose_defined(
@Py3FrameObject(object)->f_localsplus,
@cast(object, "_stp_Py3FrameObject")->f_frame->localsplus)
}
#
# TODO python 3.11 sometimes returns <NULL> for global values (timing issue?)
#
private function Py3Frame_GetGlobals (object)
{
return @choose_defined(
@Py3FrameObject(object)->f_globals,
@cast(object, "_stp_Py3FrameObject")->f_frame->f_globals)
}
private function Py3Dict_GetValue (object, idx)
{
return @choose_defined(
@Py3DictObject(object)->ma_values->values[idx],
@Py3DictObject(object)->ma_values[idx])
}
#
# Systemtap macros based on C macros in object.h.
#
@define Py3_REFCNT(object) %(
@Py3Object(@object)->ob_refcnt
%)
@define Py3_TYPE(object) %(
@Py3Object(@object)->ob_type
%)
@define Py3_SIZE(object) %(
@Py3VarObject(@object)->ob_size
%)
@define Py3Type_HasFeature(t, f) %(
((@t->tp_flags & (@f)) != 0)
%)
@define Py3Type_FastSubclass(t, f) %(
@Py3Type_HasFeature(@t, @f)
%)
#
# Systemtap macros based on C macros in bytesobject.h.
#
@define Py3Bytes_Check(op) %(
@Py3Type_FastSubclass(@Py3_TYPE(@op), %{ Py3_TPFLAGS_BYTES_SUBCLASS %})
%)
#
# Systemtap macros based on C macros in unicodeobject.h.
#
@define Py3Unicode_Check(op) %(
@Py3Type_FastSubclass(@Py3_TYPE(@op), %{ Py3_TPFLAGS_UNICODE_SUBCLASS %})
%)
/* Returns the length of the unicode string. */
@define Py3Unicode_GET_LENGTH(op) %(
((@Py3Unicode_Check(@op) && @Py3Unicode_IS_READY(@op))
? @Py3ASCIIObject(@op)->length : 0)
%)
@define Py3Unicode_IS_READY(op) %(
@Py3ASCIIObject(@op)->state->ready
%)
@define Py3Unicode_IS_ASCII(op) %(
(@Py3Unicode_Check(@op) && @Py3Unicode_IS_READY(@op)
&& @Py3ASCIIObject(@op)->state->ascii)
%)
/* Return true if the string is compact or 0 if not.
No type checks or Ready calls are performed. */
@define Py3Unicode_IS_COMPACT(op) %(
(@Py3ASCIIObject(@op)->state->compact)
%)
/* Return a void pointer to the raw unicode buffer. */
@define _Py3Unicode_COMPACT_DATA(op) %(
(@Py3Unicode_IS_ASCII(@op)
? (@op + @Py3ASCIIObject_Sizeof)
: (@op + @Py3CompactUnicodeObject_Sizeof))
%)
@define _Py3Unicode_NONCOMPACT_DATA(op) %(
(@Py3UnicodeObject(@op)->data->any)
%)
@define Py3Unicode_DATA(op) %(
(@Py3Unicode_IS_COMPACT(@op) ? @_Py3Unicode_COMPACT_DATA(@op)
: @_Py3Unicode_NONCOMPACT_DATA(@op))
%)
#
# Systemtap macros based on C macros in longobject.h.
#
@define Py3Long_Check(op) %(
@Py3Type_FastSubclass(@Py3_TYPE(@op), %{ Py3_TPFLAGS_LONG_SUBCLASS %})
%)
#
# Systemtap macros based on C macros in dictobject.h.
#
@define Py3Dict_Check(op) %(
@Py3Type_FastSubclass(@Py3_TYPE(@op), %{ Py3_TPFLAGS_DICT_SUBCLASS %})
%)
#
# Systemtap macros based on C macros in tupleobject.h.
#
@define Py3Tuple_Check(op) %(
@Py3Type_FastSubclass(@Py3_TYPE(@op), %{ Py3_TPFLAGS_TUPLE_SUBCLASS %})
%)
#
# Systemtap macros based on C macros in listobject.h.
#
@define Py3List_Check(op) %(
@Py3Type_FastSubclass(@Py3_TYPE(@op), %{ Py3_TPFLAGS_LIST_SUBCLASS %})
%)
#
# Systemtap functions based on C functions in longobject.c.
#
%{
/* Checking for overflow in PyLong_AsLong is a PITA since C doesn't define
* anything about what happens when a signed integer operation overflows,
* and some compilers think they're doing you a favor by being "clever"
* then. The bit pattern for the largest positive signed long is
* (unsigned long)LONG_MAX, and for the smallest negative signed long
* it is abs(LONG_MIN), which we could write -(unsigned long)LONG_MIN.
* However, some other compilers warn about applying unary minus to an
* unsigned operand. Hence the weird "0-".
*/
#define PY3_LLONG_MIN (-__LONG_LONG_MAX__ - 1L)
#define PY3_ABS_LLONG_MIN (0-(unsigned long long)PY3_LLONG_MIN)
%}
/* Get a C long int from an int object or any object that has an __int__
* method.
*
* On overflow, return -1 and throw an error.
*/
/*
* The Py3Long_AsLongLong() function below is actually based on
* PyLong_AsLong(). Python's PyLong_AsLongLong() converts the PyLong
* to a Bytes object. This method is simpler.
*
* On 32-bit platforms, the default for PYLONG_BITS_IN_DIGIT is 15. On
* 64-bit platforms, the default for PYLONG_BITS_IN_DIGIT is 30. We're
* going to assume that to be true, even though it can be configured
* differently.
*
* Since we can be on a 64-bit kernel but probing a 32-bit python 3
* executable, we have to handle both cases at the same time.
*/
private function Py3Long_AsLongLongAndOverflow_Small:long(v:long)
{
res = -1
i = @Py3_SIZE(v)
if (i == -1) {
/* We're using 'x & 0xffff' instead of '(short)x' */
res = -(@Py3LongObject(v)->ob_digit[0] & 0xffff)
}
else if (i == 0) {
res = 0
}
else if (i == 1) {
res = @Py3LongObject(v)->ob_digit[0]
}
else {
sign = 1
x = 0
if (i < 0) {
sign = -1
i = -(i)
}
while (--i >= 0) {
prev = x
x = ((x << %{ Py3Long_SHIFT_SMALL %})
| @Py3LongObject(v)->ob_digit[i])
if ((x >> %{ Py3Long_SHIFT_SMALL %}) != prev) {
error("Python int too large")
return res
}
}
/* Haven't lost any bits, but casting to long requires extra
* care (see comment above).
*/
if (x <= %{ __LONG_LONG_MAX__ %}) {
res = x * sign
}
else if (sign < 0 && x == %{ PY3_ABS_LLONG_MIN %}) {
res = %{ PY3_LLONG_MIN %}
}
else {
error("Python int too large")
/* res is already set to -1 */
}
}
return res
}
private function Py3Long_AsLongLongAndOverflow_Big:long(v:long)
{
res = -1
i = @Py3_SIZE(v)
if (i == -1) {
/* We're using 'x & 0xffffffff' instead of '(int32_t)x' */
res = -(@Py3LongObject(v)->ob_digit[0] & 0xffffffff)
}
else if (i == 0) {
res = 0
}
else if (i == 1) {
res = @Py3LongObject(v)->ob_digit[0]
}
else {
sign = 1
x = 0
if (i < 0) {
sign = -1
i = -(i)
}
while (--i >= 0) {
prev = x
x = ((x << %{ Py3Long_SHIFT_BIG %})
| @Py3LongObject(v)->ob_digit[i])
if ((x >> %{ Py3Long_SHIFT_BIG %}) != prev) {
error("Python int too large")
return res
}
}
/* Haven't lost any bits, but casting to long requires extra
* care (see comment above).
*/
if (x <= %{ __LONG_LONG_MAX__ %}) {
res = x * sign
}
else if (sign < 0 && x == %{ PY3_ABS_LLONG_MIN %}) {
res = %{ PY3_LLONG_MIN %}
}
else {
error("Python int too large")
/* res is already set to -1 */
}
}
return res
}
private function Py3Long_AsLongLong:long(v:long)
{
if (! @Py3Long_Check(v)) {
error(sprintf("Py3Long_AsLong called on %s object at %p",
python3_get_typename(v), v))
return -1
}
%( CONFIG_64BIT == "y" %?
%( CONFIG_COMPAT == "y" %?
if (@__compat_task) {
return Py3Long_AsLongLongAndOverflow_Small(v)
}
%)
return Py3Long_AsLongLongAndOverflow_Big(v)
%:
return Py3Long_AsLongLongAndOverflow_Small(v)
%)
}
#
# Systemtap functions based on C functions in bytesobject.c.
#
private function Py3Bytes_Size:long(object:long)
{
if (! @Py3Bytes_Check(object)) {
# NB: python code returns string_getsize(), creating a new
# string representation of the object, then returning the
# length of the new string. We can't create new objects here,
# so we'll just quit.
warn(sprintf("Py3Bytes_Size called on non-bytes object address 0x%p\n",
object))
return 0
}
return @Py3_SIZE(object)
}
#
# Systemtap functions based on C functions in unicodeobject.c.
#
private function Py3Unicode_AsASCIIString:string(object:long)
{
if (!@Py3Unicode_Check(object)) {
# NB: python returns value of string_getbuffer() here
# (basically getting a string representation of any
# object). We can't create new objects here, so we'll
# just quit.
warn(sprintf("Py3Unicode_AsASCIIString called on non-string address 0x%p\n",
object))
return ""
}
if (@Py3Unicode_IS_ASCII(object)) {
try {
return user_string_n_nofault(@Py3Unicode_DATA(object),
@Py3Unicode_GET_LENGTH(object))
} catch {
warn(sprintf("Py3Unicode_AsASCIIString failed on address 0x%p\n",
object))
}
return ""
}
try {
return text_str(user_string_n(@Py3Unicode_DATA(object),
@Py3Unicode_GET_LENGTH(object)))
} catch {
warn(sprintf("Py3Unicode_AsASCIIString failed(2) on address 0x%p\n",
@Py3Unicode_DATA(object)))
}
return ""
}
#
# Systemtap functions based on C functions in codeobject.c.
#
private function Py3Code_lnotab (object)
{
return @choose_defined(@Py3CodeObject(object)->co_lnotab,
@choose_defined(@Py3CodeObject(object)->co_linetable,
@cast(object, "_stp_Py3FrameObject")->f_frame->f_code->co_linetable))
}
private function Py3Code_firstlineno (object)
{
return @choose_defined(@Py3CodeObject(object)->co_firstlineno,
@cast(object, "_stp_Py3FrameObject")->f_frame->f_code->co_firstlineno)
}
private function Py3Code_nlocals (object)
{
return @choose_defined(@Py3CodeObject(object)->co_nlocals,
@cast(object, "_stp_Py3FrameObject")->f_frame->f_code->co_nlocals)
}
private function Py3Code_Addr2Line:long(code:long, addrq:long)
{
/*
* co_lnotab is used to compute the line number from a bytecode
* index, addrq. See the file Objects/lnotab_notes.txt in the
* python source for the details of the lnotab representation.
*
* We can't treat co_lnotab as a "real" null terminated string,
* since co_lnotab can have embedded null characters. So, we'll
* grab it character by character.
*/
size = Py3Bytes_Size(Py3Code_lnotab (code)) / 2
co_lnotab_sval = @Py3BytesObject(Py3Code_lnotab (code))->ob_sval
line = Py3Code_firstlineno(code)
addr = 0
p = 0
while (--size >= 0) {
addr += user_char(co_lnotab_sval + p++)
if (addr > addrq)
break
line += user_char(co_lnotab_sval + p++)
}
return line
}
private function Py310Code_Addr2Line:long(code:long, addrq:long)
{
/*
* co_lnotab is used to compute the line number from a bytecode
* index, addrq. See the file Objects/lnotab_notes.txt in the
* python source for the details of the lnotab representation
* for <= python 3.10, for >= python 3.11 see Objects/locations.md
*
* We can't treat co_lnotab as a "real" null terminated string,
* since co_lnotab can have embedded null characters. So, we'll
* grab it character by character.
*
*/
size = Py3Bytes_Size(Py3Code_lnotab (code)) / 2
co_lnotab_sval = @Py3BytesObject(Py3Code_lnotab (code))->ob_sval
line = Py3Code_firstlineno(code)
idx = 0
while (idx < 52) {
addr = user_long(co_lnotab_sval+idx)
idx = idx + 8
}
while (--size >= 0) {
addr += user_char(co_lnotab_sval)
co_lnotab_sval = co_lnotab_sval + 1
if (addr > addrq)
break
line += user_char(co_lnotab_sval)
co_lnotab_sval = co_lnotab_sval + 1
}
return line
}
#
# Systemtap functions based on C functions in frameobject.c.
#
private function Py3Frame_GetLineNumber (frame)
{
if (! Py3Frame_GetTrace (frame)) {
lineno = @choose_defined(@Py3FrameObject(frame)->f_lineno,
@cast(frame, "_stp_Py3FrameObject")->f_lineno)
} else {
lasti = @choose_defined(@Py3FrameObject(frame)->f_lasti,
@cast(frame, "_stp_Py3FrameObject")->f_frame->prev_instr - @cast(frame, "_stp_Py3FrameObject")->f_frame->f_code)
if (@defined(@Py3FrameObject(frame)->f_lasti))
lineno = Py3Code_Addr2Line(Py3Frame_GetCode(frame), lasti)
else
lineno = Py310Code_Addr2Line(Py3Frame_GetCode(frame), lasti)
}
return lineno
}
#
# Systemtap functions based on C functions in tupleobject.c.
#
private function Py3Tuple_GetItem:long(op:long, i:long)
{
if (!@Py3Tuple_Check(op)) {
error(sprintf("Py3Tuple_GetItem called on %s object at %p",
python3_get_typename(op), op))
return 0
}
if (i < 0 || i >= @Py3_SIZE(op)) {
error(sprintf("tuple index %d out of range (%d)", i, @Py3_SIZE(op)))
return 0
}
return @Py3TupleObject(op)->ob_item[i]
}
private function Py3Tuple_Repr:string(object:long)
{
if (!@Py3Tuple_Check(object)) {
error(sprintf("Py3Tuple_Repr called on %s object at %p",
python3_get_typename(object), object))
return ""
}
n = @Py3_SIZE(object)
if (n == 0)
return "()"
retstr = "("
first = 1
for (i = 0; i < n; i++) {
if (! first)
retstr .= " "
first = 0
retstr .= Py3Object_Repr(Py3Tuple_GetItem(object, i))
}
retstr .= ")"
return retstr
}
#
# Systemtap functions based on C functions in listobject.c.
#
private function Py3List_GetItem:long(op:long, i:long)
{
if (!@Py3List_Check(op)) {
error(sprintf("Py3List_GetItem called on %s object at %p",
python3_get_typename(op), op))
return 0
}
if (i < 0 || i >= @Py3_SIZE(op)) {
error(sprintf("tuple index %d out of range (%d)", i, @Py3_SIZE(op)))
return 0
}
return @Py3ListObject(op)->ob_item[i]
}
private function Py3List_Repr:string(object:long)
{
if (!@Py3List_Check(object)) {
error(sprintf("Py3List_Repr called on %s object at %p",
python3_get_typename(object), object))
return ""
}
n = @Py3_SIZE(object)
if (n == 0)
return "[]"
retstr = "["
first = 1
for (i = 0; i < n; i++) {
if (! first)
retstr .= " "
first = 0
retstr .= Py3Object_Repr(Py3List_GetItem(object, i))
}
retstr .= "]"
return retstr
}
#
# Systemtap functions based on C functions in dictobject.c.
#
@define DK_SIZE(dk) %(
(@choose_defined(@Py3DictKeysObject(@dk)->dk_size,
((1)<<@Py3DictKeysObject(@dk)->dk_log2_size)))
%)
@define DK_IXSIZE(dk) %(
%( CONFIG_64BIT == "y" %?
%( CONFIG_COMPAT == "y" %?
(@__compat_task
? (@DK_SIZE(@dk) <= 0xff ? 1 : (@DK_SIZE(@dk) <= 0xffff ? 2 : 4))
: (@DK_SIZE(@dk) <= 0xff ?
1 : (@DK_SIZE(@dk) <= 0xffff ?
2 : (@DK_SIZE(@dk) <= 0xffffffff ? 4 : 8))))
%:
(@DK_SIZE(@dk) <= 0xff ?
1 : (@DK_SIZE(@dk) <= 0xffff ?
2 : (@DK_SIZE(@dk) <= 0xffffffff ? 4 : 8)))
%)
%:
(@DK_SIZE(@dk) <= 0xff ? 1 : (@DK_SIZE(@dk) <= 0xffff ? 2 : 4))
%)
%)
@define DK_ENTRIES(dk) %(
(@choose_defined(@Py3DictKeysObject(@dk)->dk_entries,
(&@Py3DictKeyEntry(&@Py3DictKeysObject(@dk)->dk_indices[@DK_SIZE(@dk) * @DK_IXSIZE(@dk)]))))
// XXX: python 3.6?
// (&@Py3DictKeyEntry(&@Py3DictKeysObject(@dk)->dk_indices->as_1[@DK_SIZE(@dk) * @DK_IXSIZE(@dk)]))))
%)
@define DK_UNICODE_ENTRIES(dk) %(
(@choose_defined(@Py3DictKeysObject(@dk)->dk_entries,
@choose_defined(&@Py3DictUnicodeEntry(&@Py3DictKeysObject(@dk)->dk_indices[@DK_SIZE(@dk) * @DK_IXSIZE(@dk)]),
(&@Py3DictKeyEntry(&@Py3DictKeysObject(@dk)->dk_indices[@DK_SIZE(@dk) * @DK_IXSIZE(@dk)])))
)
)
%)
@define DK_KIND(dk) %(
(@choose_defined(@Py3DictKeysObject(@dk)->dk_kind, %{ DICT_KEYS_GENERAL %} ))
# @Py3DictKeysObject(@dk)->dk_kind
%)
@define ME_KEY(entry_ptr) %(
(@choose_defined(@Py3DictUnicodeEntry(@entry_ptr)->me_key,@Py3DictKeyEntry(@entry_ptr)->me_key))
%)
@define ME_VALUE(entry_ptr) %(
(@choose_defined(@Py3DictUnicodeEntry(@entry_ptr)->me_value,@Py3DictKeyEntry(@entry_ptr)->me_value))
%)
@define Py3ME_KEY(key_kind,entry_ptr) %(
((@key_kind == %{ DICT_KEYS_GENERAL %} ) ?
(@Py3DictKeyEntry(@entry_ptr)->me_key) :
(@ME_KEY(@entry_ptr)))
%)
@define Py3ME_VALUE(key_kind,entry_ptr) %(
((@key_kind == %{ DICT_KEYS_GENERAL %}) ?
(@Py3DictKeyEntry(@entry_ptr)->me_value) :
(@ME_VALUE(@entry_ptr)))
%)
private function Py3Dict_GetItem:long(op:long, key:string)
{
if (!@Py3Dict_Check(op)) {
error(sprintf("Py3Dict_GetItem called on %s object at %p",
python3_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.
// In python 3, each DictObject can be in one of two forms.
//
// Either:
// A combined table:
// ma_values == NULL, dk_refcnt == 1.
// Values are stored in the me_value field of the PyDictKeysObject.
// Or:
// A split table:
// ma_values != NULL, dk_refcnt >= 1
// Values are stored in the ma_values array.
// Only string (unicode) keys are allowed.
// If we've got a split table...
if (@Py3DictObject(op)->ma_values != 0) {
n = @DK_SIZE(@Py3DictObject(op)->ma_keys)
for (i = 0; i < n; i++) {
entry_ptr = &@DK_ENTRIES(@Py3DictObject(op)->ma_keys)[i]
key_kind = @DK_KIND(@Py3DictObject(op)->ma_keys)
if (@Py3ME_KEY(key_kind,entry_ptr) == 0
|| ! @Py3Unicode_Check(@Py3ME_KEY(key_kind,entry_ptr)))
continue
if (Py3Unicode_AsASCIIString(@Py3ME_KEY(key_kind,entry_ptr)) == key)
return Py3Dict_GetValue(op,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++) {
# if DK_IS_UNICODE ...
entry_ptr = (key_kind == %{ DICT_KEYS_GENERAL %} )
? &@DK_ENTRIES(@Py3DictObject(op)->ma_keys)[i]
: &@DK_UNICODE_ENTRIES(@Py3DictObject(op)->ma_keys)[i]
key_kind = @DK_KIND(@Py3DictObject(op)->ma_keys)
if (@Py3ME_KEY(key_kind,entry_ptr) == 0 || @Py3ME_VALUE(key_kind,entry_ptr) == 0
|| ! @Py3Unicode_Check(@Py3ME_KEY(key_kind,entry_ptr)))
continue
if (Py3Unicode_AsASCIIString(@Py3ME_KEY(key_kind,entry_ptr)) == key)
return @Py3ME_VALUE(key_kind,entry_ptr)
}
}
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",
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(Py3Dict_GetValue(op,i))
if (@Py3ME_KEY(key_kind,entry_ptr) == 0
|| ! @Py3Long_Check(@Py3ME_KEY(key_kind,entry_ptr)))
continue
if (Py3Long_AsLongLong(@Py3ME_KEY(key_kind,entry_ptr)) == key)
return Py3Dict_GetValue(op,i)
}
error(sprintf("Python variable '%s' cannot be found", key))
}
// 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(Py3Dict_GetValue(op,i))
key_kind = @DK_KIND(@Py3DictObject(op)->ma_keys)
if (@Py3ME_KEY(key_kind,entry_ptr) == 0 || @Py3ME_VALUE(key_kind,entry_ptr) == 0
|| ! @Py3Long_Check(@Py3ME_KEY(key_kind,entry_ptr)))
continue
if (Py3Long_AsLongLong(@Py3ME_KEY(key_kind,entry_ptr)) == key)
return @Py3ME_VALUE(key_kind,entry_ptr)
}
error(sprintf("Python variable '%s' cannot be found", key))
}
return 0
}
private function Py3Dict_Repr:string(object:long)
{
if (!@Py3Dict_Check(object)) {
error(sprintf("Py3Dict_Repr called on %s object at %p",
python3_get_typename(object), @__pointer(object)))
return ""
}
// If we've got a split table...
if (@Py3DictObject(object)->ma_values != 0) {
n = @Py3DictObject(object)->ma_used
if (n == 0)
return "{}"
retstr = "{"
first = 1
for (i = 0; i < n; i++) {
entry_ptr = &@DK_ENTRIES(@Py3DictObject(object)->ma_keys)[i]
key_kind = @DK_KIND(@Py3DictObject(object)->ma_keys)
if (@Py3ME_KEY(key_kind,entry_ptr) == 0)
continue
if (! first)
retstr .= " "
first = 0
retstr .= Py3Object_Repr(@Py3ME_KEY(key_kind,entry_ptr))
retstr .= ":"
retstr .= Py3Object_Repr(Py3Dict_GetValue(object,i))
}
retstr .= "}"
}
// If we've got a combined table...
else {
n = @choose_defined(@Py3DictObject(object)->ma_keys->dk_nentries,
@DK_SIZE(@Py3DictObject(object)->ma_keys))
if (n == 0)
return "{}"
retstr = "{"
first = 1
for (i = 0; i < n; i++) {
entry_ptr = (key_kind == %{ DICT_KEYS_GENERAL %} )
? &@DK_ENTRIES(@Py3DictObject(object)->ma_keys)[i]
: &@DK_UNICODE_ENTRIES(@Py3DictObject(object)->ma_keys)[i]
key_kind = @DK_KIND(@Py3DictObject(object)->ma_keys)
if (@Py3ME_KEY(key_kind,entry_ptr) == 0 || @Py3ME_VALUE(key_kind,entry_ptr) == 0)
continue
if (! first)
retstr .= " "
first = 0
retstr .= Py3Object_Repr(@Py3ME_KEY(key_kind,entry_ptr))
retstr .= ":"
retstr .= Py3Object_Repr(@Py3ME_VALUE(key_kind,entry_ptr))
}
retstr .= "}"
}
return retstr
}
#
# Systemtap functions based on C functions in object.c.
#
function Py3Object_Repr:string(object:long)
{
if (object == 0)
return "<NULL>"
if (@Py3Unicode_Check(object))
return sprintf("\"%s\"", Py3Unicode_AsASCIIString(object))
if (@Py3Long_Check(object))
return sprintf("%#x", Py3Long_AsLongLong(object))
if (@Py3Tuple_Check(object))
return Py3Tuple_Repr(object)
if (@Py3List_Check(object))
return Py3List_Repr(object)
if (@Py3Dict_Check(object))
return Py3Dict_Repr(object)
return sprintf("<%s object at %p>", python3_get_typename(object),
@__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 ""
}
# This function isn't really based on a function in object.c, but
# it is based on Py3Object_Repr().
private function Py3Object_GetItem:string(object:long, index:long)
{
if (object == 0) {
error("TypeError: None object cannot be indexed")
return 0
}
if (@Py3Tuple_Check(object))
return Py3Tuple_GetItem(object, index)
if (@Py3List_Check(object))
return Py3List_GetItem(object, index)
if (@Py3Dict_Check(object))
return Py3Dict_GetItem_FromLong(object, index)
error(sprintf("TypeError: '%s' object cannot be indexed",
python3_get_typename(object)))
return 0
}
private function Py3Object_GenericGetAttrWithDict:long(obj:long, name:string,
dict:long)
{
tp = @Py3_TYPE(obj)
if (tp->tp_dict == 0) {
return 0
}
if (dict == 0) {
dictoffset = tp->tp_dictoffset
if (dictoffset != 0) {
if (dictoffset < 0) {
error("yikes")
}
dict = user_long(obj + dictoffset);
}
}
if (dict != 0) {
res = Py3Dict_GetItem(dict, name)
if (res != 0)
return res
}
return 0
}
@define Py3Object_GenericGetAttr(obj, name) %(
Py3Object_GenericGetAttrWithDict(@obj, @name, 0)
%)
# The system translator will generate code that calls this function
function Py3Object_GetAttr:long(object:long, attr:string)
{
if (object == 0) {
error("The None object has no attributes")
return 0
}
if (@Py3_TYPE(object)->tp_getattro == 0) {
error(sprintf("The %s object has no attributes",
python3_get_typename(object)))
return 0
}
// Python 3 is quite different than python 2 when it comes to
// attributes. Classes are no longer their own type anymore, so we
// can't really check to see if something is a class.
//
// The python 3.6m source uses PyObject_GenericGetAttr() for most
// objects that support attributes. Now we need to figure out if
// that's the function we've got. If so, we know how to handle
// this object.
if (Py3Object_GenericGetAttr_addr != @Py3_TYPE(object)->tp_getattro) {
error(sprintf("Systemtap doesn't know how to get attributes from %s objects",
python3_get_typename(object)))
return 0
}
res = @Py3Object_GenericGetAttr(object, attr)
if (res != 0)
return res
error(sprintf("The %s object has no attribute '%s'",
python3_get_typename(object), attr))
return 0
}
#
# Systemtap support functions for python 3.
#
/*
* python_print_backtrace - Print python backtrace
*
* Description: This function is equivalent to
* print(python_sprint_backtrace(frame)), except that deeper stack
* tracing may be supported.
*/
function python_print_backtrace:long()
{
if ($$$$provider != "HelperSDT3") next;
frame = $$$arg3;
printf("Traceback (most recent call first):\n")
while (frame != 0) {
lineno = Py3Frame_GetLineNumber(frame)
code = Py3Frame_GetCode(frame)
try {
filename = Py3Unicode_AsASCIIString(Py3Frame_GetFilename(frame))
} catch {
filename = ""
}
try {
name = Py3Unicode_AsASCIIString(code->co_name)
} catch {
name = ""
}
# Quit when we make it back to the HelperSDT module.
if (isinstr(filename, "/HelperSDT/"))
break
printf(" File \"%s\", line %ld, in %s\n", filename, lineno, name)
# NB: We'd like to print the source line here as python does,
# but we can't. Python opens up the file and finds the
# appropriate line, but we can't really do that when we're in
# the kernel.
frame = Py3Frame_GetBack (frame)
}
}
/*
* python_sprint_backtrace - Get python backtrace
*
* Description: This function returns a string containing a python
* backtrace. Output may be truncated as per maximum string length
* (MAXSTRINGLEN).
*/
function python_sprint_backtrace:string()
{
if ($$$$provider != "HelperSDT3") next;
frame = $$$arg3;
retstr = "Traceback (most recent call first):\n"
while (frame != 0) {
lineno = Py3Frame_GetLineNumber(frame)
code = Py3Frame_GetCode(frame)
filename = Py3Unicode_AsASCIIString(Py3Frame_GetFilename(frame))
name = Py3Unicode_AsASCIIString(code->co_name)
# Quit when we make it back to the HelperSDT module.
if (isinstr(filename, "/HelperSDT/"))
break
retstr .= sprintf(" File \"%s\", line %d, in %s\n", filename,
lineno, name)
frame = Py3Frame_GetBack (frame)
}
return retstr
}
/*
* python3_get_typename - Get python object type name
*
* Description: This function returns a string describing the type of
* a python object.
*/
private function python3_get_typename:string(obj:long)
{
if (obj == 0)
return ""
return user_string(@Py3_TYPE(obj)->tp_name)
}
/*
* python3_initiatlize - Initialize python tapset
*
* Description: This function gets values from the HelperSDT module.
*
* Note that users shouldn't call this directly. The translator will
* generate code that calls this function with the correct arguments.
*/
function python3_initialize:long(arg1:long)
{
Py3Object_GenericGetAttr_addr = arg1
}
/*
* python3_get_locals - Get python local variables
*
* Description: This function returns a list of python local variables
* from a frame.
*
* frame: python frame object pointer
* flags: 0: function parameters only ($$parms), 1: locals only
* ($$locals), 2: all local vars, parameters and locals ($$vars)
*
* Note that users shouldn't call this directly, they should refer to
* '$$parms', '$$locals', and '$$vars' in a python probe and the
* translator will generate code that calls this function with the
* correct arguments.
*/
function python3_get_locals:string(frame:long, flags:long)
{
code = Py3Frame_GetCode(frame)
# flags == 2: get all variables
if (flags == 2) {
i = 0
n = code->co_nlocals
}
else {
n = code->co_argcount + code->co_kwonlyargcount
if (code->co_flags & %{ Py3_CO_VARARGS %})
n++
if (code->co_flags & %{ Py3_CO_VARKEYWORDS %})
n++
# flags == 0 (parms only): 0 to n (argcount)
if (flags == 0)
i = 0
# flags == 1 (locals only): n (argcount) to max
else if (flags == 1) {
i = n
n = code->co_nlocals
}
}
if (i < 0 || i > n) {
error(sprintf("python3_get_locals: invalid indicies (%d-%d)", i, n))
return ""
}
if (@defined(@cast(code, "PyCodeObject")->co_nlocalsplus)) {
localsplus = Py3Frame_GetLocalsplus(frame)
for (offset = 0; offset < code->co_nlocalsplus; offset++) {
key_obj = Py3Tuple_GetItem(code->co_localsplusnames, offset)
value_obj = user_long(localsplus + (offset * %{ sizeof(intptr_t) %}))
retstr .= sprintf("%s=%s", Py3Unicode_AsASCIIString(key_obj),
Py3Object_Repr(value_obj))
}
}
else {
# Each element in co_varnames is a tuple of strings. The values
# are in f_localsplus.
if (@defined(@cast(code, "PyCodeObject")->co_varnames))
p = code->co_varnames;
else
p = 0
localsplus = @choose_defined(@Py3FrameObject(frame)->f_localsplus,0)
first = 1
for (; i < n; i++) {
if (! first)
retstr .= " "
first = 0
key_obj = Py3Tuple_GetItem(p, i)
value_obj = user_long(localsplus + (i * %{ sizeof(intptr_t) %}))
retstr .= sprintf("%s=%s", Py3Unicode_AsASCIIString(key_obj),
Py3Object_Repr(value_obj))
}
}
return retstr
}
# The system translator will generate code that calls this function
function python3_get_var_obj:long(frame:long, var:string)
{
try {
f_code = Py3Frame_GetCode(frame)
n = f_code->co_nlocals
if (@defined(@cast(f_code, "PyCodeObject")->co_nlocalsplus)) {
localsplus = Py3Frame_GetLocalsplus(frame)
for (offset = 0; offset < f_code->co_nlocalsplus; offset++) {
key_obj = Py3Tuple_GetItem(f_code->co_localsplusnames, offset)
if (var == Py3Unicode_AsASCIIString(key_obj)) {
return user_long(localsplus + (offset * %{ sizeof(intptr_t) %}))
}
}
}
else {
# Each element in co_varnames is a tuple of strings. The values
# are in f_localsplus.
if (@defined(@cast(f_code, "PyCodeObject")->co_varnames))
p = f_code->co_varnames;
else
p = 0
localsplus = @choose_defined(@Py3FrameObject(frame)->f_localsplus,0)
for (i = 0; i < n; i++) {
key_obj = Py3Tuple_GetItem(p, i)
if (var == Py3Unicode_AsASCIIString(key_obj)) {
return user_long(localsplus + (i * %{ sizeof(intptr_t) %}))
}
}
}
# If we can't find it in the locals, we look in the globals.
f_globals = Py3Frame_GetGlobals(frame)
value_obj = Py3Dict_GetItem(f_globals, var)
if (value_obj == 0) {
error(sprintf("Python variable cannot be found"))
return 0
}
else {
return value_obj
}
} catch {
# printf("Python variable '%s' cannot be accessed\n", var)
}
}
function python3_get_var_obj:long(frame:long, var:string, index:long)
{
f_code = Py3Frame_GetCode(frame)
n = Py3Code_nlocals(f_code)
if (@defined(@cast(f_code, "PyCodeObject")->co_nlocalsplus)) {
localsplus = Py3Frame_GetLocalsplus(frame)
for (offset = 0; offset < f_code->co_nlocalsplus; offset++) {
key_obj = Py3Tuple_GetItem(f_code->co_localsplusnames, offset)
if (var == Py3Unicode_AsASCIIString(key_obj)) {
return user_long(localsplus + (offset * %{ sizeof(intptr_t) %}))
}
}
}
else {
# Each element in co_varnames is a tuple of strings. The values
# are in f_localsplus.
if (@defined(@cast(f_code, "PyCodeObject")->co_varnames))
p = f_code->co_varnames;
else
p = 0
localsplus = @choose_defined(@Py3FrameObject(frame)->f_localsplus,0)
printf("XXX3 %d %#lx\n", n, localsplus);
for (i = 0; i < n; i++) {
key_obj = Py3Tuple_GetItem(p, i)
if (var == Py3Unicode_AsASCIIString(key_obj)) {
return user_long(localsplus + (i * %{ sizeof(intptr_t) %}))
}
}
}
# If we can't find it in the locals, we look in the globals.
f_globals = Py3Frame_GetGlobals(frame)
value_obj = Py3Dict_GetItem(f_globals, var)
if (value_obj == 0) {
error(sprintf("Python variable '%s' cannot be found", var))
return 0
}
return value_obj
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists