aboutsummaryrefslogtreecommitdiff
path: root/scripts/gdb
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/gdb')
-rw-r--r--scripts/gdb/teachos.py47
-rw-r--r--scripts/gdb/teachos/__init__.py8
-rw-r--r--scripts/gdb/teachos/dump_mb2i.py241
-rw-r--r--scripts/gdb/toolchain.py35
4 files changed, 331 insertions, 0 deletions
diff --git a/scripts/gdb/teachos.py b/scripts/gdb/teachos.py
new file mode 100644
index 0000000..355f6b9
--- /dev/null
+++ b/scripts/gdb/teachos.py
@@ -0,0 +1,47 @@
+import sys
+import os
+import gdb
+import importlib.util
+
+script_path = os.path.abspath(__file__)
+script_root = os.path.dirname(script_path)
+repo_root = os.path.dirname(os.path.dirname(script_root))
+
+if script_root not in sys.path:
+ sys.path.insert(0, script_root)
+
+from teachos.dump_mb2i import DumpMB2I
+
+components = {
+ "kstd": "libs/kstd/gdb",
+ "kapi": "kapi/gdb",
+}
+
+for component, path in components.items():
+ full_path = os.path.join(repo_root, *path.split("/"))
+ init_file = os.path.join(full_path, "__init__.py")
+
+ if os.path.isfile(init_file):
+ try:
+ spec = importlib.util.spec_from_file_location(component, init_file)
+ module = importlib.util.module_from_spec(spec)
+ sys.modules[component] = module
+ spec.loader.exec_module(module)
+
+ if hasattr(module, "register_printers"):
+ module.register_printers(gdb.current_objfile())
+ gdb.write(f"Info: Registered pretty printers for '{component}'.\n")
+ else:
+ gdb.write(
+ f"Warning: '{component}' does not have 'register_printers' function\n"
+ )
+ except Exception as e:
+ gdb.write(f"Warning: Failed to load '{component}' pretty printers: {e}\n")
+ else:
+ gdb.write(f"Warning: GDB extension init not found: '{init_file}'\n")
+
+gdb.write("Info: Loaded TeachOS pretty printers.\n")
+
+DumpMB2I()
+
+gdb.write("Info: Loaded TeachOS tools.\n") \ No newline at end of file
diff --git a/scripts/gdb/teachos/__init__.py b/scripts/gdb/teachos/__init__.py
new file mode 100644
index 0000000..a5eca92
--- /dev/null
+++ b/scripts/gdb/teachos/__init__.py
@@ -0,0 +1,8 @@
+def format_size(size):
+ for unit in ["Bytes", "KiB", "MiB", "GiB", "TiB", "PiB"]:
+ if size < 1024.0:
+ if unit == "Bytes":
+ return f"{int(size)} {unit}"
+ return f"{size:.2f} {unit}"
+ size /= 1024.0
+ return f"{size:.2f} PiB"
diff --git a/scripts/gdb/teachos/dump_mb2i.py b/scripts/gdb/teachos/dump_mb2i.py
new file mode 100644
index 0000000..0657ebd
--- /dev/null
+++ b/scripts/gdb/teachos/dump_mb2i.py
@@ -0,0 +1,241 @@
+import gdb
+import struct
+from enum import IntEnum
+from teachos import format_size
+
+
+class TagType(IntEnum):
+ END = 0
+ CMDLINE = 1
+ BOOT_LOADER_NAME = 2
+ MODULE = 3
+ BASIC_MEMINFO = 4
+ BOOTDEV = 5
+ MMAP = 6
+ VBE = 7
+ FRAMEBUFFER = 8
+ ELF_SECTIONS = 9
+ APM = 10
+ EFI32_SYSTEM_TABLE_POINTER = 11
+ EFI64_SYSTEM_TABLE_POINTER = 12
+ SMBIOS_TABLES = 13
+ ACPI_OLD = 14
+ ACPI_NEW = 15
+ NETWORKING = 16
+ EFI_MEMORY_MAP = 17
+ EFI_BOOT_SERVICES_NOT_TERMINATED = 18
+ EFI32_IMAGE_HANDLE_POINTER = 19
+ EFI64_IMAGE_HANDLE_POINTER = 20
+ LOAD_BASE_ADDR = 21
+
+
+class MemoryType(IntEnum):
+ AVAILABLE = 1
+ RESERVED = 2
+ ACPI_RECLAIM = 3
+ NVS = 4
+ BAD = 5
+
+
+class FramebufferType(IntEnum):
+ INDEXED = 0
+ RGB = 1
+ TEXT = 2
+
+
+TAG_NAMES = {
+ TagType.END: "End of Tags",
+ TagType.CMDLINE: "Boot Command Line",
+ TagType.BOOT_LOADER_NAME: "Boot Loader Name",
+ TagType.MODULE: "Boot Module",
+ TagType.BASIC_MEMINFO: "Basic Memory Information",
+ TagType.BOOTDEV: "BIOS Boot Device",
+ TagType.MMAP: "Memory Map",
+ TagType.VBE: "VBE Info",
+ TagType.FRAMEBUFFER: "Framebuffer Info",
+ TagType.ELF_SECTIONS: "ELF Symbols",
+ TagType.APM: "APM Table",
+ TagType.EFI32_SYSTEM_TABLE_POINTER: "EFI 32-bit System Table Pointer",
+ TagType.EFI64_SYSTEM_TABLE_POINTER: "EFI 64-bit System Table Pointer",
+ TagType.SMBIOS_TABLES: "SMBIOS Tables",
+ TagType.ACPI_OLD: "ACPI old RSDP (1.0)",
+ TagType.ACPI_NEW: "ACPI new RSDP (2.0+)",
+ TagType.NETWORKING: "Networking Information",
+ TagType.EFI_MEMORY_MAP: "EFI Memory Map",
+ TagType.EFI_BOOT_SERVICES_NOT_TERMINATED: "EFI Boot Services Not Terminated",
+ TagType.EFI32_IMAGE_HANDLE_POINTER: "EFI 32-bit Image Handle Pointer",
+ TagType.EFI64_IMAGE_HANDLE_POINTER: "EFI 64-bit Image Handle Pointer",
+ TagType.LOAD_BASE_ADDR: "Image Load Base Physical Address",
+}
+
+MEMORY_TYPES = {
+ MemoryType.AVAILABLE: "Available",
+ MemoryType.RESERVED: "Reserved",
+ MemoryType.ACPI_RECLAIM: "ACPI Reclaim",
+ MemoryType.NVS: "Non-volatile storage",
+ MemoryType.BAD: "Bad Memory",
+}
+
+FRAMEBUFFER_TYPES = {
+ FramebufferType.INDEXED: "Indexed Color",
+ FramebufferType.RGB: "RGB",
+ FramebufferType.TEXT: "Text Mode",
+}
+
+
+INDENT = f"{' '*11}"
+
+
+class DumpMB2I(gdb.Command):
+ """
+ Dump the information provided by the Multiboot2 loader.
+ Usage: dump_mb2i <address_expression>
+ Example: dump_mb2i $rbx
+ dump_mb2i 0x8000
+ """
+
+ def __init__(self):
+ super(DumpMB2I, self).__init__("dump_mb2i", gdb.COMMAND_USER)
+
+ def invoke(self, arg, from_tty):
+ if not arg:
+ gdb.write(
+ "Error: please provide the address of the Multiboot2 information structure.\n"
+ )
+ return
+
+ try:
+ address = int(gdb.parse_and_eval(arg))
+ except gdb.error as e:
+ gdb.write(f"Error: Invalid address expression: {e}\n")
+ return
+
+ inferior = gdb.selected_inferior()
+
+ try:
+ header_data = inferior.read_memory(address, 8).tobytes()
+ total_size, reserved = struct.unpack("<II", header_data)
+ except gdb.MemoryError:
+ gdb.write(f"Error: Cannot read memory at {address:#018x}\n")
+ return
+
+ if total_size < 8 or total_size > 1024 * 1024:
+ gdb.write(
+ f"Warning: suspicious total size ({total_size} bytes). Aborting.\n"
+ )
+ return
+
+ gdb.write(f"+{'-'*70}+\n")
+ gdb.write(f"| Multiboot2 Boot Information Payload{' ':>34}|\n")
+ gdb.write(f"+{'-'*70}+\n")
+ gdb.write(f"Base Address: {address:#018x}\nTotal Size: {total_size} Bytes\n\n")
+
+ offset = 8
+
+ while offset < total_size:
+ tag_address = address + offset
+
+ try:
+ tag_header = inferior.read_memory(tag_address, 8).tobytes()
+ tag_type, tag_size = struct.unpack("<II", tag_header)
+ except gdb.MemoryError:
+ gdb.write(
+ f"Error: Cannot read memory at {tag_address:#018x} (offset {offset})\n"
+ )
+ break
+
+ if tag_type == TagType.END and tag_size == 8:
+ break
+
+ self._print_tag(inferior, tag_address, tag_type, tag_size)
+
+ offset += (tag_size + 7) & ~7
+
+ def _print_tag(self, inferior, tag_address, tag_type, tag_size):
+ name = TAG_NAMES.get(tag_type, f"Unknown Tag")
+ size = format_size(tag_size)
+ payload = format_size(tag_size - 8)
+ gdb.write(f"[Tag {tag_type:#04x}] {name} (size: {size} | payload: {payload})\n")
+
+ if tag_size <= 8 and tag_type != TagType.END:
+ return
+
+ try:
+ data = inferior.read_memory(tag_address + 8, tag_size - 8).tobytes()
+
+ handlers = {
+ TagType.CMDLINE: self._write_string_tag,
+ TagType.BOOT_LOADER_NAME: self._write_string_tag,
+ TagType.MODULE: self._write_module_tag,
+ TagType.BASIC_MEMINFO: self._write_basic_memory_info_tag,
+ TagType.BOOTDEV: self._write_boot_device_tag,
+ TagType.MMAP: self._write_memory_map_tag,
+ TagType.LOAD_BASE_ADDR: self._write_image_load_base_physical_address_tag,
+ TagType.FRAMEBUFFER: self._write_framebuffer_info_tag,
+ }
+
+ handler = handlers.get(tag_type, self._write_unknown_tag)
+ handler(data)
+
+ except Exception as e:
+ gdb.write(
+ f"{INDENT}<failed to decode tag: {e} ({tag_type:#04x} | {tag_size:#06x})>\n"
+ )
+
+ def _write_string_tag(self, data):
+ text = data.split(b"\x00")[0].decode("ascii", "replace")
+ gdb.write(f'{INDENT}"{text}"\n')
+
+ def _write_module_tag(self, data):
+ start, end = struct.unpack_from("<II", data)
+ string = data[8:].split(b"\x00")[0].decode("ascii", "replace")
+ gdb.write(
+ f"{INDENT}start: {start:#010x} | end: {end:#010x} | size: {format_size(end - start)}\n"
+ )
+ if string:
+ gdb.write(f'{INDENT}string: "{string}"\n')
+
+ def _write_basic_memory_info_tag(self, data):
+ lower, upper = struct.unpack_from("<II", data)
+ gdb.write(
+ f"{INDENT}upper memory: {format_size(upper * 1024)} | lower memory: {format_size(lower * 1024)}\n"
+ )
+
+ def _write_boot_device_tag(self, data):
+ device, partition, sub_partition = struct.unpack_from("<III", data)
+ gdb.write(
+ f"{INDENT}device: {device:#04x} | partition: {partition:#06x} | sub-partition: {sub_partition:#06x}\n"
+ )
+
+ def _write_memory_map_tag(self, data):
+ entry_size, entry_version = struct.unpack_from("<II", data)
+ if entry_size < 24:
+ return
+ num_entries = (len(data) - 8) // entry_size
+ for i in range(num_entries):
+ entry_offset = 8 + i * entry_size
+ base, length, memory_type = struct.unpack_from("<QQI", data, entry_offset)
+ type_string = MEMORY_TYPES.get(memory_type, "Unknown")
+ gdb.write(
+ f"{INDENT}[{i:02d}] {base:#018x} - {base + length:#018x} | {format_size(length)} | type: {type_string}\n"
+ )
+
+ def _write_image_load_base_physical_address_tag(self, data):
+ base = struct.unpack("<I", data)[0]
+ gdb.write(f"{INDENT}address: {base:#010x}\n")
+
+ def _write_framebuffer_info_tag(self, data):
+ address, pitch, width, height, bpp, type = struct.unpack_from("<QIIIBB", data)
+ type_string = FRAMEBUFFER_TYPES.get(type, "Unknown")
+ gdb.write(f"{INDENT}address: {address:#010x} | type: {type_string}\n")
+ gdb.write(f"{INDENT}depth: {bpp} | pitch: {format_size(pitch)}\n")
+ if type == FramebufferType.TEXT:
+ gdb.write(f"{INDENT}width: {width} chars | height: {height} chars\n")
+ else:
+ gdb.write(f"{INDENT}width: {width} px | height: {height} px\n")
+
+ def _write_unknown_tag(self, data):
+ for i in range(0, len(data), 16):
+ chunk = data[i : i + 16]
+ hex_chunk = " ".join([f"{b:02x}" for b in chunk])
+ gdb.write(f"{INDENT}{i:#010x}: {hex_chunk}\n")
diff --git a/scripts/gdb/toolchain.py b/scripts/gdb/toolchain.py
new file mode 100644
index 0000000..bbb7810
--- /dev/null
+++ b/scripts/gdb/toolchain.py
@@ -0,0 +1,35 @@
+import os
+import subprocess
+import sys
+
+
+def setup_toolchain_debugging():
+ try:
+ gcc_path = (
+ subprocess.check_output(["which", "x86_64-pc-elf-g++"])
+ .decode("utf-8")
+ .strip()
+ )
+ python_dir = None
+
+ share_path = os.path.join(os.path.dirname(os.path.dirname(gcc_path)), "share")
+ for root, dirs, _ in os.walk(share_path):
+ if "libstdcxx" in dirs:
+ python_dir = root
+ break
+
+ if python_dir:
+ sys.path.insert(0, python_dir)
+
+ from libstdcxx.v6.printers import register_libstdcxx_printers
+ from libstdcxx.v6.xmethods import register_libstdcxx_xmethods
+
+ register_libstdcxx_printers(None)
+ register_libstdcxx_xmethods(None)
+
+ print(f"Loaded Printers & Xmethods from: {python_dir}")
+ except Exception as e:
+ print(f"Debug setup failed: {e}")
+
+
+setup_toolchain_debugging()