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"]]