Source code for libdebug.utils.syscall_utils

#
# This file is part of libdebug Python library (https://github.com/libdebug/libdebug).
# Copyright (c) 2024 Roberto Alessandro Bertolini. All rights reserved.
# Licensed under the MIT license. See LICENSE file in the project root for details.
#

import functools
import json
from pathlib import Path

import requests

from libdebug.utils.libcontext import libcontext

SYSCALLS_REMOTE = "https://syscalls.mebeim.net/db"
LOCAL_FOLDER_PATH = (Path.home() / ".cache" / "libdebug" / "syscalls").resolve()


[docs] def get_remote_definition_url(arch: str) -> str: """Get the URL of the remote syscall definition file.""" match arch: case "amd64": return f"{SYSCALLS_REMOTE}/x86/64/x64/latest/table.json" case _: raise ValueError(f"Architecture {arch} not supported")
[docs] def fetch_remote_syscall_definition(arch: str) -> dict: """Fetch the syscall definition file from the remote server.""" url = get_remote_definition_url(arch) response = requests.get(url, timeout=1) response.raise_for_status() # Save the response to a local file with Path(f"{LOCAL_FOLDER_PATH}/{arch}.json").open("w") as f: f.write(response.text) return response.json()
[docs] @functools.cache def get_syscall_definitions(arch: str) -> dict: """Get the syscall definitions for the specified architecture.""" LOCAL_FOLDER_PATH.mkdir(parents=True, exist_ok=True) if (LOCAL_FOLDER_PATH / "{arch}.json").exists(): try: with (LOCAL_FOLDER_PATH / "{arch}.json").open() as f: return json.load(f) except json.decoder.JSONDecodeError: pass return fetch_remote_syscall_definition(arch)
[docs] @functools.cache def resolve_syscall_number(name: str) -> int: """Resolve a syscall name to its number.""" definitions = get_syscall_definitions(libcontext.arch) for syscall in definitions["syscalls"]: if syscall["name"] == name: return syscall["number"] raise ValueError(f'Syscall "{name}" not found')
[docs] @functools.cache def resolve_syscall_name(number: int) -> str: """Resolve a syscall number to its name.""" definitions = get_syscall_definitions(libcontext.arch) for syscall in definitions["syscalls"]: if syscall["number"] == number: return syscall["name"] raise ValueError(f'Syscall number "{number}" not found')
[docs] @functools.cache def resolve_syscall_arguments(number: int) -> list[str]: """Resolve a syscall number to its argument definition.""" definitions = get_syscall_definitions(libcontext.arch) for syscall in definitions["syscalls"]: if syscall["number"] == number: return syscall["signature"] raise ValueError(f'Syscall number "{number}" not found')
[docs] @functools.cache def get_all_syscall_numbers() -> list[int]: """Retrieves all the syscall numbers.""" definitions = get_syscall_definitions(libcontext.arch) return [syscall["number"] for syscall in definitions["syscalls"]]