Repository files navigation

CPython Frame Disassembler

A debugging tool for Python C extensions that shows the current Python bytecode location during C-level debugging.

Purpose

When debugging C extensions, for example using GDB in VS Code, you lose track of where you are in the Python code. This tool prints the current Python frame's bytecode, making it easy to orient yourself in the CPython interpreter.

Installation

Requirements

  • Python 3.9+
  • C++ compiler with C++11 support
  • Python development headers

Build from source

pip install build
python -m build
pip install dist/*.whl

Development installation

pip install -e .

Usage

Basic usage in Python code

importframe_disassembler# Add this where you want to see the bytecodeframe_disassembler.disassemble_frame(marker="CHECKPOINT")

Output:

CHECKPOINT BEGIN line=42 /path/to/file.py
[bytecode disassembly]
CHECKPOINT END line=42 /path/to/file.py

Debugging C extensions

The main use case is debugging C extensions, for example using GDB in VS Code. In the following instructions, keyboard shortcuts are given as they are in VS Code:

  1. Set a breakpoint in your C extension.
  2. When the breakpoint hits, step out (Shift-F11) 4 times to reach the interpreter level.
  3. Step over (F10) until you're above the disassemble_frame call.
  4. Now you see exactly where you are in the Python code.
  5. Use F10/F11 to navigate to the problem area.

The bytecode output serves as a landmark in the CPython interpreter, solving the problem of getting lost in interpreter code that all looks the same.

Implementation

The tool uses a C++ extension with:

  • RAII for automatic memory management
  • GIL state management for thread safety
  • Error state preservation across calls
  • Detection and rejection of no-GIL Python builds (incompatible with debugging)

History

Originally developed by Christian Tismer for PySide (Qt for Python) debugging where it has been used in production for years. This standalone version was extracted by Adrian Georg Herrmann with contributions from Christian Tismer. It uses code from Shiboken by Qt.

License

This project is licensed under the LGPL-3.0 license.

About

CPython Frame Disassembler - Debugging tool for C extensions

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

CPython Frame Disassembler

A debugging tool for Python C extensions that shows the current Python bytecode location during C-level debugging.

Purpose

When debugging C extensions, for example using GDB in VS Code, you lose track of where you are in the Python code. This tool prints the current Python frame's bytecode, making it easy to orient yourself in the CPython interpreter.

Installation

Requirements

  • Python 3.9+
  • C++ compiler with C++11 support
  • Python development headers

Build from source

pip install build
python -m build
pip install dist/*.whl

Development installation

pip install -e .

Usage

Basic usage in Python code

importframe_disassembler# Add this where you want to see the bytecodeframe_disassembler.disassemble_frame(marker="CHECKPOINT")

Output:

CHECKPOINT BEGIN line=42 /path/to/file.py
[bytecode disassembly]
CHECKPOINT END line=42 /path/to/file.py

Debugging C extensions

The main use case is debugging C extensions, for example using GDB in VS Code. In the following instructions, keyboard shortcuts are given as they are in VS Code:

  1. Set a breakpoint in your C extension.
  2. When the breakpoint hits, step out (Shift-F11) 4 times to reach the interpreter level.
  3. Step over (F10) until you're above the disassemble_frame call.
  4. Now you see exactly where you are in the Python code.
  5. Use F10/F11 to navigate to the problem area.

The bytecode output serves as a landmark in the CPython interpreter, solving the problem of getting lost in interpreter code that all looks the same.

Implementation

The tool uses a C++ extension with:

  • RAII for automatic memory management
  • GIL state management for thread safety
  • Error state preservation across calls
  • Detection and rejection of no-GIL Python builds (incompatible with debugging)

History

Originally developed by Christian Tismer for PySide (Qt for Python) debugging where it has been used in production for years. This standalone version was extracted by Adrian Georg Herrmann with contributions from Christian Tismer. It uses code from Shiboken by Qt.

License

This project is licensed under the LGPL-3.0 license.

About

CPython Frame Disassembler - Debugging tool for C extensions

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

CPython Frame Disassembler

A debugging tool for Python C extensions that shows the current Python bytecode location during C-level debugging.

Purpose

When debugging C extensions, for example using GDB in VS Code, you lose track of where you are in the Python code. This tool prints the current Python frame's bytecode, making it easy to orient yourself in the CPython interpreter.

Installation

Requirements

  • Python 3.9+
  • C++ compiler with C++11 support
  • Python development headers

Build from source

pip install build
python -m build
pip install dist/*.whl

Development installation

pip install -e .

Usage

Basic usage in Python code

importframe_disassembler# Add this where you want to see the bytecodeframe_disassembler.disassemble_frame(marker="CHECKPOINT")

Output:

CHECKPOINT BEGIN line=42 /path/to/file.py
[bytecode disassembly]
CHECKPOINT END line=42 /path/to/file.py

Debugging C extensions

The main use case is debugging C extensions, for example using GDB in VS Code. In the following instructions, keyboard shortcuts are given as they are in VS Code:

  1. Set a breakpoint in your C extension.
  2. When the breakpoint hits, step out (Shift-F11) 4 times to reach the interpreter level.
  3. Step over (F10) until you're above the disassemble_frame call.
  4. Now you see exactly where you are in the Python code.
  5. Use F10/F11 to navigate to the problem area.

The bytecode output serves as a landmark in the CPython interpreter, solving the problem of getting lost in interpreter code that all looks the same.

Implementation

The tool uses a C++ extension with:

  • RAII for automatic memory management
  • GIL state management for thread safety
  • Error state preservation across calls
  • Detection and rejection of no-GIL Python builds (incompatible with debugging)

History

Originally developed by Christian Tismer for PySide (Qt for Python) debugging where it has been used in production for years. This standalone version was extracted by Adrian Georg Herrmann with contributions from Christian Tismer. It uses code from Shiboken by Qt.

License

This project is licensed under the LGPL-3.0 license.

About

CPython Frame Disassembler - Debugging tool for C extensions

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

CPython Frame Disassembler

A debugging tool for Python C extensions that shows the current Python bytecode location during C-level debugging.

Purpose

When debugging C extensions, for example using GDB in VS Code, you lose track of where you are in the Python code. This tool prints the current Python frame's bytecode, making it easy to orient yourself in the CPython interpreter.

Installation

Requirements

  • Python 3.9+
  • C++ compiler with C++11 support
  • Python development headers

Build from source

pip install build
python -m build
pip install dist/*.whl

Development installation

pip install -e .

Usage

Basic usage in Python code

importframe_disassembler# Add this where you want to see the bytecodeframe_disassembler.disassemble_frame(marker="CHECKPOINT")

Output:

CHECKPOINT BEGIN line=42 /path/to/file.py
[bytecode disassembly]
CHECKPOINT END line=42 /path/to/file.py

Debugging C extensions

The main use case is debugging C extensions, for example using GDB in VS Code. In the following instructions, keyboard shortcuts are given as they are in VS Code:

  1. Set a breakpoint in your C extension.
  2. When the breakpoint hits, step out (Shift-F11) 4 times to reach the interpreter level.
  3. Step over (F10) until you're above the disassemble_frame call.
  4. Now you see exactly where you are in the Python code.
  5. Use F10/F11 to navigate to the problem area.

The bytecode output serves as a landmark in the CPython interpreter, solving the problem of getting lost in interpreter code that all looks the same.

Implementation

The tool uses a C++ extension with:

  • RAII for automatic memory management
  • GIL state management for thread safety
  • Error state preservation across calls
  • Detection and rejection of no-GIL Python builds (incompatible with debugging)

History

Originally developed by Christian Tismer for PySide (Qt for Python) debugging where it has been used in production for years. This standalone version was extracted by Adrian Georg Herrmann with contributions from Christian Tismer. It uses code from Shiboken by Qt.

License

This project is licensed under the LGPL-3.0 license.

About

CPython Frame Disassembler - Debugging tool for C extensions

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

CPython Frame Disassembler

A debugging tool for Python C extensions that shows the current Python bytecode location during C-level debugging.

Purpose

When debugging C extensions, for example using GDB in VS Code, you lose track of where you are in the Python code. This tool prints the current Python frame's bytecode, making it easy to orient yourself in the CPython interpreter.

Installation

Requirements

  • Python 3.9+
  • C++ compiler with C++11 support
  • Python development headers

Build from source

pip install build
python -m build
pip install dist/*.whl

Development installation

pip install -e .

Usage

Basic usage in Python code

importframe_disassembler# Add this where you want to see the bytecodeframe_disassembler.disassemble_frame(marker="CHECKPOINT")

Output:

CHECKPOINT BEGIN line=42 /path/to/file.py
[bytecode disassembly]
CHECKPOINT END line=42 /path/to/file.py

Debugging C extensions

The main use case is debugging C extensions, for example using GDB in VS Code. In the following instructions, keyboard shortcuts are given as they are in VS Code:

  1. Set a breakpoint in your C extension.
  2. When the breakpoint hits, step out (Shift-F11) 4 times to reach the interpreter level.
  3. Step over (F10) until you're above the disassemble_frame call.
  4. Now you see exactly where you are in the Python code.
  5. Use F10/F11 to navigate to the problem area.

The bytecode output serves as a landmark in the CPython interpreter, solving the problem of getting lost in interpreter code that all looks the same.

Implementation

The tool uses a C++ extension with:

  • RAII for automatic memory management
  • GIL state management for thread safety
  • Error state preservation across calls
  • Detection and rejection of no-GIL Python builds (incompatible with debugging)

History

Originally developed by Christian Tismer for PySide (Qt for Python) debugging where it has been used in production for years. This standalone version was extracted by Adrian Georg Herrmann with contributions from Christian Tismer. It uses code from Shiboken by Qt.

License

This project is licensed under the LGPL-3.0 license.

About

CPython Frame Disassembler - Debugging tool for C extensions

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

CPython Frame Disassembler

A debugging tool for Python C extensions that shows the current Python bytecode location during C-level debugging.

Purpose

When debugging C extensions, for example using GDB in VS Code, you lose track of where you are in the Python code. This tool prints the current Python frame's bytecode, making it easy to orient yourself in the CPython interpreter.

Installation

Requirements

  • Python 3.9+
  • C++ compiler with C++11 support
  • Python development headers

Build from source

pip install build
python -m build
pip install dist/*.whl

Development installation

pip install -e .

Usage

Basic usage in Python code

importframe_disassembler# Add this where you want to see the bytecodeframe_disassembler.disassemble_frame(marker="CHECKPOINT")

Output:

CHECKPOINT BEGIN line=42 /path/to/file.py
[bytecode disassembly]
CHECKPOINT END line=42 /path/to/file.py

Debugging C extensions

The main use case is debugging C extensions, for example using GDB in VS Code. In the following instructions, keyboard shortcuts are given as they are in VS Code:

  1. Set a breakpoint in your C extension.
  2. When the breakpoint hits, step out (Shift-F11) 4 times to reach the interpreter level.
  3. Step over (F10) until you're above the disassemble_frame call.
  4. Now you see exactly where you are in the Python code.
  5. Use F10/F11 to navigate to the problem area.

The bytecode output serves as a landmark in the CPython interpreter, solving the problem of getting lost in interpreter code that all looks the same.

Implementation

The tool uses a C++ extension with:

  • RAII for automatic memory management
  • GIL state management for thread safety
  • Error state preservation across calls
  • Detection and rejection of no-GIL Python builds (incompatible with debugging)

History

Originally developed by Christian Tismer for PySide (Qt for Python) debugging where it has been used in production for years. This standalone version was extracted by Adrian Georg Herrmann with contributions from Christian Tismer. It uses code from Shiboken by Qt.

License

This project is licensed under the LGPL-3.0 license.

About

CPython Frame Disassembler - Debugging tool for C extensions

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

CPython Frame Disassembler

A debugging tool for Python C extensions that shows the current Python bytecode location during C-level debugging.

Purpose

When debugging C extensions, for example using GDB in VS Code, you lose track of where you are in the Python code. This tool prints the current Python frame's bytecode, making it easy to orient yourself in the CPython interpreter.

Installation

Requirements

  • Python 3.9+
  • C++ compiler with C++11 support
  • Python development headers

Build from source

pip install build
python -m build
pip install dist/*.whl

Development installation

pip install -e .

Usage

Basic usage in Python code

importframe_disassembler# Add this where you want to see the bytecodeframe_disassembler.disassemble_frame(marker="CHECKPOINT")

Output:

CHECKPOINT BEGIN line=42 /path/to/file.py
[bytecode disassembly]
CHECKPOINT END line=42 /path/to/file.py

Debugging C extensions

The main use case is debugging C extensions, for example using GDB in VS Code. In the following instructions, keyboard shortcuts are given as they are in VS Code:

  1. Set a breakpoint in your C extension.
  2. When the breakpoint hits, step out (Shift-F11) 4 times to reach the interpreter level.
  3. Step over (F10) until you're above the disassemble_frame call.
  4. Now you see exactly where you are in the Python code.
  5. Use F10/F11 to navigate to the problem area.

The bytecode output serves as a landmark in the CPython interpreter, solving the problem of getting lost in interpreter code that all looks the same.

Implementation

The tool uses a C++ extension with:

  • RAII for automatic memory management
  • GIL state management for thread safety
  • Error state preservation across calls
  • Detection and rejection of no-GIL Python builds (incompatible with debugging)

History

Originally developed by Christian Tismer for PySide (Qt for Python) debugging where it has been used in production for years. This standalone version was extracted by Adrian Georg Herrmann with contributions from Christian Tismer. It uses code from Shiboken by Qt.

License

This project is licensed under the LGPL-3.0 license.

About

CPython Frame Disassembler - Debugging tool for C extensions

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

CPython Frame Disassembler

A debugging tool for Python C extensions that shows the current Python bytecode location during C-level debugging.

Purpose

When debugging C extensions, for example using GDB in VS Code, you lose track of where you are in the Python code. This tool prints the current Python frame's bytecode, making it easy to orient yourself in the CPython interpreter.

Installation

Requirements

  • Python 3.9+
  • C++ compiler with C++11 support
  • Python development headers

Build from source

pip install build
python -m build
pip install dist/*.whl

Development installation

pip install -e .

Usage

Basic usage in Python code

importframe_disassembler# Add this where you want to see the bytecodeframe_disassembler.disassemble_frame(marker="CHECKPOINT")

Output:

CHECKPOINT BEGIN line=42 /path/to/file.py
[bytecode disassembly]
CHECKPOINT END line=42 /path/to/file.py

Debugging C extensions

The main use case is debugging C extensions, for example using GDB in VS Code. In the following instructions, keyboard shortcuts are given as they are in VS Code:

  1. Set a breakpoint in your C extension.
  2. When the breakpoint hits, step out (Shift-F11) 4 times to reach the interpreter level.
  3. Step over (F10) until you're above the disassemble_frame call.
  4. Now you see exactly where you are in the Python code.
  5. Use F10/F11 to navigate to the problem area.

The bytecode output serves as a landmark in the CPython interpreter, solving the problem of getting lost in interpreter code that all looks the same.

Implementation

The tool uses a C++ extension with:

  • RAII for automatic memory management
  • GIL state management for thread safety
  • Error state preservation across calls
  • Detection and rejection of no-GIL Python builds (incompatible with debugging)

History

Originally developed by Christian Tismer for PySide (Qt for Python) debugging where it has been used in production for years. This standalone version was extracted by Adrian Georg Herrmann with contributions from Christian Tismer. It uses code from Shiboken by Qt.

License

This project is licensed under the LGPL-3.0 license.

About

CPython Frame Disassembler - Debugging tool for C extensions

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Used by

Contributors

Languages