QRコード写真からカーネルパニックをデコードする
Decode kernel panic from QR Code photo (gist.github.com)
要約
この投稿では、Linuxカーネルパニック時に生成されるQRコードを、ZXingReaderというツールとPythonスクリプトを使用してデコードし、圧縮されたクラッシュログを復元する方法を紹介しています。スクリプトはQRコードをスキャンしてエンコードされたデータを抽出し、zlibで解凍してログを出力します。
全文翻訳
QRコード写真からカーネルパニックをデコードする
Instantly share code, notes, and snippets.
skorotkiewicz/decode-kernel-panic.py
Last active October 30, 2026 11:50
Show Gist options
-
Star 0 (0) You must be signed in to star a gist
-
Fork 0 (0) You must be signed in to fork a gist
-
Select an option
No results found
Clone this repository at <script src="https://gist.github.com/skorotkiewicz/c59e591c26661cb52b06afc42d8ac546.js"></script>
-
Save skorotkiewicz/c59e591c26661cb52b06afc42d8ac546 to your computer and use it in GitHub Desktop.
Select an option
No results found
Clone this repository at <script src="https://gist.github.com/skorotkiewicz/c59e591c26661cb52b06afc42d8ac546.js"></script>
Save skorotkiewicz/c59e591c26661cb52b06afc42d8ac546 to your computer and use it in GitHub Desktop.
decode kernel panic from QR code photo
| #!/usr/bin/env python3 | |
| """ | |
| Scan a Linux panic QR code with ZXingReader and decompress its crash log. | |
| ./decode-kernel-panic.py screenshot.png -o panic.log | |
| """ | |
| import argparse | |
| import json | |
| from pathlib import Path | |
| import subprocess | |
| import sys | |
| from urllib.parse import parse_qs, urlsplit | |
| import zlib | |
| def decode_panic_url(url): | |
| """Decode the kernel's z parameter: 17 decimal digits per 7 little-endian bytes. |
Format reference: https://github.com/kdj0c/panic_report
"""
| | parts = urlsplit(url) |
| | parameters = parse_qs(parts.query, keep_blank_values=True) |
| | if "z" not in parameters:
| | parameters = parse_qs(parts.fragment.lstrip("?"), keep_blank_values=True) |
| | if "z" not in parameters:
| | raise ValueError("QR code URL has no compressed panic data (z parameter)") |
| | if len(parameters["z"]) != 1:
| | raise ValueError("QR code URL has multiple z parameters") |
| | |
| | digits = parameters["z"][0] |
| | if not digits or not digits.isascii() or not digits.isdecimal(): |
| | raise ValueError("panic data must contain only decimal digits") |
| | |
| | # A final, partial group uses fewer digits and bytes.
| | byte_counts = {3: 1, 5: 2, 8: 3, 10: 4, 13: 5, 15: 6, 17: 7} |
| | compressed = bytearray() |
| | for offset in range(0, len(digits), 17):
| | chunk = digits[offset:offset + 17] |
| | if len(chunk) not in byte_counts:
| | raise ValueError("invalid length of encoded panic data") |
| | try:
| | compressed.extend(int(chunk).to_bytes(byte_counts[len(chunk)], "little")) |
| | except OverflowError as exc:
| | raise ValueError("encoded panic data contains an out-of-range chunk") from exc |
| | |
| | return zlib.decompress(compressed) |
| | |
| | |
| | def scan_image(image): |
| | if not image.is_file(): |
| | raise ValueError(f"image does not exist or is not a file: {image}") |
| | try:
| | result = subprocess.run(
| | ["ZXingReader", "-formats", "QRCode", "-json", str(image.resolve())],
| | capture_output=True,
| | text=True,
| | )
| | except FileNotFoundError as exc:
| | raise ValueError("ZXingReader is required; install it and put it on PATH") from exc |
| | if result.returncode != 0:
| | detail = result.stderr.strip() or "no readable QR code found"
| | raise ValueError(f"ZXingReader failed: {detail}") |
| | if not result.stdout.strip(): |
| | raise ValueError("no readable QR code found") |
| | try:
| | qr = json.loads(result.stdout) |
| | except json.JSONDecodeError as exc:
| | raise ValueError("expected one QR code in ZXingReader's JSON output") from exc |
| | if not isinstance(qr, dict) or not isinstance(qr.get("Text"), str):
| | raise ValueError("ZXingReader returned no QR code text") |
| | return qr["Text"] |
| | |
| | |
| | def main(): |
| | parser = argparse.ArgumentParser(
| | description="Scan a Linux panic screenshot with ZXingReader and decompress its log.",
| | epilog="Requires Python 3 and ZXingReader. Decoding runs locally without network access.",
| | )
| | parser.add_argument("image", type=Path, help="screenshot or photo containing the panic QR code") |
| | parser.add_argument("-o", "--output", type=Path, help="write the log to a file instead of stdout") |
| | args = parser.parse_args() |
| | try:
| | if args.output and args.output.resolve() == args.image.resolve(): |
| | raise ValueError("output must differ from the input image") |
| | log = decode_panic_url(scan_image(args.image)) |
| | if args.output:
| | args.output.write_bytes(log) |
| | else:
| | sys.stdout.buffer.write(log) |
| | except BrokenPipeError:
| | # Allow commands such as decode-kernel-panic screenshot.png | head.
| | import os |
| | os.dup2(os.open(os.devnull, os.O_WRONLY), sys.stdout.fileno()) |
| | return 0 |
| | except (OSError, ValueError, zlib.error) as exc:
| | print(f"{parser.prog}: {exc}", file=sys.stderr) |
| | return 1 |
| | return 0 |
| | |
| | |
| | if name == "main": |
| | sys.exit(main()) |
skorotkiewicz commented Oct 30, 2026 •
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
Copy link
Copy Markdown
Author
./decode-kernel-panic.py screenshot.png -o panic.log
[画像: 2026-10-30-12-26-18-715]
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment