2424import sys
2525import socket
2626import subprocess
27- import logging
28- from typing import Optional , TYPE_CHECKING
27+ from typing import Dict , Optional , TYPE_CHECKING
2928
3029from qiling .const import QL_INTERCEPT , QL_OS
30+ from qiling .exception import QlErrorArch , QlErrorSyscallError , QlErrorSyscallNotFound
3131from qiling .os .posix .kernel_proxy .ipc import ProxyClient
3232from qiling .os .posix .kernel_proxy .proxy_fd import ql_proxy_fd
3333
3434if TYPE_CHECKING :
3535 from qiling import Qiling
3636
37- log = logging .getLogger (__name__ )
38-
3937
4038class KernelProxy :
4139 """Forward specific syscalls to a real Linux kernel via a helper process.
@@ -46,13 +44,13 @@ class KernelProxy:
4644
4745 def __init__ (self , ql : Qiling ):
4846 if sys .platform != 'linux' :
49- raise RuntimeError ("KernelProxy requires a Linux host" )
47+ raise QlErrorArch ("KernelProxy requires a Linux host" )
5048
5149 self .ql = ql
5250 self ._process : Optional [subprocess .Popen ] = None
5351 self ._client : Optional [ProxyClient ] = None
54- self ._forwarded : dict = {} # name -> syscall_nr
55- self ._reverse_table : Optional [dict ] = None # name -> nr (built on first use)
52+ self ._forwarded : Dict [ str , int ] = {} # name -> syscall_nr
53+ self ._reverse_table : Optional [Dict [ str , int ] ] = None # name -> nr (built on first use)
5654
5755 self ._start_proxy ()
5856
@@ -78,14 +76,13 @@ def _start_proxy(self):
7876 child_sock .close ()
7977
8078 self ._client = ProxyClient (parent_sock )
81- log .info (f"kernel proxy started (pid={ self ._process .pid } )" )
79+ self . ql . log .info (f"kernel proxy started (pid={ self ._process .pid } )" )
8280
83- def _build_reverse_table (self ) -> dict :
81+ def _build_reverse_table (self ) -> Dict [ str , int ] :
8482 """Build name -> syscall_nr mapping from the guest architecture's syscall table."""
8583 if self ._reverse_table is not None :
8684 return self ._reverse_table
8785
88- from qiling .os .linux .map_syscall import get_syscall_mapper
8986 from qiling .const import QL_ARCH
9087
9188 # get the raw syscall table dict for this architecture
@@ -102,7 +99,7 @@ def _build_reverse_table(self) -> dict:
10299
103100 table_name = arch_tables .get (self .ql .arch .type )
104101 if table_name is None :
105- raise RuntimeError (f"KernelProxy: unsupported architecture { self .ql .arch .type } " )
102+ raise QlErrorArch (f"KernelProxy: unsupported architecture { self .ql .arch .type } " )
106103
107104 import qiling .os .linux .map_syscall as mod
108105 table = getattr (mod , table_name )
@@ -115,7 +112,7 @@ def _resolve_syscall_nr(self, name: str) -> int:
115112 """Resolve a syscall name to its number for the guest architecture."""
116113 table = self ._build_reverse_table ()
117114 if name not in table :
118- raise ValueError (
115+ raise QlErrorSyscallNotFound (
119116 f"KernelProxy: syscall '{ name } ' not found in { self .ql .arch .type .name } syscall table"
120117 )
121118 return table [name ]
@@ -135,8 +132,8 @@ def forward_syscall(self, name: str, returns_fd: bool = False):
135132 forwarder = self ._make_forwarder (name , nr , returns_fd )
136133 self .ql .os .set_syscall (name , forwarder , QL_INTERCEPT .CALL )
137134
138- log .info (f"forwarding syscall '{ name } ' (nr={ nr } ) to kernel proxy"
139- f"{ ' [returns FD]' if returns_fd else '' } " )
135+ self . ql . log .info (f"forwarding syscall '{ name } ' (nr={ nr } ) to kernel proxy"
136+ f"{ ' [returns FD]' if returns_fd else '' } " )
140137
141138 def _make_forwarder (self , name : str , guest_nr : int , returns_fd : bool ):
142139 """Create a CALL hook closure for one syscall."""
@@ -170,17 +167,16 @@ def _get_host_syscall_nr(self, name: str) -> int:
170167 self ._host_table = self ._load_host_syscall_table ()
171168
172169 if name not in self ._host_table :
173- raise RuntimeError (f"KernelProxy: syscall '{ name } ' not available on host" )
170+ raise QlErrorSyscallNotFound (f"KernelProxy: syscall '{ name } ' not available on host" )
174171
175172 return self ._host_table [name ]
176173
177- def _load_host_syscall_table (self ) -> dict :
174+ def _load_host_syscall_table (self ) -> Dict [ str , int ] :
178175 """Load the host's syscall name->nr mapping.
179176
180177 Uses the same Qiling tables, indexed by the host architecture.
181178 """
182179 import platform
183- from qiling .const import QL_ARCH
184180 import qiling .os .linux .map_syscall as mod
185181
186182 machine = platform .machine ()
@@ -195,7 +191,7 @@ def _load_host_syscall_table(self) -> dict:
195191
196192 table_name = host_arch_map .get (machine )
197193 if table_name is None :
198- raise RuntimeError (f"KernelProxy: unsupported host architecture '{ machine } '" )
194+ raise QlErrorArch (f"KernelProxy: unsupported host architecture '{ machine } '" )
199195
200196 table = getattr (mod , table_name )
201197 return {name : nr for nr , name in table .items ()}
@@ -208,7 +204,7 @@ def _alloc_fd(ql, fd_obj) -> int:
208204 ql .os .fd [i ] = fd_obj
209205 return i
210206
211- raise OSError ("kernel_proxy: FD table full" )
207+ raise QlErrorSyscallError ("kernel_proxy: FD table full" )
212208
213209 def stop (self ):
214210 """Stop the proxy process."""
@@ -226,7 +222,7 @@ def stop(self):
226222 except subprocess .TimeoutExpired :
227223 self ._process .kill ()
228224 self ._process .wait ()
229- log .info (f"kernel proxy stopped (pid={ self ._process .pid } )" )
225+ self . ql . log .info (f"kernel proxy stopped (pid={ self ._process .pid } )" )
230226 self ._process = None
231227
232228 def __del__ (self ):
0 commit comments