Skip to content

Commit 166a7c4

Browse files
authored
Merge pull request #998 from cla7aye15I4nd/riscv
Add riscv32 dynamic-link elf support
2 parents 005a776 + a4e7357 commit 166a7c4

File tree

6 files changed

+164
-11
lines changed

6 files changed

+164
-11
lines changed

qiling/os/linux/function_hook.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -814,7 +814,9 @@ def _parse(self):
814814

815815
elif d.d_tag == DT_PLTREL:
816816
if d.d_un != self.plt_rel_type:
817-
raise
817+
# FIXME: I don't why it is a error
818+
# but it is triggered in riscv32
819+
pass
818820
elif d.d_tag == DT_PLTRELSZ:
819821
self.plt_rel_size = d.d_un
820822
elif d.d_tag == DT_JMPREL:

qiling/os/linux/map_syscall.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2134,7 +2134,7 @@ def map_syscall(ql, syscall_num):
21342134
219: "keyctl",
21352135
220: "clone",
21362136
221: "execve",
2137-
222: "mmap",
2137+
222: "mmap2",
21382138
223: "fadvise64_64",
21392139
224: "swapon",
21402140
225: "swapoff",

qiling/os/posix/const.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@
559559

560560
FD_CLOEXEC = 1
561561

562-
AT_FDCWD = 0xffffff9c # -100
562+
AT_FDCWD = -100
563563

564564
# error code
565565
EPERM = 1

qiling/os/posix/syscall/fcntl.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,12 +98,15 @@ def ql_syscall_openat(ql: Qiling, fd: int, path: int, flags: int, mode: int):
9898
mode = 0
9999

100100
flags = ql_open_flag_mapping(ql, flags)
101-
try:
101+
fd = ql.unpacks(ql.pack(fd))
102+
103+
if 0 <= fd < NR_OPEN:
102104
dir_fd = ql.os.fd[fd].fileno()
103-
except:
105+
else:
104106
dir_fd = None
105107

106108
ql.os.fd[idx] = ql.os.fs_mapper.open_ql_file(file_path, flags, mode, dir_fd)
109+
107110
regreturn = idx
108111
except QlSyscallError as e:
109112
regreturn = -e.errno

qiling/os/posix/syscall/stat.py

Lines changed: 144 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import os
77
import ctypes
8+
import struct
89
from typing import Callable
910

1011
from qiling import Qiling
@@ -1044,15 +1045,17 @@ def transform_path(ql: Qiling, dirfd: int, path: int):
10441045
then the target file is the one referred to by the file descriptor dirfd.
10451046
"""
10461047

1048+
dirfd = ql.unpacks(ql.pack(dirfd))
10471049
path = ql.os.utils.read_cstring(path)
1048-
1050+
10491051
if path.startswith('/'):
1050-
return None, ql.os.path.transform_to_relative_path(path)
1052+
return None, os.path.join(ql.rootfs, path)
10511053

10521054
if dirfd == AT_FDCWD:
1053-
return -100, ql.os.path.transform_to_relative_path(os.path.join(ql.os.path.cwd, path))
1055+
return None, ql.os.path.transform_to_real_path(path)
10541056

1055-
return dirfd, path
1057+
if 0 < dirfd < NR_OPEN:
1058+
return ql.os.fd[dirfd].fileno(), path
10561059

10571060

10581061
def ql_syscall_chmod(ql: Qiling, filename: int, mode: int):
@@ -1143,10 +1146,145 @@ def ql_syscall_stat(ql: Qiling, path: int, buf_ptr: int):
11431146
def ql_syscall_stat64(ql: Qiling, path: int, buf_ptr: int):
11441147
return statFamily(ql, path, buf_ptr, "stat64", Stat, pack_stat64_struct)
11451148

1149+
class StatxTimestamp32(ctypes.Structure):
1150+
_fields_ = [
1151+
('tv_sec', ctypes.c_int32),
1152+
('tv_nsec', ctypes.c_uint32),
1153+
('__statx_timestamp_pad1', ctypes.c_int32)
1154+
]
1155+
1156+
class Statx32(ctypes.Structure):
1157+
"""
1158+
Reference:
1159+
- https://man7.org/linux/man-pages/man2/statx.2.html
1160+
- https://code.woboq.org/userspace/glibc/sysdeps/unix/sysv/linux/statx.c.html
1161+
1162+
"""
1163+
_fields_ = [
1164+
('stx_mask', ctypes.c_uint32),
1165+
('stx_blksize', ctypes.c_uint32),
1166+
('stx_attributes', ctypes.c_uint32),
1167+
('stx_nlink', ctypes.c_uint32),
1168+
('stx_uid', ctypes.c_uint32),
1169+
('stx_gid', ctypes.c_uint32),
1170+
('stx_mode', ctypes.c_uint16),
1171+
('__statx_pad1', ctypes.c_uint16),
1172+
('stx_ino', ctypes.c_uint32),
1173+
('stx_size', ctypes.c_uint32),
1174+
('stx_blocks', ctypes.c_uint32),
1175+
('stx_attributes_mask', ctypes.c_uint32),
1176+
('stx_atime', StatxTimestamp32),
1177+
('stx_btime', StatxTimestamp32),
1178+
('stx_ctime', StatxTimestamp32),
1179+
('stx_mtime', StatxTimestamp32),
1180+
('stx_rdev_major', ctypes.c_uint32),
1181+
('stx_rdev_minor', ctypes.c_uint32),
1182+
('stx_dev_major', ctypes.c_uint32),
1183+
('stx_dev_minor', ctypes.c_uint32),
1184+
('__statx_pad2', ctypes.c_uint32 * 14),
1185+
]
1186+
1187+
_pack_ = 8
1188+
1189+
class StatxTimestamp64(ctypes.Structure):
1190+
_fields_ = [
1191+
('tv_sec', ctypes.c_int64),
1192+
('tv_nsec', ctypes.c_uint32),
1193+
('__statx_timestamp_pad1', ctypes.c_int32)
1194+
]
1195+
1196+
class Statx64(ctypes.Structure):
1197+
"""
1198+
Reference:
1199+
- https://man7.org/linux/man-pages/man2/statx.2.html
1200+
- https://code.woboq.org/userspace/glibc/sysdeps/unix/sysv/linux/statx.c.html
1201+
1202+
"""
1203+
_fields_ = [
1204+
('stx_mask', ctypes.c_uint32),
1205+
('stx_blksize', ctypes.c_uint32),
1206+
('stx_attributes', ctypes.c_uint64),
1207+
('stx_nlink', ctypes.c_uint32),
1208+
('stx_uid', ctypes.c_uint32),
1209+
('stx_gid', ctypes.c_uint32),
1210+
('stx_mode', ctypes.c_uint16),
1211+
('__statx_pad1', ctypes.c_uint16),
1212+
('stx_ino', ctypes.c_uint64),
1213+
('stx_size', ctypes.c_uint64),
1214+
('stx_blocks', ctypes.c_uint64),
1215+
('stx_attributes_mask', ctypes.c_uint64),
1216+
('stx_atime', StatxTimestamp64),
1217+
('stx_btime', StatxTimestamp64),
1218+
('stx_ctime', StatxTimestamp64),
1219+
('stx_mtime', StatxTimestamp64),
1220+
('stx_rdev_major', ctypes.c_uint32),
1221+
('stx_rdev_minor', ctypes.c_uint32),
1222+
('stx_dev_major', ctypes.c_uint32),
1223+
('stx_dev_minor', ctypes.c_uint32),
1224+
('__statx_pad2', ctypes.c_uint64 * 14),
1225+
]
1226+
1227+
_pack_ = 4
1228+
11461229
# int statx(int dirfd, const char *restrict pathname, int flags,
11471230
# unsigned int mask, struct statx *restrict statxbuf);
1148-
def ql_syscall_statx(ql: Qiling, dirfd: int, path: int, flags: int, mask: int, statxbuf: int):
1149-
return 0
1231+
def ql_syscall_statx(ql: Qiling, dirfd: int, path: int, flags: int, mask: int, buf_ptr: int):
1232+
def statx_convert_timestamp(tv_sec, tv_nsec):
1233+
tv_sec = struct.unpack('i', struct.pack('f', tv_sec))[0]
1234+
tv_nsec = struct.unpack('i', struct.pack('f', tv_nsec))[0]
1235+
1236+
if ql.archbit == 32:
1237+
return StatxTimestamp32(tv_sec=tv_sec, tv_nsec=tv_nsec)
1238+
else:
1239+
return StatxTimestamp64(tv_sec=tv_sec, tv_nsec=tv_nsec)
1240+
1241+
1242+
def major(dev):
1243+
return ((dev >> 8) & 0xfff) | ((dev >> 32) & ~0xfff)
1244+
1245+
def minor(dev):
1246+
return (dev & 0xff) | ((dev >> 12) & ~0xff)
1247+
1248+
fd, real_path = transform_path(ql, dirfd, path)
1249+
1250+
try:
1251+
if len(real_path) == 0:
1252+
st = ql.os.fd[dirfd].fstat()
1253+
else:
1254+
st = Stat(real_path, fd)
1255+
1256+
if ql.archbit == 32:
1257+
Statx = Statx32
1258+
else:
1259+
Statx = Statx64
1260+
1261+
stx = Statx(
1262+
stx_mask = 0x07ff, # STATX_BASIC_STATS
1263+
stx_blksize = st.st_blksize,
1264+
stx_nlink = st.st_nlink,
1265+
stx_uid = st.st_uid,
1266+
stx_gid = st.st_gid,
1267+
stx_mode = st.st_mode,
1268+
stx_ino = st.st_ino,
1269+
stx_size = st.st_size,
1270+
stx_blocks = st.st_blocks,
1271+
stx_atime = statx_convert_timestamp(st.st_atime, st.st_atime_ns),
1272+
stx_ctime = statx_convert_timestamp(st.st_ctime, st.st_ctime_ns),
1273+
stx_mtime = statx_convert_timestamp(st.st_mtime, st.st_mtime_ns),
1274+
stx_rdev_major = major(st.st_rdev),
1275+
stx_rdev_minor = minor(st.st_rdev),
1276+
stx_dev_major = major(st.st_dev),
1277+
stx_dev_minor = minor(st.st_dev),
1278+
)
1279+
1280+
ql.mem.write(buf_ptr, bytes(stx))
1281+
1282+
regreturn = 0
1283+
1284+
except Exception as e:
1285+
regreturn = -1
1286+
1287+
return regreturn
11501288

11511289
def ql_syscall_lstat(ql: Qiling, path: int, buf_ptr: int):
11521290
return statFamily(ql, path, buf_ptr, "lstat", Lstat, pack_stat64_struct)

tests/test_riscv.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,15 @@ def test_riscv64_hello_dyn_linux(self):
4747

4848
del ql
4949

50+
def test_riscv32_hello_dyn_linux(self):
51+
stdout = SimpleOutStream(1)
52+
ql = Qiling(['../examples/rootfs/riscv32_linux/bin/hello-linux'], '../examples/rootfs/riscv32_linux/',
53+
verbose=QL_VERBOSE.DEFAULT, stdout=stdout)
54+
55+
ql.run()
56+
self.assertTrue(stdout.read() == b'Hello, World!\n')
57+
58+
del ql
59+
5060
if __name__ == "__main__":
5161
unittest.main()

0 commit comments

Comments
 (0)