首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

深度剖析 Python 程式執行底層機制:自定義位元碼追蹤器實戰

     編輯:MySQL 資料庫相關知識

專案背景與目標

本文記錄作者基於 CPython 3.5 實作一個位元碼級追蹤器,目標為:

  • 新增自定義操作碼 DEBUG_OP
  • 實現位元碼注入機制
  • 建立 Python 回呼介面捕獲堆疊與幀資訊

核心實作步驟

1. 定義新操作碼 DEBUG_OP

在 Include/opcode.h 註冊操作碼值(此處使用 0):

#define DEBUG_OP 0
#define POP_TOP 1
#define ROT_TWO 2
// ...

2. 實作 DEBUG_OP 執行邏輯

核心任務:從幀全域變數查找 op_target 回呼、收集當前堆疊內容、呼叫回呼函數。

TARGET(DEBUG_OP) {
    _Py_IDENTIFIER(op_target);
    PyObject *target = _PyDict_GetItemId(f->f_globals, &PyId_op_target);
    if (!target) { PyErr_Clear(); DISPATCH(); }

    // 收集堆疊
    PyObject *stack_list = PyList_New(0);
    for (int i = 1; i <= STACK_LEVEL(); i++) {
        PyObject *tmp = PEEK(i) ? : Py_None;
        PyList_Append(stack_list, tmp);
    }

    // 呼叫回呼:op_target(stack_list, frame)
    PUSH(target); PUSH(stack_list); PUSH(f);
    PyObject *res = call_function(&stack_pointer, 2);
    // ... 錯誤處理與清理
}

3. 更新跳躍表使操作碼生效

修改 Python/opcode_targets.h 將 DEBUG_OP 加入分派表:

static void *opcode_targets[256] = {
    &&TARGET_DEBUG_OP,  // opcode 0
    &&TARGET_POP_TOP,
    // ...
};

位元碼注入技術

MutableCodeObject:繞過 code object 唯讀限制

class MutableCodeObject:
    args_name = ("co_argcount", "co_kwonlyargcount", ..., "co_code", "co_consts", ...)
    def __init__(self, code_obj):
        for attr in self.args_name:
            val = getattr(code_obj, attr)
            setattr(self, attr, list(val) if isinstance(val, tuple) else val)
    def get_code(self):
        args = [tuple(getattr(self, a)) if isinstance(getattr(self, a), list) else getattr(self, a)
                for a in self.args_name]
        return self.initial_code.__class__(*args)

處理跳躍指令的偏移量修正

注入 DEBUG_OP 會改變位元碼長度,需同步調整絕對/相對跳躍指令的引數:

  • 相對跳躍(FOR_ITER, JUMP_FORWARD 等):目標位址 > 插入點時,引數 +1
  • 絕對跳躍(JUMP_ABSOLUTE, POP_JUMP_IF_TRUE 等):目標位址 > 插入點時,引數 +1

封裝為可用追蹤器

實作 Trace 基類與 DummyTrace 示例,支援:

  • 自動追蹤被呼叫函數(do_auto_follow)
  • 記錄堆疊變化、指令流、幀切換
  • 輸出可讀報表

實際輸出範例

=== Entering New Frame lol (0x7fde9eaebdb0) ===
[0, ]
[2, ]
[False, ]
...
0        LOAD_FAST             0        x
1        DEBUG_OP              None
...

總結與延伸

此專案深度揭示 CPython 主迴圈、C API 程式設計、位元碼結構。後續可延伸:修改堆疊值實現熱修復、建立視覺化除錯器、分析生成器/協程/上下文管理器的位元碼行為。

完整程式碼:文末附有專案完整原始碼連結。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved