HN 日本語サマリー

← 一覧へ戻る
プログラミング

QRコード写真からカーネルパニックをデコードする

Decode kernel panic from QR Code photo (gist.github.com)

7 pointsby modinfo1 コメント

要約

この投稿では、Linuxカーネルパニック時に生成されるQRコードを、ZXingReaderというツールとPythonスクリプトを使用してデコードし、圧縮されたクラッシュログを復元する方法を紹介しています。スクリプトはQRコードをスキャンしてエンコードされたデータを抽出し、zlibで解凍してログを出力します。

全文翻訳

QRコード写真からカーネルパニックをデコードする

Instantly share code, notes, and snippets.

[画像: @skorotkiewicz]

skorotkiewicz/decode-kernel-panic.py

Last active October 30, 2026 11:50

Show Gist options

  • Download ZIP

  • 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

    Learn more about clone URLs

    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

Learn more about clone URLs

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.

Download ZIP

decode kernel panic from QR code photo

Raw

decode-kernel-panic.py

#!/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]

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