Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Allow Syscall name extraction on generic Linux #1

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
main.o
syscall_nr.h
ministrace
6 changes: 4 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
all: ministrace

ministrace: syscall_nr.h main.o
.PHONY: run

ministrace: syscall_nr.h main.c
$(CC) -o $@ $^

%.o: %.c
$(CC) -c $^

syscall_nr.h:
python get_syscalls.py /usr/include/asm/unistd_64.h > syscall_nr.h
./get_syscalls.sh
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ This repository contains a basic reimplementation of the `strace` tool.

## Building

Before building, ensure that you have the Linux headers installed on your system.
On Debian-based systems, try installing them with apt: `sudo apt install linux-headers-xxxx`.

Run `make all` to build `ministrace`. Run `./ministrace <program> <args>` to
trace `program`.

Expand All @@ -15,3 +18,5 @@ macros in `unistd_64.h` to generate a mapping.
Note that we have no information on the number and types of arguments to
syscalls. The two possible approaches here seem to be parsing syscall
implementations or manually mapping syscall numbers to argument count and types.

NOTE: The syscall extraction was tested on both Debian, Fedora and NixOS.
5 changes: 3 additions & 2 deletions get_syscalls.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import sys


def main():
syscalls = dict()
with open(sys.argv[1], "r") as fp:
Expand All @@ -9,14 +10,14 @@ def main():
definition = line[13:]
parts = definition.split()
syscalls[int(parts[1])] = parts[0]
print("void populate_syscalls() {")

print("#define SYSCALL_NAME(nr) SYSCALLS[nr]")
print(f"char *SYSCALLS[{max(syscalls.keys())}];")
print("}")
print("void populate_syscalls() {")
for (k, v) in syscalls.items():
print(f" SYSCALLS[{k}] = \"{v}\";")
print("}")


if __name__ == "__main__":
main()
74 changes: 74 additions & 0 deletions get_syscalls.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env bash

GCC="gcc"
SED="sed"

HEADER_FILE="unistd_64.h"

ensure_avail() {
command=$1
if ! which "${command}" > /dev/null; then
echo "ERROR: the ${command} is not available on your system."
exit 1
fi

echo "[OK] ${command} available."
}

get_header_locations() {
RAW=$(LC_ALL=C "${GCC}" -v -E -xc - </dev/null 2>&1 | LC_ALL=C "${SED}" -ne '/starts here/,/End of/p')

for word in $RAW; do
if [[ $word == /* ]]; then
echo "$word"
fi
done
}

ensure_avail gcc
ensure_avail sed

headers=$(get_header_locations)

CANDIDATES=""

for header in $headers; do
echo "CHECKING include dir ${header}..."
matches=$(find "${header}" -name "${HEADER_FILE}")

if [ "${#matches}" != "0" ]; then
echo "[OK] FOUND ${matches}"
CANDIDATES+=" ${matches}"
fi

done


if [ "${#CANDIDATES}" = "0" ]; then
echo "[ERR] none of the search directories contains ${HEADER_FILE}"
exit 1
fi

success=0

echo "CAN: $CANDIDATES"

for candidate in $CANDIDATES; do
OUTPUT=""

if ! OUTPUT=$(python3 ./get_syscalls.py "${candidate}" 2>&1 ); then
echo "[ERR] File ${candidate} is invalid."
else
echo "[OK] File ${candidate} is valid."
success=1
break
fi
done

if [ $success -eq 0 ]; then
echo "${OUTPUT}"
echo "[ERR] could not extract syscalls: all sources failed"
exit 1
else
echo "$OUTPUT" > ./syscall_nr.h
fi