【问题标题】:i hope access the symbol table in python我希望在 python 中访问符号表
【发布时间】:2020-06-16 09:56:35
【问题描述】:

首先,由于写的比较长,我先说抱歉。

我正在研究 Python 中的符号表,并尝试通过直接访问符号表(没有 id())来提取符号的内存地址。

所以我引用了Eli bendersky's 博客。我了解 PySEntry_Type 管理符号表(或本身)。所以,我想通过PySEntry_Type的内容,不用id()就可以找到symbol的内存地址。

然后我开始分析记忆。但是内存中的值与我所知道的不符。

首先,我研究了 symtable 和 _symtable_entry 结构。

struct symtable {
    PyObject *st_filename;          /* name of file being compiled,
                                       decoded from the filesystem encoding */
    struct _symtable_entry *st_cur; /* current symbol table entry */
    struct _symtable_entry *st_top; /* symbol table entry for module */
    PyObject *st_blocks;            /* dict: map AST node addresses
                                     *       to symbol table entries */
    PyObject *st_stack;             /* list: stack of namespace info */
    PyObject *st_global;            /* borrowed ref to st_top->ste_symbols */
    int st_nblocks;                 /* number of blocks used. kept for
                                       consistency with the corresponding
                                       compiler structure */
    PyObject *st_private;           /* name of current class or NULL */
    PyFutureFeatures *st_future;    /* modules future features that affect
                                       the symbol table */
    int recursion_depth;            /* current recursion depth */
    int recursion_limit;            /* recursion limit */
};

typedef struct _symtable_entry {
    PyObject_HEAD
    PyObject *ste_id;        /* int: key in ste_table->st_blocks */
    PyObject *ste_symbols;   /* dict: variable names to flags */
    PyObject *ste_name;      /* string: name of current block */
    PyObject *ste_varnames;  /* list of function parameters */
    PyObject *ste_children;  /* list of child blocks */
    PyObject *ste_directives;/* locations of global and nonlocal statements */
    _Py_block_ty ste_type;   /* module, class, or function */
    int ste_nested;      /* true if block is nested */
    unsigned ste_free : 1;        /* true if block has free variables */
    unsigned ste_child_free : 1;  /* true if a child block has free vars,
                                     including free refs to globals */
    unsigned ste_generator : 1;   /* true if namespace is a generator */
    unsigned ste_coroutine : 1;   /* true if namespace is a coroutine */
    unsigned ste_comprehension : 1; /* true if namespace is a list comprehension */
    unsigned ste_varargs : 1;     /* true if block has varargs */
    unsigned ste_varkeywords : 1; /* true if block has varkeywords */
    unsigned ste_returns_value : 1;  /* true if namespace uses return with
                                        an argument */
    unsigned ste_needs_class_closure : 1; /* for class scopes, true if a
                                             closure over __class__
                                             should be created */
    unsigned ste_comp_iter_target : 1; /* true if visiting comprehension target */
    int ste_comp_iter_expr; /* non-zero if visiting a comprehension range expression */
    int ste_lineno;          /* first line of block */
    int ste_col_offset;      /* offset of first line of block */
    int ste_opt_lineno;      /* lineno of last exec or import * */
    int ste_opt_col_offset;  /* offset of last exec or import * */
    struct symtable *ste_table;
} PySTEntryObject;

PyAPI_DATA(PyTypeObject) PySTEntry_Type;

然后我使用我的代码和 gdb 提取并组织了 PySEntry_Type 中的数据。

extracted data list from PySTEntry_Type
0xa376e0 : PySTEntry_Type (PySTEntry_Object)
0xa3cde0 : PyType_Type
0x74690c : String data (0x74690c : "symtable entry")
0x5782f0 : .text section
0x49b56a : .text section
0x5cb440 : PyObject_GenericGetAttr
0xa301c0 : ????
gdb-peda$ x/100x 0xa376e0
0xa376e0 <PySTEntry_Type>:  0x00000001  0x00000000  0x00a3cde0  0x00000000
0xa376f0 <PySTEntry_Type+16>:   0x00000000  0x00000000  0x0074690c  0x00000000
0xa37700 <PySTEntry_Type+32>:   0x00000068  0x00000000  0x00000000  0x00000000
0xa37710 <PySTEntry_Type+48>:   0x005782f0  0x00000000  0x00000000  0x00000000
0xa37720 <PySTEntry_Type+64>:   0x00000000  0x00000000  0x00000000  0x00000000
0xa37730 <PySTEntry_Type+80>:   0x00000000  0x00000000  0x0049b56a  0x00000000
0xa37740 <PySTEntry_Type+96>:   0x00000000  0x00000000  0x00000000  0x00000000
0xa37750 <PySTEntry_Type+112>:  0x00000000  0x00000000  0x00000000  0x00000000
0xa37760 <PySTEntry_Type+128>:  0x00000000  0x00000000  0x00000000  0x00000000
0xa37770 <PySTEntry_Type+144>:  0x005cb440  0x00000000  0x00000000  0x00000000
0xa37780 <PySTEntry_Type+160>:  0x00000000  0x00000000  0x00040000  0x00000000
0xa37790 <PySTEntry_Type+176>:  0x00000000  0x00000000  0x00000000  0x00000000
0xa377a0 <PySTEntry_Type+192>:  0x00000000  0x00000000  0x00000000  0x00000000
0xa377b0 <PySTEntry_Type+208>:  0x00000000  0x00000000  0x00000000  0x00000000
0xa377c0 <PySTEntry_Type+224>:  0x00000000  0x00000000  0x00000000  0x00000000
0xa377d0 <PySTEntry_Type+240>:  0x00a301c0  0x00000000  0x00000000  0x00000000
0xa377e0 <PySTEntry_Type+256>:  0x00000000  0x00000000  0x00000000  0x00000000
0xa377f0 <PySTEntry_Type+272>:  0x00000000  0x00000000  0x00000000  0x00000000
0xa37800 <PySTEntry_Type+288>:  0x00000000  0x00000000  0x00000000  0x00000000
0xa37810 <PySTEntry_Type+304>:  0x00000000  0x00000000  0x00000000  0x00000000
0xa37820 <PySTEntry_Type+320>:  0x00000000  0x00000000  0x00000000  0x00000000
0xa37830 <PySTEntry_Type+336>:  0x00000000  0x00000000  0x00000000  0x00000000
0xa37840 <PySTEntry_Type+352>:  0x00000000  0x00000000  0x00000000  0x00000000
---Type <return> to continue, or q <return> to quit---
0xa37850 <PySTEntry_Type+368>:  0x00000000  0x00000000  0x00000000  0x00000000
0xa37860 <PySTEntry_Type+384>:  0x00000000  0x00000000  0x00000000  0x00000000
#This is my code

import numpy as np
from ctypes import string_at
from sys import getsizeof
from binascii import hexlify
import os, sys

def print_8byte(addr, size):                         #Output in 8 bytes for easy viewing
        binary = hexlify(string_at(addr, size))     
        for i in range(int(size/8)):
                print(binary[i*16:i*16+16])

if __name__ == "__main__":
        print_8byte(0xa376e0, 400)    #0xa376e0 is PySTEntry_type

        while(1):
                addr = int(input("addr : "), 0)
                size = int(input("size : "), 0)
                print_8byte(addr, size)

hash@hash-desktop:~$ python3 test.py
b'0100000000000000'
b'e0cda30000000000'    #0xa3cde0 : PyType_Type
b'0000000000000000'
b'0c69740000000000'    #0x74690c : String data (0x74690c : "symtable entry")
b'6800000000000000'
b'0000000000000000'
b'f082570000000000'    #0x5782f0 : .text section
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'6ab5490000000000'    #0x49b56a : .text section
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'40b45c0000000000'    #0x5cb440 : PyObject_GenericGetAttr
b'0000000000000000'
b'0000000000000000'
b'0000040000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'c001a30000000000'    #0xa301c0 : ?????
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
b'0000000000000000'
addr : 

但是,似乎没有与上述 symtable 和 _symtable_entry 结构匹配的字段。

我误解了 PySEntry_Type 吗? 就算我理解错了,为什么内存中的值类型和结构体的字段不匹配呢?

抱歉,文本和数据过长,感谢您阅读

ps。使用 gdb 和我的代码提取数据没有区别。 0xa301c的值如下,可以通过我的代码查看。

addr : 0xa301c0
size : 400
b'884e640000000000'
b'0600000000000000'
b'1000000000000000'
b'0100000000000000'
b'0000000000000000'
b'c4e2730000000000'
b'0600000000000000'
b'2000000000000000'
b'0100000000000000'
b'0000000000000000'
b'fd68740000000000'
b'0600000000000000'
b'1800000000000000'
b'0100000000000000'
b'0000000000000000'
b'ad68740000000000'
.
.
.
.

【问题讨论】:

    标签: python memory-management memory-leaks memory-address symbol-table


    【解决方案1】:

    如果要检查 CPython 符号表,请使用 symtable 模块。你在做什么没有意义。

    假设您实际上查看的是PySTEntry_Type 而不是虚拟内存中完全不相关的部分,那么您查看的是低级符号表条目对象的type object。这件事是符号表条目,因为int12。它不代表符号表或符号表条目。它包含有关操作符号表条目支持的信息。

    CPython 不会在字节码编译阶段之后保留符号表。您无法检查正在运行的程序的符号表,因为它们不存在。您可以使用symtable 为代表 Python 代码的字符串创建符号表。

    【讨论】:

    • 感谢您的回答。我的目标是从符号表中提取符号的地址。如果没有符号表? id()、locals() 和 globals() 如何返回符号和值?我也使用了 symtable 但无法获取地址。
    • 他们没有。 idlocalsglobals 与编译器的符号表没有任何关系。
    • globals 获取用于管理当前全局范围的变量绑定的字典。这是运行时的事情,而不是符号表之类的编译时的事情。 locals 做了一些表面上相似但实际上更奇怪的局部变量和闭包变量。像globals 一样,它是运行时的事情,而不是编译时的事情。 id 返回一个对象的数字标签,保证与具有重叠生命周期的任何对象返回的值不同。在 CPython 上,这恰好是对象的地址,但这不是语言保证。
    猜你喜欢
    • 1970-01-01
    • 2021-12-22
    • 1970-01-01
    • 2011-08-07
    • 2012-08-28
    • 1970-01-01
    • 2016-04-21
    • 2011-09-18
    • 2011-01-13
    相关资源
    最近更新 更多