|
| 1 | +--- |
| 2 | +name: find-cpython-usage |
| 3 | +description: > |
| 4 | + Find all CPython internal headers and structs used in the codebase, particularly |
| 5 | + for profiling functionality. Use this when adding support for a new Python version |
| 6 | + to identify what CPython internals we depend on. |
| 7 | +allowed-tools: |
| 8 | + - Bash |
| 9 | + - Read |
| 10 | + - Grep |
| 11 | + - Glob |
| 12 | + - TodoWrite |
| 13 | +--- |
| 14 | + |
| 15 | +# Find CPython Internal Usage Skill |
| 16 | + |
| 17 | +This skill helps identify all CPython internal headers and structures used in the |
| 18 | +codebase, which is essential when adding support for new Python versions. |
| 19 | + |
| 20 | +## When to Use This Skill |
| 21 | + |
| 22 | +Use this skill when: |
| 23 | +- Adding support for a new Python version |
| 24 | +- Investigating CPython API dependencies |
| 25 | +- Understanding what internal APIs the profiler uses |
| 26 | +- Preparing to compare CPython versions |
| 27 | + |
| 28 | +## Key Principles |
| 29 | + |
| 30 | +1. **Focus on internal headers** - These are most likely to change between versions |
| 31 | +2. **Check all native extensions** - CPython internals are used in profiling, AppSec, and internal modules |
| 32 | +3. **Look for struct field access** - Direct field access is version-sensitive |
| 33 | +4. **Document findings** - Keep track of what you find for comparison |
| 34 | + |
| 35 | +## How This Skill Works |
| 36 | + |
| 37 | +### Step 1: Find CPython Header Includes |
| 38 | + |
| 39 | +Search for CPython header includes across all C/C++/Cython files: |
| 40 | + |
| 41 | +```bash |
| 42 | +# Find all CPython internal header includes |
| 43 | +grep -r "include.*internal/pycore" ddtrace/ --include="*.c" --include="*.cpp" --include="*.h" --include="*.hpp" --include="*.pyx" |
| 44 | + |
| 45 | +# Find all CPython cpython header includes |
| 46 | +grep -r "include.*cpython" ddtrace/ --include="*.c" --include="*.cpp" --include="*.h" --include="*.hpp" --include="*.pyx" |
| 47 | + |
| 48 | +# Find all Python.h includes (indicates CPython API usage) |
| 49 | +grep -r "#include.*Python\.h" ddtrace/ --include="*.c" --include="*.cpp" --include="*.h" --include="*.hpp" --include="*.pyx" |
| 50 | + |
| 51 | +# Find frameobject.h includes (common CPython API) |
| 52 | +grep -r "#include.*frameobject\.h" ddtrace/ --include="*.c" --include="*.cpp" --include="*.h" --include="*.hpp" --include="*.pyx" |
| 53 | + |
| 54 | +# Find PyO3 FFI usage in Rust (Rust extensions may use CPython internals) |
| 55 | +grep -r "pyo3_ffi::\|pyo3::ffi::" src/native/ --include="*.rs" || true |
| 56 | +``` |
| 57 | + |
| 58 | +**Note:** These patterns search across all native extension files (`.c`, `.cpp`, `.h`, `.hpp`, `.pyx`, `.rs`) |
| 59 | +regardless of their location in the codebase. Check `setup.py` to see which extensions are built. |
| 60 | +Rust extensions use PyO3 which may access CPython internals through the `pyo3_ffi` module. |
| 61 | + |
| 62 | +### Step 2: Find Struct Field Access |
| 63 | + |
| 64 | +Search for direct struct field access and struct definitions across all native files: |
| 65 | + |
| 66 | +```bash |
| 67 | +# Find struct field accesses (arrow operator) |
| 68 | +grep -r "->f_\|->[a-z_]*\." ddtrace/ --include="*.c" --include="*.cpp" --include="*.h" --include="*.hpp" |
| 69 | + |
| 70 | +# Find struct definitions |
| 71 | +grep -r "struct.*Py" ddtrace/ --include="*.c" --include="*.cpp" --include="*.h" --include="*.hpp" |
| 72 | + |
| 73 | +# Find common CPython struct usage |
| 74 | +grep -r "PyFrameObject\|PyThreadState\|_PyInterpreterFrame" ddtrace/ --include="*.c" --include="*.cpp" --include="*.h" --include="*.hpp" --include="*.pyx" |
| 75 | +grep -r "PyFrameObject\|PyThreadState\|PyInterpreterState" src/native/ --include="*.rs" || true |
| 76 | + |
| 77 | +# Find PyCodeObject usage |
| 78 | +grep -r "PyCodeObject" ddtrace/ --include="*.c" --include="*.cpp" --include="*.h" --include="*.hpp" --include="*.pyx" |
| 79 | +grep -r "PyCodeObject" src/native/ --include="*.rs" || true |
| 80 | +``` |
| 81 | + |
| 82 | +**Look for patterns like:** |
| 83 | +- Frame structure access (`PyFrameObject`, `_PyInterpreterFrame`) |
| 84 | +- Thread state access (`PyThreadState`) |
| 85 | +- Code object access (`PyCodeObject`) |
| 86 | +- Generator/coroutine structures |
| 87 | +- Asyncio task structures |
| 88 | + |
| 89 | +### Step 3: Identify Common Structures |
| 90 | + |
| 91 | +Common CPython structures we typically access: |
| 92 | + |
| 93 | +**Frame structures:** |
| 94 | +- `PyFrameObject` / `struct _frame` |
| 95 | +- `_PyInterpreterFrame` |
| 96 | + |
| 97 | +**State structures:** |
| 98 | +- `PyThreadState` |
| 99 | +- `PyInterpreterState` |
| 100 | +- `_PyRuntimeState` |
| 101 | + |
| 102 | +**Code structures:** |
| 103 | +- `PyCodeObject` |
| 104 | + |
| 105 | +**Generator structures:** |
| 106 | +- `PyGenObject` |
| 107 | +- `PyAsyncGenASend` |
| 108 | + |
| 109 | +**Asyncio structures:** |
| 110 | +- `FutureObj` |
| 111 | +- `TaskObj` |
| 112 | + |
| 113 | +### Step 4: Document Findings |
| 114 | + |
| 115 | +Create a list of: |
| 116 | +- All headers that are included |
| 117 | +- All structs that are accessed |
| 118 | +- All struct fields that are used directly |
| 119 | + |
| 120 | +This will be used in the next step to compare against the new Python version. |
| 121 | + |
| 122 | +## Native Extensions Using CPython APIs |
| 123 | + |
| 124 | +To find all native extensions that may use CPython APIs, check `setup.py`: |
| 125 | + |
| 126 | +```bash |
| 127 | +# View all native extensions defined in setup.py |
| 128 | +grep -A 5 "Extension\|CMakeExtension\|Cython.Distutils.Extension\|RustExtension" setup.py |
| 129 | +``` |
| 130 | + |
| 131 | +The `setup.py` file defines all native extensions (C, C++, CMake, Cython, and Rust) that |
| 132 | +are built for the project. Not all extensions use CPython internals - focus on those |
| 133 | +that access frame objects, thread state, or internal structures when searching for |
| 134 | +CPython API usage. |
| 135 | + |
| 136 | +**Note:** Rust extensions use PyO3 bindings which may access CPython internals through |
| 137 | +`pyo3_ffi` module. Search Rust source files (`.rs`) for CPython API usage as well. |
| 138 | + |
| 139 | +## Common Headers to Look For |
| 140 | + |
| 141 | +The grep commands above will identify which CPython headers are actually used in the codebase. |
| 142 | +Common patterns include: |
| 143 | + |
| 144 | +**Public Headers:** |
| 145 | +- Headers matching `*.h` in `Include/` directory (e.g., `frameobject.h`, `unicodeobject.h`) |
| 146 | +- Headers in `Include/cpython/` directory (e.g., `cpython/genobject.h`) |
| 147 | + |
| 148 | +**Internal Headers (require `Py_BUILD_CORE`):** |
| 149 | +- Headers matching `internal/pycore*.h` pattern |
| 150 | +- These are most likely to change between Python versions |
| 151 | + |
| 152 | +Focus on headers that are actually found by the grep commands rather than maintaining |
| 153 | +a hardcoded list, as the headers used may change over time. |
| 154 | + |
| 155 | +## Output Format |
| 156 | + |
| 157 | +After running this skill, you should have: |
| 158 | +1. A list of all CPython headers included in the codebase |
| 159 | +2. A list of all CPython structs accessed |
| 160 | +3. A list of struct fields accessed directly |
| 161 | +4. Files that use each header/struct |
| 162 | + |
| 163 | +This information can then be used with the `compare-cpython-versions` skill to identify what changed. |
| 164 | + |
| 165 | +## Related |
| 166 | + |
| 167 | +- **compare-cpython-versions skill**: Use findings from this skill to compare versions |
0 commit comments